summaryrefslogtreecommitdiffstats
path: root/parts/documentation/searchview.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'parts/documentation/searchview.cpp')
-rw-r--r--parts/documentation/searchview.cpp330
1 files changed, 330 insertions, 0 deletions
diff --git a/parts/documentation/searchview.cpp b/parts/documentation/searchview.cpp
new file mode 100644
index 00000000..253e9f10
--- /dev/null
+++ b/parts/documentation/searchview.cpp
@@ -0,0 +1,330 @@
+/***************************************************************************
+ * Copyright (C) 1999-2001 by Matthias Hoelzer-Kluepfel *
+ * Copyright (C) 2001 by Bernd Gehrmann *
+ * Copyright (C) 2004 by Alexander Dymo *
+ * *
+ * 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., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#include "searchview.h"
+
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qfile.h>
+#include <qtextstream.h>
+#include <qdir.h>
+#include <qregexp.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, QWidget *parent, const char *name)
+ :QWidget(parent, name), m_part(part)
+{
+ QVBoxLayout *l = new QVBoxLayout(this, 0, KDialog::spacingHint());
+
+ QVBoxLayout *l2 = new QVBoxLayout(l, 0);
+ QLabel *editLabel = new QLabel(i18n("Wor&ds to search:"), this);
+ l2->addWidget(editLabel);
+ QHBoxLayout *l21 = new QHBoxLayout(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);
+
+ QGridLayout *l3 = new QGridLayout(l, 2, 2, 0);
+ m_searchMethodBox = new KComboBox(this);
+ m_searchMethodBox->insertItem(i18n("and"));
+ m_searchMethodBox->insertItem(i18n("or"));
+ QLabel *smLabel = new QLabel(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"));
+ QLabel *rmLabel = new QLabel(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);
+
+ QVBoxLayout *l4 = new QVBoxLayout(l, 0);
+ m_view = new KListView(this);
+ QLabel *vLabel = new QLabel(m_view, i18n("Search &results:"), this);
+ l4->addWidget(vLabel);
+ l4->addWidget(m_view);
+
+ QHBoxLayout *l5 = new QHBoxLayout(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 QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Fixed));
+
+ l->addSpacing(2);
+
+ m_view->setSorting(-1);
+ m_view->addColumn(i18n("Relevance"));
+ m_view->addColumn(i18n("Title"));
+ m_view->setColumnWidthMode(0, QListView::Maximum);
+ m_view->setColumnWidthMode(1, QListView::Maximum);
+ m_view->setAllColumnsShowFocus(true);
+ m_view->setResizeMode( QListView::LastColumn );
+
+ connect(m_configButton, SIGNAL(clicked()), this, SLOT(updateConfig()));
+ connect(m_indexButton, SIGNAL(clicked()), this, SLOT(updateIndex()));
+ connect(m_edit, SIGNAL(returnPressed()), this, SLOT(search()));
+ connect(m_goSearchButton, SIGNAL(clicked()), this, SLOT(search()));
+ connect(m_view, SIGNAL(executed(QListViewItem*)), this, SLOT(executed(QListViewItem*)));
+ connect(m_view, SIGNAL(mouseButtonPressed(int, QListViewItem*, const QPoint&, int )),
+ this, SLOT(itemMouseButtonPressed(int, QListViewItem*, const QPoint&, 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 QString &arg)
+{
+ KProcess proc;
+ proc << "kdevelop-htdig" << arg;
+ proc.start(KProcess::DontCare);
+}
+
+void qt_enter_modal(QWidget *widget);
+void qt_leave_modal(QWidget *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;
+ }
+ QString 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;
+ }
+
+ QString indexdir = kapp->dirs()->saveLocation("data", "kdevdocumentation/search");
+ QDir d;
+ if (indexdir.isEmpty() || !QFile::exists(indexdir + "/htdig.conf"))
+ {
+ if (QFile::exists("/var/lib/kdevelop3/helpindex/htdig.conf"))
+ indexdir = "/var/lib/kdevelop3/helpindex";
+ else if (QFile::exists("/var/lib/kdevelop/helpindex/htdig.conf"))
+ indexdir = "/var/lib/kdevelop/helpindex";
+
+ if (!QFile::exists(indexdir + "/htdig.conf"))
+ {
+ KMessageBox::error(this, i18n("Cannot find the htdig configuration file."));
+ kdDebug() << "Cannot find the htdig configuration file" << endl;
+ return;
+ }
+ }
+
+ QString savedir = kapp->dirs()->saveLocation("data", "kdevdocumentation/search");
+ if (!d.exists(savedir))
+ d.mkdir(savedir);
+
+ QString query = QString("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;
+ QString picdir = kapp->dirs()->findResourceDir("data", "kdevdocumentation/pics/htdig.png");
+ proc->setEnvironment("PICDIR", picdir);
+ *proc << exe << "-c" << (indexdir + "/htdig.conf") << query;
+
+ connect( proc, SIGNAL(receivedStdout(KProcess *,char*,int)),
+ this, SLOT(htsearchStdout(KProcess *,char*,int)) );
+ connect( proc, SIGNAL(processExited(KProcess *)),
+ this, 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);
+ QWidget 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(QRegExp("http://localhost/"), "file:/");
+ searchResult = searchResult.replace(QRegExp("Content-type: text/html"), "");
+
+ // dump the search result
+ QFile f(savedir + "/results.html");
+ if (f.open(IO_WriteOnly))
+ {
+ QTextStream 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 += QString::fromLocal8Bit(buffer, len);
+}
+
+void SearchView::htsearchExited(KProcess *)
+{
+ kapp->exit_loop();
+}
+
+void SearchView::analyseSearchResults()
+{
+ m_view->clear();
+ QTextStream str(searchResult, IO_ReadOnly);
+ DocumentationItem *former = 0;
+ while (!str.eof())
+ {
+ QString line = str.readLine();
+
+ QRegExp starsExp("alt=\"\\*\"");
+ starsExp.setMinimal(true);
+ int stars = line.contains(starsExp);
+
+ QRegExp urlExp("<strong><a href=\"(.*)\">(.*)</a></strong>");
+ if (urlExp.search(line)==-1)
+ continue;
+ QString url = urlExp.cap(1);
+ QString title = urlExp.cap(2);
+
+ QString 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(QListViewItem *item)
+{
+ DocumentationItem *d = dynamic_cast<DocumentationItem*>(item);
+ if (!d)
+ return;
+
+ m_part->partController()->showDocument(d->url());
+}
+
+void SearchView::itemMouseButtonPressed(int button, QListViewItem *item, const QPoint &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 QString &term)
+{
+ m_edit->setText(term);
+}
+
+void SearchView::askSearchTerm()
+{
+ m_edit->setFocus();
+}
+
+void SearchView::focusInEvent(QFocusEvent */*e*/)
+{
+ m_edit->setFocus();
+}
+
+#include "searchview.moc"