File indexing completed on 2024-05-12 15:39:36
0001 /* This file is part of the KDE project 0002 * 0003 * Copyright (C) 2008 Bernhard Beschow <bbeschow cs tu berlin de> 0004 * (C) 2009 Germain Garand <germain@ebooksfrance.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 "khtmlfind_p.h" 0023 0024 #include "khtml_part.h" 0025 #include "khtmlviewbar.h" 0026 #include "khtmlfindbar.h" 0027 0028 #include "dom/html_document.h" 0029 #include "html/html_documentimpl.h" 0030 #include "rendering/render_text.h" 0031 #include "rendering/render_replaced.h" 0032 #include "xml/dom_selection.h" 0033 0034 #include "khtmlview.h" 0035 0036 #include <QClipboard> 0037 0038 #include "rendering/render_form.h" 0039 0040 #define d this 0041 0042 using khtml::RenderPosition; 0043 0044 using namespace DOM; 0045 0046 KHTMLFind::KHTMLFind(KHTMLPart *part, KHTMLFind *parent) : 0047 m_part(part), 0048 m_find(nullptr), 0049 m_parent(parent), 0050 m_findDialog(nullptr) 0051 { 0052 connect(part, SIGNAL(selectionChanged()), this, SLOT(slotSelectionChanged())); 0053 } 0054 0055 KHTMLFind::~KHTMLFind() 0056 { 0057 d->m_find = nullptr; // deleted by its parent, the view. 0058 } 0059 0060 void KHTMLFind::findTextBegin() 0061 { 0062 d->m_findPos = -1; 0063 d->m_findNode = nullptr; 0064 d->m_findPosEnd = -1; 0065 d->m_findNodeEnd = nullptr; 0066 d->m_findPosStart = -1; 0067 d->m_findNodeStart = nullptr; 0068 d->m_findNodePrevious = nullptr; 0069 delete d->m_find; 0070 d->m_find = nullptr; 0071 } 0072 0073 bool KHTMLFind::initFindNode(bool selection, bool reverse, bool fromCursor) 0074 { 0075 if (m_part->document().isNull()) { 0076 return false; 0077 } 0078 0079 DOM::NodeImpl *firstNode = nullptr; 0080 if (m_part->document().isHTMLDocument()) { 0081 firstNode = m_part->htmlDocument().body().handle(); 0082 } else { 0083 firstNode = m_part->document().handle(); 0084 } 0085 0086 if (!firstNode) { 0087 //qCDebug(KHTML_LOG) << "no first node (body or doc) -> return false"; 0088 return false; 0089 } 0090 if (selection && m_part->hasSelection()) { 0091 //qCDebug(KHTML_LOG) << "using selection"; 0092 const Selection &sel = m_part->caret(); 0093 if (!fromCursor) { 0094 d->m_findNode = reverse ? sel.end().node() : sel.start().node(); 0095 d->m_findPos = reverse ? sel.end().offset() : sel.start().offset(); 0096 } 0097 d->m_findNodeEnd = reverse ? sel.start().node() : sel.end().node(); 0098 d->m_findPosEnd = reverse ? sel.start().offset() : sel.end().offset(); 0099 d->m_findNodeStart = !reverse ? sel.start().node() : sel.end().node(); 0100 d->m_findPosStart = !reverse ? sel.start().offset() : sel.end().offset(); 0101 d->m_findNodePrevious = d->m_findNodeStart; 0102 } else { // whole document 0103 //qCDebug(KHTML_LOG) << "whole doc"; 0104 if (!fromCursor) { 0105 d->m_findNode = firstNode; 0106 d->m_findPos = reverse ? -1 : 0; 0107 } 0108 d->m_findNodeEnd = reverse ? firstNode : nullptr; 0109 d->m_findPosEnd = reverse ? 0 : -1; 0110 d->m_findNodeStart = !reverse ? firstNode : nullptr; 0111 d->m_findPosStart = !reverse ? 0 : -1; 0112 d->m_findNodePrevious = d->m_findNodeStart; 0113 if (reverse) { 0114 // Need to find out the really last object, to start from it 0115 khtml::RenderObject *obj = d->m_findNode ? d->m_findNode->renderer() : nullptr; 0116 if (obj) { 0117 // find the last object in the render tree 0118 while (obj->lastChild()) { 0119 obj = obj->lastChild(); 0120 } 0121 // now get the last object with a NodeImpl associated 0122 while (!obj->element() && obj->objectAbove()) { 0123 obj = obj->objectAbove(); 0124 } 0125 d->m_findNode = obj->element(); 0126 } 0127 } 0128 } 0129 return true; 0130 } 0131 0132 void KHTMLFind::deactivate() 0133 { 0134 // qCDebug(KHTML_LOG); 0135 d->m_lastFindState.options = d->m_findDialog->options(); 0136 d->m_lastFindState.history = d->m_findDialog->findHistory(); 0137 if (!m_parent) { 0138 d->m_findDialog->hide(); 0139 d->m_findDialog->disconnect(); 0140 d->m_findDialog->deleteLater(); 0141 } 0142 d->m_findDialog = nullptr; 0143 0144 // if the selection is limited to a single link, that link gets focus 0145 const DOM::Selection sel = m_part->caret(); 0146 if (sel.start().node() == sel.end().node()) { 0147 bool isLink = false; 0148 0149 // checks whether the node has a <A> parent 0150 DOM::NodeImpl *parent = sel.start().node(); 0151 while (parent) { 0152 if (parent->nodeType() == Node::ELEMENT_NODE && parent->id() == ID_A) { 0153 isLink = true; 0154 break; 0155 } 0156 parent = parent->parentNode(); 0157 } 0158 0159 if (isLink == true) { 0160 static_cast<DOM::DocumentImpl *>(m_part->document().handle())->setFocusNode(parent); 0161 } 0162 } 0163 } 0164 0165 void KHTMLFind::slotFindDestroyed() 0166 { 0167 d->m_find = nullptr; 0168 } 0169 0170 void KHTMLFind::activate() 0171 { 0172 // First do some init to make sure we can search in this frame 0173 if (m_part->document().isNull()) { 0174 return; 0175 } 0176 0177 // Raise if already opened 0178 if (d->m_findDialog && !m_parent) { 0179 m_part->pBottomViewBar()->showBarWidget(d->m_findDialog); 0180 return; 0181 } 0182 0183 // The lineedit of the dialog would make khtml lose its selection, otherwise 0184 #ifndef QT_NO_CLIPBOARD 0185 disconnect(qApp->clipboard(), SIGNAL(selectionChanged()), m_part, SLOT(slotClearSelection())); 0186 #endif 0187 0188 if (m_parent) { 0189 d->m_findDialog = m_parent->findBar(); 0190 } else { 0191 // Now show the dialog in which the user can choose options. 0192 d->m_findDialog = new KHTMLFindBar(m_part->widget()); 0193 d->m_findDialog->setHasSelection(m_part->hasSelection()); 0194 d->m_findDialog->setHasCursor(d->m_findNode != nullptr); 0195 #if 0 0196 if (d->m_findNode) { // has a cursor -> default to 'FromCursor' 0197 d->m_lastFindState.options |= KFind::FromCursor; 0198 } 0199 #endif 0200 0201 // TODO? optionsDialog.setPattern( d->m_lastFindState.text ); 0202 d->m_findDialog->setFindHistory(d->m_lastFindState.history); 0203 d->m_findDialog->setOptions(d->m_lastFindState.options); 0204 d->m_findDialog->setFocus(); 0205 0206 d->m_lastFindState.options = -1; // force update in findTextNext 0207 d->m_lastFindState.last_dir = -1; 0208 0209 m_part->pBottomViewBar()->addBarWidget(d->m_findDialog); 0210 m_part->pBottomViewBar()->showBarWidget(d->m_findDialog); 0211 connect(d->m_findDialog, SIGNAL(searchChanged()), this, SLOT(slotSearchChanged())); 0212 connect(d->m_findDialog, SIGNAL(findNextClicked()), this, SLOT(slotFindNext())); 0213 connect(d->m_findDialog, SIGNAL(findPreviousClicked()), this, SLOT(slotFindPrevious())); 0214 connect(d->m_findDialog, SIGNAL(hideMe()), this, SLOT(deactivate())); 0215 } 0216 #ifndef QT_NO_CLIPBOARD 0217 connect(qApp->clipboard(), SIGNAL(selectionChanged()), m_part, SLOT(slotClearSelection())); 0218 #endif 0219 if (m_findDialog) { 0220 createNewKFind(m_findDialog->pattern(), 0 /*options*/, m_findDialog, nullptr); 0221 } else if (m_parent && m_parent->find()) { 0222 createNewKFind(m_parent->find()->pattern(), m_parent->find()->options(), static_cast<QWidget *>(m_parent->find()->parent()), nullptr); 0223 } 0224 } 0225 0226 // ### this crawling through the render tree sucks. There should be another way to 0227 // do that. 0228 static inline KHTMLPart *innerPart(khtml::RenderObject *ro) 0229 { 0230 if (!ro || !ro->isWidget() || ro->isFormElement()) { 0231 return nullptr; 0232 } 0233 KHTMLView *v = qobject_cast<KHTMLView *>(static_cast<khtml::RenderWidget *>(ro)->widget()); 0234 return v ? v->part() : nullptr; 0235 } 0236 static inline KHTMLPart *innerPartFromNode(DOM::NodeImpl *node) 0237 { 0238 return (node && node->renderer() ? innerPart(node->renderer()) : nullptr); 0239 } 0240 0241 void KHTMLFind::createNewKFind(const QString &str, long options, QWidget *parent, KFindDialog *findDialog) 0242 { 0243 // First do some init to make sure we can search in this frame 0244 if (m_part->document().isNull()) { 0245 return; 0246 } 0247 0248 if (m_findNode) { 0249 if (KHTMLPart *p = innerPartFromNode(m_findNode)) { 0250 p->clearSelection(); 0251 p->findTextBegin(); 0252 } 0253 } 0254 0255 // Create the KFind object 0256 delete d->m_find; 0257 d->m_find = new KFind(str, options, parent, findDialog); 0258 d->m_find->closeFindNextDialog(); // we use KFindDialog non-modal, so we don't want other dlg popping up 0259 connect(d->m_find, SIGNAL(highlight(QString,int,int)), 0260 this, SLOT(slotHighlight(QString,int,int))); 0261 connect(d->m_find, SIGNAL(destroyed()), 0262 this, SLOT(slotFindDestroyed())); 0263 //connect(d->m_find, SIGNAL(findNext()), 0264 // this, SLOT(slotFindNext()) ); 0265 0266 if (!findDialog) { 0267 d->m_lastFindState.options = options; 0268 initFindNode(options & KFind::SelectedText, 0269 options & KFind::FindBackwards, 0270 options & KFind::FromCursor); 0271 } 0272 } 0273 0274 bool KHTMLFind::findTextNext(bool reverse) 0275 { 0276 if (!d->m_find) { 0277 // We didn't show the find dialog yet, let's do it then (#49442) 0278 activate(); 0279 0280 // FIXME Ugly hack: activate() may not create KFind object, so check whether it was created 0281 if (!d->m_find) { 0282 return false; 0283 } 0284 0285 // It also means the user is trying to match a previous pattern, so try and 0286 // restore the last saved pattern. 0287 if (!m_parent && (!d->m_findDialog || !d->m_findDialog->restoreLastPatternFromHistory())) { 0288 return false; 0289 } 0290 } 0291 0292 long options = 0; 0293 if (d->m_findDialog) { // 0 when we close the dialog 0294 // there is a search dialog 0295 // make sure pattern from search dialog is used 0296 // (### in fact pattern changes should always trigger a reconstruction of the KFind object cf. slotSearchChanged 0297 // - so make this an assert) 0298 if ((d->m_find->pattern() != d->m_findDialog->pattern())) { 0299 d->m_find->setPattern(d->m_findDialog->pattern()); 0300 d->m_find->resetCounts(); 0301 } 0302 0303 // make sure options from search dialog are used 0304 options = d->m_findDialog->options(); 0305 if (d->m_lastFindState.options != options) { 0306 d->m_find->setOptions(options); 0307 0308 if (options & KFind::SelectedText) { //#### FIXME find in selection for frames! 0309 Q_ASSERT(m_part->hasSelection()); 0310 } 0311 0312 long difference = d->m_lastFindState.options ^ options; 0313 if (difference & (KFind::SelectedText | KFind::FromCursor)) { 0314 // Important options changed -> reset search range 0315 (void) initFindNode(options & KFind::SelectedText, 0316 options & KFind::FindBackwards, 0317 options & KFind::FromCursor); 0318 } 0319 d->m_lastFindState.options = options; 0320 } 0321 } else { 0322 // no dialog 0323 options = d->m_lastFindState.options; 0324 } 0325 0326 // only adopt options for search direction manually 0327 if (reverse) { 0328 options = options ^ KFind::FindBackwards; 0329 } 0330 0331 // make sure our options are used by KFind 0332 if (d->m_find->options() != options) { 0333 d->m_find->setOptions(options); 0334 } 0335 0336 // Changing find direction. Start and end nodes must be switched. 0337 // Additionally since d->m_findNode points after the last node 0338 // that was searched, it needs to be "after" it in the opposite direction. 0339 if (d->m_lastFindState.last_dir != -1 0340 && bool(d->m_lastFindState.last_dir) != bool(options & KFind::FindBackwards)) { 0341 qSwap(d->m_findNodeEnd, d->m_findNodeStart); 0342 qSwap(d->m_findPosEnd, d->m_findPosStart); 0343 qSwap(d->m_findNode, d->m_findNodePrevious); 0344 0345 // d->m_findNode now point at the end of the last searched line - advance one node 0346 khtml::RenderObject *obj = d->m_findNode ? d->m_findNode->renderer() : nullptr; 0347 khtml::RenderObject *end = d->m_findNodeEnd ? d->m_findNodeEnd->renderer() : nullptr; 0348 if (obj == end) { 0349 obj = nullptr; 0350 } else if (obj) { 0351 do { 0352 obj = (options & KFind::FindBackwards) ? obj->objectAbove() : obj->objectBelow(); 0353 } while (obj && (!obj->element() || obj->isInlineContinuation())); 0354 } 0355 if (obj) { 0356 d->m_findNode = obj->element(); 0357 } else { 0358 // already at end, start again 0359 (void) initFindNode(options & KFind::SelectedText, 0360 options & KFind::FindBackwards, 0361 options & KFind::FromCursor); 0362 } 0363 } 0364 d->m_lastFindState.last_dir = (options & KFind::FindBackwards) ? 1 : 0; 0365 0366 int numMatchesOld = m_find->numMatches(); 0367 KFind::Result res = KFind::NoMatch; 0368 khtml::RenderObject *obj = d->m_findNode ? d->m_findNode->renderer() : nullptr; 0369 khtml::RenderObject *end = d->m_findNodeEnd ? d->m_findNodeEnd->renderer() : nullptr; 0370 //qCDebug(KHTML_LOG) << "obj=" << obj << " end=" << end; 0371 while (res == KFind::NoMatch) { 0372 if (d->m_find->needData()) { 0373 if (!obj) { 0374 //qCDebug(KHTML_LOG) << "obj=0 -> done"; 0375 break; // we're done 0376 } 0377 //qCDebug(KHTML_LOG) << " gathering data"; 0378 // First make up the QString for the current 'line' (i.e. up to \n) 0379 // We also want to remember the DOMNode for every portion of the string. 0380 // We store this in an index->node list. 0381 0382 d->m_stringPortions.clear(); 0383 bool newLine = false; 0384 QString str; 0385 DOM::NodeImpl *lastNode = d->m_findNode; 0386 while (obj && !newLine) { 0387 // Grab text from render object 0388 QString s; 0389 if (obj->renderName() == QLatin1String("RenderTextArea")) { 0390 s = static_cast<khtml::RenderTextArea *>(obj)->text(); 0391 s = s.replace(0xa0, ' '); 0392 } else if (obj->renderName() == QLatin1String("RenderLineEdit")) { 0393 khtml::RenderLineEdit *parentLine = static_cast<khtml::RenderLineEdit *>(obj); 0394 if (parentLine->widget()->echoMode() == QLineEdit::Normal) { 0395 s = parentLine->widget()->text(); 0396 } 0397 s = s.replace(0xa0, ' '); 0398 } else if (obj->isText()) { 0399 bool isLink = false; 0400 0401 // checks whether the node has a <A> parent 0402 if (options & KHTMLPart::FindLinksOnly) { 0403 DOM::NodeImpl *parent = obj->element(); 0404 while (parent) { 0405 if (parent->nodeType() == Node::ELEMENT_NODE && parent->id() == ID_A) { 0406 isLink = true; 0407 break; 0408 } 0409 parent = parent->parentNode(); 0410 } 0411 } else { 0412 isLink = true; 0413 } 0414 0415 if (isLink) { 0416 s = static_cast<khtml::RenderText *>(obj)->data().string(); 0417 s = s.replace(0xa0, ' '); 0418 } 0419 } else if (KHTMLPart *p = innerPart(obj)) { 0420 if (p->pFindTextNextInThisFrame(reverse)) { 0421 numMatchesOld++; 0422 res = KFind::Match; 0423 lastNode = obj->element(); 0424 break; 0425 } 0426 0427 } else if (obj->isBR()) { 0428 s = '\n'; 0429 } else if (!obj->isInline() && !str.isEmpty()) { 0430 s = '\n'; 0431 } 0432 0433 if (lastNode == d->m_findNodeEnd) { 0434 s.truncate(d->m_findPosEnd); 0435 } 0436 if (!s.isEmpty()) { 0437 newLine = s.indexOf('\n') != -1; // did we just get a newline? 0438 if (!(options & KFind::FindBackwards)) { 0439 //qCDebug(KHTML_LOG) << "StringPortion: " << index << "-" << index+s.length()-1 << " -> " << lastNode; 0440 d->m_stringPortions.append(StringPortion(str.length(), lastNode)); 0441 str += s; 0442 } else { // KFind itself can search backwards, so str must not be built backwards 0443 for (QList<StringPortion>::Iterator it = d->m_stringPortions.begin(); 0444 it != d->m_stringPortions.end(); 0445 ++it) { 0446 (*it).index += s.length(); 0447 } 0448 d->m_stringPortions.prepend(StringPortion(0, lastNode)); 0449 str.prepend(s); 0450 } 0451 } 0452 // Compare obj and end _after_ we processed the 'end' node itself 0453 if (obj == end) { 0454 obj = nullptr; 0455 } else { 0456 // Move on to next object (note: if we found a \n already, then obj (and lastNode) 0457 // will point to the _next_ object, i.e. they are in advance. 0458 do { 0459 // We advance until the next RenderObject that has a NodeImpl as its element(). 0460 // Otherwise (if we keep the 'last node', and it has a '\n') we might be stuck 0461 // on that object forever... 0462 obj = (options & KFind::FindBackwards) ? obj->objectAbove() : obj->objectBelow(); 0463 } while (obj && (!obj->element() || obj->isInlineContinuation())); 0464 } 0465 if (obj) { 0466 lastNode = obj->element(); 0467 } else { 0468 lastNode = nullptr; 0469 } 0470 } // end while 0471 0472 if (!str.isEmpty()) { 0473 d->m_find->setData(str, d->m_findPos); 0474 } 0475 d->m_findPos = -1; // not used during the findnext loops. Only during init. 0476 d->m_findNodePrevious = d->m_findNode; 0477 d->m_findNode = lastNode; 0478 } 0479 if (!d->m_find->needData() && !(res == KFind::Match)) { // happens if str was empty 0480 // Let KFind inspect the text fragment, and emit highlighted if a match is found 0481 res = d->m_find->find(); 0482 } 0483 } // end while 0484 0485 if (res == KFind::NoMatch) { // i.e. we're done 0486 // qCDebug(KHTML_LOG) << "No more matches."; 0487 if (!(options & KHTMLPart::FindNoPopups) && d->m_find->shouldRestart()) { 0488 // qCDebug(KHTML_LOG) << "Restarting"; 0489 initFindNode(false, options & KFind::FindBackwards, false); 0490 d->m_find->resetCounts(); 0491 findTextNext(reverse); 0492 } else { // really done 0493 // qCDebug(KHTML_LOG) << "Finishing"; 0494 //delete d->m_find; 0495 //d->m_find = 0L; 0496 initFindNode(false, options & KFind::FindBackwards, false); 0497 d->m_find->resetCounts(); 0498 d->m_part->clearSelection(); 0499 } 0500 // qCDebug(KHTML_LOG) << "Dialog closed."; 0501 } 0502 0503 if (m_findDialog != nullptr) { 0504 m_findDialog->setFoundMatch(res == KFind::Match); 0505 m_findDialog->setAtEnd(m_find->numMatches() < numMatchesOld); 0506 } 0507 0508 return res == KFind::Match; 0509 } 0510 0511 void KHTMLFind::slotHighlight(const QString & /*text*/, int index, int length) 0512 { 0513 //qCDebug(KHTML_LOG) << "slotHighlight index=" << index << " length=" << length; 0514 QList<StringPortion>::Iterator it = d->m_stringPortions.begin(); 0515 const QList<StringPortion>::Iterator itEnd = d->m_stringPortions.end(); 0516 QList<StringPortion>::Iterator prev = it; 0517 // We stop at the first portion whose index is 'greater than', and then use the previous one 0518 while (it != itEnd && (*it).index <= index) { 0519 prev = it; 0520 ++it; 0521 } 0522 Q_ASSERT(prev != itEnd); 0523 DOM::NodeImpl *node = (*prev).node; 0524 Q_ASSERT(node); 0525 0526 Selection sel(RenderPosition(node, index - (*prev).index).position()); 0527 0528 khtml::RenderObject *obj = node->renderer(); 0529 khtml::RenderTextArea *renderTextArea = nullptr; 0530 khtml::RenderLineEdit *renderLineEdit = nullptr; 0531 0532 Q_ASSERT(obj); 0533 if (obj) { 0534 int x = 0, y = 0; 0535 0536 if (obj->renderName() == QLatin1String("RenderTextArea")) { 0537 renderTextArea = static_cast<khtml::RenderTextArea *>(obj); 0538 } 0539 if (obj->renderName() == QLatin1String("RenderLineEdit")) { 0540 renderLineEdit = static_cast<khtml::RenderLineEdit *>(obj); 0541 } 0542 if (!renderLineEdit && !renderTextArea) 0543 //if (static_cast<khtml::RenderText *>(node->renderer()) 0544 // ->posOfChar(d->m_startOffset, x, y)) 0545 { 0546 int dummy; 0547 static_cast<khtml::RenderText *>(node->renderer()) 0548 ->caretPos(RenderPosition::fromDOMPosition(sel.start()).renderedOffset(), false, x, y, dummy, dummy); // more precise than posOfChar 0549 //qCDebug(KHTML_LOG) << "topleft: " << x << "," << y; 0550 if (x != -1 || y != -1) { 0551 int gox = m_part->view()->contentsX(); 0552 if (x + 50 > m_part->view()->contentsX() + m_part->view()->visibleWidth()) { 0553 gox = x - m_part->view()->visibleWidth() + 50; 0554 } 0555 if (x - 10 < m_part->view()->contentsX()) { 0556 gox = x - m_part->view()->visibleWidth() - 10; 0557 } 0558 if (gox < 0) { 0559 gox = 0; 0560 } 0561 m_part->view()->setContentsPos(gox, y - 50); 0562 } 0563 } 0564 } 0565 // Now look for end node 0566 it = prev; // no need to start from beginning again 0567 while (it != itEnd && (*it).index < index + length) { 0568 prev = it; 0569 ++it; 0570 } 0571 Q_ASSERT(prev != itEnd); 0572 0573 sel.moveTo(sel.start(), RenderPosition((*prev).node, index + length - (*prev).index).position()); 0574 0575 #if 0 0576 // qCDebug(KHTML_LOG) << "slotHighlight: " << d->m_selectionStart.handle() << "," << d->m_startOffset << " - " << 0577 d->m_selectionEnd.handle() << "," << d->m_endOffset; 0578 it = d->m_stringPortions.begin(); 0579 for (; it != d->m_stringPortions.end(); ++it) 0580 // qCDebug(KHTML_LOG) << " StringPortion: from index=" << (*it).index << " -> node=" << (*it).node; 0581 #endif 0582 if (renderTextArea) { 0583 renderTextArea->highLightWord(length, sel.end().offset() - length); 0584 } else if (renderLineEdit) { 0585 renderLineEdit->highLightWord(length, sel.end().offset() - length); 0586 } else { 0587 m_part->setCaret(sel); 0588 // d->m_doc->updateSelection(); 0589 if (sel.end().node()->renderer()) { 0590 int x, y, height, dummy; 0591 static_cast<khtml::RenderText *>(sel.end().node()->renderer()) 0592 ->caretPos(RenderPosition::fromDOMPosition(sel.end()).renderedOffset(), false, x, y, dummy, height); // more precise than posOfChar 0593 //qCDebug(KHTML_LOG) << "bottomright: " << x << "," << y+height; 0594 } 0595 } 0596 m_part->emitSelectionChanged(); 0597 0598 } 0599 0600 void KHTMLFind::slotSelectionChanged() 0601 { 0602 if (d->m_findDialog) { 0603 d->m_findDialog->setHasSelection(m_part->hasSelection()); 0604 } 0605 } 0606 0607 void KHTMLFind::slotSearchChanged() 0608 { 0609 createNewKFind(m_findDialog->pattern(), m_findDialog->options(), m_findDialog, nullptr); 0610 findTextNext(); 0611 } 0612 0613 void KHTMLFind::slotFindNext() 0614 { 0615 findTextNext(); 0616 } 0617 0618 void KHTMLFind::slotFindPrevious() 0619 { 0620 findTextNext(true); // find backwards 0621 } 0622 0623 #include "moc_khtmlfind_p.cpp"