Bibletime – a bible study tool
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

csearchdialogpages.cpp 25KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786
  1. /*********
  2. *
  3. * This file is part of BibleTime's source code, http://www.bibletime.info/.
  4. *
  5. * Copyright 1999-2006 by the BibleTime developers.
  6. * The BibleTime source code is licensed under the GNU General Public License version 2.0.
  7. *
  8. **********/
  9. #include "csearchdialogpages.h"
  10. #include "csearchdialog.h"
  11. #include "csearchanalysis.h"
  12. #include "crangechooser.h"
  13. #include "cmoduleresultview.h"
  14. #include "csearchresultview.h"
  15. #include "cmodulechooser.h"
  16. #include "backend/cswordversekey.h"
  17. #include "backend/cdisplayrendering.h"
  18. #include "frontend/display/cdisplay.h"
  19. #include "frontend/display/creaddisplay.h"
  20. #include "util/cresmgr.h"
  21. #include "util/ctoolclass.h"
  22. //TQt includes
  23. #include <tqlayout.h>
  24. #include <tqpushbutton.h>
  25. #include <tqlabel.h>
  26. #include <tqregexp.h>
  27. #include <tqeventloop.h>
  28. //KDE includes
  29. #include <tdelocale.h>
  30. #include <kcombobox.h>
  31. #include <kiconloader.h>
  32. #include <tdemessagebox.h>
  33. #include <kprogress.h>
  34. #include <tdeapplication.h>
  35. //Lucence includes
  36. //#include "CLucene.h"
  37. //#include "CLucene/util/Reader.h"
  38. //#include "CLucene/util/Misc.h"
  39. //#include "CLucene/util/dirent.h"
  40. namespace Search {
  41. namespace Result {
  42. /********************************************
  43. ************ StrongsResulClass *************
  44. ********************************************/
  45. void StrongsResultClass::initStrongsResults(void) {
  46. using namespace Rendering;
  47. CDisplayRendering render;
  48. ListCSwordModuleInfo modules;
  49. CTextRendering::KeyTreeItem::Settings settings;
  50. TQString rText, lText, key;
  51. bool found;
  52. int sIndex;
  53. int count;
  54. int index;
  55. TQString text;
  56. modules.append(srModule);
  57. sword::ListKey& result = srModule->searchResult();
  58. count = result.Count();
  59. if (!count)
  60. return;
  61. TDEApplication::kApplication()->processEvents( 1 ); //1 ms only
  62. srList.clear();
  63. // for whatever reason the text "Parsing...translations." does not appear.
  64. // this is not critical but the text is necessary to get the dialog box
  65. // to be wide enough.
  66. KProgressDialog* progress = new KProgressDialog(0, "progressDialog", i18n("Parsing Stong's Numbers"), i18n("Parsing Stong's numbers for translations."), true);
  67. progress->setAllowCancel(false);
  68. progress->setMinimumDuration(0);
  69. progress->show();
  70. progress->raise();
  71. for (index = 0; index < count; index++){
  72. progress->progressBar()->setProgress( int( (index*100) / count ) );
  73. TDEApplication::kApplication()->processEvents( 1 ); //1 ms only
  74. key = TQString::fromUtf8(result.GetElement(index)->getText());
  75. text = render.renderSingleKey(key, modules, settings);
  76. sIndex = 0;
  77. while ((rText = getStrongsNumberText(text, &sIndex)) != "")
  78. {
  79. StrongsResultList::iterator it;
  80. found = FALSE;
  81. for ( it = srList.begin(); it != srList.end(); ++it )
  82. {
  83. lText = (*it).keyText();
  84. if (lText == rText)
  85. {
  86. found = TRUE;
  87. (*it).addKeyName(key);
  88. break;
  89. }
  90. }
  91. if (found == FALSE)
  92. srList.append( StrongsResult(rText, key) );
  93. }
  94. }
  95. delete progress;
  96. progress = 0;
  97. //qHeapSort(srList);
  98. }
  99. TQString StrongsResultClass::getStrongsNumberText(const TQString& verseContent, int *startIndex) {
  100. // get the strongs text
  101. int idx1, idx2, index;
  102. TQString sNumber, strongsText;
  103. //const bool cs = CSwordModuleSearch::caseSensitive;
  104. const bool cs = false;
  105. if (*startIndex == 0) {
  106. index = verseContent.find("<body", 0);
  107. }
  108. else {
  109. index = *startIndex;
  110. }
  111. // find all the "lemma=" inside the the content
  112. while((index = verseContent.find("lemma=", index, cs)) != -1) {
  113. // get the strongs number after the lemma and compare it with the
  114. // strongs number we are looking for
  115. idx1 = verseContent.find("\"", index) + 1;
  116. idx2 = verseContent.find("\"", idx1 + 1);
  117. sNumber = verseContent.mid(idx1, idx2 - idx1);
  118. if (sNumber == lemmaText) {
  119. // strongs number is found now we need to get the text of this node
  120. // search right until the ">" is found. Get the text from here to
  121. // the next "<".
  122. index = verseContent.find(">", index, cs) + 1;
  123. idx2 = verseContent.find("<", index, cs);
  124. strongsText = verseContent.mid(index, idx2 - index);
  125. index = idx2;
  126. *startIndex = index;
  127. return(strongsText);
  128. }
  129. else {
  130. index += 6; // 6 is the length of "lemma="
  131. }
  132. }
  133. return TQString();
  134. }
  135. /********************************************
  136. ********** CSearchDialogResultPage *********
  137. ********************************************/
  138. CSearchResultPage::CSearchResultPage(TQWidget *parent, const char *name ) :
  139. SearchResultsForm(parent, name) {
  140. initView();
  141. initConnections();
  142. }
  143. CSearchResultPage::~CSearchResultPage() {}
  144. /** Initializes the view of this widget. */
  145. void CSearchResultPage::initView() {
  146. TQVBoxLayout* frameLayout = new TQVBoxLayout(m_displayFrame, 0, 6, "frameLayout");
  147. m_previewDisplay = CDisplay::createReadInstance(0, m_displayFrame);
  148. frameLayout->addWidget(m_previewDisplay->view());
  149. }
  150. /** Sets the modules which contain the result of each. */
  151. void CSearchResultPage::setSearchResult(ListCSwordModuleInfo modules) {
  152. const TQString searchedText = CSearchDialog::getSearchDialog()->searchText();
  153. reset(); //clear current modules
  154. m_modules = modules;
  155. m_moduleListBox->setupTree(modules, searchedText);
  156. //have a Bible or commentary in the modules?
  157. bool enable = false;
  158. // for (modules.first(); !enable && modules.current(); modules.next()) {
  159. ListCSwordModuleInfo::iterator end_it = modules.end();
  160. for (ListCSwordModuleInfo::iterator it(modules.begin()); it != end_it; ++it) {
  161. if ((*it)->type() == CSwordModuleInfo::Bible ) {
  162. enable = true;
  163. break;
  164. };
  165. };
  166. m_analyseButton->setEnabled(enable);
  167. }
  168. /** Resets the current list of modules and the displayed list of found entries. */
  169. void CSearchResultPage::reset() {
  170. m_moduleListBox->clear();
  171. m_resultListBox->clear();
  172. m_previewDisplay->setText(TQString());
  173. m_analyseButton->setEnabled(false);
  174. // m_modules.setAutoDelete(false); //make sure we don't delete modules accidentally
  175. m_modules.clear();
  176. }
  177. /** Update the preview of the selected key. */
  178. void CSearchResultPage::updatePreview(const TQString& key) {
  179. using namespace Rendering;
  180. CSwordModuleInfo* module = m_moduleListBox->activeModule();
  181. if ( module ) {
  182. const TQString searchedText = CSearchDialog::getSearchDialog()->searchText();
  183. //const int searchFlags = CSearchDialog::getSearchDialog()->searchFlags();
  184. TQString text;
  185. CDisplayRendering render;
  186. ListCSwordModuleInfo modules;
  187. modules.append(module);
  188. CTextRendering::KeyTreeItem::Settings settings;
  189. //for bibles render 5 context verses
  190. if (module->type() == CSwordModuleInfo::Bible) {
  191. CSwordVerseKey vk(module);
  192. vk.Headings(1);
  193. vk.key(key);
  194. ((VerseKey*)(module->module()->getKey()))->Headings(1); //HACK: enable headings for VerseKeys
  195. //first go back and then go forward the keys to be in context
  196. vk.previous(CSwordVerseKey::UseVerse);
  197. vk.previous(CSwordVerseKey::UseVerse);
  198. //include Headings in display, they are indexed and searched too
  199. if (vk.Verse() == 1){
  200. if (vk.Chapter() == 1){
  201. vk.Chapter(0);
  202. }
  203. vk.Verse(0);
  204. }
  205. const TQString startKey = vk.key();
  206. vk.key(key);
  207. vk.next(CSwordVerseKey::UseVerse);
  208. vk.next(CSwordVerseKey::UseVerse);
  209. const TQString endKey = vk.key();
  210. settings.keyRenderingFace = CTextRendering::KeyTreeItem::Settings::CompleteShort;
  211. text = render.renderKeyRange(startKey, endKey, modules, key, settings);
  212. }
  213. //for commentaries only one verse, but with heading
  214. else if (module->type() == CSwordModuleInfo::Commentary) {
  215. CSwordVerseKey vk(module);
  216. vk.Headings(1);
  217. vk.key(key);
  218. ((VerseKey*)(module->module()->getKey()))->Headings(1); //HACK: enable headings for VerseKeys
  219. //include Headings in display, they are indexed and searched too
  220. if (vk.Verse() == 1){
  221. if (vk.Chapter() == 1){
  222. vk.Chapter(0);
  223. }
  224. vk.Verse(0);
  225. }
  226. const TQString startKey = vk.key();
  227. vk.key(key);
  228. const TQString endKey = vk.key();
  229. settings.keyRenderingFace = CTextRendering::KeyTreeItem::Settings::NoKey;
  230. text = render.renderKeyRange(startKey, endKey, modules, key, settings);
  231. }
  232. else {
  233. text = render.renderSingleKey(key, modules, settings);
  234. }
  235. m_previewDisplay->setText( highlightSearchedText(text, searchedText/*, searchFlags*/) );
  236. m_previewDisplay->moveToAnchor( CDisplayRendering::keyToHTMLAnchor(key) );
  237. }
  238. }
  239. TQStringList CSearchResultPage::QueryParser(const TQString& queryString) {
  240. TQString token;
  241. TQStringList tokenList;
  242. int cnt, pos;
  243. token = "";
  244. cnt = 0;
  245. while(cnt < queryString.length()) {
  246. // add to token
  247. if ((queryString[cnt]).isLetterOrNumber() || (queryString[cnt] == '*')) {
  248. token = token + queryString[cnt];
  249. cnt++;
  250. }
  251. // token break
  252. else if (queryString[cnt] == ' ') {
  253. token = token.stripWhiteSpace();
  254. if ((token != "*") && (token != ""))
  255. tokenList.append(token);
  256. token = "";
  257. cnt++;
  258. }
  259. // clucene appears to ignore quoted strings in the sence
  260. // that it treats all the words within quoted strings as
  261. // regular tokens and not as a single token.
  262. else if (queryString[cnt] == '"') {
  263. cnt++;
  264. }
  265. // wild card - treat as a special token break
  266. //else if (queryString[cnt] == '*') {
  267. // token = token + queryString[cnt];
  268. // token = token.stripWhiteSpace();
  269. // if ((token != "*") && (token != ""))
  270. // tokenList.append(token);
  271. // // start next token with wildcard (kin*m -> kin* *m)
  272. // token = "*";
  273. // cnt++;
  274. //}
  275. // the ! token is also a token break
  276. else if (queryString[cnt] == '!') {
  277. // store away current token
  278. token = token.stripWhiteSpace();
  279. if ((token != "*") && (token != ""))
  280. tokenList.append(token);
  281. // add the ! token
  282. tokenList.append("!");
  283. token = "";
  284. cnt++;
  285. }
  286. // the - token is also a token break
  287. else if (queryString[cnt] == '-') {
  288. // store away current token
  289. token = token.stripWhiteSpace();
  290. if ((token != "*") && (token != ""))
  291. tokenList.append(token);
  292. // add the ! token
  293. tokenList.append("-");
  294. token = "";
  295. cnt++;
  296. }
  297. // the + token is also a token break
  298. else if (queryString[cnt] == '+') {
  299. // store away current token
  300. token = token.stripWhiteSpace();
  301. if ((token != "*") && (token != ""))
  302. tokenList.append(token);
  303. // add the + token
  304. tokenList.append("+");
  305. token = "";
  306. cnt++;
  307. }
  308. // the || token is also a token break
  309. else if ((queryString[cnt] == '|') && (queryString[cnt+1] == '|')) {
  310. // store away current token
  311. token = token.stripWhiteSpace();
  312. if ((token != "*") && (token != ""))
  313. tokenList.append(token);
  314. // add the || token
  315. tokenList.append("||");
  316. token = "";
  317. cnt += 2;
  318. }
  319. // the && token is also a token break
  320. else if ((queryString[cnt] == '&') && (queryString[cnt+1] == '&')) {
  321. // store away current token
  322. token = token.stripWhiteSpace();
  323. if ((token != "*") && (token != ""))
  324. tokenList.append(token);
  325. // add the || token
  326. tokenList.append("&&");
  327. token = "";
  328. cnt += 2;
  329. }
  330. else cnt++;
  331. }
  332. token = token.stripWhiteSpace();
  333. if ((token != "*") && (token != ""))
  334. tokenList.append(token);
  335. cnt = 0;
  336. TQStringList::iterator it;
  337. for ( it = tokenList.begin(); it != tokenList.end(); it++ ) {
  338. //-----------------------------------------------------------
  339. // remove all the NOT(!) tokens - these do not need to be
  340. // highlighted in the highlighter
  341. //-----------------------------------------------------------
  342. if (((*it) == "!") || ((*it) == "NOT") || ((*it) == "-")) {
  343. it = tokenList.remove(it);
  344. if (it == tokenList.end())
  345. break;
  346. it = tokenList.remove(it);
  347. if (it == tokenList.end())
  348. break;
  349. it--;
  350. }
  351. //-----------------------------------------------------------
  352. // remove all the operator tokens - these do not need to be
  353. // highlighted in the highlighter
  354. //-----------------------------------------------------------
  355. else if ( ((*it) == "||") || ((*it) == "OR") || ((*it) == "+") ||
  356. ((*it) == "AND") || ((*it) == "&&") )
  357. {
  358. it = tokenList.remove(it);
  359. if (it == tokenList.end())
  360. break;
  361. it--;
  362. }
  363. // if the token contains a ^ then trim the remainder of the
  364. // token from the ^
  365. else if ( (pos = (*it).contains("^")) >= 0 ) {
  366. (*it) = (*it).left(pos - 1);
  367. }
  368. // if the token contains a ~ then trim the remainder of the
  369. // token from the ~
  370. else if ( (pos = (*it).contains("~")) >= 0 ) {
  371. (*it) = (*it).left(pos - 2) + "*";
  372. }
  373. }
  374. return(tokenList);
  375. }
  376. const TQString CSearchResultPage::highlightSearchedText(const TQString& content, const TQString& searchedText/*, const int searchFlags*/) {
  377. TQString ret = content;
  378. //const bool cs = (searchFlags & CSwordModuleSearch::caseSensitive);
  379. const bool cs = false;
  380. // int index = 0;
  381. int index = ret.find("<body", 0);
  382. int matchLen = 0;
  383. int length = searchedText.length();
  384. const TQString rep1("<span style=\"background-color:#FFFF66;\">");
  385. const TQString rep2("</span>");
  386. const unsigned int repLength = rep1.length() + rep1.length();
  387. int sstIndex; // strong search text index for finding "strong:"
  388. bool inQuote;
  389. TQString newSearchText;
  390. newSearchText = searchedText;
  391. //---------------------------------------------------------------------
  392. // find the strongs search lemma and highlight it
  393. //---------------------------------------------------------------------
  394. // search the searched text for "strong:" until it is not found anymore
  395. sstIndex = 0;
  396. while ((sstIndex = newSearchText.find("strong:", sstIndex)) != -1) {
  397. int idx1, idx2, sTokenIndex, sTokenIndex2;
  398. TQString sNumber, lemmaText;
  399. const TQString rep3("style=\"background-color:#FFFF66;\" ");
  400. const unsigned int rep3Length = rep3.length();
  401. int strongIndex = index;
  402. //--------------------------------------------------
  403. // get the strongs number from the search text
  404. //--------------------------------------------------
  405. // first find the first space after "strong:"
  406. // this should indicate a change in search token
  407. sstIndex = sstIndex + 7;
  408. sTokenIndex = newSearchText.find(" ", sstIndex);
  409. sTokenIndex2 = newSearchText.find("|", sstIndex);
  410. if ((sTokenIndex2 != -1) && (sTokenIndex2 < sTokenIndex)) {
  411. sNumber = newSearchText.mid(sstIndex, sTokenIndex2 - sstIndex);
  412. }
  413. else {
  414. sNumber = newSearchText.mid(sstIndex, sTokenIndex - sstIndex);
  415. }
  416. // remove this strong entry
  417. sstIndex -= 7;
  418. newSearchText.replace(sstIndex, sTokenIndex - sstIndex, "");
  419. // find all the "lemma=" inside the the content
  420. while((strongIndex = ret.find("lemma=", strongIndex, cs)) != -1) {
  421. // get the strongs number after the lemma and compare it with the
  422. // strongs number we are looking for
  423. idx1 = ret.find("\"", strongIndex) + 1;
  424. idx2 = ret.find("\"", idx1 + 1);
  425. lemmaText = ret.mid(idx1, idx2 - idx1);
  426. if (lemmaText == sNumber) {
  427. // strongs number is found now we need to highlight it
  428. // I believe the easiest way is to insert rep3 just before "lemma="
  429. ret = ret.insert(strongIndex, rep3);
  430. strongIndex += rep3Length;
  431. }
  432. strongIndex += 6; // 6 is the length of "lemma="
  433. }
  434. }
  435. //---------------------------------------------------------------------
  436. // now that the strong: stuff is out of the way continue with
  437. // other search options
  438. //---------------------------------------------------------------------
  439. //-----------------------------------------------------------
  440. // try to figure out how to use the lucene query parser
  441. //-----------------------------------------------------------
  442. //using namespace lucene::queryParser;
  443. //using namespace lucene::search;
  444. //using namespace lucene::analysis;
  445. //using namespace lucene::util;
  446. //wchar_t *buf;
  447. //char buf8[1000];
  448. //standard::WhitespaceAnalyzer analyzer;
  449. //lucene_utf8towcs(m_wcharBuffer, searchedText.utf8(), MAX_CONV_SIZE);
  450. //util::scoped_ptr<Query> q( QueryParser::parse(m_wcharBuffer, _T("content"), &analyzer) );
  451. //StringReader reader(m_wcharBuffer);
  452. //TokenStream* tokenStream = analyzer.tokenStream( _T("field"), &reader);
  453. //Token token;
  454. //while(tokenStream->next(&token) != 0) {
  455. // lucene_wcstoutf8(buf8, token.termText(), 1000);
  456. // printf("%s\n", buf8);
  457. //}
  458. //===========================================================
  459. // since I could not figure out the lucene query parser, I
  460. // made a simple parser.
  461. //===========================================================
  462. TQStringList words = QueryParser(newSearchText);
  463. for ( int wi = 0; (unsigned int)wi < words.count(); ++wi ) { //search for every word in the list
  464. TQRegExp findExp;
  465. TQString word = words[ wi ];
  466. if (word.contains("*")) {
  467. length = word.length() - 1;
  468. word.replace('*', "\\S*"); //match within a word
  469. findExp = TQRegExp(word);
  470. findExp.setMinimal(TRUE);
  471. }
  472. else {
  473. length = word.length();
  474. findExp = TQRegExp("\\b" + word + "\\b");
  475. }
  476. // index = 0; //for every word start at the beginning
  477. index = ret.find("<body", 0);
  478. findExp.setCaseSensitive(cs);
  479. //while ( (index = ret.find(findExp, index)) != -1 ) { //while we found the word
  480. while ( (index = findExp.search(ret, index)) != -1 ) { //while we found the word
  481. matchLen = findExp.matchedLength();
  482. if (!CToolClass::inHTMLTag(index, ret)) {
  483. length = matchLen;
  484. ret = ret.insert( index+length, rep2 );
  485. ret = ret.insert( index, rep1 );
  486. index += repLength;
  487. }
  488. index += length;
  489. }
  490. }
  491. //tqWarning("\n\n\n%s", ret.latin1());
  492. return ret;
  493. };
  494. /** Initializes the signal slot conections of the child widgets, */
  495. void CSearchResultPage::initConnections() {
  496. connect(m_resultListBox, TQT_SIGNAL(keySelected(const TQString&)),
  497. this, TQT_SLOT(updatePreview(const TQString&)));
  498. connect(m_moduleListBox, TQT_SIGNAL(moduleSelected(CSwordModuleInfo*)),
  499. m_resultListBox, TQT_SLOT(setupTree(CSwordModuleInfo*)));
  500. connect(m_moduleListBox, TQT_SIGNAL(moduleChanged()),
  501. m_previewDisplay->connectionsProxy(), TQT_SLOT(clear()));
  502. connect(m_analyseButton, TQT_SIGNAL(clicked()), TQT_SLOT(showAnalysis()));
  503. // connect the strongs list
  504. connect(m_moduleListBox, TQT_SIGNAL(strongsSelected(CSwordModuleInfo*, TQStringList*)),
  505. m_resultListBox, TQT_SLOT(setupStrongsTree(CSwordModuleInfo*, TQStringList*)));
  506. }
  507. /** Shows a dialog with the search analysis of the current search. */
  508. void CSearchResultPage::showAnalysis() {
  509. Analysis::CSearchAnalysisDialog dlg(m_modules, this);
  510. dlg.exec();
  511. }
  512. } //end of namespace Search.Result
  513. /*************************/
  514. namespace Options {
  515. CSearchOptionsPage::CSearchOptionsPage(TQWidget *parent, const char *name ) :
  516. SearchOptionsForm(parent,name) {
  517. initView();
  518. readSettings();
  519. }
  520. CSearchOptionsPage::~CSearchOptionsPage() {
  521. saveSettings();
  522. }
  523. /** Returns the search text set in this page. */
  524. const TQString CSearchOptionsPage::searchText() {
  525. return m_searchTextCombo->currentText();
  526. }
  527. /** Sets the search text used in the page. */
  528. void CSearchOptionsPage::setSearchText(const TQString& text) {
  529. bool found = false;
  530. int i = 0;
  531. for (i = 0; !found && i < m_searchTextCombo->count(); ++i) {
  532. if (m_searchTextCombo->text(i) == text) {
  533. found = true;
  534. }
  535. }
  536. // This is needed because in the for loop i is incremented before the comparison (++i)
  537. // As a result the index i is actually one greater than expected.
  538. i--;
  539. if (!found) {
  540. i = 0;
  541. m_searchTextCombo->insertItem( text,0 );
  542. }
  543. m_searchTextCombo->setCurrentItem(i);
  544. m_searchTextCombo->reset();
  545. m_searchTextCombo->setFocus();
  546. }
  547. /** Initializes this page. */
  548. void CSearchOptionsPage::initView() {
  549. connect( m_searchTextCombo, TQT_SIGNAL(activated( const TQString& )),
  550. m_searchTextCombo, TQT_SLOT( addToHistory( const TQString& ))
  551. );
  552. connect( m_searchTextCombo, TQT_SIGNAL(returnPressed ( const TQString& )),
  553. m_searchTextCombo, TQT_SLOT(addToHistory(const TQString&))
  554. );
  555. TQToolTip::add(m_searchTextCombo, CResMgr::searchdialog::options::searchedText::tooltip);
  556. m_syntaxButton->setIconSet(SmallIconSet("contexthelp"));
  557. connect( m_syntaxButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(syntaxHelp()));
  558. m_chooseModulesButton->setIconSet(SmallIconSet("wizard"));
  559. connect(m_chooseModulesButton, TQT_SIGNAL(clicked()),
  560. this, TQT_SLOT(chooseModules()));
  561. TQToolTip::add
  562. (m_chooseModulesButton, CResMgr::searchdialog::options::moduleChooserButton::tooltip);
  563. TQToolTip::add
  564. (m_rangeChooserCombo, CResMgr::searchdialog::options::chooseScope::tooltip);
  565. refreshRanges();
  566. m_chooseRangeButton->setIconSet(SmallIconSet("configure"));
  567. connect(m_chooseRangeButton, TQT_SIGNAL(clicked()),
  568. this, TQT_SLOT(setupRanges()));
  569. //set the initial focus
  570. m_searchTextCombo->setFocus();
  571. }
  572. /** Sets the modules used by the search. */
  573. void CSearchOptionsPage::setModules( ListCSwordModuleInfo modules ) {
  574. TQString t = i18n("Searching in: ");
  575. m_modules.clear(); //remove old modules
  576. ListCSwordModuleInfo::iterator end_it = modules.end();
  577. for (ListCSwordModuleInfo::iterator it(modules.begin()); it != end_it; ++it) {
  578. //ToDo: Check for containsRef compat
  579. if (*it == 0) { //don't operate on null modules.
  580. continue;
  581. }
  582. if ( !m_modules.contains(*it) ) {
  583. m_modules.append( *it );
  584. t.append( (*it)->name() );
  585. if (*it != modules.last()) {
  586. t += TQString::fromLatin1(", "); // so that it will become a readable list (WLC, LXX, GerLut...)
  587. }
  588. }
  589. };
  590. m_modulesLabel->setText(t);
  591. emit( sigSetSearchButtonStatus( (modules.count() != 0) ) );
  592. }
  593. /** Opens the modules chooser dialog. */
  594. void CSearchOptionsPage::chooseModules() {
  595. CModuleChooserDialog* dlg = new CModuleChooserDialog(this, modules());
  596. connect(dlg, TQT_SIGNAL(modulesChanged(ListCSwordModuleInfo)),
  597. this, TQT_SLOT(setModules(ListCSwordModuleInfo)));
  598. dlg->exec();
  599. }
  600. /** Returns the list of used modules. */
  601. const ListCSwordModuleInfo CSearchOptionsPage::modules() {
  602. return m_modules;
  603. }
  604. /** Sets all options back to the default. */
  605. void CSearchOptionsPage::reset() {
  606. m_rangeChooserCombo->setCurrentItem(0); //no scope
  607. m_searchTextCombo->clearEdit();
  608. }
  609. /** Reads the settings for the searchdialog from disk. */
  610. void CSearchOptionsPage::saveSettings() {
  611. CBTConfig::set
  612. (CBTConfig::searchCompletionTexts, m_searchTextCombo->completionObject()->items());
  613. CBTConfig::set
  614. (CBTConfig::searchTexts, m_searchTextCombo->historyItems());
  615. }
  616. /** Reads the settings of the last searchdialog session. */
  617. void CSearchOptionsPage::readSettings() {
  618. m_searchTextCombo->completionObject()->setItems( CBTConfig::get
  619. (CBTConfig::searchCompletionTexts) );
  620. m_searchTextCombo->setHistoryItems( CBTConfig::get
  621. (CBTConfig::searchTexts) );
  622. }
  623. void CSearchOptionsPage::aboutToShow() {
  624. m_searchTextCombo->setFocus();
  625. }
  626. /** No descriptions */
  627. void CSearchOptionsPage::setupRanges() {
  628. CRangeChooserDialog* chooser = new CRangeChooserDialog(this);
  629. chooser->exec();
  630. refreshRanges();
  631. }
  632. /** No descriptions */
  633. void CSearchOptionsPage::syntaxHelp() {
  634. TQString syntax = i18n (
  635. "<p>Enter search terms separated by spaces. By default the search "
  636. "function will return results that match any of the search terms (OR). "
  637. "To search for all the terms separate the terms by AND.</p>") + i18n(
  638. "<p>You can use wildcards: '*' matches any sequence of characters, "
  639. "while '?' matches any single character. The use of brackets allows you to "
  640. "group your search terms, e.g. '(Jesus OR spirit) AND God'.</p>") + i18n(
  641. "<p>To search text other than the main text, enter the text type followed "
  642. "by \":\", and then the search term. For example, to search for the Strong's "
  643. "number H8077, use 'strong:H8077'.</p>") + i18n(
  644. "<p>Available text types:<br><table>"
  645. "<tr><td>heading:</td><td>searches headings</td></tr>"
  646. "<tr><td>footnote:</td><td>searches footnotes</td></tr>"
  647. "<tr><td>strong:</td><td>searches Strong's Numbers</td></tr>"
  648. "<tr><td>morph:</td><td>searches morphology codes</td></tr></table></p>") + i18n(
  649. "<p>BibleTime uses the Lucene search engine to perform your searches. "
  650. "It has many advanced features, and you can read more about it here: "
  651. "<a href=\"http://lucene.apache.org/java/docs/queryparsersyntax.html\">"
  652. "http://lucene.apache.org/java/docs/queryparsersyntax.html</a></p>");
  653. KMessageBox::about( this, syntax, i18n("Basic Search Syntax Introduction"));
  654. }
  655. /** refreshes the listof ranges and the range combobox. */
  656. void CSearchOptionsPage::refreshRanges() {
  657. //the first two options are fixed, the others can be edited using the "Setup ranges" button.
  658. m_rangeChooserCombo->clear();
  659. m_rangeChooserCombo->insertItem(i18n("No search scope"));
  660. //m_rangeChooserCombo->insertItem(i18n("Last search result"));
  661. //insert the user-defined ranges
  662. CBTConfig::StringMap map = CBTConfig::get
  663. (CBTConfig::searchScopes);
  664. CBTConfig::StringMap::Iterator it;
  665. for (it = map.begin(); it != map.end(); ++it) {
  666. m_rangeChooserCombo->insertItem(it.key());
  667. };
  668. }
  669. /** Returns the selected search scope if a search scope was selected. */
  670. sword::ListKey CSearchOptionsPage::searchScope() {
  671. if (m_rangeChooserCombo->currentItem() > 0) { //is not "no scope"
  672. CBTConfig::StringMap map = CBTConfig::get(CBTConfig::searchScopes);
  673. TQString scope = map[ m_rangeChooserCombo->currentText() ];
  674. if (!scope.isEmpty()) {
  675. return sword::VerseKey().ParseVerseList( (const char*)scope.utf8(), "Genesis 1:1", true);
  676. }
  677. }
  678. return sword::ListKey();
  679. }
  680. /*!
  681. \fn CSearchOptionsPage::hasSearchScope()
  682. */
  683. bool CSearchOptionsPage::hasSearchScope() {
  684. return (searchScope().Count() > 0);
  685. }
  686. } //end of namespace Options
  687. } //end of namespace Search
  688. #include "csearchdialogpages.moc"