Chameleon

Chameleon Svn Source Tree

Root/branches/xZenu/src/util/doxygen/addon/doxywizard/expert.cpp

Source at commit 1322 created 9 years 5 months ago.
By meklort, Add doxygen to utils folder
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 <QtGui>
8#include <QtXml>
9#include "config.h"
10#include "version.h"
11
12#undef SA
13#define SA(x) QString::fromAscii(x)
14
15static QString convertToComment(const QString &s)
16{
17 if (s.isEmpty())
18 {
19 return QString();
20 }
21 else
22 {
23 return SA("# ")+
24 s.trimmed().replace(SA("\n"),SA("\n# "))+
25 SA("\n");
26 }
27}
28
29//------------------------------------------------------------------------------------
30
31Expert::Expert()
32{
33 m_treeWidget = new QTreeWidget;
34 m_treeWidget->setColumnCount(1);
35 m_topicStack = new QStackedWidget;
36 m_inShowHelp = FALSE;
37
38 QFile file(SA(":/config.xml"));
39 QString err;
40 int errLine,errCol;
41 QDomDocument configXml;
42 if (file.open(QIODevice::ReadOnly))
43 {
44 if (!configXml.setContent(&file,false,&err,&errLine,&errCol))
45 {
46 QString msg = tr("Error parsing internal config.xml at line %1 column %2.\n%3").
47 arg(errLine).arg(errCol).arg(err);
48 QMessageBox::warning(this, tr("Error"), msg);
49 exit(1);
50 }
51 }
52 m_rootElement = configXml.documentElement();
53
54 createTopics(m_rootElement);
55 m_helper = new QTextEdit;
56 m_helper->setReadOnly(true);
57 m_splitter = new QSplitter(Qt::Vertical);
58 m_splitter->addWidget(m_treeWidget);
59 m_splitter->addWidget(m_helper);
60
61 QWidget *rightSide = new QWidget;
62 QGridLayout *grid = new QGridLayout(rightSide);
63 m_prev = new QPushButton(tr("Previous"));
64 m_prev->setEnabled(false);
65 m_next = new QPushButton(tr("Next"));
66 grid->addWidget(m_topicStack,0,0,1,2);
67 grid->addWidget(m_prev,1,0,Qt::AlignLeft);
68 grid->addWidget(m_next,1,1,Qt::AlignRight);
69 grid->setColumnStretch(0,1);
70 grid->setRowStretch(0,1);
71
72 addWidget(m_splitter);
73 addWidget(rightSide);
74 connect(m_next,SIGNAL(clicked()),SLOT(nextTopic()));
75
76 connect(m_prev,SIGNAL(clicked()),SLOT(prevTopic()));
77}
78
79Expert::~Expert()
80{
81 QHashIterator<QString,Input*> i(m_options);
82 while (i.hasNext())
83 {
84 i.next();
85 delete i.value();
86 }
87}
88
89void Expert::createTopics(const QDomElement &rootElem)
90{
91 QList<QTreeWidgetItem*> items;
92 QDomElement childElem = rootElem.firstChildElement();
93 while (!childElem.isNull())
94 {
95 if (childElem.tagName()==SA("group"))
96 {
97 QString name = childElem.attribute(SA("name"));
98 items.append(new QTreeWidgetItem((QTreeWidget*)0,QStringList(name)));
99 QWidget *widget = createTopicWidget(childElem);
100 m_topics[name] = widget;
101 m_topicStack->addWidget(widget);
102 }
103 childElem = childElem.nextSiblingElement();
104 }
105 m_treeWidget->setHeaderLabels(QStringList() << SA("Topics"));
106 m_treeWidget->insertTopLevelItems(0,items);
107 connect(m_treeWidget,
108 SIGNAL(currentItemChanged(QTreeWidgetItem *,QTreeWidgetItem *)),
109 this,
110 SLOT(activateTopic(QTreeWidgetItem *,QTreeWidgetItem *)));
111}
112
113
114QWidget *Expert::createTopicWidget(QDomElement &elem)
115{
116 QScrollArea *area = new QScrollArea;
117 QWidget *topic = new QWidget;
118 QGridLayout *layout = new QGridLayout(topic);
119 QDomElement child = elem.firstChildElement();
120 int row=0;
121 while (!child.isNull())
122 {
123 QString type = child.attribute(SA("type"));
124 if (type==SA("bool"))
125 {
126 InputBool *boolOption =
127 new InputBool(
128 layout,row,
129 child.attribute(SA("id")),
130 child.attribute(SA("defval"))==SA("1"),
131 child.attribute(SA("docs"))
132 );
133 m_options.insert(
134 child.attribute(SA("id")),
135 boolOption
136 );
137 connect(boolOption,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*)));
138 connect(boolOption,SIGNAL(changed()),SIGNAL(changed()));
139 }
140 else if (type==SA("string"))
141 {
142 InputString::StringMode mode;
143 QString format = child.attribute(SA("format"));
144 if (format==SA("dir"))
145 {
146 mode = InputString::StringDir;
147 }
148 else if (format==SA("file"))
149 {
150 mode = InputString::StringFile;
151 }
152 else // format=="string"
153 {
154 mode = InputString::StringFree;
155 }
156 InputString *stringOption =
157 new InputString(
158 layout,row,
159 child.attribute(SA("id")),
160 child.attribute(SA("defval")),
161 mode,
162 child.attribute(SA("docs")),
163 child.attribute(SA("abspath"))
164 );
165 m_options.insert(
166 child.attribute(SA("id")),
167 stringOption
168 );
169 connect(stringOption,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*)));
170 connect(stringOption,SIGNAL(changed()),SIGNAL(changed()));
171 }
172 else if (type==SA("enum"))
173 {
174 InputString *enumList = new InputString(
175 layout,row,
176 child.attribute(SA("id")),
177 child.attribute(SA("defval")),
178 InputString::StringFixed,
179 child.attribute(SA("docs"))
180 );
181 QDomElement enumVal = child.firstChildElement();
182 while (!enumVal.isNull())
183 {
184 enumList->addValue(enumVal.attribute(SA("name")));
185 enumVal = enumVal.nextSiblingElement();
186 }
187 enumList->setDefault();
188
189 m_options.insert(child.attribute(SA("id")),enumList);
190 connect(enumList,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*)));
191 connect(enumList,SIGNAL(changed()),SIGNAL(changed()));
192 }
193 else if (type==SA("int"))
194 {
195 InputInt *intOption =
196 new InputInt(
197 layout,row,
198 child.attribute(SA("id")),
199 child.attribute(SA("defval")).toInt(),
200 child.attribute(SA("minval")).toInt(),
201 child.attribute(SA("maxval")).toInt(),
202 child.attribute(SA("docs"))
203 );
204 m_options.insert(
205 child.attribute(SA("id")),
206 intOption
207 );
208 connect(intOption,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*)));
209 connect(intOption,SIGNAL(changed()),SIGNAL(changed()));
210 }
211 else if (type==SA("list"))
212 {
213 InputStrList::ListMode mode;
214 QString format = child.attribute(SA("format"));
215 if (format==SA("dir"))
216 {
217 mode = InputStrList::ListDir;
218 }
219 else if (format==SA("file"))
220 {
221 mode = InputStrList::ListFile;
222 }
223 else if (format==SA("filedir"))
224 {
225 mode = InputStrList::ListFileDir;
226 }
227 else // format=="string"
228 {
229 mode = InputStrList::ListString;
230 }
231 QStringList sl;
232 QDomElement listVal = child.firstChildElement();
233 while (!listVal.isNull())
234 {
235 sl.append(listVal.attribute(SA("name")));
236 listVal = listVal.nextSiblingElement();
237 }
238 InputStrList *listOption =
239 new InputStrList(
240 layout,row,
241 child.attribute(SA("id")),
242 sl,
243 mode,
244 child.attribute(SA("docs"))
245 );
246 m_options.insert(
247 child.attribute(SA("id")),
248 listOption
249 );
250 connect(listOption,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*)));
251 connect(listOption,SIGNAL(changed()),SIGNAL(changed()));
252 }
253 else if (type==SA("obsolete"))
254 {
255 // ignore
256 }
257 else // should not happen
258 {
259 printf("Unsupported type %s\n",qPrintable(child.attribute(SA("type"))));
260 }
261 child = child.nextSiblingElement();
262 }
263
264 // compute dependencies between options
265 child = elem.firstChildElement();
266 while (!child.isNull())
267 {
268 QString dependsOn = child.attribute(SA("depends"));
269 QString id = child.attribute(SA("id"));
270 if (!dependsOn.isEmpty())
271 {
272 Input *parentOption = m_options[dependsOn];
273 Input *thisOption = m_options[id];
274 Q_ASSERT(parentOption);
275 Q_ASSERT(thisOption);
276 if (parentOption && thisOption)
277 {
278 //printf("Adding dependency '%s' (%p)->'%s' (%p)\n",
279 // qPrintable(dependsOn),parentOption,
280 // qPrintable(id),thisOption);
281 parentOption->addDependency(thisOption);
282 }
283 }
284 child = child.nextSiblingElement();
285 }
286
287 // set initial dependencies
288 QHashIterator<QString,Input*> i(m_options);
289 while (i.hasNext())
290 {
291 i.next();
292 if (i.value())
293 {
294 i.value()->updateDependencies();
295 }
296 }
297
298 layout->setRowStretch(row,1);
299 layout->setColumnStretch(1,2);
300 layout->setSpacing(5);
301 topic->setLayout(layout);
302 area->setWidget(topic);
303 area->setWidgetResizable(true);
304 return area;
305}
306
307void Expert::activateTopic(QTreeWidgetItem *item,QTreeWidgetItem *)
308{
309 if (item)
310 {
311 QWidget *w = m_topics[item->text(0)];
312 m_topicStack->setCurrentWidget(w);
313 m_prev->setEnabled(m_topicStack->currentIndex()!=0);
314 m_next->setEnabled(m_topicStack->currentIndex()!=m_topicStack->count()-1);
315 }
316}
317
318void Expert::loadSettings(QSettings *s)
319{
320 QHashIterator<QString,Input*> i(m_options);
321 while (i.hasNext())
322 {
323 i.next();
324 QVariant var = s->value(SA("config/")+i.key());
325 if (i.value())
326 {
327 //printf("Loading key %s: type=%d value='%s'\n",qPrintable(i.key()),var.type(),qPrintable(var.toString()));
328 i.value()->value() = var;
329 i.value()->update();
330 }
331 }
332}
333
334void Expert::saveSettings(QSettings *s)
335{
336 QHashIterator<QString,Input*> i(m_options);
337 while (i.hasNext())
338 {
339 i.next();
340 //printf("Saving key %s: type=%d value='%s'\n",qPrintable(i.key()),i.value()->value().type(),qPrintable(i.value()->value().toString()));
341 if (i.value())
342 {
343 s->setValue(SA("config/")+i.key(),i.value()->value());
344 }
345 }
346}
347
348void Expert::loadConfig(const QString &fileName)
349{
350 //printf("Expert::loadConfig(%s)\n",qPrintable(fileName));
351 parseConfig(fileName,m_options);
352}
353
354void Expert::saveTopic(QTextStream &t,QDomElement &elem,QTextCodec *codec,
355 bool brief)
356{
357 // write group header
358 t << endl;
359 t << "#---------------------------------------------------------------------------" << endl;
360 t << "# " << elem.attribute(SA("docs")) << endl;
361 t << "#---------------------------------------------------------------------------" << endl;
362
363 // write options...
364 QDomElement childElem = elem.firstChildElement();
365 while (!childElem.isNull())
366 {
367 QString type = childElem.attribute(SA("type"));
368 QString name = childElem.attribute(SA("id"));
369 QHash<QString,Input*>::const_iterator i = m_options.find(name);
370 if (i!=m_options.end())
371 {
372 Input *option = i.value();
373 if (!brief)
374 {
375 t << endl;
376 t << convertToComment(childElem.attribute(SA("docs")));
377 t << endl;
378 }
379 t << name.leftJustified(23) << "= ";
380 if (option)
381 {
382 option->writeValue(t,codec);
383 }
384 t << endl;
385 }
386 childElem = childElem.nextSiblingElement();
387 }
388
389}
390
391bool Expert::writeConfig(QTextStream &t,bool brief)
392{
393 if (!brief)
394 {
395 // write global header
396 t << "# Doxyfile " << versionString << endl << endl; // TODO: add version
397 t << "# This file describes the settings to be used by the documentation system\n";
398 t << "# doxygen (www.doxygen.org) for a project\n";
399 t << "#\n";
400 t << "# All text after a hash (#) is considered a comment and will be ignored\n";
401 t << "# The format is:\n";
402 t << "# TAG = value [value, ...]\n";
403 t << "# For lists items can also be appended using:\n";
404 t << "# TAG += value [value, ...]\n";
405 t << "# Values that contain spaces should be placed between quotes (\" \")\n";
406 }
407
408 QTextCodec *codec = 0;
409 Input *option = m_options[QString::fromAscii("DOXYFILE_ENCODING")];
410 if (option)
411 {
412 codec = QTextCodec::codecForName(option->value().toString().toAscii());
413 if (codec==0) // fallback: use UTF-8
414 {
415 codec = QTextCodec::codecForName("UTF-8");
416 }
417 }
418 QDomElement childElem = m_rootElement.firstChildElement();
419 while (!childElem.isNull())
420 {
421 saveTopic(t,childElem,codec,brief);
422 childElem = childElem.nextSiblingElement();
423 }
424 return true;
425}
426
427QByteArray Expert::saveInnerState () const
428{
429 return m_splitter->saveState();
430}
431
432bool Expert::restoreInnerState ( const QByteArray & state )
433{
434 return m_splitter->restoreState(state);
435}
436
437void Expert::showHelp(Input *option)
438{
439 if (!m_inShowHelp)
440 {
441 m_inShowHelp = TRUE;
442 m_helper->setText(
443 QString::fromAscii("<qt><b>")+option->id()+
444 QString::fromAscii("</b><br>")+
445 option->docs().
446 replace(QChar::fromAscii('\n'),QChar::fromAscii(' '))+
447 QString::fromAscii("<qt>")
448 );
449 m_inShowHelp = FALSE;
450 }
451}
452
453void Expert::nextTopic()
454{
455 m_topicStack->setCurrentIndex(m_topicStack->currentIndex()+1);
456 m_next->setEnabled(m_topicStack->count()!=m_topicStack->currentIndex()+1);
457 m_prev->setEnabled(m_topicStack->currentIndex()!=0);
458 m_treeWidget->setCurrentItem(m_treeWidget->invisibleRootItem()->child(m_topicStack->currentIndex()));
459}
460
461void Expert::prevTopic()
462{
463 m_topicStack->setCurrentIndex(m_topicStack->currentIndex()-1);
464 m_next->setEnabled(m_topicStack->count()!=m_topicStack->currentIndex()+1);
465 m_prev->setEnabled(m_topicStack->currentIndex()!=0);
466 m_treeWidget->setCurrentItem(m_treeWidget->invisibleRootItem()->child(m_topicStack->currentIndex()));
467}
468
469void Expert::resetToDefaults()
470{
471 //printf("Expert::makeDefaults()\n");
472 QHashIterator<QString,Input*> i(m_options);
473 while (i.hasNext())
474 {
475 i.next();
476 if (i.value())
477 {
478 i.value()->reset();
479 }
480 }
481}
482
483static bool stringVariantToBool(const QVariant &v)
484{
485 QString s = v.toString().toLower();
486 return s==QString::fromAscii("yes") || s==QString::fromAscii("true") || s==QString::fromAscii("1");
487}
488
489static bool getBoolOption(
490 const QHash<QString,Input*>&model,const QString &name)
491{
492 Input *option = model[name];
493 Q_ASSERT(option!=0);
494 return stringVariantToBool(option->value());
495}
496
497static QString getStringOption(
498 const QHash<QString,Input*>&model,const QString &name)
499{
500 Input *option = model[name];
501 Q_ASSERT(option!=0);
502 return option->value().toString();
503}
504
505
506bool Expert::htmlOutputPresent(const QString &workingDir) const
507{
508 bool generateHtml = getBoolOption(m_options,QString::fromAscii("GENERATE_HTML"));
509 if (!generateHtml || workingDir.isEmpty()) return false;
510 QString indexFile = getHtmlOutputIndex(workingDir);
511 QFileInfo fi(indexFile);
512 return fi.exists() && fi.isFile();
513}
514
515QString Expert::getHtmlOutputIndex(const QString &workingDir) const
516{
517 QString outputDir = getStringOption(m_options,QString::fromAscii("OUTPUT_DIRECTORY"));
518 QString htmlOutputDir = getStringOption(m_options,QString::fromAscii("HTML_OUTPUT"));
519 //printf("outputDir=%s\n",qPrintable(outputDir));
520 //printf("htmlOutputDir=%s\n",qPrintable(htmlOutputDir));
521 QString indexFile = workingDir;
522 if (QFileInfo(outputDir).isAbsolute()) // override
523 {
524 indexFile = outputDir;
525 }
526 else // append
527 {
528 indexFile += QString::fromAscii("/")+outputDir;
529 }
530 if (QFileInfo(htmlOutputDir).isAbsolute()) // override
531 {
532 indexFile = htmlOutputDir;
533 }
534 else // append
535 {
536 indexFile += QString::fromAscii("/")+htmlOutputDir;
537 }
538 indexFile+=QString::fromAscii("/index.html");
539 return indexFile;
540}
541
542bool Expert::pdfOutputPresent(const QString &workingDir) const
543{
544 bool generateLatex = getBoolOption(m_options,QString::fromAscii("GENERATE_LATEX"));
545 bool pdfLatex = getBoolOption(m_options,QString::fromAscii("USE_PDFLATEX"));
546 if (!generateLatex || !pdfLatex) return false;
547 QString latexOutput = getStringOption(m_options,QString::fromAscii("LATEX_OUTPUT"));
548 QString indexFile;
549 if (QFileInfo(latexOutput).isAbsolute())
550 {
551 indexFile = latexOutput+QString::fromAscii("/refman.pdf");
552 }
553 else
554 {
555 indexFile = workingDir+QString::fromAscii("/")+
556 latexOutput+QString::fromAscii("/refman.pdf");
557 }
558 QFileInfo fi(indexFile);
559 return fi.exists() && fi.isFile();
560}
561
562

Archive Download this file

Revision: 1322