File indexing completed on 2024-05-26 16:15:49

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2007 Thomas Zander <zander@kde.org>
0003  * Copyright (C) 2008 Fredy Yanardi <fyanardi@gmail.com>
0004  * Copyright (C) 2008 Thorsten Zachmann <zachmann@kde.org>
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Library General Public License
0017  * along with this library; see the file COPYING.LIB.  If not, write to
0018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020  */
0021 
0022 #include "KoFind_p.h"
0023 
0024 #include <KoCanvasResourceManager.h>
0025 
0026 #include <kwindowsystem.h>
0027 #include <kfinddialog.h>
0028 #include <kfind.h>
0029 #include <klocalizedstring.h>
0030 
0031 #include <QTextDocument>
0032 #include <QTextCursor>
0033 #include <QTimer>
0034 #include <QAction>
0035 #include "TextDebug.h"
0036 
0037 #include "KoFind.h"
0038 #include "KoText.h"
0039 
0040 class InUse
0041 {
0042 public:
0043     InUse(bool & variable)
0044             : m_variable(variable) {
0045         m_variable = true;
0046     }
0047     ~InUse() {
0048         m_variable = false;
0049     }
0050 
0051 private:
0052     bool & m_variable;
0053 };
0054 
0055 KoFindPrivate::KoFindPrivate(KoFind *find, KoCanvasResourceManager *crp, QWidget *w)
0056         : findNext(0)
0057         , findPrev(0)
0058         , q(find)
0059         , provider(crp)
0060         , findStrategy(w)
0061         , replaceStrategy(w)
0062         , strategy(&findStrategy)
0063         , document(0)
0064         , restarted(false)
0065         , start(false)
0066         , inFind(false)
0067         , findDirection(0)
0068         , findForward(crp)
0069         , findBackward(crp)
0070 {
0071     QObject::connect(findStrategy.dialog(), SIGNAL(okClicked()), q, SLOT(startFind()));
0072     QObject::connect(replaceStrategy.dialog(), SIGNAL(okClicked()), q, SLOT(startReplace()));
0073 }
0074 
0075 void KoFindPrivate::resourceChanged(int key, const QVariant &variant)
0076 {
0077     if (key == KoText::CurrentTextDocument) {
0078         document = static_cast<QTextDocument*>(variant.value<void*>());
0079         if (!inFind) {
0080             start = true;
0081         }
0082     } else if (key == KoText::CurrentTextPosition || key == KoText::CurrentTextAnchor) {
0083         if (!inFind) {
0084             const int selectionStart = provider->intResource(KoText::CurrentTextPosition);
0085             const int selectionEnd = provider->intResource(KoText::CurrentTextAnchor);
0086             findStrategy.dialog()->setHasSelection(selectionEnd != selectionStart);
0087             replaceStrategy.dialog()->setHasSelection(selectionEnd != selectionStart);
0088 
0089             start = true;
0090             provider->clearResource(KoText::SelectedTextPosition);
0091             provider->clearResource(KoText::SelectedTextAnchor);
0092         }
0093     }
0094 }
0095 
0096 void KoFindPrivate::findActivated()
0097 {
0098     start = true;
0099 
0100     findStrategy.dialog()->setFindHistory(strategy->dialog()->findHistory());
0101 
0102     strategy = &findStrategy;
0103 
0104     strategy->dialog()->show();
0105     KWindowSystem::activateWindow(strategy->dialog()->winId());
0106 
0107     findNext->setEnabled(true);
0108     findPrev->setEnabled(true);
0109 }
0110 
0111 void KoFindPrivate::findNextActivated()
0112 {
0113     Q_ASSERT(strategy);
0114     findStrategy.dialog()->setOptions((strategy->dialog()->options() | KFind::FindBackwards) ^ KFind::FindBackwards);
0115     strategy = &findStrategy;
0116     parseSettingsAndFind();
0117 }
0118 
0119 void KoFindPrivate::findPreviousActivated()
0120 {
0121     Q_ASSERT(strategy);
0122     findStrategy.dialog()->setOptions(strategy->dialog()->options() | KFind::FindBackwards);
0123     strategy = &findStrategy;
0124     parseSettingsAndFind();
0125 }
0126 
0127 void KoFindPrivate::replaceActivated()
0128 {
0129     start = true;
0130 
0131     replaceStrategy.dialog()->setFindHistory(strategy->dialog()->findHistory());
0132 
0133     strategy = &replaceStrategy;
0134 
0135     strategy->dialog()->show();
0136     KWindowSystem::activateWindow(strategy->dialog()->winId());
0137 }
0138 
0139 void KoFindPrivate::startFind()
0140 {
0141     parseSettingsAndFind();
0142 
0143     QTimer::singleShot(0, findStrategy.dialog(), SLOT(show())); // show the findDialog again.
0144 }
0145 
0146 void KoFindPrivate::startReplace()
0147 {
0148     replaceStrategy.dialog()->hide(); // We don't want the replace dialog to keep popping up
0149     parseSettingsAndFind();
0150 }
0151 
0152 void KoFindPrivate::findDocumentSetNext(QTextDocument * document)
0153 {
0154     emit q->findDocumentSetNext(document);
0155 }
0156 
0157 void KoFindPrivate::findDocumentSetPrevious(QTextDocument * document)
0158 {
0159     emit q->findDocumentSetPrevious(document);
0160 }
0161 
0162 void KoFindPrivate::parseSettingsAndFind()
0163 {
0164     if (document == 0)
0165         return;
0166 
0167     InUse used(inFind);
0168 
0169     long options = strategy->dialog()->options();
0170 
0171     QTextDocument::FindFlags flags;
0172     if ((options & KFind::WholeWordsOnly) != 0) {
0173         flags |= QTextDocument::FindWholeWords;
0174     }
0175     if ((options & KFind::CaseSensitive) != 0) {
0176         flags |= QTextDocument::FindCaseSensitively;
0177     }
0178     if ((options & KFind::FindBackwards) != 0) {
0179         flags |= QTextDocument::FindBackward;
0180         findDirection = &findBackward;
0181     } else {
0182         findDirection = &findForward;
0183     }
0184 
0185     const bool selectedText = (options & KFind::SelectedText) != 0;
0186 
0187     if (start) {
0188         start = false;
0189         restarted = false;
0190         strategy->reset();
0191         startDocument = document;
0192         lastKnownPosition = QTextCursor(document);
0193         if (selectedText) {
0194             int selectionStart = provider->intResource(KoText::CurrentTextPosition);
0195             int selectionEnd = provider->intResource(KoText::CurrentTextAnchor);
0196             if (selectionEnd < selectionStart) {
0197                 qSwap(selectionStart, selectionEnd);
0198             }
0199             // TODO the SelectedTextPosition and SelectedTextAnchor are not highlighted yet
0200             // it would be cool to have the highlighted ligher when searching in selected text
0201             provider->setResource(KoText::SelectedTextPosition, selectionStart);
0202             provider->setResource(KoText::SelectedTextAnchor, selectionEnd);
0203             if ((options & KFind::FindBackwards) != 0) {
0204                 lastKnownPosition.setPosition(selectionEnd);
0205                 endPosition.setPosition(selectionStart);
0206             } else {
0207                 lastKnownPosition.setPosition(selectionStart);
0208                 endPosition.setPosition(selectionEnd);
0209             }
0210             startPosition = lastKnownPosition;
0211         } else {
0212             if ((options & KFind::FromCursor) != 0) {
0213                 lastKnownPosition.setPosition(provider->intResource(KoText::CurrentTextPosition));
0214             } else {
0215                 lastKnownPosition.setPosition(0);
0216             }
0217             endPosition = lastKnownPosition;
0218             startPosition = lastKnownPosition;
0219         }
0220         //debugText << "start" << lastKnownPosition.position();
0221     }
0222 
0223     QRegExp regExp;
0224     QString pattern = strategy->dialog()->pattern();
0225     if (options & KFind::RegularExpression) {
0226         regExp = QRegExp(pattern);
0227     }
0228 
0229     QTextCursor cursor;
0230     if (!regExp.isEmpty() && regExp.isValid()) {
0231         cursor = document->find(regExp, lastKnownPosition, flags);
0232     } else {
0233         cursor = document->find(pattern, lastKnownPosition, flags);
0234     }
0235 
0236     //debugText << "r" << restarted << "c > e" << ( document == startDocument && cursor > endPosition ) << ( startDocument == document && findDirection->positionReached(  cursor, endPosition ) )<< "e" << cursor.atEnd() << "n" << cursor.isNull();
0237     if ((((document == startDocument) && restarted) || selectedText)
0238             && (cursor.isNull() || findDirection->positionReached(cursor, endPosition))) {
0239         restarted = false;
0240         strategy->displayFinalDialog();
0241         lastKnownPosition = startPosition;
0242         return;
0243     } else if (cursor.isNull()) {
0244         restarted = true;
0245         findDirection->nextDocument(document, this);
0246         lastKnownPosition = QTextCursor(document);
0247         findDirection->positionCursor(lastKnownPosition);
0248         // restart from the beginning
0249         parseSettingsAndFind();
0250         return;
0251     } else {
0252         // found something
0253         bool goOn = strategy->foundMatch(cursor, findDirection);
0254         lastKnownPosition = cursor;
0255         if (goOn) {
0256             parseSettingsAndFind();
0257         }
0258     }
0259 }