PageRenderTime 47ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/pwiki/PersonalWikiFrame.py

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