File indexing completed on 2024-04-21 03:41:58

0001 /*
0002     This file is part of Kiten, a KDE Japanese Reference Tool...
0003     SPDX-FileCopyrightText: 2001 Jason Katz-Brown <jason@katzbrown.com>
0004     SPDX-FileCopyrightText: 2005 Paul Temple <paul.temple@gmx.net>
0005     SPDX-FileCopyrightText: 2006 Joseph Kerian <jkerian@gmail.com>
0006     SPDX-FileCopyrightText: 2006 Eric Kjeldergaard <kjelderg@gmail.com>
0007     SPDX-FileCopyrightText: 2011 Daniel E. Moctezuma <democtezuma@gmail.com>
0008 
0009     SPDX-License-Identifier: GPL-2.0-or-later
0010 */
0011 
0012 #include "kiten.h"
0013 
0014 #include <KActionCollection>
0015 #include <KConfigGui>
0016 #include <KEditToolBar>
0017 #include <KLocalizedString>
0018 #include <KProcess>
0019 #include <KStandardAction>
0020 #include <KStandardGuiItem>
0021 #include <KToggleAction>
0022 #include <KXMLGUIFactory>
0023 
0024 #include <QAction>
0025 #include <QApplication>
0026 #include <QClipboard>
0027 #include <QDockWidget>
0028 #include <QList>
0029 #include <QPair>
0030 #include <QScrollBar>
0031 #include <QStandardPaths>
0032 #include <QStatusBar>
0033 #include <QTimer>
0034 #include <QVBoxLayout>
0035 
0036 #include "configuredialog.h"
0037 #include "dictionaryupdatemanager.h"
0038 #include "entrylist.h"
0039 #include "entrylistmodel.h"
0040 #include "entrylistview.h"
0041 #include "kitenconfig.h"
0042 #include "resultsview.h"
0043 #include "searchstringinput.h"
0044 
0045 using namespace Qt::StringLiterals;
0046 
0047 Kiten::Kiten(QWidget *parent, const char *name)
0048     : KXmlGuiWindow(parent)
0049     , _lastQuery(DictQuery())
0050     , _radselect_proc(new KProcess(this))
0051     , _kanjibrowser_proc(new KProcess(this))
0052 {
0053     _radselect_proc->setProgram(QStandardPaths::findExecutable(QStringLiteral("kitenradselect")));
0054     _kanjibrowser_proc->setProgram(QStandardPaths::findExecutable(QStringLiteral("kitenkanjibrowser")));
0055     setStandardToolBarMenuEnabled(true);
0056     setObjectName(QLatin1String(name));
0057 
0058     /* Set up the config */
0059     _config = KitenConfigSkeleton::self();
0060     _config->load();
0061 
0062     /* ResultsView is our main widget, displaying the results of a search */
0063     _mainView = new ResultsView(this, "mainView");
0064 
0065     /* Create the export list */
0066     //  setupExportListDock();
0067 
0068     /* TODO: have a look at this idea
0069     detachedView = new ResultsView( NULL, "detachedView" );
0070     */
0071 
0072     setCentralWidget(_mainView);
0073 
0074     setupActions();
0075     // Be sure to create this manager before creating the GUI
0076     // as it needs to add a KAction to it.
0077     _dictionaryUpdateManager = new DictionaryUpdateManager(this);
0078 
0079     createGUI();
0080 
0081     _statusBar = statusBar();
0082     _optionDialog = nullptr;
0083 
0084     /* Set things as they were (as told in the config) */
0085     _autoSearchToggle->setChecked(_config->autosearch());
0086     _inputManager->setDefaultsFromConfig();
0087     updateConfiguration();
0088     applyMainWindowSettings(KSharedConfig::openStateConfig()->group(QStringLiteral("kitenWindow")));
0089 
0090     /* What happens when links are clicked or things are selected in the clipboard */
0091     connect(_mainView, &ResultsView::urlClicked, this, &Kiten::searchText);
0092     connect(QApplication::clipboard(), &QClipboard::selectionChanged, this, &Kiten::searchClipboard);
0093     connect(_inputManager, &SearchStringInput::search, this, &Kiten::searchFromEdit);
0094 
0095     connect(_mainView->verticalScrollBar(), &QAbstractSlider::valueChanged, this, &Kiten::setCurrentScrollValue);
0096     /* We need to know when to reload our dictionaries if the user updated them. */
0097     connect(_dictionaryUpdateManager, &DictionaryUpdateManager::updateFinished, this, &Kiten::loadDictionaries);
0098 
0099     /* See below for what else needs to be done */
0100     QTimer::singleShot(10, this, &Kiten::finishInit);
0101 }
0102 
0103 // Destructor to clean up the little bits
0104 Kiten::~Kiten()
0105 {
0106     if (_radselect_proc->state() != QProcess::NotRunning) {
0107         _radselect_proc->kill();
0108     }
0109     if (_kanjibrowser_proc->state() != QProcess::NotRunning) {
0110         _kanjibrowser_proc->kill();
0111     }
0112     _dictionaryManager.removeAllDictionaries();
0113     delete _optionDialog;
0114     _optionDialog = nullptr;
0115 }
0116 
0117 KitenConfigSkeleton *Kiten::getConfig()
0118 {
0119     return _config;
0120 }
0121 
0122 void Kiten::setupActions()
0123 {
0124     /* Add the basic quit/print/prefs actions, use the gui factory for keybindings */
0125     (void)KStandardAction::quit(this, SLOT(close()), actionCollection());
0126     // Why the heck is KSA:print adding it's own toolbar!?
0127     //  (void) KStandardAction::print(this, SLOT(print()), actionCollection());
0128     (void)KStandardAction::preferences(this, SLOT(slotConfigure()), actionCollection());
0129     // old style cast seems needed here, (const QObject*)
0130     KStandardAction::keyBindings(guiFactory(), &KXMLGUIFactory::showConfigureShortcutsDialog, actionCollection());
0131 
0132     QAction *radselect = actionCollection()->addAction(QStringLiteral("radselect"));
0133     radselect->setText(i18n("Radical Selector"));
0134     actionCollection()->setDefaultShortcut(radselect, Qt::CTRL | Qt::Key_R);
0135     connect(radselect, &QAction::triggered, this, &Kiten::radicalSearch);
0136 
0137     QAction *kanjibrowser = actionCollection()->addAction(QStringLiteral("kanjibrowser"));
0138     kanjibrowser->setText(i18n("Kanji Browser"));
0139     actionCollection()->setDefaultShortcut(kanjibrowser, Qt::CTRL | Qt::Key_K);
0140     connect(kanjibrowser, &QAction::triggered, this, &Kiten::kanjiBrowserSearch);
0141 
0142     /* Setup the Search Actions and our custom Edit Box */
0143     _inputManager = new SearchStringInput(this);
0144 
0145     QAction *searchButton = actionCollection()->addAction(QStringLiteral("search"));
0146     searchButton->setText(i18n("S&earch"));
0147     // Set the search button to search
0148     connect(searchButton, &QAction::triggered, this, &Kiten::searchFromEdit);
0149     searchButton->setIcon(KStandardGuiItem::find().icon());
0150 
0151     // That's not it, that's "find as you type"...
0152     //   connect( Edit, SIGNAL(completion(QString)),
0153     //            this,   SLOT(searchFromEdit()) );
0154 
0155     /* Setup our widgets that handle preferences */
0156     //   deinfCB = new KToggleAction(   i18n( "&Deinflect Verbs in Regular Search" )
0157     //                                 , 0
0158     //                                 , this
0159     //                                 , SLOT(kanjiDictChange())
0160     //                                 , actionCollection()
0161     //                                 , "deinf_toggle" );
0162 
0163     _autoSearchToggle = actionCollection()->add<KToggleAction>(QStringLiteral("autosearch_toggle"));
0164     _autoSearchToggle->setText(i18n("&Automatically Search Clipboard Selections"));
0165 
0166     _irAction = actionCollection()->add<QAction>(QStringLiteral("search_in_results"));
0167     _irAction->setText(i18n("Search &in Results"));
0168     connect(_irAction, &QAction::triggered, this, &Kiten::searchInResults);
0169 
0170     QAction *actionFocusResultsView;
0171     actionFocusResultsView = actionCollection()->addAction(QStringLiteral("focusresultview"), this, SLOT(focusResultsView()));
0172     actionCollection()->setDefaultShortcut(actionFocusResultsView, Qt::Key_Escape);
0173     actionFocusResultsView->setText(i18n("Focus result view"));
0174 
0175     (void)KStandardAction::configureToolbars(this, SLOT(configureToolBars()), actionCollection());
0176 
0177     _backAction = KStandardAction::back(this, SLOT(back()), actionCollection());
0178     _backAction->setWhatsThis(i18n("Go to the previous search query."));
0179     _forwardAction = KStandardAction::forward(this, SLOT(forward()), actionCollection());
0180     _forwardAction->setWhatsThis(i18n("Go to the next search query."));
0181     _backAction->setEnabled(false);
0182     _forwardAction->setEnabled(false);
0183 }
0184 
0185 void Kiten::setupExportListDock()
0186 {
0187     _exportListDock = new QDockWidget(i18n("Export List"), this);
0188     _exportListDockContents = new QWidget(_exportListDock);
0189     _exportListDock->setWidget(_exportListDockContents);
0190     addDockWidget(Qt::RightDockWidgetArea, _exportListDock);
0191 
0192     auto layout = new QVBoxLayout(_exportListDockContents);
0193     _exportListDockContents->setLayout(layout);
0194 
0195     _exportList = new EntryListView(_exportListDockContents);
0196 
0197     layout->addWidget(_exportList);
0198 
0199     _exportList->setModel(new EntryListModel(EntryList()));
0200 }
0201 
0202 void Kiten::addExportListEntry(int index)
0203 {
0204     auto model = qobject_cast<EntryListModel *>(_exportList->model());
0205     if (!model)
0206         return;
0207 
0208     EntryList list = model->entryList();
0209 
0210     list << _historyList.current()->at(index)->clone();
0211     model->setEntryList(list);
0212 }
0213 
0214 // This is the latter part of the initialization
0215 void Kiten::finishInit()
0216 {
0217     _statusBar->showMessage(i18n("Initializing Dictionaries"));
0218 
0219     // if it's the application's first time starting,
0220     // the app group won't exist and we show demo
0221     if (_config->initialSearch()) {
0222         if (!KConfigGui::hasSessionConfig() || !KConfigGui::sessionConfig()->hasGroup(QStringLiteral("app"))) {
0223             searchTextAndRaise(QStringLiteral("辞書"));
0224             // Note to future tinkerers... DO NOT EDIT OR TRANSLATE THAT
0225             // it's an embedded unicode search string to find "dictionary" in japanese
0226         }
0227     }
0228 
0229     _inputManager->focusInput();
0230     _statusBar->showMessage(i18n("Welcome to Kiten"));
0231     setCaption(QString());
0232 }
0233 
0234 void Kiten::focusResultsView()
0235 {
0236     _mainView->verticalScrollBar()->setFocus();
0237 }
0238 
0239 // This function is run on program window close.
0240 // It saves the settings in the config.
0241 bool Kiten::queryClose()
0242 {
0243     _config->setAutosearch(_autoSearchToggle->isChecked());
0244     _config->save();
0245 
0246     KConfigGroup configGroup = KSharedConfig::openStateConfig()->group(QStringLiteral("kitenWindow"));
0247     saveMainWindowSettings(configGroup);
0248     return true;
0249 }
0250 
0251 //////////////////////////////////////////////////////////////////////////////
0252 // SEARCHING METHODS
0253 //////////////////////////////////////////////////////////////////////////////
0254 
0255 /**
0256  * This function searches for the contents of the Edit field in the mainwindow.
0257  * Any gui choices will also be included here.
0258  */
0259 void Kiten::searchFromEdit()
0260 {
0261     qDebug() << "SEARCH FROM EDIT CALLED";
0262     DictQuery query = _inputManager->getSearchQuery();
0263     if (query != _lastQuery) {
0264         _lastQuery = query;
0265         searchAndDisplay(query);
0266     }
0267 }
0268 
0269 /**
0270  * This function is called when a kanji is clicked in the result view
0271  * or any other time in which we want to search for something that didn't
0272  * come from the input box.
0273  */
0274 void Kiten::searchText(const QString &text)
0275 {
0276     searchAndDisplay(DictQuery(text));
0277 }
0278 
0279 /**
0280  * This should change the Edit text to be appropriate and then begin a search
0281  * of the dictionaries' entries.
0282  */
0283 void Kiten::searchTextAndRaise(const QString &str)
0284 {
0285     /* Do the search */
0286     searchText(str);
0287     /* get the window as we'd like it */
0288     raise();
0289 }
0290 
0291 /**
0292  * This function will search things as they are put in the clipboard.
0293  * It checks each time to see if the autoSearchToggle is set.
0294  * This function searches for the contents of the clipboard
0295  * filter out long selections and selections that are contained in our
0296  * current search (alleviates problem where research occurs because of
0297  * X's auto-add-to-clipboard-on-select feature.
0298  */
0299 void Kiten::searchClipboard()
0300 {
0301     if (_autoSearchToggle->isChecked()) {
0302         QString clipboard = QApplication::clipboard()->text(QClipboard::Selection).simplified();
0303 
0304         // Only search if the clipboard selection was less than 20 characters wide
0305         if (clipboard.length() < 20) {
0306             DictQuery potentialQuery(clipboard);
0307             // Make sure that we're not looking for a substring of the current string (needed?)
0308             if (!(potentialQuery < _inputManager->getSearchQuery())) {
0309                 searchTextAndRaise(clipboard);
0310             }
0311 
0312             qDebug() << "Clipboard item is a substring (rejected)";
0313         } else {
0314             qDebug() << "Clipboard entry too long";
0315         }
0316     }
0317 }
0318 
0319 /**
0320  * This method performs the search and displays
0321  * the result to the screen.
0322  */
0323 void Kiten::searchAndDisplay(const DictQuery &query)
0324 {
0325     /* keep the user informed of what we are doing */
0326     _statusBar->showMessage(i18n("Searching..."));
0327 
0328     /* This gorgeous incantation is all that's necessary to fill a DictQuery
0329       with a query and an Entrylist with all of the results form all of the
0330       requested dictionaries */
0331     EntryList *results = _dictionaryManager.doSearch(query);
0332 
0333     /* if there are no results */
0334     if (results->empty()) // TODO: check here if the user actually prefers this
0335     {
0336         // create a modifiable copy of the original query
0337         DictQuery newQuery(query);
0338 
0339         bool tryAgain = false;
0340 
0341         do {
0342             // by default we don't try again
0343             tryAgain = false;
0344 
0345             // but if the matchtype is changed we try again
0346             if (newQuery.getMatchType() == DictQuery::Exact) {
0347                 newQuery.setMatchType(DictQuery::Beginning);
0348                 tryAgain = true;
0349             } else if (newQuery.getMatchType() == DictQuery::Beginning) {
0350                 newQuery.setMatchType(DictQuery::Anywhere);
0351                 tryAgain = true;
0352             }
0353 
0354             // try another search
0355             if (tryAgain) {
0356                 delete results;
0357                 results = _dictionaryManager.doSearch(newQuery);
0358 
0359                 // results means all is ok; don't try again
0360                 if (!results->empty()) {
0361                     tryAgain = false;
0362                 }
0363             }
0364         } while (tryAgain);
0365     }
0366 
0367     /* synchronize the history (and store this pointer there) */
0368     addHistory(results);
0369 
0370     /* Add the current search to our drop down list */
0371     _inputManager->setSearchQuery(results->getQuery());
0372 
0373     /* suppose it's about time to show the users the results. */
0374     displayResults(results);
0375 }
0376 
0377 /**
0378  * Search in the previous results, identical to
0379  * searchAndDisplay except for the one call.
0380  */
0381 void Kiten::searchInResults()
0382 {
0383     _statusBar->showMessage(i18n("Searching..."));
0384 
0385     DictQuery searchQuery = _inputManager->getSearchQuery();
0386     EntryList *results = _dictionaryManager.doSearchInList(searchQuery, _historyList.current());
0387 
0388     addHistory(results);
0389     _inputManager->setSearchQuery(searchQuery);
0390     displayResults(results);
0391 }
0392 
0393 /**
0394  * Given a set of Search Results items, this function does all that's needed
0395  * to put the interface into an appropriate state for those searchResults.
0396  */
0397 void Kiten::displayResults(EntryList *results)
0398 {
0399     QString infoStr;
0400     /* synchronize the statusbar */
0401     if (results->count() > 0) {
0402         infoStr = i18np("Found 1 result", "Found %1 results", results->count());
0403     } else {
0404         infoStr = i18n("No results found");
0405     }
0406     _statusBar->showMessage(infoStr);
0407     setCaption(infoStr);
0408 
0409     /* sort the results */
0410     /* synchronize the results window */
0411     if (results->count() > 0) {
0412         QStringList dictSort;
0413         QStringList fieldSort = _config->field_sortlist();
0414         if (_config->dictionary_enable() == QLatin1String("true")) {
0415             dictSort = _config->dictionary_sortlist();
0416         }
0417         results->sort(fieldSort, dictSort);
0418         _mainView->setContents(results->toHTML());
0419     } else {
0420         _mainView->setContents("<html><body>"_L1 + infoStr + "</body></html>"_L1);
0421     }
0422 
0423     _mainView->setLaterScrollValue(results->scrollValue());
0424 
0425     /* //Debuggery: to print the html results to file:
0426     QFile file( "/tmp/lala" );
0427     file.open( QIODevice::WriteOnly );
0428     file.write( results->toHTML().toUtf8() );
0429     file.close();
0430     */
0431 }
0432 
0433 void Kiten::radicalSearch()
0434 {
0435     // Radselect is a KUniqueApplication, so we don't
0436     // need to worry about opening more than one copy
0437     _radselect_proc->start();
0438 }
0439 
0440 void Kiten::kanjiBrowserSearch()
0441 {
0442     // KanjiBrowser is a KUniqueApplication, so we don't
0443     // need to worry about opening more than one copy
0444     _kanjibrowser_proc->start();
0445 }
0446 
0447 //////////////////////////////////////////////////////////////////////////////
0448 // PREFERENCES RELATED METHODS
0449 //////////////////////////////////////////////////////////////////////////////
0450 void Kiten::slotConfigure()
0451 {
0452     // If the settings dialog is open and obscured/hidden/cached, show it
0453     if (ConfigureDialog::showDialog(QStringLiteral("settings"))) {
0454         return;
0455     }
0456 
0457     // ConfigureDialog didn't find an instance of this dialog, so lets create it :
0458     _optionDialog = new ConfigureDialog(this, _config);
0459     connect(_optionDialog, &ConfigureDialog::settingsChanged, this, &Kiten::updateConfiguration);
0460 
0461     _optionDialog->show();
0462 }
0463 
0464 void Kiten::configureToolBars()
0465 {
0466     KConfigGroup configGroup = KSharedConfig::openStateConfig()->group(QStringLiteral("kitenWindow"));
0467     saveMainWindowSettings(configGroup);
0468     KEditToolBar dlg(actionCollection());
0469     connect(&dlg, &KEditToolBar::newToolBarConfig, this, &Kiten::newToolBarConfig);
0470     dlg.exec();
0471 }
0472 
0473 void Kiten::newToolBarConfig()
0474 {
0475     createGUI(QStringLiteral("kitenui.rc"));
0476     KConfigGroup configGroup = KSharedConfig::openStateConfig()->group(QStringLiteral("kitenWindow"));
0477     applyMainWindowSettings(configGroup);
0478 }
0479 
0480 /**
0481  * This function, as the name says, updates the configuration file.
0482  * It should be called in EVERY case where the configuration files change.
0483  */
0484 void Kiten::updateConfiguration()
0485 {
0486     loadDictionaries();
0487 
0488     // Update the HTML/CSS for our fonts
0489     displayHistoryItem();
0490 
0491     _inputManager->updateFontFromConfig();
0492 
0493     // Reset the content of the last query. This is because in case the user adds
0494     // new dictionaries and wants to execute the same last search, the output
0495     // will contain results of the new dictionary/dictionaries added.
0496     _lastQuery = DictQuery();
0497 
0498     /*: TODO: have a look at this as well
0499     detachedView->updateFont();
0500     */
0501 }
0502 
0503 /**
0504  * Loads the dictionaries, their settings and updates general
0505  * options for the display manager.
0506  */
0507 void Kiten::loadDictionaries()
0508 {
0509     // Avoid duplicates (this makes it easy when we need to reload the dictionaries).
0510     _dictionaryManager.removeAllDictionaries();
0511 
0512     // Load the dictionaries of each type that we can adjust in prefs
0513     for (const QString &it : _config->dictionary_list()) {
0514         loadDictConfig(it);
0515     }
0516 
0517     // Load settings for each dictionary type
0518     for (const QString &it : _dictionaryManager.listDictFileTypes()) {
0519         _dictionaryManager.loadDictSettings(it, _config);
0520     }
0521 
0522     // Update general options for the display manager (sorting by dict, etc)
0523     _dictionaryManager.loadSettings(*_config->config());
0524     qDebug() << "Dictionaries loaded!";
0525 }
0526 
0527 /**
0528  * This function loads the dictionaries from the config file for the program
0529  * to use via the dictionaryManager object.
0530  */
0531 void Kiten::loadDictConfig(const QString &dictType)
0532 {
0533     KConfigGroup group = _config->config()->group("dicts_"_L1 + dictType.toLower());
0534 
0535     // A list of QPair's Name->Path
0536     QList<QPair<QString, QString>> dictionariesToLoad;
0537 
0538     // If we need to load the global
0539     if (group.readEntry("__useGlobal", true)) {
0540         QString dictionary = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kiten/") + dictType.toLower());
0541         dictionariesToLoad.append(qMakePair(dictType, dictionary));
0542     }
0543 
0544     QStringList dictNames = group.readEntry<QStringList>("__NAMES", QStringList());
0545     for (const QString &name : dictNames) {
0546         QString dictPath = group.readEntry(name, QString());
0547         if (!dictPath.isEmpty() && !name.isEmpty()) {
0548             dictionariesToLoad.append(qMakePair(name, dictPath));
0549         }
0550     }
0551 
0552     QStringList loadedDictionaries = _dictionaryManager.listDictionariesOfType(dictType.toLower());
0553 
0554     for (const auto &it : dictionariesToLoad) {
0555         // Remove from the loadedDictionaries list all the dicts that we are supposed to load
0556         // This will leave only those that need to be unloaded at the end
0557         if (loadedDictionaries.removeAll(it.first) == 0) {
0558             _dictionaryManager.addDictionary(it.second, it.first, dictType.toLower());
0559         }
0560     }
0561 
0562     for (const QString &it : loadedDictionaries) {
0563         _dictionaryManager.removeDictionary(it);
0564     }
0565 
0566     /*
0567     #define PERSONALDictionaryLocation( __X ) KGlobal::dirs()->saveLocation(__X, \
0568             "kiten/dictionaries/",true).append("personal")
0569     if(!isKanji) { //Don't load personal dicts as kanji dicts
0570             QString personalDict(PERSONALDictionaryLocation("data"));
0571             if (QFile::exists(personalDict) &&
0572                                     loadedDicts.find(personalDict) == loadedDicts.end())
0573             {
0574                     dictionaryManager.addDictionary(personalDict,"Personal",dictType.lower());
0575             }
0576     }
0577     */
0578 }
0579 
0580 /**
0581  * This function allows one to print out the currently displayed result
0582  */
0583 void Kiten::print()
0584 {
0585     //  _ResultsView->toHTML();
0586 }
0587 
0588 /******************************************************************************
0589   HISTORY HANDLING FUNCTIONS
0590 ******************************************************************************/
0591 
0592 /**
0593  * Given one Search Result, it adds it to the history list the logic in it
0594  * exists to maintain the history list of a certain size.  Note that this method
0595  * does not display the EntryList it is given... so you can add something to the
0596  * history and display it separately.
0597  */
0598 void Kiten::addHistory(EntryList *result)
0599 {
0600     _historyList.addItem(result);
0601     enableHistoryButtons();
0602 }
0603 
0604 /**
0605  * This goes back one item in the history and displays
0606  */
0607 void Kiten::back()
0608 {
0609     _historyList.prev();
0610     displayHistoryItem();
0611 }
0612 
0613 /**
0614  * This goes forward one item in the history and displays
0615  */
0616 void Kiten::forward()
0617 {
0618     _historyList.next();
0619     displayHistoryItem();
0620 }
0621 
0622 /**
0623  * This method just sets the current element in the list and triggers the display
0624  */
0625 void Kiten::goInHistory(int index)
0626 {
0627     _historyList.setCurrent(index);
0628     displayHistoryItem();
0629 }
0630 
0631 void Kiten::displayHistoryItem()
0632 {
0633     if (_historyList.current() == nullptr)
0634         return;
0635 
0636     _inputManager->setSearchQuery(_historyList.current()->getQuery());
0637     enableHistoryButtons();
0638 
0639     displayResults(_historyList.current());
0640 }
0641 
0642 /**
0643  * This function determines whether the forward and back buttons should be enabled.
0644  * It is currently done independently of what action has just occurred.
0645  */
0646 void Kiten::enableHistoryButtons()
0647 {
0648     _backAction->setEnabled(_historyList.index() > 0);
0649     _forwardAction->setEnabled(_historyList.index() + 1 < _historyList.count());
0650 }
0651 
0652 void Kiten::setCurrentScrollValue(int value)
0653 {
0654     if (_historyList.current() == nullptr)
0655         return;
0656 
0657     _historyList.current()->setScrollValue(value);
0658 }
0659 
0660 #include "moc_kiten.cpp"