//--------------------------------------------------------------------------- #include #pragma hdrstop #include "TntSystem.hpp" #include "searchfrm.h" #include #include "mainfrm.h" #include #include "RangeMaintFrm.h" //#include #include #include "rtfhintfrm.h" #include #include "vrslstfrm.h" //--------------------------------------------------------------------------- #pragma resource "*.dfm" TsearchForm *searchForm; //--------------------------------------------------------------------------- __fastcall TsearchForm::TsearchForm(TComponent* Owner) : TForm(Owner) { initializing = true; pvrtf = new TRxRichEditX(this); pvrtf->Parent = plPreview; pvrtf->Align = alClient; pvrtf->ScrollBars = ssVertical; pvrtf->ReadOnly = true; // pvrtf->PopupMenu = PopupMenu2; // SearchText = 0; // if (!SearchText) { SearchTextOld->Visible = false; SearchText = new TTntComboBox(this); SearchText->Parent = Panel3; SearchText->Align = alClient; SearchText->ParentFont = false; SearchText->Font->Size = 12; // } // mod->Disp(*displays.insert(displays.begin(), new RTFDisp(newrtf))); // mod->setKey(DefaultVSKey); // return 0; target = 0; } //--------------------------------------------------------------------------- void __fastcall TsearchForm::searchBtnClick(TObject *Sender) { // ModMap::iterator target; class TWaitCursor { public: TWaitCursor() : oldc(Screen->Cursor) { Screen->Cursor = crHourGlass; } ~TWaitCursor() { Screen->Cursor = oldc; } private: TCursor oldc; } wait; // show hourglass if (!SearchText->Text.Length()) return; int index = SearchText->Items->IndexOf(SearchText->Text); SearchText->Items->Insert(0, SearchText->Text); if (index >= 0) SearchText->Items->Delete(index+1); SearchText->ItemIndex = 0; Caption = ""; if (target) { AnsiString cap = _tr("Searching"); cap += (AnsiString)" [ " + (AnsiString)target->Description() + (AnsiString)" (" + (AnsiString)target->Name() + (AnsiString)") ]..."; Caption = UTF8Decode(cap); resultsLV->Items->Clear(); int searchType; switch (searchTypeGroup->ItemIndex) { case 0: searchType = -2; break; case 1: searchType = -1; break; case 2: searchType = 0; break; case 3: searchType = -4; break; } int searchOptions = (caseSensitiveCkBx->Checked) ? 0 : REG_ICASE; SWKey *scope = 0; switch (scopeGroup->ItemIndex) { case 2: if (ComboBox1->ItemIndex < 0) results = VerseKey().ParseVerseList(ComboBox1->Text.c_str(), "", true); else { TCustomRange *rs = (TCustomRange *)ComboBox1->Items->Objects[ComboBox1->ItemIndex]; results = VerseKey().ParseVerseList(rs->text.c_str(), "", true); } case 1: if (!results.Count()) return; scope = &results; break; } searchBtn->Caption = _tr("Halt"); searchBtn->OnClick = TerminateSearch; searchThread = new TSearchThread(this, UTF8Encode(SearchText->Text).c_str(), searchType, searchOptions, scope); } else Caption = "Error finding target module"; } void __fastcall TsearchForm::TerminateSearch(TObject *Sender) { target->terminateSearch = true; } //--------------------------------------------------------------------------- void __fastcall TsearchForm::ListBox1DblClick(TObject *Sender) { if (!resultsLV->Items->Count) return; // assert items in list view TListItem *focused = resultsLV->ItemFocused; if (focused) { int row = focused->Index; SWKey *key = (SWKey *)*target; (*key) = UTF8Encode(resultsLV->Items->Item[row]->Caption).c_str(); if (targetpc == Form1->LexDictPageControl) { // Form1->DictKeyEdit->Text = UTF8Decode(resultsLV->Items->Item[row]->Caption.c_str()); Form1->DictKeyEdit->Text = UTF8Encode(resultsLV->Items->Item[row]->Caption).c_str(); } else { Form1->TextKeyChanged(); } } } //--------------------------------------------------------------------------- void __fastcall TsearchForm::ListBox1Click(TObject *Sender) { if (!resultsLV->Items->Count) return; // assert items in list view if (target) { TListItem *focused = resultsLV->ItemFocused; if (focused) { int row = focused->Index; ListKey verse; SWKey *key = target->CreateKey(); *key = UTF8Encode(resultsLV->Items->Item[row]->Caption).c_str(); verse << *key; delete key; pvrtf->fillWithVerses(target, &verse, 0, true, false, "Search"); } } } //--------------------------------------------------------------------------- __fastcall TsearchForm::TSearchThread::TSearchThread(TsearchForm *parent, SWBuf searchText, int searchType, int searchOptions, SWKey *scope, bool CreateSuspended) : TThread(CreateSuspended) { this->parent = parent; this->searchText = searchText; this->searchType = searchType; this->searchOptions = searchOptions; this->scope = scope; Priority = tpNormal; FreeOnTerminate = true; } void __fastcall TsearchForm::TSearchThread::updateProgressBar(void) { parent->progressBar->Position = parent->status; parent->progressBar->Repaint(); } void __fastcall TsearchForm::TSearchThread::updateStatus(void) { Synchronize((TThreadMethod)&updateProgressBar); } void TsearchForm::TSearchThread::searchProgressCallback(char status, void *searchThread) { TsearchForm::TSearchThread *thread = (TsearchForm::TSearchThread *)searchThread; thread->parent->status = status; thread->updateStatus(); } void __fastcall TsearchForm::TSearchThread::FillListBox(void) { TListItem *pItem; SWKey *savekey = (SWKey *)*(parent->target); SWKey origKeyVal = *savekey; if (!savekey->Persist()) { savekey = 0; } for (results = TOP; !results.Error(); results++) { parent->target->setKey(results); pItem = parent->resultsLV->Items->Add(); pItem->Caption = UTF8Decode((const char *)results); pItem->SubItems->Add(""); // pItem->SubItems->Add((*parent->target).second->StripText()); // pItem = resultsLV->Items->Add( } if (savekey) parent->target->setKey(*savekey); else parent->target->setKey(origKeyVal); //remove our persist key // ListBox1->Items->Pack(); // so Count is set correctly (per helpfile) AnsiString cap = ((AnsiString)parent->resultsLV->Items->Count + (AnsiString)" " + (AnsiString)((parent->resultsLV->Items->Count == 1) ? _tr("match") : _tr("matches"))) + (AnsiString)" from [ " + (AnsiString)parent->target->Description() + (AnsiString)" (" + (AnsiString)parent->target->Name() + (AnsiString)") ]"; parent->Caption = UTF8Decode(cap); parent->searchBtn->Caption = _tr("Search"); parent->searchBtn->OnClick = parent->searchBtnClick; parent->progressBar->Position = 0; } void __fastcall TsearchForm::TSearchThread::Execute() { results = parent->target->search(searchText.c_str(), searchType, searchOptions, scope, 0, searchProgressCallback, this); // let's make some intuitive decisions on when to sort by score for clucene searches bool sortByScore = ((searchType == -4) // lucene && (results.Count() > 100) && (strchr(searchText.c_str(), ' ')) && (!strchr(searchText.c_str(), '+')) && (!strchr(searchText.c_str(), '\"')) && (!strchr(searchText.c_str(), '~')) ); if ((searchType == -4) && (!sortByScore)) // resort clucene search results if necessary results.sort(); Synchronize((TThreadMethod)&FillListBox); parent->results = results; } void __fastcall TsearchForm::scopeGroupClick(TObject *Sender) { bool enabled = (scopeGroup->ItemIndex == 2); customRangeBtn->Enabled = enabled; ComboBox1->Enabled = enabled; } //--------------------------------------------------------------------------- void __fastcall TsearchForm::customRangeBtnClick(TObject *Sender) { RangeMaintForm->ShowModal(); populateRanges(); } //--------------------------------------------------------------------------- void TsearchForm::populateRanges() { ConfigEntMap::iterator loop, end; SWConfig config("./options.conf"); ComboBox1->Clear(); loop = config.Sections["CustomRanges"].begin(); end = config.Sections["CustomRanges"].end(); while (loop != end) { TCustomRange *rs = new TCustomRange(loop->first.c_str(), loop->second.c_str()); ComboBox1->Items->AddObject(UTF8Decode(rs->name.c_str()), rs); loop++; } } void __fastcall TsearchForm::FormShow(TObject *Sender) { populateRanges(); fillList(); Button1Click(0); //initially hide the modSelect sidebar } //--------------------------------------------------------------------------- void __fastcall TsearchForm::resultsLVChange(TObject *Sender, TListItem *Item, TItemChange Change) { ListBox1Click(Sender); } //--------------------------------------------------------------------------- void __fastcall TsearchForm::resultsLVCustomDrawItem(TCustomListView *Sender, TListItem *Item, TCustomDrawState State, bool &DefaultDraw) { if (target && !Form1->closing) { TRect rect = Item->DisplayRect(drSelectBounds); static UnicodeRTF filter; SWBuf buf; buf = UTF8Encode(Item->Caption).c_str(); SWKey *key = *target; // if (!SWDYNAMIC_CAST(VerseKey, key)) filter.processText(buf, *target, target); RTFHintForm->searchListDrawer->fillWithRTFString(target, ((String)" \\b " + buf.c_str() + " ").c_str(), "Search"); if (resultsLV->Selected == Item) RTFHintForm->searchListDrawer->Color = TColor(0xB4CDBB); Sender->Canvas->Brush->Color = RTFHintForm->searchListDrawer->Color; Sender->Canvas->FillRect(rect); rect.Right = resultsLV->Column[0]->Width; RTFHintForm->searchListDrawer->paintTo(Sender->Canvas->Handle, &rect, 0); ListKey verse; verse << Item->Caption.c_str(); RTFHintForm->searchListDrawer->fillWithVerses(target, &verse, 0, false, false, "Search", true); //set color back in case it got changed in fill* if (resultsLV->Selected == Item) RTFHintForm->searchListDrawer->Color = TColor(0xB4CDBB); RTFHintForm->searchListDrawer->SelStart = 3; RTFHintForm->searchListDrawer->SelLength = 1; double textHeight = RTFHintForm->searchListDrawer->SelAttributes->Height; double multiplier = 1.2; textHeight *= multiplier; int textWithMargin = 3 + textHeight; if (resultsLV->StateImages->Height < textWithMargin) { resultsLV->StateImages->Height = textWithMargin; DefaultDraw = false; return; } RTFHintForm->searchListDrawer->SelLength = 0; rect = Item->DisplayRect(drSelectBounds); rect.Left = rect.Left + resultsLV->Column[0]->Width;// + 5; RTFHintForm->searchListDrawer->paintTo(Sender->Canvas->Handle, &rect, 0); } DefaultDraw = false; } //--------------------------------------------------------------------------- void __fastcall TsearchForm::resultsLVInfoTip(TObject *Sender, TListItem *Item, AnsiString &InfoTip) { InfoTip = ""; } //--------------------------------------------------------------------------- void __fastcall TsearchForm::Button1Click(TObject *Sender) { bool newVisible = !pnlChooseMod->Visible; ChooseModSplitter->Visible = newVisible; pnlChooseMod->Visible = newVisible; } //--------------------------------------------------------------------------- void __fastcall TsearchForm::FormActivate(TObject *Sender) { if (!Form1->closing) { Mouse->Capture = 0; if (searchBtn->OnClick != TerminateSearch) { TPageControl *targetpc = Form1->TextPageControl; if ((Form1->ActiveControl == Form1->CommentaryPageControl) || (IsChild(Form1->CommentaryPageControl->Handle, Form1->ActiveControl->Handle))) targetpc = Form1->CommentaryPageControl; if ((Form1->ActiveControl == Form1->LexDictPageControl) || (IsChild(Form1->LexDictPageControl->Handle, Form1->ActiveControl->Handle))) targetpc = Form1->LexDictPageControl; if (targetpc->ActivePage->Caption == "PARALLEL") { SWModule *mod = Form1->parallelDisp->getModules()[0]; if (mod) { setTarget(mod); } } else { ModMap::iterator it = Form1->mainmgr->Modules.find(targetpc->ActivePage->Caption.c_str()); if (it != Form1->mainmgr->Modules.end()) { setTarget(it->second); } } SearchText->SetFocus(); } } initializing = false; } void TsearchForm::setTarget(SWModule *itarget) { bool diffTarget = target != itarget; target = itarget; AnsiString cap = target->Description() + (AnsiString) " (" + target->Name() + ")"; moduleName->Caption = UTF8Decode(cap); RTFHintForm->searchListDrawer->fillWithRTFString(target, "yoyo"); SearchText->Font->Name = RTFHintForm->searchListDrawer->dispAttribs.fontName; // SearchText->Font->Size = RTFHintForm->searchListDrawer->dispAttribs.fontSize; resultsLV->StateImages->Height = 1; // search framework stuff if (target->hasSearchFramework() && target->isSearchOptimallySupported("God", -4, 0, 0)) { searchTypeGroup->Items->CommaText = _tr("\"Multi Word\",\"Phrase\",\"Regular Expression\",\"Optimized Search\""); if (diffTarget) { searchTypeGroup->ItemIndex = 3; } toggleIndexBtn->Caption = _tr("Delete Index"); indexStatus->Caption = _tr("Using Indexed Searching Framework For This Book"); toggleIndexBtn->Enabled = true; usingSearchFramework = true; } else { usingSearchFramework = false; searchTypeGroup->Items->CommaText = _tr("\"Multi Word\",\"Phrase\",\"Regular Expression\""); if (diffTarget) { searchTypeGroup->ItemIndex = 0; } toggleIndexBtn->Caption = _tr("Create Index"); indexStatus->Caption = _tr("Not Using Indexed Searching Framework For This Book"); if (!target->isSearchOptimallySupported("God", -4, 0, 0)) { toggleIndexBtn->Enabled = true; } } } //--------------------------------------------------------------------------- void TsearchForm::fillList() { BibleCSMGR *manager; ModMap::iterator mods; TTreeNode *node; SWBuf nodeName; manager = Form1->mainmgr; modTreeView->Items->Clear(); if (!manager->configPath) return; for (mods = manager->Modules.begin(); mods != manager->Modules.end(); mods++) { // assert our module is not hidden ConfigEntMap *section; section = &(*Form1->layoutconf)["TextView"]; if (!strncmp(mods->second->Type(), "Comm", 4)) section = &(*Form1->layoutconf)["CommentView"]; else if (!strncmp(mods->second->Type(), "Lexi", 4)) section = &(*Form1->layoutconf)["LDView"]; if ((*section)[mods->second->Name()] == "false") continue; for (node = modTreeView->Items->GetFirstNode(); node; node = node->getNextSibling()) { if (!strcmp(node->Text.c_str(), mods->second->Type())) { break; } } if (!node) { // Add Section if (!strncmp(mods->second->Type(), "Bibl", 4)) // If Bibles, put first in list node = modTreeView->Items->AddChildFirst(0, mods->second->Type()); else node = modTreeView->Items->AddChild(0, mods->second->Type()); } nodeName = "["; nodeName += mods->second->Name(); nodeName += "] "; nodeName += mods->second->Description(); node = modTreeView->Items->AddChildObject(node, nodeName.c_str(), mods->second->Name()); } //for (node = modTreeView->Items->GetFirstNode(); node; node = node->getNextSibling()) // node->Expand(true); node = modTreeView->Items->GetFirstNode(); if (node) node->MakeVisible(); } void __fastcall TsearchForm::modTreeViewChange(TObject *Sender, TTreeNode *Node) { BibleCSMGR *manager; ModMap::iterator mods; TTreeNode *node; SWBuf nodeName; manager = Form1->mainmgr; TTreeNode* currNode = modTreeView->Selected; AnsiString nodeSubString; AnsiString modName; for (mods = manager->Modules.begin(); mods != manager->Modules.end(); mods++) { if (currNode->Text.SubString(2, currNode->Text.Pos("]") - 2) == mods->second->Name()) { // Add Section setTarget(mods->second); } } } //--------------------------------------------------------------------------- void __fastcall TsearchForm::Button2Click(TObject *Sender) { SWBuf helpDir; ConfigEntMap::iterator it = Form1->optionsconf->Sections["Help"].find("Directory"); if (it != Form1->optionsconf->Sections["Help"].end()) helpDir = (*it).second; else helpDir = ".\\help"; SWBuf helpExe = helpDir + "\\Sword.chm::searchh.html"; if ((int)ShellExecute(this->Handle, "open", "hh", helpExe.c_str(), NULL, SW_SHOWNORMAL) < 33) { helpExe = helpDir + "\\searchh.html"; ShellExecute(this->Handle, "open", helpExe.c_str(), NULL, NULL, SW_SHOWNORMAL); } } //--------------------------------------------------------------------------- void __fastcall TsearchForm::Button3Click(TObject *Sender) { if (resultsLV->Items->Count > 0) { ListKey tmpVerseList; for (int i = 0; i < resultsLV->Items->Count; i++) { tmpVerseList << UTF8Encode(resultsLV->Items->Item[i]->Caption).c_str(); } TVerseListForm *tmpForm = new TVerseListForm(this, tmpVerseList); tmpForm->Caption = _tr("Search Verse List"); tmpForm->Show(); } } //--------------------------------------------------------------------------- void TsearchForm::searchFrameworkCreateCallback(char status, void *searchForm) { TsearchForm *form = (TsearchForm *)searchForm; form->progressBar->Position = status; form->progressBar->Repaint(); } void __fastcall TsearchForm::toggleIndexBtnClick(TObject *Sender) { if (usingSearchFramework) { if (MessageBoxW(this->WindowHandle, _tr("Delete Index? Are you sure?"), _tr("Delete Index"), MB_YESNO) == IDYES) target->deleteSearchFramework(); } else { progressBar->Hint = "Creating Search Framework"; target->createSearchFramework(searchFrameworkCreateCallback, this); progressBar->Hint = ""; progressBar->Position = 0; } setTarget(target); } //---------------------------------------------------------------------------