#include "expert.h" #include "inputbool.h" #include "inputstring.h" #include "inputint.h" #include "inputstring.h" #include "inputstrlist.h" #include #include #include "config.h" #include "version.h" #undef SA #define SA(x) QString::fromAscii(x) static QString convertToComment(const QString &s) { if (s.isEmpty()) { return QString(); } else { return SA("# ")+ s.trimmed().replace(SA("\n"),SA("\n# "))+ SA("\n"); } } //------------------------------------------------------------------------------------ Expert::Expert() { m_treeWidget = new QTreeWidget; m_treeWidget->setColumnCount(1); m_topicStack = new QStackedWidget; QFile file(SA(":/config.xml")); QString err; int errLine,errCol; QDomDocument configXml; if (file.open(QIODevice::ReadOnly)) { if (!configXml.setContent(&file,false,&err,&errLine,&errCol)) { QString msg = tr("Error parsing internal config.xml at line %1 column %2.\n%3"). arg(errLine).arg(errCol).arg(err); QMessageBox::warning(this, tr("Error"), msg); exit(1); } } m_rootElement = configXml.documentElement(); createTopics(m_rootElement); m_helper = new QTextEdit; m_helper->setReadOnly(true); m_splitter = new QSplitter(Qt::Vertical); m_splitter->addWidget(m_treeWidget); m_splitter->addWidget(m_helper); QWidget *rightSide = new QWidget; QGridLayout *grid = new QGridLayout(rightSide); m_prev = new QPushButton(tr("Previous")); m_prev->setEnabled(false); m_next = new QPushButton(tr("Next")); grid->addWidget(m_topicStack,0,0,1,2); grid->addWidget(m_prev,1,0,Qt::AlignLeft); grid->addWidget(m_next,1,1,Qt::AlignRight); grid->setColumnStretch(0,1); grid->setRowStretch(0,1); addWidget(m_splitter); addWidget(rightSide); connect(m_next,SIGNAL(clicked()),SLOT(nextTopic())); connect(m_prev,SIGNAL(clicked()),SLOT(prevTopic())); } Expert::~Expert() { QHashIterator i(m_options); while (i.hasNext()) { i.next(); delete i.value(); } } void Expert::createTopics(const QDomElement &rootElem) { QList items; QDomElement childElem = rootElem.firstChildElement(); while (!childElem.isNull()) { if (childElem.tagName()==SA("group")) { QString name = childElem.attribute(SA("name")); items.append(new QTreeWidgetItem((QTreeWidget*)0,QStringList(name))); QWidget *widget = createTopicWidget(childElem); m_topics[name] = widget; m_topicStack->addWidget(widget); } childElem = childElem.nextSiblingElement(); } m_treeWidget->setHeaderLabels(QStringList() << SA("Topics")); m_treeWidget->insertTopLevelItems(0,items); connect(m_treeWidget, SIGNAL(currentItemChanged(QTreeWidgetItem *,QTreeWidgetItem *)), this, SLOT(activateTopic(QTreeWidgetItem *,QTreeWidgetItem *))); } QWidget *Expert::createTopicWidget(QDomElement &elem) { QScrollArea *area = new QScrollArea; QWidget *topic = new QWidget; QGridLayout *layout = new QGridLayout(topic); QDomElement child = elem.firstChildElement(); int row=0; while (!child.isNull()) { QString type = child.attribute(SA("type")); if (type==SA("bool")) { InputBool *boolOption = new InputBool( layout,row, child.attribute(SA("id")), child.attribute(SA("defval"))==SA("1"), child.attribute(SA("docs")) ); m_options.insert( child.attribute(SA("id")), boolOption ); connect(boolOption,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*))); connect(boolOption,SIGNAL(changed()),SIGNAL(changed())); } else if (type==SA("string")) { InputString::StringMode mode; QString format = child.attribute(SA("format")); if (format==SA("dir")) { mode = InputString::StringDir; } else if (format==SA("file")) { mode = InputString::StringFile; } else // format=="string" { mode = InputString::StringFree; } InputString *stringOption = new InputString( layout,row, child.attribute(SA("id")), child.attribute(SA("defval")), mode, child.attribute(SA("docs")), child.attribute(SA("abspath")) ); m_options.insert( child.attribute(SA("id")), stringOption ); connect(stringOption,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*))); connect(stringOption,SIGNAL(changed()),SIGNAL(changed())); } else if (type==SA("enum")) { InputString *enumList = new InputString( layout,row, child.attribute(SA("id")), child.attribute(SA("defval")), InputString::StringFixed, child.attribute(SA("docs")) ); QDomElement enumVal = child.firstChildElement(); while (!enumVal.isNull()) { enumList->addValue(enumVal.attribute(SA("name"))); enumVal = enumVal.nextSiblingElement(); } enumList->setDefault(); m_options.insert(child.attribute(SA("id")),enumList); connect(enumList,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*))); connect(enumList,SIGNAL(changed()),SIGNAL(changed())); } else if (type==SA("int")) { InputInt *intOption = new InputInt( layout,row, child.attribute(SA("id")), child.attribute(SA("defval")).toInt(), child.attribute(SA("minval")).toInt(), child.attribute(SA("maxval")).toInt(), child.attribute(SA("docs")) ); m_options.insert( child.attribute(SA("id")), intOption ); connect(intOption,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*))); connect(intOption,SIGNAL(changed()),SIGNAL(changed())); } else if (type==SA("list")) { InputStrList::ListMode mode; QString format = child.attribute(SA("format")); if (format==SA("dir")) { mode = InputStrList::ListDir; } else if (format==SA("file")) { mode = InputStrList::ListFile; } else if (format==SA("filedir")) { mode = InputStrList::ListFileDir; } else // format=="string" { mode = InputStrList::ListString; } QStringList sl; QDomElement listVal = child.firstChildElement(); while (!listVal.isNull()) { sl.append(listVal.attribute(SA("name"))); listVal = listVal.nextSiblingElement(); } InputStrList *listOption = new InputStrList( layout,row, child.attribute(SA("id")), sl, mode, child.attribute(SA("docs")) ); m_options.insert( child.attribute(SA("id")), listOption ); connect(listOption,SIGNAL(showHelp(Input*)),SLOT(showHelp(Input*))); connect(listOption,SIGNAL(changed()),SIGNAL(changed())); } else if (type==SA("obsolete")) { // ignore } else // should not happen { printf("Unsupported type %s\n",qPrintable(child.attribute(SA("type")))); } child = child.nextSiblingElement(); } // compute dependencies between options child = elem.firstChildElement(); while (!child.isNull()) { QString dependsOn = child.attribute(SA("depends")); QString id = child.attribute(SA("id")); if (!dependsOn.isEmpty()) { Input *parentOption = m_options[dependsOn]; Input *thisOption = m_options[id]; Q_ASSERT(parentOption); Q_ASSERT(thisOption); if (parentOption && thisOption) { //printf("Adding dependency '%s' (%p)->'%s' (%p)\n", // qPrintable(dependsOn),parentOption, // qPrintable(id),thisOption); parentOption->addDependency(thisOption); } } child = child.nextSiblingElement(); } // set initial dependencies QHashIterator i(m_options); while (i.hasNext()) { i.next(); if (i.value()) { i.value()->updateDependencies(); } } layout->setRowStretch(row,1); layout->setColumnStretch(1,2); layout->setSpacing(5); topic->setLayout(layout); area->setWidget(topic); area->setWidgetResizable(true); return area; } void Expert::activateTopic(QTreeWidgetItem *item,QTreeWidgetItem *) { if (item) { QWidget *w = m_topics[item->text(0)]; m_topicStack->setCurrentWidget(w); m_prev->setEnabled(m_topicStack->currentIndex()!=0); m_next->setEnabled(m_topicStack->currentIndex()!=m_topicStack->count()-1); } } void Expert::loadSettings(QSettings *s) { QHashIterator i(m_options); while (i.hasNext()) { i.next(); QVariant var = s->value(SA("config/")+i.key()); //printf("Loading key %s: type=%d\n",qPrintable(i.key()),var.type()); if (i.value()) { i.value()->value() = var; i.value()->update(); } } } void Expert::saveSettings(QSettings *s) { QHashIterator i(m_options); while (i.hasNext()) { i.next(); if (i.value()) { s->value(SA("config/")+i.key(),i.value()->value()); } } } void Expert::loadConfig(const QString &fileName) { //printf("Expert::loadConfig(%s)\n",qPrintable(fileName)); parseConfig(fileName,m_options); } void Expert::saveTopic(QTextStream &t,QDomElement &elem,QTextCodec *codec, bool brief) { // write group header t << endl; t << "#---------------------------------------------------------------------------" << endl; t << "# " << elem.attribute(SA("docs")) << endl; t << "#---------------------------------------------------------------------------" << endl; // write options... QDomElement childElem = elem.firstChildElement(); while (!childElem.isNull()) { QString type = childElem.attribute(SA("type")); QString name = childElem.attribute(SA("id")); QHash::const_iterator i = m_options.find(name); if (i!=m_options.end()) { Input *option = i.value(); if (!brief) { t << endl; t << convertToComment(childElem.attribute(SA("docs"))); t << endl; } t << name.leftJustified(23) << "= "; if (option) { option->writeValue(t,codec); } t << endl; } childElem = childElem.nextSiblingElement(); } } bool Expert::writeConfig(QTextStream &t,bool brief) { if (!brief) { // write global header t << "# Doxyfile " << versionString << endl << endl; // TODO: add version t << "# This file describes the settings to be used by the documentation system\n"; t << "# doxygen (www.doxygen.org) for a project\n"; t << "#\n"; t << "# All text after a hash (#) is considered a comment and will be ignored\n"; t << "# The format is:\n"; t << "# TAG = value [value, ...]\n"; t << "# For lists items can also be appended using:\n"; t << "# TAG += value [value, ...]\n"; t << "# Values that contain spaces should be placed between quotes (\" \")\n"; } QTextCodec *codec = 0; Input *option = m_options[QString::fromAscii("DOXYFILE_ENCODING")]; if (option) { codec = QTextCodec::codecForName(option->value().toString().toAscii()); if (codec==0) // fallback: use UTF-8 { codec = QTextCodec::codecForName("UTF-8"); } } QDomElement childElem = m_rootElement.firstChildElement(); while (!childElem.isNull()) { saveTopic(t,childElem,codec,brief); childElem = childElem.nextSiblingElement(); } return true; } QByteArray Expert::saveInnerState () const { return m_splitter->saveState(); } bool Expert::restoreInnerState ( const QByteArray & state ) { return m_splitter->restoreState(state); } void Expert::showHelp(Input *option) { m_helper->setText( QString::fromAscii("")+option->id()+ QString::fromAscii("
")+ option->docs(). replace(QChar::fromAscii('\n'),QChar::fromAscii(' '))+ QString::fromAscii("") ); } void Expert::nextTopic() { m_topicStack->setCurrentIndex(m_topicStack->currentIndex()+1); m_next->setEnabled(m_topicStack->count()!=m_topicStack->currentIndex()+1); m_prev->setEnabled(m_topicStack->currentIndex()!=0); m_treeWidget->setCurrentItem(m_treeWidget->invisibleRootItem()->child(m_topicStack->currentIndex())); } void Expert::prevTopic() { m_topicStack->setCurrentIndex(m_topicStack->currentIndex()-1); m_next->setEnabled(m_topicStack->count()!=m_topicStack->currentIndex()+1); m_prev->setEnabled(m_topicStack->currentIndex()!=0); m_treeWidget->setCurrentItem(m_treeWidget->invisibleRootItem()->child(m_topicStack->currentIndex())); } void Expert::resetToDefaults() { //printf("Expert::makeDefaults()\n"); QHashIterator i(m_options); while (i.hasNext()) { i.next(); if (i.value()) { i.value()->reset(); } } } static bool stringVariantToBool(const QVariant &v) { QString s = v.toString().toLower(); return s==QString::fromAscii("yes") || s==QString::fromAscii("true") || s==QString::fromAscii("1"); } static bool getBoolOption( const QHash&model,const QString &name) { Input *option = model[name]; Q_ASSERT(option!=0); return stringVariantToBool(option->value()); } static QString getStringOption( const QHash&model,const QString &name) { Input *option = model[name]; Q_ASSERT(option!=0); return option->value().toString(); } bool Expert::htmlOutputPresent(const QString &workingDir) const { bool generateHtml = getBoolOption(m_options,QString::fromAscii("GENERATE_HTML")); if (!generateHtml || workingDir.isEmpty()) return false; QString indexFile = getHtmlOutputIndex(workingDir); QFileInfo fi(indexFile); return fi.exists() && fi.isFile(); } QString Expert::getHtmlOutputIndex(const QString &workingDir) const { QString outputDir = getStringOption(m_options,QString::fromAscii("OUTPUT_DIRECTORY")); QString htmlOutputDir = getStringOption(m_options,QString::fromAscii("HTML_OUTPUT")); //printf("outputDir=%s\n",qPrintable(outputDir)); //printf("htmlOutputDir=%s\n",qPrintable(htmlOutputDir)); QString indexFile = workingDir; if (QFileInfo(outputDir).isAbsolute()) // override { indexFile = outputDir; } else // append { indexFile += QString::fromAscii("/")+outputDir; } if (QFileInfo(htmlOutputDir).isAbsolute()) // override { indexFile = htmlOutputDir; } else // append { indexFile += QString::fromAscii("/")+htmlOutputDir; } indexFile+=QString::fromAscii("/index.html"); return indexFile; } bool Expert::pdfOutputPresent(const QString &workingDir) const { bool generateLatex = getBoolOption(m_options,QString::fromAscii("GENERATE_LATEX")); bool pdfLatex = getBoolOption(m_options,QString::fromAscii("USE_PDFLATEX")); if (!generateLatex || !pdfLatex) return false; QString latexOutput = getStringOption(m_options,QString::fromAscii("LATEX_OUTPUT")); QString indexFile; if (QFileInfo(latexOutput).isAbsolute()) { indexFile = latexOutput+QString::fromAscii("/refman.pdf"); } else { indexFile = workingDir+QString::fromAscii("/")+ latexOutput+QString::fromAscii("/refman.pdf"); } QFileInfo fi(indexFile); return fi.exists() && fi.isFile(); }