File indexing completed on 2025-01-26 04:57:23

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