00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "searchview.h"
00025
00026 #include <qlayout.h>
00027 #include <qlabel.h>
00028 #include <qfile.h>
00029 #include <qtextstream.h>
00030 #include <qdir.h>
00031 #include <qregexp.h>
00032
00033 #include <kpushbutton.h>
00034 #include <klistview.h>
00035 #include <klineedit.h>
00036 #include <kcombobox.h>
00037 #include <klocale.h>
00038 #include <kdialog.h>
00039 #include <kprocess.h>
00040 #include <kapplication.h>
00041 #include <kstddirs.h>
00042 #include <kconfig.h>
00043 #include <kmessagebox.h>
00044 #include <kdebug.h>
00045
00046 #include <kdevpartcontroller.h>
00047 #include <kdevdocumentationplugin.h>
00048
00049 #include "documentation_part.h"
00050 #include "docutils.h"
00051
00052 SearchView::SearchView(DocumentationPart *part, QWidget *parent, const char *name)
00053 :QWidget(parent, name), m_part(part)
00054 {
00055 QVBoxLayout *l = new QVBoxLayout(this, 0, KDialog::spacingHint());
00056
00057 QVBoxLayout *l2 = new QVBoxLayout(l, 0);
00058 QLabel *editLabel = new QLabel(i18n("Wor&ds to search:"), this);
00059 l2->addWidget(editLabel);
00060 QHBoxLayout *l21 = new QHBoxLayout(l2, 0);
00061 m_edit = new KLineEdit(this);
00062 editLabel->setBuddy(m_edit);
00063 m_goSearchButton = new KPushButton(i18n("Se&arch"), this);
00064 l21->addWidget(m_edit);
00065 l21->addWidget(m_goSearchButton);
00066
00067 QGridLayout *l3 = new QGridLayout(l, 2, 2, 0);
00068 m_searchMethodBox = new KComboBox(this);
00069 m_searchMethodBox->insertItem(i18n("and"));
00070 m_searchMethodBox->insertItem(i18n("or"));
00071 QLabel *smLabel = new QLabel(m_searchMethodBox, i18n("&Method:"), this);
00072 m_sortMethodBox = new KComboBox(this);
00073 m_sortMethodBox->insertItem(i18n("Score"));
00074 m_sortMethodBox->insertItem(i18n("Title"));
00075 m_sortMethodBox->insertItem(i18n("Date"));
00076 QLabel *rmLabel = new QLabel(m_sortMethodBox, i18n("S&ort by:"), this);
00077 l3->addWidget(smLabel, 0, 0);
00078 l3->addWidget(m_searchMethodBox, 0, 1);
00079 l3->addWidget(rmLabel, 1, 0);
00080 l3->addWidget(m_sortMethodBox, 1, 1);
00081
00082 QVBoxLayout *l4 = new QVBoxLayout(l, 0);
00083 m_view = new KListView(this);
00084 QLabel *vLabel = new QLabel(m_view, i18n("Search &results:"), this);
00085 l4->addWidget(vLabel);
00086 l4->addWidget(m_view);
00087
00088 QHBoxLayout *l5 = new QHBoxLayout(l, KDialog::spacingHint());
00089 m_configButton = new KPushButton(i18n("Update Config"), this);
00090 m_indexButton = new KPushButton(i18n("Update Index"), this);
00091 l5->addWidget(m_configButton);
00092 l5->addWidget(m_indexButton);
00093 l5->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Fixed));
00094
00095 l->addSpacing(2);
00096
00097 m_view->setSorting(-1);
00098 m_view->addColumn(i18n("Relevance"));
00099 m_view->addColumn(i18n("Title"));
00100 m_view->setColumnWidthMode(0, QListView::Maximum);
00101 m_view->setColumnWidthMode(1, QListView::Maximum);
00102 m_view->setAllColumnsShowFocus(true);
00103
00104 connect(m_configButton, SIGNAL(clicked()), this, SLOT(updateConfig()));
00105 connect(m_indexButton, SIGNAL(clicked()), this, SLOT(updateIndex()));
00106 connect(m_edit, SIGNAL(returnPressed()), this, SLOT(search()));
00107 connect(m_goSearchButton, SIGNAL(clicked()), this, SLOT(search()));
00108 connect(m_view, SIGNAL(executed(QListViewItem*)), this, SLOT(executed(QListViewItem*)));
00109 connect(m_view, SIGNAL(mouseButtonPressed(int, QListViewItem*, const QPoint&, int )),
00110 this, SLOT(itemMouseButtonPressed(int, QListViewItem*, const QPoint&, int )));
00111 }
00112
00113 SearchView::~SearchView()
00114 {
00115 }
00116
00117 void SearchView::updateConfig()
00118 {
00119 runHtdig("-c");
00120 }
00121
00122 void SearchView::updateIndex()
00123 {
00124 runHtdig("-i");
00125 }
00126
00127 void SearchView::runHtdig(const QString &arg)
00128 {
00129 KProcess proc;
00130 proc << "kdevelop-htdig" << arg;
00131 proc.start(KProcess::DontCare);
00132 }
00133
00134 void qt_enter_modal(QWidget *widget);
00135 void qt_leave_modal(QWidget *widget);
00136
00137 void SearchView::search()
00138 {
00139 KConfig *config = m_part->config();
00140 config->setGroup("htdig");
00141 if (config->readBoolEntry("IsSetup", false) == false)
00142 {
00143 KMessageBox::information(this, i18n("Full text search has to be set up before usage."));
00144 if (!m_part->configure(1))
00145 return;
00146 config->writeEntry("IsSetup", true);
00147 KMessageBox::information(this, i18n("Now the full text search database will be created.\nWait for database creation to finish and then repeat search."));
00148 updateIndex();
00149 return;
00150 }
00151 QString exe = config->readPathEntry("htsearchbin", kapp->dirs()->findExe("htsearch"));
00152 if (exe.isEmpty())
00153 {
00154 KMessageBox::error(this, i18n("Cannot find the htsearch executable."));
00155 kdDebug() << "Can not find htsearch" << endl;
00156 return;
00157 }
00158
00159 QString indexdir = kapp->dirs()->saveLocation("data", "kdevdocumentation/search");
00160 QDir d;
00161 if (indexdir.isEmpty() || !QFile::exists(indexdir + "/htdig.conf"))
00162 {
00163 if (QFile::exists("/var/lib/kdevelop3/helpindex/htdig.conf"))
00164 indexdir = "/var/lib/kdevelop3/helpindex";
00165 else if (QFile::exists("/var/lib/kdevelop/helpindex/htdig.conf"))
00166 indexdir = "/var/lib/kdevelop/helpindex";
00167
00168 if (!QFile::exists(indexdir + "/htdig.conf"))
00169 {
00170 KMessageBox::error(this, i18n("Can not find the htdig configuration file."));
00171 kdDebug() << "Cannot find the htdig configuration file" << endl;
00172 return;
00173 }
00174 }
00175
00176 QString savedir = kapp->dirs()->saveLocation("data", "kdevdocumentation/search");
00177 if (!d.exists(savedir))
00178 d.mkdir(savedir);
00179
00180 QString query = QString("words=%1;method=%2;matchesperpage=%3;format=%4;sort=%5")
00181 .arg(m_edit->text())
00182 .arg(m_searchMethodBox->currentItem()==1? "or" : "and")
00183 .arg(50)
00184 .arg("builtin-short")
00185 .arg(m_sortMethodBox->currentItem()==2? "date" : m_sortMethodBox->currentItem()==1? "title" : "score");
00186
00187 kdDebug(9002) << "starting kprocess" << endl;
00188 kdDebug(9002) << "htdig line:" << exe << " -c " << (indexdir + "/htdig.conf ") << query << endl;
00189 KProcess *proc = new KProcess;
00190 QString picdir = kapp->dirs()->findResourceDir("data", "kdevdocumentation/pics/htdig.png");
00191 proc->setEnvironment("PICDIR", picdir);
00192 *proc << exe << "-c" << (indexdir + "/htdig.conf") << query;
00193
00194 connect( proc, SIGNAL(receivedStdout(KProcess *,char*,int)),
00195 this, SLOT(htsearchStdout(KProcess *,char*,int)) );
00196 connect( proc, SIGNAL(processExited(KProcess *)),
00197 this, SLOT(htsearchExited(KProcess *)) );
00198
00199 searchResult = "";
00200
00201 if (!proc->start(KProcess::NotifyOnExit, KProcess::Stdout))
00202 {
00203 KMessageBox::error(this, i18n("Cannot start the htsearch executable."));
00204 kdDebug() << "process start failed" << endl;
00205 delete proc;
00206 return;
00207 }
00208
00209
00210
00211
00212 kapp->setOverrideCursor(waitCursor);
00213 QWidget blocker(0, 0, WType_Dialog | WShowModal);
00214 qt_enter_modal(&blocker);
00215 kapp->enter_loop();
00216 qt_leave_modal(&blocker);
00217 kapp->restoreOverrideCursor();
00218
00219 if (!proc->normalExit() || proc->exitStatus() != 0)
00220 {
00221 kdDebug() << "Error running htsearch... returning now" << endl;
00222 delete proc;
00223 return;
00224 }
00225
00226 delete proc;
00227
00228
00229 searchResult = searchResult.replace(QRegExp("http://localhost/"), "file:/");
00230 searchResult = searchResult.replace(QRegExp("Content-type: text/html"), "");
00231
00232
00233 QFile f(savedir + "/results.html");
00234 if (f.open(IO_WriteOnly))
00235 {
00236 QTextStream ts(&f);
00237 ts << searchResult << endl;
00238 f.close();
00239 }
00240
00241
00242 analyseSearchResults();
00243
00244 }
00245
00246 void SearchView::htsearchStdout(KProcess *, char *buffer, int len)
00247 {
00248 searchResult += QString::fromLocal8Bit(buffer, len);
00249 }
00250
00251 void SearchView::htsearchExited(KProcess *)
00252 {
00253 kapp->exit_loop();
00254 }
00255
00256 void SearchView::analyseSearchResults()
00257 {
00258 m_view->clear();
00259 QTextStream str(searchResult, IO_ReadOnly);
00260 DocumentationItem *former = 0;
00261 while (!str.eof())
00262 {
00263 QString line = str.readLine();
00264
00265 QRegExp starsExp("alt=\"\\*\"");
00266 starsExp.setMinimal(true);
00267 int stars = line.contains(starsExp);
00268
00269 QRegExp urlExp("<strong><a href=\"(.*)\">(.*)</a></strong>");
00270 if (urlExp.search(line)==-1)
00271 continue;
00272 QString url = urlExp.cap(1);
00273 QString title = urlExp.cap(2);
00274
00275 QString starsStr;
00276 for (int i = 0; i < stars; ++i)
00277 starsStr += "*";
00278
00279 if (former)
00280 former = new DocumentationItem(DocumentationItem::Document, m_view, former, starsStr);
00281 else
00282 former = new DocumentationItem(DocumentationItem::Document, m_view, starsStr);
00283 former->setText(1, title);
00284 former->setURL(KURL(url));
00285 }
00286 }
00287
00288 void SearchView::executed(QListViewItem *item)
00289 {
00290 DocumentationItem *d = dynamic_cast<DocumentationItem*>(item);
00291 if (!d)
00292 return;
00293
00294 m_part->partController()->showDocument(d->url());
00295 }
00296
00297 void SearchView::itemMouseButtonPressed(int button, QListViewItem *item, const QPoint &pos, int c)
00298 {
00299 if ((button != Qt::RightButton) || (!item))
00300 return;
00301 DocumentationItem *docItem = dynamic_cast<DocumentationItem*>(item);
00302 if (!docItem)
00303 return;
00304
00305 DocUtils::docItemPopup(m_part, docItem, pos, true, false, 1);
00306 }
00307
00308 void SearchView::setSearchTerm(const QString &term)
00309 {
00310 m_edit->setText(term);
00311 }
00312
00313 void SearchView::askSearchTerm()
00314 {
00315 m_edit->setFocus();
00316 }
00317
00318 void SearchView::focusInEvent(QFocusEvent *)
00319 {
00320 m_edit->setFocus();
00321 }
00322
00323 #include "searchview.moc"