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.
25 #include <kiconloader.h>
27 #include <kstandarddirs.h>
29 #include <kxmlguiwindow.h>
30 #include <KApplication>
37 #include <QTextStream>
43 class TOCItem
: public NavigatorItem
46 TOCItem( TOC
*parent
, Q3ListViewItem
*parentItem
, Q3ListViewItem
*after
, const QString
&text
);
48 const TOC
*toc() const { return m_toc
; }
54 class TOCChapterItem
: public TOCItem
57 TOCChapterItem( TOC
*toc
, NavigatorItem
*parent
, Q3ListViewItem
*after
, const QString
&title
,
58 const QString
&name
);
60 virtual QString
url();
66 class TOCSectionItem
: public TOCItem
69 TOCSectionItem( TOC
*toc
, TOCChapterItem
*parent
, Q3ListViewItem
*after
, const QString
&title
,
70 const QString
&name
);
72 virtual QString
url();
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() );
99 QString cacheFile
= fileName
.replace( '/', "__" );
100 m_cacheFile
= KStandardDirs::locateLocal( "cache", "help/" + cacheFile
);
103 if ( cacheStatus() == NeedRebuild
)
109 TOC::CacheStatus
TOC::cacheStatus() const
111 if ( !QFile::exists( m_cacheFile
) ||
112 sourceFileCTime() != cachedCTime() )
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
) )
133 if ( !doc
.setContent( &f
) )
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
);
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;
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;
186 QFile
f( m_cacheFile
);
187 if ( !f
.open( QIODevice::ReadWrite
) )
191 if ( !doc
.setContent( &f
) )
194 QDomComment timestamp
= doc
.createComment( QString::number( sourceFileCTime() ) );
195 doc
.documentElement().appendChild( timestamp
);
198 QTextStream
stream( &f
);
199 stream
.setCodec( "UTF-8" );
200 stream
<< doc
.toString();
209 QFile
f( m_cacheFile
);
210 if ( !f
.open( QIODevice::ReadOnly
) )
214 if ( !doc
.setContent( &f
) )
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
)
247 for ( e
= element
.firstChild().toElement(); !e
.isNull(); e
= e
.nextSibling().toElement() )
248 if ( e
.tagName() == name
)
253 void TOC::slotItemSelected( Q3ListViewItem
*item
)
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 );
269 TOCChapterItem::TOCChapterItem( TOC
*toc
, NavigatorItem
*parent
, Q3ListViewItem
*after
,
270 const QString
&title
, const QString
&name
)
271 : TOCItem( toc
, parent
, after
, title
),
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
),
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";