/lib/pwiki/PersonalWikiFrame.py
Python | 6069 lines | 5721 code | 173 blank | 175 comment | 95 complexity | 92078558ec5a28aa64e560d7507b8213 MD5 | raw file
Possible License(s): LGPL-2.1
Large files files are truncated, but you can click here to view the full file
- # -*- coding: iso8859-1 -*-
- from __future__ import with_statement
-
- ## import profilehooks
- ## profile = profilehooks.profile(filename="profile.prf", immediate=False)
-
-
- import os, os.path, sys, gc, traceback, string, re, collections
- from os.path import *
- import time
-
- import cPickle # to create dependency?
-
- import wx, wx.html
- import wx.lib.agw.aui as aui
-
- # import urllib_red as urllib
- # import urllib
-
- from .wxHelper import GUI_ID, clearMenu, ProgressHandler, TopLevelLocker, \
- WindowUpdateLocker
- from . import wxHelper
-
- from . import TextTree
-
- from .MiscEvent import MiscEventSourceMixin, ProxyMiscEvent # , DebugSimple
-
- from WikiExceptions import *
- from Consts import HOMEPAGE
-
- from . import Utilities
- from . import SystemInfo
- from .WindowLayout import WindowSashLayouter, setWindowPos, setWindowSize
- from . import WindowLayout
-
- from .wikidata import DbBackendUtils, WikiDataManager
-
- # To generate py2exe dependency
- from . import WikiDocument
-
- from . import OsAbstract
-
- from . import DocPages
-
- from .PWikiNonCore import PWikiNonCore
-
- from .CmdLineAction import CmdLineAction
- from .WikiTxtCtrl import WikiTxtCtrl, FOLD_MENU
- from .WikiTreeCtrl import WikiTreeCtrl
- from .WikiHtmlView import createWikiHtmlView
-
- from .MainAreaPanel import MainAreaPanel
- from .UserActionCoord import UserActionCoord
- from .DocPagePresenter import DocPagePresenter
-
- from .Ipc import EVT_REMOTE_COMMAND
-
- from . import AttributeHandling, SpellChecker
-
-
- from . import AdditionalDialogs
-
-
- import StringOps
- from StringOps import uniToGui, guiToUni, mbcsDec, mbcsEnc, \
- unescapeForIni, urlFromPathname, \
- strftimeUB, pathEnc, loadEntireFile, writeEntireFile, \
- pathWordAndAnchorToWikiUrl, relativeFilePath, pathnameFromUrl
-
-
- from PluginManager import PluginAPIAggregation
- import PluginManager
-
-
- # TODO More abstract/platform independent
- try:
- import WindowsHacks
- except:
- if SystemInfo.isWindows():
- traceback.print_exc()
- WindowsHacks = None
-
-
-
- class KeyBindingsCache:
- def __init__(self, kbModule):
- self.kbModule = kbModule
- self.accelPairCache = {}
-
- def __getattr__(self, attr):
- return getattr(self.kbModule, attr, u"")
-
- def get(self, attr, default=None):
- return getattr(self.kbModule, attr, None)
-
- def getAccelPair(self, attr):
- try:
- return self.accelPairCache[attr]
- except KeyError:
- ap = wxHelper.getAccelPairFromString("\t" + getattr(self, attr))
- self.accelPairCache[attr] = ap
- return ap
-
- def matchesAccelPair(self, attr, accP):
- return self.getAccelPair(attr) == accP
-
-
- class LossyWikiCloseDeniedException(Exception):
- """
- Special exception thrown by PersonalWikiFrame.closeWiki() if user denied
- to close the wiki because it might lead to data loss
- """
- pass
-
-
-
- def _buildChainedUpdateEventFct(chain):
- def evtFct(evt):
- evt.Enable(True)
- for fct in chain:
- fct(evt)
-
- return evtFct
-
-
- # def _buildUpdateEventFctByEnableExpress(expr):
- # def evtFct(evt):
- #
- #
- # evt.Enable(True)
- # for fct in chain:
- # fct(evt)
- #
- # return evtFct
-
-
- _StatusBarStackEntry = collections.namedtuple("_StatusBarStackEntry",
- ("msg, duration, key"))
-
-
- class PersonalWikiFrame(wx.Frame, MiscEventSourceMixin):
- HOTKEY_ID_HIDESHOW_BYAPP = 1
- HOTKEY_ID_HIDESHOW_BYWIKI = 2
-
- ## @profile
- def __init__(self, parent, id, title, wikiAppDir, globalConfigDir,
- globalConfigSubDir, cmdLineAction):
- # Do not use member variables starting with "externalPlugin_"! They
- # are reserved for external plugins.
- wx.Frame.__init__(self, parent, -1, title, size = (700, 550),
- style=wx.DEFAULT_FRAME_STYLE|wx.NO_FULL_REPAINT_ON_RESIZE)
- MiscEventSourceMixin.__init__(self)
-
- if cmdLineAction.cmdLineError:
- cmdLineAction.showCmdLineUsage(self,
- _(u"Bad formatted command line.") + u"\n\n")
- self.Close()
- self.Destroy()
- return
-
- self.mainWindowConstructed = False
-
- # if not globalConfigDir or not exists(globalConfigDir):
- # self.displayErrorMessage(
- # u"Error initializing environment, couldn't locate "+
- # u"global config directory", u"Shutting Down")
- # self.Close()
-
-
- # initialize some variables
- self.globalConfigDir = globalConfigDir
- self.wikiAppDir = wikiAppDir
-
- self.globalConfigSubDir = globalConfigSubDir
-
- # TODO: Move to MainApp
- # Create the "[TextBlocks].wiki" file in the global config subdirectory
- # if the file doesn't exist yet.
- tbLoc = os.path.join(self.globalConfigSubDir, "[TextBlocks].wiki")
- if not os.path.exists(pathEnc(tbLoc)):
- writeEntireFile(tbLoc,
- """importance: high;a=[importance: high]\\n
- importance: low;a=[importance: low]\\n
- tree_position: 0;a=[tree_position: 0]\\n
- wrap: 80;a=[wrap: 80]\\n
- camelCaseWordsEnabled: false;a=[camelCaseWordsEnabled: false]\\n
- """, True)
- self.configuration = wx.GetApp().createCombinedConfiguration()
-
- # Listen to application events
- wx.GetApp().getMiscEvent().addListener(self)
-
- self.wikiPadHelp = os.path.join(self.wikiAppDir, 'WikidPadHelp',
- 'WikidPadHelp.wiki')
- self.windowLayouter = None # will be set by initializeGui()
-
- # defaults
- self.wikiData = None
- self.wikiDataManager = None
- self.lastCursorPositionInPage = {}
- self.wikiHistory = []
- self.nonModalFindDlg = None # Stores find&replace dialog, if present
- self.nonModalMainWwSearchDlg = None
- self.nonModalWwSearchDlgs = [] # Stores wiki wide search dialogs and detached fast search frames
- self.nonModalFileCleanupDlg = None # Stores file dialog FileCleanup.FileCleanupDialog
- self.spellChkDlg = None # Stores spell check dialog, if present
- self.printer = None # Stores Printer object (initialized on demand)
- self.continuousExporter = None # Exporter-derived object if continuous export is in effect
- self.statusBarStack = [] # Internal stack with statusbar information
-
- self.mainAreaPanel = None
- self.mainmenu = None
-
- self.recentWikisMenu = None
- self.recentWikisActivation = wxHelper.IdRecycler()
-
- self.textBlocksMenu = None
- self.textBlocksActivation = wxHelper.IdRecycler() # See self.fillTextBlocksMenu()
-
- self.favoriteWikisMenu = None
- self.favoriteWikisActivation = wxHelper.IdRecycler()
-
- self.pluginsMenu = None
- self.fastSearchField = None # Text field in toolbar
-
- self.cmdIdToIconNameForAttribute = None # Maps command id (=menu id) to icon name
- # needed for "Editor"->"Add icon attribute"
- self.cmdIdToColorNameForAttribute = None # Same for color names
-
- self.cmdIdToInsertString = None
-
- self.sleepMode = True
- self.eventRoundtrip = 0
-
- self.currentWikiDocumentProxyEvent = ProxyMiscEvent(self)
- self.currentWikiDocumentProxyEvent.addListener(self)
-
- self.configuration.setGlobalConfig(wx.GetApp().getGlobalConfig())
-
- # State here: Global configuration available
-
- self.loadFixedExtensions()
-
- self.nonCoreMenuItems = PWikiNonCore(self, self)
-
- # setup plugin manager and hooks API
- # dirs = ( os.path.join(self.globalConfigSubDir, u'user_extensions'),
- # os.path.join(self.wikiAppDir, u'user_extensions'),
- # os.path.join(self.wikiAppDir, u'extensions') )
- dirs = ( os.path.join(self.wikiAppDir, u'extensions'),
- os.path.join(self.wikiAppDir, u'user_extensions'),
- os.path.join(self.globalConfigSubDir, u'user_extensions') )
- self.pluginManager = PluginManager.PluginManager(dirs, systemDirIdx=0)
-
- # wx.GetApp().pauseBackgroundThreads()
-
- plm = self.pluginManager # Make it shorter
-
- pluginDummyFct = lambda module, *args, **kwargs: None
-
- self.hooks = PluginManager.PluginAPIAggregation(
- plm.registerSimplePluginAPI(("hooks", 2),
- ["startup", "newWiki", "createdWiki", "openWiki",
- "openedWiki", "openWikiWord", "newWikiWord",
- "openedWikiWord", "savingWikiWord", "savedWikiWord",
- "renamedWikiWord", "deletedWikiWord", "exit",
- "closingWiki", "droppingWiki", "closedWiki",
- "previewPageNavigation", "previewPageLoaded",
- ] ),
-
- plm.registerWrappedPluginAPI(("hooks", 1),
- startup=None, newWiki=None, createdWiki=None,
- openWiki=None, openedWiki=None, openWikiWord=None,
- newWikiWord=None, openedWikiWord=None, savingWikiWor=None,
- savedWikiWord=None, renamedWikiWord=None,
- deletedWikiWord=None, exit=None,
- closingWiki=pluginDummyFct, droppingWiki=pluginDummyFct,
- closedWiki=pluginDummyFct
- )
- )
-
- self.viPluginFunctions = plm.registerSimplePluginAPI(("ViFunctions",1),
- ("describeViFunctions",))
-
- # interfaces for menu and toolbar plugins
- self.menuFunctions = plm.registerSimplePluginAPI(("MenuFunctions",1),
- ("describeMenuItems",))
-
- self.toolbarFunctions = PluginManager.PluginAPIAggregation(
- plm.registerWrappedPluginAPI(("ToolbarFunctions",2),
- describeToolbarItems="describeToolbarItemsV02"),
- plm.registerSimplePluginAPI(("ToolbarFunctions",1),
- ("describeToolbarItems",))
- )
-
- del plm
-
- self.pluginManager.loadPlugins([ u'KeyBindings.py',
- u'EvalLibrary.py' ] )
-
-
- self.attributeChecker = AttributeHandling.AttributeChecker(self)
-
- # self.configuration.setGlobalConfig(wx.GetApp().getGlobalConfig())
-
- # State here: Plugins loaded
-
- # trigger hook
- self.hooks.startup(self)
-
- # wiki history
- history = self.configuration.get("main", "wiki_history")
- if history:
- self.wikiHistory = history.split(u";")
-
- # clipboard catcher
- if WindowsHacks is not None:
- self.clipboardInterceptor = WindowsHacks.ClipboardCatchIceptor(self)
- self.browserMoveInterceptor = WindowsHacks.BrowserMoveIceptor(self)
-
- self._interceptCollection = WindowsHacks.WinProcInterceptCollection(
- (self.clipboardInterceptor, self.browserMoveInterceptor))
- else:
- self.browserMoveInterceptor = None
- self.clipboardInterceptor = OsAbstract.createClipboardInterceptor(self)
- self._interceptCollection = OsAbstract.createInterceptCollection(
- (self.clipboardInterceptor,))
-
- if self._interceptCollection is not None:
- self._interceptCollection.start(self) # .GetHandle())
-
- # resize the window to the last position/size
- setWindowSize(self, (self.configuration.getint("main", "size_x", 200),
- self.configuration.getint("main", "size_y", 200)))
- setWindowPos(self, (self.configuration.getint("main", "pos_x", 10),
- self.configuration.getint("main", "pos_y", 10)))
-
- # Set the auto save timing
- self.autoSaveDelayAfterKeyPressed = self.configuration.getint(
- "main", "auto_save_delay_key_pressed")
- self.autoSaveDelayAfterDirty = self.configuration.getint(
- "main", "auto_save_delay_dirty")
-
- # get the position of the splitter
- self.lastSplitterPos = self.configuration.getint("main", "splitter_pos")
-
- # if a wiki to open wasn't passed in use the last_wiki from the global config
- self.cmdLineAction = cmdLineAction
- wikiToOpen = cmdLineAction.wikiToOpen
- wikiWordsToOpen = cmdLineAction.wikiWordsToOpen
- anchorToOpen = cmdLineAction.anchorToOpen
-
- if not wikiToOpen:
- wikiToOpen = self.configuration.get("main", "last_wiki")
-
- # Prepare accelerator translation before initializing GUI
- if self.configuration.getboolean("main", "menu_accels_kbdTranslate", False):
- self.translateMenuAccelerator = OsAbstract.translateAcceleratorByKbLayout
- else:
- self.translateMenuAccelerator = lambda x: x
-
- # initialize the GUI
- self.initializeGui()
-
- # Minimize on tray?
- self.tbIcon = None
- self.setShowOnTray()
-
- # windowmode: 0=normal, 1=maximized, 2=iconized, 3=maximized iconized(doesn't work)
- windowmode = self.configuration.getint("main", "windowmode")
-
- if windowmode & 1:
- self.Maximize(True)
- if windowmode & 2:
- self.Iconize(True)
-
- # Set app-bound hot key
- self.hotKeyDummyWindow = None
- self._refreshHotKeys()
-
- self.windowLayouter.layout()
-
- # State here: GUI construction finished, but frame is hidden yet
-
- # if a wiki to open is set, open it
- if wikiToOpen:
- if os.path.exists(pathEnc(wikiToOpen)):
- # tracer.runctx('self.openWiki(wikiToOpen, wikiWordsToOpen, anchorToOpen=anchorToOpen)', globals(), locals())
- self.openWiki(wikiToOpen, wikiWordsToOpen,
- anchorToOpen=anchorToOpen,
- lastTabsSubCtrls=cmdLineAction.lastTabsSubCtrls,
- activeTabNo=cmdLineAction.activeTabNo)
- # wx.GetApp().pauseBackgroundThreads()
- else:
- if cmdLineAction.wikiToOpen:
- cmdLineAction.showCmdLineUsage(self,
- _(u"Wiki doesn't exist: %s") % wikiToOpen + u"\n\n")
- self.Close()
- self.Destroy()
- return
-
- # self.statusBar.SetStatusText(
- # uniToGui(_(u"Last wiki doesn't exist: %s") % wikiToOpen), 0)
- self.displayErrorMessage(
- _(u"Wiki doesn't exist: %s") % wikiToOpen)
-
- # State here: Wiki opened (if possible), additional command line actions
- # not done yet.
-
- if cmdLineAction.rebuild == cmdLineAction.NOT_SET and \
- self.isWikiLoaded():
- cmdLineAction.rebuild = self.getConfig().getint("main",
- "wiki_onOpen_rebuild", 0)
-
- cmdLineAction.actionBeforeShow(self)
-
- if cmdLineAction.exitFinally:
- self.exitWiki()
- return
-
- self.userActionCoord = UserActionCoord(self)
- self.userActionCoord.applyConfiguration()
-
- self.Show(True)
-
- EVT_REMOTE_COMMAND(self, self.OnRemoteCommand)
-
- # Inform that idle handlers and window-specific threads can now be started
- self.mainWindowConstructed = True
- self.fireMiscEventKeys(("constructed main window",))
-
- # finally:
- # wx.GetApp().resumeBackgroundThreads()
-
-
- def loadFixedExtensions(self):
- # self.wikidPadHooks = self.getExtension('WikidPadHooks', u'WikidPadHooks.py')
- self.keyBindings = KeyBindingsCache(
- self.getExtension('KeyBindings', u'KeyBindings.py'))
- self.evalLib = self.getExtension('EvalLibrary', u'EvalLibrary.py')
- self.presentationExt = self.getExtension('Presentation', u'Presentation.py')
-
-
- def getExtension(self, extensionName, fileName):
- extensionFileName = os.path.join(self.globalConfigSubDir,
- u'user_extensions', fileName)
- if os.path.exists(pathEnc(extensionFileName)):
- userUserExtension = loadEntireFile(extensionFileName, True)
- else:
- userUserExtension = None
-
- extensionFileName = os.path.join(self.wikiAppDir, 'user_extensions',
- fileName)
- if os.path.exists(pathEnc(extensionFileName)):
- userExtension = loadEntireFile(extensionFileName, True)
- else:
- userExtension = None
-
- extensionFileName = os.path.join(self.wikiAppDir, 'extensions', fileName)
- systemExtension = loadEntireFile(extensionFileName, True)
-
- return importCode(systemExtension, userExtension, userUserExtension,
- extensionName)
-
-
- def getCurrentWikiWord(self):
- docPage = self.getCurrentDocPage()
- if docPage is None or not isinstance(docPage,
- (DocPages.WikiPage, DocPages.AliasWikiPage)):
- return None
- return docPage.getWikiWord()
-
- def getCurrentDocPage(self):
- if self.getCurrentDocPagePresenter() is None:
- return None
- return self.getCurrentDocPagePresenter().getDocPage()
-
- def getActiveEditor(self):
- if self.getCurrentDocPagePresenter() is None:
- return None
- return self.getCurrentDocPagePresenter().getSubControl("textedit")
-
- def getMainAreaPanel(self):
- return self.mainAreaPanel
-
- def isMainWindowConstructed(self):
- return self.mainWindowConstructed
-
- def getCurrentDocPagePresenter(self):
- """
- Convenience function. If main area's current presenter is not a
- doc page presenter, None is returned.
- """
- if self.mainAreaPanel is None:
- return None
-
- presenter = self.mainAreaPanel.getCurrentPresenter()
-
- if not isinstance(presenter, DocPagePresenter):
- return None
-
- return presenter
-
- def getCurrentPresenterProxyEvent(self):
- """
- This ProxyMiscEvent resends any messsages from the currently
- active DocPagePresenter
- """
- return self.mainAreaPanel.getCurrentPresenterProxyEvent()
-
- def getCurrentWikiDocumentProxyEvent(self):
- """
- This ProxyMiscEvent resends any messsages from the currently
- active WikiDocument
- """
- return self.currentWikiDocumentProxyEvent
-
- def getWikiData(self):
- if self.wikiDataManager is None:
- return None
-
- return self.wikiDataManager.getWikiData()
-
- def getWikiDataManager(self):
- """
- Deprecated, use getWikiDocument() instead
- """
- return self.wikiDataManager
-
- def getWikiDocument(self):
- return self.wikiDataManager
-
- def isWikiLoaded(self):
- return self.getWikiDocument() is not None
-
- def getWikiConfigPath(self):
- if self.wikiDataManager is None:
- return None
-
- return self.wikiDataManager.getWikiConfigPath()
-
- def getWikiDefaultWikiLanguage(self):
- if self.wikiDataManager is None:
- # No wiki loaded, so take users default
- return wx.GetApp().getUserDefaultWikiLanguage()
-
- return self.wikiDataManager.getWikiDefaultWikiLanguage()
-
- def getCmdLineAction(self):
- return self.cmdLineAction
-
- # def getUserDefaultWikiLanguage(self):
- # """
- # Returns the internal name of the default wiki language of the user.
- # """
- # return wx.GetApp().getUserDefaultWikiLanguage()
-
- def getConfig(self):
- return self.configuration
-
- def getPresentationExt(self):
- return self.presentationExt
-
- def getCollator(self):
- return wx.GetApp().getCollator()
-
- def getLogWindow(self):
- return self.logWindow
-
- def getKeyBindings(self):
- return self.keyBindings
-
- def getClipboardInterceptor(self):
- return self.clipboardInterceptor
-
- def getUserActionCoord(self):
- return self.userActionCoord
-
- def lookupIcon(self, iconname):
- """
- Returns the bitmap object for the given iconname.
- If the bitmap wasn't cached already, it is loaded and created.
- If icon is unknown, None is returned.
- """
- return wx.GetApp().getIconCache().lookupIcon(iconname)
-
- def lookupSystemIcon(self, iconname):
- """
- Returns the bitmap object for the given iconname.
- If the bitmap wasn't cached already, it is loaded and created.
- If icon is unknown, an error message is shown and an empty
- black bitmap is returned.
- """
- icon = wx.GetApp().getIconCache().lookupIcon(iconname)
- if icon is None:
- icon = wx.EmptyBitmap(16, 16)
- self.displayErrorMessage(_(u'Error, icon "%s" missing.' % iconname))
-
- return icon
-
-
- def lookupIconIndex(self, iconname):
- """
- Returns the id number into self.iconImageList of the requested icon.
- If icon is unknown, -1 is returned.
- """
- return wx.GetApp().getIconCache().lookupIconIndex(iconname)
-
-
- def resolveIconDescriptor(self, desc, default=None):
- """
- Used for plugins of type "MenuFunctions" or "ToolbarFunctions".
- Tries to find and return an appropriate wx.Bitmap object.
-
- An icon descriptor can be one of the following:
- - None
- - a wx.Bitmap object
- - the filename of a bitmap
- - a tuple of filenames, first existing file is used
-
- If no bitmap can be found, default is returned instead.
- """
- return wx.GetApp().getIconCache().resolveIconDescriptor(desc, default)
-
-
- def _OnRoundtripEvent(self, evt):
- """
- Special event handler for events which must be handled by the
- window which has currently the focus (e.g. "copy to clipboard" which
- must be done by either editor or HTML preview).
-
- These events are sent further to the currently focused window.
- If they are not consumed they go up to the parent window until
- they are here again (make a "roundtrip").
- This function also avoids an infinite loop of such events.
- """
- target = None
-
- if self.eventRoundtrip < 1:
- # First try: Focused window
- target = wx.Window.FindFocus()
-
- if target is None and self.eventRoundtrip < 2:
- # Second try: Active DocPagePresenter
- presenter = self.getCurrentDocPagePresenter()
- if presenter is not None:
- subCtl = presenter.getCurrentSubControl()
- if subCtl is not None:
- target = subCtl
- else:
- target = presenter
-
- if target is wx.Window.FindFocus():
- # No double-check if first try is equal second try
- target = None
-
- if target is None:
- return
-
- self.eventRoundtrip += 1
- try:
- target.ProcessEvent(evt)
- finally:
- self.eventRoundtrip -= 1
-
-
- def getPageHistoryDeepness(self):
- """
- Convenience method to call PageHistory.getDeepness() for current
- presenter.
- Returns tuple (back, forth) where back is the maximum number of steps
- to go backward in history, forth the max. number to go forward
- """
- dpp = self.getCurrentDocPagePresenter()
- if dpp is None:
- return (0, 0)
-
- return dpp.getPageHistory().getDeepness()
-
-
- def _OnEventToCurrentDocPPresenter(self, evt):
- """
- wx events which should be sent to current doc page presenter
- """
- # Check for infinite loop
- if self.eventRoundtrip > 0:
- return
-
- dpp = self.getCurrentDocPagePresenter()
- if dpp is None:
- return
-
- self.eventRoundtrip += 1
- try:
- dpp.ProcessEvent(evt)
- finally:
- self.eventRoundtrip -= 1
-
-
- def addMenuItem(self, menu, label, hint, evtfct=None, icondesc=None,
- menuID=None, updatefct=None, kind=wx.ITEM_NORMAL):
- if menuID is None:
- menuID = wx.NewId()
-
- if kind is None:
- kind = wx.ITEM_NORMAL
-
- lcut = label.split(u"\t", 1)
- if len(lcut) > 1:
- lcut[1] = self.translateMenuAccelerator(lcut[1])
- label = lcut[0] + u" \t" + lcut[1]
-
-
- menuitem = wx.MenuItem(menu, menuID, label + u" ", hint, kind)
- bitmap = self.resolveIconDescriptor(icondesc)
- if bitmap:
- menuitem.SetBitmap(bitmap)
-
- menu.AppendItem(menuitem)
- if evtfct is not None:
- wx.EVT_MENU(self, menuID, evtfct)
-
- if updatefct is not None:
- if isinstance(updatefct, tuple):
- updatefct = _buildChainedUpdateEventFct(updatefct)
- wx.EVT_UPDATE_UI(self, menuID, updatefct)
-
- return menuitem
-
-
- def addMenuItemByInternalDescriptor(self, menu, desc):
- if desc is None:
- return
-
- def internalAddMenuItem(function, label, statustext, shortcut=None,
- icondesc=None, menuID=None, updateFunction=None, kind=None,
- *dummy):
- """
- Compared to fillPluginsMenu() this variant supports tuples as
- update function but no auto-created submenus
- (by using '|' in item name).
- It expects an optional shortcut string before icon description
- instead of appending the shortcut with '\t' to label
-
- Furthermore it doesn't send self as additional parameter when
- menu item is called or updated.
- """
- if shortcut is not None:
- label += '\t' + shortcut
-
- self.addMenuItem(menu, label, statustext,
- function, icondesc, menuID, updateFunction, kind)
-
- internalAddMenuItem(*desc)
-
-
- def addMenuItemByUnifNameTable(self, menu, unifNameTable):
- for unifName in unifNameTable.split("\n"):
- unifName = unifName.strip()
- if unifName == "":
- continue
-
- self.addMenuItemByInternalDescriptor(menu,
- self.nonCoreMenuItems.getDescriptorFor(unifName))
-
-
-
- def buildWikiMenu(self):
- """
- Builds the first, the "Wiki" menu and returns it
- """
- wikiData = self.getWikiData()
- wikiMenu = wx.Menu()
-
- self.addMenuItem(wikiMenu, _(u'&New') + u'\t' + self.keyBindings.NewWiki,
- _(u'Create new wiki'), self.OnWikiNew)
-
- openWikiMenu = wx.Menu()
- wikiMenu.AppendMenu(wx.NewId(), _(u'&Open'), openWikiMenu)
-
- self.addMenuItem(openWikiMenu, _(u'In &This Window...') + u'\t' +
- self.keyBindings.OpenWiki,
- _(u'Open wiki in this window'), self.OnWikiOpen)
-
- self.addMenuItem(openWikiMenu, _(u'In &New Window...') + u'\t' +
- self.keyBindings.OpenWikiNewWindow,
- _(u'Open wiki in a new window'), self.OnWikiOpenNewWindow)
-
- self.addMenuItem(openWikiMenu, _(u'&Current in New Window') + u'\t' +
- self.keyBindings.CloneWindow,
- _(u'Create new window for same wiki'), self.OnCmdCloneWindow)
-
- wikiMenu.AppendSeparator()
-
- self.recentWikisMenu = wx.Menu()
- wikiMenu.AppendMenu(wx.NewId(), _(u'&Recent'), self.recentWikisMenu)
-
- self.rereadRecentWikis()
-
-
- self.favoriteWikisMenu = wx.Menu() # TODO: Try to avoid rebuilding it each time wiki menu is recreated
- self.fillFavoriteWikisMenu(self.favoriteWikisMenu)
- wikiMenu.AppendMenu(wx.NewId(), _(u"F&avorites"), self.favoriteWikisMenu)
-
-
- if wikiData is not None:
- wikiMenu.AppendSeparator()
-
- self.addMenuItem(wikiMenu, _(u'&Search Wiki...') + u'\t' +
- self.keyBindings.SearchWiki, _(u'Search whole wiki'),
- lambda evt: self.showSearchDialog(), "tb_lens")
-
-
- wikiMenu.AppendSeparator()
-
- if wikiData is not None:
- exportWikisMenu = wx.Menu()
- wikiMenu.AppendMenu(wx.NewId(), _(u'Publish as HTML'), exportWikisMenu)
-
- self.addMenuItem(exportWikisMenu,
- _(u'Wiki as Single HTML Page'),
- _(u'Publish Wiki as Single HTML Page'), self.OnExportWiki,
- menuID=GUI_ID.MENU_EXPORT_WHOLE_AS_PAGE)
-
- self.addMenuItem(exportWikisMenu,
- _(u'Wiki as Set of HTML Pages'),
- _(u'Publish Wiki as Set of HTML Pages'), self.OnExportWiki,
- menuID=GUI_ID.MENU_EXPORT_WHOLE_AS_PAGES)
-
- self.addMenuItem(exportWikisMenu,
- _(u'Current Wiki Word as HTML Page'),
- _(u'Publish Current Wiki Word as HTML Page'), self.OnExportWiki,
- menuID=GUI_ID.MENU_EXPORT_WORD_AS_PAGE)
-
- self.addMenuItem(exportWikisMenu,
- _(u'Sub-Tree as Single HTML Page'),
- _(u'Publish Sub-Tree as Single HTML Page'), self.OnExportWiki,
- menuID=GUI_ID.MENU_EXPORT_SUB_AS_PAGE)
-
- self.addMenuItem(exportWikisMenu,
- _(u'Sub-Tree as Set of HTML Pages'),
- _(u'Publish Sub-Tree as Set of HTML Pages'), self.OnExportWiki,
- menuID=GUI_ID.MENU_EXPORT_SUB_AS_PAGES)
-
- # self.addMenuItem(exportWikisMenu,
- # _(u'Export Wiki to .wiki files'),
- # _(u'Export Wiki to .wiki files in UTF-8'), self.OnExportWiki,
- # menuID=GUI_ID.MENU_EXPORT_WHOLE_AS_RAW)
-
- self.addMenuItem(exportWikisMenu, _(u'Other Export...'),
- _(u'Open general export dialog'), self.OnCmdExportDialog)
-
-
- # if wikiData is not None:
- self.addMenuItem(wikiMenu, _(u'Print...') + u'\t' + self.keyBindings.Print,
- _(u'Show the print dialog'), self.OnShowPrintMainDialog)
-
- self.addMenuItemByUnifNameTable(wikiMenu,
- """
- menuItem/mainControl/builtin/openTrashcan
- """
- )
-
- wikiMenu.AppendSeparator()
-
- self.addMenuItem(wikiMenu, _(u'&Properties...'),
- _(u'Show general information about current wiki'),
- self.OnShowWikiPropertiesDialog)
-
- maintenanceMenu = wx.Menu()
- wikiMenu.AppendMenu(wx.NewId(), _(u'Maintenance'), maintenanceMenu)
-
- if wikiData is not None:
- if wikiData.checkCapability("rebuild") == 1:
- if wikiData.checkCapability("filePerPage") == 1:
- self.addMenuItem(maintenanceMenu,
- _(u'Update ext. modif. wiki files'),
- _(u'Check for externally modified files and '
- u'update cache in background'),
- self.OnCmdUpdateExternallyModFiles,
- menuID=GUI_ID.CMD_UPDATE_EXTERNALLY_MOD_FILES_WIKI,
- updatefct=(self.OnUpdateDisReadOnlyWiki,))
-
- self.addMenuItem(maintenanceMenu, _(u'&Rebuild Wiki...'),
- _(u'Rebuild this wiki and its cache completely'),
- lambda evt: self.rebuildWiki(onlyDirty=False),
- menuID=GUI_ID.MENU_REBUILD_WIKI,
- updatefct=(self.OnUpdateDisReadOnlyWiki,))
-
- self.addMenuItem(maintenanceMenu, _(u'&Update cache...'),
- _(u'Update cache where marked as not up to date'),
- lambda evt: self.rebuildWiki(onlyDirty=True),
- menuID=GUI_ID.MENU_UPDATE_WIKI_CACHE,
- updatefct=(self.OnUpdateDisReadOnlyWiki,))
-
- self.addMenuItem(maintenanceMenu, _(u'&Initiate update...'),
- _(u'Initiate full cache update which is done mainly '
- u'in background'),
- lambda evt: self.initiateFullUpdate(),
- menuID=GUI_ID.MENU_INITATE_UPDATE_WIKI_CACHE,
- updatefct=(self.OnUpdateDisReadOnlyWiki,))
-
- self.addMenuItemByUnifNameTable(maintenanceMenu,
- """
- menuItem/mainControl/builtin/showFileCleanupDialog
- """
- )
-
- # TODO: Test for wikiDocument.isSearchIndexEnabled()
- # self.addMenuItem(maintenanceMenu, _(u'Re&index Wiki...'),
- # _(u'Rebuild the reverse index for fulltext search'),
- # lambda evt: self.rebuildSearchIndex(onlyDirty=False),
- # menuID=GUI_ID.MENU_REINDEX_REV_SEARCH,
- # updatefct=self.OnUpdateDisReadOnlyWiki)
-
-
- self.addMenuItem(maintenanceMenu, _(u'Show job count...'),
- _(u'Show how many update jobs are waiting in background'),
- self.OnCmdShowWikiJobDialog)
-
- maintenanceMenu.AppendSeparator()
-
-
- self.addMenuItem(maintenanceMenu, _(u'Open as &Type...'),
- _(u'Open wiki with a specified wiki database type'),
- self.OnWikiOpenAsType)
-
- if wikiData is not None:
- self.addMenuItem(maintenanceMenu, _(u'Reconnect...'),
- _(u'Reconnect to database after connection failure'),
- self.OnCmdReconnectDatabase)
-
- maintenanceMenu.AppendSeparator()
-
- if wikiData.checkCapability("compactify") == 1:
- self.addMenuItem(maintenanceMenu, _(u'&Optimise Database'),
- _(u'Free unused space in database'),
- lambda evt: self.vacuumWiki(),
- menuID=GUI_ID.MENU_VACUUM_WIKI,
- updatefct=(self.OnUpdateDisReadOnlyWiki,))
-
-
- if wikiData.checkCapability("plain text import") == 1:
- self.addMenuItem(maintenanceMenu, _(u'&Copy .wiki files to database'),
- _(u'Copy .wiki files to database'),
- self.OnImportFromPagefiles,
- updatefct=(self.OnUpdateDisReadOnlyWiki,))
-
-
- self.addMenuItemByUnifNameTable(maintenanceMenu,
- """
- menuItem/mainControl/builtin/recoverWikiDatabase
- """
- )
-
-
- wikiMenu.AppendSeparator() # TODO May have two separators without anything between
-
- # self.addMenuItem(wikiMenu, '&Test', 'Test', lambda evt: self.testIt())
-
- menuID=wx.NewId()
- wikiMenu.Append(menuID, _(u'E&xit'), _(u'Exit'))
- wx.EVT_MENU(self, menuID, lambda evt: self.exitWiki())
- wx.App.SetMacExitMenuItemId(menuID)
-
- return wikiMenu
-
- # if wikiData is not None and wikiData.checkCapability("versioning") == 1:
- # wikiMenu.AppendSeparator()
- #
- # # menuID=wx.NewId()
- # # wikiMenu.Append(menuID, '&Store version', 'Store new version')
- # # wx.EVT_MENU(self, menuID, lambda evt: self.showStoreVersionDialog())
- #
- # menuID=wx.NewId()
- # wikiMenu.Append(menuID, _(u'&Retrieve version'),
- # _(u'Retrieve previous version'))
- # wx.EVT_MENU(self, menuID, lambda evt: self.showSavedVersionsDialog())
- #
- # menuID=wx.NewId()
- # wikiMenu.Append(menuID, _(u'Delete &All Versions'),
- # _(u'Delete all stored versions'))
- # wx.EVT_MENU(self, menuID, lambda evt: self.showDeleteAllVersionsDialog())
-
-
-
- def fillPluginsMenu(self, pluginMenu):
- """
- Builds or rebuilds the plugin menu. This function does no id reuse
- so it shouldn't be called too often (mainly on start and when
- rebuilding menu during development of plugins)
-
- pluginMenu -- An empty wx.Menu to add items to
- """
- # pluginMenu = None
- # get info for any plugin menu items and create them as necessary
- menuItems = reduce(lambda a, b: a+list(b),
- self.menuFunctions.describeMenuItems(self), [])
-
- subStructure = {}
-
- if len(menuItems) > 0:
- def addPluginMenuItem(function, label, statustext, icondesc=None,
- menuID=None, updateFunction=None, kind=None, *dummy):
-
- labelComponents = label.split(u"|")
-
- sub = subStructure
- menu = pluginMenu
-
- for comp in labelComponents[:-1]:
- newMenu, newSub = sub.get(comp, (None, None))
- if newMenu is None:
- newMenu = wx.Menu()
- menu.AppendMenu(-1, comp, newMenu)
- newSub = {}
- sub[comp] = newMenu, newSub
-
- menu = newMenu
- sub = newSub
-
- if updateFunction is not None:
- updateFct = lambda evt: updateFunction(self, evt)
- else:
- updateFct = None
-
- self.addMenuItem(menu, labelComponents[-1], statustext,
- lambda evt: function(self, evt), icondesc, menuID,
- updateFct, kind)
-
- for item in menuItems:
- addPluginMenuItem(*item)
-
-
- def fillRecentWikisMenu(self, menu):
- """
- Refreshes the list of recent wiki menus from self.wikiHistory
- """
- idRecycler = self.recentWikisActivation
- idRecycler.clearAssoc()
-
- # Add new items
- for wiki in self.wikiHistory:
- menuID, reused = idRecycler.assocGetIdAndReused(wiki)
-
- if not reused:
- # For a new id, an event must be set
- wx.EVT_MENU(self, menuID, self.OnRecentWikiUsed)
-
- menu.Append(menuID, uniToGui(wiki))
-
-
- def OnRecentWikiUsed(self, evt):
- entry = self.recentWikisActivation.get(evt.GetId())
-
- if entry is None:
- return
-
- self.openWiki(entry)
-
-
- def rereadRecentWikis(self):
- """
- Starts rereading and rebuilding of the recent wikis submenu
- """
- if self.recentWikisMenu is None:
- return
-
- history = self.configuration.get("main", "wiki_history")
- if not history:
- return
-
- self.wikiHistory = history.split(u";")
-
- maxLen = self.configuration.getint(
- "main", "recentWikisList_length", 5)
- if len(self.wikiHistory) > maxLen:
- self.wikiHistory = self.wikiHistory[:maxLen]
-
- clearMenu(self.recentWikisMenu)
- self.fillRecentWikisMenu(self.recentWikisMenu)
-
-
- def informRecentWikisChanged(self):
- if self.getCmdLineAction().noRecent:
- return
-
- self.configuration.set("main", "wiki_history",
- ";".join(self.wikiHistory))
- wx.GetApp().fireMiscEventKeys(
- ("reread recent wikis needed",))
-
- def fillTextBlocksMenu(self, menu):
- """
- Constructs the text blocks menu submenu and necessary subsubmenus.
- If this is called more than once, previously used menu ids are reused
- for the new menu.
-
- menu -- An empty wx.Menu to add items and submenus to
- """
- # Clear IdRecycler
- self.textBlocksActivation.clearAssoc()
-
-
- wikiDoc = self.getWikiDocument()
- if wikiDoc is not None and self.requireReadAccess():
- try:
- page = wikiDoc.getFuncPage(u"wiki/TextBlocks")
- treeData = TextTree.buildTreeFromText(page.getContent(),
- TextTree.TextBlocksEntry.factory)
- TextTree.addTreeToMenu(treeData,
- menu, self.textBlocksActivation, self,
- self.OnTextBlockUsed)
- menu.AppendSeparator()
-
- except DbReadAccessError, e:
- self.lostReadAccess(e)
- traceback.print_exc()
-
-
- page = WikiDataManager.getGlobalFuncPage(u"global/TextBlocks")
- treeData = TextTree.buildTreeFromText(page.getContent(),
- TextTree.TextBlocksEntry.factory)
- TextTree.addTreeToMenu(treeData,
- menu, self.textBlocksActivation, self,
- self.OnTextBlockUsed)
-
- menu.AppendSeparator()
- menu.Append(GUI_ID.CMD_REREAD_TEXT_BLOCKS,
- _(u"Reread text blocks"),
- _(u"Reread the text block file(s) and recreate menu"))
- wx.EVT_MENU(self, GUI_ID.CMD_REREAD_TEXT_BLOCKS, self.OnRereadTextBlocks)
-
-
- def OnTextBlockUsed(self, evt):
- if self.isReadOnlyPage():
- return
-
- entry = self.textBlocksActivation.get(evt.GetId())
-
- if entry is None:
- return
-
- if u"a" in entry.flags:
- self.appendText(entry.value)
- else:
- self.addText(entry.value, replaceSel=True)
-
-
-
- def OnRereadTextBlocks(self, evt):
- self.rereadTextBlocks()
-
-
- def rereadTextBlocks(self):
- """
- Starts rereading and rebuilding of the text blocks submenu
- """
- if self.textBlocksMenu is None:
- return
-
- clearMenu(self.textBlocksMenu)
- self.fillTextBlocksMenu(self.textBlocksMenu)
-
-
- def fillFavoriteWikisMenu(self, menu):
- """
- Constructs the favorite wikis menu and necessary submenus.
- If this is called more than once, previously used menu ids are reused
- for the new menu.
-
- menu -- An empty wx.Menu to add items and submenus to
- """
- self.favoriteWikisActivation.clearAssoc()
-
- page = WikiDataManager.getGlobalFuncPage(u"global/FavoriteWikis")
- treeData = TextTree.buildTreeFromText(page.getContent(),
- TextTree.FavoriteWikisEntry.factory)
- TextTree.addTreeToMenu(treeData,
- menu, self.favoriteWikisActivation, self,
- self.OnFavoriteWikiUsed)
-
- menu.AppendSeparator()
- menu.Append(GUI_ID.CMD_ADD_CURRENT_WIKI_TO_FAVORITES,
- _(u"Add wiki"),
- _(u"Add a wiki to the favorites"))
- wx.EVT_MENU(self, GUI_ID.CMD_ADD_CURRENT_WIKI_TO_FAVORITES,
- self.OnAddToFavoriteWikis)
-
- menu.Append(GUI_ID.CMD_MANAGE_FAVORITE_WIKIS,
- _(u"Manage favorites"),
- _(u"Manage favorites"))
- wx.EVT_MENU(self, GUI_ID.CMD_MANAGE_FAVORITE_WIKIS,
- self.OnManageFavoriteWikis)
-
-
- def OnFavoriteWikiUsed(self, evt):
- try:
- entry = self.favoriteWikisActivation.get(evt.GetId())
-
- if entry is None:
- return
-
- if u"f" in entry.flags:
- # Try to focus already open frame
- frame = wx.GetApp().findFrameByWikiConfigPath(entry.value)
- if frame:
- if frame.IsIconized():
- frame.Iconize(False)
- frame.Raise()
- frame.SetFocus()
- return
-
- if u"n" in entry.flags:
- # Open in new frame
- try:
- clAction = CmdLineAction([])
- clAction.inheritFrom(self.getCmdLineAction())
- clAction.setWikiToOpen(entry.value)
- clAction.frameToOpen = 1 # Open in new frame
- wx.GetApp().startPersonalWikiFrame(clAction)
- except Exception, e:
- traceback.print_exc()
- self.displayErrorMessage(_(u'Error while starting new '
- u'WikidPad instance'), e)
- return
- else:
- # Open in same frame
- if entry.value.startswith(u"wiki:"):
- # Handle an URL
- filePath, wikiWordToOpen, anchorToOpen = \
- StringOps.wikiUrlToPathWordAndAnchor(entry.value)
- if os.path.exists(pathEnc(filePath)):
- self.openWiki(filePath, wikiWordsToOpen=(wikiWordToOpen,),
- anchorToOpen=anchorToOpen)
- else:
- self.displayErrorMessage(
- _(u"Wiki doesn't exist: %s") % filePath)
- else:
- self.openWiki(os.path.abspath(entry.value))
-
- except KeyError:
- pass
-
-
- def rereadFavoriteWikis(self):
- if self.favoriteWikisMenu is None:
- return
-
- clearMenu(self.favoriteWikisMenu)
- self.fillFavoriteWikisMenu(self.favoriteWikisMenu)
-
- # Update also toolbar by recreating
- if self.getShowToolbar():
- self.Freeze()
- try:
- self.setShowToolbar(False)
- self.setShowToolbar(True)
- finally:
- self.Thaw()
-
-
- def OnAddToFavoriteWikis(self,evt):
- document = self.getWikiDocument()
- if document is None:
- path = u""
- title = u""
- else:
- path = document.getWikiConfigPath()
- title = document.getWikiName()
-
- entry = TextTree.FavoriteWikisEntry(title, u"", u"",
- self._getStorableWikiPath(path))
- entry = TextTree.AddWikiToFavoriteWikisDialog.runModal(self, -1, entry)
-
- if entry is not None:
- page = WikiDataManager.getGlobalFuncPage(u"global/FavoriteWikis")
- text = page.getLiveText()
- if len(text) == 0 or text[-1] == u"\n":
- page.appendLiveText(entry.getTextLine() + u"\n")
- else:
- page.appendLiveText(u"\n" + entry.getTextLine() + u"\n")
-
- self.saveDocPage(page)
-
-
- def OnManageFavoriteWikis(self, evt):
- self.activatePageByUnifiedName(u"global/FavoriteWikis", tabMode=2)
-
-
- def OnInsertStringFromDict(self, evt):
- if self.isReadOnlyPage():
- return
-
- self.getActiveEditor().AddText(self.cmdIdToInsertString[evt.GetId()])
-
-
- def OnInsertIconAttribute(self, evt):
- if self.isReadOnlyPage():
- return
-
- self.insertAttribute("icon", self.cmdIdToIconNameForAttribute[evt.GetId()])
-
-
- def OnInsertColorAttribute(self, evt):
- if self.isReadOnlyPage():
- return
-
- self.insertAttribute("color", self.cmdIdToColorNameForAttribute[evt.GetId()])
-
-
- def resetCommanding(self):
- """
- Reset the "commanding" (meaning menus, toolbar(s), shortcuts)
- """
- self.buildMainMenu()
-
- # Update toolbar by recreating
- if self.getShowToolbar():
- with WindowUpdateLocker(self):
- self.setShowToolbar(False)
- self.setShowToolbar(True)
-
-
- def buildMainMenu(self):
- # ------------------------------------------------------------------------------------
- # Set up menu bar for the program.
- # ------------------------------------------------------------------------------------
- if self.mainmenu is not None:
- # This is a rebuild of an existing menu (after loading a new wikiData)
- self.mainmenu.Replace(0, self.buildWikiMenu(), _(u'W&iki'))
- return
-
-
- self.mainmenu = wx.MenuBar() # Create menu bar.
-
- wikiMenu = self.buildWikiMenu()
-
-
- editMenu = wx.Menu()
-
- self.addMenuItem(editMenu, _(u'&Undo') + u'\t' + self.keyBindings.Undo,
- _(u'Undo'), self._OnRoundtripEvent, menuID=GUI_ID.CMD_UNDO,
- updatefct=(self.OnUpdateDisReadOnlyPage, self.OnUpdateDisNotTextedit))
-
- self.addMenuItem(editMenu, _(u'&Redo') + u'\t' + self.keyBindings.Redo,
- _(u'Redo'), self._OnRoundtripEvent, menuID=GUI_ID.CMD_REDO,
- updatefct=(self.OnUpdateDisReadOnlyPage, self.OnUpdateDisNotTextedit))
-
- editMenu.AppendSeparator()
-
- # TODO: Incremental search
-
- self.addMenuItem(editMenu, _(u'&Search and Replace...') + u'\t' +
- self.keyBindings.FindAndReplace,
- _(u'Search and replace inside current page'),
- lambda evt: self.showSearchReplaceDialog(),
- updatefct=(self.OnUpdateDisNotTextedit,))
-
- editMenu.AppendSeparator()
-
- self.addMenuItem(editMenu, …
Large files files are truncated, but you can click here to view the full file