5 #include "inputstring.h"
7 #include "inputstring.h"
8 #include "inputstrlist.h"
11 #include "configdoc.h"
14 #define SA(x) QString::fromAscii(x)
16 static QString convertToComment(const QString &s)
25 s.trimmed().replace(SA("\n"),SA("\n# ")).replace(SA("# \n"), SA("#\n"))+
30 void Expert::setHeader(const char *header)
32 m_header = SA(header);
35 void Expert::add(const char *name,const char *docs)
37 Input *opt = m_options[SA(name)];
40 opt->setTemplateDocs(SA(docs));
44 //------------------------------------------------------------------------------------
48 m_treeWidget = new QTreeWidget;
49 m_treeWidget->setColumnCount(1);
50 m_topicStack = new QStackedWidget;
53 QFile file(SA(":/config.xml"));
56 QDomDocument configXml;
57 if (file.open(QIODevice::ReadOnly))
59 if (!configXml.setContent(&file,false,&err,&errLine,&errCol))
61 QString msg = tr("Error parsing internal config.xml at line %1 column %2.\n%3").
62 arg(errLine).arg(errCol).arg(err);
63 QMessageBox::warning(this, tr("Error"), msg);
67 m_rootElement = configXml.documentElement();
69 createTopics(m_rootElement);
70 m_helper = new QTextBrowser;
71 m_helper->setReadOnly(true);
72 m_helper->setOpenExternalLinks(TRUE);
73 m_splitter = new QSplitter(Qt::Vertical);
74 m_splitter->addWidget(m_treeWidget);
75 m_splitter->addWidget(m_helper);
77 QWidget *rightSide = new QWidget;
78 QGridLayout *grid = new QGridLayout(rightSide);
79 m_prev = new QPushButton(tr("Previous"));
80 m_prev->setEnabled(false);
81 m_next = new QPushButton(tr("Next"));
82 grid->addWidget(m_topicStack,0,0,1,2);
83 grid->addWidget(m_prev,1,0,Qt::AlignLeft);
84 grid->addWidget(m_next,1,1,Qt::AlignRight);
85 grid->setColumnStretch(0,1);
86 grid->setRowStretch(0,1);
88 addWidget(m_splitter);
90 connect(m_next,SIGNAL(clicked()),SLOT(nextTopic()));
92 connect(m_prev,SIGNAL(clicked()),SLOT(prevTopic()));
99 QHashIterator<QString,Input*> i(m_options);
107 void Expert::createTopics(const QDomElement &rootElem)
109 QList<QTreeWidgetItem*> items;
110 QDomElement childElem = rootElem.firstChildElement();
111 while (!childElem.isNull())
113 if (childElem.tagName()==SA("group"))
115 // Remove _ from a group name like: Source_Browser
116 QString name = childElem.attribute(SA("name")).replace(SA("_"),SA(" "));
117 items.append(new QTreeWidgetItem((QTreeWidget*)0,QStringList(name)));
118 QWidget *widget = createTopicWidget(childElem);
119 m_topics[name] = widget;
120 m_topicStack->addWidget(widget);
122 childElem = childElem.nextSiblingElement();
124 m_treeWidget->setHeaderLabels(QStringList() << SA("Topics"));
125 m_treeWidget->insertTopLevelItems(0,items);
126 connect(m_treeWidget,
127 SIGNAL(currentItemChanged(QTreeWidgetItem *,QTreeWidgetItem *)),
129 SLOT(activateTopic(QTreeWidgetItem *,QTreeWidgetItem *)));
132 static QString getDocsForNode(const QDomElement &child)
134 QString type = child.attribute(SA("type"));
135 QString docs = SA("");
136 // read documentation text
137 QDomElement docsVal = child.firstChildElement();
138 while (!docsVal.isNull())
140 if (docsVal.tagName()==SA("docs") &&
141 docsVal.attribute(SA("doxywizard")) != SA("0"))
143 for (QDomNode n = docsVal.firstChild(); !n.isNull(); n = n.nextSibling())
145 QDomText t = n.toText();
146 if (!t.isNull()) docs+=t.data();
150 docsVal = docsVal.nextSiblingElement();
153 // for an enum we list the values
154 if (type==SA("enum"))
157 docs += SA("Possible values are: ");
159 docsVal = child.firstChildElement();
160 while (!docsVal.isNull())
162 if (docsVal.tagName()==SA("value"))
166 docsVal = docsVal.nextSiblingElement();
169 docsVal = child.firstChildElement();
170 while (!docsVal.isNull())
172 if (docsVal.tagName()==SA("value"))
175 docs += SA("<code>") + docsVal.attribute(SA("name")) + SA("</code>");
176 QString desc = docsVal.attribute(SA("desc"));
185 else if (i==numValues)
194 docsVal = docsVal.nextSiblingElement();
198 docs+=SA(" The default value is: <code>")+
199 child.attribute(SA("defval"))+
203 else if (type==SA("int"))
206 docs+=SA("Minimum value: ")+child.attribute(SA("minval"))+SA(", ");
207 docs+=SA("maximum value: ")+child.attribute(SA("maxval"))+SA(", ");
208 docs+=SA("default value: ")+child.attribute(SA("defval"))+SA(".");
211 else if (type==SA("bool"))
214 if (child.hasAttribute(SA("altdefval")))
216 docs+=SA(" The default value is: system dependent.");
220 QString defval = child.attribute(SA("defval"));
221 docs+=SA(" The default value is: <code>")+
222 (defval==SA("1")?SA("YES"):SA("NO"))+
227 else if (type==SA("list"))
229 if (child.attribute(SA("format"))==SA("string"))
232 docsVal = child.firstChildElement();
233 while (!docsVal.isNull())
235 if (docsVal.tagName()==SA("value"))
237 QString showDocu = SA("");
238 if (docsVal.hasAttribute(SA("show_docu")))
240 showDocu = docsVal.attribute(SA("show_docu")).toLower();
242 if ((showDocu != SA("no")) && (docsVal.attribute(SA("name"))!=SA(""))) numValues++;
244 docsVal = docsVal.nextSiblingElement();
249 docsVal = child.firstChildElement();
250 while (!docsVal.isNull())
252 if (docsVal.tagName()==SA("value"))
254 QString showDocu = SA("");
255 if (docsVal.hasAttribute(SA("show_docu")))
257 showDocu = docsVal.attribute(SA("show_docu")).toLower();
259 if ((showDocu != SA("no")) && (docsVal.attribute(SA("name"))!=SA("")))
262 docs += SA("<code>") + docsVal.attribute(SA("name")) + SA("</code>");
263 QString desc = docsVal.attribute(SA("desc"));
266 docs += SA(" ") + desc;
272 else if (i==numValues)
282 docsVal = docsVal.nextSiblingElement();
285 // docs+= SA("<br/>");
288 else if (type==SA("string"))
290 QString defval = child.attribute(SA("defval"));
291 if (child.attribute(SA("format")) == SA("dir"))
293 if (defval != SA(""))
296 docs += SA(" The default directory is: <code>") + defval + SA("</code>.");
300 else if (child.attribute(SA("format")) == SA("file"))
302 QString abspath = child.attribute(SA("abspath"));
303 if (defval != SA(""))
306 if (abspath != SA("1"))
308 docs += SA(" The default file is: <code>") + defval + SA("</code>.");
312 docs += SA(" The default file (with absolute path) is: <code>") + defval + SA("</code>.");
318 if (abspath == SA("1"))
321 docs += SA(" The file has to be specified with full path.");
326 else if (child.attribute(SA("format")) == SA("image"))
328 QString abspath = child.attribute(SA("abspath"));
329 if (defval != SA(""))
332 if (abspath != SA("1"))
334 docs += SA(" The default image is: <code>") + defval + SA("</code>.");
338 docs += SA(" The default image (with absolute path) is: <code>") + defval + SA("</code>.");
344 if (abspath == SA("1"))
347 docs += SA(" The image has to be specified with full path.");
352 else // if (child.attribute(SA("format")) == SA("string"))
354 if (defval != SA(""))
357 docs += SA(" The default value is: <code>") + defval + SA("</code>.");
363 if (child.hasAttribute(SA("depends")))
365 QString dependsOn = child.attribute(SA("depends"));
367 docs+= SA(" This tag requires that the tag \\ref cfg_");
368 docs+= dependsOn.toLower();
370 docs+= dependsOn.toUpper();
371 docs+= SA("\" is set to <code>YES</code>.");
374 // Remove / replace doxygen markup strings
375 // the regular expressions are hard to read so the intention will be given
377 // remove \n at end and replace by a space
378 regexp.setPattern(SA("\\n$"));
379 docs.replace(regexp,SA(" "));
380 // remove <br> at end
381 regexp.setPattern(SA("<br> *$"));
382 docs.replace(regexp,SA(" "));
383 // \c word -> <code>word</code>; word ends with ')', ',', '.' or ' '
384 regexp.setPattern(SA("\\\\c[ ]+([^ \\)]+)\\)"));
385 docs.replace(regexp,SA("<code>\\1</code>)"));
387 regexp.setPattern(SA("\\\\c[ ]+([^ ,]+),"));
388 docs.replace(regexp,SA("<code>\\1</code>,"));
390 regexp.setPattern(SA("\\\\c[ ]+([^ \\.]+)\\."));
391 docs.replace(regexp,SA("<code>\\1</code>."));
393 regexp.setPattern(SA("\\\\c[ ]+([^ ]+) "));
394 docs.replace(regexp,SA("<code>\\1</code> "));
395 // `word` -> <code>word</code>
396 docs.replace(SA("``"),SA(""));
397 regexp.setPattern(SA("`([^`]+)`"));
398 docs.replace(regexp,SA("<code>\\1</code>"));
399 // \ref key "desc" -> <code>desc</code>
400 regexp.setPattern(SA("\\\\ref[ ]+[^ ]+[ ]+\"([^ ]+)\""));
401 docs.replace(regexp,SA("<code>\\1</code> "));
403 // \ref <key> -> description
404 regexp.setPattern(SA("\\\\ref[ ]+doxygen_usage"));
405 docs.replace(regexp,SA("\"Doxygen usage\""));
406 regexp.setPattern(SA("\\\\ref[ ]+extsearch"));
407 docs.replace(regexp,SA("\"External Indexing and Searching\""));
408 regexp.setPattern(SA("\\\\ref[ ]+external"));
409 docs.replace(regexp,SA("\"Linking to external documentation\""));
410 // fallback for not handled
411 docs.replace(SA("\\\\ref"),SA(""));
412 // \b word -> <b>word<\b>
413 regexp.setPattern(SA("\\\\b[ ]+([^ ]+) "));
414 docs.replace(regexp,SA("<b>\\1</b> "));
415 // \e word -> <em>word<\em>
416 regexp.setPattern(SA("\\\\e[ ]+([^ ]+) "));
417 docs.replace(regexp,SA("<em>\\1</em> "));
418 // \note -> <br>Note:
419 // @note -> <br>Note:
420 docs.replace(SA("\\note"),SA("<br>Note:"));
421 docs.replace(SA("@note"),SA("<br>Note:"));
422 // \#include -> #include
424 docs.replace(SA("\\#include"),SA("#include"));
425 docs.replace(SA("\\#undef"),SA("#undef"));
428 docs.replace(SA("-#"),SA("<br>-"));
429 docs.replace(SA(" - "),SA("<br>-"));
430 // \verbatim -> <pre>
431 // \endverbatim -> </pre>
432 docs.replace(SA("\\verbatim"),SA("<pre>"));
433 docs.replace(SA("\\endverbatim"),SA("</pre>"));
434 // \sa -> <br>See also:
436 docs.replace(SA("\\sa"),SA("<br>See also:"));
437 docs.replace(SA("\\par"),SA("<br>"));
438 // 2xbackslash -> backslash
440 docs.replace(SA("\\\\"),SA("\\"));
441 docs.replace(SA("\\@"),SA("@"));
444 docs.replace(SA("\\&"),SA("&"));
445 docs.replace(SA("\\$"),SA("$"));
448 docs.replace(SA("\\<"),SA("<"));
449 docs.replace(SA("\\>"),SA(">"));
450 regexp.setPattern(SA(" (http:[^ \\)]*)([ \\)])"));
451 docs.replace(regexp,SA(" <a href=\"\\1\">\\1</a>\\2"));
452 // LaTeX name as formula -> LaTeX
453 regexp.setPattern(SA("\\\\f\\$\\\\mbox\\{\\\\LaTeX\\}\\\\f\\$"));
454 docs.replace(regexp,SA("LaTeX"));
455 // Other forula's (now just 2) so explicitely mentioned.
456 regexp.setPattern(SA("\\\\f\\$2\\^\\{\\(16\\+\\\\mbox\\{LOOKUP\\\\_CACHE\\\\_SIZE\\}\\)\\}\\\\f\\$"));
457 docs.replace(regexp,SA("2^(16+LOOKUP_CACHE_SIZE)"));
458 regexp.setPattern(SA("\\\\f\\$2\\^\\{16\\} = 65536\\\\f\\$"));
459 docs.replace(regexp,SA("2^16=65536"));
461 return docs.trimmed();
464 QWidget *Expert::createTopicWidget(QDomElement &elem)
466 QScrollArea *area = new QScrollArea;
467 QWidget *topic = new QWidget;
468 QGridLayout *layout = new QGridLayout(topic);
469 QDomElement child = elem.firstChildElement();
471 while (!child.isNull())
473 QString setting = child.attribute(SA("setting"));
474 if (setting.isEmpty() || IS_SUPPORTED(setting.toAscii()))
476 QString type = child.attribute(SA("type"));
477 QString docs = getDocsForNode(child);
478 if (type==SA("bool"))
480 InputBool *boolOption =
483 child.attribute(SA("id")),
484 child.attribute(SA("defval"))==SA("1"),
488 child.attribute(SA("id")),
491 connect(boolOption,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*)));
492 connect(boolOption,SIGNAL(changed()),SIGNAL(changed()));
494 else if (type==SA("string"))
496 InputString::StringMode mode;
497 QString format = child.attribute(SA("format"));
498 if (format==SA("dir"))
500 mode = InputString::StringDir;
502 else if (format==SA("file"))
504 mode = InputString::StringFile;
506 else if (format==SA("image"))
508 mode = InputString::StringImage;
510 else // format=="string"
512 mode = InputString::StringFree;
514 InputString *stringOption =
517 child.attribute(SA("id")),
518 child.attribute(SA("defval")),
521 child.attribute(SA("abspath"))
524 child.attribute(SA("id")),
527 connect(stringOption,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*)));
528 connect(stringOption,SIGNAL(changed()),SIGNAL(changed()));
530 else if (type==SA("enum"))
532 InputString *enumList = new InputString(
534 child.attribute(SA("id")),
535 child.attribute(SA("defval")),
536 InputString::StringFixed,
539 QDomElement enumVal = child.firstChildElement();
540 while (!enumVal.isNull())
542 if (enumVal.tagName()==SA("value"))
544 enumList->addValue(enumVal.attribute(SA("name")));
546 enumVal = enumVal.nextSiblingElement();
548 enumList->setDefault();
550 m_options.insert(child.attribute(SA("id")),enumList);
551 connect(enumList,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*)));
552 connect(enumList,SIGNAL(changed()),SIGNAL(changed()));
554 else if (type==SA("int"))
556 InputInt *intOption =
559 child.attribute(SA("id")),
560 child.attribute(SA("defval")).toInt(),
561 child.attribute(SA("minval")).toInt(),
562 child.attribute(SA("maxval")).toInt(),
566 child.attribute(SA("id")),
569 connect(intOption,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*)));
570 connect(intOption,SIGNAL(changed()),SIGNAL(changed()));
572 else if (type==SA("list"))
574 InputStrList::ListMode mode;
575 QString format = child.attribute(SA("format"));
576 if (format==SA("dir"))
578 mode = InputStrList::ListDir;
580 else if (format==SA("file"))
582 mode = InputStrList::ListFile;
584 else if (format==SA("filedir"))
586 mode = InputStrList::ListFileDir;
588 else // format=="string"
590 mode = InputStrList::ListString;
593 QDomElement listVal = child.firstChildElement();
594 while (!listVal.isNull())
596 if (listVal.tagName()==SA("value"))
598 sl.append(listVal.attribute(SA("name")));
600 listVal = listVal.nextSiblingElement();
602 InputStrList *listOption =
605 child.attribute(SA("id")),
611 child.attribute(SA("id")),
614 connect(listOption,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*)));
615 connect(listOption,SIGNAL(changed()),SIGNAL(changed()));
617 else if (type==SA("obsolete"))
621 else // should not happen
623 printf("Unsupported type %s\n",qPrintable(child.attribute(SA("type"))));
626 child = child.nextSiblingElement();
629 // compute dependencies between options
630 child = elem.firstChildElement();
631 while (!child.isNull())
633 QString setting = child.attribute(SA("setting"));
634 QString dependsOn = child.attribute(SA("depends"));
635 QString id = child.attribute(SA("id"));
636 if (!dependsOn.isEmpty() &&
637 (setting.isEmpty() || IS_SUPPORTED(setting.toAscii())))
639 Input *parentOption = m_options[dependsOn];
642 printf("%s has depends=%s that is not valid\n",
643 qPrintable(id),qPrintable(dependsOn));
645 Input *thisOption = m_options[id];
646 Q_ASSERT(parentOption);
647 Q_ASSERT(thisOption);
648 if (parentOption && thisOption)
650 //printf("Adding dependency '%s' (%p)->'%s' (%p)\n",
651 // qPrintable(dependsOn),parentOption,
652 // qPrintable(id),thisOption);
653 parentOption->addDependency(thisOption);
656 child = child.nextSiblingElement();
659 // set initial dependencies
660 QHashIterator<QString,Input*> i(m_options);
666 i.value()->updateDependencies();
670 layout->setRowStretch(row,1);
671 layout->setColumnStretch(1,2);
672 layout->setSpacing(5);
673 topic->setLayout(layout);
674 area->setWidget(topic);
675 area->setWidgetResizable(true);
679 void Expert::activateTopic(QTreeWidgetItem *item,QTreeWidgetItem *)
683 QWidget *w = m_topics[item->text(0)];
684 m_topicStack->setCurrentWidget(w);
685 m_prev->setEnabled(m_topicStack->currentIndex()!=0);
686 m_next->setEnabled(true);
690 void Expert::loadSettings(QSettings *s)
692 QHashIterator<QString,Input*> i(m_options);
696 QVariant var = s->value(SA("config/")+i.key());
699 //printf("Loading key %s: type=%d value='%s'\n",qPrintable(i.key()),var.type(),qPrintable(var.toString()));
700 i.value()->value() = var;
706 void Expert::saveSettings(QSettings *s)
708 QHashIterator<QString,Input*> i(m_options);
712 //printf("Saving key %s: type=%d value='%s'\n",qPrintable(i.key()),i.value()->value().type(),qPrintable(i.value()->value().toString()));
715 s->setValue(SA("config/")+i.key(),i.value()->value());
720 void Expert::loadConfig(const QString &fileName)
722 //printf("Expert::loadConfig(%s)\n",qPrintable(fileName));
723 parseConfig(fileName,m_options);
726 void Expert::saveTopic(QTextStream &t,QDomElement &elem,QTextCodec *codec,
733 t << "#---------------------------------------------------------------------------" << endl;
734 t << "# " << elem.attribute(SA("docs")) << endl;
735 t << "#---------------------------------------------------------------------------" << endl;
737 QDomElement childElem = elem.firstChildElement();
738 while (!childElem.isNull())
740 QString setting = childElem.attribute(SA("setting"));
741 QString type = childElem.attribute(SA("type"));
742 QString name = childElem.attribute(SA("id"));
743 if (setting.isEmpty() || IS_SUPPORTED(setting.toAscii()))
745 QHash<QString,Input*>::const_iterator i = m_options.find(name);
746 if (i!=m_options.end())
748 Input *option = i.value();
749 if (option && !brief)
752 t << convertToComment(option->templateDocs());
755 t << name.leftJustified(MAX_OPTION_LENGTH) << "= ";
758 option->writeValue(t,codec);
763 childElem = childElem.nextSiblingElement();
767 bool Expert::writeConfig(QTextStream &t,bool brief)
769 // write global header
770 t << "# Doxyfile " << versionString << endl << endl;
773 t << convertToComment(m_header);
776 QTextCodec *codec = 0;
777 Input *option = m_options[QString::fromAscii("DOXYFILE_ENCODING")];
780 codec = QTextCodec::codecForName(option->value().toString().toAscii());
781 if (codec==0) // fallback: use UTF-8
783 codec = QTextCodec::codecForName("UTF-8");
786 QDomElement childElem = m_rootElement.firstChildElement();
787 while (!childElem.isNull())
789 if (childElem.tagName()==SA("group"))
791 saveTopic(t,childElem,codec,brief);
793 childElem = childElem.nextSiblingElement();
798 QByteArray Expert::saveInnerState () const
800 return m_splitter->saveState();
803 bool Expert::restoreInnerState ( const QByteArray & state )
805 return m_splitter->restoreState(state);
808 void Expert::showHelp(Input *option)
814 QString::fromAscii("<qt><b>")+option->id()+
815 QString::fromAscii("</b><br>")+
816 QString::fromAscii("<br/>")+
818 replace(QChar::fromAscii('\n'),QChar::fromAscii(' '))+
819 QString::fromAscii("</qt>")
821 m_inShowHelp = FALSE;
825 void Expert::nextTopic()
827 if (m_topicStack->currentIndex()+1==m_topicStack->count()) // last topic
833 m_topicStack->setCurrentIndex(m_topicStack->currentIndex()+1);
834 m_next->setEnabled(m_topicStack->count()!=m_topicStack->currentIndex()+1);
835 m_prev->setEnabled(m_topicStack->currentIndex()!=0);
836 m_treeWidget->setCurrentItem(m_treeWidget->invisibleRootItem()->child(m_topicStack->currentIndex()));
840 void Expert::prevTopic()
842 m_topicStack->setCurrentIndex(m_topicStack->currentIndex()-1);
843 m_next->setEnabled(m_topicStack->count()!=m_topicStack->currentIndex()+1);
844 m_prev->setEnabled(m_topicStack->currentIndex()!=0);
845 m_treeWidget->setCurrentItem(m_treeWidget->invisibleRootItem()->child(m_topicStack->currentIndex()));
848 void Expert::resetToDefaults()
850 //printf("Expert::makeDefaults()\n");
851 QHashIterator<QString,Input*> i(m_options);
862 static bool stringVariantToBool(const QVariant &v)
864 QString s = v.toString().toLower();
865 return s==QString::fromAscii("yes") || s==QString::fromAscii("true") || s==QString::fromAscii("1");
868 static bool getBoolOption(
869 const QHash<QString,Input*>&model,const QString &name)
871 Input *option = model[name];
873 return stringVariantToBool(option->value());
876 static QString getStringOption(
877 const QHash<QString,Input*>&model,const QString &name)
879 Input *option = model[name];
881 return option->value().toString();
885 bool Expert::htmlOutputPresent(const QString &workingDir) const
887 bool generateHtml = getBoolOption(m_options,QString::fromAscii("GENERATE_HTML"));
888 if (!generateHtml || workingDir.isEmpty()) return false;
889 QString indexFile = getHtmlOutputIndex(workingDir);
890 QFileInfo fi(indexFile);
891 return fi.exists() && fi.isFile();
894 QString Expert::getHtmlOutputIndex(const QString &workingDir) const
896 QString outputDir = getStringOption(m_options,QString::fromAscii("OUTPUT_DIRECTORY"));
897 QString htmlOutputDir = getStringOption(m_options,QString::fromAscii("HTML_OUTPUT"));
898 //printf("outputDir=%s\n",qPrintable(outputDir));
899 //printf("htmlOutputDir=%s\n",qPrintable(htmlOutputDir));
900 QString indexFile = workingDir;
901 if (QFileInfo(outputDir).isAbsolute()) // override
903 indexFile = outputDir;
907 indexFile += QString::fromAscii("/")+outputDir;
909 if (QFileInfo(htmlOutputDir).isAbsolute()) // override
911 indexFile = htmlOutputDir;
915 indexFile += QString::fromAscii("/")+htmlOutputDir;
917 indexFile+=QString::fromAscii("/index.html");
921 bool Expert::pdfOutputPresent(const QString &workingDir) const
923 bool generateLatex = getBoolOption(m_options,QString::fromAscii("GENERATE_LATEX"));
924 bool pdfLatex = getBoolOption(m_options,QString::fromAscii("USE_PDFLATEX"));
925 if (!generateLatex || !pdfLatex) return false;
926 QString latexOutput = getStringOption(m_options,QString::fromAscii("LATEX_OUTPUT"));
928 if (QFileInfo(latexOutput).isAbsolute())
930 indexFile = latexOutput+QString::fromAscii("/refman.pdf");
934 indexFile = workingDir+QString::fromAscii("/")+
935 latexOutput+QString::fromAscii("/refman.pdf");
937 QFileInfo fi(indexFile);
938 return fi.exists() && fi.isFile();
941 void Expert::refresh()
943 m_treeWidget->setCurrentItem(m_treeWidget->invisibleRootItem()->child(0));