|
|
|
/*
|
|
|
|
* This file is part of the KDE Help Center
|
|
|
|
*
|
|
|
|
* Copyright (C) 2002 Frerich Raabe (raabe@kde.org)
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program 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 General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
#include "glossary.h"
|
|
|
|
#include "view.h"
|
|
|
|
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <kconfig.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <kiconloader.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kmainwindow.h>
|
|
|
|
#include <kprocess.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <kstatusbar.h>
|
|
|
|
|
|
|
|
#include <tqheader.h>
|
|
|
|
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
using namespace KHC;
|
|
|
|
|
|
|
|
class SectionItem : public KListViewItem
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
SectionItem( TQListViewItem *parent, const TQString &text )
|
|
|
|
: KListViewItem( parent, text )
|
|
|
|
{
|
|
|
|
setOpen( false );
|
|
|
|
}
|
|
|
|
|
|
|
|
virtual void setOpen( bool open )
|
|
|
|
{
|
|
|
|
KListViewItem::setOpen(open);
|
|
|
|
|
|
|
|
setPixmap( 0, SmallIcon( TQString::tqfromLatin1( open ? "contents" : "contents2" ) ) );
|
|
|
|
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
class EntryItem : public KListViewItem
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
EntryItem( SectionItem *parent, const TQString &term, const TQString &id )
|
|
|
|
: KListViewItem( parent, term ),
|
|
|
|
m_id( id )
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString id() const { return m_id; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
TQString m_id;
|
|
|
|
};
|
|
|
|
|
|
|
|
Glossary::Glossary( TQWidget *parent ) : KListView( parent )
|
|
|
|
{
|
|
|
|
m_initialized = false;
|
|
|
|
|
|
|
|
connect( this, TQT_SIGNAL( clicked( TQListViewItem * ) ),
|
|
|
|
this, TQT_SLOT( treeItemSelected( TQListViewItem * ) ) );
|
|
|
|
connect( this, TQT_SIGNAL( returnPressed( TQListViewItem * ) ),
|
|
|
|
this, TQT_SLOT( treeItemSelected( TQListViewItem * ) ) );
|
|
|
|
|
|
|
|
setFrameStyle( TQFrame::Panel | TQFrame::Sunken );
|
|
|
|
addColumn( TQString::null );
|
|
|
|
header()->hide();
|
|
|
|
setAllColumnsShowFocus( true );
|
|
|
|
setRootIsDecorated( true );
|
|
|
|
|
|
|
|
m_byTopicItem = new KListViewItem( this, i18n( "By Topic" ) );
|
|
|
|
m_byTopicItem->setPixmap( 0, SmallIcon( "help" ) );
|
|
|
|
|
|
|
|
m_alphabItem = new KListViewItem( this, i18n( "Alphabetically" ) );
|
|
|
|
m_alphabItem->setPixmap( 0, SmallIcon( "charset" ) );
|
|
|
|
|
|
|
|
m_cacheFile = locateLocal( "cache", "help/glossary.xml" );
|
|
|
|
|
|
|
|
m_sourceFile = View::View::langLookup( TQString::tqfromLatin1( "khelpcenter/glossary/index.docbook" ) );
|
|
|
|
|
|
|
|
m_config = kapp->config();
|
|
|
|
m_config->setGroup( "Glossary" );
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void Glossary::show()
|
|
|
|
{
|
|
|
|
if ( !m_initialized ) {
|
|
|
|
if ( cacheStatus() == NeedRebuild )
|
|
|
|
rebuildGlossaryCache();
|
|
|
|
else
|
|
|
|
buildGlossaryTree();
|
|
|
|
m_initialized = true;
|
|
|
|
}
|
|
|
|
KListView::show();
|
|
|
|
}
|
|
|
|
|
|
|
|
Glossary::~Glossary()
|
|
|
|
{
|
|
|
|
m_glossEntries.setAutoDelete( true );
|
|
|
|
m_glossEntries.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
const GlossaryEntry &Glossary::entry( const TQString &id ) const
|
|
|
|
{
|
|
|
|
return *m_glossEntries[ id ];
|
|
|
|
}
|
|
|
|
|
|
|
|
Glossary::CacheStatus Glossary::cacheStatus() const
|
|
|
|
{
|
|
|
|
if ( !TQFile::exists( m_cacheFile ) ||
|
|
|
|
m_config->readPathEntry( "CachedGlossary" ) != m_sourceFile ||
|
|
|
|
m_config->readNumEntry( "CachedGlossaryTimestamp" ) != glossaryCTime() )
|
|
|
|
return NeedRebuild;
|
|
|
|
|
|
|
|
return CacheOk;
|
|
|
|
}
|
|
|
|
|
|
|
|
int Glossary::glossaryCTime() const
|
|
|
|
{
|
|
|
|
struct stat stat_buf;
|
|
|
|
stat( TQFile::encodeName( m_sourceFile ).data(), &stat_buf );
|
|
|
|
|
|
|
|
return stat_buf.st_ctime;
|
|
|
|
}
|
|
|
|
|
|
|
|
void Glossary::rebuildGlossaryCache()
|
|
|
|
{
|
|
|
|
KMainWindow *mainWindow = dynamic_cast<KMainWindow *>( kapp->mainWidget() );
|
|
|
|
Q_ASSERT( mainWindow );
|
|
|
|
mainWindow->statusBar()->message( i18n( "Rebuilding cache..." ) );
|
|
|
|
|
|
|
|
KProcess *meinproc = new KProcess;
|
|
|
|
connect( meinproc, TQT_SIGNAL( processExited( KProcess * ) ),
|
|
|
|
this, TQT_SLOT( meinprocExited( KProcess * ) ) );
|
|
|
|
|
|
|
|
*meinproc << locate( "exe", TQString::tqfromLatin1( "meinproc" ) );
|
|
|
|
*meinproc << TQString::tqfromLatin1( "--output" ) << m_cacheFile;
|
|
|
|
*meinproc << TQString::tqfromLatin1( "--stylesheet" )
|
|
|
|
<< locate( "data", TQString::tqfromLatin1( "khelpcenter/glossary.xslt" ) );
|
|
|
|
*meinproc << m_sourceFile;
|
|
|
|
|
|
|
|
meinproc->start( KProcess::NotifyOnExit );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Glossary::meinprocExited( KProcess *meinproc )
|
|
|
|
{
|
|
|
|
delete meinproc;
|
|
|
|
|
|
|
|
if ( !TQFile::exists( m_cacheFile ) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
m_config->writePathEntry( "CachedGlossary", m_sourceFile );
|
|
|
|
m_config->writeEntry( "CachedGlossaryTimestamp", glossaryCTime() );
|
|
|
|
m_config->sync();
|
|
|
|
|
|
|
|
m_status = CacheOk;
|
|
|
|
|
|
|
|
KMainWindow *mainWindow = dynamic_cast<KMainWindow *>( kapp->mainWidget() );
|
|
|
|
Q_ASSERT( mainWindow );
|
|
|
|
mainWindow->statusBar()->message( i18n( "Rebuilding cache... done." ), 2000 );
|
|
|
|
|
|
|
|
buildGlossaryTree();
|
|
|
|
}
|
|
|
|
|
|
|
|
void Glossary::buildGlossaryTree()
|
|
|
|
{
|
|
|
|
TQFile cacheFile(m_cacheFile);
|
|
|
|
if ( !cacheFile.open( IO_ReadOnly ) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
TQDomDocument doc;
|
|
|
|
if ( !doc.setContent( &cacheFile ) )
|
|
|
|
return;
|
|
|
|
|
|
|
|
TQDomNodeList sectionNodes = doc.documentElement().elementsByTagName( TQString::tqfromLatin1( "section" ) );
|
|
|
|
for ( unsigned int i = 0; i < sectionNodes.count(); i++ ) {
|
|
|
|
TQDomElement sectionElement = sectionNodes.item( i ).toElement();
|
|
|
|
TQString title = sectionElement.attribute( TQString::tqfromLatin1( "title" ) );
|
|
|
|
SectionItem *topicSection = new SectionItem( m_byTopicItem, title );
|
|
|
|
|
|
|
|
TQDomNodeList entryNodes = sectionElement.elementsByTagName( TQString::tqfromLatin1( "entry" ) );
|
|
|
|
for ( unsigned int j = 0; j < entryNodes.count(); j++ ) {
|
|
|
|
TQDomElement entryElement = entryNodes.item( j ).toElement();
|
|
|
|
|
|
|
|
TQString entryId = entryElement.attribute( TQString::tqfromLatin1( "id" ) );
|
|
|
|
if ( entryId.isNull() )
|
|
|
|
continue;
|
|
|
|
|
|
|
|
TQDomElement termElement = childElement( entryElement, TQString::tqfromLatin1( "term" ) );
|
|
|
|
TQString term = termElement.text().simplifyWhiteSpace();
|
|
|
|
|
|
|
|
EntryItem *entry = new EntryItem(topicSection, term, entryId );
|
|
|
|
m_idDict.insert( entryId, entry );
|
|
|
|
|
|
|
|
SectionItem *alphabSection = 0L;
|
|
|
|
for ( TQListViewItemIterator it( m_alphabItem ); it.current(); it++ )
|
|
|
|
if ( it.current()->text( 0 ) == term[ 0 ].upper() ) {
|
|
|
|
alphabSection = static_cast<SectionItem *>( it.current() );
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( !alphabSection )
|
|
|
|
alphabSection = new SectionItem( m_alphabItem, term[ 0 ].upper() );
|
|
|
|
|
|
|
|
new EntryItem( alphabSection, term, entryId );
|
|
|
|
|
|
|
|
TQDomElement definitionElement = childElement( entryElement, TQString::tqfromLatin1( "definition" ) );
|
|
|
|
TQString definition = definitionElement.text().simplifyWhiteSpace();
|
|
|
|
|
|
|
|
GlossaryEntryXRef::List seeAlso;
|
|
|
|
|
|
|
|
TQDomElement referencesElement = childElement( entryElement, TQString::tqfromLatin1( "references" ) );
|
|
|
|
TQDomNodeList referenceNodes = referencesElement.elementsByTagName( TQString::tqfromLatin1( "reference" ) );
|
|
|
|
if ( referenceNodes.count() > 0 )
|
|
|
|
for ( unsigned int k = 0; k < referenceNodes.count(); k++ ) {
|
|
|
|
TQDomElement referenceElement = referenceNodes.item( k ).toElement();
|
|
|
|
|
|
|
|
TQString term = referenceElement.attribute( TQString::tqfromLatin1( "term" ) );
|
|
|
|
TQString id = referenceElement.attribute( TQString::tqfromLatin1( "id" ) );
|
|
|
|
|
|
|
|
seeAlso += GlossaryEntryXRef( term, id );
|
|
|
|
}
|
|
|
|
|
|
|
|
m_glossEntries.insert( entryId, new GlossaryEntry( term, definition, seeAlso ) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void Glossary::treeItemSelected( TQListViewItem *item )
|
|
|
|
{
|
|
|
|
if ( !item )
|
|
|
|
return;
|
|
|
|
|
|
|
|
if ( EntryItem *i = dynamic_cast<EntryItem *>( item ) )
|
|
|
|
emit entrySelected( entry( i->id() ) );
|
|
|
|
|
|
|
|
item->setOpen( !item->isOpen() );
|
|
|
|
}
|
|
|
|
|
|
|
|
TQDomElement Glossary::childElement( const TQDomElement &element, const TQString &name )
|
|
|
|
{
|
|
|
|
TQDomElement e;
|
|
|
|
for ( e = element.firstChild().toElement(); !e.isNull(); e = e.nextSibling().toElement() )
|
|
|
|
if ( e.tagName() == name )
|
|
|
|
break;
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
|
|
|
|
TQString Glossary::entryToHtml( const GlossaryEntry &entry )
|
|
|
|
{
|
|
|
|
TQFile htmlFile( locate("data", "khelpcenter/glossary.html.in" ) );
|
|
|
|
if (!htmlFile.open(IO_ReadOnly))
|
|
|
|
return TQString( "<html><head></head><body><h3>%1</h3>%2</body></html>" )
|
|
|
|
.arg( i18n( "Error" ) )
|
|
|
|
.arg( i18n( "Unable to show selected glossary entry: unable to open "
|
|
|
|
"file 'glossary.html.in'!" ) );
|
|
|
|
|
|
|
|
TQString seeAlso;
|
|
|
|
if (!entry.seeAlso().isEmpty()) {
|
|
|
|
seeAlso = i18n("See also: ");
|
|
|
|
GlossaryEntryXRef::List seeAlsos = entry.seeAlso();
|
|
|
|
GlossaryEntryXRef::List::ConstIterator it = seeAlsos.begin();
|
|
|
|
GlossaryEntryXRef::List::ConstIterator end = seeAlsos.end();
|
|
|
|
for (; it != end; ++it) {
|
|
|
|
seeAlso += TQString::tqfromLatin1("<a href=\"glossentry:");
|
|
|
|
seeAlso += (*it).id();
|
|
|
|
seeAlso += TQString::tqfromLatin1("\">") + (*it).term();
|
|
|
|
seeAlso += TQString::tqfromLatin1("</a>, ");
|
|
|
|
}
|
|
|
|
seeAlso = seeAlso.left(seeAlso.length() - 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
TQTextStream htmlStream(&htmlFile);
|
|
|
|
return htmlStream.read()
|
|
|
|
.arg( i18n( "KDE Glossary" ) )
|
|
|
|
.arg( entry.term() )
|
|
|
|
.arg( View::langLookup( "khelpcenter/konq.css" ) )
|
|
|
|
.arg( View::langLookup( "khelpcenter/pointers.png" ) )
|
|
|
|
.arg( View::langLookup( "khelpcenter/khelpcenter.png" ) )
|
|
|
|
.arg( View::langLookup( "khelpcenter/lines.png" ) )
|
|
|
|
.arg( entry.term() )
|
|
|
|
.arg( entry.definition() )
|
|
|
|
.arg( seeAlso)
|
|
|
|
.arg( View::langLookup( "khelpcenter/kdelogo2.png" ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
void Glossary::slotSelectGlossEntry( const TQString &id )
|
|
|
|
{
|
|
|
|
EntryItem *newItem = m_idDict.find( id );
|
|
|
|
if ( newItem == 0 )
|
|
|
|
return;
|
|
|
|
|
|
|
|
EntryItem *curItem = dynamic_cast<EntryItem *>( currentItem() );
|
|
|
|
if ( curItem != 0 ) {
|
|
|
|
if ( curItem->id() == id )
|
|
|
|
return;
|
|
|
|
curItem->parent()->setOpen( false );
|
|
|
|
}
|
|
|
|
|
|
|
|
setCurrentItem( newItem );
|
|
|
|
ensureItemVisible( newItem );
|
|
|
|
}
|
|
|
|
|
|
|
|
#include "glossary.moc"
|
|
|
|
// vim:ts=4:sw=4:et
|