source: branches/mbutscher/work/lib/pwiki/SearchAndReplaceDialogs.py @ 431

Last change on this file since 431 was 431, checked in by mbutscher, 4 years ago

branches/mbutscher/work:

  • Fixed: Quick search window did vanish even when opening found item in background (on Windows)
  • Linux: Quick search window vanishes now when page is opened in foreground (similar but not exactly same behavior as on Windows)
File size: 92.6 KB
Line 
1# import profilehooks
2# profile = profilehooks.profile(filename="profile.prf", immediate=False)
3
4import sys, traceback, re, time
5
6import wx, wx.html, wx.xrc
7
8from rtlibRepl import minidom
9
10import Consts
11from .MiscEvent import MiscEventSourceMixin, KeyFunctionSink
12from WikiExceptions import *
13from .Utilities import DUMBTHREADSTOP, callInMainThread, callInMainThreadAsync, \
14        ThreadHolder, FunctionThreadStop
15
16from .SystemInfo import isLinux
17
18from . import wxHelper
19from wxHelper import *
20
21from .StringOps import uniToGui, guiToUni, escapeHtml
22
23from .WikiPyparsing import ParseException
24
25from .WindowLayout import setWindowPos, setWindowSize, \
26        getRelativePositionTupleToAncestor, LayeredControlPanel
27
28from .Configuration import MIDDLE_MOUSE_CONFIG_TO_TABMODE
29
30from .SearchAndReplace import SearchReplaceOperation, ListWikiPagesOperation, \
31        stripSearchString
32
33
34
35
36class _SearchResultItemInfo(object):
37    __slots__ = ("__weakref__", "wikiWord", "occCount", "occNumber", "occHtml",
38            "occPos", "html", "maxCountOccurrences")
39
40    def __init__(self, wikiWord, occPos = (-1, -1), occCount = -1,
41            maxOccCount=100):
42        self.wikiWord = wikiWord
43        if occPos[0] != -1:
44            self.occNumber = 1
45        else:
46            self.occNumber = -1  # -1: No specific occurrence
47
48        self.occHtml = u""  # HTML presentation of the occurrence
49        self.occPos = occPos  # Tuple (start, end) with position of occurrence in characters
50        self.occCount = occCount # -1: Undefined; -2: More than maxCountOccurrences
51        self.maxCountOccurrences = maxOccCount
52        self.html = None
53
54
55    def buildOccurrence(self, text, before, after, pos, occNumber, maxOccCount):
56        self.html = None
57        basum = before + after
58        self.occNumber = -1
59        self.occPos = pos
60        self.maxCountOccurrences = maxOccCount
61
62        if basum == 0:
63            # No context
64            self.occHtml = u""
65            return self
66       
67        if pos[0] is None:
68            # All occurences where deleted meanwhile dialog was open
69            self.occHtml = u""
70            self.occNumber = 0
71            self.occCount = 0
72            return self
73       
74        if pos[0] == -1:
75            # No position -> use beginning of text
76            self.occHtml = escapeHtml(text[0:basum])
77            return self
78       
79        s = max(0, pos[0] - before)
80        e = min(len(text), pos[1] + after)
81        self.occHtml = u"".join([escapeHtml(text[s:pos[0]]),
82            "<b>", escapeHtml(text[pos[0]:pos[1]]), "</b>",
83            escapeHtml(text[pos[1]:e])])
84           
85        self.occNumber = occNumber
86        return self
87
88
89    def setHtmlDirectly(self, occHtml):
90        self.occNumber = -1
91        self.occCount = -1
92        self.occHtml = occHtml
93
94
95
96    def getHtml(self):
97        if self.html is None:
98            result = [u'<table><tr><td bgcolor="#0000ff" width="6"></td>'
99                    u'<td><font color="BLUE"><b>%s</b></font>' % \
100                    escapeHtml(self.wikiWord)]
101           
102            if self.occNumber != -1:
103                stroc = [unicode(self.occNumber), u"/"]
104            else:
105                stroc = []
106               
107            if self.occCount > -1:
108                stroc.append(unicode(self.occCount))
109            elif len(stroc) > 0:
110                if self.occCount == -1:
111                    stroc.append(u"?")
112                elif self.occCount == -2:
113                    stroc.append(u">%s" % self.maxCountOccurrences)
114
115            stroc = u"".join(stroc)
116           
117            if stroc != u"":
118                result.append(u' <b>(%s)</b>' % stroc)
119               
120            if self.occHtml != u"":
121                result.append(u'<br>\n')
122                result.append(self.occHtml)
123               
124            result.append('</td></tr></table>')
125            self.html = u"".join(result)
126           
127        return self.html
128
129
130
131class SearchResultListBox(wx.HtmlListBox, MiscEventSourceMixin):
132    def __init__(self, parent, pWiki, ID):
133        wx.HtmlListBox.__init__(self, parent, ID, style = wx.SUNKEN_BORDER)
134
135        self.pWiki = pWiki
136        self.searchWikiDialog = parent
137        self.found = []
138        self.foundinfo = []
139        self.searchOp = None # last search operation set by showFound
140        self.SetItemCount(0)
141        self.isShowingSearching = False  # Show a visual feedback only while searching
142        self.contextMenuSelection = -2
143
144        wx.EVT_LEFT_DOWN(self, self.OnLeftDown)
145        wx.EVT_LEFT_DCLICK(self, self.OnLeftDown)
146        wx.EVT_MIDDLE_DOWN(self, self.OnMiddleButtonDown)
147        wx.EVT_KEY_DOWN(self, self.OnKeyDown)
148        wx.EVT_LISTBOX_DCLICK(self, ID, self.OnDClick)
149        wx.EVT_CONTEXT_MENU(self, self.OnContextMenu)
150
151
152        wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_THIS, self.OnActivateThis)
153        wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_NEW_TAB_THIS,
154                self.OnActivateNewTabThis)
155        wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_NEW_TAB_BACKGROUND_THIS,
156                self.OnActivateNewTabBackgroundThis)
157
158
159    def OnGetItem(self, i):
160        if self.isShowingSearching:
161            return u"<b>" + _(u"Searching... (click into field to abort)") + u"</b>"
162        elif self.GetCount() == 0:
163            return u"<b>" + _(u"Not found") + u"</b>"
164
165        try:
166            return self.foundinfo[i].getHtml()
167        except IndexError:
168            return u""
169
170    def showSearching(self):
171        """
172        Shows a "Searching..." as visual feedback while search runs
173        """
174        self.isShowingSearching = True
175        self.SetItemCount(1)
176        self.Refresh()
177        self.Update()
178       
179    def ensureNotShowSearching(self):
180        """
181        This function is called after a search operation and a call to
182        showFound may have happened. If it did not happen,
183        the list is cleared.
184        """
185        if self.isShowingSearching:
186            # This can only happen if showFound wasn't called
187            self.showFound(None, None, None)
188
189
190    def _displayFound(self, itemCount, threadstop):
191        """
192        Called by showFound(), must be called in main thread.
193        """
194        if threadstop.isValidThread():
195            self.SetItemCount(itemCount)
196            self.Refresh()
197
198
199    def showFound(self, sarOp, found, wikiDocument,
200            threadstop=DUMBTHREADSTOP):
201        """
202        Shows the results of search operation sarOp
203        found -- list of matching wiki words
204        wikiDocument -- WikiDocument(=WikiDataManager) object
205        """
206        if found is None or len(found) == 0:
207            self.found = []
208            self.foundinfo = []
209            self.searchOp = None
210            self.isShowingSearching = False
211            callInMainThreadAsync(self._displayFound, 1, threadstop)   # For the "Not found" entry
212        else:
213            try:
214                # Store and prepare clone of search operation
215                self.searchOp = sarOp.clone()
216                self.searchOp.replaceOp = False
217                self.searchOp.cycleToStart = True
218   
219                self.found = found
220                self.foundinfo = []
221                # Load context settings
222                before = self.pWiki.configuration.getint("main",
223                        "search_wiki_context_before")
224                after = self.pWiki.configuration.getint("main",
225                        "search_wiki_context_after")
226                       
227                countOccurrences = self.pWiki.getConfig().getboolean("main",
228                        "search_wiki_count_occurrences")
229                maxCountOccurrences = self.pWiki.getConfig().getint("main",
230                        "search_wiki_max_count_occurrences", 100)
231
232                context = before + after
233
234                if sarOp.hasParticularTextPosition():
235                    if context == 0 and not countOccurrences:
236                        # No context, no occurrence counting
237                        # -> just a list of found pages
238                        self.foundinfo = [_SearchResultItemInfo(w) for w in found]
239                    else:
240                        # "As is" or regex search
241                        sarOp.beginWikiSearch(self.pWiki.getWikiDocument())
242                        try:
243                            for w in found:
244                                threadstop.testValidThread()
245                                docPage = wikiDocument.getWikiPageNoError(w)
246                                text = docPage.getLiveTextNoTemplate()
247                                if text is None:
248                                    continue
249   
250    #                             pos = sarOp.searchText(text)
251                                pos = sarOp.searchDocPageAndText(docPage, text)
252                                if pos[0] is None:
253                                    # This can happen e.g. for boolean searches like
254                                    # 'foo or not bar' on a page which has neither 'foo'
255                                    # nor 'bar'.
256                                   
257                                    # Similar as if no particular text position available
258                                    if context == 0:
259                                        self.foundinfo.append(
260                                                _SearchResultItemInfo(w))
261                                    else:
262                                        self.foundinfo.append(
263                                                _SearchResultItemInfo(w).buildOccurrence(
264                                                text, before, after, (-1, -1), -1,
265                                                100))
266                                    continue
267                                firstpos = pos
268                               
269                                info = _SearchResultItemInfo(w, occPos=pos,
270                                        maxOccCount=maxCountOccurrences)
271   
272                                if countOccurrences:
273                                    occ = 1
274                                    while True:
275                                        pos = sarOp.searchDocPageAndText(
276                                                docPage, text, pos[1])
277                                        if pos[0] is None or pos[0] == pos[1]:
278                                            break
279                                        occ += 1
280                                        if occ > maxCountOccurrences:
281                                            occ = -2
282                                            break
283   
284                                    info.occCount = occ
285   
286                                self.foundinfo.append(info.buildOccurrence(
287                                        text, before, after, firstpos, 1,
288                                        maxCountOccurrences))
289                        finally:
290                            sarOp.endWikiSearch()
291                elif sarOp.hasWhooshHighlighting():
292                    # Index search
293                    if context == 0:
294                        # No context, occurrence counting doesn't matter
295                        # -> just a list of found pages
296                        self.foundinfo = [_SearchResultItemInfo(w) for w in found]
297                    else:
298                        sarOp.beginWikiSearch(self.pWiki.getWikiDocument())
299                        try:
300                            for w in found:
301                                threadstop.testValidThread()
302                                docPage = wikiDocument.getWikiPageNoError(w)
303                                text = docPage.getLiveTextNoTemplate()
304                                if text is None:
305                                    continue
306   
307                                html, firstPos = sarOp.highlightWhooshIndexFound(
308                                        text, docPage, before, after)
309                               
310                                info = _SearchResultItemInfo(w, occPos=(firstPos, firstPos))
311                                info.setHtmlDirectly(html)
312   
313                                self.foundinfo.append(info)
314                        finally:
315                            sarOp.endWikiSearch()
316                else:  # not sarOp.hasParticularTextPosition():
317                    # No specific position to show as context, so show beginning of page
318                    # Also, no occurrence counting possible
319                    if context == 0:
320                        self.foundinfo = [_SearchResultItemInfo(w) for w in found]
321                    else:
322                        for w in found:
323                            text = wikiDocument.getWikiPageNoError(w).\
324                                    getLiveTextNoTemplate()
325                            if text is None:
326                                continue
327                            self.foundinfo.append(
328                                    _SearchResultItemInfo(w).buildOccurrence(
329                                    text, before, after, (-1, -1), -1, 100))
330                    threadstop.testValidThread()
331               
332                threadstop.testValidThread()
333                self.isShowingSearching = False
334#                 callInMainThreadAsync(self.SetItemCount, len(self.foundinfo))
335                callInMainThreadAsync(self._displayFound, len(self.foundinfo),
336                        threadstop)
337
338            except NotCurrentThreadException:
339                self.found = []
340                self.foundinfo = []
341                self.isShowingSearching = False
342                # For the "Not found" entry
343                callInMainThreadAsync(self._displayFound, 1, threadstop)
344                raise
345
346
347    def GetSelectedWord(self):
348        sel = self.GetSelection()
349        if sel == -1 or self.GetCount() == 0:
350            return None
351        else:
352            return self.foundinfo[sel].wikiWord
353           
354    def GetCount(self):
355        return len(self.found)
356
357    def IsEmpty(self):
358        return self.GetCount() == 0
359
360
361    def _pageListFindNext(self):
362        """
363        After pressing F3 or clicking blue bar of an entry, position of
364        next found element should be shown
365        """
366        sel = self.GetSelection()
367        if sel == -1:
368            return
369       
370        info = self.foundinfo[sel]
371        if info.occPos[0] == -1 or info.occPos[1] is None:
372            return
373        if info.occNumber == -1:
374            return
375
376        before = self.pWiki.configuration.getint("main",
377                "search_wiki_context_before")
378        after = self.pWiki.configuration.getint("main",
379                "search_wiki_context_after")
380
381        maxCountOccurrences = self.pWiki.getConfig().getint("main",
382                "search_wiki_max_count_occurrences", 100)
383
384        wikiDocument = self.pWiki.getWikiDocument()
385        docPage = wikiDocument.getWikiPageNoError(info.wikiWord)
386        text = docPage.getLiveTextNoTemplate()
387        if text is not None:
388            self.searchOp.beginWikiSearch(self.pWiki.getWikiDocument())
389            try:
390#                 pos = self.searchOp.searchText(text, info.occPos[1])
391                pos = self.searchOp.searchDocPageAndText(docPage, text,
392                        info.occPos[1])
393            finally:
394                self.searchOp.endWikiSearch()
395        else:
396            pos = (-1, -1)
397
398        if pos[0] == -1:
399            # Page was changed after last search and doesn't contain any occurrence anymore
400            info.occCount = 0
401            info.buildOccurrence(text, 0, 0, pos, -1, maxCountOccurrences)
402        elif pos[0] < info.occPos[1]:
403            # Search went back to beginning, number of last occ. is also occ.count
404            info.occCount = info.occNumber
405            info.buildOccurrence(text, before, after, pos, 1,
406                    maxCountOccurrences)
407        elif info.occPos[0] == info.occPos[1]:    # pos[0] == info.occPos[1]:
408            # Match is empty
409            info.occCount = info.occNumber
410            info.buildOccurrence(text, before, after, pos, 1,
411                    maxCountOccurrences)           
412        else:
413            info.buildOccurrence(text, before, after, pos, info.occNumber + 1,
414                    maxCountOccurrences)
415
416        # TODO nicer refresh
417        self.SetSelection(-1)
418        self.SetSelection(sel)
419        self.Refresh()
420
421
422    def OnDClick(self, evt):
423        sel = self.GetSelection()
424        if sel == -1 or self.GetCount() == 0:
425            return
426
427        info = self.foundinfo[sel]
428
429        self.pWiki.openWikiPage(info.wikiWord)
430
431        editor = self.pWiki.getActiveEditor()
432        if editor is not None:
433            if info.occPos[0] != -1:
434                self.pWiki.getActiveEditor().showSelectionByCharPos(info.occPos[0],
435                        info.occPos[1])
436#                 self.pWiki.getActiveEditor().ensureSelectionExpanded()
437
438            # Works in fast search popup only if called twice
439            editor.SetFocus()
440            editor.SetFocus()
441            # Sometimes not even then
442            self.fireMiscEventKeys(("opened in foreground",))
443
444
445    def OnLeftDown(self, evt):
446        if self.isShowingSearching:
447            self.searchWikiDialog.stopSearching()
448
449        if self.GetCount() == 0:
450            return  # no evt.Skip()?
451
452        pos = evt.GetPosition()
453        hitsel = self.HitTest(pos)
454       
455        if hitsel == wx.NOT_FOUND:
456            evt.Skip()
457            return
458       
459        if pos.x < (5 + 6):
460            # Click inside the blue bar
461            self.SetSelection(hitsel)
462            self._pageListFindNext()
463            return
464       
465        evt.Skip()
466
467
468    def OnMiddleButtonDown(self, evt):
469        if self.GetCount() == 0:
470            return  # no evt.Skip()?
471
472        pos = evt.GetPosition()
473        if pos == wx.DefaultPosition:
474            hitsel = self.GetSelection()
475
476        hitsel = self.HitTest(pos)
477
478        if hitsel == wx.NOT_FOUND:
479            evt.Skip()
480            return
481
482        if pos.x < (5 + 6):
483            # Click inside the blue bar
484            self.SetSelection(hitsel)
485            self._pageListFindNext()
486            return
487       
488        info = self.foundinfo[hitsel]
489
490        if evt.ControlDown():
491            configCode = self.pWiki.getConfig().getint("main",
492                    "mouse_middleButton_withCtrl")
493        else:
494            configCode = self.pWiki.getConfig().getint("main",
495                    "mouse_middleButton_withoutCtrl")
496                   
497        tabMode = MIDDLE_MOUSE_CONFIG_TO_TABMODE[configCode]
498
499        presenter = self.pWiki.activatePageByUnifiedName(
500                u"wikipage/" + info.wikiWord, tabMode)
501       
502        if presenter is None:
503            return
504
505        if info.occPos[0] != -1:
506            presenter.getSubControl("textedit").showSelectionByCharPos(
507                    info.occPos[0], info.occPos[1])
508
509        if configCode != 1:
510            # If not new tab opened in background -> focus editor
511
512            # Works in fast search popup only if called twice
513            self.pWiki.getActiveEditor().SetFocus()
514            self.pWiki.getActiveEditor().SetFocus()
515           
516            self.fireMiscEventKeys(("opened in foreground",))
517
518       
519    def OnKeyDown(self, evt):
520        if self.GetCount() == 0:
521            return  # no evt.Skip()?
522
523        accP = getAccelPairFromKeyDown(evt)
524        matchesAccelPair = self.pWiki.keyBindings.matchesAccelPair
525       
526        if matchesAccelPair("ContinueSearch", accP):
527            # ContinueSearch is normally F3
528            self._pageListFindNext()
529        elif accP == (wx.ACCEL_NORMAL, wx.WXK_RETURN) or \
530                accP == (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_ENTER):
531            self.OnDClick(evt)
532        else:
533            evt.Skip()
534
535
536    def OnContextMenu(self, evt):
537        if self.GetCount() == 0:
538            return  # no evt.Skip()?
539
540        pos = evt.GetPosition()
541        if pos == wx.DefaultPosition:
542            hitsel = self.GetSelection()
543        else:
544            hitsel = self.HitTest(self.ScreenToClient(pos))
545
546        if hitsel == wx.NOT_FOUND:
547            evt.Skip()
548            return
549
550        self.contextMenuSelection = hitsel
551        try:
552            menu = wx.Menu()
553            appendToMenuByMenuDesc(menu, _CONTEXT_MENU_ACTIVATE)
554            self.PopupMenu(menu)
555            menu.Destroy()
556        finally:
557            self.contextMenuSelection = -2
558
559
560
561    def OnActivateThis(self, evt):
562        if self.contextMenuSelection > -1:
563            info = self.foundinfo[self.contextMenuSelection]
564
565#             presenter = self.pWiki.activateWikiWord(info.wikiWord, 0)
566            presenter = self.pWiki.activatePageByUnifiedName(
567                    u"wikipage/" + info.wikiWord, 0)
568
569            if presenter is None:
570                return
571
572            if info.occPos[0] != -1:
573                presenter.getSubControl("textedit").showSelectionByCharPos(
574                        info.occPos[0], info.occPos[1])
575   
576            # Works in fast search popup only if called twice
577            self.pWiki.getActiveEditor().SetFocus()
578            self.pWiki.getActiveEditor().SetFocus()
579           
580            # Context menu is open yet -> send later
581            wx.CallAfter(self.fireMiscEventKeys, ("opened in foreground",))
582
583
584    def OnActivateNewTabThis(self, evt):
585        if self.contextMenuSelection > -1:
586            info = self.foundinfo[self.contextMenuSelection]
587
588#             presenter = self.pWiki.activateWikiWord(info.wikiWord, 2)
589            presenter = self.pWiki.activatePageByUnifiedName(
590                    u"wikipage/" + info.wikiWord, 2)
591
592            if presenter is None:
593                return
594
595            if info.occPos[0] != -1:
596                presenter.getSubControl("textedit").showSelectionByCharPos(
597                        info.occPos[0], info.occPos[1])
598   
599            # Works in fast search popup only if called twice
600            self.pWiki.getActiveEditor().SetFocus()
601            self.pWiki.getActiveEditor().SetFocus()
602           
603            # Context menu is open yet -> send later
604            wx.CallAfter(self.fireMiscEventKeys, ("opened in foreground",))
605
606
607    def OnActivateNewTabBackgroundThis(self, evt):
608        if self.contextMenuSelection > -1:
609            info = self.foundinfo[self.contextMenuSelection]
610
611#             presenter = self.pWiki.activateWikiWord(info.wikiWord, 3)
612            presenter = self.pWiki.activatePageByUnifiedName(
613                    u"wikipage/" + info.wikiWord, 3)
614           
615            if presenter is None:
616                return
617
618            if info.occPos[0] != -1:
619                presenter.getSubControl("textedit").showSelectionByCharPos(
620                        info.occPos[0], info.occPos[1])
621
622
623class SearchPageDialog(wx.Dialog):
624    def __init__(self, mainControl, ID, title="",
625                 pos=wx.DefaultPosition, size=wx.DefaultSize,
626                 style=wx.NO_3D|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER):
627        d = wx.PreDialog()
628        self.PostCreate(d)
629
630        self.mainControl = mainControl
631
632        res = wx.xrc.XmlResource.Get()
633        res.LoadOnDialog(self, self.mainControl, "SearchPageDialog")
634
635        self.ctrls = XrcControls(self)
636
637        self.ctrls.btnClose.SetId(wx.ID_CANCEL)
638       
639        self.showExtended = True
640        self.mainSizer = self.GetSizer()
641#         self.mainSizer.Detach(self.ctrls.lbSavedSearches)
642        self.OnToggleExtended(None)
643       
644        self.firstFind = True
645        self.savedSearches = None
646
647        self._refreshSavedSearchesList()
648        self._refreshSearchHistoryCombo()
649       
650
651        # Fixes focus bug under Linux
652        self.SetFocus()
653
654        wx.EVT_BUTTON(self, GUI_ID.btnFindNext, self.OnFindNext)       
655        wx.EVT_BUTTON(self, GUI_ID.btnReplace, self.OnReplace)
656        wx.EVT_BUTTON(self, GUI_ID.btnReplaceAll, self.OnReplaceAll)
657
658        wx.EVT_BUTTON(self, GUI_ID.btnToggleExtended, self.OnToggleExtended)
659        wx.EVT_BUTTON(self, GUI_ID.btnSaveSearch, self.OnSaveSearch)
660        wx.EVT_BUTTON(self, GUI_ID.btnDeleteSearches, self.OnDeleteSearches)
661        wx.EVT_BUTTON(self, GUI_ID.btnLoadSearch, self.OnLoadSearch)
662#         wx.EVT_BUTTON(self, GUI_ID.btnLoadAndRunSearch, self.OnLoadAndRunSearch)
663
664        wx.EVT_BUTTON(self, wx.ID_CANCEL, self.OnClose)
665        wx.EVT_COMBOBOX(self, GUI_ID.cbSearch, self.OnSearchComboSelected)
666        wx.EVT_LISTBOX_DCLICK(self, GUI_ID.lbSavedSearches, self.OnLoadSearch)
667        wx.EVT_CLOSE(self, self.OnClose)
668       
669
670    def OnClose(self, evt):
671        self.mainControl.nonModalFindDlg = None
672        self.Destroy()
673
674
675    def OnToggleExtended(self, evt):
676        self.showExtended = not self.showExtended
677        winMin = self.GetMinSize()
678        winCurr = self.GetSize()
679        oldSizerMin = self.mainSizer.CalcMin()
680
681#         print "--OnToggleExtended3", repr((self.showExtended, self.mainSizer.CalcMin()))
682       
683        if not self.showExtended:
684            self.ctrls.panelSavedSearchButtons.Show(False)
685            self.mainSizer.Detach(self.ctrls.panelSavedSearchButtons)
686            self.ctrls.btnToggleExtended.SetLabel(_(u"More >>"))
687        else:
688            self.ctrls.panelSavedSearchButtons.Show(True)
689            self.mainSizer.Add(self.ctrls.panelSavedSearchButtons, (1,0), (1,2),
690                    flag=wx.ALL | wx.EXPAND | wx.ALIGN_CENTRE_VERTICAL,
691                    border=5)
692#             self.mainSizer.AddGrowableRow(1)
693            self.ctrls.btnToggleExtended.SetLabel(_(u"<< Less"))
694
695#         print "--OnToggleExtended13", repr(self.mainSizer.CalcMin())
696        self.Layout()
697
698        newSizerMin = self.mainSizer.CalcMin()
699
700        self.SetMinSize((winMin.GetWidth() - oldSizerMin.GetWidth() +
701                newSizerMin.GetWidth(),
702                winMin.GetHeight() - oldSizerMin.GetHeight() +
703                newSizerMin.GetHeight()))
704       
705        self.SetSize((winCurr.GetWidth() - oldSizerMin.GetWidth() +
706                newSizerMin.GetWidth(),
707                winCurr.GetHeight() - oldSizerMin.GetHeight() +
708                newSizerMin.GetHeight()))
709
710
711    def _buildSearchReplaceOperation(self):
712        sarOp = SearchReplaceOperation()
713        sarOp.searchStr = stripSearchString(
714                guiToUni(self.ctrls.cbSearch.GetValue()))
715        sarOp.replaceStr = guiToUni(self.ctrls.txtReplace.GetValue())
716        sarOp.replaceOp = True
717        sarOp.booleanOp = False
718        sarOp.caseSensitive = self.ctrls.cbCaseSensitive.GetValue()
719        sarOp.wholeWord = self.ctrls.cbWholeWord.GetValue()
720        sarOp.cycleToStart = False
721       
722        if self.ctrls.cbRegEx.GetValue():
723            sarOp.wildCard = 'regex'
724        else:
725            sarOp.wildCard = 'no'
726
727        sarOp.wikiWide = False
728
729        return sarOp
730
731
732    def showSearchReplaceOperation(self, sarOp):
733        """
734        Load settings from search operation into controls
735        """
736        self.ctrls.cbSearch.SetValue(uniToGui(sarOp.searchStr))
737        self.ctrls.txtReplace.SetValue(uniToGui(sarOp.replaceStr))
738        self.ctrls.cbCaseSensitive.SetValue(sarOp.caseSensitive)
739        self.ctrls.cbWholeWord.SetValue(sarOp.wholeWord)
740        self.ctrls.cbRegEx.SetValue(sarOp.wildCard == 'regex')
741
742
743
744    def buildHistoryTuple(self):
745        """
746        Build a tuple for the search history from current settings
747        """
748        return (
749                guiToUni(self.ctrls.cbSearch.GetValue()),
750                guiToUni(self.ctrls.txtReplace.GetValue()),
751                bool(self.ctrls.cbCaseSensitive.GetValue()),
752                bool(self.ctrls.cbWholeWord.GetValue()),
753                bool(self.ctrls.cbRegEx.GetValue())
754                )
755
756
757    def showHistoryTuple(self, tpl):
758        """
759        Load settings from history tuple into controls
760        """
761        self.ctrls.cbSearch.SetValue(uniToGui(tpl[0]))
762        self.ctrls.txtReplace.SetValue(uniToGui(tpl[1]))
763        self.ctrls.cbCaseSensitive.SetValue(bool(tpl[2]))
764        self.ctrls.cbWholeWord.SetValue(bool(tpl[3]))
765        self.ctrls.cbRegEx.SetValue(bool(tpl[4]))
766
767
768    def addCurrentToHistory(self):
769        tpl = self.buildHistoryTuple()
770        hist = wx.GetApp().getPageSearchHistory()
771        try:
772            pos = hist.index(tpl)
773            del hist[pos]
774            hist.insert(0, tpl)
775        except ValueError:
776            # tpl not in hist
777            hist.insert(0, tpl)
778            if len(hist) > 10:
779                hist = hist[:10]
780           
781        wx.GetApp().setPageSearchHistory(hist)
782#         self.ctrls.cbSearch.Clear()
783#         self.ctrls.cbSearch.AppendItems([tpl[0] for tpl in hist])
784
785        self.ctrls.cbSearch.Freeze()
786        try:
787            text = self.ctrls.cbSearch.GetValue()
788            self._refreshSearchHistoryCombo()
789            self.ctrls.cbSearch.SetValue(text)
790        finally:
791            self.ctrls.cbSearch.Thaw()
792
793
794    def _refreshSavedSearchesList(self):
795        wikiData = self.mainControl.getWikiData()
796        unifNames = wikiData.getDataBlockUnifNamesStartingWith(u"savedpagesearch/")
797
798        result = []
799#         suppExTypes = PluginManager.getSupportedExportTypes(mainControl,
800#                     None, continuousExport)
801
802        for un in unifNames:
803            name = un[16:]
804            content = wikiData.retrieveDataBlock(un)
805            xmlDoc = minidom.parseString(content)
806            xmlNode = xmlDoc.firstChild
807#             etype = Serialization.serFromXmlUnicode(xmlNode, u"exportTypeName")
808#             if etype not in suppExTypes:
809#                 # Export type of saved export not supported
810#                 continue
811
812            result.append((name, xmlNode))
813   
814        self.mainControl.getCollator().sortByFirst(result)
815   
816        self.savedSearches = result
817
818        self.ctrls.lbSavedSearches.Clear()
819        for search in self.savedSearches:
820            self.ctrls.lbSavedSearches.Append(uniToGui(search[0]))
821
822
823
824    def _refreshSearchHistoryCombo(self):
825        hist = wx.GetApp().getPageSearchHistory()
826        self.ctrls.cbSearch.Clear()
827        self.ctrls.cbSearch.AppendItems([tpl[0] for tpl in hist])
828
829
830    def OnDeleteSearches(self, evt):
831        sels = self.ctrls.lbSavedSearches.GetSelections()
832       
833        if len(sels) == 0:
834            return
835           
836        answer = wx.MessageBox(
837                _(u"Do you want to delete %i search(es)?") % len(sels),
838                _(u"Delete search"),
839                wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION, self)
840        if answer != wx.YES:
841            return
842
843        for s in sels:
844#             self.mainControl.getWikiData().deleteSavedSearch(self.savedSearches[s])
845            self.mainControl.getWikiData().deleteDataBlock(
846                    u"savedpagesearch/" + self.savedSearches[s][0])
847        self._refreshSavedSearchesList()
848
849
850    def OnLoadSearch(self, evt):
851        self._loadSearch()
852       
853#     def OnLoadAndRunSearch(self, evt):
854#         if self._loadSearch():
855#             try:
856#                 self._refreshPageList()
857#             except UserAbortException:
858#                 return
859#             except re.error, e:
860#                 self.displayErrorMessage(_(u'Error in regular expression'),
861#                         _(unicode(e)))
862#             except ParseException, e:
863#                 self.displayErrorMessage(_(u'Error in boolean expression'),
864#                         _(unicode(e)))
865#             except DbReadAccessError, e:
866#                 self.displayErrorMessage(_(u'Error. Maybe wiki rebuild is needed'),
867#                         _(unicode(e)))
868
869
870    def _loadSearch(self):
871        sels = self.ctrls.lbSavedSearches.GetSelections()
872       
873        if len(sels) != 1:
874            return False
875       
876        xmlNode = self.savedSearches[sels[0]][1]
877
878        sarOp = SearchReplaceOperation()
879        sarOp.serializeFromXml(xmlNode)
880        self.showSearchReplaceOperation(sarOp)
881       
882        return True
883
884
885    # TODO Store search mode
886    def OnSaveSearch(self, evt):
887        sarOp = self._buildSearchReplaceOperation()
888        try:
889            sarOp.rebuildSearchOpTree()
890        except re.error, e:
891            self.mainControl.displayErrorMessage(_(u'Error in regular expression'),
892                    _(unicode(e)))
893            return
894        except ParseException, e:
895            self.mainControl.displayErrorMessage(_(u'Error in boolean expression'),
896                    _(unicode(e)))
897            return
898
899        if len(sarOp.searchStr) > 0:
900            title = sarOp.getTitle()
901            while True:
902                title = guiToUni(wx.GetTextFromUser(_(u"Title:"),
903                        _(u"Choose search title"), title, self))
904                if title == u"":
905                    return  # Cancel
906                   
907#                 if title in self.mainControl.getWikiData().getSavedSearchTitles():
908                if (u"savedpagesearch/" + title) in self.mainControl.getWikiData()\
909                        .getDataBlockUnifNamesStartingWith(
910                        u"savedpagesearch/" + title):
911
912                    answer = wx.MessageBox(
913                            _(u"Do you want to overwrite existing search '%s'?") %
914                            title, _(u"Overwrite search"),
915                            wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION, self)
916                    if answer != wx.YES:
917                        continue
918
919#                 self.mainControl.getWikiData().saveSearch(title,
920#                         sarOp.getPackedSettings())
921
922                xmlDoc = minidom.getDOMImplementation().createDocument(None,
923                        None, None)
924                xmlNode = xmlDoc.createElement(u"savedpagesearch")
925                sarOp.serializeToXml(xmlNode, xmlDoc)
926               
927                xmlDoc.appendChild(xmlNode)
928                content = xmlDoc.toxml("utf-8")
929                xmlDoc.unlink()
930                self.mainControl.getWikiData().storeDataBlock(
931                        u"savedpagesearch/" + title, content,
932                        storeHint=Consts.DATABLOCK_STOREHINT_INTERN)
933
934                self._refreshSavedSearchesList()
935                break
936        else:
937            self.mainControl.displayErrorMessage(
938                    _(u"Invalid search string, can't save as view"))
939
940
941    def displayErrorMessage(self, errorStr, e=u""):
942        """
943        Pops up an error dialog box
944        """
945        wx.MessageBox(uniToGui(u"%s. %s." % (errorStr, e)), _(u"Error!"),
946            wx.OK, self)
947
948
949    def _nextSearch(self, sarOp):
950        editor = self.mainControl.getActiveEditor()
951        if self.ctrls.rbSearchFrom.GetSelection() == 0:
952            # Search from cursor
953            contPos = editor.getContinuePosForSearch(sarOp)
954        else:
955            # Search from beginning
956            contPos = 0
957            self.ctrls.rbSearchFrom.SetSelection(0)
958           
959        self.addCurrentToHistory()
960        start, end = editor.executeSearch(sarOp,
961                contPos)[:2]
962        if start == -1:
963            # No matches found
964            if contPos != 0:
965                # We started not at beginning, so ask if to wrap around
966                result = wx.MessageBox(_(u"End of document reached. "
967                        u"Continue at beginning?"),
968                        _(u"Continue at beginning?"),
969                        wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, self)
970                if result != wx.YES:
971                    return
972
973                start, end = editor.executeSearch(
974                        sarOp, 0)[:2]
975                if start != -1:
976                    return
977
978            # no more matches possible -> show dialog
979            wx.MessageBox(_(u"No matches found"),
980                    _(u"No matches found"), wx.OK, self)
981
982
983    def OnFindNext(self, evt):
984        if guiToUni(self.ctrls.cbSearch.GetValue()) == u"":
985            return
986
987        sarOp = self._buildSearchReplaceOperation()
988        sarOp.replaceOp = False
989        self.addCurrentToHistory()
990        try:
991            self._nextSearch(sarOp)
992            self.firstFind = False
993        except re.error, e:
994            self.displayErrorMessage(_(u'Error in regular expression'),
995                    _(unicode(e)))
996
997
998    def OnReplace(self, evt):
999        sarOp = self._buildSearchReplaceOperation()
1000#         sarOp.replaceStr = guiToUni(self.ctrls.txtReplace.GetValue())
1001#         sarOp.replaceOp = True
1002        self.addCurrentToHistory()
1003        try:
1004            self.mainControl.getActiveEditor().executeReplace(sarOp)
1005            self._nextSearch(sarOp)
1006        except re.error, e:
1007            self.displayErrorMessage(_(u'Error in regular expression'),
1008                    _(unicode(e)))
1009
1010
1011    def OnReplaceAll(self, evt):
1012        sarOp = self._buildSearchReplaceOperation()
1013#         sarOp.replaceStr = guiToUni(self.ctrls.txtReplace.GetValue())
1014#         sarOp.replaceOp = True
1015        sarOp.cycleToStart = False
1016        lastSearchPos = 0
1017        editor = self.mainControl.getActiveEditor()
1018        self.addCurrentToHistory()
1019        replaceCount = 0
1020        editor.BeginUndoAction()
1021        try:
1022            while True:
1023                nextReplacePos = editor.executeSearch(sarOp, lastSearchPos)[1]
1024                if nextReplacePos == -1:
1025                    break
1026                replaceCount += 1
1027                nextSearchPos = editor.executeReplace(sarOp)
1028                if lastSearchPos == nextReplacePos:
1029                    # Otherwise it would run infinitely
1030                    break
1031                lastSearchPos = nextSearchPos
1032        finally:
1033            editor.EndUndoAction()
1034           
1035        wx.MessageBox(_(u"%i replacements done") % replaceCount,
1036                _(u"Replace All"), wx.OK, self)
1037
1038
1039    def OnSearchComboSelected(self, evt):
1040        hist = wx.GetApp().getPageSearchHistory()
1041        self.showHistoryTuple(hist[evt.GetSelection()])
1042
1043
1044
1045class SearchWikiDialog(wx.Dialog, MiscEventSourceMixin):
1046    def __init__(self, parent, mainControl, ID, srListBox=None,
1047            allowOrdering=True, allowOkCancel=True, value=None,
1048            title="Search Wiki", pos=wx.DefaultPosition, size=wx.DefaultSize,
1049            style=wx.NO_3D|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER):
1050
1051#         _prof.start()
1052        d = wx.PreDialog()
1053        self.PostCreate(d)
1054
1055        self.mainControl = mainControl
1056
1057        res = wx.xrc.XmlResource.Get()
1058        res.LoadOnDialog(self, parent, "SearchWikiDialog")
1059        if srListBox is None:
1060            srListBox = SearchResultListBox(self, self.mainControl,
1061                    GUI_ID.htmllbPages)
1062        else:
1063            srListBox.Reparent(self)
1064
1065        res.AttachUnknownControl("htmllbPages", srListBox, self)
1066        # Necessary to workaround a bug in layout mechanism
1067        srListBox.GetGrandParent().Layout()
1068        self.ctrls = XrcControls(self)
1069
1070        self.allowOkCancel = allowOkCancel
1071        self.allowOrdering = allowOrdering
1072        if allowOkCancel:
1073            self.ctrls.btnOk.SetId(wx.ID_OK)
1074            self.ctrls.btnCancel.SetId(wx.ID_CANCEL)
1075        else:
1076            self.ctrls.btnOk.SetLabel(_(u"Close"))
1077            self.ctrls.btnOk.SetId(wx.ID_CANCEL)
1078            self.ctrls.btnCancel.Show(False)
1079
1080        currWord = self.mainControl.getCurrentWikiWord()
1081        if currWord is not None:
1082            self.ctrls.tfPageListToAdd.SetValue(uniToGui(currWord))
1083
1084        self.ctrls.cbSearch.SetWindowStyle(self.ctrls.cbSearch.GetWindowStyle()
1085                | wx.TE_PROCESS_ENTER)
1086
1087        self.listNeedsRefresh = True  # Reflects listbox content current
1088                                      # search criteria?
1089
1090        self.searchingStartTime = None
1091
1092        self.savedSearches = None
1093        self.foundPages = []
1094        self.pageListData = []
1095
1096        if not self.allowOrdering:
1097            self.ctrls.chOrdering.SetSelection(self._ORDERNAME_TO_CHOICE["no"])
1098            self.ctrls.chOrdering.Enable(False)
1099
1100        self.ctrls.rboxSearchType.EnableItem(Consts.SEARCHTYPE_INDEX,
1101                self.mainControl.getWikiDocument() is not None and \
1102                self.mainControl.getWikiDocument().isSearchIndexEnabled())
1103
1104        self._refreshSavedSearchesList()
1105        self._refreshSearchHistoryCombo()
1106
1107        if value is not None:
1108            self.showSearchReplaceOperation(value)
1109        else:
1110            config = self.mainControl.getConfig()
1111            self.ctrls.rboxSearchType.SetSelection(config.getint("main",
1112                    "search_wiki_searchType", 0))
1113            self.ctrls.cbCaseSensitive.SetValue(config.getboolean("main",
1114                    "search_wiki_caseSensitive", False))
1115            self.ctrls.cbWholeWord.SetValue(config.getboolean("main",
1116                    "search_wiki_wholeWord", False))
1117
1118            self.listPagesOperation = ListWikiPagesOperation()
1119            self._showListPagesOperation(self.listPagesOperation)
1120
1121            self.OnRadioBox(None)  # Refresh settings
1122            self._updateTabTitle()
1123
1124        # Fixes focus bug under Linux
1125        self.SetFocus()
1126        self.ctrls.cbSearch.SetFocus()
1127
1128        # Events from text search tab
1129        wx.EVT_BUTTON(self, GUI_ID.btnFindPages, self.OnSearchWiki)
1130        wx.EVT_BUTTON(self, GUI_ID.btnFindNext, self.OnFindNext)       
1131        wx.EVT_BUTTON(self, GUI_ID.btnReplace, self.OnReplace)
1132        wx.EVT_BUTTON(self, GUI_ID.btnReplaceAll, self.OnReplaceAll)
1133        wx.EVT_BUTTON(self, GUI_ID.btnSaveSearch, self.OnSaveSearch)
1134        wx.EVT_BUTTON(self, GUI_ID.btnDeleteSearches, self.OnDeleteSearches)
1135        wx.EVT_BUTTON(self, GUI_ID.btnLoadSearch, self.OnLoadSearch)
1136        wx.EVT_BUTTON(self, GUI_ID.btnLoadAndRunSearch, self.OnLoadAndRunSearch)
1137        wx.EVT_BUTTON(self, GUI_ID.btnOptions, self.OnOptions)
1138        wx.EVT_BUTTON(self, GUI_ID.btnCopyPageNamesToClipboard,
1139                self.OnCopyPageNamesToClipboard)
1140        wx.EVT_BUTTON(self, GUI_ID.btnAsResultlist, self.OnCmdAsResultlist)
1141        wx.EVT_BUTTON(self, GUI_ID.btnAsTab, self.OnCmdAsTab)
1142
1143        wx.EVT_CHAR(self.ctrls.cbSearch, self.OnCharToFind)
1144        wx.EVT_CHAR(self.ctrls.rboxSearchType, self.OnCharToFind)
1145        wx.EVT_CHAR(self.ctrls.cbCaseSensitive, self.OnCharToFind)
1146        wx.EVT_CHAR(self.ctrls.cbWholeWord, self.OnCharToFind)
1147
1148        wx.EVT_COMBOBOX(self, GUI_ID.cbSearch, self.OnSearchComboSelected)
1149        wx.EVT_LISTBOX_DCLICK(self, GUI_ID.lbSavedSearches, self.OnLoadAndRunSearch)
1150        wx.EVT_RADIOBOX(self, GUI_ID.rboxSearchType, self.OnRadioBox)
1151
1152        wx.EVT_TEXT(self, GUI_ID.cbSearch, self.OnListRefreshNeeded)
1153        wx.EVT_CHECKBOX(self, GUI_ID.cbCaseSensitive, self.OnListRefreshNeeded)
1154        wx.EVT_CHECKBOX(self, GUI_ID.cbWholeWord, self.OnListRefreshNeeded)
1155
1156
1157        # Events from page list construction tab
1158
1159        wx.EVT_TEXT(self, GUI_ID.tfSubtreeLevels, self.OnTextSubtreeLevels)
1160        wx.EVT_TEXT(self, GUI_ID.tfMatchRe, self.OnTextPageNameMatchRe)
1161
1162        wx.EVT_RADIOBUTTON(self, GUI_ID.rbPagesAll, self.OnListRefreshNeeded)
1163        wx.EVT_RADIOBUTTON(self, GUI_ID.rbPagesMatchRe, self.OnListRefreshNeeded)
1164        wx.EVT_RADIOBUTTON(self, GUI_ID.rbPagesInList, self.OnListRefreshNeeded)
1165
1166        wx.EVT_TEXT_ENTER(self, GUI_ID.tfPageListToAdd, self.OnPageListAdd)
1167        wx.EVT_BUTTON(self, GUI_ID.btnPageListUp, self.OnPageListUp)
1168        wx.EVT_BUTTON(self, GUI_ID.btnPageListDown, self.OnPageListDown)
1169        wx.EVT_BUTTON(self, GUI_ID.btnPageListSort, self.OnPageListSort)
1170
1171        wx.EVT_BUTTON(self, GUI_ID.btnPageListAdd, self.OnPageListAdd)
1172        wx.EVT_BUTTON(self, GUI_ID.btnPageListDelete, self.OnPageListDelete)
1173        wx.EVT_BUTTON(self, GUI_ID.btnPageListClearList, self.OnPageListClearList)
1174
1175        wx.EVT_BUTTON(self, GUI_ID.btnPageListCopyToClipboard,
1176                self.OnPageListCopyToClipboard)
1177
1178        wx.EVT_BUTTON(self, GUI_ID.btnPageListAddFromClipboard,
1179                self.OnPageListAddFromClipboard)
1180        wx.EVT_BUTTON(self, GUI_ID.btnPageListOverwriteFromClipboard,
1181                self.OnPageListOverwriteFromClipboard)
1182        wx.EVT_BUTTON(self, GUI_ID.btnPageListIntersectWithClipboard,
1183                self.OnPageListIntersectWithClipboard)
1184
1185        wx.EVT_BUTTON(self, GUI_ID.btnResultListPreview, self.OnResultListPreview)
1186        wx.EVT_BUTTON(self, GUI_ID.btnResultCopyToClipboard,
1187                self.OnResultCopyToClipboard)
1188
1189
1190#         wx.EVT_BUTTON(self, wx.ID_CANCEL, self.OnClose)       
1191#         wx.EVT_CLOSE(self, self.OnClose)
1192
1193        # Common events on OK, Close, Cancel
1194        wx.EVT_BUTTON(self, wx.ID_CANCEL, self.OnClose)       
1195        wx.EVT_CLOSE(self, self.OnClose)
1196        wx.EVT_BUTTON(self, wx.ID_OK, self.OnOk)
1197       
1198#         _prof.stop()
1199       
1200
1201
1202
1203    _ORDERCHOICE_TO_NAME = {
1204            0: "natural",
1205            1: "ascending",
1206            2: "asroottree",
1207            3: "no"
1208    }
1209
1210    _ORDERNAME_TO_CHOICE = {
1211            "natural": 0,
1212            "ascending": 1,
1213            "asroottree": 2,
1214            "no": 3
1215    }
1216
1217
1218    def setValue(self, value):
1219        self.value = value
1220
1221    def getValue(self):
1222        return self.value
1223
1224
1225    def displayErrorMessage(self, errorStr, e=u""):
1226        """
1227        Pops up an error dialog box
1228        """
1229        wx.MessageBox(uniToGui(u"%s. %s." % (errorStr, e)), _(u"Error!"),
1230            wx.OK, self)
1231
1232
1233    def _buildListPagesOperation(self):
1234        """
1235        Construct a ListWikiPagesOperation according to current content of the
1236        second tab of the dialog
1237        """
1238        import SearchAndReplace as Sar
1239       
1240        lpOp = Sar.ListWikiPagesOperation()
1241       
1242        if self.ctrls.rbPagesAll.GetValue():
1243            item = Sar.AllWikiPagesNode(lpOp)
1244        elif self.ctrls.rbPagesMatchRe.GetValue():
1245            pattern = self.ctrls.tfMatchRe.GetValue()
1246            try:
1247                re.compile(pattern, re.DOTALL | re.UNICODE | re.MULTILINE)
1248            except re.error, e:
1249                wx.MessageBox(_(u"Bad regular expression '%s':\n%s") %
1250                        (pattern, _(unicode(e))), _(u"Error in regular expression"),
1251                        wx.OK, self)
1252                return None
1253               
1254            item = Sar.RegexWikiPageNode(lpOp, pattern)
1255        elif self.ctrls.rbPagesInList.GetValue():
1256            try:
1257                level = int(self.ctrls.tfSubtreeLevels.GetValue())
1258                if level < 0:
1259                    raise ValueError
1260            except ValueError:
1261                level = -1
1262
1263            item = Sar.ListItemWithSubtreeWikiPagesNode(lpOp,
1264                    self.pageListData[:], level)
1265        else:
1266            return None
1267
1268        lpOp.setSearchOpTree(item)
1269        lpOp.ordering = self._ORDERCHOICE_TO_NAME[
1270                self.ctrls.chOrdering.GetSelection()]
1271
1272        return lpOp
1273
1274
1275
1276    def _buildSearchReplaceOperation(self):
1277        searchType = self.ctrls.rboxSearchType.GetSelection()
1278       
1279        sarOp = SearchReplaceOperation()
1280        sarOp.searchStr = stripSearchString(
1281                guiToUni(self.ctrls.cbSearch.GetValue()))
1282        sarOp.booleanOp = searchType == Consts.SEARCHTYPE_BOOLEANREGEX
1283       
1284        sarOp.indexSearch = 'no' if searchType != Consts.SEARCHTYPE_INDEX \
1285                else 'default'
1286        sarOp.caseSensitive = self.ctrls.cbCaseSensitive.GetValue()
1287        sarOp.wholeWord = self.ctrls.cbWholeWord.GetValue()
1288        sarOp.cycleToStart = False
1289        sarOp.wildCard = 'regex' if searchType != Consts.SEARCHTYPE_ASIS else 'no'
1290        sarOp.wikiWide = True
1291        self.listPagesOperation = self._buildListPagesOperation()
1292        sarOp.listWikiPagesOp = self.listPagesOperation
1293
1294        if not sarOp.booleanOp:
1295            sarOp.replaceStr = guiToUni(self.ctrls.txtReplace.GetValue())
1296
1297        return sarOp
1298
1299
1300    def _showListPagesOperation(self, lpOp):
1301        if lpOp is not None:
1302            item = self.listPagesOperation.searchOpTree
1303           
1304            if item.CLASS_PERSID == "AllPages":
1305                self.ctrls.rbPagesAll.SetValue(True)
1306            elif item.CLASS_PERSID == "RegexPage":
1307                self.ctrls.rbPagesMatchRe.SetValue(True)
1308                self.ctrls.tfMatchRe.SetValue(item.getPattern())
1309            elif item.CLASS_PERSID == "ListItemWithSubtreePages":
1310                self.ctrls.rbPagesInList.SetValue(True)
1311                self.pageListData = item.rootWords[:]
1312                self.ctrls.lbPageList.AppendItems(self.pageListData)
1313                if item.level == -1:
1314                    self.ctrls.tfSubtreeLevels.SetValue(u"")
1315                else:
1316                    self.ctrls.tfSubtreeLevels.SetValue(u"%i" % item.level)
1317                   
1318            self.ctrls.chOrdering.SetSelection(
1319                    self._ORDERNAME_TO_CHOICE[self.listPagesOperation.ordering])
1320           
1321            self._updateTabTitle()
1322
1323
1324    def showSearchReplaceOperation(self, sarOp):
1325        self.ctrls.cbSearch.SetValue(uniToGui(sarOp.searchStr))
1326        if sarOp.booleanOp:
1327            self.ctrls.rboxSearchType.SetSelection(Consts.SEARCHTYPE_BOOLEANREGEX)
1328        elif sarOp.indexSearch == 'default':
1329            if self.mainControl.getWikiDocument() is not None and \
1330                    self.mainControl.getWikiDocument().isSearchIndexEnabled():
1331                self.ctrls.rboxSearchType.SetSelection(Consts.SEARCHTYPE_INDEX)
1332            else:
1333                self.ctrls.rboxSearchType.SetSelection(Consts.SEARCHTYPE_BOOLEANREGEX)
1334        else:
1335            if sarOp.wildCard == 'regex':
1336                self.ctrls.rboxSearchType.SetSelection(Consts.SEARCHTYPE_REGEX)
1337            else:
1338                self.ctrls.rboxSearchType.SetSelection(Consts.SEARCHTYPE_ASIS)
1339
1340        self.ctrls.cbCaseSensitive.SetValue(sarOp.caseSensitive)
1341        self.ctrls.cbWholeWord.SetValue(sarOp.wholeWord)
1342
1343        if not sarOp.booleanOp and sarOp.replaceOp:
1344            self.ctrls.txtReplace.SetValue(uniToGui(sarOp.replaceStr))
1345
1346        self.listPagesOperation = sarOp.listWikiPagesOp
1347        self._showListPagesOperation(self.listPagesOperation)
1348
1349        self.OnRadioBox(None)  # Refresh settings
1350        self._updateTabTitle()
1351
1352
1353#     @profile
1354    def _refreshPageList(self):
1355        sarOp = self._buildSearchReplaceOperation()
1356
1357        # If allowOkCancel is True, the dialog is used to create a set of pages
1358        # so process even for an empty search string
1359        if len(sarOp.searchStr) == 0 and not self.allowOkCancel:
1360            self.foundPages = []
1361            self.ctrls.htmllbPages.showFound(None, None, None)
1362
1363            self.listNeedsRefresh = False
1364            return
1365
1366        disableSet = wxHelper.getAllChildWindows(self)
1367        disableSet.difference_update(wxHelper.getWindowParentsUpTo(
1368                self.ctrls.htmllbPages, self))
1369        disableSet = set(win for win in disableSet if win.IsEnabled())
1370
1371        self.ctrls.htmllbPages.showSearching()
1372        self.SetCursor(wx.HOURGLASS_CURSOR)
1373#         self.Freeze()
1374
1375        self.searchingStartTime = time.time()
1376
1377        if self.mainControl.configuration.getboolean("main",
1378                        "search_dontAllowCancel"):
1379            threadstop = DUMBTHREADSTOP
1380        else:
1381            threadstop = FunctionThreadStop(self._searchPoll)
1382
1383        for win in disableSet:
1384            win.Disable()
1385        try:
1386            self.foundPages = self.mainControl.getWikiDocument().searchWiki(
1387                    sarOp, self.allowOrdering, threadstop=threadstop)
1388            if not self.allowOrdering:
1389                # Use default alphabetical ordering
1390                self.mainControl.getCollator().sort(self.foundPages)
1391
1392            self.ctrls.htmllbPages.showFound(sarOp, self.foundPages,
1393                    self.mainControl.getWikiDocument(),
1394                    threadstop=threadstop)
1395
1396            self.listNeedsRefresh = False
1397
1398        except NotCurrentThreadException:
1399            raise UserAbortException()
1400        finally:
1401            self.searchingStartTime = None
1402            for win in disableSet:
1403                win.Enable()
1404
1405            # "index" option in search type was enabled by the above operation
1406            # so disable again if necessary
1407            self.ctrls.rboxSearchType.EnableItem(Consts.SEARCHTYPE_INDEX,
1408                    self.mainControl.getWikiDocument() is not None and \
1409                    self.mainControl.getWikiDocument().isSearchIndexEnabled())
1410
1411    #         self.Thaw()
1412            self.SetCursor(wx.NullCursor)
1413            self.ctrls.htmllbPages.ensureNotShowSearching()
1414
1415
1416    def _searchPoll(self):
1417        return wx.SafeYield(self, True) and self.searchingStartTime is not None
1418
1419    def stopSearching(self):
1420        self.searchingStartTime = None
1421
1422
1423    def OnOk(self, evt):
1424        self.stopSearching()
1425        val = self._buildSearchReplaceOperation()
1426        self.value = val
1427        if val is None:
1428            return
1429
1430        try:
1431            self.mainControl.nonModalWwSearchDlgs.remove(self)
1432        except ValueError:
1433            if self is self.mainControl.nonModalMainWwSearchDlg:
1434                self.mainControl.nonModalMainWwSearchDlg = None
1435
1436        if self.IsModal():
1437            self.EndModal(wx.ID_OK)
1438        else:
1439            self.Destroy()
1440#             self.fireMiscEventProps({"nonmodal closed": wx.ID_OK,
1441#                     "listWikiPagesOp": self.value})
1442
1443
1444    def OnClose(self, evt):
1445        self.stopSearching()
1446
1447        self.value = None
1448        try:
1449            self.mainControl.nonModalWwSearchDlgs.remove(self)
1450        except ValueError:
1451            if self is self.mainControl.nonModalMainWwSearchDlg:
1452                self.mainControl.nonModalMainWwSearchDlg = None
1453
1454        if self.IsModal():
1455            self.EndModal(wx.ID_CANCEL)
1456        else:
1457            self.Destroy()
1458#             self.fireMiscEventProps({"nonmodal closed": wx.ID_CANCEL,
1459#                     "listWikiPagesOp": None})
1460
1461    def OnSearchWiki(self, evt):
1462        try:
1463            self._refreshPageList()
1464            self.addCurrentToHistory()
1465            if not self.ctrls.htmllbPages.IsEmpty():
1466                self.ctrls.htmllbPages.SetFocus()
1467                self.ctrls.htmllbPages.SetSelection(0)
1468        except UserAbortException:
1469            return
1470        except re.error, e:
1471            self.displayErrorMessage(_(u'Error in regular expression'),
1472                    _(unicode(e)))
1473        except ParseException, e:
1474            self.displayErrorMessage(_(u'Error in boolean expression'),
1475                    _(unicode(e)))
1476        except DbReadAccessError, e:
1477            self.displayErrorMessage(_(u'Error. Maybe wiki rebuild is needed'),
1478                    _(unicode(e)))
1479            return
1480
1481
1482    def OnListRefreshNeeded(self, evt):
1483        self.listNeedsRefresh = True
1484        self._updateTabTitle()
1485
1486    def OnFindNext(self, evt):
1487        self._findNext()
1488
1489    def _findNext(self):
1490        if self.listNeedsRefresh:
1491            try:
1492                # Refresh list and start from beginning
1493                self._refreshPageList()
1494            except UserAbortException:
1495                return
1496            except re.error, e:
1497                self.displayErrorMessage(_(u'Error in regular expression'),
1498                        _(unicode(e)))
1499                return
1500            except ParseException, e:
1501                self.displayErrorMessage(_(u'Error in boolean expression'),
1502                        _(unicode(e)))
1503                return
1504            except DbReadAccessError, e:
1505                self.displayErrorMessage(_(u'Error. Maybe wiki rebuild is needed'),
1506                        _(unicode(e)))
1507                return
1508
1509
1510        self.addCurrentToHistory()
1511        if self.ctrls.htmllbPages.GetCount() == 0:
1512            return
1513       
1514        try:
1515            while True:           
1516                   
1517                #########self.ctrls.lb.SetSelection(self.listPosNext)
1518               
1519                wikiWord = guiToUni(self.ctrls.htmllbPages.GetSelectedWord())
1520               
1521                if not wikiWord:
1522                    self.ctrls.htmllbPages.SetSelection(0)
1523                    wikiWord = guiToUni(self.ctrls.htmllbPages.GetSelectedWord())
1524   
1525                if self.mainControl.getCurrentWikiWord() != wikiWord:
1526                    self.mainControl.openWikiPage(wikiWord)
1527                    nextOnPage = False
1528                else:
1529                    nextOnPage = True
1530   
1531                searchOp = self._buildSearchReplaceOperation()
1532                searchOp.replaceOp = False
1533                if nextOnPage:
1534                    pagePosNext = self.mainControl.getActiveEditor().executeSearch(searchOp,
1535                            -2)[1]
1536                else:
1537                    pagePosNext = self.mainControl.getActiveEditor().executeSearch(searchOp,
1538                            0)[1]
1539                   
1540                if pagePosNext != -1:
1541                    return  # Found
1542                   
1543                if self.ctrls.htmllbPages.GetSelection() == \
1544                        self.ctrls.htmllbPages.GetCount() - 1:
1545                    # Nothing more found on the last page in list, so back to
1546                    # begin of list and stop
1547                    self.ctrls.htmllbPages.SetSelection(0)
1548                    return
1549                   
1550                # Otherwise: Go to next page in list           
1551                self.ctrls.htmllbPages.SetSelection(
1552                        self.ctrls.htmllbPages.GetSelection() + 1)
1553        except re.error, e:
1554            self.displayErrorMessage(_(u'Error in regular expression'),
1555                    _(unicode(e)))
1556        except ParseException, e:
1557            self.displayErrorMessage(_(u'Error in boolean expression'),
1558                    _(unicode(e)))
1559
1560
1561
1562    def OnReplace(self, evt):
1563        sarOp = self._buildSearchReplaceOperation()
1564        sarOp.replaceOp = True
1565        try:
1566            self.mainControl.getActiveEditor().executeReplace(sarOp)
1567        except re.error, e:
1568            self.displayErrorMessage(_(u'Error in regular expression'),
1569                    _(unicode(e)))
1570            return
1571        except ParseException, e:  # Probably this can't happen
1572            self.displayErrorMessage(_(u'Error in boolean expression'),
1573                    _(unicode(e)))
1574            return
1575
1576
1577        self._findNext()
1578
1579
1580    def OnReplaceAll(self, evt):
1581        answer = wx.MessageBox(_(u"Replace all occurrences?"), _(u"Replace All"),
1582                wx.YES_NO | wx.NO_DEFAULT, self)
1583
1584        if answer != wx.YES:
1585            return
1586
1587        try:
1588            self._refreshPageList()
1589
1590            if self.ctrls.htmllbPages.GetCount() == 0:
1591                return
1592
1593            # self.pWiki.saveCurrentDocPage()
1594
1595            sarOp = self._buildSearchReplaceOperation()
1596            sarOp.replaceOp = True
1597           
1598            # wikiData = self.pWiki.getWikiData()
1599            wikiDocument = self.mainControl.getWikiDocument()
1600            self.addCurrentToHistory()
1601           
1602            replaceCount = 0
1603   
1604            for i in xrange(self.ctrls.htmllbPages.GetCount()):
1605                self.ctrls.htmllbPages.SetSelection(i)
1606                wikiWord = guiToUni(self.ctrls.htmllbPages.GetSelectedWord())
1607                wikiPage = wikiDocument.getWikiPageNoError(wikiWord)
1608                text = wikiPage.getLiveTextNoTemplate()
1609                if text is None:
1610                    continue
1611   
1612                charStartPos = 0
1613   
1614                sarOp.beginWikiSearch(self.mainControl.getWikiDocument())
1615                try:
1616                    while True:
1617                        try:
1618                            found = sarOp.searchDocPageAndText(wikiPage, text,
1619                                    charStartPos)
1620                            start, end = found[:2]
1621                        except:
1622                            # Regex error -> Stop searching
1623                            return
1624                           
1625                        if start is None: break
1626                       
1627                        repl = sarOp.replace(text, found)
1628                        text = text[:start] + repl + text[end:]  # TODO Faster?
1629                        charStartPos = start + len(repl)
1630                        replaceCount += 1
1631                        if start == end:
1632                            # Otherwise replacing would go infinitely
1633                            break
1634                finally:
1635                    sarOp.endWikiSearch()
1636
1637                wikiPage.replaceLiveText(text)
1638                   
1639            self._refreshPageList()
1640           
1641            wx.MessageBox(_(u"%i replacements done") % replaceCount,
1642                    _(u"Replace All"),
1643                wx.OK, self)       
1644        except UserAbortException:
1645            return
1646        except re.error, e:
1647            self.displayErrorMessage(_(u'Error in regular expression'),
1648                    _(unicode(e)))
1649        except ParseException, e:
1650            self.displayErrorMessage(_(u'Error in boolean expression'),
1651                    _(unicode(e)))
1652        except DbReadAccessError, e:
1653            self.displayErrorMessage(_(u'Error. Maybe wiki rebuild is needed'),
1654                    _(unicode(e)))
1655
1656
1657    def addCurrentToHistory(self):
1658        sarOp = self._buildSearchReplaceOperation()
1659        try:
1660            sarOp.rebuildSearchOpTree()
1661        except re.error:
1662            # Ignore silently
1663            return
1664        except ParseException, e:
1665            # This too
1666            return
1667
1668        data = sarOp.getPackedSettings()
1669        tpl = (sarOp.searchStr, sarOp.getPackedSettings())
1670        hist = wx.GetApp().getWikiSearchHistory()
1671        try:
1672            pos = hist.index(tpl)
1673            del hist[pos]
1674            hist.insert(0, tpl)
1675        except ValueError:
1676            # tpl not in hist
1677            hist.insert(0, tpl)
1678            if len(hist) > 10:
1679                hist = hist[:10]
1680           
1681        wx.GetApp().setWikiSearchHistory(hist)
1682        text = self.ctrls.cbSearch.GetValue()
1683        self._refreshSearchHistoryCombo()
1684#         self.ctrls.cbSearch.Clear()
1685#         self.ctrls.cbSearch.AppendItems([tpl[0] for tpl in hist])
1686        self.ctrls.cbSearch.SetValue(text)
1687
1688
1689
1690    # TODO Store search mode
1691    def OnSaveSearch(self, evt):
1692        sarOp = self._buildSearchReplaceOperation()
1693        try:
1694            sarOp.rebuildSearchOpTree()
1695        except re.error, e:
1696            self.mainControl.displayErrorMessage(_(u'Error in regular expression'),
1697                    _(unicode(e)))
1698            return
1699        except ParseException, e:
1700            self.mainControl.displayErrorMessage(_(u'Error in boolean expression'),
1701                    _(unicode(e)))
1702            return
1703
1704        if len(sarOp.searchStr) > 0:
1705            title = sarOp.getTitle()
1706            while True:
1707                title = guiToUni(wx.GetTextFromUser(_(u"Title:"),
1708                        _(u"Choose search title"), title, self))
1709                if title == u"":
1710                    return  # Cancel
1711                   
1712#                 if title in self.pWiki.getWikiData().getSavedSearchTitles():
1713                if (u"savedsearch/" + title) in self.mainControl.getWikiData()\
1714                        .getDataBlockUnifNamesStartingWith(
1715                        u"savedsearch/" + title):
1716
1717                    answer = wx.MessageBox(
1718                            _(u"Do you want to overwrite existing search '%s'?") %
1719                            title, _(u"Overwrite search"),
1720                            wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION, self)
1721                    if answer != wx.YES:
1722                        continue
1723
1724#                 self.pWiki.getWikiData().saveSearch(title,
1725#                         sarOp.getPackedSettings())
1726                self.mainControl.getWikiData().storeDataBlock(
1727                        u"savedsearch/" + title, sarOp.getPackedSettings(),
1728                        storeHint=Consts.DATABLOCK_STOREHINT_INTERN)
1729
1730                self._refreshSavedSearchesList()
1731                break
1732        else:
1733            self.mainControl.displayErrorMessage(
1734                    _(u"Invalid search string, can't save as view"))
1735
1736
1737    def OnRadioBox(self, evt):
1738        self.listNeedsRefresh = True
1739        booleanSearch = self.ctrls.rboxSearchType.GetSelection() in (1, 3)
1740
1741        self.ctrls.txtReplace.Enable(not booleanSearch)
1742        self.ctrls.btnFindNext.Enable(not booleanSearch)
1743        self.ctrls.btnReplace.Enable(not booleanSearch)
1744        self.ctrls.btnReplaceAll.Enable(not booleanSearch)
1745
1746
1747    def OnOptions(self, evt):
1748        self.mainControl.showOptionsDialog("OptionsPageSearching")
1749#         dlg = SearchWikiOptionsDialog(self, self.GetParent(), -1)
1750#         dlg.CenterOnParent(wx.BOTH)
1751#
1752#         dlg.ShowModal()
1753#         dlg.Destroy()
1754
1755
1756    def getResultListPositionTuple(self):
1757        return getRelativePositionTupleToAncestor(self.ctrls.htmllbPages, self)
1758
1759
1760    def OnCmdAsResultlist(self, evt):
1761        self.Hide()
1762       
1763        ownPos = self.GetPositionTuple()
1764        oldRelBoxPos = self.getResultListPositionTuple()
1765       
1766        frame = FastSearchPopup(self.GetParent(), self.mainControl, -1,
1767                srListBox=self.ctrls.htmllbPages)
1768        frame.setSearchOp(self._buildSearchReplaceOperation())
1769       
1770        newRelBoxPos = frame.getResultListPositionTuple()
1771
1772        # A bit math to ensure that result list in both windows is placed
1773        # at same position (looks more cool)
1774        otherPos = (ownPos[0] + oldRelBoxPos[0] - newRelBoxPos[0],
1775                ownPos[1] + oldRelBoxPos[1] - newRelBoxPos[1])
1776       
1777        setWindowPos(frame, pos=otherPos, fullVisible=True)
1778        self.mainControl.nonModalWwSearchDlgs.append(frame)
1779        frame.Show()
1780        self.Close()
1781
1782
1783    def OnCmdAsTab(self, evt):
1784        self.Hide()
1785
1786        maPanel = self.mainControl.getMainAreaPanel()
1787        presenter = LayeredControlPanel(maPanel)
1788        subCtl = SearchResultPresenterControl(presenter, self.mainControl,
1789                self.GetParent(), -1, srListBox=self.ctrls.htmllbPages)
1790        presenter.setSubControl("search result list", subCtl)
1791        presenter.switchSubControl("search result list")
1792        maPanel.appendPresenterTab(presenter)
1793        subCtl.setSearchOp(self._buildSearchReplaceOperation())
1794
1795        maPanel.showPresenter(presenter)
1796        self.Close()
1797
1798
1799#     def OnClose(self, evt):
1800#         try:
1801#             self.mainControl.nonModalWwSearchDlgs.remove(self)
1802#         except ValueError:
1803#             if self is self.mainControl.nonModalMainWwSearchDlg:
1804#                 self.mainControl.nonModalMainWwSearchDlg = None
1805#
1806#         self.Destroy()
1807
1808
1809    def _refreshSavedSearchesList(self):
1810        unifNames = self.mainControl.getWikiData()\
1811                .getDataBlockUnifNamesStartingWith(u"savedsearch/")
1812
1813        self.savedSearches = [name[12:] for name in unifNames]
1814        self.mainControl.getCollator().sort(self.savedSearches)
1815
1816        self.ctrls.lbSavedSearches.Clear()
1817        for search in self.savedSearches:
1818            self.ctrls.lbSavedSearches.Append(uniToGui(search))
1819
1820
1821    def _refreshSearchHistoryCombo(self):
1822        hist = wx.GetApp().getWikiSearchHistory()
1823        self.ctrls.cbSearch.Clear()
1824        self.ctrls.cbSearch.AppendItems([tpl[0] for tpl in hist])
1825
1826
1827    def OnDeleteSearches(self, evt):
1828        sels = self.ctrls.lbSavedSearches.GetSelections()
1829       
1830        if len(sels) == 0:
1831            return
1832           
1833        answer = wx.MessageBox(
1834                _(u"Do you want to delete %i search(es)?") % len(sels),
1835                _(u"Delete search"),
1836                wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION, self)
1837        if answer != wx.YES:
1838            return
1839
1840        for s in sels:
1841#             self.pWiki.getWikiData().deleteSavedSearch(self.savedSearches[s])
1842            self.mainControl.getWikiData().deleteDataBlock(
1843                    u"savedsearch/" + self.savedSearches[s])
1844        self._refreshSavedSearchesList()
1845
1846
1847    def OnLoadSearch(self, evt):
1848        self._loadSearch()
1849       
1850    def OnLoadAndRunSearch(self, evt):
1851        if self._loadSearch():
1852            try:
1853                self._refreshPageList()
1854            except UserAbortException:
1855                return
1856            except re.error, e:
1857                self.displayErrorMessage(_(u'Error in regular expression'),
1858                        _(unicode(e)))
1859            except ParseException, e:
1860                self.displayErrorMessage(_(u'Error in boolean expression'),
1861                        _(unicode(e)))
1862            except DbReadAccessError, e:
1863                self.displayErrorMessage(_(u'Error. Maybe wiki rebuild is needed'),
1864                        _(unicode(e)))
1865
1866
1867    def _loadSearch(self):
1868        sels = self.ctrls.lbSavedSearches.GetSelections()
1869       
1870        if len(sels) != 1:
1871            return False
1872       
1873        datablock = self.mainControl.getWikiData().retrieveDataBlock(
1874                u"savedsearch/" + self.savedSearches[sels[0]])
1875
1876        sarOp = SearchReplaceOperation()
1877        sarOp.setPackedSettings(datablock)
1878       
1879        self.showSearchReplaceOperation(sarOp)
1880       
1881        return True
1882
1883
1884    def OnSearchComboSelected(self, evt):
1885        hist = wx.GetApp().getWikiSearchHistory()
1886        sarOp = SearchReplaceOperation()
1887        sarOp.setPackedSettings(hist[evt.GetSelection()][1])
1888       
1889        self.showSearchReplaceOperation(sarOp)
1890        self.ctrls.txtReplace.SetValue(guiToUni(sarOp.replaceStr))
1891
1892
1893    def OnCopyPageNamesToClipboard(self, evt):
1894        langHelper = wx.GetApp().createWikiLanguageHelper(
1895                self.mainControl.getWikiDefaultWikiLanguage())
1896
1897        wordsText = u"".join([
1898                langHelper.createAbsoluteLinksFromWikiWords((w,)) + "\n"
1899                for w in self.foundPages])
1900
1901        copyTextToClipboard(wordsText)
1902
1903
1904    def OnTextSubtreeLevels(self, evt):
1905        self.ctrls.rbPagesInList.SetValue(True)
1906        self._updateTabTitle()
1907        self.listNeedsRefresh = True
1908
1909    def OnTextPageNameMatchRe(self, evt):
1910        self.ctrls.rbPagesMatchRe.SetValue(True)
1911        self._updateTabTitle()
1912        self.listNeedsRefresh = True
1913
1914
1915    def OnCharToFind(self, evt):
1916        if (evt.GetKeyCode() in (wx.WXK_RETURN, wx.WXK_NUMPAD_ENTER)):
1917            self.OnSearchWiki(evt)
1918        elif evt.GetKeyCode() == wx.WXK_TAB:
1919            if evt.ShiftDown():
1920                self.ctrls.cbSearch.Navigate(wx.NavigationKeyEvent.IsBackward |
1921                        wx.NavigationKeyEvent.FromTab)
1922            else:
1923                self.ctrls.cbSearch.Navigate(wx.NavigationKeyEvent.IsForward |
1924                        wx.NavigationKeyEvent.FromTab)
1925        else:
1926            evt.Skip()
1927
1928
1929    # Processing of events on second tab
1930   
1931    def _updateTabTitle(self):
1932        if self.ctrls.rbPagesAll.GetValue():
1933            self.ctrls.nbSearchWiki.SetPageText(1, _(u"Set page list"))
1934        else:
1935            self.ctrls.nbSearchWiki.SetPageText(1, _(u"*Set page list*"))           
1936
1937    def OnPageListUp(self, evt):
1938        sel = self.ctrls.lbPageList.GetSelection()
1939        if sel == wx.NOT_FOUND or sel == 0:
1940            return
1941           
1942        self.listNeedsRefresh = True
1943           
1944        dispWord = self.ctrls.lbPageList.GetString(sel)
1945        word = self.pageListData[sel]
1946       
1947        self.ctrls.lbPageList.Delete(sel)
1948        del self.pageListData[sel]
1949       
1950        self.ctrls.lbPageList.Insert(dispWord, sel - 1)
1951        self.pageListData.insert(sel - 1, word)
1952        self.ctrls.lbPageList.SetSelection(sel - 1)
1953       
1954       
1955    def OnPageListDown(self, evt):
1956        sel = self.ctrls.lbPageList.GetSelection()
1957        if sel == wx.NOT_FOUND or sel == len(self.pageListData) - 1:
1958            return
1959           
1960        self.listNeedsRefresh = True
1961
1962        dispWord = self.ctrls.lbPageList.GetString(sel)
1963        word = self.pageListData[sel]
1964       
1965        self.ctrls.lbPageList.Delete(sel)
1966        del self.pageListData[sel]
1967       
1968        self.ctrls.lbPageList.Insert(dispWord, sel + 1)
1969        self.pageListData.insert(sel + 1, word)
1970        self.ctrls.lbPageList.SetSelection(sel + 1)
1971
1972
1973    def OnPageListSort(self, evt):
1974        self.ctrls.rbPagesInList.SetValue(True)
1975        self._updateTabTitle()
1976        self.listNeedsRefresh = True
1977
1978        self.mainControl.getCollator().sort(self.pageListData)
1979       
1980        self.ctrls.lbPageList.Clear()
1981        self.ctrls.lbPageList.AppendItems(self.pageListData)
1982
1983
1984    def OnPageListAdd(self, evt):
1985        self.ctrls.rbPagesInList.SetValue(True)
1986        self._updateTabTitle()
1987
1988        word = guiToUni(self.ctrls.tfPageListToAdd.GetValue())
1989
1990        langHelper = wx.GetApp().createWikiLanguageHelper(
1991                self.mainControl.getWikiDefaultWikiLanguage())
1992        word = langHelper.extractWikiWordFromLink(word,
1993                self.mainControl.getWikiDocument())
1994        if word is None:
1995            return
1996
1997        if word in self.pageListData:
1998            return  # Already in list
1999       
2000        self.listNeedsRefresh = True
2001
2002        sel = self.ctrls.lbPageList.GetSelection()
2003        if sel == wx.NOT_FOUND:
2004            self.ctrls.lbPageList.Append(uniToGui(word))
2005            self.pageListData.append(word)
2006            self.ctrls.lbPageList.SetSelection(len(self.pageListData) - 1)
2007        else:
2008            self.ctrls.lbPageList.Insert(uniToGui(word), sel + 1)
2009            self.pageListData.insert(sel + 1, word)
2010            self.ctrls.lbPageList.SetSelection(sel + 1)
2011           
2012        self.ctrls.tfPageListToAdd.SetValue(u"")
2013
2014
2015    def OnPageListDelete(self, evt):
2016        self.ctrls.rbPagesInList.SetValue(True)
2017        self._updateTabTitle()
2018
2019        sel = self.ctrls.lbPageList.GetSelection()
2020        if sel == wx.NOT_FOUND:
2021            return
2022
2023        self.ctrls.lbPageList.Delete(sel)
2024        del self.pageListData[sel]
2025       
2026        count = len(self.pageListData)
2027        if count == 0:
2028            return
2029           
2030        self.listNeedsRefresh = True
2031       
2032        if sel >= count:
2033            sel = count - 1
2034        self.ctrls.lbPageList.SetSelection(sel)
2035
2036
2037    def OnPageListClearList(self, evt):
2038        self.ctrls.rbPagesInList.SetValue(True)
2039        self._updateTabTitle()
2040
2041        self.ctrls.lbPageList.Clear()
2042        self.pageListData = []
2043        self.listNeedsRefresh = True
2044       
2045
2046    def OnPageListAddFromClipboard(self, evt):
2047        """
2048        Take wiki words from clipboard and enter them into the list
2049        """
2050        self.ctrls.rbPagesInList.SetValue(True)
2051        self._updateTabTitle()
2052
2053        text = getTextFromClipboard()
2054        if text:
2055            self.listNeedsRefresh = True
2056            pageAst = self.mainControl.getCurrentDocPage().parseTextInContext(text)
2057            wwNodes = pageAst.iterDeepByName("wikiWord")
2058            found = {}
2059            # First fill found with already existing entries
2060            for w in self.pageListData:
2061                found[w] = None
2062
2063            for node in wwNodes:
2064                w = node.wikiWord
2065                if not found.has_key(w):
2066                    self.ctrls.lbPageList.Append(uniToGui(w))
2067                    self.pageListData.append(w)
2068                    found[w] = None
2069
2070
2071    def OnPageListOverwriteFromClipboard(self, evt):
2072        self.ctrls.lbPageList.Clear()
2073        self.listNeedsRefresh = True
2074        self.pageListData = []
2075       
2076        self.OnPageListAddFromClipboard(evt)
2077
2078
2079    def OnPageListIntersectWithClipboard(self, evt):
2080        """
2081        Take wiki words from clipboard and intersect with the list
2082        """
2083        self.ctrls.rbPagesInList.SetValue(True)
2084        self._updateTabTitle()
2085
2086        text = getTextFromClipboard()
2087       
2088        if text:
2089            self.listNeedsRefresh = True
2090            pageAst = self.mainControl.getCurrentDocPage().parseTextInContext(text)
2091            wwNodes = pageAst.iterDeepByName("wikiWord")
2092            found = {}
2093
2094            for node in wwNodes:
2095                w = node.wikiWord
2096                found[w] = None
2097
2098            pageList = self.pageListData
2099            self.pageListData = []
2100            self.ctrls.lbPageList.Clear()
2101
2102            # Now fill all with already existing entries
2103            for w in pageList:
2104                if found.has_key(w):
2105                    self.ctrls.lbPageList.Append(uniToGui(w))
2106                    self.pageListData.append(w)
2107                    del found[w]
2108
2109
2110    def OnPageListCopyToClipboard(self, evt):
2111        langHelper = wx.GetApp().createWikiLanguageHelper(
2112                self.mainControl.getWikiDefaultWikiLanguage())
2113
2114        wordsText = u"".join([
2115                langHelper.createAbsoluteLinksFromWikiWords((w,)) + "\n"
2116                for w in self.pageListData])
2117
2118        copyTextToClipboard(wordsText)
2119
2120
2121    def OnResultCopyToClipboard(self, evt):
2122        langHelper = wx.GetApp().createWikiLanguageHelper(
2123                self.mainControl.getWikiDefaultWikiLanguage())
2124
2125        wordsText = u"".join([
2126                langHelper.createAbsoluteLinksFromWikiWords((w,)) + "\n"
2127                for w in self.resultListData])
2128
2129        copyTextToClipboard(wordsText)
2130
2131
2132    def OnResultListPreview(self, evt):
2133        lpOp = self._buildListPagesOperation()
2134
2135        if lpOp is None:
2136            return
2137
2138        sarOp = SearchReplaceOperation()
2139        sarOp.listWikiPagesOp = lpOp
2140
2141        self.SetCursor(wx.HOURGLASS_CURSOR)
2142        self.Freeze()
2143        try:
2144            words = self.mainControl.getWikiDocument().searchWiki(sarOp)
2145           
2146            self.ctrls.lbResultPreview.Clear()
2147            self.ctrls.lbResultPreview.AppendItems(words)
2148               
2149            self.resultListData = words
2150        finally:
2151            self.Thaw()
2152            self.SetCursor(wx.NullCursor)
2153
2154
2155
2156class SearchResultPresenterControl(wx.Panel):
2157    """
2158    Panel which can be added to presenter in main area panel as tab showing
2159    search results.
2160    """
2161    def __init__(self, presenter, mainControl, searchDialogParent, ID,
2162            srListBox=None):
2163        super(SearchResultPresenterControl, self).__init__(presenter, ID)
2164
2165        self.mainControl = mainControl
2166        self.presenter = presenter
2167        self.searchDialogParent = searchDialogParent
2168        self.sarOp = None
2169
2170        if srListBox is None:
2171            self.resultBox = SearchResultListBox(self, self.mainControl,
2172                    GUI_ID.htmllbPages)
2173        else:
2174            srListBox.Reparent(self)
2175            self.resultBox = srListBox
2176
2177        sizer = wx.BoxSizer(wx.VERTICAL)
2178        sizer.Add(self.resultBox, 1, wx.EXPAND)
2179
2180
2181        buttonSizer = wx.BoxSizer(wx.HORIZONTAL)
2182
2183        self.btnAsResultlist = wx.Button(self,
2184                GUI_ID.CMD_SEARCH_AS_RESULTLIST, label=_(u"As Resultlist"))
2185                # TODO Allow hotkey for button
2186        buttonSizer.Add(self.btnAsResultlist, 0, wx.EXPAND)
2187
2188        self.btnAsWwSearch = wx.Button(self, GUI_ID.CMD_SEARCH_AS_WWSEARCH,
2189                label=_(u"As Full Search"))    # TODO Allow hotkey for button
2190        buttonSizer.Add(self.btnAsWwSearch, 0, wx.EXPAND)
2191
2192#         buttonSizer.AddStretchSpacer()
2193        buttonSizer.Add((0, 0), 1)
2194
2195        res = wx.xrc.XmlResource.Get()
2196        self.tabContextMenu = res.LoadMenu("MenuSearchResultTabPopup")
2197       
2198
2199        sizer.Add(buttonSizer, 0, wx.EXPAND)
2200
2201        self.SetSizer(sizer)
2202
2203        wx.EVT_BUTTON(self, GUI_ID.CMD_SEARCH_AS_RESULTLIST, self.OnCmdAsResultlist)
2204        wx.EVT_BUTTON(self, GUI_ID.CMD_SEARCH_AS_WWSEARCH, self.OnCmdAsWwSearch)
2205
2206        wx.EVT_MENU(self.tabContextMenu, GUI_ID.CMD_SEARCH_AS_RESULTLIST, self.OnCmdAsResultlist)
2207        wx.EVT_MENU(self.tabContextMenu, GUI_ID.CMD_SEARCH_AS_WWSEARCH, self.OnCmdAsWwSearch)
2208
2209
2210    # Next two to fulfill presenter subcontrol protocol
2211    def close(self):
2212        pass
2213
2214    def setLayerVisible(self, vis, scName):
2215        pass
2216
2217
2218    def setSearchOp(self, sarOp):
2219        """
2220        """
2221        self.sarOp = sarOp
2222        self.presenter.setTitle(_(u"<Search: %s>") % self.sarOp.searchStr)
2223
2224
2225    def getTabContextMenu(self):
2226        return self.tabContextMenu
2227
2228
2229    def OnCmdAsResultlist(self, evt):
2230        self.mainControl.getMainAreaPanel().detachPresenterTab(self.presenter)
2231
2232        frame = FastSearchPopup(self.searchDialogParent, self.mainControl,
2233                -1, srListBox=self.resultBox)
2234
2235        self.mainControl.nonModalWwSearchDlgs.append(frame)
2236        frame.setSearchOp(self.sarOp)
2237        frame.fixate()
2238        frame.Show()
2239
2240        self.presenter.close()
2241        self.presenter.Destroy()
2242
2243
2244    def OnCmdAsWwSearch(self, evt):
2245        self.mainControl.getMainAreaPanel().detachPresenterTab(self.presenter)
2246
2247        dlg = SearchWikiDialog(self.searchDialogParent, self.mainControl, -1,
2248                srListBox=self.resultBox, allowOkCancel=False,
2249                allowOrdering=False)
2250        dlg.showSearchReplaceOperation(self.sarOp)
2251
2252        self.mainControl.nonModalWwSearchDlgs.append(dlg)
2253        dlg.Show()
2254
2255        self.presenter.close()
2256        self.presenter.Destroy()
2257
2258#         # Set focus to dialog (hackish)
2259#         wx.CallLater(100, dlg.SetFocus)
2260
2261
2262
2263
2264class FastSearchPopup(wx.Frame):
2265    """
2266    Popup window which appears when hitting Enter in the fast search text field
2267    in the main window.
2268    Using frame because wx.PopupWindow is not available on Mac OS
2269    """
2270    def __init__(self, parent, mainControl, ID, srListBox=None,
2271            pos=wx.DefaultPosition):
2272        wx.Frame.__init__(self, parent, ID, _(u"Fast Search"), pos=pos,
2273                style=wx.RESIZE_BORDER | wx.FRAME_FLOAT_ON_PARENT | wx.SYSTEM_MENU |
2274                wx.FRAME_TOOL_WINDOW | wx.CAPTION | wx.CLOSE_BOX ) # wx.FRAME_NO_TASKBAR)
2275               
2276        self.mainControl = mainControl
2277        self.sarOp = None
2278        self.fixed = False  # if window was moved, fix it to not close automatically
2279
2280        if srListBox is None:
2281            self.resultBox = SearchResultListBox(self, self.mainControl,
2282                    GUI_ID.htmllbPages)
2283        else:
2284            srListBox.Reparent(self)
2285            self.resultBox = srListBox
2286
2287        sizer = wx.BoxSizer(wx.VERTICAL)
2288        sizer.Add(self.resultBox, 1, wx.EXPAND)
2289
2290
2291        buttonSizer = wx.BoxSizer(wx.HORIZONTAL)
2292
2293        self.btnAsWwSearch = wx.Button(self, GUI_ID.CMD_SEARCH_AS_WWSEARCH,
2294                label=_(u"As Full Search"))    # TODO Allow hotkey for button
2295        buttonSizer.Add(self.btnAsWwSearch, 0, wx.EXPAND)
2296
2297        self.btnAsTab = wx.Button(self, GUI_ID.CMD_SEARCH_AS_TAB,
2298                label=_(u"As Tab"))    # TODO Allow hotkey for button
2299        buttonSizer.Add(self.btnAsTab, 0, wx.EXPAND)
2300#         buttonSizer.AddStretchSpacer()
2301        buttonSizer.Add((0, 0), 1)
2302
2303        sizer.Add(buttonSizer, 0, wx.EXPAND)
2304
2305        self.SetSizer(sizer)
2306
2307        config = self.mainControl.getConfig()
2308        width = config.getint("main", "fastSearch_sizeX", 200)
2309        height = config.getint("main", "fastSearch_sizeY", 400)
2310
2311        setWindowSize(self, (width, height))
2312        setWindowPos(self, fullVisible=True)
2313
2314        # Fixes focus bug under Linux
2315        self.resultBox.SetFocus()
2316       
2317        self.resultBox.getMiscEvent().addListener(self)
2318
2319#         self.Bind(wx.EVT_BUTTON, self.OnCloseMe, button)
2320
2321        self.resultBox.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
2322        self.btnAsWwSearch.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
2323        self.btnAsTab.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
2324        self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus)
2325#         wx.EVT_KILL_FOCUS(self.resultBox, self.OnKillFocus)
2326        wx.EVT_BUTTON(self, GUI_ID.CMD_SEARCH_AS_WWSEARCH, self.OnCmdAsWwSearch)
2327        wx.EVT_BUTTON(self, GUI_ID.CMD_SEARCH_AS_TAB, self.OnCmdAsTab)
2328        wx.EVT_CLOSE(self, self.OnClose)
2329        wx.EVT_KEY_DOWN(self.resultBox, self.OnKeyDown)
2330#         wx.EVT_LEFT_DOWN(self, self.OnLeftDown)
2331       
2332        # To avoid unwanted move events (resulting in calls to fixate)     
2333        wx.CallAfter(self.Bind, wx.EVT_MOVE, self.OnMove)
2334
2335
2336    def fixate(self):
2337        if self.fixed:
2338            return
2339       
2340        self.resultBox.Unbind(wx.EVT_KILL_FOCUS)
2341        self.btnAsWwSearch.Unbind(wx.EVT_KILL_FOCUS)
2342        self.Unbind(wx.EVT_MOVE)
2343        self.SetTitle(_(u"Search: %s") % self.sarOp.searchStr)
2344        self.fixed = True
2345       
2346
2347    def OnMove(self, evt):
2348        evt.Skip()
2349        self.fixate()
2350
2351
2352    def getResultListPositionTuple(self):
2353        return getRelativePositionTupleToAncestor(self.resultBox, self)
2354
2355
2356    def OnCmdAsWwSearch(self, evt):
2357        self.Hide()
2358        self.fixate()
2359
2360        ownPos = self.GetPositionTuple()
2361        oldRelBoxPos = self.getResultListPositionTuple()
2362
2363        dlg = SearchWikiDialog(self.GetParent(), self.mainControl, -1,
2364                srListBox=self.resultBox, allowOkCancel=False,
2365                allowOrdering=False)
2366        dlg.showSearchReplaceOperation(self.sarOp)
2367
2368        newRelBoxPos = dlg.getResultListPositionTuple()
2369
2370        # A bit math to ensure that result list in both windows is placed
2371        # at same position (looks more cool)
2372        otherPos = (ownPos[0] + oldRelBoxPos[0] - newRelBoxPos[0],
2373                ownPos[1] + oldRelBoxPos[1] - newRelBoxPos[1])
2374
2375        setWindowPos(dlg, pos=otherPos, fullVisible=True)
2376        self.mainControl.nonModalWwSearchDlgs.append(dlg)
2377        self.Close()
2378        dlg.Show()
2379
2380        # Set focus to dialog (hackish)
2381        wx.CallLater(100, dlg.SetFocus)
2382
2383
2384    def OnCmdAsTab(self, evt):
2385        self.Hide()
2386        self.fixate()
2387
2388        maPanel = self.mainControl.getMainAreaPanel()
2389        presenter = LayeredControlPanel(maPanel)
2390        subCtl = SearchResultPresenterControl(presenter, self.mainControl,
2391                self.GetParent(), -1, srListBox=self.resultBox)
2392        presenter.setSubControl("search result list", subCtl)
2393        presenter.switchSubControl("search result list")
2394        maPanel.appendPresenterTab(presenter)
2395        subCtl.setSearchOp(self.sarOp)
2396
2397        maPanel.showPresenter(presenter)
2398        self.Close()
2399       
2400   
2401    def miscEventHappened(self, miscevt):
2402        if miscevt.getSource() is self.resultBox and miscevt.has_key(
2403                "opened in foreground"):
2404
2405            if not self.fixed:
2406                self.Close()
2407
2408       
2409    def displayErrorMessage(self, errorStr, e=u""):
2410        """
2411        Pops up an error dialog box
2412        """
2413        wx.MessageBox(uniToGui(u"%s. %s." % (errorStr, e)), u"Error!",
2414            wx.OK, self)
2415
2416
2417    def OnKeyDown(self, evt):
2418        accP = getAccelPairFromKeyDown(evt)
2419
2420        if accP == (wx.ACCEL_NORMAL, wx.WXK_ESCAPE):
2421            self.Close()
2422        else:
2423            evt.Skip()
2424
2425
2426    # def OnKillFocus(self, evt):
2427
2428    # TODO What about Mac?
2429    if isLinux():
2430        def OnKillFocus(self, evt):
2431            evt.Skip()
2432           
2433            if self.resultBox.contextMenuSelection == -2 and \
2434                    not wx.Window.FindFocus() in \
2435                    (None, self.resultBox, self.btnAsWwSearch, self.btnAsTab):
2436                # Close only if context menu is not open
2437                # otherwise crashes on GTK
2438                self.Close()
2439    else:
2440        def OnKillFocus(self, evt):
2441            evt.Skip()
2442            if not wx.Window.FindFocus() in (self.resultBox, self.btnAsWwSearch,
2443                    self.btnAsTab):
2444                self.Close()
2445
2446
2447    def OnClose(self, evt):
2448        if not self.fixed:
2449            width, height = self.GetSizeTuple()
2450            config = self.mainControl.getConfig()
2451            config.set("main", "fastSearch_sizeX", str(width))
2452            config.set("main", "fastSearch_sizeY", str(height))
2453       
2454        try:
2455            self.mainControl.nonModalWwSearchDlgs.remove(self)
2456        except ValueError:
2457            pass
2458
2459        evt.Skip()
2460
2461
2462    def _buildSearchReplaceOperation(self, searchText):
2463        config = self.mainControl.getConfig()
2464       
2465        searchType = config.getint("main", "fastSearch_searchType")
2466
2467        # TODO Make configurable
2468        sarOp = SearchReplaceOperation()
2469        sarOp.searchStr = stripSearchString(searchText)
2470        sarOp.booleanOp = searchType == Consts.SEARCHTYPE_BOOLEANREGEX
2471        sarOp.caseSensitive = config.getboolean("main",
2472                "fastSearch_caseSensitive")
2473        sarOp.wholeWord = config.getboolean("main", "fastSearch_wholeWord")
2474        sarOp.cycleToStart = False
2475        sarOp.wildCard = 'regex' if searchType != Consts.SEARCHTYPE_ASIS else 'no'
2476        sarOp.wikiWide = True
2477
2478        return sarOp
2479
2480
2481    def runSearchOnWiki(self, text):
2482        self.setSearchOp(self._buildSearchReplaceOperation(text))
2483        try:
2484            self._refreshPageList()
2485        except UserAbortException:
2486            return
2487        except re.error, e:
2488            self.displayErrorMessage(_(u'Error in regular expression'),
2489                    _(unicode(e)))
2490        except ParseException, e:
2491            self.displayErrorMessage(_(u'Error in boolean expression'),
2492                    _(unicode(e)))
2493        except DbReadAccessError, e:
2494            self.displayErrorMessage(_(u'Error. Maybe wiki rebuild is needed'),
2495                    _(unicode(e)))
2496
2497
2498    def setSearchOp(self, sarOp):
2499        """
2500        """
2501        self.sarOp = sarOp
2502
2503
2504#     def _refreshPageList(self):
2505#         self.resultBox.showSearching()
2506#         self.SetCursor(wx.HOURGLASS_CURSOR)
2507#         self.Freeze()
2508#         try:
2509#             # self.mainControl.saveCurrentDocPage()
2510#     
2511#             if len(self.sarOp.searchStr) > 0:
2512#                 self.foundPages = self.mainControl.getWikiDocument().searchWiki(self.sarOp)
2513#                 self.mainControl.getCollator().sort(self.foundPages)
2514#                 self.resultBox.showFound(self.sarOp, self.foundPages,
2515#                         self.mainControl.getWikiDocument())
2516#             else:
2517#                 self.foundPages = []
2518#                 self.resultBox.showFound(None, None, None)
2519#
2520#             self.listNeedsRefresh = False
2521#
2522#         finally:
2523#             self.Thaw()
2524#             self.SetCursor(wx.NullCursor)
2525#             self.resultBox.ensureNotShowSearching()
2526
2527
2528    def _refreshPageList(self):
2529        if len(self.sarOp.searchStr) == 0:
2530            self.foundPages = []
2531            self.resultBox.showFound(None, None, None)
2532
2533            self.listNeedsRefresh = False
2534            return
2535
2536        disableSet = wxHelper.getAllChildWindows(self)
2537        disableSet.difference_update(wxHelper.getWindowParentsUpTo(
2538                self.resultBox, self))
2539        disableSet = set(win for win in disableSet if win.IsEnabled())
2540
2541        self.resultBox.showSearching()
2542        self.SetCursor(wx.HOURGLASS_CURSOR)
2543#         self.Freeze()
2544
2545        if self.mainControl.configuration.getboolean("main",
2546                        "search_dontAllowCancel"):
2547            threadstop = DUMBTHREADSTOP
2548        else:
2549            threadstop = FunctionThreadStop(self._searchPoll)
2550
2551        self.searchingStartTime = time.time()
2552        for win in disableSet:
2553            win.Disable()
2554        try:
2555            self.foundPages = self.mainControl.getWikiDocument().searchWiki(
2556                    self.sarOp, threadstop=threadstop)
2557            self.mainControl.getCollator().sort(self.foundPages)
2558            self.resultBox.showFound(self.sarOp, self.foundPages,
2559                    self.mainControl.getWikiDocument(),
2560                    threadstop=threadstop)
2561
2562            self.listNeedsRefresh = False
2563
2564        except NotCurrentThreadException:
2565            raise UserAbortException()
2566        finally:
2567            self.searchingStartTime = None
2568            for win in disableSet:
2569                win.Enable()
2570   
2571    #         self.Thaw()
2572            self.SetCursor(wx.NullCursor)
2573            self.resultBox.ensureNotShowSearching()
2574
2575
2576    def _searchPoll(self):
2577        return wx.SafeYield(self, True) and self.searchingStartTime is not None
2578
2579    def stopSearching(self):
2580        self.searchingStartTime = None
2581
2582
2583
2584
2585
2586_CONTEXT_MENU_ACTIVATE = \
2587u"""
2588Activate;CMD_ACTIVATE_THIS
2589Activate New Tab;CMD_ACTIVATE_NEW_TAB_THIS
2590Activate New Tab Backgrd.;CMD_ACTIVATE_NEW_TAB_BACKGROUND_THIS
2591"""
2592
2593# Entries to support i18n of context menus
2594if False:
2595    N_(u"Activate")
2596    N_(u"Activate New Tab")
2597    N_(u"Activate New Tab Backgrd.")
Note: See TracBrowser for help on using the repository browser.