VirtualBox

Changeset 70231 in vbox for trunk/src/VBox/Frontends


Ignore:
Timestamp:
Dec 20, 2017 8:17:28 AM (7 years ago)
Author:
vboxsync
Message:

FE/Qt bugref:9072 Adding 'wrap around' and 'highlight all' functionalities to logviewer search

Location:
trunk/src/VBox/Frontends/VirtualBox/src/logviewer
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Frontends/VirtualBox/src/logviewer/UIVMLogViewerSearchPanel.cpp

    r70098 r70231  
    4949    , m_pNextPrevButtons(0)
    5050    , m_pCaseSensitiveCheckBox(0)
     51    , m_pMatchWholeWordCheckBox(0)
     52    , m_pHighlightAllCheckBox(0)
    5153    , m_pWarningSpacer(0), m_pWarningIcon(0), m_pWarningLabel(0)
     54    , m_iSearchPosition(0)
    5255{
    5356    /* Prepare: */
     
    7174    m_pNextPrevButtons->setEnabled(0, strSearchString.length());
    7275    m_pNextPrevButtons->setEnabled(1, strSearchString.length());
    73     /* Show/hide the warning as per search-string validity: */
    74     toggleWarning(!strSearchString.length());
     76
    7577    /* If search-string is valid: */
    7678    if (strSearchString.length())
    77         search(true, true);
     79    {
     80        /* Reset the position to force the search restart from the document's beginnig: */
     81        m_iSearchPosition = 0;
     82        search(ForwardSearch);
     83    }
    7884    /* If search-string is not valid, reset cursor position: */
    7985    else
     
    9298}
    9399
     100void UIVMLogViewerSearchPanel::sltHighlightAllCheckBox()
     101{
     102    QPlainTextEdit *pTextEdit = m_pViewer->currentLogPage();
     103    if (!pTextEdit) return;
     104    QTextDocument *pDocument = pTextEdit->document();
     105    if (!pDocument)
     106        return;
     107
     108    if (m_pHighlightAllCheckBox->isChecked())
     109    {
     110        const QString &searchString = m_pSearchEditor->text();
     111        if (searchString.isEmpty())
     112            return;
     113        highlightAll(pDocument, constructFindFlags(ForwardSearch), searchString);
     114    }
     115    else
     116    {
     117        pDocument->undo();
     118    }
     119}
     120
    94121void UIVMLogViewerSearchPanel::prepare()
    95122{
     
    112139        /* Configure main-layout: */
    113140        m_pMainLayout->setContentsMargins(0, 0, 0, 0);
     141        m_pMainLayout->setSpacing(4);
    114142
    115143        /* Create close-button: */
     
    167195        AssertPtrReturnVoid(m_pCaseSensitiveCheckBox);
    168196        {
    169             /* Configure focus for case-sensitive checkbox: */
    170             setFocusProxy(m_pCaseSensitiveCheckBox);
    171197            /* Configure font: */
    172198#ifdef VBOX_DARWIN_USE_NATIVE_CONTROLS
     
    178204            m_pMainLayout->addWidget(m_pCaseSensitiveCheckBox);
    179205        }
     206
     207        m_pMatchWholeWordCheckBox = new QCheckBox;
     208        AssertPtrReturnVoid(m_pMatchWholeWordCheckBox);
     209        {
     210            /* Configure focus for case-sensitive checkbox: */
     211            setFocusProxy(m_pMatchWholeWordCheckBox);
     212            /* Configure font: */
     213#ifdef VBOX_DARWIN_USE_NATIVE_CONTROLS
     214            QFont font = m_pMatchWholeWordCheckBox->font();
     215            font.setPointSize(::darwinSmallFontSize());
     216            m_pMatchWholeWordCheckBox->setFont(font);
     217#endif /* VBOX_DARWIN_USE_NATIVE_CONTROLS */
     218            m_pMainLayout->addWidget(m_pMatchWholeWordCheckBox);
     219        }
     220
     221        m_pHighlightAllCheckBox = new QCheckBox;
     222        AssertPtrReturnVoid(m_pHighlightAllCheckBox);
     223        {
     224            /* Configure font: */
     225#ifdef VBOX_DARWIN_USE_NATIVE_CONTROLS
     226            QFont font = m_pHighlightAllCheckBox->font();
     227            font.setPointSize(::darwinSmallFontSize());
     228            m_pHighlightAllCheckBox->setFont(font);
     229#endif /* VBOX_DARWIN_USE_NATIVE_CONTROLS */
     230            /* Add case-sensitive checkbox to main-layout: */
     231            m_pMainLayout->addWidget(m_pHighlightAllCheckBox);
     232        }
     233
    180234
    181235        /* Create warning-spacer: */
     
    233287            this, SLOT(findCurrent(const QString &)));
    234288    connect(m_pNextPrevButtons, SIGNAL(clicked(int)), this, SLOT(find(int)));
     289    connect(m_pHighlightAllCheckBox, &QCheckBox::stateChanged,
     290            this, &UIVMLogViewerSearchPanel::sltHighlightAllCheckBox);
    235291}
    236292
     
    242298    m_pSearchEditor->setToolTip(UIVMLogViewerWidget::tr("Enter a search string here"));
    243299
    244     m_pNextPrevButtons->setTitle(0, UIVMLogViewerWidget::tr("&Previous"));
    245300    m_pNextPrevButtons->setToolTip(0, UIVMLogViewerWidget::tr("Search for the previous occurrence of the string"));
    246     m_pNextPrevButtons->setTitle(1, UIVMLogViewerWidget::tr("&Next"));
    247301    m_pNextPrevButtons->setToolTip(1, UIVMLogViewerWidget::tr("Search for the next occurrence of the string"));
    248302
    249     m_pCaseSensitiveCheckBox->setText(UIVMLogViewerWidget::tr("C&ase Sensitive"));
     303    m_pCaseSensitiveCheckBox->setText(UIVMLogViewerWidget::tr("C&ase\nSensitive"));
    250304    m_pCaseSensitiveCheckBox->setToolTip(UIVMLogViewerWidget::tr("Perform case sensitive search (when checked)"));
     305
     306    m_pMatchWholeWordCheckBox->setText(UIVMLogViewerWidget::tr("Ma&tch\nWhole Word"));
     307    m_pMatchWholeWordCheckBox->setToolTip(UIVMLogViewerWidget::tr("Search matches only complete words when checked"));
     308
     309    m_pHighlightAllCheckBox->setText(UIVMLogViewerWidget::tr("Highlight\nAll"));
     310    m_pHighlightAllCheckBox->setToolTip(UIVMLogViewerWidget::tr("All occurence of the search text are highlighted"));
    251311
    252312    m_pWarningLabel->setText(UIVMLogViewerWidget::tr("String not found"));
     
    259319        /* Process Enter press as 'search-next',
    260320         * performed for any search panel widget: */
    261     case Qt::Key_Enter:
    262     case Qt::Key_Return:
    263         {
    264             if (pEvent->modifiers() == 0 ||
    265                 pEvent->modifiers() & Qt::KeypadModifier)
     321        case Qt::Key_Enter:
     322        case Qt::Key_Return:
    266323            {
    267                 /* Animate click on 'Next' button: */
     324                if (pEvent->modifiers() == 0 ||
     325                    pEvent->modifiers() & Qt::KeypadModifier)
     326                {
     327                    /* Animate click on 'Next' button: */
    268328                m_pNextPrevButtons->animateClick(1);
    269329                return;
     330                }
     331                break;
    270332            }
     333        default:
    271334            break;
    272         }
    273     default:
    274         break;
    275335    }
    276336    /* Call to base-class: */
     
    283343    switch (pEvent->type())
    284344    {
     345
    285346        /* Process key press only: */
    286     case QEvent::KeyPress:
     347        case QEvent::KeyPress:
    287348        {
    288349            /* Cast to corresponding key press event: */
     
    368429}
    369430
    370 void UIVMLogViewerSearchPanel::search(bool fForward, bool fStartCurrent /* = false */)
    371 {
    372     /* Get current log-page: */
    373     QPlainTextEdit *pBrowser = m_pViewer->currentLogPage();
    374     if (!pBrowser) return;
    375 
    376     /* Get text-cursor and its attributes: */
    377     QTextCursor cursor = pBrowser->textCursor();
    378     int iPos = cursor.position();
    379     int iAnc = cursor.anchor();
    380 
    381     /* Get the text to be searched: */
    382     QString strText = pBrowser->toPlainText();
    383     int iDiff = fStartCurrent ? 0 : 1;
    384 
    385     int iResult = -1;
    386     /* If search-direction is forward and cursor position is valid: */
    387     if (fForward && (fStartCurrent || iPos < strText.size() - 1))
    388     {
    389         /* Search and get the index of first match: */
    390         iResult = strText.indexOf(m_pSearchEditor->text(), iAnc + iDiff,
    391                                   m_pCaseSensitiveCheckBox->isChecked() ?
    392                                   Qt::CaseSensitive : Qt::CaseInsensitive);
    393 
    394         /* When searchstring is changed, search from beginning of log again: */
    395         if (iResult == -1 && fStartCurrent)
    396             iResult = strText.indexOf(m_pSearchEditor->text(), 0,
    397                                       m_pCaseSensitiveCheckBox->isChecked() ?
    398                                       Qt::CaseSensitive : Qt::CaseInsensitive);
    399     }
    400     /* If search-direction is backward: */
    401     else if (!fForward && iAnc > 0)
    402         iResult = strText.lastIndexOf(m_pSearchEditor->text(), iAnc - 1,
    403                                       m_pCaseSensitiveCheckBox->isChecked() ?
    404                                       Qt::CaseSensitive : Qt::CaseInsensitive);
    405 
    406     /* If the result is valid, move cursor-position: */
    407     if (iResult != -1)
    408     {
    409         cursor.movePosition(QTextCursor::Start,
    410                             QTextCursor::MoveAnchor);
    411         cursor.movePosition(QTextCursor::NextCharacter,
    412                             QTextCursor::MoveAnchor, iResult);
    413         cursor.movePosition(QTextCursor::NextCharacter,
    414                             QTextCursor::KeepAnchor,
    415                             m_pSearchEditor->text().size());
    416         pBrowser->setTextCursor(cursor);
    417     }
    418 
    419     /* Show/hide the warning as per search-result: */
    420     toggleWarning(iResult != -1);
     431void UIVMLogViewerSearchPanel::search(SearchDirection direction)
     432{
     433   QPlainTextEdit *pTextEdit = m_pViewer->currentLogPage();
     434   if (!pTextEdit) return;
     435   QTextDocument *pDocument = pTextEdit->document();
     436   if (!pDocument)
     437       return;
     438
     439   const QString &searchString = m_pSearchEditor->text();
     440   if (searchString.isEmpty())
     441       return;
     442
     443   QTextCursor endCursor(pDocument);
     444   endCursor.movePosition(QTextCursor::End);
     445   QTextCursor startCursor(pDocument);
     446
     447   /* Construct the find flags for QTextDocument::find function: */
     448   QTextDocument::FindFlags findFlags = constructFindFlags(direction);
     449
     450   if (m_pHighlightAllCheckBox->isChecked())
     451       highlightAll(pDocument, findFlags, searchString);
     452
     453   QTextCursor resultCursor(pDocument);
     454   int startPosition = m_iSearchPosition;
     455   if (direction == BackwardSearch)
     456       startPosition -= searchString.length();
     457   resultCursor = pDocument->find(searchString, startPosition, findFlags);
     458
     459   /* Decide whether to wrap around or to end the search */
     460   if (resultCursor.isNull())
     461   {
     462       /* End the search if we search the whole document with no find: */
     463       if ((direction == ForwardSearch && startPosition == startCursor.position()) ||
     464           (direction == BackwardSearch && startPosition == endCursor.position()))
     465       {
     466           toggleWarning(false);
     467           return;
     468       }
     469       /* Wrap the search */
     470       if (direction == ForwardSearch)
     471       {
     472           m_iSearchPosition = startCursor.position();
     473           search(ForwardSearch);
     474           return;
     475       }
     476       else
     477       {
     478           /* Set the search position away from the end position to be
     479              able to find the string at the end of the document: */
     480           m_iSearchPosition = endCursor.position() + searchString.length();
     481           search(BackwardSearch);
     482           return;
     483       }
     484   }
     485   pTextEdit->setTextCursor(resultCursor);
     486   m_iSearchPosition = resultCursor.position();
     487   toggleWarning(true);
    421488}
    422489
    423490void UIVMLogViewerSearchPanel::findNext()
    424491{
    425     search(true);
     492    search(ForwardSearch);
    426493}
    427494
    428495void UIVMLogViewerSearchPanel::findBack()
    429496{
    430     search(false);
     497    search(BackwardSearch);
     498}
     499
     500void UIVMLogViewerSearchPanel::highlightAll(QTextDocument *pDocument,
     501                                            const QTextDocument::FindFlags &findFlags,
     502                                            const QString &searchString)
     503{
     504    if (!pDocument)
     505        return;
     506    if (searchString.isEmpty())
     507        return;
     508
     509    pDocument->undo();
     510    QTextCursor highlightCursor(pDocument);
     511    QTextCharFormat colorFormat(highlightCursor.charFormat());
     512    QTextCursor cursor(pDocument);
     513    cursor.beginEditBlock();
     514
     515    colorFormat.setBackground(Qt::yellow);
     516
     517    while (!highlightCursor.isNull() && !highlightCursor.atEnd())
     518    {
     519        highlightCursor = pDocument->find(searchString, highlightCursor, findFlags);
     520
     521        if (!highlightCursor.isNull())
     522            highlightCursor.mergeCharFormat(colorFormat);
     523    }
     524    cursor.endEditBlock();
    431525}
    432526
     
    446540    m_pWarningLabel->setHidden(fHide);
    447541}
     542
     543QTextDocument::FindFlags UIVMLogViewerSearchPanel::constructFindFlags(SearchDirection eDirection)
     544{
     545   QTextDocument::FindFlags findFlags;
     546   if (eDirection == BackwardSearch)
     547       findFlags = findFlags | QTextDocument::FindBackward;
     548   if (m_pCaseSensitiveCheckBox->isChecked())
     549       findFlags = findFlags | QTextDocument::FindCaseSensitively;
     550   if (m_pMatchWholeWordCheckBox->isChecked())
     551       findFlags = findFlags | QTextDocument::FindWholeWords;
     552   return findFlags;
     553}
  • trunk/src/VBox/Frontends/VirtualBox/src/logviewer/UIVMLogViewerSearchPanel.h

    r70027 r70231  
    2020
    2121/* Qt includes: */
     22#include <QTextDocument>
    2223#include <QWidget>
    2324
     
    5556      * @param  strSearchString  Specifies search-string. */
    5657    void findCurrent(const QString &strSearchString);
     58
     59    void sltHighlightAllCheckBox();
    5760private:
    58 
     61    enum SearchDirection { ForwardSearch, BackwardSearch };
    5962    /** Prepares search-panel. */
    6063    void prepare();
     
    7679
    7780    /** Search routine.
    78       * @param  fForward       Specifies the direction of search.
    79       * @param  fStartCurrent  Specifies whether search should start from beginning of the log. */
    80     void search(bool fForward, bool fStartCurrent = false);
     81      * @param  eDirection     Specifies the seach direction */
     82    void search(SearchDirection eDirection);
    8183    /** Forward search routine wrapper. */
    8284    void findNext();
    8385    /** Backward search routine wrapper. */
    8486    void findBack();
     87    void highlightAll(QTextDocument *pDocument, const QTextDocument::FindFlags &findFlags, const QString &searchString);
    8588    /** Shows/hides the search border warning using @a fHide as hint. */
    8689    void toggleWarning(bool fHide);
     90    /** Constructs the find flags for QTextDocument::find function. */
     91    QTextDocument::FindFlags constructFindFlags(SearchDirection eDirection);
    8792
    8893    /** Holds the reference to the VM Log-Viewer this search-panel belongs to. */
     
    99104    UIRoundRectSegmentedButton *m_pNextPrevButtons;
    100105    /** Holds the instance of case-sensitive checkbox we create. */
    101     QCheckBox *m_pCaseSensitiveCheckBox;
     106    QCheckBox   *m_pCaseSensitiveCheckBox;
     107    QCheckBox   *m_pMatchWholeWordCheckBox;
     108    QCheckBox   *m_pHighlightAllCheckBox;
    102109    /** Holds the instance of warning spacer-item we create. */
    103110    QSpacerItem *m_pWarningSpacer;
    104111    /** Holds the instance of warning icon we create. */
    105     QLabel *m_pWarningIcon;
     112    QLabel      *m_pWarningIcon;
    106113    /** Holds the instance of warning label we create. */
    107     QLabel *m_pWarningLabel;
     114    QLabel      *m_pWarningLabel;
    108115    /** Holds the instance of spacer item we create. */
    109116    QSpacerItem *m_pSpacerItem;
     117    /** Holds the position where we start the next search. */
     118    int          m_iSearchPosition;
    110119};
    111120
Note: See TracChangeset for help on using the changeset viewer.

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