| 1 | from __future__ import with_statement |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | import traceback, codecs |
|---|
| 6 | from cStringIO import StringIO |
|---|
| 7 | import string, itertools, contextlib |
|---|
| 8 | import re |
|---|
| 9 | import threading |
|---|
| 10 | |
|---|
| 11 | import subprocess |
|---|
| 12 | import string |
|---|
| 13 | |
|---|
| 14 | from os.path import exists, dirname, isfile, join, basename |
|---|
| 15 | from os import rename, unlink |
|---|
| 16 | |
|---|
| 17 | from time import time, sleep |
|---|
| 18 | |
|---|
| 19 | import wx, wx.stc |
|---|
| 20 | |
|---|
| 21 | from Consts import FormatTypes |
|---|
| 22 | |
|---|
| 23 | |
|---|
| 24 | from .Utilities import DUMBTHREADSTOP, callInMainThread, ThreadHolder, \ |
|---|
| 25 | calcResizeArIntoBoundingBox |
|---|
| 26 | |
|---|
| 27 | from .wxHelper import GUI_ID, getTextFromClipboard, copyTextToClipboard, \ |
|---|
| 28 | wxKeyFunctionSink, getAccelPairFromKeyDown, appendToMenuByMenuDesc |
|---|
| 29 | from . import wxHelper |
|---|
| 30 | |
|---|
| 31 | from . import OsAbstract |
|---|
| 32 | |
|---|
| 33 | from .WikiExceptions import * |
|---|
| 34 | |
|---|
| 35 | from .SystemInfo import isUnicode, isOSX, isLinux, isWindows |
|---|
| 36 | |
|---|
| 37 | from .ParseUtilities import getFootnoteAnchorDict |
|---|
| 38 | |
|---|
| 39 | from .EnhancedScintillaControl import StyleCollector |
|---|
| 40 | |
|---|
| 41 | from .SearchableScintillaControl import SearchableScintillaControl |
|---|
| 42 | |
|---|
| 43 | |
|---|
| 44 | |
|---|
| 45 | from . import Configuration |
|---|
| 46 | from . import AdditionalDialogs |
|---|
| 47 | from . import WikiTxtDialogs |
|---|
| 48 | |
|---|
| 49 | |
|---|
| 50 | import imghdr |
|---|
| 51 | |
|---|
| 52 | |
|---|
| 53 | |
|---|
| 54 | from . import DocPages |
|---|
| 55 | from . import UserActionCoord, WindowLayout |
|---|
| 56 | |
|---|
| 57 | from .SearchAndReplace import SearchReplaceOperation |
|---|
| 58 | from . import StringOps |
|---|
| 59 | from . import SpellChecker |
|---|
| 60 | |
|---|
| 61 | |
|---|
| 62 | |
|---|
| 63 | |
|---|
| 64 | |
|---|
| 65 | |
|---|
| 66 | from ViHelper import ViHintDialog, ViHelper |
|---|
| 67 | from collections import defaultdict |
|---|
| 68 | |
|---|
| 69 | try: |
|---|
| 70 | import WindowsHacks |
|---|
| 71 | except: |
|---|
| 72 | if isWindows(): |
|---|
| 73 | traceback.print_exc() |
|---|
| 74 | WindowsHacks = None |
|---|
| 75 | |
|---|
| 76 | |
|---|
| 77 | |
|---|
| 78 | CO_FUTURE_DIVISION = 0x2000 |
|---|
| 79 | |
|---|
| 80 | |
|---|
| 81 | |
|---|
| 82 | def bytelenSct_utf8(us): |
|---|
| 83 | """ |
|---|
| 84 | us -- unicode string |
|---|
| 85 | returns: Number of bytes us requires in Scintilla (with UTF-8 encoding=Unicode) |
|---|
| 86 | """ |
|---|
| 87 | return len(StringOps.utf8Enc(us)[0]) |
|---|
| 88 | |
|---|
| 89 | |
|---|
| 90 | def bytelenSct_mbcs(us): |
|---|
| 91 | """ |
|---|
| 92 | us -- unicode string |
|---|
| 93 | returns: Number of bytes us requires in Scintilla (with mbcs encoding=Ansi) |
|---|
| 94 | """ |
|---|
| 95 | return len(StringOps.mbcsEnc(us)[0]) |
|---|
| 96 | |
|---|
| 97 | |
|---|
| 98 | |
|---|
| 99 | |
|---|
| 100 | |
|---|
| 101 | |
|---|
| 102 | |
|---|
| 103 | |
|---|
| 104 | |
|---|
| 105 | |
|---|
| 106 | |
|---|
| 107 | |
|---|
| 108 | |
|---|
| 109 | |
|---|
| 110 | |
|---|
| 111 | |
|---|
| 112 | |
|---|
| 113 | |
|---|
| 114 | |
|---|
| 115 | class WikiTxtCtrl(SearchableScintillaControl): |
|---|
| 116 | NUMBER_MARGIN = 0 |
|---|
| 117 | FOLD_MARGIN = 2 |
|---|
| 118 | SELECT_MARGIN = 1 |
|---|
| 119 | |
|---|
| 120 | |
|---|
| 121 | SUGGESTION_CMD_IDS = [GUI_ID.CMD_REPLACE_THIS_SPELLING_WITH_SUGGESTION_0, |
|---|
| 122 | GUI_ID.CMD_REPLACE_THIS_SPELLING_WITH_SUGGESTION_1, |
|---|
| 123 | GUI_ID.CMD_REPLACE_THIS_SPELLING_WITH_SUGGESTION_2, |
|---|
| 124 | GUI_ID.CMD_REPLACE_THIS_SPELLING_WITH_SUGGESTION_3, |
|---|
| 125 | GUI_ID.CMD_REPLACE_THIS_SPELLING_WITH_SUGGESTION_4, |
|---|
| 126 | GUI_ID.CMD_REPLACE_THIS_SPELLING_WITH_SUGGESTION_5, |
|---|
| 127 | GUI_ID.CMD_REPLACE_THIS_SPELLING_WITH_SUGGESTION_6, |
|---|
| 128 | GUI_ID.CMD_REPLACE_THIS_SPELLING_WITH_SUGGESTION_7, |
|---|
| 129 | GUI_ID.CMD_REPLACE_THIS_SPELLING_WITH_SUGGESTION_8, |
|---|
| 130 | GUI_ID.CMD_REPLACE_THIS_SPELLING_WITH_SUGGESTION_9] |
|---|
| 131 | |
|---|
| 132 | def __init__(self, presenter, parent, ID): |
|---|
| 133 | SearchableScintillaControl.__init__(self, presenter, |
|---|
| 134 | presenter.getMainControl(), parent, ID) |
|---|
| 135 | self.evalScope = None |
|---|
| 136 | self.stylingThreadHolder = ThreadHolder() |
|---|
| 137 | self.calltipThreadHolder = ThreadHolder() |
|---|
| 138 | self.clearStylingCache() |
|---|
| 139 | self.pageType = "normal" |
|---|
| 140 | |
|---|
| 141 | |
|---|
| 142 | self.lastFont = None |
|---|
| 143 | self.ignoreOnChange = False |
|---|
| 144 | self.dwellLockCounter = 0 |
|---|
| 145 | self.wikiLanguageHelper = None |
|---|
| 146 | self.templateIdRecycler = wxHelper.IdRecycler() |
|---|
| 147 | self.vi = None |
|---|
| 148 | |
|---|
| 149 | |
|---|
| 150 | |
|---|
| 151 | self.autoCompBackBytesMap = {} |
|---|
| 152 | |
|---|
| 153 | |
|---|
| 154 | self.tooltip_image = None |
|---|
| 155 | |
|---|
| 156 | |
|---|
| 157 | config = self.presenter.getConfig() |
|---|
| 158 | self.setWrapMode(config.getboolean("main", "wrap_mode")) |
|---|
| 159 | self.SetIndentationGuides(config.getboolean("main", "indentation_guides")) |
|---|
| 160 | self.autoIndent = config.getboolean("main", "auto_indent") |
|---|
| 161 | self.autoBullets = config.getboolean("main", "auto_bullets") |
|---|
| 162 | self.setShowLineNumbers(config.getboolean("main", "show_lineNumbers")) |
|---|
| 163 | self.foldingActive = config.getboolean("main", "editor_useFolding") |
|---|
| 164 | self.tabsToSpaces = config.getboolean("main", "editor_tabsToSpaces") |
|---|
| 165 | |
|---|
| 166 | |
|---|
| 167 | self.applyBasicSciSettings() |
|---|
| 168 | |
|---|
| 169 | self.defaultFont = config.get("main", "font", |
|---|
| 170 | self.presenter.getDefaultFontFaces()["mono"]) |
|---|
| 171 | |
|---|
| 172 | self.CallTipSetForeground(wx.Colour(0, 0, 0)) |
|---|
| 173 | |
|---|
| 174 | shorthintDelay = self.presenter.getConfig().getint("main", |
|---|
| 175 | "editor_shortHint_delay", 500) |
|---|
| 176 | self.SetMouseDwellTime(shorthintDelay) |
|---|
| 177 | |
|---|
| 178 | |
|---|
| 179 | |
|---|
| 180 | self.UsePopUp(0) |
|---|
| 181 | |
|---|
| 182 | self.SetMarginMask(self.FOLD_MARGIN, wx.stc.STC_MASK_FOLDERS) |
|---|
| 183 | self.SetMarginMask(self.NUMBER_MARGIN, 0) |
|---|
| 184 | self.SetMarginMask(self.SELECT_MARGIN, 0) |
|---|
| 185 | |
|---|
| 186 | if self.foldingActive: |
|---|
| 187 | self.SetMarginWidth(self.FOLD_MARGIN, 16) |
|---|
| 188 | else: |
|---|
| 189 | self.SetMarginWidth(self.FOLD_MARGIN, 0) |
|---|
| 190 | self.SetMarginWidth(self.SELECT_MARGIN, 16) |
|---|
| 191 | self.SetMarginWidth(self.NUMBER_MARGIN, 0) |
|---|
| 192 | |
|---|
| 193 | self.SetMarginType(self.FOLD_MARGIN, wx.stc.STC_MARGIN_SYMBOL) |
|---|
| 194 | self.SetMarginType(self.SELECT_MARGIN, wx.stc.STC_MARGIN_SYMBOL) |
|---|
| 195 | self.SetMarginType(self.NUMBER_MARGIN, wx.stc.STC_MARGIN_NUMBER) |
|---|
| 196 | |
|---|
| 197 | |
|---|
| 198 | self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDER, wx.stc.STC_MARK_PLUS) |
|---|
| 199 | self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPEN, wx.stc.STC_MARK_MINUS) |
|---|
| 200 | self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEREND, wx.stc.STC_MARK_EMPTY) |
|---|
| 201 | self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERMIDTAIL, wx.stc.STC_MARK_EMPTY) |
|---|
| 202 | self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDEROPENMID, wx.stc.STC_MARK_EMPTY) |
|---|
| 203 | self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERSUB, wx.stc.STC_MARK_EMPTY) |
|---|
| 204 | self.MarkerDefine(wx.stc.STC_MARKNUM_FOLDERTAIL, wx.stc.STC_MARK_EMPTY) |
|---|
| 205 | self.SetFoldFlags(16) |
|---|
| 206 | |
|---|
| 207 | self.SetMarginSensitive(self.FOLD_MARGIN, True) |
|---|
| 208 | self.StyleSetSpec(wx.stc.STC_STYLE_DEFAULT, "face:%(mono)s,size:%(size)d" % |
|---|
| 209 | self.presenter.getDefaultFontFaces()) |
|---|
| 210 | |
|---|
| 211 | |
|---|
| 212 | |
|---|
| 213 | for i in xrange(32): |
|---|
| 214 | self.StyleSetEOLFilled(i, True) |
|---|
| 215 | |
|---|
| 216 | |
|---|
| 217 | self.SetLexer(wx.stc.STC_LEX_CONTAINER) |
|---|
| 218 | |
|---|
| 219 | |
|---|
| 220 | |
|---|
| 221 | self.SetDropTarget(WikiTxtCtrlDropTarget(self)) |
|---|
| 222 | |
|---|
| 223 | |
|---|
| 224 | |
|---|
| 225 | |
|---|
| 226 | |
|---|
| 227 | |
|---|
| 228 | |
|---|
| 229 | |
|---|
| 230 | |
|---|
| 231 | |
|---|
| 232 | |
|---|
| 233 | |
|---|
| 234 | |
|---|
| 235 | |
|---|
| 236 | |
|---|
| 237 | |
|---|
| 238 | |
|---|
| 239 | |
|---|
| 240 | |
|---|
| 241 | |
|---|
| 242 | |
|---|
| 243 | |
|---|
| 244 | |
|---|
| 245 | |
|---|
| 246 | |
|---|
| 247 | self.SetModEventMask( |
|---|
| 248 | wx.stc.STC_MOD_INSERTTEXT | wx.stc.STC_MOD_DELETETEXT) |
|---|
| 249 | |
|---|
| 250 | |
|---|
| 251 | self.AutoCompSetSeparator(1) |
|---|
| 252 | self.AutoCompSetTypeSeparator(2) |
|---|
| 253 | |
|---|
| 254 | |
|---|
| 255 | self.presenterListener = wxKeyFunctionSink(( |
|---|
| 256 | ("saving all pages", self.onSavingAllPages), |
|---|
| 257 | ("closing current wiki", self.onClosingCurrentWiki), |
|---|
| 258 | ("dropping current wiki", self.onDroppingCurrentWiki), |
|---|
| 259 | ("reloaded current doc page", self.onReloadedCurrentPage) |
|---|
| 260 | ), self.presenter.getMiscEvent()) |
|---|
| 261 | |
|---|
| 262 | self.__sinkApp = wxKeyFunctionSink(( |
|---|
| 263 | ("options changed", self.onOptionsChanged), |
|---|
| 264 | ), wx.GetApp().getMiscEvent(), self) |
|---|
| 265 | |
|---|
| 266 | self.__sinkGlobalConfig = wxKeyFunctionSink(( |
|---|
| 267 | ("changed configuration", self.onChangedConfiguration), |
|---|
| 268 | ), wx.GetApp().getGlobalConfig().getMiscEvent(), self) |
|---|
| 269 | |
|---|
| 270 | |
|---|
| 271 | |
|---|
| 272 | |
|---|
| 273 | |
|---|
| 274 | |
|---|
| 275 | |
|---|
| 276 | |
|---|
| 277 | |
|---|
| 278 | self.__sinkMainFrame = wxKeyFunctionSink(( |
|---|
| 279 | ("idle visible", self.onIdleVisible), |
|---|
| 280 | ), self.presenter.getMainControl().getMiscEvent(), self) |
|---|
| 281 | |
|---|
| 282 | |
|---|
| 283 | |
|---|
| 284 | |
|---|
| 285 | |
|---|
| 286 | self.wikiPageSink = wxKeyFunctionSink(( |
|---|
| 287 | ("updated wiki page", self.onWikiPageUpdated), |
|---|
| 288 | ("modified spell checker session", self.OnStyleNeeded), |
|---|
| 289 | ("changed read only flag", self.onPageChangedReadOnlyFlag) |
|---|
| 290 | )) |
|---|
| 291 | |
|---|
| 292 | |
|---|
| 293 | wx.stc.EVT_STC_STYLENEEDED(self, ID, self.OnStyleNeeded) |
|---|
| 294 | wx.stc.EVT_STC_CHARADDED(self, ID, self.OnCharAdded) |
|---|
| 295 | wx.stc.EVT_STC_MODIFIED(self, ID, self.OnModified) |
|---|
| 296 | wx.stc.EVT_STC_USERLISTSELECTION(self, ID, self.OnUserListSelection) |
|---|
| 297 | wx.stc.EVT_STC_MARGINCLICK(self, ID, self.OnMarginClick) |
|---|
| 298 | wx.stc.EVT_STC_DWELLSTART(self, ID, self.OnDwellStart) |
|---|
| 299 | wx.stc.EVT_STC_DWELLEND(self, ID, self.OnDwellEnd) |
|---|
| 300 | |
|---|
| 301 | wx.EVT_LEFT_DOWN(self, self.OnClick) |
|---|
| 302 | wx.EVT_MIDDLE_DOWN(self, self.OnMiddleDown) |
|---|
| 303 | wx.EVT_LEFT_DCLICK(self, self.OnDoubleClick) |
|---|
| 304 | |
|---|
| 305 | if config.getboolean("main", "editor_useImeWorkaround", False): |
|---|
| 306 | wx.EVT_CHAR(self, self.OnChar_ImeWorkaround) |
|---|
| 307 | |
|---|
| 308 | wx.EVT_SET_FOCUS(self, self.OnSetFocus) |
|---|
| 309 | |
|---|
| 310 | wx.EVT_CONTEXT_MENU(self, self.OnContextMenu) |
|---|
| 311 | |
|---|
| 312 | |
|---|
| 313 | self.incSearchPreviousHiddenLines = None |
|---|
| 314 | self.incSearchPreviousHiddenStartLine = -1 |
|---|
| 315 | |
|---|
| 316 | self.onlineSpellCheckerActive = SpellChecker.isSpellCheckSupported() and \ |
|---|
| 317 | self.presenter.getConfig().getboolean( |
|---|
| 318 | "main", "editor_onlineSpellChecker_active", False) |
|---|
| 319 | |
|---|
| 320 | self.optionColorizeSearchFragments = self.presenter.getConfig()\ |
|---|
| 321 | .getboolean("main", "editor_colorizeSearchFragments", False) |
|---|
| 322 | |
|---|
| 323 | self.onOptionsChanged(None) |
|---|
| 324 | |
|---|
| 325 | |
|---|
| 326 | self.lastKeyPressed = time() |
|---|
| 327 | self.eolMode = self.GetEOLMode() |
|---|
| 328 | |
|---|
| 329 | self.contextMenuTokens = None |
|---|
| 330 | self.contextMenuSpellCheckSuggestions = None |
|---|
| 331 | |
|---|
| 332 | |
|---|
| 333 | wx.EVT_MENU(self, GUI_ID.CMD_UNDO, lambda evt: self.Undo()) |
|---|
| 334 | wx.EVT_MENU(self, GUI_ID.CMD_REDO, lambda evt: self.Redo()) |
|---|
| 335 | |
|---|
| 336 | wx.EVT_MENU(self, GUI_ID.CMD_CLIPBOARD_CUT, lambda evt: self.Cut()) |
|---|
| 337 | wx.EVT_MENU(self, GUI_ID.CMD_CLIPBOARD_COPY, lambda evt: self.Copy()) |
|---|
| 338 | wx.EVT_MENU(self, GUI_ID.CMD_CLIPBOARD_PASTE, lambda evt: self.Paste()) |
|---|
| 339 | wx.EVT_MENU(self, GUI_ID.CMD_SELECT_ALL, lambda evt: self.SelectAll()) |
|---|
| 340 | |
|---|
| 341 | wx.EVT_MENU(self, GUI_ID.CMD_TEXT_DELETE, lambda evt: self.ReplaceSelection("")) |
|---|
| 342 | wx.EVT_MENU(self, GUI_ID.CMD_ZOOM_IN, |
|---|
| 343 | lambda evt: self.CmdKeyExecute(wx.stc.STC_CMD_ZOOMIN)) |
|---|
| 344 | wx.EVT_MENU(self, GUI_ID.CMD_ZOOM_OUT, |
|---|
| 345 | lambda evt: self.CmdKeyExecute(wx.stc.STC_CMD_ZOOMOUT)) |
|---|
| 346 | |
|---|
| 347 | |
|---|
| 348 | for sps in self.SUGGESTION_CMD_IDS: |
|---|
| 349 | wx.EVT_MENU(self, sps, self.OnReplaceThisSpellingWithSuggestion) |
|---|
| 350 | |
|---|
| 351 | wx.EVT_MENU(self, GUI_ID.CMD_ADD_THIS_SPELLING_SESSION, |
|---|
| 352 | self.OnAddThisSpellingToIgnoreSession) |
|---|
| 353 | wx.EVT_MENU(self, GUI_ID.CMD_ADD_THIS_SPELLING_GLOBAL, |
|---|
| 354 | self.OnAddThisSpellingToIgnoreGlobal) |
|---|
| 355 | wx.EVT_MENU(self, GUI_ID.CMD_ADD_THIS_SPELLING_LOCAL, |
|---|
| 356 | self.OnAddThisSpellingToIgnoreLocal) |
|---|
| 357 | |
|---|
| 358 | wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_THIS, self.OnActivateThis) |
|---|
| 359 | wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_NEW_TAB_THIS, |
|---|
| 360 | self.OnActivateNewTabThis) |
|---|
| 361 | wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_NEW_TAB_BACKGROUND_THIS, |
|---|
| 362 | self.OnActivateNewTabBackgroundThis) |
|---|
| 363 | wx.EVT_MENU(self, GUI_ID.CMD_ACTIVATE_NEW_WINDOW_THIS, |
|---|
| 364 | self.OnActivateNewWindowThis) |
|---|
| 365 | |
|---|
| 366 | wx.EVT_MENU(self, GUI_ID.CMD_CONVERT_URL_ABSOLUTE_RELATIVE_THIS, |
|---|
| 367 | self.OnConvertUrlAbsoluteRelativeThis) |
|---|
| 368 | |
|---|
| 369 | wx.EVT_MENU(self, GUI_ID.CMD_OPEN_CONTAINING_FOLDER_THIS, |
|---|
| 370 | self.OnOpenContainingFolderThis) |
|---|
| 371 | |
|---|
| 372 | wx.EVT_MENU(self, GUI_ID.CMD_DELETE_FILE, |
|---|
| 373 | self.OnDeleteFile) |
|---|
| 374 | |
|---|
| 375 | wx.EVT_MENU(self, GUI_ID.CMD_RENAME_FILE, |
|---|
| 376 | self.OnRenameFile) |
|---|
| 377 | |
|---|
| 378 | wx.EVT_MENU(self, GUI_ID.CMD_CLIPBOARD_COPY_URL_TO_THIS_ANCHOR, |
|---|
| 379 | self.OnClipboardCopyUrlToThisAnchor) |
|---|
| 380 | |
|---|
| 381 | wx.EVT_MENU(self, GUI_ID.CMD_SELECT_TEMPLATE, self.OnSelectTemplate) |
|---|
| 382 | |
|---|
| 383 | |
|---|
| 384 | |
|---|
| 385 | |
|---|
| 386 | |
|---|
| 387 | |
|---|
| 388 | def getLoadedDocPage(self): |
|---|
| 389 | return self.presenter.getDocPage() |
|---|
| 390 | |
|---|
| 391 | def close(self): |
|---|
| 392 | """ |
|---|
| 393 | Close the editor (=prepare for destruction) |
|---|
| 394 | """ |
|---|
| 395 | self.stylingThreadHolder.setThread(None) |
|---|
| 396 | self.calltipThreadHolder.setThread(None) |
|---|
| 397 | |
|---|
| 398 | self.unloadCurrentDocPage({}) |
|---|
| 399 | self.presenterListener.disconnect() |
|---|
| 400 | |
|---|
| 401 | |
|---|
| 402 | |
|---|
| 403 | |
|---|
| 404 | |
|---|
| 405 | |
|---|
| 406 | |
|---|
| 407 | |
|---|
| 408 | |
|---|
| 409 | |
|---|
| 410 | def Copy(self, text=None): |
|---|
| 411 | if text is None: |
|---|
| 412 | text = self.GetSelectedText() |
|---|
| 413 | |
|---|
| 414 | if len(text) == 0: |
|---|
| 415 | return |
|---|
| 416 | |
|---|
| 417 | cbIcept = self.presenter.getMainControl().getClipboardInterceptor() |
|---|
| 418 | if cbIcept is not None: |
|---|
| 419 | cbIcept.informCopyInWikidPadStart(text=text) |
|---|
| 420 | try: |
|---|
| 421 | copyTextToClipboard(text) |
|---|
| 422 | finally: |
|---|
| 423 | cbIcept.informCopyInWikidPadStop() |
|---|
| 424 | else: |
|---|
| 425 | copyTextToClipboard(text) |
|---|
| 426 | |
|---|
| 427 | def Paste(self): |
|---|
| 428 | |
|---|
| 429 | text = getTextFromClipboard() |
|---|
| 430 | if text: |
|---|
| 431 | self.ReplaceSelection(text) |
|---|
| 432 | return True |
|---|
| 433 | |
|---|
| 434 | |
|---|
| 435 | filenames = wxHelper.getFilesFromClipboard() |
|---|
| 436 | if filenames is not None: |
|---|
| 437 | mc = self.presenter.getMainControl() |
|---|
| 438 | |
|---|
| 439 | paramDict = {"editor": self, "filenames": filenames, |
|---|
| 440 | "x": -1, "y": -1, "main control": mc, |
|---|
| 441 | "processDirectly": True} |
|---|
| 442 | |
|---|
| 443 | mc.getUserActionCoord().runAction( |
|---|
| 444 | u"action/editor/this/paste/files/insert/url/ask", paramDict) |
|---|
| 445 | |
|---|
| 446 | return True |
|---|
| 447 | |
|---|
| 448 | fs = self.presenter.getWikiDocument().getFileStorage() |
|---|
| 449 | imgsav = WikiTxtDialogs.ImagePasteSaver() |
|---|
| 450 | imgsav.readOptionsFromConfig(self.presenter.getConfig()) |
|---|
| 451 | |
|---|
| 452 | |
|---|
| 453 | bmp = wxHelper.getBitmapFromClipboard() |
|---|
| 454 | if bmp is not None: |
|---|
| 455 | img = bmp.ConvertToImage() |
|---|
| 456 | del bmp |
|---|
| 457 | |
|---|
| 458 | if self.presenter.getConfig().getboolean("main", |
|---|
| 459 | "editor_imagePaste_askOnEachPaste", True): |
|---|
| 460 | |
|---|
| 461 | |
|---|
| 462 | dlg = WikiTxtDialogs.ImagePasteDialog( |
|---|
| 463 | self.presenter.getMainControl(), -1, imgsav, img) |
|---|
| 464 | try: |
|---|
| 465 | dlg.ShowModal() |
|---|
| 466 | imgsav = dlg.getImagePasteSaver() |
|---|
| 467 | finally: |
|---|
| 468 | dlg.Destroy() |
|---|
| 469 | |
|---|
| 470 | destPath = imgsav.saveFile(fs, img) |
|---|
| 471 | if destPath is None: |
|---|
| 472 | |
|---|
| 473 | return True |
|---|
| 474 | |
|---|
| 475 | |
|---|
| 476 | |
|---|
| 477 | |
|---|
| 478 | |
|---|
| 479 | |
|---|
| 480 | |
|---|
| 481 | |
|---|
| 482 | |
|---|
| 483 | |
|---|
| 484 | url = self.presenter.getWikiDocument().makeAbsPathRelUrl(destPath) |
|---|
| 485 | |
|---|
| 486 | if url is None: |
|---|
| 487 | url = u"file:" + StringOps.urlFromPathname(destPath) |
|---|
| 488 | |
|---|
| 489 | self.ReplaceSelection(url) |
|---|
| 490 | |
|---|
| 491 | |
|---|
| 492 | |
|---|
| 493 | |
|---|
| 494 | |
|---|
| 495 | |
|---|
| 496 | |
|---|
| 497 | |
|---|
| 498 | |
|---|
| 499 | |
|---|
| 500 | |
|---|
| 501 | |
|---|
| 502 | |
|---|
| 503 | |
|---|
| 504 | |
|---|
| 505 | |
|---|
| 506 | return True |
|---|
| 507 | |
|---|
| 508 | if not WindowsHacks: |
|---|
| 509 | return False |
|---|
| 510 | |
|---|
| 511 | |
|---|
| 512 | destPath = imgsav.saveWmfFromClipboardToFileStorage(fs) |
|---|
| 513 | if destPath is not None: |
|---|
| 514 | url = self.presenter.getWikiDocument().makeAbsPathRelUrl(destPath) |
|---|
| 515 | |
|---|
| 516 | if url is None: |
|---|
| 517 | url = u"file:" + StringOps.urlFromPathname(destPath) |
|---|
| 518 | |
|---|
| 519 | self.ReplaceSelection(url) |
|---|
| 520 | return True |
|---|
| 521 | |
|---|
| 522 | |
|---|
| 523 | |
|---|
| 524 | |
|---|
| 525 | |
|---|
| 526 | |
|---|
| 527 | |
|---|
| 528 | |
|---|
| 529 | |
|---|
| 530 | |
|---|
| 531 | |
|---|
| 532 | |
|---|
| 533 | |
|---|
| 534 | |
|---|
| 535 | |
|---|
| 536 | |
|---|
| 537 | |
|---|
| 538 | |
|---|
| 539 | return False |
|---|
| 540 | |
|---|
| 541 | |
|---|
| 542 | def onCmdCopy(self, miscevt): |
|---|
| 543 | if wx.Window.FindFocus() != self: |
|---|
| 544 | return |
|---|
| 545 | self.Copy() |
|---|
| 546 | |
|---|
| 547 | |
|---|
| 548 | |
|---|
| 549 | def setLayerVisible(self, vis, scName=""): |
|---|
| 550 | """ |
|---|
| 551 | Informs the widget if it is really visible on the screen or not |
|---|
| 552 | """ |
|---|
| 553 | |
|---|
| 554 | |
|---|
| 555 | self.Enable(vis) |
|---|
| 556 | |
|---|
| 557 | def setWrapMode(self, onOrOff): |
|---|
| 558 | if onOrOff: |
|---|
| 559 | self.SetWrapMode(wx.stc.STC_WRAP_WORD) |
|---|
| 560 | else: |
|---|
| 561 | self.SetWrapMode(wx.stc.STC_WRAP_NONE) |
|---|
| 562 | |
|---|
| 563 | def getWrapMode(self): |
|---|
| 564 | return self.GetWrapMode() == wx.stc.STC_WRAP_WORD |
|---|
| 565 | |
|---|
| 566 | def setAutoIndent(self, onOff): |
|---|
| 567 | self.autoIndent = onOff |
|---|
| 568 | |
|---|
| 569 | def getAutoIndent(self): |
|---|
| 570 | return self.autoIndent |
|---|
| 571 | |
|---|
| 572 | def setAutoBullets(self, onOff): |
|---|
| 573 | self.autoBullets = onOff |
|---|
| 574 | |
|---|
| 575 | def getAutoBullets(self): |
|---|
| 576 | return self.autoBullets |
|---|
| 577 | |
|---|
| 578 | def setTabsToSpaces(self, onOff): |
|---|
| 579 | self.tabsToSpaces = onOff |
|---|
| 580 | self.SetUseTabs(not onOff) |
|---|
| 581 | |
|---|
| 582 | def getTabsToSpaces(self): |
|---|
| 583 | return self.tabsToSpaces |
|---|
| 584 | |
|---|
| 585 | def setShowLineNumbers(self, onOrOff): |
|---|
| 586 | if onOrOff: |
|---|
| 587 | self.SetMarginWidth(self.NUMBER_MARGIN, |
|---|
| 588 | self.TextWidth(wx.stc.STC_STYLE_LINENUMBER, "_99999")) |
|---|
| 589 | self.SetMarginWidth(self.SELECT_MARGIN, 0) |
|---|
| 590 | else: |
|---|
| 591 | self.SetMarginWidth(self.NUMBER_MARGIN, 0) |
|---|
| 592 | self.SetMarginWidth(self.SELECT_MARGIN, 16) |
|---|
| 593 | |
|---|
| 594 | def getShowLineNumbers(self): |
|---|
| 595 | return self.GetMarginWidth(self.NUMBER_MARGIN) != 0 |
|---|
| 596 | |
|---|
| 597 | |
|---|
| 598 | def setFoldingActive(self, onOrOff, forceSync=False): |
|---|
| 599 | """ |
|---|
| 600 | forceSync -- when setting folding on, the folding is completed |
|---|
| 601 | before function returns iff forceSync is True |
|---|
| 602 | """ |
|---|
| 603 | if onOrOff: |
|---|
| 604 | self.SetMarginWidth(self.FOLD_MARGIN, 16) |
|---|
| 605 | self.foldingActive = True |
|---|
| 606 | if forceSync: |
|---|
| 607 | try: |
|---|
| 608 | self.applyFolding(self.processFolding( |
|---|
| 609 | self.getPageAst(), DUMBTHREADSTOP)) |
|---|
| 610 | except NoPageAstException: |
|---|
| 611 | return |
|---|
| 612 | else: |
|---|
| 613 | self.OnStyleNeeded(None) |
|---|
| 614 | else: |
|---|
| 615 | self.SetMarginWidth(self.FOLD_MARGIN, 0) |
|---|
| 616 | self.unfoldAll() |
|---|
| 617 | self.foldingActive = False |
|---|
| 618 | |
|---|
| 619 | def getFoldingActive(self): |
|---|
| 620 | return self.foldingActive |
|---|
| 621 | |
|---|
| 622 | |
|---|
| 623 | def SetStyles(self, styleFaces = None): |
|---|
| 624 | self.SetStyleBits(5) |
|---|
| 625 | |
|---|
| 626 | |
|---|
| 627 | if styleFaces is None: |
|---|
| 628 | styleFaces = self.presenter.getDefaultFontFaces() |
|---|
| 629 | |
|---|
| 630 | config = self.presenter.getConfig() |
|---|
| 631 | styles = self.presenter.getMainControl().getPresentationExt()\ |
|---|
| 632 | .getStyles(styleFaces, config) |
|---|
| 633 | |
|---|
| 634 | for type, style in styles: |
|---|
| 635 | self.StyleSetSpec(type, style) |
|---|
| 636 | |
|---|
| 637 | if type == wx.stc.STC_STYLE_CALLTIP: |
|---|
| 638 | self.CallTipUseStyle(10) |
|---|
| 639 | |
|---|
| 640 | self.IndicatorSetStyle(2, wx.stc.STC_INDIC_SQUIGGLE) |
|---|
| 641 | self.IndicatorSetForeground(2, wx.Colour(255, 0, 0)) |
|---|
| 642 | |
|---|
| 643 | |
|---|
| 644 | def SetText(self, text, emptyUndo=True): |
|---|
| 645 | """ |
|---|
| 646 | Overrides the wxStyledTextCtrl method. |
|---|
| 647 | text -- Unicode text content to set |
|---|
| 648 | """ |
|---|
| 649 | self.incSearchCharStartPos = 0 |
|---|
| 650 | self.clearStylingCache() |
|---|
| 651 | self.pageType = "normal" |
|---|
| 652 | |
|---|
| 653 | self.SetSelection(-1, -1) |
|---|
| 654 | self.ignoreOnChange = True |
|---|
| 655 | if isUnicode(): |
|---|
| 656 | wx.stc.StyledTextCtrl.SetText(self, text) |
|---|
| 657 | else: |
|---|
| 658 | wx.stc.StyledTextCtrl.SetText(self, |
|---|
| 659 | StringOps.mbcsEnc(text, "replace")[0]) |
|---|
| 660 | self.ignoreOnChange = False |
|---|
| 661 | |
|---|
| 662 | if emptyUndo: |
|---|
| 663 | self.EmptyUndoBuffer() |
|---|
| 664 | |
|---|
| 665 | |
|---|
| 666 | |
|---|
| 667 | def replaceText(self, text): |
|---|
| 668 | if isUnicode(): |
|---|
| 669 | wx.stc.StyledTextCtrl.SetText(self, text) |
|---|
| 670 | else: |
|---|
| 671 | wx.stc.StyledTextCtrl.SetText(self, |
|---|
| 672 | StringOps.mbcsEnc(text, "replace")[0]) |
|---|
| 673 | |
|---|
| 674 | |
|---|
| 675 | def replaceTextAreaByCharPos(self, newText, start, end): |
|---|
| 676 | text = self.GetText() |
|---|
| 677 | bs = self.bytelenSct(text[:start]) |
|---|
| 678 | be = bs + self.bytelenSct(text[start:end]) |
|---|
| 679 | self.SetTargetStart(bs) |
|---|
| 680 | self.SetTargetEnd(be) |
|---|
| 681 | |
|---|
| 682 | if isUnicode(): |
|---|
| 683 | self.ReplaceTarget(newText) |
|---|
| 684 | else: |
|---|
| 685 | self.ReplaceTarget(StringOps.mbcsEnc(newText, "replace")[0]) |
|---|
| 686 | |
|---|
| 687 | |
|---|
| 688 | |
|---|
| 689 | |
|---|
| 690 | |
|---|
| 691 | |
|---|
| 692 | |
|---|
| 693 | def showSelectionByCharPos(self, start, end): |
|---|
| 694 | """ |
|---|
| 695 | Same as SetSelectionByCharPos(), but scrolls to position correctly |
|---|
| 696 | """ |
|---|
| 697 | text = self.GetText() |
|---|
| 698 | bs = self.bytelenSct(text[:start]) |
|---|
| 699 | be = bs + self.bytelenSct(text[start:end]) |
|---|
| 700 | |
|---|
| 701 | self.ensureTextRangeByBytePosExpanded(bs, be) |
|---|
| 702 | super(WikiTxtCtrl, self).showSelectionByCharPos(start, end) |
|---|
| 703 | |
|---|
| 704 | |
|---|
| 705 | def applyBasicSciSettings(self): |
|---|
| 706 | """ |
|---|
| 707 | Apply the basic Scintilla settings which are resetted to wrong |
|---|
| 708 | default values by some operations |
|---|
| 709 | """ |
|---|
| 710 | if isUnicode(): |
|---|
| 711 | self.SetCodePage(wx.stc.STC_CP_UTF8) |
|---|
| 712 | self.SetTabIndents(True) |
|---|
| 713 | self.SetBackSpaceUnIndents(True) |
|---|
| 714 | self.SetUseTabs(not self.tabsToSpaces) |
|---|
| 715 | self.SetEOLMode(wx.stc.STC_EOL_LF) |
|---|
| 716 | |
|---|
| 717 | tabWidth = self.presenter.getConfig().getint("main", |
|---|
| 718 | "editor_tabWidth", 4) |
|---|
| 719 | |
|---|
| 720 | self.SetIndent(tabWidth) |
|---|
| 721 | self.SetTabWidth(tabWidth) |
|---|
| 722 | |
|---|
| 723 | self.AutoCompSetFillUps(u":=") |
|---|
| 724 | |
|---|
| 725 | |
|---|
| 726 | self.SetYCaretPolicy(wx.stc.STC_CARET_SLOP | wx.stc.STC_CARET_EVEN, 4) |
|---|
| 727 | |
|---|
| 728 | |
|---|
| 729 | |
|---|
| 730 | def saveLoadedDocPage(self): |
|---|
| 731 | """ |
|---|
| 732 | Save loaded wiki page into database. Does not check if dirty |
|---|
| 733 | """ |
|---|
| 734 | if self.getLoadedDocPage() is None: |
|---|
| 735 | return |
|---|
| 736 | |
|---|
| 737 | page = self.getLoadedDocPage() |
|---|
| 738 | |
|---|
| 739 | |
|---|
| 740 | |
|---|
| 741 | |
|---|
| 742 | |
|---|
| 743 | |
|---|
| 744 | if self.presenter.getMainControl().saveDocPage(page): |
|---|
| 745 | self.SetSavePoint() |
|---|
| 746 | |
|---|
| 747 | |
|---|
| 748 | def unloadCurrentDocPage(self, evtprops=None): |
|---|
| 749 | |
|---|
| 750 | |
|---|
| 751 | self.stylingThreadHolder.setThread(None) |
|---|
| 752 | self.calltipThreadHolder.setThread(None) |
|---|
| 753 | |
|---|
| 754 | docPage = self.getLoadedDocPage() |
|---|
| 755 | if docPage is not None: |
|---|
| 756 | wikiWord = docPage.getWikiWord() |
|---|
| 757 | if wikiWord is not None: |
|---|
| 758 | docPage.setPresentation((self.GetCurrentPos(), |
|---|
| 759 | self.GetScrollPos(wx.HORIZONTAL), |
|---|
| 760 | self.GetScrollPos(wx.VERTICAL)), 0) |
|---|
| 761 | docPage.setPresentation((self.getFoldInfo(),), 5) |
|---|
| 762 | |
|---|
| 763 | if docPage.getDirty()[0]: |
|---|
| 764 | self.saveLoadedDocPage() |
|---|
| 765 | |
|---|
| 766 | docPage.removeTxtEditor(self) |
|---|
| 767 | |
|---|
| 768 | self.SetDocPointer(None) |
|---|
| 769 | self.applyBasicSciSettings() |
|---|
| 770 | |
|---|
| 771 | self.wikiPageSink.disconnect() |
|---|
| 772 | |
|---|
| 773 | self.presenter.setDocPage(None) |
|---|
| 774 | |
|---|
| 775 | self.clearStylingCache() |
|---|
| 776 | |
|---|
| 777 | |
|---|
| 778 | |
|---|
| 779 | self.pageType = "normal" |
|---|
| 780 | |
|---|
| 781 | |
|---|
| 782 | |
|---|
| 783 | |
|---|
| 784 | def loadFuncPage(self, funcPage, evtprops=None): |
|---|
| 785 | self.unloadCurrentDocPage(evtprops) |
|---|
| 786 | |
|---|
| 787 | content = None |
|---|
| 788 | wikiDataManager = self.presenter.getWikiDocument() |
|---|
| 789 | |
|---|
| 790 | self.presenter.setDocPage(funcPage) |
|---|
| 791 | |
|---|
| 792 | if self.getLoadedDocPage() is None: |
|---|
| 793 | return |
|---|
| 794 | |
|---|
| 795 | globalAttrs = wikiDataManager.getWikiData().getGlobalAttributes() |
|---|
| 796 | |
|---|
| 797 | font = globalAttrs.get("global.font", self.defaultFont) |
|---|
| 798 | |
|---|
| 799 | |
|---|
| 800 | if self.lastFont != font: |
|---|
| 801 | faces = self.presenter.getDefaultFontFaces().copy() |
|---|
| 802 | faces["mono"] = font |
|---|
| 803 | self.SetStyles(faces) |
|---|
| 804 | self.lastEditorFont = font |
|---|
| 805 | |
|---|
| 806 | |
|---|
| 807 | |
|---|
| 808 | |
|---|
| 809 | |
|---|
| 810 | self.wikiPageSink.setEventSource(self.getLoadedDocPage().getMiscEvent()) |
|---|
| 811 | |
|---|
| 812 | otherEditor = self.getLoadedDocPage().getTxtEditor() |
|---|
| 813 | if otherEditor is not None: |
|---|
| 814 | |
|---|
| 815 | |
|---|
| 816 | self.SetDocPointer(otherEditor.GetDocPointer()) |
|---|
| 817 | self.applyBasicSciSettings() |
|---|
| 818 | else: |
|---|
| 819 | |
|---|
| 820 | try: |
|---|
| 821 | content = self.getLoadedDocPage().getLiveText() |
|---|
| 822 | except WikiFileNotFoundException, e: |
|---|
| 823 | assert 0 |
|---|
| 824 | |
|---|
| 825 | |
|---|
| 826 | self.SetReadOnly(False) |
|---|
| 827 | self.SetText(content) |
|---|
| 828 | |
|---|
| 829 | self.getLoadedDocPage().addTxtEditor(self) |
|---|
| 830 | self._checkForReadOnly() |
|---|
| 831 | self.presenter.setTitle(self.getLoadedDocPage().getTitle()) |
|---|
| 832 | |
|---|
| 833 | |
|---|
| 834 | def loadWikiPage(self, wikiPage, evtprops=None): |
|---|
| 835 | """ |
|---|
| 836 | Save loaded page, if necessary, then load wikiPage into editor |
|---|
| 837 | """ |
|---|
| 838 | self.unloadCurrentDocPage(evtprops) |
|---|
| 839 | |
|---|
| 840 | wikiDataManager = self.presenter.getWikiDocument() |
|---|
| 841 | |
|---|
| 842 | self.presenter.setDocPage(wikiPage) |
|---|
| 843 | |
|---|
| 844 | docPage = self.getLoadedDocPage() |
|---|
| 845 | |
|---|
| 846 | if docPage is None: |
|---|
| 847 | return |
|---|
| 848 | |
|---|
| 849 | self.wikiPageSink.setEventSource(docPage.getMiscEvent()) |
|---|
| 850 | |
|---|
| 851 | otherEditor = docPage.getTxtEditor() |
|---|
| 852 | if otherEditor is not None: |
|---|
| 853 | |
|---|
| 854 | |
|---|
| 855 | self.SetDocPointer(otherEditor.GetDocPointer()) |
|---|
| 856 | self.applyBasicSciSettings() |
|---|
| 857 | else: |
|---|
| 858 | |
|---|
| 859 | try: |
|---|
| 860 | content = docPage.getLiveText() |
|---|
| 861 | except WikiFileNotFoundException, e: |
|---|
| 862 | assert 0 |
|---|
| 863 | |
|---|
| 864 | |
|---|
| 865 | self.SetReadOnly(False) |
|---|
| 866 | self.setTextAgaUpdated(content) |
|---|
| 867 | |
|---|
| 868 | if self.wikiLanguageHelper is None or \ |
|---|
| 869 | self.wikiLanguageHelper.getWikiLanguageName() != \ |
|---|
| 870 | docPage.getWikiLanguageName(): |
|---|
| 871 | |
|---|
| 872 | wx.GetApp().freeWikiLanguageHelper(self.wikiLanguageHelper) |
|---|
| 873 | self.wikiLanguageHelper = docPage.createWikiLanguageHelper() |
|---|
| 874 | |
|---|
| 875 | docPage.addTxtEditor(self) |
|---|
| 876 | self._checkForReadOnly() |
|---|
| 877 | |
|---|
| 878 | if evtprops is None: |
|---|
| 879 | evtprops = {} |
|---|
| 880 | p2 = evtprops.copy() |
|---|
| 881 | p2.update({"loading wiki page": True, "wikiPage": docPage}) |
|---|
| 882 | self.presenter.fireMiscEventProps(p2) |
|---|
| 883 | |
|---|
| 884 | |
|---|
| 885 | font = docPage.getAttributeOrGlobal("font", self.defaultFont) |
|---|
| 886 | |
|---|
| 887 | |
|---|
| 888 | if self.lastFont != font: |
|---|
| 889 | faces = self.presenter.getDefaultFontFaces().copy() |
|---|
| 890 | faces["mono"] = font |
|---|
| 891 | self.SetStyles(faces) |
|---|
| 892 | self.lastEditorFont = font |
|---|
| 893 | |
|---|
| 894 | self.pageType = docPage.getAttributes().get(u"pagetype", |
|---|
| 895 | [u"normal"])[-1] |
|---|
| 896 | |
|---|
| 897 | if self.pageType == u"normal": |
|---|
| 898 | if not docPage.isDefined(): |
|---|
| 899 | |
|---|
| 900 | self.GotoPos(self.GetLength()) |
|---|
| 901 | else: |
|---|
| 902 | anchor = evtprops.get("anchor") |
|---|
| 903 | if anchor: |
|---|
| 904 | |
|---|
| 905 | pageAst = self.getPageAst() |
|---|
| 906 | |
|---|
| 907 | anchorNodes = pageAst.iterDeepByName("anchorDef") |
|---|
| 908 | for node in anchorNodes: |
|---|
| 909 | if node.anchorLink == anchor: |
|---|
| 910 | self.gotoCharPos(node.pos + node.strLength) |
|---|
| 911 | break |
|---|
| 912 | else: |
|---|
| 913 | anchor = None |
|---|
| 914 | |
|---|
| 915 | if not anchor: |
|---|
| 916 | |
|---|
| 917 | firstcharpos = evtprops.get("firstcharpos", -1) |
|---|
| 918 | if firstcharpos != -1: |
|---|
| 919 | charlength = max(0, evtprops.get("charlength", 0)) |
|---|
| 920 | self.showSelectionByCharPos(firstcharpos, |
|---|
| 921 | firstcharpos + charlength) |
|---|
| 922 | anchor = True |
|---|
| 923 | |
|---|
| 924 | if not anchor: |
|---|
| 925 | |
|---|
| 926 | prst = docPage.getPresentation() |
|---|
| 927 | lastPos, scrollPosX, scrollPosY = prst[0:3] |
|---|
| 928 | foldInfo = prst[5] |
|---|
| 929 | self.setFoldInfo(foldInfo) |
|---|
| 930 | self.GotoPos(lastPos) |
|---|
| 931 | |
|---|
| 932 | self.scrollXY(scrollPosX, scrollPosY) |
|---|
| 933 | else: |
|---|
| 934 | self.handleSpecialPageType() |
|---|
| 935 | |
|---|
| 936 | self.presenter.setTitle(docPage.getTitle()) |
|---|
| 937 | |
|---|
| 938 | |
|---|
| 939 | def handleSpecialPageType(self): |
|---|
| 940 | |
|---|
| 941 | |
|---|
| 942 | if self.pageType == u"form": |
|---|
| 943 | self.GotoPos(0) |
|---|
| 944 | self._goToNextFormField() |
|---|
| 945 | return True |
|---|
| 946 | |
|---|
| 947 | return False |
|---|
| 948 | |
|---|
| 949 | |
|---|
| 950 | def onReloadedCurrentPage(self, miscevt): |
|---|
| 951 | """ |
|---|
| 952 | Called when already loaded page should be loaded again, mainly |
|---|
| 953 | interesting if a link with anchor is activated |
|---|
| 954 | """ |
|---|
| 955 | if not self.presenter.isCurrent(): |
|---|
| 956 | return |
|---|
| 957 | |
|---|
| 958 | anchor = miscevt.get("anchor") |
|---|
| 959 | if not anchor: |
|---|
| 960 | if self.pageType == u"normal": |
|---|
| 961 | |
|---|
| 962 | firstcharpos = miscevt.get("firstcharpos", -1) |
|---|
| 963 | if firstcharpos != -1: |
|---|
| 964 | charlength = max(0, miscevt.get("charlength", 0)) |
|---|
| 965 | self.showSelectionByCharPos(firstcharpos, |
|---|
| 966 | firstcharpos + charlength) |
|---|
| 967 | |
|---|
| 968 | return |
|---|
| 969 | |
|---|
| 970 | |
|---|
| 971 | |
|---|
| 972 | |
|---|
| 973 | |
|---|
| 974 | docPage = self.getLoadedDocPage() |
|---|
| 975 | |
|---|
| 976 | if not docPage.isDefined(): |
|---|
| 977 | return |
|---|
| 978 | |
|---|
| 979 | if self.wikiLanguageHelper is None or \ |
|---|
| 980 | self.wikiLanguageHelper.getWikiLanguageName() != \ |
|---|
| 981 | docPage.getWikiLanguageName(): |
|---|
| 982 | |
|---|
| 983 | wx.GetApp().freeWikiLanguageHelper(self.wikiLanguageHelper) |
|---|
| 984 | self.wikiLanguageHelper = docPage.createWikiLanguageHelper() |
|---|
| 985 | |
|---|
| 986 | if self.pageType == u"normal": |
|---|
| 987 | |
|---|
| 988 | try: |
|---|
| 989 | anchorNodes = self.getPageAst().iterDeepByName("anchorDef") |
|---|
| 990 | anchorNodes = self.getPageAst().iterDeepByName("anchorDef") |
|---|
| 991 | for node in anchorNodes: |
|---|
| 992 | if node.anchorLink == anchor: |
|---|
| 993 | self.gotoCharPos(node.pos + node.strLength) |
|---|
| 994 | break |
|---|
| 995 | |
|---|
| 996 | |
|---|
| 997 | |
|---|
| 998 | except NoPageAstException: |
|---|
| 999 | return |
|---|
| 1000 | |
|---|
| 1001 | |
|---|
| 1002 | def _checkForReadOnly(self): |
|---|
| 1003 | """ |
|---|
| 1004 | Set/unset read-only mode of editor according to read-only state of page. |
|---|
| 1005 | """ |
|---|
| 1006 | docPage = self.getLoadedDocPage() |
|---|
| 1007 | if docPage is None: |
|---|
| 1008 | self.SetReadOnly(True) |
|---|
| 1009 | else: |
|---|
| 1010 | self.SetReadOnly(docPage.isReadOnlyEffect()) |
|---|
| 1011 | |
|---|
| 1012 | |
|---|
| 1013 | def _getColorFromOption(self, option, defColTuple): |
|---|
| 1014 | """ |
|---|
| 1015 | Helper for onOptionsChanged() to read a color from an option |
|---|
| 1016 | and create a wx.Colour object from it. |
|---|
| 1017 | """ |
|---|
| 1018 | coltuple = StringOps.colorDescToRgbTuple(self.presenter.getConfig().get( |
|---|
| 1019 | "main", option)) |
|---|
| 1020 | |
|---|
| 1021 | if coltuple is None: |
|---|
| 1022 | coltuple = defColTuple |
|---|
| 1023 | |
|---|
| 1024 | return wx.Colour(*coltuple) |
|---|
| 1025 | |
|---|
| 1026 | |
|---|
| 1027 | def onPageChangedReadOnlyFlag(self, miscevt): |
|---|
| 1028 | self._checkForReadOnly() |
|---|
| 1029 | |
|---|
| 1030 | |
|---|
| 1031 | def onOptionsChanged(self, miscevt): |
|---|
| 1032 | faces = self.presenter.getDefaultFontFaces().copy() |
|---|
| 1033 | |
|---|
| 1034 | if isinstance(self.getLoadedDocPage(), |
|---|
| 1035 | (DocPages.WikiPage, DocPages.AliasWikiPage)): |
|---|
| 1036 | |
|---|
| 1037 | font = self.getLoadedDocPage().getAttributeOrGlobal("font", |
|---|
| 1038 | self.defaultFont) |
|---|
| 1039 | faces["mono"] = font |
|---|
| 1040 | self.lastEditorFont = font |
|---|
| 1041 | |
|---|
| 1042 | self._checkForReadOnly() |
|---|
| 1043 | |
|---|
| 1044 | self.SetStyles(faces) |
|---|
| 1045 | |
|---|
| 1046 | color = self._getColorFromOption("editor_bg_color", (255, 255, 255)) |
|---|
| 1047 | |
|---|
| 1048 | for i in xrange(32): |
|---|
| 1049 | self.StyleSetBackground(i, color) |
|---|
| 1050 | self.StyleSetBackground(wx.stc.STC_STYLE_DEFAULT, color) |
|---|
| 1051 | |
|---|
| 1052 | self.SetSelForeground(True, self._getColorFromOption( |
|---|
| 1053 | "editor_selection_fg_color", (0, 0, 0))) |
|---|
| 1054 | self.SetSelBackground(True, self._getColorFromOption( |
|---|
| 1055 | "editor_selection_bg_color", (192, 192, 192))) |
|---|
| 1056 | self.SetCaretForeground(self._getColorFromOption( |
|---|
| 1057 | "editor_caret_color", (0, 0, 0))) |
|---|
| 1058 | |
|---|
| 1059 | self.StyleSetForeground(wx.stc.STC_STYLE_DEFAULT, self._getColorFromOption( |
|---|
| 1060 | "editor_plaintext_color", (0, 0, 0))) |
|---|
| 1061 | self.StyleSetBackground(wx.stc.STC_STYLE_LINENUMBER, self._getColorFromOption( |
|---|
| 1062 | "editor_margin_bg_color", (212, 208, 200))) |
|---|
| 1063 | |
|---|
| 1064 | shorthintDelay = self.presenter.getConfig().getint("main", |
|---|
| 1065 | "editor_shortHint_delay", 500) |
|---|
| 1066 | self.SetMouseDwellTime(shorthintDelay) |
|---|
| 1067 | |
|---|
| 1068 | tabWidth = self.presenter.getConfig().getint("main", |
|---|
| 1069 | "editor_tabWidth", 4) |
|---|
| 1070 | |
|---|
| 1071 | self.SetIndent(tabWidth) |
|---|
| 1072 | self.SetTabWidth(tabWidth) |
|---|
| 1073 | |
|---|
| 1074 | |
|---|
| 1075 | |
|---|
| 1076 | use_vi_navigation = self.presenter.getConfig().getboolean("main", |
|---|
| 1077 | "editor_compatibility_ViKeys", False) |
|---|
| 1078 | |
|---|
| 1079 | self.Unbind(wx.EVT_KEY_DOWN) |
|---|
| 1080 | self.Unbind(wx.EVT_LEFT_UP) |
|---|
| 1081 | |
|---|
| 1082 | if use_vi_navigation: |
|---|
| 1083 | if self.vi is None: |
|---|
| 1084 | self.vi = ViHandler(self) |
|---|
| 1085 | |
|---|
| 1086 | self.Bind(wx.EVT_KEY_DOWN, self.vi.OnViKeyDown) |
|---|
| 1087 | self.Bind(wx.EVT_LEFT_UP, self.vi.OnLeftMouseUp) |
|---|
| 1088 | |
|---|
| 1089 | |
|---|
| 1090 | |
|---|
| 1091 | wx.CallAfter(self.vi._enableMenuShortcuts, False) |
|---|
| 1092 | else: |
|---|
| 1093 | if self.vi is not None: |
|---|
| 1094 | self.vi.TurnOff() |
|---|
| 1095 | self.vi = None |
|---|
| 1096 | self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) |
|---|
| 1097 | |
|---|
| 1098 | |
|---|
| 1099 | def onChangedConfiguration(self, miscevt): |
|---|
| 1100 | """ |
|---|
| 1101 | Called when global configuration was changed. Most things are processed |
|---|
| 1102 | by onOptionsChanged so only the online spell checker switch must be |
|---|
| 1103 | handled here. |
|---|
| 1104 | """ |
|---|
| 1105 | restyle = False |
|---|
| 1106 | |
|---|
| 1107 | newSetting = SpellChecker.isSpellCheckSupported() and \ |
|---|
| 1108 | self.presenter.getConfig().getboolean( |
|---|
| 1109 | "main", "editor_onlineSpellChecker_active", False) |
|---|
| 1110 | |
|---|
| 1111 | if newSetting != self.onlineSpellCheckerActive: |
|---|
| 1112 | self.onlineSpellCheckerActive = newSetting |
|---|
| 1113 | restyle = True |
|---|
| 1114 | |
|---|
| 1115 | newSetting = self.presenter.getConfig()\ |
|---|
| 1116 | .getboolean("main", "editor_colorizeSearchFragments", False) |
|---|
| 1117 | |
|---|
| 1118 | if newSetting != self.optionColorizeSearchFragments: |
|---|
| 1119 | self.optionColorizeSearchFragments = newSetting |
|---|
| 1120 | restyle = True |
|---|
| 1121 | |
|---|
| 1122 | if restyle: |
|---|
| 1123 | self.OnStyleNeeded(None) |
|---|
| 1124 | |
|---|
| 1125 | |
|---|
| 1126 | |
|---|
| 1127 | def onWikiPageUpdated(self, miscevt): |
|---|
| 1128 | if self.getLoadedDocPage() is None or \ |
|---|
| 1129 | not isinstance(self.getLoadedDocPage(), |
|---|
| 1130 | (DocPages.WikiPage, DocPages.AliasWikiPage)): |
|---|
| 1131 | return |
|---|
| 1132 | |
|---|
| 1133 | |
|---|
| 1134 | font = self.getLoadedDocPage().getAttributeOrGlobal("font", |
|---|
| 1135 | self.defaultFont) |
|---|
| 1136 | |
|---|
| 1137 | |
|---|
| 1138 | if self.lastFont != font: |
|---|
| 1139 | faces = self.presenter.getDefaultFontFaces().copy() |
|---|
| 1140 | faces["mono"] = font |
|---|
| 1141 | self.SetStyles(faces) |
|---|
| 1142 | self.lastEditorFont = font |
|---|
| 1143 | |
|---|
| 1144 | self.pageType = self.getLoadedDocPage().getAttributes().get(u"pagetype", |
|---|
| 1145 | [u"normal"])[-1] |
|---|
| 1146 | |
|---|
| 1147 | |
|---|
| 1148 | def handleInvalidFileSignature(self, docPage): |
|---|
| 1149 | """ |
|---|
| 1150 | Called directly from a doc page to repair the editor state if an |
|---|
| 1151 | invalid file signature was detected. |
|---|
| 1152 | |
|---|
| 1153 | docPage -- calling docpage |
|---|
| 1154 | """ |
|---|
| 1155 | if docPage is not self.getLoadedDocPage() or \ |
|---|
| 1156 | not isinstance(docPage, |
|---|
| 1157 | (DocPages.DataCarryingPage, DocPages.AliasWikiPage)): |
|---|
| 1158 | return |
|---|
| 1159 | |
|---|
| 1160 | sd, ud = docPage.getDirty() |
|---|
| 1161 | if sd: |
|---|
| 1162 | return |
|---|
| 1163 | |
|---|
| 1164 | content = docPage.getContent() |
|---|
| 1165 | docPage.setEditorText(content, dirty=False) |
|---|
| 1166 | self.ignoreOnChange = True |
|---|
| 1167 | |
|---|
| 1168 | self.setTextAgaUpdated(content) |
|---|
| 1169 | self.ignoreOnChange = False |
|---|
| 1170 | |
|---|
| 1171 | |
|---|
| 1172 | def onSavingAllPages(self, miscevt): |
|---|
| 1173 | if self.getLoadedDocPage() is not None and ( |
|---|
| 1174 | self.getLoadedDocPage().getDirty()[0] or miscevt.get("force", |
|---|
| 1175 | False)): |
|---|
| 1176 | self.saveLoadedDocPage() |
|---|
| 1177 | |
|---|
| 1178 | def onClosingCurrentWiki(self, miscevt): |
|---|
| 1179 | self.unloadCurrentDocPage() |
|---|
| 1180 | |
|---|
| 1181 | def onDroppingCurrentWiki(self, miscevt): |
|---|
| 1182 | """ |
|---|
| 1183 | An access error occurred. Get rid of any data without trying to save |
|---|
| 1184 | it. |
|---|
| 1185 | """ |
|---|
| 1186 | if self.getLoadedDocPage() is not None: |
|---|
| 1187 | self.wikiPageSink.disconnect() |
|---|
| 1188 | |
|---|
| 1189 | self.SetDocPointer(None) |
|---|
| 1190 | self.applyBasicSciSettings() |
|---|
| 1191 | |
|---|
| 1192 | self.getLoadedDocPage().removeTxtEditor(self) |
|---|
| 1193 | self.presenter.setDocPage(None) |
|---|
| 1194 | |
|---|
| 1195 | self.pageType = "normal" |
|---|
| 1196 | |
|---|
| 1197 | |
|---|
| 1198 | def OnStyleNeeded(self, evt): |
|---|
| 1199 | "Styles the text of the editor" |
|---|
| 1200 | docPage = self.getLoadedDocPage() |
|---|
| 1201 | if docPage is None: |
|---|
| 1202 | |
|---|
| 1203 | self.stopStcStyler() |
|---|
| 1204 | return |
|---|
| 1205 | |
|---|
| 1206 | |
|---|
| 1207 | |
|---|
| 1208 | text = docPage.getLiveText() |
|---|
| 1209 | textlen = len(text) |
|---|
| 1210 | |
|---|
| 1211 | t = self.stylingThreadHolder.getThread() |
|---|
| 1212 | if t is not None: |
|---|
| 1213 | self.stylingThreadHolder.setThread(None) |
|---|
| 1214 | self.clearStylingCache() |
|---|
| 1215 | |
|---|
| 1216 | |
|---|
| 1217 | if textlen < self.presenter.getConfig().getint( |
|---|
| 1218 | "main", "sync_highlight_byte_limit"): |
|---|
| 1219 | |
|---|
| 1220 | |
|---|
| 1221 | self.stylingThreadHolder.setThread(None) |
|---|
| 1222 | self.buildStyling(text, 0, threadstop=DUMBTHREADSTOP) |
|---|
| 1223 | |
|---|
| 1224 | self.applyStyling(self.stylebytes) |
|---|
| 1225 | |
|---|
| 1226 | |
|---|
| 1227 | |
|---|
| 1228 | |
|---|
| 1229 | if self.getFoldingActive(): |
|---|
| 1230 | self.storeStylingAndAst(None, self.foldingseq) |
|---|
| 1231 | else: |
|---|
| 1232 | |
|---|
| 1233 | |
|---|
| 1234 | self.stopStcStyler() |
|---|
| 1235 | |
|---|
| 1236 | sth = self.stylingThreadHolder |
|---|
| 1237 | |
|---|
| 1238 | delay = self.presenter.getConfig().getfloat( |
|---|
| 1239 | "main", "async_highlight_delay") |
|---|
| 1240 | t = threading.Thread(None, self.buildStyling, args = (text, delay, sth)) |
|---|
| 1241 | sth.setThread(t) |
|---|
| 1242 | t.setDaemon(True) |
|---|
| 1243 | t.start() |
|---|
| 1244 | |
|---|
| 1245 | |
|---|
| 1246 | def _fillTemplateMenu(self, menu): |
|---|
| 1247 | idRecycler = self.templateIdRecycler |
|---|
| 1248 | idRecycler.clearAssoc() |
|---|
| 1249 | |
|---|
| 1250 | config = self.presenter.getConfig() |
|---|
| 1251 | |
|---|
| 1252 | templateRePat = config.get(u"main", u"template_pageNamesRE", |
|---|
| 1253 | u"^template/") |
|---|
| 1254 | |
|---|
| 1255 | try: |
|---|
| 1256 | templateRe = re.compile(templateRePat, re.DOTALL | re.UNICODE) |
|---|
| 1257 | except re.error: |
|---|
| 1258 | templateRe = re.compile(u"^template/", re.DOTALL | re.UNICODE) |
|---|
| 1259 | |
|---|
| 1260 | wikiDocument = self.presenter.getWikiDocument() |
|---|
| 1261 | templateNames = [n for n in wikiDocument.getAllDefinedWikiPageNames() |
|---|
| 1262 | if templateRe.search(n)] |
|---|
| 1263 | |
|---|
| 1264 | wikiDocument.getCollator().sort(templateNames) |
|---|
| 1265 | |
|---|
| 1266 | for tn in templateNames: |
|---|
| 1267 | menuID, reused = idRecycler.assocGetIdAndReused(tn) |
|---|
| 1268 | |
|---|
| 1269 | if not reused: |
|---|
| 1270 | |
|---|
| 1271 | wx.EVT_MENU(self, menuID, self.OnTemplateUsed) |
|---|
| 1272 | |
|---|
| 1273 | menu.Append(menuID, StringOps.uniToGui(tn)) |
|---|
| 1274 | |
|---|
| 1275 | |
|---|
| 1276 | def OnTemplateUsed(self, evt): |
|---|
| 1277 | docPage = self.getLoadedDocPage() |
|---|
| 1278 | if docPage is None: |
|---|
| 1279 | return |
|---|
| 1280 | templateName = self.templateIdRecycler.get(evt.GetId()) |
|---|
| 1281 | |
|---|
| 1282 | if templateName is None: |
|---|
| 1283 | return |
|---|
| 1284 | |
|---|
| 1285 | wikiDocument = self.presenter.getWikiDocument() |
|---|
| 1286 | templatePage = wikiDocument.getWikiPage(templateName) |
|---|
| 1287 | |
|---|
| 1288 | content = self.getLoadedDocPage().getContentOfTemplate(templatePage, |
|---|
| 1289 | templatePage) |
|---|
| 1290 | docPage.setMetaDataFromTemplate(templatePage) |
|---|
| 1291 | |
|---|
| 1292 | self.SetText(content, emptyUndo=False) |
|---|
| 1293 | self.pageType = docPage.getAttributes().get(u"pagetype", |
|---|
| 1294 | [u"normal"])[-1] |
|---|
| 1295 | self.handleSpecialPageType() |
|---|
| 1296 | |
|---|
| 1297 | self.presenter.informEditorTextChanged(self) |
|---|
| 1298 | |
|---|
| 1299 | |
|---|
| 1300 | def OnSelectTemplate(self, evt): |
|---|
| 1301 | docPage = self.getLoadedDocPage() |
|---|
| 1302 | if docPage is None: |
|---|
| 1303 | return |
|---|
| 1304 | |
|---|
| 1305 | if not isinstance(docPage, DocPages.WikiPage): |
|---|
| 1306 | return |
|---|
| 1307 | |
|---|
| 1308 | if not docPage.isDefined() and not docPage.getDirty()[0]: |
|---|
| 1309 | title = _(u"Select Template") |
|---|
| 1310 | else: |
|---|
| 1311 | title = _(u"Select Template (deletes current content!)") |
|---|
| 1312 | |
|---|
| 1313 | templateName = AdditionalDialogs.SelectWikiWordDialog.runModal( |
|---|
| 1314 | self.presenter.getMainControl(), self, -1, |
|---|
| 1315 | title=title) |
|---|
| 1316 | if templateName is None: |
|---|
| 1317 | return |
|---|
| 1318 | |
|---|
| 1319 | wikiDocument = self.presenter.getWikiDocument() |
|---|
| 1320 | templatePage = wikiDocument.getWikiPage(templateName) |
|---|
| 1321 | |
|---|
| 1322 | content = self.getLoadedDocPage().getContentOfTemplate(templatePage, |
|---|
| 1323 | templatePage) |
|---|
| 1324 | docPage.setMetaDataFromTemplate(templatePage) |
|---|
| 1325 | |
|---|
| 1326 | self.SetText(content, emptyUndo=False) |
|---|
| 1327 | self.pageType = docPage.getAttributes().get(u"pagetype", |
|---|
| 1328 | [u"normal"])[-1] |
|---|
| 1329 | self.handleSpecialPageType() |
|---|
| 1330 | self.presenter.informEditorTextChanged(self) |
|---|
| 1331 | |
|---|
| 1332 | |
|---|
| 1333 | |
|---|
| 1334 | def OnContextMenu(self, evt): |
|---|
| 1335 | mousePos = self.ScreenToClient(wx.GetMousePosition()) |
|---|
| 1336 | |
|---|
| 1337 | leftFold = 0 |
|---|
| 1338 | for i in range(self.FOLD_MARGIN): |
|---|
| 1339 | leftFold += self.GetMarginWidth(i) |
|---|
| 1340 | |
|---|
| 1341 | rightFold = leftFold + self.GetMarginWidth(self.FOLD_MARGIN) |
|---|
| 1342 | |
|---|
| 1343 | menu = wx.Menu() |
|---|
| 1344 | |
|---|
| 1345 | if mousePos.x >= leftFold and mousePos.x < rightFold: |
|---|
| 1346 | |
|---|
| 1347 | |
|---|
| 1348 | appendToMenuByMenuDesc(menu, FOLD_MENU) |
|---|
| 1349 | else: |
|---|
| 1350 | |
|---|
| 1351 | nodes = self.getTokensForMousePos(mousePos) |
|---|
| 1352 | |
|---|
| 1353 | self.contextMenuTokens = nodes |
|---|
| 1354 | addActivateItem = False |
|---|
| 1355 | addFileUrlItem = False |
|---|
| 1356 | addWikiUrlItem = False |
|---|
| 1357 | addUrlToClipboardItem = False |
|---|
| 1358 | unknownWord = None |
|---|
| 1359 | for node in nodes: |
|---|
| 1360 | if node.name == "wikiWord": |
|---|
| 1361 | addActivateItem = True |
|---|
| 1362 | elif node.name == "urlLink": |
|---|
| 1363 | addActivateItem = True |
|---|
| 1364 | if node.url.startswith(u"file:") or \ |
|---|
| 1365 | node.url.startswith(u"rel://"): |
|---|
| 1366 | addFileUrlItem = True |
|---|
| 1367 | elif node.url.startswith(u"wiki:") or \ |
|---|
| 1368 | node.url.startswith(u"wikirel://"): |
|---|
| 1369 | addWikiUrlItem = True |
|---|
| 1370 | elif node.name == "insertion" and node.key == u"page": |
|---|
| 1371 | addActivateItem = True |
|---|
| 1372 | elif node.name == "anchorDef": |
|---|
| 1373 | addUrlToClipboardItem = True |
|---|
| 1374 | elif node.name == "unknownSpelling": |
|---|
| 1375 | unknownWord = node.getText() |
|---|
| 1376 | |
|---|
| 1377 | if unknownWord: |
|---|
| 1378 | |
|---|
| 1379 | spellCheckerSession = self.presenter.getWikiDocument()\ |
|---|
| 1380 | .createOnlineSpellCheckerSessionClone() |
|---|
| 1381 | spellCheckerSession.setCurrentDocPage(self.getLoadedDocPage()) |
|---|
| 1382 | if spellCheckerSession: |
|---|
| 1383 | |
|---|
| 1384 | suggestions = spellCheckerSession.suggest(unknownWord)[:5] |
|---|
| 1385 | spellCheckerSession.close() |
|---|
| 1386 | |
|---|
| 1387 | if len(suggestions) > 0: |
|---|
| 1388 | for s, mid in zip(suggestions, self.SUGGESTION_CMD_IDS): |
|---|
| 1389 | menuitem = wx.MenuItem(menu, mid, s) |
|---|
| 1390 | font = menuitem.GetFont() |
|---|
| 1391 | font.SetWeight(wx.FONTWEIGHT_BOLD) |
|---|
| 1392 | menuitem.SetFont(font) |
|---|
| 1393 | |
|---|
| 1394 | menu.AppendItem(menuitem) |
|---|
| 1395 | |
|---|
| 1396 | self.contextMenuSpellCheckSuggestions = suggestions |
|---|
| 1397 | |
|---|
| 1398 | appendToMenuByMenuDesc(menu, _CONTEXT_MENU_INTEXT_SPELLING) |
|---|
| 1399 | |
|---|
| 1400 | |
|---|
| 1401 | appendToMenuByMenuDesc(menu, _CONTEXT_MENU_INTEXT_BASE) |
|---|
| 1402 | |
|---|
| 1403 | if addActivateItem: |
|---|
| 1404 | appendToMenuByMenuDesc(menu, _CONTEXT_MENU_INTEXT_ACTIVATE) |
|---|
| 1405 | |
|---|
| 1406 | if addFileUrlItem: |
|---|
| 1407 | appendToMenuByMenuDesc(menu, _CONTEXT_MENU_INTEXT_FILE_URL) |
|---|
| 1408 | elif addWikiUrlItem: |
|---|
| 1409 | appendToMenuByMenuDesc(menu, _CONTEXT_MENU_INTEXT_WIKI_URL) |
|---|
| 1410 | |
|---|
| 1411 | if addUrlToClipboardItem: |
|---|
| 1412 | appendToMenuByMenuDesc(menu, |
|---|
| 1413 | _CONTEXT_MENU_INTEXT_URL_TO_CLIPBOARD) |
|---|
| 1414 | |
|---|
| 1415 | docPage = self.getLoadedDocPage() |
|---|
| 1416 | if isinstance(docPage, DocPages.WikiPage): |
|---|
| 1417 | if not docPage.isDefined() and not docPage.getDirty()[0]: |
|---|
| 1418 | templateSubmenu = wx.Menu() |
|---|
| 1419 | self._fillTemplateMenu(templateSubmenu) |
|---|
| 1420 | appendToMenuByMenuDesc(templateSubmenu, |
|---|
| 1421 | _CONTEXT_MENU_SELECT_TEMPLATE_IN_TEMPLATE_MENU) |
|---|
| 1422 | |
|---|
| 1423 | menu.AppendSeparator() |
|---|
| 1424 | menu.AppendMenu(wx.NewId(), _(u'Use Template'), |
|---|
| 1425 | templateSubmenu) |
|---|
| 1426 | else: |
|---|
| 1427 | appendToMenuByMenuDesc(menu, |
|---|
| 1428 | _CONTEXT_MENU_SELECT_TEMPLATE) |
|---|
| 1429 | |
|---|
| 1430 | appendToMenuByMenuDesc(menu, _CONTEXT_MENU_INTEXT_BOTTOM) |
|---|
| 1431 | |
|---|
| 1432 | |
|---|
| 1433 | item = menu.FindItemById(GUI_ID.CMD_UNDO) |
|---|
| 1434 | if item: item.Enable(self.CanUndo()) |
|---|
| 1435 | item = menu.FindItemById(GUI_ID.CMD_REDO) |
|---|
| 1436 | if item: item.Enable(self.CanRedo()) |
|---|
| 1437 | |
|---|
| 1438 | cancopy = self.GetSelectionStart() != self.GetSelectionEnd() |
|---|
| 1439 | |
|---|
| 1440 | item = menu.FindItemById(GUI_ID.CMD_TEXT_DELETE) |
|---|
| 1441 | if item: item.Enable(cancopy and not self.GetReadOnly()) |
|---|
| 1442 | item = menu.FindItemById(GUI_ID.CMD_CLIPBOARD_CUT) |
|---|
| 1443 | if item: item.Enable(cancopy and not self.GetReadOnly()) |
|---|
| 1444 | item = menu.FindItemById(GUI_ID.CMD_CLIPBOARD_COPY) |
|---|
| 1445 | if item: item.Enable(cancopy) |
|---|
| 1446 | item = menu.FindItemById(GUI_ID.CMD_CLIPBOARD_PASTE) |
|---|
| 1447 | if item: item.Enable(self.CanPaste()) |
|---|
| 1448 | |
|---|
| 1449 | |
|---|
| 1450 | with self.dwellLock(): |
|---|
| 1451 | |
|---|
| 1452 | self.PopupMenu(menu) |
|---|
| 1453 | |
|---|
| 1454 | self.contextMenuTokens = None |
|---|
| 1455 | self.contextMenuSpellCheckSuggestions = None |
|---|
| 1456 | menu.Destroy() |
|---|
| 1457 | |
|---|
| 1458 | |
|---|
| 1459 | def _goToNextFormField(self): |
|---|
| 1460 | """ |
|---|
| 1461 | If pagetype is "form" this is called when user presses TAB in |
|---|
| 1462 | text editor and after loading a form page |
|---|
| 1463 | """ |
|---|
| 1464 | searchOp = SearchReplaceOperation() |
|---|
| 1465 | searchOp.wikiWide = False |
|---|
| 1466 | searchOp.wildCard = 'regex' |
|---|
| 1467 | searchOp.caseSensitive = True |
|---|
| 1468 | searchOp.searchStr = "&&[a-zA-Z]" |
|---|
| 1469 | |
|---|
| 1470 | text = self.GetText() |
|---|
| 1471 | charStartPos = len(self.GetTextRange(0, self.GetSelectionEnd())) |
|---|
| 1472 | while True: |
|---|
| 1473 | start, end = searchOp.searchText(text, charStartPos)[:2] |
|---|
| 1474 | if start is None: |
|---|
| 1475 | return False |
|---|
| 1476 | |
|---|
| 1477 | fieldcode = text[start + 2] |
|---|
| 1478 | if fieldcode == "i": |
|---|
| 1479 | self.showSelectionByCharPos(start, end) |
|---|
| 1480 | return True |
|---|
| 1481 | |
|---|
| 1482 | charStartPos = end |
|---|
| 1483 | |
|---|
| 1484 | |
|---|
| 1485 | def handleDropText(self, x, y, text): |
|---|
| 1486 | if x != -1: |
|---|
| 1487 | |
|---|
| 1488 | self.DoDropText(x, y, text) |
|---|
| 1489 | self.gotoCharPos(self.GetSelectionCharPos()[1], scroll=False) |
|---|
| 1490 | else: |
|---|
| 1491 | self.ReplaceSelection(text) |
|---|
| 1492 | |
|---|
| 1493 | self.SetFocus() |
|---|
| 1494 | |
|---|
| 1495 | |
|---|
| 1496 | def clearStylingCache(self): |
|---|
| 1497 | self.stylebytes = None |
|---|
| 1498 | self.foldingseq = None |
|---|
| 1499 | |
|---|
| 1500 | |
|---|
| 1501 | |
|---|
| 1502 | def stopStcStyler(self): |
|---|
| 1503 | """ |
|---|
| 1504 | Stops further styling requests from Scintilla until text is modified |
|---|
| 1505 | """ |
|---|
| 1506 | self.StartStyling(self.GetLength(), 0xff) |
|---|
| 1507 | self.SetStyling(0, 0) |
|---|
| 1508 | |
|---|
| 1509 | |
|---|
| 1510 | |
|---|
| 1511 | def storeStylingAndAst(self, stylebytes, foldingseq, styleMask=0xff): |
|---|
| 1512 | self.stylebytes = stylebytes |
|---|
| 1513 | |
|---|
| 1514 | self.foldingseq = foldingseq |
|---|
| 1515 | |
|---|
| 1516 | def putStyle(): |
|---|
| 1517 | if stylebytes: |
|---|
| 1518 | self.applyStyling(stylebytes, styleMask) |
|---|
| 1519 | |
|---|
| 1520 | if foldingseq: |
|---|
| 1521 | self.applyFolding(foldingseq) |
|---|
| 1522 | |
|---|
| 1523 | wx.CallAfter(putStyle) |
|---|
| 1524 | |
|---|
| 1525 | |
|---|
| 1526 | |
|---|
| 1527 | |
|---|
| 1528 | |
|---|
| 1529 | def buildStyling(self, text, delay, threadstop=DUMBTHREADSTOP): |
|---|
| 1530 | try: |
|---|
| 1531 | if delay != 0 and not threadstop is DUMBTHREADSTOP: |
|---|
| 1532 | sleep(delay) |
|---|
| 1533 | threadstop.testRunning() |
|---|
| 1534 | |
|---|
| 1535 | docPage = self.getLoadedDocPage() |
|---|
| 1536 | if docPage is None: |
|---|
| 1537 | return |
|---|
| 1538 | |
|---|
| 1539 | for i in range(20): |
|---|
| 1540 | formatDetails = docPage.getFormatDetails() |
|---|
| 1541 | pageAst = docPage.getLivePageAst(threadstop=threadstop) |
|---|
| 1542 | threadstop.testRunning() |
|---|
| 1543 | if not formatDetails.isEquivTo(docPage.getFormatDetails()): |
|---|
| 1544 | continue |
|---|
| 1545 | else: |
|---|
| 1546 | break |
|---|
| 1547 | |
|---|
| 1548 | stylebytes = self.processTokens(text, pageAst, threadstop) |
|---|
| 1549 | |
|---|
| 1550 | threadstop.testRunning() |
|---|
| 1551 | |
|---|
| 1552 | if self.getFoldingActive(): |
|---|
| 1553 | foldingseq = self.processFolding(pageAst, threadstop) |
|---|
| 1554 | else: |
|---|
| 1555 | foldingseq = None |
|---|
| 1556 | |
|---|
| 1557 | threadstop.testRunning() |
|---|
| 1558 | |
|---|
| 1559 | if self.onlineSpellCheckerActive and \ |
|---|
| 1560 | isinstance(docPage, DocPages.AbstractWikiPage): |
|---|
| 1561 | |
|---|
| 1562 | |
|---|
| 1563 | |
|---|
| 1564 | if not threadstop is DUMBTHREADSTOP: |
|---|
| 1565 | self.storeStylingAndAst(stylebytes, foldingseq, styleMask=0x1f) |
|---|
| 1566 | |
|---|
| 1567 | scTokens = docPage.getSpellCheckerUnknownWords(threadstop=threadstop) |
|---|
| 1568 | |
|---|
| 1569 | threadstop.testRunning() |
|---|
| 1570 | |
|---|
| 1571 | if scTokens.getChildrenCount() > 0: |
|---|
| 1572 | spellStyleBytes = self.processSpellCheckTokens(text, scTokens, |
|---|
| 1573 | threadstop) |
|---|
| 1574 | |
|---|
| 1575 | threadstop.testRunning() |
|---|
| 1576 | |
|---|
| 1577 | |
|---|
| 1578 | stylebytes = "".join([chr(ord(a) | ord(b)) |
|---|
| 1579 | for a, b in itertools.izip(stylebytes, spellStyleBytes)]) |
|---|
| 1580 | |
|---|
| 1581 | self.storeStylingAndAst(stylebytes, None, styleMask=0xff) |
|---|
| 1582 | else: |
|---|
| 1583 | self.storeStylingAndAst(stylebytes, None, styleMask=0xff) |
|---|
| 1584 | else: |
|---|
| 1585 | self.storeStylingAndAst(stylebytes, foldingseq, styleMask=0xff) |
|---|
| 1586 | |
|---|
| 1587 | except NotCurrentThreadException: |
|---|
| 1588 | return |
|---|
| 1589 | |
|---|
| 1590 | |
|---|
| 1591 | |
|---|
| 1592 | _TOKEN_TO_STYLENO = { |
|---|
| 1593 | "bold": FormatTypes.Bold, |
|---|
| 1594 | "italics": FormatTypes.Italic, |
|---|
| 1595 | "urlLink": FormatTypes.Url, |
|---|
| 1596 | "script": FormatTypes.Script, |
|---|
| 1597 | "property": FormatTypes.Attribute, |
|---|
| 1598 | "attribute": FormatTypes.Attribute, |
|---|
| 1599 | "insertion": FormatTypes.Script, |
|---|
| 1600 | "anchorDef": FormatTypes.Bold, |
|---|
| 1601 | "plainText": FormatTypes.Default |
|---|
| 1602 | } |
|---|
| 1603 | |
|---|
| 1604 | |
|---|
| 1605 | def _findFragmentSearch(self, linkNode): |
|---|
| 1606 | """ |
|---|
| 1607 | linkNode -- AST node of type "wikiWord" |
|---|
| 1608 | returns |
|---|
| 1609 | (<first char pos>, <after last char pos>) of targeted search |
|---|
| 1610 | fragment if present |
|---|
| 1611 | (None, None) if not present |
|---|
| 1612 | (-1, -1) if search is not applicable |
|---|
| 1613 | """ |
|---|
| 1614 | unaliasedTarget = self.presenter.getWikiDocument()\ |
|---|
| 1615 | .getWikiPageNameForLinkTermOrAsIs(linkNode.wikiWord) |
|---|
| 1616 | |
|---|
| 1617 | docPage = self.getLoadedDocPage() |
|---|
| 1618 | if docPage is None: |
|---|
| 1619 | return (-1, -1) |
|---|
| 1620 | |
|---|
| 1621 | wikiWord = docPage.getWikiWord() |
|---|
| 1622 | if wikiWord is None: |
|---|
| 1623 | return (-1, -1) |
|---|
| 1624 | |
|---|
| 1625 | if wikiWord == unaliasedTarget: |
|---|
| 1626 | forbiddenSearchfragHit = (linkNode.pos, |
|---|
| 1627 | linkNode.pos + linkNode.strLength) |
|---|
| 1628 | else: |
|---|
| 1629 | forbiddenSearchfragHit = (0, 0) |
|---|
| 1630 | |
|---|
| 1631 | searchfrag = linkNode.searchFragment |
|---|
| 1632 | if searchfrag is None: |
|---|
| 1633 | return (-1, -1) |
|---|
| 1634 | |
|---|
| 1635 | searchOp = SearchReplaceOperation() |
|---|
| 1636 | searchOp.wildCard = "no" |
|---|
| 1637 | searchOp.searchStr = searchfrag |
|---|
| 1638 | |
|---|
| 1639 | targetPage = self.presenter.getWikiDocument().getWikiPage( |
|---|
| 1640 | linkNode.wikiWord) |
|---|
| 1641 | |
|---|
| 1642 | found = searchOp.searchDocPageAndText(targetPage, |
|---|
| 1643 | targetPage.getLiveText(), 0) |
|---|
| 1644 | |
|---|
| 1645 | if found[0] >= forbiddenSearchfragHit[0] and \ |
|---|
| 1646 | found[0] < forbiddenSearchfragHit[1]: |
|---|
| 1647 | |
|---|
| 1648 | found = searchOp.searchDocPageAndText(targetPage, |
|---|
| 1649 | targetPage.getLiveText(), forbiddenSearchfragHit[1]) |
|---|
| 1650 | |
|---|
| 1651 | return found |
|---|
| 1652 | |
|---|
| 1653 | |
|---|
| 1654 | |
|---|
| 1655 | def processTokens(self, text, pageAst, threadstop): |
|---|
| 1656 | wikiDoc = self.presenter.getWikiDocument() |
|---|
| 1657 | stylebytes = StyleCollector(FormatTypes.Default, |
|---|
| 1658 | text, self.bytelenSct) |
|---|
| 1659 | |
|---|
| 1660 | def process(pageAst, stack): |
|---|
| 1661 | for node in pageAst.iterFlatNamed(): |
|---|
| 1662 | threadstop.testRunning() |
|---|
| 1663 | |
|---|
| 1664 | styleNo = WikiTxtCtrl._TOKEN_TO_STYLENO.get(node.name) |
|---|
| 1665 | |
|---|
| 1666 | if styleNo is not None: |
|---|
| 1667 | stylebytes.bindStyle(node.pos, node.strLength, styleNo) |
|---|
| 1668 | elif node.name == "wikiWord": |
|---|
| 1669 | if wikiDoc.isCreatableWikiWord(node.wikiWord): |
|---|
| 1670 | styleNo = FormatTypes.WikiWord |
|---|
| 1671 | else: |
|---|
| 1672 | styleNo = FormatTypes.AvailWikiWord |
|---|
| 1673 | if self.optionColorizeSearchFragments and \ |
|---|
| 1674 | node.searchFragment: |
|---|
| 1675 | if self._findFragmentSearch(node)[0] == None: |
|---|
| 1676 | |
|---|
| 1677 | searchFragNode = node.fragmentNode |
|---|
| 1678 | |
|---|
| 1679 | stylebytes.bindStyle(node.pos, |
|---|
| 1680 | searchFragNode.pos - node.pos, |
|---|
| 1681 | FormatTypes.AvailWikiWord) |
|---|
| 1682 | |
|---|
| 1683 | stylebytes.bindStyle(searchFragNode.pos, |
|---|
| 1684 | searchFragNode.strLength, |
|---|
| 1685 | FormatTypes.WikiWord) |
|---|
| 1686 | |
|---|
| 1687 | stylebytes.bindStyle(searchFragNode.pos + |
|---|
| 1688 | searchFragNode.strLength, |
|---|
| 1689 | node.strLength - |
|---|
| 1690 | (searchFragNode.pos - node.pos) - |
|---|
| 1691 | searchFragNode.strLength, |
|---|
| 1692 | FormatTypes.AvailWikiWord) |
|---|
| 1693 | continue |
|---|
| 1694 | |
|---|
| 1695 | stylebytes.bindStyle(node.pos, node.strLength, styleNo) |
|---|
| 1696 | |
|---|
| 1697 | elif node.name == "todoEntry": |
|---|
| 1698 | process(node, stack + ["todoEntry"]) |
|---|
| 1699 | elif node.name == "key" and "todoEntry" in stack: |
|---|
| 1700 | stylebytes.bindStyle(node.pos, node.strLength, |
|---|
| 1701 | FormatTypes.ToDo) |
|---|
| 1702 | elif node.name == "value" and "todoEntry" in stack: |
|---|
| 1703 | process(node, stack[:]) |
|---|
| 1704 | |
|---|
| 1705 | elif node.name == "heading": |
|---|
| 1706 | if node.level < 5: |
|---|
| 1707 | styleNo = FormatTypes.Heading1 + \ |
|---|
| 1708 | (node.level - 1) |
|---|
| 1709 | else: |
|---|
| 1710 | styleNo = FormatTypes.Bold |
|---|
| 1711 | |
|---|
| 1712 | stylebytes.bindStyle(node.pos, node.strLength, styleNo) |
|---|
| 1713 | |
|---|
| 1714 | elif node.name in ("table", "tableRow", "tableCell", |
|---|
| 1715 | "orderedList", "unorderedList", "indentedText", |
|---|
| 1716 | "noExport"): |
|---|
| 1717 | process(node, stack[:]) |
|---|
| 1718 | |
|---|
| 1719 | process(pageAst, []) |
|---|
| 1720 | return stylebytes.value() |
|---|
| 1721 | |
|---|
| 1722 | |
|---|
| 1723 | def processSpellCheckTokens(self, text, scTokens, threadstop): |
|---|
| 1724 | stylebytes = StyleCollector(0, text, self.bytelenSct) |
|---|
| 1725 | for node in scTokens: |
|---|
| 1726 | threadstop.testRunning() |
|---|
| 1727 | stylebytes.bindStyle(node.pos, node.strLength, |
|---|
| 1728 | wx.stc.STC_INDIC2_MASK) |
|---|
| 1729 | |
|---|
| 1730 | return stylebytes.value() |
|---|
| 1731 | |
|---|
| 1732 | |
|---|
| 1733 | def processFolding(self, pageAst, threadstop): |
|---|
| 1734 | foldingseq = [] |
|---|
| 1735 | currLine = 0 |
|---|
| 1736 | prevLevel = 0 |
|---|
| 1737 | levelStack = [] |
|---|
| 1738 | foldHeader = False |
|---|
| 1739 | |
|---|
| 1740 | for node in pageAst: |
|---|
| 1741 | threadstop.testRunning() |
|---|
| 1742 | |
|---|
| 1743 | if node.name == "heading": |
|---|
| 1744 | while levelStack and (levelStack[-1][0] != "heading" or |
|---|
| 1745 | levelStack[-1][1] > node.level): |
|---|
| 1746 | del levelStack[-1] |
|---|
| 1747 | if not levelStack or levelStack[-1] != ("heading", node.level): |
|---|
| 1748 | levelStack.append(("heading", node.level)) |
|---|
| 1749 | foldHeader = True |
|---|
| 1750 | |
|---|
| 1751 | lfc = node.getString().count(u"\n") |
|---|
| 1752 | if len(levelStack) > prevLevel: |
|---|
| 1753 | foldHeader = True |
|---|
| 1754 | |
|---|
| 1755 | if foldHeader and lfc > 0: |
|---|
| 1756 | foldingseq.append(len(levelStack) | wx.stc.STC_FOLDLEVELHEADERFLAG) |
|---|
| 1757 | foldHeader = False |
|---|
| 1758 | lfc -= 1 |
|---|
| 1759 | |
|---|
| 1760 | if lfc > 0: |
|---|
| 1761 | foldingseq += [len(levelStack) + 1] * lfc |
|---|
| 1762 | |
|---|
| 1763 | prevLevel = len(levelStack) + 1 |
|---|
| 1764 | |
|---|
| 1765 | |
|---|
| 1766 | foldingseq.append(len(levelStack) + 1) |
|---|
| 1767 | |
|---|
| 1768 | return foldingseq |
|---|
| 1769 | |
|---|
| 1770 | |
|---|
| 1771 | def applyStyling(self, stylebytes, styleMask=0xff): |
|---|
| 1772 | if len(stylebytes) == self.GetLength(): |
|---|
| 1773 | self.StartStyling(0, styleMask) |
|---|
| 1774 | self.SetStyleBytes(len(stylebytes), stylebytes) |
|---|
| 1775 | |
|---|
| 1776 | def applyFolding(self, foldingseq): |
|---|
| 1777 | if foldingseq and self.getFoldingActive() and \ |
|---|
| 1778 | len(foldingseq) == self.GetLineCount(): |
|---|
| 1779 | for ln in xrange(len(foldingseq)): |
|---|
| 1780 | self.SetFoldLevel(ln, foldingseq[ln]) |
|---|
| 1781 | self.repairFoldingVisibility() |
|---|
| 1782 | |
|---|
| 1783 | |
|---|
| 1784 | def unfoldAll(self): |
|---|
| 1785 | """ |
|---|
| 1786 | Unfold all folded lines |
|---|
| 1787 | """ |
|---|
| 1788 | for i in xrange(self.GetLineCount()): |
|---|
| 1789 | self.SetFoldExpanded(i, True) |
|---|
| 1790 | |
|---|
| 1791 | self.ShowLines(0, self.GetLineCount()-1) |
|---|
| 1792 | |
|---|
| 1793 | |
|---|
| 1794 | def foldAll(self): |
|---|
| 1795 | """ |
|---|
| 1796 | Fold all foldable lines |
|---|
| 1797 | """ |
|---|
| 1798 | if not self.getFoldingActive(): |
|---|
| 1799 | self.setFoldingActive(True, forceSync=True) |
|---|
| 1800 | |
|---|
| 1801 | for ln in xrange(self.GetLineCount()): |
|---|
| 1802 | if self.GetFoldLevel(ln) & wx.stc.STC_FOLDLEVELHEADERFLAG and \ |
|---|
| 1803 | self.GetFoldExpanded(ln): |
|---|
| 1804 | self.ToggleFold(ln) |
|---|
| 1805 | |
|---|
| 1806 | |
|---|
| 1807 | |
|---|
| 1808 | |
|---|
| 1809 | self.Refresh() |
|---|
| 1810 | |
|---|
| 1811 | |
|---|
| 1812 | def toggleCurrentFolding(self): |
|---|
| 1813 | if not self.getFoldingActive(): |
|---|
| 1814 | return |
|---|
| 1815 | |
|---|
| 1816 | self.ToggleFold(self.LineFromPosition(self.GetCurrentPos())) |
|---|
| 1817 | |
|---|
| 1818 | |
|---|
| 1819 | def getFoldInfo(self): |
|---|
| 1820 | if not self.getFoldingActive(): |
|---|
| 1821 | return None |
|---|
| 1822 | |
|---|
| 1823 | result = [0] * self.GetLineCount() |
|---|
| 1824 | for ln in xrange(self.GetLineCount()): |
|---|
| 1825 | levComb = self.GetFoldLevel(ln) |
|---|
| 1826 | levOut = levComb & 4095 |
|---|
| 1827 | if levComb & wx.stc.STC_FOLDLEVELHEADERFLAG: |
|---|
| 1828 | levOut |= 4096 |
|---|
| 1829 | if self.GetFoldExpanded(ln): |
|---|
| 1830 | levOut |= 8192 |
|---|
| 1831 | if self.GetLineVisible(ln): |
|---|
| 1832 | levOut |= 16384 |
|---|
| 1833 | result[ln] = levOut |
|---|
| 1834 | |
|---|
| 1835 | return result |
|---|
| 1836 | |
|---|
| 1837 | |
|---|
| 1838 | def setFoldInfo(self, fldInfo): |
|---|
| 1839 | if fldInfo is None or \ |
|---|
| 1840 | not self.getFoldingActive() or \ |
|---|
| 1841 | len(fldInfo) != self.GetLineCount(): |
|---|
| 1842 | return |
|---|
| 1843 | |
|---|
| 1844 | for ln, levIn in enumerate(fldInfo): |
|---|
| 1845 | levComb = levIn & 4095 |
|---|
| 1846 | if levIn & 4096: |
|---|
| 1847 | levComb |= wx.stc.STC_FOLDLEVELHEADERFLAG |
|---|
| 1848 | |
|---|
| 1849 | self.SetFoldLevel(ln, levComb) |
|---|
| 1850 | self.SetFoldExpanded(ln, bool(levIn & 8192)) |
|---|
| 1851 | if levIn & 16384: |
|---|
| 1852 | self.ShowLines(ln, ln) |
|---|
| 1853 | else: |
|---|
| 1854 | self.HideLines(ln, ln) |
|---|
| 1855 | |
|---|
| 1856 | self.repairFoldingVisibility() |
|---|
| 1857 | |
|---|
| 1858 | |
|---|
| 1859 | |
|---|
| 1860 | def repairFoldingVisibility(self): |
|---|
| 1861 | if not self.getFoldingActive(): |
|---|
| 1862 | return |
|---|
| 1863 | |
|---|
| 1864 | lc = self.GetLineCount() |
|---|
| 1865 | |
|---|
| 1866 | if lc == 0: |
|---|
| 1867 | return |
|---|
| 1868 | |
|---|
| 1869 | self.ShowLines(0, 0) |
|---|
| 1870 | if lc == 1: |
|---|
| 1871 | return |
|---|
| 1872 | |
|---|
| 1873 | combLevel = self.GetFoldLevel(0) |
|---|
| 1874 | prevLevel = combLevel & 4095 |
|---|
| 1875 | prevIsHeader = combLevel & wx.stc.STC_FOLDLEVELHEADERFLAG |
|---|
| 1876 | prevIsExpanded = self.GetFoldExpanded(0) |
|---|
| 1877 | prevVisible = True |
|---|
| 1878 | prevLn = 0 |
|---|
| 1879 | |
|---|
| 1880 | |
|---|
| 1881 | |
|---|
| 1882 | for ln in xrange(1, lc): |
|---|
| 1883 | combLevel = self.GetFoldLevel(ln) |
|---|
| 1884 | level = combLevel & 4095 |
|---|
| 1885 | isHeader = combLevel & wx.stc.STC_FOLDLEVELHEADERFLAG |
|---|
| 1886 | isExpanded = self.GetFoldExpanded(ln) |
|---|
| 1887 | visible = self.GetLineVisible(ln) |
|---|
| 1888 | |
|---|
| 1889 | |
|---|
| 1890 | if prevVisible and not visible: |
|---|
| 1891 | |
|---|
| 1892 | if ((level <= prevLevel) and \ |
|---|
| 1893 | not (prevIsHeader and not prevIsExpanded)) or \ |
|---|
| 1894 | (prevIsHeader and prevIsExpanded): |
|---|
| 1895 | |
|---|
| 1896 | |
|---|
| 1897 | |
|---|
| 1898 | |
|---|
| 1899 | |
|---|
| 1900 | |
|---|
| 1901 | |
|---|
| 1902 | self.SetFoldExpanded(prevLn, True) |
|---|
| 1903 | self.ShowLines(ln, ln) |
|---|
| 1904 | |
|---|
| 1905 | visible = True |
|---|
| 1906 | |
|---|
| 1907 | prevLevel = level |
|---|
| 1908 | prevIsHeader = isHeader |
|---|
| 1909 | prevIsExpanded = isExpanded |
|---|
| 1910 | prevVisible = visible |
|---|
| 1911 | prevLn = ln |
|---|
| 1912 | |
|---|
| 1913 | |
|---|
| 1914 | |
|---|
| 1915 | def snip(self): |
|---|
| 1916 | |
|---|
| 1917 | text = self.GetSelectedText() |
|---|
| 1918 | |
|---|
| 1919 | |
|---|
| 1920 | self.Copy() |
|---|
| 1921 | |
|---|
| 1922 | wikiPage = self.presenter.getWikiDocument().getWikiPageNoError("ScratchPad") |
|---|
| 1923 | |
|---|
| 1924 | |
|---|
| 1925 | |
|---|
| 1926 | wikiPage.appendLiveText("\n%s\n---------------------------\n\n%s\n" % |
|---|
| 1927 | (StringOps.strftimeUB("%x %I:%M %p"), text)) |
|---|
| 1928 | |
|---|
| 1929 | def styleSelection(self, startChars, endChars=None): |
|---|
| 1930 | """ |
|---|
| 1931 | """ |
|---|
| 1932 | if endChars is None: |
|---|
| 1933 | endChars = startChars |
|---|
| 1934 | |
|---|
| 1935 | (startBytePos, endBytePos) = self.GetSelection() |
|---|
| 1936 | if startBytePos == endBytePos: |
|---|
| 1937 | (startBytePos, endBytePos) = self.getNearestWordPositions() |
|---|
| 1938 | |
|---|
| 1939 | emptySelection = startBytePos == endBytePos |
|---|
| 1940 | |
|---|
| 1941 | startCharPos = len(self.GetTextRange(0, startBytePos)) |
|---|
| 1942 | endCharPos = startCharPos + len(self.GetTextRange(startBytePos, endBytePos)) |
|---|
| 1943 | |
|---|
| 1944 | self.BeginUndoAction() |
|---|
| 1945 | try: |
|---|
| 1946 | endCharPos += len(startChars) |
|---|
| 1947 | |
|---|
| 1948 | if emptySelection: |
|---|
| 1949 | |
|---|
| 1950 | |
|---|
| 1951 | cursorCharPos = endCharPos |
|---|
| 1952 | else: |
|---|
| 1953 | |
|---|
| 1954 | cursorCharPos = endCharPos + len(endChars) |
|---|
| 1955 | |
|---|
| 1956 | self.gotoCharPos(startCharPos, scroll=False) |
|---|
| 1957 | self.AddText(startChars) |
|---|
| 1958 | |
|---|
| 1959 | self.gotoCharPos(endCharPos, scroll=False) |
|---|
| 1960 | self.AddText(endChars) |
|---|
| 1961 | |
|---|
| 1962 | self.gotoCharPos(cursorCharPos, scroll=False) |
|---|
| 1963 | finally: |
|---|
| 1964 | self.EndUndoAction() |
|---|
| 1965 | |
|---|
| 1966 | |
|---|
| 1967 | def getPageAst(self): |
|---|
| 1968 | docPage = self.getLoadedDocPage() |
|---|
| 1969 | if docPage is None: |
|---|
| 1970 | raise NoPageAstException(u"Internal error: No docPage => no page AST") |
|---|
| 1971 | |
|---|
| 1972 | return docPage.getLivePageAst() |
|---|
| 1973 | |
|---|
| 1974 | |
|---|
| 1975 | def activateTokens(self, nodeList, tabMode=0): |
|---|
| 1976 | """ |
|---|
| 1977 | Helper for activateLink() |
|---|
| 1978 | tabMode -- 0:Same tab; 2: new tab in foreground; 3: new tab in background |
|---|
| 1979 | """ |
|---|
| 1980 | if len(nodeList) == 0: |
|---|
| 1981 | return False |
|---|
| 1982 | |
|---|
| 1983 | for node in nodeList: |
|---|
| 1984 | if node.name == "wikiWord": |
|---|
| 1985 | searchStr = None |
|---|
| 1986 | |
|---|
| 1987 | |
|---|
| 1988 | if tabMode & 2: |
|---|
| 1989 | if tabMode == 6: |
|---|
| 1990 | |
|---|
| 1991 | presenter = self.presenter.getMainControl().\ |
|---|
| 1992 | createNewDocPagePresenterTabInNewFrame() |
|---|
| 1993 | else: |
|---|
| 1994 | |
|---|
| 1995 | presenter = self.presenter.getMainControl().\ |
|---|
| 1996 | createNewDocPagePresenterTab() |
|---|
| 1997 | else: |
|---|
| 1998 | |
|---|
| 1999 | presenter = self.presenter |
|---|
| 2000 | |
|---|
| 2001 | titleFromLink = self.presenter.getConfig().getboolean("main", |
|---|
| 2002 | "wikiPageTitle_fromLinkTitle", False) |
|---|
| 2003 | |
|---|
| 2004 | if not titleFromLink or node.titleNode is None: |
|---|
| 2005 | suggNewPageTitle = None |
|---|
| 2006 | else: |
|---|
| 2007 | suggNewPageTitle = node.titleNode.getString() |
|---|
| 2008 | |
|---|
| 2009 | unaliasedTarget = self.presenter.getWikiDocument()\ |
|---|
| 2010 | .getWikiPageNameForLinkTermOrAsIs(node.wikiWord) |
|---|
| 2011 | |
|---|
| 2012 | docPage = self.getLoadedDocPage() |
|---|
| 2013 | |
|---|
| 2014 | |
|---|
| 2015 | |
|---|
| 2016 | |
|---|
| 2017 | |
|---|
| 2018 | |
|---|
| 2019 | forbiddenSearchfragHit = (0, 0) |
|---|
| 2020 | if docPage is not None: |
|---|
| 2021 | wikiWord = docPage.getWikiWord() |
|---|
| 2022 | if wikiWord is not None: |
|---|
| 2023 | if wikiWord == unaliasedTarget: |
|---|
| 2024 | forbiddenSearchfragHit = (node.pos, node.pos + node.strLength) |
|---|
| 2025 | |
|---|
| 2026 | presenter.openWikiPage(unaliasedTarget, |
|---|
| 2027 | motionType="child", anchor=node.anchorLink, |
|---|
| 2028 | suggNewPageTitle=suggNewPageTitle) |
|---|
| 2029 | |
|---|
| 2030 | searchfrag = node.searchFragment |
|---|
| 2031 | if searchfrag is not None: |
|---|
| 2032 | searchOp = SearchReplaceOperation() |
|---|
| 2033 | searchOp.wildCard = "no" |
|---|
| 2034 | searchOp.searchStr = searchfrag |
|---|
| 2035 | |
|---|
| 2036 | found = presenter.getSubControl("textedit").executeSearch( |
|---|
| 2037 | searchOp, 0) |
|---|
| 2038 | |
|---|
| 2039 | if found[0] >= forbiddenSearchfragHit[0] and \ |
|---|
| 2040 | found[0] < forbiddenSearchfragHit[1]: |
|---|
| 2041 | |
|---|
| 2042 | presenter.getSubControl("textedit").executeSearch( |
|---|
| 2043 | searchOp, forbiddenSearchfragHit[1]) |
|---|
| 2044 | |
|---|
| 2045 | if not tabMode & 1: |
|---|
| 2046 | |
|---|
| 2047 | presenter.getMainControl().getMainAreaPanel().\ |
|---|
| 2048 | showPresenter(presenter) |
|---|
| 2049 | |
|---|
| 2050 | return True |
|---|
| 2051 | |
|---|
| 2052 | elif node.name == "urlLink": |
|---|
| 2053 | self.presenter.getMainControl().launchUrl(node.url) |
|---|
| 2054 | return True |
|---|
| 2055 | |
|---|
| 2056 | elif node.name == "insertion": |
|---|
| 2057 | if node.key == u"page": |
|---|
| 2058 | |
|---|
| 2059 | |
|---|
| 2060 | if tabMode & 2: |
|---|
| 2061 | if tabMode == 6: |
|---|
| 2062 | |
|---|
| 2063 | presenter = self.presenter.getMainControl().\ |
|---|
| 2064 | createNewDocPagePresenterTabInNewFrame() |
|---|
| 2065 | else: |
|---|
| 2066 | |
|---|
| 2067 | presenter = self.presenter.getMainControl().\ |
|---|
| 2068 | createNewDocPagePresenterTab() |
|---|
| 2069 | else: |
|---|
| 2070 | |
|---|
| 2071 | presenter = self.presenter |
|---|
| 2072 | |
|---|
| 2073 | presenter.openWikiPage(node.value, |
|---|
| 2074 | motionType="child") |
|---|
| 2075 | |
|---|
| 2076 | if not tabMode & 1: |
|---|
| 2077 | |
|---|
| 2078 | |
|---|
| 2079 | presenter.getMainControl().getMainAreaPanel().\ |
|---|
| 2080 | showPresenter(presenter) |
|---|
| 2081 | |
|---|
| 2082 | return True |
|---|
| 2083 | |
|---|
| 2084 | |
|---|
| 2085 | |
|---|
| 2086 | |
|---|
| 2087 | |
|---|
| 2088 | |
|---|
| 2089 | |
|---|
| 2090 | elif node.name == "footnote": |
|---|
| 2091 | try: |
|---|
| 2092 | pageAst = self.getPageAst() |
|---|
| 2093 | footnoteId = node.footnoteId |
|---|
| 2094 | |
|---|
| 2095 | anchorNode = getFootnoteAnchorDict(pageAst).get(footnoteId) |
|---|
| 2096 | if anchorNode is not None: |
|---|
| 2097 | if anchorNode.pos != node.pos: |
|---|
| 2098 | |
|---|
| 2099 | self.gotoCharPos(anchorNode.pos) |
|---|
| 2100 | else: |
|---|
| 2101 | |
|---|
| 2102 | for fnNode in pageAst.iterDeepByName("footnote"): |
|---|
| 2103 | if fnNode.footnoteId == footnoteId: |
|---|
| 2104 | self.gotoCharPos(fnNode.pos) |
|---|
| 2105 | break |
|---|
| 2106 | |
|---|
| 2107 | return True |
|---|
| 2108 | except NoPageAstException: |
|---|
| 2109 | return False |
|---|
| 2110 | else: |
|---|
| 2111 | continue |
|---|
| 2112 | |
|---|
| 2113 | return False |
|---|
| 2114 | |
|---|
| 2115 | |
|---|
| 2116 | def getTokensForMousePos(self, mousePosition=None): |
|---|
| 2117 | |
|---|
| 2118 | if mousePosition and mousePosition != wx.DefaultPosition: |
|---|
| 2119 | linkBytePos = self.PositionFromPoint(mousePosition) |
|---|
| 2120 | else: |
|---|
| 2121 | linkBytePos = self.GetCurrentPos() |
|---|
| 2122 | |
|---|
| 2123 | try: |
|---|
| 2124 | pageAst = self.getPageAst() |
|---|
| 2125 | except NoPageAstException: |
|---|
| 2126 | return [] |
|---|
| 2127 | |
|---|
| 2128 | linkCharPos = len(self.GetTextRange(0, linkBytePos)) |
|---|
| 2129 | |
|---|
| 2130 | result = pageAst.findNodesForCharPos(linkCharPos) |
|---|
| 2131 | |
|---|
| 2132 | |
|---|
| 2133 | if linkCharPos > 0: |
|---|
| 2134 | |
|---|
| 2135 | |
|---|
| 2136 | result += pageAst.findNodesForCharPos(linkCharPos - 1) |
|---|
| 2137 | |
|---|
| 2138 | if self.onlineSpellCheckerActive: |
|---|
| 2139 | docPage = self.getLoadedDocPage() |
|---|
| 2140 | if isinstance(docPage, DocPages.AbstractWikiPage): |
|---|
| 2141 | allUnknownWords = docPage.getSpellCheckerUnknownWords() |
|---|
| 2142 | wantedUnknownWords = allUnknownWords.findNodesForCharPos( |
|---|
| 2143 | linkCharPos) |
|---|
| 2144 | |
|---|
| 2145 | if linkCharPos > 0 and len(wantedUnknownWords) == 0: |
|---|
| 2146 | |
|---|
| 2147 | wantedUnknownWords = allUnknownWords.findNodesForCharPos( |
|---|
| 2148 | linkCharPos - 1) |
|---|
| 2149 | |
|---|
| 2150 | result += wantedUnknownWords |
|---|
| 2151 | |
|---|
| 2152 | return result |
|---|
| 2153 | |
|---|
| 2154 | |
|---|
| 2155 | |
|---|
| 2156 | def activateLink(self, mousePosition=None, tabMode=0): |
|---|
| 2157 | """ |
|---|
| 2158 | Activates link (wiki word or URL) |
|---|
| 2159 | tabMode -- 0:Same tab; 2: new tab in foreground; 3: new tab in background |
|---|
| 2160 | """ |
|---|
| 2161 | tokens = self.getTokensForMousePos(mousePosition) |
|---|
| 2162 | return self.activateTokens(tokens, tabMode) |
|---|
| 2163 | |
|---|
| 2164 | |
|---|
| 2165 | |
|---|
| 2166 | def OnReplaceThisSpellingWithSuggestion(self, evt): |
|---|
| 2167 | if self.contextMenuTokens and self.contextMenuSpellCheckSuggestions: |
|---|
| 2168 | for node in self.contextMenuTokens: |
|---|
| 2169 | if node.name == "unknownSpelling": |
|---|
| 2170 | self.replaceTextAreaByCharPos( |
|---|
| 2171 | self.contextMenuSpellCheckSuggestions[ |
|---|
| 2172 | self.SUGGESTION_CMD_IDS.index(evt.GetId())], |
|---|
| 2173 | node.pos, node.pos + node.strLength) |
|---|
| 2174 | break |
|---|
| 2175 | |
|---|
| 2176 | |
|---|
| 2177 | |
|---|
| 2178 | def OnAddThisSpellingToIgnoreSession(self, evt): |
|---|
| 2179 | if self.contextMenuTokens: |
|---|
| 2180 | for node in self.contextMenuTokens: |
|---|
| 2181 | if node.name == "unknownSpelling": |
|---|
| 2182 | self.presenter.getWikiDocument()\ |
|---|
| 2183 | .getOnlineSpellCheckerSession().addIgnoreWordSession( |
|---|
| 2184 | node.getText()) |
|---|
| 2185 | break |
|---|
| 2186 | |
|---|
| 2187 | |
|---|
| 2188 | def OnAddThisSpellingToIgnoreGlobal(self, evt): |
|---|
| 2189 | if self.contextMenuTokens: |
|---|
| 2190 | for node in self.contextMenuTokens: |
|---|
| 2191 | if node.name == "unknownSpelling": |
|---|
| 2192 | self.presenter.getWikiDocument()\ |
|---|
| 2193 | .getOnlineSpellCheckerSession().addIgnoreWordGlobal( |
|---|
| 2194 | node.getText()) |
|---|
| 2195 | break |
|---|
| 2196 | |
|---|
| 2197 | def OnAddThisSpellingToIgnoreLocal(self, evt): |
|---|
| 2198 | if self.contextMenuTokens: |
|---|
| 2199 | for node in self.contextMenuTokens: |
|---|
| 2200 | if node.name == "unknownSpelling": |
|---|
| 2201 | self.presenter.getWikiDocument()\ |
|---|
| 2202 | .getOnlineSpellCheckerSession().addIgnoreWordLocal( |
|---|
| 2203 | node.getText()) |
|---|
| 2204 | break |
|---|
| 2205 | |
|---|
| 2206 | |
|---|
| 2207 | |
|---|
| 2208 | def OnActivateThis(self, evt): |
|---|
| 2209 | if self.contextMenuTokens: |
|---|
| 2210 | self.activateTokens(self.contextMenuTokens, 0) |
|---|
| 2211 | |
|---|
| 2212 | def OnActivateNewTabThis(self, evt): |
|---|
| 2213 | if self.contextMenuTokens: |
|---|
| 2214 | self.activateTokens(self.contextMenuTokens, 2) |
|---|
| 2215 | |
|---|
| 2216 | def OnActivateNewTabBackgroundThis(self, evt): |
|---|
| 2217 | if self.contextMenuTokens: |
|---|
| 2218 | self.activateTokens(self.contextMenuTokens, 3) |
|---|
| 2219 | |
|---|
| 2220 | def OnActivateNewWindowThis(self, evt): |
|---|
| 2221 | if self.contextMenuTokens: |
|---|
| 2222 | self.activateTokens(self.contextMenuTokens, 6) |
|---|
| 2223 | |
|---|
| 2224 | |
|---|
| 2225 | def OnOpenContainingFolderThis(self, evt): |
|---|
| 2226 | if self.contextMenuTokens: |
|---|
| 2227 | for node in self.contextMenuTokens: |
|---|
| 2228 | if node.name == "urlLink": |
|---|
| 2229 | link = node.url |
|---|
| 2230 | |
|---|
| 2231 | if link.startswith(u"rel://") or link.startswith(u"wikirel://"): |
|---|
| 2232 | link = self.presenter.getWikiDocument()\ |
|---|
| 2233 | .makeRelUrlAbsolute(link) |
|---|
| 2234 | |
|---|
| 2235 | if link.startswith(u"file:") or link.startswith(u"wiki:"): |
|---|
| 2236 | try: |
|---|
| 2237 | path = dirname(StringOps.pathnameFromUrl(link)) |
|---|
| 2238 | if not exists(StringOps.longPathEnc(path)): |
|---|
| 2239 | self.presenter.displayErrorMessage( |
|---|
| 2240 | _(u"Folder does not exist")) |
|---|
| 2241 | return |
|---|
| 2242 | |
|---|
| 2243 | OsAbstract.startFile(self.presenter.getMainControl(), |
|---|
| 2244 | path) |
|---|
| 2245 | except IOError: |
|---|
| 2246 | pass |
|---|
| 2247 | |
|---|
| 2248 | break |
|---|
| 2249 | |
|---|
| 2250 | def OnDeleteFile(self, evt): |
|---|
| 2251 | if self.contextMenuTokens: |
|---|
| 2252 | for node in self.contextMenuTokens: |
|---|
| 2253 | if node.name == "urlLink": |
|---|
| 2254 | link = self.presenter.getWikiDocument().makeFileUrlAbsPath( |
|---|
| 2255 | node.url) |
|---|
| 2256 | if link is None: |
|---|
| 2257 | continue |
|---|
| 2258 | |
|---|
| 2259 | |
|---|
| 2260 | |
|---|
| 2261 | |
|---|
| 2262 | |
|---|
| 2263 | |
|---|
| 2264 | |
|---|
| 2265 | |
|---|
| 2266 | |
|---|
| 2267 | |
|---|
| 2268 | if not isfile(link): |
|---|
| 2269 | self.presenter.displayErrorMessage( |
|---|
| 2270 | _(u"File does not exist")) |
|---|
| 2271 | return |
|---|
| 2272 | |
|---|
| 2273 | filename = basename(link) |
|---|
| 2274 | |
|---|
| 2275 | choice = wx.MessageBox( |
|---|
| 2276 | _("Are you sure you want to delete the file: %s") % |
|---|
| 2277 | filename, _("Delete File"), |
|---|
| 2278 | wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION, self) |
|---|
| 2279 | |
|---|
| 2280 | if choice == wx.YES: |
|---|
| 2281 | OsAbstract.deleteFile(link) |
|---|
| 2282 | self.replaceTextAreaByCharPos(u"", node.pos, |
|---|
| 2283 | node.pos + node.strLength) |
|---|
| 2284 | return |
|---|
| 2285 | |
|---|
| 2286 | |
|---|
| 2287 | def OnRenameFile(self, evt): |
|---|
| 2288 | if not self.contextMenuTokens: |
|---|
| 2289 | return |
|---|
| 2290 | |
|---|
| 2291 | for node in self.contextMenuTokens: |
|---|
| 2292 | if node.name == "urlLink": |
|---|
| 2293 | link = self.presenter.getWikiDocument().makeFileUrlAbsPath( |
|---|
| 2294 | node.url) |
|---|
| 2295 | if link is not None: |
|---|
| 2296 | break |
|---|
| 2297 | else: |
|---|
| 2298 | return |
|---|
| 2299 | |
|---|
| 2300 | |
|---|
| 2301 | |
|---|
| 2302 | |
|---|
| 2303 | |
|---|
| 2304 | |
|---|
| 2305 | |
|---|
| 2306 | |
|---|
| 2307 | |
|---|
| 2308 | if not isfile(link): |
|---|
| 2309 | self.presenter.displayErrorMessage(_(u"File does not exist")) |
|---|
| 2310 | return |
|---|
| 2311 | |
|---|
| 2312 | path = dirname(link) |
|---|
| 2313 | filename = basename(link) |
|---|
| 2314 | |
|---|
| 2315 | newName = filename |
|---|
| 2316 | while True: |
|---|
| 2317 | newName = wx.GetTextFromUser(_(u"Enter new name"), |
|---|
| 2318 | _(u"Rename File"), newName, self) |
|---|
| 2319 | if not newName: |
|---|
| 2320 | |
|---|
| 2321 | return |
|---|
| 2322 | |
|---|
| 2323 | newfile = join(path, newName) |
|---|
| 2324 | |
|---|
| 2325 | if exists(newfile): |
|---|
| 2326 | if not isfile(newfile): |
|---|
| 2327 | self.presenter.displayErrorMessage( |
|---|
| 2328 | _(u"Target is not a file")) |
|---|
| 2329 | continue |
|---|
| 2330 | |
|---|
| 2331 | choice = wx.MessageBox( |
|---|
| 2332 | _("Target file exists already. Overwrite?"), |
|---|
| 2333 | _("Overwrite File"), |
|---|
| 2334 | wx.YES_NO | wx.CANCEL | wx.NO_DEFAULT | wx.ICON_QUESTION, |
|---|
| 2335 | self) |
|---|
| 2336 | if choice == wx.CANCEL: |
|---|
| 2337 | return |
|---|
| 2338 | elif choice == wx.NO: |
|---|
| 2339 | continue |
|---|
| 2340 | |
|---|
| 2341 | |
|---|
| 2342 | |
|---|
| 2343 | OsAbstract.moveFile(link, newfile) |
|---|
| 2344 | |
|---|
| 2345 | if node.url.startswith(u"rel://"): |
|---|
| 2346 | |
|---|
| 2347 | newUrl = self.presenter.getWikiDocument().makeAbsPathRelUrl( |
|---|
| 2348 | newfile) |
|---|
| 2349 | else: |
|---|
| 2350 | |
|---|
| 2351 | newUrl = u"file:" + StringOps.urlFromPathname(newfile) |
|---|
| 2352 | |
|---|
| 2353 | self.replaceTextAreaByCharPos(newUrl, node.coreNode.pos, |
|---|
| 2354 | node.coreNode.pos + node.coreNode.strLength) |
|---|
| 2355 | |
|---|
| 2356 | return |
|---|
| 2357 | |
|---|
| 2358 | |
|---|
| 2359 | |
|---|
| 2360 | def convertUrlAbsoluteRelative(self, tokenList): |
|---|
| 2361 | for node in tokenList: |
|---|
| 2362 | if node.name == "urlLink": |
|---|
| 2363 | link = node.url |
|---|
| 2364 | |
|---|
| 2365 | if ' ' in node.coreNode.getString(): |
|---|
| 2366 | addSafe = ' ' |
|---|
| 2367 | else: |
|---|
| 2368 | addSafe = '' |
|---|
| 2369 | |
|---|
| 2370 | if link.startswith(u"rel://") or link.startswith(u"wikirel://"): |
|---|
| 2371 | link = self.presenter.getWikiDocument()\ |
|---|
| 2372 | .makeRelUrlAbsolute(link, addSafe=addSafe) |
|---|
| 2373 | |
|---|
| 2374 | elif link.startswith(u"file:"): |
|---|
| 2375 | link = self.presenter.getWikiDocument()\ |
|---|
| 2376 | .makeAbsPathRelUrl(StringOps.pathnameFromUrl( |
|---|
| 2377 | link), addSafe=addSafe) |
|---|
| 2378 | if link is None: |
|---|
| 2379 | continue |
|---|
| 2380 | elif link.startswith(u"wiki:"): |
|---|
| 2381 | link = self.presenter.getWikiDocument()\ |
|---|
| 2382 | .makeAbsPathRelUrl(StringOps.pathnameFromUrl( |
|---|
| 2383 | link), addSafe=addSafe) |
|---|
| 2384 | if link is None: |
|---|
| 2385 | continue |
|---|
| 2386 | else: |
|---|
| 2387 | link = u"wiki" + link |
|---|
| 2388 | |
|---|
| 2389 | else: |
|---|
| 2390 | continue |
|---|
| 2391 | |
|---|
| 2392 | self.replaceTextAreaByCharPos(link, node.coreNode.pos, |
|---|
| 2393 | node.coreNode.pos + node.coreNode.strLength) |
|---|
| 2394 | |
|---|
| 2395 | break |
|---|
| 2396 | |
|---|
| 2397 | |
|---|
| 2398 | def convertSelectedUrlAbsoluteRelative(self): |
|---|
| 2399 | tokenList = self.getTokensForMousePos(None) |
|---|
| 2400 | self.convertUrlAbsoluteRelative(tokenList) |
|---|
| 2401 | |
|---|
| 2402 | |
|---|
| 2403 | def OnConvertUrlAbsoluteRelativeThis(self, evt): |
|---|
| 2404 | if self.contextMenuTokens: |
|---|
| 2405 | self.convertUrlAbsoluteRelative(self.contextMenuTokens) |
|---|
| 2406 | |
|---|
| 2407 | |
|---|
| 2408 | def OnClipboardCopyUrlToThisAnchor(self, evt): |
|---|
| 2409 | wikiWord = self.presenter.getWikiWord() |
|---|
| 2410 | if wikiWord is None: |
|---|
| 2411 | wx.MessageBox( |
|---|
| 2412 | _(u"This can only be done for the page of a wiki word"), |
|---|
| 2413 | _(u'Not a wiki page'), wx.OK, self) |
|---|
| 2414 | return |
|---|
| 2415 | |
|---|
| 2416 | path = self.presenter.getWikiDocument().getWikiConfigPath() |
|---|
| 2417 | for node in self.contextMenuTokens: |
|---|
| 2418 | if node.name == "anchorDef": |
|---|
| 2419 | copyTextToClipboard(StringOps.pathWordAndAnchorToWikiUrl(path, |
|---|
| 2420 | wikiWord, node.anchorLink)) |
|---|
| 2421 | return |
|---|
| 2422 | |
|---|
| 2423 | |
|---|
| 2424 | |
|---|
| 2425 | def evalScriptBlocks(self, index=-1): |
|---|
| 2426 | """ |
|---|
| 2427 | Evaluates scripts. Respects "script_security_level" option |
|---|
| 2428 | """ |
|---|
| 2429 | securityLevel = self.presenter.getConfig().getint( |
|---|
| 2430 | "main", "script_security_level") |
|---|
| 2431 | if securityLevel == 0: |
|---|
| 2432 | |
|---|
| 2433 | |
|---|
| 2434 | wx.MessageBox(_(u"Set in menu \"Wiki\", item \"Options...\", " |
|---|
| 2435 | "options page \"Security\", \n" |
|---|
| 2436 | "item \"Script security\" an appropriate value " |
|---|
| 2437 | "to execute a script."), _(u"Script execution disabled"), |
|---|
| 2438 | wx.OK, self.presenter.getMainControl()) |
|---|
| 2439 | return |
|---|
| 2440 | |
|---|
| 2441 | SCRIPTFORMAT = "script" |
|---|
| 2442 | |
|---|
| 2443 | self.ConvertEOLs(self.eolMode) |
|---|
| 2444 | (startPos, endPos) = self.GetSelection() |
|---|
| 2445 | |
|---|
| 2446 | |
|---|
| 2447 | if startPos == endPos or index > -1: |
|---|
| 2448 | |
|---|
| 2449 | |
|---|
| 2450 | try: |
|---|
| 2451 | pageAst = self.getPageAst() |
|---|
| 2452 | except NoPageAstException: |
|---|
| 2453 | return |
|---|
| 2454 | |
|---|
| 2455 | scriptNodeGroups = [list(pageAst.iterDeepByName(SCRIPTFORMAT))] |
|---|
| 2456 | |
|---|
| 2457 | |
|---|
| 2458 | if securityLevel > 1: |
|---|
| 2459 | if self.getLoadedDocPage().getAttributes().has_key( |
|---|
| 2460 | u"import_scripts"): |
|---|
| 2461 | scriptNames = self.getLoadedDocPage().getAttributes()[ |
|---|
| 2462 | u"import_scripts"] |
|---|
| 2463 | for sn in scriptNames: |
|---|
| 2464 | try: |
|---|
| 2465 | importPage = self.presenter.getWikiDocument().\ |
|---|
| 2466 | getWikiPage(sn) |
|---|
| 2467 | pageAst = importPage.getLivePageAst() |
|---|
| 2468 | scriptNodeGroups.append(list( |
|---|
| 2469 | pageAst.iterDeepByName(SCRIPTFORMAT))) |
|---|
| 2470 | except: |
|---|
| 2471 | pass |
|---|
| 2472 | |
|---|
| 2473 | if securityLevel > 2: |
|---|
| 2474 | globScriptName = self.presenter.getWikiDocument().getWikiData().\ |
|---|
| 2475 | getGlobalAttributes().get(u"global.import_scripts") |
|---|
| 2476 | |
|---|
| 2477 | if globScriptName is not None: |
|---|
| 2478 | try: |
|---|
| 2479 | importPage = self.presenter.getWikiDocument().\ |
|---|
| 2480 | getWikiPage(globScriptName) |
|---|
| 2481 | pageAst = importPage.getLivePageAst() |
|---|
| 2482 | scriptNodeGroups.append(list( |
|---|
| 2483 | pageAst.iterDeepByName(SCRIPTFORMAT))) |
|---|
| 2484 | except: |
|---|
| 2485 | pass |
|---|
| 2486 | |
|---|
| 2487 | if self.presenter.getConfig().getboolean("main", |
|---|
| 2488 | "script_search_reverse", False): |
|---|
| 2489 | scriptNodeGroups.reverse() |
|---|
| 2490 | |
|---|
| 2491 | scriptNodes = reduce(lambda a, b: a + b, scriptNodeGroups) |
|---|
| 2492 | |
|---|
| 2493 | for node in scriptNodes: |
|---|
| 2494 | script = node.findFlatByName("code").getString() |
|---|
| 2495 | script = re.sub(u"^[\r\n\s]+", u"", script) |
|---|
| 2496 | script = re.sub(u"[\r\n\s]+$", u"", script) |
|---|
| 2497 | try: |
|---|
| 2498 | if index == -1: |
|---|
| 2499 | script = re.sub(u"^\d:?\s?", u"", script) |
|---|
| 2500 | exec(script) in self.evalScope |
|---|
| 2501 | elif index > -1 and script.startswith(str(index)): |
|---|
| 2502 | script = re.sub(u"^\d:?\s?", u"", script) |
|---|
| 2503 | exec(script) in self.evalScope |
|---|
| 2504 | break |
|---|
| 2505 | |
|---|
| 2506 | except Exception, e: |
|---|
| 2507 | s = StringIO() |
|---|
| 2508 | traceback.print_exc(file=s) |
|---|
| 2509 | self.AddText(_(u"\nException: %s") % s.getvalue()) |
|---|
| 2510 | else: |
|---|
| 2511 | |
|---|
| 2512 | text = self.GetSelectedText() |
|---|
| 2513 | try: |
|---|
| 2514 | compThunk = compile(re.sub(u"[\n\r]", u"", text), "<string>", |
|---|
| 2515 | "eval", CO_FUTURE_DIVISION) |
|---|
| 2516 | result = eval(compThunk, self.evalScope) |
|---|
| 2517 | except Exception, e: |
|---|
| 2518 | s = StringIO() |
|---|
| 2519 | traceback.print_exc(file=s) |
|---|
| 2520 | result = s.getvalue() |
|---|
| 2521 | |
|---|
| 2522 | pos = self.GetCurrentPos() |
|---|
| 2523 | self.GotoPos(endPos) |
|---|
| 2524 | self.AddText(u" = %s" % unicode(result)) |
|---|
| 2525 | self.GotoPos(pos) |
|---|
| 2526 | |
|---|
| 2527 | |
|---|
| 2528 | def cleanAutoGenAreas(self, text): |
|---|
| 2529 | """ |
|---|
| 2530 | Remove any content from the autogenerated areas and return |
|---|
| 2531 | cleaned text. Call this before storing page in the database. |
|---|
| 2532 | The original text is returned if option |
|---|
| 2533 | "process_autogenerated_areas" is False. |
|---|
| 2534 | """ |
|---|
| 2535 | return text |
|---|
| 2536 | |
|---|
| 2537 | |
|---|
| 2538 | |
|---|
| 2539 | |
|---|
| 2540 | |
|---|
| 2541 | |
|---|
| 2542 | |
|---|
| 2543 | |
|---|
| 2544 | def _agaReplace(self, match): |
|---|
| 2545 | try: |
|---|
| 2546 | result = unicode(eval(match.group(2), self.evalScope)) |
|---|
| 2547 | except Exception, e: |
|---|
| 2548 | s = StringIO() |
|---|
| 2549 | traceback.print_exc(file=s) |
|---|
| 2550 | result = unicode(s.getvalue()) |
|---|
| 2551 | |
|---|
| 2552 | if len(result) == 0 or result[-1] != u"\n": |
|---|
| 2553 | result += u"\n" |
|---|
| 2554 | |
|---|
| 2555 | return match.group(1) + match.group(2) + result + match.group(4) |
|---|
| 2556 | |
|---|
| 2557 | |
|---|
| 2558 | def updateAutoGenAreas(self, text): |
|---|
| 2559 | """ |
|---|
| 2560 | Update content of the autogenerated areas and return |
|---|
| 2561 | updated text. Call this before loading the text in the editor |
|---|
| 2562 | and on user request. The original text is returned if |
|---|
| 2563 | option "process_autogenerated_areas" is False. |
|---|
| 2564 | """ |
|---|
| 2565 | return text |
|---|
| 2566 | |
|---|
| 2567 | |
|---|
| 2568 | |
|---|
| 2569 | |
|---|
| 2570 | |
|---|
| 2571 | |
|---|
| 2572 | |
|---|
| 2573 | |
|---|
| 2574 | |
|---|
| 2575 | |
|---|
| 2576 | |
|---|
| 2577 | |
|---|
| 2578 | def getAgaCleanedText(self): |
|---|
| 2579 | """ |
|---|
| 2580 | Get editor text after cleaning of autogenerated area content |
|---|
| 2581 | if configuration option is set appropriately, otherwise, the |
|---|
| 2582 | text is not modified |
|---|
| 2583 | """ |
|---|
| 2584 | return self.cleanAutoGenAreas(self.GetText()) |
|---|
| 2585 | |
|---|
| 2586 | |
|---|
| 2587 | def setTextAgaUpdated(self, text): |
|---|
| 2588 | """ |
|---|
| 2589 | Set editor text after updating of autogenerated area content |
|---|
| 2590 | if configuration option is set appropriately, otherwise, the |
|---|
| 2591 | text is not modified |
|---|
| 2592 | """ |
|---|
| 2593 | self.SetText(self.updateAutoGenAreas(text)) |
|---|
| 2594 | |
|---|
| 2595 | |
|---|
| 2596 | |
|---|
| 2597 | AGACONTENTTABLERE = re.compile(ur"^(\+{1,4})([^\n\+][^\n]*)", re.DOTALL | re.LOCALE | re.MULTILINE) |
|---|
| 2598 | |
|---|
| 2599 | def agaContentTable(self, omitfirst = False): |
|---|
| 2600 | """ |
|---|
| 2601 | Can be called by an aga to present the content table of the current page. |
|---|
| 2602 | The text is assumed to be in self.agatext variable(see updateAutoGenAreas()). |
|---|
| 2603 | If omitfirst is true, the first entry (normally the title) is not shown. |
|---|
| 2604 | """ |
|---|
| 2605 | allmatches = map(lambda m: m.group(0), self.AGACONTENTTABLERE.finditer(self.agatext)) |
|---|
| 2606 | if omitfirst and len(allmatches) > 0: |
|---|
| 2607 | allmatches = allmatches[1:] |
|---|
| 2608 | |
|---|
| 2609 | return u"\n".join(allmatches) |
|---|
| 2610 | |
|---|
| 2611 | |
|---|
| 2612 | |
|---|
| 2613 | def agaFormatList(self, l): |
|---|
| 2614 | """ |
|---|
| 2615 | Format a list l of strings in a nice way for an aga content |
|---|
| 2616 | """ |
|---|
| 2617 | return u"\n".join(l) |
|---|
| 2618 | |
|---|
| 2619 | |
|---|
| 2620 | def agaParentsTable(self): |
|---|
| 2621 | """ |
|---|
| 2622 | Can be called by an aga to present all parents of the current page. |
|---|
| 2623 | """ |
|---|
| 2624 | relations = self.getLoadedDocPage().getParentRelationships()[:] |
|---|
| 2625 | |
|---|
| 2626 | |
|---|
| 2627 | relations.sort(key=string.lower) |
|---|
| 2628 | |
|---|
| 2629 | return self.agaFormatList(relations) |
|---|
| 2630 | |
|---|
| 2631 | |
|---|
| 2632 | def ensureTextRangeByBytePosExpanded(self, byteStart, byteEnd): |
|---|
| 2633 | self.repairFoldingVisibility() |
|---|
| 2634 | |
|---|
| 2635 | startLine = self.LineFromPosition(byteStart) |
|---|
| 2636 | endLine = self.LineFromPosition(byteEnd) |
|---|
| 2637 | |
|---|
| 2638 | |
|---|
| 2639 | if endLine < startLine: |
|---|
| 2640 | startLine, endLine = endLine, startLine |
|---|
| 2641 | |
|---|
| 2642 | for checkLine in xrange(endLine, startLine - 1, -1): |
|---|
| 2643 | if not self.GetLineVisible(checkLine): |
|---|
| 2644 | line = checkLine |
|---|
| 2645 | |
|---|
| 2646 | while True: |
|---|
| 2647 | line = self.GetFoldParent(line) |
|---|
| 2648 | if line == -1: |
|---|
| 2649 | break |
|---|
| 2650 | if not self.GetFoldExpanded(line): |
|---|
| 2651 | self.ToggleFold(line) |
|---|
| 2652 | |
|---|
| 2653 | |
|---|
| 2654 | |
|---|
| 2655 | def ensureSelectionExpanded(self): |
|---|
| 2656 | """ |
|---|
| 2657 | Ensure that the selection is visible and not in a folded area |
|---|
| 2658 | """ |
|---|
| 2659 | byteStart = self.GetSelectionStart() |
|---|
| 2660 | byteEnd = self.GetSelectionEnd() |
|---|
| 2661 | |
|---|
| 2662 | self.ensureTextRangeByBytePosExpanded(byteStart, byteEnd) |
|---|
| 2663 | |
|---|
| 2664 | self.SetSelection(byteStart, byteEnd) |
|---|
| 2665 | |
|---|
| 2666 | |
|---|
| 2667 | def setSelectionForIncSearchByCharPos(self, start, end): |
|---|
| 2668 | """ |
|---|
| 2669 | Overwrites SearchableScintillaControl.setSelectionForIncSearchByCharPos |
|---|
| 2670 | Called during incremental search to select text. Will be called with |
|---|
| 2671 | start=-1 if nothing is found to select. |
|---|
| 2672 | This variant handles showing/hiding of folded lines |
|---|
| 2673 | """ |
|---|
| 2674 | |
|---|
| 2675 | |
|---|
| 2676 | if self.incSearchPreviousHiddenLines is not None: |
|---|
| 2677 | line = self.incSearchPreviousHiddenStartLine |
|---|
| 2678 | for state in self.incSearchPreviousHiddenLines: |
|---|
| 2679 | if state: |
|---|
| 2680 | self.ShowLines(line, line) |
|---|
| 2681 | else: |
|---|
| 2682 | self.HideLines(line, line) |
|---|
| 2683 | |
|---|
| 2684 | line += 1 |
|---|
| 2685 | |
|---|
| 2686 | self.incSearchPreviousHiddenLines = None |
|---|
| 2687 | self.incSearchPreviousHiddenStartLine = -1 |
|---|
| 2688 | |
|---|
| 2689 | if start == -1: |
|---|
| 2690 | |
|---|
| 2691 | self.SetSelection(self.GetSelectionStart(), self.GetSelectionStart()) |
|---|
| 2692 | return |
|---|
| 2693 | text = self.GetText() |
|---|
| 2694 | |
|---|
| 2695 | byteStart = self.bytelenSct(text[:start]) |
|---|
| 2696 | byteEnd = byteStart + self.bytelenSct(text[start:end]) |
|---|
| 2697 | startLine = self.LineFromPosition(byteStart) |
|---|
| 2698 | endLine = self.LineFromPosition(byteEnd) |
|---|
| 2699 | |
|---|
| 2700 | |
|---|
| 2701 | shownList = [] |
|---|
| 2702 | for i in xrange(startLine, endLine + 1): |
|---|
| 2703 | shownList.append(self.GetLineVisible(i)) |
|---|
| 2704 | |
|---|
| 2705 | self.incSearchPreviousHiddenLines = shownList |
|---|
| 2706 | self.incSearchPreviousHiddenStartLine = startLine |
|---|
| 2707 | |
|---|
| 2708 | |
|---|
| 2709 | self.ShowLines(startLine, endLine) |
|---|
| 2710 | self.SetSelection(byteStart, byteEnd) |
|---|
| 2711 | |
|---|
| 2712 | |
|---|
| 2713 | |
|---|
| 2714 | def startIncrementalSearch(self, initSearch=None): |
|---|
| 2715 | self.incSearchPreviousHiddenLines = None |
|---|
| 2716 | self.incSearchPreviousHiddenStartLine = -1 |
|---|
| 2717 | |
|---|
| 2718 | super(WikiTxtCtrl, self).startIncrementalSearch(initSearch) |
|---|
| 2719 | |
|---|
| 2720 | |
|---|
| 2721 | def endIncrementalSearch(self): |
|---|
| 2722 | super(WikiTxtCtrl, self).endIncrementalSearch() |
|---|
| 2723 | |
|---|
| 2724 | self.ensureSelectionExpanded() |
|---|
| 2725 | |
|---|
| 2726 | |
|---|
| 2727 | def rewrapText(self): |
|---|
| 2728 | return self.wikiLanguageHelper.handleRewrapText(self, {}) |
|---|
| 2729 | |
|---|
| 2730 | |
|---|
| 2731 | def getNearestWordPositions(self, bytepos=None): |
|---|
| 2732 | if not bytepos: |
|---|
| 2733 | bytepos = self.GetCurrentPos() |
|---|
| 2734 | return (self.WordStartPosition(bytepos, 1), self.WordEndPosition(bytepos, 1)) |
|---|
| 2735 | |
|---|
| 2736 | |
|---|
| 2737 | def autoComplete(self): |
|---|
| 2738 | """ |
|---|
| 2739 | Called when user wants autocompletion. |
|---|
| 2740 | """ |
|---|
| 2741 | text = self.GetText() |
|---|
| 2742 | wikiDocument = self.presenter.getWikiDocument() |
|---|
| 2743 | closingBracket = self.presenter.getConfig().getboolean("main", |
|---|
| 2744 | "editor_autoComplete_closingBracket", False) |
|---|
| 2745 | |
|---|
| 2746 | bytePos = self.GetCurrentPos() |
|---|
| 2747 | lineStartBytePos = self.PositionFromLine(self.LineFromPosition(bytePos)) |
|---|
| 2748 | |
|---|
| 2749 | lineStartCharPos = len(self.GetTextRange(0, lineStartBytePos)) |
|---|
| 2750 | charPos = lineStartCharPos + len(self.GetTextRange(lineStartBytePos, |
|---|
| 2751 | bytePos)) |
|---|
| 2752 | |
|---|
| 2753 | acResultTuples = self.wikiLanguageHelper.prepareAutoComplete(self, text, |
|---|
| 2754 | charPos, lineStartCharPos, wikiDocument, self.getLoadedDocPage(), |
|---|
| 2755 | {"closingBracket": closingBracket, "builtinAttribs": True}) |
|---|
| 2756 | |
|---|
| 2757 | if len(acResultTuples) > 0: |
|---|
| 2758 | self.presenter.getWikiDocument().getCollator().sortByFirst( |
|---|
| 2759 | acResultTuples) |
|---|
| 2760 | |
|---|
| 2761 | self.autoCompBackBytesMap = dict( ( |
|---|
| 2762 | (art[1], self.bytelenSct(text[charPos - art[2]:charPos])) |
|---|
| 2763 | for art in acResultTuples) ) |
|---|
| 2764 | |
|---|
| 2765 | self.UserListShow(1, u"\x01".join( |
|---|
| 2766 | [art[1] for art in acResultTuples])) |
|---|
| 2767 | |
|---|
| 2768 | |
|---|
| 2769 | def OnModified(self, evt): |
|---|
| 2770 | if not self.ignoreOnChange: |
|---|
| 2771 | |
|---|
| 2772 | if evt.GetModificationType() & \ |
|---|
| 2773 | (wx.stc.STC_MOD_INSERTTEXT | wx.stc.STC_MOD_DELETETEXT): |
|---|
| 2774 | |
|---|
| 2775 | self.presenter.informEditorTextChanged(self) |
|---|
| 2776 | |
|---|
| 2777 | |
|---|
| 2778 | |
|---|
| 2779 | |
|---|
| 2780 | |
|---|
| 2781 | |
|---|
| 2782 | def OnCharAdded(self, evt): |
|---|
| 2783 | "When the user presses enter reindent to the previous level" |
|---|
| 2784 | |
|---|
| 2785 | |
|---|
| 2786 | |
|---|
| 2787 | evt.Skip() |
|---|
| 2788 | key = evt.GetKey() |
|---|
| 2789 | |
|---|
| 2790 | if key == 10: |
|---|
| 2791 | text = self.GetText() |
|---|
| 2792 | wikiDocument = self.presenter.getWikiDocument() |
|---|
| 2793 | bytePos = self.GetCurrentPos() |
|---|
| 2794 | lineStartBytePos = self.PositionFromLine(self.LineFromPosition(bytePos)) |
|---|
| 2795 | |
|---|
| 2796 | lineStartCharPos = len(self.GetTextRange(0, lineStartBytePos)) |
|---|
| 2797 | charPos = lineStartCharPos + len(self.GetTextRange(lineStartBytePos, |
|---|
| 2798 | bytePos)) |
|---|
| 2799 | |
|---|
| 2800 | autoUnbullet = self.presenter.getConfig().getboolean("main", |
|---|
| 2801 | "editor_autoUnbullets", False) |
|---|
| 2802 | |
|---|
| 2803 | settings = { |
|---|
| 2804 | "autoUnbullet": autoUnbullet, |
|---|
| 2805 | "autoBullets": self.autoBullets, |
|---|
| 2806 | "autoIndent": self.autoIndent |
|---|
| 2807 | } |
|---|
| 2808 | |
|---|
| 2809 | self.wikiLanguageHelper.handleNewLineAfterEditor(self, text, |
|---|
| 2810 | charPos, lineStartCharPos, wikiDocument, settings) |
|---|
| 2811 | |
|---|
| 2812 | |
|---|
| 2813 | def _getExpandedByteSelectionToLine(self, extendOverChildren): |
|---|
| 2814 | """ |
|---|
| 2815 | Move the start of current selection to start of the line it's in and |
|---|
| 2816 | move end of selection to end of its line. |
|---|
| 2817 | """ |
|---|
| 2818 | selByteStart = self.GetSelectionStart(); |
|---|
| 2819 | selByteEnd = self.GetSelectionEnd(); |
|---|
| 2820 | lastLine = self.LineFromPosition(selByteEnd) |
|---|
| 2821 | selByteStart = self.PositionFromLine(self.LineFromPosition(selByteStart)) |
|---|
| 2822 | selByteEnd = self.PositionFromLine(lastLine + 1) |
|---|
| 2823 | |
|---|
| 2824 | if extendOverChildren: |
|---|
| 2825 | |
|---|
| 2826 | |
|---|
| 2827 | lastLineDeep = StringOps.splitIndentDeepness(self.GetLine(lastLine))[0] |
|---|
| 2828 | |
|---|
| 2829 | testLine = lastLine + 1 |
|---|
| 2830 | while True: |
|---|
| 2831 | testLineContent = self.GetLine(testLine) |
|---|
| 2832 | if len(testLineContent) == 0: |
|---|
| 2833 | |
|---|
| 2834 | break |
|---|
| 2835 | |
|---|
| 2836 | if StringOps.splitIndentDeepness(testLineContent)[0] <= lastLineDeep: |
|---|
| 2837 | break |
|---|
| 2838 | |
|---|
| 2839 | testLine += 1 |
|---|
| 2840 | |
|---|
| 2841 | selByteEnd = self.PositionFromLine(testLine) |
|---|
| 2842 | |
|---|
| 2843 | self.SetSelectionMode(0) |
|---|
| 2844 | self.SetSelectionStart(selByteStart) |
|---|
| 2845 | self.SetSelectionMode(0) |
|---|
| 2846 | self.SetSelectionEnd(selByteEnd) |
|---|
| 2847 | |
|---|
| 2848 | return selByteStart, selByteEnd |
|---|
| 2849 | |
|---|
| 2850 | |
|---|
| 2851 | |
|---|
| 2852 | def moveSelectedLinesOneUp(self, extendOverChildren): |
|---|
| 2853 | """ |
|---|
| 2854 | Extend current selection to full logical lines and move selected lines |
|---|
| 2855 | upward one line. |
|---|
| 2856 | extendOverChildren -- iff true, extend selection over lines more indented |
|---|
| 2857 | below the initial selection |
|---|
| 2858 | """ |
|---|
| 2859 | self.BeginUndoAction() |
|---|
| 2860 | try: |
|---|
| 2861 | selByteStart, selByteEnd = self._getExpandedByteSelectionToLine( |
|---|
| 2862 | extendOverChildren) |
|---|
| 2863 | |
|---|
| 2864 | firstLine = self.LineFromPosition(selByteStart) |
|---|
| 2865 | if firstLine > 0: |
|---|
| 2866 | content = self.GetSelectedText() |
|---|
| 2867 | if len(content) > 0: |
|---|
| 2868 | if content[-1] == u"\n": |
|---|
| 2869 | selByteEnd -= 1 |
|---|
| 2870 | else: |
|---|
| 2871 | content += u"\n" |
|---|
| 2872 | |
|---|
| 2873 | |
|---|
| 2874 | self.ReplaceSelection("") |
|---|
| 2875 | target = self.PositionFromLine(firstLine - 1) |
|---|
| 2876 | self.InsertText(target, content) |
|---|
| 2877 | self.SetSelectionMode(0) |
|---|
| 2878 | self.SetSelectionStart(target) |
|---|
| 2879 | self.SetSelectionMode(0) |
|---|
| 2880 | self.SetSelectionEnd(target + (selByteEnd - selByteStart)) |
|---|
| 2881 | finally: |
|---|
| 2882 | self.EndUndoAction() |
|---|
| 2883 | |
|---|
| 2884 | |
|---|
| 2885 | |
|---|
| 2886 | def moveSelectedLinesOneDown(self, extendOverChildren): |
|---|
| 2887 | """ |
|---|
| 2888 | Extend current selection to full logical lines and move selected lines |
|---|
| 2889 | upward one line. |
|---|
| 2890 | extendOverChildren -- iff true, extend selection over lines more indented |
|---|
| 2891 | below the initial selection |
|---|
| 2892 | """ |
|---|
| 2893 | self.BeginUndoAction() |
|---|
| 2894 | try: |
|---|
| 2895 | selByteStart, selByteEnd = self._getExpandedByteSelectionToLine( |
|---|
| 2896 | extendOverChildren) |
|---|
| 2897 | |
|---|
| 2898 | lastLine = self.LineFromPosition(selByteEnd) |
|---|
| 2899 | lineCount = self.GetLineCount() - 1 |
|---|
| 2900 | if lastLine <= lineCount: |
|---|
| 2901 | content = self.GetSelectedText() |
|---|
| 2902 | if len(content) > 0: |
|---|
| 2903 | |
|---|
| 2904 | |
|---|
| 2905 | target = self.PositionFromLine(lastLine + 1) |
|---|
| 2906 | target -= selByteEnd - selByteStart |
|---|
| 2907 | |
|---|
| 2908 | if content[-1] == u"\n": |
|---|
| 2909 | selByteEnd -= 1 |
|---|
| 2910 | else: |
|---|
| 2911 | content += u"\n" |
|---|
| 2912 | |
|---|
| 2913 | self.ReplaceSelection("") |
|---|
| 2914 | if self.GetTextRange(target - 1, |
|---|
| 2915 | target) != u"\n": |
|---|
| 2916 | self.InsertText(target, u"\n") |
|---|
| 2917 | target += 1 |
|---|
| 2918 | |
|---|
| 2919 | self.InsertText(target, content) |
|---|
| 2920 | self.SetSelectionMode(0) |
|---|
| 2921 | self.SetSelectionStart(target) |
|---|
| 2922 | self.SetSelectionMode(0) |
|---|
| 2923 | self.SetSelectionEnd(target + (selByteEnd - selByteStart)) |
|---|
| 2924 | finally: |
|---|
| 2925 | self.EndUndoAction() |
|---|
| 2926 | |
|---|
| 2927 | |
|---|
| 2928 | |
|---|
| 2929 | def OnKeyDown(self, evt): |
|---|
| 2930 | key = evt.GetKeyCode() |
|---|
| 2931 | |
|---|
| 2932 | self.lastKeyPressed = time() |
|---|
| 2933 | accP = getAccelPairFromKeyDown(evt) |
|---|
| 2934 | matchesAccelPair = self.presenter.getMainControl().keyBindings.\ |
|---|
| 2935 | matchesAccelPair |
|---|
| 2936 | |
|---|
| 2937 | |
|---|
| 2938 | |
|---|
| 2939 | |
|---|
| 2940 | |
|---|
| 2941 | |
|---|
| 2942 | |
|---|
| 2943 | |
|---|
| 2944 | |
|---|
| 2945 | |
|---|
| 2946 | |
|---|
| 2947 | |
|---|
| 2948 | |
|---|
| 2949 | |
|---|
| 2950 | |
|---|
| 2951 | |
|---|
| 2952 | |
|---|
| 2953 | |
|---|
| 2954 | |
|---|
| 2955 | |
|---|
| 2956 | if matchesAccelPair("AutoComplete", accP): |
|---|
| 2957 | |
|---|
| 2958 | |
|---|
| 2959 | self.autoComplete() |
|---|
| 2960 | |
|---|
| 2961 | elif matchesAccelPair("ActivateLink2", accP): |
|---|
| 2962 | |
|---|
| 2963 | self.activateLink() |
|---|
| 2964 | |
|---|
| 2965 | elif matchesAccelPair("ActivateLinkBackground", accP): |
|---|
| 2966 | |
|---|
| 2967 | self.activateLink(tabMode=3) |
|---|
| 2968 | |
|---|
| 2969 | elif matchesAccelPair("ActivateLink", accP): |
|---|
| 2970 | |
|---|
| 2971 | |
|---|
| 2972 | |
|---|
| 2973 | |
|---|
| 2974 | self.activateLink() |
|---|
| 2975 | |
|---|
| 2976 | elif matchesAccelPair("ActivateLinkNewTab", accP): |
|---|
| 2977 | |
|---|
| 2978 | |
|---|
| 2979 | |
|---|
| 2980 | |
|---|
| 2981 | self.activateLink(tabMode=2) |
|---|
| 2982 | |
|---|
| 2983 | elif matchesAccelPair("ActivateLinkNewWindow", accP): |
|---|
| 2984 | self.activateLink(tabMode=6) |
|---|
| 2985 | |
|---|
| 2986 | elif matchesAccelPair("LogLineUp", accP): |
|---|
| 2987 | |
|---|
| 2988 | self.moveSelectedLinesOneUp(False) |
|---|
| 2989 | elif matchesAccelPair("LogLineUpWithIndented", accP): |
|---|
| 2990 | |
|---|
| 2991 | self.moveSelectedLinesOneUp(True) |
|---|
| 2992 | elif matchesAccelPair("LogLineDown", accP): |
|---|
| 2993 | |
|---|
| 2994 | self.moveSelectedLinesOneDown(False) |
|---|
| 2995 | elif matchesAccelPair("LogLineDownWithIndented", accP): |
|---|
| 2996 | |
|---|
| 2997 | self.moveSelectedLinesOneDown(True) |
|---|
| 2998 | |
|---|
| 2999 | elif not evt.ControlDown() and not evt.ShiftDown(): |
|---|
| 3000 | if key == wx.WXK_TAB: |
|---|
| 3001 | if self.pageType == u"form": |
|---|
| 3002 | if not self._goToNextFormField(): |
|---|
| 3003 | self.presenter.getMainControl().showStatusMessage( |
|---|
| 3004 | _(u"No more fields in this 'form' page"), -1) |
|---|
| 3005 | return |
|---|
| 3006 | evt.Skip() |
|---|
| 3007 | elif key == wx.WXK_RETURN and not self.AutoCompActive(): |
|---|
| 3008 | text = self.GetText() |
|---|
| 3009 | wikiDocument = self.presenter.getWikiDocument() |
|---|
| 3010 | bytePos = self.GetCurrentPos() |
|---|
| 3011 | lineStartBytePos = self.PositionFromLine(self.LineFromPosition(bytePos)) |
|---|
| 3012 | |
|---|
| 3013 | lineStartCharPos = len(self.GetTextRange(0, lineStartBytePos)) |
|---|
| 3014 | charPos = lineStartCharPos + len(self.GetTextRange(lineStartBytePos, |
|---|
| 3015 | bytePos)) |
|---|
| 3016 | |
|---|
| 3017 | autoUnbullet = self.presenter.getConfig().getboolean("main", |
|---|
| 3018 | "editor_autoUnbullets", False) |
|---|
| 3019 | |
|---|
| 3020 | settings = { |
|---|
| 3021 | "autoUnbullet": autoUnbullet, |
|---|
| 3022 | "autoBullets": self.autoBullets, |
|---|
| 3023 | "autoIndent": self.autoIndent |
|---|
| 3024 | } |
|---|
| 3025 | |
|---|
| 3026 | if self.wikiLanguageHelper.handleNewLineBeforeEditor(self, text, |
|---|
| 3027 | charPos, lineStartCharPos, wikiDocument, settings): |
|---|
| 3028 | evt.Skip() |
|---|
| 3029 | return |
|---|
| 3030 | |
|---|
| 3031 | else: |
|---|
| 3032 | evt.Skip() |
|---|
| 3033 | |
|---|
| 3034 | else: |
|---|
| 3035 | super(WikiTxtCtrl, self).OnKeyDown(evt) |
|---|
| 3036 | |
|---|
| 3037 | |
|---|
| 3038 | def OnChar_ImeWorkaround(self, evt): |
|---|
| 3039 | """ |
|---|
| 3040 | Workaround for problem of Scintilla with some input method editors, |
|---|
| 3041 | e.g. UniKey vietnamese IME. |
|---|
| 3042 | """ |
|---|
| 3043 | key = evt.GetKeyCode() |
|---|
| 3044 | |
|---|
| 3045 | |
|---|
| 3046 | if evt.ControlDown() or (0 < key < 32): |
|---|
| 3047 | evt.Skip() |
|---|
| 3048 | return |
|---|
| 3049 | |
|---|
| 3050 | if key >= wx.WXK_START and (not isUnicode() or evt.GetUnicodeKey() != key): |
|---|
| 3051 | evt.Skip() |
|---|
| 3052 | return |
|---|
| 3053 | |
|---|
| 3054 | if isUnicode(): |
|---|
| 3055 | unichar = unichr(evt.GetUnicodeKey()) |
|---|
| 3056 | else: |
|---|
| 3057 | unichar = StringOps.mbcsDec(chr(key))[0] |
|---|
| 3058 | |
|---|
| 3059 | self.ReplaceSelection(unichar) |
|---|
| 3060 | |
|---|
| 3061 | |
|---|
| 3062 | if isLinux(): |
|---|
| 3063 | def OnSetFocus(self, evt): |
|---|
| 3064 | |
|---|
| 3065 | evt.Skip() |
|---|
| 3066 | |
|---|
| 3067 | wikiPage = self.getLoadedDocPage() |
|---|
| 3068 | if wikiPage is None: |
|---|
| 3069 | return |
|---|
| 3070 | if not isinstance(wikiPage, |
|---|
| 3071 | (DocPages.DataCarryingPage, DocPages.AliasWikiPage)): |
|---|
| 3072 | return |
|---|
| 3073 | |
|---|
| 3074 | try: |
|---|
| 3075 | wikiPage.checkFileSignatureAndMarkDirty() |
|---|
| 3076 | except (IOError, OSError, DbAccessError), e: |
|---|
| 3077 | self.presenter.getMainControl().lostAccess(e) |
|---|
| 3078 | |
|---|
| 3079 | |
|---|
| 3080 | else: |
|---|
| 3081 | def OnSetFocus(self, evt): |
|---|
| 3082 | self.presenter.makeCurrent() |
|---|
| 3083 | evt.Skip() |
|---|
| 3084 | |
|---|
| 3085 | wikiPage = self.getLoadedDocPage() |
|---|
| 3086 | if wikiPage is None: |
|---|
| 3087 | return |
|---|
| 3088 | if not isinstance(wikiPage, |
|---|
| 3089 | (DocPages.DataCarryingPage, DocPages.AliasWikiPage)): |
|---|
| 3090 | return |
|---|
| 3091 | |
|---|
| 3092 | try: |
|---|
| 3093 | wikiPage.checkFileSignatureAndMarkDirty() |
|---|
| 3094 | except (IOError, OSError, DbAccessError), e: |
|---|
| 3095 | self.presenter.getMainControl().lostAccess(e) |
|---|
| 3096 | |
|---|
| 3097 | |
|---|
| 3098 | |
|---|
| 3099 | |
|---|
| 3100 | def OnUserListSelection(self, evt): |
|---|
| 3101 | text = evt.GetText() |
|---|
| 3102 | toerase = self.autoCompBackBytesMap[text] |
|---|
| 3103 | |
|---|
| 3104 | self.SetSelection(self.GetCurrentPos() - toerase, self.GetCurrentPos()) |
|---|
| 3105 | |
|---|
| 3106 | self.ReplaceSelection(text) |
|---|
| 3107 | |
|---|
| 3108 | |
|---|
| 3109 | def OnClick(self, evt): |
|---|
| 3110 | if evt.ControlDown(): |
|---|
| 3111 | x = evt.GetX() |
|---|
| 3112 | y = evt.GetY() |
|---|
| 3113 | if not self.activateLink(wx.Point(x, y)): |
|---|
| 3114 | evt.Skip() |
|---|
| 3115 | else: |
|---|
| 3116 | evt.Skip() |
|---|
| 3117 | |
|---|
| 3118 | def OnMiddleDown(self, evt): |
|---|
| 3119 | if not evt.ControlDown(): |
|---|
| 3120 | middleConfig = self.presenter.getConfig().getint("main", |
|---|
| 3121 | "mouse_middleButton_withoutCtrl", 2) |
|---|
| 3122 | else: |
|---|
| 3123 | middleConfig = self.presenter.getConfig().getint("main", |
|---|
| 3124 | "mouse_middleButton_withCtrl", 3) |
|---|
| 3125 | |
|---|
| 3126 | tabMode = Configuration.MIDDLE_MOUSE_CONFIG_TO_TABMODE[middleConfig] |
|---|
| 3127 | |
|---|
| 3128 | if not self.activateLink(evt.GetPosition(), tabMode=tabMode): |
|---|
| 3129 | evt.Skip() |
|---|
| 3130 | |
|---|
| 3131 | |
|---|
| 3132 | def OnDoubleClick(self, evt): |
|---|
| 3133 | x = evt.GetX() |
|---|
| 3134 | y = evt.GetY() |
|---|
| 3135 | if not self.activateLink(wx.Point(x, y)): |
|---|
| 3136 | evt.Skip() |
|---|
| 3137 | |
|---|
| 3138 | |
|---|
| 3139 | |
|---|
| 3140 | |
|---|
| 3141 | |
|---|
| 3142 | |
|---|
| 3143 | |
|---|
| 3144 | |
|---|
| 3145 | |
|---|
| 3146 | |
|---|
| 3147 | |
|---|
| 3148 | |
|---|
| 3149 | |
|---|
| 3150 | |
|---|
| 3151 | |
|---|
| 3152 | |
|---|
| 3153 | |
|---|
| 3154 | |
|---|
| 3155 | |
|---|
| 3156 | |
|---|
| 3157 | |
|---|
| 3158 | |
|---|
| 3159 | |
|---|
| 3160 | |
|---|
| 3161 | |
|---|
| 3162 | |
|---|
| 3163 | |
|---|
| 3164 | |
|---|
| 3165 | |
|---|
| 3166 | def onIdleVisible(self, miscevt): |
|---|
| 3167 | if (self.IsEnabled()): |
|---|
| 3168 | if self.presenter.isCurrent(): |
|---|
| 3169 | |
|---|
| 3170 | currentLine = self.GetCurrentLine()+1 |
|---|
| 3171 | currentPos = self.GetCurrentPos() |
|---|
| 3172 | currentCol = self.GetColumn(currentPos) |
|---|
| 3173 | self.presenter.SetStatusText(_(u"Line: %d Col: %d Pos: %d") % |
|---|
| 3174 | (currentLine, currentCol, currentPos), 2) |
|---|
| 3175 | |
|---|
| 3176 | |
|---|
| 3177 | def OnDestroy(self, evt): |
|---|
| 3178 | |
|---|
| 3179 | |
|---|
| 3180 | wx.TheClipboard.Flush() |
|---|
| 3181 | evt.Skip() |
|---|
| 3182 | |
|---|
| 3183 | |
|---|
| 3184 | def OnMarginClick(self, evt): |
|---|
| 3185 | if evt.GetMargin() == self.FOLD_MARGIN: |
|---|
| 3186 | pos = evt.GetPosition() |
|---|
| 3187 | line = self.LineFromPosition(pos) |
|---|
| 3188 | modifiers = evt.GetModifiers() |
|---|
| 3189 | |
|---|
| 3190 | self.ToggleFold(line) |
|---|
| 3191 | self.repairFoldingVisibility() |
|---|
| 3192 | |
|---|
| 3193 | evt.Skip() |
|---|
| 3194 | |
|---|
| 3195 | |
|---|
| 3196 | |
|---|
| 3197 | def _threadShowCalltip(self, wikiDocument, charPos, bytePos, |
|---|
| 3198 | threadstop=DUMBTHREADSTOP): |
|---|
| 3199 | try: |
|---|
| 3200 | docPage = self.getLoadedDocPage() |
|---|
| 3201 | if docPage is None: |
|---|
| 3202 | return |
|---|
| 3203 | |
|---|
| 3204 | pageAst = docPage.getLivePageAst(threadstop=threadstop) |
|---|
| 3205 | |
|---|
| 3206 | astNodes = pageAst.findNodesForCharPos(charPos) |
|---|
| 3207 | |
|---|
| 3208 | if charPos > 0: |
|---|
| 3209 | |
|---|
| 3210 | |
|---|
| 3211 | astNodes += pageAst.findNodesForCharPos(charPos - 1) |
|---|
| 3212 | |
|---|
| 3213 | callTip = None |
|---|
| 3214 | for astNode in astNodes: |
|---|
| 3215 | if astNode.name == "wikiWord": |
|---|
| 3216 | threadstop.testRunning() |
|---|
| 3217 | wikiWord = wikiDocument.getWikiPageNameForLinkTerm( |
|---|
| 3218 | astNode.wikiWord) |
|---|
| 3219 | |
|---|
| 3220 | |
|---|
| 3221 | callInMainThread( |
|---|
| 3222 | self.presenter.getMainControl().showStatusMessage, |
|---|
| 3223 | _(u"Link to page: %s") % wikiWord, 0) |
|---|
| 3224 | |
|---|
| 3225 | if wikiWord is not None: |
|---|
| 3226 | propList = wikiDocument.getAttributeTriples( |
|---|
| 3227 | wikiWord, u"short_hint", None) |
|---|
| 3228 | if len(propList) > 0: |
|---|
| 3229 | callTip = propList[-1][2] |
|---|
| 3230 | break |
|---|
| 3231 | elif astNode.name == "urlLink": |
|---|
| 3232 | |
|---|
| 3233 | if not self.presenter.getConfig().getboolean("main", |
|---|
| 3234 | "editor_imageTooltips_localUrls", True): |
|---|
| 3235 | continue |
|---|
| 3236 | |
|---|
| 3237 | |
|---|
| 3238 | if astNode.appendixNode is None: |
|---|
| 3239 | appendixDict = {} |
|---|
| 3240 | else: |
|---|
| 3241 | appendixDict = dict(astNode.appendixNode.entries) |
|---|
| 3242 | |
|---|
| 3243 | |
|---|
| 3244 | if appendixDict.has_key("l"): |
|---|
| 3245 | urlAsImage = False |
|---|
| 3246 | elif appendixDict.has_key("i"): |
|---|
| 3247 | urlAsImage = True |
|---|
| 3248 | |
|---|
| 3249 | |
|---|
| 3250 | |
|---|
| 3251 | |
|---|
| 3252 | |
|---|
| 3253 | |
|---|
| 3254 | elif astNode.url.lower().split(".")[-1] in \ |
|---|
| 3255 | ("jpg", "jpeg", "gif", "png", "tif", "bmp"): |
|---|
| 3256 | urlAsImage = True |
|---|
| 3257 | else: |
|---|
| 3258 | urlAsImage = False |
|---|
| 3259 | |
|---|
| 3260 | |
|---|
| 3261 | if urlAsImage: |
|---|
| 3262 | path = self.presenter.getWikiDocument()\ |
|---|
| 3263 | .makeFileUrlAbsPath(astNode.url) |
|---|
| 3264 | |
|---|
| 3265 | if path is not None and isfile(path): |
|---|
| 3266 | if imghdr.what(path): |
|---|
| 3267 | config = self.presenter.getConfig() |
|---|
| 3268 | maxWidth = config.getint("main", |
|---|
| 3269 | "editor_imageTooltips_maxWidth", 200) |
|---|
| 3270 | maxHeight = config.getint("main", |
|---|
| 3271 | "editor_imageTooltips_maxHeight", 200) |
|---|
| 3272 | |
|---|
| 3273 | def SetImageTooltip(path): |
|---|
| 3274 | self.tooltip_image = ImageTooltipPanel(self, |
|---|
| 3275 | path, maxWidth, maxHeight) |
|---|
| 3276 | threadstop.testRunning() |
|---|
| 3277 | callInMainThread(SetImageTooltip, path) |
|---|
| 3278 | else: |
|---|
| 3279 | callTip = _(u"Not a valid image") |
|---|
| 3280 | break |
|---|
| 3281 | |
|---|
| 3282 | if callTip: |
|---|
| 3283 | threadstop.testRunning() |
|---|
| 3284 | callInMainThread(self.CallTipShow, bytePos, callTip) |
|---|
| 3285 | |
|---|
| 3286 | except NotCurrentThreadException: |
|---|
| 3287 | pass |
|---|
| 3288 | |
|---|
| 3289 | @contextlib.contextmanager |
|---|
| 3290 | def dwellLock(self): |
|---|
| 3291 | if self.dwellLockCounter == 0: |
|---|
| 3292 | self.OnDwellEnd(None) |
|---|
| 3293 | |
|---|
| 3294 | self.dwellLockCounter += 1 |
|---|
| 3295 | yield |
|---|
| 3296 | self.dwellLockCounter -= 1 |
|---|
| 3297 | |
|---|
| 3298 | |
|---|
| 3299 | def OnDwellStart(self, evt): |
|---|
| 3300 | if self.dwellLockCounter > 0: |
|---|
| 3301 | return |
|---|
| 3302 | |
|---|
| 3303 | wikiDocument = self.presenter.getWikiDocument() |
|---|
| 3304 | if wikiDocument is None: |
|---|
| 3305 | return |
|---|
| 3306 | bytePos = evt.GetPosition() |
|---|
| 3307 | charPos = len(self.GetTextRange(0, bytePos)) |
|---|
| 3308 | |
|---|
| 3309 | thread = threading.Thread(target=self._threadShowCalltip, |
|---|
| 3310 | args=(wikiDocument, charPos, bytePos), |
|---|
| 3311 | kwargs={"threadstop": self.calltipThreadHolder}) |
|---|
| 3312 | |
|---|
| 3313 | self.calltipThreadHolder.setThread(thread) |
|---|
| 3314 | thread.setDaemon(True) |
|---|
| 3315 | thread.start() |
|---|
| 3316 | |
|---|
| 3317 | |
|---|
| 3318 | def OnDwellEnd(self, evt): |
|---|
| 3319 | if self.dwellLockCounter > 0: |
|---|
| 3320 | return |
|---|
| 3321 | |
|---|
| 3322 | self.calltipThreadHolder.setThread(None) |
|---|
| 3323 | self.CallTipCancel() |
|---|
| 3324 | |
|---|
| 3325 | |
|---|
| 3326 | callInMainThread(self.presenter.getMainControl().showStatusMessage, "", |
|---|
| 3327 | 0) |
|---|
| 3328 | |
|---|
| 3329 | if self.tooltip_image: |
|---|
| 3330 | self.tooltip_image.Close() |
|---|
| 3331 | self.tooltip_image = None |
|---|
| 3332 | |
|---|
| 3333 | @staticmethod |
|---|
| 3334 | def userActionPasteFiles(unifActionName, paramDict): |
|---|
| 3335 | """ |
|---|
| 3336 | User action to handle pasting or dropping of files into editor. |
|---|
| 3337 | """ |
|---|
| 3338 | editor = paramDict.get("editor") |
|---|
| 3339 | if editor is None: |
|---|
| 3340 | return |
|---|
| 3341 | |
|---|
| 3342 | filenames = paramDict.get("filenames") |
|---|
| 3343 | x = paramDict.get("x") |
|---|
| 3344 | y = paramDict.get("y") |
|---|
| 3345 | |
|---|
| 3346 | dlgParams = WikiTxtDialogs.FilePasteParams() |
|---|
| 3347 | |
|---|
| 3348 | dlgParams.readOptionsFromConfig( |
|---|
| 3349 | editor.presenter.getMainControl().getConfig()) |
|---|
| 3350 | |
|---|
| 3351 | if unifActionName == u"action/editor/this/paste/files/insert/url/ask": |
|---|
| 3352 | |
|---|
| 3353 | if not paramDict.get("processDirectly", False): |
|---|
| 3354 | |
|---|
| 3355 | |
|---|
| 3356 | |
|---|
| 3357 | |
|---|
| 3358 | paramDict["processDirectly"] = True |
|---|
| 3359 | wx.CallAfter(WikiTxtCtrl.userActionPasteFiles, unifActionName, |
|---|
| 3360 | paramDict) |
|---|
| 3361 | return |
|---|
| 3362 | |
|---|
| 3363 | dlgParams = WikiTxtDialogs.FilePasteDialog.runModal( |
|---|
| 3364 | editor.presenter.getMainControl(), -1, dlgParams) |
|---|
| 3365 | if dlgParams is None: |
|---|
| 3366 | |
|---|
| 3367 | return |
|---|
| 3368 | |
|---|
| 3369 | unifActionName = dlgParams.unifActionName |
|---|
| 3370 | |
|---|
| 3371 | moveToStorage = False |
|---|
| 3372 | |
|---|
| 3373 | if unifActionName == u"action/editor/this/paste/files/insert/url/absolute": |
|---|
| 3374 | modeToStorage = False |
|---|
| 3375 | modeRelativeUrl = False |
|---|
| 3376 | elif unifActionName == u"action/editor/this/paste/files/insert/url/relative": |
|---|
| 3377 | modeToStorage = False |
|---|
| 3378 | modeRelativeUrl = True |
|---|
| 3379 | elif unifActionName == u"action/editor/this/paste/files/insert/url/tostorage": |
|---|
| 3380 | modeToStorage = True |
|---|
| 3381 | modeRelativeUrl = False |
|---|
| 3382 | elif unifActionName == u"action/editor/this/paste/files/insert/url/movetostorage": |
|---|
| 3383 | modeToStorage = True |
|---|
| 3384 | modeRelativeUrl = False |
|---|
| 3385 | moveToStorage = True |
|---|
| 3386 | else: |
|---|
| 3387 | return |
|---|
| 3388 | |
|---|
| 3389 | try: |
|---|
| 3390 | prefix = StringOps.strftimeUB(dlgParams.rawPrefix) |
|---|
| 3391 | except: |
|---|
| 3392 | traceback.print_exc() |
|---|
| 3393 | prefix = u"" |
|---|
| 3394 | |
|---|
| 3395 | try: |
|---|
| 3396 | middle = StringOps.strftimeUB(dlgParams.rawMiddle) |
|---|
| 3397 | except: |
|---|
| 3398 | traceback.print_exc() |
|---|
| 3399 | middle = u" " |
|---|
| 3400 | |
|---|
| 3401 | try: |
|---|
| 3402 | suffix = StringOps.strftimeUB(dlgParams.rawSuffix) |
|---|
| 3403 | except: |
|---|
| 3404 | traceback.print_exc() |
|---|
| 3405 | suffix = u"" |
|---|
| 3406 | |
|---|
| 3407 | |
|---|
| 3408 | urls = [] |
|---|
| 3409 | |
|---|
| 3410 | for fn in filenames: |
|---|
| 3411 | protocol = None |
|---|
| 3412 | if fn.endswith(u".wiki"): |
|---|
| 3413 | protocol = "wiki" |
|---|
| 3414 | |
|---|
| 3415 | toStorage = False |
|---|
| 3416 | if modeToStorage and protocol is None: |
|---|
| 3417 | |
|---|
| 3418 | fs = editor.presenter.getWikiDocument().getFileStorage() |
|---|
| 3419 | try: |
|---|
| 3420 | fn = fs.createDestPath(fn, move=moveToStorage) |
|---|
| 3421 | toStorage = True |
|---|
| 3422 | except Exception, e: |
|---|
| 3423 | traceback.print_exc() |
|---|
| 3424 | editor.presenter.getMainControl().displayErrorMessage( |
|---|
| 3425 | _(u"Couldn't copy file"), e) |
|---|
| 3426 | return |
|---|
| 3427 | |
|---|
| 3428 | urls.append(editor.wikiLanguageHelper.createUrlLinkFromPath( |
|---|
| 3429 | editor.presenter.getWikiDocument(), fn, |
|---|
| 3430 | relative=modeRelativeUrl or toStorage, |
|---|
| 3431 | bracketed=dlgParams.bracketedUrl, protocol=protocol)) |
|---|
| 3432 | |
|---|
| 3433 | editor.handleDropText(x, y, prefix + middle.join(urls) + suffix) |
|---|
| 3434 | |
|---|
| 3435 | |
|---|
| 3436 | def GetEOLChar(self): |
|---|
| 3437 | """ |
|---|
| 3438 | Gets the end of line char currently being used |
|---|
| 3439 | """ |
|---|
| 3440 | m_id = self.GetEOLMode() |
|---|
| 3441 | if m_id == wx.stc.STC_EOL_CR: |
|---|
| 3442 | return u'\r' |
|---|
| 3443 | elif m_id == wx.stc.STC_EOL_CRLF: |
|---|
| 3444 | return u'\r\n' |
|---|
| 3445 | else: |
|---|
| 3446 | return u'\n' |
|---|
| 3447 | |
|---|
| 3448 | def GetLastVisibleLine(self): |
|---|
| 3449 | """ |
|---|
| 3450 | Returns line number of the first visible line in viewport |
|---|
| 3451 | """ |
|---|
| 3452 | return self.GetFirstVisibleLine() + self.LinesOnScreen() - 1 |
|---|
| 3453 | |
|---|
| 3454 | def GetMiddleVisibleLine(self): |
|---|
| 3455 | """ |
|---|
| 3456 | Returns line number of the middle visible line in viewport |
|---|
| 3457 | """ |
|---|
| 3458 | |
|---|
| 3459 | fl = self.GetFirstVisibleLine() |
|---|
| 3460 | ll = self.GetLastVisibleLine() |
|---|
| 3461 | |
|---|
| 3462 | lines = ll - fl |
|---|
| 3463 | |
|---|
| 3464 | mid = fl + lines // 2 |
|---|
| 3465 | |
|---|
| 3466 | |
|---|
| 3467 | |
|---|
| 3468 | |
|---|
| 3469 | |
|---|
| 3470 | |
|---|
| 3471 | return mid |
|---|
| 3472 | |
|---|
| 3473 | |
|---|
| 3474 | |
|---|
| 3475 | |
|---|
| 3476 | |
|---|
| 3477 | |
|---|
| 3478 | |
|---|
| 3479 | |
|---|
| 3480 | |
|---|
| 3481 | |
|---|
| 3482 | |
|---|
| 3483 | |
|---|
| 3484 | |
|---|
| 3485 | |
|---|
| 3486 | |
|---|
| 3487 | |
|---|
| 3488 | |
|---|
| 3489 | |
|---|
| 3490 | |
|---|
| 3491 | |
|---|
| 3492 | |
|---|
| 3493 | |
|---|
| 3494 | |
|---|
| 3495 | |
|---|
| 3496 | |
|---|
| 3497 | |
|---|
| 3498 | |
|---|
| 3499 | |
|---|
| 3500 | |
|---|
| 3501 | class WikiTxtCtrlDropTarget(wx.PyDropTarget): |
|---|
| 3502 | def __init__(self, editor): |
|---|
| 3503 | wx.PyDropTarget.__init__(self) |
|---|
| 3504 | |
|---|
| 3505 | self.editor = editor |
|---|
| 3506 | self.resetDObject() |
|---|
| 3507 | |
|---|
| 3508 | def resetDObject(self): |
|---|
| 3509 | """ |
|---|
| 3510 | (Re)sets the dataobject at init and after each drop |
|---|
| 3511 | """ |
|---|
| 3512 | dataob = wx.DataObjectComposite() |
|---|
| 3513 | self.tobj = wx.TextDataObject() |
|---|
| 3514 | |
|---|
| 3515 | dataob.Add(self.tobj) |
|---|
| 3516 | |
|---|
| 3517 | self.fobj = wx.FileDataObject() |
|---|
| 3518 | dataob.Add(self.fobj) |
|---|
| 3519 | |
|---|
| 3520 | self.dataob = dataob |
|---|
| 3521 | self.SetDataObject(dataob) |
|---|
| 3522 | |
|---|
| 3523 | |
|---|
| 3524 | def OnDragOver(self, x, y, defresult): |
|---|
| 3525 | return self.editor.DoDragOver(x, y, defresult) |
|---|
| 3526 | |
|---|
| 3527 | |
|---|
| 3528 | def OnData(self, x, y, defresult): |
|---|
| 3529 | try: |
|---|
| 3530 | if self.GetData(): |
|---|
| 3531 | fnames = self.fobj.GetFilenames() |
|---|
| 3532 | text = self.tobj.GetText() |
|---|
| 3533 | |
|---|
| 3534 | if fnames: |
|---|
| 3535 | self.OnDropFiles(x, y, fnames) |
|---|
| 3536 | elif text: |
|---|
| 3537 | text = StringOps.lineendToInternal(text) |
|---|
| 3538 | self.OnDropText(x, y, text) |
|---|
| 3539 | |
|---|
| 3540 | return defresult |
|---|
| 3541 | |
|---|
| 3542 | finally: |
|---|
| 3543 | self.resetDObject() |
|---|
| 3544 | |
|---|
| 3545 | |
|---|
| 3546 | def OnDropText(self, x, y, text): |
|---|
| 3547 | text = StringOps.lineendToInternal(text) |
|---|
| 3548 | self.editor.handleDropText(x, y, text) |
|---|
| 3549 | |
|---|
| 3550 | |
|---|
| 3551 | def OnDropFiles(self, x, y, filenames): |
|---|
| 3552 | urls = [] |
|---|
| 3553 | |
|---|
| 3554 | |
|---|
| 3555 | controlPressed = wx.GetKeyState(wx.WXK_CONTROL) |
|---|
| 3556 | shiftPressed = wx.GetKeyState(wx.WXK_SHIFT) |
|---|
| 3557 | |
|---|
| 3558 | if isLinux(): |
|---|
| 3559 | |
|---|
| 3560 | |
|---|
| 3561 | try: |
|---|
| 3562 | filenames = [StringOps.utf8Dec(fn.encode("latin-1"))[0] |
|---|
| 3563 | for fn in filenames] |
|---|
| 3564 | except (UnicodeEncodeError, UnicodeDecodeError): |
|---|
| 3565 | pass |
|---|
| 3566 | |
|---|
| 3567 | |
|---|
| 3568 | mc = self.editor.presenter.getMainControl() |
|---|
| 3569 | |
|---|
| 3570 | paramDict = {"editor": self.editor, "filenames": filenames, |
|---|
| 3571 | "x": x, "y": y, "main control": mc} |
|---|
| 3572 | |
|---|
| 3573 | if controlPressed: |
|---|
| 3574 | suffix = u"/modkeys/ctrl" |
|---|
| 3575 | elif shiftPressed: |
|---|
| 3576 | suffix = u"/modkeys/shift" |
|---|
| 3577 | else: |
|---|
| 3578 | suffix = u"" |
|---|
| 3579 | |
|---|
| 3580 | mc.getUserActionCoord().reactOnUserEvent( |
|---|
| 3581 | u"mouse/leftdrop/editor/files" + suffix, paramDict) |
|---|
| 3582 | |
|---|
| 3583 | |
|---|
| 3584 | |
|---|
| 3585 | |
|---|
| 3586 | |
|---|
| 3587 | |
|---|
| 3588 | |
|---|
| 3589 | |
|---|
| 3590 | |
|---|
| 3591 | |
|---|
| 3592 | |
|---|
| 3593 | |
|---|
| 3594 | |
|---|
| 3595 | |
|---|
| 3596 | |
|---|
| 3597 | |
|---|
| 3598 | |
|---|
| 3599 | |
|---|
| 3600 | |
|---|
| 3601 | |
|---|
| 3602 | |
|---|
| 3603 | |
|---|
| 3604 | |
|---|
| 3605 | |
|---|
| 3606 | |
|---|
| 3607 | |
|---|
| 3608 | |
|---|
| 3609 | |
|---|
| 3610 | |
|---|
| 3611 | _ACTIONS = tuple( UserActionCoord.SimpleAction("", unifName, |
|---|
| 3612 | WikiTxtCtrl.userActionPasteFiles) for unifName in ( |
|---|
| 3613 | u"action/editor/this/paste/files/insert/url/absolute", |
|---|
| 3614 | u"action/editor/this/paste/files/insert/url/relative", |
|---|
| 3615 | u"action/editor/this/paste/files/insert/url/tostorage", |
|---|
| 3616 | u"action/editor/this/paste/files/insert/url/movetostorage", |
|---|
| 3617 | u"action/editor/this/paste/files/insert/url/ask") ) |
|---|
| 3618 | |
|---|
| 3619 | |
|---|
| 3620 | UserActionCoord.registerActions(_ACTIONS) |
|---|
| 3621 | |
|---|
| 3622 | |
|---|
| 3623 | |
|---|
| 3624 | _CONTEXT_MENU_INTEXT_SPELLING = \ |
|---|
| 3625 | u""" |
|---|
| 3626 | - |
|---|
| 3627 | Ignore;CMD_ADD_THIS_SPELLING_SESSION |
|---|
| 3628 | Add Globally;CMD_ADD_THIS_SPELLING_GLOBAL |
|---|
| 3629 | Add Locally;CMD_ADD_THIS_SPELLING_LOCAL |
|---|
| 3630 | """ |
|---|
| 3631 | |
|---|
| 3632 | |
|---|
| 3633 | _CONTEXT_MENU_INTEXT_BASE = \ |
|---|
| 3634 | u""" |
|---|
| 3635 | - |
|---|
| 3636 | Undo;CMD_UNDO |
|---|
| 3637 | Redo;CMD_REDO |
|---|
| 3638 | - |
|---|
| 3639 | Cut;CMD_CLIPBOARD_CUT |
|---|
| 3640 | Copy;CMD_CLIPBOARD_COPY |
|---|
| 3641 | Paste;CMD_CLIPBOARD_PASTE |
|---|
| 3642 | Delete;CMD_TEXT_DELETE |
|---|
| 3643 | - |
|---|
| 3644 | Select All;CMD_SELECT_ALL |
|---|
| 3645 | """ |
|---|
| 3646 | |
|---|
| 3647 | |
|---|
| 3648 | _CONTEXT_MENU_INTEXT_ACTIVATE = \ |
|---|
| 3649 | u""" |
|---|
| 3650 | - |
|---|
| 3651 | Follow Link;CMD_ACTIVATE_THIS |
|---|
| 3652 | Follow Link New Tab;CMD_ACTIVATE_NEW_TAB_THIS |
|---|
| 3653 | Follow Link New Tab Backgrd.;CMD_ACTIVATE_NEW_TAB_BACKGROUND_THIS |
|---|
| 3654 | Follow Link New Window;CMD_ACTIVATE_NEW_WINDOW_THIS |
|---|
| 3655 | """ |
|---|
| 3656 | |
|---|
| 3657 | _CONTEXT_MENU_INTEXT_WIKI_URL = \ |
|---|
| 3658 | u""" |
|---|
| 3659 | - |
|---|
| 3660 | Convert Absolute/Relative File URL;CMD_CONVERT_URL_ABSOLUTE_RELATIVE_THIS |
|---|
| 3661 | Open Containing Folder;CMD_OPEN_CONTAINING_FOLDER_THIS |
|---|
| 3662 | """ |
|---|
| 3663 | |
|---|
| 3664 | _CONTEXT_MENU_INTEXT_FILE_URL = \ |
|---|
| 3665 | u""" |
|---|
| 3666 | - |
|---|
| 3667 | Convert Absolute/Relative File URL;CMD_CONVERT_URL_ABSOLUTE_RELATIVE_THIS |
|---|
| 3668 | Open Containing Folder;CMD_OPEN_CONTAINING_FOLDER_THIS |
|---|
| 3669 | Rename file;CMD_RENAME_FILE |
|---|
| 3670 | Delete file;CMD_DELETE_FILE |
|---|
| 3671 | """ |
|---|
| 3672 | |
|---|
| 3673 | |
|---|
| 3674 | _CONTEXT_MENU_INTEXT_URL_TO_CLIPBOARD = \ |
|---|
| 3675 | u""" |
|---|
| 3676 | - |
|---|
| 3677 | Copy Anchor URL to Clipboard;CMD_CLIPBOARD_COPY_URL_TO_THIS_ANCHOR |
|---|
| 3678 | """ |
|---|
| 3679 | |
|---|
| 3680 | _CONTEXT_MENU_SELECT_TEMPLATE_IN_TEMPLATE_MENU = \ |
|---|
| 3681 | u""" |
|---|
| 3682 | - |
|---|
| 3683 | Other...;CMD_SELECT_TEMPLATE |
|---|
| 3684 | """ |
|---|
| 3685 | |
|---|
| 3686 | _CONTEXT_MENU_SELECT_TEMPLATE = \ |
|---|
| 3687 | u""" |
|---|
| 3688 | - |
|---|
| 3689 | Use Template...;CMD_SELECT_TEMPLATE |
|---|
| 3690 | """ |
|---|
| 3691 | |
|---|
| 3692 | |
|---|
| 3693 | _CONTEXT_MENU_INTEXT_BOTTOM = \ |
|---|
| 3694 | u""" |
|---|
| 3695 | - |
|---|
| 3696 | Close Tab;CMD_CLOSE_CURRENT_TAB |
|---|
| 3697 | """ |
|---|
| 3698 | |
|---|
| 3699 | |
|---|
| 3700 | |
|---|
| 3701 | FOLD_MENU = \ |
|---|
| 3702 | u""" |
|---|
| 3703 | +Show folding;CMD_CHECKBOX_SHOW_FOLDING;Show folding marks and allow folding;*ShowFolding |
|---|
| 3704 | &Toggle current folding;CMD_TOGGLE_CURRENT_FOLDING;Toggle folding of the current line;*ToggleCurrentFolding |
|---|
| 3705 | &Unfold All;CMD_UNFOLD_ALL_IN_CURRENT;Unfold everything in current editor;*UnfoldAll |
|---|
| 3706 | &Fold All;CMD_FOLD_ALL_IN_CURRENT;Fold everything in current editor;*FoldAll |
|---|
| 3707 | """ |
|---|
| 3708 | |
|---|
| 3709 | |
|---|
| 3710 | |
|---|
| 3711 | if False: |
|---|
| 3712 | N_(u"Ignore") |
|---|
| 3713 | N_(u"Add Globally") |
|---|
| 3714 | N_(u"Add Locally") |
|---|
| 3715 | |
|---|
| 3716 | N_(u"Undo") |
|---|
| 3717 | N_(u"Redo") |
|---|
| 3718 | N_(u"Cut") |
|---|
| 3719 | N_(u"Copy") |
|---|
| 3720 | N_(u"Paste") |
|---|
| 3721 | N_(u"Delete") |
|---|
| 3722 | N_(u"Select All") |
|---|
| 3723 | |
|---|
| 3724 | N_(u"Follow Link") |
|---|
| 3725 | N_(u"Follow Link New Tab") |
|---|
| 3726 | N_(u"Follow Link New Tab Backgrd.") |
|---|
| 3727 | N_(u"Follow Link New Window") |
|---|
| 3728 | |
|---|
| 3729 | N_(u"Convert Absolute/Relative File URL") |
|---|
| 3730 | N_(u"Open Containing Folder") |
|---|
| 3731 | N_(u"Rename file") |
|---|
| 3732 | N_(u"Delete file") |
|---|
| 3733 | |
|---|
| 3734 | N_(u"Copy anchor URL to clipboard") |
|---|
| 3735 | |
|---|
| 3736 | N_(u"Other...") |
|---|
| 3737 | N_(u"Use Template...") |
|---|
| 3738 | |
|---|
| 3739 | N_(u"Close Tab") |
|---|
| 3740 | |
|---|
| 3741 | N_(u"Show folding") |
|---|
| 3742 | N_(u"Show folding marks and allow folding") |
|---|
| 3743 | N_(u"&Toggle current folding") |
|---|
| 3744 | N_(u"Toggle folding of the current line") |
|---|
| 3745 | N_(u"&Unfold All") |
|---|
| 3746 | N_(u"Unfold everything in current editor") |
|---|
| 3747 | N_(u"&Fold All") |
|---|
| 3748 | N_(u"Fold everything in current editor") |
|---|
| 3749 | |
|---|
| 3750 | |
|---|
| 3751 | |
|---|
| 3752 | try: |
|---|
| 3753 | class wxPopupOrFrame(wx.PopupWindow): |
|---|
| 3754 | def __init__(self, parent, id=-1, style=None): |
|---|
| 3755 | wx.PopupWindow.__init__(self, parent) |
|---|
| 3756 | |
|---|
| 3757 | except AttributeError: |
|---|
| 3758 | class wxPopupOrFrame(wx.Frame): |
|---|
| 3759 | def __init__(self, parent, id=-1, |
|---|
| 3760 | style=wx.NO_BORDER|wx.FRAME_NO_TASKBAR|wx.FRAME_FLOAT_ON_PARENT): |
|---|
| 3761 | wx.Frame.__init__(self, parent, id, style=style) |
|---|
| 3762 | |
|---|
| 3763 | |
|---|
| 3764 | class ImageTooltipPanel(wxPopupOrFrame): |
|---|
| 3765 | """Quick panel for image tooltips""" |
|---|
| 3766 | def __init__(self, pWiki, filePath, maxWidth=200, maxHeight=200): |
|---|
| 3767 | wxPopupOrFrame.__init__(self, pWiki, -1) |
|---|
| 3768 | |
|---|
| 3769 | self.url = filePath |
|---|
| 3770 | self.pWiki = pWiki |
|---|
| 3771 | self.firstMove = True |
|---|
| 3772 | |
|---|
| 3773 | img = wx.Image(filePath, wx.BITMAP_TYPE_ANY) |
|---|
| 3774 | |
|---|
| 3775 | origWidth = img.GetWidth() |
|---|
| 3776 | origHeight = img.GetHeight() |
|---|
| 3777 | |
|---|
| 3778 | |
|---|
| 3779 | if maxWidth <= 0: |
|---|
| 3780 | maxWidth = 200 |
|---|
| 3781 | if maxHeight <= 0: |
|---|
| 3782 | maxHeight = 200 |
|---|
| 3783 | |
|---|
| 3784 | if origWidth > 0 and origHeight > 0: |
|---|
| 3785 | self.width, self.height = calcResizeArIntoBoundingBox(origWidth, |
|---|
| 3786 | origHeight, maxWidth, maxHeight) |
|---|
| 3787 | |
|---|
| 3788 | img.Rescale(self.width, self.height, quality = wx.IMAGE_QUALITY_HIGH) |
|---|
| 3789 | else: |
|---|
| 3790 | self.width = origWidth |
|---|
| 3791 | self.height = origHeight |
|---|
| 3792 | |
|---|
| 3793 | img = img.ConvertToBitmap() |
|---|
| 3794 | |
|---|
| 3795 | self.SetSize((self.width, self.height)) |
|---|
| 3796 | |
|---|
| 3797 | self.bmp = wx.StaticBitmap(self, -1, img, (0, 0), (img.GetWidth(), img.GetHeight())) |
|---|
| 3798 | self.bmp.Bind(wx.EVT_LEFT_DOWN, self.OnLeftClick) |
|---|
| 3799 | self.bmp.Bind(wx.EVT_RIGHT_DOWN, self.OnRightClick) |
|---|
| 3800 | self.bmp.Bind(wx.EVT_MOTION, self.OnMouseMotion) |
|---|
| 3801 | self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) |
|---|
| 3802 | |
|---|
| 3803 | mousePos = wx.GetMousePosition() |
|---|
| 3804 | |
|---|
| 3805 | |
|---|
| 3806 | mousePos.x += 1 |
|---|
| 3807 | mousePos.y += 1 |
|---|
| 3808 | WindowLayout.setWindowPos(self, mousePos, fullVisible=True) |
|---|
| 3809 | |
|---|
| 3810 | self.Show() |
|---|
| 3811 | |
|---|
| 3812 | self.GetParent().SetFocus() |
|---|
| 3813 | |
|---|
| 3814 | def Close(self, event=None): |
|---|
| 3815 | self.Destroy() |
|---|
| 3816 | |
|---|
| 3817 | def OnLeftClick(self, event=None): |
|---|
| 3818 | |
|---|
| 3819 | self.Close() |
|---|
| 3820 | |
|---|
| 3821 | |
|---|
| 3822 | |
|---|
| 3823 | |
|---|
| 3824 | |
|---|
| 3825 | |
|---|
| 3826 | |
|---|
| 3827 | |
|---|
| 3828 | def OnRightClick(self, event=None): |
|---|
| 3829 | self.Close() |
|---|
| 3830 | |
|---|
| 3831 | def OnMouseMotion(self, evt): |
|---|
| 3832 | if self.firstMove: |
|---|
| 3833 | self.firstMove = False |
|---|
| 3834 | evt.Skip() |
|---|
| 3835 | return |
|---|
| 3836 | |
|---|
| 3837 | self.Close() |
|---|
| 3838 | |
|---|
| 3839 | |
|---|
| 3840 | def OnKeyDown(self, event): |
|---|
| 3841 | kc = event.GetKeyCode() |
|---|
| 3842 | |
|---|
| 3843 | if kc == wx.WXK_ESCAPE: |
|---|
| 3844 | self.Close() |
|---|
| 3845 | |
|---|
| 3846 | |
|---|
| 3847 | class ViHandler(ViHelper): |
|---|
| 3848 | |
|---|
| 3849 | |
|---|
| 3850 | |
|---|
| 3851 | |
|---|
| 3852 | |
|---|
| 3853 | def __init__(self, stc): |
|---|
| 3854 | ViHelper.__init__(self, stc) |
|---|
| 3855 | |
|---|
| 3856 | self._anchor = None |
|---|
| 3857 | |
|---|
| 3858 | wx.CallAfter(self.SetDefaultCaretColour) |
|---|
| 3859 | |
|---|
| 3860 | wx.CallAfter(self.SetMode, ViHelper.NORMAL) |
|---|
| 3861 | wx.CallAfter(self.Setup) |
|---|
| 3862 | |
|---|
| 3863 | self.text_object_map = { |
|---|
| 3864 | "w" : (False, self.SelectInWord), |
|---|
| 3865 | "W" : (False, self.SelectInWORD), |
|---|
| 3866 | "s" : (False, self.SelectInSentence), |
|---|
| 3867 | "p" : (False, self.SelectInParagraph), |
|---|
| 3868 | |
|---|
| 3869 | "[" : (True, self.SelectInSquareBracket), |
|---|
| 3870 | "]" : (True, self.SelectInSquareBracket), |
|---|
| 3871 | |
|---|
| 3872 | "(" : (True, self.SelectInRoundBracket), |
|---|
| 3873 | ")" : (True, self.SelectInRoundBracket), |
|---|
| 3874 | "b" : (True, self.SelectInRoundBracket), |
|---|
| 3875 | |
|---|
| 3876 | "<" : (True, self.SelectInInequalitySigns), |
|---|
| 3877 | ">" : (True, self.SelectInInequalitySigns), |
|---|
| 3878 | |
|---|
| 3879 | "t" : (True, self.SelectInTagBlock), |
|---|
| 3880 | |
|---|
| 3881 | "{" : (True, self.SelectInBlock), |
|---|
| 3882 | "}" : (True, self.SelectInBlock), |
|---|
| 3883 | "B" : (True, self.SelectInBlock), |
|---|
| 3884 | |
|---|
| 3885 | '"' : (True, self.SelectInDoubleQuote), |
|---|
| 3886 | "'" : (True, self.SelectInSingleQuote), |
|---|
| 3887 | "`" : (True, self.SelectInTilde), |
|---|
| 3888 | |
|---|
| 3889 | |
|---|
| 3890 | |
|---|
| 3891 | u"\xc2" : (True, self.SelectInPoundSigns), |
|---|
| 3892 | u"$" : (True, self.SelectInDollarSigns), |
|---|
| 3893 | u"^" : (True, self.SelectInHats), |
|---|
| 3894 | u"%" : (True, self.SelectInPercentSigns), |
|---|
| 3895 | u"&" : (True, self.SelectInAmpersands), |
|---|
| 3896 | u"*" : (True, self.SelectInStars), |
|---|
| 3897 | u"-" : (True, self.SelectInHyphens), |
|---|
| 3898 | u"_" : (True, self.SelectInUnderscores), |
|---|
| 3899 | u"=" : (True, self.SelectInEqualSigns), |
|---|
| 3900 | u"+" : (True, self.SelectInPlusSigns), |
|---|
| 3901 | u"!" : (True, self.SelectInExclamationMarks), |
|---|
| 3902 | u"?" : (True, self.SelectInQuestionMarks), |
|---|
| 3903 | u"@" : (True, self.SelectInAtSigns), |
|---|
| 3904 | u"#" : (True, self.SelectInHashs), |
|---|
| 3905 | u"~" : (True, self.SelectInApproxSigns), |
|---|
| 3906 | u"|" : (True, self.SelectInVerticalBars), |
|---|
| 3907 | u";" : (True, self.SelectInSemicolons), |
|---|
| 3908 | u":" : (True, self.SelectInColons), |
|---|
| 3909 | u"\\" : (True, self.SelectInBackslashes), |
|---|
| 3910 | u"/" : (True, self.SelectInForwardslashes), |
|---|
| 3911 | } |
|---|
| 3912 | |
|---|
| 3913 | |
|---|
| 3914 | |
|---|
| 3915 | |
|---|
| 3916 | |
|---|
| 3917 | |
|---|
| 3918 | |
|---|
| 3919 | |
|---|
| 3920 | |
|---|
| 3921 | |
|---|
| 3922 | |
|---|
| 3923 | |
|---|
| 3924 | |
|---|
| 3925 | |
|---|
| 3926 | |
|---|
| 3927 | |
|---|
| 3928 | |
|---|
| 3929 | |
|---|
| 3930 | |
|---|
| 3931 | |
|---|
| 3932 | self.keys = { |
|---|
| 3933 | 0 : { |
|---|
| 3934 | |
|---|
| 3935 | (60, "motion") : (0, (self.DedentText, None), 1), |
|---|
| 3936 | (62, "motion") : (0, (self.IndentText, None), 1), |
|---|
| 3937 | (99, "motion") : (2, (self.EndDeleteInsert, None), 2), |
|---|
| 3938 | (100, "motion") : (0, (self.EndDelete, None), 1), |
|---|
| 3939 | (100, 115, "*") : (0, (self.DeleteSurrounding, None), 1), |
|---|
| 3940 | (121, "motion") : (0, (self.Yank, None), 1), |
|---|
| 3941 | (99, 115, "*", "*") : (0, (self.ChangeSurrounding, None), 1), |
|---|
| 3942 | |
|---|
| 3943 | (121, 115, "motion", "*") : (0, (self.PreSurround, None), 1), |
|---|
| 3944 | (121, 115, 115, "*") : (0, (self.PreSurroundLine, None), 1), |
|---|
| 3945 | (103, 117, "motion") : (0, (self.PreLowercase, None), 1), |
|---|
| 3946 | (103, 85, "motion") : (0, (self.PreUppercase, None), 1), |
|---|
| 3947 | (39, "*") : (1, (self.GotoMark, None), 0), |
|---|
| 3948 | (96, "*") : (1, (self.GotoMarkIndent, None), 0), |
|---|
| 3949 | (109, "*") : (0, (self.Mark, None), 0), |
|---|
| 3950 | (102, "*") : (1, (self.FindNextChar, None), 4), |
|---|
| 3951 | (70, "*") : (1, (self.FindNextCharBackwards, None), 4), |
|---|
| 3952 | (116, "*") : (1, (self.FindUpToNextChar, None), 5), |
|---|
| 3953 | (84, "*") : (1, (self.FindUpToNextCharBackwards, None), 5), |
|---|
| 3954 | (114, "*") : (0, (self.ReplaceChar, None), 0), |
|---|
| 3955 | |
|---|
| 3956 | (105,) : (0, (self.Insert, None), 2), |
|---|
| 3957 | (97,) : (0, (self.Append, None), 2), |
|---|
| 3958 | (73,) : (0, (self.InsertAtLineStart, None), 2), |
|---|
| 3959 | (65,) : (0, (self.AppendAtLineEnd, None), 2), |
|---|
| 3960 | (111,) : (0, (self.OpenNewLine, False), 2), |
|---|
| 3961 | (79,) : (0, (self.OpenNewLine, True), 2), |
|---|
| 3962 | (67,) : (0, (self.TruncateLineAndInsert, None), 2), |
|---|
| 3963 | (68,) : (0, (self.TruncateLine, None), 2), |
|---|
| 3964 | |
|---|
| 3965 | (120,) : (0, (self.DeleteRight, None), 1), |
|---|
| 3966 | (88,) : (0, (self.DeleteLeft, None), 1), |
|---|
| 3967 | |
|---|
| 3968 | (115,) : (0, (self.DeleteRightAndInsert, None), 2), |
|---|
| 3969 | (83,) : (0, (self.DeleteLinesAndIndentInsert, None), 2), |
|---|
| 3970 | |
|---|
| 3971 | (119,) : (1, (self.MoveCaretNextWord, None), 0), |
|---|
| 3972 | (87,) : (1, (self.MoveCaretNextWORD, None), 0), |
|---|
| 3973 | (101,) : (1, (self.MoveCaretWordEnd, None), 0), |
|---|
| 3974 | (69,) : (1, (self.MoveCaretWordEND, None), 0), |
|---|
| 3975 | (98,) : (1, (self.MoveCaretBackWord, None), 0), |
|---|
| 3976 | (66,) : (1, (self.MoveCaretBackWORD, None), 0), |
|---|
| 3977 | |
|---|
| 3978 | (123,) : (1, (self.MoveCaretParaUp, None), 0), |
|---|
| 3979 | (125,) : (1, (self.MoveCaretParaDown, None), 0), |
|---|
| 3980 | |
|---|
| 3981 | |
|---|
| 3982 | |
|---|
| 3983 | |
|---|
| 3984 | |
|---|
| 3985 | |
|---|
| 3986 | |
|---|
| 3987 | |
|---|
| 3988 | |
|---|
| 3989 | |
|---|
| 3990 | |
|---|
| 3991 | |
|---|
| 3992 | |
|---|
| 3993 | (47,) : (0, (self.StartSearch, None), 0), |
|---|
| 3994 | |
|---|
| 3995 | (110,) : (1, (self.Repeat, self.ContinueLastSearchSameDirection), 0), |
|---|
| 3996 | (78,) : (1, (self.Repeat, self.ContinueLastSearchReverseDirection), 0), |
|---|
| 3997 | |
|---|
| 3998 | (42,) : (1, (self.Repeat, self.SearchCaretWordForwards), 0), |
|---|
| 3999 | (35,) : (1, (self.Repeat, self.SearchCaretWordBackwards), 0), |
|---|
| 4000 | |
|---|
| 4001 | (103, 42) : (1, (self.Repeat, self.SearchPartialCaretWordForwards), 0), |
|---|
| 4002 | (103, 35) : (1, (self.Repeat, self.SearchPartialCaretWordBackwards), 0), |
|---|
| 4003 | |
|---|
| 4004 | |
|---|
| 4005 | (104,) : (1, (self.MoveCaretLeft, None), 0), |
|---|
| 4006 | (107,) : (1, (self.MoveCaretUp, None), 0), |
|---|
| 4007 | (108,) : (1, (self.MoveCaretRight, None), 0), |
|---|
| 4008 | (106,) : (1, (self.MoveCaretDown, None), 0), |
|---|
| 4009 | |
|---|
| 4010 | (65361,) : (1, (self.MoveCaretLeft, None), 0), |
|---|
| 4011 | (65362,) : (1, (self.MoveCaretUp, None), 0), |
|---|
| 4012 | (65363,) : (1, (self.MoveCaretRight, None), 0), |
|---|
| 4013 | (65364,) : (1, (self.MoveCaretDown, None), 0), |
|---|
| 4014 | |
|---|
| 4015 | (65293,) : (1, (self.MoveCaretDownAndIndent, None), 0), |
|---|
| 4016 | (65293,) : (1, (self.MoveCaretDownAndIndent, None), ), |
|---|
| 4017 | |
|---|
| 4018 | |
|---|
| 4019 | (36,) : (1, (self.GotoLineEnd, False), 0), |
|---|
| 4020 | (65367,) : (1, (self.GotoLineEnd, False), 0), |
|---|
| 4021 | (48,) : (1, (self.GotoLineStart, None), 0), |
|---|
| 4022 | (65360,) : (1, (self.GotoLineStart, None), 0), |
|---|
| 4023 | (94,) : (1, (self.GotoLineIndent, None), 0), |
|---|
| 4024 | (124,) : (1, (self.GotoColumn, None), 0), |
|---|
| 4025 | |
|---|
| 4026 | (40,) : (1, (self.GotoSentenceStart, None), 0), |
|---|
| 4027 | (41,) : (1, (self.GotoNextSentence, None), 0), |
|---|
| 4028 | |
|---|
| 4029 | |
|---|
| 4030 | (103, 103) : (1, (self.DocumentNavigation, (103, 103)), 0), |
|---|
| 4031 | (71,) : (1, (self.DocumentNavigation, 71), 0), |
|---|
| 4032 | (37,) : (1, (self.DocumentNavigation, 37), 0), |
|---|
| 4033 | |
|---|
| 4034 | (72,) : (1, (self.GotoViewportTop, None), 0), |
|---|
| 4035 | (76,) : (1, (self.GotoViewportBottom, None), 0), |
|---|
| 4036 | (77,) : (1, (self.GotoViewportMiddle, None), 0), |
|---|
| 4037 | |
|---|
| 4038 | (122, 122) : (0, (self.ScrollViewportMiddle, None), 0), |
|---|
| 4039 | (122, 116) : (0, (self.ScrollViewportTop, None), 0), |
|---|
| 4040 | (122, 98) : (0, (self.ScrollViewportBottom, None), 0), |
|---|
| 4041 | |
|---|
| 4042 | (90, 90) : (0, (self.ctrl.presenter.getMainControl().\ |
|---|
| 4043 | exitWiki, None), 0), |
|---|
| 4044 | |
|---|
| 4045 | (117,) : (0, (self.Undo, None), 0), |
|---|
| 4046 | (("Ctrl", 114),) : (0, (self.Redo, None), 0), |
|---|
| 4047 | |
|---|
| 4048 | (("Ctrl", 105),) : (1, (self.GotoNextJump, None), 0), |
|---|
| 4049 | (65289,) : (1, (self.GotoNextJump, None), 0), |
|---|
| 4050 | (("Ctrl", 111),) : (1, (self.GotoPreviousJump, None), 0), |
|---|
| 4051 | |
|---|
| 4052 | |
|---|
| 4053 | (59,) : (1, (self.RepeatLastFindCharCmd, None), 0), |
|---|
| 4054 | (44,) : (1, (self.RepeatLastFindCharCmdReverse, None), 0), |
|---|
| 4055 | |
|---|
| 4056 | |
|---|
| 4057 | |
|---|
| 4058 | |
|---|
| 4059 | (82,) : (0, (self.StartReplaceMode, None), 0), |
|---|
| 4060 | |
|---|
| 4061 | (118,) : (2, (self.EnterVisualMode, None), 0), |
|---|
| 4062 | (86,) : (2, (self.EnterLineVisualMode, None), 0), |
|---|
| 4063 | |
|---|
| 4064 | (74,) : (0, (self.JoinLines, None), 1), |
|---|
| 4065 | |
|---|
| 4066 | (126,) : (0, (self.SwapCase, None), 0), |
|---|
| 4067 | |
|---|
| 4068 | (121, 121) : (0, (self.YankLine, None), 0), |
|---|
| 4069 | (89,) : (0, (self.YankLine, None), 0), |
|---|
| 4070 | (112,) : (0, (self.Put, False), 0), |
|---|
| 4071 | (80,) : (0, (self.Put, True), 0), |
|---|
| 4072 | |
|---|
| 4073 | (100, 100) : (0, (self.DeleteLine, None), 1), |
|---|
| 4074 | |
|---|
| 4075 | (62, 62) : (0, (self.Indent, True), 1), |
|---|
| 4076 | (60, 60) : (0, (self.Indent, False), 1), |
|---|
| 4077 | |
|---|
| 4078 | (46,) : (0, (self.RepeatCmd, None), 0), |
|---|
| 4079 | |
|---|
| 4080 | |
|---|
| 4081 | |
|---|
| 4082 | |
|---|
| 4083 | |
|---|
| 4084 | (103, 102) : (0, (self.ctrl.activateLink, { "tabMode" : 0 }), 0), |
|---|
| 4085 | (("Ctrl", 119), 103, 102) : (0, (self.ctrl.activateLink, { "tabMode" : 2 }), 0), |
|---|
| 4086 | (103, 70) : (0, (self.ctrl.activateLink, { "tabMode" : 2 }), 0), |
|---|
| 4087 | (103, 98) : (0, (self.ctrl.activateLink, { "tabMode" : 3 }), 0), |
|---|
| 4088 | |
|---|
| 4089 | (103, 72) : (0, (self.GoBackwardInHistory, None), 0), |
|---|
| 4090 | (103, 76) : (0, (self.GoForwardInHistory, None), 0), |
|---|
| 4091 | (103, 104) : (0, (self.GoBackwardInHistory, None), 0), |
|---|
| 4092 | (103, 108) : (0, (self.GoForwardInHistory, None), 0), |
|---|
| 4093 | (91,) : (0, (self.GoBackwardInHistory, None), 0), |
|---|
| 4094 | (93,) : (0, (self.GoForwardInHistory, None), 0), |
|---|
| 4095 | (103, 116) : (0, (self.SwitchTabs, None), 0), |
|---|
| 4096 | (103, 84) : (0, (self.SwitchTabs, True), 0), |
|---|
| 4097 | (103, 114) : (0, (self.OpenHomePage, False), 0), |
|---|
| 4098 | (103, 82) : (0, (self.OpenHomePage, True), 0), |
|---|
| 4099 | (103, 111) : (0, (self.ctrl.presenter.getMainControl()). \ |
|---|
| 4100 | showWikiWordOpenDialog, None, 0), |
|---|
| 4101 | |
|---|
| 4102 | (103, 79): (0, (self.ctrl.presenter.getMainControl()). \ |
|---|
| 4103 | showWikiWordOpenDialog, None, 0), |
|---|
| 4104 | |
|---|
| 4105 | (92, 117) : (0, (self.ViewParents, False), 0), |
|---|
| 4106 | (92, 85) : (0, (self.ViewParents, True), 0), |
|---|
| 4107 | |
|---|
| 4108 | (103, 115) : (0, (self.SwitchEditorPreview, None), 0), |
|---|
| 4109 | (103, 101) : (0, (self.SwitchEditorPreview, "textedit"), 0), |
|---|
| 4110 | (103, 112) : (0, (self.SwitchEditorPreview, "preview"), 0), |
|---|
| 4111 | (65470,) : (0, (self.SwitchEditorPreview, "textedit"), 0), |
|---|
| 4112 | (65471,) : (0, (self.SwitchEditorPreview, "preview"), 0), |
|---|
| 4113 | } |
|---|
| 4114 | } |
|---|
| 4115 | |
|---|
| 4116 | |
|---|
| 4117 | |
|---|
| 4118 | for i in self.text_object_map: |
|---|
| 4119 | self.keys[0][(105, ord(i))] = (1, (self.SelectInTextObject, i), 0) |
|---|
| 4120 | self.keys[0][(97, ord(i))] = (1, (self.SelectATextObject, i), 0) |
|---|
| 4121 | |
|---|
| 4122 | |
|---|
| 4123 | |
|---|
| 4124 | |
|---|
| 4125 | |
|---|
| 4126 | self.keys[2] = self.keys[0].copy() |
|---|
| 4127 | self.keys[2].update({ |
|---|
| 4128 | |
|---|
| 4129 | (39, "*") : (1, (self.GotoMark, None), 0), |
|---|
| 4130 | (96, "*") : (1, (self.GotoMarkIndent, None), 0), |
|---|
| 4131 | (109, "*") : (0, (self.Mark, None), 0), |
|---|
| 4132 | (102, "*") : (1, (self.FindNextChar, None), 0), |
|---|
| 4133 | (70, "*") : (1, (self.FindNextCharBackwards, None), 0), |
|---|
| 4134 | (116, "*") : (1, (self.FindUpToNextChar, None), 0), |
|---|
| 4135 | (84, "*") : (1, (self.FindUpToNextCharBackwards, None), 0), |
|---|
| 4136 | (114, "*") : (0, (self.ReplaceChar, None), 2), |
|---|
| 4137 | (83, "*") : (0, (self.SurroundSelection, None), 2), |
|---|
| 4138 | |
|---|
| 4139 | |
|---|
| 4140 | (99,) : (0, (self.DeleteSelectionAndInsert, None), 2), |
|---|
| 4141 | (100,) : (0, (self.DeleteSelection, None), 1), |
|---|
| 4142 | (120,) : (0, (self.DeleteSelection, None), 1), |
|---|
| 4143 | (121,) : (0, (self.YankSelection, None), 0), |
|---|
| 4144 | (89,) : (0, (self.YankSelection, True), 0), |
|---|
| 4145 | (60,) : (0, (self.Indent, {"forward":False, "visual":True}), 0), |
|---|
| 4146 | (62,) : (0, (self.Indent, {"forward":True, "visual":True}), 0), |
|---|
| 4147 | (117,) : (0, (self.LowerCase, None), 0), |
|---|
| 4148 | (85,) : (0, (self.UpperCase, None), 0), |
|---|
| 4149 | (103, 117) : (1, self.LowerCase, 0), |
|---|
| 4150 | (103, 85) : (1, self.UpperCase, 0), |
|---|
| 4151 | }) |
|---|
| 4152 | |
|---|
| 4153 | |
|---|
| 4154 | |
|---|
| 4155 | del self.keys[2][(100, 100)] |
|---|
| 4156 | del self.keys[2][(121, 121)] |
|---|
| 4157 | del self.keys[2][(105,)] |
|---|
| 4158 | del self.keys[2][(97,)] |
|---|
| 4159 | del self.keys[2][(83,)] |
|---|
| 4160 | |
|---|
| 4161 | |
|---|
| 4162 | |
|---|
| 4163 | self.key_mods = self.GenerateKeyModifiers(self.keys) |
|---|
| 4164 | self.motion_keys = self.GenerateMotionKeys(self.keys) |
|---|
| 4165 | self.motion_key_mods = self.GenerateKeyModifiers(self.motion_keys) |
|---|
| 4166 | |
|---|
| 4167 | |
|---|
| 4168 | self.viKeyAccels = self.GenerateKeyAccelerators(self.keys) |
|---|
| 4169 | |
|---|
| 4170 | |
|---|
| 4171 | self.SINGLE_LINE_WHITESPACE = [9, 11, 12, 32] |
|---|
| 4172 | self.WORD_BREAK = '!"#$%&\'()*+,-./:;<=>?@[\\]^`{|}~' |
|---|
| 4173 | self.SENTENCE_ENDINGS = '.!?' |
|---|
| 4174 | self.SENTENCE_ENDINGS_SUFFIXS = '\'")]' |
|---|
| 4175 | |
|---|
| 4176 | self.BRACES = { |
|---|
| 4177 | "(" : ")", |
|---|
| 4178 | "[" : "]", |
|---|
| 4179 | "{" : "}", |
|---|
| 4180 | "<" : ">", |
|---|
| 4181 | } |
|---|
| 4182 | self.REVERSE_BRACES = dict((v,k) for k, v in self.BRACES.iteritems()) |
|---|
| 4183 | |
|---|
| 4184 | |
|---|
| 4185 | def Setup(self): |
|---|
| 4186 | self.AddJumpPosition(self.ctrl.GetCurrentPos()) |
|---|
| 4187 | |
|---|
| 4188 | def SetMode(self, mode): |
|---|
| 4189 | """ |
|---|
| 4190 | It would be nice to set caret alpha but i don't think its |
|---|
| 4191 | possible at the moment |
|---|
| 4192 | """ |
|---|
| 4193 | |
|---|
| 4194 | if self.mode == ViHelper.INSERT: |
|---|
| 4195 | |
|---|
| 4196 | if self.ctrl.GetCurrentPos() != \ |
|---|
| 4197 | self.GetLineStartPos(self.ctrl.GetCurrentLine()): |
|---|
| 4198 | self.ctrl.CharLeft() |
|---|
| 4199 | |
|---|
| 4200 | if self.mode == ViHelper.INSERT: |
|---|
| 4201 | |
|---|
| 4202 | if self.ctrl.GetCurLine()[0].strip() == u"": |
|---|
| 4203 | self.ctrl.LineDelete() |
|---|
| 4204 | self.ctrl.AddText(self.ctrl.GetEOLChar()) |
|---|
| 4205 | self.ctrl.CharLeft() |
|---|
| 4206 | |
|---|
| 4207 | self.mode = mode |
|---|
| 4208 | |
|---|
| 4209 | |
|---|
| 4210 | self.ctrl.ChooseCaretX() |
|---|
| 4211 | |
|---|
| 4212 | if mode == ViHelper.NORMAL: |
|---|
| 4213 | |
|---|
| 4214 | |
|---|
| 4215 | self.ctrl.SetCaretPeriod(800) |
|---|
| 4216 | |
|---|
| 4217 | self.RemoveSelection() |
|---|
| 4218 | self.ctrl.SetCaretForeground(wx.Colour(255, 0, 0)) |
|---|
| 4219 | self.ctrl.SetCaretWidth(40) |
|---|
| 4220 | self.ctrl.SetOvertype(False) |
|---|
| 4221 | self.SetSelMode("NORMAL") |
|---|
| 4222 | |
|---|
| 4223 | self.CheckLineEnd() |
|---|
| 4224 | elif mode == ViHelper.VISUAL: |
|---|
| 4225 | self.ctrl.SetCaretWidth(40) |
|---|
| 4226 | self.ctrl.SetCaretForeground(wx.Colour(250, 250, 210)) |
|---|
| 4227 | self.ctrl.SetOvertype(False) |
|---|
| 4228 | elif mode == ViHelper.INSERT: |
|---|
| 4229 | self.insert_action = [] |
|---|
| 4230 | self.ctrl.SetCaretWidth(1) |
|---|
| 4231 | self.ctrl.SetCaretForeground(self.default_caret_colour) |
|---|
| 4232 | self.ctrl.SetOvertype(False) |
|---|
| 4233 | elif mode == ViHelper.REPLACE: |
|---|
| 4234 | self.ctrl.SetCaretWidth(1) |
|---|
| 4235 | self.ctrl.SetCaretForeground(self.default_caret_colour) |
|---|
| 4236 | self.ctrl.SetOvertype(True) |
|---|
| 4237 | |
|---|
| 4238 | def OnLeftMouseUp(self, evt): |
|---|
| 4239 | """Enter visual mode if text is selected by mouse""" |
|---|
| 4240 | if len(self.ctrl.GetSelectedText()) > 0: |
|---|
| 4241 | self.EnterVisualMode(True) |
|---|
| 4242 | else: |
|---|
| 4243 | self.LeaveVisualMode() |
|---|
| 4244 | |
|---|
| 4245 | |
|---|
| 4246 | |
|---|
| 4247 | wx.CallAfter(self.CheckLineEnd) |
|---|
| 4248 | evt.Skip() |
|---|
| 4249 | |
|---|
| 4250 | |
|---|
| 4251 | def OnViKeyDown(self, evt): |
|---|
| 4252 | """ |
|---|
| 4253 | Handle keypresses when in Vi mode |
|---|
| 4254 | |
|---|
| 4255 | """ |
|---|
| 4256 | |
|---|
| 4257 | |
|---|
| 4258 | |
|---|
| 4259 | key = evt.GetRawKeyCode() |
|---|
| 4260 | |
|---|
| 4261 | |
|---|
| 4262 | if key in (65505, 65507, 65513): |
|---|
| 4263 | return |
|---|
| 4264 | |
|---|
| 4265 | accP = getAccelPairFromKeyDown(evt) |
|---|
| 4266 | |
|---|
| 4267 | if key == 65307 or accP == (2, 91): |
|---|
| 4268 | |
|---|
| 4269 | self.SetMode(ViHandler.NORMAL) |
|---|
| 4270 | self.FlushBuffers() |
|---|
| 4271 | return |
|---|
| 4272 | |
|---|
| 4273 | |
|---|
| 4274 | |
|---|
| 4275 | if len(self.ctrl.GetSelectedText()) > 0: |
|---|
| 4276 | self.EnterVisualMode() |
|---|
| 4277 | |
|---|
| 4278 | |
|---|
| 4279 | if self.mode in [1, 3]: |
|---|
| 4280 | |
|---|
| 4281 | |
|---|
| 4282 | |
|---|
| 4283 | |
|---|
| 4284 | self.insert_action.append(key) |
|---|
| 4285 | if key in [65362, 65362]: |
|---|
| 4286 | self.insert_action = [] |
|---|
| 4287 | evt.Skip() |
|---|
| 4288 | return |
|---|
| 4289 | |
|---|
| 4290 | m = self.mode |
|---|
| 4291 | |
|---|
| 4292 | |
|---|
| 4293 | |
|---|
| 4294 | |
|---|
| 4295 | if accP[0] == 2: |
|---|
| 4296 | |
|---|
| 4297 | key = ("Ctrl", key) |
|---|
| 4298 | |
|---|
| 4299 | if self._acceptable_keys is None or \ |
|---|
| 4300 | "*" not in self._acceptable_keys: |
|---|
| 4301 | if 48 <= key <= 57: |
|---|
| 4302 | if self.SetNumber(key-48): |
|---|
| 4303 | return |
|---|
| 4304 | elif 65456 <= key <= 65465: |
|---|
| 4305 | if self.SetNumber(key-65456): |
|---|
| 4306 | return |
|---|
| 4307 | |
|---|
| 4308 | self.SetCount() |
|---|
| 4309 | |
|---|
| 4310 | if self._motion and self._acceptable_keys is None: |
|---|
| 4311 | |
|---|
| 4312 | self._motion.append(key) |
|---|
| 4313 | |
|---|
| 4314 | temp = self._motion[:-1] |
|---|
| 4315 | temp.append("*") |
|---|
| 4316 | if tuple(self._motion) in self.motion_keys[m]: |
|---|
| 4317 | self.RunKeyChain(tuple(self.key_inputs), m) |
|---|
| 4318 | return |
|---|
| 4319 | |
|---|
| 4320 | elif tuple(temp) in self.motion_keys[m]: |
|---|
| 4321 | self._motion[-1] = "*" |
|---|
| 4322 | self._motion_wildcard.append(key) |
|---|
| 4323 | self.RunKeyChain(tuple(self.key_inputs), m) |
|---|
| 4324 | |
|---|
| 4325 | return |
|---|
| 4326 | |
|---|
| 4327 | elif tuple(self._motion) in self.motion_key_mods[m]: |
|---|
| 4328 | |
|---|
| 4329 | return |
|---|
| 4330 | |
|---|
| 4331 | self.FlushBuffers() |
|---|
| 4332 | return |
|---|
| 4333 | |
|---|
| 4334 | |
|---|
| 4335 | if self._acceptable_keys is not None: |
|---|
| 4336 | if key in self._acceptable_keys: |
|---|
| 4337 | self._acceptable_keys = None |
|---|
| 4338 | pass |
|---|
| 4339 | elif "*" in self._acceptable_keys: |
|---|
| 4340 | self._wildcard.append(key) |
|---|
| 4341 | self.key_inputs.append("*") |
|---|
| 4342 | self._acceptable_keys = None |
|---|
| 4343 | self.RunKeyChain(tuple(self.key_inputs), m) |
|---|
| 4344 | |
|---|
| 4345 | return |
|---|
| 4346 | elif "motion" in self._acceptable_keys: |
|---|
| 4347 | self._acceptable_keys = None |
|---|
| 4348 | self._motion.append(key) |
|---|
| 4349 | if (key,) in self.motion_keys[m]: |
|---|
| 4350 | self.key_inputs.append("motion") |
|---|
| 4351 | self.RunKeyChain(tuple(self.key_inputs), m) |
|---|
| 4352 | return |
|---|
| 4353 | if (key,) in self.motion_key_mods[m]: |
|---|
| 4354 | self.key_inputs.append("motion") |
|---|
| 4355 | return |
|---|
| 4356 | |
|---|
| 4357 | |
|---|
| 4358 | self.key_inputs.append(key) |
|---|
| 4359 | self.updateViStatus() |
|---|
| 4360 | |
|---|
| 4361 | key_chain = tuple(self.key_inputs) |
|---|
| 4362 | |
|---|
| 4363 | if self.RunKeyChain(key_chain, m): |
|---|
| 4364 | return |
|---|
| 4365 | |
|---|
| 4366 | self.FlushBuffers() |
|---|
| 4367 | |
|---|
| 4368 | def TurnOff(self): |
|---|
| 4369 | self._enableMenuShortcuts(True) |
|---|
| 4370 | self.ctrl.SetCaretWidth(1) |
|---|
| 4371 | |
|---|
| 4372 | def GetChar(self, length=1): |
|---|
| 4373 | """ |
|---|
| 4374 | Retrieves text from under caret |
|---|
| 4375 | @param length: the number of characters to get |
|---|
| 4376 | """ |
|---|
| 4377 | pos = self.ctrl.GetCurrentPos() |
|---|
| 4378 | start, end = self.minmax(pos, pos + length) |
|---|
| 4379 | start = max(0, start) |
|---|
| 4380 | end = min(end, self.ctrl.GetLength()) |
|---|
| 4381 | return self.ctrl.GetTextRange(start, end) |
|---|
| 4382 | |
|---|
| 4383 | def EmulateKeypresses(self, actions): |
|---|
| 4384 | if len(actions) > 0: |
|---|
| 4385 | |
|---|
| 4386 | eol = self.ctrl.GetEOLChar() |
|---|
| 4387 | |
|---|
| 4388 | for i in actions: |
|---|
| 4389 | if i == 65361: |
|---|
| 4390 | self.ctrl.CharLeft() |
|---|
| 4391 | elif i == 65363: |
|---|
| 4392 | self.ctrl.CharRight() |
|---|
| 4393 | elif i == 65288: |
|---|
| 4394 | self.ctrl.DeleteBackNotLine() |
|---|
| 4395 | elif i in [65535, 65439]: |
|---|
| 4396 | self.ctrl.CharRight() |
|---|
| 4397 | self.ctrl.DeleteBack() |
|---|
| 4398 | elif i in [65293, 65421]: |
|---|
| 4399 | self.ctrl.InsertText(self.ctrl.GetCurrentPos(), eol) |
|---|
| 4400 | self.ctrl.CharRight() |
|---|
| 4401 | elif i == 65289: |
|---|
| 4402 | self.ctrl.InsertText(self.ctrl.GetCurrentPos(), "\t") |
|---|
| 4403 | self.ctrl.CharRight() |
|---|
| 4404 | else: |
|---|
| 4405 | self.ctrl.InsertText(self.ctrl.GetCurrentPos(), unichr(i)) |
|---|
| 4406 | self.ctrl.CharRight() |
|---|
| 4407 | |
|---|
| 4408 | |
|---|
| 4409 | def RepeatCmd(self): |
|---|
| 4410 | |
|---|
| 4411 | if self.last_cmd is not None: |
|---|
| 4412 | self.visualBell("GREEN") |
|---|
| 4413 | self.ctrl.BeginUndoAction() |
|---|
| 4414 | cmd_type, key, count, motion, motion_wildcards, wildcards = self.last_cmd |
|---|
| 4415 | |
|---|
| 4416 | self.count = count |
|---|
| 4417 | actions = self.insert_action |
|---|
| 4418 | |
|---|
| 4419 | if cmd_type == 1: |
|---|
| 4420 | self.RunFunction(key, motion, motion_wildcards, wildcards) |
|---|
| 4421 | |
|---|
| 4422 | |
|---|
| 4423 | elif cmd_type == 2: |
|---|
| 4424 | self.RunFunction(key, motion, motion_wildcards, wildcards) |
|---|
| 4425 | |
|---|
| 4426 | |
|---|
| 4427 | self.EmulateKeypresses(actions) |
|---|
| 4428 | self.SetMode(ViHandler.NORMAL) |
|---|
| 4429 | elif cmd_type == 3: |
|---|
| 4430 | self.ReplaceChar(key) |
|---|
| 4431 | self.ctrl.EndUndoAction() |
|---|
| 4432 | self.insert_action = actions |
|---|
| 4433 | else: |
|---|
| 4434 | self.visualBell("RED") |
|---|
| 4435 | |
|---|
| 4436 | |
|---|
| 4437 | |
|---|
| 4438 | |
|---|
| 4439 | |
|---|
| 4440 | def ChangeSurrounding(self, keycodes): |
|---|
| 4441 | char_to_change = self.GetCharFromCode(keycodes[0]) |
|---|
| 4442 | if char_to_change in self.text_object_map: |
|---|
| 4443 | self.SelectATextObject(char_to_change) |
|---|
| 4444 | if self.HasSelection(): |
|---|
| 4445 | pos = self.ExtendSelectionIfRequired() |
|---|
| 4446 | self.ctrl.BeginUndoAction() |
|---|
| 4447 | self.ctrl.ReplaceSelection(self.ctrl.GetSelectedText()[1:-1]) |
|---|
| 4448 | self.ctrl.CharLeft() |
|---|
| 4449 | self.SelectSelection() |
|---|
| 4450 | self.SurroundSelection(keycodes[1]) |
|---|
| 4451 | self.ctrl.GotoPos(pos) |
|---|
| 4452 | self.ctrl.EndUndoAction() |
|---|
| 4453 | self.visualBell("GREEN") |
|---|
| 4454 | return |
|---|
| 4455 | self.visualBell("RED") |
|---|
| 4456 | |
|---|
| 4457 | def PreSurround(self, code): |
|---|
| 4458 | self.SelectSelection() |
|---|
| 4459 | self.SurroundSelection(code) |
|---|
| 4460 | |
|---|
| 4461 | def PreSurroundLine(self, code): |
|---|
| 4462 | self.SelectCurrentLine() |
|---|
| 4463 | self.SurroundSelection(code) |
|---|
| 4464 | |
|---|
| 4465 | def GetUnichrAt(self, pos): |
|---|
| 4466 | if -1 < pos < self.ctrl.GetLength(): |
|---|
| 4467 | return self.ctrl.GetTextRaw()[pos] |
|---|
| 4468 | |
|---|
| 4469 | def SelectInTextObject(self, ob): |
|---|
| 4470 | self.SelectTextObject(ob, False) |
|---|
| 4471 | |
|---|
| 4472 | def SelectATextObject(self, ob): |
|---|
| 4473 | self.SelectTextObject(ob, True) |
|---|
| 4474 | |
|---|
| 4475 | def SelectTextObject(self, ob=None, extra=False): |
|---|
| 4476 | """ |
|---|
| 4477 | Selects specified text object |
|---|
| 4478 | |
|---|
| 4479 | See vim help -> *text-objects* |
|---|
| 4480 | |
|---|
| 4481 | Two different selection methods are supported. They are given |
|---|
| 4482 | the names "In" and "A" corresponding to vim's "i(n)" and "a(n)" |
|---|
| 4483 | commands respectively. |
|---|
| 4484 | |
|---|
| 4485 | The differences between these is dependent on the type of text |
|---|
| 4486 | to be selected, it can be either a selection (e.g. words, |
|---|
| 4487 | sentences, etc...) or a block (e.g. text within [ ] or " " or |
|---|
| 4488 | ( ) etc...). |
|---|
| 4489 | """ |
|---|
| 4490 | if ob in self.text_object_map: |
|---|
| 4491 | self.text_object_map[ob][1](extra) |
|---|
| 4492 | |
|---|
| 4493 | |
|---|
| 4494 | |
|---|
| 4495 | |
|---|
| 4496 | |
|---|
| 4497 | |
|---|
| 4498 | def SelectTrailingWhitespace(self, sel_start, sel_end): |
|---|
| 4499 | self.StartSelection(sel_start) |
|---|
| 4500 | true_end = self.ctrl.GetCurrentPos() |
|---|
| 4501 | |
|---|
| 4502 | if self.ctrl.GetCharAt(sel_end+1) in \ |
|---|
| 4503 | self.SINGLE_LINE_WHITESPACE or \ |
|---|
| 4504 | self.ctrl.GetCharAt(sel_start) in \ |
|---|
| 4505 | self.SINGLE_LINE_WHITESPACE: |
|---|
| 4506 | self.MoveCaretWordEndCountWhitespace(1) |
|---|
| 4507 | |
|---|
| 4508 | elif self.ctrl.GetCharAt(sel_start-1) \ |
|---|
| 4509 | in self.SINGLE_LINE_WHITESPACE: |
|---|
| 4510 | pos = sel_start-1 |
|---|
| 4511 | while self.ctrl.GetCharAt(pos-1) \ |
|---|
| 4512 | in self.SINGLE_LINE_WHITESPACE: |
|---|
| 4513 | pos -= 1 |
|---|
| 4514 | self.ctrl.GotoPos(pos) |
|---|
| 4515 | self.StartSelection() |
|---|
| 4516 | self.ctrl.GotoPos(true_end) |
|---|
| 4517 | self.SelectSelection() |
|---|
| 4518 | |
|---|
| 4519 | def SelectInWord(self, extra=False): |
|---|
| 4520 | """ |
|---|
| 4521 | Selects n words where n is the count. Whitespace between words |
|---|
| 4522 | is counted. |
|---|
| 4523 | """ |
|---|
| 4524 | self._SelectInWords(False, extra=extra) |
|---|
| 4525 | |
|---|
| 4526 | def SelectInWORD(self, extra=False): |
|---|
| 4527 | self._SelectInWords(True, extra=extra) |
|---|
| 4528 | |
|---|
| 4529 | def _SelectInWords(self, WORD=False, extra=False): |
|---|
| 4530 | |
|---|
| 4531 | pos = self.ctrl.GetCurrentPos() |
|---|
| 4532 | |
|---|
| 4533 | if not WORD: |
|---|
| 4534 | back_word = self.MoveCaretBackWord |
|---|
| 4535 | move_caret_word_end_count_whitespace = \ |
|---|
| 4536 | self.MoveCaretWordEndCountWhitespace |
|---|
| 4537 | else: |
|---|
| 4538 | back_word = self.MoveCaretBackWORD |
|---|
| 4539 | move_caret_word_end_count_whitespace = \ |
|---|
| 4540 | self.MoveCaretWordENDCountWhitespace |
|---|
| 4541 | |
|---|
| 4542 | |
|---|
| 4543 | if self.ctrl.GetCharAt(pos) in self.SINGLE_LINE_WHITESPACE: |
|---|
| 4544 | self.MoveCaretToWhitespaceStart() |
|---|
| 4545 | else: |
|---|
| 4546 | if pos > 0: |
|---|
| 4547 | if self.GetUnichrAt(pos-1) in string.whitespace: |
|---|
| 4548 | pass |
|---|
| 4549 | elif ((self.GetUnichrAt(pos) in self.WORD_BREAK) is not (self.GetUnichrAt(pos-1) in self.WORD_BREAK)) and not WORD: |
|---|
| 4550 | pass |
|---|
| 4551 | else: |
|---|
| 4552 | back_word(1) |
|---|
| 4553 | self.StartSelection() |
|---|
| 4554 | move_caret_word_end_count_whitespace(1) |
|---|
| 4555 | self.SelectSelection() |
|---|
| 4556 | if extra: |
|---|
| 4557 | sel_start, sel_end = self._GetSelectionRange() |
|---|
| 4558 | self.SelectTrailingWhitespace(sel_start, sel_end) |
|---|
| 4559 | move_caret_word_end_count_whitespace(self.count-1) |
|---|
| 4560 | self.SelectSelection() |
|---|
| 4561 | |
|---|
| 4562 | def SelectInSentence(self, extra=False): |
|---|
| 4563 | """ Selects current sentence """ |
|---|
| 4564 | |
|---|
| 4565 | pos = start_pos = self.ctrl.GetCurrentPos() |
|---|
| 4566 | if pos > 0 and self.GetUnichrAt(pos-1) in string.whitespace: |
|---|
| 4567 | pos -= 1 |
|---|
| 4568 | char = self.GetUnichrAt(pos-1) |
|---|
| 4569 | while pos > 0 and char in string.whitespace: |
|---|
| 4570 | pos -= 1 |
|---|
| 4571 | char = self.GetUnichrAt(pos-1) |
|---|
| 4572 | if char in self.SENTENCE_ENDINGS_SUFFIXS: |
|---|
| 4573 | pos -= 1 |
|---|
| 4574 | char = self.GetUnichrAt(pos-1) |
|---|
| 4575 | while pos > 0 and char in self.SENTENCE_ENDINGS_SUFFIXS: |
|---|
| 4576 | pos -= 1 |
|---|
| 4577 | char = self.GetUnichrAt(pos-1) |
|---|
| 4578 | if char not in self.SENTENCE_ENDINGS: |
|---|
| 4579 | self.GotoSentenceStart(1) |
|---|
| 4580 | else: |
|---|
| 4581 | self.GotoSentenceStart(1) |
|---|
| 4582 | self.StartSelection() |
|---|
| 4583 | self.GotoSentenceEnd(1) |
|---|
| 4584 | self.SelectSelection() |
|---|
| 4585 | sel_start, sel_end = self._GetSelectionRange() |
|---|
| 4586 | self.ctrl.GotoPos(sel_start) |
|---|
| 4587 | if extra: |
|---|
| 4588 | self.count += 1 |
|---|
| 4589 | self.GotoSentenceEndCountWhitespace() |
|---|
| 4590 | self.SelectSelection() |
|---|
| 4591 | |
|---|
| 4592 | def SelectInParagraph(self, extra=False): |
|---|
| 4593 | """ Selects current paragraph """ |
|---|
| 4594 | |
|---|
| 4595 | self.MoveCaretParaDown(1) |
|---|
| 4596 | self.MoveCaretParaUp(1) |
|---|
| 4597 | self.StartSelection() |
|---|
| 4598 | self.MoveCaretParaDown() |
|---|
| 4599 | self.ctrl.CharLeft() |
|---|
| 4600 | self.SelectSelection() |
|---|
| 4601 | |
|---|
| 4602 | def _SelectInBracket(self, bracket, extra=False, start_pos=None, count=None): |
|---|
| 4603 | if start_pos is None: start_pos = self.ctrl.GetCurrentPos() |
|---|
| 4604 | if count is None: count = self.count |
|---|
| 4605 | |
|---|
| 4606 | if self.SearchBackwardsForChar(bracket, count): |
|---|
| 4607 | pos = self.ctrl.GetCurrentPos() |
|---|
| 4608 | |
|---|
| 4609 | pre_text = self.ctrl.GetTextRange(pos, start_pos) |
|---|
| 4610 | |
|---|
| 4611 | while pre_text.count(bracket) - pre_text.count(self.BRACES[bracket]) \ |
|---|
| 4612 | != self.count: |
|---|
| 4613 | self.ctrl.CharLeft() |
|---|
| 4614 | if self.SearchBackwardsForChar(bracket, 1): |
|---|
| 4615 | pos = self.ctrl.GetCurrentPos() |
|---|
| 4616 | pre_text = self.ctrl.GetTextRange(pos, start_pos) |
|---|
| 4617 | else: |
|---|
| 4618 | break |
|---|
| 4619 | |
|---|
| 4620 | if self.MatchBraceUnderCaret(): |
|---|
| 4621 | self.StartSelection(pos) |
|---|
| 4622 | self.SelectSelection() |
|---|
| 4623 | sel_start, sel_end = self._GetSelectionRange() |
|---|
| 4624 | if not sel_start <= start_pos <= sel_end: |
|---|
| 4625 | self.ctrl.GotoPos(sel_start-1) |
|---|
| 4626 | self._SelectInBracket(bracket, extra, start_pos, count) |
|---|
| 4627 | else: |
|---|
| 4628 | |
|---|
| 4629 | if not extra: |
|---|
| 4630 | self.StartSelection(pos+1) |
|---|
| 4631 | |
|---|
| 4632 | |
|---|
| 4633 | self.ctrl.SetSelection(sel_start, sel_end-1) |
|---|
| 4634 | else: |
|---|
| 4635 | self.ctrl.GotoPos(start_pos) |
|---|
| 4636 | |
|---|
| 4637 | def SelectInSquareBracket(self, extra=False): |
|---|
| 4638 | """ Selects text in [ ] block """ |
|---|
| 4639 | self._SelectInBracket("[", extra) |
|---|
| 4640 | |
|---|
| 4641 | def SelectInRoundBracket(self, extra=False): |
|---|
| 4642 | """ Selects text in ( ) block """ |
|---|
| 4643 | self._SelectInBracket("(", extra) |
|---|
| 4644 | |
|---|
| 4645 | def SelectInInequalitySigns(self, extra=False): |
|---|
| 4646 | """ Selects text in < > block """ |
|---|
| 4647 | self._SelectInBracket("<", extra) |
|---|
| 4648 | |
|---|
| 4649 | def SelectInTagBlock(self, extra=False): |
|---|
| 4650 | """ selects text in <aaa> </aaa> block """ |
|---|
| 4651 | |
|---|
| 4652 | |
|---|
| 4653 | def SelectInBlock(self, extra=False): |
|---|
| 4654 | """ selects text in { } block """ |
|---|
| 4655 | self._SelectInBracket("{", extra) |
|---|
| 4656 | |
|---|
| 4657 | def _SelectInChars(self, char, extra=False): |
|---|
| 4658 | pos = self.ctrl.GetCurrentPos() |
|---|
| 4659 | if self.SearchBackwardsForChar(char): |
|---|
| 4660 | start_pos = self.ctrl.GetCurrentPos() |
|---|
| 4661 | self.ctrl.GotoPos(pos) |
|---|
| 4662 | if self.SearchForwardsForChar(char): |
|---|
| 4663 | self.StartSelection(start_pos) |
|---|
| 4664 | self.SelectSelection() |
|---|
| 4665 | if not extra: |
|---|
| 4666 | sel_start, sel_end = self._GetSelectionRange() |
|---|
| 4667 | self.StartSelection(start_pos+1) |
|---|
| 4668 | self.ctrl.SetSelection(sel_start, sel_end-1) |
|---|
| 4669 | |
|---|
| 4670 | def SelectInDoubleQuote(self, extra=False): |
|---|
| 4671 | """ selects text in " " block """ |
|---|
| 4672 | self._SelectInChars('"', extra) |
|---|
| 4673 | |
|---|
| 4674 | def SelectInSingleQuote(self, extra=False): |
|---|
| 4675 | """ selects text in ' ' block """ |
|---|
| 4676 | self._SelectInChars("'", extra) |
|---|
| 4677 | |
|---|
| 4678 | def SelectInTilde(self, extra=False): |
|---|
| 4679 | """ selects text in ` ` block """ |
|---|
| 4680 | self._SelectInChars("`", extra) |
|---|
| 4681 | |
|---|
| 4682 | |
|---|
| 4683 | |
|---|
| 4684 | def SelectInPoundSigns(self, extra=False): |
|---|
| 4685 | self._SelectInChars("\xc2", extra) |
|---|
| 4686 | |
|---|
| 4687 | def SelectInDollarSigns(self, extra=False): |
|---|
| 4688 | self._SelectInChars("$", extra) |
|---|
| 4689 | |
|---|
| 4690 | def SelectInHats(self, extra=False): |
|---|
| 4691 | self._SelectInChars("^", extra) |
|---|
| 4692 | |
|---|
| 4693 | def SelectInPercentSigns(self, extra=False): |
|---|
| 4694 | self._SelectInChars("%", extra) |
|---|
| 4695 | |
|---|
| 4696 | def SelectInAmpersands(self, extra=False): |
|---|
| 4697 | self._SelectInChars("&", extra) |
|---|
| 4698 | |
|---|
| 4699 | def SelectInStars(self, extra=False): |
|---|
| 4700 | self._SelectInChars("*", extra) |
|---|
| 4701 | |
|---|
| 4702 | def SelectInHyphens(self, extra=False): |
|---|
| 4703 | self._SelectInChars("-", extra) |
|---|
| 4704 | |
|---|
| 4705 | def SelectInUnderscores(self, extra=False): |
|---|
| 4706 | self._SelectInChars("_", extra) |
|---|
| 4707 | |
|---|
| 4708 | def SelectInEqualSigns(self, extra=False): |
|---|
| 4709 | self._SelectInChars("=", extra) |
|---|
| 4710 | |
|---|
| 4711 | def SelectInPlusSigns(self, extra=False): |
|---|
| 4712 | self._SelectInChars("+", extra) |
|---|
| 4713 | |
|---|
| 4714 | def SelectInExclamationMarks(self, extra=False): |
|---|
| 4715 | self._SelectInChars("!", extra) |
|---|
| 4716 | |
|---|
| 4717 | def SelectInQuestionMarks(self, extra=False): |
|---|
| 4718 | self._SelectInChars("?", extra) |
|---|
| 4719 | |
|---|
| 4720 | def SelectInAtSigns(self, extra=False): |
|---|
| 4721 | self._SelectInChars("@", extra) |
|---|
| 4722 | |
|---|
| 4723 | def SelectInHashs(self, extra=False): |
|---|
| 4724 | self._SelectInChars("#", extra) |
|---|
| 4725 | |
|---|
| 4726 | def SelectInApproxSigns(self, extra=False): |
|---|
| 4727 | self._SelectInChars("~", extra) |
|---|
| 4728 | |
|---|
| 4729 | def SelectInVerticalBars(self, extra=False): |
|---|
| 4730 | self._SelectInChars("|", extra) |
|---|
| 4731 | |
|---|
| 4732 | def SelectInSemicolons(self, extra=False): |
|---|
| 4733 | self._SelectInChars(";", extra) |
|---|
| 4734 | |
|---|
| 4735 | def SelectInColons(self, extra=False): |
|---|
| 4736 | self._SelectInChars(":", extra) |
|---|
| 4737 | |
|---|
| 4738 | def SelectInBackslashes(self, extra=False): |
|---|
| 4739 | self._SelectInChars("\\", extra) |
|---|
| 4740 | |
|---|
| 4741 | def SelectInForwardslashes(self, extra=False): |
|---|
| 4742 | self._SelectInChars("/", extra) |
|---|
| 4743 | |
|---|
| 4744 | |
|---|
| 4745 | def SurroundSelection(self, keycode): |
|---|
| 4746 | |
|---|
| 4747 | start = self.ExtendSelectionIfRequired() |
|---|
| 4748 | |
|---|
| 4749 | text = self.ctrl.GetSelectedText() |
|---|
| 4750 | |
|---|
| 4751 | if len(text) < 1: |
|---|
| 4752 | return |
|---|
| 4753 | |
|---|
| 4754 | |
|---|
| 4755 | if text[-1] == self.ctrl.GetEOLChar(): |
|---|
| 4756 | sel_start, sel_end = self._GetSelectionRange() |
|---|
| 4757 | self.ctrl.SetSelection(sel_start, sel_end-1) |
|---|
| 4758 | text = self.ctrl.GetSelectedText() |
|---|
| 4759 | |
|---|
| 4760 | replacements = { |
|---|
| 4761 | ")" : ("(", ")"), |
|---|
| 4762 | "b" : ("(", ")"), |
|---|
| 4763 | "}" : ("{", "}"), |
|---|
| 4764 | "B" : ("{", "}"), |
|---|
| 4765 | "]" : ("[", "]"), |
|---|
| 4766 | "r" : ("[", "]"), |
|---|
| 4767 | ">" : ("<", ">"), |
|---|
| 4768 | "a" : ("<", ">"), |
|---|
| 4769 | |
|---|
| 4770 | "(" : ("( ", " )"), |
|---|
| 4771 | "{" : ("{ ", " }"), |
|---|
| 4772 | "[" : ("[ ", " ]"), |
|---|
| 4773 | |
|---|
| 4774 | |
|---|
| 4775 | |
|---|
| 4776 | |
|---|
| 4777 | |
|---|
| 4778 | "'" : ("'", "'"), |
|---|
| 4779 | '"' : ('"', '"'), |
|---|
| 4780 | "`" : ("`", "`"), |
|---|
| 4781 | |
|---|
| 4782 | } |
|---|
| 4783 | uni_chr = unichr(keycode) |
|---|
| 4784 | if uni_chr in replacements: |
|---|
| 4785 | new_text = "{0}{1}{2}".format(replacements[uni_chr][0], text, replacements[uni_chr][1]) |
|---|
| 4786 | else: |
|---|
| 4787 | new_text = "{0}{1}{2}".format(uni_chr, text, uni_chr) |
|---|
| 4788 | |
|---|
| 4789 | self.ctrl.ReplaceSelection(new_text) |
|---|
| 4790 | self.LeaveVisualMode() |
|---|
| 4791 | self.ctrl.GotoPos(start) |
|---|
| 4792 | |
|---|
| 4793 | |
|---|
| 4794 | def CheckLineEnd(self): |
|---|
| 4795 | line, line_pos = self.ctrl.GetCurLine() |
|---|
| 4796 | if self.mode not in [ViHelper.VISUAL, ViHelper.INSERT]: |
|---|
| 4797 | unicode_line = unicode(line) |
|---|
| 4798 | if len(line) > 1 and line_pos >= len(bytes(unicode_line))-1: |
|---|
| 4799 | |
|---|
| 4800 | pos = self.ctrl.GetCurrentPos()-len(bytes(unicode_line[-2])) |
|---|
| 4801 | self.ctrl.GotoPos(pos) |
|---|
| 4802 | |
|---|
| 4803 | |
|---|
| 4804 | |
|---|
| 4805 | |
|---|
| 4806 | def SelectCurrentLine(self, include_eol=True): |
|---|
| 4807 | line_no = self.ctrl.GetCurrentLine() |
|---|
| 4808 | max_line = min(line_no+self.count-1, self.ctrl.GetLineCount()) |
|---|
| 4809 | start = self.GetLineStartPos(line_no) |
|---|
| 4810 | end = self.ctrl.GetLineEndPosition(max_line) |
|---|
| 4811 | if include_eol: |
|---|
| 4812 | end += 1 |
|---|
| 4813 | self.ctrl.SetSelection(end, start) |
|---|
| 4814 | |
|---|
| 4815 | def SelectFullLines(self): |
|---|
| 4816 | """ |
|---|
| 4817 | Could probably be replaced by SetSectionMode, |
|---|
| 4818 | if it can be made to work. |
|---|
| 4819 | """ |
|---|
| 4820 | start_line, end_line = self._GetSelectedLines() |
|---|
| 4821 | if self.ctrl.GetCurrentPos() >= self.visual_line_start_pos: |
|---|
| 4822 | reverse = False |
|---|
| 4823 | |
|---|
| 4824 | |
|---|
| 4825 | if len(self.ctrl.GetLine(start_line)) > 1: |
|---|
| 4826 | text, pos = self.ctrl.GetCurLine() |
|---|
| 4827 | if len(text) > 1: |
|---|
| 4828 | end_line -= 1 |
|---|
| 4829 | |
|---|
| 4830 | else: |
|---|
| 4831 | reverse = True |
|---|
| 4832 | end_line -= 1 |
|---|
| 4833 | |
|---|
| 4834 | cur_line = self.ctrl.GetCurrentLine() |
|---|
| 4835 | self.SelectLines(start_line, end_line, reverse) |
|---|
| 4836 | |
|---|
| 4837 | |
|---|
| 4838 | def JoinLines(self): |
|---|
| 4839 | text = self.ctrl.GetSelectedText() |
|---|
| 4840 | start_line = self.ctrl.GetCurrentLine() |
|---|
| 4841 | if len(text) < 1: |
|---|
| 4842 | |
|---|
| 4843 | count = self.count if self.count > 1 else 2 |
|---|
| 4844 | self.SelectLines(start_line, min(self.ctrl.GetLineCount(), \ |
|---|
| 4845 | start_line - 1 + count)) |
|---|
| 4846 | else: |
|---|
| 4847 | start_line, end_line = self._GetSelectedLines() |
|---|
| 4848 | self.SelectLines(start_line, end_line) |
|---|
| 4849 | |
|---|
| 4850 | text = self.ctrl.GetSelectedText() |
|---|
| 4851 | |
|---|
| 4852 | eol_char = self.ctrl.GetEOLChar() |
|---|
| 4853 | |
|---|
| 4854 | |
|---|
| 4855 | |
|---|
| 4856 | lines = text.split(eol_char) |
|---|
| 4857 | new_text = [] |
|---|
| 4858 | for i in range(len(lines)): |
|---|
| 4859 | if lines[i] == u"": |
|---|
| 4860 | continue |
|---|
| 4861 | if i == 0: |
|---|
| 4862 | new_text.append(lines[i]) |
|---|
| 4863 | else: |
|---|
| 4864 | new_text.append(lines[i].lstrip()) |
|---|
| 4865 | |
|---|
| 4866 | self.ctrl.ReplaceSelection(" ".join(new_text)) |
|---|
| 4867 | |
|---|
| 4868 | def DeleteSelectionAndInsert(self): |
|---|
| 4869 | self.DeleteSelection() |
|---|
| 4870 | self.Insert() |
|---|
| 4871 | |
|---|
| 4872 | def RemoveSelection(self): |
|---|
| 4873 | """ |
|---|
| 4874 | Removes the selection. |
|---|
| 4875 | |
|---|
| 4876 | TODO: don't goto selection start pos |
|---|
| 4877 | """ |
|---|
| 4878 | pos = self.ctrl.GetAnchor() |
|---|
| 4879 | self.ctrl.SetSelection(pos,pos) |
|---|
| 4880 | |
|---|
| 4881 | |
|---|
| 4882 | def GetSelectionAnchor(self): |
|---|
| 4883 | return self._anchor |
|---|
| 4884 | |
|---|
| 4885 | def StartSelection(self, pos=None): |
|---|
| 4886 | """ Saves the current position to be used for selection start """ |
|---|
| 4887 | if pos is None: |
|---|
| 4888 | pos = self.ctrl.GetCurrentPos() |
|---|
| 4889 | self._anchor = pos |
|---|
| 4890 | |
|---|
| 4891 | def StartSelectionAtAnchor(self): |
|---|
| 4892 | """ |
|---|
| 4893 | Saves the current position to be used for selection start using |
|---|
| 4894 | the anchor as the selection start. |
|---|
| 4895 | """ |
|---|
| 4896 | if len(self.ctrl.GetSelectedText()) > 0: |
|---|
| 4897 | self._anchor = self.ctrl.GetAnchor() |
|---|
| 4898 | else: |
|---|
| 4899 | self._anchor = self.ctrl.GetCurrentPos() |
|---|
| 4900 | |
|---|
| 4901 | |
|---|
| 4902 | def SelectInLink(self): |
|---|
| 4903 | pos = self.ctrl.GetCurrentPos() |
|---|
| 4904 | start_pos = self.FindChar(91, True, 0, 1, False) |
|---|
| 4905 | self.StartSelection() |
|---|
| 4906 | end_pos = self.FindChar(93, False, -1, 1, False) |
|---|
| 4907 | |
|---|
| 4908 | if start_pos and end_pos: |
|---|
| 4909 | self.SelectSelection() |
|---|
| 4910 | |
|---|
| 4911 | def SelectSelection(self): |
|---|
| 4912 | self.ctrl.SetSelection(self._anchor, self.ctrl.GetCurrentPos()) |
|---|
| 4913 | |
|---|
| 4914 | def SelectionOnSingleLine(self): |
|---|
| 4915 | """ |
|---|
| 4916 | Assume that if an EOL char is present we have mutiple lines |
|---|
| 4917 | """ |
|---|
| 4918 | if self.ctrl.GetEOLChar() in self.ctrl.GetSelectedText(): |
|---|
| 4919 | return False |
|---|
| 4920 | else: |
|---|
| 4921 | return True |
|---|
| 4922 | |
|---|
| 4923 | def ExtendSelectionIfRequired(self): |
|---|
| 4924 | """ |
|---|
| 4925 | If selection is positive the last character is not actually |
|---|
| 4926 | selected and so a correction must be applied |
|---|
| 4927 | """ |
|---|
| 4928 | start, end = self._GetSelectionRange() |
|---|
| 4929 | if self.ctrl.GetCurrentPos() == end: |
|---|
| 4930 | self.ctrl.CharRightExtend() |
|---|
| 4931 | return start |
|---|
| 4932 | |
|---|
| 4933 | def DeleteSelection(self): |
|---|
| 4934 | """Yank selection and delete it""" |
|---|
| 4935 | start = self.ExtendSelectionIfRequired() |
|---|
| 4936 | self.ctrl.BeginUndoAction() |
|---|
| 4937 | self.YankSelection() |
|---|
| 4938 | self.ctrl.Clear() |
|---|
| 4939 | self.ctrl.GotoPos(start) |
|---|
| 4940 | self.ctrl.EndUndoAction() |
|---|
| 4941 | |
|---|
| 4942 | def _GetSelectionRange(self): |
|---|
| 4943 | """Get the range of selection such that the start is the visual start |
|---|
| 4944 | of the selection, not the logical start. |
|---|
| 4945 | |
|---|
| 4946 | """ |
|---|
| 4947 | start, end = self.minmax(self.ctrl.GetSelectionStart(), |
|---|
| 4948 | self.ctrl.GetSelectionEnd()) |
|---|
| 4949 | return start, end |
|---|
| 4950 | |
|---|
| 4951 | def _GetSelectedLines(self): |
|---|
| 4952 | """Get the first and last line (exclusive) of selection""" |
|---|
| 4953 | start, end = self._GetSelectionRange() |
|---|
| 4954 | start_line, end_line = (self.ctrl.LineFromPosition(start), |
|---|
| 4955 | self.ctrl.LineFromPosition(end - 1) + 1) |
|---|
| 4956 | return start_line, end_line |
|---|
| 4957 | |
|---|
| 4958 | def HasSelection(self): |
|---|
| 4959 | """ |
|---|
| 4960 | Detects if there's anything selected |
|---|
| 4961 | @rtype: bool |
|---|
| 4962 | """ |
|---|
| 4963 | return len(self.ctrl.GetSelectedText()) > 0 |
|---|
| 4964 | |
|---|
| 4965 | def InsertText(self, text): |
|---|
| 4966 | self.ctrl.InsertText(self.ctrl.GetCurrentPos(), text) |
|---|
| 4967 | self.MoveCaretPos(len(text)) |
|---|
| 4968 | |
|---|
| 4969 | def SelectLines(self, start, end, reverse=False): |
|---|
| 4970 | """ |
|---|
| 4971 | Selects lines |
|---|
| 4972 | |
|---|
| 4973 | @param start: start line |
|---|
| 4974 | @param end: end line |
|---|
| 4975 | @param reverse: if true selection is reversed |
|---|
| 4976 | """ |
|---|
| 4977 | start_pos = self.GetLineStartPos(start) |
|---|
| 4978 | end_pos = self.ctrl.GetLineEndPosition(end) |
|---|
| 4979 | |
|---|
| 4980 | if reverse: |
|---|
| 4981 | self.ctrl.SetSelection(end_pos, start_pos) |
|---|
| 4982 | else: |
|---|
| 4983 | self.ctrl.SetSelection(start_pos, end_pos) |
|---|
| 4984 | |
|---|
| 4985 | def PreUppercase(self): |
|---|
| 4986 | start = self.ExtendSelectionIfRequired() |
|---|
| 4987 | self.SelectSelection() |
|---|
| 4988 | self.ctrl.ReplaceSelection(self.ctrl.GetSelectedText().upper()) |
|---|
| 4989 | self.ctrl.GotoPos(start) |
|---|
| 4990 | |
|---|
| 4991 | def PreLowercase(self): |
|---|
| 4992 | start = self.ExtendSelectionIfRequired() |
|---|
| 4993 | self.SelectSelection() |
|---|
| 4994 | self.ctrl.ReplaceSelection(self.ctrl.GetSelectedText().lower()) |
|---|
| 4995 | self.ctrl.GotoPos(start) |
|---|
| 4996 | |
|---|
| 4997 | def SwapCase(self): |
|---|
| 4998 | self.ctrl.BeginUndoAction() |
|---|
| 4999 | text = self.ctrl.GetSelectedText() |
|---|
| 5000 | if len(text) == 0: |
|---|
| 5001 | self.StartSelection() |
|---|
| 5002 | self.MoveCaretRight() |
|---|
| 5003 | self.SelectSelection() |
|---|
| 5004 | text = self.ctrl.GetSelectedText() |
|---|
| 5005 | self.ctrl.ReplaceSelection(text.swapcase()) |
|---|
| 5006 | self.ctrl.EndUndoAction() |
|---|
| 5007 | |
|---|
| 5008 | def UpperCase(self): |
|---|
| 5009 | self.ctrl.ReplaceSelection(self.ctrl.GetSelectedText().upper()) |
|---|
| 5010 | |
|---|
| 5011 | def LowerCase(self): |
|---|
| 5012 | self.ctrl.ReplaceSelection(self.ctrl.GetSelectedText().lower()) |
|---|
| 5013 | |
|---|
| 5014 | def Indent(self, forward=True, repeat=1, visual=False): |
|---|
| 5015 | if visual == True: |
|---|
| 5016 | repeat = self.count |
|---|
| 5017 | |
|---|
| 5018 | self.ctrl.BeginUndoAction() |
|---|
| 5019 | |
|---|
| 5020 | if len(self.ctrl.GetSelectedText()) < 1: |
|---|
| 5021 | start_line = self.ctrl.GetCurrentLine() |
|---|
| 5022 | if self.count > 1: |
|---|
| 5023 | self.SelectLines(start_line, min(self.ctrl.GetLineCount(), \ |
|---|
| 5024 | start_line - 1 + self.count)) |
|---|
| 5025 | else: |
|---|
| 5026 | start_line, end = self._GetSelectedLines() |
|---|
| 5027 | |
|---|
| 5028 | if self.SelectionOnSingleLine(): |
|---|
| 5029 | self.GotoLineIndent() |
|---|
| 5030 | |
|---|
| 5031 | for i in range(repeat): |
|---|
| 5032 | if forward: |
|---|
| 5033 | self.ctrl.Tab() |
|---|
| 5034 | else: |
|---|
| 5035 | self.ctrl.BackTab() |
|---|
| 5036 | |
|---|
| 5037 | self.ctrl.GotoLine(start_line) |
|---|
| 5038 | self.GotoLineIndent() |
|---|
| 5039 | self.ctrl.EndUndoAction() |
|---|
| 5040 | |
|---|
| 5041 | def _PositionViewport(self, n): |
|---|
| 5042 | """ |
|---|
| 5043 | Helper function for ScrollViewport* functions. |
|---|
| 5044 | |
|---|
| 5045 | Positions the viewport around caret position |
|---|
| 5046 | |
|---|
| 5047 | """ |
|---|
| 5048 | lines = self.ctrl.LinesOnScreen() - 1 |
|---|
| 5049 | current = self.ctrl.GetCurrentLine() |
|---|
| 5050 | diff = int(lines * n) |
|---|
| 5051 | self.ctrl.ScrollToLine(current - diff) |
|---|
| 5052 | |
|---|
| 5053 | |
|---|
| 5054 | def IndentText(self): |
|---|
| 5055 | """ |
|---|
| 5056 | Post motion function. Select text and indent it |
|---|
| 5057 | """ |
|---|
| 5058 | self.SelectSelection() |
|---|
| 5059 | self.Indent(True) |
|---|
| 5060 | |
|---|
| 5061 | def DedentText(self): |
|---|
| 5062 | """ |
|---|
| 5063 | Post motion function. Select text and deindent it |
|---|
| 5064 | """ |
|---|
| 5065 | self.SelectSelection() |
|---|
| 5066 | self.Indent(False) |
|---|
| 5067 | |
|---|
| 5068 | |
|---|
| 5069 | |
|---|
| 5070 | |
|---|
| 5071 | |
|---|
| 5072 | def EnterLineVisualMode(self): |
|---|
| 5073 | """ |
|---|
| 5074 | Enter line visual mode |
|---|
| 5075 | |
|---|
| 5076 | Sets a special type of visual mode in which only full lines can |
|---|
| 5077 | be selected. |
|---|
| 5078 | |
|---|
| 5079 | NOTE: |
|---|
| 5080 | Should be possible using StyledTextCtrl.SetSelectionType() but |
|---|
| 5081 | for some reason I can't get it to work so a SetSelMode() has |
|---|
| 5082 | been implemented. |
|---|
| 5083 | |
|---|
| 5084 | """ |
|---|
| 5085 | self.SetSelMode("LINE") |
|---|
| 5086 | text, pos = self.ctrl.GetCurLine() |
|---|
| 5087 | if pos == 0: |
|---|
| 5088 | self.MoveCaretRight() |
|---|
| 5089 | self.visual_line_start_pos = self.ctrl.GetCurrentPos() |
|---|
| 5090 | if self.mode != ViHelper.VISUAL: |
|---|
| 5091 | self.SetMode(ViHelper.VISUAL) |
|---|
| 5092 | self.StartSelectionAtAnchor() |
|---|
| 5093 | |
|---|
| 5094 | |
|---|
| 5095 | |
|---|
| 5096 | |
|---|
| 5097 | def LeaveVisualMode(self): |
|---|
| 5098 | """Helper function to end visual mode""" |
|---|
| 5099 | self.ctrl.GotoPos(self.ctrl.GetSelectionStart()) |
|---|
| 5100 | if self.mode == ViHelper.VISUAL: |
|---|
| 5101 | self.SetSelMode("NORMAL") |
|---|
| 5102 | self.SetMode(ViHelper.NORMAL) |
|---|
| 5103 | |
|---|
| 5104 | def EnterVisualMode(self, mouse=False): |
|---|
| 5105 | """ |
|---|
| 5106 | Change to visual (selection) mode |
|---|
| 5107 | |
|---|
| 5108 | Will do nothing if already in visual mode |
|---|
| 5109 | |
|---|
| 5110 | @param mouse: Visual mode was started by mouse action |
|---|
| 5111 | |
|---|
| 5112 | """ |
|---|
| 5113 | if self.mode != ViHelper.VISUAL: |
|---|
| 5114 | self.SetMode(ViHelper.VISUAL) |
|---|
| 5115 | |
|---|
| 5116 | if not mouse: |
|---|
| 5117 | self.StartSelectionAtAnchor() |
|---|
| 5118 | |
|---|
| 5119 | |
|---|
| 5120 | |
|---|
| 5121 | else: |
|---|
| 5122 | self.StartSelection(self.ctrl.GetSelectionEnd()) |
|---|
| 5123 | |
|---|
| 5124 | |
|---|
| 5125 | |
|---|
| 5126 | |
|---|
| 5127 | |
|---|
| 5128 | def SearchForwardsForChar(self, search_char, count=None, |
|---|
| 5129 | wrap_lines=True, start_offset=-1): |
|---|
| 5130 | if count is None: count = self.count |
|---|
| 5131 | pos = start_pos = self.ctrl.GetCurrentPos() + start_offset |
|---|
| 5132 | |
|---|
| 5133 | text = self.ctrl.GetTextRaw() |
|---|
| 5134 | |
|---|
| 5135 | |
|---|
| 5136 | n = 0 |
|---|
| 5137 | for i in range(count): |
|---|
| 5138 | pos = text.find(search_char, pos + 1) |
|---|
| 5139 | |
|---|
| 5140 | |
|---|
| 5141 | |
|---|
| 5142 | if pos > -1: |
|---|
| 5143 | if not wrap_lines: |
|---|
| 5144 | |
|---|
| 5145 | text_to_check = self.ctrl.GetTextRange(start_pos, pos) |
|---|
| 5146 | if self.ctrl.GetEOLChar() in text_to_check: |
|---|
| 5147 | return False |
|---|
| 5148 | self.ctrl.GotoPos(pos) |
|---|
| 5149 | return True |
|---|
| 5150 | |
|---|
| 5151 | self.visualBell("RED") |
|---|
| 5152 | return False |
|---|
| 5153 | |
|---|
| 5154 | def SearchBackwardsForChar(self, search_char, count=None, |
|---|
| 5155 | wrap_lines=True, start_offset=0): |
|---|
| 5156 | """ |
|---|
| 5157 | Searches backwards in text for character. |
|---|
| 5158 | |
|---|
| 5159 | @param search_char: Character to search for. |
|---|
| 5160 | @param count: Number of characeters to find. |
|---|
| 5161 | @param wrap_lines: Should search occur on multiple lines. |
|---|
| 5162 | @param start_offset: Start offset for searching. Should be |
|---|
| 5163 | zero if character under the caret should be included in |
|---|
| 5164 | the search, -1 if not. |
|---|
| 5165 | |
|---|
| 5166 | @rtype: bool |
|---|
| 5167 | @return: True if successful, False if not. |
|---|
| 5168 | |
|---|
| 5169 | """ |
|---|
| 5170 | if count is None: count = self.count |
|---|
| 5171 | pos = start_pos = self.ctrl.GetCurrentPos() + start_offset |
|---|
| 5172 | |
|---|
| 5173 | text = self.ctrl.GetTextRaw() |
|---|
| 5174 | text_to_search = text[:pos+1] |
|---|
| 5175 | for i in range(count): |
|---|
| 5176 | pos = text_to_search.rfind(search_char) |
|---|
| 5177 | text_to_search = text[:pos] |
|---|
| 5178 | |
|---|
| 5179 | if pos > -1: |
|---|
| 5180 | if not wrap_lines: |
|---|
| 5181 | text_to_check = self.ctrl.GetTextRange(start_pos, pos) |
|---|
| 5182 | if self.ctrl.GetEOLChar() in text_to_check: |
|---|
| 5183 | return False |
|---|
| 5184 | self.ctrl.GotoPos(pos) |
|---|
| 5185 | return True |
|---|
| 5186 | |
|---|
| 5187 | self.visualBell("RED") |
|---|
| 5188 | return False |
|---|
| 5189 | |
|---|
| 5190 | def FindMatchingBrace(self, brace): |
|---|
| 5191 | if brace in self.BRACES: |
|---|
| 5192 | forward = True |
|---|
| 5193 | b = self.BRACES |
|---|
| 5194 | elif brace in self.REVERSE_BRACES: |
|---|
| 5195 | forward = False |
|---|
| 5196 | b = self.REVERSE_BRACES |
|---|
| 5197 | else: |
|---|
| 5198 | return |
|---|
| 5199 | |
|---|
| 5200 | start_pos = self.ctrl.GetCurrentPos() |
|---|
| 5201 | if forward: |
|---|
| 5202 | text = self.ctrl.GetTextRaw()[start_pos+1:] |
|---|
| 5203 | else: |
|---|
| 5204 | text = self.ctrl.GetTextRaw()[0:start_pos:][::-1] |
|---|
| 5205 | brace_count = 1 |
|---|
| 5206 | n = 0 |
|---|
| 5207 | pos = -1 |
|---|
| 5208 | for i in text: |
|---|
| 5209 | n += 1 |
|---|
| 5210 | if i == brace: |
|---|
| 5211 | brace_count += 1 |
|---|
| 5212 | elif i == b[brace]: |
|---|
| 5213 | brace_count -= 1 |
|---|
| 5214 | |
|---|
| 5215 | if brace_count < 1: |
|---|
| 5216 | if forward: |
|---|
| 5217 | pos = start_pos + n |
|---|
| 5218 | else: |
|---|
| 5219 | pos = start_pos - n |
|---|
| 5220 | break |
|---|
| 5221 | |
|---|
| 5222 | if pos > -1: |
|---|
| 5223 | self.ctrl.GotoPos(pos) |
|---|
| 5224 | return True |
|---|
| 5225 | else: |
|---|
| 5226 | self.visualBell("RED") |
|---|
| 5227 | return False |
|---|
| 5228 | |
|---|
| 5229 | def FindChar(self, code=None, reverse=False, offset=0, count=1, \ |
|---|
| 5230 | repeat=True): |
|---|
| 5231 | """ |
|---|
| 5232 | Searches current *line* for specified character. |
|---|
| 5233 | |
|---|
| 5234 | Will move the caret to this place (+/- any offset supplied). |
|---|
| 5235 | |
|---|
| 5236 | @param code: keycode of character to search for. |
|---|
| 5237 | @param reverse: If True will search backwards. |
|---|
| 5238 | @param offset: Offset to move caret post search. |
|---|
| 5239 | @param count: Number of characters to find. If not all found, |
|---|
| 5240 | i.e. count is 3 but only 2 characters on current line, will |
|---|
| 5241 | not move caret. |
|---|
| 5242 | @param repeat: Should the search be saved so it will be |
|---|
| 5243 | repeated (by "," and ";") |
|---|
| 5244 | |
|---|
| 5245 | @rtype: bool |
|---|
| 5246 | @return: True if successful, False if not. |
|---|
| 5247 | |
|---|
| 5248 | """ |
|---|
| 5249 | |
|---|
| 5250 | |
|---|
| 5251 | if code is None: |
|---|
| 5252 | return False |
|---|
| 5253 | |
|---|
| 5254 | char = bytes(self.GetCharFromCode(code)) |
|---|
| 5255 | pos = self.ctrl.GetCurrentPos() |
|---|
| 5256 | |
|---|
| 5257 | if repeat: |
|---|
| 5258 | |
|---|
| 5259 | |
|---|
| 5260 | self.last_find_cmd = { |
|---|
| 5261 | "code": code, |
|---|
| 5262 | "reverse": reverse, |
|---|
| 5263 | "offset": offset, |
|---|
| 5264 | "repeat": False |
|---|
| 5265 | } |
|---|
| 5266 | |
|---|
| 5267 | if reverse: |
|---|
| 5268 | search_cmd = self.SearchBackwardsForChar |
|---|
| 5269 | start_offset = -1 |
|---|
| 5270 | |
|---|
| 5271 | else: |
|---|
| 5272 | search_cmd = self.SearchForwardsForChar |
|---|
| 5273 | start_offset = 0 |
|---|
| 5274 | |
|---|
| 5275 | if search_cmd(char, count, False, start_offset): |
|---|
| 5276 | self.MoveCaretPos(offset) |
|---|
| 5277 | self.ctrl.ChooseCaretX() |
|---|
| 5278 | return True |
|---|
| 5279 | |
|---|
| 5280 | return False |
|---|
| 5281 | |
|---|
| 5282 | def FindNextChar(self, keycode): |
|---|
| 5283 | self.FindChar(keycode, count=self.count) |
|---|
| 5284 | |
|---|
| 5285 | def FindNextCharBackwards(self, keycode): |
|---|
| 5286 | cmd = self.FindChar(keycode, count=self.count, reverse=True) |
|---|
| 5287 | |
|---|
| 5288 | def FindUpToNextChar(self, keycode): |
|---|
| 5289 | cmd = self.FindChar(keycode, count=self.count, offset=-1) |
|---|
| 5290 | |
|---|
| 5291 | def FindUpToNextCharBackwards(self, keycode): |
|---|
| 5292 | cmd = self.FindChar(keycode, count=self.count, reverse=True, offset=1) |
|---|
| 5293 | |
|---|
| 5294 | def GetLastFindCharCmd(self): |
|---|
| 5295 | return self.last_find_cmd |
|---|
| 5296 | |
|---|
| 5297 | def RepeatLastFindCharCmd(self): |
|---|
| 5298 | args = self.GetLastFindCharCmd() |
|---|
| 5299 | if args is not None: |
|---|
| 5300 | |
|---|
| 5301 | args["count"] = self.count |
|---|
| 5302 | self.FindChar(**args) |
|---|
| 5303 | |
|---|
| 5304 | def RepeatLastFindCharCmdReverse(self): |
|---|
| 5305 | args = self.GetLastFindCharCmd() |
|---|
| 5306 | if args is not None: |
|---|
| 5307 | args["count"] = self.count |
|---|
| 5308 | args["reverse"] = not args["reverse"] |
|---|
| 5309 | self.FindChar(**args) |
|---|
| 5310 | args["reverse"] = not args["reverse"] |
|---|
| 5311 | |
|---|
| 5312 | def MatchBraceUnderCaret(self): |
|---|
| 5313 | return self.FindMatchingBrace(self.GetUnichrAt( |
|---|
| 5314 | self.ctrl.GetCurrentPos())) |
|---|
| 5315 | |
|---|
| 5316 | |
|---|
| 5317 | def _SearchText(self, text, forward=True, match_case=True, wrap=True, |
|---|
| 5318 | whole_word=True): |
|---|
| 5319 | """ |
|---|
| 5320 | Searches for next occurance of 'text' |
|---|
| 5321 | |
|---|
| 5322 | @param text: text to search for |
|---|
| 5323 | @param forward: if true searches forward in text, else |
|---|
| 5324 | search in reverse |
|---|
| 5325 | @param match_case: should search be case sensitive? |
|---|
| 5326 | """ |
|---|
| 5327 | self.AddJumpPosition(self.ctrl.GetCurrentPos() - len(text)) |
|---|
| 5328 | |
|---|
| 5329 | search_cmd = self.ctrl.SearchNext if forward else self.ctrl.SearchPrev |
|---|
| 5330 | |
|---|
| 5331 | |
|---|
| 5332 | if whole_word and match_case: |
|---|
| 5333 | flags = wx.stc.STC_FIND_WHOLEWORD|wx.stc.STC_FIND_MATCHCASE |
|---|
| 5334 | elif whole_word: |
|---|
| 5335 | flags = wx.stc.STC_FIND_WHOLEWORD |
|---|
| 5336 | elif match_case: |
|---|
| 5337 | flags = wx.stc.STC_FIND_MATCHCASE |
|---|
| 5338 | |
|---|
| 5339 | pos = search_cmd(flags, text) |
|---|
| 5340 | |
|---|
| 5341 | if pos == -1 and wrap: |
|---|
| 5342 | if forward: |
|---|
| 5343 | self.ctrl.GotoLine(0) |
|---|
| 5344 | else: |
|---|
| 5345 | self.ctrl.GotoLine(self.ctrl.GetLineCount()) |
|---|
| 5346 | self.ctrl.SearchAnchor() |
|---|
| 5347 | pos = search_cmd(flags, text) |
|---|
| 5348 | if pos != -1: |
|---|
| 5349 | self.ctrl.GotoPos(pos) |
|---|
| 5350 | |
|---|
| 5351 | def _SearchCaretWord(self, forward=True, match_case=True, whole_word=True): |
|---|
| 5352 | """ |
|---|
| 5353 | Searches for next occurance of word currently under |
|---|
| 5354 | the caret |
|---|
| 5355 | |
|---|
| 5356 | @param forward: if true searches forward in text, else |
|---|
| 5357 | search in reverse |
|---|
| 5358 | @param match_case: should search be case sensitive? |
|---|
| 5359 | """ |
|---|
| 5360 | self.SelectInWord() |
|---|
| 5361 | self.ExtendSelectionIfRequired() |
|---|
| 5362 | text = self.ctrl.GetSelectedText() |
|---|
| 5363 | |
|---|
| 5364 | |
|---|
| 5365 | if forward: |
|---|
| 5366 | self.ctrl.CharRight() |
|---|
| 5367 | else: |
|---|
| 5368 | self.ctrl.CharLeft() |
|---|
| 5369 | self.ctrl.SearchAnchor() |
|---|
| 5370 | self._SearchText(text, forward, match_case=match_case, wrap=True, whole_word=whole_word) |
|---|
| 5371 | |
|---|
| 5372 | self.last_search_args = {'text' : text, 'forward' : forward, |
|---|
| 5373 | 'match_case' : match_case, |
|---|
| 5374 | 'whole_word' : whole_word} |
|---|
| 5375 | |
|---|
| 5376 | def SearchCaretWordForwards(self): |
|---|
| 5377 | """Helper function to allow repeats""" |
|---|
| 5378 | self._SearchCaretWord(True, True, True) |
|---|
| 5379 | |
|---|
| 5380 | def SearchPartialCaretWordForwards(self): |
|---|
| 5381 | self._SearchCaretWord(True, True, False) |
|---|
| 5382 | |
|---|
| 5383 | def SearchCaretWordBackwards(self): |
|---|
| 5384 | """Helper function to allow repeats""" |
|---|
| 5385 | self._SearchCaretWord(False, True, True) |
|---|
| 5386 | |
|---|
| 5387 | def SearchPartialCaretWordBackwards(self): |
|---|
| 5388 | self._SearchCaretWord(False, True, False) |
|---|
| 5389 | |
|---|
| 5390 | def ContinueLastSearch(self, reverse): |
|---|
| 5391 | """ |
|---|
| 5392 | Repeats last search command |
|---|
| 5393 | """ |
|---|
| 5394 | args = self.last_search_args |
|---|
| 5395 | if args is not None: |
|---|
| 5396 | |
|---|
| 5397 | if reverse: |
|---|
| 5398 | args['forward'] = not args['forward'] |
|---|
| 5399 | |
|---|
| 5400 | offset = 1 if args['forward'] else -1 |
|---|
| 5401 | self.MoveCaretPos(offset) |
|---|
| 5402 | self.ctrl.SearchAnchor() |
|---|
| 5403 | |
|---|
| 5404 | self._SearchText(**args) |
|---|
| 5405 | |
|---|
| 5406 | |
|---|
| 5407 | if reverse: |
|---|
| 5408 | args['forward'] = not args['forward'] |
|---|
| 5409 | |
|---|
| 5410 | def ContinueLastSearchSameDirection(self): |
|---|
| 5411 | """Helper function to allow repeats""" |
|---|
| 5412 | self.ContinueLastSearch(False) |
|---|
| 5413 | |
|---|
| 5414 | def ContinueLastSearchReverseDirection(self): |
|---|
| 5415 | """Helper function to allow repeats""" |
|---|
| 5416 | self.ContinueLastSearch(True) |
|---|
| 5417 | |
|---|
| 5418 | |
|---|
| 5419 | |
|---|
| 5420 | |
|---|
| 5421 | |
|---|
| 5422 | def ReplaceChar(self, keycode): |
|---|
| 5423 | """ |
|---|
| 5424 | Replaces character under caret |
|---|
| 5425 | |
|---|
| 5426 | Contains some custom code to allow repeating |
|---|
| 5427 | """ |
|---|
| 5428 | |
|---|
| 5429 | char = unichr(keycode) |
|---|
| 5430 | |
|---|
| 5431 | |
|---|
| 5432 | if self.mode == ViHelper.VISUAL: |
|---|
| 5433 | sel_start, sel_end = self._GetSelectionRange() |
|---|
| 5434 | count = sel_end - sel_start |
|---|
| 5435 | self.ctrl.GotoPos(sel_start) |
|---|
| 5436 | else: |
|---|
| 5437 | count = self.count |
|---|
| 5438 | |
|---|
| 5439 | |
|---|
| 5440 | |
|---|
| 5441 | line, pos = self.ctrl.GetCurLineRaw() |
|---|
| 5442 | if pos + count > len(line): |
|---|
| 5443 | return |
|---|
| 5444 | |
|---|
| 5445 | self.last_cmd = 3, keycode, count, None |
|---|
| 5446 | |
|---|
| 5447 | self.ctrl.BeginUndoAction() |
|---|
| 5448 | self.StartSelection() |
|---|
| 5449 | self.ctrl.GotoPos(self.ctrl.GetCurrentPos()+count-1) |
|---|
| 5450 | self.EndDelete() |
|---|
| 5451 | self.Repeat(self.InsertText, arg=char) |
|---|
| 5452 | if pos + count != len(line): |
|---|
| 5453 | self.MoveCaretPos(-1) |
|---|
| 5454 | self.ctrl.EndUndoAction() |
|---|
| 5455 | |
|---|
| 5456 | def StartReplaceMode(self): |
|---|
| 5457 | |
|---|
| 5458 | self.SetMode(ViHelper.REPLACE) |
|---|
| 5459 | |
|---|
| 5460 | |
|---|
| 5461 | |
|---|
| 5462 | |
|---|
| 5463 | |
|---|
| 5464 | def _SetMark(self, code): |
|---|
| 5465 | """ |
|---|
| 5466 | Not called directly (call self.Mark instead) |
|---|
| 5467 | """ |
|---|
| 5468 | page = self.ctrl.presenter.getWikiWord() |
|---|
| 5469 | self.marks[page][code] = self.ctrl.GetCurrentPos() |
|---|
| 5470 | |
|---|
| 5471 | def GotoMark(self, char): |
|---|
| 5472 | |
|---|
| 5473 | page = self.ctrl.presenter.getWikiWord() |
|---|
| 5474 | if char in self.marks[page]: |
|---|
| 5475 | self.AddJumpPosition() |
|---|
| 5476 | pos = self.marks[page][char] |
|---|
| 5477 | |
|---|
| 5478 | |
|---|
| 5479 | |
|---|
| 5480 | pos = min(self.ctrl.GetLength(), pos) |
|---|
| 5481 | |
|---|
| 5482 | self.ctrl.GotoPos(pos) |
|---|
| 5483 | self.visualBell("GREEN") |
|---|
| 5484 | return True |
|---|
| 5485 | |
|---|
| 5486 | self.visualBell("RED") |
|---|
| 5487 | return False |
|---|
| 5488 | |
|---|
| 5489 | def GotoMarkIndent(self, char): |
|---|
| 5490 | if self.GotoMark(char): |
|---|
| 5491 | self.GotoLineIndent() |
|---|
| 5492 | |
|---|
| 5493 | |
|---|
| 5494 | |
|---|
| 5495 | |
|---|
| 5496 | |
|---|
| 5497 | def YankLine(self): |
|---|
| 5498 | """Copy the current line text to the clipboard""" |
|---|
| 5499 | |
|---|
| 5500 | line_no = self.ctrl.GetCurrentLine() |
|---|
| 5501 | max_line = min(line_no+self.count-1, self.ctrl.GetLineCount()) |
|---|
| 5502 | start = self.GetLineStartPos(line_no) |
|---|
| 5503 | end = self.ctrl.GetLineEndPosition(max_line) |
|---|
| 5504 | |
|---|
| 5505 | text = self.ctrl.GetTextRange(start, end) + self.ctrl.GetEOLChar() |
|---|
| 5506 | |
|---|
| 5507 | self.ctrl.Copy(text) |
|---|
| 5508 | |
|---|
| 5509 | def YankSelection(self, lines=False): |
|---|
| 5510 | """Copy the current selection to the clipboard""" |
|---|
| 5511 | if lines: |
|---|
| 5512 | self.SelectFullLines() |
|---|
| 5513 | self.ctrl.CharRightExtend() |
|---|
| 5514 | elif self.GetSelMode() == "LINE": |
|---|
| 5515 | |
|---|
| 5516 | start, end = self._GetSelectionRange() |
|---|
| 5517 | self.ctrl.SetSelection(start, end) |
|---|
| 5518 | self.ctrl.CharRightExtend() |
|---|
| 5519 | |
|---|
| 5520 | self.ctrl.Copy() |
|---|
| 5521 | |
|---|
| 5522 | def Yank(self): |
|---|
| 5523 | start = self.ExtendSelectionIfRequired() |
|---|
| 5524 | self.SelectSelection() |
|---|
| 5525 | self.YankSelection() |
|---|
| 5526 | self.ctrl.GotoPos(start) |
|---|
| 5527 | |
|---|
| 5528 | def Put(self, before, count=None): |
|---|
| 5529 | count = count if count is not None else self.count |
|---|
| 5530 | text = getTextFromClipboard() |
|---|
| 5531 | |
|---|
| 5532 | |
|---|
| 5533 | if not text: |
|---|
| 5534 | self.ctrl.Paste() |
|---|
| 5535 | |
|---|
| 5536 | |
|---|
| 5537 | eol = self.ctrl.GetEOLChar() |
|---|
| 5538 | eol_len = len(eol) |
|---|
| 5539 | if len(text) > eol_len: |
|---|
| 5540 | is_line = text[-len(eol):] == eol |
|---|
| 5541 | else: |
|---|
| 5542 | is_line = False |
|---|
| 5543 | |
|---|
| 5544 | self.ctrl.BeginUndoAction() |
|---|
| 5545 | |
|---|
| 5546 | if is_line: |
|---|
| 5547 | if not before: |
|---|
| 5548 | |
|---|
| 5549 | |
|---|
| 5550 | self.ctrl.LineEnd() |
|---|
| 5551 | self.MoveCaretDown(1) |
|---|
| 5552 | self.GotoLineStart() |
|---|
| 5553 | |
|---|
| 5554 | if self.HasSelection(): |
|---|
| 5555 | self.ctrl.Clear() |
|---|
| 5556 | |
|---|
| 5557 | |
|---|
| 5558 | self.InsertText(count * text) |
|---|
| 5559 | |
|---|
| 5560 | if is_line: |
|---|
| 5561 | |
|---|
| 5562 | |
|---|
| 5563 | self.GotoLineIndent() |
|---|
| 5564 | |
|---|
| 5565 | self.ctrl.EndUndoAction() |
|---|
| 5566 | |
|---|
| 5567 | |
|---|
| 5568 | |
|---|
| 5569 | |
|---|
| 5570 | def DeleteSurrounding(self, code): |
|---|
| 5571 | char = self.GetCharFromCode(code) |
|---|
| 5572 | if char in self.text_object_map: |
|---|
| 5573 | self.SelectATextObject(char) |
|---|
| 5574 | pos = self.ExtendSelectionIfRequired() |
|---|
| 5575 | self.ctrl.ReplaceSelection(self.ctrl.GetSelectedText()[1:-1]) |
|---|
| 5576 | self.ctrl.GotoPos(pos) |
|---|
| 5577 | |
|---|
| 5578 | def EndDelete(self): |
|---|
| 5579 | self.SelectSelection() |
|---|
| 5580 | self.DeleteSelection() |
|---|
| 5581 | |
|---|
| 5582 | def EndDeleteInsert(self): |
|---|
| 5583 | self.SelectSelection() |
|---|
| 5584 | self.DeleteSelection() |
|---|
| 5585 | self.Insert() |
|---|
| 5586 | |
|---|
| 5587 | def DeleteRight(self): |
|---|
| 5588 | self.ctrl.BeginUndoAction() |
|---|
| 5589 | self.StartSelection() |
|---|
| 5590 | self.SelectSelection() |
|---|
| 5591 | self.DeleteSelection() |
|---|
| 5592 | self.ctrl.EndUndoAction() |
|---|
| 5593 | |
|---|
| 5594 | def DeleteLeft(self): |
|---|
| 5595 | self.ctrl.BeginUndoAction() |
|---|
| 5596 | self.StartSelection() |
|---|
| 5597 | self.MoveCaretLeft() |
|---|
| 5598 | self.SelectSelection() |
|---|
| 5599 | self.DeleteSelection() |
|---|
| 5600 | self.ctrl.EndUndoAction() |
|---|
| 5601 | |
|---|
| 5602 | def DeleteRightAndInsert(self): |
|---|
| 5603 | self.DeleteRight() |
|---|
| 5604 | self.Insert() |
|---|
| 5605 | |
|---|
| 5606 | def DeleteLinesAndIndentInsert(self): |
|---|
| 5607 | self.ctrl.BeginUndoAction() |
|---|
| 5608 | indent = self.ctrl.GetLineIndentation(self.ctrl.GetCurrentLine()) |
|---|
| 5609 | self.DeleteLine() |
|---|
| 5610 | self.OpenNewLine(True, indent=indent) |
|---|
| 5611 | self.ctrl.EndUndoAction() |
|---|
| 5612 | |
|---|
| 5613 | def DeleteLine(self): |
|---|
| 5614 | self.ctrl.BeginUndoAction() |
|---|
| 5615 | self.SelectCurrentLine() |
|---|
| 5616 | self.DeleteSelection() |
|---|
| 5617 | self.ctrl.EndUndoAction() |
|---|
| 5618 | |
|---|
| 5619 | |
|---|
| 5620 | |
|---|
| 5621 | |
|---|
| 5622 | |
|---|
| 5623 | |
|---|
| 5624 | def GetLineStartPos(self, line): |
|---|
| 5625 | return self.ctrl.GetLineIndentPosition(line) - \ |
|---|
| 5626 | self.ctrl.GetLineIndentation(line) |
|---|
| 5627 | |
|---|
| 5628 | def GotoLineStart(self): |
|---|
| 5629 | self.ctrl.Home() |
|---|
| 5630 | |
|---|
| 5631 | def GotoLineEnd(self, true_end=True): |
|---|
| 5632 | self.ctrl.LineEnd() |
|---|
| 5633 | if not true_end: |
|---|
| 5634 | self.ctrl.CharLeft() |
|---|
| 5635 | |
|---|
| 5636 | def GotoLineIndent(self, line=None): |
|---|
| 5637 | """ |
|---|
| 5638 | Moves caret to first non-whitespace character on "line". |
|---|
| 5639 | |
|---|
| 5640 | @param line: Line number |
|---|
| 5641 | |
|---|
| 5642 | """ |
|---|
| 5643 | if line is None: line = self.ctrl.GetCurrentLine() |
|---|
| 5644 | self.ctrl.GotoPos(self.ctrl.GetLineIndentPosition(line)) |
|---|
| 5645 | self.ctrl.ChooseCaretX() |
|---|
| 5646 | |
|---|
| 5647 | def GotoColumn(self, pos=None): |
|---|
| 5648 | """ |
|---|
| 5649 | Moves caret to "pos" on current line. If no pos specified use "count". |
|---|
| 5650 | |
|---|
| 5651 | @param pos: Column position to move caret to. |
|---|
| 5652 | """ |
|---|
| 5653 | if pos is None: pos = self.count |
|---|
| 5654 | line = self.ctrl.GetCurrentLine() |
|---|
| 5655 | lstart = self.ctrl.PositionFromLine(line) |
|---|
| 5656 | lend = self.ctrl.GetLineEndPosition(line) |
|---|
| 5657 | line_len = lend - lstart |
|---|
| 5658 | column = min(line_len, pos) |
|---|
| 5659 | self.ctrl.GotoPos(lstart + column) |
|---|
| 5660 | |
|---|
| 5661 | self.ctrl.ChooseCaretX() |
|---|
| 5662 | |
|---|
| 5663 | def GotoSentenceStart(self, count=None): |
|---|
| 5664 | self.AddJumpPosition() |
|---|
| 5665 | self.Repeat(self._MoveCaretSentenceStart, count) |
|---|
| 5666 | |
|---|
| 5667 | def _MoveCaretSentenceStart(self, pos=None, start_pos=None): |
|---|
| 5668 | """ |
|---|
| 5669 | Internal function to move caret to sentence start. |
|---|
| 5670 | |
|---|
| 5671 | Call GotoSentenceStart instead. |
|---|
| 5672 | """ |
|---|
| 5673 | if pos is None: |
|---|
| 5674 | pos = self.ctrl.GetCurrentPos()-1 |
|---|
| 5675 | if start_pos is None: |
|---|
| 5676 | start_pos = pos |
|---|
| 5677 | char = self.GetUnichrAt(pos) |
|---|
| 5678 | |
|---|
| 5679 | page_length = self.ctrl.GetLength() |
|---|
| 5680 | |
|---|
| 5681 | text = self.ctrl.GetText()[:pos] |
|---|
| 5682 | |
|---|
| 5683 | n = -1 |
|---|
| 5684 | for i in self.SENTENCE_ENDINGS: |
|---|
| 5685 | index = text.rfind(i) |
|---|
| 5686 | if index != -1 and index > n: |
|---|
| 5687 | n = index |
|---|
| 5688 | pos = n |
|---|
| 5689 | |
|---|
| 5690 | if pos < 1: |
|---|
| 5691 | self.ctrl.GotoPos(0) |
|---|
| 5692 | return |
|---|
| 5693 | |
|---|
| 5694 | sentence_end_pos = pos |
|---|
| 5695 | forward_char = self.GetUnichrAt(pos+1) |
|---|
| 5696 | if forward_char in self.SENTENCE_ENDINGS_SUFFIXS: |
|---|
| 5697 | pos += 1 |
|---|
| 5698 | while forward_char in self.SENTENCE_ENDINGS_SUFFIXS: |
|---|
| 5699 | pos += 1 |
|---|
| 5700 | forward_char = self.GetUnichrAt(pos) |
|---|
| 5701 | if forward_char in string.whitespace: |
|---|
| 5702 | while forward_char in string.whitespace: |
|---|
| 5703 | pos += 1 |
|---|
| 5704 | forward_char = self.GetUnichrAt(pos) |
|---|
| 5705 | else: |
|---|
| 5706 | self._MoveCaretSentenceStart(pos-1, start_pos) |
|---|
| 5707 | return |
|---|
| 5708 | |
|---|
| 5709 | if start_pos >= pos: |
|---|
| 5710 | self.ctrl.GotoPos(pos) |
|---|
| 5711 | else: |
|---|
| 5712 | self._MoveCaretSentenceStart(sentence_end_pos-1, start_pos) |
|---|
| 5713 | |
|---|
| 5714 | def GotoNextSentence(self, count=None): |
|---|
| 5715 | self.AddJumpPosition() |
|---|
| 5716 | self.Repeat(self._MoveCaretNextSentence, count) |
|---|
| 5717 | |
|---|
| 5718 | def GotoSentenceEnd(self, count=None): |
|---|
| 5719 | self.Repeat(self._MoveCaretNextSentence, count, False) |
|---|
| 5720 | |
|---|
| 5721 | def GotoSentenceEndCountWhitespace(self, count=None): |
|---|
| 5722 | if count is None: count = self.count |
|---|
| 5723 | |
|---|
| 5724 | if count % 2: |
|---|
| 5725 | include_whitespace = False |
|---|
| 5726 | count = count / 2 + 1 |
|---|
| 5727 | move_left = False |
|---|
| 5728 | else: |
|---|
| 5729 | include_whitespace = True |
|---|
| 5730 | count = count / 2 |
|---|
| 5731 | move_left = True |
|---|
| 5732 | |
|---|
| 5733 | self.Repeat(self._MoveCaretNextSentence, count, include_whitespace) |
|---|
| 5734 | |
|---|
| 5735 | if move_left: |
|---|
| 5736 | self.ctrl.CharLeftExtend() |
|---|
| 5737 | |
|---|
| 5738 | |
|---|
| 5739 | |
|---|
| 5740 | def _MoveCaretNextSentence(self, include_whitespace=True, |
|---|
| 5741 | pos=None, start_pos=None): |
|---|
| 5742 | |
|---|
| 5743 | if pos is None: |
|---|
| 5744 | pos = self.ctrl.GetCurrentPos()+1 |
|---|
| 5745 | if start_pos is None: |
|---|
| 5746 | start_pos = pos |
|---|
| 5747 | char = self.GetUnichrAt(pos) |
|---|
| 5748 | |
|---|
| 5749 | page_length = self.ctrl.GetLength() |
|---|
| 5750 | |
|---|
| 5751 | text = self.ctrl.GetText()[pos:] |
|---|
| 5752 | |
|---|
| 5753 | n = page_length |
|---|
| 5754 | for i in self.SENTENCE_ENDINGS: |
|---|
| 5755 | index = text.find(i) |
|---|
| 5756 | if index != -1 and index < n: |
|---|
| 5757 | n = index |
|---|
| 5758 | pos = pos + n |
|---|
| 5759 | |
|---|
| 5760 | if pos+1 >= page_length: |
|---|
| 5761 | self.ctrl.GotoPos(page_length) |
|---|
| 5762 | return |
|---|
| 5763 | |
|---|
| 5764 | sentence_end_pos = pos |
|---|
| 5765 | forward_char = self.GetUnichrAt(pos+1) |
|---|
| 5766 | if forward_char in self.SENTENCE_ENDINGS_SUFFIXS: |
|---|
| 5767 | pos += 1 |
|---|
| 5768 | while forward_char in self.SENTENCE_ENDINGS_SUFFIXS: |
|---|
| 5769 | pos += 1 |
|---|
| 5770 | forward_char = self.GetUnichrAt(pos) |
|---|
| 5771 | sentence_end_pos = pos-1 |
|---|
| 5772 | if forward_char in string.whitespace: |
|---|
| 5773 | while forward_char in string.whitespace: |
|---|
| 5774 | pos += 1 |
|---|
| 5775 | forward_char = self.GetUnichrAt(pos) |
|---|
| 5776 | else: |
|---|
| 5777 | self._MoveCaretNextSentence(include_whitespace, pos+1, start_pos) |
|---|
| 5778 | return |
|---|
| 5779 | |
|---|
| 5780 | if start_pos <= pos: |
|---|
| 5781 | if include_whitespace: |
|---|
| 5782 | self.ctrl.GotoPos(pos) |
|---|
| 5783 | else: |
|---|
| 5784 | self.ctrl.GotoPos(sentence_end_pos) |
|---|
| 5785 | else: |
|---|
| 5786 | self._MoveCaretNextSentence(include_whitespace, |
|---|
| 5787 | sentence_end_pos, start_pos) |
|---|
| 5788 | |
|---|
| 5789 | def MoveCaretRight(self): |
|---|
| 5790 | self.MoveCaretPos(self.count) |
|---|
| 5791 | |
|---|
| 5792 | |
|---|
| 5793 | |
|---|
| 5794 | |
|---|
| 5795 | |
|---|
| 5796 | |
|---|
| 5797 | |
|---|
| 5798 | |
|---|
| 5799 | |
|---|
| 5800 | |
|---|
| 5801 | |
|---|
| 5802 | |
|---|
| 5803 | |
|---|
| 5804 | def MoveCaretUp(self, count=None): |
|---|
| 5805 | self.Repeat(self.ctrl.LineUp, count) |
|---|
| 5806 | self.CheckLineEnd() |
|---|
| 5807 | |
|---|
| 5808 | def MoveCaretDown(self, count=None): |
|---|
| 5809 | self.Repeat(self.ctrl.LineDown, count) |
|---|
| 5810 | self.CheckLineEnd() |
|---|
| 5811 | |
|---|
| 5812 | def MoveCaretDownAndIndent(self, count=None): |
|---|
| 5813 | self.Repeat(self.ctrl.LineDown, count) |
|---|
| 5814 | self.GotoLineIndent() |
|---|
| 5815 | |
|---|
| 5816 | def MoveCaretLeft(self): |
|---|
| 5817 | self.MoveCaretPos(-self.count) |
|---|
| 5818 | |
|---|
| 5819 | def MoveCaretPos(self, offset): |
|---|
| 5820 | """ |
|---|
| 5821 | Move caret by a given offset |
|---|
| 5822 | """ |
|---|
| 5823 | line, line_pos = self.ctrl.GetCurLine() |
|---|
| 5824 | line_no = self.ctrl.GetCurrentLine() |
|---|
| 5825 | |
|---|
| 5826 | if self.mode == ViHelper.VISUAL: |
|---|
| 5827 | if offset > 0: |
|---|
| 5828 | move_right = True |
|---|
| 5829 | move = self.ctrl.CharRightExtend |
|---|
| 5830 | stop_pos = self.GetLineStartPos(line_no) + \ |
|---|
| 5831 | self.ctrl.LineLength(line_no)-1 |
|---|
| 5832 | else: |
|---|
| 5833 | move_right = False |
|---|
| 5834 | move = self.ctrl.CharLeftExtend |
|---|
| 5835 | stop_pos = self.GetLineStartPos(line_no) |
|---|
| 5836 | else: |
|---|
| 5837 | if offset > 0: |
|---|
| 5838 | move_right = True |
|---|
| 5839 | move = self.ctrl.CharRight |
|---|
| 5840 | stop_pos = self.GetLineStartPos(line_no) + \ |
|---|
| 5841 | self.ctrl.LineLength(line_no)-2 |
|---|
| 5842 | |
|---|
| 5843 | |
|---|
| 5844 | if line_no+1 == self.ctrl.GetLineCount(): |
|---|
| 5845 | stop_pos += 1 |
|---|
| 5846 | else: |
|---|
| 5847 | move_right = False |
|---|
| 5848 | move = self.ctrl.CharLeft |
|---|
| 5849 | stop_pos = self.GetLineStartPos(line_no) |
|---|
| 5850 | |
|---|
| 5851 | for i in range(abs(offset)): |
|---|
| 5852 | if (move_right and self.ctrl.GetCurrentPos() < stop_pos) or \ |
|---|
| 5853 | (not move_right and self.ctrl.GetCurrentPos() > stop_pos): |
|---|
| 5854 | move() |
|---|
| 5855 | else: |
|---|
| 5856 | break |
|---|
| 5857 | |
|---|
| 5858 | |
|---|
| 5859 | |
|---|
| 5860 | |
|---|
| 5861 | |
|---|
| 5862 | |
|---|
| 5863 | |
|---|
| 5864 | |
|---|
| 5865 | |
|---|
| 5866 | |
|---|
| 5867 | |
|---|
| 5868 | |
|---|
| 5869 | |
|---|
| 5870 | def MoveCaretLinePos(self, offset): |
|---|
| 5871 | """ |
|---|
| 5872 | Move caret line position by a given offset |
|---|
| 5873 | |
|---|
| 5874 | Faster but does not maintain line position |
|---|
| 5875 | """ |
|---|
| 5876 | self.ctrl.ChooseCaretX() |
|---|
| 5877 | line = max(self.ctrl.GetCurrentLine() + offset, 0) |
|---|
| 5878 | line = min(line, self.ctrl.GetLineCount()) |
|---|
| 5879 | self.ctrl.GotoLine(line) |
|---|
| 5880 | line_start_pos = self.ctrl.GetCurrentPos() |
|---|
| 5881 | |
|---|
| 5882 | pos = max(index, 0) |
|---|
| 5883 | pos = min(pos, self.ctrl.GetLineEndPosition(line)-line_start_pos) |
|---|
| 5884 | self.ctrl.GotoPos(line_start_pos+pos) |
|---|
| 5885 | |
|---|
| 5886 | |
|---|
| 5887 | def MoveCaretToLinePos(self, line, index): |
|---|
| 5888 | line = max(line, 0) |
|---|
| 5889 | line = min(line, self.ctrl.GetLineCount()) |
|---|
| 5890 | self.ctrl.GotoLine(line) |
|---|
| 5891 | line_start_pos = self.ctrl.GetCurrentPos() |
|---|
| 5892 | pos = max(index, 0) |
|---|
| 5893 | pos = min(pos, self.ctrl.GetLineEndPosition(line)-line_start_pos) |
|---|
| 5894 | self.ctrl.GotoPos(line_start_pos+pos) |
|---|
| 5895 | |
|---|
| 5896 | def SaveCaretPos(self): |
|---|
| 5897 | page = self.ctrl.presenter.getWikiWord() |
|---|
| 5898 | self.previous_positions[page].append(self.ctrl.GetCurrentPos()) |
|---|
| 5899 | self.future_positions[page] = [] |
|---|
| 5900 | |
|---|
| 5901 | |
|---|
| 5902 | def MoveCaretWordEndCountWhitespace(self, count=None): |
|---|
| 5903 | self.Repeat(self._MoveCaretWord, count, |
|---|
| 5904 | { "recursion" : False, "count_whitespace" : True, \ |
|---|
| 5905 | "only_whitespace" : False }) |
|---|
| 5906 | |
|---|
| 5907 | def MoveCaretNextWord(self, count=None): |
|---|
| 5908 | self.Repeat(self.ctrl.WordRight, count) |
|---|
| 5909 | |
|---|
| 5910 | def MoveCaretWordEnd(self, count=None): |
|---|
| 5911 | self.Repeat(self._MoveCaretWord, count) |
|---|
| 5912 | |
|---|
| 5913 | def _MoveCaretWord(self, recursion=False, count_whitespace=False, |
|---|
| 5914 | only_whitespace=False, reverse=False): |
|---|
| 5915 | """ |
|---|
| 5916 | wxStyledTextCtrl's WordEnd function behaves differently to |
|---|
| 5917 | vims so it need to be replaced to get equivalent function |
|---|
| 5918 | |
|---|
| 5919 | """ |
|---|
| 5920 | pos = start_pos = self.ctrl.GetCurrentPos() |
|---|
| 5921 | char = self.GetUnichrAt(pos) |
|---|
| 5922 | |
|---|
| 5923 | if reverse: |
|---|
| 5924 | offset = -1 |
|---|
| 5925 | move = self.ctrl.CharLeft |
|---|
| 5926 | move_extend = self.ctrl.CharLeftExtend |
|---|
| 5927 | else: |
|---|
| 5928 | offset = 1 |
|---|
| 5929 | move = self.ctrl.CharRight |
|---|
| 5930 | move_extend = self.ctrl.CharRightExtend |
|---|
| 5931 | |
|---|
| 5932 | |
|---|
| 5933 | |
|---|
| 5934 | if char in string.whitespace: |
|---|
| 5935 | char = self.GetUnichrAt(pos + offset) |
|---|
| 5936 | while char in string.whitespace: |
|---|
| 5937 | pos = pos + offset |
|---|
| 5938 | char = self.GetUnichrAt(pos + offset) |
|---|
| 5939 | if not count_whitespace: |
|---|
| 5940 | self._GotoPos(pos) |
|---|
| 5941 | move() |
|---|
| 5942 | self._MoveCaretWord(recursion=True, |
|---|
| 5943 | count_whitespace=count_whitespace, |
|---|
| 5944 | only_whitespace=only_whitespace, |
|---|
| 5945 | reverse=reverse) |
|---|
| 5946 | return |
|---|
| 5947 | |
|---|
| 5948 | |
|---|
| 5949 | elif not only_whitespace and char in self.WORD_BREAK: |
|---|
| 5950 | char = self.GetUnichrAt(pos + offset) |
|---|
| 5951 | while char in self.WORD_BREAK: |
|---|
| 5952 | pos = pos + offset |
|---|
| 5953 | char = self.GetUnichrAt(pos + offset) |
|---|
| 5954 | |
|---|
| 5955 | |
|---|
| 5956 | else: |
|---|
| 5957 | char = self.GetUnichrAt(pos + offset) |
|---|
| 5958 | if char is not None: |
|---|
| 5959 | while ((only_whitespace or char not in self.WORD_BREAK) and \ |
|---|
| 5960 | char not in string.whitespace) or char in ("_"): |
|---|
| 5961 | pos = pos + offset |
|---|
| 5962 | char = self.GetUnichrAt(pos + offset) |
|---|
| 5963 | if char is None: |
|---|
| 5964 | break |
|---|
| 5965 | |
|---|
| 5966 | if pos != start_pos or recursion: |
|---|
| 5967 | self._GotoPos(pos) |
|---|
| 5968 | else: |
|---|
| 5969 | move_extend() |
|---|
| 5970 | self._MoveCaretWord(True, count_whitespace=count_whitespace, |
|---|
| 5971 | only_whitespace=only_whitespace, reverse=reverse) |
|---|
| 5972 | return |
|---|
| 5973 | |
|---|
| 5974 | def MoveCaretToWhitespaceStart(self): |
|---|
| 5975 | start = self.ctrl.GetCurrentPos() |
|---|
| 5976 | while self.ctrl.GetCharAt(start-1) in self.SINGLE_LINE_WHITESPACE: |
|---|
| 5977 | start -= 1 |
|---|
| 5978 | self.ctrl.GotoPos(start) |
|---|
| 5979 | |
|---|
| 5980 | def MoveCaretBackWord(self, count=None): |
|---|
| 5981 | self.Repeat(self._MoveCaretWord, count, { |
|---|
| 5982 | "recursion" : False, |
|---|
| 5983 | "count_whitespace" : False, |
|---|
| 5984 | "only_whitespace" : False, |
|---|
| 5985 | "reverse" : True |
|---|
| 5986 | }) |
|---|
| 5987 | |
|---|
| 5988 | def MoveCaretBackWORD(self, count=None): |
|---|
| 5989 | self.Repeat(self._MoveCaretWord, count, { |
|---|
| 5990 | "recursion" : False, |
|---|
| 5991 | "count_whitespace" : False, |
|---|
| 5992 | "only_whitespace" : True, |
|---|
| 5993 | "reverse" : True |
|---|
| 5994 | }) |
|---|
| 5995 | |
|---|
| 5996 | def MoveCaretNextWORD(self, count=None): |
|---|
| 5997 | """Wordbreaks are spaces""" |
|---|
| 5998 | def func(): |
|---|
| 5999 | self.ctrl.WordRight() |
|---|
| 6000 | while self.GetChar(-1) and not self.GetChar(-1).isspace(): |
|---|
| 6001 | self.ctrl.WordRight() |
|---|
| 6002 | self.Repeat(func, count) |
|---|
| 6003 | |
|---|
| 6004 | def MoveCaretWordEND(self, count=None): |
|---|
| 6005 | self.Repeat(self._MoveCaretWord, count, { |
|---|
| 6006 | "recursion" : False, |
|---|
| 6007 | "count_whitespace" : False, |
|---|
| 6008 | "only_whitespace" : True |
|---|
| 6009 | }) |
|---|
| 6010 | |
|---|
| 6011 | def MoveCaretWordENDCountWhitespace(self, count=None): |
|---|
| 6012 | self.Repeat(self._MoveCaretWord, count, { |
|---|
| 6013 | "recursion" : False, |
|---|
| 6014 | "count_whitespace" : True, |
|---|
| 6015 | "only_whitespace" : True |
|---|
| 6016 | }) |
|---|
| 6017 | |
|---|
| 6018 | def MoveCaretParaUp(self, count=None): |
|---|
| 6019 | self.AddJumpPosition() |
|---|
| 6020 | self.Repeat(self.ctrl.ParaUp, count) |
|---|
| 6021 | |
|---|
| 6022 | def MoveCaretParaDown(self, count=None): |
|---|
| 6023 | self.AddJumpPosition() |
|---|
| 6024 | self.Repeat(self.ctrl.ParaDown, count) |
|---|
| 6025 | |
|---|
| 6026 | def _GotoPos(self, pos): |
|---|
| 6027 | """ |
|---|
| 6028 | Save caret position |
|---|
| 6029 | """ |
|---|
| 6030 | self.ctrl.GotoPos(pos) |
|---|
| 6031 | self.ctrl.ChooseCaretX() |
|---|
| 6032 | |
|---|
| 6033 | def DocumentNavigation(self, key): |
|---|
| 6034 | """ |
|---|
| 6035 | It may be better to seperate this into multiple functions |
|---|
| 6036 | """ |
|---|
| 6037 | if key in [71, (103, 103), 37]: |
|---|
| 6038 | self.AddJumpPosition() |
|---|
| 6039 | |
|---|
| 6040 | |
|---|
| 6041 | if self.true_count: |
|---|
| 6042 | if key in [71, (103, 103)]: |
|---|
| 6043 | |
|---|
| 6044 | self.MoveCaretToLinePos(self.count-1, self.ctrl.GetCurLine()[1]) |
|---|
| 6045 | elif key == 37: |
|---|
| 6046 | max_lines = self.ctrl.GetLineCount() |
|---|
| 6047 | |
|---|
| 6048 | |
|---|
| 6049 | line_percentage = (self.count * max_lines) // 100 |
|---|
| 6050 | self.MoveCaretToLinePos(line_percentage, self.ctrl.GetCurLine()[1]) |
|---|
| 6051 | |
|---|
| 6052 | elif key == 37: |
|---|
| 6053 | |
|---|
| 6054 | self.MatchBraceUnderCaret() |
|---|
| 6055 | |
|---|
| 6056 | elif key == (103, 103): |
|---|
| 6057 | self.ctrl.GotoLine(0) |
|---|
| 6058 | |
|---|
| 6059 | elif key == (71): |
|---|
| 6060 | self.ctrl.GotoLine(self.ctrl.GetLineCount()) |
|---|
| 6061 | |
|---|
| 6062 | def GotoViewportTop(self): |
|---|
| 6063 | self.GotoLineIndent(self.ctrl.GetFirstVisibleLine()) |
|---|
| 6064 | |
|---|
| 6065 | def GotoViewportMiddle(self): |
|---|
| 6066 | self.GotoLineIndent(self.ctrl.GetMiddleVisibleLine()) |
|---|
| 6067 | |
|---|
| 6068 | def GotoViewportBottom(self): |
|---|
| 6069 | self.GotoLineIndent(self.ctrl.GetLastVisibleLine()) |
|---|
| 6070 | |
|---|
| 6071 | def ScrollViewportTop(self): |
|---|
| 6072 | self._PositionViewport(0) |
|---|
| 6073 | |
|---|
| 6074 | def ScrollViewportMiddle(self): |
|---|
| 6075 | self._PositionViewport(0.5) |
|---|
| 6076 | |
|---|
| 6077 | def ScrollViewportBottom(self): |
|---|
| 6078 | self._PositionViewport(1) |
|---|
| 6079 | |
|---|
| 6080 | def Undo(self, count=None): |
|---|
| 6081 | if self.ctrl.CanUndo(): |
|---|
| 6082 | self.visualBell("GREEN") |
|---|
| 6083 | self.Repeat(self.ctrl.Undo, count) |
|---|
| 6084 | else: |
|---|
| 6085 | self.visualBell("RED") |
|---|
| 6086 | |
|---|
| 6087 | def Redo(self, count=None): |
|---|
| 6088 | if self.ctrl.CanRedo(): |
|---|
| 6089 | self.visualBell("GREEN") |
|---|
| 6090 | self.Repeat(self.ctrl.Redo, count) |
|---|
| 6091 | else: |
|---|
| 6092 | self.visualBell("RED") |
|---|
| 6093 | |
|---|
| 6094 | |
|---|
| 6095 | def Insert(self): |
|---|
| 6096 | self.SetMode(ViHelper.INSERT) |
|---|
| 6097 | |
|---|
| 6098 | def Append(self): |
|---|
| 6099 | if self.ctrl.GetCurrentPos() != self.ctrl.GetLineEndPosition(self.ctrl.GetCurrentLine()): |
|---|
| 6100 | self.ctrl.CharRight() |
|---|
| 6101 | self.Insert() |
|---|
| 6102 | |
|---|
| 6103 | def InsertAtLineStart(self): |
|---|
| 6104 | |
|---|
| 6105 | self.GotoLineIndent(self.ctrl.GetCurrentLine()) |
|---|
| 6106 | self.ctrl.ChooseCaretX() |
|---|
| 6107 | self.Insert() |
|---|
| 6108 | |
|---|
| 6109 | def AppendAtLineEnd(self): |
|---|
| 6110 | self.ctrl.GotoPos(self.ctrl.GetLineEndPosition( |
|---|
| 6111 | self.ctrl.GetCurrentLine())) |
|---|
| 6112 | self.Append() |
|---|
| 6113 | |
|---|
| 6114 | def OpenNewLine(self, above, indent=None): |
|---|
| 6115 | self.ctrl.BeginUndoAction() |
|---|
| 6116 | |
|---|
| 6117 | if indent is None: |
|---|
| 6118 | indent = self.ctrl.GetLineIndentation(self.ctrl.GetCurrentLine()) |
|---|
| 6119 | |
|---|
| 6120 | if above: |
|---|
| 6121 | self.MoveCaretUp(1) |
|---|
| 6122 | self.GotoLineEnd() |
|---|
| 6123 | self.ctrl.AddText(self.ctrl.GetEOLChar()) |
|---|
| 6124 | self.ctrl.SetLineIndentation(self.ctrl.GetCurrentLine(), indent) |
|---|
| 6125 | self.ctrl.EndUndoAction() |
|---|
| 6126 | self.AppendAtLineEnd() |
|---|
| 6127 | |
|---|
| 6128 | def TruncateLine(self): |
|---|
| 6129 | self.ctrl.LineEndExtend() |
|---|
| 6130 | self.ctrl.CharLeftExtend() |
|---|
| 6131 | self.DeleteSelection() |
|---|
| 6132 | |
|---|
| 6133 | def TruncateLineAndInsert(self): |
|---|
| 6134 | self.TruncateLine() |
|---|
| 6135 | self.Insert() |
|---|