expert.cpp
Go to the documentation of this file.
1 #include "expert.h"
2 #include "inputbool.h"
3 #include "inputstring.h"
4 #include "inputint.h"
5 #include "inputstring.h"
6 #include "inputstrlist.h"
7 #include "config.h"
8 #include "version.h"
9 #include "configdoc.h"
10 #include "settings.h"
11 
12 #include <QTreeWidget>
13 #include <QStackedWidget>
14 #include <QTextBrowser>
15 #include <QSplitter>
16 #include <QGridLayout>
17 #include <QPushButton>
18 #include <QScrollArea>
19 #include <QFile>
20 #include <QMessageBox>
21 #include <QSettings>
22 #include <QTextStream>
23 #include <QTextCodec>
24 #include <QFileInfo>
25 
26 #define SA(x) QString::fromLatin1(x)
27 
28 
30 {
31  if (s.isEmpty())
32  {
33  return QString();
34  }
35  else
36  {
37  return SA("# ")+
38  s.trimmed().replace(SA("\n"),SA("\n# ")).replace(SA("# \n"), SA("#\n"))+
39  SA("\n");
40  }
41 }
42 
43 void Expert::setHeader(const char *header)
44 {
45  m_header = SA(header);
46 }
47 
48 void Expert::add(const char *name,const char *docs)
49 {
50  Input *opt = m_options[SA(name)];
51  if (opt)
52  {
53  opt->setTemplateDocs(SA(docs));
54  }
55 }
56 
57 //------------------------------------------------------------------------------------
58 
60 {
61  m_treeWidget = new QTreeWidget;
62  m_treeWidget->setColumnCount(1);
63  m_topicStack = new QStackedWidget;
64  m_inShowHelp = false;
65 
66  QFile file(SA(":/config.xml"));
67  QString err;
68  int errLine,errCol;
69  QDomDocument configXml;
70  if (file.open(QIODevice::ReadOnly))
71  {
72  if (!configXml.setContent(&file,false,&err,&errLine,&errCol))
73  {
74  QString msg = tr("Error parsing internal config.xml at line %1 column %2.\n%3").
75  arg(errLine).arg(errCol).arg(err);
76  QMessageBox::warning(this, tr("Error"), msg);
77  exit(1);
78  }
79  }
80  m_rootElement = configXml.documentElement();
81 
83  m_helper = new QTextBrowser;
84  m_helper->setReadOnly(true);
85  m_helper->setOpenExternalLinks(true);
86  m_splitter = new QSplitter(Qt::Vertical);
87  m_splitter->addWidget(m_treeWidget);
88  m_splitter->addWidget(m_helper);
89 
90  QWidget *rightSide = new QWidget;
91  QGridLayout *grid = new QGridLayout(rightSide);
92  m_prev = new QPushButton(tr("Previous"));
93  m_prev->setEnabled(false);
94  m_next = new QPushButton(tr("Next"));
95  grid->addWidget(m_topicStack,0,0,1,2);
96  grid->addWidget(m_prev,1,0,Qt::AlignLeft);
97  grid->addWidget(m_next,1,1,Qt::AlignRight);
98  grid->setColumnStretch(0,1);
99  grid->setRowStretch(0,1);
100 
101  addWidget(m_splitter);
102  addWidget(rightSide);
103  connect(m_next,SIGNAL(clicked()),SLOT(nextTopic()));
104 
105  connect(m_prev,SIGNAL(clicked()),SLOT(prevTopic()));
106 
107  addConfigDocs(this);
108 }
109 
111 {
112  QHashIterator<QString,Input*> i(m_options);
113  while (i.hasNext())
114  {
115  i.next();
116  delete i.value();
117  }
118 }
119 
120 void Expert::createTopics(const QDomElement &rootElem)
121 {
123  QDomElement childElem = rootElem.firstChildElement();
124  while (!childElem.isNull())
125  {
126  if (childElem.tagName()==SA("group"))
127  {
128  // Remove _ from a group name like: Source_Browser
129  QString name = childElem.attribute(SA("name")).replace(SA("_"),SA(" "));
130  items.append(new QTreeWidgetItem((QTreeWidget*)0,QStringList(name)));
131  QWidget *widget = createTopicWidget(childElem);
132  m_topics[name] = widget;
133  m_topicStack->addWidget(widget);
134  }
135  childElem = childElem.nextSiblingElement();
136  }
137  m_treeWidget->setHeaderLabels(QStringList() << SA("Topics"));
138  m_treeWidget->insertTopLevelItems(0,items);
140  SIGNAL(currentItemChanged(QTreeWidgetItem *,QTreeWidgetItem *)),
141  this,
142  SLOT(activateTopic(QTreeWidgetItem *,QTreeWidgetItem *)));
143 }
144 
145 static QString getDocsForNode(const QDomElement &child)
146 {
147  QString type = child.attribute(SA("type"));
148  QString docs = SA("");
149  // read documentation text
150  QDomElement docsVal = child.firstChildElement();
151  while (!docsVal.isNull())
152  {
153  if (docsVal.tagName()==SA("docs") &&
154  docsVal.attribute(SA("doxywizard")) != SA("0"))
155  {
156  for (QDomNode n = docsVal.firstChild(); !n.isNull(); n = n.nextSibling())
157  {
158  QDomText t = n.toText();
159  if (!t.isNull()) docs+=t.data();
160  }
161  docs += SA("<br/>");
162  }
163  docsVal = docsVal.nextSiblingElement();
164  }
165 
166  // for an enum we list the values
167  if (type==SA("enum"))
168  {
169  docs += SA("<br/>");
170  docs += SA("Possible values are: ");
171  int numValues=0;
172  docsVal = child.firstChildElement();
173  while (!docsVal.isNull())
174  {
175  if (docsVal.tagName()==SA("value"))
176  {
177  numValues++;
178  }
179  docsVal = docsVal.nextSiblingElement();
180  }
181  int i=0;
182  docsVal = child.firstChildElement();
183  while (!docsVal.isNull())
184  {
185  if (docsVal.tagName()==SA("value"))
186  {
187  i++;
188  docs += SA("<code>") + docsVal.attribute(SA("name")) + SA("</code>");
189  QString desc = docsVal.attribute(SA("desc"));
190  if (!desc.isEmpty())
191  {
192  docs+= SA(" ")+desc;
193  }
194  if (i==numValues-1)
195  {
196  docs+=SA(" and ");
197  }
198  else if (i==numValues)
199  {
200  docs+=SA(".");
201  }
202  else
203  {
204  docs+=SA(", ");
205  }
206  }
207  docsVal = docsVal.nextSiblingElement();
208  }
209  docs+=SA("<br/>");
210  docs+=SA("<br/>");
211  docs+=SA(" The default value is: <code>")+
212  child.attribute(SA("defval"))+
213  SA("</code>.");
214  docs+= SA("<br/>");
215  }
216  else if (type==SA("int"))
217  {
218  docs+=SA("<br/>");
219  docs+=SA("Minimum value: ")+child.attribute(SA("minval"))+SA(", ");
220  docs+=SA("maximum value: ")+child.attribute(SA("maxval"))+SA(", ");
221  docs+=SA("default value: ")+child.attribute(SA("defval"))+SA(".");
222  docs+= SA("<br/>");
223  }
224  else if (type==SA("bool"))
225  {
226  docs+=SA("<br/>");
227  if (child.hasAttribute(SA("altdefval")))
228  {
229  docs+=SA(" The default value is: system dependent.");
230  }
231  else
232  {
233  QString defval = child.attribute(SA("defval"));
234  docs+=SA(" The default value is: <code>")+
235  (defval==SA("1")?SA("YES"):SA("NO"))+
236  SA("</code>.");
237  }
238  docs+= SA("<br/>");
239  }
240  else if (type==SA("list"))
241  {
242  if (child.attribute(SA("format"))==SA("string"))
243  {
244  int numValues = 0;
245  docsVal = child.firstChildElement();
246  while (!docsVal.isNull())
247  {
248  if (docsVal.tagName()==SA("value"))
249  {
250  QString showDocu = SA("");
251  if (docsVal.hasAttribute(SA("show_docu")))
252  {
253  showDocu = docsVal.attribute(SA("show_docu")).toLower();
254  }
255  if ((showDocu != SA("no")) && (docsVal.attribute(SA("name"))!=SA(""))) numValues++;
256  }
257  docsVal = docsVal.nextSiblingElement();
258  }
259  if (numValues>0)
260  {
261  int i = 0;
262  docsVal = child.firstChildElement();
263  while (!docsVal.isNull())
264  {
265  if (docsVal.tagName()==SA("value"))
266  {
267  QString showDocu = SA("");
268  if (docsVal.hasAttribute(SA("show_docu")))
269  {
270  showDocu = docsVal.attribute(SA("show_docu")).toLower();
271  }
272  if ((showDocu != SA("no")) && (docsVal.attribute(SA("name"))!=SA("")))
273  {
274  i++;
275  docs += SA("<code>") + docsVal.attribute(SA("name")) + SA("</code>");
276  QString desc = docsVal.attribute(SA("desc"));
277  if (desc != SA(""))
278  {
279  docs += SA(" ") + desc;
280  }
281  if (i==numValues-1)
282  {
283  docs += SA(" and ");
284  }
285  else if (i==numValues)
286  {
287  docs += SA(".");
288  }
289  else
290  {
291  docs += SA(", ");
292  }
293  }
294  }
295  docsVal = docsVal.nextSiblingElement();
296  }
297  }
298  // docs+= SA("<br/>");
299  }
300  }
301  else if (type==SA("string"))
302  {
303  QString defval = child.attribute(SA("defval"));
304  if (child.attribute(SA("format")) == SA("dir"))
305  {
306  if (defval != SA(""))
307  {
308  docs+=SA("<br/>");
309  docs += SA(" The default directory is: <code>") + defval + SA("</code>.");
310  docs += SA("<br/>");
311  }
312  }
313  else if (child.attribute(SA("format")) == SA("file"))
314  {
315  QString abspath = child.attribute(SA("abspath"));
316  if (defval != SA(""))
317  {
318  docs+=SA("<br/>");
319  if (abspath != SA("1"))
320  {
321  docs += SA(" The default file is: <code>") + defval + SA("</code>.");
322  }
323  else
324  {
325  docs += SA(" The default file (with absolute path) is: <code>") + defval + SA("</code>.");
326  }
327  docs += SA("<br/>");
328  }
329  else
330  {
331  if (abspath == SA("1"))
332  {
333  docs+=SA("<br/>");
334  docs += SA(" The file has to be specified with full path.");
335  docs += SA("<br/>");
336  }
337  }
338  }
339  else if (child.attribute(SA("format")) == SA("image"))
340  {
341  QString abspath = child.attribute(SA("abspath"));
342  if (defval != SA(""))
343  {
344  docs+=SA("<br/>");
345  if (abspath != SA("1"))
346  {
347  docs += SA(" The default image is: <code>") + defval + SA("</code>.");
348  }
349  else
350  {
351  docs += SA(" The default image (with absolute path) is: <code>") + defval + SA("</code>.");
352  }
353  docs += SA("<br/>");
354  }
355  else
356  {
357  if (abspath == SA("1"))
358  {
359  docs+=SA("<br/>");
360  docs += SA(" The image has to be specified with full path.");
361  docs += SA("<br/>");
362  }
363  }
364  }
365  else // if (child.attribute(SA("format")) == SA("string"))
366  {
367  if (defval != SA(""))
368  {
369  docs+=SA("<br/>");
370  docs += SA(" The default value is: <code>") + defval + SA("</code>.");
371  docs += SA("<br/>");
372  }
373  }
374  }
375 
376  if (child.hasAttribute(SA("depends")))
377  {
378  QString dependsOn = child.attribute(SA("depends"));
379  docs+=SA("<br/>");
380  docs+= SA(" This tag requires that the tag \\ref cfg_");
381  docs+= dependsOn.toLower();
382  docs+= SA(" \"");
383  docs+= dependsOn.toUpper();
384  docs+= SA("\" is set to <code>YES</code>.");
385  }
386 
387  // Remove / replace doxygen markup strings
388  // the regular expressions are hard to read so the intention will be given
389  QRegExp regexp;
390  // remove \n at end and replace by a space
391  regexp.setPattern(SA("\\n$"));
392  docs.replace(regexp,SA(" "));
393  // remove <br> at end
394  regexp.setPattern(SA("<br> *$"));
395  docs.replace(regexp,SA(" "));
396  // \c word -> <code>word</code>; word ends with ')', ',', '.' or ' '
397  regexp.setPattern(SA("\\\\c[ ]+([^ \\)]+)\\)"));
398  docs.replace(regexp,SA("<code>\\1</code>)"));
399 
400  regexp.setPattern(SA("\\\\c[ ]+([^ ,]+),"));
401  docs.replace(regexp,SA("<code>\\1</code>,"));
402 
403  regexp.setPattern(SA("\\\\c[ ]+([^ \\.]+)\\."));
404  docs.replace(regexp,SA("<code>\\1</code>."));
405 
406  regexp.setPattern(SA("\\\\c[ ]+([^ ]+) "));
407  docs.replace(regexp,SA("<code>\\1</code> "));
408  // `word` -> <code>word</code>
409  docs.replace(SA("``"),SA(""));
410  regexp.setPattern(SA("`([^`]+)`"));
411  docs.replace(regexp,SA("<code>\\1</code>"));
412  // \ref key "desc" -> <code>desc</code>
413  regexp.setPattern(SA("\\\\ref[ ]+[^ ]+[ ]+\"([^ ]+)\""));
414  docs.replace(regexp,SA("<code>\\1</code> "));
415  //\ref specials
416  // \ref <key> -> description
417  regexp.setPattern(SA("\\\\ref[ ]+doxygen_usage"));
418  docs.replace(regexp,SA("\"Doxygen usage\""));
419  regexp.setPattern(SA("\\\\ref[ ]+extsearch"));
420  docs.replace(regexp,SA("\"External Indexing and Searching\""));
421  regexp.setPattern(SA("\\\\ref[ ]+external"));
422  docs.replace(regexp,SA("\"Linking to external documentation\""));
423  // fallback for not handled
424  docs.replace(SA("\\\\ref"),SA(""));
425  // \b word -> <b>word<\b>
426  regexp.setPattern(SA("\\\\b[ ]+([^ ]+) "));
427  docs.replace(regexp,SA("<b>\\1</b> "));
428  // \e word -> <em>word<\em>
429  regexp.setPattern(SA("\\\\e[ ]+([^ ]+) "));
430  docs.replace(regexp,SA("<em>\\1</em> "));
431  // \note -> <br>Note:
432  // @note -> <br>Note:
433  docs.replace(SA("\\note"),SA("<br>Note:"));
434  docs.replace(SA("@note"),SA("<br>Note:"));
435  // \#include -> #include
436  // \#undef -> #undef
437  docs.replace(SA("\\#include"),SA("#include"));
438  docs.replace(SA("\\#undef"),SA("#undef"));
439  // -# -> <br>-
440  // " - " -> <br>-
441  docs.replace(SA("-#"),SA("<br>-"));
442  docs.replace(SA(" - "),SA("<br>-"));
443  // \verbatim -> <pre>
444  // \endverbatim -> </pre>
445  docs.replace(SA("\\verbatim"),SA("<pre>"));
446  docs.replace(SA("\\endverbatim"),SA("</pre>"));
447  // \sa -> <br>See also:
448  // \par -> <br>
449  docs.replace(SA("\\sa"),SA("<br>See also:"));
450  docs.replace(SA("\\par"),SA("<br>"));
451  // 2xbackslash -> backslash
452  // \@ -> @
453  docs.replace(SA("\\\\"),SA("\\"));
454  docs.replace(SA("\\@"),SA("@"));
455  // \& -> &
456  // \$ -> $
457  docs.replace(SA("\\&"),SA("&"));
458  docs.replace(SA("\\$"),SA("$"));
459  // < -> &lt;
460  // > -> &gt;
461  docs.replace(SA("\\<"),SA("&lt;"));
462  docs.replace(SA("\\>"),SA("&gt;"));
463  regexp.setPattern(SA(" (http:[^ \\)]*)([ \\)])"));
464  docs.replace(regexp,SA(" <a href=\"\\1\">\\1</a>\\2"));
465  // LaTeX name as formula -> LaTeX
466  regexp.setPattern(SA("\\\\f\\$\\\\mbox\\{\\\\LaTeX\\}\\\\f\\$"));
467  docs.replace(regexp,SA("LaTeX"));
468  // Other formula's (now just 2) so explicitly mentioned.
469  regexp.setPattern(SA("\\\\f\\$2\\^\\{\\(16\\+\\\\mbox\\{LOOKUP\\\\_CACHE\\\\_SIZE\\}\\)\\}\\\\f\\$"));
470  docs.replace(regexp,SA("2^(16+LOOKUP_CACHE_SIZE)"));
471  regexp.setPattern(SA("\\\\f\\$2\\^\\{16\\} = 65536\\\\f\\$"));
472  docs.replace(regexp,SA("2^16=65536"));
473 
474  return docs.trimmed();
475 }
476 
477 QWidget *Expert::createTopicWidget(QDomElement &elem)
478 {
479  QScrollArea *area = new QScrollArea;
480  QWidget *topic = new QWidget;
481  QGridLayout *layout = new QGridLayout(topic);
482  QDomElement child = elem.firstChildElement();
483  int row=0;
484  while (!child.isNull())
485  {
486  QString setting = child.attribute(SA("setting"));
487  if (setting.isEmpty() || IS_SUPPORTED(setting.toLatin1()))
488  {
489  QString type = child.attribute(SA("type"));
490  QString docs = getDocsForNode(child);
491  if (type==SA("bool"))
492  {
493  InputBool *boolOption =
494  new InputBool(
495  layout,row,
496  child.attribute(SA("id")),
497  child.attribute(SA("defval"))==SA("1"),
498  docs
499  );
500  m_options.insert(
501  child.attribute(SA("id")),
502  boolOption
503  );
504  connect(boolOption,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*)));
505  connect(boolOption,SIGNAL(changed()),SIGNAL(changed()));
506  }
507  else if (type==SA("string"))
508  {
510  QString format = child.attribute(SA("format"));
511  if (format==SA("dir"))
512  {
513  mode = InputString::StringDir;
514  }
515  else if (format==SA("file"))
516  {
518  }
519  else if (format==SA("image"))
520  {
522  }
523  else // format=="string"
524  {
526  }
527  InputString *stringOption =
528  new InputString(
529  layout,row,
530  child.attribute(SA("id")),
531  child.attribute(SA("defval")),
532  mode,
533  docs,
534  child.attribute(SA("abspath"))
535  );
536  m_options.insert(
537  child.attribute(SA("id")),
538  stringOption
539  );
540  connect(stringOption,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*)));
541  connect(stringOption,SIGNAL(changed()),SIGNAL(changed()));
542  }
543  else if (type==SA("enum"))
544  {
545  InputString *enumList = new InputString(
546  layout,row,
547  child.attribute(SA("id")),
548  child.attribute(SA("defval")),
550  docs
551  );
552  QDomElement enumVal = child.firstChildElement();
553  while (!enumVal.isNull())
554  {
555  if (enumVal.tagName()==SA("value"))
556  {
557  enumList->addValue(enumVal.attribute(SA("name")));
558  }
559  enumVal = enumVal.nextSiblingElement();
560  }
561  enumList->setDefault();
562 
563  m_options.insert(child.attribute(SA("id")),enumList);
564  connect(enumList,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*)));
565  connect(enumList,SIGNAL(changed()),SIGNAL(changed()));
566  }
567  else if (type==SA("int"))
568  {
569  InputInt *intOption =
570  new InputInt(
571  layout,row,
572  child.attribute(SA("id")),
573  child.attribute(SA("defval")).toInt(),
574  child.attribute(SA("minval")).toInt(),
575  child.attribute(SA("maxval")).toInt(),
576  docs
577  );
578  m_options.insert(
579  child.attribute(SA("id")),
580  intOption
581  );
582  connect(intOption,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*)));
583  connect(intOption,SIGNAL(changed()),SIGNAL(changed()));
584  }
585  else if (type==SA("list"))
586  {
588  QString format = child.attribute(SA("format"));
589  if (format==SA("dir"))
590  {
591  mode = InputStrList::ListDir;
592  }
593  else if (format==SA("file"))
594  {
595  mode = InputStrList::ListFile;
596  }
597  else if (format==SA("filedir"))
598  {
600  }
601  else // format=="string"
602  {
604  }
605  QStringList sl;
606  QDomElement listVal = child.firstChildElement();
607  while (!listVal.isNull())
608  {
609  if (listVal.tagName()==SA("value"))
610  {
611  sl.append(listVal.attribute(SA("name")));
612  }
613  listVal = listVal.nextSiblingElement();
614  }
615  InputStrList *listOption =
616  new InputStrList(
617  layout,row,
618  child.attribute(SA("id")),
619  sl,
620  mode,
621  docs
622  );
623  m_options.insert(
624  child.attribute(SA("id")),
625  listOption
626  );
627  connect(listOption,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*)));
628  connect(listOption,SIGNAL(changed()),SIGNAL(changed()));
629  }
630  else if (type==SA("obsolete"))
631  {
632  // ignore
633  }
634  else // should not happen
635  {
636  printf("Unsupported type %s\n",qPrintable(child.attribute(SA("type"))));
637  }
638  } // IS_SUPPORTED
639  child = child.nextSiblingElement();
640  }
641 
642  // compute dependencies between options
643  child = elem.firstChildElement();
644  while (!child.isNull())
645  {
646  QString setting = child.attribute(SA("setting"));
647  QString dependsOn = child.attribute(SA("depends"));
648  QString id = child.attribute(SA("id"));
649  if (!dependsOn.isEmpty() &&
650  (setting.isEmpty() || IS_SUPPORTED(setting.toLatin1())))
651  {
652  Input *parentOption = m_options[dependsOn];
653  if (parentOption==0)
654  {
655  printf("%s has depends=%s that is not valid\n",
656  qPrintable(id),qPrintable(dependsOn));
657  }
658  Input *thisOption = m_options[id];
659  Q_ASSERT(parentOption);
660  Q_ASSERT(thisOption);
661  if (parentOption && thisOption)
662  {
663  //printf("Adding dependency '%s' (%p)->'%s' (%p)\n",
664  // qPrintable(dependsOn),parentOption,
665  // qPrintable(id),thisOption);
666  parentOption->addDependency(thisOption);
667  }
668  }
669  child = child.nextSiblingElement();
670  }
671 
672  // set initial dependencies
673  QHashIterator<QString,Input*> i(m_options);
674  while (i.hasNext())
675  {
676  i.next();
677  if (i.value())
678  {
679  i.value()->updateDependencies();
680  }
681  }
682 
683  layout->setRowStretch(row,1);
684  layout->setColumnStretch(1,2);
685  layout->setSpacing(5);
686  topic->setLayout(layout);
687  area->setWidget(topic);
688  area->setWidgetResizable(true);
689  return area;
690 }
691 
692 void Expert::activateTopic(QTreeWidgetItem *item,QTreeWidgetItem *)
693 {
694  if (item)
695  {
696  QWidget *w = m_topics[item->text(0)];
697  m_topicStack->setCurrentWidget(w);
698  m_prev->setEnabled(m_topicStack->currentIndex()!=0);
699  m_next->setEnabled(true);
700  }
701 }
702 
703 void Expert::loadSettings(QSettings *s)
704 {
705  QHashIterator<QString,Input*> i(m_options);
706  while (i.hasNext())
707  {
708  i.next();
709  QVariant var = s->value(SA("config/")+i.key());
710  if (i.value())
711  {
712  //printf("Loading key %s: type=%d value='%s'\n",qPrintable(i.key()),var.type(),qPrintable(var.toString()));
713  i.value()->value() = var;
714  i.value()->update();
715  }
716  }
717 }
718 
719 void Expert::saveSettings(QSettings *s)
720 {
721  QHashIterator<QString,Input*> i(m_options);
722  while (i.hasNext())
723  {
724  i.next();
725  //printf("Saving key %s: type=%d value='%s'\n",qPrintable(i.key()),i.value()->value().type(),qPrintable(i.value()->value().toString()));
726  if (i.value())
727  {
728  s->setValue(SA("config/")+i.key(),i.value()->value());
729  }
730  }
731 }
732 
734 {
735  //printf("Expert::loadConfig(%s)\n",qPrintable(fileName));
736  parseConfig(fileName,m_options);
737 }
738 
739 void Expert::saveTopic(QTextStream &t,QDomElement &elem,QTextCodec *codec,
740  bool brief)
741 {
742  if (!brief)
743  {
744  t << endl;
745  }
746  t << "#---------------------------------------------------------------------------" << endl;
747  t << "# " << elem.attribute(SA("docs")) << endl;
748  t << "#---------------------------------------------------------------------------" << endl;
749  // write options...
750  QDomElement childElem = elem.firstChildElement();
751  while (!childElem.isNull())
752  {
753  QString setting = childElem.attribute(SA("setting"));
754  QString type = childElem.attribute(SA("type"));
755  QString name = childElem.attribute(SA("id"));
756  if (setting.isEmpty() || IS_SUPPORTED(setting.toLatin1()))
757  {
759  if (i!=m_options.end())
760  {
761  Input *option = i.value();
762  if (option && !brief)
763  {
764  t << endl;
765  t << convertToComment(option->templateDocs());
766  t << endl;
767  }
768  t << name.leftJustified(MAX_OPTION_LENGTH) << "= ";
769  if (option)
770  {
771  option->writeValue(t,codec);
772  }
773  t << endl;
774  }
775  }
776  childElem = childElem.nextSiblingElement();
777  }
778 }
779 
781 {
782  // write global header
783  t << "# Doxyfile " << versionString << endl << endl;
784  if (!brief)
785  {
787  }
788 
789  QTextCodec *codec = 0;
790  Input *option = m_options[QString::fromLatin1("DOXYFILE_ENCODING")];
791  if (option)
792  {
793  codec = QTextCodec::codecForName(option->value().toString().toLatin1());
794  if (codec==0) // fallback: use UTF-8
795  {
796  codec = QTextCodec::codecForName("UTF-8");
797  }
798  }
799  QDomElement childElem = m_rootElement.firstChildElement();
800  while (!childElem.isNull())
801  {
802  if (childElem.tagName()==SA("group"))
803  {
804  saveTopic(t,childElem,codec,brief);
805  }
806  childElem = childElem.nextSiblingElement();
807  }
808  return true;
809 }
810 
812 {
813  return m_splitter->saveState();
814 }
815 
816 bool Expert::restoreInnerState ( const QByteArray & state )
817 {
818  return m_splitter->restoreState(state);
819 }
820 
821 void Expert::showHelp(Input *option)
822 {
823  if (!m_inShowHelp)
824  {
825  m_inShowHelp = true;
826  m_helper->setText(
827  QString::fromLatin1("<qt><b>")+option->id()+
828  QString::fromLatin1("</b><br>")+
829  QString::fromLatin1("<br/>")+
830  option->docs().
831  replace(QChar::fromLatin1('\n'),QChar::fromLatin1(' '))+
832  QString::fromLatin1("</qt>")
833  );
834  m_inShowHelp = false;
835  }
836 }
837 
839 {
840  if (m_topicStack->currentIndex()+1==m_topicStack->count()) // last topic
841  {
842  done();
843  }
844  else
845  {
846  m_topicStack->setCurrentIndex(m_topicStack->currentIndex()+1);
847  m_next->setEnabled(m_topicStack->count()!=m_topicStack->currentIndex()+1);
848  m_prev->setEnabled(m_topicStack->currentIndex()!=0);
849  m_treeWidget->setCurrentItem(m_treeWidget->invisibleRootItem()->child(m_topicStack->currentIndex()));
850  }
851 }
852 
854 {
855  m_topicStack->setCurrentIndex(m_topicStack->currentIndex()-1);
856  m_next->setEnabled(m_topicStack->count()!=m_topicStack->currentIndex()+1);
857  m_prev->setEnabled(m_topicStack->currentIndex()!=0);
858  m_treeWidget->setCurrentItem(m_treeWidget->invisibleRootItem()->child(m_topicStack->currentIndex()));
859 }
860 
862 {
863  //printf("Expert::makeDefaults()\n");
864  QHashIterator<QString,Input*> i(m_options);
865  while (i.hasNext())
866  {
867  i.next();
868  if (i.value())
869  {
870  i.value()->reset();
871  }
872  }
873 }
874 
875 static bool stringVariantToBool(const QVariant &v)
876 {
877  QString s = v.toString().toLower();
878  return s==QString::fromLatin1("yes") || s==QString::fromLatin1("true") || s==QString::fromLatin1("1");
879 }
880 
881 static bool getBoolOption(
882  const QHash<QString,Input*>&model,const QString &name)
883 {
884  Input *option = model[name];
885  Q_ASSERT(option!=0);
886  return stringVariantToBool(option->value());
887 }
888 
890  const QHash<QString,Input*>&model,const QString &name)
891 {
892  Input *option = model[name];
893  Q_ASSERT(option!=0);
894  return option->value().toString();
895 }
896 
897 
898 bool Expert::htmlOutputPresent(const QString &workingDir) const
899 {
900  bool generateHtml = getBoolOption(m_options,QString::fromLatin1("GENERATE_HTML"));
901  if (!generateHtml || workingDir.isEmpty()) return false;
902  QString indexFile = getHtmlOutputIndex(workingDir);
903  QFileInfo fi(indexFile);
904  return fi.exists() && fi.isFile();
905 }
906 
908 {
909  QString outputDir = getStringOption(m_options,QString::fromLatin1("OUTPUT_DIRECTORY"));
910  QString htmlOutputDir = getStringOption(m_options,QString::fromLatin1("HTML_OUTPUT"));
911  //printf("outputDir=%s\n",qPrintable(outputDir));
912  //printf("htmlOutputDir=%s\n",qPrintable(htmlOutputDir));
913  QString indexFile = workingDir;
914  if (QFileInfo(outputDir).isAbsolute()) // override
915  {
916  indexFile = outputDir;
917  }
918  else // append
919  {
920  indexFile += QString::fromLatin1("/")+outputDir;
921  }
922  if (QFileInfo(htmlOutputDir).isAbsolute()) // override
923  {
924  indexFile = htmlOutputDir;
925  }
926  else // append
927  {
928  indexFile += QString::fromLatin1("/")+htmlOutputDir;
929  }
930  indexFile+=QString::fromLatin1("/index.html");
931  return indexFile;
932 }
933 
934 bool Expert::pdfOutputPresent(const QString &workingDir) const
935 {
936  bool generateLatex = getBoolOption(m_options,QString::fromLatin1("GENERATE_LATEX"));
937  bool pdfLatex = getBoolOption(m_options,QString::fromLatin1("USE_PDFLATEX"));
938  if (!generateLatex || !pdfLatex) return false;
939  QString latexOutput = getStringOption(m_options,QString::fromLatin1("LATEX_OUTPUT"));
940  QString indexFile;
941  if (QFileInfo(latexOutput).isAbsolute())
942  {
943  indexFile = latexOutput+QString::fromLatin1("/refman.pdf");
944  }
945  else
946  {
947  indexFile = workingDir+QString::fromLatin1("/")+
948  latexOutput+QString::fromLatin1("/refman.pdf");
949  }
950  QFileInfo fi(indexFile);
951  return fi.exists() && fi.isFile();
952 }
953 
955 {
956  m_treeWidget->setCurrentItem(m_treeWidget->invisibleRootItem()->child(0));
957 }
958 
static QCString name
Definition: declinfo.cpp:673
void addValue(QString s)
void activateTopic(QTreeWidgetItem *, QTreeWidgetItem *)
Definition: expert.cpp:692
void setHeader(const char *name)
Definition: expert.cpp:43
QTreeWidget * m_treeWidget
Definition: expert.h:62
void saveTopic(QTextStream &t, QDomElement &elem, QTextCodec *codec, bool brief)
Definition: expert.cpp:739
bool isEmpty() const
Definition: qstring.h:682
bool brief
Iterator append(const T &x)
Definition: qvaluelist.h:372
bool writeConfig(QTextStream &t, bool brief)
Definition: expert.cpp:780
QWidget * createTopicWidget(QDomElement &elem)
Definition: expert.cpp:477
The QRegExp class provides pattern matching using regular expressions or wildcards.
Definition: qregexp.h:46
void msg(const char *fmt,...)
Definition: message.cpp:107
virtual QVariant & value()=0
static bool stringVariantToBool(const QVariant &v)
Definition: expert.cpp:875
bool htmlOutputPresent(const QString &workingDir) const
Definition: expert.cpp:898
void append(const type *d)
Definition: qlist.h:73
QSplitter * m_splitter
Definition: expert.h:60
QByteArray saveInnerState() const
Definition: expert.cpp:811
QHash< QString, Input * > m_options
Definition: expert.h:66
void refresh()
Definition: expert.cpp:954
opt
Definition: train.py:196
QPushButton * m_next
Definition: expert.h:67
static bool format(QChar::Decomposition tag, QString &str, int index, int len)
Definition: qstring.cpp:11496
virtual QString templateDocs() const =0
virtual void addDependency(Input *option)=0
Definition: model.py:1
QString m_header
Definition: expert.h:71
The QString class provides an abstraction of Unicode text and the classic C null-terminated char arra...
Definition: qstring.h:350
intermediate_table::const_iterator const_iterator
void addConfigDocs(DocIntf *doc)
#define SA(x)
Definition: expert.cpp:26
QString getHtmlOutputIndex(const QString &workingDir) const
Definition: expert.cpp:907
void setPattern(const QCString &pattern)
Definition: qregexp.h:71
static QString fromLatin1(const char *, int len=-1)
Definition: qstring.cpp:14539
def connect(nxgraph, k1, k2, p1=0, p2=0, kwds)
Definition: graph.py:30
void add(const char *name, const char *doc)
Definition: expert.cpp:48
void nextTopic()
Definition: expert.cpp:838
bool isFile() const
void createTopics(const QDomElement &)
Definition: expert.cpp:120
void showHelp(Input *)
Definition: expert.cpp:821
~Expert()
Definition: expert.cpp:110
const char * data() const
Definition: qstring.h:542
fileName
Definition: dumpTree.py:9
static bool getBoolOption(const QHash< QString, Input * > &model, const QString &name)
Definition: expert.cpp:881
QStackedWidget * m_topicStack
Definition: expert.h:63
virtual QString id() const =0
A list of strings.
Definition: qstringlist.h:51
static QString getStringOption(const QHash< QString, Input * > &model, const QString &name)
Definition: expert.cpp:889
QPushButton * m_prev
Definition: expert.h:68
std::void_t< T > n
bool open(int)
Definition: qfile_unix.cpp:134
static QString getDocsForNode(const QDomElement &child)
Definition: expert.cpp:145
char versionString[]
Definition: version.cpp:1
bool parseConfig(const QString &fileName, const QHash< QString, Input * > &options)
QString & replace(uint index, uint len, const QString &)
Definition: qstring.cpp:13665
Expert()
Definition: expert.cpp:59
void saveSettings(QSettings *)
Definition: expert.cpp:719
bool restoreInnerState(const QByteArray &state)
Definition: expert.cpp:816
void err(const char *fmt,...)
Definition: message.cpp:226
Definition: input.h:9
QTextBrowser * m_helper
Definition: expert.h:61
The QFile class is an I/O device that operates on files.
Definition: qfile.h:50
void setDefault()
The QTextStream class provides basic functions for reading and writing text using a QIODevice...
Definition: qtextstream.h:53
static QTextCodec * codecForName(const char *hint, int accuracy=0)
Definition: qtextcodec.cpp:626
int var
Definition: 018_def.c:9
void loadSettings(QSettings *)
Definition: expert.cpp:703
QDomElement m_rootElement
Definition: expert.h:69
void done()
void loadConfig(const QString &fileName)
Definition: expert.cpp:733
virtual void setTemplateDocs(const QString &docs)=0
void prevTopic()
Definition: expert.cpp:853
Provides conversion between text encodings.
Definition: qtextcodec.h:62
QHash< QString, QWidget * > m_topics
Definition: expert.h:64
#define IS_SUPPORTED(x)
Definition: settings.h:5
The QFileInfo class provides system-independent file information.
Definition: qfileinfo.h:51
virtual QString docs() const =0
bool pdfOutputPresent(const QString &workingDir) const
Definition: expert.cpp:934
QCString & replace(uint index, uint len, const char *s)
Definition: qcstring.cpp:411
static QCString * s
Definition: config.cpp:1042
void changed()
bool m_inShowHelp
Definition: expert.h:70
void resetToDefaults()
Definition: expert.cpp:861
QTextStream & endl(QTextStream &s)
Definition: qlist.h:54
bool exists() const
Definition: qfileinfo.cpp:265
static QString convertToComment(const QString &s)
Definition: expert.cpp:29
virtual void writeValue(QTextStream &t, QTextCodec *codec)=0