htmlhelp.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002  *
00003  * $Id: htmlhelp.cpp,v 1.8 2001/03/19 19:27:40 root Exp $
00004  *
00005  * Copyright (C) 1997-2008 by Dimitri van Heesch.
00006  *
00007  * Permission to use, copy, modify, and distribute this software and its
00008  * documentation under the terms of the GNU General Public License is hereby 
00009  * granted. No representations are made about the suitability of this software 
00010  * for any purpose. It is provided "as is" without express or implied warranty.
00011  * See the GNU General Public License for more details.
00012  *
00013  * Documents produced by Doxygen are derivative works derived from the
00014  * input used in their production; they are not affected by this license.
00015  *
00016  * The code is this file is largely based on a contribution from
00017  * Harm van der Heijden <H.v.d.Heijden@phys.tue.nl>
00018  * Please send thanks to him and bug reports to me :-)
00019  */
00020 
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <qlist.h>
00024 #include <qdict.h>
00025 
00026 #include "htmlhelp.h"
00027 #include "config.h"
00028 #include "message.h"
00029 #include "doxygen.h"
00030 #include "language.h"
00031 
00032 //----------------------------------------------------------------------------
00033 
00034 struct IndexField
00035 {
00036   QCString name;
00037   QCString url;
00038   QCString anchor;
00039   bool     link;
00040   bool     reversed;
00041 };
00042 
00043 class IndexFieldList : public QList<IndexField>
00044 {
00045   public:
00046     int compareItems(GCI item1, GCI item2)
00047     {
00048       return stricmp(((IndexField *)item1)->name,((IndexField *)item2)->name);
00049     }
00050    ~IndexFieldList() {}
00051 };
00052 
00053 class IndexFieldListIterator : public QListIterator<IndexField>
00054 {
00055   public:
00056     IndexFieldListIterator( const IndexFieldList &list) :
00057        QListIterator<IndexField>(list) {}
00058 };
00059 
00060 class IndexFieldDict : public QDict<IndexField>
00061 {
00062   public:
00063     IndexFieldDict(int size) : QDict<IndexField>(size) {}
00064    ~IndexFieldDict() {}
00065 };
00066 
00070 class HtmlHelpIndex
00071 {
00072   public:
00073     HtmlHelpIndex();
00074    ~HtmlHelpIndex();
00075     void addItem(const char *first,const char *second, 
00076                  const char *url, const char *anchor,
00077                  bool hasLink,bool reversed);
00078     void writeFields(QTextStream &t);
00079   private:
00080     IndexFieldList *list;
00081     IndexFieldDict *dict;   
00082 };
00083 
00085 HtmlHelpIndex::HtmlHelpIndex()
00086 {
00087   list = new IndexFieldList;
00088   dict = new IndexFieldDict(10007);
00089   list->setAutoDelete(TRUE);
00090 }
00091 
00093 HtmlHelpIndex::~HtmlHelpIndex()
00094 {
00095   delete list;
00096   delete dict;
00097 }
00098 
00112 void HtmlHelpIndex::addItem(const char *level1,const char *level2,
00113                        const char *url,const char *anchor,bool hasLink,
00114                        bool reversed)
00115 {
00116   QCString key = level1; 
00117   if (level2) key+= (QCString)"?" + level2;
00118   if (dict->find(key)==0) // new key
00119   {
00120     //printf(">>>>>>>>> HtmlHelpIndex::addItem(%s,%s,%s,%s)\n",
00121     //      level1,level2,url,anchor);
00122     IndexField *f = new IndexField;
00123     f->name     = key;
00124     f->url      = url;
00125     f->anchor   = anchor;
00126     f->link     = hasLink;
00127     f->reversed = reversed;
00128     list->inSort(f);
00129     dict->insert(key,f);
00130   }
00131 }
00132 
00159 void HtmlHelpIndex::writeFields(QTextStream &t)
00160 {
00161   IndexFieldListIterator ifli(*list);
00162   IndexField *f;
00163   QCString lastLevel1;
00164   bool level2Started=FALSE;
00165   for (;(f=ifli.current());++ifli)
00166   {
00167     QCString level1,level2;
00168     int i;
00169     if ((i=f->name.find('?'))!=-1)
00170     {
00171       level1 = f->name.left(i);
00172       level2 = f->name.right(f->name.length()-i-1); 
00173     }
00174     else
00175     {
00176       level1  = f->name.copy();
00177     }
00178 
00179     if (level1!=lastLevel1)
00180     { // finish old list at level 2
00181       if (level2Started) t << "  </UL>" << endl;
00182       level2Started=FALSE;
00183     
00184       // <Antony>
00185       // Added this code so that an item with only one subitem is written
00186       // without any subitem.
00187       // For example:
00188       //   a1, b1 -> will create only a1, not separate subitem for b1
00189       //   a2, b2
00190       //   a2, b3
00191       QCString nextLevel1;
00192       IndexField* fnext = ++ifli;
00193       if (fnext)
00194       {
00195         nextLevel1 = fnext->name.left(fnext->name.find('?'));
00196         --ifli;
00197       }
00198       if (level1 != nextLevel1)
00199       {
00200         level2 = "";
00201       }
00202       // </Antony>
00203 
00204       if (level2.isEmpty())
00205       {
00206         t << "  <LI><OBJECT type=\"text/sitemap\">";
00207         t << "<param name=\"Local\" value=\"" << f->url << Doxygen::htmlFileExtension;
00208         if (!f->anchor.isEmpty() && f->reversed) t << "#" << f->anchor;  
00209         t << "\">";
00210         t << "<param name=\"Name\" value=\"" << level1 << "\">"
00211            "</OBJECT>\n";
00212       }
00213       else
00214       {
00215         if (f->link)
00216         {
00217           t << "  <LI><OBJECT type=\"text/sitemap\">";
00218           t << "<param name=\"Local\" value=\"" << f->url << Doxygen::htmlFileExtension;
00219           if (!f->anchor.isEmpty() && f->reversed) t << "#" << f->anchor;  
00220           t << "\">";
00221           t << "<param name=\"Name\" value=\"" << level1 << "\">"
00222                "</OBJECT>\n";
00223         }
00224         else
00225         {
00226           t << "  <LI><OBJECT type=\"text/sitemap\">";
00227           t << "<param name=\"See Also\" value=\"" << level1 << "\">";
00228           t << "<param name=\"Name\" value=\"" << level1 << "\">"
00229                "</OBJECT>\n";
00230         }
00231       }
00232     }
00233     if (!level2Started && !level2.isEmpty())
00234     { // start new list at level 2
00235       t << "  <UL>" << endl;
00236       level2Started=TRUE;
00237     }
00238     else if (level2Started && level2.isEmpty())
00239     { // end list at level 2
00240       t << "  </UL>" << endl;
00241       level2Started=FALSE;
00242     }
00243     if (level2Started)
00244     {
00245       t << "    <LI><OBJECT type=\"text/sitemap\">";
00246       t << "<param name=\"Local\" value=\"" << f->url << Doxygen::htmlFileExtension;
00247       if (!f->anchor.isEmpty()) t << "#" << f->anchor;  
00248       t << "\">";
00249       t << "<param name=\"Name\" value=\"" << level2 << "\">"
00250          "</OBJECT>\n";
00251     }
00252     lastLevel1 = level1.copy();
00253   } 
00254   if (level2Started) t << "  </UL>" << endl;
00255 }
00256 
00257 //----------------------------------------------------------------------------
00258 
00259 HtmlHelp *HtmlHelp::theInstance = 0;
00260 
00265 HtmlHelp::HtmlHelp() : indexFileDict(1009)
00266 {
00267   /* initial depth */
00268   dc = 0;
00269   cf = kf = 0;
00270   index = new HtmlHelpIndex;
00271 }
00272 
00273 #if 0
00274 
00276 HtmlHelp *HtmlHelp::getInstance()
00277 {
00278   if (theInstance==0) theInstance = new HtmlHelp;
00279   return theInstance;
00280 }
00281 #endif
00282 
00283 static QDict<QCString> s_languageDict;
00284 
00290 void HtmlHelp::initialize()
00291 {
00292   /* open the contents file */
00293   QCString fName = Config_getString("HTML_OUTPUT") + "/index.hhc";
00294   cf = new QFile(fName);
00295   if (!cf->open(IO_WriteOnly))
00296   {
00297     err("Could not open file %s for writing\n",fName.data());
00298     exit(1);
00299   }
00300   /* Write the header of the contents file */
00301   cts.setDevice(cf);
00302   cts.setEncoding(QTextStream::UnicodeUTF8);
00303   cts << "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n"
00304          "<HTML><HEAD></HEAD><BODY>\n"
00305          "<OBJECT type=\"text/site properties\">\n"
00306          "<param name=\"FrameName\" value=\"right\">\n"
00307          "</OBJECT>\n"
00308          "<UL>\n";
00309   
00310   /* open the contents file */
00311   fName = Config_getString("HTML_OUTPUT") + "/index.hhk";
00312   kf = new QFile(fName);
00313   if (!kf->open(IO_WriteOnly))
00314   {
00315     err("Could not open file %s for writing\n",fName.data());
00316     exit(1);
00317   }
00318   /* Write the header of the contents file */
00319   kts.setDevice(kf);
00320   kts.setEncoding(QTextStream::UnicodeUTF8);
00321   kts << "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n"
00322          "<HTML><HEAD></HEAD><BODY>\n"
00323          "<OBJECT type=\"text/site properties\">\n"
00324          "<param name=\"FrameName\" value=\"right\">\n"
00325          "</OBJECT>\n"
00326          "<UL>\n";
00327 
00328   /* language codes for Html help
00329      0x405 Czech
00330      0x406 Danish
00331      0x413 Dutch
00332      0xC09 English (Australia)
00333      0x809 English (Britain)
00334      0x1009 English (Canada)
00335      0x1809 English (Ireland)
00336      0x1409 English (New Zealand)
00337      0x1C09 English (South Africa)
00338      0x409 English (United States)
00339      0x40B Finnish
00340      0x40C French
00341      0x407 German
00342      0x408 Greece
00343      0x40E Hungarian
00344      0x410 Italian
00345      0x814 Norwegian
00346      0x415 Polish
00347      0x816 Portuguese(Portugal)
00348      0x416 Portuguese(Brazil)
00349      0x419 Russian
00350      0x80A Spanish(Mexico)
00351      0xC0A Spanish(Modern Sort)
00352      0x40A Spanish(Traditional Sort)
00353      0x41D Swedish
00354      0x41F Turkey
00355      0x411 Japanese
00356      0x412 Korean
00357      0x804 Chinese (PRC)
00358      0x404 Chinese (Taiwan)
00359   */
00360   s_languageDict.setAutoDelete(TRUE);
00361   s_languageDict.clear();
00362   s_languageDict.insert("czech",       new QCString("0x405 Czech"));
00363   s_languageDict.insert("danish",      new QCString("0x406 Danish"));
00364   s_languageDict.insert("dutch",       new QCString("0x413 Dutch"));
00365   s_languageDict.insert("finnish",     new QCString("0x40B Finnish"));
00366   s_languageDict.insert("french",      new QCString("0x40C French"));
00367   s_languageDict.insert("german",      new QCString("0x407 German"));
00368   s_languageDict.insert("greece",      new QCString("0x408 Greece"));
00369   s_languageDict.insert("hungarian",   new QCString("0x40E Hungarian"));
00370   s_languageDict.insert("italian",     new QCString("0x410 Italian"));
00371   s_languageDict.insert("norwegian",   new QCString("0x814 Norwegian"));
00372   s_languageDict.insert("polish",      new QCString("0x415 Polish"));
00373   s_languageDict.insert("portugese",   new QCString("0x816 Portuguese(Portugal)"));
00374   s_languageDict.insert("brazil",      new QCString("0x416 Portuguese(Brazil)"));
00375   s_languageDict.insert("russian",     new QCString("0x419 Russian"));
00376   s_languageDict.insert("spanish",     new QCString("0x40A Spannish(Traditional Sort)"));
00377   s_languageDict.insert("swedish",     new QCString("0x41D Swedish"));
00378   s_languageDict.insert("turkey",      new QCString("0x41F Turkey"));
00379   s_languageDict.insert("japanese",    new QCString("0x411 Japanese"));
00380   s_languageDict.insert("japanese-en", new QCString("0x411 Japanese"));
00381   s_languageDict.insert("korean",      new QCString("0x412 Korean"));
00382   s_languageDict.insert("chinese",     new QCString("0x804 Chinese (PRC)"));
00383   s_languageDict.insert("chinese-traditional", new QCString("0x404 Chinese (Taiwan)"));
00384 }
00385 
00386 
00387 static QCString getLanguageString()
00388 {
00389   if (!theTranslator->idLanguage().isEmpty())
00390   {
00391     QCString *s = s_languageDict[theTranslator->idLanguage()];
00392     if (s)
00393     {
00394       return *s;
00395     }
00396   }
00397   // default language
00398   return "0x409 English (United States)";
00399 }
00400   
00401 
00402 
00403 void HtmlHelp::createProjectFile()
00404 {
00405   /* Write the project file */
00406   QCString fName = Config_getString("HTML_OUTPUT") + "/index.hhp";
00407   QFile f(fName);
00408   if (f.open(IO_WriteOnly))
00409   {
00410     QTextStream t(&f);
00411 #if QT_VERSION >= 200
00412     t.setEncoding(QTextStream::UnicodeUTF8);
00413 #endif
00414 
00415    
00416     
00417     QCString indexName="index"+Doxygen::htmlFileExtension;
00418     if (Config_getBool("GENERATE_TREEVIEW")) indexName="main"+Doxygen::htmlFileExtension;
00419     t << "[OPTIONS]\n";
00420     if (!Config_getString("CHM_FILE").isEmpty())
00421     {
00422       t << "Compiled file=" << Config_getString("CHM_FILE") << "\n";
00423     }
00424     t << "Compatibility=1.1\n"
00425          "Full-text search=Yes\n"
00426          "Contents file=index.hhc\n"
00427          "Default Window=main\n"
00428          "Default topic=" << indexName << "\n"
00429          "Index file=index.hhk\n"
00430          "Language=" << getLanguageString() << endl;
00431     if (Config_getBool("BINARY_TOC")) t << "Binary TOC=YES\n";
00432     if (Config_getBool("GENERATE_CHI")) t << "Create CHI file=YES\n";
00433     t << "Title=" << Config_getString("PROJECT_NAME") << endl << endl;
00434     
00435     t << "[WINDOWS]" << endl;
00436     t << "main=\"" << Config_getString("PROJECT_NAME") << "\",\"index.hhc\","
00437          "\"index.hhk\",\"" << indexName << "\",\"" << 
00438          indexName << "\",,,,,0x23520,,0x387e,,,,,,,,0" << endl << endl;
00439     
00440     t << "[FILES]" << endl;
00441     char *s = indexFiles.first();
00442     while (s)
00443     {
00444       t << s << endl;
00445       s = indexFiles.next();
00446     }
00447     t << "tabs.css" << endl;
00448     t << "tab_b.gif" << endl;
00449     t << "tab_l.gif" << endl;
00450     t << "tab_r.gif" << endl;
00451     if (Config_getBool("HTML_DYNAMIC_SECTIONS"))
00452     {
00453       t << "open.gif" << endl;
00454       t << "closed.gif" << endl;
00455     }
00456     f.close();
00457   }
00458   else
00459   {
00460     err("Could not open file %s for writing\n",fName.data());
00461   }
00462 }
00463 
00464 void HtmlHelp::addIndexFile(const char *s)
00465 {
00466   if (indexFileDict.find(s)==0)
00467   {
00468     indexFiles.append(s);
00469     indexFileDict.insert(s,(void *)0x8);
00470   }
00471 }
00472 
00477 void HtmlHelp::finalize()
00478 {
00479   // end the contents file
00480   cts << "</UL>\n";
00481   cts << "</BODY>\n";
00482   cts << "</HTML>\n";
00483   cts.unsetDevice();
00484   cf->close();
00485   delete cf;
00486   
00487   index->writeFields(kts);
00488   
00489   // end the index file
00490   kts << "</UL>\n";
00491   kts << "</BODY>\n";
00492   kts << "</HTML>\n";
00493   kts.unsetDevice();
00494   kf->close();
00495   delete kf;
00496 
00497   createProjectFile();
00498   s_languageDict.clear();
00499 }
00500 
00505 void HtmlHelp::incContentsDepth()
00506 {
00507   int i; for (i=0;i<dc+1;i++) cts << "  ";
00508   cts << "<UL>\n";
00509   ++dc;
00510 }
00511 
00516 void HtmlHelp::decContentsDepth()
00517 {
00518   int i; for (i=0;i<dc;i++) cts << "  ";
00519   cts << "</UL>\n";
00520   --dc;
00521 }
00522 
00530 void HtmlHelp::addContentsItem(bool isDir,
00531                                const char *name,
00532                                const char * /*ref*/, 
00533                                const char *file,
00534                                const char *anchor)
00535 {
00536   // If we're using a binary toc then folders cannot have links. 
00537   if(Config_getBool("BINARY_TOC") && isDir) 
00538   {
00539     file = 0;
00540     anchor = 0;
00541   }
00542   
00543   int i; for (i=0;i<dc;i++) cts << "  ";
00544   cts << "<LI><OBJECT type=\"text/sitemap\">";
00545   cts << "<param name=\"Name\" value=\"" << name << "\">";
00546   if (file)      // made file optional param - KPW
00547   {
00548     cts << "<param name=\"Local\" value=\"" << file << Doxygen::htmlFileExtension;
00549     if (anchor) cts << "#" << anchor;  
00550     cts << "\">";
00551   }
00552   cts << "<param name=\"ImageNumber\" value=\"";
00553   if (isDir)  // added - KPW
00554   {
00555     cts << (int)BOOK_CLOSED ;
00556   }
00557   else
00558   {
00559     cts << (int)TEXT;
00560   }
00561   cts << "\">";
00562   cts << "</OBJECT>\n";
00563 }
00564 
00574 void HtmlHelp::addIndexItem(const char *level1, const char *level2,
00575                             const char *contRef, const char *memRef, 
00576                             const char *anchor,const MemberDef *md)
00577 {
00578   (void)md;
00579   index->addItem(level1,level2,contRef,anchor,TRUE,FALSE);
00580   index->addItem(level2,level1,memRef,anchor,TRUE,TRUE);
00581 }
00582 



Generated on Mon Mar 31 10:58:39 2008 by  doxygen 1.5.1