File indexing completed on 2024-05-05 05:48:58

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 "logViewWidget.h"
0008 
0009 #include <QAction>
0010 #include <QActionGroup>
0011 #include <QHeaderView>
0012 
0013 #include <KLocalizedString>
0014 #include <QIcon>
0015 
0016 #include "ksystemlog_debug.h"
0017 
0018 #include "logViewColumn.h"
0019 
0020 #include "logLine.h"
0021 #include "logViewModel.h"
0022 #include "logViewWidgetItem.h"
0023 
0024 #include "ksystemlogConfig.h"
0025 
0026 LogViewWidget::LogViewWidget(QWidget *parent)
0027     : QTreeWidget(parent)
0028 {
0029     // TODO Add this setWhatsThis() to all columns each time they change
0030     // setWhatThis(i18n("<p>This is the main view of KSystemLog. It displays the last lines of the selected
0031     // log. Please see the documentation to discovers the meaning of each icons and existing log.</p><p>Log
0032     // lines in <b>bold</b> are the last added to the list.</p>"));
0033 
0034     const QStringList headerLabels{i18n("Date"), i18n("Message")};
0035 
0036     mLogViewModel = new LogViewModel(this);
0037     mHeadersTogglingActions = new QActionGroup(this);
0038     mHeadersTogglingActions->setExclusive(false);
0039     connect(mHeadersTogglingActions, &QActionGroup::triggered, this, &LogViewWidget::toggleHeader);
0040 
0041     setHeaderLabels(headerLabels);
0042 
0043     // Header
0044     header()->setContextMenuPolicy(Qt::ActionsContextMenu);
0045     // header()->setMovable(true);
0046     header()->setSectionsMovable(true);
0047 
0048     setSortingEnabled(true);
0049     sortItems(0, Qt::AscendingOrder);
0050 
0051     setAnimated(true);
0052 
0053     setRootIsDecorated(false);
0054 
0055     setAllColumnsShowFocus(true);
0056 
0057     setAlternatingRowColors(true);
0058 
0059     setSelectionMode(QAbstractItemView::ExtendedSelection);
0060 
0061     setContextMenuPolicy(Qt::ActionsContextMenu);
0062     setProperty("_breeze_borders_sides", QVariant::fromValue(QFlags{Qt::TopEdge}));
0063 }
0064 
0065 LogViewWidget::~LogViewWidget()
0066 {
0067     delete mLogViewModel;
0068 }
0069 
0070 void LogViewWidget::setColumns(const LogViewColumns &columns)
0071 {
0072     qCDebug(KSYSTEMLOG) << "Updating columns using " << columns << "...";
0073 
0074     // First, delete all current columns
0075     setColumnCount(0);
0076 
0077     setHeaderLabels(columns.toStringList());
0078 
0079     sortItems(0, Qt::AscendingOrder);
0080 
0081     // Remove previous header actions
0082     QListIterator<QAction *> it(mHeadersTogglingActions->actions());
0083     it.toBack();
0084     while (it.hasPrevious()) {
0085         QAction *action = it.previous();
0086 
0087         header()->removeAction(action);
0088         mHeadersTogglingActions->removeAction(action);
0089 
0090         delete action;
0091     }
0092 
0093     // Add new actions
0094     int columnIndex = 0;
0095 
0096     const auto columnsLst = columns.columns();
0097     for (const LogViewColumn &column : columnsLst) {
0098         auto action = new QAction(this);
0099         action->setText(column.columnName());
0100         // helloAction->setIcon(QIcon::fromTheme( QLatin1String( "media-playback-start" )));
0101         // helloAction->setShortcut(Qt::CTRL | Qt::Key_M);
0102         action->setCheckable(true);
0103         action->setChecked(true);
0104         action->setToolTip(i18n("Display/Hide the '%1' column", column.columnName()));
0105         action->setData(QVariant(columnIndex));
0106 
0107         mHeadersTogglingActions->addAction(action);
0108 
0109         ++columnIndex;
0110     }
0111 
0112     header()->addActions(mHeadersTogglingActions->actions());
0113 
0114     Q_EMIT columnsChanged(columns);
0115 
0116     qCDebug(KSYSTEMLOG) << "Log View Widget updated...";
0117 }
0118 
0119 void LogViewWidget::resizeColumns()
0120 {
0121     // Resize all columns except the last one (which always take the last available space)
0122     for (int i = 0; i < columnCount() - 1; ++i) {
0123         resizeColumnToContents(i);
0124     }
0125 }
0126 
0127 void LogViewWidget::selectAll()
0128 {
0129     if (notHiddenItemCount() > 0) {
0130         QTreeWidget::selectAll();
0131     }
0132 }
0133 
0134 int LogViewWidget::itemCount() const
0135 {
0136     return topLevelItemCount();
0137 }
0138 
0139 QList<LogLine *> LogViewWidget::logLines()
0140 {
0141     QList<LogLine *> logLines;
0142 
0143     QTreeWidgetItemIterator it(this);
0144     while (*it) {
0145         auto item = static_cast<LogViewWidgetItem *>(*it);
0146         logLines.append(item->logLine());
0147         ++it;
0148     }
0149 
0150     return logLines;
0151 }
0152 
0153 LogViewWidgetItem *LogViewWidget::findNewestItem()
0154 {
0155     LogViewWidgetItem *newestItem = nullptr;
0156 
0157     QTreeWidgetItemIterator it(this);
0158     while (*it) {
0159         auto item = static_cast<LogViewWidgetItem *>(*it);
0160         if (!newestItem || newestItem->logLine()->isOlderThan(*(item->logLine()))) {
0161             newestItem = item;
0162         }
0163 
0164         ++it;
0165     }
0166 
0167     return newestItem;
0168 }
0169 
0170 LogViewWidgetItem *LogViewWidget::findItem(LogLine *searchedLogLine)
0171 {
0172     QTreeWidgetItemIterator it(this);
0173     while (*it) {
0174         auto item = static_cast<LogViewWidgetItem *>(*it);
0175         if (item->logLine()->equals(*searchedLogLine)) {
0176             return item;
0177         }
0178 
0179         ++it;
0180     }
0181 
0182     return nullptr;
0183 }
0184 
0185 QList<LogViewWidgetItem *> LogViewWidget::items()
0186 {
0187     QList<LogViewWidgetItem *> items;
0188 
0189     QTreeWidgetItemIterator it(this);
0190     while (*it) {
0191         items.append(static_cast<LogViewWidgetItem *>(*it));
0192         ++it;
0193     }
0194 
0195     return items;
0196 }
0197 
0198 LogViewModel *LogViewWidget::model() const
0199 {
0200     return mLogViewModel;
0201 }
0202 
0203 bool LogViewWidget::hasItemsSelected()
0204 {
0205     return !selectedItems().isEmpty();
0206 }
0207 
0208 LogViewWidgetItem *LogViewWidget::firstSelectedItem()
0209 {
0210     QTreeWidgetItemIterator const it(this, QTreeWidgetItemIterator::Selected);
0211 
0212     // Returns the first selected item or NULL is there is no item selected
0213     return static_cast<LogViewWidgetItem *>(*it);
0214 }
0215 
0216 LogViewWidgetItem *LogViewWidget::lastSelectedItem()
0217 {
0218     QTreeWidgetItemIterator it(this, QTreeWidgetItemIterator::Selected);
0219 
0220     QTreeWidgetItem *item = nullptr;
0221     while (*it) {
0222         item = (*it);
0223 
0224         ++it;
0225     }
0226 
0227     // Returns the last selected item or NULL is there is no item selected
0228     return static_cast<LogViewWidgetItem *>(item);
0229 }
0230 
0231 void LogViewWidget::expandAll()
0232 {
0233     QTreeWidgetItemIterator it(this);
0234     while (*it) {
0235         expandItem(*it);
0236         ++it;
0237     }
0238 }
0239 
0240 void LogViewWidget::collapseAll()
0241 {
0242     QTreeWidgetItemIterator it(this);
0243     while (*it) {
0244         collapseItem(*it);
0245         ++it;
0246     }
0247 }
0248 
0249 void LogViewWidget::toggleToolTip(bool enabled)
0250 {
0251     qCDebug(KSYSTEMLOG) << "Toggle tool tip " << enabled;
0252 
0253     QTreeWidgetItemIterator it(this);
0254     while (*it) {
0255         auto item = static_cast<LogViewWidgetItem *>(*it);
0256         item->toggleToolTip(enabled);
0257 
0258         ++it;
0259     }
0260 }
0261 
0262 void LogViewWidget::scrollToNewestItem()
0263 {
0264     qCDebug(KSYSTEMLOG) << "Scrolling to the newest item...";
0265 
0266     // Scroll to last item if requested
0267     if (KSystemLogConfig::newLinesDisplayed()) {
0268         LogViewWidgetItem *newestItem = findNewestItem();
0269         if (newestItem) {
0270             scrollToItem(newestItem);
0271         }
0272     }
0273 }
0274 
0275 int LogViewWidget::notHiddenItemCount()
0276 {
0277     int count = 0;
0278 
0279     QTreeWidgetItemIterator it(this, QTreeWidgetItemIterator::NotHidden);
0280     while (*it) {
0281         count++;
0282         ++it;
0283     }
0284 
0285     return count;
0286 }
0287 
0288 void LogViewWidget::toggleHeader(QAction *action)
0289 {
0290     qCDebug(KSYSTEMLOG) << "Toggling header";
0291 
0292     int const columnIndex = action->data().toInt();
0293     if (header()->isSectionHidden(columnIndex)) {
0294         header()->setSectionHidden(columnIndex, false);
0295     } else {
0296         header()->setSectionHidden(columnIndex, true);
0297     }
0298 }
0299 
0300 #include "moc_logViewWidget.cpp"