0647bb622ae621deb177e66a9d3e997cb691eb64
[quassel.git] / src / contrib / libqxt-2007-10-24 / tools / doqsy / main.cpp
1 #include <QFile>
2 #include <QDebug>
3 #include <QtXml>
4 #include <QxtHtmlTemplate>
5 #include <QStringList>
6 #include <QPair>
7 #include <QHash>
8 #include <QSettings>
9 #include <QCoreApplication>
10 #include <QFileInfo>
11 #include <QDir>
12 #include <QProcess>
13
14
15 struct Module;
16 struct Class
17 {
18     QString name;
19     QString ref;
20
21     QString desc;
22
23     Module * module;
24
25 };
26 struct Module
27 {
28     QString name;
29     QString ref;
30
31     QString desc;
32
33
34     QList<Class *> classes;
35 };
36
37
38 bool sortClassBynameLessThen(const Class *s1, const Class *s2)
39 {
40     return s1->name < s2->name;
41 }
42 bool sortModuleBynameLessThen(const Module *s1, const Module *s2)
43 {
44     return s1->name < s2->name;
45 }
46
47
48
49
50 ///information collected from the xml files
51 QList<Class *> classes;
52 QList<Class *> publiclasses;
53 QList<Module *> modules;
54
55 ///settings
56 QString outputDir;
57 QString templateDir;
58 QString xmlDir;
59
60
61
62
63 Class * findClassByRef(QString ref)
64 {
65     foreach(Class * c,classes)
66     {
67         if (c->ref==ref)
68             return c;
69     }
70     qFatal("ref %s invalid",qPrintable(ref));
71     return 0;
72 }
73
74
75
76
77
78
79
80 QString refToLink( QString ref)
81 {
82     QStringList e=ref.split("_");
83
84     QString object=e.at(0);
85     QString sub;
86     if(e.count()>1)
87         sub=e.at(1);
88
89
90
91     ///FIXME that's a dirty hack. Might not actualy be sane
92     ///TODO external reference resolving
93     if (!object.contains("Qxt"))
94     {
95         object="http://doc.trolltech.com/latest/"+object;
96
97         if (sub.startsWith("1"))
98             sub=sub.mid(1);
99     }
100
101
102     if(sub.size())
103         return object+".html#"+sub;
104     else
105         return object+".html";
106 }
107
108
109
110
111
112
113
114 QString descRTF(QDomElement element)
115 {
116     ///TODO parse the rest
117
118
119
120
121     QString text;
122
123
124     for(QDomNode n = element.firstChild(); !n.isNull(); n = n.nextSibling())
125     {
126         if (n.isElement ())
127         {
128             QDomElement e= n.toElement();
129             if(e.tagName ()=="para")
130             {
131                 text += "<p>"+descRTF(e)+"</p>";
132             }
133             else if(e.tagName ()=="programlisting")
134             {
135                 text += "<div class=\"code\">"+descRTF(e)+"</div>";
136             }
137             else if(e.tagName ()=="codeline")
138             {
139                 text += descRTF(e)+"<br/>\r\n";
140             }
141             else if(e.tagName ()=="highlight")
142             {
143                 text += "<span class=\"highlight_"+e.attribute("class")+"\"  >"+descRTF(e)+"</span>";
144             }
145             else if(e.tagName ()=="ref")
146             {
147                 ///ignore namespaces, we don't have them
148                 if(e.attribute("refid").startsWith("namespace"))
149                     text +=descRTF(e);
150                 else
151                     text += "<a class=\"reflink\" href=\""+refToLink(e.attribute("refid"))+"\">"+descRTF(e)+"</a>";
152             }
153             else if(e.tagName ()=="image")
154             {
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>";
158             }
159             else if(e.tagName ()=="linebreak")
160             {
161                 text += "<br/>\r\n";
162             }
163             else 
164             {
165                  text += e.text().replace("<","&lt;").replace(">","&gt;")+" ";
166             }
167         }
168         else if (n.isText ()) 
169         {
170             text += n.toText().data().replace("<","&lt;").replace(">","&gt;");
171         }
172     }
173     return text;
174 }
175
176
177
178
179
180
181 ///fill classes and modules globals
182 void parseIndex(QString location)
183 {
184
185
186     QDomDocument doc("doc");
187     QFile file(location+"/index.xml");
188     if (!file.open(QIODevice::ReadOnly))
189         qFatal("cannot open file");
190     QString  errorMsg;
191     int errorLine=0;
192     int errorColumn=0;
193
194     if (!doc.setContent(&file,&errorMsg,&errorLine,&errorColumn)) 
195     {
196         qCritical("%s:%i:%i %s",qPrintable(location+"/index.xml"),errorLine,errorColumn,qPrintable(errorMsg));
197     }
198     file.close();
199
200     QDomElement docElem = doc.documentElement();
201     if(docElem.tagName ()!="doxygenindex")
202         qFatal("unexpected top node in %s",qPrintable(location+"/index.xml"));
203
204
205     QDomElement e = docElem.firstChildElement("compound");
206     while(!e.isNull()) 
207     {
208         if (e.attribute("kind")=="class")
209         {
210             Class * cl=new Class;
211             cl->module=0;
212             cl->name=e.firstChildElement("name").text();
213             cl->ref=e.attribute("refid");
214             classes.append(cl);
215         }
216         else if (e.attribute("kind")=="group")
217         {
218             Module * cl=new Module;
219             cl->name=e.firstChildElement("name").text();
220             cl->ref=e.attribute("refid");
221             modules.append(cl);
222         }
223         else
224         {
225             qWarning("no way to document %s",qPrintable(e.attribute("kind")));
226         }
227     e = e.nextSiblingElement("compound");
228     }
229
230 }
231
232
233
234 void parseModule(QString location,Module *m)
235 {
236     QDomDocument doc("doc");
237     QString filename=location+"/"+m->ref+".xml";
238
239     QFile file(filename);
240     if (!file.open(QIODevice::ReadOnly))
241         qFatal("cannot open file %s",qPrintable(filename));
242     QString  errorMsg;
243     int errorLine=0;
244     int errorColumn=0;
245
246     if (!doc.setContent(&file,&errorMsg,&errorLine,&errorColumn)) 
247     {
248         qCritical("%s:%i:%i %s",qPrintable(filename),errorLine,errorColumn,qPrintable(errorMsg));
249     }
250     file.close();
251
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));
256
257
258
259     m->desc=descRTF(def.firstChildElement("detaileddescription"));
260
261
262
263     QDomElement e = def.firstChildElement("innerclass");
264     while(!e.isNull()) 
265     {
266         if (e.attribute("prot")=="public")
267         {
268             Class * cll=findClassByRef(e.attribute("refid"));
269             m->classes.append(cll);
270             cll->module=m;
271         }
272         else
273         {
274             qWarning("non public member in %s",qPrintable(m->ref));
275         }
276     e = e.nextSiblingElement("innerclass");
277     }
278
279 }
280
281
282 QString printPublicClasses()
283 {
284
285     QxtHtmlTemplate t;
286     if(!t.open(templateDir+"/classes.html"))qFatal("cannot open template");
287     QxtHtmlTemplate t_i;
288     if(!t_i.open(templateDir+"/classes-unroll.html"))qFatal("cannot open template");
289
290
291     uint trs=classes.count()/4;
292     QHash<uint,QString> rowstring;
293     uint cr=1;
294
295     QString lastChar=" ";
296     foreach(Class * cl,publiclasses)
297     {
298         if (cl->name.count()<3)qFatal("bad class name %s",qPrintable(cl->name));
299
300
301         if(cl->name.at(3)!=lastChar.at(0))
302         {
303             lastChar=cl->name.at(3);
304             rowstring[cr]+="<th>"+lastChar+"</th>";
305             cr++;
306             if(cr>trs)
307                 cr=1;
308         }
309
310         t_i.clear();
311         t_i["name"]=cl->name;
312         t_i["link"]=refToLink(cl->ref);
313
314         rowstring[cr]+=t_i.render();
315         cr++;
316         if(cr>trs)
317             cr=1;
318     }
319
320     foreach(QString rowstr, rowstring.values())
321     {
322         t["unroll"]+="<tr>\r\n"+rowstr+"</tr>\r\n\r\n";
323     }
324     return t.render();;
325 }
326
327
328
329
330
331
332 QString printModules()
333 {
334     QxtHtmlTemplate t;
335     if(!t.open(templateDir+"/modules.html"))qFatal("cannot open template");
336     QxtHtmlTemplate t_i;
337     if(!t_i.open(templateDir+"/modules-unroll.html"))qFatal("cannot open template");
338
339
340     int i=0;
341
342
343     foreach(Module * cl,modules)
344     {
345         i++;
346         t_i.clear();
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();
352     }
353     return t.render();;
354 }
355
356
357
358
359
360
361
362
363 QString printClass(QString location,Class * cl)
364 {
365     QDomDocument doc("doc");
366     QString filename=location+"/"+cl->ref+".xml";
367
368     QFile file(filename);
369
370     if (!file.open(QIODevice::ReadOnly))
371         qFatal("cannot open file %s",qPrintable(filename));
372
373     QString  errorMsg;
374     int errorLine=0;
375     int errorColumn=0;
376
377     if (!doc.setContent(&file,&errorMsg,&errorLine,&errorColumn)) 
378     {
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);
382     }
383     file.close();
384
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");
389
390
391
392     QxtHtmlTemplate t;
393     if(!t.open(templateDir+"/class.html"))qFatal("cannot open template");
394
395
396
397
398     ///name
399     t["class_name"]=def.firstChildElement("compoundname").text();
400     t["ref"]=def.attribute("id");
401
402     if(cl->module)
403     {
404         t["module_name"]=cl->module->name;
405         t["module_link"]=cl->module->ref+".html";
406     }
407     else
408         qWarning("class %s has no module defined",qPrintable(cl->name));
409
410
411
412
413     ///description
414     cl->desc=def.firstChildElement("briefdescription").text();
415     t["desc_short"]=cl->desc;
416     t["desc_detailed"]=descRTF(def.firstChildElement("detaileddescription"));
417
418
419
420     ///inherits
421     t["inherits"]="";
422     QDomElement basecompoundref =def.firstChildElement("basecompoundref");
423     if(!basecompoundref.isNull())
424     {
425         QxtHtmlTemplate t_i;
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();
430     }
431
432
433
434     ///sections
435     t["sections"]="";
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");
440
441     QDomElement sectiondef=def.firstChildElement("sectiondef");
442     while(!sectiondef.isNull()) 
443     {
444         if(sectiondef.attribute("kind").startsWith("private"))///skip private stuff
445         {
446             sectiondef = sectiondef.nextSiblingElement("sectiondef");
447             continue;
448         }
449
450
451         t_section.clear();
452
453         t_section["kind"]=sectiondef.attribute("kind");
454         t_section["desc"]=sectiondef.attribute("kind"); ///TODO: map kind to desc
455
456
457
458
459         qDebug()<<"parsing section "<<t_section["kind"];
460
461         QDomElement member=sectiondef.firstChildElement("memberdef");
462         while(!member.isNull()) 
463         {
464         qDebug()<<"parsing member "<<member.firstChildElement("name").text();
465
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"));
471
472             t_section["list"]+=t_members_unroll.render();
473
474
475
476             ///Member Function Documentation (impl) 
477             t_impl.clear();
478
479             QStringList lii=member.attribute("id").split("_");
480             if(lii.count()>1)
481                 t_impl["ref"]=lii.at(1);
482             else
483                 t_impl["ref"]=lii.at(0);
484
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"));
489
490
491             t["impl"]+=t_impl.render();
492
493             member = member.nextSiblingElement("memberdef");
494         }
495
496
497         t["sections"]+=t_section.render();
498
499         sectiondef = sectiondef.nextSiblingElement("sectiondef");
500     }
501
502
503     return t.render();
504 }
505
506
507
508
509
510
511
512 QString printModule(Module * m)
513 {
514     QxtHtmlTemplate t;
515     if(!t.open(templateDir+"/module.html"))qFatal("cannot open template");
516     QxtHtmlTemplate t_i;
517     if(!t_i.open(templateDir+"/modules-unroll.html"))qFatal("cannot open template");
518
519     t["name"]+=m->name;
520     t["desc"]+=m->desc;
521
522     int i=0;
523     qSort(m->classes.begin(), m->classes.end(), sortClassBynameLessThen);
524     foreach(Class * cl,m->classes)
525     {
526         i++;
527         t_i.clear();
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();
533     }
534     return t.render();;
535 }
536
537
538
539
540
541 QString printListOfMembers(QString location,Class * cl)
542 {
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"));
547     QString  errorMsg;
548     int errorLine=0;
549     int errorColumn=0;
550
551     if (!doc.setContent(&file,&errorMsg,&errorLine,&errorColumn)) 
552     {
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);
556     }
557     file.close();
558
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");
563
564
565
566     QxtHtmlTemplate t;
567     if(!t.open(templateDir+"/class-members.html"))qFatal("cannot open template");
568
569
570     ///name
571     t["class_name"]=def.firstChildElement("compoundname").text();
572     t["ref"]=def.attribute("id");
573
574     ///list
575     QDomElement list =def.firstChildElement("listofallmembers");
576     t["list"]="";
577
578     QxtHtmlTemplate t_i;
579     if(!t_i.open(templateDir+"/class-members-unroll.html"))
580         qFatal("cannot open template");
581
582
583     QDomElement member=list.firstChildElement("member");
584     while(!member.isNull()) 
585     {
586         if(member.attribute("prot")=="private")///skip private members
587         {
588             member = member.nextSiblingElement("memberdef");
589             continue;
590         }
591
592
593
594         t_i.clear();
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");
599     }
600
601     return t.render();
602 }
603
604
605
606
607
608
609
610 void wrapToFile(QString filename,QString content)
611 {
612
613     QxtHtmlTemplate site;
614     if(!site.open(templateDir+"/site.html"))qFatal("cannot open template");
615     site["content"]=content;
616
617     QFile file(outputDir+"/"+filename);
618     if (!file.open(QIODevice::WriteOnly))
619         qFatal("cannot open output file %s",qPrintable(filename));
620
621     file.write(site.render().toUtf8());
622
623     file.close();
624 }
625
626
627
628
629
630
631 int main(int argc,char ** argv)
632 {
633
634     QCoreApplication app(argc,argv);
635     qDebug("[greetings]");
636
637
638     QString settingsfile="Doqsyfile";
639
640
641     if(app.arguments().count()>1)
642     {
643        settingsfile=app.arguments().at(1);
644     }
645
646     if(!QFileInfo(settingsfile).exists())
647         qFatal("cannot open %s",qPrintable(settingsfile));
648
649     if (!QDir::setCurrent (QFileInfo(settingsfile).absolutePath ()))
650         qFatal("unable to change working directory to %s",qPrintable(QFileInfo(settingsfile).absolutePath ()));
651
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();
657
658
659
660     QDir().mkpath(outputDir);
661     settings.endGroup();
662
663
664
665     if(!QDir::temp().mkpath("doqsytmp"))
666         qFatal("cannot make  temp dir");
667     xmlDir=QDir::tempPath()+"doqsytmp";
668
669
670
671     
672
673     QString doxygeninput;
674
675     settings.beginGroup ("doxygen");
676     foreach(QString key,settings.allKeys())
677     {
678         doxygeninput+=(key+"="+settings.value(key).toString()+"\r\n");
679     }
680     settings.endGroup();
681
682     doxygeninput+=  "XML_OUTPUT             = "+xmlDir+"\r\n"
683                         "OUTPUT_DIRECTORY       = "+QDir::tempPath()+"\r\n"
684                         "GENERATE_XML           = YES\r\n";
685
686
687
688     qDebug("[running doxygen]");
689
690
691     QProcess doxygenprocess;
692
693     doxygenprocess.setProcessChannelMode(QProcess::ForwardedChannels);
694
695     doxygenprocess.setWorkingDirectory (QDir().absolutePath ());
696
697     doxygenprocess.start (doxyexe,QStringList()<<"-");
698
699     if(!doxygenprocess.waitForStarted ())
700         qFatal("doxygen failed to start");
701
702     doxygenprocess.write(doxygeninput.toUtf8());
703
704     doxygenprocess.closeWriteChannel();
705
706     if(!doxygenprocess.waitForFinished (120000))
707         qFatal("doxygen failed to finish within 2 minutes");
708
709     if(doxygenprocess.exitCode ())
710         qFatal("doxygen run unsecussfull");
711
712
713     qDebug("[beginn parsing]");
714
715     parseIndex(xmlDir);
716
717
718     qSort(classes.begin(), classes.end(), sortClassBynameLessThen);
719     qSort(modules.begin(), modules.end(), sortModuleBynameLessThen);
720
721     foreach(Module *  m,modules)
722     {
723         qDebug()<<"parsing module"<<m->ref;
724         parseModule(xmlDir,m);
725         publiclasses+=m->classes;
726     }
727
728     wrapToFile("modules.html",printModules());
729
730     qSort(publiclasses.begin(), publiclasses.end(), sortClassBynameLessThen);
731     wrapToFile("classes.html",printPublicClasses());
732
733
734
735
736
737     foreach(Class * c,classes)
738     {
739         qDebug()<<"parsing class "<<c->name;
740         wrapToFile(c->ref+".html",printClass(xmlDir,c));
741         wrapToFile(c->ref+"-members.html",printListOfMembers(xmlDir,c));
742     }
743
744     foreach(Module *  m,modules)
745     {
746         wrapToFile(m->ref+".html",printModule(m));
747     }
748
749
750
751
752     QxtHtmlTemplate t_i;
753     if(!t_i.open(templateDir+"/index.html"))
754         qFatal("cannot open template");
755     
756     wrapToFile("index.html",t_i.render());
757     qDebug("[done]");
758     return 0;
759 }
760