File indexing completed on 2024-04-21 05:46:24

0001 /*
0002     SPDX-FileCopyrightText: 2007 Nicolas Ternisien <nicolas.ternisien@gmail.com>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "tabLogViewsWidget.h"
0008 
0009 #include <QMenu>
0010 #include <QPushButton>
0011 
0012 #include <KLocalizedString>
0013 #include <QIcon>
0014 
0015 #include "ksystemlog_debug.h"
0016 
0017 #include "logViewExport.h"
0018 #include "view.h"
0019 
0020 #include "defaults.h"
0021 #include "logManager.h"
0022 #include "logMode.h"
0023 #include "logViewWidget.h"
0024 #include "tabLogManager.h"
0025 
0026 TabLogViewsWidget::TabLogViewsWidget(QWidget *parent)
0027     : QTabWidget(parent)
0028 {
0029     auto tabNewTabButton = new QPushButton(QIcon::fromTheme(QStringLiteral("tab-new")), QLatin1String(""), this);
0030     connect(tabNewTabButton, &QAbstractButton::clicked, this, &TabLogViewsWidget::createTab);
0031 
0032     tabNewTabButton->setToolTip(i18n("Create a new tab"));
0033     tabNewTabButton->setWhatsThis(i18n("Creates a new tab which can display another log."));
0034 
0035     auto tabCloseTabButton = new QPushButton(QIcon::fromTheme(QStringLiteral("tab-close")), QLatin1String(""), this);
0036     connect(tabCloseTabButton, &QAbstractButton::clicked, this, &TabLogViewsWidget::closeTab);
0037 
0038     tabCloseTabButton->setToolTip(i18n("Close the current tab"));
0039     tabCloseTabButton->setWhatsThis(i18n("Closes the current tab."));
0040 
0041     setCornerWidget(tabNewTabButton, Qt::TopLeftCorner);
0042     setCornerWidget(tabCloseTabButton, Qt::TopRightCorner);
0043 
0044     setUsesScrollButtons(true);
0045 
0046     // The context menu is managed manually
0047     setContextMenuPolicy(Qt::ActionsContextMenu);
0048 
0049     // connect(this, SIGNAL(mouseDoubleClick()), this, SLOT(createTab()));
0050     // connect(this, SIGNAL(contextMenu(QPoint)), this, SLOT(showContextMenu(QPoint)));
0051     // connect(this, SIGNAL(contextMenu(QWidget*,QPoint)), this, SLOT(showContextMenu(QWidget*,QPoint)));
0052 
0053     // TODO Use this (need to connect to movedTab(int, int) signal and update the QList
0054     // setTabReorderingEnabled(true);
0055 
0056     connect(this, &QTabWidget::currentChanged, this, &TabLogViewsWidget::changeCurrentTab);
0057 }
0058 
0059 TabLogViewsWidget::~TabLogViewsWidget()
0060 {
0061     const QList<TabLogManager *> copy = mTabLogManagers;
0062 
0063     for (TabLogManager *tabLogManager : copy) {
0064         mTabLogManagers.removeAll(tabLogManager);
0065         delete tabLogManager;
0066     }
0067 }
0068 
0069 void TabLogViewsWidget::newTab(View *view)
0070 {
0071     qCDebug(KSYSTEMLOG) << "Inserting to a new tab the view ";
0072 
0073     // Add a tab at the end of the widget
0074     insertTab(count(), view, QIcon::fromTheme(QStringLiteral(NO_MODE_ICON)), i18n("No Log"));
0075 
0076     tabBar()->setVisible(count() > 1);
0077 }
0078 
0079 void TabLogViewsWidget::changeTab(View *view, const QIcon &icon, const QString &label)
0080 {
0081     qCDebug(KSYSTEMLOG) << "Changing tab " << label;
0082     const int index = indexOf(view);
0083     setTabIcon(index, icon);
0084     setTabText(index, label);
0085 }
0086 
0087 QList<LogManager *> TabLogViewsWidget::logManagers() const
0088 {
0089     QList<LogManager *> logManagers;
0090     const auto tabLogManagers = mTabLogManagers;
0091     logManagers.reserve(tabLogManagers.count());
0092     for (TabLogManager *tabLogManager : tabLogManagers) {
0093         logManagers.append(tabLogManager->logManager());
0094     }
0095 
0096     return logManagers;
0097 }
0098 
0099 LogManager *TabLogViewsWidget::findRelatedLogManager(View *view)
0100 {
0101     return findRelatedTabLogManager(view)->logManager();
0102 }
0103 
0104 TabLogManager *TabLogViewsWidget::findRelatedTabLogManager(View *view) const
0105 {
0106     for (TabLogManager *tabLogManager : std::as_const(mTabLogManagers)) {
0107         if (tabLogManager->logManager()->usedView() == view) {
0108             return tabLogManager;
0109         }
0110     }
0111 
0112     qCCritical(KSYSTEMLOG) << "No log manager found";
0113     return nullptr;
0114 }
0115 
0116 TabLogManager *TabLogViewsWidget::activeTabLogManager() const
0117 {
0118     View *currentView = static_cast<View *>(currentWidget());
0119 
0120     return findRelatedTabLogManager(currentView);
0121 }
0122 
0123 LogManager *TabLogViewsWidget::activeLogManager() const
0124 {
0125     TabLogManager *tabLogManager = activeTabLogManager();
0126     if (tabLogManager) {
0127         return tabLogManager->logManager();
0128     }
0129     return nullptr;
0130 }
0131 
0132 LogManager *TabLogViewsWidget::createTab()
0133 {
0134     qCDebug(KSYSTEMLOG) << "Creating a new tab";
0135 
0136     return newTabLogManager()->logManager();
0137 }
0138 
0139 void TabLogViewsWidget::moveTabLeft()
0140 {
0141     qCDebug(KSYSTEMLOG) << "Duplicate tab to the left";
0142 
0143     TabLogManager *currentTabLogManager = activeTabLogManager();
0144     const int position = indexOf(currentTabLogManager->logManager()->usedView());
0145 
0146     if (position <= 0) {
0147         qCCritical(KSYSTEMLOG) << "Tab Position <= 0 : " << position;
0148         return;
0149     }
0150 
0151     mTabLogManagers.removeAt(position);
0152     mTabLogManagers.insert(position - 1, currentTabLogManager);
0153 
0154     tabBar()->moveTab(position, position - 1);
0155 }
0156 
0157 void TabLogViewsWidget::moveTabRight()
0158 {
0159     qCDebug(KSYSTEMLOG) << "Duplicate tab to the right";
0160 
0161     TabLogManager *currentTabLogManager = activeTabLogManager();
0162     const int position = indexOf(currentTabLogManager->logManager()->usedView());
0163 
0164     if (position >= count() - 1) {
0165         qCCritical(KSYSTEMLOG) << "Tab Position >= count()-1 : " << position;
0166         return;
0167     }
0168 
0169     mTabLogManagers.removeAt(position);
0170     mTabLogManagers.insert(position + 1, currentTabLogManager);
0171 
0172     tabBar()->moveTab(position, position + 1);
0173 }
0174 
0175 LogManager *TabLogViewsWidget::duplicateTab()
0176 {
0177     qCDebug(KSYSTEMLOG) << "Duplicate current tab";
0178 
0179     TabLogManager *currentManager = activeTabLogManager();
0180 
0181     TabLogManager *tabLogManager = newTabLogManager();
0182 
0183     LogMode *mode = currentManager->logManager()->logMode();
0184 
0185     load(mode, tabLogManager->logManager());
0186 
0187     // Returns the newly created LogManager
0188     return tabLogManager->logManager();
0189 }
0190 
0191 TabLogManager *TabLogViewsWidget::newTabLogManager()
0192 {
0193     qCDebug(KSYSTEMLOG) << "Creating new View...";
0194 
0195     View *view = new View(this);
0196 
0197     qCDebug(KSYSTEMLOG) << "Creating new LogManager...";
0198 
0199     auto logManager = new LogManager(view);
0200 
0201     // Signals from LogManager to Main Class
0202     connect(logManager, &LogManager::tabTitleChanged, this, &TabLogViewsWidget::changeTab);
0203     connect(logManager, &LogManager::logUpdated, this, &TabLogViewsWidget::changeTitleAddedLines);
0204 
0205     auto tabLogManager = new TabLogManager(logManager);
0206     mTabLogManagers.append(tabLogManager);
0207 
0208     qCDebug(KSYSTEMLOG) << "New LogManager created";
0209 
0210     // Finally add the view to the tabs
0211     newTab(view);
0212 
0213     Q_EMIT logManagerCreated(logManager);
0214 
0215     setCurrentIndex(count() - 1);
0216 
0217     // Set focus to the list
0218     view->logViewWidget()->setFocus();
0219 
0220     // Returns the newly created TabLogManager
0221     return tabLogManager;
0222 }
0223 
0224 void TabLogViewsWidget::closeTab()
0225 {
0226     if (count() == 1) {
0227         qCCritical(KSYSTEMLOG) << "Cannot close tab, one tab left";
0228         return;
0229     }
0230 
0231     TabLogManager *currentTabLogManager = activeTabLogManager();
0232 
0233     mTabLogManagers.removeAll(currentTabLogManager);
0234 
0235     removeTab(indexOf(currentTabLogManager->logManager()->usedView()));
0236     if (count() == 1) {
0237         tabBar()->hide();
0238     }
0239 
0240     delete currentTabLogManager;
0241 }
0242 
0243 void TabLogViewsWidget::load(LogMode *logMode, LogManager *manager, const QVariant &analyzerOptions)
0244 {
0245     qCDebug(KSYSTEMLOG) << "Loading a new mode : " << logMode->name();
0246 
0247     if (!manager) {
0248         qCCritical(KSYSTEMLOG) << "Error while loading a manager ";
0249         return;
0250     }
0251 
0252     // The manager is now using the Log mode passed in parameter
0253     manager->initialize(logMode, analyzerOptions);
0254 
0255     // Launch the reading
0256     manager->reload();
0257 }
0258 
0259 void TabLogViewsWidget::reloadCurrent()
0260 {
0261     qCDebug(KSYSTEMLOG) << "Reloading current log manager...";
0262 
0263     LogManager *manager = activeLogManager();
0264 
0265     if (manager) {
0266         manager->reload();
0267     }
0268 }
0269 
0270 void TabLogViewsWidget::reloadAll()
0271 {
0272     qCDebug(KSYSTEMLOG) << "Reloading all tabs...";
0273 
0274     const auto tabLogManagers = mTabLogManagers;
0275     for (TabLogManager *tabLogManager : tabLogManagers) {
0276         // Log manager without log mode does not need to be reloaded
0277         if (!tabLogManager->logManager()->logMode()) {
0278             continue;
0279         }
0280 
0281         // Do a simple reload if it is an open log mode
0282         if (tabLogManager->logManager()->logMode()->id() == QLatin1String("openLogMode")) {
0283             tabLogManager->logManager()->reload();
0284             continue;
0285         }
0286 
0287         // Do a full loading of other log modes (needed if log files have been modified)
0288         load(tabLogManager->logManager()->logMode(), tabLogManager->logManager(), tabLogManager->logManager()->analyzerOptions());
0289     }
0290 }
0291 
0292 void TabLogViewsWidget::changeCurrentTab(int index)
0293 {
0294     qCDebug(KSYSTEMLOG) << "Changing current tab...";
0295 
0296     if (index == -1) {
0297         return;
0298     }
0299 
0300     TabLogManager *tabLogManager = activeTabLogManager();
0301 
0302     // Reinit the new lines count since last selection
0303     tabLogManager->initNewLinesCount();
0304 
0305     // If the tab displayed the new added line count, rename it to the default log mode name
0306     changeTab(tabLogManager->logManager()->usedView(), logModeIcon(tabLogManager->logManager()->logMode()), tabLogManager->title());
0307 
0308     qCDebug(KSYSTEMLOG) << "Current tab changed";
0309 }
0310 
0311 void TabLogViewsWidget::changeReloadingTab(View *view, bool reloading)
0312 {
0313     TabLogManager *tabLogManager = findRelatedTabLogManager(view);
0314 
0315     if (reloading) {
0316         changeTab(tabLogManager->logManager()->usedView(), QIcon::fromTheme(QStringLiteral("view-refresh")), tabLogManager->title());
0317     } else {
0318         changeTab(tabLogManager->logManager()->usedView(), logModeIcon(tabLogManager->logManager()->logMode()), tabLogManager->title());
0319     }
0320 }
0321 
0322 void TabLogViewsWidget::changeTitleAddedLines(View *view, int addedLinesSinceLastUpdate)
0323 {
0324     qCDebug(KSYSTEMLOG) << "Changing title" << addedLinesSinceLastUpdate << " added lines...";
0325     LogManager *currentManager = activeLogManager();
0326 
0327     // Only display added line on tab title if this is not an update of the current tab
0328     if (currentManager->usedView() != view) {
0329         TabLogManager *tabLogManager = findRelatedTabLogManager(view);
0330         tabLogManager->addNewLinesCount(addedLinesSinceLastUpdate);
0331 
0332         // Update the tab title
0333         changeTab(tabLogManager->logManager()->usedView(), logModeIcon(tabLogManager->logManager()->logMode()), tabLogManager->title());
0334     }
0335 }
0336 
0337 void TabLogViewsWidget::expandAllCurrentView()
0338 {
0339     activeLogManager()->usedView()->logViewWidget()->expandAll();
0340 }
0341 
0342 void TabLogViewsWidget::collapseAllCurrentView()
0343 {
0344     activeLogManager()->usedView()->logViewWidget()->collapseAll();
0345 }
0346 
0347 void TabLogViewsWidget::selectAllCurrentView()
0348 {
0349     activeLogManager()->usedView()->logViewWidget()->selectAll();
0350 }
0351 
0352 void TabLogViewsWidget::fileSaveCurrentView()
0353 {
0354     LogViewExport logViewExport(this, activeLogManager()->usedView()->logViewWidget());
0355     connect(&logViewExport, &LogViewExport::statusBarChanged, this, &TabLogViewsWidget::statusBarChanged);
0356     logViewExport.fileSave();
0357 }
0358 
0359 void TabLogViewsWidget::copyToClipboardCurrentView()
0360 {
0361     LogViewExport logViewExport(this, activeLogManager()->usedView()->logViewWidget());
0362     connect(&logViewExport, &LogViewExport::statusBarChanged, this, &TabLogViewsWidget::statusBarChanged);
0363     logViewExport.copyToClipboard();
0364 }
0365 
0366 void TabLogViewsWidget::sendMailCurrentView()
0367 {
0368     LogViewExport logViewExport(this, activeLogManager()->usedView()->logViewWidget());
0369     connect(&logViewExport, &LogViewExport::statusBarChanged, this, &TabLogViewsWidget::statusBarChanged);
0370     logViewExport.sendMail();
0371 }
0372 
0373 void TabLogViewsWidget::printSelectionCurrentView()
0374 {
0375     LogViewExport logViewExport(this, activeLogManager()->usedView()->logViewWidget());
0376     connect(&logViewExport, &LogViewExport::statusBarChanged, this, &TabLogViewsWidget::statusBarChanged);
0377     logViewExport.printSelection();
0378 }
0379 
0380 void TabLogViewsWidget::printPreviewSelectionCurrentView()
0381 {
0382     LogViewExport logViewExport(this, activeLogManager()->usedView()->logViewWidget());
0383     connect(&logViewExport, &LogViewExport::statusBarChanged, this, &TabLogViewsWidget::statusBarChanged);
0384     logViewExport.printPreview();
0385 }
0386 
0387 QIcon TabLogViewsWidget::logModeIcon(LogMode *logMode) const
0388 {
0389     if (!logMode) {
0390         return QIcon::fromTheme(QStringLiteral(NO_MODE_ICON));
0391     } else {
0392         return logMode->icon();
0393     }
0394 }
0395 
0396 void TabLogViewsWidget::prepareContextMenu(bool /*onTab*/)
0397 {
0398     if (!mContextMenu) {
0399         mContextMenu = new QMenu(this);
0400         mContextMenu->addActions(actions());
0401     }
0402 
0403     // TODO Disable some actions, depending of the onTab value
0404 }
0405 
0406 void TabLogViewsWidget::showContextMenu(const QPoint &cursorPosition)
0407 {
0408     qCDebug(KSYSTEMLOG) << "Showing context menu at " << cursorPosition;
0409 
0410     prepareContextMenu(false);
0411 
0412     mContextMenu->popup(cursorPosition);
0413 }
0414 
0415 void TabLogViewsWidget::showContextMenu(QWidget *tab, const QPoint &cursorPosition)
0416 {
0417     qCDebug(KSYSTEMLOG) << "Showing context menu at " << cursorPosition << " at " << tab->objectName();
0418 
0419     prepareContextMenu(true);
0420 
0421     mContextMenu->popup(cursorPosition);
0422 }
0423 
0424 #include "moc_tabLogViewsWidget.cpp"