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( '/', "__" );
101 cacheFile
= cacheFile
.replace( ':', "_" );
103 m_cacheFile
= KStandardDirs::locateLocal( "cache", "help/" + cacheFile
);
106 if ( cacheStatus() == NeedRebuild
)
112 TOC::CacheStatus
TOC::cacheStatus() const
114 if ( !QFile::exists( m_cacheFile
) ||
115 sourceFileCTime() != cachedCTime() )
121 int TOC::sourceFileCTime() const
123 struct stat stat_buf
;
124 stat( QFile::encodeName( m_sourceFile
).data(), &stat_buf
);
126 return stat_buf
.st_ctime
;
129 int TOC::cachedCTime() const
131 QFile
f( m_cacheFile
);
132 if ( !f
.open( QIODevice::ReadOnly
) )
136 if ( !doc
.setContent( &f
) )
139 QDomComment timestamp
= doc
.documentElement().lastChild().toComment();
141 return timestamp
.data().trimmed().toInt();
144 void TOC::buildCache()
146 KXmlGuiWindow
*mainWindow
= dynamic_cast<KXmlGuiWindow
*>( kapp
->activeWindow() );
148 KProcess
*meinproc
= new KProcess
;
149 connect( meinproc
, SIGNAL( finished( int, QProcess::ExitStatus
) ),
150 this, SLOT( meinprocExited( int, QProcess::ExitStatus
) ) );
152 *meinproc
<< KStandardDirs::locate("exe", "meinproc4");
153 *meinproc
<< "--stylesheet" << KStandardDirs::locate( "data", "khelpcenter/table-of-contents.xslt" );
154 *meinproc
<< "--output" << m_cacheFile
;
155 *meinproc
<< m_sourceFile
;
157 meinproc
->setOutputChannelMode(KProcess::OnlyStderrChannel
);
159 if (!meinproc
->waitForStarted()) {
160 kError() << "could not start process" << meinproc
->program();
161 if (mainWindow
&& !m_alreadyWarned
) {
162 ; // add warning message box with don't display again option
163 // http://api.kde.org/4.0-api/kdelibs-apidocs/kdeui/html/classKDialog.html
164 m_alreadyWarned
= true;
170 void TOC::meinprocExited( int exitCode
, QProcess::ExitStatus exitStatus
)
172 KProcess
*meinproc
= static_cast<KProcess
*>(sender());
173 KXmlGuiWindow
*mainWindow
= dynamic_cast<KXmlGuiWindow
*>( kapp
->activeWindow() );
175 if ( exitStatus
== QProcess::CrashExit
|| exitCode
!= 0 ) {
176 kError() << "running" << meinproc
->program() << "failed with exitCode" << exitCode
;
177 kError() << "stderr output:" << meinproc
->readAllStandardError();
178 if (mainWindow
&& !m_alreadyWarned
) {
179 ; // add warning message box with don't display again option
180 // http://api.kde.org/4.0-api/kdelibs-apidocs/kdeui/html/classKDialog.html
181 m_alreadyWarned
= true;
189 QFile
f( m_cacheFile
);
190 if ( !f
.open( QIODevice::ReadWrite
) )
194 if ( !doc
.setContent( &f
) )
197 QDomComment timestamp
= doc
.createComment( QString::number( sourceFileCTime() ) );
198 doc
.documentElement().appendChild( timestamp
);
201 QTextStream
stream( &f
);
202 stream
.setCodec( "UTF-8" );
203 stream
<< doc
.toString();
207 kDebug() << "on german systems umlauts are displayed as '?' for unknown (Qt'r related ?) reasons. Please fix.";
215 QFile
f( m_cacheFile
);
216 if ( !f
.open( QIODevice::ReadOnly
) )
220 if ( !doc
.setContent( &f
) )
223 TOCChapterItem
*chapItem
= 0;
224 QDomNodeList chapters
= doc
.documentElement().elementsByTagName( "chapter" );
225 for ( int chapterCount
= 0; chapterCount
< chapters
.count(); chapterCount
++ ) {
226 QDomElement chapElem
= chapters
.item( chapterCount
).toElement();
227 QDomElement chapTitleElem
= childElement( chapElem
, QLatin1String( "title" ) );
228 QString chapTitle
= chapTitleElem
.text().simplified();
229 QDomElement chapRefElem
= childElement( chapElem
, QLatin1String( "anchor" ) );
230 QString chapRef
= chapRefElem
.text().trimmed();
232 chapItem
= new TOCChapterItem( this, m_parentItem
, chapItem
, chapTitle
, chapRef
);
234 TOCSectionItem
*sectItem
= 0;
235 QDomNodeList sections
= chapElem
.elementsByTagName( "section" );
236 for ( int sectCount
= 0; sectCount
< sections
.count(); sectCount
++ ) {
237 QDomElement sectElem
= sections
.item( sectCount
).toElement();
238 QDomElement sectTitleElem
= childElement( sectElem
, QLatin1String( "title" ) );
239 QString sectTitle
= sectTitleElem
.text().simplified();
240 QDomElement sectRefElem
= childElement( sectElem
, QLatin1String( "anchor" ) );
241 QString sectRef
= sectRefElem
.text().trimmed();
243 sectItem
= new TOCSectionItem( this, chapItem
, sectItem
, sectTitle
, sectRef
);
247 m_parentItem
->setOpen( true );
250 QDomElement
TOC::childElement( const QDomElement
&element
, const QString
&name
)
253 for ( e
= element
.firstChild().toElement(); !e
.isNull(); e
= e
.nextSibling().toElement() )
254 if ( e
.tagName() == name
)
259 void TOC::slotItemSelected( Q3ListViewItem
*item
)
262 if ( ( tocItem
= dynamic_cast<TOCItem
*>( item
) ) )
263 emit
itemSelected( tocItem
->entry()->url() );
265 item
->setOpen( !item
->isOpen() );
268 TOCItem::TOCItem( TOC
*toc
, Q3ListViewItem
*parentItem
, Q3ListViewItem
*after
, const QString
&text
)
269 : NavigatorItem( new DocEntry( text
), parentItem
, after
)
271 setAutoDeleteDocEntry( true );
275 TOCChapterItem::TOCChapterItem( TOC
*toc
, NavigatorItem
*parent
, Q3ListViewItem
*after
,
276 const QString
&title
, const QString
&name
)
277 : TOCItem( toc
, parent
, after
, title
),
281 entry()->setUrl(url());
284 QString
TOCChapterItem::url()
286 return QLatin1String("help:") + toc()->application() + QLatin1Char('/') + m_name
287 + QLatin1String(".html");
290 TOCSectionItem::TOCSectionItem( TOC
*toc
, TOCChapterItem
*parent
, Q3ListViewItem
*after
,
291 const QString
&title
, const QString
&name
)
292 : TOCItem( toc
, parent
, after
, title
),
295 setPixmap( 0, SmallIcon( "text-plain" ) );
296 entry()->setUrl(url());
299 QString
TOCSectionItem::url()
301 if ( static_cast<TOCSectionItem
*>( parent()->firstChild() ) == this )
302 return static_cast<TOCChapterItem
*>( parent() )->url() + '#' + m_name
;
304 return "help:" + toc()->application() + '/' + m_name
+ ".html";