diff --git a/src/lay/lay/layHelpSource.cc b/src/lay/lay/layHelpSource.cc index e33569d8b..0b5edd062 100644 --- a/src/lay/lay/layHelpSource.cc +++ b/src/lay/lay/layHelpSource.cc @@ -554,6 +554,21 @@ HelpSource::get_outline (const std::string &u) return ol; } +void +HelpSource::search_completers (const std::string &string, std::list &completers) +{ + size_t n = 0; + const size_t max_completers = 100; + + // first produce all hits with match + for (std::vector ::const_iterator i = m_index.begin (); i < m_index.end () && n < max_completers; ++i) { + if (i->normalized_key.find (string) != std::string::npos) { + completers.push_back (i->key); + ++n; + } + } +} + std::string HelpSource::next_topic (const std::string &url) { diff --git a/src/lay/lay/layHelpSource.h b/src/lay/lay/layHelpSource.h index dc3af75c2..d355cd2b5 100644 --- a/src/lay/lay/layHelpSource.h +++ b/src/lay/lay/layHelpSource.h @@ -82,8 +82,9 @@ public: virtual QImage get_image (const std::string &url); virtual std::string get_css (const std::string &url); - virtual std::string next_topic (const std::string &url); + virtual void search_completers(const std::string &search_string, std::list &completers); + virtual std::string next_topic (const std::string &url); virtual std::string prev_topic (const std::string &url); QDomDocument get_dom (const std::string &u); diff --git a/src/laybasic/laybasic/BrowserPanel.ui b/src/laybasic/laybasic/BrowserPanel.ui index bcd83e6fc..ac0144c39 100644 --- a/src/laybasic/laybasic/BrowserPanel.ui +++ b/src/laybasic/laybasic/BrowserPanel.ui @@ -52,52 +52,6 @@ - - - - TextLabel - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 6 - 20 - - - - - - - - Previous Topic - - - ... - - - - :/prev_topic.png:/prev_topic.png - - - - 24 - 24 - - - - true - - - @@ -114,111 +68,6 @@ - - - - Home - - - ... - - - - :/home.png:/home.png - - - - 24 - 24 - - - - true - - - - - - - Next Topic - - - ... - - - - :/next_topic.png:/next_topic.png - - - - 24 - 24 - - - - true - - - - - - - - 0 - 0 - - - - - - - - Back - - - ... - - - - :/back.png:/back.png - - - - 24 - 24 - - - - true - - - - - - - Qt::Horizontal - - - QSizePolicy::Fixed - - - - 6 - 20 - - - - - - - - - - - :/find.png - - - @@ -360,6 +209,9 @@ QFrame::Raised + + 2 + 0 @@ -372,25 +224,47 @@ 0 - - - - - - - :/find.png - - - - Find on page + Find on page - + + + ... + + + + :/find.png:/find.png + + + true + + + + + + + true + + + + + + + ... + + + + :/clear_edit.png:/clear_edit.png + + + true + + @@ -402,8 +276,15 @@ - - + + + + TextLabel + + + + + Qt::Horizontal @@ -412,13 +293,156 @@ - 5 + 6 20 + + + + Back + + + ... + + + + :/back.png:/back.png + + + + 24 + 24 + + + + true + + + + + + + Qt::Horizontal + + + QSizePolicy::Fixed + + + + 6 + 20 + + + + + + + + Next Topic + + + ... + + + + :/next_topic.png:/next_topic.png + + + + 24 + 24 + + + + true + + + + + + + Previous Topic + + + ... + + + + :/prev_topic.png:/prev_topic.png + + + + 24 + 24 + + + + true + + + + + + + Home + + + ... + + + + :/home.png:/home.png + + + + 24 + 24 + + + + true + + + + + + + + 0 + 0 + + + + true + + + + + + + ... + + + + :/find.png:/find.png + + + true + + + + + + Find + + + Ctrl+F + + @@ -428,7 +452,7 @@ - searchEdit + search_edit back_pb forward_pb home_pb @@ -436,5 +460,22 @@ - + + + toolButton + clicked() + search_frame + hide() + + + 816 + 571 + + + 371 + 577 + + + + diff --git a/src/laybasic/laybasic/layBrowserPanel.cc b/src/laybasic/laybasic/layBrowserPanel.cc index 1da5393a7..22d1fa529 100644 --- a/src/laybasic/laybasic/layBrowserPanel.cc +++ b/src/laybasic/laybasic/layBrowserPanel.cc @@ -34,6 +34,9 @@ #endif #include +#include +#include +#include namespace lay { @@ -73,18 +76,35 @@ BrowserPanel::init () mp_ui->browser->set_panel (this); mp_ui->browser->setWordWrapMode (QTextOption::WordWrap); + mp_ui->browser->addAction (mp_ui->action_find); + connect (mp_ui->back_pb, SIGNAL (clicked ()), this, SLOT (back ())); connect (mp_ui->forward_pb, SIGNAL (clicked ()), this, SLOT (forward ())); connect (mp_ui->next_topic_pb, SIGNAL (clicked ()), this, SLOT (next ())); connect (mp_ui->prev_topic_pb, SIGNAL (clicked ()), this, SLOT (prev ())); connect (mp_ui->home_pb, SIGNAL (clicked ()), this, SLOT (home ())); - connect (mp_ui->searchEdit, SIGNAL (returnPressed ()), this, SLOT (search_edited ())); + connect (mp_ui->search_edit, SIGNAL (textEdited (const QString &)), this, SLOT (search_text_changed (const QString &))); + connect (mp_ui->search_edit, SIGNAL (returnPressed ()), this, SLOT (search_edited ())); + connect (mp_ui->search_button, SIGNAL (clicked ()), this, SLOT (search_edited ())); connect (mp_ui->browser, SIGNAL (textChanged ()), this, SLOT (text_changed ())); connect (mp_ui->browser, SIGNAL (backwardAvailable (bool)), mp_ui->back_pb, SLOT (setEnabled (bool))); connect (mp_ui->browser, SIGNAL (forwardAvailable (bool)), mp_ui->forward_pb, SLOT (setEnabled (bool))); connect (mp_ui->outline_tree, SIGNAL (itemActivated (QTreeWidgetItem *, int)), this, SLOT (outline_item_clicked (QTreeWidgetItem *))); + connect (mp_ui->action_find, SIGNAL (triggered ()), this, SLOT (find ())); + connect (mp_ui->on_page_search_edit, SIGNAL (textChanged (const QString &)), this, SLOT (page_search_edited ())); + connect (mp_ui->on_page_search_edit, SIGNAL (returnPressed ()), this, SLOT (page_search_next ())); + connect (mp_ui->on_page_search_next, SIGNAL (clicked ()), this, SLOT (page_search_next ())); - mp_ui->searchEdit->hide (); + mp_completer = new QCompleter (this); + mp_completer->setFilterMode (Qt::MatchStartsWith); + mp_completer->setCaseSensitivity (Qt::CaseInsensitive); + mp_completer->setCompletionMode (QCompleter::UnfilteredPopupCompletion); + mp_completer_model = new QStringListModel (mp_completer); + mp_completer->setModel (mp_completer_model); + mp_ui->search_edit->setCompleter (mp_completer); + + mp_ui->search_frame->hide (); + mp_ui->search_edit->hide (); set_label (std::string ()); } @@ -110,6 +130,87 @@ BrowserPanel::url () const return m_cached_url; } +void +BrowserPanel::find () +{ + mp_ui->search_frame->show (); + mp_ui->on_page_search_edit->setFocus(); +} + +void +BrowserPanel::page_search_edited () +{ + m_search_selection.clear (); + m_search_index = -1; + + if (mp_ui->on_page_search_edit->text ().size () < 2) { + mp_ui->browser->setExtraSelections (m_search_selection); + return; + } + + QString search_text = mp_ui->on_page_search_edit->text (); + + QTextDocument *doc = mp_ui->browser->document (); + for (QTextBlock b = doc->firstBlock (); b.isValid (); b = b.next ()) { + + int from = 0; + int index; + + QString t = b.text (); + + while ((index = t.indexOf (search_text, from, Qt::CaseInsensitive)) >= 0) { + + QTextCursor highlight (b); + highlight.movePosition (QTextCursor::NextCharacter, QTextCursor::MoveAnchor, index); + highlight.movePosition (QTextCursor::NextCharacter, QTextCursor::KeepAnchor, search_text.size ()); + + QTextEdit::ExtraSelection extra_selection; + extra_selection.cursor = highlight; + extra_selection.format.setBackground (QColor (255, 255, 160)); + m_search_selection.push_back (extra_selection); + + from = index + search_text.size (); + + } + + } + + if (! m_search_selection.empty ()) { + m_search_index = 0; + mp_ui->browser->setExtraSelections (m_search_selection); + mp_ui->browser->setTextCursor (m_search_selection [m_search_index].cursor); + } +} + +void +BrowserPanel::page_search_next () +{ + if (m_search_index >= 0) { + + ++m_search_index; + if (m_search_index >= m_search_selection.size ()) { + m_search_index = 0; + } + + mp_ui->browser->setTextCursor (m_search_selection [m_search_index].cursor); + + } +} + +void +BrowserPanel::search_text_changed (const QString &text) +{ + QList strings; + if (! text.isEmpty () && mp_source.get ()) { + std::list cl; + mp_source->search_completers (tl::to_string (text.toLower ()), cl); + for (std::list::const_iterator i = cl.begin (); i != cl.end (); ++i) { + strings.push_back (tl::to_qstring (*i)); + } + } + mp_completer_model->setStringList (strings); +} + void BrowserPanel::text_changed () { @@ -259,15 +360,15 @@ BrowserPanel::search (const std::string &s) void BrowserPanel::search_edited () { - if (mp_ui->searchEdit->text ().size () > 0) { + if (mp_ui->search_edit->text ().size () > 0) { QUrl url (tl::to_qstring (m_search_url)); #if QT_VERSION >= 0x050000 QUrlQuery qi; - qi.addQueryItem (tl::to_qstring (m_search_query_item), mp_ui->searchEdit->text ()); + qi.addQueryItem (tl::to_qstring (m_search_query_item), mp_ui->search_edit->text ()); url.setQuery (qi); #else QList > qi; - qi.push_back (QPair (tl::to_qstring (m_search_query_item), mp_ui->searchEdit->text ())); + qi.push_back (QPair (tl::to_qstring (m_search_query_item), mp_ui->search_edit->text ())); url.setQueryItems (qi); #endif load (url.toEncoded ().constData ()); @@ -279,7 +380,7 @@ BrowserPanel::set_search_url (const std::string &url, const std::string &query_i { m_search_url = url; m_search_query_item = query_item; - mp_ui->searchEdit->setVisible (! url.empty ()); + mp_ui->search_edit->setVisible (! url.empty ()); } void @@ -474,6 +575,12 @@ BrowserSource::get_outline (const std::string & /*url*/) return BrowserOutline (); } +void +BrowserSource::search_completers (const std::string & /*search_string*/, std::list & /*completers*/) +{ + // .. nothing here .. +} + std::string BrowserSource::get (const std::string & /*url*/) { diff --git a/src/laybasic/laybasic/layBrowserPanel.h b/src/laybasic/laybasic/layBrowserPanel.h index b974de658..3c02123a4 100644 --- a/src/laybasic/laybasic/layBrowserPanel.h +++ b/src/laybasic/laybasic/layBrowserPanel.h @@ -30,12 +30,15 @@ #include "gsiObject.h" #include +#include #include #include #include class QTreeWidgetItem; +class QCompleter; +class QStringListModel; namespace Ui { @@ -204,6 +207,11 @@ public: */ virtual BrowserOutline get_outline (const std::string &url); + /** + * @brief Gets the search completer items for a given search string + */ + virtual void search_completers (const std::string &search_string, std::list &completers); + /** * @brief Get the image for a given "int" URL in an image */ @@ -385,7 +393,15 @@ public slots: */ void home (); + /** + * @brief "find" activated + */ + void find (); + protected slots: + void page_search_edited (); + void page_search_next(); + void search_text_changed(const QString &text); void search_edited (); void text_changed (); void outline_item_clicked (QTreeWidgetItem *item); @@ -408,6 +424,10 @@ private: tl::DeferredMethod m_back_dm; std::string m_search_url, m_search_query_item; QString m_current_title; + QList m_search_selection; + int m_search_index; + QCompleter *mp_completer; + QStringListModel *mp_completer_model; void init (); };