changeset 25042:ba5af45bbfc4 stable

documentation widget based on qt help engine (bug #53006)
author Torsten <mttl@mailbox.org>
date Wed, 28 Mar 2018 21:46:11 +0200
parents d5d61f1b6de0
children cc20786d2165 b6aea95a7bf9
files libgui/src/documentation-dock-widget.cc libgui/src/documentation-dock-widget.h libgui/src/documentation.cc libgui/src/documentation.h libgui/src/m-editor/file-editor.cc libgui/src/main-window.cc libgui/src/module.mk m4/acinclude.m4
diffstat 8 files changed, 397 insertions(+), 43 deletions(-) [+]
line wrap: on
line diff
--- a/libgui/src/documentation-dock-widget.cc	Wed Mar 28 13:41:48 2018 -0700
+++ b/libgui/src/documentation-dock-widget.cc	Wed Mar 28 21:46:11 2018 +0200
@@ -39,42 +39,38 @@
     set_title (tr ("Documentation"));
     setStatusTip (tr ("See the documentation for help."));
 
-    m_webinfo = new octave::webinfo (this);
-    setWidget (m_webinfo);
-    setFocusProxy (m_webinfo);
+    m_docs = new octave::documentation (this);
+    setWidget (m_docs);
+    setFocusProxy (m_docs);
 
     connect (p, SIGNAL (show_doc_signal (const QString&)),
              this, SLOT (showDoc (const QString&)));
   }
 
-  void documentation_dock_widget::notice_settings (const QSettings *settings)
+  documentation_dock_widget::~documentation_dock_widget (void)
   {
-    m_webinfo->notice_settings (settings);
+    if (m_docs)
+      delete m_docs;
   }
 
-  void documentation_dock_widget::load_info_file (void)
+  void documentation_dock_widget::notice_settings (const QSettings *settings)
   {
-    octave::help_system& help_sys
-      = octave::__get_help_system__ ("doc widget: load_info_file");
-
-    QString info_file = QString::fromStdString (help_sys.info_file ());
-
-    m_webinfo->load_info_file (info_file);
+    m_docs->notice_settings (settings);
   }
 
   void documentation_dock_widget::copyClipboard (void)
   {
-    m_webinfo->copyClipboard ();
+    m_docs->copyClipboard ();
   }
 
   void documentation_dock_widget::pasteClipboard (void)
   {
-    m_webinfo->pasteClipboard ();
+    m_docs->pasteClipboard ();
   }
 
   void documentation_dock_widget::selectAll (void)
   {
-    m_webinfo->selectAll ();
+    m_docs->selectAll ();
   }
 
   void documentation_dock_widget::showDoc (const QString& name)
@@ -85,6 +81,6 @@
 
     raise ();
 
-    m_webinfo->load_ref (name);
+    m_docs->load_ref (name);
   }
 }
--- a/libgui/src/documentation-dock-widget.h	Wed Mar 28 13:41:48 2018 -0700
+++ b/libgui/src/documentation-dock-widget.h	Wed Mar 28 21:46:11 2018 +0200
@@ -24,8 +24,7 @@
 #define octave_documentation_dock_widget_h 1
 
 #include "octave-dock-widget.h"
