From 528949c71a12f54dc7b71133a32d9ee91cb53298 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Tue, 5 Jun 2012 19:31:43 +0000 Subject: BasicHistory - the alternative for history++ git-svn-id: http://svn.miranda-ng.org/main/trunk@317 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/BasicHistory/Searcher.cpp | 388 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 388 insertions(+) create mode 100644 plugins/BasicHistory/Searcher.cpp (limited to 'plugins/BasicHistory/Searcher.cpp') diff --git a/plugins/BasicHistory/Searcher.cpp b/plugins/BasicHistory/Searcher.cpp new file mode 100644 index 0000000000..c93685bcf3 --- /dev/null +++ b/plugins/BasicHistory/Searcher.cpp @@ -0,0 +1,388 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#include "StdAfx.h" +#include "Searcher.h" +#include "resource.h" + +Searcher::Searcher() + :lastFindSelection(-1), + findBack(false), + matchCase(false), + matchWholeWords(false), + onlyIn(false), + onlyOut(false), + context(NULL) +{ +} + +void Searcher::ChangeFindDirection(bool isBack) +{ + if(isBack != findBack) + { + findBack = isBack; + ClearFind(); + TBBUTTONINFO tbInfo; + tbInfo.cbSize = sizeof(TBBUTTONINFO); + tbInfo.dwMask = TBIF_TEXT | TBIF_IMAGE; + if(isBack) + { + tbInfo.pszText = TranslateT("Find Previous"); + tbInfo.iImage = 1; + } + else + { + tbInfo.pszText = TranslateT("Find Next"); + tbInfo.iImage = 0; + } + SendMessage(context->toolbarWindow, TB_SETBUTTONINFO, (WPARAM)IDM_FIND, (LPARAM)&tbInfo); + } + + Find(); +} + +void Searcher::ClearFind() +{ + if(lastFindSelection != -1) + { + SendMessage(context->editWindow,EM_SETOPTIONS,ECOOP_AND,~ECO_NOHIDESEL); + lastFindSelection = -1; + } +} + +inline TCHAR mytoupper(TCHAR a, std::locale* loc) +{ + return std::toupper(a, *loc); +} + +bool Searcher::CompareStr(std::wstring str, TCHAR *strFind) +{ + std::locale loc; + if(!matchCase) + std::transform(str.begin(), str.end(), str.begin(), std::bind2nd(std::ptr_fun(mytoupper), &loc)); + if(!matchWholeWords) + return str.find(strFind) < str.length(); + size_t findid = str.find(strFind); + size_t findLen = _tcslen(strFind); + while(findid < str.length()) + { + if((findid == 0 || std::isspace(str[findid - 1], loc) || std::ispunct(str[findid - 1], loc)) && + (findid + findLen >= str.length() || std::isspace(str[findid + findLen], loc) || std::ispunct(str[findid + findLen], loc))) + return true; + findid = str.find(strFind, findid + 1); + } + + return false; +} + +void Searcher::Find() +{ + FINDTEXTEX ft; + TCHAR str[128]; + int curSel = 0; + bool isStart = false; + bool finished = false; + ft.chrg.cpMin = 0; + ft.chrg.cpMax = -1; + ft.lpstrText = str; + if(context->currentGroup.size() < 1) + { + SendMessage(context->editWindow,EM_SETOPTIONS,ECOOP_AND,~ECO_NOHIDESEL); + lastFindSelection = -1; + return; + } + + GetWindowText(context->findWindow, str, 128); + if(!str[0]) + { + TCHAR buf[256]; + mir_sntprintf(buf, 256, TranslateT("\"%s\" not found"), str); + MessageBox(context->hWnd, buf, TranslateT("Search"), MB_OK | MB_ICONINFORMATION); + return; + } + if(!matchCase) + { + std::locale loc; + std::transform(str, str + _tcslen(str), str, std::bind2nd(std::ptr_fun(mytoupper), &loc)); + } + + bool findBack1 = findBack ^ !searchForInMes; + bool findBack2 = findBack ^ !searchForInLG; + int adder1 = findBack1 ? -1 : 1; + int adder2 = findBack2 ? -1 : 1; + WPARAM findStyle = (findBack1 ? 0 : FR_DOWN) | (matchCase ? FR_MATCHCASE : 0) | (matchWholeWords ? FR_WHOLEWORD : 0); + if(lastFindSelection >= 0 && lastFindSelection < (int)context->currentGroup.size()) + { + if(onlyIn && context->currentGroup[lastFindSelection].isMe || onlyOut && !context->currentGroup[lastFindSelection].isMe) + { + curSel = lastFindSelection + adder1; + } + else + { + SendDlgItemMessage(context->hWnd,IDC_EDIT,EM_EXGETSEL,0,(LPARAM)&ft.chrg); + if(findBack1) + { + ft.chrg.cpMin = ft.chrg.cpMin < context->currentGroup[lastFindSelection].endPos ? ft.chrg.cpMin : context->currentGroup[lastFindSelection].endPos; + ft.chrg.cpMax = context->currentGroup[lastFindSelection].startPos; + } + else + { + ft.chrg.cpMin = ft.chrg.cpMax > context->currentGroup[lastFindSelection].startPos ? ft.chrg.cpMax : context->currentGroup[lastFindSelection].startPos; + ft.chrg.cpMax = context->currentGroup[lastFindSelection].endPos; + } + SendMessage(context->editWindow,EM_FINDTEXTEX, findStyle,(LPARAM)&ft); + if(ft.chrgText.cpMin < 0 || ft.chrgText.cpMax < 0) + { + curSel = lastFindSelection + adder1; + } + else + { + if(isFindContactChanged && startFindContact == context->hContact && isFindSelChanged && context->selected == startFindSel && ((!findBack1 && ft.chrg.cpMin >= startFindPos) || (findBack1 && ft.chrg.cpMax <= startFindPos))) + { + finished = true; + } + else + { + curSel = lastFindSelection; + SendMessage(context->editWindow,EM_EXSETSEL,0,(LPARAM)&ft.chrgText); + SendMessage(context->editWindow,EM_SETOPTIONS,ECOOP_OR,ECO_NOHIDESEL); + lastFindSelection = curSel; + return; + } + } + } + } + else + { + isStart = true; + SendMessage(context->editWindow,EM_SETOPTIONS,ECOOP_OR,ECO_NOHIDESEL); + SendMessage(context->editWindow,EM_EXGETSEL,0,(LPARAM)&ft.chrg); + startFindPos = findBack1 ? ft.chrg.cpMin : (ft.chrg.cpMax >= 0 ? ft.chrg.cpMax : ft.chrg.cpMin); + startFindSel = context->selected; + if(startFindPos < 0) + startFindPos = 0; + isFindSelChanged = false; + startFindContact = context->hContact; + isFindContactChanged = !allUsers; + if(findBack1) + for(curSel = (int)context->currentGroup.size() - 1; curSel >= 0; --curSel) + { + if(context->currentGroup[curSel].startPos < startFindPos) + break; + } + else + for(; curSel < (int)context->currentGroup.size(); ++curSel) + { + if(context->currentGroup[curSel].endPos > startFindPos) + break; + } + } + + if(!finished) + { + for(; curSel < (int)context->currentGroup.size() && curSel >= 0; curSel += adder1) + { + if(onlyIn && context->currentGroup[curSel].isMe || onlyOut && !context->currentGroup[curSel].isMe) + continue; + if(CompareStr(context->currentGroup[curSel].description, str)) + { + if(findBack1) + { + ft.chrg.cpMin = context->currentGroup[curSel].endPos; + ft.chrg.cpMax = context->currentGroup[curSel].startPos; + if(!isFindSelChanged && ft.chrg.cpMin > startFindPos) + ft.chrg.cpMin = startFindPos; + } + else + { + ft.chrg.cpMin = context->currentGroup[curSel].startPos; + ft.chrg.cpMax = context->currentGroup[curSel].endPos; + if(!isFindSelChanged && ft.chrg.cpMin < startFindPos) + ft.chrg.cpMin = startFindPos; + } + SendMessage(context->editWindow,EM_FINDTEXTEX, findStyle,(LPARAM)&ft); + if(!(ft.chrgText.cpMin < 0 || ft.chrgText.cpMax < 0)) + { + if(isFindContactChanged && startFindContact == context->hContact && isFindSelChanged && context->selected == startFindSel && ((!findBack1 && ft.chrg.cpMin >= startFindPos) || (findBack1 && ft.chrg.cpMax <= startFindPos))) + { + finished = true; + break; + } + SendMessage(context->editWindow,EM_EXSETSEL,0,(LPARAM)&ft.chrgText); + SendMessage(context->editWindow,EM_SETOPTIONS,ECOOP_OR,ECO_NOHIDESEL); + lastFindSelection = curSel; + return; + } + } + } + } + + if(isFindContactChanged && startFindContact == context->hContact && isFindSelChanged && context->selected == startFindSel) + { + finished = true; + } + + if(!finished) + { + isFindSelChanged = true; + if(onlyGroup) + { + if(IsInSel(context->selected, str)) + { + CHARRANGE ch; + ch.cpMin = ch.cpMax = findBack1 ? MAXLONG : 0; + SendMessage(context->editWindow,EM_EXSETSEL,0,(LPARAM)&ch); + lastFindSelection = findBack1 ? (int)context->currentGroup.size() - 1 : 0; + Find(); + return; + } + } + else + { + for(int sel = context->selected + adder2; ; sel += adder2) + { + if(sel < 0) + { + isFindContactChanged = true; + if(allUsers) + { + HANDLE hNext = context->hContact; + do + { + hNext = context->GetNextContact(hNext, adder2); + } + while(hNext != startFindContact && !context->SearchInContact(hNext, str, this)); + context->SelectContact(hNext); + } + + sel = (int)context->eventList.size() - 1; + } + else if(sel >= (int)context->eventList.size()) + { + isFindContactChanged = true; + if(allUsers) + { + HANDLE hNext = context->hContact; + do + { + hNext = context->GetNextContact(hNext, adder2); + } + while(hNext != startFindContact && !context->SearchInContact(hNext, str, this)); + context->SelectContact(hNext); + } + + sel = 0; + } + if(IsInSel(sel, str)) + { + LVITEM item = {0}; + item.mask = LVIF_STATE; + item.iItem = context->selected; + item.state = 0; + item.stateMask = LVIS_SELECTED; + ListView_SetItem(context->listWindow, &item); + item.iItem = sel; + item.state = LVIS_SELECTED; + ListView_SetItem(context->listWindow, &item); + ListView_EnsureVisible(context->listWindow, sel, FALSE); + CHARRANGE ch; + ch.cpMin = ch.cpMax = findBack1 ? MAXLONG : 0; + SendMessage(context->editWindow,EM_EXSETSEL,0,(LPARAM)&ch); + SendMessage(context->editWindow,EM_SETOPTIONS,ECOOP_OR,ECO_NOHIDESEL); + lastFindSelection = findBack1 ? (int)context->currentGroup.size() - 1 : 0; + isFindSelChanged = true; + Find(); + return; + } + if(startFindContact == context->hContact && sel == startFindSel) + break; + } + } + } + + if(startFindContact != context->hContact) + { + context->SelectContact(startFindContact); + } + + if(startFindSel != context->selected) + { + LVITEM item = {0}; + item.mask = LVIF_STATE; + item.iItem = context->selected; + item.state = 0; + item.stateMask = LVIS_SELECTED; + ListView_SetItem(context->listWindow, &item); + item.iItem = startFindSel; + item.state = LVIS_SELECTED; + ListView_SetItem(context->listWindow, &item); + ListView_EnsureVisible(context->listWindow, startFindSel, FALSE); + context->SelectEventGroup(startFindSel); + SendMessage(context->editWindow,EM_SETOPTIONS,ECOOP_OR,ECO_NOHIDESEL); + } + ft.chrgText.cpMin = startFindPos; + ft.chrgText.cpMax = startFindPos; + SendMessage(context->editWindow,EM_EXSETSEL,0,(LPARAM)&ft.chrgText); + SendMessage(context->editWindow,EM_SETOPTIONS,ECOOP_AND,~ECO_NOHIDESEL); + lastFindSelection = -1; + if(isStart) + { + TCHAR buf[256]; + GetWindowText(context->findWindow, str, 128); + mir_sntprintf(buf, 256, TranslateT("\"%s\" not found"), str); + MessageBox(context->hWnd, buf, TranslateT("Search"), MB_OK | MB_ICONINFORMATION); + } + else + { + MessageBox(context->hWnd, TranslateTS(onlyGroup ? LPGENT("You have reached the end of the group.") : LPGENT("You have reached the end of the history.")), TranslateT("Search"), MB_OK | MB_ICONINFORMATION); + } +} + +bool Searcher::IsInSel(int sel, TCHAR *strFind) +{ + if(sel < 0 || sel >= (int)context->eventList.size()) + return false; + + TCHAR str[MAXSELECTSTR + 8]; // for safety reason + EventList::EventData data; + for(std::deque::iterator it = context->eventList[sel].begin(); it != context->eventList[sel].end(); ++it) + { + EventList::EventIndex hDbEvent = *it; + if(context->GetEventData(hDbEvent, data)) + { + bool isMe = data.isMe; + if(onlyIn && isMe || onlyOut && !isMe) + continue; + context->GetEventMessage(hDbEvent, str); + if(CompareStr(str, strFind)) + { + return true; + } + } + } + + return false; +} + +bool Searcher::Compare(const bool isMe, const std::wstring& message, TCHAR *strFind) +{ + if(onlyIn && isMe || onlyOut && !isMe) + return false; + + return CompareStr(message, strFind); +} -- cgit v1.2.3