00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "docdoxygenplugin.h"
00021
00022 #include <unistd.h>
00023
00024 #include <qdom.h>
00025 #include <qfile.h>
00026 #include <qfileinfo.h>
00027 #include <qdialog.h>
00028 #include <qregexp.h>
00029
00030 #include <kurl.h>
00031 #include <kaboutdata.h>
00032 #include <kconfig.h>
00033 #include <klocale.h>
00034 #include <kstandarddirs.h>
00035
00036 #include <urlutil.h>
00037 #include <kdevgenericfactory.h>
00038
00039 #include "../../../../config.h"
00040
00041 class DoxyDocumentationCatalogItem: public DocumentationCatalogItem
00042 {
00043 public:
00044 DoxyDocumentationCatalogItem(const QString &origUrl, DocumentationPlugin* plugin,
00045 KListView *parent, const QString &name)
00046 :DocumentationCatalogItem(plugin, parent, name), m_origUrl(origUrl)
00047 {
00048 }
00049 DoxyDocumentationCatalogItem(const QString &origUrl, DocumentationPlugin* plugin,
00050 DocumentationItem *parent, const QString &name)
00051 :DocumentationCatalogItem(plugin, parent, name), m_origUrl(origUrl)
00052 {
00053 }
00054 QString origUrl() const { return m_origUrl; }
00055
00056 private:
00057 QString m_origUrl;
00058 };
00059
00060
00061 static const KAboutData data("docdoxygenplugin", I18N_NOOP("Doxygen documentation plugin"), "1.0");
00062 typedef KDevGenericFactory<DocDoxygenPlugin> DocDoxygenPluginFactory;
00063 K_EXPORT_COMPONENT_FACTORY( libdocdoxygenplugin, DocDoxygenPluginFactory(&data) )
00064
00065 DocDoxygenPlugin::DocDoxygenPlugin(QObject* parent, const char* name, const QStringList)
00066 :DocumentationPlugin(DocDoxygenPluginFactory::instance()->config(), parent, name)
00067 {
00068 setCapabilities(Index | FullTextSearch | ProjectDocumentation);
00069 autoSetup();
00070 }
00071
00072 DocDoxygenPlugin::~DocDoxygenPlugin()
00073 {
00074 }
00075
00076 QPair<KFile::Mode, QString> DocDoxygenPlugin::catalogLocatorProps()
00077 {
00078 return QPair<KFile::Mode, QString>(KFile::File, "index.html *.tag");
00079 }
00080
00081 QString DocDoxygenPlugin::catalogTitle(const QString& url)
00082 {
00083 QFileInfo fi(url);
00084 if (!fi.exists())
00085 return QString::null;
00086
00087 if (fi.extension(false) == "html")
00088 {
00089 QFile f(url);
00090 if (!f.open(IO_ReadOnly))
00091 return QString::null;
00092
00093 QTextStream ts(&f);
00094 QString contents = ts.read();
00095 QRegExp re(".*<title>(.*)</title>.*");
00096 re.setCaseSensitive(false);
00097 re.search(contents);
00098 return re.cap(1);
00099 }
00100 else if (fi.extension(false) == "tag")
00101 {
00102 QFile *f = 0;
00103 QFile f1(fi.dirPath(true) + "/html/index.html");
00104 if (f1.open(IO_ReadOnly))
00105 f = &f1;
00106 QFile f2(fi.dirPath(true) + "/index.html");
00107 if (f2.open(IO_ReadOnly))
00108 f = &f2;
00109 if (f != 0)
00110 {
00111 QTextStream ts(f);
00112 QString contents = ts.read();
00113 QRegExp re(".*<title>(.*)</title>.*");
00114 re.setCaseSensitive(false);
00115 re.search(contents);
00116 return re.cap(1);
00117 }
00118 }
00119 return QString::null;
00120 }
00121
00122 QString DocDoxygenPlugin::pluginName() const
00123 {
00124 return i18n("Doxygen Documentation Collection");
00125 }
00126
00127 QStringList DocDoxygenPlugin::fullTextSearchLocations()
00128 {
00129 QStringList locs;
00130
00131 QMap<QString, QString> entryMap = config->entryMap("Locations");
00132
00133 for (QMap<QString, QString>::const_iterator it = entryMap.begin();
00134 it != entryMap.end(); ++it)
00135 {
00136 config->setGroup("Search Settings");
00137 if (config->readBoolEntry(it.key(), false))
00138 {
00139 config->setGroup("Locations");
00140 QFileInfo fi(config->readPathEntry(it.key()));
00141 locs << fi.dirPath(true);
00142 }
00143 }
00144
00145 return locs;
00146 }
00147
00148 void DocDoxygenPlugin::setCatalogURL(DocumentationCatalogItem* item)
00149 {
00150 if (item->url().url().endsWith("tag"))
00151 {
00152 QFileInfo fi(item->url().directory(false) + "html/index.html");
00153 if (fi.exists())
00154 {
00155 item->setURL(KURL::fromPathOrURL(fi.absFilePath()));
00156 return;
00157 }
00158 QFileInfo fi2(item->url().directory(false) + "index.html");
00159 if (fi2.exists())
00160 {
00161 item->setURL(KURL::fromPathOrURL(fi2.absFilePath()));
00162 return;
00163 }
00164 item->setURL(KURL());
00165 }
00166 }
00167
00168 bool DocDoxygenPlugin::needRefreshIndex(DocumentationCatalogItem* item)
00169 {
00170 DoxyDocumentationCatalogItem *doxyItem = dynamic_cast<DoxyDocumentationCatalogItem*>(item);
00171 if (!doxyItem)
00172 return false;
00173
00174 QFileInfo fi(doxyItem->origUrl());
00175 config->setGroup("Index");
00176 if (fi.lastModified() > config->readDateTimeEntry(item->text(0), new QDateTime()))
00177 {
00178 kdDebug() << "need rebuild index for " << item->text(0) << endl;
00179 config->writeEntry(item->text(0), fi.lastModified());
00180 return true;
00181 }
00182 else
00183 return false;
00184 }
00185
00186 void DocDoxygenPlugin::autoSetupPlugin()
00187 {
00188 QString doxyDocDir(KDELIBS_DOXYDIR);
00189 doxyDocDir = URLUtil::envExpand(doxyDocDir);
00190 if (doxyDocDir.isEmpty())
00191 {
00192 QStringList apiDirs = DocDoxygenPluginFactory::instance()->dirs()->findDirs("html", "kdelibs-apidocs");
00193 if (apiDirs.count() > 0)
00194 doxyDocDir = apiDirs.first();
00195 }
00196 if (!doxyDocDir.isEmpty())
00197 {
00198 config->setGroup("Search Settings");
00199 config->writeEntry("The KDE API Reference (The KDE API Reference)", true);
00200 config->setGroup("Index Settings");
00201 config->writeEntry("The KDE API Reference (The KDE API Reference)", true);
00202 config->setGroup("Locations");
00203 config->writePathEntry("The KDE API Reference (The KDE API Reference)", doxyDocDir + QString("/index.html"));
00204 }
00205 }
00206
00207 void DocDoxygenPlugin::createIndex(IndexBox* index, DocumentationCatalogItem* item)
00208 {
00209 QFileInfo fi(item->url().path());
00210 if (!fi.exists())
00211 return;
00212
00213 DoxyDocumentationCatalogItem *doxyItem = dynamic_cast<DoxyDocumentationCatalogItem*>(item);
00214 if (!doxyItem)
00215 return;
00216
00217
00218 if (doxyItem->origUrl().endsWith("tag"))
00219 {
00220 QString htmlUrl;
00221 QFileInfo fi2(item->url().directory(false) + "index.html");
00222 if (fi2.exists())
00223 htmlUrl = fi2.dirPath(true) + "/";
00224 QFileInfo fi(item->url().directory(false) + "html/index.html");
00225 if (fi.exists())
00226 htmlUrl = fi.dirPath(true) + "/";
00227
00228 createBookIndex(doxyItem->origUrl(), index, item, htmlUrl);
00229 }
00230
00231
00232 QDir d(fi.dirPath(true));
00233 QStringList fileList = d.entryList("*", QDir::Dirs);
00234
00235 QStringList::ConstIterator it;
00236 for (it = fileList.begin(); it != fileList.end(); ++it)
00237 {
00238 QString dirName = (*it);
00239 if (dirName == "." || dirName == ".." || dirName == "common")
00240 continue;
00241 if (QFile::exists(d.absFilePath(*it) + "/html/index.html"))
00242 {
00243 createBookIndex(d.absFilePath(*it) + "/" + *it + ".tag", index, item);
00244 }
00245 }
00246 }
00247
00248 void DocDoxygenPlugin::createTOC(DocumentationCatalogItem* item)
00249 {
00250 QFileInfo fi(item->url().path());
00251 if (!fi.exists())
00252 return;
00253
00254 DoxyDocumentationCatalogItem *doxyItem = dynamic_cast<DoxyDocumentationCatalogItem*>(item);
00255 if (!doxyItem)
00256 return;
00257
00258
00259 if (doxyItem->origUrl().endsWith("tag"))
00260 {
00261 QString htmlUrl;
00262 QFileInfo fi2(item->url().directory(false) + "index.html");
00263 if (fi2.exists())
00264 htmlUrl = fi2.dirPath(true) + "/";
00265 QFileInfo fi(item->url().directory(false) + "html/index.html");
00266 if (fi.exists())
00267 htmlUrl = fi.dirPath(true) + "/";
00268 if (!htmlUrl.isEmpty())
00269 createBookTOC(item, doxyItem->origUrl(), htmlUrl);
00270 }
00271
00272
00273 QDir d(fi.dirPath(true));
00274 QStringList fileList = d.entryList("*", QDir::Dirs, QDir::Name | QDir::Reversed);
00275 QStringList::ConstIterator it;
00276 for (it = fileList.begin(); it != fileList.end(); ++it)
00277 {
00278 QString dirName = (*it);
00279 if (dirName == "." || dirName == ".." || dirName == "common")
00280 continue;
00281 if (QFile::exists(d.absFilePath(*it) + "/html/index.html"))
00282 {
00283 DocumentationItem *docItem = new DocumentationItem(DocumentationItem::Book, item, *it);
00284 docItem->setURL(KURL(d.absFilePath(*it) + "/html/index.html"));
00285 docItem->setExpandable(true);
00286 createBookTOC(docItem);
00287 }
00288 }
00289 }
00290
00291 DocumentationCatalogItem *DocDoxygenPlugin::createCatalog(KListView *contents, const QString &title, const QString &url)
00292 {
00293 kdDebug() << "DocDoxygenPlugin::createCatalog: url=" << url << endl;
00294 DocumentationCatalogItem *item = new DoxyDocumentationCatalogItem(url, this, contents, title);
00295 item->setURL(url);
00296 return item;
00297 }
00298
00299 void DocDoxygenPlugin::createBookTOC(DocumentationItem *item, const QString &tagUrl, const QString &baseHtmlUrl)
00300 {
00301 QString tagName;
00302 if (tagUrl.isEmpty())
00303 tagName = item->url().upURL().directory(false) + item->text(0) + ".tag";
00304 else
00305 tagName = tagUrl;
00306
00307 QString baseUrl;
00308 if (baseHtmlUrl.isEmpty())
00309 baseUrl = item->url().directory(false);
00310 else
00311 baseUrl = baseHtmlUrl;
00312
00313
00314 if (!QFile::exists(tagName))
00315 return;
00316
00317 QFile f(tagName);
00318 if (!f.open(IO_ReadOnly))
00319 {
00320 kdDebug(9002) << "Could not open tag file: " << f.name() << endl;
00321 return;
00322 }
00323
00324 QDomDocument dom;
00325 if (!dom.setContent(&f) || dom.documentElement().nodeName() != "tagfile")
00326 {
00327 kdDebug(9002) << "No valid tag file" << endl;
00328 return;
00329 }
00330 f.close();
00331
00332 QDomElement docEl = dom.documentElement();
00333
00334 QDomElement childEl = docEl.lastChild().toElement();
00335 while (!childEl.isNull())
00336 {
00337 if (childEl.tagName() == "compound" && childEl.attribute("kind") == "class")
00338 {
00339 QString classname = childEl.namedItem("name").firstChild().toText().data();
00340 QString filename = childEl.namedItem("filename").firstChild().toText().data();
00341
00342 if (QFile::exists(baseUrl + filename))
00343 {
00344 DocumentationItem *docItem = new DocumentationItem(DocumentationItem::Document,
00345 item, classname);
00346 docItem->setURL(KURL(baseUrl + filename));
00347 }
00348 }
00349 childEl = childEl.previousSibling().toElement();
00350 }
00351 }
00352
00353 void DocDoxygenPlugin::createBookIndex(const QString &tagfile, IndexBox* index, DocumentationCatalogItem* item, const QString &baseHtmlUrl)
00354 {
00355 QString tagName = tagfile;
00356 kdDebug() << tagfile << endl;
00357 if (!QFile::exists(tagName))
00358 return;
00359
00360 QFile f(tagName);
00361 if (!f.open(IO_ReadOnly))
00362 {
00363 kdDebug(9002) << "Could not open tag file: " << f.name() << endl;
00364 return;
00365 }
00366
00367 QDomDocument dom;
00368 if (!dom.setContent(&f) || dom.documentElement().nodeName() != "tagfile")
00369 {
00370 kdDebug(9002) << "No valid tag file" << endl;
00371 return;
00372 }
00373 f.close();
00374
00375 QDomElement docEl = dom.documentElement();
00376 QString prefix = baseHtmlUrl.isEmpty() ? KURL(tagfile).directory(false) + "html/" : baseHtmlUrl;
00377 createIndexFromTag(dom, index, item, docEl, prefix);
00378 }
00379
00380 void DocDoxygenPlugin::createIndexFromTag(QDomDocument &dom, IndexBox *index,
00381 DocumentationCatalogItem *item, QDomElement &parentEl, const QString &prefix)
00382 {
00383 QDomElement docEl = parentEl;
00384
00385 QDomElement childEl = docEl.firstChild().toElement();
00386 while (!childEl.isNull())
00387 {
00388 if (childEl.tagName() == "compound" &&
00389 ((childEl.attribute("kind") == "class")
00390 || (childEl.attribute("kind") == "struct")
00391 || (childEl.attribute("kind") == "namespace") ))
00392 {
00393 QString classname = childEl.namedItem("name").firstChild().toText().data();
00394 QString filename = childEl.namedItem("filename").firstChild().toText().data();
00395
00396 IndexItemProto *indexItem = new IndexItemProto(this, item, index, classname,
00397 i18n("%1 Class Reference").arg(classname));
00398 indexItem->addURL(KURL(prefix + filename));
00399
00400 createIndexFromTag(dom, index, item, childEl, prefix + filename);
00401 }
00402 else if ((childEl.tagName() == "member") &&
00403 ((childEl.attribute("kind") == "function")
00404 || (childEl.attribute("kind") == "slot")
00405 || (childEl.attribute("kind") == "signal") ))
00406 {
00407 QString classname = parentEl.namedItem("name").firstChild().toText().data();
00408 QString membername = childEl.namedItem("name").firstChild().toText().data();
00409 QString anchor = childEl.namedItem("anchor").firstChild().toText().data();
00410 QString arglist = childEl.namedItem("arglist").firstChild().toText().data();
00411
00412 if (classname != membername)
00413 {
00414 IndexItemProto *indexItem = new IndexItemProto(this, item, index, membername,i18n("%1::%2%3 Member Reference").arg(classname).arg(membername).arg(arglist));
00415 indexItem->addURL(KURL(prefix + "#" + anchor));
00416 }
00417 }
00418 childEl = childEl.nextSibling().toElement();
00419 }
00420 }
00421
00422 ProjectDocumentationPlugin *DocDoxygenPlugin::projectDocumentationPlugin(ProjectDocType type)
00423 {
00424 if (type == APIDocs)
00425 return new ProjectDocumentationPlugin(this, type);
00426 return DocumentationPlugin::projectDocumentationPlugin(type);
00427 }
00428
00429 #include "docdoxygenplugin.moc"