00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "docdevhelpplugin.h"
00021
00022 #include <unistd.h>
00023
00024 #include <qdom.h>
00025 #include <qfile.h>
00026 #include <qfileinfo.h>
00027 #include <qdialog.h>
00028
00029 #include <kurl.h>
00030 #include <kaboutdata.h>
00031 #include <kconfig.h>
00032 #include <klocale.h>
00033 #include <kstandarddirs.h>
00034
00035 #include <kdevgenericfactory.h>
00036
00037 #include "../../../../config.h"
00038
00039 class DevHelpDocumentationCatalogItem: public DocumentationCatalogItem
00040 {
00041 public:
00042 DevHelpDocumentationCatalogItem(const QString &devHelpFile, DocumentationPlugin* plugin,
00043 KListView *parent, const QString &name)
00044 :DocumentationCatalogItem(plugin, parent, name), m_devHelpFile(devHelpFile)
00045 {
00046 }
00047 DevHelpDocumentationCatalogItem(const QString &devHelpFile, DocumentationPlugin* plugin,
00048 DocumentationItem *parent, const QString &name)
00049 :DocumentationCatalogItem(plugin, parent, name), m_devHelpFile(devHelpFile)
00050 {
00051 }
00052 QString devHelpFile() const { return m_devHelpFile; }
00053
00054 private:
00055 QString m_devHelpFile;
00056 };
00057
00058
00059 static const KAboutData data("docdevhelpplugin", I18N_NOOP("DevHelp documentation plugin"), "1.0");
00060 typedef KDevGenericFactory<DocDevHelpPlugin> DocDevHelpPluginFactory;
00061 K_EXPORT_COMPONENT_FACTORY( libdocdevhelpplugin, DocDevHelpPluginFactory(&data) )
00062
00063 DocDevHelpPlugin::DocDevHelpPlugin(QObject* parent, const char* name,
00064 const QStringList )
00065 :DocumentationPlugin(DocDevHelpPluginFactory::instance()->config(), parent, name)
00066 {
00067 setCapabilities(Index | FullTextSearch | ProjectDocumentation);
00068 autoSetup();
00069 }
00070
00071 DocDevHelpPlugin::~DocDevHelpPlugin()
00072 {
00073 }
00074
00075 DocumentationCatalogItem* DocDevHelpPlugin::createCatalog(KListView* contents, const QString& title, const QString& url)
00076 {
00077 return new DevHelpDocumentationCatalogItem(url, this, contents, title);
00078 }
00079
00080 QPair<KFile::Mode, QString> DocDevHelpPlugin::catalogLocatorProps()
00081 {
00082 return QPair<KFile::Mode, QString>(KFile::File, "*.devhelp");
00083 }
00084
00085 QString DocDevHelpPlugin::catalogTitle(const QString& url)
00086 {
00087 QFileInfo fi(url);
00088 if (!fi.exists())
00089 return QString::null;
00090
00091 QFile f(url);
00092 if (!f.open(IO_ReadOnly))
00093 return QString::null;
00094
00095 QDomDocument doc;
00096 if (!doc.setContent(&f))
00097 return QString::null;
00098 f.close();
00099
00100 QDomElement docEl = doc.documentElement();
00101
00102 return docEl.attribute("title", QString::null);
00103 }
00104
00105 QString DocDevHelpPlugin::pluginName() const
00106 {
00107 return i18n("Devhelp Documentation Collection");
00108 }
00109
00110 QStringList DocDevHelpPlugin::fullTextSearchLocations()
00111 {
00112 QStringList locs;
00113
00114 QMap<QString, QString> entryMap = config->entryMap("Locations");
00115
00116 for (QMap<QString, QString>::const_iterator it = entryMap.begin();
00117 it != entryMap.end(); ++it)
00118 {
00119 config->setGroup("Search Settings");
00120 if (config->readBoolEntry(it.key(), false))
00121 {
00122 config->setGroup("Locations");
00123 QFileInfo fi(config->readPathEntry(it.key()));
00124 locs << fi.dirPath(true);
00125 }
00126 }
00127
00128 return locs;
00129 }
00130
00131 bool DocDevHelpPlugin::needRefreshIndex(DocumentationCatalogItem* item)
00132 {
00133 DevHelpDocumentationCatalogItem *dhItem = dynamic_cast<DevHelpDocumentationCatalogItem *>(item);
00134 if (!dhItem)
00135 return false;
00136
00137 QFileInfo fi(dhItem->devHelpFile());
00138 config->setGroup("Index");
00139 if (fi.lastModified() > config->readDateTimeEntry(dhItem->text(0), new QDateTime()))
00140 {
00141 kdDebug() << "need rebuild index for " << dhItem->text(0) << endl;
00142 config->writeEntry(item->text(0), fi.lastModified());
00143 return true;
00144 }
00145 else
00146 return false;
00147 }
00148
00149 void DocDevHelpPlugin::autoSetupPlugin()
00150 {
00151 QValueStack<QString> scanStack;
00152
00153 pushToScanStack(scanStack, getenv("DEVHELP_SEARCH_PATH"));
00154 pushToScanStack(scanStack, QString(getenv("HOME")) + "/.devhelp/books");
00155
00156 QString dhexepath = DocDevHelpPluginFactory::instance()->dirs()->findExe("devhelp");
00157 if (!dhexepath.isEmpty())
00158 {
00159 QFileInfo fi(dhexepath);
00160 QString path = KURL(fi.dirPath(true)).upURL().path(1);
00161 pushToScanStack(scanStack, path + "share/devhelp/books");
00162 pushToScanStack(scanStack, path + "share/gtk-doc/html");
00163 }
00164
00165 pushToScanStack(scanStack, "/usr/share/gtk-doc/html");
00166 pushToScanStack(scanStack, "/usr/share/devhelp/books/");
00167 pushToScanStack(scanStack, "/usr/local/share/devhelp/books");
00168 pushToScanStack(scanStack, "/usr/local/share/gtk-doc/html");
00169 pushToScanStack(scanStack, "/opt/gnome/share/devhelp/books");
00170 pushToScanStack(scanStack, "/opt/gnome/share/gtk-doc/html");
00171 pushToScanStack(scanStack, "/opt/gnome2/share/devhelp/books");
00172 pushToScanStack(scanStack, "/opt/gnome2/share/gtk-doc/html");
00173
00174
00175 QStringList scanList;
00176 QDir dir;
00177 do
00178 {
00179 dir.setPath(scanStack.pop());
00180 if (!dir.exists())
00181 continue;
00182 scanList << dir.path();
00183
00184 const QFileInfoList *dirEntries = dir.entryInfoList();
00185 QPtrListIterator<QFileInfo> it(*dirEntries);
00186 for (; it.current(); ++it)
00187 {
00188 QString fileName = it.current()->fileName();
00189 if (fileName == "." || fileName == "..")
00190 continue;
00191 QString path = it.current()->absFilePath();
00192 if (it.current()->isDir())
00193 {
00194 scanStack.push(path);
00195 }
00196 }
00197 } while (!scanStack.isEmpty());
00198
00199 for (QStringList::const_iterator it = scanList.begin(); it != scanList.end(); ++it)
00200 {
00201 scanDevHelpDir(*it);
00202 }
00203 }
00204
00205 void DocDevHelpPlugin::scanDevHelpDir(const QString &path)
00206 {
00207 QDir d(path);
00208 if (! d.exists())
00209 return;
00210
00211 d.setFilter(QDir::Files);
00212
00213 const QFileInfoList *list = d.entryInfoList();
00214 QFileInfoListIterator it( *list );
00215 QFileInfo *fi;
00216 while ( (fi = it.current()) != 0 )
00217 {
00218 if (fi->extension() == "devhelp")
00219 {
00220 config->setGroup("Locations");
00221 config->writePathEntry(catalogTitle(fi->absFilePath()), fi->absFilePath());
00222 }
00223 ++it;
00224 }
00225 }
00226
00227 void DocDevHelpPlugin::pushToScanStack(QValueStack<QString> &stack, const QString &value)
00228 {
00229 if ( (!value.isEmpty()) && (!stack.contains(value)) )
00230 {
00231 stack << value;
00232 kdDebug() << "Devhelp scan stack: +: " << value << endl;
00233 }
00234 }
00235
00236 void DocDevHelpPlugin::createIndex(IndexBox* index, DocumentationCatalogItem* item)
00237 {
00238 DevHelpDocumentationCatalogItem *dhItem = dynamic_cast<DevHelpDocumentationCatalogItem *>(item);
00239 if (!dhItem)
00240 return;
00241
00242 QFileInfo fi(dhItem->devHelpFile());
00243
00244 QFile f(dhItem->devHelpFile());
00245 if (!f.open(IO_ReadOnly))
00246 {
00247 kdDebug(9002) << "Could not read" << dhItem->devHelpFile() << endl;
00248 return;
00249 }
00250
00251 QDomDocument doc;
00252 if (!doc.setContent(&f))
00253 {
00254 kdDebug() << "Not a valid devhelp file: " << dhItem->devHelpFile() << endl;
00255 return;
00256 }
00257 f.close();
00258
00259 QString baseUrl = KURL(dhItem->devHelpFile()).directory();
00260
00261 QDomElement docEl = doc.documentElement();
00262 QDomElement chaptersEl = docEl.namedItem("functions").toElement();
00263 QDomElement childEl = chaptersEl.firstChild().toElement();
00264 while (!childEl.isNull())
00265 {
00266 if (childEl.tagName() == "function")
00267 {
00268 QString name = childEl.attribute("name");
00269 QString url = childEl.attribute("link");
00270
00271 IndexItemProto *ii = new IndexItemProto(this, item, index, name, item->text(0));
00272 ii->addURL(KURL(baseUrl+"/"+url));
00273 }
00274 childEl = childEl.nextSibling().toElement();
00275 }
00276 }
00277
00278 void DocDevHelpPlugin::createTOC(DocumentationCatalogItem* item)
00279 {
00280 DevHelpDocumentationCatalogItem *dhItem = dynamic_cast<DevHelpDocumentationCatalogItem *>(item);
00281 if (!dhItem)
00282 return;
00283
00284 QFileInfo fi(dhItem->devHelpFile());
00285
00286 QFile f(dhItem->devHelpFile());
00287 if (!f.open(IO_ReadOnly))
00288 {
00289 kdDebug(9002) << "Could not read" << dhItem->devHelpFile() << endl;
00290 return;
00291 }
00292
00293 QDomDocument doc;
00294 if (!doc.setContent(&f))
00295 {
00296 kdDebug() << "Not a valid devhelp file: " << dhItem->devHelpFile() << endl;
00297 return;
00298 }
00299 f.close();
00300
00301 QDomElement docEl = doc.documentElement();
00302 QDomElement chaptersEl = docEl.namedItem("chapters").toElement();
00303
00304 QDomElement childEl = chaptersEl.lastChild().toElement();
00305 QString baseUrl = KURL(dhItem->devHelpFile()).directory();
00306 addTocSect(dhItem, childEl, baseUrl, true);
00307 }
00308
00309 void DocDevHelpPlugin::addTocSect(DocumentationItem *parent, QDomElement childEl,
00310 QString baseUrl, bool book)
00311 {
00312 while (!childEl.isNull())
00313 {
00314 if ( (childEl.tagName() == "sub") || (childEl.tagName() == "chapter"))
00315 {
00316 QString name = childEl.attribute("name");
00317 QString url = childEl.attribute("link");
00318
00319 if (name.isEmpty() && url.contains("ix"))
00320 name = "Index";
00321
00322 DocumentationItem *item = new DocumentationItem(
00323 book ? DocumentationItem::Book : DocumentationItem::Document, parent, name);
00324 item->setURL(KURL(baseUrl+"/"+url));
00325
00326 QDomElement grandchildEl = childEl.lastChild().toElement();
00327 addTocSect(item, grandchildEl, baseUrl);
00328 }
00329 childEl = childEl.previousSibling().toElement();
00330 }
00331 }
00332
00333 void DocDevHelpPlugin::setCatalogURL(DocumentationCatalogItem* item)
00334 {
00335 DevHelpDocumentationCatalogItem *dhItem = dynamic_cast<DevHelpDocumentationCatalogItem *>(item);
00336 if (!dhItem)
00337 return;
00338
00339 QFileInfo fi(dhItem->devHelpFile());
00340
00341 QFile f(dhItem->devHelpFile());
00342 if (!f.open(IO_ReadOnly))
00343 {
00344 kdDebug(9002) << "Could not read" << dhItem->devHelpFile() << endl;
00345 return;
00346 }
00347 QDomDocument doc;
00348 if (!doc.setContent(&f))
00349 {
00350 kdDebug(9002) << "Not a valid Devhelp file: " << dhItem->devHelpFile() << endl;
00351 return;
00352 }
00353 f.close();
00354
00355 QDomElement docEl = doc.documentElement();
00356 QDomElement titleEl = docEl.namedItem("book").toElement();
00357
00358 if (item->url().isEmpty())
00359 {
00360 KURL url(fi.dirPath(true) + "/" + docEl.attribute("link", QString::null));
00361 item->setURL(url);
00362 }
00363 }
00364
00365 ProjectDocumentationPlugin *DocDevHelpPlugin::projectDocumentationPlugin(ProjectDocType type)
00366 {
00367 if (type == APIDocs)
00368 return new ProjectDocumentationPlugin(this, type);
00369 return DocumentationPlugin::projectDocumentationPlugin(type);
00370 }
00371
00372 #include "docdevhelpplugin.moc"