root/branches/mbutscher/work/lib/pwiki/PersonalWikiFrame.py @ 190

Revision 190, 202.6 kB (checked in by mbutscher, 4 years ago)

branches/mbutscher/work:
2.0beta02

* Faster stop when closing WikidPad
* Option to let selection in doc. structure

automatically follow text cursor position in editor

* Saved exports similar to saved searches
* Wiki page files in UTF-16 encoding (with

appropriate BOM) can now be read by WikidPad

* Bug fixed: Wiki-wide search couldn't be opened if

a functional page was in current editor

* Bug fixed: Dialog to append/prepend wikiword failed

Line 
1## import hotshot
2## _prof = hotshot.Profile("hotshot.prf")
3
4import os, sys, gc, traceback, string, re
5from os.path import *
6from time import localtime, time, sleep
7
8import cPickle  # to create dependency?
9
10import wx, wx.html
11
12# import urllib_red as urllib
13# import urllib
14
15from wxHelper import GUI_ID, getAccelPairFromKeyDown, \
16        getAccelPairFromString, LayerSizer, appendToMenuByMenuDesc, \
17        setHotKeyByString, DummyWindow, IdRecycler, clearMenu, \
18        copyTextToClipboard, ProgressHandler
19
20import TextTree
21
22from MiscEvent import MiscEventSourceMixin, ProxyMiscEvent  # , DebugSimple
23
24from WikiExceptions import *
25from Consts import HOMEPAGE
26
27import Configuration
28from WindowLayout import WindowSashLayouter, setWindowPos, setWindowSize
29
30from wikidata import DbBackendUtils, WikiDataManager
31
32# To generate py2exe dependency
33import WikiDocument
34
35import OsAbstract
36
37import DocPages
38
39
40from CmdLineAction import CmdLineAction
41from WikiTxtCtrl import WikiTxtCtrl, FOLD_MENU
42from WikiTreeCtrl import WikiTreeCtrl
43from WikiHtmlView import createWikiHtmlView
44from LogWindow import LogWindow
45from DocStructureCtrl import DocStructureCtrl
46from timeView.TimeViewCtrl import TimeViewCtrl
47from MainAreaPanel import MainAreaPanel
48from UserActionCoord import UserActionCoord
49from DocPagePresenter import DocPagePresenter
50
51from Ipc import EVT_REMOTE_COMMAND
52
53import PropertyHandling, SpellChecker
54
55# from PageHistory import PageHistory
56 #from SearchAndReplace import SearchReplaceOperation
57from Printing import Printer, PrintMainDialog
58
59from AdditionalDialogs import *
60import AdditionalDialogs
61from OptionsDialog import OptionsDialog
62from SearchAndReplaceDialogs import *
63
64
65
66import Exporters
67from StringOps import uniToGui, guiToUni, mbcsDec, mbcsEnc, \
68        unescapeForIni, \
69        wikiUrlToPathWordAndAnchor, urlFromPathname, flexibleUrlUnquote, \
70        strftimeUB, pathEnc, loadEntireFile, writeEntireFile, \
71        pathWordAndAnchorToWikiUrl, relativeFilePath, pathnameFromUrl
72
73
74from PluginManager import *
75
76# TODO More abstract/platform independent
77try:
78    import WindowsHacks
79except:
80    if Configuration.isWindows():
81        traceback.print_exc()
82    WindowsHacks = None
83
84
85
86class KeyBindingsCache:
87    def __init__(self, kbModule):
88        self.kbModule = kbModule
89        self.accelPairCache = {}
90       
91    def __getattr__(self, attr):
92        return getattr(self.kbModule, attr, u"")
93   
94    def get(self, attr, default=None):
95        return getattr(self.kbModule, attr, None)
96
97    def getAccelPair(self, attr):
98        try:
99            return self.accelPairCache[attr]
100        except KeyError:
101            ap = getAccelPairFromString("\t" + getattr(self, attr))
102            self.accelPairCache[attr] = ap
103            return ap
104
105    def matchesAccelPair(self, attr, accP):
106        return self.getAccelPair(attr) == accP
107
108
109class LossyWikiCloseDeniedException(Exception):
110    """
111    Special exception thrown by PersonalWikiFrame.closeWiki() if user denied
112    to close the wiki because it might lead to data loss
113    """
114    pass
115
116
117
118def _buildChainedUpdateEventFct(chain):
119    def evtFct(evt):
120        evt.Enable(True)
121        for fct in chain:
122            fct(evt)
123       
124    return evtFct
125
126
127# def _buildUpdateEventFctByEnableExpress(expr):
128#     def evtFct(evt):
129#         
130#         
131#         evt.Enable(True)
132#         for fct in chain:
133#             fct(evt)
134#         
135#     return evtFct
136
137   
138
139class PersonalWikiFrame(wx.Frame, MiscEventSourceMixin):
140    HOTKEY_ID_HIDESHOW_BYAPP = 1
141    HOTKEY_ID_HIDESHOW_BYWIKI = 2
142
143    def __init__(self, parent, id, title, wikiAppDir, globalConfigDir,
144            globalConfigSubDir, cmdLineAction):
145        # Do not use member variables starting with "externalPlugin_"! They
146        # are reserved for external plugins.
147        wx.Frame.__init__(self, parent, -1, title, size = (700, 550),
148                         style=wx.DEFAULT_FRAME_STYLE|wx.NO_FULL_REPAINT_ON_RESIZE)
149        MiscEventSourceMixin.__init__(self)
150
151        if cmdLineAction.cmdLineError:
152            cmdLineAction.showCmdLineUsage(self,
153                    _(u"Bad formatted command line.") + u"\n\n")
154            self.Close()
155            self.Destroy()
156            return
157
158        self.sleepMode = False  # Is program in low resource sleep mode?
159
160#         if not globalConfigDir or not exists(globalConfigDir):
161#             self.displayErrorMessage(
162#                     u"Error initializing environment, couldn't locate "+
163#                     u"global config directory", u"Shutting Down")
164#             self.Close()
165
166
167        # initialize some variables
168        self.globalConfigDir = globalConfigDir
169        self.wikiAppDir = wikiAppDir
170
171        self.globalConfigSubDir = globalConfigSubDir
172
173        # Create the "[TextBlocks].wiki" file in the global config subdirectory
174        # if the file doesn't exist yet.
175        tbLoc = join(self.globalConfigSubDir, "[TextBlocks].wiki")
176        if not exists(pathEnc(tbLoc)):
177            writeEntireFile(tbLoc,
178"""importance: high;a=[importance: high]\\n
179importance: low;a=[importance: low]\\n
180tree_position: 0;a=[tree_position: 0]\\n
181wrap: 80;a=[wrap: 80]\\n
182camelCaseWordsEnabled: false;a=[camelCaseWordsEnabled: false]\\n
183""", True)
184        self.configuration = wx.GetApp().createCombinedConfiguration()
185       
186        # Listen to application events
187        wx.GetApp().getMiscEvent().addListener(self)
188       
189        self.wikiPadHelp = join(self.wikiAppDir, 'WikidPadHelp',
190                'WikidPadHelp.wiki')
191        self.windowLayouter = None  # will be set by initializeGui()
192
193        # defaults
194        self.wikiData = None
195        self.wikiDataManager = None
196        self.lastCursorPositionInPage = {}
197        self.wikiHistory = []
198        self.findDlg = None  # Stores find&replace dialog, if present
199        self.mainWwSearchDlg = None
200        self.wwSearchDlgs = []   # Stores wiki wide search dialogs and detached fast search frames
201        self.spellChkDlg = None  # Stores spell check dialog, if present
202        self.continuousExporter = None   # Exporter-derived object if continuous export is in effect
203       
204        self.mainAreaPanel = None
205        self.mainmenu = None
206
207        self.recentWikisMenu = None
208        self.recentWikisActivation = IdRecycler()
209
210        self.textBlocksMenu = None
211        self.textBlocksActivation = IdRecycler() # See self.fillTextBlocksMenu()
212
213        self.favoriteWikisMenu = None
214        self.favoriteWikisActivation = IdRecycler()
215
216        self.pluginsMenu = None
217        self.fastSearchField = None   # Text field in toolbar
218       
219        self.cmdIdToIconNameForAttribute = None # Maps command id (=menu id) to icon name
220                                    # needed for "Editor"->"Add icon attribute"
221        self.cmdIdToColorNameForAttribute = None # Same for color names
222       
223        self.cmdIdToInsertString = None
224
225        self.eventRoundtrip = 0
226
227        self.currentWikiDocumentProxyEvent = ProxyMiscEvent(self)
228        self.currentWikiDocumentProxyEvent.addListener(self)
229
230        # setup plugin manager and hooks API
231        dirs = ( join(self.globalConfigSubDir, u'user_extensions'),
232                join(self.wikiAppDir, u'user_extensions'),
233                join(self.wikiAppDir, u'extensions') )
234        self.pluginManager = PluginManager(dirs)
235
236#         wx.GetApp().pauseBackgroundThreads()
237
238        self.hooks = self.pluginManager.registerPluginAPI(("hooks",1),
239            ["startup", "newWiki", "createdWiki", "openWiki", "openedWiki",
240             "openWikiWord", "newWikiWord", "openedWikiWord", "savingWikiWord",
241             "savedWikiWord", "renamedWikiWord", "deletedWikiWord", "exit"] )
242        # interfaces for menu and toolbar plugins
243        self.menuFunctions = self.pluginManager.registerPluginAPI(("MenuFunctions",1),
244                                ("describeMenuItems",))
245        self.toolbarFunctions = self.pluginManager.registerPluginAPI(("ToolbarFunctions",1),
246                                ("describeToolbarItems",))
247
248        # load extensions
249        self.loadExtensions()
250
251        self.propertyChecker = PropertyHandling.PropertyChecker(self)
252
253        self.configuration.setGlobalConfig(wx.GetApp().getGlobalConfig())
254
255        # trigger hook
256        self.hooks.startup(self)
257
258        # Initialize printing
259        self.printer = Printer(self)
260
261        # wiki history
262        history = self.configuration.get("main", "wiki_history")
263        if history:
264            self.wikiHistory = history.split(u";")
265
266        # clipboard catcher 
267        if WindowsHacks is None:
268            self.clipboardInterceptor = None
269            self.browserMoveInterceptor = None
270            self._interceptCollection = None
271        else:
272            self.clipboardInterceptor = WindowsHacks.ClipboardCatchIceptor(self)
273            self.browserMoveInterceptor = WindowsHacks.BrowserMoveIceptor(self)
274
275            self._interceptCollection = WindowsHacks.WinProcInterceptCollection(
276                    (self.clipboardInterceptor,
277                    self.browserMoveInterceptor))
278            self._interceptCollection.start(self.GetHandle())
279
280#             self.clipboardInterceptor.intercept(self.GetHandle())
281
282        # resize the window to the last position/size
283        setWindowSize(self, (self.configuration.getint("main", "size_x", 200),
284                self.configuration.getint("main", "size_y", 200)))
285        setWindowPos(self, (self.configuration.getint("main", "pos_x", 10),
286                self.configuration.getint("main", "pos_y", 10)))
287
288        # Set the auto save timing
289        self.autoSaveDelayAfterKeyPressed = self.configuration.getint(
290                "main", "auto_save_delay_key_pressed")
291        self.autoSaveDelayAfterDirty = self.configuration.getint(
292                "main", "auto_save_delay_dirty")
293
294        # get the position of the splitter
295        self.lastSplitterPos = self.configuration.getint("main", "splitter_pos")
296               
297        self.layoutMainTreePosition = self.configuration.getint("main",
298                "mainTree_position", 0)
299        self.layoutViewsTreePosition = self.configuration.getint("main",
300                "viewsTree_position", 0)
301        self.layoutDocStructurePosition = self.configuration.getint("main",
302                "docStructure_position", 0)
303        self.layoutTimeViewPosition = self.configuration.getint("main",
304                "timeView_position", 0)
305
306        # this will keep track of the last font used in the editor
307        self.lastEditorFont = None
308
309        # should WikiWords be enabled or not for the current wiki
310        self.wikiWordsEnabled = True
311
312        # if a wiki to open wasn't passed in use the last_wiki from the global config
313        wikiToOpen = cmdLineAction.wikiToOpen
314        wikiWordsToOpen = cmdLineAction.wikiWordsToOpen
315        anchorToOpen = cmdLineAction.anchorToOpen
316
317        if not wikiToOpen:
318            wikiToOpen = self.configuration.get("main", "last_wiki")
319
320        # initialize the GUI
321        self.initializeGui()
322
323        # Minimize on tray?
324        ## self.showOnTray = self.globalConfig.getboolean("main", "showontray")
325
326        self.tbIcon = None
327        self.setShowOnTray()
328
329        # windowmode:  0=normal, 1=maximized, 2=iconized, 3=maximized iconized(doesn't work)
330        windowmode = self.configuration.getint("main", "windowmode")
331
332        if windowmode & 1:
333            self.Maximize(True)
334        if windowmode & 2:
335            self.Iconize(True)
336           
337        # Set app-bound hot key
338        self.hotKeyDummyWindow = None
339        self._refreshHotKeys()
340
341        # if a wiki to open is set, open it
342        if wikiToOpen:
343            if exists(pathEnc(wikiToOpen)):
344 #                tracer.runctx('self.openWiki(wikiToOpen, wikiWordsToOpen, anchorToOpen=anchorToOpen)', globals(), locals())
345                self.openWiki(wikiToOpen, wikiWordsToOpen,
346                        anchorToOpen=anchorToOpen)
347#                 wx.GetApp().pauseBackgroundThreads()
348            else:
349                self.statusBar.SetStatusText(
350                        uniToGui(_(u"Last wiki doesn't exist: %s") % wikiToOpen), 0)
351
352        cmdLineAction.actionBeforeShow(self)
353
354        if cmdLineAction.exitFinally:
355            self.exitWiki()
356            return
357
358        self.userActionCoord = UserActionCoord(self)
359        self.userActionCoord.applyConfiguration()
360
361        self.Show(True)
362
363        EVT_REMOTE_COMMAND(self, self.OnRemoteCommand)
364
365        # Inform that idle handlers and window-specific threads can now be started
366        self.fireMiscEventKeys(("constructed main window",))
367
368#         finally:
369#             wx.GetApp().resumeBackgroundThreads()
370
371
372    def loadExtensions(self):
373#         self.wikidPadHooks = self.getExtension('WikidPadHooks', u'WikidPadHooks.py')
374        self.keyBindings = KeyBindingsCache(
375                self.getExtension('KeyBindings', u'KeyBindings.py'))
376        self.evalLib = self.getExtension('EvalLibrary', u'EvalLibrary.py')
377        self.presentationExt = self.getExtension('Presentation', u'Presentation.py')
378        self.pluginManager.loadPlugins([ u'KeyBindings.py',
379                u'EvalLibrary.py' ] )
380
381
382    def getExtension(self, extensionName, fileName):
383        extensionFileName = join(self.globalConfigSubDir, u'user_extensions',
384                fileName)
385        if exists(pathEnc(extensionFileName)):
386            userUserExtension = loadEntireFile(extensionFileName, True)
387        else:
388            userUserExtension = None
389
390        extensionFileName = join(self.wikiAppDir, 'user_extensions', fileName)
391        if exists(pathEnc(extensionFileName)):
392            userExtension = loadEntireFile(extensionFileName, True)
393        else:
394            userExtension = None
395
396        extensionFileName = join(self.wikiAppDir, 'extensions', fileName)
397        systemExtension = loadEntireFile(extensionFileName, True)
398
399        return importCode(systemExtension, userExtension, userUserExtension,
400                extensionName)
401
402
403    def getCurrentWikiWord(self):
404        docPage = self.getCurrentDocPage()
405        if docPage is None or not isinstance(docPage,
406                (DocPages.WikiPage, DocPages.AliasWikiPage)):
407            return None
408        return docPage.getWikiWord()
409
410    def getCurrentDocPage(self):
411        if self.getCurrentDocPagePresenter() is None:
412            return None
413        return self.getCurrentDocPagePresenter().getDocPage()
414
415    def getActiveEditor(self):
416        if self.getCurrentDocPagePresenter() is None:
417            return None
418        return self.getCurrentDocPagePresenter().getSubControl("textedit")
419
420    def getMainAreaPanel(self):
421        return self.mainAreaPanel
422
423    def getCurrentDocPagePresenter(self):
424        """
425        Convenience function. If main area's current presenter is not a
426        doc page presenter, None is returned.
427        """
428        if self.mainAreaPanel is None:
429            return None
430
431        presenter = self.mainAreaPanel.getCurrentPresenter()
432
433        if not isinstance(presenter, DocPagePresenter):
434            return None
435
436        return presenter
437
438    def getCurrentPresenterProxyEvent(self):
439        """
440        This ProxyMiscEvent resends any messsages from the currently
441        active DocPagePresenter
442        """
443        return self.mainAreaPanel.getCurrentPresenterProxyEvent()
444
445    def getCurrentWikiDocumentProxyEvent(self):
446        """
447        This ProxyMiscEvent resends any messsages from the currently
448        active WikiDocument
449        """
450        return self.currentWikiDocumentProxyEvent
451
452    def getWikiData(self):
453        if self.wikiDataManager is None:
454            return None
455
456        return self.wikiDataManager.getWikiData()
457
458    def getWikiDataManager(self):
459        """
460        Deprecated, use getWikiDocument() instead
461        """
462        return self.wikiDataManager
463
464    def getWikiDocument(self):
465        return self.wikiDataManager
466
467    def isWikiLoaded(self):
468        return self.getWikiDocument() is not None
469
470    def getWikiConfigPath(self):
471        if self.wikiDataManager is None:
472            return None
473
474        return self.wikiDataManager.getWikiConfigPath()
475       
476    def getWikiDefaultWikiLanguage(self):
477        if self.wikiDataManager is None:
478            # No wiki loaded, so take users default
479            return wx.GetApp().getUserDefaultWikiLanguage()
480
481        return self.wikiDataManager.getWikiDefaultWikiLanguage()
482
483#     def getUserDefaultWikiLanguage(self):
484#         """
485#         Returns the internal name of the default wiki language of the user.
486#         """
487#         return wx.GetApp().getUserDefaultWikiLanguage()
488
489    def getConfig(self):
490        return self.configuration
491
492    def getPresentationExt(self):
493        return self.presentationExt
494
495    def getCollator(self):
496        return wx.GetApp().getCollator()
497
498    def getLogWindow(self):
499        return self.logWindow
500
501    def getKeyBindings(self):
502        return self.keyBindings
503       
504    def getClipboardInterceptor(self):
505        return self.clipboardInterceptor
506
507    def getUserActionCoord(self):
508        return self.userActionCoord
509
510    def lookupIcon(self, iconname):
511        """
512        Returns the bitmap object for the given iconname.
513        If the bitmap wasn't cached already, it is loaded and created.
514        If icon is unknown, None is returned.
515        """
516        return wx.GetApp().getIconCache().lookupIcon(iconname)
517
518    def lookupSystemIcon(self, iconname):
519        """
520        Returns the bitmap object for the given iconname.
521        If the bitmap wasn't cached already, it is loaded and created.
522        If icon is unknown, an error message is shown and an empty
523        black bitmap is returned.
524        """
525        icon = wx.GetApp().getIconCache().lookupIcon(iconname)
526        if icon is None:
527            icon = wx.EmptyBitmap(16, 16)
528            self.displayErrorMessage(_(u'Error, icon "%s" missing.' % iconname))
529
530        return icon
531
532
533    def lookupIconIndex(self, iconname):
534        """
535        Returns the id number into self.iconImageList of the requested icon.
536        If icon is unknown, -1 is returned.
537        """
538        return wx.GetApp().getIconCache().lookupIconIndex(iconname)
539
540
541    def resolveIconDescriptor(self, desc, default=None):
542        """
543        Used for plugins of type "MenuFunctions" or "ToolbarFunctions".
544        Tries to find and return an appropriate wx.Bitmap object.
545       
546        An icon descriptor can be one of the following:
547            - None
548            - a wx.Bitmap object
549            - the filename of a bitmap
550            - a tuple of filenames, first existing file is used
551       
552        If no bitmap can be found, default is returned instead.
553        """
554        return wx.GetApp().getIconCache().resolveIconDescriptor(desc, default)
555
556
557    def _OnRoundtripEvent(self, evt):
558        """
559        Special event handler for events which must be handled by the
560        window which has currently the focus (e.g. "copy to clipboard" which
561        must be done by either editor or HTML preview).
562       
563        These events are sent further to the currently focused window.
564        If they are not consumed they go up to the parent window until
565        they are here again (make a "roundtrip").
566        This function also avoids an infinite loop of such events.
567        """
568        # Check for infinite loop
569        if self.eventRoundtrip > 0:
570            return
571
572        self.eventRoundtrip += 1
573        try:
574            focus = wx.Window.FindFocus()
575            if focus is not None:
576                focus.ProcessEvent(evt)
577        finally:
578            self.eventRoundtrip -= 1
579
580
581    def _OnEventToCurrentDocPPresenter(self, evt):
582        """
583        wx events which should be sent to current doc page presenter
584        """
585        # Check for infinite loop
586        if self.eventRoundtrip > 0:
587            return
588
589        dpp = self.getCurrentDocPagePresenter()
590        if dpp is None:
591            return
592
593        self.eventRoundtrip += 1
594        try:
595            dpp.ProcessEvent(evt)
596        finally:
597            self.eventRoundtrip -= 1
598
599
600    def addMenuItem(self, menu, label, text, evtfct=None, icondesc=None,
601            menuID=None, updatefct=None, kind=wx.ITEM_NORMAL):
602        if menuID is None:
603            menuID = wx.NewId()
604           
605        if kind is None:
606            kind = wx.ITEM_NORMAL
607
608        menuitem = wx.MenuItem(menu, menuID, label, text, kind)
609        bitmap = self.resolveIconDescriptor(icondesc)
610        if bitmap:
611            menuitem.SetBitmap(bitmap)
612
613        menu.AppendItem(menuitem)
614        if evtfct is not None:
615            wx.EVT_MENU(self, menuID, evtfct)
616
617        if updatefct is not None:
618            if isinstance(updatefct, tuple):
619                updatefct = _buildChainedUpdateEventFct(updatefct)
620            wx.EVT_UPDATE_UI(self, menuID, updatefct)
621
622        return menuitem
623
624
625    def buildWikiMenu(self):
626        """
627        Builds the first, the "Wiki" menu and returns it
628        """
629        wikiData = self.getWikiData()
630        wikiMenu = wx.Menu()
631
632        self.addMenuItem(wikiMenu, _(u'&New') + u'\t' + self.keyBindings.NewWiki,
633                _(u'Create new wiki'), self.OnWikiNew)
634
635        openWikiMenu = wx.Menu()
636        wikiMenu.AppendMenu(wx.NewId(), _(u'&Open'), openWikiMenu)
637
638        self.addMenuItem(openWikiMenu, _(u'In &This Window...') + u'\t' +
639                self.keyBindings.OpenWiki,
640                _(u'Open wiki in this window'), self.OnWikiOpen)
641
642        self.addMenuItem(openWikiMenu, _(u'In &New Window...') + u'\t' +
643                self.keyBindings.OpenWikiNewWindow,
644                _(u'Open wiki in a new window'), self.OnWikiOpenNewWindow)
645
646        self.addMenuItem(openWikiMenu, _(u'&Current in New Window') + u'\t' +
647                self.keyBindings.CloneWindow,
648                _(u'Create new window for same wiki'), self.OnCmdCloneWindow)
649
650        wikiMenu.AppendSeparator()
651
652        self.recentWikisMenu = wx.Menu()
653        wikiMenu.AppendMenu(wx.NewId(), _(u'&Recent'), self.recentWikisMenu)
654
655        self.rereadRecentWikis()
656
657
658        self.favoriteWikisMenu = wx.Menu()  # TODO: Try to avoid rebuilding it each time wiki menu is recreated
659        self.fillFavoriteWikisMenu(self.favoriteWikisMenu)
660        wikiMenu.AppendMenu(wx.NewId(), _(u"F&avorites"), self.favoriteWikisMenu)
661
662
663        if wikiData is not None:
664            wikiMenu.AppendSeparator()
665
666            self.addMenuItem(wikiMenu, _(u'&Search Wiki...') + u'\t' +
667                    self.keyBindings.SearchWiki, _(u'Search whole wiki'),
668                    lambda evt: self.showSearchDialog(), "tb_lens")
669
670
671        wikiMenu.AppendSeparator()
672
673        if wikiData is not None:
674            exportWikisMenu = wx.Menu()
675            wikiMenu.AppendMenu(wx.NewId(), _(u'Publish as HTML'), exportWikisMenu)
676   
677            self.addMenuItem(exportWikisMenu,
678                    _(u'Wiki as Single HTML Page'),
679                    _(u'Publish Wiki as Single HTML Page'), self.OnExportWiki,
680                    menuID=GUI_ID.MENU_EXPORT_WHOLE_AS_PAGE)
681
682            self.addMenuItem(exportWikisMenu,
683                    _(u'Wiki as Set of HTML Pages'),
684                    _(u'Publish Wiki as Set of HTML Pages'), self.OnExportWiki,
685                    menuID=GUI_ID.MENU_EXPORT_WHOLE_AS_PAGES)
686
687            self.addMenuItem(exportWikisMenu,
688                    _(u'Current Wiki Word as HTML Page'),
689                    _(u'Publish Current Wiki Word as HTML Page'), self.OnExportWiki,
690                    menuID=GUI_ID.MENU_EXPORT_WORD_AS_PAGE)
691   
692            self.addMenuItem(exportWikisMenu,
693                    _(u'Sub-Tree as Single HTML Page'),
694                    _(u'Publish Sub-Tree as Single HTML Page'), self.OnExportWiki,
695                    menuID=GUI_ID.MENU_EXPORT_SUB_AS_PAGE)
696   
697            self.addMenuItem(exportWikisMenu,
698                    _(u'Sub-Tree as Set of HTML Pages'),
699                    _(u'Publish Sub-Tree as Set of HTML Pages'), self.OnExportWiki,
700                    menuID=GUI_ID.MENU_EXPORT_SUB_AS_PAGES)
701   
702#             self.addMenuItem(exportWikisMenu,
703#                     _(u'Export Wiki to .wiki files'),
704#                     _(u'Export Wiki to .wiki files in UTF-8'), self.OnExportWiki,
705#                     menuID=GUI_ID.MENU_EXPORT_WHOLE_AS_RAW)
706   
707            self.addMenuItem(exportWikisMenu, _(u'Other Export...'),
708                    _(u'Open general export dialog'), self.OnCmdExportDialog)
709
710
711#         if wikiData is not None:
712            self.addMenuItem(wikiMenu, _(u'Print...') + u'\t' + self.keyBindings.Print,
713                    _(u'Show the print dialog'),
714                    lambda evt: self.printer.showPrintMainDialog())
715
716            wikiMenu.AppendSeparator()
717
718            self.addMenuItem(wikiMenu, _(u'&Properties...'),
719                    _(u'Show general information about current wiki'),
720                    self.OnShowWikiPropertiesDialog)
721
722        maintenanceMenu = wx.Menu()
723        wikiMenu.AppendMenu(wx.NewId(), _(u'Maintenance'), maintenanceMenu)
724
725        if wikiData is not None:
726            if wikiData.checkCapability("rebuild") == 1:
727                self.addMenuItem(maintenanceMenu, _(u'&Rebuild Wiki...'),
728                        _(u'Rebuild this wiki and its cache completely'),
729                        lambda evt: self.rebuildWiki(onlyDirty=False),
730                        menuID=GUI_ID.MENU_REBUILD_WIKI,
731                        updatefct=self.OnUpdateDisReadOnlyWiki)
732
733                self.addMenuItem(maintenanceMenu, _(u'&Update cache...'),
734                        _(u'Update cache where marked as not up to date'),
735                        lambda evt: self.rebuildWiki(onlyDirty=True),
736                        menuID=GUI_ID.MENU_UPDATE_WIKI_CACHE,
737                        updatefct=self.OnUpdateDisReadOnlyWiki)
738
739                self.addMenuItem(maintenanceMenu, _(u'&Initiate update...'),
740                        _(u'Initiate full cache update which is done mainly '
741                        u'in background'),
742                        lambda evt: self.initiateFullUpdate(),
743                        menuID=GUI_ID.MENU_INITATE_UPDATE_WIKI_CACHE,
744                        updatefct=self.OnUpdateDisReadOnlyWiki)
745               
746
747            self.addMenuItem(maintenanceMenu, _(u'Show job count...'),
748                    _(u'Show how many update jobs are waiting in background'),
749                    self.OnCmdShowWikiJobDialog)
750                   
751            maintenanceMenu.AppendSeparator()
752
753        self.addMenuItem(maintenanceMenu, _(u'Open as &Type...'),
754                _(u'Open wiki with a specified wiki database type'),
755                self.OnWikiOpenAsType)
756
757        if wikiData is not None:
758            self.addMenuItem(maintenanceMenu, _(u'Reconnect...'),
759                    _(u'Reconnect to database after connection failure'),
760                    self.OnCmdReconnectDatabase)
761                   
762            maintenanceMenu.AppendSeparator()
763   
764            if wikiData.checkCapability("compactify") == 1:
765                self.addMenuItem(maintenanceMenu, _(u'&Optimise Database'),
766                        _(u'Free unused space in database'),
767                        lambda evt: self.vacuumWiki(),
768                        menuID=GUI_ID.MENU_VACUUM_WIKI,
769                        updatefct=self.OnUpdateDisReadOnlyWiki)
770
771
772            if wikiData.checkCapability("plain text import") == 1:
773                self.addMenuItem(maintenanceMenu, _(u'&Copy .wiki files to database'),
774                        _(u'Copy .wiki files to database'),
775                        self.OnImportFromPagefiles,
776                        updatefct=self.OnUpdateDisReadOnlyWiki)
777
778
779        wikiMenu.AppendSeparator()  # TODO May have two separators without anything between
780
781#         self.addMenuItem(wikiMenu, '&Test', 'Test', lambda evt: self.testIt())
782
783        menuID=wx.NewId()
784        wikiMenu.Append(menuID, _(u'E&xit'), _(u'Exit'))
785        wx.EVT_MENU(self, menuID, lambda evt: self.exitWiki())
786        wx.App.SetMacExitMenuItemId(menuID)
787
788        return wikiMenu
789
790#         if wikiData is not None and wikiData.checkCapability("versioning") == 1:
791#             wikiMenu.AppendSeparator()
792#     
793# #             menuID=wx.NewId()
794# #             wikiMenu.Append(menuID, '&Store version', 'Store new version')
795# #             wx.EVT_MENU(self, menuID, lambda evt: self.showStoreVersionDialog())
796#     
797#             menuID=wx.NewId()
798#             wikiMenu.Append(menuID, _(u'&Retrieve version'),
799#                     _(u'Retrieve previous version'))
800#             wx.EVT_MENU(self, menuID, lambda evt: self.showSavedVersionsDialog())
801#     
802#             menuID=wx.NewId()
803#             wikiMenu.Append(menuID, _(u'Delete &All Versions'),
804#                     _(u'Delete all stored versions'))
805#             wx.EVT_MENU(self, menuID, lambda evt: self.showDeleteAllVersionsDialog())
806
807
808
809    def fillPluginsMenu(self, pluginMenu):
810        """
811        Builds or rebuilds the plugin menu. This function does no id reuse
812        so it shouldn't be called too often (mainly on start and when
813        rebuilding menu during development of plugins)
814
815        pluginMenu -- An empty wx.Menu to add items to
816        """
817#         pluginMenu = None
818        # get info for any plugin menu items and create them as necessary
819        menuItems = reduce(lambda a, b: a+list(b),
820                self.menuFunctions.describeMenuItems(self), [])
821       
822        subStructure = {}
823
824        if len(menuItems) > 0:
825            def addPluginMenuItem(function, label, statustext, icondesc=None,
826                    menuID=None, updateFunction=None, kind=None):
827               
828                labelComponents = label.split(u"|")
829               
830                sub = subStructure
831                menu = pluginMenu
832
833                for comp in labelComponents[:-1]:
834                    newMenu, newSub = sub.get(comp, (None, None))
835                    if newMenu is None:
836                        newMenu = wx.Menu()
837                        menu.AppendMenu(-1, comp, newMenu)
838                        newSub = {}
839                        sub[comp] = newMenu, newSub
840                   
841                    menu = newMenu
842                    sub = newSub
843
844                if updateFunction is not None:
845                    updateFct = lambda evt: updateFunction(self, evt)
846                else:
847                    updateFct = None
848
849                self.addMenuItem(menu, labelComponents[-1], statustext,
850                        lambda evt: function(self, evt), icondesc, menuID,
851                        updateFct, kind)
852
853            for item in menuItems:
854                addPluginMenuItem(*item)
855
856
857    def fillRecentWikisMenu(self, menu):
858        """
859        Refreshes the list of recent wiki menus from self.wikiHistory
860        """
861        idRecycler = self.recentWikisActivation
862        idRecycler.clearAssoc()
863
864        # Add new items
865        for wiki in self.wikiHistory:
866            menuID, reused = idRecycler.assocGetIdAndReused(wiki)
867
868            if not reused:
869                # For a new id, an event must be set
870                wx.EVT_MENU(self, menuID, self.OnRecentWikiUsed)
871
872            menu.Append(menuID, uniToGui(wiki))
873
874
875    def OnRecentWikiUsed(self, evt):
876        entry = self.recentWikisActivation.get(evt.GetId())
877
878        if entry is None:
879            return
880
881        self.openWiki(entry)
882
883
884    def rereadRecentWikis(self):
885        """
886        Starts rereading and rebuilding of the recent wikis submenu
887        """
888        if self.recentWikisMenu is None:
889            return
890       
891        history = self.configuration.get("main", "wiki_history")
892        if not history:
893            return
894       
895        self.wikiHistory = history.split(u";")
896       
897        maxLen = self.configuration.getint(
898                "main", "recentWikisList_length", 5)
899        if len(self.wikiHistory) > maxLen:
900            self.wikiHistory = self.wikiHistory[:maxLen]
901
902        clearMenu(self.recentWikisMenu)
903        self.fillRecentWikisMenu(self.recentWikisMenu)
904
905
906    def informRecentWikisChanged(self):
907        self.configuration.set("main", "wiki_history",
908                ";".join(self.wikiHistory))
909        wx.GetApp().fireMiscEventKeys(
910                ("reread recent wikis needed",))
911
912    def fillTextBlocksMenu(self, menu):
913        """
914        Constructs the text blocks menu submenu and necessary subsubmenus.
915        If this is called more than once, previously used menu ids are reused
916        for the new menu.
917       
918        menu -- An empty wx.Menu to add items and submenus to
919        """
920        # Clear IdRecycler
921        self.textBlocksActivation.clearAssoc()
922
923
924        wikiDoc = self.getWikiDocument()
925        if wikiDoc is not None and self.requireReadAccess():
926            try:
927                page = wikiDoc.getFuncPage(u"wiki/TextBlocks")
928                treeData = TextTree.buildTreeFromText(page.getContent(),
929                        TextTree.TextBlocksEntry.factory)
930                TextTree.addTreeToMenu(treeData,
931                        menu, self.textBlocksActivation, self,
932                        self.OnTextBlockUsed)
933                menu.AppendSeparator()
934
935            except DbReadAccessError, e:
936                self.lostReadAccess(e)
937                traceback.print_exc()
938
939
940        page = WikiDataManager.getGlobalFuncPage(u"global/TextBlocks")
941        treeData = TextTree.buildTreeFromText(page.getContent(),
942                TextTree.TextBlocksEntry.factory)
943        TextTree.addTreeToMenu(treeData,
944                menu, self.textBlocksActivation, self,
945                self.OnTextBlockUsed)
946
947        menu.AppendSeparator()
948        menu.Append(GUI_ID.CMD_REREAD_TEXT_BLOCKS,
949                _(u"Reread text blocks"),
950                _(u"Reread the text block file(s) and recreate menu"))
951        wx.EVT_MENU(self, GUI_ID.CMD_REREAD_TEXT_BLOCKS, self.OnRereadTextBlocks)
952
953
954    def OnTextBlockUsed(self, evt):
955        if self.isReadOnlyPage():
956            return
957
958        entry = self.textBlocksActivation.get(evt.GetId())
959
960        if entry is None:
961            return
962
963        if u"a" in entry.flags:
964            self.appendText(entry.value)
965        else:
966            self.addText(entry.value, replaceSel=True)
967
968
969   
970    def OnRereadTextBlocks(self, evt):
971        self.rereadTextBlocks()
972       
973       
974    def rereadTextBlocks(self):
975        """
976        Starts rereading and rebuilding of the text blocks submenu
977        """
978        if self.textBlocksMenu is None:
979            return
980
981        clearMenu(self.textBlocksMenu)
982        self.fillTextBlocksMenu(self.textBlocksMenu)
983
984
985    def fillFavoriteWikisMenu(self, menu):
986        """
987        Constructs the favorite wikis menu and necessary submenus.
988        If this is called more than once, previously used menu ids are reused
989        for the new menu.
990       
991        menu -- An empty wx.Menu to add items and submenus to
992        """
993        self.favoriteWikisActivation.clearAssoc()
994
995        wikiDoc = self.getWikiDocument()
996
997        page = WikiDataManager.getGlobalFuncPage(u"global/FavoriteWikis")
998        treeData = TextTree.buildTreeFromText(page.getContent(),
999                TextTree.FavoriteWikisEntry.factory)
1000        TextTree.addTreeToMenu(treeData,
1001                menu, self.favoriteWikisActivation, self,
1002                self.OnFavoriteWikiUsed)
1003
1004        menu.AppendSeparator()
1005        menu.Append(GUI_ID.CMD_ADD_CURRENT_WIKI_TO_FAVORITES,
1006                _(u"Add wiki"),
1007                _(u"Add a wiki to the favorites"))
1008        wx.EVT_MENU(self, GUI_ID.CMD_ADD_CURRENT_WIKI_TO_FAVORITES,
1009                self.OnAddToFavoriteWikis)
1010
1011        menu.Append(GUI_ID.CMD_MANAGE_FAVORITE_WIKIS,
1012                _(u"Manage favorites"),
1013                _(u"Manage favorites"))
1014        wx.EVT_MENU(self, GUI_ID.CMD_MANAGE_FAVORITE_WIKIS,
1015                self.OnManageFavoriteWikis)
1016
1017
1018    def OnFavoriteWikiUsed(self, evt):
1019        try:
1020            entry = self.favoriteWikisActivation.get(evt.GetId())
1021
1022            if entry is None:
1023                return
1024
1025            if u"n" in entry.flags:
1026                # Open in new frame
1027                try:
1028                    clAction = CmdLineAction([])
1029                    clAction.setWikiToOpen(entry.value)
1030                    clAction.frameToOpen = 1  # Open in new frame
1031                    wx.GetApp().startPersonalWikiFrame(clAction)
1032                except Exception, e:
1033                    traceback.print_exc()
1034                    self.displayErrorMessage(_(u'Error while starting new '
1035                            u'WikidPad instance'), e)
1036                    return
1037            else:
1038                # Open in same frame
1039                if entry.value.startswith(u"wiki:"):
1040                    # Handle an URL
1041                    filePath, wikiWordToOpen, anchorToOpen = \
1042                            wikiUrlToPathWordAndAnchor(entry.value)
1043                    if exists(pathEnc(filePath)):
1044                        self.openWiki(filePath, wikiWordsToOpen=(wikiWordToOpen,),
1045                                anchorToOpen=anchorToOpen)
1046                else:
1047                    self.openWiki(abspath(entry.value))
1048
1049        except KeyError:
1050            pass
1051
1052
1053    def rereadFavoriteWikis(self):
1054        if self.favoriteWikisMenu is None:
1055            return
1056
1057        clearMenu(self.favoriteWikisMenu)
1058        self.fillFavoriteWikisMenu(self.favoriteWikisMenu)
1059       
1060        # Update also toolbar by recreating
1061        if self.getShowToolbar():
1062            self.Freeze()
1063            try:
1064                self.setShowToolbar(False)
1065                self.setShowToolbar(True)
1066            finally:
1067                self.Thaw()
1068
1069
1070    def OnAddToFavoriteWikis(self,evt):
1071        document = self.getWikiDocument()
1072        if document is None:
1073            path = u""
1074            title = u""
1075        else:
1076            path = document.getWikiConfigPath()
1077            title = document.getWikiName()
1078
1079        entry = TextTree.FavoriteWikisEntry(title, u"", u"",
1080                self._getStorableWikiPath(path))
1081        entry = TextTree.AddWikiToFavoriteWikisDialog.runModal(self, -1, entry)
1082       
1083        if entry is not None:
1084            page = WikiDataManager.getGlobalFuncPage(u"global/FavoriteWikis")
1085            text = page.getLiveText()
1086            if len(text) == 0 or text[-1] == u"\n":
1087                page.appendLiveText(entry.getTextLine() + u"\n")
1088            else:
1089                page.appendLiveText(u"\n" + entry.getTextLine() + u"\n")
1090
1091            self.saveDocPage(page)
1092
1093
1094    def OnManageFavoriteWikis(self, evt):
1095        self.activatePageByUnifiedName(u"global/FavoriteWikis", tabMode=2)
1096
1097
1098    def OnInsertStringFromDict(self, evt):
1099        if self.isReadOnlyPage():
1100            return
1101
1102        self.getActiveEditor().AddText(self.cmdIdToInsertString[evt.GetId()])
1103
1104
1105    def OnInsertIconAttribute(self, evt):
1106        if self.isReadOnlyPage():
1107            return
1108
1109        self.insertAttribute("icon", self.cmdIdToIconNameForAttribute[evt.GetId()])
1110
1111
1112    def OnInsertColorAttribute(self, evt):
1113        if self.isReadOnlyPage():
1114            return
1115
1116        self.insertAttribute("color", self.cmdIdToColorNameForAttribute[evt.GetId()])
1117
1118
1119    def buildMainMenu(self):
1120        # ------------------------------------------------------------------------------------
1121        # Set up menu bar for the program.
1122        # ------------------------------------------------------------------------------------
1123        if self.mainmenu is not None:
1124            # This is a rebuild of an existing menu (after loading a new wikiData)
1125            self.mainmenu.Replace(0, self.buildWikiMenu(), 'W&iki')
1126            return
1127
1128
1129        self.mainmenu = wx.MenuBar()   # Create menu bar.
1130
1131        wikiMenu = self.buildWikiMenu()
1132
1133       
1134        editMenu = wx.Menu()
1135       
1136        self.addMenuItem(editMenu, _(u'&Undo') + u'\t' + self.keyBindings.Undo,
1137                _(u'Undo'), self._OnRoundtripEvent, menuID=GUI_ID.CMD_UNDO,
1138                updatefct=(self.OnUpdateDisReadOnlyPage, self.OnUpdateDisNotTextedit))
1139
1140        self.addMenuItem(editMenu, _(u'&Redo') + u'\t' + self.keyBindings.Redo,
1141                _(u'Redo'), self._OnRoundtripEvent, menuID=GUI_ID.CMD_REDO,
1142                updatefct=(self.OnUpdateDisReadOnlyPage, self.OnUpdateDisNotTextedit))
1143 
1144        editMenu.AppendSeparator()
1145
1146        # TODO: Incremental search
1147       
1148        self.addMenuItem(editMenu, _(u'&Search and Replace...') + u'\t' +
1149                self.keyBindings.FindAndReplace,
1150                _(u'Search and replace inside current page'),
1151                lambda evt: self.showSearchReplaceDialog(),
1152                updatefct=self.OnUpdateDisNotTextedit)
1153
1154        editMenu.AppendSeparator()
1155
1156        self.addMenuItem(editMenu, _(u'Cu&t') + u'\t' + self.keyBindings.Cut,
1157                _(u'Cut'), self._OnRoundtripEvent,
1158                "tb_cut", menuID=GUI_ID.CMD_CLIPBOARD_CUT,
1159                updatefct=(self.OnUpdateDisReadOnlyPage, self.OnUpdateDisNotTextedit))
1160
1161        self.addMenuItem(editMenu, _(u'&Copy') + u'\t' + self.keyBindings.Copy,
1162                _(u'Copy'), self._OnRoundtripEvent,
1163                "tb_copy", menuID=GUI_ID.CMD_CLIPBOARD_COPY)
1164
1165        self.addMenuItem(editMenu, _(u'&Paste') + u'\t' + self.keyBindings.Paste,
1166                _(u'Paste'), self._OnRoundtripEvent,
1167                "tb_paste", menuID=GUI_ID.CMD_CLIPBOARD_PASTE,
1168                updatefct=(self.OnUpdateDisReadOnlyPage, self.OnUpdateDisNotTextedit))
1169
1170        editMenu.AppendSeparator()
1171
1172        self.addMenuItem(editMenu, _(u'Copy to Sc&ratchPad') + u'\t' + \
1173                self.keyBindings.CopyToScratchPad,
1174                _(u'Copy selected text to ScratchPad'), lambda evt: self.getActiveEditor().snip(),
1175                "tb_copy", updatefct=self.OnUpdateDisReadOnlyWiki)
1176
1177        self.textBlocksMenu = wx.Menu()
1178        self.fillTextBlocksMenu(self.textBlocksMenu)
1179
1180        editMenu.AppendMenu(GUI_ID.MENU_TEXT_BLOCKS, _(u'Paste T&extblock'),
1181                self.textBlocksMenu)
1182        wx.EVT_UPDATE_UI(self, GUI_ID.MENU_TEXT_BLOCKS,
1183                self.OnUpdateDisReadOnlyPage)
1184       
1185
1186        if self.clipboardInterceptor is not None:
1187            clipCatchMenu = wx.Menu()
1188            editMenu.AppendMenu(wx.NewId(), _(u'C&lipboard Catcher'),
1189                    clipCatchMenu)
1190
1191            self.addMenuItem(clipCatchMenu, _(u'Set at Page') + u'\t' +
1192                    self.keyBindings.CatchClipboardAtPage,
1193                    _(u"Text copied to clipboard is also appended to this page"),
1194                    self.OnClipboardCatcherAtPage,
1195                    menuID=GUI_ID.CMD_CLIPBOARD_CATCHER_AT_PAGE,
1196                    updatefct=self.OnUpdateClipboardCatcher,
1197                    kind=wx.ITEM_RADIO)
1198
1199            self.addMenuItem(clipCatchMenu, _(u'Set at Cursor') + u'\t' +
1200                    self.keyBindings.CatchClipboardAtCursor,
1201                    _(u"Text copied to clipboard is also added to cursor position"),
1202                    self.OnClipboardCatcherAtCursor,
1203                    menuID=GUI_ID.CMD_CLIPBOARD_CATCHER_AT_CURSOR,
1204                    updatefct=self.OnUpdateClipboardCatcher,
1205                    kind=wx.ITEM_RADIO)
1206
1207            self.addMenuItem(clipCatchMenu, _(u'Set Off') + u'\t' +
1208                    self.keyBindings.CatchClipboardOff,
1209                    _(u"Switch off clipboard catcher"),
1210                    self.OnClipboardCatcherOff,
1211                    menuID=GUI_ID.CMD_CLIPBOARD_CATCHER_OFF,
1212                    updatefct=self.OnUpdateClipboardCatcher,
1213                    kind=wx.ITEM_RADIO)
1214
1215
1216
1217        if SpellChecker.isSpellCheckSupported():
1218            editMenu.AppendSeparator()
1219
1220            self.addMenuItem(editMenu, _(u'Spell Check...') + u'\t' +
1221                    self.keyBindings.SpellCheck,
1222                    _(u'Spell check current and possibly further pages'),
1223                    lambda evt: self.showSpellCheckerDialog(),
1224                    updatefct=(self.OnUpdateDisReadOnlyPage, self.OnUpdateDisNotTextedit))
1225
1226#             menuItem = wx.MenuItem(clipCatchMenu, GUI_ID.CMD_CLIPBOARD_CATCHER_AT_PAGE,
1227#                     _(u'Set at Page') + u'\t' + self.keyBindings.CatchClipboardAtPage,
1228#                     _(u"Text copied to clipboard is also appended to this page"),
1229#                     wx.ITEM_RADIO)
1230#             clipCatchMenu.AppendItem(menuItem)
1231#             wx.EVT_MENU(self, GUI_ID.CMD_CLIPBOARD_CATCHER_AT_PAGE,
1232#                     self.OnClipboardCatcherAtPage)
1233#             wx.EVT_UPDATE_UI(self, GUI_ID.CMD_CLIPBOARD_CATCHER_AT_PAGE,
1234#                     self.OnUpdateClipboardCatcher)
1235#
1236#
1237#             menuItem = wx.MenuItem(clipCatchMenu, GUI_ID.CMD_CLIPBOARD_CATCHER_AT_CURSOR,
1238#                     _(u'Set at Cursor') + u'\t' + self.keyBindings.CatchClipboardAtCursor,
1239#                     _(u"Text copied to clipboard is also added to cursor position"),
1240#                     wx.ITEM_RADIO)
1241#             clipCatchMenu.AppendItem(menuItem)
1242#             wx.EVT_MENU(self, GUI_ID.CMD_CLIPBOARD_CATCHER_AT_CURSOR,
1243#                     self.OnClipboardCatcherAtCursor)
1244#             wx.EVT_UPDATE_UI(self, GUI_ID.CMD_CLIPBOARD_CATCHER_AT_CURSOR,
1245#                     self.OnUpdateClipboardCatcher)
1246#
1247#
1248#             menuItem = wx.MenuItem(clipCatchMenu, GUI_ID.CMD_CLIPBOARD_CATCHER_OFF,
1249#                     _(u'Set Off') + u'\t' + self.keyBindings.CatchClipboardOff,
1250#                     _(u"Switch off clipboard catcher"), wx.ITEM_RADIO)
1251#             clipCatchMenu.AppendItem(menuItem)
1252#             wx.EVT_MENU(self, GUI_ID.CMD_CLIPBOARD_CATCHER_OFF,
1253#                     self.OnClipboardCatcherOff)
1254#             wx.EVT_UPDATE_UI(self, GUI_ID.CMD_CLIPBOARD_CATCHER_OFF,
1255#                     self.OnUpdateClipboardCatcher)
1256
1257
1258        editMenu.AppendSeparator()
1259
1260
1261        insertMenu = wx.Menu()
1262        editMenu.AppendMenu(wx.NewId(), _(u'&Insert'), insertMenu)
1263
1264        self.addMenuItem(insertMenu, _(u'&File URL...') + '\t' +
1265                self.keyBindings.AddFileUrl, _(u'Use file dialog to add URL'),
1266                lambda evt: self.showAddFileUrlDialog(),
1267                updatefct=(self.OnUpdateDisReadOnlyPage, self.OnUpdateDisNotTextedit))
1268
1269
1270        self.addMenuItem(insertMenu, _(u'Current &Date') + u'\t' +
1271                self.keyBindings.InsertDate, _(u'Insert current date'),
1272                lambda evt: self.insertDate(), "date",
1273                updatefct=(self.OnUpdateDisReadOnlyPage, self.OnUpdateDisNotTextedit,
1274                    self.OnUpdateDisNotWikiPage))
1275
1276        # TODO: Insert colorname, color value, icon name
1277
1278
1279        settingsMenu = wx.Menu()
1280        editMenu.AppendMenu(wx.NewId(), _(u'&Settings'), settingsMenu)
1281
1282
1283        self.addMenuItem(settingsMenu, _(u'&Date Format...'),
1284                _(u'Set date format for inserting current date'),
1285                lambda evt: self.showDateformatDialog())
1286
1287
1288        self.addMenuItem(settingsMenu, _(u"Auto-&Wrap"),
1289                _(u"Set if editor should wrap long lines"),
1290                self.OnCmdCheckWrapMode,
1291                updatefct=self.OnUpdateWrapMode,
1292                kind=wx.ITEM_CHECK)
1293
1294
1295#         menuID=wx.NewId()
1296#         wrapModeMenuItem = wx.MenuItem(settingsMenu, menuID, _(u"Auto-&Wrap"),
1297#                 _(u"Set if editor should wrap long lines"), wx.ITEM_CHECK)
1298#         settingsMenu.AppendItem(wrapModeMenuItem)
1299#         wx.EVT_MENU(self, menuID, self.OnCmdCheckWrapMode)
1300#         wx.EVT_UPDATE_UI(self, menuID, self.OnUpdateWrapMode)
1301
1302
1303        self.addMenuItem(settingsMenu, _(u"Auto-&Indent"),
1304                _(u"Auto indentation"),
1305                self.OnCmdCheckAutoIndent,
1306                updatefct=self.OnUpdateAutoIndent,
1307                kind=wx.ITEM_CHECK)
1308
1309#         menuID=wx.NewId()
1310#         autoIndentMenuItem = wx.MenuItem(settingsMenu, menuID,
1311#                 _(u"Auto-&Indent"), _(u"Auto indentation"), wx.ITEM_CHECK)
1312#         settingsMenu.AppendItem(autoIndentMenuItem)
1313#         wx.EVT_MENU(self, menuID, self.OnCmdCheckAutoIndent)
1314#         wx.EVT_UPDATE_UI(self, menuID, self.OnUpdateAutoIndent)
1315
1316
1317        self.addMenuItem(settingsMenu, _(u"Auto-&Bullets"),
1318                _(u"Show bullet on next line if current has one"),
1319                self.OnCmdCheckAutoBullets,
1320                updatefct=self.OnUpdateAutoBullets,
1321                kind=wx.ITEM_CHECK)
1322
1323#         menuID=wx.NewId()
1324#         autoBulletsMenuItem = wx.MenuItem(settingsMenu, menuID,
1325#                 _(u"Auto-&Bullets"),
1326#                 _(u"Show bullet on next line if current has one"),
1327#                 wx.ITEM_CHECK)
1328#         settingsMenu.AppendItem(autoBulletsMenuItem)
1329#         wx.EVT_MENU(self, menuID, self.OnCmdCheckAutoBullets)
1330#         wx.EVT_UPDATE_UI(self, menuID,
1331#                 self.OnUpdateAutoBullets)
1332
1333        self.addMenuItem(settingsMenu, _(u"Tabs to spaces"),
1334                _(u"Write spaces when hitting TAB key"),
1335                self.OnCmdCheckTabsToSpaces,
1336                updatefct=self.OnUpdateTabsToSpaces,
1337                kind=wx.ITEM_CHECK)
1338
1339#         menuID=wx.NewId()
1340#         autoBulletsMenuItem = wx.MenuItem(settingsMenu, menuID,
1341#                 _(u"Tabs to spaces"), _(u"Write spaces when hitting TAB key"),
1342#                 wx.ITEM_CHECK)
1343#         settingsMenu.AppendItem(autoBulletsMenuItem)
1344#         wx.EVT_MENU(self, menuID, self.OnCmdCheckTabsToSpaces)
1345#         wx.EVT_UPDATE_UI(self, menuID,
1346#                 self.OnUpdateTabsToSpaces)
1347
1348
1349
1350        viewMenu = wx.Menu()
1351       
1352        self.addMenuItem(viewMenu, _(u'Show T&oolbar') + u'\t' +
1353                self.keyBindings.ShowToolbar,
1354                _(u"Show toolbar"),
1355                lambda evt: self.setShowToolbar(
1356                not self.getConfig().getboolean("main", "toolbar_show", True)),
1357                menuID=GUI_ID.CMD_SHOW_TOOLBAR,
1358                updatefct=self.OnUpdateToolbarMenuItem,
1359                kind=wx.ITEM_CHECK)
1360
1361        self.addMenuItem(viewMenu, _(u'Show &Tree View') + u'\t' +
1362                self.keyBindings.ShowTreeControl,
1363                _(u"Show Tree Control"),
1364                lambda evt: self.setShowTreeControl(
1365                self.windowLayouter.isWindowCollapsed("maintree")),
1366                updatefct=self.OnUpdateTreeCtrlMenuItem,
1367                kind=wx.ITEM_CHECK)
1368
1369
1370        self.addMenuItem(viewMenu, _(u'Show &Chron. View') + u'\t' +
1371                self.keyBindings.ShowTimeView,
1372                _(u"Show chronological view"),
1373                lambda evt: self.setShowTimeView(
1374                self.windowLayouter.isWindowCollapsed("time view")),
1375                updatefct=self.OnUpdateTimeViewMenuItem,
1376                kind=wx.ITEM_CHECK)
1377
1378
1379
1380        self.addMenuItem(viewMenu, _(u'Show &Page Structure') + u'\t' +
1381                self.keyBindings.ShowDocStructure,
1382                _(u"Show structure (headings) of the page"),
1383                lambda evt: self.setShowDocStructure(
1384                self.windowLayouter.isWindowCollapsed("doc structure")),
1385                updatefct=self.OnUpdateDocStructureMenuItem,
1386                kind=wx.ITEM_CHECK)
1387
1388
1389        # TODO: Show error log
1390
1391        viewMenu.AppendSeparator()
1392
1393
1394        self.addMenuItem(viewMenu, _(u"Show &Indentation Guides"),
1395                _(u"Show indentation guides in editor"),
1396                self.OnCmdCheckIndentationGuides,
1397                updatefct=self.OnUpdateIndentationGuides,
1398                kind=wx.ITEM_CHECK)
1399 
1400        self.addMenuItem(viewMenu, _(u"Show Line &Numbers"),
1401                _(u"Show line numbers in editor"),
1402                self.OnCmdCheckShowLineNumbers,
1403                updatefct=self.OnUpdateShowLineNumbers,
1404                kind=wx.ITEM_CHECK)
1405       
1406        viewMenu.AppendSeparator()
1407       
1408        self.addMenuItem(viewMenu, _(u'Stay on Top') + u'\t' +
1409                self.keyBindings.StayOnTop,
1410                _(u"Stay on Top of all other windows"),
1411                lambda evt: self.setStayOnTop(not self.getStayOnTop()),
1412                menuID=GUI_ID.CMD_STAY_ON_TOP,
1413                updatefct=self.OnUpdateStayOnTopMenuItem,
1414                kind=wx.ITEM_CHECK)
1415       
1416        viewMenu.AppendSeparator()
1417       
1418        self.addMenuItem(viewMenu, _(u'&Zoom In') + u'\t' + self.keyBindings.ZoomIn,
1419                _(u'Zoom In'), self._OnRoundtripEvent, "tb_zoomin",
1420                menuID=GUI_ID.CMD_ZOOM_IN)
1421
1422        self.addMenuItem(viewMenu, _(u'Zoo&m Out') + u'\t' + self.keyBindings.ZoomOut,
1423                _(u'Zoom Out'), self._OnRoundtripEvent, "tb_zoomout",
1424                menuID=GUI_ID.CMD_ZOOM_OUT)
1425
1426
1427#         menuItem = wx.MenuItem(viewMenu, GUI_ID.CMD_SHOW_TOOLBAR,
1428#                 _(u'Show Toolbar') + u'\t' + self.keyBindings.ShowToolbar,
1429#                 _(u"Show Toolbar"), wx.ITEM_CHECK)
1430#         viewMenu.AppendItem(menuItem)
1431#         wx.EVT_MENU(self, GUI_ID.CMD_SHOW_TOOLBAR, lambda evt: self.setShowToolbar(
1432#                 not self.getConfig().getboolean("main", "toolbar_show", True)))
1433#         wx.EVT_UPDATE_UI(self, GUI_ID.CMD_SHOW_TOOLBAR,
1434#                 self.OnUpdateToolbarMenuItem)
1435
1436#         menuID = wx.NewId()
1437#         menuItem = wx.MenuItem(viewMenu, menuID,
1438#                 _(u'Show &Doc. Structure') + u'\t' + self.keyBindings.ShowDocStructure,
1439#                 _(u"Show Document Structure"), wx.ITEM_CHECK)
1440#         viewMenu.AppendItem(menuItem)
1441#         wx.EVT_MENU(self, menuID, lambda evt: self.setShowDocStructure(
1442#                 self.windowLayouter.isWindowCollapsed("doc structure")))
1443#         wx.EVT_UPDATE_UI(self, menuID, self.OnUpdateDocStructureMenuItem)
1444
1445#         menuID = wx.NewId()
1446#         menuItem = wx.MenuItem(viewMenu, menuID,
1447#                 _(u'&Show Time View') + u'\t' + self.keyBindings.ShowTimeView,
1448#                 _(u"Show Time View"), wx.ITEM_CHECK)
1449#         viewMenu.AppendItem(menuItem)
1450#         wx.EVT_MENU(self, menuID, lambda evt: self.setShowTimeView(
1451#                 self.windowLayouter.isWindowCollapsed("time view")))
1452#         wx.EVT_UPDATE_UI(self, menuID, self.OnUpdateTimeViewMenuItem)
1453
1454#         menuItem = wx.MenuItem(viewMenu, GUI_ID.CMD_STAY_ON_TOP,
1455#                 _(u'Stay on Top') + u'\t' + self.keyBindings.StayOnTop,
1456#                 _(u"Stay on Top"), wx.ITEM_CHECK)
1457#         viewMenu.AppendItem(menuItem)
1458#         wx.EVT_MENU(self, GUI_ID.CMD_STAY_ON_TOP, lambda evt: self.setStayOnTop(
1459#                 not self.getStayOnTop()))
1460#         wx.EVT_UPDATE_UI(self, GUI_ID.CMD_STAY_ON_TOP,
1461#                 self.OnUpdateStayOnTopMenuItem)
1462
1463#         menuID=wx.NewId()
1464#         indentGuidesMenuItem = wx.MenuItem(viewMenu, menuID,
1465#                 _(u"&View Indentation Guides"), _(u"View Indentation Guides"),
1466#                 wx.ITEM_CHECK)
1467#         viewMenu.AppendItem(indentGuidesMenuItem)
1468#         wx.EVT_MENU(self, menuID, self.OnCmdCheckIndentationGuides)
1469#         wx.EVT_UPDATE_UI(self, menuID, self.OnUpdateIndentationGuides)
1470
1471#         menuID=wx.NewId()
1472#         showLineNumbersMenuItem = wx.MenuItem(viewMenu, menuID,
1473#                 _(u"Show line numbers"), _(u"Show line numbers"),
1474#                 wx.ITEM_CHECK)
1475#         viewMenu.AppendItem(showLineNumbersMenuItem)
1476#         wx.EVT_MENU(self, menuID, self.OnCmdCheckShowLineNumbers)
1477#         wx.EVT_UPDATE_UI(self, menuID, self.OnUpdateShowLineNumbers)
1478
1479#         menuID = wx.NewId()
1480#         menuItem = wx.MenuItem(viewMenu, menuID,
1481#                 _(u'&Show Tree Control') + u'\t' + self.keyBindings.ShowTreeControl,
1482#                 _(u"Show Tree Control"), wx.ITEM_CHECK)
1483#         viewMenu.AppendItem(menuItem)
1484#         wx.EVT_MENU(self, menuID, lambda evt: self.setShowTreeControl(
1485#                 self.windowLayouter.isWindowCollapsed("maintree")))
1486#         wx.EVT_UPDATE_UI(self, menuID, self.OnUpdateTreeCtrlMenuItem)
1487
1488
1489        tabsMenu = wx.Menu()
1490       
1491        # TODO: open new tab              (now: no menuchoice; open with current item)
1492        # TODO: close current tab         (now: no menuchoice)
1493
1494#         tabsMenu.AppendSeparator()
1495
1496        self.addMenuItem(tabsMenu, _(u'Toggle Ed./Prev') + u'\t' +
1497                self.keyBindings.ShowSwitchEditorPreview,
1498                _(u'Switch between editor and preview'),
1499                lambda evt: self.setDocPagePresenterSubControl(None),  "tb_switch ed prev",
1500                    menuID=GUI_ID.CMD_TAB_SHOW_SWITCH_EDITOR_PREVIEW)
1501
1502        self.addMenuItem(tabsMenu, _(u'Enter Edit Mode') + u'\t' + self.keyBindings.ShowEditor,
1503                _(u'Show editor in tab'),
1504                lambda evt: self.setDocPagePresenterSubControl("textedit"),  #  "tb_editor",
1505                    menuID=GUI_ID.CMD_TAB_SHOW_EDITOR)
1506
1507        self.addMenuItem(tabsMenu, _(u'Enter Preview Mode') + u'\t' +
1508                self.keyBindings.ShowPreview,
1509                _(u'Show preview in tab'),
1510                lambda evt: self.setDocPagePresenterSubControl("preview"),  #   "tb_preview",
1511                    menuID=GUI_ID.CMD_TAB_SHOW_PREVIEW)
1512
1513        tabsMenu.AppendSeparator()
1514
1515        appendToMenuByMenuDesc(tabsMenu, FOLD_MENU, self.keyBindings)
1516
1517        wx.EVT_MENU(self, GUI_ID.CMD_CHECKBOX_SHOW_FOLDING,
1518                self.OnCmdCheckShowFolding)
1519        wx.EVT_UPDATE_UI(self, GUI_ID.CMD_CHECKBOX_SHOW_FOLDING,
1520                self.OnUpdateShowFolding)
1521
1522        wx.EVT_MENU(self, GUI_ID.CMD_TOGGLE_CURRENT_FOLDING,
1523                lambda evt: self.getActiveEditor().toggleCurrentFolding())
1524        wx.EVT_MENU(self, GUI_ID.CMD_UNFOLD_ALL_IN_CURRENT,
1525                lambda evt: self.getActiveEditor().unfoldAll())
1526        wx.EVT_MENU(self, GUI_ID.CMD_FOLD_ALL_IN_CURRENT,
1527                lambda evt: self.getActiveEditor().foldAll())
1528       
1529
1530
1531        wikiPageMenu = wx.Menu()
1532
1533        self.addMenuItem(wikiPageMenu, _(u'&Save') + u'\t' + self.keyBindings.Save,
1534                _(u'Save all open pages'),
1535                lambda evt: (self.saveAllDocPages(),
1536                self.getWikiData().commit()), "tb_save",
1537                menuID=GUI_ID.CMD_SAVE_WIKI,
1538                updatefct=self.OnUpdateDisReadOnlyWiki)
1539
1540        # TODO More fine grained check for en-/disabling of rename and delete?
1541        self.addMenuItem(wikiPageMenu, _(u'&Rename') + u'\t' + self.keyBindings.Rename,
1542                _(u'Rename current wiki word'), lambda evt: self.showWikiWordRenameDialog(),
1543                "tb_rename",
1544                menuID=GUI_ID.CMD_RENAME_PAGE,
1545                updatefct=(self.OnUpdateDisReadOnlyWiki, self.OnUpdateDisNotWikiPage))
1546
1547        self.addMenuItem(wikiPageMenu, _(u'&Delete') + u'\t' + self.keyBindings.Delete,
1548                _(u'Delete current wiki word'), lambda evt: self.showWikiWordDeleteDialog(),
1549                "tb_delete",
1550                menuID=GUI_ID.CMD_DELETE_PAGE,
1551                updatefct=(self.OnUpdateDisReadOnlyWiki, self.OnUpdateDisNotWikiPage))
1552
1553        wikiPageMenu.AppendSeparator()
1554
1555        self.addMenuItem(wikiPageMenu, _(u'Set as Roo&t') + u'\t' + self.keyBindings.SetAsRoot,
1556                _(u'Set current wiki word as tree root'),
1557                lambda evt: self.setCurrentWordAsRoot(),
1558                )
1559
1560        self.addMenuItem(wikiPageMenu, _(u'R&eset Root') + u'\t' + self.keyBindings.ResetRoot,
1561                _(u'Set home wiki word as tree root'),
1562                lambda evt: self.setHomeWordAsRoot(),
1563                )
1564
1565        self.addMenuItem(wikiPageMenu, _(u'S&ynchronise Tree'),
1566                _(u'Find the current wiki word in the tree'), lambda evt: self.findCurrentWordInTree(),
1567                "tb_cycle", updatefct=(self.OnUpdateDisNotWikiPage,))
1568
1569        wikiPageMenu.AppendSeparator()
1570
1571        self.addMenuItem(wikiPageMenu, _(u'&Follow Link') + u'\t' +
1572                self.keyBindings.ActivateLink, _(u'Activate link/word'),
1573                lambda evt: self.getActiveEditor().activateLink(),
1574                updatefct=(self.OnUpdateDisNotTextedit, self.OnUpdateDisNotWikiPage)
1575                )
1576
1577        self.addMenuItem(wikiPageMenu, _(u'Follow Link in &New Tab') + u'\t' +
1578                self.keyBindings.ActivateLinkNewTab, _(u'Activate link/word in new tab'),
1579                lambda evt: self.getActiveEditor().activateLink(tabMode=2),
1580                updatefct=(self.OnUpdateDisNotTextedit, self.OnUpdateDisNotWikiPage)
1581                )
1582
1583        self.addMenuItem(wikiPageMenu, _(u'Copy &URL to Clipboard') + u'\t' +
1584                self.keyBindings.ClipboardCopyUrlToCurrentWikiword,
1585                _(u'Copy full "wiki:" URL of the word to clipboard'),
1586                self.OnCmdClipboardCopyUrlToCurrentWikiWord,
1587                updatefct=(self.OnUpdateDisNotWikiPage,))
1588
1589
1590
1591        formatMenu = wx.Menu()
1592       
1593        self.addMenuItem(formatMenu, _(u'&Bold') + u'\t' + self.keyBindings.Bold,
1594                _(u'Bold'), lambda evt: self.keyBindings.makeBold(self.getActiveEditor()),
1595                "tb_bold",
1596                menuID=GUI_ID.CMD_FORMAT_BOLD,
1597                updatefct=(self.OnUpdateDisReadOnlyPage, self.OnUpdateDisNotTextedit,
1598                    self.OnUpdateDisNotWikiPage))
1599
1600        self.addMenuItem(formatMenu, _(u'&Italic') + u'\t' + self.keyBindings.Italic,
1601                _(u'Italic'), lambda evt: self.keyBindings.makeItalic(self.getActiveEditor()),
1602                "tb_italic",
1603                menuID=GUI_ID.CMD_FORMAT_ITALIC,
1604                updatefct=(self.OnUpdateDisReadOnlyPage, self.OnUpdateDisNotTextedit,
1605                    self.OnUpdateDisNotWikiPage))
1606
1607        self.addMenuItem(formatMenu, _(u'&Heading') + u'\t' + self.keyBindings.Heading,
1608                _(u'Add Heading'), lambda evt: self.keyBindings.addHeading(self.getActiveEditor()),
1609                "tb_heading",
1610                menuID=GUI_ID.CMD_FORMAT_HEADING_PLUS,
1611                updatefct=(self.OnUpdateDisReadOnlyPage, self.OnUpdateDisNotTextedit,
1612                    self.OnUpdateDisNotWikiPage))
1613
1614        formatMenu.AppendSeparator()
1615
1616        self.addMenuItem(formatMenu, _(u'&Rewrap Text') + u'\t' +
1617                self.keyBindings.RewrapText,
1618                _(u'Rewrap Text'),
1619                lambda evt: self.getActiveEditor().rewrapText(),
1620                updatefct=self.OnUpdateDisReadOnlyPage)
1621
1622        convertMenu = wx.Menu()
1623        formatMenu.AppendMenu(wx.NewId(), _(u'&Convert'), convertMenu)
1624
1625        self.addMenuItem(convertMenu,
1626                _(u'Selection to &Link') + u'\t' + self.keyBindings.MakeWikiWord,
1627                _(u'Remove non-allowed characters and make sel. a wiki word link'),
1628                lambda evt: self.keyBindings.makeWikiWord(self.getActiveEditor()),
1629                "pin", menuID=GUI_ID.CMD_FORMAT_WIKIZE_SELECTED,
1630                updatefct=(self.OnUpdateDisReadOnlyPage, self.OnUpdateDisNotTextedit))
1631       
1632        self.addMenuItem(convertMenu, _(u'Selection to &Wiki Word') + u'\t' +
1633                self.keyBindings.ReplaceTextByWikiword,
1634                _(u'Put selected text in a new or existing wiki word'),
1635                lambda evt: self.showReplaceTextByWikiwordDialog(),
1636                updatefct=self.OnUpdateDisReadOnlyPage)
1637
1638        formatMenu.AppendSeparator()
1639
1640
1641        iconsMenu, cmdIdToIconName = PropertyHandling.buildIconsSubmenu(
1642                wx.GetApp().getIconCache())
1643        for cmi in cmdIdToIconName.keys():
1644            wx.EVT_MENU(self, cmi, self.OnInsertStringFromDict)
1645
1646        formatMenu.AppendMenu(GUI_ID.MENU_ADD_ICON_NAME,
1647                _(u'&Icon Name'), iconsMenu)
1648        wx.EVT_UPDATE_UI(self, GUI_ID.MENU_ADD_ICON_NAME,
1649                self.OnUpdateDisReadOnlyPage)
1650
1651        self.cmdIdToInsertString = cmdIdToIconName
1652       
1653       
1654        colorsMenu, cmdIdToColorName = PropertyHandling.buildColorsSubmenu()
1655        for cmi in cmdIdToColorName.keys():
1656            wx.EVT_MENU(self, cmi, self.OnInsertStringFromDict)
1657
1658        formatMenu.AppendMenu(GUI_ID.MENU_ADD_STRING_NAME,
1659                _(u'&Color Name'), colorsMenu)
1660        wx.EVT_UPDATE_UI(self, GUI_ID.MENU_ADD_STRING_NAME,
1661                self.OnUpdateDisReadOnlyPage)
1662
1663        self.cmdIdToInsertString.update(cmdIdToColorName)
1664
1665
1666        addAttributeMenu = wx.Menu()
1667        formatMenu.AppendMenu(wx.NewId(), _(u'&Add Attribute'), addAttributeMenu)
1668
1669        # Build full submenu for icon attributes
1670        iconsMenu, self.cmdIdToIconNameForAttribute = PropertyHandling.buildIconsSubmenu(
1671                wx.GetApp().getIconCache())
1672        for cmi in self.cmdIdToIconNameForAttribute.keys():
1673            wx.EVT_MENU(self, cmi, self.OnInsertIconAttribute)
1674
1675        addAttributeMenu.AppendMenu(GUI_ID.MENU_ADD_ICON_ATTRIBUTE,
1676                _(u'&Icon Attribute'), iconsMenu)
1677        wx.EVT_UPDATE_UI(self, GUI_ID.MENU_ADD_ICON_ATTRIBUTE,
1678                self.OnUpdateDisReadOnlyPage)
1679
1680        # Build submenu for color attributes
1681        colorsMenu, self.cmdIdToColorNameForAttribute = PropertyHandling.buildColorsSubmenu()
1682        for cmi in self.cmdIdToColorNameForAttribute.keys():
1683            wx.EVT_MENU(self, cmi, self.OnInsertColorAttribute)
1684
1685        addAttributeMenu.AppendMenu(GUI_ID.MENU_ADD_COLOR_ATTRIBUTE,
1686                _(u'&Color Attribute'), colorsMenu)
1687        wx.EVT_UPDATE_UI(self, GUI_ID.MENU_ADD_COLOR_ATTRIBUTE,
1688                self.OnUpdateDisReadOnlyPage)
1689
1690        # TODO: Bold attribute
1691
1692
1693        navigateMenu = wx.Menu()
1694
1695        self.addMenuItem(navigateMenu, _(u'&Back') + u'\t' + self.keyBindings.GoBack,
1696                _(u'Go backward'), self._OnEventToCurrentDocPPresenter,
1697                "tb_back", menuID=GUI_ID.CMD_PAGE_HISTORY_GO_BACK)
1698
1699        self.addMenuItem(navigateMenu, _(u'&Forward') + u'\t' + self.keyBindings.GoForward,
1700                _(u'Go forward'), self._OnEventToCurrentDocPPresenter,
1701                "tb_forward", menuID=GUI_ID.CMD_PAGE_HISTORY_GO_FORWARD)
1702
1703
1704        self.addMenuItem(navigateMenu, _(u'&Wiki Home') + u'\t' + self.keyBindings.GoHome,
1705                _(u'Go to wiki homepage'),
1706                lambda evt: self.openWikiPage(self.getWikiDocument().getWikiName(),
1707                    forceTreeSyncFromRoot=True),
1708                "tb_home")
1709
1710        navigateMenu.AppendSeparator()
1711
1712        self.addMenuItem(navigateMenu, _(u'Go to &Page...') + u'\t' +
1713                self.keyBindings.OpenWikiWord, _(u'Open wiki word'),
1714                lambda evt: self.showWikiWordOpenDialog(),
1715                "tb_doc")
1716
1717
1718        self.addMenuItem(navigateMenu, _(u'Go to P&arent...') + u'\t' +
1719                self.keyBindings.ViewParents,
1720                _(u'List parents of current wiki word'),
1721                lambda evt: self.viewParents(self.getCurrentWikiWord()))
1722
1723        self.addMenuItem(navigateMenu, _(u'List &Children...') + u'\t' +
1724                self.keyBindings.ViewChildren,
1725                _(u'List children of current wiki word'),
1726                lambda evt: self.viewChildren(self.getCurrentWikiWord()))
1727
1728        self.addMenuItem(navigateMenu, _(u'List Pa&rentless Pages') + u'\t' +
1729                self.keyBindings.ViewParentless,
1730                _(u'List nodes with no parent relations'),
1731                lambda evt: self.viewParentLess())
1732
1733        navigateMenu.AppendSeparator()
1734
1735        self.addMenuItem(navigateMenu, _(u'Show &History...') + u'\t' + self.keyBindings.ViewHistory,
1736                _(u'View tab history'), self._OnEventToCurrentDocPPresenter,
1737                menuID=GUI_ID.CMD_PAGE_HISTORY_LIST)
1738
1739        self.addMenuItem(navigateMenu, _(u'&Up History...') + u'\t' + self.keyBindings.UpHistory,
1740                _(u'Up in tab history'), self._OnEventToCurrentDocPPresenter,
1741                menuID=GUI_ID.CMD_PAGE_HISTORY_LIST_UP)
1742
1743        self.addMenuItem(navigateMenu, _(u'&Down History...') + u'\t' + self.keyBindings.DownHistory,
1744                _(u'Down in tab history'), self._OnEventToCurrentDocPPresenter,
1745                menuID=GUI_ID.CMD_PAGE_HISTORY_LIST_DOWN)
1746
1747        navigateMenu.AppendSeparator()
1748
1749        self.addMenuItem(navigateMenu, _(u'Add B&ookmark') + u'\t' +
1750                self.keyBindings.AddBookmark, _(u'Add bookmark to page'),
1751                lambda evt: self.insertAttribute("bookmarked", "true"),
1752                "pin", updatefct=(self.OnUpdateDisReadOnlyWiki, self.OnUpdateDisNotWikiPage))
1753
1754        self.addMenuItem(navigateMenu, _(u'Go to &Bookmark...') + u'\t' +
1755                self.keyBindings.ViewBookmarks, _(u'List bookmarks'),
1756                lambda evt: self.viewBookmarks())
1757
1758
1759        extraMenu = wx.Menu()
1760
1761        self.addMenuItem(extraMenu, _(u'&Export...'),
1762                _(u'Open general export dialog'), self.OnCmdExportDialog,
1763                updatefct=self.OnUpdateDisNoWiki)
1764
1765        self.addMenuItem(extraMenu, _(u'&Continuous Export...'),
1766                _(u'Open export dialog for continuous export of changes'),
1767                self.OnCmdContinuousExportDialog,
1768                updatefct=(self.OnUpdateDisNoWiki,
1769                self.OnUpdateContinuousExportDialog), kind=wx.ITEM_CHECK)
1770
1771
1772        self.addMenuItem(extraMenu, _(u'&Import...'),
1773                _(u'Import dialog'), self.OnCmdImportDialog,
1774                updatefct=self.OnUpdateDisReadOnlyWiki)
1775
1776        extraMenu.AppendSeparator()
1777
1778        evaluationMenu=wx.Menu()
1779        extraMenu.AppendMenu(wx.NewId(), _(u"Scripts"), evaluationMenu,
1780                _(u"Run scripts, evaluate expressions"))
1781
1782        self.addMenuItem(evaluationMenu, _(u'&Eval') + u'\t' + self.keyBindings.Eval,
1783                _(u'Evaluate script blocks'),
1784                lambda evt: self.getActiveEditor().evalScriptBlocks())
1785
1786        for i in range(1,7):
1787            self.addMenuItem(evaluationMenu,
1788                    (_(u'Run Function &%i') + u'\tCtrl-%i') % (i, i),
1789                    _(u'Run script function %i') % i,
1790                    lambda evt, i=i: self.getActiveEditor().evalScriptBlocks(i))
1791
1792        extraMenu.AppendSeparator()
1793
1794        self.addMenuItem(extraMenu, _(u'O&ptions...'),
1795                _(u'Set options'), lambda evt: self.showOptionsDialog(),
1796                menuID = wx.ID_PREFERENCES)
1797
1798
1799
1800        helpMenu = wx.Menu()
1801
1802        def openHelp(evt):
1803            try:
1804                clAction = CmdLineAction([])
1805                clAction.wikiToOpen = self.wikiPadHelp
1806                clAction.frameToOpen = 1  # Open in new frame
1807
1808                wx.GetApp().startPersonalWikiFrame(clAction)
1809            except Exception, e:
1810                traceback.print_exc()
1811                self.displayErrorMessage(_(u'Error while starting new '
1812                        u'WikidPad instance'), e)
1813                return
1814
1815        self.addMenuItem(helpMenu, _(u'&Open help wiki'),
1816                _(u'Open WikidPadHelp, the help wiki'), openHelp)
1817
1818
1819#         menuID=wx.NewId()
1820#         helpMenu.Append(menuID, _(u'&Open WikidPadHelp'), _(u'Open WikidPadHelp'))
1821#         wx.EVT_MENU(self, menuID, openHelp)
1822
1823        helpMenu.AppendSeparator()
1824
1825        self.addMenuItem(helpMenu, _(u'&Visit Homepage'),
1826                _(u'Visit wikidPad homepage'),
1827                lambda evt: OsAbstract.startFile(self, HOMEPAGE))
1828
1829#         menuID=wx.NewId()
1830#         helpMenu.Append(menuID, _(u'&Visit wikidPad Homepage'), _(u'Visit Homepage'))
1831#         wx.EVT_MENU(self, menuID, lambda evt: OsAbstract.startFile(self, HOMEPAGE))
1832
1833        helpMenu.AppendSeparator()
1834
1835        self.addMenuItem(helpMenu,
1836                _(u'Show &License'),
1837                _(u'Show license of WikidPad and used components'),
1838                lambda evt: OsAbstract.startFile(self,
1839                join(self.wikiAppDir, u'license.txt')))
1840
1841#         menuID = wx.NewId()
1842#         helpMenu.Append(menuID, _(u'View &License'), _(u'View License'))
1843#         wx.EVT_MENU(self, menuID, lambda evt: OsAbstract.startFile(self,
1844#                 join(self.wikiAppDir, u'license.txt')))
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865        # Build menubar from all the menus
1866
1867        if wx.Platform != "__WXMAC__":
1868            #don't need final separator if about item is going to app menu
1869            helpMenu.AppendSeparator()
1870
1871        menuID = wx.ID_ABOUT
1872        helpMenu.Append(menuID, _(u'&About'), _(u'About WikidPad'))
1873
1874        wx.EVT_MENU(self, menuID, lambda evt: self.showAboutDialog())
1875
1876        self.mainmenu.Append(wikiMenu, _(u'&Wiki'))
1877        self.mainmenu.Append(editMenu, _(u'&Edit'))
1878        self.mainmenu.Append(viewMenu, _(u'&View'))
1879        self.mainmenu.Append(tabsMenu, _(u'&Tabs'))
1880        self.mainmenu.Append(wikiPageMenu, _(u'Wiki &Page'))
1881        self.mainmenu.Append(formatMenu, _(u'&Format'))
1882        self.mainmenu.Append(navigateMenu, _(u'&Navigate'))
1883        self.mainmenu.Append(extraMenu, _(u'E&xtra'))
1884
1885       
1886#         self.mainmenu.AppendMenu(wx.NewId(), _(u'&Wiki'), wikiMenu)
1887#         self.mainmenu.AppendMenu(wx.NewId(), _(u'&Edit'), editMenu)
1888#         self.mainmenu.AppendMenu(wx.NewId(), _(u'&View'), viewMenu)
1889#         self.mainmenu.AppendMenu(wx.NewId(), _(u'&Tabs'), tabsMenu)
1890#         self.mainmenu.AppendMenu(wx.NewId(), _(u'Wiki &Page'), wikiPageMenu)
1891#         self.mainmenu.AppendMenu(wx.NewId(), _(u'&Format'), formatMenu)
1892#         self.mainmenu.AppendMenu(wx.NewId(), _(u'&Navigate'), navigateMenu)
1893#         self.mainmenu.AppendMenu(wx.NewId(), _(u'E&xtra'), extraMenu)
1894
1895
1896
1897        self.pluginsMenu = wx.Menu()
1898        self.fillPluginsMenu(self.pluginsMenu)
1899        self.mainmenu.Append(self.pluginsMenu, _(u"Pl&ugins"))
1900
1901
1902        # Mac does not use menu accelerators anyway and wx special cases &Help
1903        # to the in build Help menu this check stops 2 help menus on mac
1904        if wx.Platform == "__WXMAC__":
1905            self.mainmenu.Append(helpMenu, _(u'&Help'))
1906        else:
1907            self.mainmenu.Append(helpMenu, _(u'He&lp'))
1908
1909
1910        self.SetMenuBar(self.mainmenu)
1911
1912#         if self.getWikiConfigPath():  # If a wiki is open
1913#             self.mainmenu.EnableTop(1, 1)
1914#             self.mainmenu.EnableTop(2, 1)
1915#             self.mainmenu.EnableTop(3, 1)
1916#         else:
1917#             self.mainmenu.EnableTop(1, 0)
1918#             self.mainmenu.EnableTop(2, 0)
1919#             self.mainmenu.EnableTop(3, 0)
1920
1921
1922
1923    def buildToolbar(self):
1924        # ------------------------------------------------------------------------------------
1925        # Create the toolbar
1926        # ------------------------------------------------------------------------------------
1927
1928        tb = self.CreateToolBar(wx.TB_HORIZONTAL | wx.NO_BORDER | wx.TB_FLAT | wx.TB_TEXT)
1929        seperator = self.lookupSystemIcon("tb_seperator")
1930
1931        icon = self.lookupSystemIcon("tb_back")
1932        tbID = GUI_ID.CMD_PAGE_HISTORY_GO_BACK
1933        tb.AddSimpleTool(tbID, icon, _(u"Back") + " " + self.keyBindings.GoBack,
1934                _(u"Back"))
1935        wx.EVT_TOOL(self, tbID, self._OnEventToCurrentDocPPresenter)
1936
1937        icon = self.lookupSystemIcon("tb_forward")
1938        tbID = GUI_ID.CMD_PAGE_HISTORY_GO_FORWARD
1939        tb.AddSimpleTool(tbID, icon, _(u"Forward") + " " + self.keyBindings.GoForward,
1940                _(u"Forward"))
1941        wx.EVT_TOOL(self, tbID, self._OnEventToCurrentDocPPresenter)
1942
1943        icon = self.lookupSystemIcon("tb_home")
1944        tbID = wx.NewId()
1945        tb.AddSimpleTool(tbID, icon, _(u"Wiki Home") + " " + self.keyBindings.GoHome,
1946                _(u"Wiki Home"))
1947        wx.EVT_TOOL(self, tbID,
1948                lambda evt: self.openWikiPage(self.getWikiDocument().getWikiName(),
1949                forceTreeSyncFromRoot=True))
1950
1951        icon = self.lookupSystemIcon("tb_doc")
1952        tbID = wx.NewId()
1953        tb.AddSimpleTool(tbID, icon,
1954                _(u"Open Wiki Word") + " " + self.keyBindings.OpenWikiWord,
1955                _(u"Open Wiki Word"))
1956        wx.EVT_TOOL(self, tbID, lambda evt: self.showWikiWordOpenDialog())
1957
1958        icon = self.lookupSystemIcon("tb_lens")
1959        tbID = wx.NewId()
1960        tb.AddSimpleTool(tbID, icon, _(u"Search") + " " + self.keyBindings.SearchWiki,
1961                _(u"Search"))
1962        wx.EVT_TOOL(self, tbID, lambda evt: self.showSearchDialog())
1963
1964        icon = self.lookupSystemIcon("tb_cycle")
1965        tbID = wx.NewId()
1966        tb.AddSimpleTool(tbID, icon, _(u"Find current word in tree"),
1967                _(u"Find current word in tree"))
1968        wx.EVT_TOOL(self, tbID, lambda evt: self.findCurrentWordInTree())
1969
1970        tb.AddSimpleTool(wx.NewId(), seperator, _(u"Separator"), _(u"Separator"))
1971
1972        icon = self.lookupSystemIcon("tb_save")
1973        tb.AddSimpleTool(GUI_ID.CMD_SAVE_WIKI, icon,
1974                _(u"Save Wiki Word") + " " + self.keyBindings.Save,
1975                _(u"Save Wiki Word"))
1976
1977        icon = self.lookupSystemIcon("tb_rename")
1978        tb.AddSimpleTool(GUI_ID.CMD_RENAME_PAGE, icon,
1979                _(u"Rename Wiki Word") + " " + self.keyBindings.Rename,
1980                _(u"Rename Wiki Word"))
1981#         wx.EVT_TOOL(self, tbID, lambda evt: self.showWikiWordRenameDialog())
1982
1983        icon = self.lookupSystemIcon("tb_delete")
1984        tb.AddSimpleTool(GUI_ID.CMD_DELETE_PAGE, icon,
1985                _(u"Delete") + " " + self.keyBindings.Delete, _(u"Delete Wiki Word"))
1986#         wx.EVT_TOOL(self, tbID, lambda evt: self.showWikiWordDeleteDialog())
1987
1988        tb.AddSimpleTool(wx.NewId(), seperator, _(u"Separator"), _(u"Separator"))
1989
1990        icon = self.lookupSystemIcon("tb_heading")
1991        tb.AddSimpleTool(GUI_ID.CMD_FORMAT_HEADING_PLUS, icon,
1992                _(u"Heading") + " " + self.keyBindings.Heading, _(u"Heading"))
1993#         wx.EVT_TOOL(self, tbID, lambda evt: self.keyBindings.addHeading(
1994#                 self.getActiveEditor()))
1995
1996        icon = self.lookupSystemIcon("tb_bold")
1997        tb.AddSimpleTool(GUI_ID.CMD_FORMAT_BOLD, icon,
1998                _(u"Bold") + " " + self.keyBindings.Bold, _(u"Bold"))
1999#         wx.EVT_TOOL(self, tbID, lambda evt: self.keyBindings.makeBold(
2000#                 self.getActiveEditor()))
2001
2002        icon = self.lookupSystemIcon("tb_italic")
2003        tb.AddSimpleTool(GUI_ID.CMD_FORMAT_ITALIC, icon,
2004                _(u"Italic") + " " + self.keyBindings.Italic, _(u"Italic"))
2005#         wx.EVT_TOOL(self, tbID, lambda evt: self.keyBindings.makeItalic(
2006#                 self.getActiveEditor()))
2007
2008        tb.AddSimpleTool(wx.NewId(), seperator, _(u"Separator"), _(u"Separator"))
2009
2010        icon = self.lookupSystemIcon("tb_switch ed prev")
2011        tbID = GUI_ID.CMD_TAB_SHOW_SWITCH_EDITOR_PREVIEW
2012        tb.AddSimpleTool(tbID, icon, _(u"Switch Editor/Preview"),
2013                _(u"Switch between editor and preview"))
2014
2015        icon = self.lookupSystemIcon("tb_zoomin")
2016        tbID = GUI_ID.CMD_ZOOM_IN
2017        tb.AddSimpleTool(tbID, icon, _(u"Zoom In"), _(u"Zoom In"))
2018        wx.EVT_TOOL(self, tbID, self._OnRoundtripEvent)
2019
2020        icon = self.lookupSystemIcon("tb_zoomout")
2021        tbID = GUI_ID.CMD_ZOOM_OUT
2022        tb.AddSimpleTool(tbID, icon, _(u"Zoom Out"), _(u"Zoom Out"))
2023        wx.EVT_TOOL(self, tbID, self._OnRoundtripEvent)
2024
2025
2026        self.fastSearchField = wx.TextCtrl(tb, GUI_ID.TF_FASTSEARCH,
2027                style=wx.TE_PROCESS_ENTER | wx.TE_RICH)
2028        tb.AddControl(self.fastSearchField)
2029        wx.EVT_KEY_DOWN(self.fastSearchField, self.OnFastSearchKeyDown)
2030
2031        icon = self.lookupSystemIcon("tb_wikize")
2032        tb.AddSimpleTool(GUI_ID.CMD_FORMAT_WIKIZE_SELECTED, icon,
2033                _(u"Wikize Selected Word ") + self.keyBindings.MakeWikiWord,
2034                _(u"Wikize Selected Word"))
2035#         wx.EVT_TOOL(self, tbID, lambda evt: self.keyBindings.makeWikiWord(self.getActiveEditor()))
2036
2037        # Build favorite wikis tool buttons
2038        wikiDoc = self.getWikiDocument()
2039        page = WikiDataManager.getGlobalFuncPage(u"global/FavoriteWikis")
2040        treeData = TextTree.buildTreeFromText(page.getContent(),
2041                TextTree.FavoriteWikisEntry.factory)
2042       
2043        toolEntries = [(None, None)] * 9
2044
2045        # Filter entries from activation map with a digit (1 to 9) in the flags.
2046        # This digit defines the position in the toolbar.
2047        for menuID, entry in self.favoriteWikisActivation.iteritems():
2048            num = entry.getToolbarPosition()
2049            if num != -1:
2050                toolEntries[num - 1] = (menuID, entry)
2051
2052        defIcon = self.lookupSystemIcon("tb_doc")
2053
2054        # Now go through found entries to create tool buttons
2055        for menuID, entry in toolEntries:
2056            if entry is None:
2057                # No entry for this digit
2058                continue
2059
2060            icon = self.resolveIconDescriptor(entry.iconDesc, defIcon)
2061            tbID = menuID
2062            tb.AddSimpleTool(tbID, icon, entry.title, entry.value)
2063#             wx.EVT_TOOL(self, tbID, self._OnRoundtripEvent)   # TODO Check if needed on Linux/GTK
2064
2065
2066        # get info for any plugin toolbar items and create them as necessary
2067        toolbarItems = reduce(lambda a, b: a+list(b),
2068                self.toolbarFunctions.describeToolbarItems(self), [])
2069       
2070        def addPluginTool(function, tooltip, statustext, icondesc, tbID=None,
2071                updateFunction=None):
2072            if tbID is None:
2073                tbID = wx.NewId()
2074               
2075            icon = self.resolveIconDescriptor(icondesc, defIcon)
2076            # tb.AddLabelTool(tbID, label, icon, wxNullBitmap, 0, tooltip)
2077            tb.AddSimpleTool(tbID, icon, tooltip, statustext)
2078            wx.EVT_TOOL(self, tbID, lambda evt: function(self, evt))
2079
2080            if updateFunction is not None:
2081                wx.EVT_UPDATE_UI(self, tbID, lambda evt: updateFunction(self, evt))
2082
2083
2084        for item in toolbarItems:
2085            addPluginTool(*item)
2086
2087
2088        tb.Realize()
2089
2090
2091
2092    def initializeGui(self):
2093        "initializes the gui environment"
2094
2095        # ------------------------------------------------------------------------------------
2096        # Create the status bar
2097        # ------------------------------------------------------------------------------------
2098        self.statusBar = wx.StatusBar(self, -1)
2099        self.statusBar.SetFieldsCount(3)
2100
2101        # Measure necessary widths of status fields
2102        dc = wx.ClientDC(self.statusBar)
2103        try:
2104            dc.SetFont(self.statusBar.GetFont())
2105            posWidth = dc.GetTextExtent(
2106                    _(u"Line: 9999 Col: 9999 Pos: 9999999988888"))[0]
2107            dc.SetFont(wx.NullFont)
2108        finally:
2109            del dc
2110
2111       
2112        # Create main area panel first
2113        self.mainAreaPanel = MainAreaPanel(self, self, -1)
2114#         self.mainAreaPanel = MainAreaPanel(self)
2115        self.mainAreaPanel.getMiscEvent().addListener(self)
2116
2117        p = self.createNewDocPagePresenterTab()
2118        self.mainAreaPanel.prepareCurrentPresenter(p)
2119 
2120        # Build layout:
2121
2122        self.windowLayouter = WindowSashLayouter(self, self.createWindow)
2123
2124        cfstr = self.getConfig().get("main", "windowLayout")
2125        self.windowLayouter.setWinPropsByConfig(cfstr)
2126       
2127        self.windowLayouter.realize()
2128#         self.windowLayouter.layout()
2129
2130        self.tree = self.windowLayouter.getWindowForName("maintree")
2131        self.logWindow = self.windowLayouter.getWindowForName("log")
2132
2133
2134       
2135
2136#         wx.EVT_NOTEBOOK_PAGE_CHANGED(self, self.mainAreaPanel.GetId(),
2137#                 self.OnNotebookPageChanged)
2138#         wx.EVT_CONTEXT_MENU(self.mainAreaPanel, self.OnNotebookContextMenu)
2139#
2140#         wx.EVT_SET_FOCUS(self.mainAreaPanel, self.OnNotebookFocused)
2141
2142
2143        # ------------------------------------------------------------------------------------
2144        # Create menu and toolbar
2145        # ------------------------------------------------------------------------------------
2146       
2147        self.buildMainMenu()
2148        if self.getConfig().getboolean("main", "toolbar_show", True):
2149            self.setShowToolbar(True)
2150
2151        wx.EVT_MENU(self, GUI_ID.CMD_SWITCH_FOCUS, self.OnSwitchFocus)
2152
2153        # Table with additional possible accelerators
2154        ADD_ACCS = (
2155                ("CloseCurrentTab", GUI_ID.CMD_CLOSE_CURRENT_TAB),
2156                ("SwitchFocus", GUI_ID.CMD_SWITCH_FOCUS),
2157                ("GoNextTab", GUI_ID.CMD_GO_NEXT_TAB),
2158                ("GoPreviousTab", GUI_ID.CMD_GO_PREVIOUS_TAB),
2159                ("FocusFastSearchField", GUI_ID.CMD_FOCUS_FAST_SEARCH_FIELD)
2160#                 ("ActivateLink2", GUI_ID.CMD_ACTIVATE_LINK)
2161                )
2162
2163
2164        # Add alternative accelerators for clipboard operations
2165        accs = [
2166                (wx.ACCEL_CTRL, wx.WXK_INSERT, GUI_ID.CMD_CLIPBOARD_COPY),
2167                (wx.ACCEL_SHIFT, wx.WXK_INSERT, GUI_ID.CMD_CLIPBOARD_PASTE),
2168                (wx.ACCEL_SHIFT, wx.WXK_DELETE, GUI_ID.CMD_CLIPBOARD_CUT)
2169                ]
2170
2171
2172        # Add additional accelerators
2173        for keyName, menuId in ADD_ACCS:
2174            accP = self.keyBindings.getAccelPair(keyName)
2175            if accP != (None, None):
2176                accs.append((accP[0], accP[1], menuId))
2177
2178        if Configuration.isLinux():   # Actually if wxGTK
2179            accs += [(wx.ACCEL_NORMAL, fkey, GUI_ID.SPECIAL_EAT_KEY)
2180                    for fkey in range(wx.WXK_F1, wx.WXK_F24 + 1)] + \
2181                    [(wx.ACCEL_SHIFT, fkey, GUI_ID.SPECIAL_EAT_KEY)
2182                    for fkey in range(wx.WXK_F1, wx.WXK_F24 + 1)]
2183   
2184            wx.EVT_MENU(self, GUI_ID.SPECIAL_EAT_KEY, lambda evt: None)
2185
2186        self.SetAcceleratorTable(wx.AcceleratorTable(accs))
2187
2188        # Check if window should stay on top
2189        self.setStayOnTop(self.getConfig().getboolean("main", "frame_stayOnTop",
2190                False))
2191
2192        self.statusBar.SetStatusWidths([-1, -1, posWidth])
2193        self.SetStatusBar(self.statusBar)
2194
2195        # Register the App IDLE handler
2196        wx.EVT_IDLE(self, self.OnIdle)
2197
2198        # Register the App close handler
2199        wx.EVT_CLOSE(self, self.OnCloseButton)
2200
2201#         # Check resizing to layout sash windows
2202        wx.EVT_SIZE(self, self.OnSize)
2203
2204        wx.EVT_ICONIZE(self, self.OnIconize)
2205        wx.EVT_MAXIMIZE(self, self.OnMaximize)
2206       
2207        wx.EVT_MENU(self, GUI_ID.CMD_CLOSE_CURRENT_TAB, self._OnRoundtripEvent)
2208        wx.EVT_MENU(self, GUI_ID.CMD_GO_NEXT_TAB, self._OnRoundtripEvent)
2209        wx.EVT_MENU(self, GUI_ID.CMD_GO_PREVIOUS_TAB, self._OnRoundtripEvent)
2210        wx.EVT_MENU(self, GUI_ID.CMD_FOCUS_FAST_SEARCH_FIELD,
2211                self.OnCmdFocusFastSearchField)
2212
2213
2214    def OnUpdateTreeCtrlMenuItem(self, evt):
2215        evt.Check(not self.windowLayouter.isWindowCollapsed("maintree"))
2216
2217    def OnUpdateToolbarMenuItem(self, evt):
2218        evt.Check(not self.GetToolBar() is None)
2219
2220    def OnUpdateDocStructureMenuItem(self, evt):
2221        evt.Check(not self.windowLayouter.isWindowCollapsed("doc structure"))
2222
2223    def OnUpdateTimeViewMenuItem(self, evt):
2224        evt.Check(not self.windowLayouter.isWindowCollapsed("time view"))
2225
2226    def OnUpdateStayOnTopMenuItem(self, evt):
2227        evt.Check(self.getStayOnTop())
2228
2229
2230    def OnSwitchFocus(self, evt):
2231        foc = wx.Window.FindFocus()
2232        mainAreaPanel = self.mainAreaPanel
2233        while foc != None:
2234            if foc == mainAreaPanel:
2235                self.tree.SetFocus()
2236                return
2237           
2238            foc = foc.GetParent()
2239           
2240        mainAreaPanel.SetFocus()
2241
2242
2243    def OnFastSearchKeyDown(self, evt):
2244        """
2245        Process wx.EVT_KEY_DOWN in the fast search text field
2246        """
2247        acc = getAccelPairFromKeyDown(evt)
2248        if acc == (wx.ACCEL_NORMAL, wx.WXK_RETURN) or \
2249                acc == (wx.ACCEL_NORMAL, wx.WXK_NUMPAD_ENTER):
2250            text = guiToUni(self.fastSearchField.GetValue())
2251            tfHeight = self.fastSearchField.GetSize()[1]
2252            pos = self.fastSearchField.ClientToScreen((0, tfHeight))
2253
2254            popup = FastSearchPopup(self, self, -1, pos=pos)
2255            popup.Show()
2256            try:
2257                popup.runSearchOnWiki(text)
2258            except re.error, e:
2259                popup.Show(False)
2260                self.displayErrorMessage(_(u'Regular expression error'), e)
2261        else:
2262            evt.Skip()
2263
2264#     def OnFastSearchChar(self, evt):
2265#         print "OnFastSearchChar", repr(evt.GetUnicodeKey()), repr(evt.GetKeyCode())
2266#         evt.Skip()
2267
2268    def OnCmdReconnectDatabase(self, evt):
2269        result = wx.MessageBox(_(u"Are you sure you want to reconnect? "
2270                u"You may lose some data by this process."),
2271                _(u'Reconnect database'),
2272                wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, self)
2273
2274        wd = self.getWikiDocument()
2275        if result == wx.YES and wd is not None:
2276            wd.setReadAccessFailed(True)
2277            wd.setWriteAccessFailed(True)
2278            # Try reading
2279            while True:
2280                try:
2281                    wd.reconnect()
2282                    wd.setReadAccessFailed(False)
2283                    break   # Success
2284                except (IOError, OSError, DbAccessError), e:
2285                    sys.stderr.write(_(u"Error while trying to reconnect:\n"))
2286                    traceback.print_exc()
2287                    result = wx.MessageBox(uniToGui(_(
2288                            u'There was an error while reconnecting the database\n\n'
2289                            u'Would you like to try it again?\n%s') %
2290                            e), _(u'Error reconnecting!'),
2291                            wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, self)
2292                    if result == wx.NO:
2293                        return
2294
2295            # Try writing
2296            while True:
2297                try:
2298                    # write out the current configuration
2299                    self.writeCurrentConfig()
2300                    self.getWikiData().testWrite()
2301
2302                    wd.setNoAutoSaveFlag(False)
2303                    wd.setWriteAccessFailed(False)
2304                    break   # Success
2305                except (IOError, OSError, DbWriteAccessError), e:
2306                    sys.stderr.write(_(u"Error while trying to write:\n"))
2307                    traceback.print_exc()
2308                    result = wx.MessageBox(uniToGui(_(
2309                            u'There was an error while writing to the database\n\n'
2310                            u'Would you like to try it again?\n%s') %
2311                            e), _(u'Error writing!'),
2312                            wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, self)
2313                    if result == wx.NO:
2314                        break
2315
2316               
2317    def OnRemoteCommand(self, evt):
2318        try:
2319            clAction = CmdLineAction(evt.getCmdLine())
2320            wx.GetApp().startPersonalWikiFrame(clAction)
2321        except Exception, e:
2322            traceback.print_exc()
2323            self.displayErrorMessage(_(u'Error while starting new '
2324                    u'WikidPad instance'), e)
2325            return
2326
2327
2328    def OnShowHideHotkey(self, evt):
2329        if self.IsActive():
2330            self.Iconize(True)
2331        else:
2332            if self.IsIconized():
2333                self.Iconize(False)
2334                self.Show(True)
2335
2336            self.Raise()
2337
2338
2339    def OnCmdFocusFastSearchField(self, evt):
2340        if self.fastSearchField is not None:
2341            self.fastSearchField.SetFocus()
2342
2343
2344    def OnCmdClipboardCopyUrlToCurrentWikiWord(self, evt):
2345        wikiWord = self.getCurrentWikiWord()
2346        if wikiWord is None:
2347            return
2348       
2349        path = self.getWikiDocument().getWikiConfigPath()
2350        copyTextToClipboard(pathWordAndAnchorToWikiUrl(path, wikiWord, None))
2351
2352
2353    def goBrowserBack(self):
2354        evt = wx.CommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED,
2355                GUI_ID.CMD_PAGE_HISTORY_GO_BACK)
2356        self._OnEventToCurrentDocPPresenter(evt)
2357
2358    def goBrowserForward(self):
2359        evt = wx.CommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED,
2360                GUI_ID.CMD_PAGE_HISTORY_GO_FORWARD)
2361        self._OnEventToCurrentDocPPresenter(evt)
2362
2363
2364    def _refreshHotKeys(self):
2365        """
2366        Refresh the system-wide hotkey settings according to configuration
2367        """
2368        # A dummy window must be destroyed and recreated because
2369        # Unregistering a hotkey doesn't work
2370        if self.hotKeyDummyWindow is not None:
2371            self.hotKeyDummyWindow.Destroy()
2372
2373        self.hotKeyDummyWindow = DummyWindow(self, id=GUI_ID.WND_HOTKEY_DUMMY)
2374        if self.configuration.getboolean("main",
2375                "hotKey_showHide_byApp_isActive"):
2376            setHotKeyByString(self.hotKeyDummyWindow,
2377                    self.HOTKEY_ID_HIDESHOW_BYAPP,
2378                    self.configuration.get("main",
2379                    "hotKey_showHide_byApp", u""))
2380
2381        if self.getWikiDocument() is not None:
2382            setHotKeyByString(self.hotKeyDummyWindow,
2383                    self.HOTKEY_ID_HIDESHOW_BYWIKI,
2384                    self.configuration.get("main",
2385                    "hotKey_showHide_byWiki", u""))
2386        wx.EVT_HOTKEY(self.hotKeyDummyWindow, self.HOTKEY_ID_HIDESHOW_BYAPP,
2387                self.OnShowHideHotkey)
2388        wx.EVT_HOTKEY(self.hotKeyDummyWindow, self.HOTKEY_ID_HIDESHOW_BYWIKI,
2389                self.OnShowHideHotkey)
2390
2391
2392    def createWindow(self, winProps, parent):
2393        """
2394        Creates tree, editor, splitter, ... according to the given window name
2395        in winProps
2396        """
2397        winName = winProps["name"]
2398        if winName == "maintree" or winName == "viewstree":
2399            tree = WikiTreeCtrl(self, parent, -1, winName[:-4])
2400            # assign the image list
2401            try:
2402                # For native wx tree:
2403                # tree.AssignImageList(wx.GetApp().getIconCache().getNewImageList())
2404                # For custom tree control:
2405                tree.SetImageListNoGrayedItems(
2406                        wx.GetApp().getIconCache().getImageList())
2407            except Exception, e:
2408                traceback.print_exc()
2409                self.displayErrorMessage(_(u'There was an error loading the icons '
2410                        'for the tree control.'), e)
2411            if self.getWikiConfigPath() is not None and winName == "viewstree":
2412                tree.setViewsAsRoot()
2413                tree.expandRoot()
2414            return tree
2415        elif winName.startswith("txteditor"):
2416            editor = WikiTxtCtrl(winProps["presenter"], parent, -1)
2417            editor.evalScope = { 'editor' : editor,
2418                    'pwiki' : self, 'lib': self.evalLib}
2419
2420            # enable and zoom the editor
2421            editor.Enable(0)
2422            editor.SetZoom(self.configuration.getint("main", "zoom"))
2423            return editor
2424        elif winName == "log":
2425            return LogWindow(parent, -1, self)
2426        elif winName == "doc structure":
2427            return DocStructureCtrl(parent, -1, self)
2428        elif winName == "time view":
2429            return TimeViewCtrl(parent, -1, self)
2430        elif winName == "main area panel"# TODO remove this hack
2431            self.mainAreaPanel.Reparent(parent)
2432               
2433#             if not self._mainAreaPanelCreated:
2434#                 print "--Parent main area panel2", repr(parent)
2435#                 self.mainAreaPanel.Create(parent, -1)
2436#                 self._mainAreaPanelCreated = True
2437
2438#             self.mainAreaPanel.Reparent(parent)
2439#             self.mainAreaPanel = MainAreaPanel(parent, self, -1)
2440#             self.mainAreaPanel.getMiscEvent().addListener(self)
2441#
2442#             p = self.createNewDocPagePresenterTab()
2443#             self.mainAreaPanel.setCurrentDocPagePresenter(p)
2444
2445            return self.mainAreaPanel
2446
2447
2448
2449    def createNewDocPagePresenterTab(self):
2450        presenter = DocPagePresenter(self.mainAreaPanel, self)
2451        presenter.setLayerVisible(False)
2452        presenter.Hide()
2453
2454        editor = self.createWindow({"name": "txteditor1",
2455                "presenter": presenter}, presenter)
2456        editor.setLayerVisible(False, "textedit")
2457        presenter.setSubControl("textedit", editor)
2458
2459        htmlView = createWikiHtmlView(presenter, presenter, -1)
2460        htmlView.setLayerVisible(False, "preview")
2461        presenter.setSubControl("preview", htmlView)
2462
2463        presenter.switchSubControl("textedit")
2464
2465        return self.mainAreaPanel.appendPresenterTab(presenter)
2466
2467
2468#     def appendLogMessage(self, msg):
2469#         """
2470#         Add message to log window, make log window visible if necessary
2471#         """
2472#         if self.configuration.getboolean("main", "log_window_autoshow"):
2473#             self.windowLayouter.expandWindow("log")
2474#         self.logWindow.appendMessage(msg)
2475
2476    def showLogWindow(self):
2477        self.windowLayouter.expandWindow("log")
2478
2479    def hideLogWindow(self):
2480        self.windowLayouter.collapseWindow("log")
2481
2482    def reloadMenuPlugins(self):
2483        if self.mainmenu is not None:
2484            self.menuFunctions = self.pluginManager.registerPluginAPI((
2485                    "MenuFunctions",1), ("describeMenuItems",))
2486
2487            self.loadExtensions()
2488
2489            # This is a rebuild of an existing menu (after loading a new wikiData)
2490            clearMenu(self.pluginsMenu)
2491            self.fillPluginsMenu(self.pluginsMenu)
2492
2493            return
2494
2495
2496    def resourceSleep(self):
2497        """
2498        Free unnecessary resources if program is iconized
2499        """
2500        if self.sleepMode:
2501            return  # Already in sleep mode
2502        self.sleepMode = True
2503       
2504        toolBar = self.GetToolBar()
2505        if toolBar is not None:
2506            toolBar.Destroy()
2507
2508        self.SetMenuBar(None)
2509        self.mainmenu.Destroy()
2510
2511        # Set menu/menu items to None
2512        self.mainmenu = None
2513        self.recentWikisMenu = None
2514        self.textBlocksMenu = None
2515        self.favoriteWikisMenu = None
2516        # self.showOnTrayMenuItem = None
2517
2518        # TODO Clear cache only if exactly one window uses centralized iconLookupCache
2519        #      Maybe weak references?
2520#         for k in self.iconLookupCache.keys():
2521#             self.iconLookupCache[k] = (self.iconLookupCache[k][0], None)
2522##      Even worse:  wxGetApp().getIconCache().clearIconBitmaps()
2523
2524        gc.collect()
2525
2526
2527    def resourceWakeup(self):
2528        """
2529        Aquire resources after program is restored
2530        """
2531        if not self.sleepMode:
2532            return  # Already in wake mode
2533        self.sleepMode = False
2534
2535        self.buildMainMenu()
2536        self.setShowToolbar(self.getConfig().getboolean("main", "toolbar_show",
2537                True))
2538        self.setShowOnTray()
2539
2540
2541    def testIt(self):
2542        self.reloadMenuPlugins()
2543       
2544
2545
2546
2547#     def testIt(self):
2548#         self.hhelp = wx.html.HtmlHelpController()
2549#         self.hhelp.AddBook(join(self.wikiAppDir, "helptest/helptest.hhp"))
2550#         self.hhelp.DisplayID(1)
2551
2552#     def testIt(self):
2553#         rect = self.statusBar.GetFieldRect(0)
2554#         
2555#         dc = wx.WindowDC(self.statusBar)
2556#         dc.SetBrush(wx.RED_BRUSH)
2557#         dc.SetPen(wx.RED_PEN)
2558#         dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)
2559#         dc.SetPen(wx.WHITE_PEN)
2560#         dc.SetFont(self.statusBar.GetFont())
2561#         dc.DrawText(u"Saving page", rect.x + 2, rect.y + 2)
2562#         dc.SetFont(wx.NullFont)
2563#         dc.SetBrush(wx.NullBrush)
2564#         dc.SetPen(wx.NullPen)
2565
2566        # self.statusBar.Refresh()
2567
2568
2569
2570    def OnIconize(self, evt):
2571        if self.configuration.getboolean("main", "showontray"):
2572            self.Show(not self.IsIconized())
2573
2574        evt.Skip()
2575
2576
2577    def OnMaximize(self, evt):
2578        evt.Skip()
2579
2580
2581    # TODO Reset preview and other possible details
2582    def resetGui(self):
2583        # delete everything in the current tree
2584        self.tree.DeleteAllItems()
2585       
2586        viewsTree = self.windowLayouter.getWindowForName("viewstree")
2587        if viewsTree is not None:
2588            viewsTree.DeleteAllItems()
2589
2590       
2591        # reset the editor
2592        self.getActiveEditor().loadWikiPage(None)
2593        self.getActiveEditor().SetSelection(-1, -1)
2594        self.getActiveEditor().EmptyUndoBuffer()
2595        self.getActiveEditor().Disable()
2596
2597        # reset tray
2598        self.setShowOnTray()
2599
2600
2601    def _getRelativeWikiPath(self, path):
2602        """
2603        Converts the absolute path to a relative path if possible. Otherwise
2604        the unmodified path is returned.
2605        """
2606        relPath = relativeFilePath(self.wikiAppDir, path)
2607       
2608        if relPath is None:
2609            return path
2610        else:
2611            return relPath
2612
2613
2614    def _getStorableWikiPath(self, path):
2615        """
2616        Converts the absolute path to a relative path if possible and if option
2617        is set to do this. Otherwise the unmodified path is returned.
2618        """
2619        if not self.getConfig().getboolean("main", "wikiPathes_relative", False):
2620            return path
2621
2622        return self._getRelativeWikiPath(path)
2623
2624
2625    def newWiki(self, wikiName, wikiDir):
2626        "creates a new wiki"
2627        if len(DbBackendUtils.listHandlers()) == 0:
2628            self.displayErrorMessage(
2629                    _(u'No data handler available to create database.'))
2630            return
2631
2632        wikiName = string.replace(wikiName, u" ", u"")
2633        wikiDir = join(wikiDir, wikiName)
2634        configFileLoc = join(wikiDir, u"%s.wiki" % wikiName)
2635
2636#         self.statusBar.SetStatusText(uniToGui(u"Creating Wiki: %s" % wikiName), 0)
2637
2638        createIt = True;
2639        if (exists(pathEnc(wikiDir))):
2640            dlg=wx.MessageDialog(self,
2641                    uniToGui(_(u"A wiki already exists in '%s', overwrite? "
2642                    u"(This deletes everything in and below this directory!)") %
2643                    wikiDir), _(u'Warning'), wx.YES_NO)
2644            result = dlg.ShowModal()
2645            dlg.Destroy()
2646            if result == wx.ID_YES:
2647                os.rmdir(wikiDir)  # TODO bug
2648                createIt = True
2649            elif result == wx.ID_NO:
2650                createIt = False
2651
2652        if createIt:
2653#             # Ask for the data handler to use
2654#             index = wx.GetSingleChoiceIndex(_(u"Choose database type"),
2655#                     _(u"Choose database type"), [wdh[1] for wdh in wdhandlers],
2656#                     self)
2657#             if index == -1:
2658#                 return
2659#
2660#             wdhName = wdhandlers[index][0]
2661
2662            wdhName, wlangName = AdditionalDialogs.NewWikiSettings.runModal(
2663                    self, -1, self)
2664                   
2665            if wdhName is None:
2666                return
2667
2668
2669            # create the new dir for the wiki
2670            os.mkdir(wikiDir)
2671
2672            allIsWell = True
2673
2674            dataDir = join(wikiDir, "data")
2675            dataDir = mbcsDec(abspath(dataDir), "replace")[0]
2676
2677            # create the data directory for the data files
2678            try:
2679                WikiDataManager.createWikiDb(self, wdhName, wikiName, dataDir,
2680                        False)
2681  #               createWikiDbFunc(wikiName, dataDir, False)
2682            except WikiDBExistsException:
2683                # The DB exists, should it be overwritten
2684                dlg=wx.MessageDialog(self, _(u'A wiki database already exists '
2685                        u'in this location, overwrite?'),
2686                        _(u'Wiki DB Exists'), wx.YES_NO)
2687                result = dlg.ShowModal()
2688                if result == wx.ID_YES:
2689  #                   createWikiDbFunc(wikiName, dataDir, True)
2690                    WikiDataManager.createWikiDb(self, wdhName, wikiName, dataDir,
2691                        True)
2692                else:
2693                    allIsWell = False
2694
2695                dlg.Destroy()
2696            except Exception, e:
2697                self.displayErrorMessage(
2698                        _(u'There was an error creating the wiki database.'), e)
2699                traceback.print_exc()               
2700                allIsWell = False
2701           
2702            if (allIsWell):
2703                try:
2704                    self.hooks.newWiki(self, wikiName, wikiDir)
2705   
2706                    # everything is ok, write out the config file
2707                    # create a new config file for the new wiki
2708                    wikiConfig = wx.GetApp().createWikiConfiguration()
2709    #                 
2710                    wikiConfig.createEmptyConfig(configFileLoc)
2711                    wikiConfig.fillWithDefaults()
2712                   
2713                    wikiConfig.set("main", "wiki_name", wikiName)
2714                    wikiConfig.set("main", "last_wiki_word", wikiName)
2715                    wikiConfig.set("main", "wiki_database_type", wdhName)
2716                    wikiConfig.set("main", "wiki_wikiLanguage", wlangName)
2717                    wikiConfig.set("wiki_db", "data_dir", "data")
2718                    wikiConfig.save()
2719
2720                    self.closeWiki()
2721                   
2722                    # open the new wiki
2723                    self.openWiki(configFileLoc)
2724                    p = self.wikiDataManager.createWikiPage(u"WikiSettings")
2725
2726                    langHelper = wx.GetApp().createWikiLanguageHelper(
2727                            self.getWikiDefaultWikiLanguage())
2728
2729                    text = langHelper.getNewDefaultWikiSettingsPage(self)
2730#                     p.save(text, False)
2731#                     p.update(text, False)
2732                    p.replaceLiveText(text, False)
2733   
2734                    p = self.wikiDataManager.createWikiPage(u"ScratchPad")
2735                    text = u"++ Scratch Pad\n\n"
2736#                     p.save(text, False)
2737#                     p.update(text, False)
2738                    p.replaceLiveText(text, False)
2739
2740                    self.getActiveEditor().GotoPos(self.getActiveEditor().GetLength())
2741                    self.getActiveEditor().AddText(u"\n\n\t* WikiSettings\n")
2742                    self.saveAllDocPages()
2743                   
2744                    # trigger hook
2745                    self.hooks.createdWiki(self, wikiName, wikiDir)
2746   
2747                    # reopen the root
2748                    self.openWikiPage(self.wikiName, False, False)
2749
2750                except (IOError, OSError, DbAccessError), e:
2751                    self.lostAccess(e)
2752                    raise
2753
2754
2755    def _askForDbType(self):
2756        """
2757        Show dialog to ask for the wiki data handler (= database type)
2758        for opening a wiki
2759        """
2760        wdhandlers = DbBackendUtils.listHandlers()
2761        if len(wdhandlers) == 0:
2762            self.displayErrorMessage(
2763                    'No data handler available to open database.')
2764            return None
2765
2766        # Ask for the data handler to use
2767        index = wx.GetSingleChoiceIndex(_(u"Choose database type"),
2768                _(u"Choose database type"), [wdh[1] for wdh in wdhandlers],
2769                self)
2770        if index == -1:
2771            return None
2772           
2773        return wdhandlers[index][0]
2774
2775
2776
2777    def openWiki(self, wikiCombinedFilename, wikiWordsToOpen=None,
2778            ignoreWdhName=False, anchorToOpen=None):
2779        """
2780        opens up a wiki
2781        ignoreWdhName -- Should the name of the wiki data handler in the
2782                wiki config file (if any) be ignored?
2783        """
2784
2785        # Fix special case
2786        if wikiWordsToOpen == (None,):
2787            wikiWordsToOpen = None
2788
2789        # Save the state of the currently open wiki, if there was one open
2790        # if the new config is the same as the old, don't resave state since
2791        # this could be a wiki overwrite from newWiki. We don't want to overwrite
2792        # the new config with the old one.
2793
2794        wikiCombinedFilename = abspath(join(self.wikiAppDir, wikiCombinedFilename))
2795
2796        # make sure the config exists
2797        cfgPath, splittedWikiWord = WikiDataManager.splitConfigPathAndWord(
2798                wikiCombinedFilename)
2799
2800        if cfgPath is None:
2801            self.displayErrorMessage(_(u"Invalid path or missing file '%s'")
2802                        % wikiCombinedFilename)
2803
2804            # Try to remove combined filename from recent files if existing
2805           
2806            self.removeFromWikiHistory(wikiCombinedFilename)
2807#             try:
2808#                 self.wikiHistory.remove(
2809#                         self._getRelativeWikiPath(wikiCombinedFilename))
2810#                 self.informRecentWikisChanged()
2811#             except ValueError:
2812#                 pass
2813
2814
2815            return False
2816
2817#        if self.wikiConfigFilename != wikiConfigFilename:
2818        self.closeWiki()
2819       
2820        # Remove path from recent file list if present (we will add it again
2821        # on top if everything went fine).
2822       
2823        self.removeFromWikiHistory(cfgPath)
2824
2825        # trigger hooks
2826        self.hooks.openWiki(self, wikiCombinedFilename)
2827
2828        if ignoreWdhName:
2829            # Explicitly ask for wiki data handler
2830            dbtype = self._askForDbType()
2831            if dbtype is None:
2832                return
2833        else:
2834            # Try to get handler name from wiki config file
2835            dbtype = None
2836       
2837        wikiLang = None
2838       
2839        ignoreLock = self.getConfig().getboolean("main", "wikiLockFile_ignore",
2840                False)
2841        createLock = self.getConfig().getboolean("main", "wikiLockFile_create",
2842                True)
2843
2844        while True:
2845            try:
2846                wikiDataManager = WikiDataManager.openWikiDocument(
2847                        cfgPath, dbtype, wikiLang, ignoreLock, createLock)
2848                frmcode, frmtext = wikiDataManager.checkDatabaseFormat()
2849                if frmcode == 2:
2850                    # Unreadable db format
2851                    self.displayErrorMessage(
2852                            _(u"Error connecting to database in '%s'")
2853                            % cfgPath, frmtext)
2854                    return False
2855                elif frmcode == 1:
2856                    # Update needed -> ask
2857                    answer = wx.MessageBox(_(u"The wiki needs an update to work "
2858                            u"with this version of WikidPad. Older versions of "
2859                            u"WikidPad may be unable to read the wiki after "
2860                            u"an update."), _(u'Update database?'),
2861                            wx.OK | wx.CANCEL | wx.ICON_QUESTION, self)
2862                    if answer == wx.CANCEL:
2863                        return False
2864
2865                wikiDataManager.connect()
2866                break
2867            except (UnknownDbHandlerException, DbHandlerNotAvailableException), e:
2868                # Could not get a handler name from wiki config file
2869                # (probably old database) or required handler not available,
2870                # so ask user
2871                self.displayErrorMessage(unicode(e))
2872                dbtype, dummy = AdditionalDialogs.NewWikiSettings.runModal(
2873                        self, -1, self, dbtype,
2874                        AdditionalDialogs.NewWikiSettings.DEFAULT_GREY)
2875#                 dbtype = self._askForDbType()
2876                if dbtype is None:
2877                    return False
2878
2879                continue # Try again
2880            except UnknownWikiLanguageException, e:
2881                # Could not get a handler name from wiki config file
2882                # (probably old database) or required handler not available,
2883                # so ask user
2884                self.displayErrorMessage(unicode(e))
2885                dummy, wikiLang = AdditionalDialogs.NewWikiSettings.runModal(
2886                        self, -1, self,
2887                        AdditionalDialogs.NewWikiSettings.DEFAULT_GREY, wikiLang)
2888#                 dbtype = self._askForDbType()
2889                if wikiLang is None:
2890                    return False
2891
2892                continue # Try again
2893            except LockedWikiException, e:
2894                # Database already in use by different instance
2895                answer = wx.MessageBox(_(u"Wiki '%s' is probably in use by different\n"
2896                        u"instance of WikidPad. Connect anyway (dangerous!)?") % cfgPath,
2897                        _(u"Wiki already in use"), wx.YES_NO, self)
2898                if answer == wx.NO:
2899                    return False
2900                else:
2901                    ignoreLock = True
2902                    continue # Try again
2903
2904            except (BadConfigurationFileException,
2905                    MissingConfigurationFileException), e:
2906                self.displayErrorMessage(_(u"Configuration file '%s' is corrupted or "
2907                        u"missing.\nYou may have to change some settings in configuration "
2908                        u'page "Current Wiki" and below which were lost.') % cfgPath)
2909                wdhName = self._askForDbType()
2910                if wdhName is None:
2911                    return False
2912
2913                wikiName = basename(cfgPath)[:-5] # Remove ".wiki"
2914
2915                wikiConfig = wx.GetApp().createWikiConfiguration()
2916
2917                wikiConfig.createEmptyConfig(cfgPath)
2918                wikiConfig.fillWithDefaults()
2919
2920                wikiConfig.set("main", "wiki_name", wikiName)
2921                wikiConfig.set("main", "last_wiki_word", wikiName)
2922                wikiConfig.set("main", "wiki_database_type", wdhName)
2923                wikiConfig.set("wiki_db", "data_dir", "data")
2924                wikiConfig.save()
2925               
2926                continue # Try again
2927
2928            except (IOError, OSError, DbReadAccessError,
2929                    BadConfigurationFileException,
2930                    MissingConfigurationFileException), e:
2931                # Something else went wrong
2932                self.displayErrorMessage(_(u"Error connecting to database in '%s'")
2933                        % cfgPath, e)
2934                if not isinstance(e, DbReadAccessError):
2935                    traceback.print_exc()
2936#                 self.lostAccess(e)
2937                return False
2938            except DbWriteAccessError, e:
2939                self.displayErrorMessage(_(u"Can't write to database '%s'")
2940                        % cfgPath, e)
2941                break   # ???
2942
2943        # OK, things look good
2944
2945        # set the member variables.
2946
2947        self.wikiDataManager = wikiDataManager
2948        self.currentWikiDocumentProxyEvent.setWatchedEvent(
2949                self.wikiDataManager.getMiscEvent())
2950
2951#         self.wikiDataManager.getMiscEvent().addListener(self)
2952        self.wikiData = wikiDataManager.getWikiData()
2953
2954        self.wikiName = self.wikiDataManager.getWikiName()
2955        self.dataDir = self.wikiDataManager.getDataDir()
2956       
2957        self.getConfig().setWikiConfig(self.wikiDataManager.getWikiConfig())
2958       
2959        try:
2960            furtherWikiWords = []
2961
2962            lastWikiWords = wikiWordsToOpen
2963            if wikiWordsToOpen is None:
2964                if splittedWikiWord:
2965                    # Take wiki word from combinedFilename
2966                    wikiWordsToOpen = (splittedWikiWord,)
2967                else:
2968                    # Try to find first wiki word
2969                    firstWikiWord = self.getConfig().get("main",
2970                        "first_wiki_word", u"")
2971                    if firstWikiWord != u"":
2972                        wikiWordsToOpen = (firstWikiWord,)
2973                    else:
2974                        # Nothing worked so take the last open wiki words
2975                        lastWikiWord = self.getConfig().get("main",
2976                                "last_wiki_word", u"")
2977                        fwws = self.getConfig().get("main",
2978                                "further_wiki_words", u"")
2979                        if fwws != u"":
2980                            furtherWikiWords = [unescapeForIni(w) for w in
2981                                    fwws.split(u";")]
2982                        else:
2983                            furtherWikiWords = ()
2984                       
2985                        wikiWordsToOpen = (lastWikiWord,) + \
2986                                tuple(furtherWikiWords)
2987
2988
2989            # reset the gui
2990            self.buildMainMenu()
2991   
2992            # enable the top level menus
2993            if self.mainmenu:
2994                self.mainmenu.EnableTop(1, 1)
2995                self.mainmenu.EnableTop(2, 1)
2996                self.mainmenu.EnableTop(3, 1)
2997               
2998            self.fireMiscEventKeys(("opened wiki",))
2999           
3000            # open the home page    # TODO!
3001#             self.openWikiPage(self.wikiName)
3002
3003            self.tree.SetScrollPos(wx.VERTICAL, 0)
3004           
3005            lastRoot = self.getConfig().get("main", "tree_last_root_wiki_word",
3006                    None)
3007            if not (lastRoot and
3008                    self.getWikiDocument().isDefinedWikiLink(lastRoot)):
3009                lastRoot = self.wikiName
3010               
3011            self.tree.setRootByWord(lastRoot)
3012            self.tree.readExpandedNodesFromConfig()
3013            self.tree.expandRoot()
3014            self.getConfig().set("main", "tree_last_root_wiki_word", lastRoot)
3015
3016            viewsTree = self.windowLayouter.getWindowForName("viewstree")
3017            if viewsTree is not None:
3018                viewsTree.setViewsAsRoot()
3019                viewsTree.readExpandedNodesFromConfig()
3020                viewsTree.expandRoot()
3021
3022
3023            # Remove/Replace undefined wiki words
3024            wwo = []
3025            for word in wikiWordsToOpen:
3026                if self.getWikiDocument().isDefinedWikiLink(word):
3027                    wwo.append(word)
3028                    continue
3029
3030                wordsStartingWith = self.getWikiData().getWikiLinksStartingWith(
3031                        word, True)
3032                if len(wordsStartingWith) > 0:
3033                    word = wordsStartingWith[0]
3034                    wwo.append(word)
3035                    continue
3036
3037            wikiWordsToOpen = wwo
3038
3039            # now try and open the last wiki page as leftmost tab
3040            if len(wikiWordsToOpen) > 0 and wikiWordsToOpen[0] != self.wikiName:
3041                firstWikiWord = wikiWordsToOpen[0]
3042#                 # if the word is not a wiki word see if a word that starts with the word can be found
3043#                 if not self.getWikiDocument().isDefinedWikiWord(firstWikiWord):
3044#                     wordsStartingWith = self.getWikiData().getWikiWordsStartingWith(
3045#                             firstWikiWord, True)
3046#                     if wordsStartingWith:
3047#                         firstWikiWord = wordsStartingWith[0]
3048
3049                self.openWikiPage(firstWikiWord, anchor=anchorToOpen)
3050                self.findCurrentWordInTree()
3051            else:
3052                self.openWikiPage(self.wikiName)
3053
3054            # If present, open further words in tabs on the right
3055            for word in wikiWordsToOpen[1:]:
3056#                 if not self.getWikiDocument().isDefinedWikiWord(word):
3057#                     wordsStartingWith = self.getWikiData().getWikiWordsStartingWith(
3058#                             word, True)
3059#                     if wordsStartingWith:
3060#                         word = wordsStartingWith[0]
3061                self.activatePageByUnifiedName(u"wikipage/" + word,
3062                        tabMode=3)
3063
3064            self.tree.SetScrollPos(wx.HORIZONTAL, 0)
3065           
3066            # enable the editor control whether or not the wiki root was found
3067            for dpp in self.getMainAreaPanel().getPresenters():
3068                if isinstance(dpp, DocPagePresenter):
3069                    e = dpp.getSubControl("textedit")
3070                    e.Enable(True)
3071
3072            # update the last accessed wiki config var
3073            self.lastAccessedWiki(self.getWikiConfigPath())
3074
3075            # Rebuild text blocks menu
3076            self.rereadTextBlocks()
3077           
3078            self._refreshHotKeys()
3079           
3080            # reset tray
3081            self.setShowOnTray()
3082
3083            # trigger hook
3084            self.hooks.openedWiki(self, self.wikiName, wikiCombinedFilename)
3085   
3086            # return that the wiki was opened successfully
3087            return True
3088        except (IOError, OSError, DbAccessError), e:
3089            self.lostAccess(e)
3090            return False
3091
3092
3093    def setCurrentWordAsRoot(self):
3094        """
3095        Set current wiki word as root of the tree
3096        """
3097        self.setWikiWordAsRoot(self.getCurrentWikiWord())
3098
3099
3100    def setHomeWordAsRoot(self):
3101        self.setWikiWordAsRoot(self.getWikiDocument().getWikiName())
3102
3103
3104    def setWikiWordAsRoot(self, word):
3105        if not self.requireReadAccess():
3106            return
3107        try:
3108            if word is not None and \
3109                    self.getWikiDocument().isDefinedWikiLink(word):
3110                self.tree.setRootByWord(word)
3111                self.tree.expandRoot()
3112                self.getConfig().set("main", "tree_last_root_wiki_word", word)
3113
3114        except (IOError, OSError, DbAccessError), e:
3115            self.lostAccess(e)
3116            raise
3117
3118
3119    def closeWiki(self, saveState=True):
3120
3121        def errCloseAnywayMsg():
3122            return wx.MessageBox(_(u"There is no (write-)access to underlying wiki\n"
3123                    "Close anyway and loose possible changes?"),
3124                    _(u'Close anyway'),
3125                    wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION, self)
3126
3127
3128        if self.getWikiConfigPath():
3129            wd = self.getWikiDocument()
3130            # Do not require access here, otherwise the user will not be able to
3131            # close a disconnected wiki
3132            if not wd.getReadAccessFailed() and not wd.getWriteAccessFailed():
3133                try:
3134                    self.fireMiscEventKeys(("closing current wiki",))
3135
3136                    if self.getWikiData() and saveState:
3137                        self.saveCurrentWikiState()
3138                except (IOError, OSError, DbAccessError), e:
3139                    self.lostAccess(e)
3140                    if errCloseAnywayMsg() == wx.NO:
3141                        raise
3142                    else:
3143                        traceback.print_exc()
3144                        self.fireMiscEventKeys(("dropping current wiki",))
3145
3146                if self.continuousExporter is not None:
3147                    self.continuousExporter.stopContinuousExport()
3148                    self.continuousExporter = None
3149
3150                try:
3151
3152                    self.lastAccessedWiki(self.getWikiConfigPath())
3153                    if self.getWikiData():
3154                        wd.release()
3155                except (IOError, OSError, DbAccessError), e:
3156                    pass               
3157                self.wikiData = None
3158                if self.wikiDataManager is not None:
3159                    self.currentWikiDocumentProxyEvent.setWatchedEvent(None)
3160                self.wikiDataManager = None
3161            else:
3162                # We had already a problem, so ask what to do
3163                if errCloseAnywayMsg() == wx.NO:
3164                    raise LossyWikiCloseDeniedException
3165               
3166                self.fireMiscEventKeys(("dropping current wiki",))
3167
3168                self.wikiData = None
3169                if self.wikiDataManager is not None:
3170                    self.currentWikiDocumentProxyEvent.setWatchedEvent(None)
3171                self.wikiDataManager = None
3172               
3173            self._refreshHotKeys()
3174
3175            self.getConfig().setWikiConfig(None)
3176            if self.clipboardInterceptor is not None:
3177                self.clipboardInterceptor.catchOff()
3178
3179            self.fireMiscEventKeys(("closed current wiki",))
3180            self.resetGui()
3181
3182
3183    def saveCurrentWikiState(self):
3184        try:
3185            # write out the current config
3186            self.writeCurrentConfig()
3187   
3188            # save the current wiki page if it is dirty
3189            if self.isWikiLoaded():
3190                self.saveAllDocPages()
3191   
3192            # database commits
3193            if self.getWikiData():
3194                self.getWikiData().commit()
3195        except (IOError, OSError, DbAccessError), e:
3196            self.lostAccess(e)
3197            raise
3198
3199
3200    def requireReadAccess(self):
3201        """
3202        Check flag in WikiDocument if database is readable. If not, take
3203        measures to re-establish it. If read access is probably possible,
3204        return True
3205        """
3206        wd = self.getWikiDocument()
3207        if wd is None:
3208            wx.MessageBox(_(u"This operation requires an open database"),
3209                    _(u'No open database'), wx.OK, self)
3210            return False
3211
3212        if not wd.getReadAccessFailed():
3213            return True
3214
3215        while True:
3216            wd = self.getWikiDocument()
3217            if wd is None:
3218                return False
3219
3220            self.SetFocus()
3221            result = wx.MessageBox(_(u"No connection to database. "
3222                    u"Try to reconnect?"), _(u'Reconnect database?'),
3223                    wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, self)
3224
3225            if result == wx.NO:
3226                return False
3227
3228            self.statusBar.PushStatusText(
3229                    _(u"Trying to reconnect database..."), 0)
3230            try:
3231                try:
3232                    wd.reconnect()
3233                    wd.setNoAutoSaveFlag(False)
3234                    wd.setReadAccessFailed(False)
3235                    self.requireWriteAccess()  # Just to test it  # TODO ?
3236                    return True  # Success
3237                except DbReadAccessError, e:
3238                    sys.stderr.write(_(u"Error while trying to reconnect:\n"))
3239                    traceback.print_exc()
3240                    self.SetFocus()
3241                    self.displayErrorMessage(_(u'Error while reconnecting '
3242                            'database'), e)
3243            finally:
3244                self.statusBar.PopStatusText(0)
3245
3246
3247    def requireWriteAccess(self):
3248        """
3249        Check flag in WikiDocument if database is writable. If not, take
3250        measures to re-establish it. If write access is probably possible,
3251        return True
3252        """
3253        if not self.requireReadAccess():
3254            return False
3255       
3256        if not self.getWikiDocument().getWriteAccessFailed():
3257            return True
3258
3259        while True:
3260            wd = self.getWikiDocument()
3261            if wd is None:
3262                return False
3263
3264            self.SetFocus()
3265            result = wx.MessageBox(
3266                    _(u"This operation needs write access to database\n"
3267                    u"Try to write?"), _(u'Try writing?'),
3268                    wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, self)
3269
3270            if result == wx.NO:
3271                return False
3272
3273            self.statusBar.PushStatusText(
3274                    _(u"Trying to write to database..."), 0)
3275            try:
3276                try:
3277                    # write out the current configuration
3278                    self.writeCurrentConfig()
3279                    self.getWikiData().testWrite()
3280
3281                    wd.setNoAutoSaveFlag(False)
3282                    wd.setWriteAccessFailed(False)
3283                    return True  # Success
3284                except (IOError, OSError, DbWriteAccessError), e:
3285                    sys.stderr.write(_(u"Error while trying to write:\n"))
3286                    traceback.print_exc()
3287                    self.SetFocus()
3288                    self.displayErrorMessage(_(u'Error while writing to '
3289                            'database'), e)
3290            finally:
3291                self.statusBar.PopStatusText(0)
3292
3293
3294    def lostAccess(self, exc):
3295        if isinstance(exc, DbReadAccessError):
3296            self.lostReadAccess(exc)
3297        elif isinstance(exc, DbWriteAccessError):
3298            self.lostWriteAccess(exc)
3299        else:
3300            self.lostReadAccess(exc)
3301
3302
3303    def lostReadAccess(self, exc):
3304        """
3305        Called if read access was lost during an operation
3306        """
3307        if self.getWikiDocument().getReadAccessFailed():
3308            # Was already handled -> ignore
3309            return
3310           
3311        self.SetFocus()
3312        wx.MessageBox(_(u"Database connection error: %s.\n"
3313                u"Try to re-establish, then run \"Wiki\"->\"Reconnect\"") % unicode(exc),
3314                _(u'Connection lost'), wx.OK, self)
3315
3316#         wd.setWriteAccessFailed(True) ?
3317        self.getWikiDocument().setReadAccessFailed(True)
3318
3319
3320    def lostWriteAccess(self, exc):
3321        """
3322        Called if read access was lost during an operation
3323        """
3324        if self.getWikiDocument().getWriteAccessFailed():
3325            # Was already handled -> ignore
3326            return
3327
3328        self.SetFocus()
3329        wx.MessageBox(_(u"No write access to database: %s.\n"
3330                u" Try to re-establish, then run \"Wiki\"->\"Reconnect\"") % unicode(exc),
3331                _(u'Connection lost'), wx.OK, self)
3332
3333        self.getWikiDocument().setWriteAccessFailed(True)
3334
3335
3336    def tryAutoReconnect(self):   # TODO ???
3337        """
3338        Try reconnect after an error, if not already tried automatically
3339        """
3340        wd = self.getWikiDocument()
3341        if wd is None:
3342            return False
3343
3344        if wd.getAutoReconnectTriedFlag():
3345            # Automatic reconnect was tried already, so don't try again
3346            return False
3347
3348        self.statusBar.PushStatusText(_(u"Trying to reconnect ..."), 0)
3349
3350        try:
3351            try:
3352                wd.setNoAutoSaveFlag(True)
3353                wd.reconnect()
3354                wd.setNoAutoSaveFlag(False)
3355                return True
3356            except:
3357                sys.stderr.write(_(u"Error while trying to reconnect:") + u"\n")
3358                traceback.print_exc()
3359        finally:
3360            self.statusBar.PopStatusText(0)
3361
3362        return False
3363
3364
3365    def openFuncPage(self, funcTag, **evtprops):
3366        dpp = self.getCurrentDocPagePresenter()
3367        if dpp is None:
3368            dpp = self.createNewDocPagePresenterTab()
3369
3370        dpp.openFuncPage(funcTag, **evtprops)
3371
3372
3373    def openWikiPage(self, wikiWord, addToHistory=True,
3374            forceTreeSyncFromRoot=False, forceReopen=False, **evtprops):
3375        ## _prof.start()
3376        dpp = self.getCurrentDocPagePresenter()
3377        if dpp is None:
3378            dpp = self.createNewDocPagePresenterTab()
3379
3380        dpp.openWikiPage(wikiWord, addToHistory, forceTreeSyncFromRoot,
3381                forceReopen, **evtprops)
3382
3383        self.getMainAreaPanel().showPresenter(dpp)
3384        ## _prof.stop()
3385
3386
3387    def saveCurrentDocPage(self, force=False):
3388        dpp = self.getCurrentDocPagePresenter()
3389        if dpp is None:
3390            return
3391           
3392        dpp.saveCurrentDocPage(force)
3393
3394
3395    def activatePageByUnifiedName(self, unifName, tabMode=0):
3396        """
3397        tabMode -- 0:Same tab; 2: new tab in foreground; 3: new tab in background
3398        """
3399        # open the wiki page
3400        if tabMode & 2:
3401            # New tab
3402            presenter = self.createNewDocPagePresenterTab()
3403        else:
3404            # Same tab
3405            presenter = self.getCurrentDocPagePresenter()
3406            if presenter is None:
3407                presenter = self.createNewDocPagePresenterTab()
3408
3409        presenter.openDocPage(unifName, motionType="child")
3410
3411        if not tabMode & 1:
3412            # Show in foreground
3413            self.getMainAreaPanel().showPresenter(presenter)
3414
3415        return presenter
3416
3417
3418    def saveAllDocPages(self, force = False, async=False):
3419        if not self.requireWriteAccess():
3420            return
3421
3422        try:
3423            self.fireMiscEventProps({"saving all pages": None, "force": force})
3424            self.refreshPageStatus()
3425        except (IOError, OSError, DbAccessError), e:
3426            self.lostAccess(e)
3427            raise
3428
3429
3430    def saveDocPage(self, page, text=None):
3431        """
3432        Save page unconditionally
3433        """
3434        if page is None:
3435            return False
3436
3437        if page.isReadOnlyEffect():
3438            return True   # return False?
3439
3440        if not self.requireWriteAccess():
3441            return
3442
3443        self.statusBar.PushStatusText(u"Saving page", 0)
3444        try:
3445            # Test if editor is active
3446            if page.getTxtEditor() is None:
3447                # No editor -> nothing to do
3448                return False
3449
3450            text = page.getLiveText()
3451
3452            word = page.getWikiWord()
3453            if word is not None:
3454                # trigger hooks
3455                self.hooks.savingWikiWord(self, word)
3456
3457            while True:
3458                try:
3459                    if word is not None:
3460                        # only for real wiki pages
3461                        # TODO Enable support for AGAs again
3462#                         page.save(self.getActiveEditor().cleanAutoGenAreas(text))
3463#                         page.update(self.getActiveEditor().updateAutoGenAreas(text))   # ?
3464                        page.writeToDatabase()
3465                        self.propertyChecker.initiateCheckPage(page)
3466
3467
3468
3469                        # trigger hooks
3470                        self.hooks.savedWikiWord(self, word)
3471                    else:
3472                        page.writeToDatabase()
3473
3474                    self.getWikiData().commit()
3475                    return True
3476                except (IOError, OSError, DbAccessError), e:
3477                    self.lostAccess(e)
3478                    raise
3479        finally:
3480            self.statusBar.PopStatusText(0)
3481
3482
3483    def deleteWikiWord(self, wikiWord):
3484        if wikiWord and self.requireWriteAccess():
3485            try:
3486                if self.getWikiDocument().isDefinedWikiLink(wikiWord):
3487                    page = self.getWikiDocument().getWikiPage(wikiWord)
3488                    page.deletePage()
3489            except (IOError, OSError, DbAccessError), e:
3490                self.lostAccess(e)
3491                raise
3492
3493
3494    def renameWikiWord(self, wikiWord, toWikiWord, modifyText, **evtprops):
3495        """
3496        Renames current wiki word to toWikiWord.
3497        Returns True if renaming was done successful.
3498       
3499        modifyText -- Should the text of links to the renamed page be
3500                modified? (This text replacement works unreliably)
3501        """
3502        if wikiWord is None or not self.requireWriteAccess():
3503            return False
3504
3505        try:
3506            self.saveAllDocPages()
3507
3508            if wikiWord == self.getWikiDocument().getWikiName():
3509                # Renaming of root word = renaming of wiki config file
3510                wikiConfigFilename = self.getWikiDocument().getWikiConfigPath()
3511                self.removeFromWikiHistory(wikiConfigFilename)
3512#                 self.wikiHistory.remove(wikiConfigFilename)
3513                self.getWikiDocument().renameWikiWord(wikiWord, toWikiWord,
3514                        modifyText)
3515                # Store some additional information
3516                self.lastAccessedWiki(
3517                        self.getWikiDocument().getWikiConfigPath())
3518            else:
3519                self.getWikiDocument().renameWikiWord(wikiWord, toWikiWord,
3520                        modifyText)
3521
3522            return True
3523        except (IOError, OSError, DbAccessError), e:
3524            self.lostAccess(e)
3525            raise
3526        except WikiDataException, e:
3527            traceback.print_exc()               
3528            self.displayErrorMessage(unicode(e))
3529            return False
3530
3531
3532    def findCurrentWordInTree(self):
3533        try:
3534            self.tree.buildTreeForWord(self.getCurrentWikiWord(), selectNode=True)
3535        except Exception, e:
3536            traceback.print_exc()
3537
3538
3539    def makeRelUrlAbsolute(self, relurl):
3540        """
3541        Return the absolute path for a rel: URL
3542        """
3543#         relpath = urllib.url2pathname(relurl[6:])
3544        relpath = pathnameFromUrl(relurl[6:], False)
3545
3546        url = "file:" + urlFromPathname(
3547                abspath(join(dirname(self.getWikiConfigPath()), relpath)))
3548
3549        return url
3550
3551
3552    def launchUrl(self, link):
3553#         link2 = flexibleUrlUnquote(link)
3554        if self.configuration.getint(
3555                "main", "new_window_on_follow_wiki_url") == 1 or \
3556                not link.startswith(u"wiki:"):
3557
3558            if link.startswith(u"rel://"):
3559                # This is a relative link
3560                link = self.makeRelUrlAbsolute(link)
3561
3562            try:
3563                OsAbstract.startFile(self, link)
3564            except Exception, e:
3565                traceback.print_exc()
3566                self.displayErrorMessage(_(u"Couldn't start file"), e)
3567                return False
3568
3569            return True
3570        elif self.configuration.getint(
3571                "main", "new_window_on_follow_wiki_url") != 1:
3572
3573            filePath, wikiWordToOpen, anchorToOpen = wikiUrlToPathWordAndAnchor(
3574                    link)
3575            if exists(filePath):
3576                self.openWiki(filePath, wikiWordsToOpen=(wikiWordToOpen,),
3577                        anchorToOpen=anchorToOpen)  # ?
3578                return True
3579            else:
3580                self.statusBar.SetStatusText(
3581                        uniToGui(_(u"Couldn't open wiki: %s") % link), 0)
3582                return False
3583        return False
3584
3585
3586
3587    def refreshPageStatus(self, docPage = None):
3588        """
3589        Read information from page and present it in the field 1 of the
3590        status bar and in the title bar.
3591        """
3592        fmt = mbcsEnc(self.getConfig().get("main", "pagestatus_timeformat"),
3593                "replace")[0]
3594
3595        if docPage is None:
3596            docPage = self.getCurrentDocPage()
3597
3598        if docPage is None or not isinstance(docPage,
3599                (DocPages.WikiPage, DocPages.AliasWikiPage)):
3600            self.statusBar.SetStatusText(uniToGui(u""), 1)
3601            return
3602
3603        pageStatus = u""   # wikiWord
3604
3605        modTime, creaTime = docPage.getTimestamps()[:2]
3606        if modTime is not None:
3607#             pageStatus += _(u"Mod.: %s") % \
3608#                     mbcsDec(strftime(fmt, localtime(modTime)), "replace")[0]
3609#             pageStatus += _(u"; Crea.: %s") % \
3610#                     mbcsDec(strftime(fmt, localtime(creaTime)), "replace")[0]
3611            pageStatus += _(u"Mod.: %s") % strftimeUB(fmt, modTime)
3612            pageStatus += _(u"; Crea.: %s") % strftimeUB(fmt, creaTime)
3613
3614        self.statusBar.SetStatusText(uniToGui(pageStatus), 1)
3615
3616        self.SetTitle(uniToGui(u"%s: %s - %s - WikidPad" %
3617                (self.getWikiDocument().getWikiName(), docPage.getWikiWord(),
3618                self.getWikiConfigPath(), )))
3619
3620
3621    def viewWordSelection(self, title, words, motionType):
3622        """
3623        View a single choice to select a word to go to
3624        title -- Title of the dialog
3625        words -- Sequence of the words to choose from
3626        motionType -- motion type to set in openWikiPage if word was choosen
3627        """
3628        if not self.requireReadAccess():
3629            return
3630        try:
3631            dlg = ChooseWikiWordDialog(self, -1, words, motionType, title)
3632            dlg.CenterOnParent(wx.BOTH)
3633            dlg.ShowModal()
3634            dlg.Destroy()
3635        except (IOError, OSError, DbAccessError), e:
3636            self.lostAccess(e)
3637            raise
3638
3639
3640    def viewParents(self, ofWord):
3641        if not self.requireReadAccess():
3642            return
3643        try:
3644            parents = self.getWikiData().getParentRelationships(ofWord)
3645        except (IOError, OSError, DbAccessError), e:
3646            self.lostAccess(e)
3647            raise
3648        self.viewWordSelection(_(u"Parent nodes of '%s'") % ofWord, parents,
3649                "parent")
3650
3651
3652    def viewParentLess(self):
3653        if not self.requireReadAccess():
3654            return
3655        try:
3656            parentLess = self.getWikiData().getParentlessWikiWords()
3657        except (IOError, OSError, DbAccessError), e:
3658            self.lostAccess(e)
3659            raise
3660        self.viewWordSelection(_(u"Parentless nodes"), parentLess,
3661                "random")
3662
3663
3664    def viewChildren(self, ofWord):
3665        if not self.requireReadAccess():
3666            return
3667        try:
3668            children = self.getWikiData().getChildRelationships(ofWord)
3669        except (IOError, OSError, DbAccessError), e:
3670            self.lostAccess(e)
3671            raise
3672        self.viewWordSelection(_(u"Child nodes of '%s'") % ofWord, children,
3673                "child")
3674
3675
3676    def viewBookmarks(self):
3677        if not self.requireReadAccess():
3678            return
3679        try:
3680            bookmarked = [w for w,k,v in self.getWikiDocument()
3681                    .getPropertyTriples(None, "bookmarked", u"true")]
3682        except (IOError, OSError, DbAccessError), e:
3683            self.lostAccess(e)
3684            raise
3685        self.viewWordSelection(_(u"Bookmarks"), bookmarked,
3686                "random")
3687
3688
3689    def removeFromWikiHistory(self, path):
3690        """
3691        Remove path from wiki history (if present) and sends an event.
3692        """
3693        try:
3694            self.wikiHistory.remove(self._getRelativeWikiPath(path))
3695            self.informRecentWikisChanged()
3696        except ValueError:
3697            pass
3698
3699        # Try absolute
3700        try:
3701            self.wikiHistory.remove(path)
3702            self.informRecentWikisChanged()
3703        except ValueError:
3704            pass
3705
3706
3707    def lastAccessedWiki(self, wikiConfigFilename):
3708        """
3709        Writes to the global config the location of the last accessed wiki
3710        and updates file history.
3711        """
3712        wikiConfigFilename = self._getStorableWikiPath(wikiConfigFilename)
3713       
3714        if wikiConfigFilename == self.wikiPadHelp:
3715            return
3716       
3717        # create a new config file for the new wiki
3718        self.configuration.set("main", "last_wiki", wikiConfigFilename)
3719        if wikiConfigFilename not in self.wikiHistory:
3720            self.wikiHistory = [wikiConfigFilename] + self.wikiHistory
3721
3722            # only keep most recent items
3723            maxLen = self.configuration.getint(
3724                    "main", "recentWikisList_length", 5)
3725            if len(self.wikiHistory) > maxLen:
3726                self.wikiHistory = self.wikiHistory[:maxLen]
3727
3728            self.informRecentWikisChanged()
3729
3730        self.configuration.set("main", "last_active_dir", dirname(wikiConfigFilename))
3731        self.writeGlobalConfig()
3732
3733
3734    # Only needed for scripts
3735    def setAutoSave(self, onOrOff):
3736        self.autoSave = onOrOff
3737        self.configuration.set("main", "auto_save", self.autoSave)
3738
3739
3740    def setShowTreeControl(self, onOrOff):
3741        self.windowLayouter.expandWindow("maintree", onOrOff)
3742        if onOrOff:
3743            self.windowLayouter.focusWindow("maintree")
3744
3745
3746    def getShowToolbar(self):
3747        return not self.GetToolBar() is None
3748
3749    def setShowToolbar(self, onOrOff):
3750        """
3751        Control, if toolbar should be shown or not
3752        """
3753        self.getConfig().set("main", "toolbar_show", bool(onOrOff))
3754
3755        if bool(onOrOff) == self.getShowToolbar():
3756            # Desired state already reached
3757            return
3758
3759        if onOrOff:
3760            self.buildToolbar()
3761        else:
3762            self.fastSearchField = None   
3763            self.GetToolBar().Destroy()
3764            self.SetToolBar(None)
3765
3766
3767    def setShowDocStructure(self, onOrOff):
3768        self.windowLayouter.expandWindow("doc structure", onOrOff)
3769        if onOrOff:
3770            self.windowLayouter.focusWindow("doc structure")
3771
3772    def setShowTimeView(self, onOrOff):
3773        self.windowLayouter.expandWindow("time view", onOrOff)
3774        if onOrOff:
3775            self.windowLayouter.focusWindow("time view")
3776
3777
3778    def getStayOnTop(self):
3779        """
3780        Returns if this window is set to stay on top of all others
3781        """
3782        return bool(self.GetWindowStyleFlag() & wx.STAY_ON_TOP)
3783
3784    def setStayOnTop(self, onOrOff):
3785        style = self.GetWindowStyleFlag()
3786       
3787        if onOrOff:
3788            style |= wx.STAY_ON_TOP
3789        else:
3790            style &= ~wx.STAY_ON_TOP
3791
3792        self.SetWindowStyleFlag(style)
3793
3794
3795    def setShowOnTray(self, onOrOff=None):
3796        """
3797        Update UI and config according to the settings of onOrOff.
3798        If onOrOff is omitted, UI is updated according to current
3799        setting of the global config
3800        """
3801        if not onOrOff is None:
3802            self.configuration.set("main", "showontray", onOrOff)
3803        else:
3804            onOrOff = self.configuration.getboolean("main", "showontray")
3805
3806
3807        tooltip = None
3808        if self.getWikiConfigPath():  # If a wiki is open
3809            tooltip = _(u"Wiki: %s") % self.getWikiConfigPath()  # self.wikiName
3810            iconName = self.getConfig().get("main", "wiki_icon", u"")
3811        else:
3812            tooltip = u"Wikidpad"
3813            iconName = u""
3814
3815        bmp = None
3816        if iconName != u"":
3817            bmp = wx.GetApp().getIconCache().lookupIcon(iconName)
3818
3819
3820        if onOrOff:
3821            if self.tbIcon is None:
3822                self.tbIcon = TaskBarIcon(self)
3823
3824            if Configuration.isLinux():
3825                # On Linux, the tray icon must be resized here, otherwise
3826                # it might be too large.
3827                if bmp is not None:
3828                    img = bmp.ConvertToImage()
3829                else:
3830                    img = wx.Image(os.path.join(self.wikiAppDir, 'icons',
3831                            'pwiki.ico'), wx.BITMAP_TYPE_ICO)
3832
3833                img.Rescale(20, 20)
3834                bmp = wx.BitmapFromImage(img)
3835                icon = wx.IconFromBitmap(bmp)
3836                self.tbIcon.SetIcon(icon, uniToGui(tooltip))
3837            else:
3838                if bmp is not None:               
3839                    self.tbIcon.SetIcon(wx.IconFromBitmap(bmp),
3840                            uniToGui(tooltip))
3841                else:
3842                    self.tbIcon.SetIcon(wx.GetApp().standardIcon,
3843                            uniToGui(tooltip))
3844
3845        else:
3846            if self.tbIcon is not None:
3847                if self.tbIcon.IsIconInstalled():
3848                    self.tbIcon.RemoveIcon()
3849
3850                self.tbIcon.Destroy()
3851                self.tbIcon = None
3852
3853#         # TODO  Move to better function
3854#         if bmp is not None:               
3855#             self.SetIcon(wx.IconFromBitmap(bmp))
3856#         else:
3857#             print "setShowOnTray25", repr(os.path.join(self.wikiAppDir,
3858#                     'icons', 'pwiki.ico')), repr(wx.Icon(os.path.join(self.wikiAppDir,
3859#                     'icons', 'pwiki.ico'), wx.BITMAP_TYPE_ICO))
3860# #             self.SetIcon(wx.Icon(os.path.join(self.wikiAppDir,
3861# #                     'icons', 'pwiki.ico'), wx.BITMAP_TYPE_ICO))
3862#             self.SetIcon(wx.GetApp().standardIcon)
3863
3864
3865    def setHideUndefined(self, onOrOff=None):
3866        """
3867        Set if undefined WikiWords should be hidden in the tree
3868        """
3869
3870        if not onOrOff is None:
3871            self.configuration.set("main", "hideundefined", onOrOff)
3872        else:
3873            onOrOff = self.configuration.getboolean("main", "hideundefined")
3874
3875
3876#     _LAYOUT_WITHOUT_VIEWSTREE = "name:main area panel;"\
3877#         "layout relation:%s&layout relative to:main area panel&name:maintree&"\
3878#             "layout sash position:170&layout sash effective position:170;"\
3879#         "layout relation:below&layout relative to:main area panel&name:log&"\
3880#             "layout sash position:1&layout sash effective position:120"
3881#
3882#     _LAYOUT_WITH_VIEWSTREE = "name:main area panel;"\
3883#             "layout relation:%s&layout relative to:main area panel&name:maintree&"\
3884#                 "layout sash position:170&layout sash effective position:170;"\
3885#             "layout relation:%s&layout relative to:maintree&name:viewstree;"\
3886#             "layout relation:below&layout relative to:main area panel&name:log&"\
3887#                 "layout sash position:1&layout sash effective position:120"
3888
3889    def changeLayoutByCf(self, layoutCfStr):
3890        """
3891        Create a new window layouter according to the
3892        layout configuration string layoutCfStr. Try to reuse and reparent
3893        existing windows.
3894        BUG: Reparenting seems to disturb event handling for tree events and
3895            isn't available for all OS'
3896        """
3897#         # Reparent reusable windows so they aren't destroyed when
3898#         #   cleaning main window
3899#         # TODO Reparent not available for all OS'
3900#         cachedWindows = {}
3901# #         for n, w in self.windowLayouter.winNameToObject.iteritems():
3902#         for n, w in self.windowLayouter.winNameToProxy.iteritems():
3903#             print "--toCache", repr(n), repr(w)
3904#             cachedWindows[n] = w
3905# #             w.Reparent(None)
3906#             w.Reparent(self)
3907#
3908#         self.windowLayouter.cleanMainWindow(cachedWindows.values())
3909#
3910#         # make own creator function which provides already existing windows
3911#         def cachedCreateWindow(winProps, parent):
3912#             """
3913#             Wrapper around _actualCreateWindow to maintain a cache
3914#             of already existing windows
3915#             """
3916#             winName = winProps["name"]
3917#
3918#             # Try in cache:
3919#             window = cachedWindows.get(winName)
3920# #             print "--cachedCreateWindow", repr(winName), repr(window)
3921#             if window is not None:
3922#                 window.Reparent(parent)    # TODO Reparent not available for all OS'
3923#                 del cachedWindows[winName]
3924#                 return window
3925#
3926#             window = self.createWindow(winProps, parent)
3927#
3928#             return window
3929#         
3930#         self.windowLayouter = WindowSashLayouter(self, cachedCreateWindow)
3931#
3932#         # Destroy windows which weren't reused
3933#         # TODO Call close method of object window if present
3934#         for n, w in cachedWindows.iteritems():
3935#             w.Destroy()
3936#
3937#         self.windowLayouter.setWinPropsByConfig(layoutCfStr)
3938
3939        # Handle no size events while realizing layout
3940        self.Unbind(wx.EVT_SIZE)
3941
3942        self.windowLayouter.realizeNewLayoutByCf(layoutCfStr)
3943
3944#         self.windowLayouter.realize()
3945        self.windowLayouter.layout()
3946
3947        wx.EVT_SIZE(self, self.OnSize)
3948
3949        self.tree = self.windowLayouter.getWindowForName("maintree")
3950        self.logWindow = self.windowLayouter.getWindowForName("log")
3951
3952
3953#     def getClipboardCatcher(self):
3954#         return self.clipboardCatcher is not None and \
3955#                 self.clipboardCatcher.isActive()
3956
3957    def OnClipboardCatcherOff(self, evt):
3958        self.clipboardInterceptor.catchOff()
3959
3960    def OnClipboardCatcherAtPage(self, evt):
3961        if self.isReadOnlyPage():
3962            return
3963
3964        self.clipboardInterceptor.catchAtPage(self.getCurrentDocPage())
3965
3966    def OnClipboardCatcherAtCursor(self, evt):
3967        if self.isReadOnlyPage():
3968            return
3969
3970        self.clipboardInterceptor.catchAtCursor()
3971
3972
3973    def OnUpdateClipboardCatcher(self, evt):
3974        cc = self.clipboardInterceptor
3975        if cc is None:
3976            return  # Shouldn't be called anyway
3977           
3978        wikiDoc = self.getWikiDocument()
3979        enableCatcher = not self.isReadOnlyPage()
3980
3981        if evt.GetId() == GUI_ID.CMD_CLIPBOARD_CATCHER_OFF:
3982            evt.Check(cc.getMode() == cc.MODE_OFF)
3983        elif evt.GetId() == GUI_ID.CMD_CLIPBOARD_CATCHER_AT_CURSOR:
3984            evt.Enable(enableCatcher)
3985            evt.Check(cc.getMode() == cc.MODE_AT_CURSOR)
3986        elif evt.GetId() == GUI_ID.CMD_CLIPBOARD_CATCHER_AT_PAGE:
3987            evt.Enable(enableCatcher)
3988            if cc.getMode() == cc.MODE_AT_PAGE:
3989                evt.Check(True)
3990                evt.SetText(_(u"Set at Page: %s\t%s") %
3991                        (self.clipboardInterceptor.getWikiWord(),
3992                        self.keyBindings.CatchClipboardAtPage))
3993            else:
3994                evt.Check(False)
3995                evt.SetText(_(u'Set at Page') + u'\t' +
3996                        self.keyBindings.CatchClipboardAtPage)
3997
3998    def writeGlobalConfig(self):
3999        "writes out the global config file"
4000        try:
4001            self.configuration.save()
4002        except (IOError, OSError, DbAccessError), e:
4003            self.lostAccess(e)
4004            raise
4005        except Exception, e:
4006            self.displayErrorMessage(_(u"Error saving global configuration"), e)
4007
4008
4009    def writeCurrentConfig(self):
4010        "writes out the current config file"
4011        try:
4012            self.configuration.save()
4013        except (IOError, OSError, DbAccessError), e:
4014            self.lostAccess(e)
4015            raise
4016        except Exception, e:
4017            self.displayErrorMessage(_(u"Error saving current configuration"), e)
4018
4019
4020    def showWikiWordOpenDialog(self):
4021        OpenWikiWordDialog.runModal(self, self, -1)
4022#         dlg = OpenWikiWordDialog(self, -1)
4023#         try:
4024#             dlg.CenterOnParent(wx.BOTH)
4025#             dlg.ShowModal()
4026        self.getActiveEditor().SetFocus()
4027#         finally:
4028#             dlg.Destroy()
4029
4030
4031    def showWikiWordRenameDialog(self, wikiWord=None):
4032        if wikiWord is None:
4033            wikiWord = self.getCurrentWikiWord()
4034
4035        if wikiWord is not None:
4036            wikiWord = self.getWikiData().getUnAliasedWikiWord(wikiWord)
4037
4038        if wikiWord is None:
4039            self.displayErrorMessage(_(u"No real wiki word selected to rename"))
4040            return
4041       
4042        if self.isReadOnlyPage():
4043            return
4044
4045        dlg = wx.TextEntryDialog(self, uniToGui(_(u"Rename '%s' to:") %
4046                wikiWord), _(u"Rename Wiki Word"), wikiWord, wx.OK | wx.CANCEL)
4047
4048        try:
4049            while dlg.ShowModal() == wx.ID_OK and \
4050                    not self.showWikiWordRenameConfirmDialog(wikiWord,
4051                            guiToUni(dlg.GetValue())):
4052                pass
4053
4054        finally:
4055            dlg.Destroy()
4056
4057    # TODO Unicode
4058    def showStoreVersionDialog(self):
4059        dlg = wx.TextEntryDialog (self, _(u"Description:"),
4060                                 _(u"Store new version"), u"",
4061                                 wx.OK | wx.CANCEL)
4062
4063        description = None
4064        if dlg.ShowModal() == wx.ID_OK:
4065            description = dlg.GetValue()
4066        dlg.Destroy()
4067
4068        if not description is None:
4069            self.saveAllDocPages()
4070            self.getWikiData().storeVersion(description)
4071
4072
4073    def showDeleteAllVersionsDialog(self):
4074        result = wx.MessageBox(_(u"Do you want to delete all stored versions?"),
4075                _(u"Delete All Versions"),
4076                wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION, self)
4077
4078        if result == wx.YES:
4079            self.getWikiData().deleteVersioningData()
4080
4081
4082#     def showSavedVersionsDialog(self):
4083#         if not self.getWikiData().hasVersioningData():
4084#             dlg=wx.MessageDialog(self,
4085#                     _(u"This wiki does not contain any version information"),
4086#                     _(u'Retrieve version'), wx.OK)
4087#             dlg.ShowModal()
4088#             dlg.Destroy()
4089#             return
4090#
4091#         dlg = SavedVersionsDialog(self, -1)
4092#         dlg.CenterOnParent(wx.BOTH)
4093#
4094#         version = None
4095#         if dlg.ShowModal() == wx.ID_OK:
4096#             version = dlg.GetValue()
4097#         dlg.Destroy()
4098#
4099#         if version:
4100#             dlg=wx.MessageDialog(self,
4101#                     _(u"This will overwrite current content if not stored as "
4102#                     u"version. Continue?"),
4103#                     _(u'Retrieve version'), wx.YES_NO)
4104#             if dlg.ShowModal() == wx.ID_YES:
4105#                 dlg.Destroy()
4106#                 self.saveAllDocPages()
4107#                 word = self.getCurrentWikiWord()
4108#                 self.getWikiData().applyStoredVersion(version[0])
4109#                 self.rebuildWiki(skipConfirm=True)
4110#                 ## self.tree.collapse()
4111#                 self.openWikiPage(self.getCurrentWikiWord(), forceTreeSyncFromRoot=True, forceReopen=True)
4112#                 ## self.findCurrentWordInTree()
4113#             else:
4114#                 dlg.Destroy()
4115
4116
4117    # TODO Check if new name already exists (?)
4118    def showWikiWordRenameConfirmDialog(self, wikiWord, toWikiWord):
4119        """
4120        Checks if renaming operation is valid, presents either an error
4121        message or a confirmation dialog.
4122        Returns -- True iff renaming was done successfully
4123        """
4124#         wikiWord = self.getCurrentWikiWord()
4125
4126        if not toWikiWord or len(toWikiWord) == 0:
4127            return False
4128           
4129        langHelper = wx.GetApp().createWikiLanguageHelper(
4130                self.getWikiDefaultWikiLanguage())
4131               
4132        errMsg = langHelper.checkForInvalidWikiWord(toWikiWord,
4133                self.getWikiDocument())
4134
4135        if errMsg:
4136            self.displayErrorMessage(_(u"'%s' is an invalid wiki word. %s.") %
4137                    (toWikiWord, errMsg))
4138            return False
4139
4140        if wikiWord == toWikiWord:
4141            self.displayErrorMessage(_(u"Can't rename to itself"))
4142            return False
4143
4144        if wikiWord == "ScratchPad":
4145            self.displayErrorMessage(_(u"The scratch pad cannot be renamed."))
4146            return False
4147
4148        try:
4149            if not self.getWikiDocument().isCreatableWikiWord(toWikiWord):
4150                self.displayErrorMessage(
4151                        _(u"Cannot rename to '%s', word already exists") %
4152                        toWikiWord)
4153                return False
4154
4155            # Link rename mode from options
4156            lrm = self.getConfig().getint("main",
4157                    "wikiWord_rename_wikiLinks", 2)
4158            if lrm == 0:
4159                result = wx.NO
4160            elif lrm == 1:
4161                result = wx.YES
4162            else: # lrm == 2: ask for each rename operation
4163                result = wx.MessageBox(
4164                        _(u"Do you want to modify all links to the wiki word "
4165                        u"'%s' renamed to '%s' (this operation is unreliable)?") %
4166                        (wikiWord, toWikiWord),
4167                        _(u'Rename Wiki Word'),
4168                        wx.YES_NO | wx.CANCEL | wx.ICON_QUESTION, self)
4169
4170            if result == wx.YES or result == wx.NO:
4171                try:
4172                    self.renameWikiWord(wikiWord, toWikiWord, result == wx.YES)
4173                    return True
4174                except WikiDataException, e:
4175                    traceback.print_exc()               
4176                    self.displayErrorMessage(unicode(e))
4177   
4178            return False
4179        except (IOError, OSError, DbAccessError), e:
4180            self.lostAccess(e)
4181            raise
4182
4183
4184    def showSearchDialog(self):
4185        if self.mainWwSearchDlg != None:
4186            if isinstance(self.mainWwSearchDlg, SearchWikiDialog):
4187                self.mainWwSearchDlg.SetFocus()
4188            return
4189
4190        self.mainWwSearchDlg = SearchWikiDialog(self, self, -1,
4191                allowOkCancel=False, allowOrdering=False)
4192        self.mainWwSearchDlg.CenterOnParent(wx.BOTH)
4193        self.mainWwSearchDlg.Show()
4194
4195
4196    def showWikiWordDeleteDialog(self, wikiWord=None):
4197        if wikiWord is None:
4198            wikiWord = self.getCurrentWikiWord()
4199
4200        if wikiWord is not None:
4201            wikiWord = self.getWikiData().getUnAliasedWikiWord(wikiWord)
4202
4203        if wikiWord == u"ScratchPad":
4204            self.displayErrorMessage(_(u"The scratch pad cannot be deleted"))
4205            return
4206
4207        if wikiWord is None:
4208            self.displayErrorMessage(_(u"No real wiki word to delete"))
4209            return
4210           
4211        if self.isReadOnlyPage():
4212            return   # TODO Error message
4213
4214        dlg = wx.MessageDialog(self,
4215                uniToGui(_(u"Are you sure you want to delete wiki word '%s'?") % wikiWord),
4216                _(u'Delete Wiki Word'), wx.YES_NO | wx.NO_DEFAULT)
4217        result = dlg.ShowModal()
4218        if result == wx.ID_YES:
4219            try:
4220                self.saveAllDocPages()
4221                self.deleteWikiWord(wikiWord)
4222            except (IOError, OSError, DbAccessError), e:
4223                self.lostAccess(e)
4224                raise
4225            except WikiDataException, e:
4226                self.displayErrorMessage(unicode(e))
4227
4228        dlg.Destroy()
4229
4230
4231    def showSearchReplaceDialog(self):
4232        if self.findDlg != None:
4233            if isinstance(self.findDlg, SearchPageDialog):
4234                self.findDlg.SetFocus()
4235            return
4236
4237        self.findDlg = SearchPageDialog(self, -1)
4238        self.findDlg.CenterOnParent(wx.BOTH)
4239        self.findDlg.Show()
4240
4241
4242    def showReplaceTextByWikiwordDialog(self):
4243        if self.getCurrentWikiWord() is None:
4244            self.displayErrorMessage(_(u"No real wiki word to modify"))
4245            return
4246       
4247        if self.isReadOnlyPage():
4248            return
4249
4250        wikiWord = ""
4251        newWord = True
4252        try:
4253            langHelper = wx.GetApp().createWikiLanguageHelper(
4254                    self.getWikiDefaultWikiLanguage())
4255
4256            while True:
4257                wikiWord = guiToUni(wx.GetTextFromUser(
4258                        _(u"Replace text by WikiWord:"),
4259                        _(u"Replace by Wiki Word"), wikiWord, self))
4260                       
4261                if not wikiWord:
4262                    return False
4263                   
4264                validWikiWord = langHelper.extractWikiWordFromLink(wikiWord,
4265                        self.getWikiDocument())
4266       
4267                if validWikiWord is None:
4268                    self.displayErrorMessage(_(u"'%s' is an invalid wiki word.") % wikiWord)
4269                    continue
4270
4271                knownWikiWord = self.getWikiDocument().getUnAliasedWikiWord(
4272                            validWikiWord)
4273
4274                if knownWikiWord is not None:
4275                    result = wx.MessageBox(uniToGui(_(
4276                            u'Wiki word %s exists already\n'
4277                            u'Would you like to append to the word?') %
4278                            knownWikiWord), _(u'Word exists'),
4279                            wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, self)
4280                   
4281                    if result == wx.NO:
4282                        continue
4283                       
4284                    validWikiWord = knownWikiWord
4285                    newWord = False
4286
4287                break
4288
4289            text = self.getActiveEditor().GetSelectedText()
4290            if newWord:
4291                page = self.wikiDataManager.createWikiPage(validWikiWord)
4292                # TODO Respect template property?
4293                title = self.wikiDataManager.getWikiPageTitle(validWikiWord)
4294                if title is not None:
4295                    ptp = self.wikiDataManager.getPageTitlePrefix()
4296                    page.replaceLiveText(u"%s %s\n\n%s" % (ptp, title, text))
4297                    self.saveDocPage(page)
4298                else:
4299                    page.replaceLiveText(text)
4300                    self.saveDocPage(page)
4301            else:
4302                page = self.wikiDataManager.getWikiPage(validWikiWord)
4303                page.appendLiveText(u"\n\n" + text)
4304               
4305               
4306            self.getActiveEditor().ReplaceSelection(
4307                    langHelper.createLinkFromWikiWord(validWikiWord,
4308                    self.getCurrentDocPage()))
4309
4310        except (IOError, OSError, DbAccessError), e:
4311            self.lostAccess(e)
4312            raise
4313
4314
4315    def showSelectIconDialog(self):
4316#         dlg = SelectIconDialog(self, -1, wx.GetApp().getIconCache())
4317#         dlg.CenterOnParent(wx.BOTH)
4318#         if dlg.ShowModal() == wx.ID_OK:
4319#             iconname = dlg.GetValue()
4320#
4321#         dlg.Destroy()
4322#
4323        iconname = SelectIconDialog.runModal(self, -1,
4324                wx.GetApp().getIconCache())
4325
4326        if iconname:
4327            self.insertAttribute("icon", iconname)
4328
4329    def showDateformatDialog(self):
4330        fmt = self.configuration.get("main", "strftime")
4331
4332        dlg = DateformatDialog(self, -1, self, deffmt = fmt)
4333        dlg.CenterOnParent(wx.BOTH)
4334        dateformat = None
4335
4336        if dlg.ShowModal() == wx.ID_OK:
4337            dateformat = dlg.GetValue()
4338        dlg.Destroy()
4339
4340        if not dateformat is None:
4341            self.configuration.set("main", "strftime", dateformat)
4342
4343    def showOptionsDialog(self):
4344        dlg = OptionsDialog(self, -1)
4345        dlg.CenterOnParent(wx.BOTH)
4346
4347        result = dlg.ShowModal()
4348        oldSettings = dlg.getOldSettings()
4349       
4350        dlg.Destroy()
4351
4352        if result == wx.ID_OK:
4353            # Perform operations to reset GUI parts after option changes
4354            self.autoSaveDelayAfterKeyPressed = self.configuration.getint(
4355                    "main", "auto_save_delay_key_pressed")
4356            self.autoSaveDelayAfterDirty = self.configuration.getint(
4357                    "main", "auto_save_delay_dirty")
4358            maxLen = self.configuration.getint(
4359                    "main", "recentWikisList_length", 5)
4360            self.wikiHistory = self.wikiHistory[:maxLen]
4361
4362            self.setShowOnTray()
4363            self.setHideUndefined()
4364            self.rereadRecentWikis()
4365            self.refreshPageStatus()
4366           
4367            # TODO Move this to WikiDataManager!
4368            # Set file storage according to configuration
4369            fs = self.getWikiDataManager().getFileStorage()
4370           
4371            fs.setModDateMustMatch(self.configuration.getboolean("main",
4372                    "fileStorage_identity_modDateMustMatch", False))
4373            fs.setFilenameMustMatch(self.configuration.getboolean("main",
4374                    "fileStorage_identity_filenameMustMatch", False))
4375            fs.setModDateIsEnough(self.configuration.getboolean("main",
4376                    "fileStorage_identity_modDateIsEnough", False))
4377
4378
4379            # Build new layout config string
4380            newLayoutMainTreePosition = self.configuration.getint("main",
4381                "mainTree_position", 0)
4382            newLayoutViewsTreePosition = self.configuration.getint("main",
4383                "viewsTree_position", 0)
4384            newLayoutDocStructurePosition = self.configuration.getint("main",
4385                "docStructure_position", 0)
4386            newLayoutTimeViewPosition = self.configuration.getint("main",
4387                "timeView_position", 0)   
4388            if self.layoutViewsTreePosition != newLayoutViewsTreePosition or \
4389                    self.layoutMainTreePosition != newLayoutMainTreePosition or \
4390                    self.layoutDocStructurePosition != newLayoutDocStructurePosition or \
4391                    self.layoutTimeViewPosition != newLayoutTimeViewPosition:
4392
4393                self.layoutViewsTreePosition = newLayoutViewsTreePosition
4394                self.layoutMainTreePosition = newLayoutMainTreePosition
4395                self.layoutDocStructurePosition = newLayoutDocStructurePosition
4396                self.layoutTimeViewPosition = newLayoutTimeViewPosition
4397
4398                mainPos = {0:"left", 1:"right", 2:"above", 3:"below"}\
4399                        [newLayoutMainTreePosition]
4400
4401                # Set layout for main tree
4402                layoutCfStr = "name:main area panel;"\
4403                        "layout relation:%s&layout relative to:main area panel&name:maintree&"\
4404                        "layout sash position:170&layout sash effective position:170" % \
4405                        mainPos
4406
4407                # Add layout for Views tree
4408                if newLayoutViewsTreePosition > 0:
4409#                     # Don't show "Views" tree
4410#                     layoutCfStr = self._LAYOUT_WITHOUT_VIEWSTREE % mainPos
4411#                 else:
4412                    viewsPos = {1:"above", 2:"below", 3:"left", 4:"right"}\
4413                            [newLayoutViewsTreePosition]
4414#                     layoutCfStr += self._LAYOUT_WITH_VIEWSTREE % \
4415#                             (mainPos, viewsPos)
4416                    layoutCfStr += ";layout relation:%s&layout relative to:maintree&name:viewstree" % \
4417                            viewsPos
4418
4419                if newLayoutTimeViewPosition > 0:
4420                    timeViewPos = {1:"left", 2:"right", 3:"above", 4:"below"}\
4421                        [newLayoutTimeViewPosition]
4422                    layoutCfStr += ";layout relation:%s&layout relative to:main area panel&name:time view&"\
4423                                "layout sash position:120&layout sash effective position:120" % \
4424                                timeViewPos
4425
4426                # Layout for doc structure window
4427                if newLayoutDocStructurePosition > 0:
4428                    docStructPos = {1:"left", 2:"right", 3:"above", 4:"below"}\
4429                        [newLayoutDocStructurePosition]
4430                    layoutCfStr += ";layout relation:%s&layout relative to:main area panel&name:doc structure&"\
4431                                "layout sash position:120&layout sash effective position:120" % \
4432                                docStructPos
4433
4434                # Layout for log window
4435                layoutCfStr += ";layout relation:below&layout relative to:main area panel&name:log&"\
4436                            "layout sash position:1&layout sash effective position:120"
4437                           
4438
4439                self.configuration.set("main", "windowLayout", layoutCfStr)
4440                # Call of changeLayoutByCf() crashes on Linux/GTK so save
4441                # data beforehand
4442                self.saveCurrentWikiState()
4443                self.changeLayoutByCf(layoutCfStr)
4444           
4445            self.userActionCoord.applyConfiguration()
4446            self._refreshHotKeys()
4447
4448            wx.GetApp().fireMiscEventProps({"options changed": True,
4449                    "old config settings": oldSettings})
4450
4451
4452    def OnCmdExportDialog(self, evt):
4453        self.saveAllDocPages()
4454        self.getWikiData().commit()
4455
4456        dlg = ExportDialog(self, -1, continuousExport=False)
4457        dlg.CenterOnParent(wx.BOTH)
4458
4459        result = dlg.ShowModal()
4460        dlg.Destroy()
4461
4462
4463    def OnCmdContinuousExportDialog(self, evt):
4464        if self.continuousExporter is not None:
4465            self.continuousExporter.stopContinuousExport()
4466            self.continuousExporter = None
4467            return
4468
4469        self.saveAllDocPages()
4470        self.getWikiData().commit()
4471
4472        dlg = ExportDialog(self, -1, continuousExport=True)
4473        try:
4474            dlg.CenterOnParent(wx.BOTH)
4475   
4476            dlg.ShowModal()
4477            exporter = dlg.GetValue()
4478            self.continuousExporter = exporter
4479        finally:
4480            dlg.Destroy()
4481
4482
4483    def OnUpdateContinuousExportDialog(self, evt):
4484        evt.Check(self.continuousExporter is not None)
4485
4486
4487    EXPORT_PARAMS = {
4488            GUI_ID.MENU_EXPORT_WHOLE_AS_PAGE:
4489                    (Exporters.HtmlExporter, u"html_multi", None),
4490            GUI_ID.MENU_EXPORT_WHOLE_AS_PAGES:
4491                    (Exporters.HtmlExporter, u"html_single", None),
4492            GUI_ID.MENU_EXPORT_WORD_AS_PAGE:
4493                    (Exporters.HtmlExporter, u"html_multi", None),
4494            GUI_ID.MENU_EXPORT_SUB_AS_PAGE:
4495                    (Exporters.HtmlExporter, u"html_multi", None),
4496            GUI_ID.MENU_EXPORT_SUB_AS_PAGES:
4497                    (Exporters.HtmlExporter, u"html_single", None),
4498            GUI_ID.MENU_EXPORT_WHOLE_AS_RAW:
4499                    (Exporters.TextExporter, u"raw_files", (1,))
4500            }
4501
4502
4503    def OnExportWiki(self, evt):
4504        import SearchAndReplace as Sar
4505
4506        defdir = self.getConfig().get("main", "export_default_dir", u"")
4507        if defdir == u"":
4508            defdir = self.getLastActiveDir()
4509       
4510        typ = evt.GetId()
4511        # Export to dir
4512        dest = wx.DirSelector(_(u"Select Export Directory"), defdir,
4513        wx.DD_DEFAULT_STYLE|wx.DD_NEW_DIR_BUTTON, parent=self)
4514
4515        try:
4516            if dest:
4517                if typ in (GUI_ID.MENU_EXPORT_WHOLE_AS_PAGE,
4518                        GUI_ID.MENU_EXPORT_WHOLE_AS_PAGES,
4519                        GUI_ID.MENU_EXPORT_WHOLE_AS_RAW):
4520                    # Export whole wiki
4521   
4522                    lpOp = Sar.ListWikiPagesOperation()
4523                    item = Sar.AllWikiPagesNode(lpOp)
4524                    lpOp.setSearchOpTree(item)
4525                    lpOp.ordering = "asroottree"  # Slow, but more intuitive
4526                    wordList = self.getWikiDocument().searchWiki(lpOp)
4527   
4528    #                 wordList = self.getWikiData().getAllDefinedWikiPageNames()
4529                   
4530                elif typ in (GUI_ID.MENU_EXPORT_SUB_AS_PAGE,
4531                        GUI_ID.MENU_EXPORT_SUB_AS_PAGES):
4532                    # Export a subtree of current word
4533                    if self.getCurrentWikiWord() is None:
4534                        self.displayErrorMessage(
4535                                _(u"No real wiki word selected as root"))
4536                        return
4537                    lpOp = Sar.ListWikiPagesOperation()
4538                    item = Sar.ListItemWithSubtreeWikiPagesNode(lpOp,
4539                            [self.getCurrentWikiWord()], -1)
4540                    lpOp.setSearchOpTree(item)
4541                    lpOp.ordering = "asroottree"  # Slow, but more intuitive
4542                    wordList = self.getWikiDocument().searchWiki(lpOp)
4543   
4544    #                 wordList = self.getWikiData().getAllSubWords(
4545    #                         [self.getCurrentWikiWord()])
4546                else:
4547                    if self.getCurrentWikiWord() is None:
4548                        self.displayErrorMessage(
4549                                _(u"No real wiki word selected as root"))
4550                        return
4551
4552                    wordList = (self.getCurrentWikiWord(),)
4553
4554                expclass, exptype, addopt = self.EXPORT_PARAMS[typ]
4555               
4556                self.saveAllDocPages()
4557                self.getWikiData().commit()
4558
4559                ob = expclass(self)
4560                if addopt is None:
4561                    # Additional options not given -> take default provided by exporter
4562                    addopt = ob.getAddOpt(None)
4563
4564                pgh = ProgressHandler(_(u"Exporting"), u"", 0, self)
4565                pgh.open(0)
4566                pgh.update(0, _(u"Preparing"))
4567
4568                try:
4569                    ob.export(self.getWikiDataManager(), wordList, exptype, dest,
4570                            False, addopt, pgh)
4571                finally:
4572                    pgh.close()
4573
4574                self.configuration.set("main", "last_active_dir", dest)
4575
4576        except (IOError, OSError, DbAccessError), e:
4577            self.lostAccess(e)
4578            raise
4579
4580
4581    def OnCmdImportDialog(self, evt):
4582        if self.isReadOnlyWiki():
4583            return
4584
4585        self.saveAllDocPages()
4586        self.getWikiData().commit()
4587
4588        dlg = ImportDialog(self, -1, self)
4589        dlg.CenterOnParent(wx.BOTH)
4590
4591        result = dlg.ShowModal()
4592        dlg.Destroy()
4593
4594
4595    def showAddFileUrlDialog(self):
4596        if self.isReadOnlyPage():
4597            return
4598
4599        dlg = wx.FileDialog(self, _(u"Choose a file to create URL for"),
4600                self.getLastActiveDir(), "", "*.*", wx.OPEN)
4601        if dlg.ShowModal() == wx.ID_OK:
4602            url = urlFromPathname(dlg.GetPath())
4603            if dlg.GetPath().endswith(".wiki"):
4604                url = "wiki:" + url
4605            else:
4606#                 doCopy = False  # Necessary because key state may change between
4607#                                 # the two ifs
4608#                 if False:
4609#                     # Relative rel: URL
4610#                     locPath = self.editor.pWiki.getWikiConfigPath()
4611#                     if locPath is not None:
4612#                         locPath = dirname(locPath)
4613#                         relPath = relativeFilePath(locPath, fn)
4614#                         if relPath is None:
4615#                             # Absolute path needed
4616#                             urls.append("file:%s" % url)
4617#                         else:
4618#                             urls.append("rel://%s" % urllib.pathname2url(relPath))
4619#                 else:
4620   
4621                # Absolute file: URL
4622                url = "file:" + url
4623               
4624            self.getActiveEditor().AddText(url)
4625            self.configuration.set("main", "last_active_dir", dirname(dlg.GetPath()))
4626           
4627        dlg.Destroy()
4628
4629
4630
4631    def showSpellCheckerDialog(self):
4632        if self.spellChkDlg != None:
4633            return
4634        try:
4635            self.spellChkDlg = SpellChecker.SpellCheckerDialog(self, -1, self)
4636        except (IOError, OSError, DbAccessError), e:
4637            self.lostAccess(e)
4638            raise
4639
4640        self.spellChkDlg.CenterOnParent(wx.BOTH)
4641        self.spellChkDlg.Show()
4642        self.spellChkDlg.checkNext(startPos=0)
4643
4644
4645
4646    def initiateFullUpdate(self, skipConfirm=False):
4647        if self.isReadOnlyWiki():
4648            return
4649
4650        if not skipConfirm:
4651            result = wx.MessageBox(_(u"Are you sure you want to start a full "
4652                    u"rebuild of wiki in background?"),
4653                    _(u'Initiate update'),
4654                    wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, self)
4655
4656        if skipConfirm or result == wx.YES :
4657            try:
4658                self.saveAllDocPages()
4659                progresshandler = ProgressHandler(
4660                        _(u"     Initiating update     "),
4661                        _(u"     Initiating update     "), 0, self)
4662                self.getWikiDataManager().initiateFullUpdate(progresshandler)
4663       
4664    #         self.tree.collapse()
4665    #
4666    #         # TODO Adapt for functional pages
4667    #         if self.getCurrentWikiWord() is not None:
4668    #             self.openWikiPage(self.getCurrentWikiWord(),
4669    #                     forceTreeSyncFromRoot=True)
4670    #         self.tree.expandRoot()
4671            except (IOError, OSError, DbAccessError), e:
4672                self.lostAccess(e)
4673                raise
4674            except Exception, e:
4675                self.displayErrorMessage(_(u"Error initiating update"), e)
4676                traceback.print_exc()
4677
4678
4679    def rebuildWiki(self, skipConfirm=False, onlyDirty=False):
4680        if self.isReadOnlyWiki():
4681            return
4682
4683        if not skipConfirm:
4684            result = wx.MessageBox(_(u"Are you sure you want to rebuild this wiki? "
4685                    u"You may want to backup your data first!"),
4686                    _(u'Rebuild wiki'),
4687                    wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION, self)
4688
4689        if skipConfirm or result == wx.YES :
4690            try:
4691                self.saveAllDocPages()
4692                progresshandler = ProgressHandler(
4693                        _(u"     Rebuilding wiki     "),
4694                        _(u"     Rebuilding wiki     "), 0, self)
4695                self.getWikiDataManager().rebuildWiki(progresshandler,
4696                        onlyDirty=onlyDirty)
4697
4698                self.tree.collapse()
4699
4700                # TODO Adapt for functional pages
4701                if self.getCurrentWikiWord() is not None:
4702                    self.openWikiPage(self.getCurrentWikiWord(),
4703                            forceTreeSyncFromRoot=True)
4704                self.tree.expandRoot()
4705            except (IOError, OSError, DbAccessError), e:
4706                self.lostAccess(e)
4707                raise
4708            except Exception, e:
4709                self.displayErrorMessage(_(u"Error rebuilding wiki"), e)
4710                traceback.print_exc()
4711
4712
4713    def vacuumWiki(self):
4714        if self.isReadOnlyWiki():
4715            return
4716
4717        try:
4718            self.getWikiData().vacuum()
4719        except (IOError, OSError, DbAccessError), e:
4720            self.lostAccess(e)
4721            raise
4722
4723
4724#     def OnCmdCloneWindow(self, evt):
4725#         _prof.start()
4726#         self._OnCmdCloneWindow(evt)
4727#         _prof.stop()
4728
4729
4730    def OnCmdCloneWindow(self, evt):
4731        wd = self.getWikiDocument()
4732        if wd is None:
4733            return
4734
4735        try:
4736            clAction = CmdLineAction([])
4737            clAction.wikiToOpen = wd.getWikiConfigPath()
4738            clAction.frameToOpen = 1  # Open in new frame
4739            wws = self.getMainAreaPanel().getOpenWikiWords()
4740           
4741            if wws is not None:
4742                clAction.wikiWordsToOpen = wws
4743
4744            wx.GetApp().startPersonalWikiFrame(clAction)
4745        except Exception, e:
4746            traceback.print_exc()
4747            self.displayErrorMessage(_(u'Error while starting new '
4748                    u'WikidPad instance'), e)
4749            return
4750
4751
4752    def OnImportFromPagefiles(self, evt):
4753        if self.isReadOnlyWiki():
4754            return
4755
4756        dlg=wx.MessageDialog(self,
4757                _(u"This could overwrite pages in the database. Continue?"),
4758                _(u"Import pagefiles"), wx.YES_NO)
4759
4760        result = dlg.ShowModal()
4761        if result == wx.ID_YES:
4762            self.getWikiData().copyWikiFilesToDatabase()
4763
4764
4765    def setDocPagePresenterSubControl(self, scName):
4766        presenter = self.getCurrentDocPagePresenter()
4767        if presenter is None:
4768            return
4769       
4770        if scName is None:
4771            self.getMainAreaPanel().switchDocPagePresenterTabEditorPreview(
4772                    presenter)
4773        else:
4774            presenter.switchSubControl(scName, gainFocus=True)
4775
4776       
4777
4778#     def OnCmdSwitchEditorPreview(self, evt):
4779#         presenter = self.getCurrentDocPagePresenter()
4780#         if presenter is None:
4781#             return
4782#
4783#         self.getMainAreaPanel().switchDocPagePresenterTabEditorPreview(presenter)
4784
4785
4786    def insertAttribute(self, key, value, wikiWord=None):
4787        langHelper = wx.GetApp().createWikiLanguageHelper(
4788                self.getWikiDefaultWikiLanguage())
4789
4790        if wikiWord is None:
4791            attr = langHelper.createAttributeFromComponents(key, value)
4792            self.getActiveEditor().AppendText(attr)
4793        else:
4794            try:
4795                # self.saveCurrentDocPage()
4796                if self.getWikiDocument().isDefinedWikiLink(wikiWord):
4797                    page = self.getWikiDocument().getWikiPage(wikiWord)
4798                    attr = langHelper.createAttributeFromComponents(key, value,
4799                            page)
4800                    page.appendLiveText(attr)
4801            except (IOError, OSError, DbAccessError), e:
4802                self.lostAccess(e)
4803                raise
4804
4805
4806    def addText(self, text, replaceSel=False):
4807        """
4808        Add text to current active editor view
4809        """
4810        ed = self.getActiveEditor()
4811        ed.BeginUndoAction()
4812        try:
4813            if replaceSel:
4814                ed.ReplaceSelection(text)
4815            else:
4816                ed.AddText(text)
4817        finally:
4818            ed.EndUndoAction()
4819
4820
4821    def appendText(self, text):
4822        """
4823        Append text to current active editor view
4824        """
4825        ed = self.getActiveEditor()
4826        ed.BeginUndoAction()
4827        try:
4828            self.getActiveEditor().AppendText(text)
4829        finally:
4830            ed.EndUndoAction()
4831
4832
4833    def insertDate(self):
4834        if self.isReadOnlyPage():
4835            return
4836
4837#         # strftime can't handle unicode correctly, so conversion is needed
4838#         mstr = mbcsEnc(self.configuration.get("main", "strftime"), "replace")[0]
4839#         self.getActiveEditor().AddText(mbcsDec(strftime(mstr), "replace")[0])
4840
4841        mstr = self.configuration.get("main", "strftime")
4842        self.getActiveEditor().AddText(strftimeUB(mstr))
4843
4844    def getLastActiveDir(self):
4845        return self.configuration.get("main", "last_active_dir", os.getcwd())
4846
4847   
4848    def stdDialog(self, dlgtype, title, message, additional=None):
4849        """
4850        Used to show a dialog, especially in scripts.
4851        Possible values for dlgtype:
4852        "text": input text to dialog, additional is the default text
4853            when showing dlg returns entered text on OK or empty string
4854        "o": As displayMessage, shows only OK button
4855        "oc": Shows OK and Cancel buttons, returns either "ok" or "cancel"
4856        "yn": Yes and No buttons, returns either "yes" or "no"
4857        "ync": like "yn" but with additional cancel button, can also return
4858            "cancel"
4859        """
4860        if dlgtype == "text":
4861            if additional is None:
4862                additional = u""
4863            return guiToUni(wx.GetTextFromUser(uniToGui(message),
4864                    uniToGui(title), uniToGui(additional), self))
4865        else:
4866            style = None
4867            if dlgtype == "o":
4868                style = wx.OK
4869            elif dlgtype == "oc":
4870                style = wx.OK | wx.CANCEL
4871            elif dlgtype == "yn":
4872                style = wx.YES_NO
4873            elif dlgtype == "ync":
4874                style = wx.YES_NO | wx.CANCEL
4875           
4876            if style is None:
4877                raise RuntimeError, _(u"Unknown dialog type")
4878
4879            result = wx.MessageBox(uniToGui(message), uniToGui(title), style, self)
4880           
4881            if result == wx.OK:
4882                return "ok"
4883            elif result == wx.CANCEL:
4884                return "cancel"
4885            elif result == wx.YES:
4886                return "yes"
4887            elif result == wx.NO:
4888                return "no"
4889               
4890            raise RuntimeError, _(u"Internal Error")
4891
4892    def displayMessage(self, title, str):
4893        """pops up a dialog box,
4894        used by scripts only
4895        """
4896        dlg_m = wx.MessageDialog(self, uniToGui(u"%s" % str), title, wx.OK)
4897        dlg_m.ShowModal()
4898        dlg_m.Destroy()
4899
4900
4901    def displayErrorMessage(self, errorStr, e=u""):
4902        "pops up a error dialog box"
4903        dlg_m = wx.MessageDialog(self, uniToGui(u"%s. %s." % (errorStr, e)),
4904                'Error!', wx.OK)
4905        dlg_m.ShowModal()
4906        dlg_m.Destroy()
4907        try:
4908            self.statusBar.SetStatusText(uniToGui(errorStr), 0)
4909        except:
4910            pass
4911
4912
4913    def showAboutDialog(self):
4914        dlg = AboutDialog(self)
4915        dlg.ShowModal()
4916        dlg.Destroy()
4917
4918    def OnShowWikiPropertiesDialog(self, evt):
4919        dlg = WikiPropertiesDialog(self, -1, self)
4920        dlg.ShowModal()
4921        dlg.Destroy()
4922
4923    def OnCmdShowWikiJobDialog(self, evt):
4924        dlg = WikiJobDialog(self, -1, self)
4925        dlg.ShowModal()
4926        dlg.Destroy()
4927
4928
4929    # ----------------------------------------------------------------------------------------
4930    # Event handlers from here on out.
4931    # ----------------------------------------------------------------------------------------
4932
4933
4934    def miscEventHappened(self, miscEvt):
4935        """
4936        Handle misc events
4937        """
4938        try:
4939            if miscEvt.getSource() is self.getWikiDocument():
4940                # Event from wiki document aka wiki data manager
4941                if miscEvt.has_key("deleted wiki page"):
4942                    wikiPage = miscEvt.get("wikiPage")
4943                    # trigger hooks
4944                    self.hooks.deletedWikiWord(self,
4945                            wikiPage.getWikiWord())
4946   
4947#                     self.fireMiscEventProps(miscEvt.getProps())
4948   
4949                elif miscEvt.has_key("renamed wiki page"):
4950                    oldWord = miscEvt.get("wikiPage").getWikiWord()
4951                    newWord = miscEvt.get("newWord")
4952
4953                    # trigger hooks
4954                    self.hooks.renamedWikiWord(self, oldWord, newWord)
4955
4956#                 elif miscEvt.has_key("updated wiki page"):
4957#                     # This was send from a WikiDocument(=WikiDataManager) object,
4958#                     # send it again to listening components
4959#                     self.fireMiscEventProps(miscEvt.getProps())
4960            elif miscEvt.getSource() is self.getMainAreaPanel():
4961                self.fireMiscEventProps(miscEvt.getProps())
4962#                 if miscEvt.has_key("changed current docpage presenter"):
4963#                     self.hooks.switchedToWikiWord(self, oldWord, newWord)
4964
4965            # Depending on wiki-related or global func. page, the following
4966            # events come from document or application object
4967
4968            if (miscEvt.getSource() is self.getWikiDocument()) or \
4969                   (miscEvt.getSource() is wx.GetApp()):
4970                if miscEvt.has_key("reread text blocks needed"):
4971                    self.rereadTextBlocks()
4972                elif miscEvt.has_key("reread personal word list needed"):
4973                    if self.spellChkDlg is not None:
4974                        self.spellChkDlg.rereadPersonalWordLists()
4975                elif miscEvt.has_key("reread favorite wikis needed"):
4976                    self.rereadFavoriteWikis()
4977                elif miscEvt.has_key("reread recent wikis needed"):
4978                    self.rereadRecentWikis()
4979
4980
4981        except (IOError, OSError, DbAccessError), e:
4982            self.lostAccess(e)
4983            raise
4984
4985
4986    def getDefDirForWikiOpenNew(self):
4987        """
4988        Return the appropriate default directory to start when user
4989        wants to create a new or open an existing wiki.
4990        """
4991        startDir = self.getConfig().get("main",
4992                "wikiOpenNew_defaultDir", u"")
4993        if startDir == u"":
4994            startDir = self.getWikiConfigPath()
4995            if startDir is None:
4996                startDir = self.getLastActiveDir()
4997            else:
4998                startDir = dirname(dirname(startDir))
4999       
5000        return startDir
5001
5002
5003
5004
5005    def OnWikiOpen(self, event):
5006        dlg = wx.FileDialog(self, _(u"Choose a Wiki to open"),
5007                self.getDefDirForWikiOpenNew(), "", "*.wiki", wx.OPEN)
5008        if dlg.ShowModal() == wx.ID_OK:
5009            self.openWiki(mbcsDec(abspath(dlg.GetPath()), "replace")[0])
5010        dlg.Destroy()
5011
5012
5013    def OnWikiOpenNewWindow(self, event):
5014        dlg = wx.FileDialog(self, _(u"Choose a Wiki to open"),
5015                self.getDefDirForWikiOpenNew(), "", "*.wiki", wx.OPEN)
5016        if dlg.ShowModal() == wx.ID_OK:
5017            try:
5018                clAction = CmdLineAction([])
5019                clAction.wikiToOpen = mbcsDec(abspath(dlg.GetPath()), "replace")[0]
5020                clAction.frameToOpen = 1  # Open in new frame
5021                wx.GetApp().startPersonalWikiFrame(clAction)
5022            except Exception, e:
5023                traceback.print_exc()
5024                self.displayErrorMessage(_(u'Error while starting new '
5025                        u'WikidPad instance'), e)
5026                return
5027
5028        dlg.Destroy()
5029
5030
5031    def OnWikiOpenAsType(self, event):
5032        dlg = wx.FileDialog(self, _(u"Choose a Wiki to open"),
5033                self.getDefDirForWikiOpenNew(), "", "*.wiki", wx.OPEN)
5034        if dlg.ShowModal() == wx.ID_OK:
5035            self.openWiki(mbcsDec(abspath(dlg.GetPath()), "replace")[0],
5036                    ignoreWdhName=True)
5037        dlg.Destroy()
5038
5039
5040    def OnWikiNew(self, event):
5041        dlg = wx.TextEntryDialog (self,
5042                _(u"Name for new wiki (must be in the form of a WikiWord):"),
5043                _(u"Create New Wiki"), u"MyWiki", wx.OK | wx.CANCEL)
5044
5045        if dlg.ShowModal() == wx.ID_OK:
5046            wikiName = guiToUni(dlg.GetValue())
5047            userLangHelper = wx.GetApp().createWikiLanguageHelper(
5048                    wx.GetApp().getUserDefaultWikiLanguage())
5049
5050            wikiName = userLangHelper.extractWikiWordFromLink(wikiName)
5051            # TODO: Further measures to exclude prohibited characters
5052
5053            # make sure this is a valid wiki word
5054            errMsg = userLangHelper.checkForInvalidWikiWord(wikiName)
5055
5056            if errMsg is None:
5057                dlg = wx.DirDialog(self, _(u"Directory to store new wiki"),
5058                        self.getDefDirForWikiOpenNew(),
5059                        style=wx.DD_DEFAULT_STYLE|wx.DD_NEW_DIR_BUTTON)
5060                if dlg.ShowModal() == wx.ID_OK:
5061                    self.newWiki(wikiName, dlg.GetPath())
5062            else:
5063                self.displayErrorMessage(_(u"'%s' is an invalid wiki word. %s")
5064                        % (wikiName, errMsg))
5065
5066        dlg.Destroy()
5067
5068
5069    def OnIdle(self, evt):
5070        if not self.configuration.getboolean("main", "auto_save"):  # self.autoSave:
5071            return
5072        if self.getWikiDocument() is None or self.getWikiDocument().getWriteAccessFailed():
5073            # No automatic saving due to previous error
5074            return
5075
5076        # check if the current wiki page needs to be saved
5077        if self.getCurrentDocPage():
5078            (saveDirtySince, updateDirtySince) = \
5079                    self.getCurrentDocPage().getDirtySince()
5080            if saveDirtySince is not None:
5081                currentTime = time()
5082                # only try and save if the user stops typing
5083                if (currentTime - self.getActiveEditor().lastKeyPressed) > \
5084                        self.autoSaveDelayAfterKeyPressed:
5085#                     if saveDirty:
5086                    if (currentTime - saveDirtySince) > \
5087                            self.autoSaveDelayAfterDirty:
5088                        self.saveAllDocPages()
5089#                     elif updateDirty:
5090#                         if (currentTime - self.currentWikiPage.lastUpdate) > 5:
5091#                             self.updateRelationships()
5092
5093    def OnSize(self, evt):
5094        if self.windowLayouter is not None:
5095            self.windowLayouter.layout()
5096
5097
5098    def isReadOnlyWiki(self):
5099        wikiDoc = self.getWikiDocument()
5100        return (wikiDoc is None) or wikiDoc.isReadOnlyEffect()
5101
5102
5103    def isReadOnlyPage(self):
5104        docPage = self.getCurrentDocPage()
5105        return (docPage is None) or docPage.isReadOnlyEffect()
5106               
5107
5108    def OnUpdateDisNoWiki(self, evt):
5109        """
5110        Called for ui-update to disable menu item if no wiki loaded.
5111        """
5112        evt.Enable(self.isWikiLoaded())
5113
5114
5115    def OnUpdateDisReadOnlyWiki(self, evt):
5116        """
5117        Called for ui-update to disable menu item if wiki is read-only.
5118        """
5119        evt.Enable(not self.isReadOnlyWiki())
5120
5121    def OnUpdateDisReadOnlyPage(self, evt):
5122        """
5123        Called for ui-update to disable menu item if page is read-only.
5124        """
5125        evt.Enable(not self.isReadOnlyPage())
5126
5127    def OnUpdateDisNotTextedit(self, evt):
5128        """
5129        Disables item if current presenter doesn't show textedit subcontrol.
5130        """
5131        pres = self.getCurrentDocPagePresenter()
5132        if pres is None or pres.getCurrentSubControlName() != "textedit":
5133            evt.Enable(False)
5134
5135    def OnUpdateDisNotWikiPage(self, evt):
5136        """
5137        Disables item if current presenter doesn't show a real wiki page.
5138        """
5139        if self.getCurrentWikiWord() is None:
5140            evt.Enable(False)           
5141
5142
5143    def OnCmdCheckWrapMode(self, evt):       
5144        self.getActiveEditor().setWrapMode(evt.IsChecked())
5145        self.configuration.set("main", "wrap_mode", evt.IsChecked())
5146
5147    def OnUpdateWrapMode(self, evt):
5148        editor = self.getActiveEditor()
5149        evt.Check(editor is not None and editor.getWrapMode())
5150        evt.Enable(editor is not None)
5151
5152
5153    def OnCmdCheckIndentationGuides(self, evt):       
5154        self.getActiveEditor().SetIndentationGuides(evt.IsChecked())
5155        self.configuration.set("main", "indentation_guides", evt.IsChecked())
5156
5157    def OnUpdateIndentationGuides(self, evt):
5158        editor = self.getActiveEditor()
5159        evt.Check(editor is not None and editor.GetIndentationGuides())
5160        evt.Enable(editor is not None)
5161
5162
5163    def OnCmdCheckAutoIndent(self, evt):       
5164        self.getActiveEditor().setAutoIndent(evt.IsChecked())
5165        self.configuration.set("main", "auto_indent", evt.IsChecked())
5166
5167    def OnUpdateAutoIndent(self, evt):
5168        editor = self.getActiveEditor()
5169        evt.Check(editor is not None and editor.getAutoIndent())
5170        evt.Enable(editor is not None)
5171
5172
5173    def OnCmdCheckAutoBullets(self, evt):       
5174        self.getActiveEditor().setAutoBullets(evt.IsChecked())
5175        self.configuration.set("main", "auto_bullets", evt.IsChecked())
5176
5177    def OnUpdateAutoBullets(self, evt):
5178        editor = self.getActiveEditor()
5179        evt.Check(editor is not None and editor.getAutoBullets())
5180        evt.Enable(editor is not None)
5181
5182
5183    def OnCmdCheckTabsToSpaces(self, evt):       
5184        self.getActiveEditor().setTabsToSpaces(evt.IsChecked())
5185        self.configuration.set("main", "editor_tabsToSpaces", evt.IsChecked())
5186
5187    def OnUpdateTabsToSpaces(self, evt):
5188        editor = self.getActiveEditor()
5189        evt.Check(editor is not None and editor.getTabsToSpaces())
5190        evt.Enable(editor is not None)
5191
5192
5193    def OnCmdCheckShowLineNumbers(self, evt):       
5194        self.getActiveEditor().setShowLineNumbers(evt.IsChecked())
5195        self.configuration.set("main", "show_lineNumbers", evt.IsChecked())
5196
5197    def OnUpdateShowLineNumbers(self, evt):
5198        editor = self.getActiveEditor()
5199        evt.Check(editor is not None and editor.getShowLineNumbers())
5200        evt.Enable(editor is not None)
5201
5202
5203    def OnCmdCheckShowFolding(self, evt):       
5204        self.getActiveEditor().setFoldingActive(evt.IsChecked())
5205        self.configuration.set("main", "editor_useFolding", evt.IsChecked())
5206
5207    def OnUpdateShowFolding(self, evt):
5208        editor = self.getActiveEditor()
5209        evt.Check(editor is not None and editor.getFoldingActive())
5210        evt.Enable(editor is not None)
5211
5212
5213    def OnCloseButton(self, evt):
5214        if self.configuration.getboolean("main", "minimize_on_closeButton"):
5215            self.Iconize(True)
5216        else:
5217#             tracer.runctx('self._prepareExitWiki()', globals(), locals())
5218            self._prepareExitWiki()
5219            self.Destroy()
5220            evt.Skip()
5221
5222
5223    def exitWiki(self):
5224        self._prepareExitWiki()
5225        self.Destroy()
5226
5227    def _prepareExitWiki(self):
5228#         if not self.configuration.getboolean("main", "minimize_on_closeButton"):
5229#             self.Close()
5230#         else:
5231#             self.prepareExit()
5232#             self.Destroy()
5233#
5234#
5235#     def prepareExit(self):
5236        # Stop clipboard catcher if running
5237#         if self.clipboardInterceptor is not None:
5238#             self.clipboardInterceptor.catchOff()
5239
5240        if self._interceptCollection is not None:
5241            self._interceptCollection.close()
5242
5243        self.getMainAreaPanel().updateConfig()
5244        self.closeWiki()
5245
5246        wx.GetApp().getMiscEvent().removeListener(self)
5247
5248        # if the frame is not minimized
5249        # update the size/pos of the global config
5250        if not self.IsIconized():
5251            curSize = self.GetSize()
5252            self.configuration.set("main", "size_x", curSize.x)
5253            self.configuration.set("main", "size_y", curSize.y)
5254            curPos = self.GetPosition()
5255            self.configuration.set("main", "pos_x", curPos.x)
5256            self.configuration.set("main", "pos_y", curPos.y)
5257
5258        # windowmode:  0=normal, 1=maximized, 2=iconized, 3=maximized iconized
5259
5260        windowmode = 0
5261        if self.IsMaximized():
5262            windowmode |= 1
5263        if self.IsIconized():
5264            windowmode |= 2
5265
5266        self.configuration.set("main", "windowmode", windowmode)
5267
5268        layoutCfStr = self.windowLayouter.getWinPropsForConfig()
5269        self.configuration.set("main", "windowLayout", layoutCfStr)
5270
5271        self.configuration.set("main", "frame_stayOnTop", self.getStayOnTop())
5272        self.configuration.set("main", "zoom", self.getActiveEditor().GetZoom())
5273        self.configuration.set("main", "wiki_history", ";".join(self.wikiHistory))
5274        self.writeGlobalConfig()
5275
5276        # trigger hook
5277        self.hooks.exit(self)
5278
5279        self.getMainAreaPanel().close()
5280
5281        # save the current wiki state
5282#         self.saveCurrentWikiState()
5283
5284        wx.TheClipboard.Flush()
5285
5286        if self.tbIcon is not None:
5287            if self.tbIcon.IsIconInstalled():
5288                self.tbIcon.RemoveIcon()
5289
5290            self.tbIcon.Destroy()
5291            # May mysteriously prevent crash when closing WikidPad minimized
5292            #   on tray
5293            sleep(0.1)
5294            self.tbIcon = None
5295       
5296        wx.GetApp().unregisterMainFrame(self)
5297
5298
5299
5300class TaskBarIcon(wx.TaskBarIcon):
5301    def __init__(self, pWiki):
5302        wx.TaskBarIcon.__init__(self)
5303        self.pWiki = pWiki
5304
5305        # Register menu events
5306        wx.EVT_MENU(self, GUI_ID.TBMENU_RESTORE, self.OnLeftUp)
5307        wx.EVT_MENU(self, GUI_ID.TBMENU_SAVE,
5308                lambda evt: (self.pWiki.saveAllDocPages(),
5309                self.pWiki.getWikiData().commit()))
5310        wx.EVT_MENU(self, GUI_ID.TBMENU_EXIT, lambda evt: self.pWiki.exitWiki())
5311
5312        if self.pWiki.clipboardInterceptor is not None:
5313            wx.EVT_MENU(self, GUI_ID.CMD_CLIPBOARD_CATCHER_AT_CURSOR,
5314                    self.pWiki.OnClipboardCatcherAtCursor)
5315            wx.EVT_MENU(self, GUI_ID.CMD_CLIPBOARD_CATCHER_OFF,
5316                    self.pWiki.OnClipboardCatcherOff)
5317
5318            wx.EVT_UPDATE_UI(self, GUI_ID.CMD_CLIPBOARD_CATCHER_AT_CURSOR,
5319                    self.pWiki.OnUpdateClipboardCatcher)
5320            wx.EVT_UPDATE_UI(self, GUI_ID.CMD_CLIPBOARD_CATCHER_OFF,
5321                    self.pWiki.OnUpdateClipboardCatcher)
5322
5323        wx.EVT_TASKBAR_LEFT_UP(self, self.OnLeftUp)
5324
5325
5326    def OnLeftUp(self, evt):
5327        if self.pWiki.IsIconized():
5328            self.pWiki.Iconize(False)
5329            self.pWiki.Show(True)
5330       
5331        self.pWiki.Raise()
5332
5333
5334    def CreatePopupMenu(self):
5335        tbMenu = wx.Menu()
5336        # Build menu
5337        if self.pWiki.clipboardInterceptor is not None:
5338            menuItem = wx.MenuItem(tbMenu,
5339                    GUI_ID.CMD_CLIPBOARD_CATCHER_AT_CURSOR,
5340                    _(u"Clipboard Catcher at Cursor"), u"", wx.ITEM_CHECK)
5341            tbMenu.AppendItem(menuItem)
5342
5343            menuItem = wx.MenuItem(tbMenu, GUI_ID.CMD_CLIPBOARD_CATCHER_OFF,
5344                    _(u"Clipboard Catcher off"), u"", wx.ITEM_CHECK)
5345            tbMenu.AppendItem(menuItem)
5346           
5347            tbMenu.AppendSeparator()
5348
5349
5350        appendToMenuByMenuDesc(tbMenu, _SYSTRAY_CONTEXT_MENU_BASE)
5351
5352
5353        return tbMenu
5354
5355
5356def importCode(code, usercode, userUserCode, name, add_to_sys_modules=False):
5357    """
5358    Import dynamically generated code as a module.
5359    usercode and code are the objects containing the code
5360    (a string, a file handle or an actual compiled code object,
5361    same types as accepted by an exec statement), usercode
5362    may be None. code is executed first, usercode thereafter
5363    and can overwrite settings in code. The name is the name to give to the module,
5364    and the final argument says wheter to add it to sys.modules
5365    or not. If it is added, a subsequent import statement using
5366    name will return this module. If it is not added to sys.modules
5367    import will try to load it in the normal fashion.
5368
5369    import foo
5370
5371    is equivalent to
5372
5373    foofile = open("/path/to/foo.py")
5374    foo = importCode(foofile,"foo",1)
5375
5376    Returns a newly generated module.
5377    """
5378    import sys,imp
5379
5380    module = imp.new_module(name)
5381
5382    exec code in module.__dict__
5383    if usercode is not None:
5384        exec usercode in module.__dict__
5385    if userUserCode is not None:
5386        exec userUserCode in module.__dict__
5387    if add_to_sys_modules:
5388        sys.modules[name] = module
5389
5390    return module
5391
5392
5393
5394
5395_SYSTRAY_CONTEXT_MENU_BASE = \
5396u"""
5397Restore;TBMENU_RESTORE
5398Save;TBMENU_SAVE
5399Exit;TBMENU_EXIT
5400"""
5401
5402
5403# Entries to support i18n of context menus
5404
5405N_(u"Restore")
5406N_(u"Save")
5407N_(u"Exit")
5408
5409# _TASKBAR_CONTEXT_MENU_CLIPCATCH = \
5410# u"""
5411# Clipboard Catcher at Cursor;CMD_CLIPBOARD_CATCHER_AT_CURSOR
5412# Clipboard Catcher off;CMD_CLIPBOARD_CATCHER_OFF
5413# -
5414# """
5415
5416
5417
5418
5419#         This function must FOLLOW the actual update eventhandler in the
5420#         updatefct tuple of self.addMenuItem.
Note: See TracBrowser for help on using the browser.