diff options
Diffstat (limited to 'parts/documentation/interfaces/kdevdocumentationplugin.cpp')
-rw-r--r-- | parts/documentation/interfaces/kdevdocumentationplugin.cpp | 721 |
1 files changed, 721 insertions, 0 deletions
diff --git a/parts/documentation/interfaces/kdevdocumentationplugin.cpp b/parts/documentation/interfaces/kdevdocumentationplugin.cpp new file mode 100644 index 00000000..8e336c83 --- /dev/null +++ b/parts/documentation/interfaces/kdevdocumentationplugin.cpp @@ -0,0 +1,721 @@ +/* This file is part of the KDE project + Copyright (C) 2004 by Alexander Dymo <cloudtemple@mksat.net> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +#include "kdevdocumentationplugin.h" + +#include <qfile.h> +#include <qpainter.h> +#include <qstyle.h> +#include <qheader.h> +#include <qtextstream.h> + +#include <kstandarddirs.h> +#include <kiconloader.h> +#include <kconfig.h> +#include <kdebug.h> +#include <kdirwatch.h> +#include <klocale.h> + +//class DocumentationItem + +DocumentationItem::DocumentationItem(DocumentationItem::Type type, KListView *parent, + const QString &name) + :KListViewItem(parent, name), m_type(type) +{ + init(); +} + +DocumentationItem::DocumentationItem(DocumentationItem::Type type, KListViewItem *parent, + const QString &name) + :KListViewItem(parent, name), m_type(type) +{ + init(); +} + +DocumentationItem::DocumentationItem(DocumentationItem::Type type, KListView *parent, + KListViewItem *after, const QString &name) + :KListViewItem(parent, after, name), m_type(type) +{ + init(); +} + +DocumentationItem::DocumentationItem(DocumentationItem::Type type, KListViewItem * parent, + KListViewItem * after, const QString & name ) + :KListViewItem(parent, after, name), m_type(type) +{ + init(); +} + + +void DocumentationItem::init( ) +{ + QString icon; + + switch (m_type) + { + case Collection: + case Catalog: + icon = "folder"; + break; + case Book: + icon = "contents"; + break; + default: + icon = "document"; + } + + setPixmap(0, SmallIcon(icon)); +} + + + + + +//class DocumentationCatalogItem + + +DocumentationCatalogItem::DocumentationCatalogItem(DocumentationPlugin* plugin, + KListView *parent, const QString &name) + :DocumentationItem(DocumentationItem::Catalog, parent, name), m_plugin(plugin), + isLoaded(false), isActivated(false), m_isProjectDocumentationItem(false) +{ + setExpandable(true); + m_plugin->addCatalog(this); +} + +DocumentationCatalogItem::DocumentationCatalogItem(DocumentationPlugin* plugin, + DocumentationItem *parent, const QString &name) + :DocumentationItem(DocumentationItem::Catalog, parent, name), m_plugin(plugin), + isLoaded(false), isActivated(false), m_isProjectDocumentationItem(false) +{ + setExpandable(true); + m_plugin->addCatalog(this); +} + +DocumentationCatalogItem::~ DocumentationCatalogItem( ) +{ + m_plugin->clearCatalog(this); +} + +void DocumentationCatalogItem::setOpen(bool o) +{ + if (o) + { + load(); + } + DocumentationItem::setOpen(o); +} + +void DocumentationCatalogItem::load() +{ +if(isLoaded) +return; + + plugin()->createTOC(this); + isLoaded = true; +} + +void DocumentationCatalogItem::activate() +{ + if (!isActivated) + { + plugin()->setCatalogURL(this); + isActivated = true; + } + DocumentationItem::activate(); +} + + + + +//class IndexItemProto + +IndexItemProto::IndexItemProto(DocumentationPlugin *plugin, DocumentationCatalogItem *catalog, + IndexBox *listbox, const QString &text, const QString &description) + : m_listbox(listbox), m_text(text), m_description(description) +{ + plugin->indexes[catalog].append(this); + m_listbox->addIndexItem(this); +} + +IndexItemProto::~IndexItemProto() +{ + m_listbox->removeIndexItem(this); +} + + +//class IndexItem + +IndexItem::IndexItem(IndexBox *listbox, const QString &text) + :QListBoxText(listbox, text), m_listbox(listbox) +{ +} + +IndexItem::List IndexItem::urls() const +{ + List urlList; + QValueList<IndexItemProto*> itemProtos = m_listbox->items[text()]; + for (QValueList<IndexItemProto*>::const_iterator it = itemProtos.begin(); + it != itemProtos.end(); ++it) + urlList.append(qMakePair((*it)->description(), (*it)->url())); + return urlList; +} + + + + +//class ConfigurationItem + +ConfigurationItem::ConfigurationItem(QListView *parent, DocumentationPlugin * plugin, const QString &title, const QString &url, + bool indexPossible, bool fullTextSearchPossible) + :QCheckListItem(parent, "", QCheckListItem::CheckBox), m_title(title), m_url(url), + m_origTitle(title), m_contents(true), m_index(false), m_fullTextSearch(false), + m_indexPossible(indexPossible), m_fullTextSearchPossible(fullTextSearchPossible), + m_docPlugin( plugin ) +{ + setText(3, m_title); + setText(4, m_url); +} + +void ConfigurationItem::paintCell(QPainter *p, const QColorGroup &cg, int column, + int width, int align) +{ + if ( (column == 0) || (column == 1) || (column == 2) ) + { + if ( !p ) + return; + + QListView *lv = listView(); + if ( !lv ) + return; + + const BackgroundMode bgmode = lv->viewport()->backgroundMode(); + const QColorGroup::ColorRole crole = QPalette::backgroundRoleFromMode( bgmode ); + p->fillRect(0, 0, width, height(), cg.brush(crole)); + + QFontMetrics fm(lv->fontMetrics()); + int boxsize = lv->style().pixelMetric(QStyle::PM_CheckListButtonSize, lv); + int marg = lv->itemMargin(); + int styleflags = QStyle::Style_Default; + + if (((column == 0) && m_contents) || ((column == 1) && m_index) || ((column == 2) && m_fullTextSearch)) + styleflags |= QStyle::Style_On; + else + styleflags |= QStyle::Style_Off; + if ((column == 0) || ((column == 1) && m_indexPossible) || ((column == 2) && m_fullTextSearchPossible)) + styleflags |= QStyle::Style_Enabled; + + int x = 0; + int y = 0; + x += 3; + if (align & AlignVCenter) + y = ((height() - boxsize) / 2) + marg; + else + y = (fm.height() + 2 + marg - boxsize) / 2; + + QStyleOption opt(this); + lv->style().drawPrimitive(QStyle::PE_CheckListIndicator, p, + QRect(x, y, boxsize, fm.height() + 2 + marg), cg, styleflags, opt); + + return; + } + QListViewItem::paintCell(p, cg, column, width, align); +} + +int ConfigurationItem::width(const QFontMetrics &fm, const QListView *lv, int c) const +{ + if ((c == 0) || (c == 1) || (c == 2)) + return lv->style().pixelMetric(QStyle::PM_CheckListButtonSize, lv) + 4; + return QListViewItem::width(fm, lv, c); +} + + + + + + + + +//class DocumentationPlugin + +DocumentationPlugin::DocumentationPlugin(KConfig *pluginConfig, QObject *parent, const char *name) + :QObject(parent, name), config(pluginConfig), m_indexCreated(false) +{ +} + +DocumentationPlugin::~DocumentationPlugin() +{ +} + +void DocumentationPlugin::autoSetup() +{ + config->setGroup("General"); + if ( ! config->readBoolEntry("Autosetup", false) ) + { + autoSetupPlugin(); + config->setGroup("General"); + config->writeEntry("Autosetup", true); + config->sync(); + } +} + +void DocumentationPlugin::reload() +{ + clear(); + for (QValueList<DocumentationCatalogItem *>::iterator it = catalogs.begin(); + it != catalogs.end(); ++it) + { + createTOC(*it); + } +} + +void DocumentationPlugin::clear() +{ + for (QValueList<DocumentationCatalogItem *>::iterator it = catalogs.begin(); + it != catalogs.end(); ++it) + { + clearCatalog(*it); + } +} + +void DocumentationPlugin::clearCatalog(DocumentationCatalogItem *item) +{ + //clear named catalog map + for (QMap<QString, DocumentationCatalogItem*>::iterator it = namedCatalogs.begin(); + it != namedCatalogs.end(); ++it) + { + if (it.data() == item) + { + namedCatalogs.remove(it); + break; + } + } + //clear indexes for catalog + QValueList<IndexItemProto *> idx = indexes[item]; + for (QValueList<IndexItemProto *>::iterator it = idx.begin(); it != idx.end(); ++it) + { + delete *it; + } + indexes.remove(item); + + //remove catalog + catalogs.remove(item); +} + +void DocumentationPlugin::createIndex(IndexBox *index) +{ + if (m_indexCreated) + return; + + for (QValueList<DocumentationCatalogItem *>::iterator it = catalogs.begin(); + it != catalogs.end(); ++it) + { + loadIndex(index, *it); + } + m_indexCreated = true; +} + +void DocumentationPlugin::cacheIndex(DocumentationCatalogItem *item) +{ + kdDebug() << "Creating index cache for " << item->text(0) << endl; + + QString cacheName = locateLocal("data", QString("kdevdocumentation/index/cache_") + item->text(0)); + QFile cacheFile(cacheName); + if (!cacheFile.open(IO_WriteOnly)) + return; + + QTextStream str(&cacheFile); + str.setEncoding(QTextStream::Unicode); + str << CACHE_VERSION << endl; + + QValueList<IndexItemProto*> catalogIndexes = indexes[item]; + for (QValueList<IndexItemProto*>::const_iterator it = catalogIndexes.constBegin(); + it != catalogIndexes.constEnd(); ++it) + { + str << (*it)->text() << endl; + str << (*it)->description() << endl; + str << (*it)->url().url() << endl; + } + + cacheFile.close(); +} + +bool DocumentationPlugin::loadCachedIndex(IndexBox *index, DocumentationCatalogItem *item) +{ + QString cacheName = locateLocal("data", QString("kdevdocumentation/index/cache_") + item->cacheVersion() + item->text(0)); + QFile cacheFile(cacheName); + if (!cacheFile.open(IO_ReadOnly)) + return false; + + kdDebug() << "Using cached index for item: " << item->text(0) << endl; + + QTextStream str(&cacheFile); + str.setEncoding(QTextStream::Unicode); + QString cache = str.read(); + QStringList cacheList = QStringList::split("\n", cache, true); + QString ver = cacheList.first(); + if (ver != CACHE_VERSION) + { + kdDebug() << "Wrong cache version: " << ver << endl; + return false; + } + QStringList::const_iterator it = cacheList.begin(); + it++; + QString s[3]; int c = 0; + for (; it != cacheList.end(); ++it) + { + s[c] = *it; + if (c == 2) + { + IndexItemProto *ii = new IndexItemProto(this, item, index, s[0], s[1]); + ii->addURL(KURL(s[2])); + c = 0; + } + else c++; + } + cacheFile.close(); + + return true; +} + +void DocumentationPlugin::addCatalog(DocumentationCatalogItem *item) +{ + catalogs.append(item); + namedCatalogs[item->text(0)] = item; +// indexes[item] = QValueList<IndexItem*>(); +} + +void DocumentationPlugin::addCatalogConfiguration(KListView *configurationView, + const QString &title, const QString &url) +{ + new ConfigurationItem(configurationView, this, title, url, + hasCapability(Index), hasCapability(FullTextSearch)); +} + +void DocumentationPlugin::editCatalogConfiguration(ConfigurationItem *configurationItem, + const QString &title, const QString &url) +{ + configurationItem->setTitle(title); + configurationItem->setURL(url); +} + +void DocumentationPlugin::deleteCatalogConfiguration(const ConfigurationItem *const configurationItem) +{ + deletedConfigurationItems << configurationItem->title(); +} + +void DocumentationPlugin::clearCatalogIndex(DocumentationCatalogItem *item) +{ + //clear indexes for catalog + QValueList<IndexItemProto *> idx = indexes[item]; + for (QValueList<IndexItemProto *>::iterator it = idx.begin(); it != idx.end(); ++it) + { + delete *it; + } + indexes.remove(item); +} + +void DocumentationPlugin::loadIndex(IndexBox *index, DocumentationCatalogItem *item) +{ + if (!indexEnabled(item)) + return; + if (!needRefreshIndex(item) && loadCachedIndex(index, item)) + return; + createIndex(index, item); + cacheIndex(item); +} + +void DocumentationPlugin::init(KListView *contents) +{ + config->setGroup("Locations"); + QMap<QString, QString> entryMap = config->entryMap("Locations"); + + for (QMap<QString, QString>::const_iterator it = entryMap.begin(); + it != entryMap.end(); ++it) + { + if (catalogEnabled(it.key())) + createCatalog(contents, it.key(), config->readPathEntry(it.key())); + } +} + +void DocumentationPlugin::reinit(KListView *contents, IndexBox *index, QStringList restrictions) +{ + config->setGroup("Locations"); + QMap<QString, QString> entryMap = config->entryMap("Locations"); + + //remove deleted in configuration catalogs + for (QStringList::const_iterator it = deletedConfigurationItems.constBegin(); + it != deletedConfigurationItems.constEnd(); ++it) + { + if (namedCatalogs.contains(*it)) + delete namedCatalogs[*it]; + } + deletedConfigurationItems.clear(); + + //update configuration + for (QMap<QString, QString>::const_iterator it = entryMap.begin(); + it != entryMap.end(); ++it) + { + config->setGroup("Locations"); + if (restrictions.contains(it.key()) || (!catalogEnabled(it.key()))) + { + if (namedCatalogs.contains(it.key())) + delete namedCatalogs[it.key()]; + } + else + { + kdDebug() << "updating 1" << endl; + if (!namedCatalogs.contains(it.key())) //create catalog if it does not exist + { + DocumentationCatalogItem * item = createCatalog(contents, it.key(), config->readPathEntry(it.key())); + loadIndex(index, item); + index->setDirty(true); +// index->refill(indexes[item]); + } + else if (!indexEnabled(namedCatalogs[it.key()])) //clear index if it is disabled in configuration + { + kdDebug() << " updating: clearCatalogIndex" << endl; + clearCatalogIndex(namedCatalogs[it.key()]); + } + else if ( (indexEnabled(namedCatalogs[it.key()])) //index is requested in configuration but does not yet exist + && (!indexes.contains(namedCatalogs[it.key()])) ) + { + kdDebug() << " index requested " << endl; + loadIndex(index, namedCatalogs[it.key()]); + index->setDirty(true); + } + m_indexCreated = true; + } + } +} + +void DocumentationPlugin::loadCatalogConfiguration(KListView *configurationView) +{ + config->setGroup("Locations"); + QMap<QString, QString> entryMap = config->entryMap("Locations"); + + for (QMap<QString, QString>::const_iterator it = entryMap.begin(); + it != entryMap.end(); ++it) + { + if (namedCatalogs.contains(it.key()) + && namedCatalogs[it.key()]->isProjectDocumentationItem()) + continue; + + config->setGroup("Locations"); + ConfigurationItem *item = new ConfigurationItem(configurationView, this, it.key(), + config->readPathEntry(it.key()), + hasCapability(Index), hasCapability(FullTextSearch)); + config->setGroup("TOC Settings"); + item->setContents(config->readBoolEntry(item->title(), true)); + config->setGroup("Index Settings"); + item->setIndex(config->readBoolEntry(item->title(), false)); + config->setGroup("Search Settings"); + item->setFullTextSearch(config->readBoolEntry(item->title(), false)); + } +} + +void DocumentationPlugin::saveCatalogConfiguration(KListView *configurationView) +{ + config->setGroup("Locations"); + + for (QStringList::const_iterator it = deletedConfigurationItems.constBegin(); + it != deletedConfigurationItems.constEnd(); ++it) + { + config->deleteEntry(*it); + } + + QListViewItemIterator it(configurationView); + while (it.current()) + { + ConfigurationItem *confItem = dynamic_cast<ConfigurationItem*>(it.current()); + if ( confItem->docPlugin() != this ) + { + ++it; + continue; + } + + config->setGroup("Locations"); + if (confItem->isChanged()) + config->deleteEntry(confItem->origTitle()); + config->writePathEntry(confItem->title(), confItem->url()); + + config->setGroup("TOC Settings"); + if (confItem->isChanged()) + config->deleteEntry(confItem->origTitle()); + config->writeEntry(confItem->title(), confItem->contents()); + + config->setGroup("Index Settings"); + if (confItem->isChanged()) + config->deleteEntry(confItem->origTitle()); + config->writeEntry(confItem->title(), confItem->index()); + + config->setGroup("Search Settings"); + if (confItem->isChanged()) + config->deleteEntry(confItem->origTitle()); + config->writeEntry(confItem->title(), confItem->fullTextSearch()); + + ++it; + } + config->sync(); +} + +void DocumentationPlugin::setIndexEnabled( DocumentationCatalogItem * item, bool e ) +{ + QString group = config->group(); + config->setGroup("Index Settings"); + config->writeEntry(item->text(0), e); + config->setGroup(group); +} + +bool DocumentationPlugin::indexEnabled( DocumentationCatalogItem * item ) const +{ + QString group = config->group(); + config->setGroup("Index Settings"); + bool b = config->readBoolEntry(item->text(0), false); + config->setGroup(group); + return b; +} + +bool DocumentationPlugin::catalogEnabled(const QString &name) const +{ + QString group = config->group(); + config->setGroup("TOC Settings"); + bool b = config->readBoolEntry(name, true); + config->setGroup(group); + return b; +} + +void DocumentationPlugin::setCatalogEnabled(const QString &name, bool e) +{ + QString group = config->group(); + config->setGroup("TOC Settings"); + config->writeEntry(name, e); + config->setGroup(group); +} + + + + +//class IndexBox + +IndexBox::IndexBox(QWidget *parent, const char *name) + :KListBox(parent, name), m_dirty(false) +{ +} + +void IndexBox::addIndexItem(IndexItemProto *item) +{ + items[item->text()].append(item); +} + +void IndexBox::removeIndexItem(IndexItemProto *item) +{ + QString text = item->text(); + items[text].remove(item); + if (items[text].count() == 0) + { + items.remove(text); + QListBoxItem *item = findItem(text, Qt::CaseSensitive | Qt::ExactMatch); + if (item) + delete item; + } +} + +void IndexBox::fill() +{ + for (QMap<QString, QValueList<IndexItemProto*> >::const_iterator it = items.begin(); + it != items.end(); ++it) + { + new IndexItem(this, it.key()); + } +} + +void IndexBox::setDirty(bool dirty) +{ + m_dirty = dirty; +} + +void IndexBox::refill() +{ + if (m_dirty) + { + clear(); + fill(); + setDirty(false); + } +} + + +ProjectDocumentationPlugin::ProjectDocumentationPlugin(DocumentationPlugin *docPlugin, DocumentationPlugin::ProjectDocType type) + :QObject(0, 0), m_docPlugin(docPlugin), m_catalog(0), m_type(type), m_contents(0), m_index(0) +{ + kdDebug() << "ProjectDocumentationPlugin::ProjectDocumentationPlugin for type " << type << endl; + + m_watch = new KDirWatch(this); + connect(m_watch, SIGNAL(dirty(const QString&)), this, SLOT(reinit())); + m_watch->startScan(); +} + +ProjectDocumentationPlugin::~ProjectDocumentationPlugin() +{ + deinit(); +} + +void ProjectDocumentationPlugin::init(KListView *contents, IndexBox *index, const QString &url) +{ + m_contents = contents; + m_index = index; + m_url = url; + + if (m_catalog) + deinit(); + m_catalog = m_docPlugin->createCatalog(contents, + m_type == DocumentationPlugin::APIDocs ? i18n("Project API Documentation") + : i18n("Project User Manual"), url); + if (m_catalog) + { + m_catalog->setProjectDocumentationItem(true); + m_watch->addFile(url); + } +} + +void ProjectDocumentationPlugin::reinit() +{ + deinit(); + if (m_contents != 0 && m_index != 0 && m_url != 0) + init(m_contents, m_index, m_url); +} + +void ProjectDocumentationPlugin::deinit() +{ + m_watch->removeFile(m_url); + delete m_catalog; + m_catalog = 0; +} + +QString ProjectDocumentationPlugin::pluginName() const +{ + return m_docPlugin->pluginName(); +} + +QString ProjectDocumentationPlugin::catalogURL() const +{ + return m_url; +} + +#include "kdevdocumentationplugin.moc" |