/*************************************************************************** * Copyright (C) 1999-2001 by Matthias Hoelzer-Kluepfel * * hoelzer@kde.org * * Copyright (C) 2001 by Bernd Gehrmann * * bernd@kdevelop.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 #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #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 TDEListView(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, TQ_SIGNAL(clicked()), this, TQ_SLOT(updateConfig())); connect(m_indexButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(updateIndex())); connect(m_edit, TQ_SIGNAL(returnPressed()), this, TQ_SLOT(search())); connect(m_goSearchButton, TQ_SIGNAL(clicked()), this, TQ_SLOT(search())); connect(m_view, TQ_SIGNAL(executed(TQListViewItem*)), this, TQ_SLOT(executed(TQListViewItem*))); connect(m_view, TQ_SIGNAL(mouseButtonPressed(int, TQListViewItem*, const TQPoint&, int )), this, TQ_SLOT(itemMouseButtonPressed(int, TQListViewItem*, const TQPoint&, int ))); } SearchView::~SearchView() { } void SearchView::updateConfig() { runHtdig("-c"); } void SearchView::updateIndex() { runHtdig("-i"); TDEConfig *config = m_part->config(); config->setGroup("htdig"); config->writeEntry("IsSetup", true); config->sync(); } void SearchView::runHtdig(const TQString &arg) { TDEProcess proc; proc << "tdevelop-htdig" << arg; proc.start(TDEProcess::DontCare); } void tqt_enter_modal(TQWidget *widget); void tqt_leave_modal(TQWidget *widget); void SearchView::search() { TDEConfig *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 TDevelop to perform full text search. Please install ht://Dig and use Documentation page in Configure TDevelop 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 tdeprocess" << endl; kdDebug(9002) << "htdig line:" << exe << " -c " << (indexdir + "/htdig.conf ") << query << endl; TDEProcess *proc = new TDEProcess; TQString picdir = kapp->dirs()->findResourceDir("data", "kdevdocumentation/pics/htdig.png"); proc->setEnvironment("PICDIR", picdir); *proc << exe << "-c" << (indexdir + "/htdig.conf") << query; connect( proc, TQ_SIGNAL(receivedStdout(TDEProcess *,char*,int)), this, TQ_SLOT(htsearchStdout(TDEProcess *,char*,int)) ); connect( proc, TQ_SIGNAL(processExited(TDEProcess *)), this, TQ_SLOT(htsearchExited(TDEProcess *)) ); searchResult = ""; if (!proc->start(TDEProcess::NotifyOnExit, TDEProcess::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); tqt_enter_modal(&blocker); kapp->enter_loop(); tqt_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(TDEProcess *, char *buffer, int len) { searchResult += TQString::fromLocal8Bit(buffer, len); } void SearchView::htsearchExited(TDEProcess *) { 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("(.*)"); 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(item); if (!d) return; m_part->partController()->showDocument(d->url()); } void SearchView::itemMouseButtonPressed(int button, TQListViewItem *item, const TQPoint &pos, int // c ) { if ((button != TQt::RightButton) || (!item)) return; DocumentationItem *docItem = dynamic_cast(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"