1 /*
2 SPDX-FileCopyrightText: 2007 Nicolas Ternisien <nicolas.ternisien@gmail.com>
3
4 SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
7 #include "tabLogViewsWidget.h"
8
9 #include <QMenu>
10 #include <QPushButton>
11
12 #include <KLocalizedString>
13 #include <QIcon>
14
15 #include "ksystemlog_debug.h"
16
17 #include "logViewExport.h"
18 #include "view.h"
19
20 #include "defaults.h"
21 #include "logManager.h"
22 #include "logMode.h"
23 #include "logViewWidget.h"
24 #include "tabLogManager.h"
25
TabLogViewsWidget(QWidget * parent)26 TabLogViewsWidget::TabLogViewsWidget(QWidget *parent)
27 : QTabWidget(parent)
28 {
29 auto tabNewTabButton = new QPushButton(QIcon::fromTheme(QStringLiteral("tab-new")), QLatin1String(""), this);
30 connect(tabNewTabButton, &QAbstractButton::clicked, this, &TabLogViewsWidget::createTab);
31
32 tabNewTabButton->setToolTip(i18n("Create a new tab"));
33 tabNewTabButton->setWhatsThis(i18n("Creates a new tab which can display another log."));
34
35 auto tabCloseTabButton = new QPushButton(QIcon::fromTheme(QStringLiteral("tab-close")), QLatin1String(""), this);
36 connect(tabCloseTabButton, &QAbstractButton::clicked, this, &TabLogViewsWidget::closeTab);
37
38 tabCloseTabButton->setToolTip(i18n("Close the current tab"));
39 tabCloseTabButton->setWhatsThis(i18n("Closes the current tab."));
40
41 setCornerWidget(tabNewTabButton, Qt::TopLeftCorner);
42 setCornerWidget(tabCloseTabButton, Qt::TopRightCorner);
43
44 setUsesScrollButtons(true);
45
46 // The context menu is managed manually
47 setContextMenuPolicy(Qt::ActionsContextMenu);
48
49 // connect(this, SIGNAL(mouseDoubleClick()), this, SLOT(createTab()));
50 // connect(this, SIGNAL(contextMenu(QPoint)), this, SLOT(showContextMenu(QPoint)));
51 // connect(this, SIGNAL(contextMenu(QWidget*,QPoint)), this, SLOT(showContextMenu(QWidget*,QPoint)));
52
53 // TODO Use this (need to connect to movedTab(int, int) signal and update the QList
54 // setTabReorderingEnabled(true);
55
56 connect(this, &QTabWidget::currentChanged, this, &TabLogViewsWidget::changeCurrentTab);
57 }
58
~TabLogViewsWidget()59 TabLogViewsWidget::~TabLogViewsWidget()
60 {
61 const QList<TabLogManager *> copy = mTabLogManagers;
62
63 for (TabLogManager *tabLogManager : copy) {
64 mTabLogManagers.removeAll(tabLogManager);
65 delete tabLogManager;
66 }
67 }
68
newTab(View * view)69 void TabLogViewsWidget::newTab(View *view)
70 {
71 qCDebug(KSYSTEMLOG) << "Inserting to a new tab the view ";
72
73 // Add a tab at the end of the widget
74 insertTab(count(), view, QIcon::fromTheme(QStringLiteral(NO_MODE_ICON)), i18n("No Log"));
75
76 tabBar()->setVisible(count() > 1);
77 }
78
changeTab(View * view,const QIcon & icon,const QString & label)79 void TabLogViewsWidget::changeTab(View *view, const QIcon &icon, const QString &label)
80 {
81 qCDebug(KSYSTEMLOG) << "Changing tab " << label;
82 const int index = indexOf(view);
83 setTabIcon(index, icon);
84 setTabText(index, label);
85 }
86
logManagers() const87 QList<LogManager *> TabLogViewsWidget::logManagers() const
88 {
89 QList<LogManager *> logManagers;
90 const auto tabLogManagers = mTabLogManagers;
91 logManagers.reserve(tabLogManagers.count());
92 for (TabLogManager *tabLogManager : tabLogManagers) {
93 logManagers.append(tabLogManager->logManager());
94 }
95
96 return logManagers;
97 }
98
findRelatedLogManager(View * view)99 LogManager *TabLogViewsWidget::findRelatedLogManager(View *view)
100 {
101 return findRelatedTabLogManager(view)->logManager();
102 }
103
findRelatedTabLogManager(View * view) const104 TabLogManager *TabLogViewsWidget::findRelatedTabLogManager(View *view) const
105 {
106 for (TabLogManager *tabLogManager : std::as_const(mTabLogManagers)) {
107 if (tabLogManager->logManager()->usedView() == view) {
108 return tabLogManager;
109 }
110 }
111
112 qCCritical(KSYSTEMLOG) << "No log manager found";
113 return nullptr;
114 }
115
activeTabLogManager() const116 TabLogManager *TabLogViewsWidget::activeTabLogManager() const
117 {
118 View *currentView = static_cast<View *>(currentWidget());
119
120 return findRelatedTabLogManager(currentView);
121 }
122
activeLogManager() const123 LogManager *TabLogViewsWidget::activeLogManager() const
124 {
125 TabLogManager *tabLogManager = activeTabLogManager();
126 if (tabLogManager) {
127 return tabLogManager->logManager();
128 }
129 return nullptr;
130 }
131
createTab()132 LogManager *TabLogViewsWidget::createTab()
133 {
134 qCDebug(KSYSTEMLOG) << "Creating a new tab";
135
136 return newTabLogManager()->logManager();
137 }
138
moveTabLeft()139 void TabLogViewsWidget::moveTabLeft()
140 {
141 qCDebug(KSYSTEMLOG) << "Duplicate tab to the left";
142
143 TabLogManager *currentTabLogManager = activeTabLogManager();
144 const int position = indexOf(currentTabLogManager->logManager()->usedView());
145
146 if (position <= 0) {
147 qCCritical(KSYSTEMLOG) << "Tab Position <= 0 : " << position;
148 return;
149 }
150
151 mTabLogManagers.removeAt(position);
152 mTabLogManagers.insert(position - 1, currentTabLogManager);
153
154 tabBar()->moveTab(position, position - 1);
155 }
156
moveTabRight()157 void TabLogViewsWidget::moveTabRight()
158 {
159 qCDebug(KSYSTEMLOG) << "Duplicate tab to the right";
160
161 TabLogManager *currentTabLogManager = activeTabLogManager();
162 const int position = indexOf(currentTabLogManager->logManager()->usedView());
163
164 if (position >= count() - 1) {
165 qCCritical(KSYSTEMLOG) << "Tab Position >= count()-1 : " << position;
166 return;
167 }
168
169 mTabLogManagers.removeAt(position);
170 mTabLogManagers.insert(position + 1, currentTabLogManager);
171
172 tabBar()->moveTab(position, position + 1);
173 }
174
duplicateTab()175 LogManager *TabLogViewsWidget::duplicateTab()
176 {
177 qCDebug(KSYSTEMLOG) << "Duplicate current tab";
178
179 TabLogManager *currentManager = activeTabLogManager();
180
181 TabLogManager *tabLogManager = newTabLogManager();
182
183 LogMode *mode = currentManager->logManager()->logMode();
184
185 load(mode, tabLogManager->logManager());
186
187 // Returns the newly created LogManager
188 return tabLogManager->logManager();
189 }
190
newTabLogManager()191 TabLogManager *TabLogViewsWidget::newTabLogManager()
192 {
193 qCDebug(KSYSTEMLOG) << "Creating new View...";
194
195 View *view = new View(this);
196
197 qCDebug(KSYSTEMLOG) << "Creating new LogManager...";
198
199 auto logManager = new LogManager(view);
200
201 // Signals from LogManager to Main Class
202 connect(logManager, &LogManager::tabTitleChanged, this, &TabLogViewsWidget::changeTab);
203 connect(logManager, &LogManager::logUpdated, this, &TabLogViewsWidget::changeTitleAddedLines);
204
205 auto tabLogManager = new TabLogManager(logManager);
206 mTabLogManagers.append(tabLogManager);
207
208 qCDebug(KSYSTEMLOG) << "New LogManager created";
209
210 // Finally add the view to the tabs
211 newTab(view);
212
213 Q_EMIT logManagerCreated(logManager);
214
215 setCurrentIndex(count() - 1);
216
217 // Set focus to the list
218 view->logViewWidget()->setFocus();
219
220 // Returns the newly created TabLogManager
221 return tabLogManager;
222 }
223
closeTab()224 void TabLogViewsWidget::closeTab()
225 {
226 if (count() == 1) {
227 qCCritical(KSYSTEMLOG) << "Cannot close tab, one tab left";
228 return;
229 }
230
231 TabLogManager *currentTabLogManager = activeTabLogManager();
232
233 mTabLogManagers.removeAll(currentTabLogManager);
234
235 removeTab(indexOf(currentTabLogManager->logManager()->usedView()));
236 if (count() == 1) {
237 tabBar()->hide();
238 }
239
240 delete currentTabLogManager;
241 }
242
load(LogMode * logMode,LogManager * manager,const QVariant & analyzerOptions)243 void TabLogViewsWidget::load(LogMode *logMode, LogManager *manager, const QVariant &analyzerOptions)
244 {
245 qCDebug(KSYSTEMLOG) << "Loading a new mode : " << logMode->name();
246
247 if (!manager) {
248 qCCritical(KSYSTEMLOG) << "Error while loading a manager ";
249 return;
250 }
251
252 // The manager is now using the Log mode passed in parameter
253 manager->initialize(logMode, analyzerOptions);
254
255 // Launch the reading
256 manager->reload();
257 }
258
reloadCurrent()259 void TabLogViewsWidget::reloadCurrent()
260 {
261 qCDebug(KSYSTEMLOG) << "Reloading current log manager...";
262
263 LogManager *manager = activeLogManager();
264
265 if (manager) {
266 manager->reload();
267 }
268 }
269
reloadAll()270 void TabLogViewsWidget::reloadAll()
271 {
272 qCDebug(KSYSTEMLOG) << "Reloading all tabs...";
273
274 const auto tabLogManagers = mTabLogManagers;
275 for (TabLogManager *tabLogManager : tabLogManagers) {
276 // Log manager without log mode does not need to be reloaded
277 if (!tabLogManager->logManager()->logMode()) {
278 continue;
279 }
280
281 // Do a simple reload if it is an open log mode
282 if (tabLogManager->logManager()->logMode()->id() == QLatin1String("openLogMode")) {
283 tabLogManager->logManager()->reload();
284 continue;
285 }
286
287 // Do a full loading of other log modes (needed if log files have been modified)
288 load(tabLogManager->logManager()->logMode(), tabLogManager->logManager(), tabLogManager->logManager()->analyzerOptions());
289 }
290 }
291
changeCurrentTab(int index)292 void TabLogViewsWidget::changeCurrentTab(int index)
293 {
294 qCDebug(KSYSTEMLOG) << "Changing current tab...";
295
296 if (index == -1) {
297 return;
298 }
299
300 TabLogManager *tabLogManager = activeTabLogManager();
301
302 // Reinit the new lines count since last selection
303 tabLogManager->initNewLinesCount();
304
305 // If the tab displayed the new added line count, rename it to the default log mode name
306 changeTab(tabLogManager->logManager()->usedView(), logModeIcon(tabLogManager->logManager()->logMode()), tabLogManager->title());
307
308 qCDebug(KSYSTEMLOG) << "Current tab changed";
309 }
310
changeReloadingTab(View * view,bool reloading)311 void TabLogViewsWidget::changeReloadingTab(View *view, bool reloading)
312 {
313 TabLogManager *tabLogManager = findRelatedTabLogManager(view);
314
315 if (reloading) {
316 changeTab(tabLogManager->logManager()->usedView(), QIcon::fromTheme(QStringLiteral("view-refresh")), tabLogManager->title());
317 } else {
318 changeTab(tabLogManager->logManager()->usedView(), logModeIcon(tabLogManager->logManager()->logMode()), tabLogManager->title());
319 }
320 }
321
changeTitleAddedLines(View * view,int addedLinesSinceLastUpdate)322 void TabLogViewsWidget::changeTitleAddedLines(View *view, int addedLinesSinceLastUpdate)
323 {
324 qCDebug(KSYSTEMLOG) << "Changing title" << addedLinesSinceLastUpdate << " added lines...";
325 LogManager *currentManager = activeLogManager();
326
327 // Only display added line on tab title if this is not an update of the current tab
328 if (currentManager->usedView() != view) {
329 TabLogManager *tabLogManager = findRelatedTabLogManager(view);
330 tabLogManager->addNewLinesCount(addedLinesSinceLastUpdate);
331
332 // Update the tab title
333 changeTab(tabLogManager->logManager()->usedView(), logModeIcon(tabLogManager->logManager()->logMode()), tabLogManager->title());
334 }
335 }
336
expandAllCurrentView()337 void TabLogViewsWidget::expandAllCurrentView()
338 {
339 activeLogManager()->usedView()->logViewWidget()->expandAll();
340 }
341
collapseAllCurrentView()342 void TabLogViewsWidget::collapseAllCurrentView()
343 {
344 activeLogManager()->usedView()->logViewWidget()->collapseAll();
345 }
346
selectAllCurrentView()347 void TabLogViewsWidget::selectAllCurrentView()
348 {
349 activeLogManager()->usedView()->logViewWidget()->selectAll();
350 }
351
fileSaveCurrentView()352 void TabLogViewsWidget::fileSaveCurrentView()
353 {
354 LogViewExport logViewExport(this, activeLogManager()->usedView()->logViewWidget());
355 connect(&logViewExport, &LogViewExport::statusBarChanged, this, &TabLogViewsWidget::statusBarChanged);
356 logViewExport.fileSave();
357 }
358
copyToClipboardCurrentView()359 void TabLogViewsWidget::copyToClipboardCurrentView()
360 {
361 LogViewExport logViewExport(this, activeLogManager()->usedView()->logViewWidget());
362 connect(&logViewExport, &LogViewExport::statusBarChanged, this, &TabLogViewsWidget::statusBarChanged);
363 logViewExport.copyToClipboard();
364 }
365
sendMailCurrentView()366 void TabLogViewsWidget::sendMailCurrentView()
367 {
368 LogViewExport logViewExport(this, activeLogManager()->usedView()->logViewWidget());
369 connect(&logViewExport, &LogViewExport::statusBarChanged, this, &TabLogViewsWidget::statusBarChanged);
370 logViewExport.sendMail();
371 }
372
printSelectionCurrentView()373 void TabLogViewsWidget::printSelectionCurrentView()
374 {
375 LogViewExport logViewExport(this, activeLogManager()->usedView()->logViewWidget());
376 connect(&logViewExport, &LogViewExport::statusBarChanged, this, &TabLogViewsWidget::statusBarChanged);
377 logViewExport.printSelection();
378 }
379
printPreviewSelectionCurrentView()380 void TabLogViewsWidget::printPreviewSelectionCurrentView()
381 {
382 LogViewExport logViewExport(this, activeLogManager()->usedView()->logViewWidget());
383 connect(&logViewExport, &LogViewExport::statusBarChanged, this, &TabLogViewsWidget::statusBarChanged);
384 logViewExport.printPreview();
385 }
386
logModeIcon(LogMode * logMode) const387 QIcon TabLogViewsWidget::logModeIcon(LogMode *logMode) const
388 {
389 if (!logMode) {
390 return QIcon::fromTheme(QStringLiteral(NO_MODE_ICON));
391 } else {
392 return logMode->icon();
393 }
394 }
395
prepareContextMenu(bool)396 void TabLogViewsWidget::prepareContextMenu(bool /*onTab*/)
397 {
398 if (!mContextMenu) {
399 mContextMenu = new QMenu(this);
400 mContextMenu->addActions(actions());
401 }
402
403 // TODO Disable some actions, depending of the onTab value
404 }
405
showContextMenu(const QPoint & cursorPosition)406 void TabLogViewsWidget::showContextMenu(const QPoint &cursorPosition)
407 {
408 qCDebug(KSYSTEMLOG) << "Showing context menu at " << cursorPosition;
409
410 prepareContextMenu(false);
411
412 mContextMenu->popup(cursorPosition);
413 }
414
showContextMenu(QWidget * tab,const QPoint & cursorPosition)415 void TabLogViewsWidget::showContextMenu(QWidget *tab, const QPoint &cursorPosition)
416 {
417 qCDebug(KSYSTEMLOG) << "Showing context menu at " << cursorPosition << " at " << tab->objectName();
418
419 prepareContextMenu(true);
420
421 mContextMenu->popup(cursorPosition);
422 }
423