You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdevelop/parts/documentation/plugins/doxygen/docdoxygenplugin.cpp

530 lines
18 KiB

/***************************************************************************
* Copyright (C) 2004 by Alexander Dymo *
* cloudtemple@mksat.net *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. *
***************************************************************************/
#include "docdoxygenplugin.h"
#include <unistd.h>
#include <tqdom.h>
#include <tqfile.h>
#include <tqfileinfo.h>
#include <tqdialog.h>
#include <tqregexp.h>
#include <tqvaluestack.h>
#include <kurl.h>
#include <kaboutdata.h>
#include <kconfig.h>
#include <klocale.h>
#include <kstandarddirs.h>
#include <urlutil.h>
#include <kdevgenericfactory.h>
#include <kdevplugininfo.h>
#include "../../../../config.h"
class DoxyDocumentationCatalogItem: public DocumentationCatalogItem
{
public:
DoxyDocumentationCatalogItem(const TQString &origUrl, DocumentationPlugin* plugin,
KListView *tqparent, const TQString &name)
:DocumentationCatalogItem(plugin, tqparent, name), m_origUrl(origUrl)
{
}
DoxyDocumentationCatalogItem(const TQString &origUrl, DocumentationPlugin* plugin,
DocumentationItem *tqparent, const TQString &name)
:DocumentationCatalogItem(plugin, tqparent, name), m_origUrl(origUrl)
{
}
TQString origUrl() const { return m_origUrl; }
private:
TQString m_origUrl;
};
static const KDevPluginInfo data("docdoxygenplugin");
typedef KDevGenericFactory<DocDoxygenPlugin> DocDoxygenPluginFactory;
K_EXPORT_COMPONENT_FACTORY( libdocdoxygenplugin, DocDoxygenPluginFactory(data) )
DocDoxygenPlugin::DocDoxygenPlugin(TQObject* tqparent, const char* name, const TQStringList)
:DocumentationPlugin(DocDoxygenPluginFactory::instance()->config(), tqparent, name)
{
setCapabilities(Index | FullTextSearch | ProjectDocumentation | CustomDocumentationTitles );
autoSetup();
}
DocDoxygenPlugin::~DocDoxygenPlugin()
{
}
TQPair<KFile::Mode, TQString> DocDoxygenPlugin::catalogLocatorProps()
{
return TQPair<KFile::Mode, TQString>(KFile::File, "index.html *.tag");
}
TQString DocDoxygenPlugin::catalogTitle(const TQString& url)
{
TQFileInfo fi(url);
if (!fi.exists())
return TQString();
if (fi.extension(false) == "html")
{
TQFile f(url);
if (!f.open(IO_ReadOnly))
return TQString();
TQTextStream ts(&f);
TQString contents = ts.read();
TQRegExp re(".*<title>(.*)</title>.*");
re.setCaseSensitive(false);
re.search(contents);
return re.cap(1);
}
else if (fi.extension(false) == "tag")
{
TQFile *f = 0;
TQFile f1(fi.dirPath(true) + "/html/index.html");
if (f1.open(IO_ReadOnly))
f = &f1;
TQFile f2(fi.dirPath(true) + "/index.html");
if (f2.open(IO_ReadOnly))
f = &f2;
if (f != 0)
{
TQTextStream ts(f);
TQString contents = ts.read();
TQRegExp re(".*<title>(.*)</title>.*");
re.setCaseSensitive(false);
re.search(contents);
return re.cap(1);
}
}
return TQString();
}
TQString DocDoxygenPlugin::pluginName() const
{
return i18n("Doxygen Documentation Collection");
}
TQStringList DocDoxygenPlugin::fullTextSearchLocations()
{
TQStringList locs;
TQMap<TQString, TQString> entryMap = config->entryMap("Locations");
for (TQMap<TQString, TQString>::const_iterator it = entryMap.begin();
it != entryMap.end(); ++it)
{
config->setGroup("Search Settings");
if (config->readBoolEntry(it.key(), false))
{
config->setGroup("Locations");
TQFileInfo fi(config->readPathEntry(it.key()));
locs << fi.dirPath(true);
}
}
return locs;
}
void DocDoxygenPlugin::setCatalogURL(DocumentationCatalogItem* item)
{
if (item->url().url().endsWith("tag"))
{
TQFileInfo fi(item->url().directory(false) + "html/index.html");
if (fi.exists())
{
item->setURL(KURL::fromPathOrURL(fi.absFilePath()));
return;
}
TQFileInfo fi2(item->url().directory(false) + "index.html");
if (fi2.exists())
{
item->setURL(KURL::fromPathOrURL(fi2.absFilePath()));
return;
}
item->setURL(KURL());
}
}
bool DocDoxygenPlugin::needRefreshIndex(DocumentationCatalogItem* item)
{
DoxyDocumentationCatalogItem *doxyItem = dynamic_cast<DoxyDocumentationCatalogItem*>(item);
if (!doxyItem)
return false;
TQFileInfo fi(doxyItem->origUrl());
config->setGroup("Index");
if (fi.lastModified() > config->readDateTimeEntry(item->text(0), new TQDateTime()))
{
kdDebug() << "need rebuild index for " << item->text(0) << endl;
config->writeEntry(item->text(0), fi.lastModified());
return true;
}
else
return false;
}
void DocDoxygenPlugin::autoSetupPlugin()
{
autoSetupDocs(KDELIBS_DOXYDIR, "en/kdelibs-apidocs", "The KDE API Reference (The KDE API Reference)");
autoSetupDocs("", "en/kdevelop-apidocs", "The KDevelop Platform API Documentation (KDevelop)");
}
void DocDoxygenPlugin::autoSetupDocs(const TQString &defaultDir, const TQString &searchDir,
const TQString &name)
{
TQString doxyDocDir(defaultDir);
doxyDocDir = URLUtil::envExpand(doxyDocDir);
if (doxyDocDir.isEmpty())
{
TQStringList apiDirs = DocDoxygenPluginFactory::instance()->dirs()->findDirs("html", searchDir);
for (TQStringList::const_iterator it = apiDirs.begin(); it != apiDirs.end(); ++it )
{
doxyDocDir = *it;
TQString indexFile = doxyDocDir + "index.html";
if (TQFile::exists(indexFile))
{
doxyDocDir = doxyDocDir + "/" + searchDir;
break;
}
doxyDocDir = "";
}
}
if (!doxyDocDir.isEmpty())
{
config->setGroup("Search Settings");
config->writeEntry(name, true);
config->setGroup("Index Settings");
config->writeEntry(name, true);
config->setGroup("Locations");
config->writePathEntry(name, doxyDocDir + TQString("/index.html"));
}
}
void DocDoxygenPlugin::createIndex(IndexBox* index, DocumentationCatalogItem* item)
{
TQFileInfo fi(item->url().path());
if (!fi.exists())
return;
DoxyDocumentationCatalogItem *doxyItem = dynamic_cast<DoxyDocumentationCatalogItem*>(item);
if (!doxyItem)
return;
//doxygen documentation mode (if catalog points to a .tag)
if (doxyItem->origUrl().endsWith("tag"))
{
TQString htmlUrl;
TQFileInfo fi2(item->url().directory(false) + "index.html");
if (fi2.exists())
htmlUrl = fi2.dirPath(true) + "/";
TQFileInfo fi(item->url().directory(false) + "html/index.html");
if (fi.exists())
htmlUrl = fi.dirPath(true) + "/";
createBookIndex(doxyItem->origUrl(), index, item, htmlUrl);
}
//KDE doxygen documentation mode (if catalog points to a index.html)
TQDir d;
TQValueStack<TQString> dirStack;
dirStack.push(fi.dirPath(true));
do {
d.setPath(dirStack.pop());
if (!d.exists())
continue;
const TQFileInfoList *dirEntries = d.entryInfoList();
if (!dirEntries) continue;
TQPtrListIterator<TQFileInfo> it(*dirEntries);
for (; it.current(); ++it)
{
TQString fileName = it.current()->fileName();
if (fileName == "." || fileName == ".." || fileName == "common" || fileName == "html")
continue;
if (it.current()->isDir())
dirStack.push(it.current()->absFilePath());
}
if (TQFile::exists(d.absPath() + "/html/index.html"))
createBookIndex(d.absPath() + "/" + d.dirName() + ".tag", index, item);
} while (!dirStack.isEmpty());
}
void DocDoxygenPlugin::createTOC(DocumentationCatalogItem* item)
{
TQFileInfo fi(item->url().path());
if (!fi.exists())
return;
DoxyDocumentationCatalogItem *doxyItem = dynamic_cast<DoxyDocumentationCatalogItem*>(item);
if (!doxyItem)
return;
//doxygen documentation mode (if catalog points to a .tag)
if (doxyItem->origUrl().endsWith("tag"))
{
TQString htmlUrl;
TQFileInfo fi2(item->url().directory(false) + "index.html");
if (fi2.exists())
htmlUrl = fi2.dirPath(true) + "/";
TQFileInfo fi(item->url().directory(false) + "html/index.html");
if (fi.exists())
htmlUrl = fi.dirPath(true) + "/";
if (!htmlUrl.isEmpty())
createBookTOC(item, doxyItem->origUrl(), htmlUrl);
}
//KDE doxygen documentation mode (if catalog points to a index.html)
TQDir d;
TQValueStack<TQString> dirStack;
dirStack.push(fi.dirPath(true));
do {
d.setPath(dirStack.pop());
if (!d.exists())
continue;
const TQFileInfoList *dirEntries = d.entryInfoList();
if (!dirEntries) continue;
TQPtrListIterator<TQFileInfo> it(*dirEntries);
for (; it.current(); ++it)
{
TQString fileName = it.current()->fileName();
if (fileName == "." || fileName == ".." || fileName == "common" || fileName == "html")
continue;
if (it.current()->isDir())
dirStack.push(it.current()->absFilePath());
}
if (TQFile::exists(d.absPath() + "/html/index.html"))
{
DocumentationItem *docItem = new DocumentationItem(DocumentationItem::Book, item, d.dirName());
docItem->setURL(KURL(d.absPath() + "/html/index.html"));
docItem->setExpandable(true);
createBookTOC(docItem);
}
} while (!dirStack.isEmpty());
}
DocumentationCatalogItem *DocDoxygenPlugin::createCatalog(KListView *contents, const TQString &title, const TQString &url)
{
kdDebug() << "DocDoxygenPlugin::createCatalog: url=" << url << endl;
DocumentationCatalogItem *item = new DoxyDocumentationCatalogItem(url, this, contents, title);
item->setURL(url);
return item;
}
void DocDoxygenPlugin::createBookTOC(DocumentationItem *item, const TQString &tagUrl, const TQString &baseHtmlUrl)
{
TQString tagName;
if (tagUrl.isEmpty())
tagName = item->url().upURL().directory(false) + item->text(0) + ".tag";
else
tagName = tagUrl;
TQString baseUrl;
if (baseHtmlUrl.isEmpty())
baseUrl = item->url().directory(false);
else
baseUrl = baseHtmlUrl;
//@todo list html files in the directory if tag was not found
if (!TQFile::exists(tagName))
return;
TQStringList tagFileList;
if (tagName.endsWith(".tag"))
tagFileList = tagFiles(TQFileInfo(tagName).dirPath() + "/");
else
tagFileList += tagName;
TQStringList::ConstIterator end = tagFileList.constEnd();
for (TQStringList::ConstIterator it = tagFileList.constBegin(); it != end; ++it)
{
TQFile f(*it);
if (!f.open(IO_ReadOnly))
{
kdDebug(9002) << "Could not open tag file: " << f.name() << endl;
return;
}
TQDomDocument dom;
if (!dom.setContent(&f) || dom.documentElement().nodeName() != "tagfile")
{
kdDebug(9002) << "No valid tag file" << endl;
return;
}
f.close();
TQDomElement docEl = dom.documentElement();
TQDomElement childEl = docEl.lastChild().toElement();
while (!childEl.isNull())
{
if (childEl.tagName() == "compound" && childEl.attribute("kind") == "class")
{
TQString classname = childEl.namedItem("name").firstChild().toText().data();
TQString filename = childEl.namedItem("filename").firstChild().toText().data();
if (TQFile::exists(baseUrl + filename))
{
DocumentationItem *docItem = new DocumentationItem(DocumentationItem::Document,
item, classname);
docItem->setURL(KURL(baseUrl + filename));
}
}
childEl = childEl.previousSibling().toElement();
}
}
}
void DocDoxygenPlugin::createBookIndex(const TQString &tagfile, IndexBox* index, DocumentationCatalogItem* item, const TQString &baseHtmlUrl)
{
TQString tagName = tagfile;
kdDebug() << tagfile << endl;
if (!TQFile::exists(tagName))
return;
TQString prefix = baseHtmlUrl.isEmpty() ? KURL(tagfile).directory(false) + "html/" : baseHtmlUrl;
TQStringList tagFileList = tagFiles(TQFileInfo(tagName).dirPath() + "/");
TQStringList::ConstIterator end = tagFileList.constEnd();
for (TQStringList::ConstIterator it = tagFileList.constBegin(); it != end; ++it)
{
TQFile f(*it);
if (!f.open(IO_ReadOnly))
{
kdDebug(9002) << "Could not open tag file: " << f.name() << endl;
return;
}
TQDomDocument dom;
if (!dom.setContent(&f) || dom.documentElement().nodeName() != "tagfile")
{
kdDebug(9002) << "No valid tag file" << endl;
return;
}
f.close();
TQDomElement docEl = dom.documentElement();
createIndexFromTag(dom, index, item, docEl, prefix);
}
}
void DocDoxygenPlugin::createIndexFromTag(TQDomDocument &dom, IndexBox *index,
DocumentationCatalogItem *item, TQDomElement &tqparentEl, const TQString &prefix)
{
TQDomElement docEl = tqparentEl;
TQDomElement childEl = docEl.firstChild().toElement();
while (!childEl.isNull())
{
if (childEl.tagName() == "compound" &&
((childEl.attribute("kind") == "class")
|| (childEl.attribute("kind") == "struct")
|| (childEl.attribute("kind") == "namespace") ))
{
TQString classname = childEl.namedItem("name").firstChild().toText().data();
TQString filename = childEl.namedItem("filename").firstChild().toText().data();
IndexItemProto *indexItem = new IndexItemProto(this, item, index, classname,
i18n("%1 Class Reference").tqarg(classname));
indexItem->addURL(KURL(prefix + filename));
createIndexFromTag(dom, index, item, childEl, prefix + filename);
}
else if ((childEl.tagName() == "member") &&
((childEl.attribute("kind") == "function")
|| (childEl.attribute("kind") == "slot")
|| (childEl.attribute("kind") == "signal") ))
{
TQString classname = tqparentEl.namedItem("name").firstChild().toText().data();
TQString membername = childEl.namedItem("name").firstChild().toText().data();
TQString anchor = childEl.namedItem("anchor").firstChild().toText().data();
TQString arglist = childEl.namedItem("arglist").firstChild().toText().data();
if (classname != membername)
{
IndexItemProto *indexItem = new IndexItemProto(this, item, index, membername,i18n("%1::%2%3 Member Reference").tqarg(classname).tqarg(membername).tqarg(arglist));
indexItem->addURL(KURL(prefix + "#" + anchor));
}
}
childEl = childEl.nextSibling().toElement();
}
}
ProjectDocumentationPlugin *DocDoxygenPlugin::projectDocumentationPlugin(ProjectDocType type)
{
if (type == APIDocs)
return new ProjectDocumentationPlugin(this, type);
return DocumentationPlugin::projectDocumentationPlugin(type);
}
TQStringList DocDoxygenPlugin::tagFiles(const TQString& path, int level)
{
TQStringList r;
TQDir dir(path);
if (level > 10) return r;
if (!dir.isReadable()) return r;
if (!dir.exists()) return r;
TQStringList dirList;
TQStringList fileList;
TQStringList::Iterator it;
dir.setFilter ( TQDir::Dirs);
dirList = dir.entryList();
dirList.remove(".");
dirList.remove("..");
dir.setFilter(TQDir::Files | TQDir::Hidden | TQDir::System);
fileList = dir.entryList();
TQStringList::Iterator end = dirList.end();
for ( it = dirList.begin(); it != end; ++it )
{
TQString name = *it;
if (TQFileInfo( dir, *it ).isSymLink())
continue;
r += tagFiles(path + name + "/", level + 1 );
}
TQStringList::Iterator fend = fileList.end();
for ( it = fileList.begin(); it != fend; ++it )
{
TQString name = *it;
TQFileInfo fi( dir, *it );
if (fi.isSymLink() || !fi.isFile())
continue;
if (TQDir::match(TQString("*.tag"), name))
r += (path+name);
}
return r;
}
#include "docdoxygenplugin.moc"