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 "logViewWidget.h"
8
9 #include <QAction>
10 #include <QHeaderView>
11
12 #include <KLocalizedString>
13 #include <QIcon>
14
15 #include "ksystemlog_debug.h"
16
17 #include "logViewColumn.h"
18
19 #include "logLine.h"
20 #include "logViewModel.h"
21 #include "logViewWidgetItem.h"
22
23 #include "ksystemlogConfig.h"
24
LogViewWidget(QWidget * parent)25 LogViewWidget::LogViewWidget(QWidget *parent)
26 : QTreeWidget(parent)
27 {
28 // TODO Add this setWhatsThis() to all columns each time they change
29 // setWhatThis(i18n("<p>This is the main view of KSystemLog. It displays the last lines of the selected
30 // log. Please see the documentation to discovers the meaning of each icons and existing log.</p><p>Log
31 // lines in <b>bold</b> are the last added to the list.</p>"));
32
33 const QStringList headerLabels{i18n("Date"), i18n("Message")};
34
35 mLogViewModel = new LogViewModel(this);
36 mHeadersTogglingActions = new QActionGroup(this);
37 mHeadersTogglingActions->setExclusive(false);
38 connect(mHeadersTogglingActions, &QActionGroup::triggered, this, &LogViewWidget::toggleHeader);
39
40 setHeaderLabels(headerLabels);
41
42 // Header
43 header()->setContextMenuPolicy(Qt::ActionsContextMenu);
44 // header()->setMovable(true);
45 header()->setSectionsMovable(true);
46
47 setSortingEnabled(true);
48 sortItems(0, Qt::AscendingOrder);
49
50 setAnimated(true);
51
52 setRootIsDecorated(false);
53
54 setAllColumnsShowFocus(true);
55
56 setAlternatingRowColors(true);
57
58 setSelectionMode(QAbstractItemView::ExtendedSelection);
59
60 setContextMenuPolicy(Qt::ActionsContextMenu);
61 }
62
~LogViewWidget()63 LogViewWidget::~LogViewWidget()
64 {
65 delete mLogViewModel;
66 }
67
setColumns(const LogViewColumns & columns)68 void LogViewWidget::setColumns(const LogViewColumns &columns)
69 {
70 qCDebug(KSYSTEMLOG) << "Updating columns using " << columns << "...";
71
72 // First, delete all current columns
73 setColumnCount(0);
74
75 setHeaderLabels(columns.toStringList());
76
77 sortItems(0, Qt::AscendingOrder);
78
79 // Remove previous header actions
80 QListIterator<QAction *> it(mHeadersTogglingActions->actions());
81 it.toBack();
82 while (it.hasPrevious()) {
83 QAction *action = it.previous();
84
85 header()->removeAction(action);
86 mHeadersTogglingActions->removeAction(action);
87
88 delete action;
89 }
90
91 // Add new actions
92 int columnIndex = 0;
93
94 const auto columnsLst = columns.columns();
95 for (const LogViewColumn &column : columnsLst) {
96 auto action = new QAction(this);
97 action->setText(column.columnName());
98 // helloAction->setIcon(QIcon::fromTheme( QLatin1String( "media-playback-start" )));
99 // helloAction->setShortcut(Qt::CTRL | Qt::Key_M);
100 action->setCheckable(true);
101 action->setChecked(true);
102 action->setToolTip(i18n("Display/Hide the '%1' column", column.columnName()));
103 action->setData(QVariant(columnIndex));
104
105 mHeadersTogglingActions->addAction(action);
106
107 ++columnIndex;
108 }
109
110 header()->addActions(mHeadersTogglingActions->actions());
111
112 Q_EMIT columnsChanged(columns);
113
114 qCDebug(KSYSTEMLOG) << "Log View Widget updated...";
115 }
116
resizeColumns()117 void LogViewWidget::resizeColumns()
118 {
119 // Resize all columns except the last one (which always take the last available space)
120 for (int i = 0; i < columnCount() - 1; ++i) {
121 resizeColumnToContents(i);
122 }
123 }
124
selectAll()125 void LogViewWidget::selectAll()
126 {
127 if (notHiddenItemCount() > 0) {
128 QTreeWidget::selectAll();
129 }
130 }
131
itemCount() const132 int LogViewWidget::itemCount() const
133 {
134 return topLevelItemCount();
135 }
136
logLines()137 QList<LogLine *> LogViewWidget::logLines()
138 {
139 QList<LogLine *> logLines;
140
141 QTreeWidgetItemIterator it(this);
142 while (*it) {
143 auto item = static_cast<LogViewWidgetItem *>(*it);
144 logLines.append(item->logLine());
145 ++it;
146 }
147
148 return logLines;
149 }
150
findNewestItem()151 LogViewWidgetItem *LogViewWidget::findNewestItem()
152 {
153 LogViewWidgetItem *newestItem = nullptr;
154
155 QTreeWidgetItemIterator it(this);
156 while (*it) {
157 auto item = static_cast<LogViewWidgetItem *>(*it);
158 if (!newestItem || newestItem->logLine()->isOlderThan(*(item->logLine()))) {
159 newestItem = item;
160 }
161
162 ++it;
163 }
164
165 return newestItem;
166 }
167
findItem(LogLine * searchedLogLine)168 LogViewWidgetItem *LogViewWidget::findItem(LogLine *searchedLogLine)
169 {
170 QTreeWidgetItemIterator it(this);
171 while (*it) {
172 auto item = static_cast<LogViewWidgetItem *>(*it);
173 if (item->logLine()->equals(*searchedLogLine)) {
174 return item;
175 }
176
177 ++it;
178 }
179
180 return nullptr;
181 }
182
items()183 QList<LogViewWidgetItem *> LogViewWidget::items()
184 {
185 QList<LogViewWidgetItem *> items;
186
187 QTreeWidgetItemIterator it(this);
188 while (*it) {
189 items.append(static_cast<LogViewWidgetItem *>(*it));
190 ++it;
191 }
192
193 return items;
194 }
195
model() const196 LogViewModel *LogViewWidget::model() const
197 {
198 return mLogViewModel;
199 }
200
hasItemsSelected()201 bool LogViewWidget::hasItemsSelected()
202 {
203 return !selectedItems().isEmpty();
204 }
205
firstSelectedItem()206 LogViewWidgetItem *LogViewWidget::firstSelectedItem()
207 {
208 QTreeWidgetItemIterator it(this, QTreeWidgetItemIterator::Selected);
209
210 // Returns the first selected item or NULL is there is no item selected
211 return static_cast<LogViewWidgetItem *>(*it);
212 }
213
lastSelectedItem()214 LogViewWidgetItem *LogViewWidget::lastSelectedItem()
215 {
216 QTreeWidgetItemIterator it(this, QTreeWidgetItemIterator::Selected);
217
218 QTreeWidgetItem *item = nullptr;
219 while (*it) {
220 item = (*it);
221
222 ++it;
223 }
224
225 // Returns the last selected item or NULL is there is no item selected
226 return static_cast<LogViewWidgetItem *>(item);
227 }
228
expandAll()229 void LogViewWidget::expandAll()
230 {
231 QTreeWidgetItemIterator it(this);
232 while (*it) {
233 expandItem(*it);
234 ++it;
235 }
236 }
237
collapseAll()238 void LogViewWidget::collapseAll()
239 {
240 QTreeWidgetItemIterator it(this);
241 while (*it) {
242 collapseItem(*it);
243 ++it;
244 }
245 }
246
toggleToolTip(bool enabled)247 void LogViewWidget::toggleToolTip(bool enabled)
248 {
249 qCDebug(KSYSTEMLOG) << "Toggle tool tip " << enabled;
250
251 QTreeWidgetItemIterator it(this);
252 while (*it) {
253 auto item = static_cast<LogViewWidgetItem *>(*it);
254 item->toggleToolTip(enabled);
255
256 ++it;
257 }
258 }
259
scrollToNewestItem()260 void LogViewWidget::scrollToNewestItem()
261 {
262 qCDebug(KSYSTEMLOG) << "Scrolling to the newest item...";
263
264 // Scroll to last item if requested
265 if (KSystemLogConfig::newLinesDisplayed()) {
266 LogViewWidgetItem *newestItem = findNewestItem();
267 if (newestItem) {
268 scrollToItem(newestItem);
269 }
270 }
271 }
272
notHiddenItemCount()273 int LogViewWidget::notHiddenItemCount()
274 {
275 int count = 0;
276
277 QTreeWidgetItemIterator it(this, QTreeWidgetItemIterator::NotHidden);
278 while (*it) {
279 count++;
280 ++it;
281 }
282
283 return count;
284 }
285
toggleHeader(QAction * action)286 void LogViewWidget::toggleHeader(QAction *action)
287 {
288 qCDebug(KSYSTEMLOG) << "Toggling header";
289
290 int columnIndex = action->data().toInt();
291 if (header()->isSectionHidden(columnIndex)) {
292 header()->setSectionHidden(columnIndex, false);
293 } else {
294 header()->setSectionHidden(columnIndex, true);
295 }
296 }
297