OSDN Git Service

It's 2011 now.
[qt-creator-jp/qt-creator-jp.git] / src / plugins / find / searchresultwindow.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "searchresultwindow.h"
35 #include "searchresulttreemodel.h"
36 #include "searchresulttreeitems.h"
37 #include "searchresulttreeview.h"
38 #include "ifindsupport.h"
39
40 #include <aggregation/aggregate.h>
41 #include <coreplugin/icore.h>
42 #include <coreplugin/actionmanager/actionmanager.h>
43 #include <coreplugin/actionmanager/command.h>
44 #include <coreplugin/coreconstants.h>
45 #include <coreplugin/icontext.h>
46 #include <coreplugin/uniqueidmanager.h>
47 #include <utils/qtcassert.h>
48
49 #include <QtCore/QFile>
50 #include <QtCore/QTextStream>
51 #include <QtCore/QSettings>
52 #include <QtCore/QDebug>
53 #include <QtCore/QDir>
54 #include <QtGui/QListWidget>
55 #include <QtGui/QToolButton>
56 #include <QtGui/QLineEdit>
57 #include <QtGui/QStackedWidget>
58 #include <QtGui/QLabel>
59 #include <QtGui/QFont>
60 #include <QtGui/QAction>
61
62 static const char SETTINGSKEYSECTIONNAME[] = "SearchResults";
63 static const char SETTINGSKEYEXPANDRESULTS[] = "ExpandResults";
64
65 namespace Find {
66
67 namespace Internal {
68
69     class WideEnoughLineEdit : public QLineEdit {
70         Q_OBJECT
71     public:
72         WideEnoughLineEdit(QWidget *parent):QLineEdit(parent){
73             connect(this, SIGNAL(textChanged(QString)),
74                     this, SLOT(updateGeometry()));
75         }
76         ~WideEnoughLineEdit(){}
77         QSize sizeHint() const {
78             QSize sh = QLineEdit::minimumSizeHint();
79             sh.rwidth() += qMax(25 * fontMetrics().width(QLatin1Char('x')),
80                                 fontMetrics().width(text()));
81             return sh;
82         }
83     public slots:
84         void updateGeometry() { QLineEdit::updateGeometry(); }
85     };
86
87     class SearchResultFindSupport : public IFindSupport
88     {
89         Q_OBJECT
90     public:
91         SearchResultFindSupport(SearchResultTreeView *view)
92             : m_view(view)
93         {
94         }
95
96         bool supportsReplace() const { return false; }
97
98         Find::FindFlags supportedFindFlags() const
99         {
100             return Find::FindBackward | Find::FindCaseSensitively
101                     | Find::FindRegularExpression | Find::FindWholeWords;
102         }
103
104         void resetIncrementalSearch()
105         {
106             m_incrementalFindStart = QModelIndex();
107         }
108
109         void clearResults() { }
110
111         QString currentFindString() const
112         {
113             return QString();
114         }
115
116         QString completedFindString() const
117         {
118             return QString();
119         }
120
121         void highlightAll(const QString &txt, Find::FindFlags findFlags)
122         {
123             Q_UNUSED(txt)
124             Q_UNUSED(findFlags)
125             return;
126         }
127
128         IFindSupport::Result findIncremental(const QString &txt, Find::FindFlags findFlags)
129         {
130             if (!m_incrementalFindStart.isValid())
131                 m_incrementalFindStart = m_view->currentIndex();
132             m_view->setCurrentIndex(m_incrementalFindStart);
133             return find(txt, findFlags);
134         }
135
136         IFindSupport::Result findStep(const QString &txt, Find::FindFlags findFlags)
137         {
138             IFindSupport::Result result = find(txt, findFlags);
139             if (result == IFindSupport::Found)
140                 m_incrementalFindStart = m_view->currentIndex();
141             return result;
142         }
143
144         IFindSupport::Result find(const QString &txt, Find::FindFlags findFlags)
145         {
146             if (txt.isEmpty())
147                 return IFindSupport::NotFound;
148             QModelIndex index;
149             if (findFlags & Find::FindRegularExpression) {
150                 bool sensitive = (findFlags & Find::FindCaseSensitively);
151                 index = m_view->model()->find(QRegExp(txt, (sensitive ? Qt::CaseSensitive : Qt::CaseInsensitive)),
152                                       m_view->currentIndex(),
153                                       Find::textDocumentFlagsForFindFlags(findFlags));
154             } else {
155                 index = m_view->model()->find(txt, m_view->currentIndex(),
156                                       Find::textDocumentFlagsForFindFlags(findFlags));
157             }
158             if (index.isValid()) {
159                 m_view->setCurrentIndex(index);
160                 m_view->scrollTo(index);
161                 if (index.parent().isValid())
162                     m_view->expand(index.parent());
163                 return IFindSupport::Found;
164             }
165             return IFindSupport::NotFound;
166         }
167
168         void replace(const QString &before, const QString &after,
169             Find::FindFlags findFlags)
170         {
171             Q_UNUSED(before)
172             Q_UNUSED(after)
173             Q_UNUSED(findFlags)
174         }
175
176         bool replaceStep(const QString &before, const QString &after,
177             Find::FindFlags findFlags)
178         {
179             Q_UNUSED(before)
180             Q_UNUSED(after)
181             Q_UNUSED(findFlags)
182             return false;
183         }
184
185         int replaceAll(const QString &before, const QString &after,
186             Find::FindFlags findFlags)
187         {
188             Q_UNUSED(before)
189             Q_UNUSED(after)
190             Q_UNUSED(findFlags)
191             return 0;
192         }
193
194     private:
195         SearchResultTreeView *m_view;
196         QModelIndex m_incrementalFindStart;
197     };
198
199     struct SearchResultWindowPrivate {
200         SearchResultWindowPrivate();
201
202         Internal::SearchResultTreeView *m_searchResultTreeView;
203         QListWidget *m_noMatchesFoundDisplay;
204         QToolButton *m_expandCollapseButton;
205         QAction *m_expandCollapseAction;
206         QLabel *m_replaceLabel;
207         QLineEdit *m_replaceTextEdit;
208         QToolButton *m_replaceButton;
209         static const bool m_initiallyExpand = false;
210         QStackedWidget *m_widget;
211         SearchResult *m_currentSearch;
212         int m_itemCount;
213         bool m_isShowingReplaceUI;
214         bool m_focusReplaceEdit;
215     };
216
217     SearchResultWindowPrivate::SearchResultWindowPrivate()
218         : m_currentSearch(0),
219         m_itemCount(0),
220         m_isShowingReplaceUI(false),
221         m_focusReplaceEdit(false)
222     {
223     }
224 }
225
226 using namespace Find::Internal;
227
228 /*!
229     \enum Find::SearchResultWindow::SearchMode
230     Specifies if a search should show the replace UI or not.
231
232     \value SearchOnly
233            The search doesn't support replace.
234     \value SearchAndReplace
235            The search supports replace, so show the UI for it.
236 */
237
238 /*!
239     \class Find::SearchResult
240     \brief Reports user interaction like activation of a search result item.
241
242     Whenever a new search is initiated via startNewSearch, an instance of this
243     class is returned to provide the initiator with the hooks for handling user
244     interaction.
245 */
246
247 /*!
248     \fn void SearchResult::activated(const Find::SearchResultItem &item)
249     \brief Sent if the user activated (e.g. double-clicked) a search result
250     \a item.
251 */
252
253 /*!
254     \fn void SearchResult::replaceButtonClicked(const QString &replaceText, const QList<Find::SearchResultItem> &checkedItems)
255     \brief Sent when the user initiated a replace, e.g. by pressing the replace
256     all button.
257
258     The signal reports the text to use for replacement in \a replaceText,
259     and the list of search result items that were selected by the user
260     in \a checkedItems.
261     The handler of this signal should apply the replace only on the selected
262     items.
263 */
264
265 /*!
266     \class Find::SearchResultWindow
267     \brief The SearchResultWindow class is the implementation of a commonly
268     shared \gui{Search Results} output pane. Use it to show search results
269     to a user.
270
271     Whenever you want to show the user a list of search results, or want
272     to present UI for a global search and replace, use the single instance
273     of this class.
274
275     Except for being an implementation of a output pane, the
276     SearchResultWindow has a few methods and one enum that allows other
277     plugins to show their search results and hook into the user actions for
278     selecting an entry and performing a global replace.
279
280     Whenever you start a search, call startNewSearch(SearchMode) to initialize
281     the search result window. The parameter determines if the GUI for
282     replacing should be shown.
283     The method returns a SearchResult object that is your
284     hook into the signals from user interaction for this search.
285     When you produce search results, call addResults or addResult to add them
286     to the search result window.
287     After the search has finished call finishSearch to inform the search
288     result window about it.
289
290     After that you get activated signals via your SearchResult instance when
291     the user selects a search result item, and, if you started the search
292     with the SearchAndReplace option, the replaceButtonClicked signal
293     when the user requests a replace.
294 */
295
296 /*!
297     \fn QString SearchResultWindow::displayName() const
298     \internal
299 */
300
301 SearchResultWindow *SearchResultWindow::m_instance = 0;
302
303 /*!
304     \fn SearchResultWindow::SearchResultWindow()
305     \internal
306 */
307 SearchResultWindow::SearchResultWindow() : d(new SearchResultWindowPrivate)
308 {
309     m_instance = this;
310     d->m_widget = new QStackedWidget;
311     d->m_widget->setWindowTitle(displayName());
312
313     d->m_searchResultTreeView = new Internal::SearchResultTreeView(d->m_widget);
314     d->m_searchResultTreeView->setFrameStyle(QFrame::NoFrame);
315     d->m_searchResultTreeView->setAttribute(Qt::WA_MacShowFocusRect, false);
316     d->m_widget->addWidget(d->m_searchResultTreeView);
317     Aggregation::Aggregate * agg = new Aggregation::Aggregate;
318     agg->add(d->m_searchResultTreeView);
319     agg->add(new SearchResultFindSupport(d->m_searchResultTreeView));
320
321     d->m_noMatchesFoundDisplay = new QListWidget(d->m_widget);
322     d->m_noMatchesFoundDisplay->addItem(tr("No matches found!"));
323     d->m_noMatchesFoundDisplay->setFrameStyle(QFrame::NoFrame);
324     d->m_widget->addWidget(d->m_noMatchesFoundDisplay);
325
326     d->m_expandCollapseButton = new QToolButton(d->m_widget);
327     d->m_expandCollapseButton->setAutoRaise(true);
328
329     d->m_expandCollapseAction = new QAction(tr("Expand All"), this);
330     d->m_expandCollapseAction->setCheckable(true);
331     d->m_expandCollapseAction->setIcon(QIcon(QLatin1String(":/find/images/expand.png")));
332     Core::Command *cmd = Core::ICore::instance()->actionManager()->registerAction(
333             d->m_expandCollapseAction, "Find.ExpandAll",
334             Core::Context(Core::Constants::C_GLOBAL));
335     d->m_expandCollapseButton->setDefaultAction(cmd->action());
336
337     d->m_replaceLabel = new QLabel(tr("Replace with:"), d->m_widget);
338     d->m_replaceLabel->setContentsMargins(12, 0, 5, 0);
339     d->m_replaceTextEdit = new WideEnoughLineEdit(d->m_widget);
340     d->m_replaceButton = new QToolButton(d->m_widget);
341     d->m_replaceButton->setToolTip(tr("Replace all occurrences"));
342     d->m_replaceButton->setText(tr("Replace"));
343     d->m_replaceButton->setToolButtonStyle(Qt::ToolButtonTextOnly);
344     d->m_replaceButton->setAutoRaise(true);
345     d->m_replaceTextEdit->setTabOrder(d->m_replaceTextEdit, d->m_searchResultTreeView);
346
347     connect(d->m_searchResultTreeView, SIGNAL(jumpToSearchResult(SearchResultItem)),
348             this, SLOT(handleJumpToSearchResult(SearchResultItem)));
349     connect(d->m_expandCollapseAction, SIGNAL(toggled(bool)), this, SLOT(handleExpandCollapseToolButton(bool)));
350     connect(d->m_replaceTextEdit, SIGNAL(returnPressed()), this, SLOT(handleReplaceButton()));
351     connect(d->m_replaceButton, SIGNAL(clicked()), this, SLOT(handleReplaceButton()));
352
353     readSettings();
354     setShowReplaceUI(false);
355 }
356
357 /*!
358     \fn SearchResultWindow::~SearchResultWindow()
359     \internal
360 */
361 SearchResultWindow::~SearchResultWindow()
362 {
363     writeSettings();
364     delete d->m_currentSearch;
365     d->m_currentSearch = 0;
366     delete d->m_widget;
367     d->m_widget = 0;
368     d->m_itemCount = 0;
369     delete d;
370 }
371
372 /*!
373     \fn SearchResultWindow *SearchResultWindow::instance()
374     \brief Returns the single shared instance of the Search Results window.
375 */
376 SearchResultWindow *SearchResultWindow::instance()
377 {
378     return m_instance;
379 }
380
381 /*!
382     \fn void SearchResultWindow::setTextToReplace(const QString &textToReplace)
383     \brief Sets the value in the UI element that allows the user to type
384     the text that should replace text in search results to \a textToReplace.
385 */
386 void SearchResultWindow::setTextToReplace(const QString &textToReplace)
387 {
388     d->m_replaceTextEdit->setText(textToReplace);
389 }
390
391 /*!
392     \fn QString SearchResultWindow::textToReplace() const
393     \brief Returns the text that should replace the text in search results.
394 */
395 QString SearchResultWindow::textToReplace() const
396 {
397     return d->m_replaceTextEdit->text();
398 }
399
400 /*!
401     \fn void SearchResultWindow::setShowReplaceUI(bool show)
402     \internal
403 */
404 void SearchResultWindow::setShowReplaceUI(bool show)
405 {
406     d->m_searchResultTreeView->model()->setShowReplaceUI(show);
407     d->m_replaceLabel->setVisible(show);
408     d->m_replaceTextEdit->setVisible(show);
409     d->m_replaceButton->setVisible(show);
410     d->m_isShowingReplaceUI = show;
411 }
412
413 /*!
414     \fn void SearchResultWindow::handleReplaceButton()
415     \internal
416 */
417 void SearchResultWindow::handleReplaceButton()
418 {
419     QTC_ASSERT(d->m_currentSearch, return);
420     // check if button is actually enabled, because this is also triggered
421     // by pressing return in replace line edit
422     if (d->m_replaceButton->isEnabled())
423         d->m_currentSearch->replaceButtonClicked(d->m_replaceTextEdit->text(), checkedItems());
424 }
425
426 /*!
427     \fn QList<SearchResultItem> SearchResultWindow::checkedItems() const
428     \internal
429 */
430 QList<SearchResultItem> SearchResultWindow::checkedItems() const
431 {
432     QList<SearchResultItem> result;
433     Internal::SearchResultTreeModel *model = d->m_searchResultTreeView->model();
434     const int fileCount = model->rowCount(QModelIndex());
435     for (int i = 0; i < fileCount; ++i) {
436         QModelIndex fileIndex = model->index(i, 0, QModelIndex());
437         Internal::SearchResultTreeItem *fileItem = static_cast<Internal::SearchResultTreeItem *>(fileIndex.internalPointer());
438         Q_ASSERT(fileItem != 0);
439         for (int rowIndex = 0; rowIndex < fileItem->childrenCount(); ++rowIndex) {
440             QModelIndex textIndex = model->index(rowIndex, 0, fileIndex);
441             Internal::SearchResultTreeItem *rowItem = static_cast<Internal::SearchResultTreeItem *>(textIndex.internalPointer());
442             if (rowItem->checkState())
443                 result << rowItem->item;
444         }
445     }
446     return result;
447 }
448
449 /*!
450     \fn void SearchResultWindow::visibilityChanged(bool)
451     \internal
452 */
453 void SearchResultWindow::visibilityChanged(bool /*visible*/)
454 {
455 }
456
457 /*!
458     \fn QWidget *SearchResultWindow::outputWidget(QWidget *)
459     \internal
460 */
461 QWidget *SearchResultWindow::outputWidget(QWidget *)
462 {
463     return d->m_widget;
464 }
465
466 /*!
467     \fn QList<QWidget*> SearchResultWindow::toolBarWidgets() const
468     \internal
469 */
470 QList<QWidget*> SearchResultWindow::toolBarWidgets() const
471 {
472     return QList<QWidget*>() << d->m_expandCollapseButton << d->m_replaceLabel << d->m_replaceTextEdit << d->m_replaceButton;
473 }
474
475 /*!
476     \fn SearchResult *SearchResultWindow::startNewSearch(SearchMode searchOrSearchAndReplace)
477     \brief Tells the search results window to start a new search.
478
479     This will clear the contents of the previous search and initialize the UI
480     with regard to showing the replace UI or not (depending on the search mode
481     in \a searchOrSearchAndReplace).
482     Returns a SearchResult object that is used for signaling user interaction
483     with the results of this search.
484 */
485 SearchResult *SearchResultWindow::startNewSearch(SearchMode searchOrSearchAndReplace)
486 {
487     clearContents();
488     setShowReplaceUI(searchOrSearchAndReplace != SearchOnly);
489     delete d->m_currentSearch;
490     d->m_currentSearch = new SearchResult;
491     return d->m_currentSearch;
492 }
493
494 /*!
495     \fn void SearchResultWindow::finishSearch()
496     \brief Notifies the search result window that the current search
497     has finished, and the UI should reflect that.
498 */
499 void SearchResultWindow::finishSearch()
500 {
501     if (d->m_itemCount > 0) {
502         d->m_replaceButton->setEnabled(true);
503     } else {
504         showNoMatchesFound();
505     }
506 }
507
508 /*!
509     \fn void SearchResultWindow::clearContents()
510     \brief Clears the current contents in the search result window.
511 */
512 void SearchResultWindow::clearContents()
513 {
514     d->m_replaceTextEdit->setEnabled(false);
515     d->m_replaceButton->setEnabled(false);
516     d->m_replaceTextEdit->clear();
517     d->m_searchResultTreeView->clear();
518     d->m_itemCount = 0;
519     d->m_widget->setCurrentWidget(d->m_searchResultTreeView);
520     navigateStateChanged();
521 }
522
523 /*!
524     \fn void SearchResultWindow::showNoMatchesFound()
525     \internal
526 */
527 void SearchResultWindow::showNoMatchesFound()
528 {
529     d->m_replaceTextEdit->setEnabled(false);
530     d->m_replaceButton->setEnabled(false);
531     d->m_widget->setCurrentWidget(d->m_noMatchesFoundDisplay);
532 }
533
534 /*!
535     \fn bool SearchResultWindow::isEmpty() const
536     Returns if the search result window currently doesn't show any results.
537 */
538 bool SearchResultWindow::isEmpty() const
539 {
540     return (d->m_searchResultTreeView->model()->rowCount() < 1);
541 }
542
543 /*!
544     \fn int SearchResultWindow::numberOfResults() const
545     Returns the number of search results currently shown in the search
546     results window.
547 */
548 int SearchResultWindow::numberOfResults() const
549 {
550     return d->m_itemCount;
551 }
552
553 /*!
554     \fn bool SearchResultWindow::hasFocus()
555     \internal
556 */
557 bool SearchResultWindow::hasFocus()
558 {
559     return d->m_searchResultTreeView->hasFocus() || (d->m_isShowingReplaceUI && d->m_replaceTextEdit->hasFocus());
560 }
561
562 /*!
563     \fn bool SearchResultWindow::canFocus()
564     \internal
565 */
566 bool SearchResultWindow::canFocus()
567 {
568     return d->m_itemCount > 0;
569 }
570
571 /*!
572     \fn void SearchResultWindow::setFocus()
573     \internal
574 */
575 void SearchResultWindow::setFocus()
576 {
577     if (d->m_itemCount > 0) {
578         if (!d->m_isShowingReplaceUI) {
579             d->m_searchResultTreeView->setFocus();
580         } else {
581             if (!d->m_widget->focusWidget()
582                     || d->m_widget->focusWidget() == d->m_replaceTextEdit
583                     || d->m_focusReplaceEdit) {
584                 d->m_replaceTextEdit->setFocus();
585                 d->m_replaceTextEdit->selectAll();
586             } else {
587                 d->m_searchResultTreeView->setFocus();
588             }
589         }
590     }
591 }
592
593 /*!
594     \fn void SearchResultWindow::setTextEditorFont(const QFont &font)
595     \internal
596 */
597 void SearchResultWindow::setTextEditorFont(const QFont &font)
598 {
599     d->m_searchResultTreeView->setTextEditorFont(font);
600 }
601
602 /*!
603     \fn void SearchResultWindow::handleJumpToSearchResult(int index, bool)
604     \internal
605 */
606 void SearchResultWindow::handleJumpToSearchResult(const SearchResultItem &item)
607 {
608     QTC_ASSERT(d->m_currentSearch, return);
609     d->m_currentSearch->activated(item);
610 }
611
612 /*!
613     \fn void SearchResultWindow::addResult(const QString &fileName, int lineNumber, const QString &rowText, int searchTermStart, int searchTermLength, const QVariant &userData)
614     \brief Adds a single result line to the search results.
615
616     The \a fileName, \a lineNumber and \a rowText are shown in the result line.
617     \a searchTermStart and \a searchTermLength specify the region that
618     should be visually marked (string position and length in \a rowText).
619     You can attach arbitrary \a userData to the search result, which can
620     be used e.g. when reacting to the signals of the SearchResult for your search.
621
622     \sa addResults()
623 */
624 void SearchResultWindow::addResult(const QString &fileName, int lineNumber, const QString &rowText,
625     int searchTermStart, int searchTermLength, const QVariant &userData)
626 {
627     SearchResultItem item;
628     item.path = QStringList() << QDir::toNativeSeparators(fileName);
629     item.lineNumber = lineNumber;
630     item.text = rowText;
631     item.textMarkPos = searchTermStart;
632     item.textMarkLength = searchTermLength;
633     item.useTextEditorFont = true;
634     item.userData = userData;
635     addResults(QList<SearchResultItem>() << item, AddOrdered);
636 }
637
638 /*!
639     \fn void SearchResultWindow::addResults(QList<SearchResultItem> &items)
640     \brief Adds all of the given search result \a items to the search
641     results window.
642
643     \sa addResult()
644 */
645 void SearchResultWindow::addResults(QList<SearchResultItem> &items, AddMode mode)
646 {
647     bool firstItems = (d->m_itemCount == 0);
648     d->m_itemCount += items.size();
649     d->m_searchResultTreeView->addResults(items, mode);
650     if (firstItems) {
651         d->m_replaceTextEdit->setEnabled(true);
652         // We didn't have an item before, set the focus to the search widget
653         d->m_focusReplaceEdit = true;
654         setFocus();
655         d->m_focusReplaceEdit = false;
656         d->m_searchResultTreeView->selectionModel()->select(d->m_searchResultTreeView->model()->index(0, 0, QModelIndex()), QItemSelectionModel::Select);
657         emit navigateStateChanged();
658     }
659 }
660
661 /*!
662     \fn void SearchResultWindow::handleExpandCollapseToolButton(bool checked)
663     \internal
664 */
665 void SearchResultWindow::handleExpandCollapseToolButton(bool checked)
666 {
667     d->m_searchResultTreeView->setAutoExpandResults(checked);
668     if (checked)
669         d->m_searchResultTreeView->expandAll();
670     else
671         d->m_searchResultTreeView->collapseAll();
672 }
673
674 /*!
675     \fn void SearchResultWindow::readSettings()
676     \internal
677 */
678 void SearchResultWindow::readSettings()
679 {
680     QSettings *s = Core::ICore::instance()->settings();
681     if (s) {
682         s->beginGroup(QLatin1String(SETTINGSKEYSECTIONNAME));
683         d->m_expandCollapseAction->setChecked(s->value(QLatin1String(SETTINGSKEYEXPANDRESULTS), d->m_initiallyExpand).toBool());
684         s->endGroup();
685     }
686 }
687
688 /*!
689     \fn void SearchResultWindow::writeSettings()
690     \internal
691 */
692 void SearchResultWindow::writeSettings()
693 {
694     QSettings *s = Core::ICore::instance()->settings();
695     if (s) {
696         s->beginGroup(QLatin1String(SETTINGSKEYSECTIONNAME));
697         s->setValue(QLatin1String(SETTINGSKEYEXPANDRESULTS), d->m_expandCollapseAction->isChecked());
698         s->endGroup();
699     }
700 }
701
702 /*!
703     \fn int SearchResultWindow::priorityInStatusBar() const
704     \internal
705 */
706 int SearchResultWindow::priorityInStatusBar() const
707 {
708     return 80;
709 }
710
711 /*!
712     \fn bool SearchResultWindow::canNext()
713     \internal
714 */
715 bool SearchResultWindow::canNext()
716 {
717     return d->m_itemCount > 0;
718 }
719
720 /*!
721     \fn bool SearchResultWindow::canPrevious()
722     \internal
723 */
724 bool SearchResultWindow::canPrevious()
725 {
726     return d->m_itemCount > 0;
727 }
728
729 /*!
730     \fn void SearchResultWindow::goToNext()
731     \internal
732 */
733 void SearchResultWindow::goToNext()
734 {
735     if (d->m_itemCount == 0)
736         return;
737     QModelIndex idx = d->m_searchResultTreeView->model()->next(d->m_searchResultTreeView->currentIndex());
738     if (idx.isValid()) {
739         d->m_searchResultTreeView->setCurrentIndex(idx);
740         d->m_searchResultTreeView->emitJumpToSearchResult(idx);
741     }
742 }
743
744 /*!
745     \fn void SearchResultWindow::goToPrev()
746     \internal
747 */
748 void SearchResultWindow::goToPrev()
749 {
750     if (!d->m_searchResultTreeView->model()->rowCount())
751         return;
752     QModelIndex idx = d->m_searchResultTreeView->model()->prev(d->m_searchResultTreeView->currentIndex());
753     if (idx.isValid()) {
754         d->m_searchResultTreeView->setCurrentIndex(idx);
755         d->m_searchResultTreeView->emitJumpToSearchResult(idx);
756     }
757 }
758
759 /*!
760     \fn bool SearchResultWindow::canNavigate()
761     \internal
762 */
763 bool SearchResultWindow::canNavigate()
764 {
765     return true;
766 }
767
768 } // namespace Find
769
770
771 #include "searchresultwindow.moc"