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