GNU Octave  4.4.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
documentation.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2018 Torsten <mttl@maibox.org>
4 
5 This file is part of Octave.
6 
7 Octave is free software: you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <https://www.gnu.org/licenses/>.
20 
21 */
22 
23 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 #include "defaults.h"
28 #include "file-ops.h"
29 #include "oct-env.h"
30 
31 #include <QApplication>
32 #include <QCompleter>
33 #include <QDir>
34 #include <QFile>
35 #include <QFileInfo>
36 #include <QHelpContentWidget>
37 #include <QHelpIndexWidget>
38 #include <QHelpSearchEngine>
39 #include <QHelpSearchQueryWidget>
40 #include <QHelpSearchResultWidget>
41 #include <QLabel>
42 #include <QLineEdit>
43 #include <QMessageBox>
44 #include <QShortcut>
45 #include <QTabWidget>
46 #include <QToolButton>
47 #include <QVBoxLayout>
48 
49 #include "documentation.h"
50 #include "resource-manager.h"
51 
52 namespace octave
53 {
54  // The documentation splitter, which is the main widget
55  // of the doc dock widget
57  : QSplitter (Qt::Horizontal, p)
58  {
59  // Get original collection
60  QString collection = getenv ("OCTAVE_QTHELP_COLLECTION");
61  if (collection.isEmpty ())
64  + "octave_interpreter.qhc");
65 
66  // Setup the help engine with the original collection, use a writable copy
67  // of the original collection and load the help data
68  m_help_engine = new QHelpEngine (collection, this);
69 
70  QString tmpdir = QDir::tempPath();
72  = QString::fromStdString (octave::sys::tempnam (tmpdir.toStdString (),
73  "oct-qhelp-"));
74 
75  if (m_help_engine->copyCollectionFile (m_collection))
76  m_help_engine->setCollectionFile (m_collection);
77  else
78  QMessageBox::warning (this, tr ("Octave Documentation"),
79  tr ("Could not copy help collection to temporary\n"
80  "file. Search capabilities may be affected.\n"
81  "%1").arg (m_help_engine->error ()));
82 
83  connect(m_help_engine, SIGNAL(setupFinished()),
84  m_help_engine->searchEngine(), SLOT(indexDocumentation()));
85 
86  if (! m_help_engine->setupData())
87  {
88  QMessageBox::warning (this, tr ("Octave Documentation"),
89  tr ("Could not setup the data required for the\n"
90  "documentation viewer. Only help texts in\n"
91  "the Console Widget will be available."));
92  if (m_help_engine)
93  delete m_help_engine;
94  m_help_engine = 0;
95  return;
96  }
97 
98  // The browser
99  QWidget *browser_find = new QWidget (this);
100  m_doc_browser = new documentation_browser (m_help_engine, browser_find);
101  connect (m_doc_browser, SIGNAL (cursorPositionChanged (void)),
102  this, SLOT(handle_cursor_position_change (void)));
103 
104  QWidget *find_footer = new QWidget (browser_find);
105  QLabel *find_label = new QLabel (tr ("Find:"), find_footer);
106  m_find_line_edit = new QLineEdit (find_footer);
107  connect (m_find_line_edit, SIGNAL (returnPressed (void)),
108  this, SLOT(find_forward (void)));
109  connect (m_find_line_edit, SIGNAL (textEdited (const QString&)),
110  this, SLOT(find_forward_from_anchor (const QString&)));
111  QToolButton *forward_button = new QToolButton (find_footer);
112  forward_button->setText (tr ("Search forward"));
113  forward_button->setToolTip (tr ("Search forward"));
114  forward_button->setIcon (resource_manager::icon ("go-down"));
115  connect (forward_button, SIGNAL (pressed (void)),
116  this, SLOT(find_forward (void)));
117  QToolButton *backward_button = new QToolButton (find_footer);
118  backward_button->setText (tr ("Search backward"));
119  backward_button->setToolTip (tr ("Search backward"));
120  backward_button->setIcon (resource_manager::icon ("go-up"));
121  connect (backward_button, SIGNAL (pressed (void)),
122  this, SLOT(find_backward (void)));
123  QHBoxLayout *h_box_find_footer = new QHBoxLayout (find_footer);
124  h_box_find_footer->addWidget (find_label);
125  h_box_find_footer->addWidget (m_find_line_edit);
126  h_box_find_footer->addWidget (forward_button);
127  h_box_find_footer->addWidget (backward_button);
128  h_box_find_footer->setMargin (2);
129  find_footer->setLayout (h_box_find_footer);
130 
131  QVBoxLayout *v_box_browser_find = new QVBoxLayout (browser_find);
132  v_box_browser_find->addWidget (m_doc_browser);
133  v_box_browser_find->addWidget (find_footer);
134  browser_find->setLayout (v_box_browser_find);
135 
136  QShortcut *show_shortcut = new QShortcut (QKeySequence (QKeySequence::Find), p);
137  show_shortcut->setContext (Qt::WidgetWithChildrenShortcut);
138  connect (show_shortcut, SIGNAL (activated (void)),
139  m_find_line_edit->parentWidget (), SLOT (show (void)));
140  connect (show_shortcut, SIGNAL (activated (void)),
141  m_find_line_edit, SLOT (selectAll (void)));
142  connect (show_shortcut, SIGNAL (activated (void)),
143  m_find_line_edit, SLOT (setFocus (void)));
144  QShortcut *hide_shortcut = new QShortcut (Qt::Key_Escape, p);
145  hide_shortcut->setContext (Qt::WidgetWithChildrenShortcut);
146  connect (hide_shortcut, SIGNAL (activated (void)),
147  m_find_line_edit->parentWidget (), SLOT(hide (void)));
148  connect (hide_shortcut, SIGNAL (activated (void)),
149  m_doc_browser, SLOT (setFocus (void)));
150  QShortcut *findnext_shortcut = new QShortcut (QKeySequence (QKeySequence::FindNext), p);
151  findnext_shortcut->setContext (Qt::WidgetWithChildrenShortcut);
152  connect (findnext_shortcut, SIGNAL (activated (void)),
153  this, SLOT(find_forward (void)));
154  QShortcut *findprev_shortcut = new QShortcut (QKeySequence (QKeySequence::FindPrevious), p);
155  findprev_shortcut->setContext (Qt::WidgetWithChildrenShortcut);
156  connect (findprev_shortcut, SIGNAL (activated (void)),
157  this, SLOT(find_backward (void)));
158  find_footer->hide ();
160 
161  // Layout contents, index and search
162  QTabWidget *navi = new QTabWidget (this);
163  navi->setTabsClosable (false);
164  navi->setMovable (true);
165 
166  // Contents
167  QHelpContentWidget *content = m_help_engine->contentWidget ();
168  navi->addTab (content, tr ("Contents"));
169 
170  connect(m_help_engine->contentWidget (),
171  SIGNAL (linkActivated (const QUrl&)),
172  m_doc_browser, SLOT(handle_index_clicked (const QUrl&)));
173 
174  // Index
175  QHelpIndexWidget *index = m_help_engine->indexWidget ();
176 
177  m_filter = new QComboBox (this);
178  m_filter->setToolTip (tr ("Enter text to search the indices"));
179  m_filter->setEditable (true);
180  m_filter->setInsertPolicy (QComboBox::NoInsert);
181  m_filter->setMaxCount (10);
182  m_filter->setMaxVisibleItems (10);
183  m_filter->setSizeAdjustPolicy (
184  QComboBox::AdjustToMinimumContentsLengthWithIcon);
185  QSizePolicy sizePol (QSizePolicy::Expanding, QSizePolicy::Preferred);
186  m_filter->setSizePolicy (sizePol);
187  m_filter->completer ()->setCaseSensitivity (Qt::CaseSensitive);
188  QLabel *filter_label = new QLabel (tr ("Search"));
189 
190  QWidget *filter_all = new QWidget (navi);
191  QHBoxLayout *h_box_index = new QHBoxLayout (filter_all);
192  h_box_index->addWidget (filter_label);
193  h_box_index->addWidget (m_filter);
194  h_box_index->setMargin (2);
195  filter_all->setLayout (h_box_index);
196 
197  QWidget *index_all = new QWidget (navi);
198  QVBoxLayout *v_box_index = new QVBoxLayout (index_all);
199  v_box_index->addWidget (filter_all);
200  v_box_index->addWidget (index);
201  index_all->setLayout (v_box_index);
202 
203  navi->addTab (index_all, tr ("Index"));
204 
205  connect(m_help_engine->indexWidget (),
206  SIGNAL (linkActivated (const QUrl&, const QString&)),
207  m_doc_browser, SLOT(handle_index_clicked (const QUrl&,
208  const QString&)));
209 
210  connect (m_filter, SIGNAL (editTextChanged (const QString&)),
211  this, SLOT(filter_update (const QString&)));
212 
213  connect (m_filter->lineEdit (), SIGNAL (editingFinished (void)),
214  this, SLOT(filter_update_history (void)));
215 
216  // Search
217  QHelpSearchEngine *search_engine = m_help_engine->searchEngine ();
218  QHelpSearchQueryWidget *search = search_engine->queryWidget ();
219  QHelpSearchResultWidget *result = search_engine->resultWidget ();
220  QWidget *search_all = new QWidget (navi);
221  QVBoxLayout *v_box_search = new QVBoxLayout (search_all);
222  v_box_search->addWidget (search);
223  v_box_search->addWidget (result);
224  search_all->setLayout (v_box_search);
225  navi->addTab (search_all, tr ("Search"));
226 
227  connect (search, SIGNAL (search (void)),
228  this, SLOT(global_search (void)));
229 
230  connect (search_engine, SIGNAL (searchingStarted (void)),
231  this, SLOT(global_search_started (void)));
232  connect (search_engine, SIGNAL (searchingFinished (int)),
233  this, SLOT(global_search_finished (int)));
234 
235  connect (search_engine->resultWidget (),
236  SIGNAL (requestShowLink (const QUrl&)),
238  SLOT(handle_index_clicked (const QUrl&)));
239 
240  // Fill the splitter
241  insertWidget (0, navi);
242  insertWidget (1, browser_find);
243  setStretchFactor (1, 1);
244 
245  // Initial view: Contents
246  m_doc_browser->setSource (QUrl (
247  "qthelp://org.octave.interpreter-1.0/doc/octave.html/index.html"));
248  }
249 
251  {
252  if (m_help_engine)
253  delete m_help_engine;
254 
255  // Cleanup temporary file and directory
256  QFile file (m_collection);
257  if (file.exists ())
258  {
259  QFileInfo finfo (file);
260  QString bname = finfo.fileName ();
261  QDir dir = finfo.absoluteDir ();
262  dir.setFilter (QDir::Dirs | QDir::NoDotAndDotDot | QDir::Hidden);
263  QStringList namefilter;
264  namefilter.append ("*" + bname + "*");
265  foreach (QFileInfo fi, dir.entryInfoList (namefilter))
266  {
267  std::string file_name = fi.absoluteFilePath ().toStdString ();
268  sys::recursive_rmdir (file_name);
269  }
270 
271  file.remove();
272  }
273  }
274 
276  {
277 #if defined (HAVE_QHELPSEARCHQUERYWIDGET_SEARCHINPUT)
278  QString queries
279  = m_help_engine->searchEngine ()->queryWidget ()->searchInput ();
280 #else
282  = m_help_engine->searchEngine ()->queryWidget ()->query ();
283 #endif
284 
285  m_help_engine->searchEngine ()->search (queries);
286  }
287 
289  {
290  qApp->setOverrideCursor(QCursor(Qt::WaitCursor));
291  }
292 
294  {
295  qApp->restoreOverrideCursor();
296  }
297 
298  void documentation::notice_settings (const QSettings *) { }
299 
301 
303 
304  void documentation::selectAll (void) { }
305 
306  void documentation::load_ref (const QString& ref_name)
307  {
308  if (m_help_engine)
309  {
310  QMap<QString, QUrl> found_links
311  = m_help_engine->linksForIdentifier (ref_name);
312  if (found_links.count() > 0)
313  m_doc_browser->setSource (found_links.constBegin().value());
314  }
315  }
316 
317  void documentation::filter_update (const QString& expression)
318  {
319  if (! m_help_engine)
320  return;
321 
322  QString wildcard;
323  if (expression.contains (QLatin1Char('*')))
324  wildcard = expression;
325 
326  m_help_engine->indexWidget ()->filterIndices(expression, wildcard);
327  }
328 
330  {
331  QString text = m_filter->currentText (); // get current text
332  int index = m_filter->findText (text); // and its actual index
333 
334  if (index > -1)
335  m_filter->removeItem (index); // remove if already existing
336 
337  m_filter->insertItem (0, text); // (re)insert at beginning
338  m_filter->setCurrentIndex (0);
339  }
340 
342  {
343  if (! m_help_engine)
344  return;
345 
346  m_doc_browser->find (m_find_line_edit->text ());
348  }
349 
351  {
352  if (! m_help_engine)
353  return;
354 
355  m_doc_browser->find (m_find_line_edit->text (), QTextDocument::FindBackward);
357  }
358 
360  {
361  if (! m_help_engine)
362  return;
363 
364  QTextCursor textcur = m_doc_browser->textCursor ();
365  textcur.setPosition (m_search_anchor_position);
366  m_doc_browser->setTextCursor (textcur);
367  m_doc_browser->find (text);
368  }
369 
371  {
372  if (! m_help_engine)
373  return;
374 
375  m_search_anchor_position = m_doc_browser->textCursor ().position ();
376  }
377 
379  {
380  if (! m_help_engine)
381  return;
382 
383  if (m_doc_browser->hasFocus ())
385  }
386 
387  void documentation::registerDoc (const QString& qch)
388  {
389  if (m_help_engine)
390  {
391  QString ns = m_help_engine->namespaceName (qch);
392  bool do_setup = true;
393  if (m_help_engine->registeredDocumentations ().contains (ns))
394  {
395  if (m_help_engine->documentationFileName (ns) == qch)
396  do_setup = false;
397  else
398  {
399  m_help_engine->unregisterDocumentation (ns);
400  m_help_engine->registerDocumentation (qch);
401  }
402  }
403  else if (! m_help_engine->registerDocumentation (qch))
404  {
405  QMessageBox::warning (this, tr ("Octave Documentation"),
406  tr ("Unable to register help file %1.").
407  arg (qch));
408  do_setup = false;
409  return;
410  }
411 
412  if (do_setup)
413  m_help_engine->setupData();
414  }
415  }
416 
417  void documentation::unregisterDoc (const QString& qch)
418  {
419  QString ns = m_help_engine->namespaceName (qch);
420  if (m_help_engine
421  && m_help_engine->registeredDocumentations ().contains (ns)
422  && m_help_engine->documentationFileName (ns) == qch)
423  {
424  m_help_engine->unregisterDocumentation (ns);
425  m_help_engine->setupData ();
426  }
427  }
428 
429 
430  // The documentation browser
432  : QTextBrowser (p), m_help_engine (he)
433  { }
434 
436  { }
437 
439  const QString&)
440  {
441  setSource (url);
442  }
443 
444  void documentation_browser::notice_settings (const QSettings *)
445  { }
446 
447  QVariant documentation_browser::loadResource (int type, const QUrl &url)
448  {
449  if (url.scheme () == "qthelp")
450  return QVariant (m_help_engine->fileData(url));
451  else
452  return QTextBrowser::loadResource(type, url);
453  }
454 
455 }
QHelpEngine * m_help_engine
Definition: documentation.h:97
std::string oct_doc_dir(void)
Definition: defaults.cc:297
For example cd octave end example noindent changes the current working directory to file
Definition: dirfns.cc:124
void filter_update_history(void)
void find_forward_from_anchor(const QString &text)
void handle_index_clicked(const QUrl &url, const QString &keyword=QString())
std::string tempnam(const std::string &dir, const std::string &pfx)
Definition: file-ops.cc:638
QString fromStdString(const std::string &s)
static double fi[256]
Definition: randmtzig.cc:435
void notice_settings(const QSettings *settings)
void registerDoc(const QString &name)
octave_value arg
Definition: pr-output.cc:3244
std::string dir_sep_str(void)
Definition: file-ops.cc:233
int recursive_rmdir(const std::string &name)
Definition: file-ops.cc:540
void filter_update(const QString &expression)
void unregisterDoc(const QString &name)
virtual QVariant loadResource(int type, const QUrl &url)
void record_anchor_position(void)
void handle_cursor_position_change(void)
void load_ref(const QString &name)
void notice_settings(const QSettings *settings)
idx type
Definition: ov.cc:3114
static std::list< std::string > search(const std::string &path, const std::string &original_name, bool all)
Definition: kpse.cc:395
documentation_browser * m_doc_browser
Definition: documentation.h:98
With real return the complex result
Definition: data.cc:3260
std::string url
Definition: urlwrite.cc:118
void warning(const char *fmt,...)
Definition: error.cc:801
documentation(QWidget *parent=nullptr)
static QIcon icon(const QString &icon_name, bool fallback=true)
documentation_browser(QHelpEngine *help_engine, QWidget *parent=nullptr)
p
Definition: lu.cc:138
QLineEdit * m_find_line_edit
Definition: documentation.h:99
void global_search_started(void)
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:888
void global_search_finished(int hits)