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/devhelp/docdevhelpplugin.cpp

397 lines
12 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 "docdevhelpplugin.h"
#include <unistd.h>
#include <tqdom.h>
#include <tqfile.h>
#include <tqfileinfo.h>
#include <tqdialog.h>
#include <kurl.h>
#include <tdeaboutdata.h>
#include <tdeconfig.h>
#include <tdelocale.h>
#include <kstandarddirs.h>
#include <kdevgenericfactory.h>
#include <kdevplugininfo.h>
#include "../../../../config.h"
class DevHelpDocumentationCatalogItem: public DocumentationCatalogItem
{
public:
DevHelpDocumentationCatalogItem(const TQString &devHelpFile, DocumentationPlugin* plugin,
TDEListView *parent, TDEListViewItem *after, const TQString &name)
:DocumentationCatalogItem(plugin, parent, after, name), m_devHelpFile(devHelpFile)
{
}
DevHelpDocumentationCatalogItem(const TQString &devHelpFile, DocumentationPlugin* plugin,
DocumentationItem *parent, const TQString &name)
:DocumentationCatalogItem(plugin, parent, name), m_devHelpFile(devHelpFile)
{
}
TQString devHelpFile() const { return m_devHelpFile; }
virtual TQString cacheVersion() const {
unsigned int checksum=0;
for(int a=0;a<m_devHelpFile.length(); a++) {
checksum += (a+1) * (int)m_devHelpFile[a];
}
TQString str;
TQTextOStream( &str ) << checksum;
return str;
}
protected:
private:
TQString m_devHelpFile;
};
static const KDevPluginInfo data("docdevhelpplugin");
typedef KDevGenericFactory<DocDevHelpPlugin> DocDevHelpPluginFactory;
K_EXPORT_COMPONENT_FACTORY( libdocdevhelpplugin, DocDevHelpPluginFactory(data) )
DocDevHelpPlugin::DocDevHelpPlugin(TQObject* parent, const char* name,
const TQStringList /*args*/)
:DocumentationPlugin(DocDevHelpPluginFactory::instance()->config(), parent, name)
{
setCapabilities(Index | FullTextSearch | ProjectDocumentation);
autoSetup();
}
DocDevHelpPlugin::~DocDevHelpPlugin()
{
}
DocumentationCatalogItem* DocDevHelpPlugin::createCatalog(TDEListView* contents, TDEListViewItem *after, const TQString& title, const TQString& url)
{
return new DevHelpDocumentationCatalogItem(url, this, contents, after, title);
}
TQPair<KFile::Mode, TQString> DocDevHelpPlugin::catalogLocatorProps()
{
return TQPair<KFile::Mode, TQString>(KFile::File, "*.devhelp");
}
TQString DocDevHelpPlugin::catalogTitle(const TQString& url)
{
TQFileInfo fi(url);
if (!fi.exists())
return TQString();
TQFile f(url);
if (!f.open(IO_ReadOnly))
return TQString();
TQDomDocument doc;
if (!doc.setContent(&f))
return TQString();
f.close();
TQDomElement docEl = doc.documentElement();
return docEl.attribute("title", TQString());
}
TQString DocDevHelpPlugin::pluginName() const
{
return i18n("Devhelp Documentation Collection");
}
TQStringList DocDevHelpPlugin::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;
}
bool DocDevHelpPlugin::needRefreshIndex(DocumentationCatalogItem* item)
{
DevHelpDocumentationCatalogItem *dhItem = dynamic_cast<DevHelpDocumentationCatalogItem *>(item);
if (!dhItem)
return false;
TQFileInfo fi(dhItem->devHelpFile());
config->setGroup("Index");
if (fi.lastModified() > config->readDateTimeEntry(dhItem->text(0), new TQDateTime()))
{
kdDebug() << "need rebuild index for " << dhItem->text(0) << endl;
config->writeEntry(item->text(0), fi.lastModified());
return true;
}
else
return false;
}
void DocDevHelpPlugin::autoSetupPlugin()
{
// Clear groups, to allow for re-autosetup calls
config->deleteGroup("Index");
config->deleteGroup("Index Settings");
config->deleteGroup("Locations");
config->deleteGroup("Search Settings");
config->deleteGroup("TOC Settings");
config->sync();
TQValueStack<TQString> scanStack;
pushToScanStack(scanStack, getenv("DEVHELP_SEARCH_PATH"));
pushToScanStack(scanStack, TQString(getenv("HOME")) + "/.devhelp/books");
TQString dhexepath = DocDevHelpPluginFactory::instance()->dirs()->findExe("devhelp");
if (!dhexepath.isEmpty())
{
TQFileInfo fi(dhexepath);
TQString path = KURL(fi.dirPath(true)).upURL().path(1);
pushToScanStack(scanStack, path + "share/devhelp/books");
pushToScanStack(scanStack, path + "share/gtk-doc/html");
}
pushToScanStack(scanStack, "/usr/share/gtk-doc/html");
pushToScanStack(scanStack, "/usr/share/devhelp/books/");
pushToScanStack(scanStack, "/usr/local/share/devhelp/books");
pushToScanStack(scanStack, "/usr/local/share/gtk-doc/html");
pushToScanStack(scanStack, "/opt/gnome/share/devhelp/books");
pushToScanStack(scanStack, "/opt/gnome/share/gtk-doc/html");
pushToScanStack(scanStack, "/opt/gnome2/share/devhelp/books");
pushToScanStack(scanStack, "/opt/gnome2/share/gtk-doc/html");
//fill the list of scan dirs (with subdirectories)
TQStringList scanList;
TQDir dir;
do
{
dir.setPath(scanStack.pop());
if (!dir.exists())
continue;
scanList << dir.path();
const TQFileInfoList *dirEntries = dir.entryInfoList();
if ( !dirEntries ) continue;
TQPtrListIterator<TQFileInfo> it(*dirEntries);
for (; it.current(); ++it)
{
TQString fileName = it.current()->fileName();
if (fileName == "." || fileName == "..")
continue;
TQString path = it.current()->absFilePath();
if (it.current()->isDir())
{
scanStack.push(path);
}
}
} while (!scanStack.isEmpty());
for (TQStringList::const_iterator it = scanList.begin(); it != scanList.end(); ++it)
{
scanDevHelpDir(*it);
}
config->sync();
}
void DocDevHelpPlugin::scanDevHelpDir(const TQString &path)
{
TQDir d(path);
if (! d.exists() || !d.isReadable())
return;
d.setFilter(TQDir::Files);
//scan for *.devhelp files
const TQFileInfoList *list = d.entryInfoList();
TQFileInfoListIterator it( *list );
TQFileInfo *fi;
while ( (fi = it.current()) != 0 )
{
if (fi->extension() == "devhelp")
{
config->setGroup("Locations");
config->writePathEntry(catalogTitle(fi->absFilePath()), fi->absFilePath());
}
++it;
}
}
void DocDevHelpPlugin::pushToScanStack(TQValueStack<TQString> &stack, const TQString &value)
{
if ( (!value.isEmpty()) && (!stack.contains(value)) )
{
stack << value;
kdDebug() << "Devhelp scan stack: +: " << value << endl;
}
}
void DocDevHelpPlugin::createIndex(IndexBox* index, DocumentationCatalogItem* item)
{
DevHelpDocumentationCatalogItem *dhItem = dynamic_cast<DevHelpDocumentationCatalogItem *>(item);
if (!dhItem)
return;
TQFileInfo fi(dhItem->devHelpFile());
TQFile f(dhItem->devHelpFile());
if (!f.open(IO_ReadOnly))
{
kdDebug(9002) << "Could not read" << dhItem->devHelpFile() << endl;
return;
}
TQDomDocument doc;
if (!doc.setContent(&f))
{
kdDebug() << "Not a valid devhelp file: " << dhItem->devHelpFile() << endl;
return;
}
f.close();
TQString baseUrl = KURL(dhItem->devHelpFile()).directory();
TQDomElement docEl = doc.documentElement();
TQDomElement chaptersEl = docEl.namedItem("functions").toElement();
TQDomElement childEl = chaptersEl.firstChild().toElement();
while (!childEl.isNull())
{
if (childEl.tagName() == "function")
{
TQString name = childEl.attribute("name");
TQString url = childEl.attribute("link");
IndexItemProto *ii = new IndexItemProto(this, item, index, name, item->text(0));
ii->addURL(KURL(baseUrl+"/"+url));
}
childEl = childEl.nextSibling().toElement();
}
}
void DocDevHelpPlugin::createTOC(DocumentationCatalogItem* item)
{
DevHelpDocumentationCatalogItem *dhItem = dynamic_cast<DevHelpDocumentationCatalogItem *>(item);
if (!dhItem)
return;
TQFileInfo fi(dhItem->devHelpFile());
TQFile f(dhItem->devHelpFile());
if (!f.open(IO_ReadOnly))
{
kdDebug(9002) << "Could not read" << dhItem->devHelpFile() << endl;
return;
}
TQDomDocument doc;
if (!doc.setContent(&f))
{
kdDebug() << "Not a valid devhelp file: " << dhItem->devHelpFile() << endl;
return;
}
f.close();
TQDomElement docEl = doc.documentElement();
TQDomElement chaptersEl = docEl.namedItem("chapters").toElement();
TQDomElement childEl = chaptersEl.lastChild().toElement();
TQString baseUrl = KURL(dhItem->devHelpFile()).directory();
addTocSect(dhItem, childEl, baseUrl, true);
}
void DocDevHelpPlugin::addTocSect(DocumentationItem *parent, TQDomElement childEl,
TQString baseUrl, bool book)
{
while (!childEl.isNull())
{
if ( (childEl.tagName() == "sub") || (childEl.tagName() == "chapter"))
{
TQString name = childEl.attribute("name");
TQString url = childEl.attribute("link");
if (name.isEmpty() && url.contains("ix"))
name = "Index";
DocumentationItem *item = new DocumentationItem(
book ? DocumentationItem::Book : DocumentationItem::Document, parent, name);
item->setURL(KURL(baseUrl+"/"+url));
TQDomElement grandchildEl = childEl.lastChild().toElement();
addTocSect(item, grandchildEl, baseUrl);
}
childEl = childEl.previousSibling().toElement();
}
}
void DocDevHelpPlugin::setCatalogURL(DocumentationCatalogItem* item)
{
DevHelpDocumentationCatalogItem *dhItem = dynamic_cast<DevHelpDocumentationCatalogItem *>(item);
if (!dhItem)
return;
TQFileInfo fi(dhItem->devHelpFile());
TQFile f(dhItem->devHelpFile());
if (!f.open(IO_ReadOnly))
{
kdDebug(9002) << "Could not read" << dhItem->devHelpFile() << endl;
return;
}
TQDomDocument doc;
if (!doc.setContent(&f))
{
kdDebug(9002) << "Not a valid Devhelp file: " << dhItem->devHelpFile() << endl;
return;
}
f.close();
TQDomElement docEl = doc.documentElement();
TQDomElement titleEl = docEl.namedItem("book").toElement();
if (item->url().isEmpty())
{
KURL url(fi.dirPath(true) + "/" + docEl.attribute("link", TQString()));
item->setURL(url);
}
}
ProjectDocumentationPlugin *DocDevHelpPlugin::projectDocumentationPlugin(ProjectDocType type)
{
if (type == APIDocs)
return new ProjectDocumentationPlugin(this, type);
return DocumentationPlugin::projectDocumentationPlugin(type);
}
#include "docdevhelpplugin.moc"