PageRenderTime 88ms CodeModel.GetById 42ms RepoModel.GetById 0ms app.codeStats 1ms

/lib/pwiki/WikiTxtCtrl.py

https://bitbucket.org/xkjq/wikidpad_svn
Python | 7961 lines | 7593 code | 196 blank | 172 comment | 14 complexity | f4e308862a3cff5d0fbdfcda1e526217 MD5 | raw file
Possible License(s): LGPL-2.1

Large files files are truncated, but you can click here to view the full file

  1. from __future__ import with_statement
  2. ## import hotshot
  3. ## _prof = hotshot.Profile("hotshot.prf")
  4. import pdb
  5. import traceback, codecs
  6. from cStringIO import StringIO
  7. import string, itertools, contextlib
  8. import re # import pwiki.srePersistent as re
  9. import threading
  10. import subprocess
  11. import textwrap
  12. from os.path import exists, dirname, isfile, isdir, join, basename
  13. from os import rename, unlink, listdir
  14. from time import time, sleep
  15. import wx, wx.stc
  16. from Consts import FormatTypes
  17. from .Utilities import DUMBTHREADSTOP, callInMainThread, ThreadHolder, \
  18. calcResizeArIntoBoundingBox, DictFromFields
  19. from .wxHelper import GUI_ID, getTextFromClipboard, copyTextToClipboard, \
  20. wxKeyFunctionSink, getAccelPairFromKeyDown, appendToMenuByMenuDesc
  21. from . import wxHelper
  22. from . import OsAbstract
  23. from .WikiExceptions import *
  24. from .SystemInfo import isUnicode, isOSX, isLinux, isWindows
  25. from .ParseUtilities import getFootnoteAnchorDict
  26. from .EnhancedScintillaControl import StyleCollector
  27. from .SearchableScintillaControl import SearchableScintillaControl
  28. from . import Configuration
  29. from . import AdditionalDialogs
  30. from . import WikiTxtDialogs
  31. # image stuff
  32. import imghdr
  33. # import WikiFormatting
  34. from . import DocPages
  35. from . import UserActionCoord, WindowLayout
  36. from .SearchAndReplace import SearchReplaceOperation
  37. from . import StringOps
  38. from . import SpellChecker
  39. # from StringOps import * # TODO Remove this
  40. # mbcsDec, uniToGui, guiToUni, \
  41. # wikiWordToLabel, revStr, lineendToInternal, lineendToOs
  42. # NOTE: TEMPORY
  43. import inspect
  44. from ViHelper import ViHintDialog, ViHelper
  45. from collections import defaultdict
  46. try:
  47. import WindowsHacks
  48. except:
  49. if isWindows():
  50. traceback.print_exc()
  51. WindowsHacks = None
  52. # Python compiler flag for float division
  53. CO_FUTURE_DIVISION = 0x2000
  54. class WikiTxtCtrl(SearchableScintillaControl):
  55. NUMBER_MARGIN = 0
  56. FOLD_MARGIN = 2
  57. SELECT_MARGIN = 1
  58. # Not the best of all possible solutions
  59. SUGGESTION_CMD_IDS = [GUI_ID.CMD_REPLACE_THIS_SPELLING_WITH_SUGGESTION_0,
  60. GUI_ID.CMD_REPLACE_THIS_SPELLING_WITH_SUGGESTION_1,
  61. GUI_ID.CMD_REPLACE_THIS_SPELLING_WITH_SUGGESTION_2,
  62. GUI_ID.CMD_REPLACE_THIS_SPELLING_WITH_SUGGESTION_3,
  63. GUI_ID.CMD_REPLACE_THIS_SPELLING_WITH_SUGGESTION_4,
  64. GUI_ID.CMD_REPLACE_THIS_SPELLING_WITH_SUGGESTION_5,
  65. GUI_ID.CMD_REPLACE_THIS_SPELLING_WITH_SUGGESTION_6,
  66. GUI_ID.CMD_REPLACE_THIS_SPELLING_WITH_SUGGESTION_7,
  67. GUI_ID.CMD_REPLACE_THIS_SPELLING_WITH_SUGGESTION_8,
  68. GUI_ID.CMD_REPLACE_THIS_SPELLING_WITH_SUGGESTION_9]
  69. def __init__(self, presenter, parent, ID):
  70. SearchableScintillaControl.__init__(self, presenter,
  71. presenter.getMainControl(), parent, ID)
  72. self.evalScope = None
  73. self.stylingThreadHolder = ThreadHolder()
  74. self.calltipThreadHolder = ThreadHolder()
  75. self.contextMenuThreadHolder = ThreadHolder()
  76. self.clearStylingCache()
  77. self.pageType = "normal" # The pagetype controls some special editor behaviour
  78. # self.idleCounter = 0 # Used to reduce idle load
  79. # self.loadedDocPage = None
  80. self.lastFont = None
  81. self.ignoreOnChange = False
  82. self.dwellLockCounter = 0 # Don't process dwell start messages if >0
  83. self.wikiLanguageHelper = None
  84. self.templateIdRecycler = wxHelper.IdRecycler()
  85. self.vi = None # Contains ViHandler instance if vi key handling enabled
  86. # If autocompletion word was choosen, how many bytes to delete backward
  87. # before inserting word
  88. self.autoCompBackBytesMap = {} # Maps selected word to number of backbytes
  89. # Inline image
  90. self.tooltip_image = None
  91. # configurable editor settings
  92. config = self.presenter.getConfig()
  93. # TODO: set wrap indent mode (for wx >= 2.9)
  94. self.setWrapMode(config.getboolean("main", "wrap_mode"))
  95. self.SetIndentationGuides(config.getboolean("main", "indentation_guides"))
  96. self.autoIndent = config.getboolean("main", "auto_indent")
  97. self.autoBullets = config.getboolean("main", "auto_bullets")
  98. self.setShowLineNumbers(config.getboolean("main", "show_lineNumbers"))
  99. self.foldingActive = config.getboolean("main", "editor_useFolding")
  100. self.tabsToSpaces = config.getboolean("main", "editor_tabsToSpaces")
  101. # editor settings
  102. self.applyBasicSciSettings()
  103. self.defaultFont = config.get("main", "font",
  104. self.presenter.getDefaultFontFaces()["mono"])
  105. self.CallTipSetForeground(wx.Colour(0, 0, 0))
  106. shorthintDelay = self.presenter.getConfig().getint("main",
  107. "editor_shortHint_delay", 500)
  108. self.SetMouseDwellTime(shorthintDelay)
  109. # Popup menu must be created by Python code to replace clipboard functions
  110. # for unicode build on Win 98/ME
  111. self.UsePopUp(0)
  112. self.SetMarginMask(self.FOLD_MARGIN, wx.stc.STC_MASK_FOLDERS)
  113. self.SetMarginMask(self.NUMBER_MARGIN, 0)
  114. self.SetMarginMask(self.SELECT_MARGIN, 0)
  115. if self.foldingActive:
  116. self.SetMarginWidth(self.FOLD_MARGIN, 16)
  117. else:
  118. self.SetMarginWidth(self.FOLD_MARGIN, 0)
  119. self.SetMarginWidth(self.SELECT_MARGIN, 16)
  120. self.SetMarginWidth(self.NUMBER_MARGIN, 0)
  121. self.SetMarginType(self.FOLD_MARGIN, wx.stc.STC_MARGIN_SYMBOL)
  122. self.SetMarginType(self.SELECT_MARGIN, wx.stc.STC_MARGIN_SYMBOL)
  123. self.SetMarginType(self.NUMBER_MARGIN, wx.stc.STC_MARGIN_NUMBER)
  124. # Optical details
  125. self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDER, wx.stc.STC_MARK_PLUS)
  126. self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPEN, wx.stc.STC_MARK_MINUS)
  127. self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEREND, wx.stc.STC_MARK_EMPTY)
  128. self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERMIDTAIL, wx.stc.STC_MARK_EMPTY)
  129. self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPENMID, wx.stc.STC_MARK_EMPTY)
  130. self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERSUB, wx.stc.STC_MARK_EMPTY)
  131. self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERTAIL, wx.stc.STC_MARK_EMPTY)
  132. self.SetFoldFlags(16)
  133. self.SetMarginSensitive(self.FOLD_MARGIN, True)
  134. self.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" %
  135. self.presenter.getDefaultFontFaces())
  136. # self.setFoldingActive(self.foldingActive)
  137. for i in xrange(32):
  138. self.StyleSetEOLFilled(i, True)
  139. # i plan on lexing myself
  140. self.SetLexer(wx.stc.STC_LEX_CONTAINER)
  141. # make the text control a drop target for files and text
  142. self.SetDropTarget(WikiTxtCtrlDropTarget(self))
  143. # self.CmdKeyClearAll()
  144. #
  145. # # register some keyboard commands
  146. # self.CmdKeyAssign(ord('+'), wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMIN)
  147. # self.CmdKeyAssign(ord('-'), wx.stc.STC_SCMOD_CTRL, wx.stc.STC_CMD_ZOOMOUT)
  148. # self.CmdKeyAssign(wx.stc.STC_KEY_HOME, 0, wx.stc.STC_CMD_HOMEWRAP)
  149. # self.CmdKeyAssign(wx.stc.STC_KEY_END, 0, wx.stc.STC_CMD_LINEENDWRAP)
  150. # self.CmdKeyAssign(wx.stc.STC_KEY_HOME, wx.stc.STC_SCMOD_SHIFT,
  151. # wx.stc.STC_CMD_HOMEWRAPEXTEND)
  152. # self.CmdKeyAssign(wx.stc.STC_KEY_END, wx.stc.STC_SCMOD_SHIFT,
  153. # wx.stc.STC_CMD_LINEENDWRAPEXTEND)
  154. #
  155. #
  156. # # Clear all key mappings for clipboard operations
  157. # # PersonalWikiFrame handles them and calls the special clipboard functions
  158. # # instead of the normal ones
  159. # self.CmdKeyClear(wx.stc.STC_KEY_INSERT, wx.stc.STC_SCMOD_CTRL)
  160. # self.CmdKeyClear(wx.stc.STC_KEY_INSERT, wx.stc.STC_SCMOD_SHIFT)
  161. # self.CmdKeyClear(wx.stc.STC_KEY_DELETE, wx.stc.STC_SCMOD_SHIFT)
  162. #
  163. # self.CmdKeyClear(ord('X'), wx.stc.STC_SCMOD_CTRL)
  164. # self.CmdKeyClear(ord('C'), wx.stc.STC_SCMOD_CTRL)
  165. # self.CmdKeyClear(ord('V'), wx.stc.STC_SCMOD_CTRL)
  166. self.SetModEventMask(
  167. wx.stc.STC_MOD_INSERTTEXT | wx.stc.STC_MOD_DELETETEXT)
  168. # set the autocomplete separator
  169. self.AutoCompSetSeparator(1) # ord('~')
  170. self.AutoCompSetTypeSeparator(2) # ord('?')
  171. # register some event handlers
  172. self.presenterListener = wxKeyFunctionSink((
  173. ("saving all pages", self.onSavingAllPages),
  174. ("closing current wiki", self.onClosingCurrentWiki),
  175. ("dropping current wiki", self.onDroppingCurrentWiki),
  176. ("reloaded current doc page", self.onReloadedCurrentPage)
  177. ), self.presenter.getMiscEvent())
  178. self.__sinkApp = wxKeyFunctionSink((
  179. ("options changed", self.onOptionsChanged),
  180. ), wx.GetApp().getMiscEvent(), self)
  181. self.__sinkGlobalConfig = wxKeyFunctionSink((
  182. ("changed configuration", self.onChangedConfiguration),
  183. ), wx.GetApp().getGlobalConfig().getMiscEvent(), self)
  184. # if not self.presenter.getMainControl().isMainWindowConstructed():
  185. # # Install event handler to wait for construction
  186. # self.__sinkMainFrame = wxKeyFunctionSink((
  187. # ("constructed main window", self.onConstructedMainWindow),
  188. # ), self.presenter.getMainControl().getMiscEvent(), self)
  189. # else:
  190. # self.onConstructedMainWindow(None)
  191. self.__sinkMainFrame = wxKeyFunctionSink((
  192. ("idle visible", self.onIdleVisible),
  193. ), self.presenter.getMainControl().getMiscEvent(), self)
  194. # self.presenter.getMiscEvent().addListener(self.presenterListener)
  195. self.wikiPageSink = wxKeyFunctionSink((
  196. ("updated wiki page", self.onWikiPageUpdated), # fired by a WikiPage
  197. ("modified spell checker session", self.OnStyleNeeded), # ???
  198. ("changed read only flag", self.onPageChangedReadOnlyFlag)
  199. ))
  200. wx.stc.EVT_STC_STYLENEEDED(self, ID, self.OnStyleNeeded)
  201. wx.stc.EVT_STC_CHARADDED(self, ID, self.OnCharAdded)
  202. wx.stc.EVT_STC_MODIFIED(self, ID, self.OnModified)
  203. wx.stc.EVT_STC_USERLISTSELECTION(self, ID, self.OnUserListSelection)
  204. wx.stc.EVT_STC_MARGINCLICK(self, ID, self.OnMarginClick)
  205. wx.stc.EVT_STC_DWELLSTART(self, ID, self.OnDwellStart)
  206. wx.stc.EVT_STC_DWELLEND(self, ID, self.OnDwellEnd)
  207. # wx.EVT_LEFT_DOWN(self, self.OnClick)
  208. wx.EVT_MIDDLE_DOWN(self, self.OnMiddleDown)
  209. wx.EVT_LEFT_DCLICK(self, self.OnDoubleClick)
  210. # if config.getboolean("main", "editor_useImeWorkaround", False):
  211. # wx.EVT_CHAR(self, self.OnChar_ImeWorkaround)
  212. wx.EVT_SET_FOCUS(self, self.OnSetFocus)
  213. wx.EVT_CONTEXT_MENU(self, self.OnContextMenu)
  214. # self.incSearchCharStartPos = 0
  215. self.incSearchPreviousHiddenLines = None
  216. self.incSearchPreviousHiddenStartLine = -1
  217. self.onlineSpellCheckerActive = SpellChecker.isSpellCheckSupported() and \
  218. self.presenter.getConfig().getboolean(
  219. "main", "editor_onlineSpellChecker_active", False)
  220. self.optionColorizeSearchFragments = self.presenter.getConfig()\
  221. .getboolean("main", "editor_colorizeSearchFragments", False)
  222. self.onOptionsChanged(None)
  223. # when was a key pressed last. used to check idle time.
  224. self.lastKeyPressed = time()
  225. self.eolMode = self.GetEOLMode()
  226. # Check if modifiers where pressed since last extended logical line move
  227. # See self.moveSelectedLinesOneUp() for the reason of this
  228. self.modifiersPressedSinceExtLogLineMove = False
  229. self.contextMenuTokens = None
  230. self.contextMenuSpellCheckSuggestions = None
  231. # Connect context menu events to functions
  232. wx.EVT_MENU(self, GUI_ID.CMD_UNDO, lambda evt: self.Undo())
  233. wx.EVT_MENU(self, GUI_ID.CMD_REDO, lambda evt: self.Redo())
  234. wx.EVT_MENU(self, GUI_ID.CMD_CLIPBOARD_CUT, lambda evt: self.Cut())
  235. wx.EVT_MENU(self, GUI_ID.CMD_CLIPBOARD_COPY, lambda evt: self.Copy())
  236. wx.EVT_MENU(self, GUI_ID.CMD_CLIPBOARD_PASTE, lambda evt: self.Paste())
  237. wx.EVT_MENU(self, GUI_ID.CMD_CLIPBOARD_PASTE_RAW_HTML,
  238. lambda evt: self.pasteRawHtml())
  239. wx.EVT_MENU(self, GUI_ID.CMD_SELECT_ALL, lambda evt: self.SelectAll())
  240. wx.EVT_MENU(self, GUI_ID.CMD_TEXT_DELETE, lambda evt: self.ReplaceSelection(""))
  241. wx.EVT_MENU(self, GUI_ID.CMD_ZOOM_IN,
  242. lambda evt: self.CmdKeyExecute(wx.stc.STC_CMD_ZOOMIN))
  243. wx.EVT_MENU(self, GUI_ID.CMD_ZOOM_OUT,
  244. lambda evt: self.CmdKeyExecute(wx.stc.STC_CMD_ZOOMOUT))
  245. for sps in self.SUGGESTION_CMD_IDS:
  246. wx.EVT_MENU(self, sps, self.OnReplaceThisSpellingWithSuggestion)
  247. wx.EVT_MENU(self, GUI_ID.CMD_ADD_THIS_SPELLING_SESSION,
  248. self.OnAddThisSpellingToIgnoreSession)
  249. wx.EVT_MENU(self, GUI_ID.CMD_ADD_THIS_SPELLING_GLOBAL,
  250. self.OnAddThisSpellingToIgnoreGlobal)
  251. wx.EVT_MENU(self, GUI_ID.CMD_ADD_THIS_SPELLING_LOCAL,
  252. self.OnAddThisSpellingToIgnoreLocal)
  253. wx.EVT_MENU(self, GUI_ID.CMD_LOGICAL_LINE_UP,
  254. self.OnLogicalLineMove)
  255. wx.EVT_MENU(self, GUI_ID.CMD_LOGICAL_LINE_UP_WITH_INDENT,
  256. self.OnLogicalLineMove)
  257. wx.EVT_MENU(self, GUI_ID.CMD_LOGICAL_LINE_DOWN,
  258. self.OnLogicalLineMove)
  259. wx.EVT_MENU(self, GUI_ID.CMD_LOGICAL_LINE_DOWN_WITH_INDENT,
  260. self.OnLogicalLineMove)
  261. wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_THIS, self.OnActivateThis)
  262. wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_NEW_TAB_THIS,
  263. self.OnActivateNewTabThis)
  264. wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_NEW_TAB_BACKGROUND_THIS,
  265. self.OnActivateNewTabBackgroundThis)
  266. wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_NEW_WINDOW_THIS,
  267. self.OnActivateNewWindowThis)
  268. # Passing the evt here is not strictly necessary, but it may be
  269. # used in the future
  270. wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_THIS_LEFT,
  271. lambda evt: self.OnActivateThis(evt, u"left"))
  272. wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_NEW_TAB_THIS_LEFT,
  273. lambda evt: self.OnActivateNewTabThis(evt, u"left"))
  274. wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_NEW_TAB_BACKGROUND_THIS_LEFT,
  275. lambda evt: self.OnActivateNewTabBackgroundThis(evt, u"left"))
  276. wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_THIS_RIGHT,
  277. lambda evt: self.OnActivateThis(evt, u"right"))
  278. wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_NEW_TAB_THIS_RIGHT,
  279. lambda evt: self.OnActivateNewTabThis(evt, u"right"))
  280. wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_NEW_TAB_BACKGROUND_THIS_RIGHT,
  281. lambda evt: self.OnActivateNewTabBackgroundThis(evt, u"right"))
  282. wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_THIS_ABOVE,
  283. lambda evt: self.OnActivateThis(evt, u"above"))
  284. wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_NEW_TAB_THIS_ABOVE,
  285. lambda evt: self.OnActivateNewTabThis(evt, u"above"))
  286. wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_NEW_TAB_BACKGROUND_THIS_ABOVE,
  287. lambda evt: self.OnActivateNewTabBackgroundThis(evt, u"above"))
  288. wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_THIS_BELOW,
  289. lambda evt: self.OnActivateThis(evt, u"below"))
  290. wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_NEW_TAB_THIS_BELOW,
  291. lambda evt: self.OnActivateNewTabThis(evt, u"below"))
  292. wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_NEW_TAB_BACKGROUND_THIS_BELOW,
  293. lambda evt: self.OnActivateNewTabBackgroundThis(evt, u"below"))
  294. wx.EVT_MENU(self, GUI_ID.CMD_CONVERT_URL_ABSOLUTE_RELATIVE_THIS,
  295. self.OnConvertUrlAbsoluteRelativeThis)
  296. wx.EVT_MENU(self, GUI_ID.CMD_OPEN_CONTAINING_FOLDER_THIS,
  297. self.OnOpenContainingFolderThis)
  298. wx.EVT_MENU(self, GUI_ID.CMD_DELETE_FILE,
  299. self.OnDeleteFile)
  300. wx.EVT_MENU(self, GUI_ID.CMD_RENAME_FILE,
  301. self.OnRenameFile)
  302. wx.EVT_MENU(self, GUI_ID.CMD_CLIPBOARD_COPY_URL_TO_THIS_ANCHOR,
  303. self.OnClipboardCopyUrlToThisAnchor)
  304. wx.EVT_MENU(self, GUI_ID.CMD_SELECT_TEMPLATE, self.OnSelectTemplate)
  305. # 2.8 does not support SetEditable - Define a dummy function for now
  306. if wx.version().startswith("2.8"):
  307. def SetEditable(self, state):
  308. pass
  309. # def __getattr__(self, attr):
  310. # return getattr(self.cnt, attr)
  311. def getLoadedDocPage(self):
  312. return self.presenter.getDocPage()
  313. def close(self):
  314. """
  315. Close the editor (=prepare for destruction)
  316. """
  317. self.stylingThreadHolder.setThread(None)
  318. self.calltipThreadHolder.setThread(None)
  319. self.contextMenuThreadHolder.setThread(None)
  320. self.unloadCurrentDocPage({}) # ?
  321. self.presenterListener.disconnect()
  322. # self.presenter.getMiscEvent().removeListener(self.presenterListener)
  323. # def onConstructedMainWindow(self, evt):
  324. # """
  325. # Now we can register idle handler.
  326. # """
  327. # wx.EVT_IDLE(self, self.OnIdle)
  328. def Copy(self, text=None):
  329. if text is None:
  330. text = self.GetSelectedText()
  331. if len(text) == 0:
  332. return
  333. cbIcept = self.presenter.getMainControl().getClipboardInterceptor()
  334. if cbIcept is not None:
  335. cbIcept.informCopyInWikidPadStart(text=text)
  336. try:
  337. copyTextToClipboard(text)
  338. finally:
  339. cbIcept.informCopyInWikidPadStop()
  340. else:
  341. copyTextToClipboard(text)
  342. def Paste(self):
  343. # Text pasted?
  344. text = getTextFromClipboard()
  345. if text:
  346. self.ReplaceSelection(text)
  347. return True
  348. # File(name)s pasted?
  349. filenames = wxHelper.getFilesFromClipboard()
  350. if filenames is not None:
  351. mc = self.presenter.getMainControl()
  352. paramDict = {"editor": self, "filenames": filenames,
  353. "x": -1, "y": -1, "main control": mc,
  354. "processDirectly": True}
  355. # mc.getUserActionCoord().runAction(
  356. # u"action/editor/this/paste/files/insert/url/ask", paramDict)
  357. mc.getUserActionCoord().reactOnUserEvent(
  358. u"event/paste/editor/files", paramDict)
  359. return True
  360. fs = self.presenter.getWikiDocument().getFileStorage()
  361. imgsav = WikiTxtDialogs.ImagePasteSaver()
  362. imgsav.readOptionsFromConfig(self.presenter.getConfig())
  363. # Bitmap pasted?
  364. bmp = wxHelper.getBitmapFromClipboard()
  365. if bmp is not None:
  366. img = bmp.ConvertToImage()
  367. del bmp
  368. if self.presenter.getConfig().getboolean("main",
  369. "editor_imagePaste_askOnEachPaste", True):
  370. # Options say to present dialog on an image paste operation
  371. # Send image so it can be used for preview
  372. dlg = WikiTxtDialogs.ImagePasteDialog(
  373. self.presenter.getMainControl(), -1, imgsav, img)
  374. try:
  375. dlg.ShowModal()
  376. imgsav = dlg.getImagePasteSaver()
  377. finally:
  378. dlg.Destroy()
  379. destPath = imgsav.saveFile(fs, img)
  380. if destPath is None:
  381. # Couldn't find unused filename or saving denied
  382. return True
  383. url = self.presenter.getWikiDocument().makeAbsPathRelUrl(destPath)
  384. if url is None:
  385. url = u"file:" + StringOps.urlFromPathname(destPath)
  386. self.ReplaceSelection(url)
  387. return True
  388. if not WindowsHacks:
  389. return False
  390. # Windows Meta File pasted?
  391. destPath = imgsav.saveWmfFromClipboardToFileStorage(fs)
  392. if destPath is not None:
  393. url = self.presenter.getWikiDocument().makeAbsPathRelUrl(destPath)
  394. # Windows Meta File pasted?
  395. destPath = imgsav.saveWmfFromClipboardToFileStorage(fs)
  396. if destPath is not None:
  397. url = self.presenter.getWikiDocument().makeAbsPathRelUrl(destPath)
  398. if url is None:
  399. url = u"file:" + StringOps.urlFromPathname(destPath)
  400. self.ReplaceSelection(url)
  401. return True
  402. # Text pasted?
  403. text = getTextFromClipboard()
  404. if text:
  405. self.ReplaceSelection(text)
  406. return True
  407. return False
  408. def pasteRawHtml(self):
  409. rawHtml, url = wxHelper.getHtmlFromClipboard()
  410. if rawHtml:
  411. return self.wikiLanguageHelper.handlePasteRawHtml(self, rawHtml, {})
  412. return False
  413. def onCmdCopy(self, miscevt):
  414. if wx.Window.FindFocus() != self:
  415. return
  416. self.Copy()
  417. def setLayerVisible(self, vis, scName=""):
  418. """
  419. Informs the widget if it is really visible on the screen or not
  420. """
  421. # if vis:
  422. # self.Enable(True)
  423. self.Enable(vis)
  424. def isCharWrap(self):
  425. docPage = self.getLoadedDocPage()
  426. if docPage is not None:
  427. return docPage.getAttributeOrGlobal(u"wrap_type", u"word").lower()\
  428. .startswith(u"char")
  429. else:
  430. return False
  431. def setWrapMode(self, onOrOff, charWrap=None):
  432. if charWrap is None:
  433. charWrap = self.isCharWrap()
  434. if onOrOff:
  435. if charWrap:
  436. self.SetWrapMode(wx.stc.STC_WRAP_CHAR)
  437. else:
  438. self.SetWrapMode(wx.stc.STC_WRAP_WORD)
  439. else:
  440. self.SetWrapMode(wx.stc.STC_WRAP_NONE)
  441. def getWrapMode(self):
  442. return self.GetWrapMode() != wx.stc.STC_WRAP_NONE
  443. def setAutoIndent(self, onOff):
  444. self.autoIndent = onOff
  445. def getAutoIndent(self):
  446. return self.autoIndent
  447. def setAutoBullets(self, onOff):
  448. self.autoBullets = onOff
  449. def getAutoBullets(self):
  450. return self.autoBullets
  451. def setTabsToSpaces(self, onOff):
  452. self.tabsToSpaces = onOff
  453. self.SetUseTabs(not onOff)
  454. def getTabsToSpaces(self):
  455. return self.tabsToSpaces
  456. def setShowLineNumbers(self, onOrOff):
  457. if onOrOff:
  458. self.SetMarginWidth(self.NUMBER_MARGIN,
  459. self.TextWidth(wx.stc.STC_STYLE_LINENUMBER, "_99999"))
  460. self.SetMarginWidth(self.SELECT_MARGIN, 0)
  461. else:
  462. self.SetMarginWidth(self.NUMBER_MARGIN, 0)
  463. self.SetMarginWidth(self.SELECT_MARGIN, 16)
  464. def getShowLineNumbers(self):
  465. return self.GetMarginWidth(self.NUMBER_MARGIN) != 0
  466. def setFoldingActive(self, onOrOff, forceSync=False):
  467. """
  468. forceSync -- when setting folding on, the folding is completed
  469. before function returns iff forceSync is True
  470. """
  471. if onOrOff:
  472. self.SetMarginWidth(self.FOLD_MARGIN, 16)
  473. self.foldingActive = True
  474. if forceSync:
  475. try:
  476. self.applyFolding(self.processFolding(
  477. self.getPageAst(), DUMBTHREADSTOP))
  478. except NoPageAstException:
  479. return
  480. else:
  481. self.OnStyleNeeded(None)
  482. else:
  483. self.SetMarginWidth(self.FOLD_MARGIN, 0)
  484. self.unfoldAll()
  485. self.foldingActive = False
  486. def getFoldingActive(self):
  487. return self.foldingActive
  488. def SetStyles(self, styleFaces = None):
  489. self.SetStyleBits(5)
  490. # create the styles
  491. if styleFaces is None:
  492. styleFaces = self.presenter.getDefaultFontFaces()
  493. config = self.presenter.getConfig()
  494. styles = self.presenter.getMainControl().getPresentationExt()\
  495. .getStyles(styleFaces, config)
  496. for type, style in styles:
  497. self.StyleSetSpec(type, style)
  498. if type == wx.stc.STC_STYLE_CALLTIP:
  499. self.CallTipUseStyle(10)
  500. self.IndicatorSetStyle(2, wx.stc.STC_INDIC_SQUIGGLE)
  501. self.IndicatorSetForeground(2, wx.Colour(255, 0, 0))
  502. def SetText(self, text, emptyUndo=True):
  503. """
  504. Overrides the wxStyledTextCtrl method.
  505. text -- Unicode text content to set
  506. """
  507. self.incSearchCharStartPos = 0
  508. self.clearStylingCache()
  509. self.pageType = "normal"
  510. self.SetSelection(-1, -1)
  511. self.ignoreOnChange = True
  512. if isUnicode():
  513. wx.stc.StyledTextCtrl.SetText(self, text)
  514. else:
  515. wx.stc.StyledTextCtrl.SetText(self,
  516. StringOps.mbcsEnc(text, "replace")[0])
  517. self.ignoreOnChange = False
  518. if emptyUndo:
  519. self.EmptyUndoBuffer()
  520. # self.applyBasicSciSettings()
  521. def replaceText(self, text):
  522. if isUnicode():
  523. wx.stc.StyledTextCtrl.SetText(self, text)
  524. else:
  525. wx.stc.StyledTextCtrl.SetText(self,
  526. StringOps.mbcsEnc(text, "replace")[0])
  527. def replaceTextAreaByCharPos(self, newText, start, end):
  528. text = self.GetText()
  529. bs = self.bytelenSct(text[:start])
  530. be = bs + self.bytelenSct(text[start:end])
  531. self.SetTargetStart(bs)
  532. self.SetTargetEnd(be)
  533. if isUnicode():
  534. self.ReplaceTarget(newText)
  535. else:
  536. self.ReplaceTarget(StringOps.mbcsEnc(newText, "replace")[0])
  537. # text = self.GetText()
  538. # text = text[:pos] + newText + text[(pos + len):]
  539. #
  540. # self.replaceText(text)
  541. def showSelectionByCharPos(self, start, end):
  542. """
  543. Same as SetSelectionByCharPos(), but scrolls to position correctly
  544. """
  545. text = self.GetText()
  546. bs = self.bytelenSct(text[:start])
  547. be = bs + self.bytelenSct(text[start:end])
  548. self.ensureTextRangeByBytePosExpanded(bs, be)
  549. super(WikiTxtCtrl, self).showSelectionByCharPos(start, end)
  550. def applyBasicSciSettings(self):
  551. """
  552. Apply the basic Scintilla settings which are resetted to wrong
  553. default values by some operations
  554. """
  555. if isUnicode():
  556. self.SetCodePage(wx.stc.STC_CP_UTF8)
  557. self.SetTabIndents(True)
  558. self.SetBackSpaceUnIndents(True)
  559. self.SetUseTabs(not self.tabsToSpaces)
  560. self.SetEOLMode(wx.stc.STC_EOL_LF)
  561. tabWidth = self.presenter.getConfig().getint("main",
  562. "editor_tabWidth", 4)
  563. self.SetIndent(tabWidth)
  564. self.SetTabWidth(tabWidth)
  565. self.AutoCompSetFillUps(u":=") # TODO Add '.'?
  566. # self.SetYCaretPolicy(wxSTC_CARET_SLOP, 2)
  567. # self.SetYCaretPolicy(wxSTC_CARET_JUMPS | wxSTC_CARET_EVEN, 4)
  568. self.SetYCaretPolicy(wx.stc.STC_CARET_SLOP | wx.stc.STC_CARET_EVEN, 4)
  569. def saveLoadedDocPage(self):
  570. """
  571. Save loaded wiki page into database. Does not check if dirty
  572. """
  573. if self.getLoadedDocPage() is None:
  574. return
  575. page = self.getLoadedDocPage()
  576. # if not self.loadedDocPage.getDirty()[0]:
  577. # return
  578. # text = self.GetText()
  579. # page.replaceLiveText(text)
  580. if self.presenter.getMainControl().saveDocPage(page):
  581. self.SetSavePoint()
  582. def unloadCurrentDocPage(self, evtprops=None):
  583. ## _prof.start()
  584. # Stop threads
  585. self.stylingThreadHolder.setThread(None)
  586. self.calltipThreadHolder.setThread(None)
  587. docPage = self.getLoadedDocPage()
  588. if docPage is not None:
  589. wikiWord = docPage.getWikiWord()
  590. if wikiWord is not None:
  591. docPage.setPresentation((self.GetCurrentPos(),
  592. self.GetScrollPos(wx.HORIZONTAL),
  593. self.GetScrollPos(wx.VERTICAL)), 0)
  594. docPage.setPresentation((self.getFoldInfo(),), 5)
  595. if docPage.getDirty()[0]:
  596. self.saveLoadedDocPage()
  597. docPage.removeTxtEditor(self)
  598. self.SetDocPointer(None)
  599. self.applyBasicSciSettings()
  600. self.wikiPageSink.disconnect()
  601. self.presenter.setDocPage(None)
  602. self.clearStylingCache()
  603. # self.stylebytes = None
  604. # self.foldingseq = None
  605. # self.pageAst = None
  606. self.pageType = "normal"
  607. ## _prof.stop()
  608. def loadFuncPage(self, funcPage, evtprops=None):
  609. self.unloadCurrentDocPage(evtprops)
  610. # set the editor text
  611. content = None
  612. wikiDataManager = self.presenter.getWikiDocument()
  613. self.presenter.setDocPage(funcPage)
  614. if self.getLoadedDocPage() is None:
  615. return # TODO How to handle?
  616. globalAttrs = wikiDataManager.getWikiData().getGlobalAttributes()
  617. # get the font that should be used in the editor
  618. font = globalAttrs.get("global.font", self.defaultFont)
  619. # set the styles in the editor to the font
  620. if self.lastFont != font:
  621. faces = self.presenter.getDefaultFontFaces().copy()
  622. faces["mono"] = font
  623. self.SetStyles(faces)
  624. self.lastEditorFont = font
  625. # this updates depending on attribute "wrap_type" (word or character)
  626. self.setWrapMode(self.getWrapMode())
  627. # p2 = evtprops.copy()
  628. # p2.update({"loading current page": True})
  629. # self.pWiki.fireMiscEventProps(p2) # TODO Remove this hack
  630. self.wikiPageSink.setEventSource(self.getLoadedDocPage().getMiscEvent())
  631. otherEditor = self.getLoadedDocPage().getTxtEditor()
  632. if otherEditor is not None:
  633. # Another editor contains already this page, so share its
  634. # Scintilla document object for synchronized editing
  635. self.SetDocPointer(otherEditor.GetDocPointer())
  636. self.applyBasicSciSettings()
  637. else:
  638. # Load content
  639. try:
  640. content = self.getLoadedDocPage().getLiveText()
  641. except WikiFileNotFoundException, e:
  642. assert 0 # TODO
  643. # now fill the text into the editor
  644. self.SetReadOnly(False)
  645. self.SetText(content)
  646. if self.wikiLanguageHelper is None or \
  647. self.wikiLanguageHelper.getWikiLanguageName() != \
  648. self.getLoadedDocPage().getWikiLanguageName():
  649. wx.GetApp().freeWikiLanguageHelper(self.wikiLanguageHelper)
  650. self.wikiLanguageHelper = self.getLoadedDocPage().createWikiLanguageHelper()
  651. self.getLoadedDocPage().addTxtEditor(self)
  652. self._checkForReadOnly()
  653. self.presenter.setTitle(self.getLoadedDocPage().getTitle())
  654. def loadWikiPage(self, wikiPage, evtprops=None):
  655. """
  656. Save loaded page, if necessary, then load wikiPage into editor
  657. """
  658. self.unloadCurrentDocPage(evtprops)
  659. # set the editor text
  660. wikiDataManager = self.presenter.getWikiDocument()
  661. self.presenter.setDocPage(wikiPage)
  662. docPage = self.getLoadedDocPage()
  663. if docPage is None:
  664. return # TODO How to handle?
  665. self.wikiPageSink.setEventSource(docPage.getMiscEvent())
  666. otherEditor = docPage.getTxtEditor()
  667. if otherEditor is not None:
  668. # Another editor contains already this page, so share its
  669. # Scintilla document object for synchronized editing
  670. self.SetDocPointer(otherEditor.GetDocPointer())
  671. self.applyBasicSciSettings()
  672. else:
  673. # Load content
  674. try:
  675. content = docPage.getLiveText()
  676. except WikiFileNotFoundException, e:
  677. assert 0 # TODO
  678. # now fill the text into the editor
  679. self.SetReadOnly(False)
  680. self.setTextAgaUpdated(content)
  681. if self.wikiLanguageHelper is None or \
  682. self.wikiLanguageHelper.getWikiLanguageName() != \
  683. docPage.getWikiLanguageName():
  684. wx.GetApp().freeWikiLanguageHelper(self.wikiLanguageHelper)
  685. self.wikiLanguageHelper = docPage.createWikiLanguageHelper()
  686. docPage.addTxtEditor(self)
  687. self._checkForReadOnly()
  688. if evtprops is None:
  689. evtprops = {}
  690. p2 = evtprops.copy()
  691. p2.update({"loading wiki page": True, "wikiPage": docPage})
  692. self.presenter.fireMiscEventProps(p2) # TODO Remove this hack
  693. # get the font that should be used in the editor
  694. font = docPage.getAttributeOrGlobal("font", self.defaultFont)
  695. # set the styles in the editor to the font
  696. if self.lastFont != font:
  697. faces = self.presenter.getDefaultFontFaces().copy()
  698. faces["mono"] = font
  699. self.SetStyles(faces)
  700. self.lastEditorFont = font
  701. # this updates depending on attribute "wrap_type" (word or character)
  702. self.setWrapMode(self.getWrapMode())
  703. self.pageType = docPage.getAttributes().get(u"pagetype",
  704. [u"normal"])[-1]
  705. if self.pageType == u"normal":
  706. if not docPage.isDefined():
  707. # This is a new, not yet defined page, so go to the end of page
  708. self.GotoPos(self.GetLength())
  709. else:
  710. anchor = evtprops.get("anchor")
  711. if anchor:
  712. # Scroll page according to the anchor
  713. pageAst = self.getPageAst()
  714. anchorNodes = pageAst.iterDeepByName("anchorDef")
  715. for node in anchorNodes:
  716. if node.anchorLink == anchor:
  717. self.gotoCharPos(node.pos + node.strLength)
  718. break
  719. else:
  720. anchor = None # Not found
  721. if not anchor:
  722. # Is there a position given in the eventprops?
  723. firstcharpos = evtprops.get("firstcharpos", -1)
  724. if firstcharpos != -1:
  725. charlength = max(0, evtprops.get("charlength", 0))
  726. self.showSelectionByCharPos(firstcharpos,
  727. firstcharpos + charlength)
  728. anchor = True
  729. if not anchor:
  730. # see if there is a saved position for this page
  731. prst = docPage.getPresentation()
  732. lastPos, scrollPosX, scrollPosY = prst[0:3]
  733. foldInfo = prst[5]
  734. self.setFoldInfo(foldInfo)
  735. self.GotoPos(lastPos)
  736. self.scrollXY(scrollPosX, scrollPosY)
  737. else:
  738. self.handleSpecialPageType()
  739. self.presenter.setTitle(docPage.getTitle())
  740. def handleSpecialPageType(self):
  741. # self.allowRectExtend(self.pageType != u"texttree")
  742. if self.pageType == u"form":
  743. self.GotoPos(0)
  744. self._goToNextFormField()
  745. return True
  746. return False
  747. def onReloadedCurrentPage(self, miscevt):
  748. """
  749. Called when already loaded page should be loaded again, mainly
  750. interesting if a link with anchor is activated
  751. """
  752. if not self.presenter.isCurrent():
  753. return
  754. anchor = miscevt.get("anchor")
  755. if not anchor:
  756. if self.pageType == u"normal":
  757. # Is there a position given in the eventprops?
  758. firstcharpos = miscevt.get("firstcharpos", -1)
  759. if firstcharpos != -1:
  760. charlength = max(0, miscevt.get("charlength", 0))
  761. self.showSelectionByCharPos(firstcharpos,
  762. firstcharpos + charlength)
  763. return
  764. # if not anchor:
  765. # return
  766. docPage = self.getLoadedDocPage()
  767. if not docPage.isDefined():
  768. return
  769. if self.wikiLanguageHelper is None or \
  770. self.wikiLanguageHelper.getWikiLanguageName() != \
  771. docPage.getWikiLanguageName():
  772. wx.GetApp().freeWikiLanguageHelper(self.wikiLanguageHelper)
  773. self.wikiLanguageHelper = docPage.createWikiLanguageHelper()
  774. if self.pageType == u"normal":
  775. # Scroll page according to the anchor
  776. try:
  777. anchorNodes = self.getPageAst().iterDeepByName("anchorDef")
  778. anchorNodes = self.getPageAst().iterDeepByName("anchorDef")
  779. for node in anchorNodes:
  780. if node.anchorLink == anchor:
  781. self.gotoCharPos(node.pos + node.strLength)
  782. break
  783. # else:
  784. # anchor = None # Not found
  785. except NoPageAstException:
  786. return
  787. def _checkForReadOnly(self):
  788. """
  789. Set/unset read-only mode of editor according to read-only state of page.
  790. """
  791. docPage = self.getLoadedDocPage()
  792. if docPage is None:
  793. self.SetReadOnly(True)
  794. else:
  795. self.SetReadOnly(docPage.isReadOnlyEffect())
  796. def _getColorFromOption(self, option, defColTuple):
  797. """
  798. Helper for onOptionsChanged() to read a color from an option
  799. and create a wx.Colour object from it.
  800. """
  801. coltuple = StringOps.colorDescToRgbTuple(self.presenter.getConfig().get(
  802. "main", option))
  803. if coltuple is None:
  804. coltuple = defColTuple
  805. return wx.Colour(*coltuple)
  806. def onPageChangedReadOnlyFlag(self, miscevt):
  807. self._checkForReadOnly()
  808. def onOptionsChanged(self, miscevt):
  809. faces = self.presenter.getDefaultFontFaces().copy()
  810. if isinstance(self.getLoadedDocPage(),
  811. (DocPages.WikiPage, DocPages.AliasWikiPage)):
  812. font = self.getLoadedDocPage().getAttributeOrGlobal("font",
  813. self.defaultFont)
  814. faces["mono"] = font
  815. self.lastEditorFont = font # ???
  816. self._checkForReadOnly()
  817. self.SetStyles(faces)
  818. color = self._getColorFromOption("editor_bg_color", (255, 255, 255))
  819. for i in xrange(32):
  820. self.StyleSetBackground(i, color)
  821. self.StyleSetBackground(wx.stc.STC_STYLE_DEFAULT, color)
  822. self.SetSelForeground(True, self._getColorFromOption(
  823. "editor_selection_fg_color", (0, 0, 0)))
  824. self.SetSelBackground(True, self._getColorFromOption(
  825. "editor_selection_bg_color", (192, 192, 192)))
  826. self.SetCaretForeground(self._getColorFromOption(
  827. "editor_caret_color", (0, 0, 0)))
  828. # Set default color (especially for folding lines)
  829. self.StyleSetForeground(wx.stc.STC_STYLE_DEFAULT, self._getColorFromOption(
  830. "editor_plaintext_color", (0, 0, 0)))
  831. self.StyleSetBackground(wx.stc.STC_STYLE_LINENUMBER, self._getColorFromOption(
  832. "editor_margin_bg_color", (212, 208, 200)))
  833. shorthintDelay = self.presenter.getConfig().getint("main",
  834. "editor_shortHint_delay", 500)
  835. self.SetMouseDwellTime(shorthintDelay)
  836. tabWidth = self.presenter.getConfig().getint("main",
  837. "editor_tabWidth", 4)
  838. self.SetIndent(tabWidth)
  839. self.SetTabWidth(tabWidth)
  840. # this updates depending on attribute "wrap_type" (word or character)
  841. self.setWrapMode(self.getWrapMode())
  842. # To allow switching vi keys on and off without restart
  843. use_vi_navigation = self.presenter.getConfig().getboolean("main",
  844. "editor_compatibility_ViKeys", False)
  845. self.Unbind(wx.EVT_CHAR)
  846. self.Unbind(wx.EVT_KEY_DOWN)
  847. self.Unbind(wx.EVT_KEY_UP)
  848. self.Unbind(wx.EVT_LEFT_UP)
  849. #self.Unbind(wx.EVT_SCROLLWIN)
  850. self.Unbind(wx.EVT_MOUSEWHEEL)
  851. if use_vi_navigation:
  852. if self.vi is None:
  853. self.vi = ViHandler(self)
  854. if not isLinux():
  855. # Need to merge with OnChar_ImeWorkaround
  856. self.Bind(wx.EVT_CHAR, self.vi.OnChar)
  857. self.Bind(wx.EVT_KEY_DOWN, self.vi.OnViKeyDown)
  858. self.Bind(wx.EVT_LEFT_DOWN, self.vi.OnMouseClick)
  859. self.Bind(wx.EVT_LEFT_UP, self.vi.OnLeftMouseUp)
  860. # TODO: Replace with seperate scroll events
  861. #self.Bind(wx.EVT_SCROLLWIN, self.vi.OnScroll)
  862. if self.vi.settings["caret_scroll"]:
  863. self.Bind(wx.EVT_MOUSEWHEEL, self.vi.OnMouseScroll)
  864. # Should probably store shortcut state in a global
  865. # variable otherwise this will be run each time
  866. # a new tab is opened
  867. wx.CallAfter(self.vi._enableMenuShortcuts, False)
  868. else:
  869. if self.vi is not None:
  870. self.vi.TurnOff()
  871. self.vi = None
  872. if self.presenter.getConfig().getboolean("main",
  873. "editor_useImeWorkaround", False):
  874. wx.EVT_CHAR(self, self.OnChar_ImeWorkaround)
  875. self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
  876. self.Bind(wx.EVT_KEY_UP, self.OnKeyUp)
  877. self.Bind(wx.EVT_LEFT_DOWN, self.OnClick)
  878. self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
  879. if not isLinux():
  880. self.Bind(wx.EVT_CHAR, None)
  881. def onChangedConfiguration(self, miscevt):
  882. """
  883. Called when global configuration was changed. Most things are processed
  884. by onOptionsChanged so only the online spell checker switch must be
  885. handled here.
  886. """
  887. restyle = False
  888. newSetting = SpellChecker.isSpellCheckSupported() and \
  889. self.presenter.getConfig().getboolean(
  890. "main", "editor_onlineSpellChecker_active", False)
  891. if newSetting != self.onlineSpellCheckerActive:
  892. self.onlineSpellCheckerActive = newSetting
  893. restyle = True
  894. newSetting = self.presenter.getConfig()\
  895. .getboolean("main", "editor_colorizeSearchFragments", False)
  896. if newSetting != self.optionColorizeSearchFragments:
  897. self.optionColorizeSearchFragments = newSetting
  898. restyle = True
  899. if restyle:
  900. self.OnStyleNeeded(None)
  901. def onWikiPageUpdated(self, miscevt):
  902. if self.getLoadedDocPage() is None or \
  903. not isinstance(self.getLoadedDocPage(),
  904. (DocPages.WikiPage, DocPages.AliasWikiPage)):
  905. return
  906. # get the font that should be used in the editor
  907. font = self.getLoadedDocPage().getAttributeOrGlobal("font",
  908. self.defaultFont)
  909. # set the styles in the editor to the font
  910. if self.lastFont != font:
  911. faces = self.presenter.getDefaultFontFaces().copy()
  912. faces["mono"] = font
  913. self.SetStyles(faces)
  914. self.lastEditorFont = font
  915. # this updates depending on attribute "wrap_type" (word or character)
  916. self.setWrapMode(self.getWrapMode())
  917. self.pageType = self.getLoadedDocPage().getAttributes().get(u"pagetype",
  918. [u"normal"])[-1]
  919. def handleInvalidFileSignature(self, docPage):
  920. """
  921. Called directly from a doc page to repair the editor state if an
  922. invalid file signature was detected.
  923. docPage -- calling docpage
  924. """
  925. if docPage is not self.getLoadedDocPage() or \
  926. not isinstance(docPage,
  927. (DocPages.DataCarryingPage, DocPages.AliasWikiPage)):
  928. return
  929. sd, ud = docPage.getDirty()
  930. if sd:
  931. return # TODO What to do on conflict?
  932. content = docPage.getContent()
  933. docPage.setEditorText(content, dirty=False)
  934. self.ignoreOnChange = True
  935. # TODO: Store/restore selection & scroll pos.
  936. self.setTextAgaUpdated(content)
  937. self.ignoreOnChange = False
  938. def onSavingAllPages(self, miscevt):
  939. if self.getLoadedDocPage() is not None and (
  940. self.getLoadedDocPage().getDirty()[0] or miscevt.get("force",
  941. False)):
  942. self.saveLoadedDocPage()
  943. def onClosingCurrentWiki(self, miscevt):
  944. self.unloadCurrentDocPage()
  945. def onDroppingCurrentWiki(self, miscevt):
  946. """
  947. An access error occurred. Get rid of any data without trying to save
  948. it.
  949. """
  950. if self.getLoadedDocPage() is not None:
  951. self.wikiPageSink.disconnect()
  952. self.SetDocPointer(None)
  953. self.applyBasicSciSettings()
  954. self.getLoadedDocPage().removeTxtEditor(self)
  955. self.presenter.setDocPage(None)
  956. # self.loadedDocPage = None
  957. self.pageType = "normal"
  958. def OnStyleNeeded(self, evt):
  959. "Styles the text of the editor"
  960. docPage = self.getLoadedDocPage()
  961. if docPage is None:
  962. # This avoids further request from STC:
  963. self.stopStcStyler()
  964. return
  965. # get the text to regex against (use doc pages getLiveText because
  966. # it's cached
  967. text = docPage.getLiveText() # self.GetText()
  968. textlen = len(text)
  969. t = self.stylingThreadHolder.getThread()
  970. if t is not None:
  971. self.stylingThreadHolder.setThread(None)
  972. self.clearStylingCache()
  973. if textlen < self.presenter.getConfig().getint(
  974. "main", "sync_highlight_byte_limit"):
  975. # if True:
  976. # Synchronous styling
  977. self.stylingThreadHolder.setThread(None)
  978. self.buildStyling(text, 0, threadstop=DUMBTHREADSTOP)
  979. self.applyStyling(self.stylebytes) # TODO Necessary?
  980. # We can't call applyFolding directly because this in turn
  981. # calls repairFoldingVisibility which can't work while in
  982. # EVT_STC_STYLENEEDED event (at least for wxPython 2.6.2)
  983. # storeStylingAndAst() sends a StyleDoneEvent instead
  984. if self.getFoldingActive():
  985. self.storeStylingAndAst(None, self.foldingseq)
  986. else:
  987. # Asynchronous styling
  988. # This avoids further request from STC:
  989. self.stopStcStyler()
  990. sth = self.stylingThreadHolder
  991. delay = self.presenter.getConfig().getfloat(
  992. "main", "async_highlight_delay")
  993. t = threading.Thread(None, self.buildStyling, args = (text, delay, sth))
  994. sth.setThread(t)
  995. t.setDaemon(True)
  996. t.start()
  997. def _fillTemplateMenu(self, menu):
  998. idRecycler = self.templateIdRecycler
  999. idRecycler.clearAssoc()
  1000. config = self.presenter.getConfig()
  1001. templateRePat = config.get(u"main", u"template_pageNamesRE",
  1002. u"^template/")
  1003. try:
  1004. templateRe = re.compile(templateRePat, re.DOTALL | re.UNICODE)
  1005. except re.error:
  1006. templateRe = re.compile(u"^template/", re.DOTALL | re.UNICODE)
  1007. wikiDocument = self.presenter.getWikiDocument()
  1008. templateNames = [n for n in wikiDocument.getAllDefinedWikiPageNames()
  1009. if templateRe.search(n)]
  1010. wikiDocument.getCollator().sort(templateNames)
  1011. for tn in templateNames:
  1012. menuID, reused = idRecycler.assocGetIdAndReused(tn)
  1013. if not reused:
  1014. # For a new id, an event must be set
  1015. wx.EVT_MENU(self, menuID, self.OnTemplateUsed)
  1016. menu.Append(menuID, StringOps.uniToGui(tn))
  1017. def OnTemplateUsed(self, evt):
  1018. docPage = self.getLoadedDocPage()
  1019. if docPage is None:
  1020. return
  1021. templateName = self.templateIdRecycler.get(evt.GetId())
  1022. if templateName is None:
  1023. return
  1024. wikiDocument = self.presenter.getWikiDocument()
  1025. templatePage = wikiDocument.getWikiPage(templateName)
  1026. content = self.getLoadedDocPage().getContentOfTemplate(templatePage,
  1027. templatePage)
  1028. docPage.setMetaDataFromTemplate(templatePage)
  1029. self.SetText(content, emptyUndo=False)
  1030. self.pageType = docPage.getAttributes().get(u"pagetype",
  1031. [u"normal"])[-1]
  1032. self.handleSpecialPageType()
  1033. # TODO Handle form mode
  1034. self.presenter.informEditorTextChanged(self)
  1035. def

Large files files are truncated, but you can click here to view the full file