-
-#include "webinfo.h"
+#include "documentation.h"
 
 namespace octave
 {
@@ -36,13 +35,12 @@
   public:
 
     documentation_dock_widget (QWidget *parent = nullptr);
+    ~documentation_dock_widget (void);
 
   public slots:
 
     void notice_settings (const QSettings *settings);
 
-    void load_info_file (void);
-
   protected slots:
 
     void copyClipboard (void);
@@ -53,7 +51,7 @@
 
   private:
 
-    octave::webinfo *m_webinfo;
+    octave::documentation *m_docs;
   };
 }
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/documentation.cc	Wed Mar 28 21:46:11 2018 +0200
@@ -0,0 +1,256 @@
+/*
+
+Copyright (C) 2018 Torsten <mttl@maibox.org>
+
+This file is part of Octave.
+
+Octave is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Octave is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<https://www.gnu.org/licenses/>.
+
+*/
+
+#if defined (HAVE_CONFIG_H)
+#  include "config.h"
+#endif
+
+#include <QApplication>
+#include <QCompleter>
+#include <QHelpContentWidget>
+#include <QHelpIndexWidget>
+#include <QHelpSearchEngine>
+#include <QHelpSearchQueryWidget>
+#include <QHelpSearchResultWidget>
+#include <QLabel>
+#include <QLineEdit>
+#include <QTabWidget>
+#include <QMessageBox>
+#include <QVBoxLayout>
+
+#include "documentation.h"
+
+namespace octave
+{
+  // The documentation splitter, which is the main widget
+  // of the doc dock widget
+  documentation::documentation (QWidget *p)
+    : QSplitter (Qt::Horizontal, p)
+  {
+    QString collection = getenv ("OCTAVE_QTHELP_COLLECTION");
+
+    // Setup the help engine and load the help data
+    m_help_engine = new QHelpEngine (collection, this);
+
+    connect(m_help_engine, SIGNAL(setupFinished()),
+            m_help_engine->searchEngine(), SLOT(indexDocumentation()));
+
+    if (! m_help_engine->setupData())
+      {
+        QMessageBox::warning (this, tr ("Octave Documentation"),
+                              tr ("Could not setup the data required for the\n"
+                                  "documentation viewer. Only help texts in\n"
+                                  "the Console Widget will be available."));
+        if (m_help_engine)
+          {
+            delete m_help_engine;
+            m_help_engine = 0;
+          }
+      }
+
+    // The browser
+    m_doc_browser = new documentation_browser (m_help_engine, this);
+
+    // Layout contents, index and search
+    QTabWidget *navi = new QTabWidget (this);
+    navi->setTabsClosable (false);
+    navi->setMovable (true);
+
+    // Contents
+    QHelpContentWidget *content = m_help_engine->contentWidget ();
+    navi->addTab (content, tr ("Contents"));
+
+    connect(m_help_engine->contentWidget (),
+            SIGNAL (linkActivated (const QUrl&)),
+            m_doc_browser, SLOT(handle_index_clicked (const QUrl&)));
+
+    // Index
+    QHelpIndexWidget *index = m_help_engine->indexWidget ();
+
+    m_filter = new QComboBox (this);
+    m_filter->setToolTip (tr ("Enter text to search the indices"));
+    m_filter->setEditable (true);
+    m_filter->setInsertPolicy (QComboBox::NoInsert);
+    m_filter->setMaxCount (10);
+    m_filter->setMaxVisibleItems (10);
+    m_filter->setSizeAdjustPolicy (
+      QComboBox::AdjustToMinimumContentsLengthWithIcon);
+    QSizePolicy sizePol (QSizePolicy::Expanding, QSizePolicy::Preferred);
+    m_filter->setSizePolicy (sizePol);
+    m_filter->completer ()->setCaseSensitivity (Qt::CaseSensitive);
+    QLabel *filter_label = new QLabel (tr ("Search"));
+
+    QWidget *filter_all = new QWidget (navi);
+    QHBoxLayout *h_box_index = new QHBoxLayout (filter_all);
+    h_box_index->addWidget (filter_label);
+    h_box_index->addWidget (m_filter);
+    h_box_index->setMargin (2);
+    filter_all->setLayout (h_box_index);
+
+    QWidget *index_all = new QWidget (navi);
+    QVBoxLayout *v_box_index = new QVBoxLayout (index_all);
+    v_box_index->addWidget (filter_all);
+    v_box_index->addWidget (index);
+    index_all->setLayout (v_box_index);
+
+    navi->addTab (index_all, tr ("Index"));
+
+    connect(m_help_engine->indexWidget (),
+            SIGNAL (linkActivated (const QUrl&, const QString&)),
+            m_doc_browser, SLOT(handle_index_clicked (const QUrl&,
+                                                       const QString&)));
+
+    connect (m_filter, SIGNAL (editTextChanged (const QString&)),
+             this, SLOT(filter_update (const QString&)));
+
+    connect (m_filter->lineEdit (), SIGNAL (editingFinished (void)),
+             this, SLOT(filter_update_history (void)));
+
+    // Search
+    QHelpSearchEngine *search_engine = m_help_engine->searchEngine ();
+    QHelpSearchQueryWidget *search = search_engine->queryWidget ();
+    QHelpSearchResultWidget *result = search_engine->resultWidget ();
+    QWidget *search_all = new QWidget (navi);
+    QVBoxLayout *v_box_search = new QVBoxLayout (search_all);
+    v_box_search->addWidget (search);
+    v_box_search->addWidget (result);
+    search_all->setLayout (v_box_search);
+    navi->addTab (search_all, tr ("Search"));
+
+    connect (search, SIGNAL (search (void)),
+             this, SLOT(global_search (void)));
+
+    connect (search_engine, SIGNAL (searchingStarted (void)),
+             this, SLOT(global_search_started (void)));
+    connect (search_engine, SIGNAL (searchingFinished (int)),
+             this, SLOT(global_search_finished (int)));
+
+    connect (search_engine->resultWidget (),
+             SIGNAL (requestShowLink (const QUrl&)),
+             m_doc_browser,
+             SLOT(handle_index_clicked (const QUrl&)));
+
+    // Fill the splitter
+    insertWidget (0, navi);
+    insertWidget (1, m_doc_browser);
+    setStretchFactor (1, 1);
+
+    // Initial view: Contents
+    m_doc_browser->setSource (QUrl (
+        "qthelp://org.octave.interpreter-1.0/doc/octave.html/index.html"));
+  }
+
+  documentation::~documentation (void)
+  {
+    if (m_help_engine)
+      delete m_help_engine;
+  }
+
+  void documentation::global_search (void)
+  {
+    QList<QHelpSearchQuery> queries
+      = m_help_engine->searchEngine ()->queryWidget ()->query ();
+    m_help_engine->searchEngine ()->search (queries);
+  }
+
+  void documentation::global_search_started (void)
+  {
+    qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
+  }
+
+  void documentation::global_search_finished (int)
+  {
+    qApp->restoreOverrideCursor();
+  }
+
+  void documentation::notice_settings (const QSettings *) { }
+
+  void documentation::copyClipboard (void) { }
+
+  void documentation::pasteClipboard (void) { }
+
+  void documentation::selectAll (void) { }
+
+  void documentation::load_ref (const QString& ref_name)
+  {
+    if (m_help_engine)
+      {
+        QMap<QString, QUrl> found_links
+          = m_help_engine->linksForIdentifier (ref_name);
+        if (found_links.count() > 0)
+          m_doc_browser->setSource (found_links.constBegin().value());
+      }
+  }
+
+  void documentation::filter_update (const QString& expression)
+  {
+    if (! m_help_engine)
+      return;
+
+    QString wildcard;
+    if (expression.contains(QLatin1Char('*')))
+      wildcard = expression;
+
+    m_help_engine->indexWidget ()->filterIndices(expression, wildcard);
+  }
+
+  void documentation::filter_update_history (void)
+  {
+    QString text = m_filter->currentText ();   // get current text
+    int index = m_filter->findText (text);     // and its actual index
+
+    if (index > -1)
+      m_filter->removeItem (index);            // remove if already existing
+
+    m_filter->insertItem (0, text);            // (re)insert at beginning
+    m_filter->setCurrentIndex (0);
+  }
+
+
+
+  // The documentation browser
+  documentation_browser::documentation_browser (QHelpEngine *he, QWidget *p)
+    : QTextBrowser (p), m_help_engine (he)
+  { }
+
+  documentation_browser::~documentation_browser (void)
+  { }
+
+  void documentation_browser::handle_index_clicked (const QUrl& url,
+                                                    const QString&)
+  {
+    setSource (url);
+  }
+
+  void documentation_browser::notice_settings (const QSettings *)
+  { }
+
+  QVariant documentation_browser::loadResource (int type,
+                                                const QUrl &url)
+    {
+        if (url.scheme () == "qthelp")
+          return QVariant (m_help_engine->fileData(url));
+        else
+          return QTextBrowser::loadResource(type, url);
+    }
+
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/libgui/src/documentation.h	Wed Mar 28 21:46:11 2018 +0200
@@ -0,0 +1,98 @@
+/*
+
+Copyright (C) 2018 Torsten <mttl@maibox.org>
+
+This file is part of Octave.
+
+Octave is free software: you can redistribute it and/or modify it
+under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+Octave is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Octave; see the file COPYING.  If not, see
+<https://www.gnu.org/licenses/>.
+
+*/
+
+#if ! defined (octave_documentation_h)
+#define octave_documentation_h 1
+
+#include <QComboBox>
+#include <QWidget>
+#include <QSettings>
+#include <QSplitter>
+#include <QTextBrowser>
+#include <QtHelp/QHelpEngine>
+
+namespace octave
+{
+  // The documentation browser
+  class documentation_browser : public QTextBrowser
+  {
+    Q_OBJECT
+
+  public:
+
+    documentation_browser (QHelpEngine *help_engine, QWidget *parent = nullptr);
+    ~documentation_browser (void);
+
+    virtual QVariant loadResource (int type, const QUrl &url);
+
+  public slots:
+
+    void handle_index_clicked (const QUrl& url,
+                               const QString& keyword = QString ());
+    void notice_settings (const QSettings *settings);
+
+  private:
+
+    QHelpEngine *m_help_engine;
+
+  };
+
+
+  // The documentaiton main class (splitter)
+  class documentation : public QSplitter
+  {
+    Q_OBJECT
+
+  public:
+
+    documentation (QWidget *parent = nullptr);
+    ~documentation (void);
+
+  public slots:
+
+    void notice_settings (const QSettings *settings);
+
+    void copyClipboard (void);
+    void pasteClipboard (void);
+    void selectAll (void);
+
+    void load_ref (const QString & name);
+
+  private slots:
+
+    void global_search (void);
+    void global_search_started (void);
+    void global_search_finished (int hits);
+    void filter_update (const QString& expression);
+    void filter_update_history (void);
+
+  private:
+
+    QHelpEngine *m_help_engine;
+    documentation_browser *m_doc_browser;
+    QComboBox *m_filter;
+
+  };
+
+}
+
+#endif
--- a/libgui/src/m-editor/file-editor.cc	Wed Mar 28 13:41:48 2018 -0700
+++ b/libgui/src/m-editor/file-editor.cc	Wed Mar 28 21:46:11 2018 +0200
@@ -37,6 +37,7 @@
 #include <QMessageBox>
 #include <QMimeData>
 #include <QProcess>
+#include <QPushButton>
 #include <QStyle>
 #include <QTabBar>
 #include <QTextStream>
@@ -987,15 +988,15 @@
     m_tool_bar->setIconSize (QSize (icon_size,icon_size));
 
     int tab_width_min = settings->value ("editor/notebook_tab_width_min", 160)
-      .toInt ();
+                        .toInt ();
     int tab_width_max = settings->value ("editor/notebook_tab_width_max", 300)
-      .toInt ();
+                        .toInt ();
 
     if (settings->value ("editor/longWindowTitle", false).toBool ())
       {
         QString style_sheet = QString ("QTabBar::tab "
                                        "{min-width: %1px; max-width: %2px;}")
-          .arg (tab_width_min).arg (tab_width_max);
+                              .arg (tab_width_min).arg (tab_width_max);
         m_tab_widget->setElideMode (Qt::ElideLeft);
         m_tab_widget->setStyleSheet (style_sheet);
       }
@@ -1516,7 +1517,7 @@
     QSettings *settings = resource_manager::get_settings ();
     m_mru_files = settings->value ("editor/mru_file_list").toStringList ();
     m_mru_files_encodings = settings->value ("editor/mru_file_encodings")
-      .toStringList ();
+                            .toStringList ();
 
     if (m_mru_files_encodings.count () != m_mru_files.count ())
       {
--- a/libgui/src/main-window.cc	Wed Mar 28 13:41:48 2018 -0700
+++ b/libgui/src/main-window.cc	Wed Mar 28 21:46:11 2018 +0200
@@ -40,6 +40,7 @@
 #include <QFileDialog>
 #include <QMessageBox>
 #include <QIcon>
+#include <QTextBrowser>
 #include <QTextStream>
 #include <QThread>
 #include <QDateTime>
@@ -211,9 +212,6 @@
     connect (m_interpreter, SIGNAL (octave_ready_signal (void)),
              this, SLOT (handle_octave_ready (void)));
 
-    connect (m_interpreter, SIGNAL (octave_ready_signal (void)),
-             m_doc_browser_window, SLOT (load_info_file (void)));
-
     connect (m_interpreter, SIGNAL (octave_finished_signal (int)),
              this, SLOT (handle_octave_finished (int)));
 
@@ -662,14 +660,14 @@
     }
 
     widget_icon_data[] =
-      {
-        // array of possible icon sets (name, path (complete for NONE))
-        // the first entry here is the default!
-        {"NONE",    ":/actions/icons/logo.png"},
-        {"GRAPHIC", ":/actions/icons/graphic_logo_"},
-        {"LETTER",  ":/actions/icons/letter_logo_"},
-        {"", ""} // end marker has empty name
-      };
+    {
+      // array of possible icon sets (name, path (complete for NONE))
+      // the first entry here is the default!
+      {"NONE",    ":/actions/icons/logo.png"},
+      {"GRAPHIC", ":/actions/icons/graphic_logo_"},
+      {"LETTER",  ":/actions/icons/letter_logo_"},
+      {"", ""} // end marker has empty name
+    };
 
     int count = 0;
     int icon_set_found = 0; // default
@@ -691,7 +689,8 @@
       {
         QString name = widget->objectName ();
         if (! name.isEmpty ())
-          { // if children has a name
+          {
+            // if children has a name
             icon = widget_icon_data[icon_set_found].path; // prefix | octave-logo
             if (widget_icon_data[icon_set_found].name != "NONE")
               icon += name + ".png"; // add widget name and ext.
@@ -700,7 +699,7 @@
       }
     if (widget_icon_data[icon_set_found].name != "NONE")
       m_release_notes_icon = widget_icon_data[icon_set_found].path
-        + "ReleaseWidget.png";
+                             + "ReleaseWidget.png";
     else
       m_release_notes_icon = ":/actions/icons/logo.png";
 
@@ -2571,7 +2570,8 @@
     // file menu
     shortcut_manager::set_shortcut (m_open_action, "main_file:open_file");
     shortcut_manager::set_shortcut (m_new_script_action, "main_file:new_file");
-    shortcut_manager::set_shortcut (m_new_function_action, "main_file:new_function");
+    shortcut_manager::set_shortcut (m_new_function_action,
+                                    "main_file:new_function");
     shortcut_manager::set_shortcut (m_new_function_action, "main_file:new_figure");
     shortcut_manager::set_shortcut (m_load_workspace_action,
                                     "main_file:load_workspace");
@@ -2611,7 +2611,8 @@
                                     "main_window:show_workspace");
     shortcut_manager::set_shortcut (m_show_file_browser_action,
                                     "main_window:show_file_browser");
-    shortcut_manager::set_shortcut (m_show_editor_action, "main_window:show_editor");
+    shortcut_manager::set_shortcut (m_show_editor_action,
+                                    "main_window:show_editor");
     shortcut_manager::set_shortcut (m_show_documentation_action,
                                     "main_window:show_doc");
     shortcut_manager::set_shortcut (m_show_variable_editor_action,
@@ -2623,7 +2624,8 @@
                                     "main_window:file_browser");
     shortcut_manager::set_shortcut (m_editor_action, "main_window:editor");
     shortcut_manager::set_shortcut (m_documentation_action, "main_window:doc");
-    shortcut_manager::set_shortcut (m_variable_editor_action, "main_window:variable_editor");
+    shortcut_manager::set_shortcut (m_variable_editor_action,
+                                    "main_window:variable_editor");
     shortcut_manager::set_shortcut (m_reset_windows_action, "main_window:reset");
 
     // help menu
--- a/libgui/src/module.mk	Wed Mar 28 13:41:48 2018 -0700
+++ b/libgui/src/module.mk	Wed Mar 28 21:46:11 2018 +0200
@@ -106,6 +106,7 @@
   %reldir%/moc-external-editor-interface.cc \
   %reldir%/moc-dialog.cc \
   %reldir%/moc-documentation-dock-widget.cc \
+  %reldir%/moc-documentation.cc \
   %reldir%/moc-files-dock-widget.cc \
   %reldir%/moc-history-dock-widget.cc \
   %reldir%/moc-main-window.cc \
@@ -152,6 +153,7 @@
   %reldir%/dialog.h \
   %reldir%/octave-dock-widget.h \
   %reldir%/documentation-dock-widget.h \
+  %reldir%/documentation.h \
   %reldir%/external-editor-interface.h \
   %reldir%/files-dock-widget.h \
   %reldir%/history-dock-widget.h \
@@ -187,6 +189,7 @@
 %canon_reldir%_%canon_reldir%_la_SOURCES = \
   %reldir%/dialog.cc \
   %reldir%/documentation-dock-widget.cc \
+  %reldir%/documentation.cc \
   %reldir%/external-editor-interface.cc \
   %reldir%/files-dock-widget.cc \
   %reldir%/history-dock-widget.cc \
--- a/m4/acinclude.m4	Wed Mar 28 13:41:48 2018 -0700
+++ b/m4/acinclude.m4	Wed Mar 28 21:46:11 2018 +0200
@@ -1835,10 +1835,10 @@
   ## Check for Qt libraries
   case "$qt_version" in
     4)
-      QT_MODULES="QtCore QtGui QtNetwork QtOpenGL"
+      QT_MODULES="QtCore QtGui QtNetwork QtOpenGL QtHelp"
     ;;
     5)
-      QT_MODULES="Qt5Core Qt5Gui Qt5Network Qt5OpenGL Qt5PrintSupport"
+      QT_MODULES="Qt5Core Qt5Gui Qt5Network Qt5OpenGL Qt5PrintSupport Qt5Help"
     ;;
     *)
       AC_MSG_ERROR([Unrecognized Qt version $qt_version])