Developer Documentation
helpWidget.cc
1 /*===========================================================================*\
2 * *
3 * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39 * *
40 \*===========================================================================*/
41 
42 
43 #include "helpWidget.hh"
44 
46 
47 //#define DEBUG_HELP_CONTENTS
48 
49 HelpWidget::HelpWidget(QWidget* parent, const QString& _homeSite /*=""*/, const bool _loadHomeSite /*= true*/)
50  : QMainWindow(parent),
51  searchWidget_(0),
52  tabWidget_(0),
53  textWindow_(0),
54  helpEngine_(0),
55  searchEngine_(0) {
56 
57  setupUi(this);
58 
59  homeSite_ = _homeSite;
60 
61  QString filename = QString( OpenFlipper::Options::configDirStr() );
62  filename += OpenFlipper::Options::dirSeparator();
63  filename += "Help.qhc";
64 
65  QDir helpDir = QDir(OpenFlipper::Options::helpDirStr());
66 
67  QString iconPath = QString(OpenFlipper::Options::iconDirStr())+QString(OpenFlipper::Options::dirSeparator());
68 
69  // Set Buttons
70  backButton_->setIcon(QIcon(iconPath+"arrow-left.png"));
71  forwardButton_->setIcon(QIcon(iconPath+"arrow-right.png"));
72  homeButton_->setIcon(QIcon(iconPath+"go-home.png"));
73  searchButton_->setIcon(QIcon(iconPath+"edit-find.png"));
74 
75  tabWidget_ = new QTabWidget(this);
76 
77  // Generate the help engine. The filename is in the users home directory and
78  // contains all registered help resources.
79  helpEngine_ = new QHelpEngine(filename, this);
80 
81  helpEngine_->setupData();
82 
83  // Get all currently registered nameSpaces
84  QStringList registeredNamespaces =helpEngine_->registeredDocumentations();
85 
86  QStringList documentationFiles;
87 
88  // Get a list of all loaded documentation files from the namespaces
89  QStringList helpFiles = helpDir.entryList(QStringList("*.qch"),QDir::Files);
90 
91  // Write absolute path into filenames
92  for (QStringList::iterator iter = helpFiles.begin(); iter != helpFiles.end(); ++iter)
93  *iter = helpDir.path()+ OpenFlipper::Options::dirSeparator() + *iter;
94 
95  for ( int i = 0; i < registeredNamespaces.size() ; ++i)
96  {
97  QString registredFilename (helpEngine_->documentationFileName(registeredNamespaces[i]));
98 
99  // re-register documentation if location changed
100  if (helpFiles.indexOf(registredFilename) != -1)
101  documentationFiles.push_back( registredFilename );
102  else
103  helpEngine_->unregisterDocumentation(registeredNamespaces[i]);
104  }
105 
106  for ( int i = 0 ; i < helpFiles.size() ; ++i ) {
107  const QString filename = helpFiles[i];
108 
109  // Don't register files twice (stored between multiple OpenFlipper executions)
110  if (documentationFiles.contains(filename))
111  continue;
112 
113  // Try to register the file
114  if ( !helpEngine_->registerDocumentation( filename ) ) {
115  std::cerr << "Error when trying to register file " << filename.toStdString() << std::endl;
116  std::cerr << helpFiles[i].toStdString() << " :" << helpEngine_->error().toStdString() << std::endl;
117  }
118 
119  }
120 
121  searchEngine_ = new QHelpSearchEngine(helpEngine_, this);
122 
123  textWindow_ = new HelpBrowser(helpEngine_, this);
124 
125  homeIndex_ = tabWidget_->addTab(textWindow_, tr("Home"));
126 
127  gridLayout_->addWidget(helpEngine_->contentWidget(), 1, 0);
128  gridLayout_->addWidget(tabWidget_, 1, 1);
129 
130  gridLayout_->setColumnStretch(0, 1);
131  gridLayout_->setColumnStretch(1, 3);
132 
133  // Search popup at bottom of window
134  searchWidget_ = new QDockWidget(tr("Search results"), this);
135  searchWidget_->setFeatures( QDockWidget::DockWidgetClosable );
136 
137  searchWidget_->resize(this->size().width(), floor( double(this->size().height() / 3)) );
138 
139  searchWidget_->setWidget(searchEngine_->queryWidget());
140  //searchWidget_->setWidget(results_);
141 
142  searchWidget_->hide();
143  addDockWidget(Qt::BottomDockWidgetArea, searchWidget_);
144 
145 
146  // Entry in tree view has been clicked
147  connect(helpEngine_->contentWidget(), SIGNAL(linkActivated(const QUrl&)),
148  this, SLOT(linkActivated(const QUrl&)));
149 
150  // Search button
151  connect(searchButton_, SIGNAL(clicked()), this, SLOT(showSearchWidget()));
152 
153  // Search button
154  connect(searchEngine_->queryWidget(), SIGNAL(search()), this, SLOT(startSearch()));
155 
156  // Show results if search is finished
157  connect(searchEngine_, SIGNAL(searchingFinished(int)), this, SLOT(showResults(int)));
158 
159  // Show results if search is finished
160  connect(searchEngine_->resultWidget(), SIGNAL(requestShowLink(const QUrl&)),
161  this, SLOT(showFoundSite(const QUrl&)));
162 
163  // Back button
164  connect(backButton_, SIGNAL(clicked()), this, SLOT(goBack()));
165 
166  // Forward button
167  connect(forwardButton_, SIGNAL(clicked()), this, SLOT(goForward()));
168 
169  // Forward button
170  connect(homeButton_, SIGNAL(clicked()), this, SLOT(goHome()));
171 
172  // Source has been reloaded, so the buttons need an update and the modelview
173  connect(textWindow_, SIGNAL(sourceChanged(const QUrl&)), this, SLOT(update(const QUrl&)));
174 
175  // the history has changed, so the buttons need an update
176  connect(textWindow_, SIGNAL(historyChanged(const QUrl&)), this, SLOT(updateButtons()));
177 
178  // Register documentation
179  // Seems to be an unneeded call!
180  //helpEngine_->registerDocumentation(filename);
181 
182  QStringList tmp = helpEngine_->registeredDocumentations ();
183 
184  #ifdef DEBUG_HELP_CONTENTS
185  for ( int i = 0 ; i < tmp.size(); ++i) {
186  std::cerr << "=========================================================================================" << std::endl;
187  std::cerr << "Registered namespace: " << tmp[i].toStdString() << std::endl;
188  std::cerr << "From file : " << helpEngine_->documentationFileName(tmp[i]).toStdString() << std::endl;
189 
190 
191  QList<QStringList> filterAttribs = helpEngine_->filterAttributeSets (tmp[i]);
192 // std::cerr << "Filter attributes:" << std::endl;
193 // for ( int j = 0 ; j < filterAttribs.size(); ++j) {
194 // for ( int k = 0 ; k < filterAttribs[j].size(); ++k) {
195 // std::cerr << filterAttribs[j][k].toStdString() << std::endl;
196 // }
197 // }
198 
199  // Print a list of all files included in this help file
200  if ( !filterAttribs.empty() ) {
201  QList<QUrl> list = helpEngine_->files ( tmp[i], filterAttribs[0]);
202  for ( int j = 0 ; j < list.size(); ++j) {
203  std::cerr << list[j].toString().toStdString() << std::endl;
204  }
205  } else {
206  std::cerr << "Error, empty filter! Unable to get list of included files." << std::endl;
207  }
208 
209 
210  }
211  #endif
212 
213  if (_loadHomeSite)
214  {
215  // Load main page
216  textWindow_->open(QUrl(homeSite_));
217  }
218 }
219 
220 void HelpWidget::activateLink(const QUrl& _url)
221 {
222  //open and show the url
223  linkActivated(_url);
224 }
225 
226 void HelpWidget::linkActivated(const QUrl& _url) {
227 
228  textWindow_->open(_url);
229  tabWidget_->setCurrentIndex(homeIndex_);
230 }
231 
232 void HelpWidget::startSearch() {
233 
234  searchEngine_->search(searchEngine_->queryWidget()->query());
235 }
236 
237 void HelpWidget::setHomeSite(const QString& _homeSite) {
238 
239  homeSite_ = _homeSite;
240 }
241 
242 void HelpWidget::showFoundSite(const QUrl& _url) {
243 
244  textWindow_->open(_url);
245  tabWidget_->setCurrentIndex(homeIndex_);
246 }
247 
248 void HelpWidget::update(const QUrl& _url ) {
249 
250  updateButtons();
251 
252  //search for the entry and select the item in the contentWidget
253  //in our case, it is the treeView on the left side
254  QUrl newUrl = textWindow_->resolveUrl(_url);
255  //search for the selected url
256  QModelIndex modelIndex = helpEngine_->contentWidget()->indexOf(newUrl);
257 
258  //select this url in content widget
259  if (modelIndex.isValid())
260  helpEngine_->contentWidget()->setCurrentIndex( modelIndex );
261 }
262 
263 void HelpWidget::goForward() {
264 
265  textWindow_->forward();
266 
267  tabWidget_->setCurrentIndex(homeIndex_);
268 
269  updateButtons();
270 }
271 
272 void HelpWidget::goBack() {
273 
274  textWindow_->backward();
275 
276  tabWidget_->setCurrentIndex(homeIndex_);
277 
278  updateButtons();
279 }
280 
281 void HelpWidget::goHome() {
282 
283  textWindow_->open(homeSite_);
284 
285  tabWidget_->setCurrentIndex(homeIndex_);
286 
287  updateButtons();
288 }
289 
290 void HelpWidget::updateButtons() {
291 
292  if(!textWindow_->isBackwardAvailable()) {
293  backButton_->setEnabled(false);
294  } else {
295  backButton_->setEnabled(true);
296  }
297 
298  if(!textWindow_->isForwardAvailable()) {
299  forwardButton_->setEnabled(false);
300  } else {
301  forwardButton_->setEnabled(true);
302  }
303 }
304 
305 void HelpWidget::showSearchWidget() {
306 
307  searchWidget_->show();
308 }
309 
310 void HelpWidget::showResults(int /*_hits*/) {
311 
312  searchWidget_->hide();
313 
314  int resultsTabIndex_ = tabWidget_->addTab(searchEngine_->resultWidget(), tr("Results") );
315  tabWidget_->setCurrentIndex(resultsTabIndex_);
316 }
317 
318 void HelpWidget::openFoundSite(QListWidgetItem* /*_item*/) {
319 
320 }
321 
322 HelpWidget::~HelpWidget() {
323 
324  delete searchWidget_;
325  delete textWindow_;
326 }
HelpBrowser(QHelpEngine *_helpEngine, QWidget *parent=0)
Constructor.
Definition: helpBrowser.cc:46
QHelpEngine * helpEngine_
The help engine the widget is working on.
Definition: helpBrowser.hh:162