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.
23 #include <kapplication.h>
26 #include <kiconloader.h>
28 #include <kxmlguiwindow.h>
30 #include <kstandarddirs.h>
31 #include <kstatusbar.h>
33 #include <Qt3Support/Q3Header>
36 #include <QTextStream>
43 class SectionItem
: public K3ListViewItem
46 SectionItem( Q3ListViewItem
*parent
, const QString
&text
)
47 : K3ListViewItem( parent
, text
)
52 virtual void setOpen( bool open
)
54 K3ListViewItem::setOpen(open
);
56 setPixmap( 0, SmallIcon( QLatin1String( open
? "help-contents" : "contents2" ) ) );
61 class EntryItem
: public K3ListViewItem
64 EntryItem( SectionItem
*parent
, const QString
&term
, const QString
&id
)
65 : K3ListViewItem( parent
, term
),
70 QString
id() const { return m_id
; }
76 bool Glossary::m_alreadyWarned
= false;
78 Glossary::Glossary( QWidget
*parent
) : K3ListView( parent
)
80 m_initialized
= false;
82 setFrameStyle( QFrame::NoFrame
);
84 connect( this, SIGNAL( clicked( Q3ListViewItem
* ) ),
85 this, SLOT( treeItemSelected( Q3ListViewItem
* ) ) );
86 connect( this, SIGNAL( returnPressed( Q3ListViewItem
* ) ),
87 this, SLOT( treeItemSelected( Q3ListViewItem
* ) ) );
89 addColumn( QString() );
91 setAllColumnsShowFocus( true );
92 setRootIsDecorated( true );
94 m_byTopicItem
= new K3ListViewItem( this, i18n( "By Topic" ) );
95 m_byTopicItem
->setPixmap( 0, SmallIcon( "help-contents" ) );
97 m_alphabItem
= new K3ListViewItem( this, i18n( "Alphabetically" ) );
98 m_alphabItem
->setPixmap( 0, SmallIcon( "character-set" ) );
100 m_cacheFile
= KStandardDirs::locateLocal( "cache", "help/glossary.xml" );
102 m_sourceFile
= View::langLookup( QLatin1String( "khelpcenter/glossary/index.docbook" ) );
104 m_config
= KGlobal::config();
105 //m_config->setGroup( "Glossary" );
109 void Glossary::showEvent(QShowEvent
*event
)
111 if ( !m_initialized
) {
112 if ( cacheStatus() == NeedRebuild
)
113 rebuildGlossaryCache();
116 m_initialized
= true;
118 K3ListView::showEvent(event
);
121 Glossary::~Glossary()
123 qDeleteAll( m_glossEntries
);
126 const GlossaryEntry
&Glossary::entry( const QString
&id
) const
128 return *m_glossEntries
[ id
];
131 Glossary::CacheStatus
Glossary::cacheStatus() const
133 if ( !QFile::exists( m_cacheFile
) ||
134 m_config
->group("Glossary").readPathEntry( "CachedGlossary", QString() ) != m_sourceFile
||
135 m_config
->group("Glossary").readEntry( "CachedGlossaryTimestamp" ).toInt() != glossaryCTime() )
141 int Glossary::glossaryCTime() const
143 struct stat stat_buf
;
144 stat( QFile::encodeName( m_sourceFile
).data(), &stat_buf
);
146 return stat_buf
.st_ctime
;
149 void Glossary::rebuildGlossaryCache()
151 KXmlGuiWindow
*mainWindow
= dynamic_cast<KXmlGuiWindow
*>( kapp
->activeWindow() );
153 mainWindow
->statusBar()->showMessage( i18n( "Rebuilding glossary cache..." ) );
155 KProcess
*meinproc
= new KProcess
;
156 connect( meinproc
, SIGNAL( finished(int,QProcess::ExitStatus
) ),
157 this, SLOT( meinprocFinished(int,QProcess::ExitStatus
) ) );
159 *meinproc
<< KStandardDirs::locate( "exe", QLatin1String( "meinproc4" ) );
160 *meinproc
<< QLatin1String( "--output" ) << m_cacheFile
;
161 *meinproc
<< QLatin1String( "--stylesheet" )
162 << KStandardDirs::locate( "data", QLatin1String( "khelpcenter/glossary.xslt" ) );
163 *meinproc
<< m_sourceFile
;
165 meinproc
->setOutputChannelMode(KProcess::OnlyStderrChannel
);
167 if (!meinproc
->waitForStarted()) {
168 kError() << "could not start process" << meinproc
->program();
169 if (mainWindow
&& !m_alreadyWarned
) {
170 ; // add warning message box with don't display again option
171 // http://api.kde.org/4.0-api/kdelibs-apidocs/kdeui/html/classKDialog.html
172 m_alreadyWarned
= true;
178 void Glossary::meinprocFinished( int exitCode
, QProcess::ExitStatus exitStatus
)
180 KProcess
*meinproc
= static_cast<KProcess
*>(sender());
181 KXmlGuiWindow
*mainWindow
= dynamic_cast<KXmlGuiWindow
*>( kapp
->activeWindow() );
183 if (exitStatus
!= QProcess::NormalExit
|| exitCode
!= 0) {
184 kError() << "running" << meinproc
->program() << "failed with exitCode" << exitCode
;
185 kError() << "stderr output:" << meinproc
->readAllStandardError();
186 if (mainWindow
&& !m_alreadyWarned
) {
187 ; // add warning message box with don't display again option
188 // http://api.kde.org/4.0-api/kdelibs-apidocs/kdeui/html/classKDialog.html
189 m_alreadyWarned
= true;
196 if ( !QFile::exists( m_cacheFile
) )
199 m_config
->group("Glossary").writePathEntry( "CachedGlossary", m_sourceFile
);
200 m_config
->group("Glossary").writeEntry( "CachedGlossaryTimestamp", glossaryCTime() );
206 mainWindow
->statusBar()->showMessage( i18n( "Rebuilding cache... done." ), 2000 );
211 void Glossary::buildGlossaryTree()
213 QFile
cacheFile(m_cacheFile
);
214 if ( !cacheFile
.open( QIODevice::ReadOnly
) )
218 if ( !doc
.setContent( &cacheFile
) )
221 QDomNodeList sectionNodes
= doc
.documentElement().elementsByTagName( QLatin1String( "section" ) );
222 for ( int i
= 0; i
< sectionNodes
.count(); i
++ ) {
223 QDomElement sectionElement
= sectionNodes
.item( i
).toElement();
224 QString title
= sectionElement
.attribute( QLatin1String( "title" ) );
225 SectionItem
*topicSection
= new SectionItem( m_byTopicItem
, title
);
227 QDomNodeList entryNodes
= sectionElement
.elementsByTagName( QLatin1String( "entry" ) );
228 for ( int j
= 0; j
< entryNodes
.count(); j
++ ) {
229 QDomElement entryElement
= entryNodes
.item( j
).toElement();
231 QString entryId
= entryElement
.attribute( QLatin1String( "id" ) );
232 if ( entryId
.isNull() )
235 QDomElement termElement
= childElement( entryElement
, QLatin1String( "term" ) );
236 QString term
= termElement
.text().simplified();
238 EntryItem
*entry
= new EntryItem(topicSection
, term
, entryId
);
239 m_idDict
.insert( entryId
, entry
);
241 SectionItem
*alphabSection
= 0L;
242 for ( Q3ListViewItemIterator
it( m_alphabItem
); it
.current(); it
++ )
243 if ( it
.current()->text( 0 ) == QString( term
[ 0 ].toUpper() ) ) {
244 alphabSection
= static_cast<SectionItem
*>( it
.current() );
248 if ( !alphabSection
)
249 alphabSection
= new SectionItem( m_alphabItem
, QString( term
[ 0 ].toUpper() ) );
251 new EntryItem( alphabSection
, term
, entryId
);
253 QDomElement definitionElement
= childElement( entryElement
, QLatin1String( "definition" ) );
254 QString definition
= definitionElement
.text().simplified();
256 GlossaryEntryXRef::List seeAlso
;
258 QDomElement referencesElement
= childElement( entryElement
, QLatin1String( "references" ) );
259 QDomNodeList referenceNodes
= referencesElement
.elementsByTagName( QLatin1String( "reference" ) );
260 if ( referenceNodes
.count() > 0 )
261 for ( int k
= 0; k
< referenceNodes
.count(); k
++ ) {
262 QDomElement referenceElement
= referenceNodes
.item( k
).toElement();
264 QString term
= referenceElement
.attribute( QLatin1String( "term" ) );
265 QString id
= referenceElement
.attribute( QLatin1String( "id" ) );
267 seeAlso
+= GlossaryEntryXRef( term
, id
);
270 m_glossEntries
.insert( entryId
, new GlossaryEntry( term
, definition
, seeAlso
) );
275 void Glossary::treeItemSelected( Q3ListViewItem
*item
)
280 if ( EntryItem
*i
= dynamic_cast<EntryItem
*>( item
) )
281 emit
entrySelected( entry( i
->id() ) );
283 item
->setOpen( !item
->isOpen() );
286 QDomElement
Glossary::childElement( const QDomElement
&element
, const QString
&name
)
289 for ( e
= element
.firstChild().toElement(); !e
.isNull(); e
= e
.nextSibling().toElement() )
290 if ( e
.tagName() == name
)
295 QString
Glossary::entryToHtml( const GlossaryEntry
&entry
)
297 QFile
htmlFile( KStandardDirs::locate("data", "khelpcenter/glossary.html.in" ) );
298 if (!htmlFile
.open(QIODevice::ReadOnly
))
299 return QString( "<html><head></head><body><h3>%1</h3>%2</body></html>" )
300 .arg( i18n( "Error" ) )
301 .arg( i18n( "Unable to show selected glossary entry: unable to open "
302 "file 'glossary.html.in'!" ) );
305 if (!entry
.seeAlso().isEmpty()) {
306 seeAlso
= i18n("See also: ");
307 GlossaryEntryXRef::List seeAlsos
= entry
.seeAlso();
308 GlossaryEntryXRef::List::ConstIterator it
= seeAlsos
.begin();
309 GlossaryEntryXRef::List::ConstIterator end
= seeAlsos
.end();
310 for (; it
!= end
; ++it
) {
311 seeAlso
+= QLatin1String("<a href=\"glossentry:");
312 seeAlso
+= (*it
).id();
313 seeAlso
+= QLatin1String("\">") + (*it
).term();
314 seeAlso
+= QLatin1String("</a>, ");
316 seeAlso
= seeAlso
.left(seeAlso
.length() - 2);
319 QTextStream
htmlStream(&htmlFile
);
320 return htmlStream
.readAll()
321 .arg( i18n( "KDE Glossary" ) )
323 .arg( View::langLookup( QLatin1String("khelpcenter/konq.css") ) )
324 .arg( View::langLookup( QLatin1String("khelpcenter/pointers.png") ) )
325 .arg( View::langLookup( QLatin1String("khelpcenter/khelpcenter.png") ) )
326 .arg( View::langLookup( QLatin1String("khelpcenter/lines.png") ) )
328 .arg( entry
.definition() )
330 .arg( View::langLookup( QLatin1String("khelpcenter/kdelogo2.png") ) );
333 void Glossary::slotSelectGlossEntry( const QString
&id
)
335 if ( !m_idDict
.contains( id
) )
338 EntryItem
*newItem
= m_idDict
.value( id
);
339 EntryItem
*curItem
= dynamic_cast<EntryItem
*>( currentItem() );
340 if ( curItem
!= 0 ) {
341 if ( curItem
->id() == id
)
343 curItem
->parent()->setOpen( false );
346 setCurrentItem( newItem
);
347 ensureItemVisible( newItem
);
350 #include "glossary.moc"