You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
331 lines
12 KiB
331 lines
12 KiB
/***************************************************************************
|
|
* Copyright (C) 1999-2001 by Matthias Hoelzer-Kluepfel *
|
|
* hoelzer@kde.org *
|
|
* Copyright (C) 2001 by Bernd Gehrmann *
|
|
* bernd@tdevelop.org *
|
|
* Copyright (C) 2004 by Alexander Dymo *
|
|
* cloudtemple@mksat.net *
|
|
* *
|
|
* 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 "searchview.h"
|
|
|
|
#include <tqlayout.h>
|
|
#include <tqlabel.h>
|
|
#include <tqfile.h>
|
|
#include <tqtextstream.h>
|
|
#include <tqdir.h>
|
|
#include <tqregexp.h>
|
|
|
|
#include <kpushbutton.h>
|
|
#include <klistview.h>
|
|
#include <klineedit.h>
|
|
#include <kcombobox.h>
|
|
#include <klocale.h>
|
|
#include <kdialog.h>
|
|
#include <kprocess.h>
|
|
#include <kapplication.h>
|
|
#include <kstandarddirs.h>
|
|
#include <kconfig.h>
|
|
#include <kmessagebox.h>
|
|
#include <kdebug.h>
|
|
|
|
#include <kdevpartcontroller.h>
|
|
#include <kdevdocumentationplugin.h>
|
|
|
|
#include "documentation_part.h"
|
|
#include "docutils.h"
|
|
|
|
SearchView::SearchView(DocumentationPart *part, TQWidget *parent, const char *name)
|
|
:TQWidget(parent, name), m_part(part)
|
|
{
|
|
TQVBoxLayout *l = new TQVBoxLayout(this, 0, KDialog::spacingHint());
|
|
|
|
TQVBoxLayout *l2 = new TQVBoxLayout(l, 0);
|
|
TQLabel *editLabel = new TQLabel(i18n("Wor&ds to search:"), this);
|
|
l2->addWidget(editLabel);
|
|
TQHBoxLayout *l21 = new TQHBoxLayout(l2, 0);
|
|
m_edit = new KLineEdit(this);
|
|
editLabel->setBuddy(m_edit);
|
|
m_goSearchButton = new KPushButton(i18n("Se&arch"), this);
|
|
l21->addWidget(m_edit);
|
|
l21->addWidget(m_goSearchButton);
|
|
|
|
TQGridLayout *l3 = new TQGridLayout(l, 2, 2, 0);
|
|
m_searchMethodBox = new KComboBox(this);
|
|
m_searchMethodBox->insertItem(i18n("and"));
|
|
m_searchMethodBox->insertItem(i18n("or"));
|
|
TQLabel *smLabel = new TQLabel(m_searchMethodBox, i18n("&Method:"), this);
|
|
m_sortMethodBox = new KComboBox(this);
|
|
m_sortMethodBox->insertItem(i18n("Score"));
|
|
m_sortMethodBox->insertItem(i18n("Title"));
|
|
m_sortMethodBox->insertItem(i18n("Date"));
|
|
TQLabel *rmLabel = new TQLabel(m_sortMethodBox, i18n("S&ort by:"), this);
|
|
l3->addWidget(smLabel, 0, 0);
|
|
l3->addWidget(m_searchMethodBox, 0, 1);
|
|
l3->addWidget(rmLabel, 1, 0);
|
|
l3->addWidget(m_sortMethodBox, 1, 1);
|
|
|
|
TQVBoxLayout *l4 = new TQVBoxLayout(l, 0);
|
|
m_view = new KListView(this);
|
|
TQLabel *vLabel = new TQLabel(m_view, i18n("Search &results:"), this);
|
|
l4->addWidget(vLabel);
|
|
l4->addWidget(m_view);
|
|
|
|
TQHBoxLayout *l5 = new TQHBoxLayout(l, KDialog::spacingHint());
|
|
m_configButton = new KPushButton(i18n("Update Config"), this);
|
|
m_indexButton = new KPushButton(i18n("Update Index"), this);
|
|
l5->addWidget(m_configButton);
|
|
l5->addWidget(m_indexButton);
|
|
l5->addItem(new TQSpacerItem(1, 1, TQSizePolicy::Expanding, TQSizePolicy::Fixed));
|
|
|
|
l->addSpacing(2);
|
|
|
|
m_view->setSorting(-1);
|
|
m_view->addColumn(i18n("Relevance"));
|
|
m_view->addColumn(i18n("Title"));
|
|
m_view->setColumnWidthMode(0, TQListView::Maximum);
|
|
m_view->setColumnWidthMode(1, TQListView::Maximum);
|
|
m_view->setAllColumnsShowFocus(true);
|
|
m_view->setResizeMode( TQListView::LastColumn );
|
|
|
|
connect(m_configButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(updateConfig()));
|
|
connect(m_indexButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(updateIndex()));
|
|
connect(m_edit, TQT_SIGNAL(returnPressed()), this, TQT_SLOT(search()));
|
|
connect(m_goSearchButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(search()));
|
|
connect(m_view, TQT_SIGNAL(executed(TQListViewItem*)), this, TQT_SLOT(executed(TQListViewItem*)));
|
|
connect(m_view, TQT_SIGNAL(mouseButtonPressed(int, TQListViewItem*, const TQPoint&, int )),
|
|
this, TQT_SLOT(itemMouseButtonPressed(int, TQListViewItem*, const TQPoint&, int )));
|
|
}
|
|
|
|
SearchView::~SearchView()
|
|
{
|
|
}
|
|
|
|
void SearchView::updateConfig()
|
|
{
|
|
runHtdig("-c");
|
|
}
|
|
|
|
void SearchView::updateIndex()
|
|
{
|
|
runHtdig("-i");
|
|
KConfig *config = m_part->config();
|
|
config->setGroup("htdig");
|
|
config->writeEntry("IsSetup", true);
|
|
config->sync();
|
|
}
|
|
|
|
void SearchView::runHtdig(const TQString &arg)
|
|
{
|
|
KProcess proc;
|
|
proc << "tdevelop-htdig" << arg;
|
|
proc.start(KProcess::DontCare);
|
|
}
|
|
|
|
void qt_enter_modal(TQWidget *widget);
|
|
void qt_leave_modal(TQWidget *widget);
|
|
|
|
void SearchView::search()
|
|
{
|
|
KConfig *config = m_part->config();
|
|
config->setGroup("htdig");
|
|
if (config->readBoolEntry("IsSetup", false) == false)
|
|
{
|
|
KMessageBox::information(this, i18n("Full text search has to be set up before usage."));
|
|
if (!m_part->configure(1))
|
|
return;
|
|
KMessageBox::information(this, i18n("Now the full text search database will be created.\nWait for database creation to finish and then repeat search."));
|
|
updateIndex();
|
|
return;
|
|
}
|
|
TQString exe = config->readPathEntry("htsearchbin", kapp->dirs()->findExe("htsearch"));
|
|
if (exe.isEmpty())
|
|
{
|
|
KMessageBox::error(this, i18n("Cannot find the htsearch executable.\nIt is part of the ht://Dig package that is used by KDevelop to perform full text search. Please install ht://Dig and use Documentation page in Configure KDevelop dialog to set the htsearch location."));
|
|
kdDebug() << "Can not find htsearch" << endl;
|
|
return;
|
|
}
|
|
|
|
TQString indexdir = kapp->dirs()->saveLocation("data", "kdevdocumentation/search");
|
|
TQDir d;
|
|
if (indexdir.isEmpty() || !TQFile::exists(indexdir + "/htdig.conf"))
|
|
{
|
|
if (TQFile::exists("/var/lib/tdevelop3/helpindex/htdig.conf"))
|
|
indexdir = "/var/lib/tdevelop3/helpindex";
|
|
else if (TQFile::exists("/var/lib/tdevelop/helpindex/htdig.conf"))
|
|
indexdir = "/var/lib/tdevelop/helpindex";
|
|
|
|
if (!TQFile::exists(indexdir + "/htdig.conf"))
|
|
{
|
|
KMessageBox::error(this, i18n("Cannot find the htdig configuration file."));
|
|
kdDebug() << "Cannot find the htdig configuration file" << endl;
|
|
return;
|
|
}
|
|
}
|
|
|
|
TQString savedir = kapp->dirs()->saveLocation("data", "kdevdocumentation/search");
|
|
if (!d.exists(savedir))
|
|
d.mkdir(savedir);
|
|
|
|
TQString query = TQString("words=%1;method=%2;matchesperpage=%3;format=%4;sort=%5")
|
|
.arg(m_edit->text())
|
|
.arg(m_searchMethodBox->currentItem()==1? "or" : "and")
|
|
.arg(50)
|
|
.arg("builtin-short")
|
|
.arg(m_sortMethodBox->currentItem()==2? "date" : m_sortMethodBox->currentItem()==1? "title" : "score");
|
|
|
|
kdDebug(9002) << "starting kprocess" << endl;
|
|
kdDebug(9002) << "htdig line:" << exe << " -c " << (indexdir + "/htdig.conf ") << query << endl;
|
|
KProcess *proc = new KProcess;
|
|
TQString picdir = kapp->dirs()->findResourceDir("data", "kdevdocumentation/pics/htdig.png");
|
|
proc->setEnvironment("PICDIR", picdir);
|
|
*proc << exe << "-c" << (indexdir + "/htdig.conf") << query;
|
|
|
|
connect( proc, TQT_SIGNAL(receivedStdout(KProcess *,char*,int)),
|
|
this, TQT_SLOT(htsearchStdout(KProcess *,char*,int)) );
|
|
connect( proc, TQT_SIGNAL(processExited(KProcess *)),
|
|
this, TQT_SLOT(htsearchExited(KProcess *)) );
|
|
|
|
searchResult = "";
|
|
|
|
if (!proc->start(KProcess::NotifyOnExit, KProcess::Stdout))
|
|
{
|
|
KMessageBox::error(this, i18n("Cannot start the htsearch executable."));
|
|
kdDebug() << "process start failed" << endl;
|
|
delete proc;
|
|
return;
|
|
}
|
|
|
|
// While receiving data from the subprocess, we want
|
|
// to block the user interface, but still get repaint
|
|
// events. Hack taken from NetAccess...
|
|
kapp->setOverrideCursor(waitCursor);
|
|
TQWidget blocker(0, 0, WType_Dialog | WShowModal);
|
|
qt_enter_modal(&blocker);
|
|
kapp->enter_loop();
|
|
qt_leave_modal(&blocker);
|
|
kapp->restoreOverrideCursor();
|
|
|
|
if (!proc->normalExit() || proc->exitStatus() != 0)
|
|
{
|
|
kdDebug() << "Error running htsearch... returning now" << endl;
|
|
delete proc;
|
|
return;
|
|
}
|
|
|
|
delete proc;
|
|
|
|
// modify the search result
|
|
searchResult = searchResult.replace(TQRegExp("http://localhost/"), "file:/");
|
|
searchResult = searchResult.replace(TQRegExp("Content-type: text/html"), "");
|
|
|
|
// dump the search result
|
|
TQFile f(savedir + "/results.html");
|
|
if (f.open(IO_WriteOnly))
|
|
{
|
|
TQTextStream ts(&f);
|
|
ts << searchResult << endl;
|
|
f.close();
|
|
}
|
|
|
|
//show results
|
|
analyseSearchResults();
|
|
// m_part->partController()->showDocument(KURL("file://" + indexdir + "/results.html"));
|
|
}
|
|
|
|
void SearchView::htsearchStdout(KProcess *, char *buffer, int len)
|
|
{
|
|
searchResult += TQString::fromLocal8Bit(buffer, len);
|
|
}
|
|
|
|
void SearchView::htsearchExited(KProcess *)
|
|
{
|
|
kapp->exit_loop();
|
|
}
|
|
|
|
void SearchView::analyseSearchResults()
|
|
{
|
|
m_view->clear();
|
|
TQTextStream str(searchResult, IO_ReadOnly);
|
|
DocumentationItem *former = 0;
|
|
while (!str.eof())
|
|
{
|
|
TQString line = str.readLine();
|
|
|
|
TQRegExp starsExp("alt=\"\\*\"");
|
|
starsExp.setMinimal(true);
|
|
int stars = line.contains(starsExp);
|
|
|
|
TQRegExp urlExp("<strong><a href=\"(.*)\">(.*)</a></strong>");
|
|
if (urlExp.search(line)==-1)
|
|
continue;
|
|
TQString url = urlExp.cap(1);
|
|
TQString title = urlExp.cap(2);
|
|
|
|
TQString starsStr;
|
|
for (int i = 0; i < stars; ++i)
|
|
starsStr += "*";
|
|
|
|
if (former)
|
|
former = new DocumentationItem(DocumentationItem::Document, m_view, former, starsStr);
|
|
else
|
|
former = new DocumentationItem(DocumentationItem::Document, m_view, starsStr);
|
|
former->setText(1, title);
|
|
former->setURL(KURL(url));
|
|
}
|
|
|
|
executed( m_view->firstChild() );
|
|
}
|
|
|
|
void SearchView::executed(TQListViewItem *item)
|
|
{
|
|
DocumentationItem *d = dynamic_cast<DocumentationItem*>(item);
|
|
if (!d)
|
|
return;
|
|
|
|
m_part->partController()->showDocument(d->url());
|
|
}
|
|
|
|
void SearchView::itemMouseButtonPressed(int button, TQListViewItem *item, const TQPoint &pos, int // c
|
|
)
|
|
{
|
|
if ((button != Qt::RightButton) || (!item))
|
|
return;
|
|
DocumentationItem *docItem = dynamic_cast<DocumentationItem*>(item);
|
|
if (!docItem)
|
|
return;
|
|
|
|
DocUtils::docItemPopup(m_part, docItem, pos, true, false, 1);
|
|
}
|
|
|
|
void SearchView::setSearchTerm(const TQString &term)
|
|
{
|
|
m_edit->setText(term);
|
|
}
|
|
|
|
void SearchView::askSearchTerm()
|
|
{
|
|
m_edit->setFocus();
|
|
}
|
|
|
|
void SearchView::focusInEvent(TQFocusEvent */*e*/)
|
|
{
|
|
m_edit->setFocus();
|
|
}
|
|
|
|
#include "searchview.moc"
|