4 #include <QxtHtmlTemplate>
9 #include <QCoreApplication>
34 QList<Class *> classes;
38 bool sortClassBynameLessThen(const Class *s1, const Class *s2)
40 return s1->name < s2->name;
42 bool sortModuleBynameLessThen(const Module *s1, const Module *s2)
44 return s1->name < s2->name;
50 ///information collected from the xml files
51 QList<Class *> classes;
52 QList<Class *> publiclasses;
53 QList<Module *> modules;
63 Class * findClassByRef(QString ref)
65 foreach(Class * c,classes)
70 qFatal("ref %s invalid",qPrintable(ref));
80 QString refToLink( QString ref)
82 QStringList e=ref.split("_");
84 QString object=e.at(0);
91 ///FIXME that's a dirty hack. Might not actualy be sane
92 ///TODO external reference resolving
93 if (!object.contains("Qxt"))
95 object="http://doc.trolltech.com/latest/"+object;
97 if (sub.startsWith("1"))
103 return object+".html#"+sub;
105 return object+".html";
114 QString descRTF(QDomElement element)
116 ///TODO parse the rest
124 for(QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling())
128 QDomElement e= n.toElement();
129 if(e.tagName ()=="para")
131 text += "<p>"+descRTF(e)+"</p>";
133 else if(e.tagName ()=="programlisting")
135 text += "<div class=\"code\">"+descRTF(e)+"</div>";
137 else if(e.tagName ()=="codeline")
139 text += descRTF(e)+"<br/>\r\n";
141 else if(e.tagName ()=="highlight")
143 text += "<span class=\"highlight_"+e.attribute("class")+"\" >"+descRTF(e)+"</span>";
145 else if(e.tagName ()=="ref")
147 ///ignore namespaces, we don't have them
148 if(e.attribute("refid").startsWith("namespace"))
151 text += "<a class=\"reflink\" href=\""+refToLink(e.attribute("refid"))+"\">"+descRTF(e)+"</a>";
153 else if(e.tagName ()=="image")
155 QString s=descRTF(e);
156 text += "<table class=\"descimg\" ><tr><td><img alt=\""+s+"\" src=\""+e.attribute("name")+"\"></td></tr>";
157 text += "<tr><td><sup>"+s+"</sup></td></tr></table>";
159 else if(e.tagName ()=="linebreak")
165 text += e.text().replace("<","<").replace(">",">")+" ";
168 else if (n.isText ())
170 text += n.toText().data().replace("<","<").replace(">",">");
181 ///fill classes and modules globals
182 void parseIndex(QString location)
186 QDomDocument doc("doc");
187 QFile file(location+"/index.xml");
188 if (!file.open(QIODevice::ReadOnly))
189 qFatal("cannot open file");
194 if (!doc.setContent(&file,&errorMsg,&errorLine,&errorColumn))
196 qCritical("%s:%i:%i %s",qPrintable(location+"/index.xml"),errorLine,errorColumn,qPrintable(errorMsg));
200 QDomElement docElem = doc.documentElement();
201 if(docElem.tagName ()!="doxygenindex")
202 qFatal("unexpected top node in %s",qPrintable(location+"/index.xml"));
205 QDomElement e = docElem.firstChildElement("compound");
208 if (e.attribute("kind")=="class")
210 Class * cl=new Class;
212 cl->name=e.firstChildElement("name").text();
213 cl->ref=e.attribute("refid");
216 else if (e.attribute("kind")=="group")
218 Module * cl=new Module;
219 cl->name=e.firstChildElement("name").text();
220 cl->ref=e.attribute("refid");
225 qWarning("no way to document %s",qPrintable(e.attribute("kind")));
227 e = e.nextSiblingElement("compound");
234 void parseModule(QString location,Module *m)
236 QDomDocument doc("doc");
237 QString filename=location+"/"+m->ref+".xml";
239 QFile file(filename);
240 if (!file.open(QIODevice::ReadOnly))
241 qFatal("cannot open file %s",qPrintable(filename));
246 if (!doc.setContent(&file,&errorMsg,&errorLine,&errorColumn))
248 qCritical("%s:%i:%i %s",qPrintable(filename),errorLine,errorColumn,qPrintable(errorMsg));
252 QDomElement docElem = doc.documentElement();
253 QDomElement def = docElem.firstChildElement("compounddef");
254 if(def.attribute("id")!=m->ref)
255 qFatal("combound def %s not expected in %s",qPrintable(def.attribute("id")),qPrintable(filename));
259 m->desc=descRTF(def.firstChildElement("detaileddescription"));
263 QDomElement e = def.firstChildElement("innerclass");
266 if (e.attribute("prot")=="public")
268 Class * cll=findClassByRef(e.attribute("refid"));
269 m->classes.append(cll);
274 qWarning("non public member in %s",qPrintable(m->ref));
276 e = e.nextSiblingElement("innerclass");
282 QString printPublicClasses()
286 if(!t.open(templateDir+"/classes.html"))qFatal("cannot open template");
288 if(!t_i.open(templateDir+"/classes-unroll.html"))qFatal("cannot open template");
291 uint trs=classes.count()/4;
292 QHash<uint,QString> rowstring;
295 QString lastChar=" ";
296 foreach(Class * cl,publiclasses)
298 if (cl->name.count()<3)qFatal("bad class name %s",qPrintable(cl->name));
301 if(cl->name.at(3)!=lastChar.at(0))
303 lastChar=cl->name.at(3);
304 rowstring[cr]+="<th>"+lastChar+"</th>";
311 t_i["name"]=cl->name;
312 t_i["link"]=refToLink(cl->ref);
314 rowstring[cr]+=t_i.render();
320 foreach(QString rowstr, rowstring.values())
322 t["unroll"]+="<tr>\r\n"+rowstr+"</tr>\r\n\r\n";
332 QString printModules()
335 if(!t.open(templateDir+"/modules.html"))qFatal("cannot open template");
337 if(!t_i.open(templateDir+"/modules-unroll.html"))qFatal("cannot open template");
343 foreach(Module * cl,modules)
347 t_i["iseven"]=QString::number(i%2);
348 t_i["name"]=cl->name;
349 t_i["link"]=cl->ref+".html";
350 t_i["desc"]=cl->desc;
351 t["unroll"]+=t_i.render();
363 QString printClass(QString location,Class * cl)
365 QDomDocument doc("doc");
366 QString filename=location+"/"+cl->ref+".xml";
368 QFile file(filename);
370 if (!file.open(QIODevice::ReadOnly))
371 qFatal("cannot open file %s",qPrintable(filename));
377 if (!doc.setContent(&file,&errorMsg,&errorLine,&errorColumn))
379 qCritical("%s:%i:%i %s",qPrintable(filename),errorLine,errorColumn,qPrintable(errorMsg));
380 return QString("%1:%2:%3 %4").arg(filename).arg(errorLine)
381 .arg(errorColumn).arg(errorMsg);
385 QDomElement docElem = doc.documentElement();
386 if(docElem.tagName ()!="doxygen")
387 qFatal("unexpected top node in %s",qPrintable(filename));
388 QDomElement def = docElem.firstChildElement("compounddef");
393 if(!t.open(templateDir+"/class.html"))qFatal("cannot open template");
399 t["class_name"]=def.firstChildElement("compoundname").text();
400 t["ref"]=def.attribute("id");
404 t["module_name"]=cl->module->name;
405 t["module_link"]=cl->module->ref+".html";
408 qWarning("class %s has no module defined",qPrintable(cl->name));
414 cl->desc=def.firstChildElement("briefdescription").text();
415 t["desc_short"]=cl->desc;
416 t["desc_detailed"]=descRTF(def.firstChildElement("detaileddescription"));
422 QDomElement basecompoundref =def.firstChildElement("basecompoundref");
423 if(!basecompoundref.isNull())
426 if(!t_i.open(templateDir+"/class-unroll-inherits.html"))qFatal("cannot open template");
427 t_i["name"]=basecompoundref.text();
428 t_i["link"]=refToLink(basecompoundref.attribute("refid"));
429 t["inherits"]=t_i.render();
436 QxtHtmlTemplate t_section,t_members_unroll,t_impl;
437 if(!t_section.open(templateDir+"/class-section.html"))qFatal("cannot open template");
438 if(!t_members_unroll.open(templateDir+"/class-section-unroll.html"))qFatal("cannot open template");
439 if(!t_impl.open(templateDir+"/class-impl.html"))qFatal("cannot open template");
441 QDomElement sectiondef=def.firstChildElement("sectiondef");
442 while(!sectiondef.isNull())
444 if(sectiondef.attribute("kind").startsWith("private"))///skip private stuff
446 sectiondef = sectiondef.nextSiblingElement("sectiondef");
453 t_section["kind"]=sectiondef.attribute("kind");
454 t_section["desc"]=sectiondef.attribute("kind"); ///TODO: map kind to desc
459 qDebug()<<"parsing section "<<t_section["kind"];
461 QDomElement member=sectiondef.firstChildElement("memberdef");
462 while(!member.isNull())
464 qDebug()<<"parsing member "<<member.firstChildElement("name").text();
466 t_members_unroll.clear();
467 t_members_unroll["name"]=member.firstChildElement("name").text();
468 t_members_unroll["signature"]=member.firstChildElement("argsstring").text();
469 t_members_unroll["type"]=member.firstChildElement("type").text();
470 t_members_unroll["link"]=refToLink(member.attribute("id"));
472 t_section["list"]+=t_members_unroll.render();
476 ///Member Function Documentation (impl)
479 QStringList lii=member.attribute("id").split("_");
481 t_impl["ref"]=lii.at(1);
483 t_impl["ref"]=lii.at(0);
485 t_impl["name"]=member.firstChildElement("name").text();
486 t_impl["signature"]=member.firstChildElement("argsstring").text();
487 t_impl["type"]=member.firstChildElement("type").text();
488 t_impl["desc"]=descRTF(member.firstChildElement("detaileddescription"));
491 t["impl"]+=t_impl.render();
493 member = member.nextSiblingElement("memberdef");
497 t["sections"]+=t_section.render();
499 sectiondef = sectiondef.nextSiblingElement("sectiondef");
512 QString printModule(Module * m)
515 if(!t.open(templateDir+"/module.html"))qFatal("cannot open template");
517 if(!t_i.open(templateDir+"/modules-unroll.html"))qFatal("cannot open template");
523 qSort(m->classes.begin(), m->classes.end(), sortClassBynameLessThen);
524 foreach(Class * cl,m->classes)
528 t_i["iseven"]=QString::number(i%2);
529 t_i["name"]=cl->name;
530 t_i["link"]=cl->ref+".html";
531 t_i["desc"]=cl->desc;
532 t["unroll"]+=t_i.render();
541 QString printListOfMembers(QString location,Class * cl)
543 QDomDocument doc("doc");
544 QFile file(location+"/"+cl->ref+".xml");
545 if (!file.open(QIODevice::ReadOnly))
546 qFatal("cannot open file %s",qPrintable(location+"/"+cl->ref+".xml"));
551 if (!doc.setContent(&file,&errorMsg,&errorLine,&errorColumn))
553 qCritical("%s:%i:%i %s",qPrintable(location+"/"+cl->ref+".xml"),errorLine,errorColumn,qPrintable(errorMsg));
554 return QString("%1:%2:%3 %4").arg(location+"/index.xml").arg(errorLine)
555 .arg(errorColumn).arg(errorMsg);
559 QDomElement docElem = doc.documentElement();
560 if(docElem.tagName ()!="doxygen")
561 qFatal("unexpected top node in %s",qPrintable(location+"/"+cl->ref+".xml"));
562 QDomElement def = docElem.firstChildElement("compounddef");
567 if(!t.open(templateDir+"/class-members.html"))qFatal("cannot open template");
571 t["class_name"]=def.firstChildElement("compoundname").text();
572 t["ref"]=def.attribute("id");
575 QDomElement list =def.firstChildElement("listofallmembers");
579 if(!t_i.open(templateDir+"/class-members-unroll.html"))
580 qFatal("cannot open template");
583 QDomElement member=list.firstChildElement("member");
584 while(!member.isNull())
586 if(member.attribute("prot")=="private")///skip private members
588 member = member.nextSiblingElement("memberdef");
595 t_i["name"]=member.firstChildElement("name").text();
596 t_i["link"]=refToLink(member.attribute("refid"));
597 t["list"]+=t_i.render();
598 member = member.nextSiblingElement("member");
610 void wrapToFile(QString filename,QString content)
613 QxtHtmlTemplate site;
614 if(!site.open(templateDir+"/site.html"))qFatal("cannot open template");
615 site["content"]=content;
617 QFile file(outputDir+"/"+filename);
618 if (!file.open(QIODevice::WriteOnly))
619 qFatal("cannot open output file %s",qPrintable(filename));
621 file.write(site.render().toUtf8());
631 int main(int argc,char ** argv)
634 QCoreApplication app(argc,argv);
635 qDebug("[greetings]");
638 QString settingsfile="Doqsyfile";
641 if(app.arguments().count()>1)
643 settingsfile=app.arguments().at(1);
646 if(!QFileInfo(settingsfile).exists())
647 qFatal("cannot open %s",qPrintable(settingsfile));
649 if (!QDir::setCurrent (QFileInfo(settingsfile).absolutePath ()))
650 qFatal("unable to change working directory to %s",qPrintable(QFileInfo(settingsfile).absolutePath ()));
652 QSettings settings(settingsfile,QSettings::IniFormat);
653 settings.beginGroup ("doqsy");
654 outputDir=settings.value("output","doc").toString();
655 templateDir=settings.value("templates","templates").toString();
656 QString doxyexe=settings.value("doxygen","doxygen").toString();
660 QDir().mkpath(outputDir);
665 if(!QDir::temp().mkpath("doqsytmp"))
666 qFatal("cannot make temp dir");
667 xmlDir=QDir::tempPath()+"doqsytmp";
673 QString doxygeninput;
675 settings.beginGroup ("doxygen");
676 foreach(QString key,settings.allKeys())
678 doxygeninput+=(key+"="+settings.value(key).toString()+"\r\n");
682 doxygeninput+= "XML_OUTPUT = "+xmlDir+"\r\n"
683 "OUTPUT_DIRECTORY = "+QDir::tempPath()+"\r\n"
684 "GENERATE_XML = YES\r\n";
688 qDebug("[running doxygen]");
691 QProcess doxygenprocess;
693 doxygenprocess.setProcessChannelMode(QProcess::ForwardedChannels);
695 doxygenprocess.setWorkingDirectory (QDir().absolutePath ());
697 doxygenprocess.start (doxyexe,QStringList()<<"-");
699 if(!doxygenprocess.waitForStarted ())
700 qFatal("doxygen failed to start");
702 doxygenprocess.write(doxygeninput.toUtf8());
704 doxygenprocess.closeWriteChannel();
706 if(!doxygenprocess.waitForFinished (120000))
707 qFatal("doxygen failed to finish within 2 minutes");
709 if(doxygenprocess.exitCode ())
710 qFatal("doxygen run unsecussfull");
713 qDebug("[beginn parsing]");
718 qSort(classes.begin(), classes.end(), sortClassBynameLessThen);
719 qSort(modules.begin(), modules.end(), sortModuleBynameLessThen);
721 foreach(Module * m,modules)
723 qDebug()<<"parsing module"<<m->ref;
724 parseModule(xmlDir,m);
725 publiclasses+=m->classes;
728 wrapToFile("modules.html",printModules());
730 qSort(publiclasses.begin(), publiclasses.end(), sortClassBynameLessThen);
731 wrapToFile("classes.html",printPublicClasses());
737 foreach(Class * c,classes)
739 qDebug()<<"parsing class "<<c->name;
740 wrapToFile(c->ref+".html",printClass(xmlDir,c));
741 wrapToFile(c->ref+"-members.html",printListOfMembers(xmlDir,c));
744 foreach(Module * m,modules)
746 wrapToFile(m->ref+".html",printModule(m));
753 if(!t_i.open(templateDir+"/index.html"))
754 qFatal("cannot open template");
756 wrapToFile("index.html",t_i.render());