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 }