File indexing completed on 2025-02-16 04:56:04
0001 /* SPDX-FileCopyrightText: 2010 Torgny Nyblom <nyblom@kde.org> 0002 * SPDX-FileCopyrightText: 2010-2024 Laurent Montel <montel@kde.org> 0003 * 0004 * SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include "findbarbase.h" 0008 #include <KStatefulBrush> 0009 0010 #include <PimCommon/LineEditWithCompleterNg> 0011 0012 #include <KColorScheme> 0013 #include <KLocalizedString> 0014 #include <QIcon> 0015 0016 #include <QEvent> 0017 #include <QHBoxLayout> 0018 #include <QKeyEvent> 0019 #include <QLabel> 0020 #include <QMenu> 0021 #include <QPushButton> 0022 #include <QTimer> 0023 #include <QToolButton> 0024 0025 using namespace KSieveUi; 0026 0027 FindBarBase::FindBarBase(QWidget *parent) 0028 : QWidget(parent) 0029 { 0030 auto lay = new QHBoxLayout(this); 0031 lay->setContentsMargins(2, 2, 2, 2); 0032 0033 auto closeBtn = new QToolButton(this); 0034 closeBtn->setIcon(QIcon::fromTheme(QStringLiteral("dialog-close"))); 0035 closeBtn->setObjectName(QLatin1StringView("close")); 0036 closeBtn->setIconSize(QSize(16, 16)); 0037 closeBtn->setToolTip(i18n("Close")); 0038 0039 #ifndef QT_NO_ACCESSIBILITY 0040 closeBtn->setAccessibleName(i18n("Close")); 0041 #endif 0042 0043 closeBtn->setAutoRaise(true); 0044 lay->addWidget(closeBtn); 0045 0046 auto label = new QLabel(i18nc("Find text", "F&ind:"), this); 0047 lay->addWidget(label); 0048 0049 mSearch = new PimCommon::LineEditWithCompleterNg(this); 0050 mSearch->setObjectName(QLatin1StringView("searchline")); 0051 mSearch->setToolTip(i18n("Text to search for")); 0052 mSearch->setClearButtonEnabled(true); 0053 label->setBuddy(mSearch); 0054 lay->addWidget(mSearch); 0055 0056 mFindNextBtn = new QPushButton(QIcon::fromTheme(QStringLiteral("go-down-search")), i18nc("Find and go to the next search match", "Next"), this); 0057 mFindNextBtn->setToolTip(i18n("Jump to next match")); 0058 mFindNextBtn->setObjectName(QLatin1StringView("findnext")); 0059 lay->addWidget(mFindNextBtn); 0060 mFindNextBtn->setEnabled(false); 0061 0062 mFindPrevBtn = new QPushButton(QIcon::fromTheme(QStringLiteral("go-up-search")), i18nc("Find and go to the previous search match", "Previous"), this); 0063 mFindPrevBtn->setToolTip(i18n("Jump to previous match")); 0064 mFindPrevBtn->setObjectName(QLatin1StringView("findprevious")); 0065 lay->addWidget(mFindPrevBtn); 0066 mFindPrevBtn->setEnabled(false); 0067 0068 auto optionsBtn = new QPushButton(this); 0069 optionsBtn->setText(i18n("Options")); 0070 optionsBtn->setToolTip(i18n("Modify search behavior")); 0071 mOptionsMenu = new QMenu(optionsBtn); 0072 mCaseSensitiveAct = mOptionsMenu->addAction(i18n("Case sensitive")); 0073 mCaseSensitiveAct->setCheckable(true); 0074 0075 optionsBtn->setMenu(mOptionsMenu); 0076 lay->addWidget(optionsBtn); 0077 0078 connect(closeBtn, &QToolButton::clicked, this, &FindBarBase::closeBar); 0079 connect(mFindNextBtn, &QPushButton::clicked, this, &FindBarBase::findNext); 0080 connect(mFindPrevBtn, &QPushButton::clicked, this, &FindBarBase::findPrev); 0081 connect(mCaseSensitiveAct, &QAction::toggled, this, &FindBarBase::caseSensitivityChanged); 0082 connect(mSearch, &QLineEdit::textChanged, this, &FindBarBase::autoSearch); 0083 0084 mStatus = new QLabel(this); 0085 mStatus->setObjectName(QLatin1StringView("status")); 0086 mStatus->setTextFormat(Qt::PlainText); 0087 QFontMetrics fm(mStatus->font()); 0088 mNotFoundString = i18n("Phrase not found"); 0089 mStatus->setFixedWidth(fm.boundingRect(mNotFoundString).width()); 0090 lay->addWidget(mStatus); 0091 0092 setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed)); 0093 // lay->addStretch(); 0094 hide(); 0095 } 0096 0097 FindBarBase::~FindBarBase() = default; 0098 0099 QMenu *FindBarBase::optionsMenu() 0100 { 0101 return mOptionsMenu; 0102 } 0103 0104 QString FindBarBase::text() const 0105 { 0106 return mSearch->text(); 0107 } 0108 0109 void FindBarBase::setText(const QString &text) 0110 { 0111 mSearch->setText(text); 0112 } 0113 0114 void FindBarBase::focusAndSetCursor() 0115 { 0116 setFocus(); 0117 mStatus->clear(); 0118 mSearch->selectAll(); 0119 mSearch->setFocus(); 0120 } 0121 0122 void FindBarBase::autoSearch(const QString &str) 0123 { 0124 const bool isNotEmpty = (!str.isEmpty()); 0125 mFindPrevBtn->setEnabled(isNotEmpty); 0126 mFindNextBtn->setEnabled(isNotEmpty); 0127 if (isNotEmpty) { 0128 QTimer::singleShot(0, this, [this]() { 0129 slotSearchText(); 0130 }); 0131 } else { 0132 clearSelections(); 0133 } 0134 } 0135 0136 void FindBarBase::slotSearchText(bool backward, bool isAutoSearch) 0137 { 0138 searchText(backward, isAutoSearch); 0139 } 0140 0141 void FindBarBase::setFoundMatch(bool match) 0142 { 0143 #ifndef QT_NO_STYLE_STYLESHEET 0144 QString styleSheet; 0145 0146 if (!mSearch->text().isEmpty()) { 0147 if (mNegativeBackground.isEmpty()) { 0148 KStatefulBrush bgBrush(KColorScheme::View, KColorScheme::PositiveBackground); 0149 mPositiveBackground = QStringLiteral("QLineEdit{ background-color:%1 }").arg(bgBrush.brush(mSearch->palette()).color().name()); 0150 bgBrush = KStatefulBrush(KColorScheme::View, KColorScheme::NegativeBackground); 0151 mNegativeBackground = QStringLiteral("QLineEdit{ background-color:%1 }").arg(bgBrush.brush(mSearch->palette()).color().name()); 0152 } 0153 if (match) { 0154 styleSheet = mPositiveBackground; 0155 mStatus->clear(); 0156 } else { 0157 styleSheet = mNegativeBackground; 0158 mStatus->setText(mNotFoundString); 0159 } 0160 } 0161 mSearch->setStyleSheet(styleSheet); 0162 #endif 0163 } 0164 0165 void FindBarBase::searchText(bool backward, bool isAutoSearch) 0166 { 0167 Q_UNUSED(backward) 0168 Q_UNUSED(isAutoSearch) 0169 } 0170 0171 void FindBarBase::addToCompletion(const QString &text) 0172 { 0173 mSearch->addCompletionItem(text); 0174 } 0175 0176 void FindBarBase::findNext() 0177 { 0178 searchText(false, false); 0179 addToCompletion(mLastSearchStr); 0180 } 0181 0182 void FindBarBase::findPrev() 0183 { 0184 searchText(true, false); 0185 addToCompletion(mLastSearchStr); 0186 } 0187 0188 void FindBarBase::caseSensitivityChanged(bool b) 0189 { 0190 updateSensitivity(b); 0191 } 0192 0193 void FindBarBase::updateSensitivity(bool) 0194 { 0195 } 0196 0197 void FindBarBase::slotHighlightAllChanged(bool b) 0198 { 0199 updateHighLight(b); 0200 } 0201 0202 void FindBarBase::updateHighLight(bool) 0203 { 0204 } 0205 0206 void FindBarBase::clearSelections() 0207 { 0208 setFoundMatch(false); 0209 } 0210 0211 void FindBarBase::closeBar() 0212 { 0213 // Make sure that all old searches are cleared 0214 mSearch->clear(); 0215 clearSelections(); 0216 mSearch->clearFocus(); 0217 Q_EMIT hideFindBar(); 0218 } 0219 0220 bool FindBarBase::event(QEvent *e) 0221 { 0222 // Close the bar when pressing Escape. 0223 // Not using a QShortcut for this because it could conflict with 0224 // window-global actions (e.g. Emil Sedgh binds Esc to "close tab"). 0225 // With a shortcut override we can catch this before it gets to kactions. 0226 const bool shortCutOverride = (e->type() == QEvent::ShortcutOverride); 0227 if (shortCutOverride || e->type() == QEvent::KeyPress) { 0228 auto kev = static_cast<QKeyEvent *>(e); 0229 if (kev->key() == Qt::Key_Escape) { 0230 if (shortCutOverride) { 0231 e->accept(); 0232 return true; 0233 } 0234 e->accept(); 0235 closeBar(); 0236 return true; 0237 } else if (kev->key() == Qt::Key_Enter || kev->key() == Qt::Key_Return) { 0238 e->accept(); 0239 if (shortCutOverride) { 0240 return true; 0241 } 0242 if (mSearch->text().isEmpty()) { 0243 return true; 0244 } 0245 if (kev->modifiers() & Qt::ShiftModifier) { 0246 findPrev(); 0247 } else if (kev->modifiers() == Qt::NoModifier) { 0248 findNext(); 0249 } 0250 return true; 0251 } 0252 } 0253 return QWidget::event(e); 0254 } 0255 0256 #include "moc_findbarbase.cpp"