You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
317 lines
8.2 KiB
317 lines
8.2 KiB
/* |
|
SPDX-FileCopyrightText: 2004 Enrico Ros <eros.kde@email.it> |
|
SPDX-FileCopyrightText: 2007, 2009-2010 Pino Toscano <pino@kde.org> |
|
|
|
SPDX-License-Identifier: GPL-2.0-or-later |
|
*/ |
|
|
|
#include "searchlineedit.h" |
|
|
|
// local includes |
|
|
|
// qt/kde includes |
|
#include <KBusyIndicatorWidget> |
|
#include <KColorScheme> |
|
#include <KLocalizedString> |
|
#include <KMessageBox> |
|
#include <QApplication> |
|
#include <QLayout> |
|
#include <QTimer> |
|
|
|
SearchLineEdit::SearchLineEdit(QWidget *parent, Okular::Document *document) |
|
: KLineEdit(parent) |
|
, m_document(document) |
|
, m_minLength(0) |
|
, m_caseSensitivity(Qt::CaseInsensitive) |
|
, m_searchType(Okular::Document::AllDocument) |
|
, m_id(-1) |
|
, m_moveViewport(false) |
|
, m_changed(false) |
|
, m_fromStart(true) |
|
, m_findAsYouType(true) |
|
, m_searchRunning(false) |
|
{ |
|
setObjectName(QStringLiteral("SearchLineEdit")); |
|
setClearButtonEnabled(true); |
|
|
|
// a timer to ensure that we don't flood the document with requests to search |
|
m_inputDelayTimer = new QTimer(this); |
|
m_inputDelayTimer->setSingleShot(true); |
|
connect(m_inputDelayTimer, &QTimer::timeout, this, &SearchLineEdit::startSearch); |
|
|
|
connect(this, &SearchLineEdit::textChanged, this, &SearchLineEdit::slotTextChanged); |
|
connect(document, &Okular::Document::searchFinished, this, &SearchLineEdit::searchFinished); |
|
} |
|
|
|
void SearchLineEdit::clearText() |
|
{ |
|
clear(); |
|
} |
|
|
|
void SearchLineEdit::setSearchCaseSensitivity(Qt::CaseSensitivity cs) |
|
{ |
|
m_caseSensitivity = cs; |
|
m_changed = true; |
|
} |
|
|
|
void SearchLineEdit::setSearchMinimumLength(int length) |
|
{ |
|
m_minLength = length; |
|
m_changed = true; |
|
} |
|
|
|
void SearchLineEdit::setSearchType(Okular::Document::SearchType type) |
|
{ |
|
if (type == m_searchType) { |
|
return; |
|
} |
|
|
|
disconnect(this, &SearchLineEdit::returnPressed, this, &SearchLineEdit::slotReturnPressed); |
|
|
|
m_searchType = type; |
|
|
|
// Only connect Enter for next/prev searches, the rest of searches are document global so |
|
// next/prev search does not make sense for them |
|
if (m_searchType == Okular::Document::NextMatch || m_searchType == Okular::Document::PreviousMatch) { |
|
connect(this, &SearchLineEdit::returnPressed, this, &SearchLineEdit::slotReturnPressed); |
|
} |
|
|
|
if (!m_changed) { |
|
m_changed = (m_searchType != Okular::Document::NextMatch && m_searchType != Okular::Document::PreviousMatch); |
|
} |
|
} |
|
|
|
void SearchLineEdit::setSearchId(int id) |
|
{ |
|
m_id = id; |
|
m_changed = true; |
|
} |
|
|
|
void SearchLineEdit::setSearchColor(const QColor &color) |
|
{ |
|
m_color = color; |
|
m_changed = true; |
|
} |
|
|
|
void SearchLineEdit::setSearchMoveViewport(bool move) |
|
{ |
|
m_moveViewport = move; |
|
} |
|
|
|
void SearchLineEdit::setSearchFromStart(bool fromStart) |
|
{ |
|
m_fromStart = fromStart; |
|
} |
|
|
|
void SearchLineEdit::setFindAsYouType(bool findAsYouType) |
|
{ |
|
m_findAsYouType = findAsYouType; |
|
} |
|
|
|
void SearchLineEdit::resetSearch() |
|
{ |
|
// Stop the currently running search, if any |
|
stopSearch(); |
|
|
|
// Clear highlights |
|
if (m_id != -1) { |
|
m_document->resetSearch(m_id); |
|
} |
|
|
|
// Make sure that the search will be reset at the next one |
|
m_changed = true; |
|
|
|
// Reset input box color |
|
prepareLineEditForSearch(); |
|
} |
|
|
|
bool SearchLineEdit::isSearchRunning() const |
|
{ |
|
return m_searchRunning; |
|
} |
|
|
|
void SearchLineEdit::restartSearch() |
|
{ |
|
m_inputDelayTimer->stop(); |
|
m_inputDelayTimer->start(700); |
|
m_changed = true; |
|
} |
|
|
|
void SearchLineEdit::stopSearch() |
|
{ |
|
if (m_id == -1 || !m_searchRunning) { |
|
return; |
|
} |
|
|
|
m_inputDelayTimer->stop(); |
|
// ### this should just cancel the search with id m_id, not all of them |
|
m_document->cancelSearch(); |
|
// flagging as "changed" so the search will be reset at the next one |
|
m_changed = true; |
|
} |
|
|
|
void SearchLineEdit::findNext() |
|
{ |
|
if (m_id == -1 || m_searchType != Okular::Document::NextMatch) { |
|
return; |
|
} |
|
|
|
if (!m_changed) { |
|
Q_EMIT searchStarted(); |
|
m_searchRunning = true; |
|
m_document->continueSearch(m_id, m_searchType); |
|
} else { |
|
startSearch(); |
|
} |
|
} |
|
|
|
void SearchLineEdit::findPrev() |
|
{ |
|
if (m_id == -1 || m_searchType != Okular::Document::PreviousMatch) { |
|
return; |
|
} |
|
|
|
if (!m_changed) { |
|
Q_EMIT searchStarted(); |
|
m_searchRunning = true; |
|
m_document->continueSearch(m_id, m_searchType); |
|
} else { |
|
startSearch(); |
|
} |
|
} |
|
|
|
void SearchLineEdit::slotTextChanged(const QString &text) |
|
{ |
|
Q_UNUSED(text); |
|
|
|
prepareLineEditForSearch(); |
|
|
|
if (m_findAsYouType) { |
|
restartSearch(); |
|
} else { |
|
m_changed = true; |
|
} |
|
} |
|
|
|
void SearchLineEdit::prepareLineEditForSearch() |
|
{ |
|
QPalette pal = palette(); |
|
const int textLength = text().length(); |
|
if (textLength > 0 && textLength < m_minLength) { |
|
const KColorScheme scheme(QPalette::Active, KColorScheme::View); |
|
pal.setBrush(QPalette::Base, scheme.background(KColorScheme::NegativeBackground)); |
|
pal.setBrush(QPalette::Text, scheme.foreground(KColorScheme::NegativeText)); |
|
} else { |
|
const QPalette qAppPalette = QApplication::palette(); |
|
pal.setColor(QPalette::Base, qAppPalette.color(QPalette::Base)); |
|
pal.setColor(QPalette::Text, qAppPalette.color(QPalette::Text)); |
|
} |
|
setPalette(pal); |
|
} |
|
|
|
void SearchLineEdit::slotReturnPressed(const QString &text) |
|
{ |
|
Q_UNUSED(text); |
|
|
|
m_inputDelayTimer->stop(); |
|
prepareLineEditForSearch(); |
|
if (QApplication::keyboardModifiers() == Qt::ShiftModifier) { |
|
m_searchType = Okular::Document::PreviousMatch; |
|
findPrev(); |
|
} else { |
|
m_searchType = Okular::Document::NextMatch; |
|
findNext(); |
|
} |
|
} |
|
|
|
void SearchLineEdit::startSearch() |
|
{ |
|
if (m_id == -1 || !m_color.isValid()) { |
|
return; |
|
} |
|
|
|
if (m_changed && (m_searchType == Okular::Document::NextMatch || m_searchType == Okular::Document::PreviousMatch)) { |
|
m_document->resetSearch(m_id); |
|
} |
|
m_changed = false; |
|
// search text if have more than 3 chars or else clear search |
|
QString thistext = text(); |
|
if (thistext.length() >= qMax(m_minLength, 1)) { |
|
Q_EMIT searchStarted(); |
|
m_searchRunning = true; |
|
m_document->searchText(m_id, thistext, m_fromStart, m_caseSensitivity, m_searchType, m_moveViewport, m_color); |
|
} else { |
|
m_document->resetSearch(m_id); |
|
} |
|
} |
|
|
|
void SearchLineEdit::searchFinished(int id, Okular::Document::SearchStatus endStatus) |
|
{ |
|
// ignore the searches not started by this search edit |
|
if (id != m_id) { |
|
return; |
|
} |
|
|
|
// if not found, use warning colors |
|
if (endStatus == Okular::Document::NoMatchFound) { |
|
QPalette pal = palette(); |
|
const KColorScheme scheme(QPalette::Active, KColorScheme::View); |
|
pal.setBrush(QPalette::Base, scheme.background(KColorScheme::NegativeBackground)); |
|
pal.setBrush(QPalette::Text, scheme.foreground(KColorScheme::NegativeText)); |
|
setPalette(pal); |
|
} else { |
|
QPalette pal = palette(); |
|
const QPalette qAppPalette = QApplication::palette(); |
|
pal.setColor(QPalette::Base, qAppPalette.color(QPalette::Base)); |
|
pal.setColor(QPalette::Text, qAppPalette.color(QPalette::Text)); |
|
setPalette(pal); |
|
} |
|
|
|
m_searchRunning = false; |
|
Q_EMIT searchStopped(); |
|
} |
|
|
|
SearchLineWidget::SearchLineWidget(QWidget *parent, Okular::Document *document) |
|
: QWidget(parent) |
|
{ |
|
QHBoxLayout *layout = new QHBoxLayout(this); |
|
layout->setContentsMargins(0, 0, 0, 0); |
|
|
|
m_edit = new SearchLineEdit(this, document); |
|
layout->addWidget(m_edit); |
|
|
|
m_anim = new KBusyIndicatorWidget(this); |
|
m_anim->setFixedSize(22, 22); |
|
layout->addWidget(m_anim); |
|
m_anim->hide(); |
|
|
|
m_timer = new QTimer(this); |
|
m_timer->setSingleShot(true); |
|
connect(m_timer, &QTimer::timeout, this, &SearchLineWidget::slotTimedout); |
|
|
|
connect(m_edit, &SearchLineEdit::searchStarted, this, &SearchLineWidget::slotSearchStarted); |
|
connect(m_edit, &SearchLineEdit::searchStopped, this, &SearchLineWidget::slotSearchStopped); |
|
} |
|
|
|
SearchLineEdit *SearchLineWidget::lineEdit() const |
|
{ |
|
return m_edit; |
|
} |
|
|
|
void SearchLineWidget::slotSearchStarted() |
|
{ |
|
m_timer->start(100); |
|
} |
|
|
|
void SearchLineWidget::slotSearchStopped() |
|
{ |
|
m_timer->stop(); |
|
m_anim->hide(); |
|
} |
|
|
|
void SearchLineWidget::slotTimedout() |
|
{ |
|
m_anim->show(); |
|
} |
|
|
|
#include "moc_searchlineedit.cpp"
|
|
|