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 "logViewSearchWidget.h" 0008 0009 #include <QCheckBox> 0010 #include <QColor> 0011 #include <QPalette> 0012 #include <QPushButton> 0013 #include <QString> 0014 #include <QTimer> 0015 0016 #include <KLocalizedString> 0017 #include <QIcon> 0018 0019 #include "ksystemlog_debug.h" 0020 #include "logViewWidget.h" 0021 #include "logViewWidgetItem.h" 0022 0023 LogViewSearchWidget::LogViewSearchWidget(QWidget *parent) 0024 : QWidget(parent) 0025 { 0026 setupUi(this); 0027 0028 // Get the searchLine base color to be able to restore it later 0029 mSearchLineBaseColor = searchLine->palette().color(QPalette::Base); 0030 mSearchLineTextColor = searchLine->palette().color(QPalette::Text); 0031 0032 // Default configuration of the hiding message timer 0033 mMessageHidingTimer = new QTimer(this); 0034 mMessageHidingTimer->setSingleShot(true); 0035 mMessageHidingTimer->setInterval(2000); 0036 connect(mMessageHidingTimer, &QTimer::timeout, this, &LogViewSearchWidget::hideMessage); 0037 0038 // The message widget is hidden by default 0039 hideMessage(); 0040 0041 closeButton->setIcon(QIcon::fromTheme(QStringLiteral("dialog-close"))); 0042 connect(closeButton, &QAbstractButton::clicked, this, &QWidget::hide); 0043 0044 next->setIcon(QIcon::fromTheme(QStringLiteral("arrow-down"))); 0045 connect(next, &QAbstractButton::clicked, this, &LogViewSearchWidget::findNext); 0046 0047 previous->setIcon(QIcon::fromTheme(QStringLiteral("arrow-up"))); 0048 connect(previous, &QAbstractButton::clicked, this, &LogViewSearchWidget::findPrevious); 0049 0050 searchLabel->setBuddy(searchLine); 0051 0052 connect(searchLine, SIGNAL(textEdited(QString)), this, SLOT(findFirst(QString))); 0053 connect(searchLine, &QLineEdit::textEdited, this, &LogViewSearchWidget::highlightAll); 0054 0055 connect(searchLine, &QLineEdit::returnPressed, this, &LogViewSearchWidget::findNext); 0056 0057 connect(caseSensitive, SIGNAL(clicked()), this, SLOT(findFirst())); 0058 0059 connect(caseSensitive, &QAbstractButton::clicked, this, &LogViewSearchWidget::highlightAll); 0060 connect(highlightAllButton, &QAbstractButton::clicked, this, &LogViewSearchWidget::highlightAll); 0061 0062 findFirst(searchLine->text()); 0063 } 0064 0065 LogViewSearchWidget::~LogViewSearchWidget() 0066 { 0067 } 0068 0069 void LogViewSearchWidget::displaySearch() 0070 { 0071 searchLine->setFocus(); 0072 searchLine->setSelection(0, searchLine->text().length()); 0073 show(); 0074 } 0075 0076 void LogViewSearchWidget::setTreeWidget(LogViewWidget *logViewWidget) 0077 { 0078 mLogViewWidget = logViewWidget; 0079 } 0080 0081 void LogViewSearchWidget::findFirst(const QString &text) 0082 { 0083 const bool textIsNotEmpty = !text.isEmpty(); 0084 next->setEnabled(textIsNotEmpty); 0085 previous->setEnabled(textIsNotEmpty); 0086 if (textIsNotEmpty) { 0087 findFirst(); 0088 } 0089 } 0090 0091 void LogViewSearchWidget::findFirst() 0092 { 0093 internalFind(nullptr, LogViewSearchWidget::Next); 0094 } 0095 0096 void LogViewSearchWidget::findNext() 0097 { 0098 qCDebug(KSYSTEMLOG) << "Finding next"; 0099 0100 LogViewWidgetItem *lastSelectedItem = mLogViewWidget->lastSelectedItem(); 0101 internalFind(lastSelectedItem, LogViewSearchWidget::Next); 0102 } 0103 0104 void LogViewSearchWidget::findPrevious() 0105 { 0106 qCDebug(KSYSTEMLOG) << "Finding previous"; 0107 0108 LogViewWidgetItem *firstSelectedItem = mLogViewWidget->firstSelectedItem(); 0109 internalFind(firstSelectedItem, LogViewSearchWidget::Previous); 0110 } 0111 0112 void LogViewSearchWidget::internalFind(LogViewWidgetItem *fromItem, Direction direction) 0113 { 0114 if (searchLine->text().isEmpty()) { 0115 return; 0116 } 0117 0118 QTreeWidgetItemIterator it(mLogViewWidget, QTreeWidgetItemIterator::NotHidden); 0119 initIterator(it, direction); 0120 0121 // Go to the selected position + 1 (if we already found an item) 0122 if (fromItem) { 0123 while (*it) { 0124 auto item = static_cast<LogViewWidgetItem *>(*it); 0125 0126 if (item == fromItem) { 0127 iteratorJump(it, direction); 0128 break; 0129 } 0130 0131 iteratorJump(it, direction); 0132 } 0133 } 0134 0135 // Iterates to fromItem +1 to the last item of the list 0136 while (*it) { 0137 auto item = static_cast<LogViewWidgetItem *>(*it); 0138 0139 bool const found = findItem(item); 0140 if (found) { 0141 return; 0142 } 0143 0144 iteratorJump(it, direction); 0145 } 0146 0147 // If we do not begin the search from the beginning, we do it now 0148 if (fromItem) { 0149 it = QTreeWidgetItemIterator(mLogViewWidget, QTreeWidgetItemIterator::NotHidden); 0150 initIterator(it, direction); 0151 0152 LogViewWidgetItem *item = nullptr; 0153 while (*it && item != fromItem) { 0154 item = static_cast<LogViewWidgetItem *>(*it); 0155 0156 bool const found = findItem(item); 0157 if (found) { 0158 showMessage(i18n("Reached end of list."), QStringLiteral("dialog-information")); 0159 return; 0160 } 0161 0162 iteratorJump(it, direction); 0163 } 0164 } 0165 0166 setSearchLineNotFound(true); 0167 } 0168 0169 inline void LogViewSearchWidget::initIterator(QTreeWidgetItemIterator &it, Direction direction) 0170 { 0171 // Previous direction : Go to the last item 0172 if (direction == LogViewSearchWidget::Previous) { 0173 QTreeWidgetItemIterator testedIterator(it); 0174 while (true) { 0175 ++testedIterator; 0176 if (!(*testedIterator)) { 0177 break; 0178 } 0179 0180 ++it; 0181 } 0182 } 0183 } 0184 0185 inline void LogViewSearchWidget::iteratorJump(QTreeWidgetItemIterator &it, Direction direction) 0186 { 0187 if (direction == LogViewSearchWidget::Next) { 0188 ++it; 0189 } else { 0190 --it; 0191 } 0192 } 0193 0194 bool LogViewSearchWidget::compareItem(LogViewWidgetItem *item) 0195 { 0196 Qt::CaseSensitivity caseSensitivity = Qt::CaseInsensitive; 0197 if (caseSensitive->isChecked()) { 0198 caseSensitivity = Qt::CaseSensitive; 0199 } 0200 0201 if (searchLine->text().isEmpty()) { 0202 return false; 0203 } 0204 0205 if (item->logLine()->exportToText().contains(searchLine->text(), caseSensitivity)) { 0206 return true; 0207 } 0208 0209 return false; 0210 } 0211 0212 bool LogViewSearchWidget::findItem(LogViewWidgetItem *item) 0213 { 0214 if (compareItem(item)) { 0215 unselectAll(); 0216 0217 setSearchLineNotFound(false); 0218 item->setSelected(true); 0219 mLogViewWidget->setCurrentItem(item); 0220 mLogViewWidget->scrollToItem(item); 0221 return true; 0222 } 0223 0224 return false; 0225 } 0226 0227 void LogViewSearchWidget::setSearchLineNotFound(bool notFound) 0228 { 0229 QPalette palette = searchLine->palette(); 0230 if (notFound) { 0231 palette.setColor(QPalette::Base, QColor(255, 102, 102)); // or Qt::red or QColor(235, 0, 0) 0232 palette.setColor(QPalette::Text, QColor(255, 255, 255)); 0233 } else { 0234 palette.setColor(QPalette::Base, mSearchLineBaseColor); 0235 palette.setColor(QPalette::Text, mSearchLineTextColor); 0236 } 0237 0238 searchLine->setPalette(palette); 0239 0240 if (notFound) { 0241 showMessage(i18n("Phrase not found."), QStringLiteral("dialog-error")); 0242 } else { 0243 hideMessage(); 0244 } 0245 } 0246 0247 void LogViewSearchWidget::unselectAll() 0248 { 0249 const QList<QTreeWidgetItem *> selectedItems = mLogViewWidget->selectedItems(); 0250 for (QTreeWidgetItem *item : selectedItems) { 0251 item->setSelected(false); 0252 } 0253 } 0254 0255 void LogViewSearchWidget::showMessage(const QString &text, const QString &iconText) 0256 { 0257 message->setText(text); 0258 message->show(); 0259 0260 messageIcon->setPixmap(QIcon::fromTheme(iconText).pixmap(style()->pixelMetric(QStyle::PM_SmallIconSize))); 0261 messageIcon->show(); 0262 0263 mMessageHidingTimer->start(); 0264 } 0265 0266 void LogViewSearchWidget::hideMessage() 0267 { 0268 message->hide(); 0269 messageIcon->hide(); 0270 0271 mMessageHidingTimer->stop(); 0272 } 0273 0274 void LogViewSearchWidget::highlightAll() 0275 { 0276 if (highlightAllButton->isChecked()) { 0277 unlightAll(); 0278 0279 qCDebug(KSYSTEMLOG) << "Highlighting all"; 0280 QTreeWidgetItemIterator it(mLogViewWidget, QTreeWidgetItemIterator::All); 0281 while (*it) { 0282 auto item = static_cast<LogViewWidgetItem *>(*it); 0283 0284 if (compareItem(item)) { 0285 item->setBackground(item->columnCount() - 1, QColor(255, 255, 16 * 8 + 11)); 0286 } 0287 0288 ++it; 0289 } 0290 } else { 0291 unlightAll(); 0292 } 0293 } 0294 0295 void LogViewSearchWidget::unlightAll() 0296 { 0297 qCDebug(KSYSTEMLOG) << "Unlighting all"; 0298 0299 QTreeWidgetItemIterator it(mLogViewWidget, QTreeWidgetItemIterator::All); 0300 while (*it) { 0301 auto item = static_cast<LogViewWidgetItem *>(*it); 0302 0303 // We retrieve the default column background using the first column data, where the background never 0304 // changes 0305 item->setBackground(item->columnCount() - 1, qvariant_cast<QBrush>(item->data(0, Qt::BackgroundRole))); 0306 0307 ++it; 0308 } 0309 } 0310 0311 #include "moc_logViewSearchWidget.cpp"