Make a branch to make krunner Good Enough For Aaron™.
[kdebase/uwolfer.git] / runtime / khelpcenter / toc.cpp
blob18e8c33a6ca7aed71c2e8e4e21bb596234ad7605
1 /*
2 * This file is part of the KDE Help Center
4 * Copyright (C) 2002 Frerich Raabe (raabe@kde.org)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21 #include "toc.h"
23 #include "docentry.h"
25 #include <kiconloader.h>
26 #include <kprocess.h>
27 #include <kstandarddirs.h>
28 #include <kdebug.h>
29 #include <kxmlguiwindow.h>
30 #include <KApplication>
31 #include <KStatusBar>
32 #include <klocale.h>
34 #include <QDir>
35 #include <QFileInfo>
36 //Added by qt3to4:
37 #include <QTextStream>
38 #include <QPixmap>
39 #include <sys/stat.h>
41 using namespace KHC;
43 class TOCItem : public NavigatorItem
45 public:
46 TOCItem( TOC *parent, Q3ListViewItem *parentItem, Q3ListViewItem *after, const QString &text );
48 const TOC *toc() const { return m_toc; }
50 private:
51 TOC *m_toc;
54 class TOCChapterItem : public TOCItem
56 public:
57 TOCChapterItem( TOC *toc, NavigatorItem *parent, Q3ListViewItem *after, const QString &title,
58 const QString &name );
60 virtual QString url();
62 private:
63 QString m_name;
66 class TOCSectionItem : public TOCItem
68 public:
69 TOCSectionItem( TOC *toc, TOCChapterItem *parent, Q3ListViewItem *after, const QString &title,
70 const QString &name );
72 virtual QString url();
74 private:
75 QString m_name;
78 bool TOC::m_alreadyWarned = false;
80 TOC::TOC( NavigatorItem *parentItem )
82 m_parentItem = parentItem;
85 void TOC::build( const QString &file )
87 QFileInfo fileInfo( file );
88 QString fileName = fileInfo.absoluteFilePath();
89 const QStringList resourceDirs = KGlobal::dirs()->resourceDirs( "html" );
90 QStringList::ConstIterator it = resourceDirs.begin();
91 QStringList::ConstIterator end = resourceDirs.end();
92 for ( ; it != end; ++it ) {
93 if ( fileName.startsWith( *it ) ) {
94 fileName.remove( 0, ( *it ).length() );
95 break;
99 QString cacheFile = fileName.replace( '/', "__" );
100 m_cacheFile = KStandardDirs::locateLocal( "cache", "help/" + cacheFile );
101 m_sourceFile = file;
103 if ( cacheStatus() == NeedRebuild )
104 buildCache();
105 else
106 fillTree();
109 TOC::CacheStatus TOC::cacheStatus() const
111 if ( !QFile::exists( m_cacheFile ) ||
112 sourceFileCTime() != cachedCTime() )
113 return NeedRebuild;
115 return CacheOk;
118 int TOC::sourceFileCTime() const
120 struct stat stat_buf;
121 stat( QFile::encodeName( m_sourceFile ).data(), &stat_buf );
123 return stat_buf.st_ctime;
126 int TOC::cachedCTime() const
128 QFile f( m_cacheFile );
129 if ( !f.open( QIODevice::ReadOnly ) )
130 return 0;
132 QDomDocument doc;
133 if ( !doc.setContent( &f ) )
134 return 0;
136 QDomComment timestamp = doc.documentElement().lastChild().toComment();
138 return timestamp.data().trimmed().toInt();
141 void TOC::buildCache()
143 KXmlGuiWindow *mainWindow = dynamic_cast<KXmlGuiWindow *>( kapp->activeWindow() );
145 KProcess *meinproc = new KProcess;
146 connect( meinproc, SIGNAL( finished( int, QProcess::ExitStatus) ),
147 this, SLOT( meinprocExited( int, QProcess::ExitStatus) ) );
149 *meinproc << KStandardDirs::locate("exe", "meinproc4");
150 *meinproc << "--stylesheet" << KStandardDirs::locate( "data", "khelpcenter/table-of-contents.xslt" );
151 *meinproc << "--output" << m_cacheFile;
152 *meinproc << m_sourceFile;
154 meinproc->setOutputChannelMode(KProcess::OnlyStderrChannel);
155 meinproc->start();
156 if (!meinproc->waitForStarted()) {
157 kError() << "could not start process" << meinproc->program();
158 if (mainWindow && !m_alreadyWarned) {
159 ; // add warning message box with don't display again option
160 // http://api.kde.org/4.0-api/kdelibs-apidocs/kdeui/html/classKDialog.html
161 m_alreadyWarned = true;
163 delete meinproc;
167 void TOC::meinprocExited( int exitCode, QProcess::ExitStatus exitStatus)
169 KProcess *meinproc = static_cast<KProcess *>(sender());
170 KXmlGuiWindow *mainWindow = dynamic_cast<KXmlGuiWindow *>( kapp->activeWindow() );
172 if ( exitStatus == QProcess::CrashExit || exitCode != 0 ) {
173 kError() << "running" << meinproc->program() << "failed with exitCode" << exitCode;
174 kError() << "stderr output:" << meinproc->readAllStandardError();
175 if (mainWindow && !m_alreadyWarned) {
176 ; // add warning message box with don't display again option
177 // http://api.kde.org/4.0-api/kdelibs-apidocs/kdeui/html/classKDialog.html
178 m_alreadyWarned = true;
180 delete meinproc;
181 return;
184 delete meinproc;
186 QFile f( m_cacheFile );
187 if ( !f.open( QIODevice::ReadWrite ) )
188 return;
190 QDomDocument doc;
191 if ( !doc.setContent( &f ) )
192 return;
194 QDomComment timestamp = doc.createComment( QString::number( sourceFileCTime() ) );
195 doc.documentElement().appendChild( timestamp );
197 f.seek( 0 );
198 QTextStream stream( &f );
199 stream.setCodec( "UTF-8" );
200 stream << doc.toString();
202 f.close();
204 fillTree();
207 void TOC::fillTree()
209 QFile f( m_cacheFile );
210 if ( !f.open( QIODevice::ReadOnly ) )
211 return;
213 QDomDocument doc;
214 if ( !doc.setContent( &f ) )
215 return;
217 TOCChapterItem *chapItem = 0;
218 QDomNodeList chapters = doc.documentElement().elementsByTagName( "chapter" );
219 for ( int chapterCount = 0; chapterCount < chapters.count(); chapterCount++ ) {
220 QDomElement chapElem = chapters.item( chapterCount ).toElement();
221 QDomElement chapTitleElem = childElement( chapElem, QLatin1String( "title" ) );
222 QString chapTitle = chapTitleElem.text().simplified();
223 QDomElement chapRefElem = childElement( chapElem, QLatin1String( "anchor" ) );
224 QString chapRef = chapRefElem.text().trimmed();
226 chapItem = new TOCChapterItem( this, m_parentItem, chapItem, chapTitle, chapRef );
228 TOCSectionItem *sectItem = 0;
229 QDomNodeList sections = chapElem.elementsByTagName( "section" );
230 for ( int sectCount = 0; sectCount < sections.count(); sectCount++ ) {
231 QDomElement sectElem = sections.item( sectCount ).toElement();
232 QDomElement sectTitleElem = childElement( sectElem, QLatin1String( "title" ) );
233 QString sectTitle = sectTitleElem.text().simplified();
234 QDomElement sectRefElem = childElement( sectElem, QLatin1String( "anchor" ) );
235 QString sectRef = sectRefElem.text().trimmed();
237 sectItem = new TOCSectionItem( this, chapItem, sectItem, sectTitle, sectRef );
241 m_parentItem->setOpen( true );
244 QDomElement TOC::childElement( const QDomElement &element, const QString &name )
246 QDomElement e;
247 for ( e = element.firstChild().toElement(); !e.isNull(); e = e.nextSibling().toElement() )
248 if ( e.tagName() == name )
249 break;
250 return e;
253 void TOC::slotItemSelected( Q3ListViewItem *item )
255 TOCItem *tocItem;
256 if ( ( tocItem = dynamic_cast<TOCItem *>( item ) ) )
257 emit itemSelected( tocItem->entry()->url() );
259 item->setOpen( !item->isOpen() );
262 TOCItem::TOCItem( TOC *toc, Q3ListViewItem *parentItem, Q3ListViewItem *after, const QString &text )
263 : NavigatorItem( new DocEntry( text ), parentItem, after )
265 setAutoDeleteDocEntry( true );
266 m_toc = toc;
269 TOCChapterItem::TOCChapterItem( TOC *toc, NavigatorItem *parent, Q3ListViewItem *after,
270 const QString &title, const QString &name )
271 : TOCItem( toc, parent, after, title ),
272 m_name( name )
274 setOpen( false );
275 entry()->setUrl(url());
278 QString TOCChapterItem::url()
280 return QLatin1String("help:") + toc()->application() + QLatin1Char('/') + m_name
281 + QLatin1String(".html");
284 TOCSectionItem::TOCSectionItem( TOC *toc, TOCChapterItem *parent, Q3ListViewItem *after,
285 const QString &title, const QString &name )
286 : TOCItem( toc, parent, after, title ),
287 m_name( name )
289 setPixmap( 0, SmallIcon( "document" ) );
290 entry()->setUrl(url());
293 QString TOCSectionItem::url()
295 if ( static_cast<TOCSectionItem *>( parent()->firstChild() ) == this )
296 return static_cast<TOCChapterItem *>( parent() )->url() + '#' + m_name;
298 return "help:" + toc()->application() + '/' + m_name + ".html";
301 #include "toc.moc"
302 // vim:ts=2:sw=2:et