VirtualBox

source: vbox/trunk/src/VBox/Frontends/VirtualBox/src/helpbrowser/UIHelpViewer.cpp@ 88411

Last change on this file since 88411 was 88411, checked in by vboxsync, 4 years ago

FE/Qt: bugref:9831. Saving/loading zoom percentage.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.4 KB
Line 
1/* $Id: UIHelpViewer.cpp 88411 2021-04-08 11:25:05Z vboxsync $ */
2/** @file
3 * VBox Qt GUI - UIHelpBrowserWidget class implementation.
4 */
5
6/*
7 * Copyright (C) 2010-2020 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/* Qt includes: */
19#include <QClipboard>
20#include <QtGlobal>
21#ifdef VBOX_WITH_QHELP_VIEWER
22 #include <QtHelp/QHelpEngine>
23 #include <QtHelp/QHelpContentWidget>
24 #include <QtHelp/QHelpIndexWidget>
25 #include <QtHelp/QHelpSearchEngine>
26 #include <QtHelp/QHelpSearchQueryWidget>
27 #include <QtHelp/QHelpSearchResultWidget>
28#endif
29#include <QLabel>
30#include <QMenu>
31#include <QHBoxLayout>
32#include <QScrollBar>
33#include <QTextBlock>
34#include <QWidgetAction>
35#ifdef RT_OS_SOLARIS
36# include <QFontDatabase>
37#endif
38
39/* GUI includes: */
40#include "QIToolButton.h"
41#include "UIHelpViewer.h"
42#include "UIHelpBrowserWidget.h"
43#include "UIIconPool.h"
44#include "UISearchLineEdit.h"
45
46/* COM includes: */
47#include "COMEnums.h"
48#include "CSystemProperties.h"
49
50#ifdef VBOX_WITH_QHELP_VIEWER
51
52static int iZoomPercentageStep = 20;
53const QPair<int, int> UIHelpViewer::zoomPercentageMinMax = QPair<int, int>(20, 300);
54
55
56/*********************************************************************************************************************************
57* UIContextMenuNavigationAction definition. *
58*********************************************************************************************************************************/
59class UIContextMenuNavigationAction : public QWidgetAction
60{
61
62 Q_OBJECT;
63
64signals:
65
66 void sigGoBackward();
67 void sigGoForward();
68 void sigGoHome();
69 void sigAddBookmark();
70
71public:
72
73 UIContextMenuNavigationAction(QObject *pParent = 0);
74 void setBackwardAvailable(bool fAvailable);
75 void setForwardAvailable(bool fAvailable);
76
77protected:
78
79
80private slots:
81
82
83private:
84
85 void prepare();
86 QIToolButton *m_pBackwardButton;
87 QIToolButton *m_pForwardButton;
88 QIToolButton *m_pHomeButton;
89 QIToolButton *m_pAddBookmarkButton;
90};
91
92/*********************************************************************************************************************************
93* UIFindInPageWidget definition. *
94*********************************************************************************************************************************/
95class UIFindInPageWidget : public QIWithRetranslateUI<QWidget>
96{
97
98 Q_OBJECT;
99
100signals:
101
102 void sigDragging(const QPoint &delta);
103 void sigSearchTextChanged(const QString &strSearchText);
104 void sigSelectNextMatch();
105 void sigSelectPreviousMatch();
106 void sigClose();
107
108public:
109
110 UIFindInPageWidget(QWidget *pParent = 0);
111 void setMatchCountAndCurrentIndex(int iTotalMatchCount, int iCurrentlyScrolledIndex);
112 void clearSearchField();
113
114protected:
115
116 virtual bool eventFilter(QObject *pObject, QEvent *pEvent) /* override */;
117 virtual void keyPressEvent(QKeyEvent *pEvent) /* override */;
118
119private:
120
121 void prepare();
122 void retranslateUi();
123 UISearchLineEdit *m_pSearchLineEdit;
124 QIToolButton *m_pNextButton;
125 QIToolButton *m_pPreviousButton;
126 QIToolButton *m_pCloseButton;
127 QLabel *m_pDragMoveLabel;
128 QPoint m_previousMousePosition;
129};
130
131
132/*********************************************************************************************************************************
133* UIContextMenuNavigationAction implementation. *
134*********************************************************************************************************************************/
135UIContextMenuNavigationAction::UIContextMenuNavigationAction(QObject *pParent /* = 0 */)
136 :QWidgetAction(pParent)
137 , m_pBackwardButton(0)
138 , m_pForwardButton(0)
139 , m_pHomeButton(0)
140 , m_pAddBookmarkButton(0)
141{
142 prepare();
143}
144
145void UIContextMenuNavigationAction::setBackwardAvailable(bool fAvailable)
146{
147 if (m_pBackwardButton)
148 m_pBackwardButton->setEnabled(fAvailable);
149}
150
151void UIContextMenuNavigationAction::setForwardAvailable(bool fAvailable)
152{
153 if (m_pForwardButton)
154 m_pForwardButton->setEnabled(fAvailable);
155}
156
157void UIContextMenuNavigationAction::prepare()
158{
159 QWidget *pWidget = new QWidget;
160 setDefaultWidget(pWidget);
161 QHBoxLayout *pMainLayout = new QHBoxLayout(pWidget);
162 AssertReturnVoid(pMainLayout);
163
164 m_pBackwardButton = new QIToolButton;
165 m_pForwardButton = new QIToolButton;
166 m_pHomeButton = new QIToolButton;
167 m_pAddBookmarkButton = new QIToolButton;
168
169 AssertReturnVoid(m_pBackwardButton &&
170 m_pForwardButton &&
171 m_pHomeButton);
172 m_pForwardButton->setEnabled(false);
173 m_pBackwardButton->setEnabled(false);
174 m_pHomeButton->setIcon(UIIconPool::iconSet(":/help_browser_home_32px.png"));
175 m_pForwardButton->setIcon(UIIconPool::iconSet(":/help_browser_forward_32px.png", ":/help_browser_forward_disabled_32px.png"));
176 m_pBackwardButton->setIcon(UIIconPool::iconSet(":/help_browser_backward_32px.png", ":/help_browser_backward_disabled_32px.png"));
177 m_pAddBookmarkButton->setIcon(UIIconPool::iconSet(":/help_browser_add_bookmark.png"));
178
179 pMainLayout->addWidget(m_pBackwardButton);
180 pMainLayout->addWidget(m_pForwardButton);
181 pMainLayout->addWidget(m_pHomeButton);
182 pMainLayout->addWidget(m_pAddBookmarkButton);
183 pMainLayout->setContentsMargins(0, 0, 0, 0);
184 //pMainLayout->addSpacerItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Fixed));
185
186 connect(m_pBackwardButton, &QIToolButton::pressed,
187 this, &UIContextMenuNavigationAction::sigGoBackward);
188 connect(m_pForwardButton, &QIToolButton::pressed,
189 this, &UIContextMenuNavigationAction::sigGoForward);
190 connect(m_pHomeButton, &QIToolButton::pressed,
191 this, &UIContextMenuNavigationAction::sigGoHome);
192 connect(m_pAddBookmarkButton, &QIToolButton::pressed,
193 this, &UIContextMenuNavigationAction::sigAddBookmark);
194}
195
196
197/*********************************************************************************************************************************
198* UIFindInPageWidget implementation. *
199*********************************************************************************************************************************/
200UIFindInPageWidget::UIFindInPageWidget(QWidget *pParent /* = 0 */)
201 : QIWithRetranslateUI<QWidget>(pParent)
202 , m_pSearchLineEdit(0)
203 , m_pNextButton(0)
204 , m_pPreviousButton(0)
205 , m_pCloseButton(0)
206 , m_previousMousePosition(-1, -1)
207{
208 prepare();
209}
210
211void UIFindInPageWidget::setMatchCountAndCurrentIndex(int iTotalMatchCount, int iCurrentlyScrolledIndex)
212{
213 if (!m_pSearchLineEdit)
214 return;
215 m_pSearchLineEdit->setMatchCount(iTotalMatchCount);
216 m_pSearchLineEdit->setScrollToIndex(iCurrentlyScrolledIndex);
217}
218
219void UIFindInPageWidget::clearSearchField()
220{
221 if (!m_pSearchLineEdit)
222 return;
223 m_pSearchLineEdit->blockSignals(true);
224 m_pSearchLineEdit->reset();
225 m_pSearchLineEdit->blockSignals(false);
226}
227
228bool UIFindInPageWidget::eventFilter(QObject *pObject, QEvent *pEvent)
229{
230 if (pObject == m_pDragMoveLabel)
231 {
232 if (pEvent->type() == QEvent::Enter)
233 m_pDragMoveLabel->setCursor(Qt::CrossCursor);
234 else if (pEvent->type() == QEvent::Leave)
235 {
236 if (parentWidget())
237 m_pDragMoveLabel->setCursor(parentWidget()->cursor());
238 }
239 else if (pEvent->type() == QEvent::MouseMove)
240 {
241 QMouseEvent *pMouseEvent = static_cast<QMouseEvent*>(pEvent);
242 if (pMouseEvent->buttons() == Qt::LeftButton)
243 {
244 if (m_previousMousePosition != QPoint(-1, -1))
245 emit sigDragging(pMouseEvent->globalPos() - m_previousMousePosition);
246 m_previousMousePosition = pMouseEvent->globalPos();
247 m_pDragMoveLabel->setCursor(Qt::ClosedHandCursor);
248 }
249 }
250 else if (pEvent->type() == QEvent::MouseButtonRelease)
251 {
252 m_previousMousePosition = QPoint(-1, -1);
253 m_pDragMoveLabel->setCursor(Qt::CrossCursor);
254 }
255 }
256 return QIWithRetranslateUI<QWidget>::eventFilter(pObject, pEvent);
257}
258
259void UIFindInPageWidget::keyPressEvent(QKeyEvent *pEvent)
260{
261 switch (pEvent->key())
262 {
263 case Qt::Key_Escape:
264 emit sigClose();
265 return;
266 break;
267 case Qt::Key_Down:
268 emit sigSelectNextMatch();
269 return;
270 break;
271 case Qt::Key_Up:
272 emit sigSelectPreviousMatch();
273 return;
274 break;
275 default:
276 QIWithRetranslateUI<QWidget>::keyPressEvent(pEvent);
277 break;
278 }
279}
280
281void UIFindInPageWidget::prepare()
282{
283 setAutoFillBackground(true);
284 setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);
285
286 QHBoxLayout *pLayout = new QHBoxLayout(this);
287 m_pSearchLineEdit = new UISearchLineEdit;
288 AssertReturnVoid(pLayout && m_pSearchLineEdit);
289 setFocusProxy(m_pSearchLineEdit);
290 QFontMetrics fontMetric(m_pSearchLineEdit->font());
291 setMinimumSize(40 * fontMetric.width("x"),
292 fontMetric.height() +
293 qApp->style()->pixelMetric(QStyle::PM_LayoutBottomMargin) +
294 qApp->style()->pixelMetric(QStyle::PM_LayoutTopMargin));
295
296 connect(m_pSearchLineEdit, &UISearchLineEdit::textChanged,
297 this, &UIFindInPageWidget::sigSearchTextChanged);
298
299 m_pDragMoveLabel = new QLabel;
300 AssertReturnVoid(m_pDragMoveLabel);
301 m_pDragMoveLabel->installEventFilter(this);
302 m_pDragMoveLabel->setPixmap(QPixmap(":/drag_move_16px.png"));
303 pLayout->addWidget(m_pDragMoveLabel);
304
305
306 pLayout->setSpacing(0);
307 pLayout->addWidget(m_pSearchLineEdit);
308
309 m_pPreviousButton = new QIToolButton;
310 m_pNextButton = new QIToolButton;
311 m_pCloseButton = new QIToolButton;
312
313 pLayout->addWidget(m_pPreviousButton);
314 pLayout->addWidget(m_pNextButton);
315 pLayout->addWidget(m_pCloseButton);
316
317 m_pPreviousButton->setIcon(UIIconPool::iconSet(":/arrow_up_10px.png"));
318 m_pNextButton->setIcon(UIIconPool::iconSet(":/arrow_down_10px.png"));
319 m_pCloseButton->setIcon(UIIconPool::iconSet(":/close_16px.png"));
320
321 connect(m_pPreviousButton, &QIToolButton::pressed, this, &UIFindInPageWidget::sigSelectPreviousMatch);
322 connect(m_pNextButton, &QIToolButton::pressed, this, &UIFindInPageWidget::sigSelectNextMatch);
323 connect(m_pCloseButton, &QIToolButton::pressed, this, &UIFindInPageWidget::sigClose);
324}
325
326void UIFindInPageWidget::retranslateUi()
327{
328}
329
330
331/*********************************************************************************************************************************
332* UIHelpViewer implementation. *
333*********************************************************************************************************************************/
334
335UIHelpViewer::UIHelpViewer(const QHelpEngine *pHelpEngine, QWidget *pParent /* = 0 */)
336 :QIWithRetranslateUI<QTextBrowser>(pParent)
337 , m_pHelpEngine(pHelpEngine)
338 , m_pFindInPageWidget(new UIFindInPageWidget(this))
339 , m_fFindWidgetDragged(false)
340 , m_iMarginForFindWidget(qApp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin))
341 , m_iSelectedMatchIndex(0)
342 , m_iSearchTermLength(0)
343 , m_iZoomPercentage(100)
344{
345 m_iInitialFontPointSize = font().pointSize();
346 setUndoRedoEnabled(true);
347 connect(m_pFindInPageWidget, &UIFindInPageWidget::sigDragging,
348 this, &UIHelpViewer::sltHandleFindWidgetDrag);
349 connect(m_pFindInPageWidget, &UIFindInPageWidget::sigSearchTextChanged,
350 this, &UIHelpViewer::sltHandleFindInPageSearchTextChange);
351
352 connect(m_pFindInPageWidget, &UIFindInPageWidget::sigSelectPreviousMatch,
353 this, &UIHelpViewer::sltSelectPreviousMatch);
354 connect(m_pFindInPageWidget, &UIFindInPageWidget::sigSelectNextMatch,
355 this, &UIHelpViewer::sltSelectNextMatch);
356 connect(m_pFindInPageWidget, &UIFindInPageWidget::sigClose,
357 this, &UIHelpViewer::sigCloseFindInPageWidget);
358
359 m_pFindInPageWidget->setVisible(false);
360 retranslateUi();
361}
362
363QVariant UIHelpViewer::loadResource(int type, const QUrl &name)
364{
365 if (name.scheme() == "qthelp" && m_pHelpEngine)
366 return QVariant(m_pHelpEngine->fileData(name));
367 else
368 return QTextBrowser::loadResource(type, name);
369}
370
371void UIHelpViewer::emitHistoryChangedSignal()
372{
373 emit historyChanged();
374 emit backwardAvailable(true);
375}
376
377void UIHelpViewer::setSource(const QUrl &url)
378{
379 QTextBrowser::setSource(url);
380 QTextDocument *pDocument = document();
381 iterateDocumentImages();
382 if (!pDocument || pDocument->isEmpty())
383 {
384 setText(tr("<div><p><h3>404. Not found.</h3>The page <b>%1</b> could not be found.</p></div>").arg(url.toString()));
385 }
386 if (m_pFindInPageWidget && m_pFindInPageWidget->isVisible())
387 {
388 document()->undo();
389 m_pFindInPageWidget->clearSearchField();
390 }
391}
392
393void UIHelpViewer::sltToggleFindInPageWidget(bool fVisible)
394{
395 if (!m_pFindInPageWidget)
396 return;
397 /* Closing the find in page widget causes QTextBrowser to jump to the top of the document. This hack puts it back into position: */
398 int iPosition = verticalScrollBar()->value();
399 m_iMarginForFindWidget = verticalScrollBar()->width() +
400 qApp->style()->pixelMetric(QStyle::PM_LayoutLeftMargin);
401 /* Try to position the widget somewhere meaningful initially: */
402 if (!m_fFindWidgetDragged)
403 m_pFindInPageWidget->move(width() - m_iMarginForFindWidget - m_pFindInPageWidget->width(),
404 m_iMarginForFindWidget);
405
406 m_pFindInPageWidget->setVisible(fVisible);
407
408 if (!fVisible)
409 {
410 document()->undo();
411 m_pFindInPageWidget->clearSearchField();
412 verticalScrollBar()->setValue(iPosition);
413 }
414 else
415 m_pFindInPageWidget->setFocus();
416}
417
418void UIHelpViewer::setFont(const QFont &font)
419{
420 QIWithRetranslateUI<QTextBrowser>::setFont(font);
421 /* Make sure the font size of the find in widget stays constant: */
422 if (m_pFindInPageWidget)
423 {
424 QFont wFont(font);
425 wFont.setPointSize(m_iInitialFontPointSize);
426 m_pFindInPageWidget->setFont(wFont);
427 }
428}
429
430bool UIHelpViewer::isFindInPageWidgetVisible() const
431{
432 if (m_pFindInPageWidget)
433 return m_pFindInPageWidget->isVisible();
434 return false;
435}
436
437void UIHelpViewer::zoom(ZoomOperation enmZoomOperation)
438{
439 int iPrevZoom = m_iZoomPercentage;
440 switch (enmZoomOperation)
441 {
442 case ZoomOperation_In:
443 iPrevZoom += iZoomPercentageStep;
444 break;
445 case ZoomOperation_Out:
446 iPrevZoom -= iZoomPercentageStep;
447 break;
448 case ZoomOperation_Reset:
449 default:
450 iPrevZoom = 100;
451 break;
452 }
453 setZoomPercentage(iPrevZoom);
454}
455
456void UIHelpViewer::setZoomPercentage(int iZoomPercentage)
457{
458 if (iZoomPercentage > zoomPercentageMinMax.second ||
459 iZoomPercentage < zoomPercentageMinMax.first ||
460 m_iZoomPercentage == iZoomPercentage)
461 return;
462
463 m_iZoomPercentage = iZoomPercentage;
464 scaleFont();
465 emit sigZoomPercentageChanged(m_iZoomPercentage);
466}
467
468
469int UIHelpViewer::zoomPercentage() const
470{
471 return m_iZoomPercentage;
472}
473
474void UIHelpViewer::contextMenuEvent(QContextMenuEvent *event)
475{
476 QMenu pMenu;
477
478 UIContextMenuNavigationAction *pNavigationActions = new UIContextMenuNavigationAction;
479 pNavigationActions->setBackwardAvailable(isBackwardAvailable());
480 pNavigationActions->setForwardAvailable(isForwardAvailable());
481
482 connect(pNavigationActions, &UIContextMenuNavigationAction::sigGoBackward,
483 this, &UIHelpViewer::sigGoBackward);
484 connect(pNavigationActions, &UIContextMenuNavigationAction::sigGoForward,
485 this, &UIHelpViewer::sigGoForward);
486 connect(pNavigationActions, &UIContextMenuNavigationAction::sigGoHome,
487 this, &UIHelpViewer::sigGoHome);
488 connect(pNavigationActions, &UIContextMenuNavigationAction::sigAddBookmark,
489 this, &UIHelpViewer::sigAddBookmark);
490
491 QAction *pOpenLinkAction = new QAction(UIHelpBrowserWidget::tr("Open Link"));
492 connect(pOpenLinkAction, &QAction::triggered,
493 this, &UIHelpViewer::sltHandleOpenLink);
494
495 QAction *pOpenInNewTabAction = new QAction(UIHelpBrowserWidget::tr("Open Link in New Tab"));
496 connect(pOpenInNewTabAction, &QAction::triggered,
497 this, &UIHelpViewer::sltHandleOpenLinkInNewTab);
498
499 QAction *pCopyLink = new QAction(UIHelpBrowserWidget::tr("Copy Link"));
500 connect(pCopyLink, &QAction::triggered,
501 this, &UIHelpViewer::sltHandleCopyLink);
502
503
504 QAction *pFindInPage = new QAction(UIHelpBrowserWidget::tr("Find in Page"));
505 pFindInPage->setCheckable(true);
506 if (m_pFindInPageWidget)
507 pFindInPage->setChecked(m_pFindInPageWidget->isVisible());
508 connect(pFindInPage, &QAction::toggled, this, &UIHelpViewer::sltToggleFindInPageWidget);
509
510 pMenu.addAction(pNavigationActions);
511 pMenu.addAction(pOpenLinkAction);
512 pMenu.addAction(pOpenInNewTabAction);
513 pMenu.addAction(pCopyLink);
514 pMenu.addAction(pFindInPage);
515
516 QString strAnchor = anchorAt(event->pos());
517 if (!strAnchor.isEmpty())
518 {
519 QString strLink = source().resolved(anchorAt(event->pos())).toString();
520 pOpenLinkAction->setData(strLink);
521 pOpenInNewTabAction->setData(strLink);
522 pCopyLink->setData(strLink);
523 }
524 else
525 {
526 pOpenLinkAction->setEnabled(false);
527 pOpenInNewTabAction->setEnabled(false);
528 pCopyLink->setEnabled(false);
529 }
530 pMenu.exec(event->globalPos());
531}
532
533void UIHelpViewer::resizeEvent(QResizeEvent *pEvent)
534{
535 /* Make sure the widget stays inside the parent during parent resize: */
536 if (m_pFindInPageWidget)
537 {
538 if (!isRectInside(m_pFindInPageWidget->geometry(), m_iMarginForFindWidget))
539 moveFindWidgetIn(m_iMarginForFindWidget);
540 }
541 QIWithRetranslateUI<QTextBrowser>::resizeEvent(pEvent);
542}
543
544void UIHelpViewer::wheelEvent(QWheelEvent *pEvent)
545{
546 Q_UNUSED(pEvent);
547 /* Disable wheel scaling for now: */
548#if 0
549 int iPreviousSize = font().pointSize();
550 /* QTextBrowser::wheelEvent sets a new font size: */
551 QTextBrowser::wheelEvent(pEvent);
552 /* Don't allow font size to get too large or small: */
553 if (font().pointSize() >= UIHelpBrowserWidget::fontScaleMinMax.second * m_iInitialFontPointSize ||
554 font().pointSize() <= UIHelpBrowserWidget::fontScaleMinMax.first * m_iInitialFontPointSize)
555 {
556 QFont mFont = font();
557 mFont.setPointSize(iPreviousSize);
558 setFont(mFont);
559 }
560 else
561 emit sigFontPointSizeChanged(font().pointSize());
562#endif
563}
564
565void UIHelpViewer::mousePressEvent(QMouseEvent *pEvent)
566{
567 QString strAnchor = anchorAt(pEvent->pos());
568 if (!strAnchor.isEmpty())
569 {
570 if (pEvent->modifiers() & Qt::ControlModifier)
571 {
572 QString strLink = source().resolved(strAnchor).toString();
573 emit sigOpenLinkInNewTab(strLink, true);
574 return;
575 }
576 }
577 QIWithRetranslateUI<QTextBrowser>::mousePressEvent(pEvent);
578}
579
580void UIHelpViewer::retranslateUi()
581{
582}
583
584void UIHelpViewer::moveFindWidgetIn(int iMargin)
585{
586 if (!m_pFindInPageWidget)
587 return;
588
589 QRect rect = m_pFindInPageWidget->geometry();
590 if (rect.left() < iMargin)
591 rect.translate(-rect.left() + iMargin, 0);
592 if (rect.right() > width() - iMargin)
593 rect.translate((width() - iMargin - rect.right()), 0);
594 if (rect.top() < iMargin)
595 rect.translate(0, -rect.top() + iMargin);
596
597 if (rect.bottom() > height() - iMargin)
598 rect.translate(0, (height() - iMargin - rect.bottom()));
599 m_pFindInPageWidget->setGeometry(rect);
600 m_pFindInPageWidget->update();
601}
602
603bool UIHelpViewer::isRectInside(const QRect &rect, int iMargin) const
604{
605 if (rect.left() < iMargin || rect.top() < iMargin)
606 return false;
607 if (rect.right() > width() - iMargin || rect.bottom() > height() - iMargin)
608 return false;
609 return true;
610}
611
612void UIHelpViewer::findAllMatches(const QString &searchString)
613{
614 QTextDocument *pDocument = document();
615 AssertReturnVoid(pDocument);
616
617 m_matchedCursorPosition.clear();
618 if (searchString.isEmpty())
619 return;
620 QTextCursor cursor(pDocument);
621 QTextDocument::FindFlags flags;
622 int iMatchCount = 0;
623 while (!cursor.isNull() && !cursor.atEnd())
624 {
625 cursor = pDocument->find(searchString, cursor, flags);
626 if (!cursor.isNull())
627 {
628 m_matchedCursorPosition << cursor.position() - searchString.length();
629 ++iMatchCount;
630 }
631 }
632}
633
634void UIHelpViewer::highlightFinds(int iSearchTermLength)
635{
636 QTextDocument* pDocument = document();
637 AssertReturnVoid(pDocument);
638 /* Clear previous highlight: */
639 pDocument->undo();
640
641 QTextCursor highlightCursor(pDocument);
642 QTextCursor cursor(pDocument);
643 cursor.beginEditBlock();
644 for (int i = 0; i < m_matchedCursorPosition.size(); ++i)
645 {
646 highlightCursor.setPosition(m_matchedCursorPosition[i]);
647
648 QTextCharFormat colorFormat(highlightCursor.charFormat());
649 colorFormat.setBackground(Qt::yellow);
650
651 highlightCursor.setPosition(m_matchedCursorPosition[i] + iSearchTermLength, QTextCursor::KeepAnchor);
652 if (!highlightCursor.isNull())
653 highlightCursor.setCharFormat(colorFormat);
654 }
655 cursor.endEditBlock();
656}
657
658void UIHelpViewer::selectMatch(int iMatchIndex, int iSearchStringLength)
659{
660 QTextCursor cursor = textCursor();
661 /* Move the cursor to the beginning of the matched string: */
662 cursor.setPosition(m_matchedCursorPosition.at(iMatchIndex), QTextCursor::MoveAnchor);
663 /* Move the cursor to the end of the matched string while keeping the anchor at the begining thus selecting the text: */
664 cursor.setPosition(m_matchedCursorPosition.at(iMatchIndex) + iSearchStringLength, QTextCursor::KeepAnchor);
665 ensureCursorVisible();
666 setTextCursor(cursor);
667}
668
669void UIHelpViewer::sltHandleOpenLinkInNewTab()
670{
671 QAction *pSender = qobject_cast<QAction*>(sender());
672 if (!pSender)
673 return;
674 QUrl url = pSender->data().toUrl();
675 if (url.isValid())
676 emit sigOpenLinkInNewTab(url, false);
677}
678
679void UIHelpViewer::sltHandleOpenLink()
680{
681 QAction *pSender = qobject_cast<QAction*>(sender());
682 if (!pSender)
683 return;
684 QUrl url = pSender->data().toUrl();
685 if (url.isValid())
686 QTextBrowser::setSource(url);
687}
688
689void UIHelpViewer::sltHandleCopyLink()
690{
691 QAction *pSender = qobject_cast<QAction*>(sender());
692 if (!pSender)
693 return;
694 QUrl url = pSender->data().toUrl();
695 if (url.isValid())
696 {
697 QClipboard *pClipboard = QApplication::clipboard();
698 if (pClipboard)
699 pClipboard->setText(url.toString());
700 }
701}
702
703void UIHelpViewer::sltHandleFindWidgetDrag(const QPoint &delta)
704{
705 if (!m_pFindInPageWidget)
706 return;
707 QRect geo = m_pFindInPageWidget->geometry();
708 geo.translate(delta);
709
710 /* Allow the move if m_pFindInPageWidget stays inside after the move: */
711 if (isRectInside(geo, m_iMarginForFindWidget))
712 m_pFindInPageWidget->move(m_pFindInPageWidget->pos() + delta);
713 m_fFindWidgetDragged = true;
714 update();
715}
716
717void UIHelpViewer::sltHandleFindInPageSearchTextChange(const QString &strSearchText)
718{
719 m_iSearchTermLength = strSearchText.length();
720 findAllMatches(strSearchText);
721 highlightFinds(m_iSearchTermLength);
722 //scrollToMatch(int iMatchIndex);
723 selectMatch(0, m_iSearchTermLength);
724 if (m_pFindInPageWidget)
725 m_pFindInPageWidget->setMatchCountAndCurrentIndex(m_matchedCursorPosition.size(), 0);
726}
727
728void UIHelpViewer::sltSelectPreviousMatch()
729{
730 m_iSelectedMatchIndex = m_iSelectedMatchIndex <= 0 ? m_matchedCursorPosition.size() - 1 : (m_iSelectedMatchIndex - 1);
731 selectMatch(m_iSelectedMatchIndex, m_iSearchTermLength);
732 if (m_pFindInPageWidget)
733 m_pFindInPageWidget->setMatchCountAndCurrentIndex(m_matchedCursorPosition.size(), m_iSelectedMatchIndex);
734}
735
736void UIHelpViewer::sltSelectNextMatch()
737{
738 m_iSelectedMatchIndex = m_iSelectedMatchIndex >= m_matchedCursorPosition.size() - 1 ? 0 : (m_iSelectedMatchIndex + 1);
739 selectMatch(m_iSelectedMatchIndex, m_iSearchTermLength);
740 if (m_pFindInPageWidget)
741 m_pFindInPageWidget->setMatchCountAndCurrentIndex(m_matchedCursorPosition.size(), m_iSelectedMatchIndex);
742}
743
744void UIHelpViewer::iterateDocumentImages()
745{
746 m_imageSizesMap.clear();
747 QTextCursor cursor = textCursor();
748 cursor.movePosition(QTextCursor::Start);
749 while (!cursor.atEnd())
750 {
751 cursor.movePosition(QTextCursor::NextCharacter);
752 if (cursor.charFormat().isImageFormat())
753 {
754 QTextImageFormat imageFormat = cursor.charFormat().toImageFormat();
755 m_imageSizesMap[imageFormat.name()] = imageFormat.width();
756 }
757 }
758}
759
760void UIHelpViewer::scaleFont()
761{
762 QFont mFont = font();
763 mFont.setPointSize(m_iInitialFontPointSize * m_iZoomPercentage / 100.);
764 setFont(mFont);
765}
766
767#include "UIHelpViewer.moc"
768
769#endif /* #ifdef VBOX_WITH_QHELP_VIEWER */
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette