root/branches/mbutscher/work/lib/pwiki/AdditionalDialogs.py @ 251

Revision 251, 76.8 kB (checked in by mbutscher, 2 years ago)

branches/stable-2.1:
2.1rc01_1
* Bug fixed: Doc structure window removed selection when it lost focus
* Bug fixed: rel:// links with non-internal preview renderer lead to

exception and failure

* Bug fixed: URL links with title give exception

branches/mbutscher/work:
2.2beta01_1
* Bug fixed: Doc structure window removed selection when it lost focus
* Bug fixed: rel:// links with non-internal preview renderer lead to

exception and failure

* Bug fixed: URL links with title give exception
* Bug fixed: export dialog didn't work

Line 
1# -*- coding: iso8859-1 -*-
2import sys, traceback
3# from time import strftime
4import re
5
6from os.path import exists, isdir, isfile
7
8from rtlibRepl import minidom
9
10import wx, wx.html, wx.xrc
11
12
13from wxHelper import *
14
15try:
16    import sqlite3api as sqlite
17except:
18    sqlite = None
19
20
21from StringOps import uniToGui, guiToUni, mbcsEnc, mbcsDec, \
22        escapeForIni, unescapeForIni, escapeHtml, strftimeUB, pathEnc, \
23        writeEntireFile
24from wikidata import DbBackendUtils
25
26from WikiExceptions import *
27import Serialization
28import SystemInfo
29
30from Consts import VERSION_STRING, DATABLOCK_STOREHINT_INTERN
31
32
33
34class SelectWikiWordDialog(wx.Dialog):
35    """
36    Called for "Append/Prepend wiki word" in tree node context menu
37    """
38    def __init__(self, pWiki, parent, ID, title=None,
39                 pos=wx.DefaultPosition, size=wx.DefaultSize,
40                 style=wx.NO_3D):
41
42        d = wx.PreDialog()
43        self.PostCreate(d)
44
45        self.pWiki = pWiki
46        self.wikiWord = None
47        self.listContent = []
48        self.ignoreTextChange = 0
49       
50        res = wx.xrc.XmlResource.Get()
51        res.LoadOnDialog(self, parent, "SelectWikiWordDialog")
52
53        if title is not None:
54            self.SetTitle(title)
55
56        self.ctrls = XrcControls(self)
57
58        self.ctrls.btnOk.SetId(wx.ID_OK)
59        self.ctrls.btnCancel.SetId(wx.ID_CANCEL)
60       
61        # Fixes focus bug under Linux
62        self.SetFocus()
63
64        wx.EVT_BUTTON(self, wx.ID_OK, self.OnOk)
65
66        wx.EVT_TEXT(self, ID, self.OnText)
67        wx.EVT_CHAR(self.ctrls.text, self.OnCharText)
68        wx.EVT_CHAR(self.ctrls.lb, self.OnCharListBox)
69        wx.EVT_LISTBOX(self, ID, self.OnListBox)
70        wx.EVT_LISTBOX_DCLICK(self, GUI_ID.lb, self.OnOk)
71
72
73    def _fillListContent(self, searchTxt):
74        if len(searchTxt) == 0:
75            self.listContent = []
76            return
77
78        if searchTxt == u"%":
79            self.listContent = self.pWiki.getWikiData()\
80                    .getWikiWordMatchTermsWith(u"")
81            return
82       
83        # Filter out anything else than real words and explicit aliases
84        self.listContent = self.pWiki.getWikiData().getWikiWordMatchTermsWith(
85                searchTxt)
86
87
88    def OnOk(self, evt):
89        sel = self.ctrls.lb.GetSelection()
90        if sel != wx.NOT_FOUND:
91            term = self.listContent[sel]
92            self.wikiWord = term[2]
93        else:
94            self.wikiWord = guiToUni(self.ctrls.text.GetValue())
95   
96            if not self.pWiki.getWikiDocument().isDefinedWikiLink(self.wikiWord):
97                self._fillListContent(self.wikiWord)
98                if len(self.listContent) > 0:
99                    self.wikiWord = self.listContent[0][2]
100                else:
101                    langHelper = wx.GetApp().createWikiLanguageHelper(
102                            self.pWiki.getWikiDefaultWikiLanguage())
103                    wikiWord = langHelper.extractWikiWordFromLink(self.wikiWord,
104                            self.pWiki.getWikiDocument())
105   
106                    if wikiWord is None:
107                        # Entered text is not a valid wiki word
108                        # TODO Error message?
109                        self.ctrls.text.SetFocus()
110                        return
111
112                    self.wikiWord = wikiWord
113
114        self.EndModal(wx.ID_OK)
115       
116               
117    def GetValue(self):
118        return self.wikiWord
119
120    def OnText(self, evt):
121        if self.ignoreTextChange:
122            self.ignoreTextChange -= 1
123            return
124
125        text = guiToUni(evt.GetString())
126
127        self.ctrls.lb.Freeze()
128        try:
129            self.ctrls.lb.Clear()
130            self._fillListContent(text)
131
132            for term in self.listContent:
133                self.ctrls.lb.Append(term[0])
134        finally:
135            self.ctrls.lb.Thaw()
136
137
138    def OnListBox(self, evt):
139        sel = self.ctrls.lb.GetSelection()
140        if sel != wx.NOT_FOUND:
141            if self.listContent[sel][0] != self.listContent[sel][2]:
142                self.ctrls.stLinkTo.SetLabel(uniToGui(_(u"Links to:") + u" " +
143                        self.listContent[sel][2]))
144            else:
145                self.ctrls.stLinkTo.SetLabel(u"")
146            self.ignoreTextChange += 1
147            self.ctrls.text.SetValue(self.listContent[sel][0])
148        else:
149            self.ctrls.stLinkTo.SetLabel(u"")
150
151
152
153    def OnCharText(self, evt):
154        if (evt.GetKeyCode() == wx.WXK_DOWN) and not self.ctrls.lb.IsEmpty():
155            self.ctrls.lb.SetFocus()
156            self.ctrls.lb.SetSelection(0)
157            self.OnListBox(None)  # TODO Check if works for non-Windows
158        elif (evt.GetKeyCode() == wx.WXK_UP):
159            pass
160        else:
161            evt.Skip()
162
163
164    def OnCharListBox(self, evt):
165        if (evt.GetKeyCode() == wx.WXK_UP) and (self.ctrls.lb.GetSelection() == 0):
166            self.ctrls.text.SetFocus()
167            self.ctrls.lb.Deselect(0)
168            self.ctrls.text.SetSelection(-1, -1)
169        else:
170            evt.Skip()
171           
172
173SelectWikiWordDialog.runModal = staticmethod(runDialogModalFactory(SelectWikiWordDialog))
174
175     
176
177class OpenWikiWordDialog(wx.Dialog):
178    def __init__(self, pWiki, parent, ID, title=None,
179                 pos=wx.DefaultPosition, size=wx.DefaultSize,
180                 style=wx.NO_3D):
181
182        d = wx.PreDialog()
183        self.PostCreate(d)
184
185        self.pWiki = pWiki
186        self.value = None
187        self.listContent = []
188        self.ignoreTextChange = 0
189
190        res = wx.xrc.XmlResource.Get()
191        res.LoadOnDialog(self, parent, "OpenWikiWordDialog")
192
193        if title is not None:
194            self.SetTitle(title)
195
196        self.ctrls = XrcControls(self)
197       
198        self.ctrls.chSort.SetSelection(self.pWiki.getConfig().getint("main",
199                "openWikiWordDialog_sortOrder", 0))
200
201        self.ctrls.btnOk.SetId(wx.ID_OK)
202        self.ctrls.btnCancel.SetId(wx.ID_CANCEL)
203       
204        # Fixes focus bug under Linux
205        self.SetFocus()
206
207        wx.EVT_TEXT(self, ID, self.OnText)
208        wx.EVT_CHAR(self.ctrls.text, self.OnCharText)
209        wx.EVT_CHAR(self.ctrls.lb, self.OnCharListBox)
210        wx.EVT_LISTBOX(self, ID, self.OnListBox)
211        wx.EVT_LISTBOX_DCLICK(self, GUI_ID.lb, self.OnOk)
212        wx.EVT_BUTTON(self, wx.ID_OK, self.OnOk)
213        wx.EVT_BUTTON(self, GUI_ID.btnCreate, self.OnCreate)
214        wx.EVT_CHOICE(self, GUI_ID.chSort, self.OnChoiceSort)
215        wx.EVT_BUTTON(self, GUI_ID.btnDelete, self.OnDelete)
216        wx.EVT_BUTTON(self, GUI_ID.btnNewTab, self.OnNewTab)
217        wx.EVT_BUTTON(self, GUI_ID.btnNewTabBackground, self.OnNewTabBackground)
218
219    def OnOk(self, evt):
220        if self.activateSelectedWikiWords(0):
221            self.EndModal(wx.ID_OK)
222
223
224    def _fillListContent(self, searchTxt):
225        if len(searchTxt) == 0:
226            self.listContent = []
227            return
228       
229        orderChoice = self.ctrls.chSort.GetSelection()
230       
231        if orderChoice == 1:
232            orderBy = "visited"
233            descend = True
234        elif orderChoice == 2:
235            orderBy = "visited"
236            descend = False
237        else:   # orderChoice == 0:
238            orderBy = "word"
239            descend = False
240       
241        if searchTxt == u"%":
242            self.listContent = self.pWiki.getWikiData()\
243                    .getWikiWordMatchTermsWith(u"", orderBy=orderBy,
244                    descend=descend)
245            return
246       
247        self.listContent = self.pWiki.getWikiData().getWikiWordMatchTermsWith(
248                searchTxt, orderBy=orderBy, descend=descend)
249
250
251    def activateSelectedWikiWords(self, tabMode):
252        sel = self.ctrls.lb.GetSelections()
253        if len(sel) > 0:
254            self.value = tuple(self.listContent[s] for s in sel)
255        else:
256            entered = guiToUni(self.ctrls.text.GetValue())
257
258            if len(entered) == 0:
259                # Nothing entered probably means the user doesn't want to
260                # continue, so return True
261                return True
262
263            if not self.pWiki.getWikiDocument().isDefinedWikiLink(entered):
264                langHelper = wx.GetApp().createWikiLanguageHelper(
265                        self.pWiki.getWikiDefaultWikiLanguage())
266                wikiWord = langHelper.extractWikiWordFromLink(entered,
267                        self.pWiki.getWikiDocument())
268
269                if wikiWord is not None and \
270                        self.pWiki.getWikiDocument().isDefinedWikiLink(wikiWord):
271                    self.value = ((wikiWord, 0,
272                            self.pWiki.getWikiDocument()\
273                            .getUnAliasedWikiWord(wikiWord), -1),)
274                else:
275                    self._fillListContent(entered)
276#                     terms = self.pWiki.getWikiData().getWikiWordMatchTermsWith(
277#                             entered)
278                    if len(self.listContent) > 0:
279                        self.value = (self.listContent[0],)
280                    else:
281                        if wikiWord is None:
282                            self.pWiki.displayErrorMessage(
283                                    _(u"'%s' is an invalid WikiWord") % entered)
284                            # Entered text is not a valid wiki word
285                            self.ctrls.text.SetFocus()
286                            return False
287
288                        # wikiWord is valid but nonexisting, so maybe create it?
289                        result = wx.MessageBox(
290                                uniToGui(_(u"'%s' is not an existing wikiword. Create?") %
291                                wikiWord), uniToGui(_(u"Create")),
292                                wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, self)
293   
294                        if result == wx.NO:
295                            self.ctrls.text.SetFocus()
296                            return False
297   
298                        self.value = ((wikiWord, 0, wikiWord, -1, -1),)
299            else:
300                self.value = ((entered, 0, entered, -1, -1),)
301
302        if self.pWiki.activatePageByUnifiedName(u"wikipage/" + self.value[0][2],
303                tabMode=tabMode, firstcharpos=self.value[0][3],
304                charlength=self.value[0][4]) is None:   # TODO: Go to charPos
305            return True   # False instead ?
306
307        for term in self.value[1:]:
308            if self.pWiki.activatePageByUnifiedName(u"wikipage/" + term[2],
309                    tabMode=3, firstcharpos=term[3],
310                    charlength=term[4]) is None:   # TODO: Go to charPos
311                break
312
313        return True
314
315
316    def GetValue(self):
317        return self.value
318
319    def OnText(self, evt):
320        if self.ignoreTextChange:
321            self.ignoreTextChange -= 1
322            return
323
324        text = guiToUni(self.ctrls.text.GetValue())  # evt.GetString())
325       
326        listBox = self.ctrls.lb
327
328        listBox.Freeze()
329        try:
330            listBox.Clear()
331            self._fillListContent(text)
332
333            listBox.AppendItems([term[0] for term in self.listContent])
334
335#             for term in self.listContent:
336#                 listBox.Append(term[0])
337        finally:
338            listBox.Thaw()
339
340
341    def OnChoiceSort(self, evt):
342        self.pWiki.getConfig().set("main", "openWikiWordDialog_sortOrder",
343                self.ctrls.chSort.GetSelection())
344
345        self.OnText(evt)
346
347
348    def OnListBox(self, evt):
349        sel = self.ctrls.lb.GetSelections()
350        if len(sel) > 0:
351            sel = sel[0]
352            if self.listContent[sel][0] != self.listContent[sel][2]:
353                self.ctrls.stLinkTo.SetLabel(uniToGui(_(u"Links to:") + u" " +
354                        self.listContent[sel][2]))
355            else:
356                self.ctrls.stLinkTo.SetLabel(u"")
357            self.ignoreTextChange += 1
358            self.ctrls.text.SetValue(self.listContent[sel][0])
359        else:
360            self.ctrls.stLinkTo.SetLabel(u"")
361
362
363    def OnCharText(self, evt):
364        if (evt.GetKeyCode() == wx.WXK_DOWN) and not self.ctrls.lb.IsEmpty():
365            self.ctrls.lb.SetFocus()
366            self.ctrls.lb.SetSelection(0)
367            self.OnListBox(None)  # TODO Check if it works for non-Windows
368        elif (evt.GetKeyCode() == wx.WXK_UP):
369            pass
370        else:
371            evt.Skip()
372
373
374    def OnCharListBox(self, evt):
375        if (evt.GetKeyCode() == wx.WXK_UP) and (self.ctrls.lb.GetSelections() == (0,)):
376            self.ctrls.text.SetFocus()
377            self.ctrls.lb.Deselect(0)
378            self.OnListBox(None)  # TODO Check if it works for non-Windows
379            self.ctrls.text.SetSelection(-1, -1)
380        else:
381            evt.Skip()
382           
383           
384    def OnCreate(self, evt):
385        """
386        Create new WikiWord
387        """
388        langHelper = wx.GetApp().createWikiLanguageHelper(
389                self.pWiki.getWikiDefaultWikiLanguage(),
390                self.pWiki.getWikiDocument())
391        entered = guiToUni(self.ctrls.text.GetValue())
392        wikiWord = langHelper.extractWikiWordFromLink(entered)
393
394        if wikiWord is None:
395            self.pWiki.displayErrorMessage(_(u"'%s' is an invalid WikiWord") %
396                    entered)
397            self.ctrls.text.SetFocus()
398            return
399       
400        if not self.pWiki.getWikiDocument().isCreatableWikiWord(wikiWord):
401            self.pWiki.displayErrorMessage(_(u"'%s' exists already") % wikiWord)
402            self.ctrls.text.SetFocus()
403            return
404
405        self.value = (wikiWord, 0, wikiWord, -1)
406        self.pWiki.activatePageByUnifiedName(u"wikipage/" + wikiWord,
407                tabMode=0)
408        self.EndModal(wx.ID_OK)
409
410
411    def OnDelete(self, evt):
412        sellen = len(self.ctrls.lb.GetSelections())
413        if sellen > 0:
414            answer = wx.MessageBox(
415                    _(u"Do you want to delete %i wiki page(s)?") % sellen,
416                    (u"Delete Wiki Page(s)"),
417                    wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION, self)
418
419            if answer != wx.YES:
420                return
421
422            self.pWiki.saveAllDocPages()
423            for s in self.ctrls.lb.GetSelections():
424                delword = self.listContent[s][2]
425                # Un-alias word
426                delword = self.pWiki.getWikiDocument().getUnAliasedWikiWord(delword)
427
428                if delword is not None:
429                    page = self.pWiki.getWikiDocument().getWikiPage(delword)
430                    page.deletePage()
431                   
432                    # self.pWiki.getWikiData().deleteWord(delword)
433       
434                    # trigger hooks
435                    self.pWiki.hooks.deletedWikiWord(self.pWiki, delword)
436
437#                     p2 = {}
438#                     p2["deleted page"] = True
439#                     p2["deleted wiki page"] = True
440#                     p2["wikiWord"] = delword
441#                     self.pWiki.fireMiscEventProps(p2)
442           
443#             self.pWiki.pageHistory.goAfterDeletion()
444
445            self.EndModal(wx.ID_OK)
446
447 
448 
449    def OnNewTab(self, evt):
450        if self.activateSelectedWikiWords(2):
451            self.EndModal(wx.ID_OK)
452
453    def OnNewTabBackground(self, evt):
454        self.activateSelectedWikiWords(3)
455
456OpenWikiWordDialog.runModal = staticmethod(runDialogModalFactory(OpenWikiWordDialog))
457
458
459
460class ChooseWikiWordDialog(wx.Dialog):
461    """
462    Used to allow selection from list of parents, parentless words, children
463    or bookmarked words.
464    """
465    def __init__(self, pWiki, ID, words, motionType, title=None,
466                 pos=wx.DefaultPosition, size=wx.DefaultSize):
467        d = wx.PreDialog()
468        self.PostCreate(d)
469       
470        self.pWiki = pWiki
471        res = wx.xrc.XmlResource.Get()
472        res.LoadOnDialog(self, self.pWiki, "ChooseWikiWordDialog")
473       
474        self.ctrls = XrcControls(self)
475       
476        if title is not None:
477            self.SetTitle(title)
478
479        self.ctrls.staTitle.SetLabel(title)
480       
481        self.motionType = motionType
482        self.unsortedWords = words
483
484        self.ctrls.cbSortAlphabetically.SetValue(
485                self.pWiki.getConfig().get("main",
486                "chooseWikiWordDialog_sortOrder") == u"AlphaAsc")
487
488        self._sortAndFillWords()
489       
490        self.ctrls.btnOk.SetId(wx.ID_OK)
491        self.ctrls.btnCancel.SetId(wx.ID_CANCEL)
492       
493        # Fixes focus bug under Linux
494        self.SetFocus()
495
496        wx.EVT_BUTTON(self, GUI_ID.btnDelete, self.OnDelete)
497        wx.EVT_BUTTON(self, GUI_ID.btnNewTab, self.OnNewTab)
498        wx.EVT_BUTTON(self, wx.ID_OK, self.OnOk)
499        wx.EVT_LISTBOX_DCLICK(self, GUI_ID.lb, self.OnOk)
500        wx.EVT_CHECKBOX(self, GUI_ID.cbSortAlphabetically,
501                self.OnCbSortAlphabetically)
502
503
504    def OnDelete(self, evt):
505        sellen = len(self.ctrls.lb.GetSelections())
506        if sellen > 0:
507            answer = wx.MessageBox(
508                    _(u"Do you want to delete %i wiki page(s)?") % sellen,
509                    (u"Delete Wiki Page(s)"),
510                    wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION, self)
511
512            if answer != wx.YES:
513                return
514
515            self.pWiki.saveAllDocPages()
516            for s in self.ctrls.lb.GetSelections():
517                delword = self.words[s]
518                # Un-alias word
519                delword = self.pWiki.getWikiDocument().getUnAliasedWikiWord(delword)
520
521                if delword is not None:
522                    page = self.pWiki.getWikiDocument().getWikiPage(delword)
523                    page.deletePage()
524                   
525                    # self.pWiki.getWikiData().deleteWord(delword)
526       
527                    # trigger hooks
528                    self.pWiki.hooks.deletedWikiWord(self.pWiki, delword)
529                   
530#             self.pWiki.pageHistory.goAfterDeletion()
531
532            self.EndModal(wx.ID_OK)
533
534
535    def OnOk(self, evt):
536        self.activateSelected(False)
537#         sels = self.ctrls.lb.GetSelections()
538#         if len(sels) != 1:
539#             return # We can only go to exactly one wiki word
540#             
541#         wikiWord = self.words[sels[0]]
542#         try:
543#             self.pWiki.openWikiPage(wikiWord, forceTreeSyncFromRoot=True,
544#                     motionType=self.motionType)
545#         finally:
546#             self.EndModal(GUI_ID.btnDelete)
547
548
549    def OnNewTab(self, evt):
550        self.activateSelected(True)
551
552       
553    def activateSelected(self, allNewTabs):
554        """
555        allNewTabs -- True: All selected words go to newly created tabs,
556                False: The first selected word changes current tab
557        """
558        selIdxs = self.ctrls.lb.GetSelections()
559        if len(selIdxs) == 0:
560            return
561
562        try:
563            if not allNewTabs:
564                self.pWiki.openWikiPage(self.words[selIdxs[0]],
565                        forceTreeSyncFromRoot=True, motionType=self.motionType)
566
567                selWords = [self.words[idx] for idx in selIdxs[1:]]
568            else:
569                selWords = [self.words[idx] for idx in selIdxs]
570
571            for word in selWords:
572                if self.pWiki.activatePageByUnifiedName(u"wikipage/" + word,
573                        2) is None:
574                    break
575        finally:
576            self.EndModal(wx.ID_OK)
577
578 
579    def OnCbSortAlphabetically(self, evt):
580        self.pWiki.getConfig().set("main",
581                "chooseWikiWordDialog_sortOrder", (u"AlphaAsc" if
582                self.ctrls.cbSortAlphabetically.GetValue() else u"None"))
583        self._sortAndFillWords()
584
585 
586    def _sortAndFillWords(self):
587        """
588        Sort words according to settings in dialog.
589        """
590        self.words = self.unsortedWords[:]
591        if self.ctrls.cbSortAlphabetically.GetValue():
592            self.pWiki.getCollator().sort(self.words)
593           
594        wordsgui = map(uniToGui, self.words)
595       
596        self.ctrls.lb.Set(wordsgui)
597
598
599
600
601class RenameWikiWordDialog(wx.Dialog):
602    def __init__(self, mainControl, fromWikiWord, parent, ID, title=None,
603                 pos=wx.DefaultPosition, size=wx.DefaultSize,
604                 style=wx.NO_3D):
605
606        d = wx.PreDialog()
607        self.PostCreate(d)
608
609        self.mainControl = mainControl
610        self.fromWikiWord = fromWikiWord
611
612        self.value = None
613
614        res = wx.xrc.XmlResource.Get()
615        res.LoadOnDialog(self, parent, "RenameWikiWordDialog")
616
617        if title is not None:
618            self.SetTitle(title)
619
620        self.ctrls = XrcControls(self)
621
622        self.ctrls.btnOk.SetId(wx.ID_OK)
623        self.ctrls.btnOk = self.ctrls._byId(wx.ID_OK)
624        self.ctrls.btnCancel.SetId(wx.ID_CANCEL)
625
626        self.ctrls.stFromWikiWord.SetLabel(self.fromWikiWord)
627        self.ctrls.tfToWikiWord.SetValue(self.fromWikiWord)
628        self.ctrls.btnOk.Enable(False)
629        self.ctrls.cbModifyLinks.SetValue(self.mainControl.getConfig().getboolean(
630                "main", "wikiWord_renameDefault_modifyWikiLinks", False))
631        self.ctrls.cbRenameSubPages.SetValue(self.mainControl.getConfig().getboolean(
632                "main", "wikiWord_renameDefault_renameSubPages", True))
633
634        # Fixes focus bug under Linux
635        self.SetFocus()
636
637        wx.EVT_BUTTON(self, wx.ID_OK, self.OnOk)
638        wx.EVT_TEXT(self, GUI_ID.tfToWikiWord, self.OnTextToWikiWord)
639
640
641
642#         wx.EVT_BUTTON(self, wx.ID_OK, self.OnOk)
643#
644#         wx.EVT_CHAR(self.ctrls.text, self.OnCharText)
645#         wx.EVT_CHAR(self.ctrls.lb, self.OnCharListBox)
646#         wx.EVT_LISTBOX(self, ID, self.OnListBox)
647#         wx.EVT_LISTBOX_DCLICK(self, GUI_ID.lb, self.OnOk)
648#         wx.EVT_BUTTON(self, GUI_ID.btnCreate, self.OnCreate)
649#         wx.EVT_BUTTON(self, GUI_ID.btnDelete, self.OnDelete)
650#         wx.EVT_BUTTON(self, GUI_ID.btnNewTab, self.OnNewTab)
651#         wx.EVT_BUTTON(self, GUI_ID.btnNewTabBackground, self.OnNewTabBackground)
652
653
654
655    def OnOk(self, evt):
656        msg = self._checkValidToWikiWord()
657        if msg is not None:
658            return
659
660        toWikiWord = self.ctrls.tfToWikiWord.GetValue()
661
662        try:
663            self.mainControl.renameWikiWord(self.fromWikiWord, toWikiWord,
664                    self.ctrls.cbModifyLinks.GetValue(),
665                    self.ctrls.cbRenameSubPages.GetValue())
666        except RenameWikiWordException, e:
667            wx.MessageBox(_(u"Can't process renaming:\n%s") %
668                    e.getFlowText(), _(u"Can't rename"),
669                    wx.OK | wx.ICON_HAND, self)
670            return
671        except WikiDataException, e:
672            traceback.print_exc()               
673            self.displayErrorMessage(unicode(e))
674        except (IOError, OSError, DbAccessError):
675            pass
676
677        self.EndModal(wx.ID_OK)
678
679
680    def updateValidToWikiWord(self):
681        msg = self._checkValidToWikiWord()
682        if msg is None:
683            self.ctrls.btnOk.Enable(True)
684            self.ctrls.stErrorMessage.SetLabel(u"")
685        else:
686            self.ctrls.btnOk.Enable(False)
687            self.ctrls.stErrorMessage.SetLabel(msg)
688
689
690    def _checkValidToWikiWord(self):
691        toWikiWord = self.ctrls.tfToWikiWord.GetValue()
692
693        if not toWikiWord or len(toWikiWord) == 0:
694            return u"" # No error message, but disable OK
695           
696        langHelper = wx.GetApp().createWikiLanguageHelper(
697                self.mainControl.getWikiDefaultWikiLanguage())
698
699        errMsg = langHelper.checkForInvalidWikiWord(toWikiWord,
700                self.mainControl.getWikiDocument())
701
702        if errMsg:
703            return errMsg   # _(u"Invalid wiki word. %s") % errMsg
704
705        if self.fromWikiWord == toWikiWord:
706            return _(u"Can't rename to itself")
707
708#         try:
709        if not self.mainControl.getWikiDocument().isCreatableWikiWord(toWikiWord):
710            return _(u"Word already exists")
711
712        # Word is OK
713        return None
714
715#         except (IOError, OSError, DbAccessError), e:
716#             self.mainControl.lostAccess(e)
717#             raise
718
719
720    def OnTextToWikiWord(self, evt):
721        evt.Skip()
722        self.updateValidToWikiWord()
723
724
725    def GetValue(self):
726        return self.value
727
728
729
730RenameWikiWordDialog.runModal = staticmethod(runDialogModalFactory(RenameWikiWordDialog))
731
732
733
734
735
736
737
738
739
740
741
742
743
744class SelectIconDialog(wx.Dialog):
745    def __init__(self, parent, ID, iconCache, title="Select Icon",
746                 pos=wx.DefaultPosition, size=wx.DefaultSize,
747                 style=wx.NO_3D|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER):
748        wx.Dialog.__init__(self, parent, ID, title, pos, size, style)
749
750        self.iconCache = iconCache
751        self.iconImageList = self.iconCache.iconImageList
752       
753        self.iconNames = [n for n in self.iconCache.iconLookupCache.keys()
754                if not n.startswith("tb_")]
755#         filter(lambda n: not n.startswith("tb_"),
756#                 self.iconCache.iconLookupCache.keys())
757        self.iconNames.sort()
758       
759        # Now continue with the normal construction of the dialog
760        # contents
761        sizer = wx.BoxSizer(wx.VERTICAL)
762
763        label = wx.StaticText(self, -1, _(u"Select Icon"))
764        sizer.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
765
766        box = wx.BoxSizer(wx.VERTICAL)
767
768        self.lc = wx.ListCtrl(self, -1, wx.DefaultPosition, wx.Size(145, 200),
769                style = wx.LC_REPORT | wx.LC_NO_HEADER)    ## | wx.BORDER_NONE
770               
771        self.lc.SetImageList(self.iconImageList, wx.IMAGE_LIST_SMALL)
772        self.lc.InsertColumn(0, _(u"Icon"))
773
774        for icn in self.iconNames:
775            self.lc.InsertImageStringItem(sys.maxint, icn,
776                    self.iconCache.lookupIconIndex(icn))
777#         self.lc.SetColumnWidth(0, wx.LIST_AUTOSIZE)
778        autosizeColumn(self.lc, 0)
779       
780       
781        box.Add(self.lc, 1, wx.ALIGN_CENTRE|wx.ALL|wx.EXPAND, 5)
782
783        sizer.Add(box, 1, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
784
785        line = wx.StaticLine(self, -1, size=(20,-1), style=wx.LI_HORIZONTAL)
786        sizer.Add(line, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.TOP, 5)
787
788        box = wx.BoxSizer(wx.HORIZONTAL)
789
790        btn = wx.Button(self, wx.ID_OK, _(u" OK "))
791        btn.SetDefault()
792        box.Add(btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
793
794        btn = wx.Button(self, wx.ID_CANCEL, _(u" Cancel "))
795        box.Add(btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
796
797        sizer.Add(box, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
798
799        self.SetSizer(sizer)
800        self.SetAutoLayout(True)
801        sizer.Fit(self)
802
803        self.value = None
804       
805        # Fixes focus bug under Linux
806        self.SetFocus()
807
808        wx.EVT_BUTTON(self, wx.ID_OK, self.OnOk)
809        wx.EVT_LIST_ITEM_ACTIVATED(self, self.lc.GetId(), self.OnOk)
810
811    def GetValue(self):
812        """
813        Return name of selected icon or None
814        """
815        return self.value
816
817
818#     @staticmethod
819#     def runModal(parent, ID, iconCache, title="Select Icon",
820#             pos=wx.DefaultPosition, size=wx.DefaultSize,
821#             style=wx.NO_3D|wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER):
822#
823#         dlg = SelectIconDialog(parent, ID, iconCache, title, pos, size, style)
824#         try:
825#             dlg.CenterOnParent(wx.BOTH)
826#             if dlg.ShowModal() == wx.ID_OK:
827#                 return dlg.GetValue()
828#             else:
829#                 return None
830#
831#         finally:
832#             dlg.Destroy()
833
834
835    def OnOk(self, evt):
836        no = self.lc.GetNextItem(-1, state = wx.LIST_STATE_SELECTED)
837        if no > -1:
838            self.value = self.iconNames[no]
839        else:
840            self.value = None
841           
842        self.EndModal(wx.ID_OK)
843
844
845
846# class SavedVersionsDialog(wx.Dialog):
847#     def __init__(self, pWiki, ID, title="Saved Versions",
848#                  pos=wx.DefaultPosition, size=wx.DefaultSize,
849#                  style=wx.NO_3D):
850#         wx.Dialog.__init__(self, pWiki, ID, title, pos, size, style)
851#         self.pWiki = pWiki
852#         self.value = None       
853#         
854#         # Now continue with the normal construction of the dialog
855#         # contents
856#         sizer = wx.BoxSizer(wx.VERTICAL)
857#
858#         label = wx.StaticText(self, -1, _(u"Saved Versions"))
859#         sizer.Add(label, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
860#
861#         box = wx.BoxSizer(wx.VERTICAL)
862#
863#         self.lb = wx.ListBox(self, -1, wx.DefaultPosition, wx.Size(165, 200),
864#                 [], wx.LB_SINGLE)
865#
866#         # fill in the listbox
867#         self.versions = self.pWiki.getWikiData().getStoredVersions()
868#             
869#         for version in self.versions:
870#             self.lb.Append(version[1])
871#
872#         box.Add(self.lb, 1, wx.ALIGN_CENTRE|wx.ALL, 5)
873#
874#         sizer.AddSizer(box, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
875#
876#         line = wx.StaticLine(self, -1, size=(20,-1), style=wx.LI_HORIZONTAL)
877#         sizer.Add(line, 0, wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.RIGHT|wx.TOP, 5)
878#
879#         box = wx.BoxSizer(wx.HORIZONTAL)
880#
881#         btn = wx.Button(self, wx.ID_OK, _(u" Retrieve "))
882#         btn.SetDefault()
883#         box.Add(btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
884#
885#         btn = wx.Button(self, wx.ID_CANCEL, _(u" Cancel "))
886#         box.Add(btn, 0, wx.ALIGN_CENTRE|wx.ALL, 5)
887#
888#         sizer.AddSizer(box, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
889#
890#         self.SetSizer(sizer)
891#         self.SetAutoLayout(True)
892#         sizer.Fit(self)
893#         
894#         # Fixes focus bug under Linux
895#         self.SetFocus()
896#
897#         ## wx.EVT_BUTTON(self, wxID_OK, self.OnRetrieve)
898#         wx.EVT_LISTBOX(self, ID, self.OnListBox)
899#         wx.EVT_LISTBOX_DCLICK(self, ID, lambda evt: self.EndModal(wx.ID_OK))
900#         
901# ##    def OnRetrieve(self, evt):
902# ##        if self.value:
903# ##            self.pWiki.getWikiData().deleteSavedSearch(self.value)
904# ##            self.EndModal(wxID_CANCEL)
905#         
906#     def GetValue(self):
907#         """ Returns None or tuple (<id>, <description>, <creation date>)
908#         """
909#         return self.value
910#
911#     def OnListBox(self, evt):
912#         self.value = self.versions[evt.GetSelection()]
913
914
915SelectIconDialog.runModal = staticmethod(runDialogModalFactory(SelectIconDialog))
916
917
918
919
920class DateformatDialog(wx.Dialog):
921
922    # HTML explanation for strftime:
923    FORMATHELP = N_(ur"""<html>
924<body bgcolor="#FFFFFF">
925
926<table border="1" align="center" style="border-collapse: collapse">
927    <tr><td align="center" valign="baseline"><b>Directive</b></td>
928        <td align="left"><b>Meaning</b></td></tr>
929    <tr><td align="center" valign="baseline"><code>%a</code></td>
930        <td align="left">Locale's abbreviated weekday name.</td></tr>
931    <tr><td align="center" valign="baseline"><code>%A</code></td>
932        <td align="left">Locale's full weekday name.</td></tr>
933    <tr><td align="center" valign="baseline"><code>%b</code></td>
934        <td align="left">Locale's abbreviated month name.</td></tr>
935    <tr><td align="center" valign="baseline"><code>%B</code></td>
936        <td align="left">Locale's full month name.</td></tr>
937    <tr><td align="center" valign="baseline"><code>%c</code></td>
938        <td align="left">Locale's appropriate date and time representation.</td></tr>
939    <tr><td align="center" valign="baseline"><code>%d</code></td>
940        <td align="left">Day of the month as a decimal number [01,31].</td></tr>
941    <tr><td align="center" valign="baseline"><code>%H</code></td>
942        <td align="left">Hour (24-hour clock) as a decimal number [00,23].</td></tr>
943    <tr><td align="center" valign="baseline"><code>%I</code></td>
944        <td align="left">Hour (12-hour clock) as a decimal number [01,12].</td></tr>
945    <tr><td align="center" valign="baseline"><code>%j</code></td>
946        <td align="left">Day of the year as a decimal number [001,366].</td></tr>
947    <tr><td align="center" valign="baseline"><code>%m</code></td>
948        <td align="left">Month as a decimal number [01,12].</td></tr>
949    <tr><td align="center" valign="baseline"><code>%M</code></td>
950        <td align="left">Minute as a decimal number [00,59].</td></tr>
951    <tr><td align="center" valign="baseline"><code>%p</code></td>
952        <td align="left">Locale's equivalent of either AM or PM.</td></tr>
953    <tr><td align="center" valign="baseline"><code>%S</code></td>
954        <td align="left">Second as a decimal number [00,61].</td></tr>
955    <tr><td align="center" valign="baseline"><code>%u</code></td>
956        <td align="left">Weekday as a decimal number [1(Monday),7].</td></tr>
957    <tr><td align="center" valign="baseline"><code>%U</code></td>
958        <td align="left">Week number of the year (Sunday as the first day of the
959                week) as a decimal number [00,53].  All days in a new year
960                preceding the first Sunday are considered to be in week 0.</td></tr>
961    <tr><td align="center" valign="baseline"><code>%w</code></td>
962        <td align="left">Weekday as a decimal number [0(Sunday),6].</td></tr>
963    <tr><td align="center" valign="baseline"><code>%W</code></td>
964        <td align="left">Week number of the year (Monday as the first day of the
965                week) as a decimal number [00,53].  All days in a new year
966                preceding the first Monday are considered to be in week 0.</td></tr>
967    <tr><td align="center" valign="baseline"><code>%x</code></td>
968        <td align="left">Locale's appropriate date representation.</td></tr>
969    <tr><td align="center" valign="baseline"><code>%X</code></td>
970        <td align="left">Locale's appropriate time representation.</td></tr>
971    <tr><td align="center" valign="baseline"><code>%y</code></td>
972        <td align="left">Year without century as a decimal number [00,99].</td></tr>
973    <tr><td align="center" valign="baseline"><code>%Y</code></td>
974        <td align="left">Year with century as a decimal number.</td></tr>
975    <tr><td align="center" valign="baseline"><code>%Z</code></td>
976        <td align="left">Time zone name (no characters if no time zone exists).</td></tr>
977    <tr><td align="center" valign="baseline"><code>%%</code></td>
978        <td align="left">A literal "<tt class="character">%</tt>" character.</td></tr>
979    <tr><td align="center" valign="baseline"><code>\n</code></td>
980        <td align="left">A newline.</td></tr>
981    <tr><td align="center" valign="baseline"><code>\\</code></td>
982        <td align="left">A literal "<tt class="character">\</tt>" character.</td></tr>
983    </tbody>
984</table>
985</body>
986</html>
987""")
988
989    def __init__(self, parent, ID, mainControl, title=None,
990                 pos=wx.DefaultPosition, size=wx.DefaultSize,
991                 style=wx.NO_3D, deffmt=u""):
992        """
993        deffmt -- Initial value for format string
994        """
995        d = wx.PreDialog()
996        self.PostCreate(d)
997       
998        self.mainControl = mainControl
999        self.value = u""     
1000        res = wx.xrc.XmlResource.Get()
1001        res.LoadOnDialog(self, parent, "DateformatDialog")
1002
1003        if title is not None:
1004            self.SetTitle(title)
1005       
1006        # Create HTML explanation
1007        html = wx.html.HtmlWindow(self, -1)
1008        html.SetPage(_(self.FORMATHELP))
1009        res.AttachUnknownControl("htmlExplain", html, self)
1010       
1011        self.ctrls = XrcControls(self)
1012       
1013        self.ctrls.btnOk.SetId(wx.ID_OK)
1014        self.ctrls.btnCancel.SetId(wx.ID_CANCEL)
1015       
1016        # Set dropdown list of recent time formats
1017        tfs = self.mainControl.getConfig().get("main", "recent_time_formats")
1018        self.recentFormats = [unescapeForIni(s) for s in tfs.split(u";")]
1019        for f in self.recentFormats:
1020            self.ctrls.fieldFormat.Append(f)
1021
1022        self.ctrls.fieldFormat.SetValue(deffmt)
1023        self.OnText(None)
1024       
1025        # Fixes focus bug under Linux
1026        self.SetFocus()
1027       
1028        wx.EVT_BUTTON(self, wx.ID_OK, self.OnOk)
1029        wx.EVT_TEXT(self, XRCID("fieldFormat"), self.OnText)
1030
1031
1032    def OnText(self, evt):
1033        preview = _(u"<invalid>")
1034        text = guiToUni(self.ctrls.fieldFormat.GetValue())
1035        try:
1036            preview = strftimeUB(text)
1037            self.value = text
1038        except:
1039#             traceback.print_exc()
1040            pass
1041
1042        self.ctrls.fieldPreview.SetLabel(preview)
1043       
1044       
1045    def GetValue(self):
1046        return self.value
1047       
1048   
1049    def OnOk(self, evt):
1050        if self.value != u"":
1051            # Update recent time formats list
1052           
1053            try:
1054                self.recentFormats.remove(self.value)
1055            except ValueError:
1056                pass
1057               
1058            self.recentFormats.insert(0, self.value)
1059            if len(self.recentFormats) > 10:
1060                self.recentFormats = self.recentFormats[:10]
1061
1062            # Escape to store it in configuration
1063            tfs = u";".join([escapeForIni(f, u";") for f in self.recentFormats])
1064            self.mainControl.getConfig().set("main", "recent_time_formats", tfs)
1065
1066        self.EndModal(wx.ID_OK)
1067
1068
1069
1070class FontFaceDialog(wx.Dialog):
1071    """
1072    Presents a list of available fonts (its face names) and renders a sample
1073    string with currently selected face.
1074    """
1075    def __init__(self, parent, ID, mainControl, value="",
1076                 pos=wx.DefaultPosition, size=wx.DefaultSize,
1077                 style=wx.NO_3D):
1078        """
1079        value -- Current value of a text field containing a face name (used to
1080                 choose default item in the shown list box)
1081        """
1082        d = wx.PreDialog()
1083        self.PostCreate(d)
1084
1085        self.parent = parent
1086        self.mainControl = mainControl
1087        self.value = value
1088
1089        res = wx.xrc.XmlResource.Get()
1090        res.LoadOnDialog(self, self.parent, "FontFaceDialog")
1091
1092        self.ctrls = XrcControls(self)
1093
1094        self.ctrls.btnOk.SetId(wx.ID_OK)
1095        self.ctrls.btnCancel.SetId(wx.ID_CANCEL)
1096
1097        # Fill font listbox
1098        fenum = wx.FontEnumerator()
1099        fenum.EnumerateFacenames()
1100        facelist = fenum.GetFacenames()
1101        self.mainControl.getCollator().sort(facelist)
1102
1103        for f in facelist:
1104            self.ctrls.lbFacenames.Append(f)
1105           
1106        if len(facelist) > 0:
1107            try:
1108                # In wxPython, this can throw an exception if self.value
1109                # does not match an item
1110                if not self.ctrls.lbFacenames.SetStringSelection(self.value):
1111                    self.ctrls.lbFacenames.SetSelection(0)
1112            except:
1113                self.ctrls.lbFacenames.SetSelection(0)
1114
1115            self.OnFaceSelected(None)
1116           
1117        # Fixes focus bug under Linux
1118        self.SetFocus()
1119           
1120        wx.EVT_BUTTON(self, wx.ID_OK, self.OnOk)
1121        wx.EVT_LISTBOX(self, GUI_ID.lbFacenames, self.OnFaceSelected)
1122        wx.EVT_LISTBOX_DCLICK(self, GUI_ID.lbFacenames, self.OnOk)
1123
1124
1125    def OnOk(self, evt):
1126        self.value = self.ctrls.lbFacenames.GetStringSelection()
1127        evt.Skip()
1128
1129       
1130    def OnFaceSelected(self, evt):
1131        face = self.ctrls.lbFacenames.GetStringSelection()
1132        font = wx.Font(12, wx.DEFAULT, wx.NORMAL, wx.NORMAL, False, face)
1133        self.ctrls.stFacePreview.SetLabel(face)
1134        self.ctrls.stFacePreview.SetFont(font)
1135
1136    def GetValue(self):
1137        return self.value
1138
1139
1140
1141class ExportDialog(wx.Dialog):
1142    def __init__(self, mainControl, ID, continuousExport=False, title=None,
1143                 pos=wx.DefaultPosition, size=wx.DefaultSize):
1144        from . import Exporters
1145        from .SearchAndReplace import SearchReplaceOperation
1146
1147        d = wx.PreDialog()
1148        self.PostCreate(d)
1149       
1150        self.mainControl = mainControl
1151        self.value = None
1152       
1153        self.listPagesOperation = SearchReplaceOperation()
1154        self.continuousExport = continuousExport
1155        self.savedExports = None
1156       
1157        # In addition to exporter list, this set will contain type tags of all
1158        # supported exports (used for saved exports list).
1159        self.supportedExportTypes = set()
1160        res = wx.xrc.XmlResource.Get()
1161        res.LoadOnDialog(self, self.mainControl, "ExportDialog")
1162
1163        self.ctrls = XrcControls(self)
1164
1165        if continuousExport:
1166            self.SetTitle(_(u"Continuous Export"))
1167
1168        self.emptyPanel = None
1169
1170        exporterList = [] # List of tuples (<exporter object>, <export tag>,
1171                          # <readable description>, <additional options panel>)
1172
1173        addOptSizer = LayerSizer()
1174
1175        # TODO Move to e.g. ExportOperation.py
1176        for ob in Exporters.describeExporters(self.mainControl):   # TODO search plugins
1177            for tp in ob.getExportTypes(self.ctrls.additOptions, continuousExport):
1178                panel = tp[2]
1179                if panel is None:
1180                    if self.emptyPanel is None:
1181                        # Necessary to avoid a crash       
1182                        self.emptyPanel = wx.Panel(self.ctrls.additOptions)
1183                        # self.emptyPanel.Fit()
1184                    panel = self.emptyPanel
1185                else:
1186                    pass
1187                    # panel.Fit()
1188
1189                # Add Tuple (Exporter object, export type tag,
1190                #     export type description, additional options panel)
1191                exporterList.append((ob, tp[0], tp[1], panel))
1192                self.supportedExportTypes.add(tp[0])
1193                addOptSizer.Add(panel)
1194
1195
1196        self.ctrls.additOptions.SetSizer(addOptSizer)
1197        self.ctrls.additOptions.SetMinSize(addOptSizer.GetMinSize())
1198
1199        self.ctrls.additOptions.Fit()
1200        self.Fit()
1201
1202#         self.ctrls.additOptions.Fit()
1203#         mins = self.ctrls.additOptions.GetMinSize()
1204#
1205#         self.ctrls.additOptions.SetMinSize(wx.Size(mins.width+10, mins.height+10))
1206#         self.Fit()
1207
1208        self.exporterList = exporterList
1209
1210        self.ctrls.btnOk.SetId(wx.ID_OK)
1211        self.ctrls.btnCancel.SetId(wx.ID_CANCEL)
1212       
1213        defdir = self.mainControl.getConfig().get("main", "export_default_dir",
1214                u"")
1215        if defdir == u"":
1216            defdir = self.mainControl.getLastActiveDir()
1217
1218        self.ctrls.tfDestination.SetValue(defdir)
1219
1220        for e in self.exporterList:
1221            e[3].Show(False)
1222            e[3].Enable(False)
1223            self.ctrls.chExportTo.Append(e[2])
1224           
1225#         # Enable first addit. options panel
1226#         self.exporterList[0][3].Enable(True)
1227#         self.exporterList[0][3].Show(True)
1228
1229        self.ctrls.chExportTo.SetSelection(0) 
1230        self._refreshForEtype()
1231        self._refreshSavedExportsList()
1232
1233        # Fixes focus bug under Linux
1234        self.SetFocus()
1235
1236        wx.EVT_CHOICE(self, GUI_ID.chExportTo, self.OnExportTo)
1237        wx.EVT_CHOICE(self, GUI_ID.chSelectedSet, self.OnChSelectedSet)
1238
1239        wx.EVT_LISTBOX_DCLICK(self, GUI_ID.lbSavedExports, self.OnLoadAndRunExport)
1240
1241        wx.EVT_BUTTON(self, wx.ID_OK, self.OnOk)
1242        wx.EVT_BUTTON(self, GUI_ID.btnSelectDestination, self.OnSelectDest)
1243        wx.EVT_BUTTON(self, GUI_ID.btnSaveExport, self.OnSaveExport)
1244        wx.EVT_BUTTON(self, GUI_ID.btnLoadExport, self.OnLoadExport)
1245        wx.EVT_BUTTON(self, GUI_ID.btnLoadAndRunExport, self.OnLoadAndRunExport)
1246        wx.EVT_BUTTON(self, GUI_ID.btnDeleteExports, self.OnDeleteExports)
1247
1248
1249    def _refreshForEtype(self):
1250        for e in self.exporterList:
1251            e[3].Show(False)
1252            e[3].Enable(False)
1253
1254        ob, etype, desc, panel = \
1255                self.exporterList[self.ctrls.chExportTo.GetSelection()][:4]
1256
1257        # Enable appropriate addit. options panel
1258        panel.Enable(True)
1259        panel.Show(True)
1260
1261        expDestWildcards = ob.getExportDestinationWildcards(etype)
1262
1263        if expDestWildcards is None:
1264            # Directory destination
1265            self.ctrls.stDestination.SetLabel(_(u"Destination directory:"))
1266        else:
1267            # File destination
1268            self.ctrls.stDestination.SetLabel(_(u"Destination file:"))
1269
1270
1271    def OnExportTo(self, evt):
1272        self._refreshForEtype()
1273        evt.Skip()
1274
1275
1276    def OnChSelectedSet(self, evt):
1277        selset = self.ctrls.chSelectedSet.GetSelection()
1278        if selset == 3:  # Custom
1279            from .SearchAndReplaceDialogs import SearchWikiDialog
1280
1281            dlg = SearchWikiDialog(self, self.mainControl, -1,
1282                    value=self.listPagesOperation)
1283            if dlg.ShowModal() == wx.ID_OK:
1284                self.listPagesOperation = dlg.getValue()
1285            dlg.Destroy()
1286
1287    def OnOk(self, evt):
1288        self._runExporter()
1289
1290       
1291    def _runExporter(self):
1292        # Run exporter
1293        ob, etype, desc, panel = \
1294                self.exporterList[self.ctrls.chExportTo.GetSelection()][:4]
1295
1296        # If this returns None, export goes to a directory
1297        expDestWildcards = ob.getExportDestinationWildcards(etype)
1298        if expDestWildcards is None:
1299            # Export to a directory
1300            if not exists(pathEnc(self.ctrls.tfDestination.GetValue())):
1301                self.mainControl.displayErrorMessage(
1302                        _(u"Destination directory does not exist"))
1303                return
1304           
1305            if not isdir(pathEnc(self.ctrls.tfDestination.GetValue())):
1306                self.mainControl.displayErrorMessage(
1307                        _(u"Destination must be a directory"))
1308                return
1309        else:
1310            if exists(pathEnc(self.ctrls.tfDestination.GetValue())) and \
1311                    not isfile(pathEnc(self.ctrls.tfDestination.GetValue())):
1312                self.mainControl.displayErrorMessage(
1313                        _(u"Destination must be a file"))
1314                return
1315
1316        sarOp = self._getEffectiveListWikiPagesOperation()
1317        if sarOp is None:
1318            return
1319
1320        if panel is self.emptyPanel:
1321            panel = None
1322
1323        pgh = ProgressHandler(_(u"Exporting"), u"", 0, self)
1324        pgh.open(0)
1325        pgh.update(0, _(u"Preparing"))
1326
1327        try:
1328            if self.continuousExport:
1329                ob.startContinuousExport(self.mainControl.getWikiDocument(),
1330                        sarOp, etype, guiToUni(self.ctrls.tfDestination.GetValue()),
1331                        self.ctrls.compatFilenames.GetValue(), ob.getAddOpt(panel),
1332                        pgh)
1333   
1334                self.value = ob
1335            else:
1336                wordList = self.mainControl.getWikiDocument().searchWiki(sarOp,
1337                        True)
1338       
1339                try:
1340                    ob.export(self.mainControl.getWikiDocument(), wordList, etype,
1341                            guiToUni(self.ctrls.tfDestination.GetValue()),
1342                            self.ctrls.compatFilenames.GetValue(), ob.getAddOpt(panel),
1343                            pgh)
1344                except ExportException, e:
1345                    self.mainControl.displayErrorMessage(_(u"Error while exporting"),
1346                    unicode(e))
1347
1348        finally:
1349            pgh.close()
1350            self.EndModal(wx.ID_OK)
1351
1352       
1353    def OnSelectDest(self, evt):
1354        ob, etype, desc, panel = \
1355                self.exporterList[self.ctrls.chExportTo.GetSelection()][:4]
1356
1357        expDestWildcards = ob.getExportDestinationWildcards(etype)
1358
1359        if expDestWildcards is None:
1360            # Only transfer between GUI elements, so no unicode conversion
1361            seldir = wx.DirSelector(_(u"Select Export Directory"),
1362                    self.ctrls.tfDestination.GetValue(),
1363                    style=wx.DD_DEFAULT_STYLE|wx.DD_NEW_DIR_BUTTON, parent=self)
1364               
1365            if seldir:
1366                self.ctrls.tfDestination.SetValue(seldir)
1367
1368        else:
1369            # Build wildcard string
1370            wcs = []
1371            for wd, wp in expDestWildcards:
1372                wcs.append(wd)
1373                wcs.append(wp)
1374               
1375            wcs.append(_(u"All files (*.*)"))
1376            wcs.append(u"*")
1377           
1378            wcs = u"|".join(wcs)
1379           
1380            selfile = wx.FileSelector(_(u"Select Export File"),
1381                    self.ctrls.tfDestination.GetValue(),
1382                    default_filename = "", default_extension = "",
1383                    wildcard = wcs, flags=wx.SAVE | wx.OVERWRITE_PROMPT,
1384                    parent=self)
1385
1386            if selfile:
1387                self.ctrls.tfDestination.SetValue(selfile)
1388
1389
1390    def GetValue(self):
1391        return self.value
1392
1393
1394    def _getEffectiveListWikiPagesOperation(self):
1395        """
1396        Return the list operation appropriate for the current GUI settings.
1397        Shows message in case of an error and returns None
1398        """
1399        import SearchAndReplace as Sar
1400
1401        # Create wordList (what to export)
1402        selset = self.ctrls.chSelectedSet.GetSelection()
1403        root = self.mainControl.getCurrentWikiWord()
1404
1405        if root is None and selset in (0, 1):
1406            self.mainControl.displayErrorMessage(
1407                    _(u"No real wiki word selected as root"))
1408            return None
1409
1410        if selset == 3:
1411            return self.listPagesOperation
1412
1413        lpOp = Sar.ListWikiPagesOperation()
1414
1415        if selset == 0:
1416            # single page
1417            item = Sar.ListItemWithSubtreeWikiPagesNode(lpOp, [root], 0)
1418            lpOp.setSearchOpTree(item)
1419            lpOp.ordering = "asroottree"  # Slow, but more intuitive
1420        elif selset == 1:
1421            # subtree
1422            item = Sar.ListItemWithSubtreeWikiPagesNode(lpOp, [root], -1)
1423            lpOp.setSearchOpTree(item)
1424            lpOp.ordering = "asroottree"
1425        elif selset == 2:
1426            # whole wiki
1427            item = Sar.AllWikiPagesNode(lpOp)
1428            lpOp.setSearchOpTree(item)
1429            lpOp.ordering = "asroottree"
1430        else:
1431            raise InternalError("Unknown selection for export set")
1432
1433        result = Sar.SearchReplaceOperation()
1434        result.listWikiPagesOp = lpOp
1435
1436        return result
1437
1438
1439    def _refreshSavedExportsList(self):
1440#         wikiData = self.mainControl.getWikiData()
1441#         unifNames = wikiData.getDataBlockUnifNamesStartingWith(u"savedexport/")
1442#
1443#         result = []
1444#         for un in unifNames:
1445#             name = un[12:]
1446#             content = wikiData.retrieveDataBlock(un)
1447#             xmlDoc = minidom.parseString(content)
1448#             xmlNode = xmlDoc.firstChild
1449#             etype = Serialization.serFromXmlUnicode(xmlNode, u"exportTypeName")
1450#             if etype not in self.supportedExportTypes:
1451#                 # Export type of saved export not supported
1452#                 continue
1453#
1454#             result.append((name, xmlNode))
1455#
1456#         self.mainControl.getCollator().sortByFirst(result)
1457#
1458#         self.savedExports = result
1459
1460        from . import Exporters
1461
1462        self.savedExports = Exporters.retrieveSavedExportsList(self.mainControl,
1463                self.mainControl.getWikiData(), self.continuousExport)
1464
1465        self.ctrls.lbSavedExports.Clear()
1466        for exportName, xmlNode in self.savedExports:
1467            self.ctrls.lbSavedExports.Append(uniToGui(exportName))
1468
1469
1470
1471    def OnSaveExport(self, evt):
1472        defValue = u""
1473       
1474        sels = self.ctrls.lbSavedExports.GetSelections()
1475       
1476        if len(sels) == 1:
1477            defValue = self.savedExports[sels[0]][0]
1478
1479        while True:
1480            title = guiToUni(wx.GetTextFromUser(_(u"Title:"),
1481                    _(u"Choose export title"), defValue, self))
1482            if title == u"":
1483                return  # Cancel
1484               
1485            if (u"savedexport/" + title) in self.mainControl.getWikiData()\
1486                    .getDataBlockUnifNamesStartingWith(
1487                    u"savedexport/" + title):
1488
1489                answer = wx.MessageBox(
1490                        _(u"Do you want to overwrite existing export '%s'?") %
1491                        title, _(u"Overwrite export"),
1492                        wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION, self)
1493                if answer == wx.NO:
1494                    continue
1495
1496            xmlDoc = minidom.getDOMImplementation().createDocument(None, None, None)
1497            xmlHead = xmlDoc.createElement(u"savedExport")
1498
1499            xmlNode = self._buildSavedExport(xmlHead, xmlDoc)
1500            if xmlNode is None:
1501                return
1502           
1503            xmlDoc.appendChild(xmlNode)
1504            content = xmlDoc.toxml("utf-8")
1505            xmlDoc.unlink()
1506            self.mainControl.getWikiData().storeDataBlock(
1507                    u"savedexport/" + title, content,
1508                    storeHint=DATABLOCK_STOREHINT_INTERN)
1509           
1510            self._refreshSavedExportsList()
1511            return
1512
1513
1514    def OnLoadExport(self, evt):
1515        self._loadExport()
1516       
1517       
1518    def OnLoadAndRunExport(self, evt):
1519        if self._loadExport():
1520            self._runExporter()
1521
1522#     def OnLoadAndRunSearch(self, evt):
1523#         if self._loadSearch():
1524#             try:
1525#                 self._refreshSavedExportsList()
1526#             except re.error, e:
1527#                 self.displayErrorMessage(_(u'Error in regular expression'),
1528#                         _(unicode(e)))
1529
1530
1531    def OnDeleteExports(self, evt):
1532        sels = self.ctrls.lbSavedExports.GetSelections()
1533       
1534        if len(sels) == 0:
1535            return
1536
1537        answer = wx.MessageBox(
1538                _(u"Do you want to delete %i export(s)?") % len(sels),
1539                _(u"Delete export"),
1540                wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION, self)
1541        if answer == wx.NO:
1542            return
1543
1544        for s in sels:
1545            self.mainControl.getWikiData().deleteDataBlock(
1546                    u"savedexport/" + self.savedExports[s][0])
1547        self._refreshSavedExportsList()
1548
1549
1550    def _loadExport(self):
1551        sels = self.ctrls.lbSavedExports.GetSelections()
1552       
1553        if len(sels) != 1:
1554            return False
1555
1556        xmlNode = self.savedExports[sels[0]][1]
1557        return self._showExportProfile(xmlNode)
1558
1559
1560    def _buildSavedExport(self, xmlHead, xmlDoc):
1561        """
1562        Builds the saved export as XML code from GUI settings.
1563        Returns the xmlHead (aka XML "savedExport") node or None in
1564        case of an error.
1565        """
1566
1567        ob, etype, desc, panel = \
1568                self.exporterList[self.ctrls.chExportTo.GetSelection()][:4]
1569       
1570        addOptVer = ob.getAddOptVersion()
1571       
1572        if addOptVer == -1:
1573            # An addOpt version of -1 means that the addOpt value does not
1574            # have a defined format and therefore can't be stored
1575            self.mainControl.displayErrorMessage(
1576                    _(u"Selected export type does not support saving"))
1577            return None   # TODO Error message!!
1578
1579        Serialization.serToXmlUnicode(xmlHead, xmlDoc, u"exportTypeName", etype)
1580
1581        Serialization.serToXmlUnicode(xmlHead, xmlDoc, u"destinationPath",
1582                guiToUni(self.ctrls.tfDestination.GetValue()))
1583
1584        pageSetXml = xmlDoc.createElement(u"pageSet")
1585        xmlHead.appendChild(pageSetXml)
1586
1587        sarOp = self._getEffectiveListWikiPagesOperation()
1588        if sarOp is None:
1589            return None
1590
1591        sarOp.serializeToXml(pageSetXml, xmlDoc)
1592
1593        addOptXml = xmlDoc.createElement(u"additionalOptions")
1594        xmlHead.appendChild(addOptXml)
1595
1596        addOptXml.setAttribute(u"version", unicode(addOptVer))
1597        addOptXml.setAttribute(u"type", u"simpleTuple")
1598
1599        Serialization.convertTupleToXml(addOptXml, xmlDoc, ob.getAddOpt(panel))
1600
1601        return xmlHead
1602
1603
1604
1605    def _showExportProfile(self, xmlNode):
1606        from .SearchAndReplace import SearchReplaceOperation
1607
1608        try:
1609            etypeProfile = Serialization.serFromXmlUnicode(xmlNode,
1610                    u"exportTypeName")
1611
1612            for sel, (ob, etype, desc, panel) in enumerate(self.exporterList):
1613                if etype == etypeProfile:
1614                    break
1615            else:
1616                self.mainControl.displayErrorMessage(
1617                        _(u"Export type '%s' of saved export is not supported") %
1618                        etypeProfile)
1619                return False
1620
1621            addOptXml = Serialization.findXmlElementFlat(xmlNode,
1622                    u"additionalOptions")
1623
1624            addOptVersion = int(addOptXml.getAttribute(u"version"))
1625
1626            if addOptVersion != ob.getAddOptVersion():
1627                self.mainControl.displayErrorMessage(
1628                        _(u"Saved export uses different version for additional "
1629                        "options than current export\nExport type: '%s'\n"
1630                        "Saved export version: %i\nCurrent export version: %i") %
1631                        (etypeProfile, addOptVersion, ob.getAddOptVersion()))
1632                return False
1633
1634            if addOptXml.getAttribute(u"type") != u"simpleTuple":
1635                self.mainControl.displayErrorMessage(
1636                        _(u"Type of additional option storage ('%s') is unknown") %
1637                        addOptXml.getAttribute(u"type"))
1638                return False
1639   
1640            pageSetXml = Serialization.findXmlElementFlat(xmlNode, u"pageSet")
1641           
1642            sarOp = SearchReplaceOperation()
1643   
1644            sarOp.serializeFromXml(pageSetXml)
1645   
1646            addOpt = Serialization.convertTupleFromXml(addOptXml)
1647   
1648            self.listPagesOperation = sarOp
1649            self.ctrls.chSelectedSet.SetSelection(3)
1650            self.ctrls.chExportTo.SetSelection(sel)
1651            ob.setAddOpt(addOpt, panel)
1652   
1653            self.ctrls.tfDestination.SetValue(uniToGui(
1654                    Serialization.serFromXmlUnicode(xmlNode, u"destinationPath")))
1655                   
1656            self._refreshForEtype()
1657           
1658            return True
1659        except SerializationException, e:
1660            self.mainControl.displayErrorMessage(_(u"Error during retrieving "
1661                    "saved export: ") + e.message)
1662
1663
1664ExportDialog.runModal = staticmethod(runDialogModalFactory(ExportDialog))
1665
1666
1667
1668
1669
1670class ImportDialog(wx.Dialog):
1671    def __init__(self, parent, ID, mainControl, title="Import",
1672                 pos=wx.DefaultPosition, size=wx.DefaultSize):
1673        from . import Importers
1674
1675        d = wx.PreDialog()
1676        self.PostCreate(d)
1677       
1678        self.parent = parent
1679        self.mainControl = mainControl
1680       
1681        res = wx.xrc.XmlResource.Get()
1682        res.LoadOnDialog(self, self.parent, "ImportDialog")
1683
1684        self.ctrls = XrcControls(self)
1685
1686        self.emptyPanel = None
1687       
1688        importerList = [] # List of tuples (<importer object>, <import tag=type>,
1689                          # <readable description>, <additional options panel>)
1690       
1691        addOptSizer = LayerSizer()
1692
1693        for ob in Importers.describeImporters(self.mainControl):   # TODO search plugins
1694            for tp in ob.getImportTypes(self.ctrls.additOptions):
1695                panel = tp[2]
1696                if panel is None:
1697                    if self.emptyPanel is None:
1698                        # Necessary to avoid a crash       
1699                        self.emptyPanel = wx.Panel(self.ctrls.additOptions)
1700                        # self.emptyPanel.Fit()
1701                    panel = self.emptyPanel
1702                else:
1703                    pass
1704                    # panel.Fit()
1705
1706                # Add Tuple (Importer object, import type tag,
1707                #     import type description, additional options panel)
1708                importerList.append((ob, tp[0], tp[1], panel))
1709                addOptSizer.Add(panel)
1710
1711        self.ctrls.additOptions.SetSizer(addOptSizer)
1712        self.ctrls.additOptions.SetMinSize(addOptSizer.GetMinSize())
1713
1714        self.ctrls.additOptions.Fit()
1715        self.Fit()
1716
1717#         self.ctrls.additOptions.Fit()
1718#         mins = self.ctrls.additOptions.GetMinSize()
1719#         
1720#         self.ctrls.additOptions.SetMinSize(wx.Size(mins.width+10, mins.height+10))
1721#         self.Fit()
1722
1723       
1724        self.importerList = importerList
1725
1726        self.ctrls.btnOk.SetId(wx.ID_OK)
1727        self.ctrls.btnCancel.SetId(wx.ID_CANCEL)
1728       
1729        self.ctrls.tfSource.SetValue(self.mainControl.getLastActiveDir())
1730       
1731        for e in self.importerList:
1732            e[3].Show(False)
1733            e[3].Enable(False)
1734            self.ctrls.chImportFormat.Append(e[2])
1735           
1736#         # Enable first addit. options panel
1737#         self.importerList[0][3].Enable(True)
1738#         self.importerList[0][3].Show(True)
1739        self.ctrls.chImportFormat.SetSelection(0)
1740        self._refreshForItype()
1741       
1742        # Fixes focus bug under Linux
1743        self.SetFocus()
1744
1745        wx.EVT_CHOICE(self, GUI_ID.chImportFormat, self.OnImportFormat)
1746
1747        wx.EVT_BUTTON(self, wx.ID_OK, self.OnOk)
1748        wx.EVT_BUTTON(self, GUI_ID.btnSelectSource, self.OnSelectSrc)
1749
1750
1751    def _refreshForItype(self):
1752        """
1753        Refresh GUI depending on chosen import type
1754        """
1755        for e in self.importerList:
1756            e[3].Show(False)
1757            e[3].Enable(False)
1758
1759        ob, itype, desc, panel = \
1760                self.importerList[self.ctrls.chImportFormat.GetSelection()][:4]
1761
1762        # Enable appropriate addit. options panel
1763        panel.Enable(True)
1764        panel.Show(True)
1765
1766        impSrcWildcards = ob.getImportSourceWildcards(itype)
1767
1768        if impSrcWildcards is None:
1769            # Directory source
1770            self.ctrls.stSource.SetLabel(_(u"Source directory:"))
1771        else:
1772            # File source
1773            self.ctrls.stSource.SetLabel(_(u"Source file:"))
1774
1775
1776    def OnImportFormat(self, evt):
1777        self._refreshForItype()
1778        evt.Skip()
1779
1780
1781
1782    def OnOk(self, evt):
1783        # Run importer
1784        ob, itype, desc, panel = \
1785                self.importerList[self.ctrls.chImportFormat.GetSelection()][:4]
1786               
1787        if not exists(guiToUni(self.ctrls.tfSource.GetValue())):
1788            self.mainControl.displayErrorMessage(
1789                    _(u"Source does not exist"))
1790            return
1791
1792        # If this returns None, import goes to a directory
1793        impSrcWildcards = ob.getImportSourceWildcards(itype)
1794        if impSrcWildcards is None:
1795            # Import from a directory
1796           
1797            if not isdir(guiToUni(self.ctrls.tfSource.GetValue())):
1798                self.mainControl.displayErrorMessage(
1799                        _(u"Source must be a directory"))
1800                return
1801        else:
1802            if not isfile(guiToUni(self.ctrls.tfSource.GetValue())):
1803                self.mainControl.displayErrorMessage(
1804                        _(u"Source must be a file"))
1805                return
1806
1807        if panel is self.emptyPanel:
1808            panel = None
1809
1810        try:
1811            ob.doImport(self.mainControl.getWikiDocument(), itype,
1812                    guiToUni(self.ctrls.tfSource.GetValue()),
1813                    False, ob.getAddOpt(panel))
1814        except ImportException, e:
1815            self.mainControl.displayErrorMessage(_(u"Error while importing"),
1816                    unicode(e))
1817
1818        self.EndModal(wx.ID_OK)
1819
1820       
1821    def OnSelectSrc(self, evt):
1822        ob, itype, desc, panel = \
1823                self.importerList[self.ctrls.chImportFormat.GetSelection()][:4]
1824
1825        impSrcWildcards = ob.getImportSourceWildcards(itype)
1826
1827        if impSrcWildcards is None:
1828            # Only transfer between GUI elements, so no unicode conversion
1829            seldir = wx.DirSelector(_(u"Select Import Directory"),
1830                    self.ctrls.tfSource.GetValue(),
1831                    style=wx.DD_DEFAULT_STYLE, parent=self)
1832
1833            if seldir:
1834                self.ctrls.tfSource.SetValue(seldir)
1835
1836        else:
1837            # Build wildcard string
1838            wcs = []
1839            for wd, wp in impSrcWildcards:
1840                wcs.append(wd)
1841                wcs.append(wp)
1842               
1843            wcs.append(_(u"All files (*.*)"))
1844            wcs.append(_(u"*"))
1845           
1846            wcs = u"|".join(wcs)
1847           
1848            selfile = wx.FileSelector(_(u"Select Import File"),
1849                    self.ctrls.tfSource.GetValue(),
1850                    default_filename = "", default_extension = "",
1851                    wildcard = wcs, flags=wx.OPEN | wx.FILE_MUST_EXIST,
1852                    parent=self)
1853
1854            if selfile:
1855                self.ctrls.tfSource.SetValue(selfile)
1856
1857
1858
1859def _children(win, indent=0):
1860    print " " * indent + repr(win), win.GetId()
1861    for c in win.GetChildren():
1862        _children(c, indent=indent+2)
1863
1864
1865
1866class NewWikiSettings(wx.Dialog):
1867    """
1868    Dialog to choose options when creating a new wiki or when a wiki with
1869    damaged configuration file is opened.
1870    """
1871    DEFAULT_GREY = 1
1872
1873    def __init__(self, parent, ID, mainControl, defDbHandler=None,
1874            defWikiLang=None, title="", pos=wx.DefaultPosition,
1875            size=wx.DefaultSize):
1876        d = wx.PreDialog()
1877        self.PostCreate(d)
1878
1879        self.mainControl = mainControl
1880        self.value = None, None
1881
1882        res = wx.xrc.XmlResource.Get()
1883        res.LoadOnDialog(self, parent, "NewWikiSettingsDialog")
1884
1885        self.ctrls = XrcControls(self)
1886
1887        # Retrieve lists of db backends and wiki languages
1888        self.dbHandlers = DbBackendUtils.listHandlers()
1889        self.wikiLanguages = wx.GetApp().listWikiLanguageDescriptions()
1890
1891        errMsg = ""
1892
1893        if len(self.dbHandlers) == 0:
1894            errMsg += 'No data handler available'
1895        if len(self.wikiLanguages) == 0:
1896            errMsg += 'No wiki language handler available'
1897
1898        if errMsg:
1899            self.mainControl.displayErrorMessage(errMsg)
1900            self.EndModal(wx.ID_CANCEL)
1901            return
1902
1903        if defDbHandler is not NewWikiSettings.DEFAULT_GREY:
1904            self.ctrls.lbDatabaseType.Set([h[1] for h in self.dbHandlers])
1905            for i, h in enumerate(self.dbHandlers):
1906                if h[0] == defDbHandler:
1907                    self.ctrls.lbDatabaseType.SetSelection(i)
1908                    break
1909            else:
1910                self.ctrls.lbDatabaseType.SetSelection(0)
1911
1912            self.ctrls.cbWikiPageFilesAsciiOnly.SetValue(SystemInfo.isOSX())
1913
1914        else:
1915            self.ctrls.lbDatabaseType.Enable(False)
1916            self.ctrls.cbWikiPageFilesAsciiOnly.Enable(False)
1917            self.ctrls.lbDatabaseType.SetBackgroundColour(wx.LIGHT_GREY)
1918
1919        if defWikiLang is not NewWikiSettings.DEFAULT_GREY:
1920            self.ctrls.lbWikiLanguage.Set([l[1] for l in self.wikiLanguages])
1921            for i, l in enumerate(self.wikiLanguages):
1922                if l[0] == defWikiLang:
1923                    self.ctrls.lbWikiLanguage.SetSelection(i)
1924                    break
1925            else:
1926                self.ctrls.lbWikiLanguage.SetSelection(0)
1927
1928        else:
1929            self.ctrls.lbWikiLanguage.Enable(False)
1930            self.ctrls.lbWikiLanguage.SetBackgroundColour(wx.LIGHT_GREY)
1931
1932        self.ctrls.btnOk.SetId(wx.ID_OK)
1933        self.ctrls.btnCancel.SetId(wx.ID_CANCEL)
1934
1935        wx.EVT_BUTTON(self, wx.ID_OK, self.OnOk)
1936
1937
1938    def GetValue(self):
1939        return self.value
1940
1941    def OnOk(self, evt):
1942        dbSel = self.ctrls.lbDatabaseType.GetSelection()
1943        langSel = self.ctrls.lbWikiLanguage.GetSelection()
1944       
1945        dbH = None
1946        wlH = None
1947       
1948        if dbSel != wx.NOT_FOUND:
1949            dbH = self.dbHandlers[dbSel][0]
1950        if langSel != wx.NOT_FOUND:
1951            wlH = self.wikiLanguages[langSel][0]
1952       
1953        self.value = (dbH, wlH, self.ctrls.cbWikiPageFilesAsciiOnly.GetValue())
1954
1955        self.EndModal(wx.ID_OK)
1956
1957NewWikiSettings.runModal = staticmethod(runDialogModalFactory(NewWikiSettings))
1958
1959
1960
1961class AboutDialog(wx.Dialog):
1962    """ An about box that uses an HTML window """
1963
1964    TEXT_TEMPLATE = N_(u'''
1965<html>
1966<body bgcolor="#FFFFFF">
1967    <center>
1968        <table bgcolor="#CCCCCC" width="100%%" cellspacing="0" cellpadding="0" border="1">
1969            <tr>
1970                <td align="center"><h2>%s</h2></td>
1971            </tr>
1972        </table>
1973
1974        <p>
1975wikidPad is a Wiki-like notebook for storing your thoughts, ideas, todo lists, contacts, or anything else you can think of to write down.
1976What makes wikidPad different from other notepad applications is the ease with which you can cross-link your information.        </p>       
1977        <br><br>
1978
1979        <table border=0 cellpadding=1 cellspacing=0>
1980            <tr><td width="30%%" align="right"><font size="3"><b>Author:</b></font></td><td nowrap><font size="3">Michael Butscher</font></td></tr>
1981            <tr><td width="30%%" align="right"><font size="3"><b>Email:</b></font></td><td nowrap><font size="3">mbutscher@gmx.de</font></td></tr>
1982            <tr><td width="30%%" align="right"><font size="3"><b>URL:</b></font></td><td nowrap><font size="3">http://www.mbutscher.de/software.html</font></td></tr>
1983            <tr><td width="30%%" align="right">&nbsp;</td></tr>
1984            <tr><td width="30%%" align="right"><font size="3"><b>Author:</b></font></td><td nowrap><font size="3">Jason Horman</font></td></tr>
1985            <tr><td width="30%%" align="right"><font size="3"><b>Email:</b></font></td><td nowrap><font size="3">wikidpad@jhorman.org</font></td></tr>
1986            <tr><td width="30%%" align="right"><font size="3"><b>URL:</b></font></td><td nowrap><font size="3">http://www.jhorman.org/wikidPad/</font></td></tr>
1987            <tr><td width="30%%" align="right">&nbsp;</td></tr>
1988            <tr><td width="30%%" align="right"><font size="3"><b>Author:</b></font></td><td nowrap><font size="3">Gerhard Reitmayr</font></td></tr>
1989            <tr><td width="30%%" align="right"><font size="3"><b>Email:</b></font></td><td nowrap><font size="3">gerhard.reitmayr@gmail.com</font></td></tr>
1990            <tr><td width="30%%" align="right">&nbsp;</td></tr>
1991            <tr><td width="30%%" align="right">&nbsp;</td></tr>
1992            <tr><td width="30%%" align="left" colspan="2" nowrap><font size="3"><b>Translations:</b></font></td></tr>
1993            <tr><td width="30%%" align="right"><font size="3"><b>Chinese:</b></font></td><td nowrap><font size="3">yuxiaoxu@msn.com</font></td></tr>
1994            <tr><td width="30%%" align="right"><font size="3"><b>Hungarian:</b></font></td><td nowrap><font size="3">Török Árpád</font></td></tr>
1995            <tr><td width="30%%" align="right"><font size="3"><b>Russian:</b></font></td><td nowrap><font size="3">Oleg Domanov</font></td></tr>
1996            <tr><td width="30%%" align="right"><font size="3"><b>Swedish:</b></font></td><td nowrap><font size="3">Stefan Berg</font></td></tr>
1997        </table>
1998    </center>
1999   
2000   
2001
2002   
2003    <hr />
2004   
2005    <p>Your configuration directory is: <b>%s</b><br />
2006    Sqlite version: <b>%s</b><br />
2007    wxPython version: <b>%s</b>
2008    </p>
2009   
2010</body>
2011</html>
2012''')
2013
2014    def __init__(self, pWiki):
2015        wx.Dialog.__init__(self, pWiki, -1, _(u'About WikidPad'),
2016                          size=(470, 330) )
2017       
2018        if sqlite is None:
2019            sqliteVer = _(u"N/A")
2020        else:
2021            sqliteVer = sqlite.getLibVersion()
2022
2023        text = _(self.TEXT_TEMPLATE) % (VERSION_STRING,
2024                escapeHtml(pWiki.globalConfigDir), escapeHtml(sqliteVer),
2025                escapeHtml(wx.__version__))
2026
2027        html = wx.html.HtmlWindow(self, -1)
2028        html.SetPage(text)
2029        button = wx.Button(self, wx.ID_OK, _(u"Okay"))
2030
2031        # constraints for the html window
2032        lc = wx.LayoutConstraints()
2033        lc.top.SameAs(self, wx.Top, 5)
2034        lc.left.SameAs(self, wx.Left, 5)
2035        lc.bottom.SameAs(button, wx.Top, 5)
2036        lc.right.SameAs(self, wx.Right, 5)
2037        html.SetConstraints(lc)
2038
2039        # constraints for the button
2040        lc = wx.LayoutConstraints()
2041        lc.bottom.SameAs(self, wx.Bottom, 5)
2042        lc.centreX.SameAs(self, wx.CentreX)
2043        lc.width.AsIs()
2044        lc.height.AsIs()
2045        button.SetConstraints(lc)
2046
2047        self.SetAutoLayout(True)
2048        self.Layout()
2049        self.CentreOnParent(wx.BOTH)
2050       
2051        # Fixes focus bug under Linux
2052        self.SetFocus()
2053
2054
2055
2056class SimpleInfoDialog(wx.Dialog):
2057    def __init__(self, *args, **kwargs):
2058        wx.Dialog.__init__(self, *args, **kwargs)
2059
2060        self.txtBgColor = self.GetBackgroundColour()
2061
2062        button = wx.Button(self, wx.ID_OK)
2063        button.SetDefault()
2064
2065        mainsizer = wx.BoxSizer(wx.VERTICAL)
2066
2067        self.lineSizer = wx.FlexGridSizer(0, 2)
2068        self.lineSizer.AddGrowableCol(1, 1)
2069
2070        self.fillInfoLines()
2071
2072        mainsizer.Add(self.lineSizer, 0, wx.ALL | wx.EXPAND, 0)
2073
2074        inputsizer = wx.BoxSizer(wx.HORIZONTAL)
2075        inputsizer.Add(button, 0, wx.ALL | wx.EXPAND, 5)
2076        inputsizer.Add((0, 0), 1)   # Stretchable spacer
2077
2078        mainsizer.Add(inputsizer, 0, wx.ALL | wx.EXPAND, 0)
2079       
2080        wx.EVT_BUTTON(self, wx.ID_OK, self.OnOk)
2081        wx.EVT_CLOSE(self, self.OnOk)
2082
2083
2084        self.SetSizer(mainsizer)
2085        self.Fit()
2086
2087        # Fixes focus bug under Linux
2088        self.SetFocus()
2089
2090
2091
2092    def _addLine(self, label, value, multiLine=False):
2093
2094        if value is not None:
2095            self.lineSizer.Add(wx.StaticText(self, -1, label), 0,
2096                    wx.ALL | wx.EXPAND, 5)
2097        else:
2098            # If no value given, show no label (as static text)
2099            # but show label as value
2100            self.lineSizer.Add((0, 0), 1)
2101            value = label
2102
2103        if multiLine:
2104            ctl = wx.TextCtrl(self, -1, value,
2105                    style = wx.TE_MULTILINE | wx.TE_READONLY)
2106        else:
2107            ctl = wx.TextCtrl(self, -1, value, style = wx.TE_READONLY)
2108        ctl.SetBackgroundColour(self.txtBgColor)
2109        self.lineSizer.Add(ctl, 1, wx.ALL | wx.EXPAND, 5)
2110
2111        return ctl
2112
2113       
2114    def fillInfoLines(self):
2115        raise NotImplementedError #abstract
2116       
2117   
2118    def OnOk(self, evt):
2119        evt.Skip()
2120       
2121
2122
2123
2124class WikiPropertiesDialog(SimpleInfoDialog):
2125    """
2126    Show general information about currently open wiki
2127    """
2128    def __init__(self, parent, id, mainControl):
2129        self.mainControl = mainControl
2130        SimpleInfoDialog.__init__(self, parent, id, _(u'Wiki Properties'),
2131                          size=(470, 330),
2132                          style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER)
2133
2134    def fillInfoLines(self):
2135        wd = self.mainControl.getWikiDocument()
2136        if wd is None:
2137            label = _(u"No wiki loaded")
2138            self._addLine(label, None)
2139            return
2140
2141        label = _(u"Wiki config. path:")
2142        value = wd.getWikiConfigPath()
2143        self._addLine(label, value)
2144
2145#         wikiData = wd.getWikiData()
2146
2147        label = _(u"Wiki database backend:")
2148#         if wd is None:
2149#             value = _(u"N/A")
2150#         else:
2151        value = wd.getDbtype()
2152
2153        self._addLine(label, value)
2154
2155        label = _(u"Number of wiki pages:")
2156#         if wd is None:
2157#             value = _(u"N/A")
2158#         else:
2159        value = unicode(len(wd.getAllDefinedWikiPageNames()))
2160
2161        self._addLine(label, value)
2162
2163        if wd.isReadOnlyEffect():
2164            label = _(u"Wiki is read-only. Reason:")
2165
2166            if wd.getWriteAccessFailed():
2167                value = _(u"Write access to database lost. Try \"Wiki\"->\"Reconnect\"")
2168            elif wd.getWriteAccessDeniedByConfig():
2169                value = _(u"Wiki was set read-only in options dialog")
2170            elif wd.getWriteAccessDenied():
2171                try:
2172                    f = open(pathEnc(wd.getWikiConfigPath()), "r+b")
2173                    f.close()
2174                    value = _("Can't write wiki config.:") + u" " + _("Unknown reason")
2175                except IOError, e:
2176                    value = _("Can't write wiki config.:") + u" " + unicode(e)
2177            else:
2178                value = _("Unknown reason")
2179           
2180            self._addLine(label, value, multiLine=True)
2181
2182
2183class WikiJobDialog(SimpleInfoDialog):
2184    """
2185    Show information about currently open wiki
2186    """
2187    def __init__(self, parent, id, mainControl):
2188        self.jobTxtCtrl = None
2189        self.mainControl = mainControl
2190
2191        SimpleInfoDialog.__init__(self, parent, id, _(u'Jobs'),
2192                          size=(470, 330) )
2193
2194        # Start timer
2195        self.timer = wx.Timer(self, GUI_ID.TIMER_JOBDIALOG)
2196        self.OnTimer(None)
2197        self.timer.Start(500, False)
2198
2199        wx.EVT_TIMER(self, GUI_ID.TIMER_JOBDIALOG, self.OnTimer)
2200
2201
2202    def OnOk(self, evt):
2203        evt.Skip()
2204        self.timer.Stop()
2205       
2206
2207    def fillInfoLines(self):
2208        self.jobTxtCtrl = self._addLine(_(u"Number of Jobs:"), u"0")
2209
2210    def OnTimer(self, evt):
2211        wd = self.mainControl.getWikiDocument()
2212        if wd is not None:
2213            exe = wd.getUpdateExecutor()
2214            if exe is not None:
2215                self.jobTxtCtrl.SetValue(unicode(exe.getJobCount()))
Note: See TracBrowser for help on using the browser.