mirror of
https://bitbucket.org/smil3y/kde-playground.git
synced 2025-02-23 10:22:50 +00:00
407 lines
10 KiB
C++
407 lines
10 KiB
C++
|
|
/*
|
|
* searchwidget.cpp - part of the KDE Help Center
|
|
*
|
|
* Copyright (C) 1999 Matthias Elter (me@kde.org)
|
|
* (C) 2000 Matthias Hoelzer-Kluepfel (hoelzer@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 "searchwidget.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <errno.h>
|
|
|
|
#include <QLabel>
|
|
#include <QPushButton>
|
|
#include <QComboBox>
|
|
#include <QLayout>
|
|
#include <QVBoxLayout>
|
|
#include <QHBoxLayout>
|
|
#include <QBoxLayout>
|
|
#include <QtDBus/QDBusConnection>
|
|
|
|
#include <KConfig>
|
|
#include <KApplication>
|
|
#include <KLocale>
|
|
#include <KDebug>
|
|
#include <KIconLoader>
|
|
|
|
#include "scopeitem.h"
|
|
#include "docentrytraverser.h"
|
|
#include "kcmhelpcenter.h"
|
|
#include "prefs.h"
|
|
#include "searchengine.h"
|
|
|
|
namespace KHC {
|
|
|
|
SearchWidget::SearchWidget( SearchEngine *engine, QWidget *parent )
|
|
: QWidget( parent ), mEngine( engine ),
|
|
mScopeCount( 0 )
|
|
{
|
|
QDBusConnection::sessionBus().registerObject("/SearchWidget", this, QDBusConnection::ExportScriptableSlots);
|
|
|
|
QBoxLayout *topLayout = new QVBoxLayout( this );
|
|
topLayout->setMargin( 2 );
|
|
topLayout->setSpacing( 2 );
|
|
|
|
QBoxLayout *hLayout = new QHBoxLayout();
|
|
topLayout->addLayout( hLayout );
|
|
|
|
mMethodCombo = new QComboBox( this );
|
|
mMethodCombo->addItem( i18n("and") );
|
|
mMethodCombo->addItem( i18n("or") );
|
|
|
|
QLabel *l = new QLabel( i18n("&Method:"), this );
|
|
l->setBuddy( mMethodCombo );
|
|
|
|
hLayout->addWidget( l );
|
|
hLayout->addWidget( mMethodCombo );
|
|
|
|
hLayout = new QHBoxLayout();
|
|
topLayout->addLayout( hLayout );
|
|
|
|
mPagesCombo = new QComboBox( this );
|
|
mPagesCombo->addItem( QLatin1String("5") );
|
|
mPagesCombo->addItem( QLatin1String("10") );
|
|
mPagesCombo->addItem( QLatin1String("25") );
|
|
mPagesCombo->addItem( QLatin1String("50") );
|
|
mPagesCombo->addItem( QLatin1String("1000") );
|
|
|
|
l = new QLabel( i18n("Max. &results:"), this );
|
|
l->setBuddy( mPagesCombo );
|
|
|
|
hLayout->addWidget( l );
|
|
hLayout->addWidget( mPagesCombo );
|
|
|
|
hLayout = new QHBoxLayout();
|
|
topLayout->addLayout( hLayout );
|
|
|
|
mScopeCombo = new QComboBox( this );
|
|
for (int i=0; i < ScopeNum; ++i ) {
|
|
mScopeCombo->addItem( scopeSelectionLabel( i ) );
|
|
}
|
|
connect( mScopeCombo, SIGNAL( activated( int ) ),
|
|
SLOT( scopeSelectionChanged( int ) ) );
|
|
|
|
l = new QLabel( i18n("&Scope selection:"), this );
|
|
l->setBuddy( mScopeCombo );
|
|
|
|
hLayout->addWidget( l );
|
|
hLayout->addWidget( mScopeCombo );
|
|
|
|
mScopeListView = new QTreeWidget( this );
|
|
mScopeListView->setColumnCount( 1 );
|
|
mScopeListView->setHeaderLabels( QStringList() << i18n("Scope") );
|
|
topLayout->addWidget( mScopeListView, 1 );
|
|
|
|
QPushButton *indexButton = new QPushButton( i18n("Build Search &Index..."),
|
|
this );
|
|
connect( indexButton, SIGNAL( clicked() ), SIGNAL( showIndexDialog() ) );
|
|
topLayout->addWidget( indexButton );
|
|
|
|
// FIXME: Use SearchHandler on double-clicked document
|
|
#if 0
|
|
connect( mScopeListView, SIGNAL(itemDoubleClicked(QTreeWidgetItem*,int) ),
|
|
SLOT(scopeDoubleClicked(QTreeWidgetItem*)) );
|
|
#endif
|
|
connect( mScopeListView, SIGNAL(itemClicked(QTreeWidgetItem*,int)),
|
|
SLOT(scopeClicked(QTreeWidgetItem*)) );
|
|
}
|
|
|
|
|
|
SearchWidget::~SearchWidget()
|
|
{
|
|
writeConfig( KGlobal::config().data() );
|
|
}
|
|
|
|
|
|
void SearchWidget::readConfig( KConfig *cfg )
|
|
{
|
|
KConfigGroup searchGroup(cfg, "Search");
|
|
int scopeSelection = searchGroup.readEntry( "ScopeSelection", (int)ScopeDefault );
|
|
mScopeCombo->setCurrentIndex( scopeSelection );
|
|
if ( scopeSelection != ScopeDefault ) scopeSelectionChanged( scopeSelection );
|
|
|
|
mMethodCombo->setCurrentIndex( Prefs::method() );
|
|
mPagesCombo->setCurrentIndex( Prefs::maxCount() );
|
|
|
|
if ( scopeSelection == ScopeCustom ) {
|
|
KConfigGroup searchScopeGroup(cfg, "Custom Search Scope" );
|
|
QTreeWidgetItemIterator it( mScopeListView );
|
|
while( *it ) {
|
|
if ( (*it)->type() == ScopeItem::rttiId() ) {
|
|
ScopeItem *item = static_cast<ScopeItem *>(*it);
|
|
item->setOn( searchScopeGroup.readEntry(
|
|
item->entry()->identifier(),
|
|
item->isOn() ) );
|
|
}
|
|
++it;
|
|
}
|
|
}
|
|
|
|
checkScope();
|
|
}
|
|
|
|
void SearchWidget::writeConfig( KConfig *cfg )
|
|
{
|
|
KConfigGroup cg (cfg, "Search");
|
|
|
|
cg.writeEntry( "ScopeSelection", mScopeCombo->currentIndex() );
|
|
Prefs::setMethod( mMethodCombo->currentIndex() );
|
|
Prefs::setMaxCount( mPagesCombo->currentIndex() );
|
|
|
|
if ( mScopeCombo->currentIndex() == ScopeCustom ) {
|
|
KConfigGroup cg2 (cfg, "Custom Search Scope");
|
|
QTreeWidgetItemIterator it( mScopeListView );
|
|
while( (*it) ) {
|
|
if ( (*it)->type() == ScopeItem::rttiId() ) {
|
|
ScopeItem *item = static_cast<ScopeItem *>( (*it) );
|
|
cg2.writeEntry( item->entry()->identifier(), item->isOn() );
|
|
}
|
|
++it;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SearchWidget::slotSwitchBoxes()
|
|
{
|
|
QTreeWidgetItemIterator it( mScopeListView );
|
|
while( (*it) ) {
|
|
if ( (*it)->type() == ScopeItem::rttiId() ) {
|
|
ScopeItem *item = static_cast<ScopeItem *>( (*it) );
|
|
item->setOn( !item->isOn() );
|
|
}
|
|
++it;
|
|
}
|
|
|
|
checkScope();
|
|
}
|
|
|
|
void SearchWidget::scopeSelectionChanged( int id )
|
|
{
|
|
QTreeWidgetItemIterator it( mScopeListView );
|
|
while( (*it) ) {
|
|
if ( (*it)->type() == ScopeItem::rttiId() ) {
|
|
ScopeItem *item = static_cast<ScopeItem *>( (*it) );
|
|
bool state = item->isOn();
|
|
switch( id ) {
|
|
case ScopeDefault:
|
|
state = item->entry()->searchEnabledDefault();
|
|
break;
|
|
case ScopeAll:
|
|
state = true;
|
|
break;
|
|
case ScopeNone:
|
|
state = false;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
if ( state != item->isOn() ) {
|
|
item->setOn( state );
|
|
}
|
|
}
|
|
++it;
|
|
}
|
|
|
|
checkScope();
|
|
}
|
|
|
|
QString SearchWidget::method()
|
|
{
|
|
QString m = "and";
|
|
if ( mMethodCombo->currentIndex() == 1)
|
|
m = "or";
|
|
|
|
return m;
|
|
}
|
|
|
|
int SearchWidget::pages()
|
|
{
|
|
int p = mPagesCombo->currentText().toInt();
|
|
|
|
return p;
|
|
}
|
|
|
|
QString SearchWidget::scope()
|
|
{
|
|
QString scope;
|
|
|
|
QTreeWidgetItemIterator it( mScopeListView );
|
|
while( (*it) ) {
|
|
if ( (*it)->type() == ScopeItem::rttiId() ) {
|
|
ScopeItem *item = static_cast<ScopeItem *>( (*it) );
|
|
if ( item->isOn() ) {
|
|
if ( !scope.isEmpty() ) scope += '&';
|
|
scope += QLatin1String("scope=") + item->entry()->identifier();
|
|
}
|
|
}
|
|
++it;
|
|
}
|
|
|
|
return scope;
|
|
}
|
|
|
|
class ScopeTraverser : public DocEntryTraverser
|
|
{
|
|
public:
|
|
ScopeTraverser( SearchWidget *widget, int level ) :
|
|
mWidget( widget ), mLevel( level ), mParentItem( 0 ) {}
|
|
|
|
~ScopeTraverser()
|
|
{
|
|
if( mParentItem && !mParentItem->childCount() ) delete mParentItem;
|
|
}
|
|
|
|
void process( DocEntry *entry )
|
|
{
|
|
if ( mWidget->engine()->canSearch( entry ) &&
|
|
( !mWidget->engine()->needsIndex( entry ) ||
|
|
entry->indexExists( Prefs::indexDirectory() ) ) ) {
|
|
ScopeItem *item = 0;
|
|
if ( mParentItem ) {
|
|
item = new ScopeItem( mParentItem, entry );
|
|
} else {
|
|
item = new ScopeItem( mWidget->listView(), entry );
|
|
}
|
|
item->setOn( entry->searchEnabled() );
|
|
}
|
|
}
|
|
|
|
DocEntryTraverser *createChild( DocEntry *entry )
|
|
{
|
|
if ( mLevel >= mNestingLevel ) {
|
|
++mLevel;
|
|
return this;
|
|
} else {
|
|
ScopeTraverser *t = new ScopeTraverser( mWidget, mLevel + 1 );
|
|
QTreeWidgetItem *item = 0;
|
|
if ( mParentItem ) {
|
|
item = new QTreeWidgetItem( mParentItem, QStringList() << entry->name() );
|
|
} else {
|
|
item = new QTreeWidgetItem( mWidget->listView(), QStringList() << entry->name() );
|
|
}
|
|
item->setExpanded( true );
|
|
t->mParentItem = item;
|
|
return t;
|
|
}
|
|
}
|
|
|
|
DocEntryTraverser *parentTraverser()
|
|
{
|
|
if ( mLevel > mNestingLevel ) return this;
|
|
else return mParent;
|
|
}
|
|
|
|
void deleteTraverser()
|
|
{
|
|
if ( mLevel > mNestingLevel ) --mLevel;
|
|
else delete this;
|
|
}
|
|
|
|
private:
|
|
SearchWidget *mWidget;
|
|
int mLevel;
|
|
QTreeWidgetItem *mParentItem;
|
|
|
|
static int mNestingLevel;
|
|
};
|
|
|
|
int ScopeTraverser::mNestingLevel = 2;
|
|
|
|
void SearchWidget::searchIndexUpdated()
|
|
{
|
|
KGlobal::config()->reparseConfiguration();
|
|
updateScopeList();
|
|
update();
|
|
}
|
|
|
|
void SearchWidget::updateScopeList()
|
|
{
|
|
mScopeListView->clear();
|
|
|
|
ScopeTraverser t( this, 0 );
|
|
DocMetaInfo::self()->traverseEntries( &t );
|
|
|
|
checkScope();
|
|
}
|
|
|
|
void SearchWidget::scopeDoubleClicked( QTreeWidgetItem* item )
|
|
{
|
|
if ( !item || item->type() != ScopeItem::rttiId() ) return;
|
|
ScopeItem *scopeItem = static_cast<ScopeItem *>( item );
|
|
|
|
QString searchUrl = scopeItem->entry()->search();
|
|
|
|
kDebug() << "DoubleClick: " << searchUrl;
|
|
|
|
emit searchResult( searchUrl );
|
|
}
|
|
|
|
void SearchWidget::scopeClicked( QTreeWidgetItem* )
|
|
{
|
|
checkScope();
|
|
|
|
mScopeCombo->setCurrentIndex( ScopeCustom );
|
|
}
|
|
|
|
QString SearchWidget::scopeSelectionLabel( int id ) const
|
|
{
|
|
switch( id ) {
|
|
case ScopeCustom:
|
|
return i18nc("Label for searching documentation using custom (user defined) scope", "Custom");
|
|
case ScopeDefault:
|
|
return i18nc("Label for searching documentation using default search scope", "Default");
|
|
case ScopeAll:
|
|
return i18nc("Label for searching documentation in all subsections", "All");
|
|
case ScopeNone:
|
|
return i18nc("Label for scope that deselects all search subsections", "None");
|
|
default:
|
|
return i18nc("Label for Unknown search scope, that should never appear", "unknown");
|
|
}
|
|
}
|
|
|
|
void SearchWidget::checkScope()
|
|
{
|
|
mScopeCount = 0;
|
|
|
|
QTreeWidgetItemIterator it( mScopeListView );
|
|
while( (*it) ) {
|
|
if ( (*it)->type() == ScopeItem::rttiId() ) {
|
|
ScopeItem *item = static_cast<ScopeItem *>( (*it) );
|
|
if ( item->isOn() ) {
|
|
++mScopeCount;
|
|
}
|
|
item->entry()->enableSearch( item->isOn() );
|
|
}
|
|
++it;
|
|
}
|
|
|
|
emit scopeCountChanged( mScopeCount );
|
|
}
|
|
|
|
int SearchWidget::scopeCount() const
|
|
{
|
|
return mScopeCount;
|
|
}
|
|
|
|
}
|
|
|
|
#include "moc_searchwidget.cpp"
|
|
|
|
// vim:ts=2:sw=2:et
|