diff options
Diffstat (limited to 'khelpcenter/kcmhelpcenter.cpp')
-rw-r--r-- | khelpcenter/kcmhelpcenter.cpp | 687 |
1 files changed, 687 insertions, 0 deletions
diff --git a/khelpcenter/kcmhelpcenter.cpp b/khelpcenter/kcmhelpcenter.cpp new file mode 100644 index 000000000..df8f1b36e --- /dev/null +++ b/khelpcenter/kcmhelpcenter.cpp @@ -0,0 +1,687 @@ +/* + This file is part of KHelpcenter. + + Copyright (C) 2002 Cornelius Schumacher <[email protected]> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public + License version 2 as published by the Free Software Foundation. + + 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; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. +*/ + +#include "kcmhelpcenter.h" + +#include "htmlsearchconfig.h" +#include "docmetainfo.h" +#include "prefs.h" +#include "searchhandler.h" +#include "searchengine.h" + +#include <tdeconfig.h> +#include <kdebug.h> +#include <tdelocale.h> +#include <tdeglobal.h> +#include <tdeaboutdata.h> +#include <kdialog.h> +#include <kstandarddirs.h> +#include <kprocess.h> +#include <tdeapplication.h> +#include <dcopclient.h> +#include <tdetempfile.h> +#include <kurlrequester.h> +#include <tdemessagebox.h> +#include <tdelistview.h> +#include <klineedit.h> +#include <tqlayout.h> +#include <tqpushbutton.h> +#include <tqdir.h> +#include <tqtabwidget.h> +#include <tqprogressbar.h> +#include <tqfile.h> +#include <tqlabel.h> +#include <tqvbox.h> +#include <tqtextedit.h> +#include <tqregexp.h> + +#include <unistd.h> +#include <sys/types.h> + +using namespace KHC; + +IndexDirDialog::IndexDirDialog( TQWidget *parent ) + : KDialogBase( parent, 0, true, i18n("Change Index Folder"), Ok | Cancel ) +{ + TQFrame *topFrame = makeMainWidget(); + + TQBoxLayout *urlLayout = new TQHBoxLayout( topFrame ); + + TQLabel *label = new TQLabel( i18n("Index folder:"), topFrame ); + urlLayout->addWidget( label ); + + mIndexUrlRequester = new KURLRequester( topFrame ); + mIndexUrlRequester->setMode( KFile::Directory | KFile::ExistingOnly | + KFile::LocalOnly ); + urlLayout->addWidget( mIndexUrlRequester ); + + mIndexUrlRequester->setURL( Prefs::indexDirectory() ); + connect(mIndexUrlRequester->lineEdit(),TQT_SIGNAL(textChanged ( const TQString & )), this, TQT_SLOT(slotUrlChanged( const TQString &))); + slotUrlChanged( mIndexUrlRequester->lineEdit()->text() ); +} + +void IndexDirDialog::slotUrlChanged( const TQString &_url ) +{ + enableButtonOK( !_url.isEmpty() ); +} + + +void IndexDirDialog::slotOk() +{ + Prefs::setIndexDirectory( mIndexUrlRequester->url() ); + accept(); +} + + +IndexProgressDialog::IndexProgressDialog( TQWidget *parent ) + : KDialog( parent, "IndexProgressDialog", true ), + mFinished( true ) +{ + setCaption( i18n("Build Search Indices") ); + + TQBoxLayout *topLayout = new TQVBoxLayout( this ); + topLayout->setMargin( marginHint() ); + topLayout->setSpacing( spacingHint() ); + + mLabel = new TQLabel( this ); + mLabel->setAlignment( AlignHCenter ); + topLayout->addWidget( mLabel ); + + mProgressBar = new TQProgressBar( this ); + topLayout->addWidget( mProgressBar ); + + mLogLabel = new TQLabel( i18n("Index creation log:"), this ); + topLayout->addWidget( mLogLabel ); + + mLogView = new TQTextEdit( this ); + mLogView->setTextFormat( LogText ); + mLogView->setMinimumHeight( 200 ); + topLayout->addWidget( mLogView, 1 ); + + TQBoxLayout *buttonLayout = new TQHBoxLayout( topLayout ); + + buttonLayout->addStretch( 1 ); + + mDetailsButton = new TQPushButton( this ); + connect( mDetailsButton, TQT_SIGNAL( clicked() ), TQT_SLOT( toggleDetails() ) ); + buttonLayout->addWidget( mDetailsButton ); + + hideDetails(); + + mEndButton = new TQPushButton( this ); + connect( mEndButton, TQT_SIGNAL( clicked() ), TQT_SLOT( slotEnd() ) ); + buttonLayout->addWidget( mEndButton ); + + setFinished( false ); +} + +IndexProgressDialog::~IndexProgressDialog() +{ + if ( !mLogView->isHidden() ) { + TDEConfig *cfg = TDEGlobal::config(); + cfg->setGroup( "indexprogressdialog" ); + cfg->writeEntry( "size", size() ); + } +} + +void IndexProgressDialog::setTotalSteps( int steps ) +{ + mProgressBar->setTotalSteps( steps ); + mProgressBar->setProgress( 0 ); + setFinished( false ); + mLogView->clear(); +} + +void IndexProgressDialog::advanceProgress() +{ + mProgressBar->setProgress( mProgressBar->progress() + 1 ); +} + +void IndexProgressDialog::setLabelText( const TQString &text ) +{ + mLabel->setText( text ); +} + +void IndexProgressDialog::setMinimumLabelWidth( int width ) +{ + mLabel->setMinimumWidth( width ); +} + +void IndexProgressDialog::setFinished( bool finished ) +{ + if ( finished == mFinished ) return; + + mFinished = finished; + + if ( mFinished ) { + mEndButton->setText( i18n("Close") ); + mLabel->setText( i18n("Index creation finished.") ); + } else { + mEndButton->setText( i18n("Stop") ); + } +} + +void IndexProgressDialog::appendLog( const TQString &text ) +{ + mLogView->append( text ); +} + +void IndexProgressDialog::slotEnd() +{ + if ( mFinished ) { + emit closed(); + accept(); + } else { + emit cancelled(); + reject(); + } +} + +void IndexProgressDialog::toggleDetails() +{ + TDEConfig *cfg = TDEGlobal::config(); + cfg->setGroup( "indexprogressdialog" ); + if ( mLogView->isHidden() ) { + mLogLabel->show(); + mLogView->show(); + mDetailsButton->setText( i18n("Details <<") ); + TQSize size = cfg->readSizeEntry( "size" ); + if ( !size.isEmpty() ) resize( size ); + } else { + cfg->writeEntry( "size", size() ); + hideDetails(); + } +} + +void IndexProgressDialog::hideDetails() +{ + mLogLabel->hide(); + mLogView->hide(); + mDetailsButton->setText( i18n("Details >>") ); + layout()->activate(); + adjustSize(); +} + + +KCMHelpCenter::KCMHelpCenter( KHC::SearchEngine *engine, TQWidget *parent, + const char *name) + : DCOPObject( "kcmhelpcenter" ), + KDialogBase( parent, name, false, i18n("Build Search Index"), + Ok | Cancel, Ok, true ), + mEngine( engine ), mProgressDialog( 0 ), mCurrentEntry( 0 ), mCmdFile( 0 ), + mProcess( 0 ), mIsClosing( false ), mRunAsRoot( false ) +{ + TQWidget *widget = makeMainWidget(); + + setupMainWidget( widget ); + + setButtonOK( i18n("Build Index") ); + + mConfig = TDEGlobal::config(); + + DocMetaInfo::self()->scanMetaInfo(); + + load(); + + bool success = kapp->dcopClient()->connectDCOPSignal( "khc_indexbuilder", + 0, "buildIndexProgress()", "kcmhelpcenter", + "slotIndexProgress()", false ); + if ( !success ) kdError() << "connect DCOP signal failed" << endl; + + success = kapp->dcopClient()->connectDCOPSignal( "khc_indexbuilder", + 0, "buildIndexError(TQString)", "kcmhelpcenter", + "slotIndexError(TQString)", false ); + if ( !success ) kdError() << "connect DCOP signal failed" << endl; + + resize( configDialogSize( "IndexDialog" ) ); +} + +KCMHelpCenter::~KCMHelpCenter() +{ + saveDialogSize( "IndexDialog" ); +} + +void KCMHelpCenter::setupMainWidget( TQWidget *parent ) +{ + TQVBoxLayout *topLayout = new TQVBoxLayout( parent ); + topLayout->setSpacing( KDialog::spacingHint() ); + + TQString helpText = + i18n("To be able to search a document, there needs to exist a search\n" + "index. The status column of the list below shows, if an index\n" + "for a document exists.\n") + + i18n("To create an index check the box in the list and press the\n" + "\"Build Index\" button.\n"); + + TQLabel *label = new TQLabel( helpText, parent ); + topLayout->addWidget( label ); + + mListView = new TDEListView( parent ); + mListView->setFullWidth( true ); + mListView->addColumn( i18n("Search Scope") ); + mListView->addColumn( i18n("Status") ); + mListView->setColumnAlignment( 1, AlignCenter ); + topLayout->addWidget( mListView ); + connect( mListView, TQT_SIGNAL( clicked( TQListViewItem * ) ), + TQT_SLOT( checkSelection() ) ); + + TQBoxLayout *urlLayout = new TQHBoxLayout( topLayout ); + + TQLabel *urlLabel = new TQLabel( i18n("Index folder:"), parent ); + urlLayout->addWidget( urlLabel ); + + mIndexDirLabel = new TQLabel( parent ); + urlLayout->addWidget( mIndexDirLabel, 1 ); + + TQPushButton *button = new TQPushButton( i18n("Change..."), parent ); + connect( button, TQT_SIGNAL( clicked() ), TQT_SLOT( showIndexDirDialog() ) ); + urlLayout->addWidget( button ); + + TQBoxLayout *buttonLayout = new TQHBoxLayout( topLayout ); + + buttonLayout->addStretch( 1 ); +} + +void KCMHelpCenter::defaults() +{ +} + +bool KCMHelpCenter::save() +{ + kdDebug(1401) << "KCMHelpCenter::save()" << endl; + + if ( !TQFile::exists( Prefs::indexDirectory() ) ) { + KMessageBox::sorry( this, + i18n("<qt>The folder <b>%1</b> does not exist; unable to create index.</qt>") + .arg( Prefs::indexDirectory() ) ); + return false; + } else { + return buildIndex(); + } + + return true; +} + +void KCMHelpCenter::load() +{ + findWriteableIndexDir(); + mIndexDirLabel->setText( Prefs::indexDirectory() ); + + mListView->clear(); + + DocEntry::List entries = DocMetaInfo::self()->docEntries(); + DocEntry::List::ConstIterator it; + for( it = entries.begin(); it != entries.end(); ++it ) { +// kdDebug(1401) << "Entry: " << (*it)->name() << " Indexer: '" +// << (*it)->indexer() << "'" << endl; + if ( mEngine->canSearch( *it ) && mEngine->needsIndex( *it ) ) { + ScopeItem *item = new ScopeItem( mListView, *it ); + item->setOn( (*it)->searchEnabled() ); + } + } + + updateStatus(); +} + +void KCMHelpCenter::updateStatus() +{ + TQListViewItemIterator it( mListView ); + while ( it.current() != 0 ) { + ScopeItem *item = static_cast<ScopeItem *>( it.current() ); + TQString status; + if ( item->entry()->indexExists( Prefs::indexDirectory() ) ) { + status = i18n("OK"); + item->setOn( false ); + } else { + status = i18n("Missing"); + } + item->setText( 1, status ); + + ++it; + } + + checkSelection(); +} + +bool KCMHelpCenter::buildIndex() +{ + kdDebug(1401) << "Build Index" << endl; + + kdDebug() << "IndexPath: '" << Prefs::indexDirectory() << "'" << endl; + + if ( mProcess ) { + kdError() << "Error: Index Process still running." << endl; + return false; + } + + mIndexQueue.clear(); + + TQFontMetrics fm( font() ); + int maxWidth = 0; + + mCmdFile = new KTempFile; + mCmdFile->setAutoDelete( true ); + TQTextStream *ts = mCmdFile->textStream(); + if ( !ts ) { + kdError() << "Error opening command file." << endl; + deleteCmdFile(); + return false; + } else { + kdDebug() << "Writing to file '" << mCmdFile->name() << "'" << endl; + } + + bool hasError = false; + + TQListViewItemIterator it( mListView ); + while ( it.current() != 0 ) { + ScopeItem *item = static_cast<ScopeItem *>( it.current() ); + if ( item->isOn() ) { + DocEntry *entry = item->entry(); + + TQString docText = i18n("Document '%1' (%2):\n") + .arg( entry->identifier() ) + .arg( entry->name() ); + if ( entry->documentType().isEmpty() ) { + KMessageBox::sorry( this, docText + + i18n("No document type.") ); + hasError = true; + } else { + SearchHandler *handler = mEngine->handler( entry->documentType() ); + if ( !handler ) { + KMessageBox::sorry( this, docText + + i18n("No search handler available for document type '%1'.") + .arg( entry->documentType() ) ); + hasError = true; + } else { + TQString indexer = handler->indexCommand( entry->identifier() ); + if ( indexer.isEmpty() ) { + KMessageBox::sorry( this, docText + + i18n("No indexing command specified for document type '%1'.") + .arg( entry->documentType() ) ); + hasError = true; + } else { + indexer.replace( TQRegExp( "%i" ), entry->identifier() ); + indexer.replace( TQRegExp( "%d" ), Prefs::indexDirectory() ); + indexer.replace( TQRegExp( "%p" ), entry->url() ); + kdDebug() << "INDEXER: " << indexer << endl; + *ts << indexer << endl; + + int width = fm.width( entry->name() ); + if ( width > maxWidth ) maxWidth = width; + + mIndexQueue.append( entry ); + } + } + } + } + ++it; + } + + mCmdFile->close(); + + if ( mIndexQueue.isEmpty() ) { + deleteCmdFile(); + return !hasError; + } + + mCurrentEntry = mIndexQueue.begin(); + TQString name = (*mCurrentEntry)->name(); + + if ( !mProgressDialog ) { + mProgressDialog = new IndexProgressDialog( this ); + connect( mProgressDialog, TQT_SIGNAL( cancelled() ), + TQT_SLOT( cancelBuildIndex() ) ); + connect( mProgressDialog, TQT_SIGNAL( closed() ), + TQT_SLOT( slotProgressClosed() ) ); + } + mProgressDialog->setLabelText( name ); + mProgressDialog->setTotalSteps( mIndexQueue.count() ); + mProgressDialog->setMinimumLabelWidth( maxWidth ); + mProgressDialog->show(); + + startIndexProcess(); + + return true; +} + +void KCMHelpCenter::startIndexProcess() +{ + kdDebug() << "KCMHelpCenter::startIndexProcess()" << endl; + + mProcess = new TDEProcess; + + if ( mRunAsRoot ) { + *mProcess << "tdesu" << "--nonewdcop"; + kdDebug() << "Run as root" << endl; + } + + *mProcess << locate("exe", "khc_indexbuilder"); + *mProcess << mCmdFile->name(); + *mProcess << Prefs::indexDirectory(); + + connect( mProcess, TQT_SIGNAL( processExited( TDEProcess * ) ), + TQT_SLOT( slotIndexFinished( TDEProcess * ) ) ); + connect( mProcess, TQT_SIGNAL( receivedStdout( TDEProcess *, char *, int ) ), + TQT_SLOT( slotReceivedStdout(TDEProcess *, char *, int ) ) ); + connect( mProcess, TQT_SIGNAL( receivedStderr( TDEProcess *, char *, int ) ), + TQT_SLOT( slotReceivedStderr( TDEProcess *, char *, int ) ) ); + + if ( !mProcess->start( TDEProcess::NotifyOnExit, TDEProcess::AllOutput ) ) { + kdError() << "KCMHelpcenter::startIndexProcess(): Failed to start process." + << endl; + } +} + +void KCMHelpCenter::cancelBuildIndex() +{ + kdDebug() << "cancelBuildIndex()" << endl; + + deleteProcess(); + deleteCmdFile(); + mIndexQueue.clear(); + + if ( mIsClosing ) { + mIsClosing = false; + } +} + +void KCMHelpCenter::slotIndexFinished( TDEProcess *proc ) +{ + kdDebug() << "KCMHelpCenter::slotIndexFinished()" << endl; + + if ( proc == 0 ) { + kdWarning() << "Process null." << endl; + return; + } + + if ( proc != mProcess ) { + kdError() << "Unexpected Process finished." << endl; + return; + } + + if ( mProcess->normalExit() && mProcess->exitStatus() == 2 ) { + if ( mRunAsRoot ) { + kdError() << "Insufficient permissions." << endl; + } else { + kdDebug() << "Insufficient permissions. Trying again as root." << endl; + mRunAsRoot = true; + deleteProcess(); + startIndexProcess(); + return; + } + } else if ( !mProcess->normalExit() || mProcess->exitStatus() != 0 ) { + kdDebug() << "TDEProcess reported an error." << endl; + KMessageBox::error( this, i18n("Failed to build index.") ); + } else { + mConfig->setGroup( "Search" ); + mConfig->writeEntry( "IndexExists", true ); + emit searchIndexUpdated(); + } + + deleteProcess(); + deleteCmdFile(); + + mCurrentEntry = 0; + + if ( mProgressDialog ) { + mProgressDialog->setFinished( true ); + } + + mStdOut = TQString(); + mStdErr = TQString(); + + if ( mIsClosing ) { + if ( !mProgressDialog->isVisible() ) { + mIsClosing = false; + accept(); + } + } +} + +void KCMHelpCenter::deleteProcess() +{ + delete mProcess; + mProcess = 0; +} + +void KCMHelpCenter::deleteCmdFile() +{ + delete mCmdFile; + mCmdFile = 0; +} + +void KCMHelpCenter::slotIndexProgress() +{ + if( !mProcess ) + return; + + kdDebug() << "KCMHelpCenter::slotIndexProgress()" << endl; + + updateStatus(); + + advanceProgress(); +} + +void KCMHelpCenter::slotIndexError( const TQString &str ) +{ + if( !mProcess ) + return; + + kdDebug() << "KCMHelpCenter::slotIndexError()" << endl; + + KMessageBox::sorry( this, i18n("Error executing indexing build command:\n%1") + .arg( str ) ); + + if ( mProgressDialog ) { + mProgressDialog->appendLog( "<i>" + str + "</i>" ); + } + + advanceProgress(); +} + +void KCMHelpCenter::advanceProgress() +{ + if ( mProgressDialog && mProgressDialog->isVisible() ) { + mProgressDialog->advanceProgress(); + mCurrentEntry++; + if ( mCurrentEntry != mIndexQueue.end() ) { + TQString name = (*mCurrentEntry)->name(); + mProgressDialog->setLabelText( name ); + } + } +} + +void KCMHelpCenter::slotReceivedStdout( TDEProcess *, char *buffer, int buflen ) +{ + TQString text = TQString::fromLocal8Bit( buffer, buflen ); + int pos = text.findRev( '\n' ); + if ( pos < 0 ) { + mStdOut.append( text ); + } else { + if ( mProgressDialog ) { + mProgressDialog->appendLog( mStdOut + text.left( pos ) ); + mStdOut = text.mid( pos + 1 ); + } + } +} + +void KCMHelpCenter::slotReceivedStderr( TDEProcess *, char *buffer, int buflen ) +{ + TQString text = TQString::fromLocal8Bit( buffer, buflen ); + int pos = text.findRev( '\n' ); + if ( pos < 0 ) { + mStdErr.append( text ); + } else { + if ( mProgressDialog ) { + mProgressDialog->appendLog( "<i>" + mStdErr + text.left( pos ) + + "</i>"); + mStdErr = text.mid( pos + 1 ); + } + } +} + +void KCMHelpCenter::slotOk() +{ + if ( buildIndex() ) { + if ( !mProcess ) accept(); + else mIsClosing = true; + } +} + +void KCMHelpCenter::slotProgressClosed() +{ + kdDebug() << "KCMHelpCenter::slotProgressClosed()" << endl; + + if ( mIsClosing ) accept(); +} + +void KCMHelpCenter::showIndexDirDialog() +{ + IndexDirDialog dlg( this ); + if ( dlg.exec() == TQDialog::Accepted ) { + load(); + } +} + +void KCMHelpCenter::checkSelection() +{ + int count = 0; + + TQListViewItemIterator it( mListView ); + while ( it.current() != 0 ) { + ScopeItem *item = static_cast<ScopeItem *>( it.current() ); + if ( item->isOn() ) { + ++count; + } + ++it; + } + + enableButtonOK( count != 0 ); +} + +void KCMHelpCenter::findWriteableIndexDir() +{ + TQFileInfo currentDir( Prefs::indexDirectory() ); + if ( !currentDir.isWritable() ) + Prefs::setIndexDirectory( TDEGlobal::dirs()->saveLocation("data", "khelpcenter/index/") ); +} +#include "kcmhelpcenter.moc" + +// vim:ts=2:sw=2:et |