| 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 | |
|---|
| 1087 | |
|---|
| 1088 | self.Bind(wx.EVT_KEY_DOWN, self.vi.OnViKeyDown) |
|---|
| 1089 | self.Bind(wx.EVT_LEFT_UP, self.vi.OnLeftMouseUp) |
|---|
| 1090 | self.Bind(wx.EVT_SCROLLWIN, self.vi.OnScroll) |
|---|
| 1091 | self.Bind(wx.EVT_MOUSEWHEEL, self.vi.OnMouseScroll) |
|---|
| 1092 | |
|---|
| 1093 | |
|---|
| 1094 | |
|---|
| 1095 | wx.CallAfter(self.vi._enableMenuShortcuts, False) |
|---|
| 1096 | else: |
|---|
| 1097 | if self.vi is not None: |
|---|
| 1098 | self.vi.TurnOff() |
|---|
| 1099 | self.vi = None |
|---|
| 1100 | self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) |
|---|
| 1101 | |
|---|
| 1102 | |
|---|
| 1103 | def onChangedConfiguration(self, miscevt): |
|---|
| 1104 | """ |
|---|
| 1105 | Called when global configuration was changed. Most things are processed |
|---|
| 1106 | by onOptionsChanged so only the online spell checker switch must be |
|---|
| 1107 | handled here. |
|---|
| 1108 | """ |
|---|
| 1109 | restyle = False |
|---|
| 1110 | |
|---|
| 1111 | newSetting = SpellChecker.isSpellCheckSupported() and \ |
|---|
| 1112 | self.presenter.getConfig().getboolean( |
|---|
| 1113 | "main", "editor_onlineSpellChecker_active", False) |
|---|
| 1114 | |
|---|
| 1115 | if newSetting != self.onlineSpellCheckerActive: |
|---|
| 1116 | self.onlineSpellCheckerActive = newSetting |
|---|
| 1117 | restyle = True |
|---|
| 1118 | |
|---|
| 1119 | newSetting = self.presenter.getConfig()\ |
|---|
| 1120 | .getboolean("main", "editor_colorizeSearchFragments", False) |
|---|
| 1121 | |
|---|
| 1122 | if newSetting != self.optionColorizeSearchFragments: |
|---|
| 1123 | self.optionColorizeSearchFragments = newSetting |
|---|
| 1124 | restyle = True |
|---|
| 1125 | |
|---|
| 1126 | if restyle: |
|---|
| 1127 | self.OnStyleNeeded(None) |
|---|
| 1128 | |
|---|
| 1129 | |
|---|
| 1130 | |
|---|
| 1131 | def onWikiPageUpdated(self, miscevt): |
|---|
| 1132 | if self.getLoadedDocPage() is None or \ |
|---|
| 1133 | not isinstance(self.getLoadedDocPage(), |
|---|
| 1134 | (DocPages.WikiPage, DocPages.AliasWikiPage)): |
|---|
| 1135 | return |
|---|
| 1136 | |
|---|
| 1137 | |
|---|
| 1138 | font = self.getLoadedDocPage().getAttributeOrGlobal("font", |
|---|
| 1139 | self.defaultFont) |
|---|
| 1140 | |
|---|
| 1141 | |
|---|
| 1142 | if self.lastFont != font: |
|---|
| 1143 | faces = self.presenter.getDefaultFontFaces().copy() |
|---|
| 1144 | faces["mono"] = font |
|---|
| 1145 | self.SetStyles(faces) |
|---|
| 1146 | self.lastEditorFont = font |
|---|
| 1147 | |
|---|
| 1148 | self.pageType = self.getLoadedDocPage().getAttributes().get(u"pagetype", |
|---|
| 1149 | [u"normal"])[-1] |
|---|
| 1150 | |
|---|
| 1151 | |
|---|
| 1152 | def handleInvalidFileSignature(self, docPage): |
|---|
| 1153 | """ |
|---|
| 1154 | Called directly from a doc page to repair the editor state if an |
|---|
| 1155 | invalid file signature was detected. |
|---|
| 1156 | |
|---|
| 1157 | docPage -- calling docpage |
|---|
| 1158 | """ |
|---|
| 1159 | if docPage is not self.getLoadedDocPage() or \ |
|---|
| 1160 | not isinstance(docPage, |
|---|
| 1161 | (DocPages.DataCarryingPage, DocPages.AliasWikiPage)): |
|---|
| 1162 | return |
|---|
| 1163 | |
|---|
| 1164 | sd, ud = docPage.getDirty() |
|---|
| 1165 | if sd: |
|---|
| 1166 | return |
|---|
| 1167 | |
|---|
| 1168 | content = docPage.getContent() |
|---|
| 1169 | docPage.setEditorText(content, dirty=False) |
|---|
| 1170 | self.ignoreOnChange = True |
|---|
| 1171 | |
|---|
| 1172 | self.setTextAgaUpdated(content) |
|---|
| 1173 | self.ignoreOnChange = False |
|---|
| 1174 | |
|---|
| 1175 | |
|---|
| 1176 | def onSavingAllPages(self, miscevt): |
|---|
| 1177 | if self.getLoadedDocPage() is not None and ( |
|---|
| 1178 | self.getLoadedDocPage().getDirty()[0] or miscevt.get("force", |
|---|
| 1179 | False)): |
|---|
| 1180 | self.saveLoadedDocPage() |
|---|
| 1181 | |
|---|
| 1182 | def onClosingCurrentWiki(self, miscevt): |
|---|
| 1183 | self.unloadCurrentDocPage() |
|---|
| 1184 | |
|---|
| 1185 | def onDroppingCurrentWiki(self, miscevt): |
|---|
| 1186 | """ |
|---|
| 1187 | An access error occurred. Get rid of any data without trying to save |
|---|
| 1188 | it. |
|---|
| 1189 | """ |
|---|
| 1190 | if self.getLoadedDocPage() is not None: |
|---|
| 1191 | self.wikiPageSink.disconnect() |
|---|
| 1192 | |
|---|
| 1193 | self.SetDocPointer(None) |
|---|
| 1194 | self.applyBasicSciSettings() |
|---|
| 1195 | |
|---|
| 1196 | self.getLoadedDocPage().removeTxtEditor(self) |
|---|
| 1197 | self.presenter.setDocPage(None) |
|---|
| 1198 | |
|---|
| 1199 | self.pageType = "normal" |
|---|
| 1200 | |
|---|
| 1201 | |
|---|
| 1202 | def OnStyleNeeded(self, evt): |
|---|
| 1203 | "Styles the text of the editor" |
|---|
| 1204 | docPage = self.getLoadedDocPage() |
|---|
| 1205 | if docPage is None: |
|---|
| 1206 | |
|---|
| 1207 | self.stopStcStyler() |
|---|
| 1208 | return |
|---|
| 1209 | |
|---|
| 1210 | |
|---|
| 1211 | |
|---|
| 1212 | text = docPage.getLiveText() |
|---|
| 1213 | textlen = len(text) |
|---|
| 1214 | |
|---|
| 1215 | t = self.stylingThreadHolder.getThread() |
|---|
| 1216 | if t is not None: |
|---|
| 1217 | self.stylingThreadHolder.setThread(None) |
|---|
| 1218 | self.clearStylingCache() |
|---|
| 1219 | |
|---|
| 1220 | |
|---|
| 1221 | if textlen < self.presenter.getConfig().getint( |
|---|
| 1222 | "main", "sync_highlight_byte_limit"): |
|---|
| 1223 | |
|---|
| 1224 | |
|---|
| 1225 | self.stylingThreadHolder.setThread(None) |
|---|
| 1226 | self.buildStyling(text, 0, threadstop=DUMBTHREADSTOP) |
|---|
| 1227 | |
|---|
| 1228 | self.applyStyling(self.stylebytes) |
|---|
| 1229 | |
|---|
| 1230 | |
|---|
| 1231 | |
|---|
| 1232 | |
|---|
| 1233 | if self.getFoldingActive(): |
|---|
| 1234 | self.storeStylingAndAst(None, self.foldingseq) |
|---|
| 1235 | else: |
|---|
| 1236 | |
|---|
| 1237 | |
|---|
| 1238 | self.stopStcStyler() |
|---|
| 1239 | |
|---|
| 1240 | sth = self.stylingThreadHolder |
|---|
| 1241 | |
|---|
| 1242 | delay = self.presenter.getConfig().getfloat( |
|---|
| 1243 | "main", "async_highlight_delay") |
|---|
| 1244 | t = threading.Thread(None, self.buildStyling, args = (text, delay, sth)) |
|---|
| 1245 | sth.setThread(t) |
|---|
| 1246 | t.setDaemon(True) |
|---|
| 1247 | t.start() |
|---|
| 1248 | |
|---|
| 1249 | |
|---|
| 1250 | def _fillTemplateMenu(self, menu): |
|---|
| 1251 | idRecycler = self.templateIdRecycler |
|---|
| 1252 | idRecycler.clearAssoc() |
|---|
| 1253 | |
|---|
| 1254 | config = self.presenter.getConfig() |
|---|
| 1255 | |
|---|
| 1256 | templateRePat = config.get(u"main", u"template_pageNamesRE", |
|---|
| 1257 | u"^template/") |
|---|
| 1258 | |
|---|
| 1259 | try: |
|---|
| 1260 | templateRe = re.compile(templateRePat, re.DOTALL | re.UNICODE) |
|---|
| 1261 | except re.error: |
|---|
| 1262 | templateRe = re.compile(u"^template/", re.DOTALL | re.UNICODE) |
|---|
| 1263 | |
|---|
| 1264 | wikiDocument = self.presenter.getWikiDocument() |
|---|
| 1265 | templateNames = [n for n in wikiDocument.getAllDefinedWikiPageNames() |
|---|
| 1266 | if templateRe.search(n)] |
|---|
| 1267 | |
|---|
| 1268 | wikiDocument.getCollator().sort(templateNames) |
|---|
| 1269 | |
|---|
| 1270 | for tn in templateNames: |
|---|
| 1271 | menuID, reused = idRecycler.assocGetIdAndReused(tn) |
|---|
| 1272 | |
|---|
| 1273 | if not reused: |
|---|
| 1274 | |
|---|
| 1275 | wx.EVT_MENU(self, menuID, self.OnTemplateUsed) |
|---|
| 1276 | |
|---|
| 1277 | menu.Append(menuID, StringOps.uniToGui(tn)) |
|---|
| 1278 | |
|---|
| 1279 | |
|---|
| 1280 | def OnTemplateUsed(self, evt): |
|---|
| 1281 | docPage = self.getLoadedDocPage() |
|---|
| 1282 | if docPage is None: |
|---|
| 1283 | return |
|---|
| 1284 | templateName = self.templateIdRecycler.get(evt.GetId()) |
|---|
| 1285 | |
|---|
| 1286 | if templateName is None: |
|---|
| 1287 | return |
|---|
| 1288 | |
|---|
| 1289 | wikiDocument = self.presenter.getWikiDocument() |
|---|
| 1290 | templatePage = wikiDocument.getWikiPage(templateName) |
|---|
| 1291 | |
|---|
| 1292 | content = self.getLoadedDocPage().getContentOfTemplate(templatePage, |
|---|
| 1293 | templatePage) |
|---|
| 1294 | docPage.setMetaDataFromTemplate(templatePage) |
|---|
| 1295 | |
|---|
| 1296 | self.SetText(content, emptyUndo=False) |
|---|
| 1297 | self.pageType = docPage.getAttributes().get(u"pagetype", |
|---|
| 1298 | [u"normal"])[-1] |
|---|
| 1299 | self.handleSpecialPageType() |
|---|
| 1300 | |
|---|
| 1301 | self.presenter.informEditorTextChanged(self) |
|---|
| 1302 | |
|---|
| 1303 | |
|---|
| 1304 | def OnSelectTemplate(self, evt): |
|---|
| 1305 | docPage = self.getLoadedDocPage() |
|---|
| 1306 | if docPage is None: |
|---|
| 1307 | return |
|---|
| 1308 | |
|---|
| 1309 | if not isinstance(docPage, DocPages.WikiPage): |
|---|
| 1310 | return |
|---|
| 1311 | |
|---|
| 1312 | if not docPage.isDefined() and not docPage.getDirty()[0]: |
|---|
| 1313 | title = _(u"Select Template") |
|---|
| 1314 | else: |
|---|
| 1315 | title = _(u"Select Template (deletes current content!)") |
|---|
| 1316 | |
|---|
| 1317 | templateName = AdditionalDialogs.SelectWikiWordDialog.runModal( |
|---|
| 1318 | self.presenter.getMainControl(), self, -1, |
|---|
| 1319 | title=title) |
|---|
| 1320 | if templateName is None: |
|---|
| 1321 | return |
|---|
| 1322 | |
|---|
| 1323 | wikiDocument = self.presenter.getWikiDocument() |
|---|
| 1324 | templatePage = wikiDocument.getWikiPage(templateName) |
|---|
| 1325 | |
|---|
| 1326 | content = self.getLoadedDocPage().getContentOfTemplate(templatePage, |
|---|
| 1327 | templatePage) |
|---|
| 1328 | docPage.setMetaDataFromTemplate(templatePage) |
|---|
| 1329 | |
|---|
| 1330 | self.SetText(content, emptyUndo=False) |
|---|
| 1331 | self.pageType = docPage.getAttributes().get(u"pagetype", |
|---|
| 1332 | [u"normal"])[-1] |
|---|
| 1333 | self.handleSpecialPageType() |
|---|
| 1334 | self.presenter.informEditorTextChanged(self) |
|---|
| 1335 | |
|---|
| 1336 | |
|---|
| 1337 | |
|---|
| 1338 | def OnContextMenu(self, evt): |
|---|
| 1339 | mousePos = self.ScreenToClient(wx.GetMousePosition()) |
|---|
| 1340 | |
|---|
| 1341 | leftFold = 0 |
|---|
| 1342 | for i in range(self.FOLD_MARGIN): |
|---|
| 1343 | leftFold += self.GetMarginWidth(i) |
|---|
| 1344 | |
|---|
| 1345 | rightFold = leftFold + self.GetMarginWidth(self.FOLD_MARGIN) |
|---|
| 1346 | |
|---|
| 1347 | menu = wx.Menu() |
|---|
| 1348 | |
|---|
| 1349 | if mousePos.x >= leftFold and mousePos.x < rightFold: |
|---|
| 1350 | |
|---|
| 1351 | |
|---|
| 1352 | appendToMenuByMenuDesc(menu, FOLD_MENU) |
|---|
| 1353 | else: |
|---|
| 1354 | |
|---|
| 1355 | nodes = self.getTokensForMousePos(mousePos) |
|---|
| 1356 | |
|---|
| 1357 | self.contextMenuTokens = nodes |
|---|
| 1358 | addActivateItem = False |
|---|
| 1359 | addFileUrlItem = False |
|---|
| 1360 | addWikiUrlItem = False |
|---|
| 1361 | addUrlToClipboardItem = False |
|---|
| 1362 | unknownWord = None |
|---|
| 1363 | for node in nodes: |
|---|
| 1364 | if node.name == "wikiWord": |
|---|
| 1365 | addActivateItem = True |
|---|
| 1366 | elif node.name == "urlLink": |
|---|
| 1367 | addActivateItem = True |
|---|
| 1368 | if node.url.startswith(u"file:") or \ |
|---|
| 1369 | node.url.startswith(u"rel://"): |
|---|
| 1370 | addFileUrlItem = True |
|---|
| 1371 | elif node.url.startswith(u"wiki:") or \ |
|---|
| 1372 | node.url.startswith(u"wikirel://"): |
|---|
| 1373 | addWikiUrlItem = True |
|---|
| 1374 | elif node.name == "insertion" and node.key == u"page": |
|---|
| 1375 | addActivateItem = True |
|---|
| 1376 | elif node.name == "anchorDef": |
|---|
| 1377 | addUrlToClipboardItem = True |
|---|
| 1378 | elif node.name == "unknownSpelling": |
|---|
| 1379 | unknownWord = node.getText() |
|---|
| 1380 | |
|---|
| 1381 | if unknownWord: |
|---|
| 1382 | |
|---|
| 1383 | spellCheckerSession = self.presenter.getWikiDocument()\ |
|---|
| 1384 | .createOnlineSpellCheckerSessionClone() |
|---|
| 1385 | spellCheckerSession.setCurrentDocPage(self.getLoadedDocPage()) |
|---|
| 1386 | if spellCheckerSession: |
|---|
| 1387 | |
|---|
| 1388 | suggestions = spellCheckerSession.suggest(unknownWord)[:5] |
|---|
| 1389 | spellCheckerSession.close() |
|---|
| 1390 | |
|---|
| 1391 | if len(suggestions) > 0: |
|---|
| 1392 | for s, mid in zip(suggestions, self.SUGGESTION_CMD_IDS): |
|---|
| 1393 | menuitem = wx.MenuItem(menu, mid, s) |
|---|
| 1394 | font = menuitem.GetFont() |
|---|
| 1395 | font.SetWeight(wx.FONTWEIGHT_BOLD) |
|---|
| 1396 | menuitem.SetFont(font) |
|---|
| 1397 | |
|---|
| 1398 | menu.AppendItem(menuitem) |
|---|
| 1399 | |
|---|
| 1400 | self.contextMenuSpellCheckSuggestions = suggestions |
|---|
| 1401 | |
|---|
| 1402 | appendToMenuByMenuDesc(menu, _CONTEXT_MENU_INTEXT_SPELLING) |
|---|
| 1403 | |
|---|
| 1404 | |
|---|
| 1405 | appendToMenuByMenuDesc(menu, _CONTEXT_MENU_INTEXT_BASE) |
|---|
| 1406 | |
|---|
| 1407 | if addActivateItem: |
|---|
| 1408 | appendToMenuByMenuDesc(menu, _CONTEXT_MENU_INTEXT_ACTIVATE) |
|---|
| 1409 | |
|---|
| 1410 | if addFileUrlItem: |
|---|
| 1411 | appendToMenuByMenuDesc(menu, _CONTEXT_MENU_INTEXT_FILE_URL) |
|---|
| 1412 | elif addWikiUrlItem: |
|---|
| 1413 | appendToMenuByMenuDesc(menu, _CONTEXT_MENU_INTEXT_WIKI_URL) |
|---|
| 1414 | |
|---|
| 1415 | if addUrlToClipboardItem: |
|---|
| 1416 | appendToMenuByMenuDesc(menu, |
|---|
| 1417 | _CONTEXT_MENU_INTEXT_URL_TO_CLIPBOARD) |
|---|
| 1418 | |
|---|
| 1419 | docPage = self.getLoadedDocPage() |
|---|
| 1420 | if isinstance(docPage, DocPages.WikiPage): |
|---|
| 1421 | if not docPage.isDefined() and not docPage.getDirty()[0]: |
|---|
| 1422 | templateSubmenu = wx.Menu() |
|---|
| 1423 | self._fillTemplateMenu(templateSubmenu) |
|---|
| 1424 | appendToMenuByMenuDesc(templateSubmenu, |
|---|
| 1425 | _CONTEXT_MENU_SELECT_TEMPLATE_IN_TEMPLATE_MENU) |
|---|
| 1426 | |
|---|
| 1427 | menu.AppendSeparator() |
|---|
| 1428 | menu.AppendMenu(wx.NewId(), _(u'Use Template'), |
|---|
| 1429 | templateSubmenu) |
|---|
| 1430 | else: |
|---|
| 1431 | appendToMenuByMenuDesc(menu, |
|---|
| 1432 | _CONTEXT_MENU_SELECT_TEMPLATE) |
|---|
| 1433 | |
|---|
| 1434 | appendToMenuByMenuDesc(menu, _CONTEXT_MENU_INTEXT_BOTTOM) |
|---|
| 1435 | |
|---|
| 1436 | |
|---|
| 1437 | item = menu.FindItemById(GUI_ID.CMD_UNDO) |
|---|
| 1438 | if item: item.Enable(self.CanUndo()) |
|---|
| 1439 | item = menu.FindItemById(GUI_ID.CMD_REDO) |
|---|
| 1440 | if item: item.Enable(self.CanRedo()) |
|---|
| 1441 | |
|---|
| 1442 | cancopy = self.GetSelectionStart() != self.GetSelectionEnd() |
|---|
| 1443 | |
|---|
| 1444 | item = menu.FindItemById(GUI_ID.CMD_TEXT_DELETE) |
|---|
| 1445 | if item: item.Enable(cancopy and not self.GetReadOnly()) |
|---|
| 1446 | item = menu.FindItemById(GUI_ID.CMD_CLIPBOARD_CUT) |
|---|
| 1447 | if item: item.Enable(cancopy and not self.GetReadOnly()) |
|---|
| 1448 | item = menu.FindItemById(GUI_ID.CMD_CLIPBOARD_COPY) |
|---|
| 1449 | if item: item.Enable(cancopy) |
|---|
| 1450 | item = menu.FindItemById(GUI_ID.CMD_CLIPBOARD_PASTE) |
|---|
| 1451 | if item: item.Enable(self.CanPaste()) |
|---|
| 1452 | |
|---|
| 1453 | |
|---|
| 1454 | with self.dwellLock(): |
|---|
| 1455 | |
|---|
| 1456 | self.PopupMenu(menu) |
|---|
| 1457 | |
|---|
| 1458 | self.contextMenuTokens = None |
|---|
| 1459 | self.contextMenuSpellCheckSuggestions = None |
|---|
| 1460 | menu.Destroy() |
|---|
| 1461 | |
|---|
| 1462 | |
|---|
| 1463 | def _goToNextFormField(self): |
|---|
| 1464 | """ |
|---|
| 1465 | If pagetype is "form" this is called when user presses TAB in |
|---|
| 1466 | text editor and after loading a form page |
|---|
| 1467 | """ |
|---|
| 1468 | searchOp = SearchReplaceOperation() |
|---|
| 1469 | searchOp.wikiWide = False |
|---|
| 1470 | searchOp.wildCard = 'regex' |
|---|
| 1471 | searchOp.caseSensitive = True |
|---|
| 1472 | searchOp.searchStr = "&&[a-zA-Z]" |
|---|
| 1473 | |
|---|
| 1474 | text = self.GetText() |
|---|
| 1475 | charStartPos = len(self.GetTextRange(0, self.GetSelectionEnd())) |
|---|
| 1476 | while True: |
|---|
| 1477 | start, end = searchOp.searchText(text, charStartPos)[:2] |
|---|
| 1478 | if start is None: |
|---|
| 1479 | return False |
|---|
| 1480 | |
|---|
| 1481 | fieldcode = text[start + 2] |
|---|
| 1482 | if fieldcode == "i": |
|---|
| 1483 | self.showSelectionByCharPos(start, end) |
|---|
| 1484 | return True |
|---|
| 1485 | |
|---|
| 1486 | charStartPos = end |
|---|
| 1487 | |
|---|
| 1488 | |
|---|
| 1489 | def handleDropText(self, x, y, text): |
|---|
| 1490 | if x != -1: |
|---|
| 1491 | |
|---|
| 1492 | self.DoDropText(x, y, text) |
|---|
| 1493 | self.gotoCharPos(self.GetSelectionCharPos()[1], scroll=False) |
|---|
| 1494 | else: |
|---|
| 1495 | self.ReplaceSelection(text) |
|---|
| 1496 | |
|---|
| 1497 | self.SetFocus() |
|---|
| 1498 | |
|---|
| 1499 | |
|---|
| 1500 | def clearStylingCache(self): |
|---|
| 1501 | self.stylebytes = None |
|---|
| 1502 | self.foldingseq = None |
|---|
| 1503 | |
|---|
| 1504 | |
|---|
| 1505 | |
|---|
| 1506 | def stopStcStyler(self): |
|---|
| 1507 | """ |
|---|
| 1508 | Stops further styling requests from Scintilla until text is modified |
|---|
| 1509 | """ |
|---|
| 1510 | self.StartStyling(self.GetLength(), 0xff) |
|---|
| 1511 | self.SetStyling(0, 0) |
|---|
| 1512 | |
|---|
| 1513 | |
|---|
| 1514 | |
|---|
| 1515 | def storeStylingAndAst(self, stylebytes, foldingseq, styleMask=0xff): |
|---|
| 1516 | self.stylebytes = stylebytes |
|---|
| 1517 | |
|---|
| 1518 | self.foldingseq = foldingseq |
|---|
| 1519 | |
|---|
| 1520 | def putStyle(): |
|---|
| 1521 | if stylebytes: |
|---|
| 1522 | self.applyStyling(stylebytes, styleMask) |
|---|
| 1523 | |
|---|
| 1524 | if foldingseq: |
|---|
| 1525 | self.applyFolding(foldingseq) |
|---|
| 1526 | |
|---|
| 1527 | wx.CallAfter(putStyle) |
|---|
| 1528 | |
|---|
| 1529 | |
|---|
| 1530 | |
|---|
| 1531 | |
|---|
| 1532 | |
|---|
| 1533 | def buildStyling(self, text, delay, threadstop=DUMBTHREADSTOP): |
|---|
| 1534 | try: |
|---|
| 1535 | if delay != 0 and not threadstop is DUMBTHREADSTOP: |
|---|
| 1536 | sleep(delay) |
|---|
| 1537 | threadstop.testRunning() |
|---|
| 1538 | |
|---|
| 1539 | docPage = self.getLoadedDocPage() |
|---|
| 1540 | if docPage is None: |
|---|
| 1541 | return |
|---|
| 1542 | |
|---|
| 1543 | for i in range(20): |
|---|
| 1544 | formatDetails = docPage.getFormatDetails() |
|---|
| 1545 | pageAst = docPage.getLivePageAst(threadstop=threadstop) |
|---|
| 1546 | threadstop.testRunning() |
|---|
| 1547 | if not formatDetails.isEquivTo(docPage.getFormatDetails()): |
|---|
| 1548 | continue |
|---|
| 1549 | else: |
|---|
| 1550 | break |
|---|
| 1551 | |
|---|
| 1552 | stylebytes = self.processTokens(text, pageAst, threadstop) |
|---|
| 1553 | |
|---|
| 1554 | threadstop.testRunning() |
|---|
| 1555 | |
|---|
| 1556 | if self.getFoldingActive(): |
|---|
| 1557 | foldingseq = self.processFolding(pageAst, threadstop) |
|---|
| 1558 | else: |
|---|
| 1559 | foldingseq = None |
|---|
| 1560 | |
|---|
| 1561 | threadstop.testRunning() |
|---|
| 1562 | |
|---|
| 1563 | if self.onlineSpellCheckerActive and \ |
|---|
| 1564 | isinstance(docPage, DocPages.AbstractWikiPage): |
|---|
| 1565 | |
|---|
| 1566 | |
|---|
| 1567 | |
|---|
| 1568 | if not threadstop is DUMBTHREADSTOP: |
|---|
| 1569 | self.storeStylingAndAst(stylebytes, foldingseq, styleMask=0x1f) |
|---|
| 1570 | |
|---|
| 1571 | scTokens = docPage.getSpellCheckerUnknownWords(threadstop=threadstop) |
|---|
| 1572 | |
|---|
| 1573 | threadstop.testRunning() |
|---|
| 1574 | |
|---|
| 1575 | if scTokens.getChildrenCount() > 0: |
|---|
| 1576 | spellStyleBytes = self.processSpellCheckTokens(text, scTokens, |
|---|
| 1577 | threadstop) |
|---|
| 1578 | |
|---|
| 1579 | threadstop.testRunning() |
|---|
| 1580 | |
|---|
| 1581 | |
|---|
| 1582 | stylebytes = "".join([chr(ord(a) | ord(b)) |
|---|
| 1583 | for a, b in itertools.izip(stylebytes, spellStyleBytes)]) |
|---|
| 1584 | |
|---|
| 1585 | self.storeStylingAndAst(stylebytes, None, styleMask=0xff) |
|---|
| 1586 | else: |
|---|
| 1587 | self.storeStylingAndAst(stylebytes, None, styleMask=0xff) |
|---|
| 1588 | else: |
|---|
| 1589 | self.storeStylingAndAst(stylebytes, foldingseq, styleMask=0xff) |
|---|
| 1590 | |
|---|
| 1591 | except NotCurrentThreadException: |
|---|
| 1592 | return |
|---|
| 1593 | |
|---|
| 1594 | |
|---|
| 1595 | |
|---|
| 1596 | _TOKEN_TO_STYLENO = { |
|---|
| 1597 | "bold": FormatTypes.Bold, |
|---|
| 1598 | "italics": FormatTypes.Italic, |
|---|
| 1599 | "urlLink": FormatTypes.Url, |
|---|
| 1600 | "script": FormatTypes.Script, |
|---|
| 1601 | "property": FormatTypes.Attribute, |
|---|
| 1602 | "attribute": FormatTypes.Attribute, |
|---|
| 1603 | "insertion": FormatTypes.Script, |
|---|
| 1604 | "anchorDef": FormatTypes.Bold, |
|---|
| 1605 | "plainText": FormatTypes.Default |
|---|
| 1606 | } |
|---|
| 1607 | |
|---|
| 1608 | |
|---|
| 1609 | def _findFragmentSearch(self, linkNode): |
|---|
| 1610 | """ |
|---|
| 1611 | linkNode -- AST node of type "wikiWord" |
|---|
| 1612 | returns |
|---|
| 1613 | (<first char pos>, <after last char pos>) of targeted search |
|---|
| 1614 | fragment if present |
|---|
| 1615 | (None, None) if not present |
|---|
| 1616 | (-1, -1) if search is not applicable |
|---|
| 1617 | """ |
|---|
| 1618 | unaliasedTarget = self.presenter.getWikiDocument()\ |
|---|
| 1619 | .getWikiPageNameForLinkTermOrAsIs(linkNode.wikiWord) |
|---|
| 1620 | |
|---|
| 1621 | docPage = self.getLoadedDocPage() |
|---|
| 1622 | if docPage is None: |
|---|
| 1623 | return (-1, -1) |
|---|
| 1624 | |
|---|
| 1625 | wikiWord = docPage.getWikiWord() |
|---|
| 1626 | if wikiWord is None: |
|---|
| 1627 | return (-1, -1) |
|---|
| 1628 | |
|---|
| 1629 | if wikiWord == unaliasedTarget: |
|---|
| 1630 | forbiddenSearchfragHit = (linkNode.pos, |
|---|
| 1631 | linkNode.pos + linkNode.strLength) |
|---|
| 1632 | else: |
|---|
| 1633 | forbiddenSearchfragHit = (0, 0) |
|---|
| 1634 | |
|---|
| 1635 | searchfrag = linkNode.searchFragment |
|---|
| 1636 | if searchfrag is None: |
|---|
| 1637 | return (-1, -1) |
|---|
| 1638 | |
|---|
| 1639 | searchOp = SearchReplaceOperation() |
|---|
| 1640 | searchOp.wildCard = "no" |
|---|
| 1641 | searchOp.searchStr = searchfrag |
|---|
| 1642 | |
|---|
| 1643 | targetPage = self.presenter.getWikiDocument().getWikiPage( |
|---|
| 1644 | linkNode.wikiWord) |
|---|
| 1645 | |
|---|
| 1646 | found = searchOp.searchDocPageAndText(targetPage, |
|---|
| 1647 | targetPage.getLiveText(), 0) |
|---|
| 1648 | |
|---|
| 1649 | if found[0] >= forbiddenSearchfragHit[0] and \ |
|---|
| 1650 | found[0] < forbiddenSearchfragHit[1]: |
|---|
| 1651 | |
|---|
| 1652 | found = searchOp.searchDocPageAndText(targetPage, |
|---|
| 1653 | targetPage.getLiveText(), forbiddenSearchfragHit[1]) |
|---|
| 1654 | |
|---|
| 1655 | return found |
|---|
| 1656 | |
|---|
| 1657 | |
|---|
| 1658 | |
|---|
| 1659 | def processTokens(self, text, pageAst, threadstop): |
|---|
| 1660 | wikiDoc = self.presenter.getWikiDocument() |
|---|
| 1661 | stylebytes = StyleCollector(FormatTypes.Default, |
|---|
| 1662 | text, self.bytelenSct) |
|---|
| 1663 | |
|---|
| 1664 | def process(pageAst, stack): |
|---|
| 1665 | for node in pageAst.iterFlatNamed(): |
|---|
| 1666 | threadstop.testRunning() |
|---|
| 1667 | |
|---|
| 1668 | styleNo = WikiTxtCtrl._TOKEN_TO_STYLENO.get(node.name) |
|---|
| 1669 | |
|---|
| 1670 | if styleNo is not None: |
|---|
| 1671 | stylebytes.bindStyle(node.pos, node.strLength, styleNo) |
|---|
| 1672 | elif node.name == "wikiWord": |
|---|
| 1673 | if wikiDoc.isCreatableWikiWord(node.wikiWord): |
|---|
| 1674 | styleNo = FormatTypes.WikiWord |
|---|
| 1675 | else: |
|---|
| 1676 | styleNo = FormatTypes.AvailWikiWord |
|---|
| 1677 | if self.optionColorizeSearchFragments and \ |
|---|
| 1678 | node.searchFragment: |
|---|
| 1679 | if self._findFragmentSearch(node)[0] == None: |
|---|
| 1680 | |
|---|
| 1681 | searchFragNode = node.fragmentNode |
|---|
| 1682 | |
|---|
| 1683 | stylebytes.bindStyle(node.pos, |
|---|
| 1684 | searchFragNode.pos - node.pos, |
|---|
| 1685 | FormatTypes.AvailWikiWord) |
|---|
| 1686 | |
|---|
| 1687 | stylebytes.bindStyle(searchFragNode.pos, |
|---|
| 1688 | searchFragNode.strLength, |
|---|
| 1689 | FormatTypes.WikiWord) |
|---|
| 1690 | |
|---|
| 1691 | stylebytes.bindStyle(searchFragNode.pos + |
|---|
| 1692 | searchFragNode.strLength, |
|---|
| 1693 | node.strLength - |
|---|
| 1694 | (searchFragNode.pos - node.pos) - |
|---|
| 1695 | searchFragNode.strLength, |
|---|
| 1696 | FormatTypes.AvailWikiWord) |
|---|
| 1697 | continue |
|---|
| 1698 | |
|---|
| 1699 | stylebytes.bindStyle(node.pos, node.strLength, styleNo) |
|---|
| 1700 | |
|---|
| 1701 | elif node.name == "todoEntry": |
|---|
| 1702 | process(node, stack + ["todoEntry"]) |
|---|
| 1703 | elif node.name == "key" and "todoEntry" in stack: |
|---|
| 1704 | stylebytes.bindStyle(node.pos, node.strLength, |
|---|
| 1705 | FormatTypes.ToDo) |
|---|
| 1706 | elif node.name == "value" and "todoEntry" in stack: |
|---|
| 1707 | process(node, stack[:]) |
|---|
| 1708 | |
|---|
| 1709 | elif node.name == "heading": |
|---|
| 1710 | if node.level < 5: |
|---|
| 1711 | styleNo = FormatTypes.Heading1 + \ |
|---|
| 1712 | (node.level - 1) |
|---|
| 1713 | else: |
|---|
| 1714 | styleNo = FormatTypes.Bold |
|---|
| 1715 | |
|---|
| 1716 | stylebytes.bindStyle(node.pos, node.strLength, styleNo) |
|---|
| 1717 | |
|---|
| 1718 | elif node.name in ("table", "tableRow", "tableCell", |
|---|
| 1719 | "orderedList", "unorderedList", "indentedText", |
|---|
| 1720 | "noExport"): |
|---|
| 1721 | process(node, stack[:]) |
|---|
| 1722 | |
|---|
| 1723 | process(pageAst, []) |
|---|
| 1724 | return stylebytes.value() |
|---|
| 1725 | |
|---|
| 1726 | |
|---|
| 1727 | def processSpellCheckTokens(self, text, scTokens, threadstop): |
|---|
| 1728 | stylebytes = StyleCollector(0, text, self.bytelenSct) |
|---|
| 1729 | for node in scTokens: |
|---|
| 1730 | threadstop.testRunning() |
|---|
| 1731 | stylebytes.bindStyle(node.pos, node.strLength, |
|---|
| 1732 | wx.stc.STC_INDIC2_MASK) |
|---|
| 1733 | |
|---|
| 1734 | return stylebytes.value() |
|---|
| 1735 | |
|---|
| 1736 | |
|---|
| 1737 | def processFolding(self, pageAst, threadstop): |
|---|
| 1738 | foldingseq = [] |
|---|
| 1739 | currLine = 0 |
|---|
| 1740 | prevLevel = 0 |
|---|
| 1741 | levelStack = [] |
|---|
| 1742 | foldHeader = False |
|---|
| 1743 | |
|---|
| 1744 | for node in pageAst: |
|---|
| 1745 | threadstop.testRunning() |
|---|
| 1746 | |
|---|
| 1747 | if node.name == "heading": |
|---|
| 1748 | while levelStack and (levelStack[-1][0] != "heading" or |
|---|
| 1749 | levelStack[-1][1] > node.level): |
|---|
| 1750 | del levelStack[-1] |
|---|
| 1751 | if not levelStack or levelStack[-1] != ("heading", node.level): |
|---|
| 1752 | levelStack.append(("heading", node.level)) |
|---|
| 1753 | foldHeader = True |
|---|
| 1754 | |
|---|
| 1755 | lfc = node.getString().count(u"\n") |
|---|
| 1756 | if len(levelStack) > prevLevel: |
|---|
| 1757 | foldHeader = True |
|---|
| 1758 | |
|---|
| 1759 | if foldHeader and lfc > 0: |
|---|
| 1760 | foldingseq.append(len(levelStack) | wx.stc.STC_FOLDLEVELHEADERFLAG) |
|---|
| 1761 | foldHeader = False |
|---|
| 1762 | lfc -= 1 |
|---|
| 1763 | |
|---|
| 1764 | if lfc > 0: |
|---|
| 1765 | foldingseq += [len(levelStack) + 1] * lfc |
|---|
| 1766 | |
|---|
| 1767 | prevLevel = len(levelStack) + 1 |
|---|
| 1768 | |
|---|
| 1769 | |
|---|
| 1770 | foldingseq.append(len(levelStack) + 1) |
|---|
| 1771 | |
|---|
| 1772 | return foldingseq |
|---|
| 1773 | |
|---|
| 1774 | |
|---|
| 1775 | def applyStyling(self, stylebytes, styleMask=0xff): |
|---|
| 1776 | if len(stylebytes) == self.GetLength(): |
|---|
| 1777 | self.StartStyling(0, styleMask) |
|---|
| 1778 | self.SetStyleBytes(len(stylebytes), stylebytes) |
|---|
| 1779 | |
|---|
| 1780 | def applyFolding(self, foldingseq): |
|---|
| 1781 | if foldingseq and self.getFoldingActive() and \ |
|---|
| 1782 | len(foldingseq) == self.GetLineCount(): |
|---|
| 1783 | for ln in xrange(len(foldingseq)): |
|---|
| 1784 | self.SetFoldLevel(ln, foldingseq[ln]) |
|---|
| 1785 | self.repairFoldingVisibility() |
|---|
| 1786 | |
|---|
| 1787 | |
|---|
| 1788 | def unfoldAll(self): |
|---|
| 1789 | """ |
|---|
| 1790 | Unfold all folded lines |
|---|
| 1791 | """ |
|---|
| 1792 | for i in xrange(self.GetLineCount()): |
|---|
| 1793 | self.SetFoldExpanded(i, True) |
|---|
| 1794 | |
|---|
| 1795 | self.ShowLines(0, self.GetLineCount()-1) |
|---|
| 1796 | |
|---|
| 1797 | |
|---|
| 1798 | def foldAll(self): |
|---|
| 1799 | """ |
|---|
| 1800 | Fold all foldable lines |
|---|
| 1801 | """ |
|---|
| 1802 | if not self.getFoldingActive(): |
|---|
| 1803 | self.setFoldingActive(True, forceSync=True) |
|---|
| 1804 | |
|---|
| 1805 | for ln in xrange(self.GetLineCount()): |
|---|
| 1806 | if self.GetFoldLevel(ln) & wx.stc.STC_FOLDLEVELHEADERFLAG and \ |
|---|
| 1807 | self.GetFoldExpanded(ln): |
|---|
| 1808 | self.ToggleFold(ln) |
|---|
| 1809 | |
|---|
| 1810 | |
|---|
| 1811 | |
|---|
| 1812 | |
|---|
| 1813 | self.Refresh() |
|---|
| 1814 | |
|---|
| 1815 | |
|---|
| 1816 | def toggleCurrentFolding(self): |
|---|
| 1817 | if not self.getFoldingActive(): |
|---|
| 1818 | return |
|---|
| 1819 | |
|---|
| 1820 | self.ToggleFold(self.LineFromPosition(self.GetCurrentPos())) |
|---|
| 1821 | |
|---|
| 1822 | |
|---|
| 1823 | def getFoldInfo(self): |
|---|
| 1824 | if not self.getFoldingActive(): |
|---|
| 1825 | return None |
|---|
| 1826 | |
|---|
| 1827 | result = [0] * self.GetLineCount() |
|---|
| 1828 | for ln in xrange(self.GetLineCount()): |
|---|
| 1829 | levComb = self.GetFoldLevel(ln) |
|---|
| 1830 | levOut = levComb & 4095 |
|---|
| 1831 | if levComb & wx.stc.STC_FOLDLEVELHEADERFLAG: |
|---|
| 1832 | levOut |= 4096 |
|---|
| 1833 | if self.GetFoldExpanded(ln): |
|---|
| 1834 | levOut |= 8192 |
|---|
| 1835 | if self.GetLineVisible(ln): |
|---|
| 1836 | levOut |= 16384 |
|---|
| 1837 | result[ln] = levOut |
|---|
| 1838 | |
|---|
| 1839 | return result |
|---|
| 1840 | |
|---|
| 1841 | |
|---|
| 1842 | def setFoldInfo(self, fldInfo): |
|---|
| 1843 | if fldInfo is None or \ |
|---|
| 1844 | not self.getFoldingActive() or \ |
|---|
| 1845 | len(fldInfo) != self.GetLineCount(): |
|---|
| 1846 | return |
|---|
| 1847 | |
|---|
| 1848 | for ln, levIn in enumerate(fldInfo): |
|---|
| 1849 | levComb = levIn & 4095 |
|---|
| 1850 | if levIn & 4096: |
|---|
| 1851 | levComb |= wx.stc.STC_FOLDLEVELHEADERFLAG |
|---|
| 1852 | |
|---|
| 1853 | self.SetFoldLevel(ln, levComb) |
|---|
| 1854 | self.SetFoldExpanded(ln, bool(levIn & 8192)) |
|---|
| 1855 | if levIn & 16384: |
|---|
| 1856 | self.ShowLines(ln, ln) |
|---|
| 1857 | else: |
|---|
| 1858 | self.HideLines(ln, ln) |
|---|
| 1859 | |
|---|
| 1860 | self.repairFoldingVisibility() |
|---|
| 1861 | |
|---|
| 1862 | |
|---|
| 1863 | |
|---|
| 1864 | def repairFoldingVisibility(self): |
|---|
| 1865 | if not self.getFoldingActive(): |
|---|
| 1866 | return |
|---|
| 1867 | |
|---|
| 1868 | lc = self.GetLineCount() |
|---|
| 1869 | |
|---|
| 1870 | if lc == 0: |
|---|
| 1871 | return |
|---|
| 1872 | |
|---|
| 1873 | self.ShowLines(0, 0) |
|---|
| 1874 | if lc == 1: |
|---|
| 1875 | return |
|---|
| 1876 | |
|---|
| 1877 | combLevel = self.GetFoldLevel(0) |
|---|
| 1878 | prevLevel = combLevel & 4095 |
|---|
| 1879 | prevIsHeader = combLevel & wx.stc.STC_FOLDLEVELHEADERFLAG |
|---|
| 1880 | prevIsExpanded = self.GetFoldExpanded(0) |
|---|
| 1881 | prevVisible = True |
|---|
| 1882 | prevLn = 0 |
|---|
| 1883 | |
|---|
| 1884 | |
|---|
| 1885 | |
|---|
| 1886 | for ln in xrange(1, lc): |
|---|
| 1887 | combLevel = self.GetFoldLevel(ln) |
|---|
| 1888 | level = combLevel & 4095 |
|---|
| 1889 | isHeader = combLevel & wx.stc.STC_FOLDLEVELHEADERFLAG |
|---|
| 1890 | isExpanded = self.GetFoldExpanded(ln) |
|---|
| 1891 | visible = self.GetLineVisible(ln) |
|---|
| 1892 | |
|---|
| 1893 | |
|---|
| 1894 | if prevVisible and not visible: |
|---|
| 1895 | |
|---|
| 1896 | if ((level <= prevLevel) and \ |
|---|
| 1897 | not (prevIsHeader and not prevIsExpanded)) or \ |
|---|
| 1898 | (prevIsHeader and prevIsExpanded): |
|---|
| 1899 | |
|---|
| 1900 | |
|---|
| 1901 | |
|---|
| 1902 | |
|---|
| 1903 | |
|---|
| 1904 | |
|---|
| 1905 | |
|---|
| 1906 | self.SetFoldExpanded(prevLn, True) |
|---|
| 1907 | self.ShowLines(ln, ln) |
|---|
| 1908 | |
|---|
| 1909 | visible = True |
|---|
| 1910 | |
|---|
| 1911 | prevLevel = level |
|---|
| 1912 | prevIsHeader = isHeader |
|---|
| 1913 | prevIsExpanded = isExpanded |
|---|
| 1914 | prevVisible = visible |
|---|
| 1915 | prevLn = ln |
|---|
| 1916 | |
|---|
| 1917 | |
|---|
| 1918 | |
|---|
| 1919 | def snip(self): |
|---|
| 1920 | |
|---|
| 1921 | text = self.GetSelectedText() |
|---|
| 1922 | |
|---|
| 1923 | |
|---|
| 1924 | self.Copy() |
|---|
| 1925 | |
|---|
| 1926 | wikiPage = self.presenter.getWikiDocument().getWikiPageNoError("ScratchPad") |
|---|
| 1927 | |
|---|
| 1928 | |
|---|
| 1929 | |
|---|
| 1930 | wikiPage.appendLiveText("\n%s\n---------------------------\n\n%s\n" % |
|---|
| 1931 | (StringOps.strftimeUB("%x %I:%M %p"), text)) |
|---|
| 1932 | |
|---|
| 1933 | def styleSelection(self, startChars, endChars=None): |
|---|
| 1934 | """ |
|---|
| 1935 | """ |
|---|
| 1936 | if endChars is None: |
|---|
| 1937 | endChars = startChars |
|---|
| 1938 | |
|---|
| 1939 | (startBytePos, endBytePos) = self.GetSelection() |
|---|
| 1940 | if startBytePos == endBytePos: |
|---|
| 1941 | (startBytePos, endBytePos) = self.getNearestWordPositions() |
|---|
| 1942 | |
|---|
| 1943 | emptySelection = startBytePos == endBytePos |
|---|
| 1944 | |
|---|
| 1945 | startCharPos = len(self.GetTextRange(0, startBytePos)) |
|---|
| 1946 | endCharPos = startCharPos + len(self.GetTextRange(startBytePos, endBytePos)) |
|---|
| 1947 | |
|---|
| 1948 | self.BeginUndoAction() |
|---|
| 1949 | try: |
|---|
| 1950 | endCharPos += len(startChars) |
|---|
| 1951 | |
|---|
| 1952 | if emptySelection: |
|---|
| 1953 | |
|---|
| 1954 | |
|---|
| 1955 | cursorCharPos = endCharPos |
|---|
| 1956 | else: |
|---|
| 1957 | |
|---|
| 1958 | cursorCharPos = endCharPos + len(endChars) |
|---|
| 1959 | |
|---|
| 1960 | self.gotoCharPos(startCharPos, scroll=False) |
|---|
| 1961 | self.AddText(startChars) |
|---|
| 1962 | |
|---|
| 1963 | self.gotoCharPos(endCharPos, scroll=False) |
|---|
| 1964 | self.AddText(endChars) |
|---|
| 1965 | |
|---|
| 1966 | self.gotoCharPos(cursorCharPos, scroll=False) |
|---|
| 1967 | finally: |
|---|
| 1968 | self.EndUndoAction() |
|---|
| 1969 | |
|---|
| 1970 | |
|---|
| 1971 | def getPageAst(self): |
|---|
| 1972 | docPage = self.getLoadedDocPage() |
|---|
| 1973 | if docPage is None: |
|---|
| 1974 | raise NoPageAstException(u"Internal error: No docPage => no page AST") |
|---|
| 1975 | |
|---|
| 1976 | return docPage.getLivePageAst() |
|---|
| 1977 | |
|---|
| 1978 | |
|---|
| 1979 | def activateTokens(self, nodeList, tabMode=0): |
|---|
| 1980 | """ |
|---|
| 1981 | Helper for activateLink() |
|---|
| 1982 | tabMode -- 0:Same tab; 2: new tab in foreground; 3: new tab in background |
|---|
| 1983 | """ |
|---|
| 1984 | if len(nodeList) == 0: |
|---|
| 1985 | return False |
|---|
| 1986 | |
|---|
| 1987 | for node in nodeList: |
|---|
| 1988 | if node.name == "wikiWord": |
|---|
| 1989 | searchStr = None |
|---|
| 1990 | |
|---|
| 1991 | |
|---|
| 1992 | if tabMode & 2: |
|---|
| 1993 | if tabMode == 6: |
|---|
| 1994 | |
|---|
| 1995 | presenter = self.presenter.getMainControl().\ |
|---|
| 1996 | createNewDocPagePresenterTabInNewFrame() |
|---|
| 1997 | else: |
|---|
| 1998 | |
|---|
| 1999 | presenter = self.presenter.getMainControl().\ |
|---|
| 2000 | createNewDocPagePresenterTab() |
|---|
| 2001 | else: |
|---|
| 2002 | |
|---|
| 2003 | presenter = self.presenter |
|---|
| 2004 | |
|---|
| 2005 | titleFromLink = self.presenter.getConfig().getboolean("main", |
|---|
| 2006 | "wikiPageTitle_fromLinkTitle", False) |
|---|
| 2007 | |
|---|
| 2008 | if not titleFromLink or node.titleNode is None: |
|---|
| 2009 | suggNewPageTitle = None |
|---|
| 2010 | else: |
|---|
| 2011 | suggNewPageTitle = node.titleNode.getString() |
|---|
| 2012 | |
|---|
| 2013 | unaliasedTarget = self.presenter.getWikiDocument()\ |
|---|
| 2014 | .getWikiPageNameForLinkTermOrAsIs(node.wikiWord) |
|---|
| 2015 | |
|---|
| 2016 | docPage = self.getLoadedDocPage() |
|---|
| 2017 | |
|---|
| 2018 | |
|---|
| 2019 | |
|---|
| 2020 | |
|---|
| 2021 | |
|---|
| 2022 | |
|---|
| 2023 | forbiddenSearchfragHit = (0, 0) |
|---|
| 2024 | if docPage is not None: |
|---|
| 2025 | wikiWord = docPage.getWikiWord() |
|---|
| 2026 | if wikiWord is not None: |
|---|
| 2027 | if wikiWord == unaliasedTarget: |
|---|
| 2028 | forbiddenSearchfragHit = (node.pos, node.pos + node.strLength) |
|---|
| 2029 | |
|---|
| 2030 | presenter.openWikiPage(unaliasedTarget, |
|---|
| 2031 | motionType="child", anchor=node.anchorLink, |
|---|
| 2032 | suggNewPageTitle=suggNewPageTitle) |
|---|
| 2033 | |
|---|
| 2034 | searchfrag = node.searchFragment |
|---|
| 2035 | if searchfrag is not None: |
|---|
| 2036 | searchOp = SearchReplaceOperation() |
|---|
| 2037 | searchOp.wildCard = "no" |
|---|
| 2038 | searchOp.searchStr = searchfrag |
|---|
| 2039 | |
|---|
| 2040 | found = presenter.getSubControl("textedit").executeSearch( |
|---|
| 2041 | searchOp, 0) |
|---|
| 2042 | |
|---|
| 2043 | if found[0] >= forbiddenSearchfragHit[0] and \ |
|---|
| 2044 | found[0] < forbiddenSearchfragHit[1]: |
|---|
| 2045 | |
|---|
| 2046 | presenter.getSubControl("textedit").executeSearch( |
|---|
| 2047 | searchOp, forbiddenSearchfragHit[1]) |
|---|
| 2048 | |
|---|
| 2049 | if not tabMode & 1: |
|---|
| 2050 | |
|---|
| 2051 | presenter.getMainControl().getMainAreaPanel().\ |
|---|
| 2052 | showPresenter(presenter) |
|---|
| 2053 | |
|---|
| 2054 | return True |
|---|
| 2055 | |
|---|
| 2056 | elif node.name == "urlLink": |
|---|
| 2057 | self.presenter.getMainControl().launchUrl(node.url) |
|---|
| 2058 | return True |
|---|
| 2059 | |
|---|
| 2060 | elif node.name == "insertion": |
|---|
| 2061 | if node.key == u"page": |
|---|
| 2062 | |
|---|
| 2063 | |
|---|
| 2064 | if tabMode & 2: |
|---|
| 2065 | if tabMode == 6: |
|---|
| 2066 | |
|---|
| 2067 | presenter = self.presenter.getMainControl().\ |
|---|
| 2068 | createNewDocPagePresenterTabInNewFrame() |
|---|
| 2069 | else: |
|---|
| 2070 | |
|---|
| 2071 | presenter = self.presenter.getMainControl().\ |
|---|
| 2072 | createNewDocPagePresenterTab() |
|---|
| 2073 | else: |
|---|
| 2074 | |
|---|
| 2075 | presenter = self.presenter |
|---|
| 2076 | |
|---|
| 2077 | presenter.openWikiPage(node.value, |
|---|
| 2078 | motionType="child") |
|---|
| 2079 | |
|---|
| 2080 | if not tabMode & 1: |
|---|
| 2081 | |
|---|
| 2082 | |
|---|
| 2083 | presenter.getMainControl().getMainAreaPanel().\ |
|---|
| 2084 | showPresenter(presenter) |
|---|
| 2085 | |
|---|
| 2086 | return True |
|---|
| 2087 | |
|---|
| 2088 | |
|---|
| 2089 | |
|---|
| 2090 | |
|---|
| 2091 | |
|---|
| 2092 | |
|---|
| 2093 | |
|---|
| 2094 | elif node.name == "footnote": |
|---|
| 2095 | try: |
|---|
| 2096 | pageAst = self.getPageAst() |
|---|
| 2097 | footnoteId = node.footnoteId |
|---|
| 2098 | |
|---|
| 2099 | anchorNode = getFootnoteAnchorDict(pageAst).get(footnoteId) |
|---|
| 2100 | if anchorNode is not None: |
|---|
| 2101 | if anchorNode.pos != node.pos: |
|---|
| 2102 | |
|---|
| 2103 | self.gotoCharPos(anchorNode.pos) |
|---|
| 2104 | else: |
|---|
| 2105 | |
|---|
| 2106 | for fnNode in pageAst.iterDeepByName("footnote"): |
|---|
| 2107 | if fnNode.footnoteId == footnoteId: |
|---|
| 2108 | self.gotoCharPos(fnNode.pos) |
|---|
| 2109 | break |
|---|
| 2110 | |
|---|
| 2111 | return True |
|---|
| 2112 | except NoPageAstException: |
|---|
| 2113 | return False |
|---|
| 2114 | else: |
|---|
| 2115 | continue |
|---|
| 2116 | |
|---|
| 2117 | return False |
|---|
| 2118 | |
|---|
| 2119 | |
|---|
| 2120 | def getTokensForMousePos(self, mousePosition=None): |
|---|
| 2121 | |
|---|
| 2122 | if mousePosition and mousePosition != wx.DefaultPosition: |
|---|
| 2123 | linkBytePos = self.PositionFromPoint(mousePosition) |
|---|
| 2124 | else: |
|---|
| 2125 | linkBytePos = self.GetCurrentPos() |
|---|
| 2126 | |
|---|
| 2127 | try: |
|---|
| 2128 | pageAst = self.getPageAst() |
|---|
| 2129 | except NoPageAstException: |
|---|
| 2130 | return [] |
|---|
| 2131 | |
|---|
| 2132 | linkCharPos = len(self.GetTextRange(0, linkBytePos)) |
|---|
| 2133 | |
|---|
| 2134 | result = pageAst.findNodesForCharPos(linkCharPos) |
|---|
| 2135 | |
|---|
| 2136 | |
|---|
| 2137 | if linkCharPos > 0: |
|---|
| 2138 | |
|---|
| 2139 | |
|---|
| 2140 | result += pageAst.findNodesForCharPos(linkCharPos - 1) |
|---|
| 2141 | |
|---|
| 2142 | if self.onlineSpellCheckerActive: |
|---|
| 2143 | docPage = self.getLoadedDocPage() |
|---|
| 2144 | if isinstance(docPage, DocPages.AbstractWikiPage): |
|---|
| 2145 | allUnknownWords = docPage.getSpellCheckerUnknownWords() |
|---|
| 2146 | wantedUnknownWords = allUnknownWords.findNodesForCharPos( |
|---|
| 2147 | linkCharPos) |
|---|
| 2148 | |
|---|
| 2149 | if linkCharPos > 0 and len(wantedUnknownWords) == 0: |
|---|
| 2150 | |
|---|
| 2151 | wantedUnknownWords = allUnknownWords.findNodesForCharPos( |
|---|
| 2152 | linkCharPos - 1) |
|---|
| 2153 | |
|---|
| 2154 | result += wantedUnknownWords |
|---|
| 2155 | |
|---|
| 2156 | return result |
|---|
| 2157 | |
|---|
| 2158 | |
|---|
| 2159 | |
|---|
| 2160 | def activateLink(self, mousePosition=None, tabMode=0): |
|---|
| 2161 | """ |
|---|
| 2162 | Activates link (wiki word or URL) |
|---|
| 2163 | tabMode -- 0:Same tab; 2: new tab in foreground; 3: new tab in background |
|---|
| 2164 | """ |
|---|
| 2165 | tokens = self.getTokensForMousePos(mousePosition) |
|---|
| 2166 | return self.activateTokens(tokens, tabMode) |
|---|
| 2167 | |
|---|
| 2168 | |
|---|
| 2169 | |
|---|
| 2170 | def OnReplaceThisSpellingWithSuggestion(self, evt): |
|---|
| 2171 | if self.contextMenuTokens and self.contextMenuSpellCheckSuggestions: |
|---|
| 2172 | for node in self.contextMenuTokens: |
|---|
| 2173 | if node.name == "unknownSpelling": |
|---|
| 2174 | self.replaceTextAreaByCharPos( |
|---|
| 2175 | self.contextMenuSpellCheckSuggestions[ |
|---|
| 2176 | self.SUGGESTION_CMD_IDS.index(evt.GetId())], |
|---|
| 2177 | node.pos, node.pos + node.strLength) |
|---|
| 2178 | break |
|---|
| 2179 | |
|---|
| 2180 | |
|---|
| 2181 | |
|---|
| 2182 | def OnAddThisSpellingToIgnoreSession(self, evt): |
|---|
| 2183 | if self.contextMenuTokens: |
|---|
| 2184 | for node in self.contextMenuTokens: |
|---|
| 2185 | if node.name == "unknownSpelling": |
|---|
| 2186 | self.presenter.getWikiDocument()\ |
|---|
| 2187 | .getOnlineSpellCheckerSession().addIgnoreWordSession( |
|---|
| 2188 | node.getText()) |
|---|
| 2189 | break |
|---|
| 2190 | |
|---|
| 2191 | |
|---|
| 2192 | def OnAddThisSpellingToIgnoreGlobal(self, evt): |
|---|
| 2193 | if self.contextMenuTokens: |
|---|
| 2194 | for node in self.contextMenuTokens: |
|---|
| 2195 | if node.name == "unknownSpelling": |
|---|
| 2196 | self.presenter.getWikiDocument()\ |
|---|
| 2197 | .getOnlineSpellCheckerSession().addIgnoreWordGlobal( |
|---|
| 2198 | node.getText()) |
|---|
| 2199 | break |
|---|
| 2200 | |
|---|
| 2201 | def OnAddThisSpellingToIgnoreLocal(self, evt): |
|---|
| 2202 | if self.contextMenuTokens: |
|---|
| 2203 | for node in self.contextMenuTokens: |
|---|
| 2204 | if node.name == "unknownSpelling": |
|---|
| 2205 | self.presenter.getWikiDocument()\ |
|---|
| 2206 | .getOnlineSpellCheckerSession().addIgnoreWordLocal( |
|---|
| 2207 | node.getText()) |
|---|
| 2208 | break |
|---|
| 2209 | |
|---|
| 2210 | |
|---|
| 2211 | |
|---|
| 2212 | def OnActivateThis(self, evt): |
|---|
| 2213 | if self.contextMenuTokens: |
|---|
| 2214 | self.activateTokens(self.contextMenuTokens, 0) |
|---|
| 2215 | |
|---|
| 2216 | def OnActivateNewTabThis(self, evt): |
|---|
| 2217 | if self.contextMenuTokens: |
|---|
| 2218 | self.activateTokens(self.contextMenuTokens, 2) |
|---|
| 2219 | |
|---|
| 2220 | def OnActivateNewTabBackgroundThis(self, evt): |
|---|
| 2221 | if self.contextMenuTokens: |
|---|
| 2222 | self.activateTokens(self.contextMenuTokens, 3) |
|---|
| 2223 | |
|---|
| 2224 | def OnActivateNewWindowThis(self, evt): |
|---|
| 2225 | if self.contextMenuTokens: |
|---|
| 2226 | self.activateTokens(self.contextMenuTokens, 6) |
|---|
| 2227 | |
|---|
| 2228 | |
|---|
| 2229 | def OnOpenContainingFolderThis(self, evt): |
|---|
| 2230 | if self.contextMenuTokens: |
|---|
| 2231 | for node in self.contextMenuTokens: |
|---|
| 2232 | if node.name == "urlLink": |
|---|
| 2233 | link = node.url |
|---|
| 2234 | |
|---|
| 2235 | if link.startswith(u"rel://") or link.startswith(u"wikirel://"): |
|---|
| 2236 | link = self.presenter.getWikiDocument()\ |
|---|
| 2237 | .makeRelUrlAbsolute(link) |
|---|
| 2238 | |
|---|
| 2239 | if link.startswith(u"file:") or link.startswith(u"wiki:"): |
|---|
| 2240 | try: |
|---|
| 2241 | path = dirname(StringOps.pathnameFromUrl(link)) |
|---|
| 2242 | if not exists(StringOps.longPathEnc(path)): |
|---|
| 2243 | self.presenter.displayErrorMessage( |
|---|
| 2244 | _(u"Folder does not exist")) |
|---|
| 2245 | return |
|---|
| 2246 | |
|---|
| 2247 | OsAbstract.startFile(self.presenter.getMainControl(), |
|---|
| 2248 | path) |
|---|
| 2249 | except IOError: |
|---|
| 2250 | pass |
|---|
| 2251 | |
|---|
| 2252 | break |
|---|
| 2253 | |
|---|
| 2254 | def OnDeleteFile(self, evt): |
|---|
| 2255 | if self.contextMenuTokens: |
|---|
| 2256 | for node in self.contextMenuTokens: |
|---|
| 2257 | if node.name == "urlLink": |
|---|
| 2258 | link = self.presenter.getWikiDocument().makeFileUrlAbsPath( |
|---|
| 2259 | node.url) |
|---|
| 2260 | if link is None: |
|---|
| 2261 | continue |
|---|
| 2262 | |
|---|
| 2263 | |
|---|
| 2264 | |
|---|
| 2265 | |
|---|
| 2266 | |
|---|
| 2267 | |
|---|
| 2268 | |
|---|
| 2269 | |
|---|
| 2270 | |
|---|
| 2271 | |
|---|
| 2272 | if not isfile(link): |
|---|
| 2273 | self.presenter.displayErrorMessage( |
|---|
| 2274 | _(u"File does not exist")) |
|---|
| 2275 | return |
|---|
| 2276 | |
|---|
| 2277 | filename = basename(link) |
|---|
| 2278 | |
|---|
| 2279 | choice = wx.MessageBox( |
|---|
| 2280 | _("Are you sure you want to delete the file: %s") % |
|---|
| 2281 | filename, _("Delete File"), |
|---|
| 2282 | wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION, self) |
|---|
| 2283 | |
|---|
| 2284 | if choice == wx.YES: |
|---|
| 2285 | OsAbstract.deleteFile(link) |
|---|
| 2286 | self.replaceTextAreaByCharPos(u"", node.pos, |
|---|
| 2287 | node.pos + node.strLength) |
|---|
| 2288 | return |
|---|
| 2289 | |
|---|
| 2290 | |
|---|
| 2291 | def OnRenameFile(self, evt): |
|---|
| 2292 | if not self.contextMenuTokens: |
|---|
| 2293 | return |
|---|
| 2294 | |
|---|
| 2295 | for node in self.contextMenuTokens: |
|---|
| 2296 | if node.name == "urlLink": |
|---|
| 2297 | link = self.presenter.getWikiDocument().makeFileUrlAbsPath( |
|---|
| 2298 | node.url) |
|---|
| 2299 | if link is not None: |
|---|
| 2300 | break |
|---|
| 2301 | else: |
|---|
| 2302 | return |
|---|
| 2303 | |
|---|
| 2304 | |
|---|
| 2305 | |
|---|
| 2306 | |
|---|
| 2307 | |
|---|
| 2308 | |
|---|
| 2309 | |
|---|
| 2310 | |
|---|
| 2311 | |
|---|
| 2312 | if not isfile(link): |
|---|
| 2313 | self.presenter.displayErrorMessage(_(u"File does not exist")) |
|---|
| 2314 | return |
|---|
| 2315 | |
|---|
| 2316 | path = dirname(link) |
|---|
| 2317 | filename = basename(link) |
|---|
| 2318 | |
|---|
| 2319 | newName = filename |
|---|
| 2320 | while True: |
|---|
| 2321 | newName = wx.GetTextFromUser(_(u"Enter new name"), |
|---|
| 2322 | _(u"Rename File"), newName, self) |
|---|
| 2323 | if not newName: |
|---|
| 2324 | |
|---|
| 2325 | return |
|---|
| 2326 | |
|---|
| 2327 | newfile = join(path, newName) |
|---|
| 2328 | |
|---|
| 2329 | if exists(newfile): |
|---|
| 2330 | if not isfile(newfile): |
|---|
| 2331 | self.presenter.displayErrorMessage( |
|---|
| 2332 | _(u"Target is not a file")) |
|---|
| 2333 | continue |
|---|
| 2334 | |
|---|
| 2335 | choice = wx.MessageBox( |
|---|
| 2336 | _("Target file exists already. Overwrite?"), |
|---|
| 2337 | _("Overwrite File"), |
|---|
| 2338 | wx.YES_NO | wx.CANCEL | wx.NO_DEFAULT | wx.ICON_QUESTION, |
|---|
| 2339 | self) |
|---|
| 2340 | if choice == wx.CANCEL: |
|---|
| 2341 | return |
|---|
| 2342 | elif choice == wx.NO: |
|---|
| 2343 | continue |
|---|
| 2344 | |
|---|
| 2345 | |
|---|
| 2346 | |
|---|
| 2347 | OsAbstract.moveFile(link, newfile) |
|---|
| 2348 | |
|---|
| 2349 | if node.url.startswith(u"rel://"): |
|---|
| 2350 | |
|---|
| 2351 | newUrl = self.presenter.getWikiDocument().makeAbsPathRelUrl( |
|---|
| 2352 | newfile) |
|---|
| 2353 | else: |
|---|
| 2354 | |
|---|
| 2355 | newUrl = u"file:" + StringOps.urlFromPathname(newfile) |
|---|
| 2356 | |
|---|
| 2357 | self.replaceTextAreaByCharPos(newUrl, node.coreNode.pos, |
|---|
| 2358 | node.coreNode.pos + node.coreNode.strLength) |
|---|
| 2359 | |
|---|
| 2360 | return |
|---|
| 2361 | |
|---|
| 2362 | |
|---|
| 2363 | |
|---|
| 2364 | def convertUrlAbsoluteRelative(self, tokenList): |
|---|
| 2365 | for node in tokenList: |
|---|
| 2366 | if node.name == "urlLink": |
|---|
| 2367 | link = node.url |
|---|
| 2368 | |
|---|
| 2369 | if ' ' in node.coreNode.getString(): |
|---|
| 2370 | addSafe = ' ' |
|---|
| 2371 | else: |
|---|
| 2372 | addSafe = '' |
|---|
| 2373 | |
|---|
| 2374 | if link.startswith(u"rel://") or link.startswith(u"wikirel://"): |
|---|
| 2375 | link = self.presenter.getWikiDocument()\ |
|---|
| 2376 | .makeRelUrlAbsolute(link, addSafe=addSafe) |
|---|
| 2377 | |
|---|
| 2378 | elif link.startswith(u"file:"): |
|---|
| 2379 | link = self.presenter.getWikiDocument()\ |
|---|
| 2380 | .makeAbsPathRelUrl(StringOps.pathnameFromUrl( |
|---|
| 2381 | link), addSafe=addSafe) |
|---|
| 2382 | if link is None: |
|---|
| 2383 | continue |
|---|
| 2384 | elif link.startswith(u"wiki:"): |
|---|
| 2385 | link = self.presenter.getWikiDocument()\ |
|---|
| 2386 | .makeAbsPathRelUrl(StringOps.pathnameFromUrl( |
|---|
| 2387 | link), addSafe=addSafe) |
|---|
| 2388 | if link is None: |
|---|
| 2389 | continue |
|---|
| 2390 | else: |
|---|
| 2391 | link = u"wiki" + link |
|---|
| 2392 | |
|---|
| 2393 | else: |
|---|
| 2394 | continue |
|---|
| 2395 | |
|---|
| 2396 | self.replaceTextAreaByCharPos(link, node.coreNode.pos, |
|---|
| 2397 | node.coreNode.pos + node.coreNode.strLength) |
|---|
| 2398 | |
|---|
| 2399 | break |
|---|
| 2400 | |
|---|
| 2401 | |
|---|
| 2402 | def convertSelectedUrlAbsoluteRelative(self): |
|---|
| 2403 | tokenList = self.getTokensForMousePos(None) |
|---|
| 2404 | self.convertUrlAbsoluteRelative(tokenList) |
|---|
| 2405 | |
|---|
| 2406 | |
|---|
| 2407 | def OnConvertUrlAbsoluteRelativeThis(self, evt): |
|---|
| 2408 | if self.contextMenuTokens: |
|---|
| 2409 | self.convertUrlAbsoluteRelative(self.contextMenuTokens) |
|---|
| 2410 | |
|---|
| 2411 | |
|---|
| 2412 | def OnClipboardCopyUrlToThisAnchor(self, evt): |
|---|
| 2413 | wikiWord = self.presenter.getWikiWord() |
|---|
| 2414 | if wikiWord is None: |
|---|
| 2415 | wx.MessageBox( |
|---|
| 2416 | _(u"This can only be done for the page of a wiki word"), |
|---|
| 2417 | _(u'Not a wiki page'), wx.OK, self) |
|---|
| 2418 | return |
|---|
| 2419 | |
|---|
| 2420 | path = self.presenter.getWikiDocument().getWikiConfigPath() |
|---|
| 2421 | for node in self.contextMenuTokens: |
|---|
| 2422 | if node.name == "anchorDef": |
|---|
| 2423 | copyTextToClipboard(StringOps.pathWordAndAnchorToWikiUrl(path, |
|---|
| 2424 | wikiWord, node.anchorLink)) |
|---|
| 2425 | return |
|---|
| 2426 | |
|---|
| 2427 | |
|---|
| 2428 | |
|---|
| 2429 | def evalScriptBlocks(self, index=-1): |
|---|
| 2430 | """ |
|---|
| 2431 | Evaluates scripts. Respects "script_security_level" option |
|---|
| 2432 | """ |
|---|
| 2433 | securityLevel = self.presenter.getConfig().getint( |
|---|
| 2434 | "main", "script_security_level") |
|---|
| 2435 | if securityLevel == 0: |
|---|
| 2436 | |
|---|
| 2437 | |
|---|
| 2438 | wx.MessageBox(_(u"Set in menu \"Wiki\", item \"Options...\", " |
|---|
| 2439 | "options page \"Security\", \n" |
|---|
| 2440 | "item \"Script security\" an appropriate value " |
|---|
| 2441 | "to execute a script."), _(u"Script execution disabled"), |
|---|
| 2442 | wx.OK, self.presenter.getMainControl()) |
|---|
| 2443 | return |
|---|
| 2444 | |
|---|
| 2445 | SCRIPTFORMAT = "script" |
|---|
| 2446 | |
|---|
| 2447 | self.ConvertEOLs(self.eolMode) |
|---|
| 2448 | (startPos, endPos) = self.GetSelection() |
|---|
| 2449 | |
|---|
| 2450 | |
|---|
| 2451 | if startPos == endPos or index > -1: |
|---|
| 2452 | |
|---|
| 2453 | |
|---|
| 2454 | try: |
|---|
| 2455 | pageAst = self.getPageAst() |
|---|
| 2456 | except NoPageAstException: |
|---|
| 2457 | return |
|---|
| 2458 | |
|---|
| 2459 | scriptNodeGroups = [list(pageAst.iterDeepByName(SCRIPTFORMAT))] |
|---|
| 2460 | |
|---|
| 2461 | |
|---|
| 2462 | if securityLevel > 1: |
|---|
| 2463 | if self.getLoadedDocPage().getAttributes().has_key( |
|---|
| 2464 | u"import_scripts"): |
|---|
| 2465 | scriptNames = self.getLoadedDocPage().getAttributes()[ |
|---|
| 2466 | u"import_scripts"] |
|---|
| 2467 | for sn in scriptNames: |
|---|
| 2468 | try: |
|---|
| 2469 | importPage = self.presenter.getWikiDocument().\ |
|---|
| 2470 | getWikiPage(sn) |
|---|
| 2471 | pageAst = importPage.getLivePageAst() |
|---|
| 2472 | scriptNodeGroups.append(list( |
|---|
| 2473 | pageAst.iterDeepByName(SCRIPTFORMAT))) |
|---|
| 2474 | except: |
|---|
| 2475 | pass |
|---|
| 2476 | |
|---|
| 2477 | if securityLevel > 2: |
|---|
| 2478 | globScriptName = self.presenter.getWikiDocument().getWikiData().\ |
|---|
| 2479 | getGlobalAttributes().get(u"global.import_scripts") |
|---|
| 2480 | |
|---|
| 2481 | if globScriptName is not None: |
|---|
| 2482 | try: |
|---|
| 2483 | importPage = self.presenter.getWikiDocument().\ |
|---|
| 2484 | getWikiPage(globScriptName) |
|---|
| 2485 | pageAst = importPage.getLivePageAst() |
|---|
| 2486 | scriptNodeGroups.append(list( |
|---|
| 2487 | pageAst.iterDeepByName(SCRIPTFORMAT))) |
|---|
| 2488 | except: |
|---|
| 2489 | pass |
|---|
| 2490 | |
|---|
| 2491 | if self.presenter.getConfig().getboolean("main", |
|---|
| 2492 | "script_search_reverse", False): |
|---|
| 2493 | scriptNodeGroups.reverse() |
|---|
| 2494 | |
|---|
| 2495 | scriptNodes = reduce(lambda a, b: a + b, scriptNodeGroups) |
|---|
| 2496 | |
|---|
| 2497 | for node in scriptNodes: |
|---|
| 2498 | script = node.findFlatByName("code").getString() |
|---|
| 2499 | script = re.sub(u"^[\r\n\s]+", u"", script) |
|---|
| 2500 | script = re.sub(u"[\r\n\s]+$", u"", script) |
|---|
| 2501 | try: |
|---|
| 2502 | if index == -1: |
|---|
| 2503 | script = re.sub(u"^\d:?\s?", u"", script) |
|---|
| 2504 | exec(script) in self.evalScope |
|---|
| 2505 | elif index > -1 and script.startswith(str(index)): |
|---|
| 2506 | script = re.sub(u"^\d:?\s?", u"", script) |
|---|
| 2507 | exec(script) in self.evalScope |
|---|
| 2508 | break |
|---|
| 2509 | |
|---|
| 2510 | except Exception, e: |
|---|
| 2511 | s = StringIO() |
|---|
| 2512 | traceback.print_exc(file=s) |
|---|
| 2513 | self.AddText(_(u"\nException: %s") % s.getvalue()) |
|---|
| 2514 | else: |
|---|
| 2515 | |
|---|
| 2516 | text = self.GetSelectedText() |
|---|
| 2517 | try: |
|---|
| 2518 | compThunk = compile(re.sub(u"[\n\r]", u"", text), "<string>", |
|---|
| 2519 | "eval", CO_FUTURE_DIVISION) |
|---|
| 2520 | result = eval(compThunk, self.evalScope) |
|---|
| 2521 | except Exception, e: |
|---|
| 2522 | s = StringIO() |
|---|
| 2523 | traceback.print_exc(file=s) |
|---|
| 2524 | result = s.getvalue() |
|---|
| 2525 | |
|---|
| 2526 | pos = self.GetCurrentPos() |
|---|
| 2527 | self.GotoPos(endPos) |
|---|
| 2528 | self.AddText(u" = %s" % unicode(result)) |
|---|
| 2529 | self.GotoPos(pos) |
|---|
| 2530 | |
|---|
| 2531 | |
|---|
| 2532 | def cleanAutoGenAreas(self, text): |
|---|
| 2533 | """ |
|---|
| 2534 | Remove any content from the autogenerated areas and return |
|---|
| 2535 | cleaned text. Call this before storing page in the database. |
|---|
| 2536 | The original text is returned if option |
|---|
| 2537 | "process_autogenerated_areas" is False. |
|---|
| 2538 | """ |
|---|
| 2539 | return text |
|---|
| 2540 | |
|---|
| 2541 | |
|---|
| 2542 | |
|---|
| 2543 | |
|---|
| 2544 | |
|---|
| 2545 | |
|---|
| 2546 | |
|---|
| 2547 | |
|---|
| 2548 | def _agaReplace(self, match): |
|---|
| 2549 | try: |
|---|
| 2550 | result = unicode(eval(match.group(2), self.evalScope)) |
|---|
| 2551 | except Exception, e: |
|---|
| 2552 | s = StringIO() |
|---|
| 2553 | traceback.print_exc(file=s) |
|---|
| 2554 | result = unicode(s.getvalue()) |
|---|
| 2555 | |
|---|
| 2556 | if len(result) == 0 or result[-1] != u"\n": |
|---|
| 2557 | result += u"\n" |
|---|
| 2558 | |
|---|
| 2559 | return match.group(1) + match.group(2) + result + match.group(4) |
|---|
| 2560 | |
|---|
| 2561 | |
|---|
| 2562 | def updateAutoGenAreas(self, text): |
|---|
| 2563 | """ |
|---|
| 2564 | Update content of the autogenerated areas and return |
|---|
| 2565 | updated text. Call this before loading the text in the editor |
|---|
| 2566 | and on user request. The original text is returned if |
|---|
| 2567 | option "process_autogenerated_areas" is False. |
|---|
| 2568 | """ |
|---|
| 2569 | return text |
|---|
| 2570 | |
|---|
| 2571 | |
|---|
| 2572 | |
|---|
| 2573 | |
|---|
| 2574 | |
|---|
| 2575 | |
|---|
| 2576 | |
|---|
| 2577 | |
|---|
| 2578 | |
|---|
| 2579 | |
|---|
| 2580 | |
|---|
| 2581 | |
|---|
| 2582 | def getAgaCleanedText(self): |
|---|
| 2583 | """ |
|---|
| 2584 | Get editor text after cleaning of autogenerated area content |
|---|
| 2585 | if configuration option is set appropriately, otherwise, the |
|---|
| 2586 | text is not modified |
|---|
| 2587 | """ |
|---|
| 2588 | return self.cleanAutoGenAreas(self.GetText()) |
|---|
| 2589 | |
|---|
| 2590 | |
|---|
| 2591 | def setTextAgaUpdated(self, text): |
|---|
| 2592 | """ |
|---|
| 2593 | Set editor text after updating of autogenerated area content |
|---|
| 2594 | if configuration option is set appropriately, otherwise, the |
|---|
| 2595 | text is not modified |
|---|
| 2596 | """ |
|---|
| 2597 | self.SetText(self.updateAutoGenAreas(text)) |
|---|
| 2598 | |
|---|
| 2599 | |
|---|
| 2600 | |
|---|
| 2601 | AGACONTENTTABLERE = re.compile(ur"^(\+{1,4})([^\n\+][^\n]*)", re.DOTALL | re.LOCALE | re.MULTILINE) |
|---|
| 2602 | |
|---|
| 2603 | def agaContentTable(self, omitfirst = False): |
|---|
| 2604 | """ |
|---|
| 2605 | Can be called by an aga to present the content table of the current page. |
|---|
| 2606 | The text is assumed to be in self.agatext variable(see updateAutoGenAreas()). |
|---|
| 2607 | If omitfirst is true, the first entry (normally the title) is not shown. |
|---|
| 2608 | """ |
|---|
| 2609 | allmatches = map(lambda m: m.group(0), self.AGACONTENTTABLERE.finditer(self.agatext)) |
|---|
| 2610 | if omitfirst and len(allmatches) > 0: |
|---|
| 2611 | allmatches = allmatches[1:] |
|---|
| 2612 | |
|---|
| 2613 | return u"\n".join(allmatches) |
|---|
| 2614 | |
|---|
| 2615 | |
|---|
| 2616 | |
|---|
| 2617 | def agaFormatList(self, l): |
|---|
| 2618 | """ |
|---|
| 2619 | Format a list l of strings in a nice way for an aga content |
|---|
| 2620 | """ |
|---|
| 2621 | return u"\n".join(l) |
|---|
| 2622 | |
|---|
| 2623 | |
|---|
| 2624 | def agaParentsTable(self): |
|---|
| 2625 | """ |
|---|
| 2626 | Can be called by an aga to present all parents of the current page. |
|---|
| 2627 | """ |
|---|
| 2628 | relations = self.getLoadedDocPage().getParentRelationships()[:] |
|---|
| 2629 | |
|---|
| 2630 | |
|---|
| 2631 | relations.sort(key=string.lower) |
|---|
| 2632 | |
|---|
| 2633 | return self.agaFormatList(relations) |
|---|
| 2634 | |
|---|
| 2635 | |
|---|
| 2636 | def ensureTextRangeByBytePosExpanded(self, byteStart, byteEnd): |
|---|
| 2637 | self.repairFoldingVisibility() |
|---|
| 2638 | |
|---|
| 2639 | startLine = self.LineFromPosition(byteStart) |
|---|
| 2640 | endLine = self.LineFromPosition(byteEnd) |
|---|
| 2641 | |
|---|
| 2642 | |
|---|
| 2643 | if endLine < startLine: |
|---|
| 2644 | startLine, endLine = endLine, startLine |
|---|
| 2645 | |
|---|
| 2646 | for checkLine in xrange(endLine, startLine - 1, -1): |
|---|
| 2647 | if not self.GetLineVisible(checkLine): |
|---|
| 2648 | line = checkLine |
|---|
| 2649 | |
|---|
| 2650 | while True: |
|---|
| 2651 | line = self.GetFoldParent(line) |
|---|
| 2652 | if line == -1: |
|---|
| 2653 | break |
|---|
| 2654 | if not self.GetFoldExpanded(line): |
|---|
| 2655 | self.ToggleFold(line) |
|---|
| 2656 | |
|---|
| 2657 | |
|---|
| 2658 | |
|---|
| 2659 | def ensureSelectionExpanded(self): |
|---|
| 2660 | """ |
|---|
| 2661 | Ensure that the selection is visible and not in a folded area |
|---|
| 2662 | """ |
|---|
| 2663 | byteStart = self.GetSelectionStart() |
|---|
| 2664 | byteEnd = self.GetSelectionEnd() |
|---|
| 2665 | |
|---|
| 2666 | self.ensureTextRangeByBytePosExpanded(byteStart, byteEnd) |
|---|
| 2667 | |
|---|
| 2668 | self.SetSelection(byteStart, byteEnd) |
|---|
| 2669 | |
|---|
| 2670 | |
|---|
| 2671 | def setSelectionForIncSearchByCharPos(self, start, end): |
|---|
| 2672 | """ |
|---|
| 2673 | Overwrites SearchableScintillaControl.setSelectionForIncSearchByCharPos |
|---|
| 2674 | Called during incremental search to select text. Will be called with |
|---|
| 2675 | start=-1 if nothing is found to select. |
|---|
| 2676 | This variant handles showing/hiding of folded lines |
|---|
| 2677 | """ |
|---|
| 2678 | |
|---|
| 2679 | |
|---|
| 2680 | if self.incSearchPreviousHiddenLines is not None: |
|---|
| 2681 | line = self.incSearchPreviousHiddenStartLine |
|---|
| 2682 | for state in self.incSearchPreviousHiddenLines: |
|---|
| 2683 | if state: |
|---|
| 2684 | self.ShowLines(line, line) |
|---|
| 2685 | else: |
|---|
| 2686 | self.HideLines(line, line) |
|---|
| 2687 | |
|---|
| 2688 | line += 1 |
|---|
| 2689 | |
|---|
| 2690 | self.incSearchPreviousHiddenLines = None |
|---|
| 2691 | self.incSearchPreviousHiddenStartLine = -1 |
|---|
| 2692 | |
|---|
| 2693 | if start == -1: |
|---|
| 2694 | |
|---|
| 2695 | self.SetSelection(self.GetSelectionStart(), self.GetSelectionStart()) |
|---|
| 2696 | return |
|---|
| 2697 | text = self.GetText() |
|---|
| 2698 | |
|---|
| 2699 | byteStart = self.bytelenSct(text[:start]) |
|---|
| 2700 | byteEnd = byteStart + self.bytelenSct(text[start:end]) |
|---|
| 2701 | startLine = self.LineFromPosition(byteStart) |
|---|
| 2702 | endLine = self.LineFromPosition(byteEnd) |
|---|
| 2703 | |
|---|
| 2704 | |
|---|
| 2705 | shownList = [] |
|---|
| 2706 | for i in xrange(startLine, endLine + 1): |
|---|
| 2707 | shownList.append(self.GetLineVisible(i)) |
|---|
| 2708 | |
|---|
| 2709 | self.incSearchPreviousHiddenLines = shownList |
|---|
| 2710 | self.incSearchPreviousHiddenStartLine = startLine |
|---|
| 2711 | |
|---|
| 2712 | |
|---|
| 2713 | self.ShowLines(startLine, endLine) |
|---|
| 2714 | self.SetSelection(byteStart, byteEnd) |
|---|
| 2715 | |
|---|
| 2716 | |
|---|
| 2717 | |
|---|
| 2718 | def startIncrementalSearch(self, initSearch=None): |
|---|
| 2719 | self.incSearchPreviousHiddenLines = None |
|---|
| 2720 | self.incSearchPreviousHiddenStartLine = -1 |
|---|
| 2721 | |
|---|
| 2722 | super(WikiTxtCtrl, self).startIncrementalSearch(initSearch) |
|---|
| 2723 | |
|---|
| 2724 | |
|---|
| 2725 | def endIncrementalSearch(self): |
|---|
| 2726 | super(WikiTxtCtrl, self).endIncrementalSearch() |
|---|
| 2727 | |
|---|
| 2728 | self.ensureSelectionExpanded() |
|---|
| 2729 | |
|---|
| 2730 | |
|---|
| 2731 | def rewrapText(self): |
|---|
| 2732 | return self.wikiLanguageHelper.handleRewrapText(self, {}) |
|---|
| 2733 | |
|---|
| 2734 | |
|---|
| 2735 | def getNearestWordPositions(self, bytepos=None): |
|---|
| 2736 | if not bytepos: |
|---|
| 2737 | bytepos = self.GetCurrentPos() |
|---|
| 2738 | return (self.WordStartPosition(bytepos, 1), self.WordEndPosition(bytepos, 1)) |
|---|
| 2739 | |
|---|
| 2740 | |
|---|
| 2741 | def autoComplete(self): |
|---|
| 2742 | """ |
|---|
| 2743 | Called when user wants autocompletion. |
|---|
| 2744 | """ |
|---|
| 2745 | text = self.GetText() |
|---|
| 2746 | wikiDocument = self.presenter.getWikiDocument() |
|---|
| 2747 | closingBracket = self.presenter.getConfig().getboolean("main", |
|---|
| 2748 | "editor_autoComplete_closingBracket", False) |
|---|
| 2749 | |
|---|
| 2750 | bytePos = self.GetCurrentPos() |
|---|
| 2751 | lineStartBytePos = self.PositionFromLine(self.LineFromPosition(bytePos)) |
|---|
| 2752 | |
|---|
| 2753 | lineStartCharPos = len(self.GetTextRange(0, lineStartBytePos)) |
|---|
| 2754 | charPos = lineStartCharPos + len(self.GetTextRange(lineStartBytePos, |
|---|
| 2755 | bytePos)) |
|---|
| 2756 | |
|---|
| 2757 | acResultTuples = self.wikiLanguageHelper.prepareAutoComplete(self, text, |
|---|
| 2758 | charPos, lineStartCharPos, wikiDocument, self.getLoadedDocPage(), |
|---|
| 2759 | {"closingBracket": closingBracket, "builtinAttribs": True}) |
|---|
| 2760 | |
|---|
| 2761 | if len(acResultTuples) > 0: |
|---|
| 2762 | self.presenter.getWikiDocument().getCollator().sortByFirst( |
|---|
| 2763 | acResultTuples) |
|---|
| 2764 | |
|---|
| 2765 | self.autoCompBackBytesMap = dict( ( |
|---|
| 2766 | (art[1], self.bytelenSct(text[charPos - art[2]:charPos])) |
|---|
| 2767 | for art in acResultTuples) ) |
|---|
| 2768 | |
|---|
| 2769 | self.UserListShow(1, u"\x01".join( |
|---|
| 2770 | [art[1] for art in acResultTuples])) |
|---|
| 2771 | |
|---|
| 2772 | |
|---|
| 2773 | def OnModified(self, evt): |
|---|
| 2774 | if not self.ignoreOnChange: |
|---|
| 2775 | |
|---|
| 2776 | if evt.GetModificationType() & \ |
|---|
| 2777 | (wx.stc.STC_MOD_INSERTTEXT | wx.stc.STC_MOD_DELETETEXT): |
|---|
| 2778 | |
|---|
| 2779 | self.presenter.informEditorTextChanged(self) |
|---|
| 2780 | |
|---|
| 2781 | |
|---|
| 2782 | |
|---|
| 2783 | |
|---|
| 2784 | |
|---|
| 2785 | |
|---|
| 2786 | def OnCharAdded(self, evt): |
|---|
| 2787 | "When the user presses enter reindent to the previous level" |
|---|
| 2788 | |
|---|
| 2789 | |
|---|
| 2790 | |
|---|
| 2791 | evt.Skip() |
|---|
| 2792 | key = evt.GetKey() |
|---|
| 2793 | |
|---|
| 2794 | if key == 10: |
|---|
| 2795 | text = self.GetText() |
|---|
| 2796 | wikiDocument = self.presenter.getWikiDocument() |
|---|
| 2797 | bytePos = self.GetCurrentPos() |
|---|
| 2798 | lineStartBytePos = self.PositionFromLine(self.LineFromPosition(bytePos)) |
|---|
| 2799 | |
|---|
| 2800 | lineStartCharPos = len(self.GetTextRange(0, lineStartBytePos)) |
|---|
| 2801 | charPos = lineStartCharPos + len(self.GetTextRange(lineStartBytePos, |
|---|
| 2802 | bytePos)) |
|---|
| 2803 | |
|---|
| 2804 | autoUnbullet = self.presenter.getConfig().getboolean("main", |
|---|
| 2805 | "editor_autoUnbullets", False) |
|---|
| 2806 | |
|---|
| 2807 | settings = { |
|---|
| 2808 | "autoUnbullet": autoUnbullet, |
|---|
| 2809 | "autoBullets": self.autoBullets, |
|---|
| 2810 | "autoIndent": self.autoIndent |
|---|
| 2811 | } |
|---|
| 2812 | |
|---|
| 2813 | self.wikiLanguageHelper.handleNewLineAfterEditor(self, text, |
|---|
| 2814 | charPos, lineStartCharPos, wikiDocument, settings) |
|---|
| 2815 | |
|---|
| 2816 | |
|---|
| 2817 | def _getExpandedByteSelectionToLine(self, extendOverChildren): |
|---|
| 2818 | """ |
|---|
| 2819 | Move the start of current selection to start of the line it's in and |
|---|
| 2820 | move end of selection to end of its line. |
|---|
| 2821 | """ |
|---|
| 2822 | selByteStart = self.GetSelectionStart(); |
|---|
| 2823 | selByteEnd = self.GetSelectionEnd(); |
|---|
| 2824 | lastLine = self.LineFromPosition(selByteEnd) |
|---|
| 2825 | selByteStart = self.PositionFromLine(self.LineFromPosition(selByteStart)) |
|---|
| 2826 | selByteEnd = self.PositionFromLine(lastLine + 1) |
|---|
| 2827 | |
|---|
| 2828 | if extendOverChildren: |
|---|
| 2829 | |
|---|
| 2830 | |
|---|
| 2831 | lastLineDeep = StringOps.splitIndentDeepness(self.GetLine(lastLine))[0] |
|---|
| 2832 | |
|---|
| 2833 | testLine = lastLine + 1 |
|---|
| 2834 | while True: |
|---|
| 2835 | testLineContent = self.GetLine(testLine) |
|---|
| 2836 | if len(testLineContent) == 0: |
|---|
| 2837 | |
|---|
| 2838 | break |
|---|
| 2839 | |
|---|
| 2840 | if StringOps.splitIndentDeepness(testLineContent)[0] <= lastLineDeep: |
|---|
| 2841 | break |
|---|
| 2842 | |
|---|
| 2843 | testLine += 1 |
|---|
| 2844 | |
|---|
| 2845 | selByteEnd = self.PositionFromLine(testLine) |
|---|
| 2846 | |
|---|
| 2847 | self.SetSelectionMode(0) |
|---|
| 2848 | self.SetSelectionStart(selByteStart) |
|---|
| 2849 | self.SetSelectionMode(0) |
|---|
| 2850 | self.SetSelectionEnd(selByteEnd) |
|---|
| 2851 | |
|---|
| 2852 | return selByteStart, selByteEnd |
|---|
| 2853 | |
|---|
| 2854 | |
|---|
| 2855 | |
|---|
| 2856 | def moveSelectedLinesOneUp(self, extendOverChildren): |
|---|
| 2857 | """ |
|---|
| 2858 | Extend current selection to full logical lines and move selected lines |
|---|
| 2859 | upward one line. |
|---|
| 2860 | extendOverChildren -- iff true, extend selection over lines more indented |
|---|
| 2861 | below the initial selection |
|---|
| 2862 | """ |
|---|
| 2863 | self.BeginUndoAction() |
|---|
| 2864 | try: |
|---|
| 2865 | selByteStart, selByteEnd = self._getExpandedByteSelectionToLine( |
|---|
| 2866 | extendOverChildren) |
|---|
| 2867 | |
|---|
| 2868 | firstLine = self.LineFromPosition(selByteStart) |
|---|
| 2869 | if firstLine > 0: |
|---|
| 2870 | content = self.GetSelectedText() |
|---|
| 2871 | if len(content) > 0: |
|---|
| 2872 | if content[-1] == u"\n": |
|---|
| 2873 | selByteEnd -= 1 |
|---|
| 2874 | else: |
|---|
| 2875 | content += u"\n" |
|---|
| 2876 | |
|---|
| 2877 | |
|---|
| 2878 | self.ReplaceSelection("") |
|---|
| 2879 | target = self.PositionFromLine(firstLine - 1) |
|---|
| 2880 | self.InsertText(target, content) |
|---|
| 2881 | self.SetSelectionMode(0) |
|---|
| 2882 | self.SetSelectionStart(target) |
|---|
| 2883 | self.SetSelectionMode(0) |
|---|
| 2884 | self.SetSelectionEnd(target + (selByteEnd - selByteStart)) |
|---|
| 2885 | finally: |
|---|
| 2886 | self.EndUndoAction() |
|---|
| 2887 | |
|---|
| 2888 | |
|---|
| 2889 | |
|---|
| 2890 | def moveSelectedLinesOneDown(self, extendOverChildren): |
|---|
| 2891 | """ |
|---|
| 2892 | Extend current selection to full logical lines and move selected lines |
|---|
| 2893 | upward one line. |
|---|
| 2894 | extendOverChildren -- iff true, extend selection over lines more indented |
|---|
| 2895 | below the initial selection |
|---|
| 2896 | """ |
|---|
| 2897 | self.BeginUndoAction() |
|---|
| 2898 | try: |
|---|
| 2899 | selByteStart, selByteEnd = self._getExpandedByteSelectionToLine( |
|---|
| 2900 | extendOverChildren) |
|---|
| 2901 | |
|---|
| 2902 | lastLine = self.LineFromPosition(selByteEnd) |
|---|
| 2903 | lineCount = self.GetLineCount() - 1 |
|---|
| 2904 | if lastLine <= lineCount: |
|---|
| 2905 | content = self.GetSelectedText() |
|---|
| 2906 | if len(content) > 0: |
|---|
| 2907 | |
|---|
| 2908 | |
|---|
| 2909 | target = self.PositionFromLine(lastLine + 1) |
|---|
| 2910 | target -= selByteEnd - selByteStart |
|---|
| 2911 | |
|---|
| 2912 | if content[-1] == u"\n": |
|---|
| 2913 | selByteEnd -= 1 |
|---|
| 2914 | else: |
|---|
| 2915 | content += u"\n" |
|---|
| 2916 | |
|---|
| 2917 | self.ReplaceSelection("") |
|---|
| 2918 | if self.GetTextRange(target - 1, |
|---|
| 2919 | target) != u"\n": |
|---|
| 2920 | self.InsertText(target, u"\n") |
|---|
| 2921 | target += 1 |
|---|
| 2922 | |
|---|
| 2923 | self.InsertText(target, content) |
|---|
| 2924 | self.SetSelectionMode(0) |
|---|
| 2925 | self.SetSelectionStart(target) |
|---|
| 2926 | self.SetSelectionMode(0) |
|---|
| 2927 | self.SetSelectionEnd(target + (selByteEnd - selByteStart)) |
|---|
| 2928 | finally: |
|---|
| 2929 | self.EndUndoAction() |
|---|
| 2930 | |
|---|
| 2931 | |
|---|
| 2932 | |
|---|
| 2933 | def OnKeyDown(self, evt): |
|---|
| 2934 | key = evt.GetKeyCode() |
|---|
| 2935 | |
|---|
| 2936 | self.lastKeyPressed = time() |
|---|
| 2937 | accP = getAccelPairFromKeyDown(evt) |
|---|
| 2938 | matchesAccelPair = self.presenter.getMainControl().keyBindings.\ |
|---|
| 2939 | matchesAccelPair |
|---|
| 2940 | |
|---|
| 2941 | |
|---|
| 2942 | |
|---|
| 2943 | |
|---|
| 2944 | |
|---|
| 2945 | |
|---|
| 2946 | |
|---|
| 2947 | |
|---|
| 2948 | |
|---|
| 2949 | |
|---|
| 2950 | |
|---|
| 2951 | |
|---|
| 2952 | |
|---|
| 2953 | |
|---|
| 2954 | |
|---|
| 2955 | |
|---|
| 2956 | |
|---|
| 2957 | |
|---|
| 2958 | |
|---|
| 2959 | |
|---|
| 2960 | if matchesAccelPair("AutoComplete", accP): |
|---|
| 2961 | |
|---|
| 2962 | |
|---|
| 2963 | self.autoComplete() |
|---|
| 2964 | |
|---|
| 2965 | elif matchesAccelPair("ActivateLink2", accP): |
|---|
| 2966 | |
|---|
| 2967 | self.activateLink() |
|---|
| 2968 | |
|---|
| 2969 | elif matchesAccelPair("ActivateLinkBackground", accP): |
|---|
| 2970 | |
|---|
| 2971 | self.activateLink(tabMode=3) |
|---|
| 2972 | |
|---|
| 2973 | elif matchesAccelPair("ActivateLink", accP): |
|---|
| 2974 | |
|---|
| 2975 | |
|---|
| 2976 | |
|---|
| 2977 | |
|---|
| 2978 | self.activateLink() |
|---|
| 2979 | |
|---|
| 2980 | elif matchesAccelPair("ActivateLinkNewTab", accP): |
|---|
| 2981 | |
|---|
| 2982 | |
|---|
| 2983 | |
|---|
| 2984 | |
|---|
| 2985 | self.activateLink(tabMode=2) |
|---|
| 2986 | |
|---|
| 2987 | elif matchesAccelPair("ActivateLinkNewWindow", accP): |
|---|
| 2988 | self.activateLink(tabMode=6) |
|---|
| 2989 | |
|---|
| 2990 | elif matchesAccelPair("LogLineUp", accP): |
|---|
| 2991 | |
|---|
| 2992 | self.moveSelectedLinesOneUp(False) |
|---|
| 2993 | elif matchesAccelPair("LogLineUpWithIndented", accP): |
|---|
| 2994 | |
|---|
| 2995 | self.moveSelectedLinesOneUp(True) |
|---|
| 2996 | elif matchesAccelPair("LogLineDown", accP): |
|---|
| 2997 | |
|---|
| 2998 | self.moveSelectedLinesOneDown(False) |
|---|
| 2999 | elif matchesAccelPair("LogLineDownWithIndented", accP): |
|---|
| 3000 | |
|---|
| 3001 | self.moveSelectedLinesOneDown(True) |
|---|
| 3002 | |
|---|
| 3003 | elif not evt.ControlDown() and not evt.ShiftDown(): |
|---|
| 3004 | if key == wx.WXK_TAB: |
|---|
| 3005 | if self.pageType == u"form": |
|---|
| 3006 | if not self._goToNextFormField(): |
|---|
| 3007 | self.presenter.getMainControl().showStatusMessage( |
|---|
| 3008 | _(u"No more fields in this 'form' page"), -1) |
|---|
| 3009 | return |
|---|
| 3010 | evt.Skip() |
|---|
| 3011 | elif key == wx.WXK_RETURN and not self.AutoCompActive(): |
|---|
| 3012 | text = self.GetText() |
|---|
| 3013 | wikiDocument = self.presenter.getWikiDocument() |
|---|
| 3014 | bytePos = self.GetCurrentPos() |
|---|
| 3015 | lineStartBytePos = self.PositionFromLine(self.LineFromPosition(bytePos)) |
|---|
| 3016 | |
|---|
| 3017 | lineStartCharPos = len(self.GetTextRange(0, lineStartBytePos)) |
|---|
| 3018 | charPos = lineStartCharPos + len(self.GetTextRange(lineStartBytePos, |
|---|
| 3019 | bytePos)) |
|---|
| 3020 | |
|---|
| 3021 | autoUnbullet = self.presenter.getConfig().getboolean("main", |
|---|
| 3022 | "editor_autoUnbullets", False) |
|---|
| 3023 | |
|---|
| 3024 | settings = { |
|---|
| 3025 | "autoUnbullet": autoUnbullet, |
|---|
| 3026 | "autoBullets": self.autoBullets, |
|---|
| 3027 | "autoIndent": self.autoIndent |
|---|
| 3028 | } |
|---|
| 3029 | |
|---|
| 3030 | if self.wikiLanguageHelper.handleNewLineBeforeEditor(self, text, |
|---|
| 3031 | charPos, lineStartCharPos, wikiDocument, settings): |
|---|
| 3032 | evt.Skip() |
|---|
| 3033 | return |
|---|
| 3034 | |
|---|
| 3035 | else: |
|---|
| 3036 | evt.Skip() |
|---|
| 3037 | |
|---|
| 3038 | else: |
|---|
| 3039 | super(WikiTxtCtrl, self).OnKeyDown(evt) |
|---|
| 3040 | |
|---|
| 3041 | |
|---|
| 3042 | def OnChar_ImeWorkaround(self, evt): |
|---|
| 3043 | """ |
|---|
| 3044 | Workaround for problem of Scintilla with some input method editors, |
|---|
| 3045 | e.g. UniKey vietnamese IME. |
|---|
| 3046 | """ |
|---|
| 3047 | key = evt.GetKeyCode() |
|---|
| 3048 | |
|---|
| 3049 | |
|---|
| 3050 | if evt.ControlDown() or (0 < key < 32): |
|---|
| 3051 | evt.Skip() |
|---|
| 3052 | return |
|---|
| 3053 | |
|---|
| 3054 | if key >= wx.WXK_START and (not isUnicode() or evt.GetUnicodeKey() != key): |
|---|
| 3055 | evt.Skip() |
|---|
| 3056 | return |
|---|
| 3057 | |
|---|
| 3058 | if isUnicode(): |
|---|
| 3059 | unichar = unichr(evt.GetUnicodeKey()) |
|---|
| 3060 | else: |
|---|
| 3061 | unichar = StringOps.mbcsDec(chr(key))[0] |
|---|
| 3062 | |
|---|
| 3063 | self.ReplaceSelection(unichar) |
|---|
| 3064 | |
|---|
| 3065 | |
|---|
| 3066 | if isLinux(): |
|---|
| 3067 | def OnSetFocus(self, evt): |
|---|
| 3068 | |
|---|
| 3069 | evt.Skip() |
|---|
| 3070 | |
|---|
| 3071 | wikiPage = self.getLoadedDocPage() |
|---|
| 3072 | if wikiPage is None: |
|---|
| 3073 | return |
|---|
| 3074 | if not isinstance(wikiPage, |
|---|
| 3075 | (DocPages.DataCarryingPage, DocPages.AliasWikiPage)): |
|---|
| 3076 | return |
|---|
| 3077 | |
|---|
| 3078 | try: |
|---|
| 3079 | wikiPage.checkFileSignatureAndMarkDirty() |
|---|
| 3080 | except (IOError, OSError, DbAccessError), e: |
|---|
| 3081 | self.presenter.getMainControl().lostAccess(e) |
|---|
| 3082 | |
|---|
| 3083 | |
|---|
| 3084 | else: |
|---|
| 3085 | def OnSetFocus(self, evt): |
|---|
| 3086 | self.presenter.makeCurrent() |
|---|
| 3087 | evt.Skip() |
|---|
| 3088 | |
|---|
| 3089 | wikiPage = self.getLoadedDocPage() |
|---|
| 3090 | if wikiPage is None: |
|---|
| 3091 | return |
|---|
| 3092 | if not isinstance(wikiPage, |
|---|
| 3093 | (DocPages.DataCarryingPage, DocPages.AliasWikiPage)): |
|---|
| 3094 | return |
|---|
| 3095 | |
|---|
| 3096 | try: |
|---|
| 3097 | wikiPage.checkFileSignatureAndMarkDirty() |
|---|
| 3098 | except (IOError, OSError, DbAccessError), e: |
|---|
| 3099 | self.presenter.getMainControl().lostAccess(e) |
|---|
| 3100 | |
|---|
| 3101 | |
|---|
| 3102 | |
|---|
| 3103 | |
|---|
| 3104 | def OnUserListSelection(self, evt): |
|---|
| 3105 | text = evt.GetText() |
|---|
| 3106 | toerase = self.autoCompBackBytesMap[text] |
|---|
| 3107 | |
|---|
| 3108 | self.SetSelection(self.GetCurrentPos() - toerase, self.GetCurrentPos()) |
|---|
| 3109 | |
|---|
| 3110 | self.ReplaceSelection(text) |
|---|
| 3111 | |
|---|
| 3112 | |
|---|
| 3113 | def OnClick(self, evt): |
|---|
| 3114 | if evt.ControlDown(): |
|---|
| 3115 | x = evt.GetX() |
|---|
| 3116 | y = evt.GetY() |
|---|
| 3117 | if not self.activateLink(wx.Point(x, y)): |
|---|
| 3118 | evt.Skip() |
|---|
| 3119 | else: |
|---|
| 3120 | evt.Skip() |
|---|
| 3121 | |
|---|
| 3122 | def OnMiddleDown(self, evt): |
|---|
| 3123 | if not evt.ControlDown(): |
|---|
| 3124 | middleConfig = self.presenter.getConfig().getint("main", |
|---|
| 3125 | "mouse_middleButton_withoutCtrl", 2) |
|---|
| 3126 | else: |
|---|
| 3127 | middleConfig = self.presenter.getConfig().getint("main", |
|---|
| 3128 | "mouse_middleButton_withCtrl", 3) |
|---|
| 3129 | |
|---|
| 3130 | tabMode = Configuration.MIDDLE_MOUSE_CONFIG_TO_TABMODE[middleConfig] |
|---|
| 3131 | |
|---|
| 3132 | if not self.activateLink(evt.GetPosition(), tabMode=tabMode): |
|---|
| 3133 | evt.Skip() |
|---|
| 3134 | |
|---|
| 3135 | |
|---|
| 3136 | def OnDoubleClick(self, evt): |
|---|
| 3137 | x = evt.GetX() |
|---|
| 3138 | y = evt.GetY() |
|---|
| 3139 | if not self.activateLink(wx.Point(x, y)): |
|---|
| 3140 | evt.Skip() |
|---|
| 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 | |
|---|
| 3167 | |
|---|
| 3168 | |
|---|
| 3169 | |
|---|
| 3170 | def onIdleVisible(self, miscevt): |
|---|
| 3171 | if (self.IsEnabled()): |
|---|
| 3172 | if self.presenter.isCurrent(): |
|---|
| 3173 | |
|---|
| 3174 | currentLine = self.GetCurrentLine()+1 |
|---|
| 3175 | currentPos = self.GetCurrentPos() |
|---|
| 3176 | currentCol = self.GetColumn(currentPos) |
|---|
| 3177 | self.presenter.SetStatusText(_(u"Line: %d Col: %d Pos: %d") % |
|---|
| 3178 | (currentLine, currentCol, currentPos), 2) |
|---|
| 3179 | |
|---|
| 3180 | |
|---|
| 3181 | def OnDestroy(self, evt): |
|---|
| 3182 | |
|---|
| 3183 | |
|---|
| 3184 | wx.TheClipboard.Flush() |
|---|
| 3185 | evt.Skip() |
|---|
| 3186 | |
|---|
| 3187 | |
|---|
| 3188 | def OnMarginClick(self, evt): |
|---|
| 3189 | if evt.GetMargin() == self.FOLD_MARGIN: |
|---|
| 3190 | pos = evt.GetPosition() |
|---|
| 3191 | line = self.LineFromPosition(pos) |
|---|
| 3192 | modifiers = evt.GetModifiers() |
|---|
| 3193 | |
|---|
| 3194 | self.ToggleFold(line) |
|---|
| 3195 | self.repairFoldingVisibility() |
|---|
| 3196 | |
|---|
| 3197 | evt.Skip() |
|---|
| 3198 | |
|---|
| 3199 | |
|---|
| 3200 | |
|---|
| 3201 | def _threadShowCalltip(self, wikiDocument, charPos, bytePos, |
|---|
| 3202 | threadstop=DUMBTHREADSTOP): |
|---|
| 3203 | try: |
|---|
| 3204 | docPage = self.getLoadedDocPage() |
|---|
| 3205 | if docPage is None: |
|---|
| 3206 | return |
|---|
| 3207 | |
|---|
| 3208 | pageAst = docPage.getLivePageAst(threadstop=threadstop) |
|---|
| 3209 | |
|---|
| 3210 | astNodes = pageAst.findNodesForCharPos(charPos) |
|---|
| 3211 | |
|---|
| 3212 | if charPos > 0: |
|---|
| 3213 | |
|---|
| 3214 | |
|---|
| 3215 | astNodes += pageAst.findNodesForCharPos(charPos - 1) |
|---|
| 3216 | |
|---|
| 3217 | callTip = None |
|---|
| 3218 | for astNode in astNodes: |
|---|
| 3219 | if astNode.name == "wikiWord": |
|---|
| 3220 | threadstop.testRunning() |
|---|
| 3221 | wikiWord = wikiDocument.getWikiPageNameForLinkTerm( |
|---|
| 3222 | astNode.wikiWord) |
|---|
| 3223 | |
|---|
| 3224 | |
|---|
| 3225 | callInMainThread( |
|---|
| 3226 | self.presenter.getMainControl().showStatusMessage, |
|---|
| 3227 | _(u"Link to page: %s") % wikiWord, 0) |
|---|
| 3228 | |
|---|
| 3229 | if wikiWord is not None: |
|---|
| 3230 | propList = wikiDocument.getAttributeTriples( |
|---|
| 3231 | wikiWord, u"short_hint", None) |
|---|
| 3232 | if len(propList) > 0: |
|---|
| 3233 | callTip = propList[-1][2] |
|---|
| 3234 | break |
|---|
| 3235 | elif astNode.name == "urlLink": |
|---|
| 3236 | |
|---|
| 3237 | if not self.presenter.getConfig().getboolean("main", |
|---|
| 3238 | "editor_imageTooltips_localUrls", True): |
|---|
| 3239 | continue |
|---|
| 3240 | |
|---|
| 3241 | |
|---|
| 3242 | if astNode.appendixNode is None: |
|---|
| 3243 | appendixDict = {} |
|---|
| 3244 | else: |
|---|
| 3245 | appendixDict = dict(astNode.appendixNode.entries) |
|---|
| 3246 | |
|---|
| 3247 | |
|---|
| 3248 | if appendixDict.has_key("l"): |
|---|
| 3249 | urlAsImage = False |
|---|
| 3250 | elif appendixDict.has_key("i"): |
|---|
| 3251 | urlAsImage = True |
|---|
| 3252 | |
|---|
| 3253 | |
|---|
| 3254 | |
|---|
| 3255 | |
|---|
| 3256 | |
|---|
| 3257 | |
|---|
| 3258 | elif astNode.url.lower().split(".")[-1] in \ |
|---|
| 3259 | ("jpg", "jpeg", "gif", "png", "tif", "bmp"): |
|---|
| 3260 | urlAsImage = True |
|---|
| 3261 | else: |
|---|
| 3262 | urlAsImage = False |
|---|
| 3263 | |
|---|
| 3264 | |
|---|
| 3265 | if urlAsImage: |
|---|
| 3266 | path = self.presenter.getWikiDocument()\ |
|---|
| 3267 | .makeFileUrlAbsPath(astNode.url) |
|---|
| 3268 | |
|---|
| 3269 | if path is not None and isfile(path): |
|---|
| 3270 | if imghdr.what(path): |
|---|
| 3271 | config = self.presenter.getConfig() |
|---|
| 3272 | maxWidth = config.getint("main", |
|---|
| 3273 | "editor_imageTooltips_maxWidth", 200) |
|---|
| 3274 | maxHeight = config.getint("main", |
|---|
| 3275 | "editor_imageTooltips_maxHeight", 200) |
|---|
| 3276 | |
|---|
| 3277 | def SetImageTooltip(path): |
|---|
| 3278 | self.tooltip_image = ImageTooltipPanel(self, |
|---|
| 3279 | path, maxWidth, maxHeight) |
|---|
| 3280 | threadstop.testRunning() |
|---|
| 3281 | callInMainThread(SetImageTooltip, path) |
|---|
| 3282 | else: |
|---|
| 3283 | callTip = _(u"Not a valid image") |
|---|
| 3284 | break |
|---|
| 3285 | |
|---|
| 3286 | if callTip: |
|---|
| 3287 | threadstop.testRunning() |
|---|
| 3288 | callInMainThread(self.CallTipShow, bytePos, callTip) |
|---|
| 3289 | |
|---|
| 3290 | except NotCurrentThreadException: |
|---|
| 3291 | pass |
|---|
| 3292 | |
|---|
| 3293 | @contextlib.contextmanager |
|---|
| 3294 | def dwellLock(self): |
|---|
| 3295 | if self.dwellLockCounter == 0: |
|---|
| 3296 | self.OnDwellEnd(None) |
|---|
| 3297 | |
|---|
| 3298 | self.dwellLockCounter += 1 |
|---|
| 3299 | yield |
|---|
| 3300 | self.dwellLockCounter -= 1 |
|---|
| 3301 | |
|---|
| 3302 | |
|---|
| 3303 | def OnDwellStart(self, evt): |
|---|
| 3304 | if self.dwellLockCounter > 0: |
|---|
| 3305 | return |
|---|
| 3306 | |
|---|
| 3307 | wikiDocument = self.presenter.getWikiDocument() |
|---|
| 3308 | if wikiDocument is None: |
|---|
| 3309 | return |
|---|
| 3310 | bytePos = evt.GetPosition() |
|---|
| 3311 | charPos = len(self.GetTextRange(0, bytePos)) |
|---|
| 3312 | |
|---|
| 3313 | thread = threading.Thread(target=self._threadShowCalltip, |
|---|
| 3314 | args=(wikiDocument, charPos, bytePos), |
|---|
| 3315 | kwargs={"threadstop": self.calltipThreadHolder}) |
|---|
| 3316 | |
|---|
| 3317 | self.calltipThreadHolder.setThread(thread) |
|---|
| 3318 | thread.setDaemon(True) |
|---|
| 3319 | thread.start() |
|---|
| 3320 | |
|---|
| 3321 | |
|---|
| 3322 | def OnDwellEnd(self, evt): |
|---|
| 3323 | if self.dwellLockCounter > 0: |
|---|
| 3324 | return |
|---|
| 3325 | |
|---|
| 3326 | self.calltipThreadHolder.setThread(None) |
|---|
| 3327 | self.CallTipCancel() |
|---|
| 3328 | |
|---|
| 3329 | |
|---|
| 3330 | callInMainThread(self.presenter.getMainControl().showStatusMessage, "", |
|---|
| 3331 | 0) |
|---|
| 3332 | |
|---|
| 3333 | if self.tooltip_image: |
|---|
| 3334 | self.tooltip_image.Close() |
|---|
| 3335 | self.tooltip_image = None |
|---|
| 3336 | |
|---|
| 3337 | @staticmethod |
|---|
| 3338 | def userActionPasteFiles(unifActionName, paramDict): |
|---|
| 3339 | """ |
|---|
| 3340 | User action to handle pasting or dropping of files into editor. |
|---|
| 3341 | """ |
|---|
| 3342 | editor = paramDict.get("editor") |
|---|
| 3343 | if editor is None: |
|---|
| 3344 | return |
|---|
| 3345 | |
|---|
| 3346 | filenames = paramDict.get("filenames") |
|---|
| 3347 | x = paramDict.get("x") |
|---|
| 3348 | y = paramDict.get("y") |
|---|
| 3349 | |
|---|
| 3350 | dlgParams = WikiTxtDialogs.FilePasteParams() |
|---|
| 3351 | |
|---|
| 3352 | dlgParams.readOptionsFromConfig( |
|---|
| 3353 | editor.presenter.getMainControl().getConfig()) |
|---|
| 3354 | |
|---|
| 3355 | if unifActionName == u"action/editor/this/paste/files/insert/url/ask": |
|---|
| 3356 | |
|---|
| 3357 | if not paramDict.get("processDirectly", False): |
|---|
| 3358 | |
|---|
| 3359 | |
|---|
| 3360 | |
|---|
| 3361 | |
|---|
| 3362 | paramDict["processDirectly"] = True |
|---|
| 3363 | wx.CallAfter(WikiTxtCtrl.userActionPasteFiles, unifActionName, |
|---|
| 3364 | paramDict) |
|---|
| 3365 | return |
|---|
| 3366 | |
|---|
| 3367 | dlgParams = WikiTxtDialogs.FilePasteDialog.runModal( |
|---|
| 3368 | editor.presenter.getMainControl(), -1, dlgParams) |
|---|
| 3369 | if dlgParams is None: |
|---|
| 3370 | |
|---|
| 3371 | return |
|---|
| 3372 | |
|---|
| 3373 | unifActionName = dlgParams.unifActionName |
|---|
| 3374 | |
|---|
| 3375 | moveToStorage = False |
|---|
| 3376 | |
|---|
| 3377 | if unifActionName == u"action/editor/this/paste/files/insert/url/absolute": |
|---|
| 3378 | modeToStorage = False |
|---|
| 3379 | modeRelativeUrl = False |
|---|
| 3380 | elif unifActionName == u"action/editor/this/paste/files/insert/url/relative": |
|---|
| 3381 | modeToStorage = False |
|---|
| 3382 | modeRelativeUrl = True |
|---|
| 3383 | elif unifActionName == u"action/editor/this/paste/files/insert/url/tostorage": |
|---|
| 3384 | modeToStorage = True |
|---|
| 3385 | modeRelativeUrl = False |
|---|
| 3386 | elif unifActionName == u"action/editor/this/paste/files/insert/url/movetostorage": |
|---|
| 3387 | modeToStorage = True |
|---|
| 3388 | modeRelativeUrl = False |
|---|
| 3389 | moveToStorage = True |
|---|
| 3390 | else: |
|---|
| 3391 | return |
|---|
| 3392 | |
|---|
| 3393 | try: |
|---|
| 3394 | prefix = StringOps.strftimeUB(dlgParams.rawPrefix) |
|---|
| 3395 | except: |
|---|
| 3396 | traceback.print_exc() |
|---|
| 3397 | prefix = u"" |
|---|
| 3398 | |
|---|
| 3399 | try: |
|---|
| 3400 | middle = StringOps.strftimeUB(dlgParams.rawMiddle) |
|---|
| 3401 | except: |
|---|
| 3402 | traceback.print_exc() |
|---|
| 3403 | middle = u" " |
|---|
| 3404 | |
|---|
| 3405 | try: |
|---|
| 3406 | suffix = StringOps.strftimeUB(dlgParams.rawSuffix) |
|---|
| 3407 | except: |
|---|
| 3408 | traceback.print_exc() |
|---|
| 3409 | suffix = u"" |
|---|
| 3410 | |
|---|
| 3411 | |
|---|
| 3412 | urls = [] |
|---|
| 3413 | |
|---|
| 3414 | for fn in filenames: |
|---|
| 3415 | protocol = None |
|---|
| 3416 | if fn.endswith(u".wiki"): |
|---|
| 3417 | protocol = "wiki" |
|---|
| 3418 | |
|---|
| 3419 | toStorage = False |
|---|
| 3420 | if modeToStorage and protocol is None: |
|---|
| 3421 | |
|---|
| 3422 | fs = editor.presenter.getWikiDocument().getFileStorage() |
|---|
| 3423 | try: |
|---|
| 3424 | fn = fs.createDestPath(fn, move=moveToStorage) |
|---|
| 3425 | toStorage = True |
|---|
| 3426 | except Exception, e: |
|---|
| 3427 | traceback.print_exc() |
|---|
| 3428 | editor.presenter.getMainControl().displayErrorMessage( |
|---|
| 3429 | _(u"Couldn't copy file"), e) |
|---|
| 3430 | return |
|---|
| 3431 | |
|---|
| 3432 | urls.append(editor.wikiLanguageHelper.createUrlLinkFromPath( |
|---|
| 3433 | editor.presenter.getWikiDocument(), fn, |
|---|
| 3434 | relative=modeRelativeUrl or toStorage, |
|---|
| 3435 | bracketed=dlgParams.bracketedUrl, protocol=protocol)) |
|---|
| 3436 | |
|---|
| 3437 | editor.handleDropText(x, y, prefix + middle.join(urls) + suffix) |
|---|
| 3438 | |
|---|
| 3439 | |
|---|
| 3440 | def GetEOLChar(self): |
|---|
| 3441 | """ |
|---|
| 3442 | Gets the end of line char currently being used |
|---|
| 3443 | """ |
|---|
| 3444 | m_id = self.GetEOLMode() |
|---|
| 3445 | if m_id == wx.stc.STC_EOL_CR: |
|---|
| 3446 | return u'\r' |
|---|
| 3447 | elif m_id == wx.stc.STC_EOL_CRLF: |
|---|
| 3448 | return u'\r\n' |
|---|
| 3449 | else: |
|---|
| 3450 | return u'\n' |
|---|
| 3451 | |
|---|
| 3452 | def GetLastVisibleLine(self): |
|---|
| 3453 | """ |
|---|
| 3454 | Returns line number of the first visible line in viewport |
|---|
| 3455 | """ |
|---|
| 3456 | return self.GetFirstVisibleLine() + self.LinesOnScreen() - 1 |
|---|
| 3457 | |
|---|
| 3458 | def GetMiddleVisibleLine(self): |
|---|
| 3459 | """ |
|---|
| 3460 | Returns line number of the middle visible line in viewport |
|---|
| 3461 | """ |
|---|
| 3462 | |
|---|
| 3463 | fl = self.GetFirstVisibleLine() |
|---|
| 3464 | ll = self.GetLastVisibleLine() |
|---|
| 3465 | |
|---|
| 3466 | lines = ll - fl |
|---|
| 3467 | |
|---|
| 3468 | mid = fl + lines // 2 |
|---|
| 3469 | |
|---|
| 3470 | |
|---|
| 3471 | |
|---|
| 3472 | |
|---|
| 3473 | |
|---|
| 3474 | |
|---|
| 3475 | return mid |
|---|
| 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 | |
|---|
| 3502 | |
|---|
| 3503 | |
|---|
| 3504 | |
|---|
| 3505 | class WikiTxtCtrlDropTarget(wx.PyDropTarget): |
|---|
| 3506 | def __init__(self, editor): |
|---|
| 3507 | wx.PyDropTarget.__init__(self) |
|---|
| 3508 | |
|---|
| 3509 | self.editor = editor |
|---|
| 3510 | self.resetDObject() |
|---|
| 3511 | |
|---|
| 3512 | def resetDObject(self): |
|---|
| 3513 | """ |
|---|
| 3514 | (Re)sets the dataobject at init and after each drop |
|---|
| 3515 | """ |
|---|
| 3516 | dataob = wx.DataObjectComposite() |
|---|
| 3517 | self.tobj = wx.TextDataObject() |
|---|
| 3518 | |
|---|
| 3519 | dataob.Add(self.tobj) |
|---|
| 3520 | |
|---|
| 3521 | self.fobj = wx.FileDataObject() |
|---|
| 3522 | dataob.Add(self.fobj) |
|---|
| 3523 | |
|---|
| 3524 | self.dataob = dataob |
|---|
| 3525 | self.SetDataObject(dataob) |
|---|
| 3526 | |
|---|
| 3527 | |
|---|
| 3528 | def OnDragOver(self, x, y, defresult): |
|---|
| 3529 | return self.editor.DoDragOver(x, y, defresult) |
|---|
| 3530 | |
|---|
| 3531 | |
|---|
| 3532 | def OnData(self, x, y, defresult): |
|---|
| 3533 | try: |
|---|
| 3534 | if self.GetData(): |
|---|
| 3535 | fnames = self.fobj.GetFilenames() |
|---|
| 3536 | text = self.tobj.GetText() |
|---|
| 3537 | |
|---|
| 3538 | if fnames: |
|---|
| 3539 | self.OnDropFiles(x, y, fnames) |
|---|
| 3540 | elif text: |
|---|
| 3541 | text = StringOps.lineendToInternal(text) |
|---|
| 3542 | self.OnDropText(x, y, text) |
|---|
| 3543 | |
|---|
| 3544 | return defresult |
|---|
| 3545 | |
|---|
| 3546 | finally: |
|---|
| 3547 | self.resetDObject() |
|---|
| 3548 | |
|---|
| 3549 | |
|---|
| 3550 | def OnDropText(self, x, y, text): |
|---|
| 3551 | text = StringOps.lineendToInternal(text) |
|---|
| 3552 | self.editor.handleDropText(x, y, text) |
|---|
| 3553 | |
|---|
| 3554 | |
|---|
| 3555 | def OnDropFiles(self, x, y, filenames): |
|---|
| 3556 | urls = [] |
|---|
| 3557 | |
|---|
| 3558 | |
|---|
| 3559 | controlPressed = wx.GetKeyState(wx.WXK_CONTROL) |
|---|
| 3560 | shiftPressed = wx.GetKeyState(wx.WXK_SHIFT) |
|---|
| 3561 | |
|---|
| 3562 | if isLinux(): |
|---|
| 3563 | |
|---|
| 3564 | |
|---|
| 3565 | try: |
|---|
| 3566 | filenames = [StringOps.utf8Dec(fn.encode("latin-1"))[0] |
|---|
| 3567 | for fn in filenames] |
|---|
| 3568 | except (UnicodeEncodeError, UnicodeDecodeError): |
|---|
| 3569 | pass |
|---|
| 3570 | |
|---|
| 3571 | |
|---|
| 3572 | mc = self.editor.presenter.getMainControl() |
|---|
| 3573 | |
|---|
| 3574 | paramDict = {"editor": self.editor, "filenames": filenames, |
|---|
| 3575 | "x": x, "y": y, "main control": mc} |
|---|
| 3576 | |
|---|
| 3577 | if controlPressed: |
|---|
| 3578 | suffix = u"/modkeys/ctrl" |
|---|
| 3579 | elif shiftPressed: |
|---|
| 3580 | suffix = u"/modkeys/shift" |
|---|
| 3581 | else: |
|---|
| 3582 | suffix = u"" |
|---|
| 3583 | |
|---|
| 3584 | mc.getUserActionCoord().reactOnUserEvent( |
|---|
| 3585 | u"mouse/leftdrop/editor/files" + suffix, paramDict) |
|---|
| 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 | |
|---|
| 3612 | |
|---|
| 3613 | |
|---|
| 3614 | |
|---|
| 3615 | _ACTIONS = tuple( UserActionCoord.SimpleAction("", unifName, |
|---|
| 3616 | WikiTxtCtrl.userActionPasteFiles) for unifName in ( |
|---|
| 3617 | u"action/editor/this/paste/files/insert/url/absolute", |
|---|
| 3618 | u"action/editor/this/paste/files/insert/url/relative", |
|---|
| 3619 | u"action/editor/this/paste/files/insert/url/tostorage", |
|---|
| 3620 | u"action/editor/this/paste/files/insert/url/movetostorage", |
|---|
| 3621 | u"action/editor/this/paste/files/insert/url/ask") ) |
|---|
| 3622 | |
|---|
| 3623 | |
|---|
| 3624 | UserActionCoord.registerActions(_ACTIONS) |
|---|
| 3625 | |
|---|
| 3626 | |
|---|
| 3627 | |
|---|
| 3628 | _CONTEXT_MENU_INTEXT_SPELLING = \ |
|---|
| 3629 | u""" |
|---|
| 3630 | - |
|---|
| 3631 | Ignore;CMD_ADD_THIS_SPELLING_SESSION |
|---|
| 3632 | Add Globally;CMD_ADD_THIS_SPELLING_GLOBAL |
|---|
| 3633 | Add Locally;CMD_ADD_THIS_SPELLING_LOCAL |
|---|
| 3634 | """ |
|---|
| 3635 | |
|---|
| 3636 | |
|---|
| 3637 | _CONTEXT_MENU_INTEXT_BASE = \ |
|---|
| 3638 | u""" |
|---|
| 3639 | - |
|---|
| 3640 | Undo;CMD_UNDO |
|---|
| 3641 | Redo;CMD_REDO |
|---|
| 3642 | - |
|---|
| 3643 | Cut;CMD_CLIPBOARD_CUT |
|---|
| 3644 | Copy;CMD_CLIPBOARD_COPY |
|---|
| 3645 | Paste;CMD_CLIPBOARD_PASTE |
|---|
| 3646 | Delete;CMD_TEXT_DELETE |
|---|
| 3647 | - |
|---|
| 3648 | Select All;CMD_SELECT_ALL |
|---|
| 3649 | """ |
|---|
| 3650 | |
|---|
| 3651 | |
|---|
| 3652 | _CONTEXT_MENU_INTEXT_ACTIVATE = \ |
|---|
| 3653 | u""" |
|---|
| 3654 | - |
|---|
| 3655 | Follow Link;CMD_ACTIVATE_THIS |
|---|
| 3656 | Follow Link New Tab;CMD_ACTIVATE_NEW_TAB_THIS |
|---|
| 3657 | Follow Link New Tab Backgrd.;CMD_ACTIVATE_NEW_TAB_BACKGROUND_THIS |
|---|
| 3658 | Follow Link New Window;CMD_ACTIVATE_NEW_WINDOW_THIS |
|---|
| 3659 | """ |
|---|
| 3660 | |
|---|
| 3661 | _CONTEXT_MENU_INTEXT_WIKI_URL = \ |
|---|
| 3662 | u""" |
|---|
| 3663 | - |
|---|
| 3664 | Convert Absolute/Relative File URL;CMD_CONVERT_URL_ABSOLUTE_RELATIVE_THIS |
|---|
| 3665 | Open Containing Folder;CMD_OPEN_CONTAINING_FOLDER_THIS |
|---|
| 3666 | """ |
|---|
| 3667 | |
|---|
| 3668 | _CONTEXT_MENU_INTEXT_FILE_URL = \ |
|---|
| 3669 | u""" |
|---|
| 3670 | - |
|---|
| 3671 | Convert Absolute/Relative File URL;CMD_CONVERT_URL_ABSOLUTE_RELATIVE_THIS |
|---|
| 3672 | Open Containing Folder;CMD_OPEN_CONTAINING_FOLDER_THIS |
|---|
| 3673 | Rename file;CMD_RENAME_FILE |
|---|
| 3674 | Delete file;CMD_DELETE_FILE |
|---|
| 3675 | """ |
|---|
| 3676 | |
|---|
| 3677 | |
|---|
| 3678 | _CONTEXT_MENU_INTEXT_URL_TO_CLIPBOARD = \ |
|---|
| 3679 | u""" |
|---|
| 3680 | - |
|---|
| 3681 | Copy Anchor URL to Clipboard;CMD_CLIPBOARD_COPY_URL_TO_THIS_ANCHOR |
|---|
| 3682 | """ |
|---|
| 3683 | |
|---|
| 3684 | _CONTEXT_MENU_SELECT_TEMPLATE_IN_TEMPLATE_MENU = \ |
|---|
| 3685 | u""" |
|---|
| 3686 | - |
|---|
| 3687 | Other...;CMD_SELECT_TEMPLATE |
|---|
| 3688 | """ |
|---|
| 3689 | |
|---|
| 3690 | _CONTEXT_MENU_SELECT_TEMPLATE = \ |
|---|
| 3691 | u""" |
|---|
| 3692 | - |
|---|
| 3693 | Use Template...;CMD_SELECT_TEMPLATE |
|---|
| 3694 | """ |
|---|
| 3695 | |
|---|
| 3696 | |
|---|
| 3697 | _CONTEXT_MENU_INTEXT_BOTTOM = \ |
|---|
| 3698 | u""" |
|---|
| 3699 | - |
|---|
| 3700 | Close Tab;CMD_CLOSE_CURRENT_TAB |
|---|
| 3701 | """ |
|---|
| 3702 | |
|---|
| 3703 | |
|---|
| 3704 | |
|---|
| 3705 | FOLD_MENU = \ |
|---|
| 3706 | u""" |
|---|
| 3707 | +Show folding;CMD_CHECKBOX_SHOW_FOLDING;Show folding marks and allow folding;*ShowFolding |
|---|
| 3708 | &Toggle current folding;CMD_TOGGLE_CURRENT_FOLDING;Toggle folding of the current line;*ToggleCurrentFolding |
|---|
| 3709 | &Unfold All;CMD_UNFOLD_ALL_IN_CURRENT;Unfold everything in current editor;*UnfoldAll |
|---|
| 3710 | &Fold All;CMD_FOLD_ALL_IN_CURRENT;Fold everything in current editor;*FoldAll |
|---|
| 3711 | """ |
|---|
| 3712 | |
|---|
| 3713 | |
|---|
| 3714 | |
|---|
| 3715 | if False: |
|---|
| 3716 | N_(u"Ignore") |
|---|
| 3717 | N_(u"Add Globally") |
|---|
| 3718 | N_(u"Add Locally") |
|---|
| 3719 | |
|---|
| 3720 | N_(u"Undo") |
|---|
| 3721 | N_(u"Redo") |
|---|
| 3722 | N_(u"Cut") |
|---|
| 3723 | N_(u"Copy") |
|---|
| 3724 | N_(u"Paste") |
|---|
| 3725 | N_(u"Delete") |
|---|
| 3726 | N_(u"Select All") |
|---|
| 3727 | |
|---|
| 3728 | N_(u"Follow Link") |
|---|
| 3729 | N_(u"Follow Link New Tab") |
|---|
| 3730 | N_(u"Follow Link New Tab Backgrd.") |
|---|
| 3731 | N_(u"Follow Link New Window") |
|---|
| 3732 | |
|---|
| 3733 | N_(u"Convert Absolute/Relative File URL") |
|---|
| 3734 | N_(u"Open Containing Folder") |
|---|
| 3735 | N_(u"Rename file") |
|---|
| 3736 | N_(u"Delete file") |
|---|
| 3737 | |
|---|
| 3738 | N_(u"Copy anchor URL to clipboard") |
|---|
| 3739 | |
|---|
| 3740 | N_(u"Other...") |
|---|
| 3741 | N_(u"Use Template...") |
|---|
| 3742 | |
|---|
| 3743 | N_(u"Close Tab") |
|---|
| 3744 | |
|---|
| 3745 | N_(u"Show folding") |
|---|
| 3746 | N_(u"Show folding marks and allow folding") |
|---|
| 3747 | N_(u"&Toggle current folding") |
|---|
| 3748 | N_(u"Toggle folding of the current line") |
|---|
| 3749 | N_(u"&Unfold All") |
|---|
| 3750 | N_(u"Unfold everything in current editor") |
|---|
| 3751 | N_(u"&Fold All") |
|---|
| 3752 | N_(u"Fold everything in current editor") |
|---|
| 3753 | |
|---|
| 3754 | |
|---|
| 3755 | |
|---|
| 3756 | try: |
|---|
| 3757 | class wxPopupOrFrame(wx.PopupWindow): |
|---|
| 3758 | def __init__(self, parent, id=-1, style=None): |
|---|
| 3759 | wx.PopupWindow.__init__(self, parent) |
|---|
| 3760 | |
|---|
| 3761 | except AttributeError: |
|---|
| 3762 | class wxPopupOrFrame(wx.Frame): |
|---|
| 3763 | def __init__(self, parent, id=-1, |
|---|
| 3764 | style=wx.NO_BORDER|wx.FRAME_NO_TASKBAR|wx.FRAME_FLOAT_ON_PARENT): |
|---|
| 3765 | wx.Frame.__init__(self, parent, id, style=style) |
|---|
| 3766 | |
|---|
| 3767 | |
|---|
| 3768 | class ImageTooltipPanel(wxPopupOrFrame): |
|---|
| 3769 | """Quick panel for image tooltips""" |
|---|
| 3770 | def __init__(self, pWiki, filePath, maxWidth=200, maxHeight=200): |
|---|
| 3771 | wxPopupOrFrame.__init__(self, pWiki, -1) |
|---|
| 3772 | |
|---|
| 3773 | self.url = filePath |
|---|
| 3774 | self.pWiki = pWiki |
|---|
| 3775 | self.firstMove = True |
|---|
| 3776 | |
|---|
| 3777 | img = wx.Image(filePath, wx.BITMAP_TYPE_ANY) |
|---|
| 3778 | |
|---|
| 3779 | origWidth = img.GetWidth() |
|---|
| 3780 | origHeight = img.GetHeight() |
|---|
| 3781 | |
|---|
| 3782 | |
|---|
| 3783 | if maxWidth <= 0: |
|---|
| 3784 | maxWidth = 200 |
|---|
| 3785 | if maxHeight <= 0: |
|---|
| 3786 | maxHeight = 200 |
|---|
| 3787 | |
|---|
| 3788 | if origWidth > 0 and origHeight > 0: |
|---|
| 3789 | self.width, self.height = calcResizeArIntoBoundingBox(origWidth, |
|---|
| 3790 | origHeight, maxWidth, maxHeight) |
|---|
| 3791 | |
|---|
| 3792 | img.Rescale(self.width, self.height, quality = wx.IMAGE_QUALITY_HIGH) |
|---|
| 3793 | else: |
|---|
| 3794 | self.width = origWidth |
|---|
| 3795 | self.height = origHeight |
|---|
| 3796 | |
|---|
| 3797 | img = img.ConvertToBitmap() |
|---|
| 3798 | |
|---|
| 3799 | self.SetSize((self.width, self.height)) |
|---|
| 3800 | |
|---|
| 3801 | self.bmp = wx.StaticBitmap(self, -1, img, (0, 0), (img.GetWidth(), img.GetHeight())) |
|---|
| 3802 | self.bmp.Bind(wx.EVT_LEFT_DOWN, self.OnLeftClick) |
|---|
| 3803 | self.bmp.Bind(wx.EVT_RIGHT_DOWN, self.OnRightClick) |
|---|
| 3804 | self.bmp.Bind(wx.EVT_MOTION, self.OnMouseMotion) |
|---|
| 3805 | self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown) |
|---|
| 3806 | |
|---|
| 3807 | mousePos = wx.GetMousePosition() |
|---|
| 3808 | |
|---|
| 3809 | |
|---|
| 3810 | mousePos.x += 1 |
|---|
| 3811 | mousePos.y += 1 |
|---|
| 3812 | WindowLayout.setWindowPos(self, mousePos, fullVisible=True) |
|---|
| 3813 | |
|---|
| 3814 | self.Show() |
|---|
| 3815 | |
|---|
| 3816 | self.GetParent().SetFocus() |
|---|
| 3817 | |
|---|
| 3818 | def Close(self, event=None): |
|---|
| 3819 | self.Destroy() |
|---|
| 3820 | |
|---|
| 3821 | def OnLeftClick(self, event=None): |
|---|
| 3822 | |
|---|
| 3823 | self.Close() |
|---|
| 3824 | |
|---|
| 3825 | |
|---|
| 3826 | |
|---|
| 3827 | |
|---|
| 3828 | |
|---|
| 3829 | |
|---|
| 3830 | |
|---|
| 3831 | |
|---|
| 3832 | def OnRightClick(self, event=None): |
|---|
| 3833 | self.Close() |
|---|
| 3834 | |
|---|
| 3835 | def OnMouseMotion(self, evt): |
|---|
| 3836 | if self.firstMove: |
|---|
| 3837 | self.firstMove = False |
|---|
| 3838 | evt.Skip() |
|---|
| 3839 | return |
|---|
| 3840 | |
|---|
| 3841 | self.Close() |
|---|
| 3842 | |
|---|
| 3843 | |
|---|
| 3844 | def OnKeyDown(self, event): |
|---|
| 3845 | kc = event.GetKeyCode() |
|---|
| 3846 | |
|---|
| 3847 | if kc == wx.WXK_ESCAPE: |
|---|
| 3848 | self.Close() |
|---|
| 3849 | |
|---|
| 3850 | |
|---|
| 3851 | class ViHandler(ViHelper): |
|---|
| 3852 | |
|---|
| 3853 | |
|---|
| 3854 | |
|---|
| 3855 | |
|---|
| 3856 | |
|---|
| 3857 | |
|---|
| 3858 | def __init__(self, stc): |
|---|
| 3859 | ViHelper.__init__(self, stc) |
|---|
| 3860 | |
|---|
| 3861 | self._anchor = None |
|---|
| 3862 | |
|---|
| 3863 | wx.CallAfter(self.SetDefaultCaretColour) |
|---|
| 3864 | |
|---|
| 3865 | wx.CallAfter(self.SetMode, ViHelper.NORMAL) |
|---|
| 3866 | wx.CallAfter(self.Setup) |
|---|
| 3867 | |
|---|
| 3868 | self.text_object_map = { |
|---|
| 3869 | "w" : (False, self.SelectInWord), |
|---|
| 3870 | "W" : (False, self.SelectInWORD), |
|---|
| 3871 | "s" : (False, self.SelectInSentence), |
|---|
| 3872 | "p" : (False, self.SelectInParagraph), |
|---|
| 3873 | |
|---|
| 3874 | "[" : (True, self.SelectInSquareBracket), |
|---|
| 3875 | "]" : (True, self.SelectInSquareBracket), |
|---|
| 3876 | |
|---|
| 3877 | "(" : (True, self.SelectInRoundBracket), |
|---|
| 3878 | ")" : (True, self.SelectInRoundBracket), |
|---|
| 3879 | "b" : (True, self.SelectInRoundBracket), |
|---|
| 3880 | |
|---|
| 3881 | "<" : (True, self.SelectInInequalitySigns), |
|---|
| 3882 | ">" : (True, self.SelectInInequalitySigns), |
|---|
| 3883 | |
|---|
| 3884 | "t" : (True, self.SelectInTagBlock), |
|---|
| 3885 | |
|---|
| 3886 | "{" : (True, self.SelectInBlock), |
|---|
| 3887 | "}" : (True, self.SelectInBlock), |
|---|
| 3888 | "B" : (True, self.SelectInBlock), |
|---|
| 3889 | |
|---|
| 3890 | '"' : (True, self.SelectInDoubleQuote), |
|---|
| 3891 | "'" : (True, self.SelectInSingleQuote), |
|---|
| 3892 | "`" : (True, self.SelectInTilde), |
|---|
| 3893 | |
|---|
| 3894 | |
|---|
| 3895 | |
|---|
| 3896 | u"\xc2" : (True, self.SelectInPoundSigns), |
|---|
| 3897 | u"$" : (True, self.SelectInDollarSigns), |
|---|
| 3898 | u"^" : (True, self.SelectInHats), |
|---|
| 3899 | u"%" : (True, self.SelectInPercentSigns), |
|---|
| 3900 | u"&" : (True, self.SelectInAmpersands), |
|---|
| 3901 | u"*" : (True, self.SelectInStars), |
|---|
| 3902 | u"-" : (True, self.SelectInHyphens), |
|---|
| 3903 | u"_" : (True, self.SelectInUnderscores), |
|---|
| 3904 | u"=" : (True, self.SelectInEqualSigns), |
|---|
| 3905 | u"+" : (True, self.SelectInPlusSigns), |
|---|
| 3906 | u"!" : (True, self.SelectInExclamationMarks), |
|---|
| 3907 | u"?" : (True, self.SelectInQuestionMarks), |
|---|
| 3908 | u"@" : (True, self.SelectInAtSigns), |
|---|
| 3909 | u"#" : (True, self.SelectInHashs), |
|---|
| 3910 | u"~" : (True, self.SelectInApproxSigns), |
|---|
| 3911 | u"|" : (True, self.SelectInVerticalBars), |
|---|
| 3912 | u";" : (True, self.SelectInSemicolons), |
|---|
| 3913 | u":" : (True, self.SelectInColons), |
|---|
| 3914 | u"\\" : (True, self.SelectInBackslashes), |
|---|
| 3915 | u"/" : (True, self.SelectInForwardslashes), |
|---|
| 3916 | } |
|---|
| 3917 | |
|---|
| 3918 | |
|---|
| 3919 | |
|---|
| 3920 | |
|---|
| 3921 | |
|---|
| 3922 | |
|---|
| 3923 | |
|---|
| 3924 | |
|---|
| 3925 | |
|---|
| 3926 | |
|---|
| 3927 | |
|---|
| 3928 | |
|---|
| 3929 | |
|---|
| 3930 | |
|---|
| 3931 | |
|---|
| 3932 | |
|---|
| 3933 | |
|---|
| 3934 | |
|---|
| 3935 | |
|---|
| 3936 | |
|---|
| 3937 | self.keys = { |
|---|
| 3938 | 0 : { |
|---|
| 3939 | |
|---|
| 3940 | (60, "motion") : (0, (self.DedentText, None), 1), |
|---|
| 3941 | (62, "motion") : (0, (self.IndentText, None), 1), |
|---|
| 3942 | (99, "motion") : (2, (self.EndDeleteInsert, None), 2), |
|---|
| 3943 | (100, "motion") : (0, (self.EndDelete, None), 1), |
|---|
| 3944 | (100, 115, "*") : (0, (self.DeleteSurrounding, None), 1), |
|---|
| 3945 | (121, "motion") : (0, (self.Yank, None), 1), |
|---|
| 3946 | (99, 115, "*", "*") : (0, (self.ChangeSurrounding, None), 1), |
|---|
| 3947 | |
|---|
| 3948 | (121, 115, "motion", "*") : (0, (self.PreSurround, None), 1), |
|---|
| 3949 | (121, 115, 115, "*") : (0, (self.PreSurroundLine, None), 1), |
|---|
| 3950 | (103, 117, "motion") : (0, (self.PreLowercase, None), 1), |
|---|
| 3951 | (103, 85, "motion") : (0, (self.PreUppercase, None), 1), |
|---|
| 3952 | (39, "*") : (1, (self.GotoMark, None), 0), |
|---|
| 3953 | (96, "*") : (1, (self.GotoMarkIndent, None), 0), |
|---|
| 3954 | (109, "*") : (0, (self.Mark, None), 0), |
|---|
| 3955 | (102, "*") : (1, (self.FindNextChar, None), 4), |
|---|
| 3956 | (70, "*") : (1, (self.FindNextCharBackwards, None), 4), |
|---|
| 3957 | (116, "*") : (1, (self.FindUpToNextChar, None), 5), |
|---|
| 3958 | (84, "*") : (1, (self.FindUpToNextCharBackwards, None), 5), |
|---|
| 3959 | (114, "*") : (0, (self.ReplaceChar, None), 0), |
|---|
| 3960 | |
|---|
| 3961 | (105,) : (0, (self.Insert, None), 2), |
|---|
| 3962 | (97,) : (0, (self.Append, None), 2), |
|---|
| 3963 | (73,) : (0, (self.InsertAtLineStart, None), 2), |
|---|
| 3964 | (65,) : (0, (self.AppendAtLineEnd, None), 2), |
|---|
| 3965 | (111,) : (0, (self.OpenNewLine, False), 2), |
|---|
| 3966 | (79,) : (0, (self.OpenNewLine, True), 2), |
|---|
| 3967 | (67,) : (0, (self.TruncateLineAndInsert, None), 2), |
|---|
| 3968 | (68,) : (0, (self.TruncateLine, None), 2), |
|---|
| 3969 | |
|---|
| 3970 | (120,) : (0, (self.DeleteRight, None), 1), |
|---|
| 3971 | (88,) : (0, (self.DeleteLeft, None), 1), |
|---|
| 3972 | |
|---|
| 3973 | (115,) : (0, (self.DeleteRightAndInsert, None), 2), |
|---|
| 3974 | (83,) : (0, (self.DeleteLinesAndIndentInsert, None), 2), |
|---|
| 3975 | |
|---|
| 3976 | (119,) : (1, (self.MoveCaretNextWord, None), 0), |
|---|
| 3977 | (87,) : (1, (self.MoveCaretNextWORD, None), 0), |
|---|
| 3978 | (103, 101) : (1, (self.MoveCaretPreviousWordEnd, None), 0), |
|---|
| 3979 | |
|---|
| 3980 | (101,) : (1, (self.MoveCaretWordEnd, None), 0), |
|---|
| 3981 | (69,) : (1, (self.MoveCaretWordEND, None), 0), |
|---|
| 3982 | (98,) : (1, (self.MoveCaretBackWord, None), 0), |
|---|
| 3983 | (66,) : (1, (self.MoveCaretBackWORD, None), 0), |
|---|
| 3984 | |
|---|
| 3985 | (123,) : (1, (self.MoveCaretParaUp, None), 0), |
|---|
| 3986 | (125,) : (1, (self.MoveCaretParaDown, None), 0), |
|---|
| 3987 | |
|---|
| 3988 | |
|---|
| 3989 | |
|---|
| 3990 | (47,) : (0, (self.StartSearch, None), 0), |
|---|
| 3991 | |
|---|
| 3992 | (110,) : (1, (self.Repeat, self.ContinueLastSearchSameDirection), 0), |
|---|
| 3993 | (78,) : (1, (self.Repeat, self.ContinueLastSearchReverseDirection), 0), |
|---|
| 3994 | |
|---|
| 3995 | (42,) : (1, (self.Repeat, self.SearchCaretWordForwards), 0), |
|---|
| 3996 | (35,) : (1, (self.Repeat, self.SearchCaretWordBackwards), 0), |
|---|
| 3997 | |
|---|
| 3998 | (103, 42) : (1, (self.Repeat, self.SearchPartialCaretWordForwards), 0), |
|---|
| 3999 | (103, 35) : (1, (self.Repeat, self.SearchPartialCaretWordBackwards), 0), |
|---|
| 4000 | |
|---|
| 4001 | |
|---|
| 4002 | |
|---|
| 4003 | (104,) : (1, (self.MoveCaretLeft, None), 0), |
|---|
| 4004 | (107,) : (1, (self.MoveCaretUp, None), 0), |
|---|
| 4005 | (108,) : (1, (self.MoveCaretRight, None), 0), |
|---|
| 4006 | (106,) : (1, (self.MoveCaretDown, None), 0), |
|---|
| 4007 | (103, 107) : (1, (self.MoveCaretUp, None), 0), |
|---|
| 4008 | (103, 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 | (45,) : (1, (self.GotoLineIndentPreviousLine, None), 0), |
|---|
| 4024 | (43,) : (1, (self.GotoLineIndentNextLine, None), 0), |
|---|
| 4025 | (94,) : (1, (self.GotoLineIndent, None), 0), |
|---|
| 4026 | (124,) : (1, (self.GotoColumn, None), 0), |
|---|
| 4027 | |
|---|
| 4028 | (40,) : (1, (self.GotoSentenceStart, None), 0), |
|---|
| 4029 | (41,) : (1, (self.GotoNextSentence, None), 0), |
|---|
| 4030 | |
|---|
| 4031 | |
|---|
| 4032 | (103, 103) : (1, (self.DocumentNavigation, (103, 103)), 0), |
|---|
| 4033 | (71,) : (1, (self.DocumentNavigation, 71), 0), |
|---|
| 4034 | (37,) : (1, (self.DocumentNavigation, 37), 0), |
|---|
| 4035 | |
|---|
| 4036 | (72,) : (1, (self.GotoViewportTop, None), 0), |
|---|
| 4037 | (76,) : (1, (self.GotoViewportBottom, None), 0), |
|---|
| 4038 | (77,) : (1, (self.GotoViewportMiddle, None), 0), |
|---|
| 4039 | |
|---|
| 4040 | (122, 122) : (0, (self.ScrollViewportMiddle, None), 0), |
|---|
| 4041 | (122, 116) : (0, (self.ScrollViewportTop, None), 0), |
|---|
| 4042 | (122, 98) : (0, (self.ScrollViewportBottom, None), 0), |
|---|
| 4043 | |
|---|
| 4044 | (("Ctrl", 117),) : (0, (self.ScrollViewportUpHalfScreen, |
|---|
| 4045 | None), 0), |
|---|
| 4046 | (("Ctrl", 100),) : (0, (self.ScrollViewportDownHalfScreen, |
|---|
| 4047 | None), 0), |
|---|
| 4048 | (("Ctrl", 98),) : (0, (self.ScrollViewportUpFullScreen, |
|---|
| 4049 | None), 0), |
|---|
| 4050 | (("Ctrl", 102),) : (0, (self.ScrollViewportDownFullScreen, |
|---|
| 4051 | None), 0), |
|---|
| 4052 | |
|---|
| 4053 | (("Ctrl", 101),) : (0, (self.ScrollViewportLineDown, |
|---|
| 4054 | None), 0), |
|---|
| 4055 | (("Ctrl", 121),) : (0, (self.ScrollViewportLineUp, |
|---|
| 4056 | None), 0), |
|---|
| 4057 | |
|---|
| 4058 | (90, 90) : (0, (self.ctrl.presenter.getMainControl().\ |
|---|
| 4059 | exitWiki, None), 0), |
|---|
| 4060 | |
|---|
| 4061 | (117,) : (0, (self.Undo, None), 0), |
|---|
| 4062 | (("Ctrl", 114),) : (0, (self.Redo, None), 0), |
|---|
| 4063 | |
|---|
| 4064 | (("Ctrl", 105),) : (1, (self.GotoNextJump, None), 0), |
|---|
| 4065 | (65289,) : (1, (self.GotoNextJump, None), 0), |
|---|
| 4066 | (("Ctrl", 111),) : (1, (self.GotoPreviousJump, None), 0), |
|---|
| 4067 | |
|---|
| 4068 | |
|---|
| 4069 | (59,) : (1, (self.RepeatLastFindCharCmd, None), 0), |
|---|
| 4070 | (44,) : (1, (self.RepeatLastFindCharCmdReverse, None), 0), |
|---|
| 4071 | |
|---|
| 4072 | |
|---|
| 4073 | |
|---|
| 4074 | |
|---|
| 4075 | (82,) : (0, (self.StartReplaceMode, None), 0), |
|---|
| 4076 | |
|---|
| 4077 | (118,) : (2, (self.EnterVisualMode, None), 0), |
|---|
| 4078 | (86,) : (2, (self.EnterLineVisualMode, None), 0), |
|---|
| 4079 | |
|---|
| 4080 | (74,) : (0, (self.JoinLines, None), 1), |
|---|
| 4081 | |
|---|
| 4082 | (126,) : (0, (self.SwapCase, None), 0), |
|---|
| 4083 | |
|---|
| 4084 | (121, 121) : (0, (self.YankLine, None), 0), |
|---|
| 4085 | (89,) : (0, (self.YankLine, None), 0), |
|---|
| 4086 | (112,) : (0, (self.Put, False), 0), |
|---|
| 4087 | (80,) : (0, (self.Put, True), 0), |
|---|
| 4088 | |
|---|
| 4089 | (100, 100) : (0, (self.DeleteLine, None), 1), |
|---|
| 4090 | |
|---|
| 4091 | (62, 62) : (0, (self.Indent, True), 1), |
|---|
| 4092 | (60, 60) : (0, (self.Indent, False), 1), |
|---|
| 4093 | |
|---|
| 4094 | (46,) : (0, (self.RepeatCmd, None), 0), |
|---|
| 4095 | |
|---|
| 4096 | |
|---|
| 4097 | |
|---|
| 4098 | |
|---|
| 4099 | |
|---|
| 4100 | (103, 102) : (0, (self.ctrl.activateLink, { "tabMode" : 0 }), 0), |
|---|
| 4101 | (("Ctrl", 119), 103, 102) : (0, (self.ctrl.activateLink, { "tabMode" : 2 }), 0), |
|---|
| 4102 | (103, 70) : (0, (self.ctrl.activateLink, { "tabMode" : 2 }), 0), |
|---|
| 4103 | (103, 98) : (0, (self.ctrl.activateLink, { "tabMode" : 3 }), 0), |
|---|
| 4104 | |
|---|
| 4105 | (103, 72) : (0, (self.GoBackwardInHistory, None), 0), |
|---|
| 4106 | (103, 76) : (0, (self.GoForwardInHistory, None), 0), |
|---|
| 4107 | (103, 104) : (0, (self.GoBackwardInHistory, None), 0), |
|---|
| 4108 | (103, 108) : (0, (self.GoForwardInHistory, None), 0), |
|---|
| 4109 | (91,) : (0, (self.GoBackwardInHistory, None), 0), |
|---|
| 4110 | (93,) : (0, (self.GoForwardInHistory, None), 0), |
|---|
| 4111 | (103, 116) : (0, (self.SwitchTabs, None), 0), |
|---|
| 4112 | (103, 84) : (0, (self.SwitchTabs, True), 0), |
|---|
| 4113 | (103, 114) : (0, (self.OpenHomePage, False), 0), |
|---|
| 4114 | (103, 82) : (0, (self.OpenHomePage, True), 0), |
|---|
| 4115 | (103, 111) : (0, (self.ctrl.presenter.getMainControl()). \ |
|---|
| 4116 | showWikiWordOpenDialog, None, 0), |
|---|
| 4117 | |
|---|
| 4118 | (103, 79): (0, (self.ctrl.presenter.getMainControl()). \ |
|---|
| 4119 | showWikiWordOpenDialog, None, 0), |
|---|
| 4120 | |
|---|
| 4121 | (92, 117) : (0, (self.ViewParents, False), 0), |
|---|
| 4122 | (92, 85) : (0, (self.ViewParents, True), 0), |
|---|
| 4123 | |
|---|
| 4124 | (103, 115) : (0, (self.SwitchEditorPreview, None), 0), |
|---|
| 4125 | |
|---|
| 4126 | |
|---|
| 4127 | |
|---|
| 4128 | (103, 112) : (0, (self.SwitchEditorPreview, "preview"), 0), |
|---|
| 4129 | (65470,) : (0, (self.SwitchEditorPreview, "textedit"), 0), |
|---|
| 4130 | (65471,) : (0, (self.SwitchEditorPreview, "preview"), 0), |
|---|
| 4131 | } |
|---|
| 4132 | } |
|---|
| 4133 | |
|---|
| 4134 | |
|---|
| 4135 | |
|---|
| 4136 | for i in self.text_object_map: |
|---|
| 4137 | self.keys[0][(105, ord(i))] = (1, (self.SelectInTextObject, i), 0) |
|---|
| 4138 | self.keys[0][(97, ord(i))] = (1, (self.SelectATextObject, i), 0) |
|---|
| 4139 | |
|---|
| 4140 | |
|---|
| 4141 | |
|---|
| 4142 | self.keys[1] = { |
|---|
| 4143 | (("Ctrl", 64),) : (0, (self.InsertPreviousText, None), 0), |
|---|
| 4144 | (("Ctrl", 97),) : (0, (self.InsertPreviousTextLeaveInsertMode, |
|---|
| 4145 | None), 0), |
|---|
| 4146 | (("Ctrl", 110),) : (0, (self.Autocomplete, True), 0), |
|---|
| 4147 | (("Ctrl", 112),) : (0, (self.Autocomplete, False), 0), |
|---|
| 4148 | } |
|---|
| 4149 | |
|---|
| 4150 | |
|---|
| 4151 | |
|---|
| 4152 | |
|---|
| 4153 | |
|---|
| 4154 | self.keys[2] = self.keys[0].copy() |
|---|
| 4155 | self.keys[2].update({ |
|---|
| 4156 | |
|---|
| 4157 | (39, "*") : (1, (self.GotoMark, None), 0), |
|---|
| 4158 | (96, "*") : (1, (self.GotoMarkIndent, None), 0), |
|---|
| 4159 | (109, "*") : (0, (self.Mark, None), 0), |
|---|
| 4160 | (102, "*") : (1, (self.FindNextChar, None), 0), |
|---|
| 4161 | (70, "*") : (1, (self.FindNextCharBackwards, None), 0), |
|---|
| 4162 | (116, "*") : (1, (self.FindUpToNextChar, None), 0), |
|---|
| 4163 | (84, "*") : (1, (self.FindUpToNextCharBackwards, None), 0), |
|---|
| 4164 | (114, "*") : (0, (self.ReplaceChar, None), 2), |
|---|
| 4165 | (83, "*") : (0, (self.SurroundSelection, None), 2), |
|---|
| 4166 | |
|---|
| 4167 | |
|---|
| 4168 | (99,) : (0, (self.DeleteSelectionAndInsert, None), 2), |
|---|
| 4169 | (100,) : (0, (self.DeleteSelection, None), 1), |
|---|
| 4170 | (120,) : (0, (self.DeleteSelection, None), 1), |
|---|
| 4171 | (121,) : (0, (self.Yank, None), 0), |
|---|
| 4172 | (89,) : (0, (self.Yank, True), 0), |
|---|
| 4173 | (60,) : (0, (self.Indent, {"forward":False, "visual":True}), 0), |
|---|
| 4174 | (62,) : (0, (self.Indent, {"forward":True, "visual":True}), 0), |
|---|
| 4175 | (117,) : (0, (self.LowerCase, None), 0), |
|---|
| 4176 | (85,) : (0, (self.UpperCase, None), 0), |
|---|
| 4177 | (103, 117) : (1, self.LowerCase, 0), |
|---|
| 4178 | (103, 85) : (1, self.UpperCase, 0), |
|---|
| 4179 | }) |
|---|
| 4180 | |
|---|
| 4181 | |
|---|
| 4182 | |
|---|
| 4183 | del self.keys[2][(100, 100)] |
|---|
| 4184 | del self.keys[2][(121, 121)] |
|---|
| 4185 | del self.keys[2][(105,)] |
|---|
| 4186 | del self.keys[2][(97,)] |
|---|
| 4187 | del self.keys[2][(83,)] |
|---|
| 4188 | |
|---|
| 4189 | self.keys[3] = {} |
|---|
| 4190 | |
|---|
| 4191 | |
|---|
| 4192 | |
|---|
| 4193 | self.key_mods = self.GenerateKeyModifiers(self.keys) |
|---|
| 4194 | self.motion_keys = self.GenerateMotionKeys(self.keys) |
|---|
| 4195 | self.motion_key_mods = self.GenerateKeyModifiers(self.motion_keys) |
|---|
| 4196 | |
|---|
| 4197 | |
|---|
| 4198 | self.viKeyAccels = self.GenerateKeyAccelerators(self.keys) |
|---|
| 4199 | |
|---|
| 4200 | |
|---|
| 4201 | self.SINGLE_LINE_WHITESPACE = [9, 11, 12, 32] |
|---|
| 4202 | self.WORD_BREAK = '!"#$%&\'()*+,-./:;<=>?@[\\]^`{|}~' |
|---|
| 4203 | self.WORD_BREAK_INCLUDING_WHITESPACE = \ |
|---|
| 4204 | '!"#$%&\'()*+,-./:;<=>?@[\\]^`{|}~ \n\r' |
|---|
| 4205 | self.SENTENCE_ENDINGS = '.!?' |
|---|
| 4206 | self.SENTENCE_ENDINGS_SUFFIXS = '\'")]' |
|---|
| 4207 | |
|---|
| 4208 | self.BRACES = { |
|---|
| 4209 | "(" : ")", |
|---|
| 4210 | "[" : "]", |
|---|
| 4211 | "{" : "}", |
|---|
| 4212 | "<" : ">", |
|---|
| 4213 | } |
|---|
| 4214 | self.REVERSE_BRACES = dict((v,k) for k, v in self.BRACES.iteritems()) |
|---|
| 4215 | |
|---|
| 4216 | self._undo_state = 0 |
|---|
| 4217 | self._undo_pos = -1 |
|---|
| 4218 | self._undo_start_position = None |
|---|
| 4219 | self._undo_positions = [] |
|---|
| 4220 | |
|---|
| 4221 | |
|---|
| 4222 | def Setup(self): |
|---|
| 4223 | self.AddJumpPosition(self.ctrl.GetCurrentPos()) |
|---|
| 4224 | |
|---|
| 4225 | def SetMode(self, mode): |
|---|
| 4226 | """ |
|---|
| 4227 | It would be nice to set caret alpha but i don't think its |
|---|
| 4228 | possible at the moment |
|---|
| 4229 | """ |
|---|
| 4230 | |
|---|
| 4231 | if self.mode == ViHelper.INSERT: |
|---|
| 4232 | |
|---|
| 4233 | |
|---|
| 4234 | if self.ctrl.GetCurrentPos() != \ |
|---|
| 4235 | self.GetLineStartPos(self.ctrl.GetCurrentLine()) and \ |
|---|
| 4236 | self.ctrl.GetLineCount() != self.ctrl.GetCurrentLine() + 1: |
|---|
| 4237 | self.ctrl.CharLeft() |
|---|
| 4238 | self.EndUndo(force=True) |
|---|
| 4239 | |
|---|
| 4240 | if self.mode == ViHelper.INSERT: |
|---|
| 4241 | |
|---|
| 4242 | if self.ctrl.GetCurLine()[0].strip() == u"": |
|---|
| 4243 | self.ctrl.LineDelete() |
|---|
| 4244 | self.ctrl.AddText(self.ctrl.GetEOLChar()) |
|---|
| 4245 | self.ctrl.CharLeft() |
|---|
| 4246 | elif self.mode == ViHelper.REPLACE: |
|---|
| 4247 | |
|---|
| 4248 | self.EndUndo() |
|---|
| 4249 | |
|---|
| 4250 | self.mode = mode |
|---|
| 4251 | |
|---|
| 4252 | |
|---|
| 4253 | self.ctrl.ChooseCaretX() |
|---|
| 4254 | |
|---|
| 4255 | if mode == ViHelper.NORMAL: |
|---|
| 4256 | |
|---|
| 4257 | |
|---|
| 4258 | self.ctrl.SetCaretPeriod(800) |
|---|
| 4259 | |
|---|
| 4260 | self.RemoveSelection() |
|---|
| 4261 | self.ctrl.SetCaretForeground(wx.Colour(255, 0, 0)) |
|---|
| 4262 | self.ctrl.SetCaretWidth(40) |
|---|
| 4263 | self.ctrl.SetOvertype(False) |
|---|
| 4264 | self.SetSelMode("NORMAL") |
|---|
| 4265 | |
|---|
| 4266 | self.CheckLineEnd() |
|---|
| 4267 | elif mode == ViHelper.VISUAL: |
|---|
| 4268 | self.ctrl.SetCaretWidth(40) |
|---|
| 4269 | self.ctrl.SetCaretForeground(wx.Colour(250, 250, 210)) |
|---|
| 4270 | self.ctrl.SetOvertype(False) |
|---|
| 4271 | elif mode == ViHelper.INSERT: |
|---|
| 4272 | self.insert_action = [] |
|---|
| 4273 | self.ctrl.SetCaretWidth(1) |
|---|
| 4274 | self.ctrl.SetCaretForeground(self.default_caret_colour) |
|---|
| 4275 | self.ctrl.SetOvertype(False) |
|---|
| 4276 | elif mode == ViHelper.REPLACE: |
|---|
| 4277 | self.ctrl.SetCaretWidth(1) |
|---|
| 4278 | self.ctrl.SetCaretForeground(self.default_caret_colour) |
|---|
| 4279 | self.ctrl.SetOvertype(True) |
|---|
| 4280 | |
|---|
| 4281 | |
|---|
| 4282 | |
|---|
| 4283 | |
|---|
| 4284 | |
|---|
| 4285 | def BeginUndo(self, use_start_pos=False): |
|---|
| 4286 | if self._undo_state == 0: |
|---|
| 4287 | self.ctrl.BeginUndoAction() |
|---|
| 4288 | |
|---|
| 4289 | |
|---|
| 4290 | self._undo_positions = \ |
|---|
| 4291 | self._undo_positions[:self._undo_pos + 1] |
|---|
| 4292 | |
|---|
| 4293 | if use_start_pos: |
|---|
| 4294 | if self.HasSelection: |
|---|
| 4295 | self._undo_start_position = self.ctrl.GetSelectionStart() |
|---|
| 4296 | else: |
|---|
| 4297 | self._undo_start_position = self.ctrl.GetCurrentPos() |
|---|
| 4298 | self._undo_state += 1 |
|---|
| 4299 | |
|---|
| 4300 | |
|---|
| 4301 | def EndUndo(self, force=False): |
|---|
| 4302 | if force: self._undo_state = 1 |
|---|
| 4303 | |
|---|
| 4304 | if self._undo_state == 1: |
|---|
| 4305 | self.ctrl.EndUndoAction() |
|---|
| 4306 | if self._undo_start_position is not None: |
|---|
| 4307 | self._undo_positions.append(self._undo_start_position) |
|---|
| 4308 | self._undo_start_position = None |
|---|
| 4309 | |
|---|
| 4310 | elif self.HasSelection: |
|---|
| 4311 | self._undo_positions.append(self.ctrl.GetSelectionStart()) |
|---|
| 4312 | else: |
|---|
| 4313 | self._undo_positions.append(self.ctrl.GetCurrentPos()) |
|---|
| 4314 | self._undo_pos += 1 |
|---|
| 4315 | self._undo_state -= 1 |
|---|
| 4316 | |
|---|
| 4317 | def _Undo(self): |
|---|
| 4318 | if self._undo_pos < 0: |
|---|
| 4319 | return False |
|---|
| 4320 | self.ctrl.Undo() |
|---|
| 4321 | self.ctrl.GotoPos(self._undo_positions[self._undo_pos]) |
|---|
| 4322 | self._undo_pos -= 1 |
|---|
| 4323 | |
|---|
| 4324 | def _Redo(self): |
|---|
| 4325 | |
|---|
| 4326 | if self._undo_pos > len(self._undo_positions): |
|---|
| 4327 | return False |
|---|
| 4328 | |
|---|
| 4329 | self.ctrl.Redo() |
|---|
| 4330 | self._undo_pos += 1 |
|---|
| 4331 | |
|---|
| 4332 | |
|---|
| 4333 | |
|---|
| 4334 | def GotoFirstVisibleLine(self): |
|---|
| 4335 | line = self.ctrl.GetFirstVisibleLine() |
|---|
| 4336 | if line < self.ctrl.GetCurrentLine(): |
|---|
| 4337 | return |
|---|
| 4338 | self.ctrl.GotoLine(line) |
|---|
| 4339 | |
|---|
| 4340 | def GotoLastVisibleLine(self): |
|---|
| 4341 | line = self.ctrl.GetLastVisibleLine() |
|---|
| 4342 | if line > self.ctrl.GetCurrentLine(): |
|---|
| 4343 | return |
|---|
| 4344 | self.ctrl.GotoLine(line) |
|---|
| 4345 | |
|---|
| 4346 | def OnMouseScroll(self, evt): |
|---|
| 4347 | current_line = self.ctrl.GetCurrentLine() |
|---|
| 4348 | top_line = self.ctrl.GetFirstVisibleLine() + 1 |
|---|
| 4349 | bottom_line = self.ctrl.GetLastVisibleLine() |
|---|
| 4350 | |
|---|
| 4351 | if current_line < top_line: |
|---|
| 4352 | wx.CallAfter(self.GotoFirstVisibleLine) |
|---|
| 4353 | elif current_line > bottom_line: |
|---|
| 4354 | wx.CallAfter(self.GotoLastVisibleLine) |
|---|
| 4355 | |
|---|
| 4356 | |
|---|
| 4357 | |
|---|
| 4358 | |
|---|
| 4359 | |
|---|
| 4360 | |
|---|
| 4361 | |
|---|
| 4362 | |
|---|
| 4363 | |
|---|
| 4364 | |
|---|
| 4365 | |
|---|
| 4366 | evt.Skip() |
|---|
| 4367 | |
|---|
| 4368 | |
|---|
| 4369 | def OnScroll(self, evt): |
|---|
| 4370 | """ |
|---|
| 4371 | Vim never lets the caret out of the viewport so track any |
|---|
| 4372 | viewport movements |
|---|
| 4373 | """ |
|---|
| 4374 | |
|---|
| 4375 | current_line = self.ctrl.GetCurrentLine() |
|---|
| 4376 | top_line = self.ctrl.GetFirstVisibleLine()+1 |
|---|
| 4377 | bottom_line = self.ctrl.GetLastVisibleLine()-1 |
|---|
| 4378 | |
|---|
| 4379 | if current_line < top_line: |
|---|
| 4380 | self.MoveCaretToLine(top_line) |
|---|
| 4381 | elif current_line > bottom_line: |
|---|
| 4382 | self.MoveCaretToLine(bottom_line) |
|---|
| 4383 | evt.Skip() |
|---|
| 4384 | |
|---|
| 4385 | def OnLeftMouseUp(self, evt): |
|---|
| 4386 | """Enter visual mode if text is selected by mouse""" |
|---|
| 4387 | if len(self.ctrl.GetSelectedText()) > 0: |
|---|
| 4388 | self.EnterVisualMode(True) |
|---|
| 4389 | else: |
|---|
| 4390 | self.LeaveVisualMode() |
|---|
| 4391 | |
|---|
| 4392 | |
|---|
| 4393 | |
|---|
| 4394 | wx.CallAfter(self.CheckLineEnd) |
|---|
| 4395 | evt.Skip() |
|---|
| 4396 | |
|---|
| 4397 | def OnAutocompleteKeyDown(self, evt): |
|---|
| 4398 | if evt.GetKeyCode() in (wx.WXK_UP, wx.WXK_DOWN, wx.WXK_LEFT, wx.WXK_RIGHT, wx.WXK_RETURN, wx.WXK_ESCAPE): |
|---|
| 4399 | evt.Skip() |
|---|
| 4400 | return |
|---|
| 4401 | |
|---|
| 4402 | if evt.GetRawKeyCode() in (65505, 65507, 65513): |
|---|
| 4403 | return |
|---|
| 4404 | |
|---|
| 4405 | |
|---|
| 4406 | if evt.ControlDown(): |
|---|
| 4407 | if evt.GetKeyCode() == 80: |
|---|
| 4408 | evt = wx.KeyEvent(wx.wxEVT_KEY_DOWN) |
|---|
| 4409 | evt.m_keyCode = wx.WXK_UP |
|---|
| 4410 | wx.PostEvent(self.ctrl, evt) |
|---|
| 4411 | return |
|---|
| 4412 | |
|---|
| 4413 | elif evt.GetKeyCode() == 78: |
|---|
| 4414 | evt = wx.KeyEvent(wx.wxEVT_KEY_DOWN) |
|---|
| 4415 | evt.m_keyCode = wx.WXK_DOWN |
|---|
| 4416 | wx.PostEvent(self.ctrl, evt) |
|---|
| 4417 | return |
|---|
| 4418 | |
|---|
| 4419 | elif evt.GetKeyCode() == 91: |
|---|
| 4420 | evt = wx.KeyEvent(wx.wxEVT_KEY_DOWN) |
|---|
| 4421 | evt.m_keyCode = wx.WXK_ESCAPE |
|---|
| 4422 | wx.PostEvent(self.ctrl, evt) |
|---|
| 4423 | return |
|---|
| 4424 | |
|---|
| 4425 | |
|---|
| 4426 | evt.Skip() |
|---|
| 4427 | self.ctrl.Bind(wx.EVT_KEY_DOWN, None) |
|---|
| 4428 | |
|---|
| 4429 | def OnViKeyDown(self, evt): |
|---|
| 4430 | """ |
|---|
| 4431 | Handle keypresses when in Vi mode |
|---|
| 4432 | |
|---|
| 4433 | """ |
|---|
| 4434 | |
|---|
| 4435 | |
|---|
| 4436 | |
|---|
| 4437 | |
|---|
| 4438 | key = evt.GetKeyCode() |
|---|
| 4439 | |
|---|
| 4440 | if not evt.ControlDown() and not evt.ShiftDown(): |
|---|
| 4441 | if key == wx.WXK_TAB: |
|---|
| 4442 | if self.ctrl.pageType == u"form": |
|---|
| 4443 | if not self.ctrl._goToNextFormField(): |
|---|
| 4444 | self.ctrl.presenter.getMainControl().showStatusMessage( |
|---|
| 4445 | _(u"No more fields in this 'form' page"), -1) |
|---|
| 4446 | return |
|---|
| 4447 | evt.Skip() |
|---|
| 4448 | elif key == wx.WXK_RETURN and not self.ctrl.AutoCompActive(): |
|---|
| 4449 | text = self.ctrl.GetText() |
|---|
| 4450 | wikiDocument = self.ctrl.presenter.getWikiDocument() |
|---|
| 4451 | bytePos = self.ctrl.GetCurrentPos() |
|---|
| 4452 | lineStartBytePos = self.ctrl.PositionFromLine( |
|---|
| 4453 | self.ctrl.LineFromPosition(bytePos)) |
|---|
| 4454 | |
|---|
| 4455 | lineStartCharPos = len(self.ctrl.GetTextRange(0, |
|---|
| 4456 | lineStartBytePos)) |
|---|
| 4457 | charPos = lineStartCharPos + len(self.ctrl.GetTextRange( |
|---|
| 4458 | lineStartBytePos, bytePos)) |
|---|
| 4459 | |
|---|
| 4460 | autoUnbullet = self.ctrl.presenter.getConfig().getboolean("main", |
|---|
| 4461 | "editor_autoUnbullets", False) |
|---|
| 4462 | |
|---|
| 4463 | settings = { |
|---|
| 4464 | "autoUnbullet": autoUnbullet, |
|---|
| 4465 | "autoBullets": self.ctrl.autoBullets, |
|---|
| 4466 | "autoIndent": self.ctrl.autoIndent |
|---|
| 4467 | } |
|---|
| 4468 | |
|---|
| 4469 | if self.ctrl.wikiLanguageHelper.handleNewLineBeforeEditor( |
|---|
| 4470 | self.ctrl, text, charPos, lineStartCharPos, |
|---|
| 4471 | wikiDocument, settings): |
|---|
| 4472 | evt.Skip() |
|---|
| 4473 | return |
|---|
| 4474 | |
|---|
| 4475 | |
|---|
| 4476 | elif bytePos != self.ctrl.GetCurrentPos(): |
|---|
| 4477 | return |
|---|
| 4478 | |
|---|
| 4479 | |
|---|
| 4480 | |
|---|
| 4481 | key = evt.GetRawKeyCode() |
|---|
| 4482 | |
|---|
| 4483 | |
|---|
| 4484 | if key in (65505, 65507, 65513): |
|---|
| 4485 | return |
|---|
| 4486 | |
|---|
| 4487 | accP = getAccelPairFromKeyDown(evt) |
|---|
| 4488 | |
|---|
| 4489 | |
|---|
| 4490 | |
|---|
| 4491 | |
|---|
| 4492 | if key == 65307 or accP == (2, 91) or accP == (2, 99): |
|---|
| 4493 | |
|---|
| 4494 | self.SetMode(ViHandler.NORMAL) |
|---|
| 4495 | self.FlushBuffers() |
|---|
| 4496 | return |
|---|
| 4497 | |
|---|
| 4498 | |
|---|
| 4499 | |
|---|
| 4500 | if self.HasSelection(): |
|---|
| 4501 | self.EnterVisualMode() |
|---|
| 4502 | |
|---|
| 4503 | |
|---|
| 4504 | try: |
|---|
| 4505 | if 2 in accP[0]: |
|---|
| 4506 | |
|---|
| 4507 | key = ("Ctrl", key) |
|---|
| 4508 | except TypeError: |
|---|
| 4509 | if accP[0] == 2: |
|---|
| 4510 | key = ("Ctrl", key) |
|---|
| 4511 | |
|---|
| 4512 | m = self.mode |
|---|
| 4513 | |
|---|
| 4514 | if m in [1, 3]: |
|---|
| 4515 | |
|---|
| 4516 | |
|---|
| 4517 | |
|---|
| 4518 | |
|---|
| 4519 | |
|---|
| 4520 | |
|---|
| 4521 | self.insert_action.append(key) |
|---|
| 4522 | if key in [65362, 65362]: |
|---|
| 4523 | self.insert_action = [] |
|---|
| 4524 | if not self.RunKeyChain((key,), m): |
|---|
| 4525 | evt.Skip() |
|---|
| 4526 | return |
|---|
| 4527 | |
|---|
| 4528 | |
|---|
| 4529 | |
|---|
| 4530 | |
|---|
| 4531 | |
|---|
| 4532 | if self._acceptable_keys is None or \ |
|---|
| 4533 | "*" not in self._acceptable_keys: |
|---|
| 4534 | if 48 <= key <= 57: |
|---|
| 4535 | if self.SetNumber(key-48): |
|---|
| 4536 | return |
|---|
| 4537 | elif 65456 <= key <= 65465: |
|---|
| 4538 | if self.SetNumber(key-65456): |
|---|
| 4539 | return |
|---|
| 4540 | |
|---|
| 4541 | self.SetCount() |
|---|
| 4542 | |
|---|
| 4543 | if self._motion and self._acceptable_keys is None: |
|---|
| 4544 | |
|---|
| 4545 | self._motion.append(key) |
|---|
| 4546 | |
|---|
| 4547 | temp = self._motion[:-1] |
|---|
| 4548 | temp.append("*") |
|---|
| 4549 | if tuple(self._motion) in self.motion_keys[m]: |
|---|
| 4550 | self.RunKeyChain(tuple(self.key_inputs), m) |
|---|
| 4551 | return |
|---|
| 4552 | |
|---|
| 4553 | elif tuple(temp) in self.motion_keys[m]: |
|---|
| 4554 | self._motion[-1] = "*" |
|---|
| 4555 | self._motion_wildcard.append(key) |
|---|
| 4556 | self.RunKeyChain(tuple(self.key_inputs), m) |
|---|
| 4557 | |
|---|
| 4558 | return |
|---|
| 4559 | |
|---|
| 4560 | elif tuple(self._motion) in self.motion_key_mods[m]: |
|---|
| 4561 | |
|---|
| 4562 | return |
|---|
| 4563 | |
|---|
| 4564 | self.FlushBuffers() |
|---|
| 4565 | return |
|---|
| 4566 | |
|---|
| 4567 | |
|---|
| 4568 | if self._acceptable_keys is not None: |
|---|
| 4569 | if key in self._acceptable_keys: |
|---|
| 4570 | self._acceptable_keys = None |
|---|
| 4571 | pass |
|---|
| 4572 | elif "*" in self._acceptable_keys: |
|---|
| 4573 | self._wildcard.append(key) |
|---|
| 4574 | self.key_inputs.append("*") |
|---|
| 4575 | self._acceptable_keys = None |
|---|
| 4576 | self.RunKeyChain(tuple(self.key_inputs), m) |
|---|
| 4577 | |
|---|
| 4578 | return |
|---|
| 4579 | elif "motion" in self._acceptable_keys: |
|---|
| 4580 | self._acceptable_keys = None |
|---|
| 4581 | self._motion.append(key) |
|---|
| 4582 | if (key,) in self.motion_keys[m]: |
|---|
| 4583 | self.key_inputs.append("motion") |
|---|
| 4584 | self.RunKeyChain(tuple(self.key_inputs), m) |
|---|
| 4585 | return |
|---|
| 4586 | if (key,) in self.motion_key_mods[m]: |
|---|
| 4587 | self.key_inputs.append("motion") |
|---|
| 4588 | return |
|---|
| 4589 | |
|---|
| 4590 | |
|---|
| 4591 | self.key_inputs.append(key) |
|---|
| 4592 | self.updateViStatus() |
|---|
| 4593 | |
|---|
| 4594 | key_chain = tuple(self.key_inputs) |
|---|
| 4595 | |
|---|
| 4596 | if self.RunKeyChain(key_chain, m): |
|---|
| 4597 | return |
|---|
| 4598 | |
|---|
| 4599 | self.FlushBuffers() |
|---|
| 4600 | |
|---|
| 4601 | def TurnOff(self): |
|---|
| 4602 | self._enableMenuShortcuts(True) |
|---|
| 4603 | self.ctrl.SetCaretWidth(1) |
|---|
| 4604 | |
|---|
| 4605 | def GetChar(self, length=1): |
|---|
| 4606 | """ |
|---|
| 4607 | Retrieves text from under caret |
|---|
| 4608 | @param length: the number of characters to get |
|---|
| 4609 | """ |
|---|
| 4610 | pos = self.ctrl.GetCurrentPos() |
|---|
| 4611 | start, end = self.minmax(pos, pos + length) |
|---|
| 4612 | start = max(0, start) |
|---|
| 4613 | end = min(end, self.ctrl.GetLength()) |
|---|
| 4614 | return self.ctrl.GetTextRange(start, end) |
|---|
| 4615 | |
|---|
| 4616 | def EmulateKeypresses(self, actions): |
|---|
| 4617 | if len(actions) > 0: |
|---|
| 4618 | |
|---|
| 4619 | eol = self.ctrl.GetEOLChar() |
|---|
| 4620 | |
|---|
| 4621 | for i in actions: |
|---|
| 4622 | |
|---|
| 4623 | if i == 65361: |
|---|
| 4624 | self.ctrl.CharLeft() |
|---|
| 4625 | elif i == 65363: |
|---|
| 4626 | self.ctrl.CharRight() |
|---|
| 4627 | elif i == 65288: |
|---|
| 4628 | self.ctrl.DeleteBackNotLine() |
|---|
| 4629 | elif i in [65535, 65439]: |
|---|
| 4630 | self.ctrl.CharRight() |
|---|
| 4631 | self.ctrl.DeleteBack() |
|---|
| 4632 | elif i in [65293, 65421]: |
|---|
| 4633 | self.ctrl.InsertText(self.ctrl.GetCurrentPos(), eol) |
|---|
| 4634 | self.ctrl.CharRight() |
|---|
| 4635 | elif i == 65289: |
|---|
| 4636 | self.ctrl.InsertText(self.ctrl.GetCurrentPos(), "\t") |
|---|
| 4637 | self.ctrl.CharRight() |
|---|
| 4638 | else: |
|---|
| 4639 | self.ctrl.InsertText(self.ctrl.GetCurrentPos(), unichr(i)) |
|---|
| 4640 | self.ctrl.CharRight() |
|---|
| 4641 | |
|---|
| 4642 | |
|---|
| 4643 | def RepeatCmd(self): |
|---|
| 4644 | |
|---|
| 4645 | if self.last_cmd is not None: |
|---|
| 4646 | self.visualBell("GREEN") |
|---|
| 4647 | self.BeginUndo() |
|---|
| 4648 | cmd_type, key, count, motion, motion_wildcards, wildcards = self.last_cmd |
|---|
| 4649 | |
|---|
| 4650 | self.count = count |
|---|
| 4651 | actions = self.insert_action |
|---|
| 4652 | |
|---|
| 4653 | if cmd_type == 1: |
|---|
| 4654 | self.RunFunction(key, motion, motion_wildcards, wildcards) |
|---|
| 4655 | |
|---|
| 4656 | |
|---|
| 4657 | elif cmd_type == 2: |
|---|
| 4658 | self.RunFunction(key, motion, motion_wildcards, wildcards) |
|---|
| 4659 | |
|---|
| 4660 | |
|---|
| 4661 | self.EmulateKeypresses(actions) |
|---|
| 4662 | self.SetMode(ViHandler.NORMAL) |
|---|
| 4663 | elif cmd_type == 3: |
|---|
| 4664 | self.ReplaceChar(key) |
|---|
| 4665 | self.EndUndo() |
|---|
| 4666 | self.insert_action = actions |
|---|
| 4667 | else: |
|---|
| 4668 | self.visualBell("RED") |
|---|
| 4669 | |
|---|
| 4670 | |
|---|
| 4671 | |
|---|
| 4672 | |
|---|
| 4673 | |
|---|
| 4674 | def Autocomplete(self, forwards): |
|---|
| 4675 | if not self.ctrl.AutoCompActive(): |
|---|
| 4676 | |
|---|
| 4677 | if self.GetUnichrAt(self.ctrl.GetCurrentPos()-1) in \ |
|---|
| 4678 | self.WORD_BREAK_INCLUDING_WHITESPACE: |
|---|
| 4679 | word = u"[a-zA-Z0-9_]" |
|---|
| 4680 | word_length = 0 |
|---|
| 4681 | |
|---|
| 4682 | else: |
|---|
| 4683 | |
|---|
| 4684 | self.SelectInWord() |
|---|
| 4685 | self.ExtendSelectionIfRequired() |
|---|
| 4686 | word = self.ctrl.GetSelectedText() |
|---|
| 4687 | word_length = len(word) |
|---|
| 4688 | |
|---|
| 4689 | |
|---|
| 4690 | |
|---|
| 4691 | |
|---|
| 4692 | text = self.ctrl.GetTextRange( |
|---|
| 4693 | self.ctrl.GetCurrentPos(), self.ctrl.GetLength()) |
|---|
| 4694 | word_list = re.findall(ur"\b{0}.*?\b".format(word), text, re.U) |
|---|
| 4695 | text = self.ctrl.GetTextRange(0, self.ctrl.GetCurrentPos()) |
|---|
| 4696 | word_list.extend(re.findall(ur"\b{0}.*?\b".format(word), text, re.U)) |
|---|
| 4697 | |
|---|
| 4698 | |
|---|
| 4699 | if len(word_list) <= 1: |
|---|
| 4700 | if self.HasSelection(): |
|---|
| 4701 | self.ctrl.CharRight() |
|---|
| 4702 | self.visualBell("RED") |
|---|
| 4703 | return |
|---|
| 4704 | |
|---|
| 4705 | |
|---|
| 4706 | words = set() |
|---|
| 4707 | words.add(word) |
|---|
| 4708 | word_list_prepped = "\x01".join([i for i in word_list if i not in words and not words.add(i)]) |
|---|
| 4709 | |
|---|
| 4710 | if self.HasSelection(): |
|---|
| 4711 | self.ctrl.CharRight() |
|---|
| 4712 | self.ctrl.AutoCompShow(word_length, word_list_prepped) |
|---|
| 4713 | self.ctrl.Bind(wx.EVT_KEY_DOWN, self.OnAutocompleteKeyDown) |
|---|
| 4714 | |
|---|
| 4715 | |
|---|
| 4716 | def GotoSelectionStart(self): |
|---|
| 4717 | self.ctrl.GotoPos(self.ctrl.GetSelectionStart()) |
|---|
| 4718 | |
|---|
| 4719 | def InsertPreviousText(self): |
|---|
| 4720 | self.EmulateKeypresses(self.insert_action) |
|---|
| 4721 | |
|---|
| 4722 | def InsertPreviousTextLeaveInsertMode(self): |
|---|
| 4723 | self.InsertPreviousText() |
|---|
| 4724 | self.SetMode(ViHelper.NORMAL) |
|---|
| 4725 | |
|---|
| 4726 | def ChangeSurrounding(self, keycodes): |
|---|
| 4727 | char_to_change = self.GetCharFromCode(keycodes[0]) |
|---|
| 4728 | if char_to_change in self.text_object_map: |
|---|
| 4729 | self.SelectATextObject(char_to_change) |
|---|
| 4730 | if self.HasSelection(): |
|---|
| 4731 | pos = self.ExtendSelectionIfRequired() |
|---|
| 4732 | self.BeginUndo() |
|---|
| 4733 | self.ctrl.ReplaceSelection(self.ctrl.GetSelectedText()[1:-1]) |
|---|
| 4734 | self.ctrl.CharLeft() |
|---|
| 4735 | self.SelectSelection() |
|---|
| 4736 | self.SurroundSelection(keycodes[1]) |
|---|
| 4737 | self.ctrl.GotoPos(pos) |
|---|
| 4738 | self.EndUndo() |
|---|
| 4739 | self.visualBell("GREEN") |
|---|
| 4740 | return |
|---|
| 4741 | self.visualBell("RED") |
|---|
| 4742 | |
|---|
| 4743 | def PreSurround(self, code): |
|---|
| 4744 | self.SelectSelection(False) |
|---|
| 4745 | self.SurroundSelection(code) |
|---|
| 4746 | |
|---|
| 4747 | def PreSurroundLine(self, code): |
|---|
| 4748 | self.SelectCurrentLine() |
|---|
| 4749 | self.SurroundSelection(code) |
|---|
| 4750 | |
|---|
| 4751 | def GetUnichrAt(self, pos): |
|---|
| 4752 | if -1 < pos < self.ctrl.GetLength(): |
|---|
| 4753 | return self.ctrl.GetTextRaw()[pos] |
|---|
| 4754 | |
|---|
| 4755 | def SelectInTextObject(self, ob): |
|---|
| 4756 | self.SelectTextObject(ob, False) |
|---|
| 4757 | |
|---|
| 4758 | def SelectATextObject(self, ob): |
|---|
| 4759 | self.SelectTextObject(ob, True) |
|---|
| 4760 | |
|---|
| 4761 | def SelectTextObject(self, ob=None, extra=False): |
|---|
| 4762 | """ |
|---|
| 4763 | Selects specified text object |
|---|
| 4764 | |
|---|
| 4765 | See vim help -> *text-objects* |
|---|
| 4766 | |
|---|
| 4767 | Two different selection methods are supported. They are given |
|---|
| 4768 | the names "In" and "A" corresponding to vim's "i(n)" and "a(n)" |
|---|
| 4769 | commands respectively. |
|---|
| 4770 | |
|---|
| 4771 | The differences between these is dependent on the type of text |
|---|
| 4772 | to be selected, it can be either a selection (e.g. words, |
|---|
| 4773 | sentences, etc...) or a block (e.g. text within [ ] or " " or |
|---|
| 4774 | ( ) etc...). |
|---|
| 4775 | """ |
|---|
| 4776 | if ob in self.text_object_map: |
|---|
| 4777 | self.text_object_map[ob][1](extra) |
|---|
| 4778 | |
|---|
| 4779 | |
|---|
| 4780 | |
|---|
| 4781 | |
|---|
| 4782 | |
|---|
| 4783 | |
|---|
| 4784 | def SelectTrailingWhitespace(self, sel_start, sel_end): |
|---|
| 4785 | self.StartSelection(sel_start) |
|---|
| 4786 | true_end = self.ctrl.GetCurrentPos() |
|---|
| 4787 | |
|---|
| 4788 | if self.ctrl.GetCharAt(sel_end+1) in \ |
|---|
| 4789 | self.SINGLE_LINE_WHITESPACE or \ |
|---|
| 4790 | self.ctrl.GetCharAt(sel_start) in \ |
|---|
| 4791 | self.SINGLE_LINE_WHITESPACE: |
|---|
| 4792 | self.MoveCaretWordEndCountWhitespace(1) |
|---|
| 4793 | |
|---|
| 4794 | elif self.ctrl.GetCharAt(sel_start-1) \ |
|---|
| 4795 | in self.SINGLE_LINE_WHITESPACE: |
|---|
| 4796 | pos = sel_start-1 |
|---|
| 4797 | while self.ctrl.GetCharAt(pos-1) \ |
|---|
| 4798 | in self.SINGLE_LINE_WHITESPACE: |
|---|
| 4799 | pos -= 1 |
|---|
| 4800 | self.ctrl.GotoPos(pos) |
|---|
| 4801 | self.StartSelection() |
|---|
| 4802 | self.ctrl.GotoPos(true_end) |
|---|
| 4803 | self.SelectSelection() |
|---|
| 4804 | |
|---|
| 4805 | def SelectInWord(self, extra=False): |
|---|
| 4806 | """ |
|---|
| 4807 | Selects n words where n is the count. Whitespace between words |
|---|
| 4808 | is counted. |
|---|
| 4809 | """ |
|---|
| 4810 | self._SelectInWords(False, extra=extra) |
|---|
| 4811 | |
|---|
| 4812 | def SelectInWORD(self, extra=False): |
|---|
| 4813 | self._SelectInWords(True, extra=extra) |
|---|
| 4814 | |
|---|
| 4815 | def _SelectInWords(self, WORD=False, extra=False): |
|---|
| 4816 | |
|---|
| 4817 | pos = self.ctrl.GetCurrentPos() |
|---|
| 4818 | |
|---|
| 4819 | if not WORD: |
|---|
| 4820 | back_word = self.MoveCaretBackWord |
|---|
| 4821 | move_caret_word_end_count_whitespace = \ |
|---|
| 4822 | self.MoveCaretWordEndCountWhitespace |
|---|
| 4823 | else: |
|---|
| 4824 | back_word = self.MoveCaretBackWORD |
|---|
| 4825 | move_caret_word_end_count_whitespace = \ |
|---|
| 4826 | self.MoveCaretWordENDCountWhitespace |
|---|
| 4827 | |
|---|
| 4828 | |
|---|
| 4829 | if self.ctrl.GetCharAt(pos) in self.SINGLE_LINE_WHITESPACE: |
|---|
| 4830 | self.MoveCaretToWhitespaceStart() |
|---|
| 4831 | else: |
|---|
| 4832 | if pos > 0: |
|---|
| 4833 | if self.GetUnichrAt(pos-1) in string.whitespace: |
|---|
| 4834 | pass |
|---|
| 4835 | elif ((self.GetUnichrAt(pos) in self.WORD_BREAK) is not (self.GetUnichrAt(pos-1) in self.WORD_BREAK)) and not WORD: |
|---|
| 4836 | pass |
|---|
| 4837 | else: |
|---|
| 4838 | back_word(1) |
|---|
| 4839 | self.StartSelection() |
|---|
| 4840 | move_caret_word_end_count_whitespace(1) |
|---|
| 4841 | self.SelectSelection() |
|---|
| 4842 | if extra: |
|---|
| 4843 | sel_start, sel_end = self._GetSelectionRange() |
|---|
| 4844 | self.SelectTrailingWhitespace(sel_start, sel_end) |
|---|
| 4845 | move_caret_word_end_count_whitespace(self.count-1) |
|---|
| 4846 | self.SelectSelection() |
|---|
| 4847 | |
|---|
| 4848 | def SelectInSentence(self, extra=False): |
|---|
| 4849 | """ Selects current sentence """ |
|---|
| 4850 | |
|---|
| 4851 | pos = start_pos = self.ctrl.GetCurrentPos() |
|---|
| 4852 | if pos > 0 and self.GetUnichrAt(pos-1) in string.whitespace: |
|---|
| 4853 | pos -= 1 |
|---|
| 4854 | char = self.GetUnichrAt(pos-1) |
|---|
| 4855 | while pos > 0 and char in string.whitespace: |
|---|
| 4856 | pos -= 1 |
|---|
| 4857 | char = self.GetUnichrAt(pos-1) |
|---|
| 4858 | if char in self.SENTENCE_ENDINGS_SUFFIXS: |
|---|
| 4859 | pos -= 1 |
|---|
| 4860 | char = self.GetUnichrAt(pos-1) |
|---|
| 4861 | while pos > 0 and char in self.SENTENCE_ENDINGS_SUFFIXS: |
|---|
| 4862 | pos -= 1 |
|---|
| 4863 | char = self.GetUnichrAt(pos-1) |
|---|
| 4864 | if char not in self.SENTENCE_ENDINGS: |
|---|
| 4865 | self.GotoSentenceStart(1) |
|---|
| 4866 | else: |
|---|
| 4867 | self.GotoSentenceStart(1) |
|---|
| 4868 | self.StartSelection() |
|---|
| 4869 | self.GotoSentenceEnd(1) |
|---|
| 4870 | self.SelectSelection() |
|---|
| 4871 | sel_start, sel_end = self._GetSelectionRange() |
|---|
| 4872 | self.ctrl.GotoPos(sel_start) |
|---|
| 4873 | if extra: |
|---|
| 4874 | self.count += 1 |
|---|
| 4875 | self.GotoSentenceEndCountWhitespace() |
|---|
| 4876 | self.SelectSelection() |
|---|
| 4877 | |
|---|
| 4878 | def SelectInParagraph(self, extra=False): |
|---|
| 4879 | """ Selects current paragraph """ |
|---|
| 4880 | |
|---|
| 4881 | self.MoveCaretParaDown(1) |
|---|
| 4882 | self.MoveCaretParaUp(1) |
|---|
| 4883 | self.StartSelection() |
|---|
| 4884 | self.MoveCaretParaDown() |
|---|
| 4885 | self.ctrl.CharLeft() |
|---|
| 4886 | self.SelectSelection() |
|---|
| 4887 | |
|---|
| 4888 | def _SelectInBracket(self, bracket, extra=False, start_pos=None, count=None): |
|---|
| 4889 | if start_pos is None: start_pos = self.ctrl.GetCurrentPos() |
|---|
| 4890 | if count is None: count = self.count |
|---|
| 4891 | |
|---|
| 4892 | if self.SearchBackwardsForChar(bracket, count): |
|---|
| 4893 | pos = self.ctrl.GetCurrentPos() |
|---|
| 4894 | |
|---|
| 4895 | pre_text = self.ctrl.GetTextRange(pos, start_pos) |
|---|
| 4896 | |
|---|
| 4897 | while pre_text.count(bracket) - pre_text.count(self.BRACES[bracket]) \ |
|---|
| 4898 | != self.count: |
|---|
| 4899 | self.ctrl.CharLeft() |
|---|
| 4900 | if self.SearchBackwardsForChar(bracket, 1): |
|---|
| 4901 | pos = self.ctrl.GetCurrentPos() |
|---|
| 4902 | pre_text = self.ctrl.GetTextRange(pos, start_pos) |
|---|
| 4903 | else: |
|---|
| 4904 | break |
|---|
| 4905 | |
|---|
| 4906 | if self.MatchBraceUnderCaret(): |
|---|
| 4907 | self.StartSelection(pos) |
|---|
| 4908 | self.SelectSelection() |
|---|
| 4909 | sel_start, sel_end = self._GetSelectionRange() |
|---|
| 4910 | if not sel_start <= start_pos <= sel_end: |
|---|
| 4911 | self.ctrl.GotoPos(sel_start-1) |
|---|
| 4912 | self._SelectInBracket(bracket, extra, start_pos, count) |
|---|
| 4913 | else: |
|---|
| 4914 | |
|---|
| 4915 | if not extra: |
|---|
| 4916 | self.StartSelection(pos+1) |
|---|
| 4917 | |
|---|
| 4918 | |
|---|
| 4919 | self.ctrl.SetSelection(sel_start, sel_end-1) |
|---|
| 4920 | else: |
|---|
| 4921 | self.ctrl.GotoPos(start_pos) |
|---|
| 4922 | |
|---|
| 4923 | def SelectInSquareBracket(self, extra=False): |
|---|
| 4924 | """ Selects text in [ ] block """ |
|---|
| 4925 | self._SelectInBracket("[", extra) |
|---|
| 4926 | |
|---|
| 4927 | def SelectInRoundBracket(self, extra=False): |
|---|
| 4928 | """ Selects text in ( ) block """ |
|---|
| 4929 | self._SelectInBracket("(", extra) |
|---|
| 4930 | |
|---|
| 4931 | def SelectInInequalitySigns(self, extra=False): |
|---|
| 4932 | """ Selects text in < > block """ |
|---|
| 4933 | self._SelectInBracket("<", extra) |
|---|
| 4934 | |
|---|
| 4935 | def SelectInTagBlock(self, extra=False): |
|---|
| 4936 | """ selects text in <aaa> </aaa> block """ |
|---|
| 4937 | |
|---|
| 4938 | |
|---|
| 4939 | def SelectInBlock(self, extra=False): |
|---|
| 4940 | """ selects text in { } block """ |
|---|
| 4941 | self._SelectInBracket("{", extra) |
|---|
| 4942 | |
|---|
| 4943 | def _SelectInChars(self, char, extra=False): |
|---|
| 4944 | pos = self.ctrl.GetCurrentPos() |
|---|
| 4945 | if self.SearchBackwardsForChar(char): |
|---|
| 4946 | start_pos = self.ctrl.GetCurrentPos() |
|---|
| 4947 | self.ctrl.GotoPos(pos) |
|---|
| 4948 | if self.SearchForwardsForChar(char): |
|---|
| 4949 | self.StartSelection(start_pos) |
|---|
| 4950 | self.SelectSelection() |
|---|
| 4951 | if not extra: |
|---|
| 4952 | sel_start, sel_end = self._GetSelectionRange() |
|---|
| 4953 | self.StartSelection(start_pos+1) |
|---|
| 4954 | self.ctrl.SetSelection(sel_start, sel_end-1) |
|---|
| 4955 | |
|---|
| 4956 | def SelectInDoubleQuote(self, extra=False): |
|---|
| 4957 | """ selects text in " " block """ |
|---|
| 4958 | self._SelectInChars('"', extra) |
|---|
| 4959 | |
|---|
| 4960 | def SelectInSingleQuote(self, extra=False): |
|---|
| 4961 | """ selects text in ' ' block """ |
|---|
| 4962 | self._SelectInChars("'", extra) |
|---|
| 4963 | |
|---|
| 4964 | def SelectInTilde(self, extra=False): |
|---|
| 4965 | """ selects text in ` ` block """ |
|---|
| 4966 | self._SelectInChars("`", extra) |
|---|
| 4967 | |
|---|
| 4968 | |
|---|
| 4969 | |
|---|
| 4970 | def SelectInPoundSigns(self, extra=False): |
|---|
| 4971 | self._SelectInChars("\xc2", extra) |
|---|
| 4972 | |
|---|
| 4973 | def SelectInDollarSigns(self, extra=False): |
|---|
| 4974 | self._SelectInChars("$", extra) |
|---|
| 4975 | |
|---|
| 4976 | def SelectInHats(self, extra=False): |
|---|
| 4977 | self._SelectInChars("^", extra) |
|---|
| 4978 | |
|---|
| 4979 | def SelectInPercentSigns(self, extra=False): |
|---|
| 4980 | self._SelectInChars("%", extra) |
|---|
| 4981 | |
|---|
| 4982 | def SelectInAmpersands(self, extra=False): |
|---|
| 4983 | self._SelectInChars("&", extra) |
|---|
| 4984 | |
|---|
| 4985 | def SelectInStars(self, extra=False): |
|---|
| 4986 | self._SelectInChars("*", extra) |
|---|
| 4987 | |
|---|
| 4988 | def SelectInHyphens(self, extra=False): |
|---|
| 4989 | self._SelectInChars("-", extra) |
|---|
| 4990 | |
|---|
| 4991 | def SelectInUnderscores(self, extra=False): |
|---|
| 4992 | self._SelectInChars("_", extra) |
|---|
| 4993 | |
|---|
| 4994 | def SelectInEqualSigns(self, extra=False): |
|---|
| 4995 | self._SelectInChars("=", extra) |
|---|
| 4996 | |
|---|
| 4997 | def SelectInPlusSigns(self, extra=False): |
|---|
| 4998 | self._SelectInChars("+", extra) |
|---|
| 4999 | |
|---|
| 5000 | def SelectInExclamationMarks(self, extra=False): |
|---|
| 5001 | self._SelectInChars("!", extra) |
|---|
| 5002 | |
|---|
| 5003 | def SelectInQuestionMarks(self, extra=False): |
|---|
| 5004 | self._SelectInChars("?", extra) |
|---|
| 5005 | |
|---|
| 5006 | def SelectInAtSigns(self, extra=False): |
|---|
| 5007 | self._SelectInChars("@", extra) |
|---|
| 5008 | |
|---|
| 5009 | def SelectInHashs(self, extra=False): |
|---|
| 5010 | self._SelectInChars("#", extra) |
|---|
| 5011 | |
|---|
| 5012 | def SelectInApproxSigns(self, extra=False): |
|---|
| 5013 | self._SelectInChars("~", extra) |
|---|
| 5014 | |
|---|
| 5015 | def SelectInVerticalBars(self, extra=False): |
|---|
| 5016 | self._SelectInChars("|", extra) |
|---|
| 5017 | |
|---|
| 5018 | def SelectInSemicolons(self, extra=False): |
|---|
| 5019 | self._SelectInChars(";", extra) |
|---|
| 5020 | |
|---|
| 5021 | def SelectInColons(self, extra=False): |
|---|
| 5022 | self._SelectInChars(":", extra) |
|---|
| 5023 | |
|---|
| 5024 | def SelectInBackslashes(self, extra=False): |
|---|
| 5025 | self._SelectInChars("\\", extra) |
|---|
| 5026 | |
|---|
| 5027 | def SelectInForwardslashes(self, extra=False): |
|---|
| 5028 | self._SelectInChars("/", extra) |
|---|
| 5029 | |
|---|
| 5030 | |
|---|
| 5031 | def SurroundSelection(self, keycode): |
|---|
| 5032 | |
|---|
| 5033 | start = self.ExtendSelectionIfRequired() |
|---|
| 5034 | |
|---|
| 5035 | text = self.ctrl.GetSelectedText() |
|---|
| 5036 | |
|---|
| 5037 | if len(text) < 1: |
|---|
| 5038 | return |
|---|
| 5039 | |
|---|
| 5040 | self.BeginUndo() |
|---|
| 5041 | |
|---|
| 5042 | |
|---|
| 5043 | if text[-1] == self.ctrl.GetEOLChar(): |
|---|
| 5044 | sel_start, sel_end = self._GetSelectionRange() |
|---|
| 5045 | self.ctrl.SetSelection(sel_start, sel_end-1) |
|---|
| 5046 | text = self.ctrl.GetSelectedText() |
|---|
| 5047 | |
|---|
| 5048 | replacements = { |
|---|
| 5049 | ")" : ("(", ")"), |
|---|
| 5050 | "b" : ("(", ")"), |
|---|
| 5051 | "}" : ("{", "}"), |
|---|
| 5052 | "B" : ("{", "}"), |
|---|
| 5053 | "]" : ("[", "]"), |
|---|
| 5054 | "r" : ("[", "]"), |
|---|
| 5055 | ">" : ("<", ">"), |
|---|
| 5056 | "a" : ("<", ">"), |
|---|
| 5057 | |
|---|
| 5058 | "(" : ("( ", " )"), |
|---|
| 5059 | "{" : ("{ ", " }"), |
|---|
| 5060 | "[" : ("[ ", " ]"), |
|---|
| 5061 | |
|---|
| 5062 | |
|---|
| 5063 | |
|---|
| 5064 | |
|---|
| 5065 | |
|---|
| 5066 | "'" : ("'", "'"), |
|---|
| 5067 | '"' : ('"', '"'), |
|---|
| 5068 | "`" : ("`", "`"), |
|---|
| 5069 | |
|---|
| 5070 | } |
|---|
| 5071 | uni_chr = unichr(keycode) |
|---|
| 5072 | if uni_chr in replacements: |
|---|
| 5073 | new_text = "{0}{1}{2}".format(replacements[uni_chr][0], text, replacements[uni_chr][1]) |
|---|
| 5074 | else: |
|---|
| 5075 | new_text = "{0}{1}{2}".format(uni_chr, text, uni_chr) |
|---|
| 5076 | |
|---|
| 5077 | self.ctrl.ReplaceSelection(new_text) |
|---|
| 5078 | self.LeaveVisualMode() |
|---|
| 5079 | self.ctrl.GotoPos(start) |
|---|
| 5080 | self.EndUndo() |
|---|
| 5081 | |
|---|
| 5082 | |
|---|
| 5083 | def CheckLineEnd(self): |
|---|
| 5084 | |
|---|
| 5085 | line, line_pos = self.ctrl.GetCurLine() |
|---|
| 5086 | if self.mode not in [ViHelper.VISUAL, ViHelper.INSERT]: |
|---|
| 5087 | unicode_line = unicode(line) |
|---|
| 5088 | if len(line) > 1 and line_pos >= len(bytes(unicode_line))-1: |
|---|
| 5089 | |
|---|
| 5090 | pos = self.ctrl.GetCurrentPos()-len(bytes(unicode_line[-1])) |
|---|
| 5091 | self.ctrl.GotoPos(pos) |
|---|
| 5092 | |
|---|
| 5093 | |
|---|
| 5094 | |
|---|
| 5095 | |
|---|
| 5096 | def SelectCurrentLine(self, include_eol=True): |
|---|
| 5097 | line_no = self.ctrl.GetCurrentLine() |
|---|
| 5098 | max_line = min(line_no+self.count-1, self.ctrl.GetLineCount()) |
|---|
| 5099 | start = self.GetLineStartPos(line_no) |
|---|
| 5100 | end = self.ctrl.GetLineEndPosition(max_line) |
|---|
| 5101 | |
|---|
| 5102 | |
|---|
| 5103 | |
|---|
| 5104 | if max_line + 1 == self.ctrl.GetLineCount(): |
|---|
| 5105 | start -= 1 |
|---|
| 5106 | |
|---|
| 5107 | if include_eol: |
|---|
| 5108 | end += 1 |
|---|
| 5109 | self.ctrl.SetSelection(end, start) |
|---|
| 5110 | |
|---|
| 5111 | def SelectFullLines(self): |
|---|
| 5112 | """ |
|---|
| 5113 | Could probably be replaced by SetSectionMode, |
|---|
| 5114 | if it can be made to work. |
|---|
| 5115 | """ |
|---|
| 5116 | start_line, end_line = self._GetSelectedLines() |
|---|
| 5117 | if self.ctrl.GetCurrentPos() >= self.visual_line_start_pos: |
|---|
| 5118 | reverse = False |
|---|
| 5119 | |
|---|
| 5120 | |
|---|
| 5121 | if len(self.ctrl.GetLine(start_line)) > 1: |
|---|
| 5122 | text, pos = self.ctrl.GetCurLine() |
|---|
| 5123 | if len(text) > 1: |
|---|
| 5124 | end_line -= 1 |
|---|
| 5125 | |
|---|
| 5126 | else: |
|---|
| 5127 | reverse = True |
|---|
| 5128 | end_line -= 1 |
|---|
| 5129 | |
|---|
| 5130 | cur_line = self.ctrl.GetCurrentLine() |
|---|
| 5131 | self.SelectLines(start_line, end_line, reverse) |
|---|
| 5132 | |
|---|
| 5133 | |
|---|
| 5134 | def JoinLines(self): |
|---|
| 5135 | text = self.ctrl.GetSelectedText() |
|---|
| 5136 | start_line = self.ctrl.GetCurrentLine() |
|---|
| 5137 | if len(text) < 1: |
|---|
| 5138 | |
|---|
| 5139 | count = self.count if self.count > 1 else 2 |
|---|
| 5140 | self.SelectLines(start_line, min(self.ctrl.GetLineCount(), \ |
|---|
| 5141 | start_line - 1 + count)) |
|---|
| 5142 | else: |
|---|
| 5143 | start_line, end_line = self._GetSelectedLines() |
|---|
| 5144 | self.SelectLines(start_line, end_line) |
|---|
| 5145 | |
|---|
| 5146 | text = self.ctrl.GetSelectedText() |
|---|
| 5147 | |
|---|
| 5148 | eol_char = self.ctrl.GetEOLChar() |
|---|
| 5149 | |
|---|
| 5150 | |
|---|
| 5151 | |
|---|
| 5152 | lines = text.split(eol_char) |
|---|
| 5153 | new_text = [] |
|---|
| 5154 | for i in range(len(lines)): |
|---|
| 5155 | if lines[i] == u"": |
|---|
| 5156 | continue |
|---|
| 5157 | if i == 0: |
|---|
| 5158 | new_text.append(lines[i]) |
|---|
| 5159 | else: |
|---|
| 5160 | new_text.append(lines[i].lstrip()) |
|---|
| 5161 | |
|---|
| 5162 | self.ctrl.ReplaceSelection(" ".join(new_text)) |
|---|
| 5163 | |
|---|
| 5164 | def DeleteSelectionAndInsert(self): |
|---|
| 5165 | self.DeleteSelection() |
|---|
| 5166 | self.Insert() |
|---|
| 5167 | |
|---|
| 5168 | def RemoveSelection(self): |
|---|
| 5169 | """ |
|---|
| 5170 | Removes the selection. |
|---|
| 5171 | |
|---|
| 5172 | TODO: don't goto selection start pos |
|---|
| 5173 | """ |
|---|
| 5174 | pos = self.ctrl.GetAnchor() |
|---|
| 5175 | self.ctrl.SetSelection(pos,pos) |
|---|
| 5176 | |
|---|
| 5177 | |
|---|
| 5178 | def GetSelectionAnchor(self): |
|---|
| 5179 | return self._anchor |
|---|
| 5180 | |
|---|
| 5181 | def StartSelection(self, pos=None): |
|---|
| 5182 | """ Saves the current position to be used for selection start """ |
|---|
| 5183 | if pos is None: |
|---|
| 5184 | pos = self.ctrl.GetCurrentPos() |
|---|
| 5185 | self._anchor = pos |
|---|
| 5186 | |
|---|
| 5187 | def StartSelectionAtAnchor(self): |
|---|
| 5188 | """ |
|---|
| 5189 | Saves the current position to be used for selection start using |
|---|
| 5190 | the anchor as the selection start. |
|---|
| 5191 | """ |
|---|
| 5192 | if len(self.ctrl.GetSelectedText()) > 0: |
|---|
| 5193 | self._anchor = self.ctrl.GetAnchor() |
|---|
| 5194 | else: |
|---|
| 5195 | self._anchor = self.ctrl.GetCurrentPos() |
|---|
| 5196 | |
|---|
| 5197 | |
|---|
| 5198 | def SelectInLink(self): |
|---|
| 5199 | pos = self.ctrl.GetCurrentPos() |
|---|
| 5200 | start_pos = self.FindChar(91, True, 0, 1, False) |
|---|
| 5201 | self.StartSelection() |
|---|
| 5202 | end_pos = self.FindChar(93, False, -1, 1, False) |
|---|
| 5203 | |
|---|
| 5204 | if start_pos and end_pos: |
|---|
| 5205 | self.SelectSelection() |
|---|
| 5206 | |
|---|
| 5207 | def SelectSelection(self, offset_motion=True): |
|---|
| 5208 | |
|---|
| 5209 | |
|---|
| 5210 | |
|---|
| 5211 | if offset_motion and self._motion in ( |
|---|
| 5212 | [101], [69], [36], [102, "*"], [70, "*"], [116, "*"], [84, "*"]): |
|---|
| 5213 | |
|---|
| 5214 | self.ExtendSelectionIfRequired() |
|---|
| 5215 | |
|---|
| 5216 | self.ctrl.SetSelection(self._anchor, self.ctrl.GetCurrentPos()) |
|---|
| 5217 | |
|---|
| 5218 | |
|---|
| 5219 | def SelectionOnSingleLine(self): |
|---|
| 5220 | """ |
|---|
| 5221 | Assume that if an EOL char is present we have mutiple lines |
|---|
| 5222 | """ |
|---|
| 5223 | if self.ctrl.GetEOLChar() in self.ctrl.GetSelectedText(): |
|---|
| 5224 | return False |
|---|
| 5225 | else: |
|---|
| 5226 | return True |
|---|
| 5227 | |
|---|
| 5228 | def ExtendSelectionIfRequired(self): |
|---|
| 5229 | """ |
|---|
| 5230 | If selection is positive the last character is not actually |
|---|
| 5231 | selected and so a correction must be applied |
|---|
| 5232 | """ |
|---|
| 5233 | start, end = self._GetSelectionRange() |
|---|
| 5234 | if self.ctrl.GetCurrentPos() == end: |
|---|
| 5235 | self.ctrl.CharRightExtend() |
|---|
| 5236 | return start |
|---|
| 5237 | |
|---|
| 5238 | def DeleteSelection(self): |
|---|
| 5239 | """Yank selection and delete it""" |
|---|
| 5240 | |
|---|
| 5241 | |
|---|
| 5242 | self.BeginUndo() |
|---|
| 5243 | self.YankSelection() |
|---|
| 5244 | self.ctrl.Clear() |
|---|
| 5245 | |
|---|
| 5246 | self.EndUndo() |
|---|
| 5247 | self.LeaveVisualMode() |
|---|
| 5248 | |
|---|
| 5249 | def _GetSelectionRange(self): |
|---|
| 5250 | """Get the range of selection such that the start is the visual start |
|---|
| 5251 | of the selection, not the logical start. |
|---|
| 5252 | |
|---|
| 5253 | """ |
|---|
| 5254 | start, end = self.minmax(self.ctrl.GetSelectionStart(), |
|---|
| 5255 | self.ctrl.GetSelectionEnd()) |
|---|
| 5256 | return start, end |
|---|
| 5257 | |
|---|
| 5258 | def _GetSelectedLines(self): |
|---|
| 5259 | """Get the first and last line (exclusive) of selection""" |
|---|
| 5260 | start, end = self._GetSelectionRange() |
|---|
| 5261 | start_line, end_line = (self.ctrl.LineFromPosition(start), |
|---|
| 5262 | self.ctrl.LineFromPosition(end - 1) + 1) |
|---|
| 5263 | return start_line, end_line |
|---|
| 5264 | |
|---|
| 5265 | def HasSelection(self): |
|---|
| 5266 | """ |
|---|
| 5267 | Detects if there's anything selected |
|---|
| 5268 | @rtype: bool |
|---|
| 5269 | """ |
|---|
| 5270 | return len(self.ctrl.GetSelectedText()) > 0 |
|---|
| 5271 | |
|---|
| 5272 | def InsertText(self, text): |
|---|
| 5273 | self.ctrl.InsertText(self.ctrl.GetCurrentPos(), text) |
|---|
| 5274 | self.MoveCaretPos(len(text)) |
|---|
| 5275 | |
|---|
| 5276 | def SelectLines(self, start, end, reverse=False): |
|---|
| 5277 | """ |
|---|
| 5278 | Selects lines |
|---|
| 5279 | |
|---|
| 5280 | @param start: start line |
|---|
| 5281 | @param end: end line |
|---|
| 5282 | @param reverse: if true selection is reversed |
|---|
| 5283 | """ |
|---|
| 5284 | start_pos = self.GetLineStartPos(start) |
|---|
| 5285 | end_pos = self.ctrl.GetLineEndPosition(end) |
|---|
| 5286 | |
|---|
| 5287 | if reverse: |
|---|
| 5288 | self.ctrl.SetSelection(end_pos, start_pos) |
|---|
| 5289 | else: |
|---|
| 5290 | self.ctrl.SetSelection(start_pos, end_pos) |
|---|
| 5291 | |
|---|
| 5292 | def PreUppercase(self): |
|---|
| 5293 | start = self.ExtendSelectionIfRequired() |
|---|
| 5294 | self.SelectSelection() |
|---|
| 5295 | self.ctrl.ReplaceSelection(self.ctrl.GetSelectedText().upper()) |
|---|
| 5296 | self.ctrl.GotoPos(start) |
|---|
| 5297 | |
|---|
| 5298 | def PreLowercase(self): |
|---|
| 5299 | start = self.ExtendSelectionIfRequired() |
|---|
| 5300 | self.SelectSelection() |
|---|
| 5301 | self.ctrl.ReplaceSelection(self.ctrl.GetSelectedText().lower()) |
|---|
| 5302 | self.ctrl.GotoPos(start) |
|---|
| 5303 | |
|---|
| 5304 | def SwapCase(self): |
|---|
| 5305 | self.BeginUndo() |
|---|
| 5306 | text = self.ctrl.GetSelectedText() |
|---|
| 5307 | if len(text) == 0: |
|---|
| 5308 | self.StartSelection() |
|---|
| 5309 | self.MoveCaretRight() |
|---|
| 5310 | self.SelectSelection() |
|---|
| 5311 | text = self.ctrl.GetSelectedText() |
|---|
| 5312 | self.ctrl.ReplaceSelection(text.swapcase()) |
|---|
| 5313 | self.EndUndo() |
|---|
| 5314 | |
|---|
| 5315 | def UpperCase(self): |
|---|
| 5316 | self.ctrl.ReplaceSelection(self.ctrl.GetSelectedText().upper()) |
|---|
| 5317 | |
|---|
| 5318 | def LowerCase(self): |
|---|
| 5319 | self.ctrl.ReplaceSelection(self.ctrl.GetSelectedText().lower()) |
|---|
| 5320 | |
|---|
| 5321 | def Indent(self, forward=True, repeat=1, visual=False): |
|---|
| 5322 | if visual == True: |
|---|
| 5323 | repeat = self.count |
|---|
| 5324 | |
|---|
| 5325 | self.BeginUndo() |
|---|
| 5326 | |
|---|
| 5327 | if len(self.ctrl.GetSelectedText()) < 1: |
|---|
| 5328 | start_line = self.ctrl.GetCurrentLine() |
|---|
| 5329 | if self.count > 1: |
|---|
| 5330 | self.SelectLines(start_line, min(self.ctrl.GetLineCount(), \ |
|---|
| 5331 | start_line - 1 + self.count)) |
|---|
| 5332 | else: |
|---|
| 5333 | start_line, end = self._GetSelectedLines() |
|---|
| 5334 | |
|---|
| 5335 | if self.SelectionOnSingleLine(): |
|---|
| 5336 | self.GotoLineIndent() |
|---|
| 5337 | |
|---|
| 5338 | for i in range(repeat): |
|---|
| 5339 | if forward: |
|---|
| 5340 | self.ctrl.Tab() |
|---|
| 5341 | else: |
|---|
| 5342 | self.ctrl.BackTab() |
|---|
| 5343 | |
|---|
| 5344 | self.ctrl.GotoLine(start_line) |
|---|
| 5345 | self.GotoLineIndent() |
|---|
| 5346 | self.EndUndo() |
|---|
| 5347 | |
|---|
| 5348 | def _PositionViewport(self, n): |
|---|
| 5349 | """ |
|---|
| 5350 | Helper function for ScrollViewport* functions. |
|---|
| 5351 | |
|---|
| 5352 | Positions the viewport around caret position |
|---|
| 5353 | |
|---|
| 5354 | """ |
|---|
| 5355 | lines = self.ctrl.LinesOnScreen() - 1 |
|---|
| 5356 | current = self.ctrl.GetCurrentLine() |
|---|
| 5357 | diff = int(lines * n) |
|---|
| 5358 | self.ctrl.ScrollToLine(current - diff) |
|---|
| 5359 | |
|---|
| 5360 | def GetViewportPosition(self): |
|---|
| 5361 | lines = self.ctrl.LinesOnScreen() - 1 |
|---|
| 5362 | current = self.ctrl.GetCurrentLine() |
|---|
| 5363 | first_visible_line = self.ctrl.GetFirstVisibleLine() |
|---|
| 5364 | |
|---|
| 5365 | n = current - first_visible_line |
|---|
| 5366 | |
|---|
| 5367 | return n / float(lines) |
|---|
| 5368 | |
|---|
| 5369 | def _ScrollViewportByLines(self, n): |
|---|
| 5370 | first_visible_line = self.ctrl.GetFirstVisibleLine() |
|---|
| 5371 | lines_on_screen = self.ctrl.LinesOnScreen() |
|---|
| 5372 | |
|---|
| 5373 | line = max(0, first_visible_line + n) |
|---|
| 5374 | line = min(line, self.ctrl.GetLineCount() - lines_on_screen) |
|---|
| 5375 | self.ctrl.ScrollToLine(line) |
|---|
| 5376 | if self.ctrl.GetCurrentLine() < line: |
|---|
| 5377 | self.ctrl.LineDown() |
|---|
| 5378 | elif self.ctrl.GetCurrentLine() > first_visible_line + lines_on_screen-2: |
|---|
| 5379 | self.ctrl.LineUp() |
|---|
| 5380 | |
|---|
| 5381 | def _ScrollViewport(self, n): |
|---|
| 5382 | view_pos = self.GetViewportPosition() |
|---|
| 5383 | lines = self.ctrl.LinesOnScreen() |
|---|
| 5384 | current_line = self.ctrl.GetCurrentLine() |
|---|
| 5385 | new_line = max(0, current_line + n * lines) |
|---|
| 5386 | new_line = min(new_line, self.ctrl.GetLineCount()) |
|---|
| 5387 | self.GotoLineIndent(new_line) |
|---|
| 5388 | self._PositionViewport(view_pos) |
|---|
| 5389 | |
|---|
| 5390 | def IndentText(self): |
|---|
| 5391 | """ |
|---|
| 5392 | Post motion function. Select text and indent it |
|---|
| 5393 | """ |
|---|
| 5394 | self.SelectSelection() |
|---|
| 5395 | self.Indent(True) |
|---|
| 5396 | |
|---|
| 5397 | def DedentText(self): |
|---|
| 5398 | """ |
|---|
| 5399 | Post motion function. Select text and deindent it |
|---|
| 5400 | """ |
|---|
| 5401 | self.SelectSelection() |
|---|
| 5402 | self.Indent(False) |
|---|
| 5403 | |
|---|
| 5404 | |
|---|
| 5405 | |
|---|
| 5406 | |
|---|
| 5407 | |
|---|
| 5408 | def EnterLineVisualMode(self): |
|---|
| 5409 | """ |
|---|
| 5410 | Enter line visual mode |
|---|
| 5411 | |
|---|
| 5412 | Sets a special type of visual mode in which only full lines can |
|---|
| 5413 | be selected. |
|---|
| 5414 | |
|---|
| 5415 | NOTE: |
|---|
| 5416 | Should be possible using StyledTextCtrl.SetSelectionType() but |
|---|
| 5417 | for some reason I can't get it to work so a SetSelMode() has |
|---|
| 5418 | been implemented. |
|---|
| 5419 | |
|---|
| 5420 | """ |
|---|
| 5421 | self.SetSelMode("LINE") |
|---|
| 5422 | text, pos = self.ctrl.GetCurLine() |
|---|
| 5423 | if pos == 0: |
|---|
| 5424 | self.MoveCaretRight() |
|---|
| 5425 | self.visual_line_start_pos = self.ctrl.GetCurrentPos() |
|---|
| 5426 | if self.mode != ViHelper.VISUAL: |
|---|
| 5427 | self.SetMode(ViHelper.VISUAL) |
|---|
| 5428 | self.StartSelectionAtAnchor() |
|---|
| 5429 | |
|---|
| 5430 | |
|---|
| 5431 | |
|---|
| 5432 | |
|---|
| 5433 | def LeaveVisualMode(self): |
|---|
| 5434 | """Helper function to end visual mode""" |
|---|
| 5435 | self.ctrl.GotoPos(self.ctrl.GetSelectionStart()) |
|---|
| 5436 | if self.mode == ViHelper.VISUAL: |
|---|
| 5437 | self.SetSelMode("NORMAL") |
|---|
| 5438 | self.SetMode(ViHelper.NORMAL) |
|---|
| 5439 | |
|---|
| 5440 | def EnterVisualMode(self, mouse=False): |
|---|
| 5441 | """ |
|---|
| 5442 | Change to visual (selection) mode |
|---|
| 5443 | |
|---|
| 5444 | Will do nothing if already in visual mode |
|---|
| 5445 | |
|---|
| 5446 | @param mouse: Visual mode was started by mouse action |
|---|
| 5447 | |
|---|
| 5448 | """ |
|---|
| 5449 | if self.mode != ViHelper.VISUAL: |
|---|
| 5450 | self.SetMode(ViHelper.VISUAL) |
|---|
| 5451 | |
|---|
| 5452 | if not mouse: |
|---|
| 5453 | self.StartSelectionAtAnchor() |
|---|
| 5454 | |
|---|
| 5455 | |
|---|
| 5456 | |
|---|
| 5457 | else: |
|---|
| 5458 | self.StartSelection(self.ctrl.GetSelectionEnd()) |
|---|
| 5459 | |
|---|
| 5460 | |
|---|
| 5461 | |
|---|
| 5462 | |
|---|
| 5463 | |
|---|
| 5464 | def SearchForwardsForChar(self, search_char, count=None, |
|---|
| 5465 | wrap_lines=True, start_offset=-1): |
|---|
| 5466 | if count is None: count = self.count |
|---|
| 5467 | pos = start_pos = self.ctrl.GetCurrentPos() + start_offset |
|---|
| 5468 | |
|---|
| 5469 | text = self.ctrl.GetTextRaw() |
|---|
| 5470 | |
|---|
| 5471 | |
|---|
| 5472 | n = 0 |
|---|
| 5473 | for i in range(count): |
|---|
| 5474 | pos = text.find(search_char, pos + 1) |
|---|
| 5475 | |
|---|
| 5476 | |
|---|
| 5477 | |
|---|
| 5478 | if pos > -1: |
|---|
| 5479 | if not wrap_lines: |
|---|
| 5480 | |
|---|
| 5481 | text_to_check = self.ctrl.GetTextRange(start_pos, pos) |
|---|
| 5482 | if self.ctrl.GetEOLChar() in text_to_check: |
|---|
| 5483 | return False |
|---|
| 5484 | self.ctrl.GotoPos(pos) |
|---|
| 5485 | return True |
|---|
| 5486 | |
|---|
| 5487 | self.visualBell("RED") |
|---|
| 5488 | return False |
|---|
| 5489 | |
|---|
| 5490 | def SearchBackwardsForChar(self, search_char, count=None, |
|---|
| 5491 | wrap_lines=True, start_offset=0): |
|---|
| 5492 | """ |
|---|
| 5493 | Searches backwards in text for character. |
|---|
| 5494 | |
|---|
| 5495 | @param search_char: Character to search for. |
|---|
| 5496 | @param count: Number of characeters to find. |
|---|
| 5497 | @param wrap_lines: Should search occur on multiple lines. |
|---|
| 5498 | @param start_offset: Start offset for searching. Should be |
|---|
| 5499 | zero if character under the caret should be included in |
|---|
| 5500 | the search, -1 if not. |
|---|
| 5501 | |
|---|
| 5502 | @rtype: bool |
|---|
| 5503 | @return: True if successful, False if not. |
|---|
| 5504 | |
|---|
| 5505 | """ |
|---|
| 5506 | if count is None: count = self.count |
|---|
| 5507 | pos = start_pos = self.ctrl.GetCurrentPos() + start_offset |
|---|
| 5508 | |
|---|
| 5509 | text = self.ctrl.GetTextRaw() |
|---|
| 5510 | text_to_search = text[:pos+1] |
|---|
| 5511 | for i in range(count): |
|---|
| 5512 | pos = text_to_search.rfind(search_char) |
|---|
| 5513 | text_to_search = text[:pos] |
|---|
| 5514 | |
|---|
| 5515 | if pos > -1: |
|---|
| 5516 | if not wrap_lines: |
|---|
| 5517 | text_to_check = self.ctrl.GetTextRange(start_pos, pos) |
|---|
| 5518 | if self.ctrl.GetEOLChar() in text_to_check: |
|---|
| 5519 | return False |
|---|
| 5520 | self.ctrl.GotoPos(pos) |
|---|
| 5521 | return True |
|---|
| 5522 | |
|---|
| 5523 | self.visualBell("RED") |
|---|
| 5524 | return False |
|---|
| 5525 | |
|---|
| 5526 | def FindMatchingBrace(self, brace): |
|---|
| 5527 | if brace in self.BRACES: |
|---|
| 5528 | forward = True |
|---|
| 5529 | b = self.BRACES |
|---|
| 5530 | elif brace in self.REVERSE_BRACES: |
|---|
| 5531 | forward = False |
|---|
| 5532 | b = self.REVERSE_BRACES |
|---|
| 5533 | else: |
|---|
| 5534 | return |
|---|
| 5535 | |
|---|
| 5536 | start_pos = self.ctrl.GetCurrentPos() |
|---|
| 5537 | if forward: |
|---|
| 5538 | text = self.ctrl.GetTextRaw()[start_pos+1:] |
|---|
| 5539 | else: |
|---|
| 5540 | text = self.ctrl.GetTextRaw()[0:start_pos:][::-1] |
|---|
| 5541 | brace_count = 1 |
|---|
| 5542 | n = 0 |
|---|
| 5543 | pos = -1 |
|---|
| 5544 | for i in text: |
|---|
| 5545 | n += 1 |
|---|
| 5546 | if i == brace: |
|---|
| 5547 | brace_count += 1 |
|---|
| 5548 | elif i == b[brace]: |
|---|
| 5549 | brace_count -= 1 |
|---|
| 5550 | |
|---|
| 5551 | if brace_count < 1: |
|---|
| 5552 | if forward: |
|---|
| 5553 | pos = start_pos + n |
|---|
| 5554 | else: |
|---|
| 5555 | pos = start_pos - n |
|---|
| 5556 | break |
|---|
| 5557 | |
|---|
| 5558 | if pos > -1: |
|---|
| 5559 | self.ctrl.GotoPos(pos) |
|---|
| 5560 | return True |
|---|
| 5561 | else: |
|---|
| 5562 | self.visualBell("RED") |
|---|
| 5563 | return False |
|---|
| 5564 | |
|---|
| 5565 | def FindChar(self, code=None, reverse=False, offset=0, count=1, \ |
|---|
| 5566 | repeat=True): |
|---|
| 5567 | """ |
|---|
| 5568 | Searches current *line* for specified character. |
|---|
| 5569 | |
|---|
| 5570 | Will move the caret to this place (+/- any offset supplied). |
|---|
| 5571 | |
|---|
| 5572 | @param code: keycode of character to search for. |
|---|
| 5573 | @param reverse: If True will search backwards. |
|---|
| 5574 | @param offset: Offset to move caret post search. |
|---|
| 5575 | @param count: Number of characters to find. If not all found, |
|---|
| 5576 | i.e. count is 3 but only 2 characters on current line, will |
|---|
| 5577 | not move caret. |
|---|
| 5578 | @param repeat: Should the search be saved so it will be |
|---|
| 5579 | repeated (by "," and ";") |
|---|
| 5580 | |
|---|
| 5581 | @rtype: bool |
|---|
| 5582 | @return: True if successful, False if not. |
|---|
| 5583 | |
|---|
| 5584 | """ |
|---|
| 5585 | if code is None: |
|---|
| 5586 | return False |
|---|
| 5587 | |
|---|
| 5588 | char = bytes(self.GetCharFromCode(code)) |
|---|
| 5589 | pos = self.ctrl.GetCurrentPos() |
|---|
| 5590 | |
|---|
| 5591 | if repeat: |
|---|
| 5592 | |
|---|
| 5593 | |
|---|
| 5594 | self.last_find_cmd = { |
|---|
| 5595 | "code": code, |
|---|
| 5596 | "reverse": reverse, |
|---|
| 5597 | "offset": offset, |
|---|
| 5598 | "repeat": False |
|---|
| 5599 | } |
|---|
| 5600 | |
|---|
| 5601 | if reverse: |
|---|
| 5602 | search_cmd = self.SearchBackwardsForChar |
|---|
| 5603 | start_offset = -1 |
|---|
| 5604 | offset = - offset |
|---|
| 5605 | |
|---|
| 5606 | else: |
|---|
| 5607 | search_cmd = self.SearchForwardsForChar |
|---|
| 5608 | start_offset = 0 |
|---|
| 5609 | |
|---|
| 5610 | if search_cmd(char, count, False, start_offset): |
|---|
| 5611 | self.MoveCaretPos(offset) |
|---|
| 5612 | self.ctrl.ChooseCaretX() |
|---|
| 5613 | return True |
|---|
| 5614 | |
|---|
| 5615 | return False |
|---|
| 5616 | |
|---|
| 5617 | def FindNextChar(self, keycode): |
|---|
| 5618 | self.FindChar(keycode, count=self.count) |
|---|
| 5619 | |
|---|
| 5620 | def FindNextCharBackwards(self, keycode): |
|---|
| 5621 | cmd = self.FindChar(keycode, count=self.count, reverse=True) |
|---|
| 5622 | |
|---|
| 5623 | def FindUpToNextChar(self, keycode): |
|---|
| 5624 | cmd = self.FindChar(keycode, count=self.count, offset=-1) |
|---|
| 5625 | |
|---|
| 5626 | def FindUpToNextCharBackwards(self, keycode): |
|---|
| 5627 | cmd = self.FindChar(keycode, count=self.count, reverse=True, offset=-1) |
|---|
| 5628 | |
|---|
| 5629 | def GetLastFindCharCmd(self): |
|---|
| 5630 | return self.last_find_cmd |
|---|
| 5631 | |
|---|
| 5632 | def RepeatLastFindCharCmd(self): |
|---|
| 5633 | args = self.GetLastFindCharCmd() |
|---|
| 5634 | if args is not None: |
|---|
| 5635 | |
|---|
| 5636 | args["count"] = self.count |
|---|
| 5637 | self.FindChar(**args) |
|---|
| 5638 | |
|---|
| 5639 | def RepeatLastFindCharCmdReverse(self): |
|---|
| 5640 | args = self.GetLastFindCharCmd() |
|---|
| 5641 | if args is not None: |
|---|
| 5642 | args["count"] = self.count |
|---|
| 5643 | args["reverse"] = not args["reverse"] |
|---|
| 5644 | self.FindChar(**args) |
|---|
| 5645 | args["reverse"] = not args["reverse"] |
|---|
| 5646 | |
|---|
| 5647 | def MatchBraceUnderCaret(self): |
|---|
| 5648 | return self.FindMatchingBrace(self.GetUnichrAt( |
|---|
| 5649 | self.ctrl.GetCurrentPos())) |
|---|
| 5650 | |
|---|
| 5651 | |
|---|
| 5652 | def _SearchText(self, text, forward=True, match_case=True, wrap=True, |
|---|
| 5653 | whole_word=True): |
|---|
| 5654 | """ |
|---|
| 5655 | Searches for next occurance of 'text' |
|---|
| 5656 | |
|---|
| 5657 | @param text: text to search for |
|---|
| 5658 | @param forward: if true searches forward in text, else |
|---|
| 5659 | search in reverse |
|---|
| 5660 | @param match_case: should search be case sensitive? |
|---|
| 5661 | """ |
|---|
| 5662 | self.AddJumpPosition(self.ctrl.GetCurrentPos() - len(text)) |
|---|
| 5663 | |
|---|
| 5664 | search_cmd = self.ctrl.SearchNext if forward else self.ctrl.SearchPrev |
|---|
| 5665 | |
|---|
| 5666 | |
|---|
| 5667 | if whole_word and match_case: |
|---|
| 5668 | flags = wx.stc.STC_FIND_WHOLEWORD|wx.stc.STC_FIND_MATCHCASE |
|---|
| 5669 | elif whole_word: |
|---|
| 5670 | flags = wx.stc.STC_FIND_WHOLEWORD |
|---|
| 5671 | elif match_case: |
|---|
| 5672 | flags = wx.stc.STC_FIND_MATCHCASE |
|---|
| 5673 | |
|---|
| 5674 | pos = search_cmd(flags, text) |
|---|
| 5675 | |
|---|
| 5676 | if pos == -1 and wrap: |
|---|
| 5677 | if forward: |
|---|
| 5678 | self.ctrl.GotoLine(0) |
|---|
| 5679 | else: |
|---|
| 5680 | self.ctrl.GotoLine(self.ctrl.GetLineCount()) |
|---|
| 5681 | self.ctrl.SearchAnchor() |
|---|
| 5682 | pos = search_cmd(flags, text) |
|---|
| 5683 | if pos != -1: |
|---|
| 5684 | self.ctrl.GotoPos(pos) |
|---|
| 5685 | |
|---|
| 5686 | def _SearchCaretWord(self, forward=True, match_case=True, whole_word=True): |
|---|
| 5687 | """ |
|---|
| 5688 | Searches for next occurance of word currently under |
|---|
| 5689 | the caret |
|---|
| 5690 | |
|---|
| 5691 | @param forward: if true searches forward in text, else |
|---|
| 5692 | search in reverse |
|---|
| 5693 | @param match_case: should search be case sensitive? |
|---|
| 5694 | @param whole_word: must the entire string match as a word |
|---|
| 5695 | """ |
|---|
| 5696 | self.SelectInWord() |
|---|
| 5697 | self.ExtendSelectionIfRequired() |
|---|
| 5698 | text = self.ctrl.GetSelectedText() |
|---|
| 5699 | |
|---|
| 5700 | |
|---|
| 5701 | if forward: |
|---|
| 5702 | self.ctrl.CharRight() |
|---|
| 5703 | else: |
|---|
| 5704 | self.ctrl.CharLeft() |
|---|
| 5705 | self.ctrl.SearchAnchor() |
|---|
| 5706 | self._SearchText(text, forward, match_case=match_case, wrap=True, whole_word=whole_word) |
|---|
| 5707 | |
|---|
| 5708 | self.last_search_args = {'text' : text, 'forward' : forward, |
|---|
| 5709 | 'match_case' : match_case, |
|---|
| 5710 | 'whole_word' : whole_word} |
|---|
| 5711 | |
|---|
| 5712 | def SearchCaretWordForwards(self): |
|---|
| 5713 | """Helper function to allow repeats""" |
|---|
| 5714 | self._SearchCaretWord(True, True, True) |
|---|
| 5715 | |
|---|
| 5716 | def SearchPartialCaretWordForwards(self): |
|---|
| 5717 | self._SearchCaretWord(True, True, False) |
|---|
| 5718 | |
|---|
| 5719 | def SearchCaretWordBackwards(self): |
|---|
| 5720 | """Helper function to allow repeats""" |
|---|
| 5721 | self._SearchCaretWord(False, True, True) |
|---|
| 5722 | |
|---|
| 5723 | def SearchPartialCaretWordBackwards(self): |
|---|
| 5724 | self._SearchCaretWord(False, True, False) |
|---|
| 5725 | |
|---|
| 5726 | def ContinueLastSearch(self, reverse): |
|---|
| 5727 | """ |
|---|
| 5728 | Repeats last search command |
|---|
| 5729 | """ |
|---|
| 5730 | args = self.last_search_args |
|---|
| 5731 | if args is not None: |
|---|
| 5732 | |
|---|
| 5733 | if reverse: |
|---|
| 5734 | args['forward'] = not args['forward'] |
|---|
| 5735 | |
|---|
| 5736 | offset = 1 if args['forward'] else -1 |
|---|
| 5737 | self.MoveCaretPos(offset) |
|---|
| 5738 | self.ctrl.SearchAnchor() |
|---|
| 5739 | |
|---|
| 5740 | self._SearchText(**args) |
|---|
| 5741 | |
|---|
| 5742 | |
|---|
| 5743 | if reverse: |
|---|
| 5744 | args['forward'] = not args['forward'] |
|---|
| 5745 | |
|---|
| 5746 | def ContinueLastSearchSameDirection(self): |
|---|
| 5747 | """Helper function to allow repeats""" |
|---|
| 5748 | self.ContinueLastSearch(False) |
|---|
| 5749 | |
|---|
| 5750 | def ContinueLastSearchReverseDirection(self): |
|---|
| 5751 | """Helper function to allow repeats""" |
|---|
| 5752 | self.ContinueLastSearch(True) |
|---|
| 5753 | |
|---|
| 5754 | |
|---|
| 5755 | |
|---|
| 5756 | |
|---|
| 5757 | |
|---|
| 5758 | def ReplaceChar(self, keycode): |
|---|
| 5759 | """ |
|---|
| 5760 | Replaces character under caret |
|---|
| 5761 | |
|---|
| 5762 | Contains some custom code to allow repeating |
|---|
| 5763 | """ |
|---|
| 5764 | |
|---|
| 5765 | char = unichr(keycode) |
|---|
| 5766 | |
|---|
| 5767 | |
|---|
| 5768 | if self.mode == ViHelper.VISUAL: |
|---|
| 5769 | sel_start, sel_end = self._GetSelectionRange() |
|---|
| 5770 | count = sel_end - sel_start |
|---|
| 5771 | self.ctrl.GotoPos(sel_start) |
|---|
| 5772 | else: |
|---|
| 5773 | count = self.count |
|---|
| 5774 | |
|---|
| 5775 | |
|---|
| 5776 | |
|---|
| 5777 | line, pos = self.ctrl.GetCurLineRaw() |
|---|
| 5778 | line_length = len(line) |
|---|
| 5779 | |
|---|
| 5780 | |
|---|
| 5781 | |
|---|
| 5782 | if self.ctrl.GetLineCount() == self.ctrl.GetCurrentLine() + 1: |
|---|
| 5783 | line_length += 1 |
|---|
| 5784 | |
|---|
| 5785 | if pos + count > line_length: |
|---|
| 5786 | return |
|---|
| 5787 | |
|---|
| 5788 | self.last_cmd = 3, keycode, count, None |
|---|
| 5789 | |
|---|
| 5790 | self.BeginUndo() |
|---|
| 5791 | self.StartSelection() |
|---|
| 5792 | self.ctrl.GotoPos(self.ctrl.GetCurrentPos()+count) |
|---|
| 5793 | self.EndDelete() |
|---|
| 5794 | self.Repeat(self.InsertText, arg=char) |
|---|
| 5795 | if pos + count != line_length: |
|---|
| 5796 | self.MoveCaretPos(-1) |
|---|
| 5797 | self.EndUndo() |
|---|
| 5798 | |
|---|
| 5799 | def StartReplaceMode(self): |
|---|
| 5800 | |
|---|
| 5801 | self.BeginUndo() |
|---|
| 5802 | self.SetMode(ViHelper.REPLACE) |
|---|
| 5803 | |
|---|
| 5804 | |
|---|
| 5805 | |
|---|
| 5806 | |
|---|
| 5807 | |
|---|
| 5808 | def _SetMark(self, code): |
|---|
| 5809 | """ |
|---|
| 5810 | Not called directly (call self.Mark instead) |
|---|
| 5811 | """ |
|---|
| 5812 | page = self.ctrl.presenter.getWikiWord() |
|---|
| 5813 | self.marks[page][code] = self.ctrl.GetCurrentPos() |
|---|
| 5814 | |
|---|
| 5815 | def GotoMark(self, char): |
|---|
| 5816 | |
|---|
| 5817 | page = self.ctrl.presenter.getWikiWord() |
|---|
| 5818 | if char in self.marks[page]: |
|---|
| 5819 | self.AddJumpPosition() |
|---|
| 5820 | pos = self.marks[page][char] |
|---|
| 5821 | |
|---|
| 5822 | |
|---|
| 5823 | |
|---|
| 5824 | pos = min(self.ctrl.GetLength(), pos) |
|---|
| 5825 | |
|---|
| 5826 | self.ctrl.GotoPos(pos) |
|---|
| 5827 | self.visualBell("GREEN") |
|---|
| 5828 | return True |
|---|
| 5829 | |
|---|
| 5830 | self.visualBell("RED") |
|---|
| 5831 | return False |
|---|
| 5832 | |
|---|
| 5833 | def GotoMarkIndent(self, char): |
|---|
| 5834 | if self.GotoMark(char): |
|---|
| 5835 | self.GotoLineIndent() |
|---|
| 5836 | |
|---|
| 5837 | |
|---|
| 5838 | |
|---|
| 5839 | |
|---|
| 5840 | |
|---|
| 5841 | def YankLine(self): |
|---|
| 5842 | """Copy the current line text to the clipboard""" |
|---|
| 5843 | |
|---|
| 5844 | line_no = self.ctrl.GetCurrentLine() |
|---|
| 5845 | max_line = min(line_no+self.count-1, self.ctrl.GetLineCount()) |
|---|
| 5846 | start = self.GetLineStartPos(line_no) |
|---|
| 5847 | end = self.ctrl.GetLineEndPosition(max_line) |
|---|
| 5848 | |
|---|
| 5849 | text = self.ctrl.GetTextRange(start, end) + self.ctrl.GetEOLChar() |
|---|
| 5850 | |
|---|
| 5851 | self.ctrl.Copy(text) |
|---|
| 5852 | |
|---|
| 5853 | def YankSelection(self, lines=False): |
|---|
| 5854 | """Copy the current selection to the clipboard""" |
|---|
| 5855 | if self.mode == ViHelper.VISUAL: |
|---|
| 5856 | self.ExtendSelectionIfRequired() |
|---|
| 5857 | if lines: |
|---|
| 5858 | self.SelectFullLines() |
|---|
| 5859 | self.ctrl.CharRightExtend() |
|---|
| 5860 | elif self.GetSelMode() == "LINE": |
|---|
| 5861 | |
|---|
| 5862 | start, end = self._GetSelectionRange() |
|---|
| 5863 | self.ctrl.SetSelection(start, end) |
|---|
| 5864 | self.ctrl.CharRightExtend() |
|---|
| 5865 | |
|---|
| 5866 | self.ctrl.Copy() |
|---|
| 5867 | |
|---|
| 5868 | def Yank(self, lines=False): |
|---|
| 5869 | self.SelectSelection() |
|---|
| 5870 | |
|---|
| 5871 | |
|---|
| 5872 | self.YankSelection(lines) |
|---|
| 5873 | self.GotoSelectionStart() |
|---|
| 5874 | |
|---|
| 5875 | def Put(self, before, count=None): |
|---|
| 5876 | count = count if count is not None else self.count |
|---|
| 5877 | text = getTextFromClipboard() |
|---|
| 5878 | |
|---|
| 5879 | self.BeginUndo(True) |
|---|
| 5880 | |
|---|
| 5881 | |
|---|
| 5882 | if not text: |
|---|
| 5883 | self.ctrl.Paste() |
|---|
| 5884 | |
|---|
| 5885 | |
|---|
| 5886 | eol = self.ctrl.GetEOLChar() |
|---|
| 5887 | eol_len = len(eol) |
|---|
| 5888 | if len(text) > eol_len: |
|---|
| 5889 | is_line = text[-len(eol):] == eol |
|---|
| 5890 | else: |
|---|
| 5891 | is_line = False |
|---|
| 5892 | |
|---|
| 5893 | |
|---|
| 5894 | if is_line: |
|---|
| 5895 | if not before: |
|---|
| 5896 | |
|---|
| 5897 | |
|---|
| 5898 | self.ctrl.LineEnd() |
|---|
| 5899 | self.MoveCaretDown(1) |
|---|
| 5900 | self.GotoLineStart() |
|---|
| 5901 | |
|---|
| 5902 | if self.HasSelection(): |
|---|
| 5903 | self.ctrl.Clear() |
|---|
| 5904 | |
|---|
| 5905 | |
|---|
| 5906 | self.InsertText(count * text) |
|---|
| 5907 | |
|---|
| 5908 | if is_line: |
|---|
| 5909 | |
|---|
| 5910 | |
|---|
| 5911 | self.GotoLineIndent() |
|---|
| 5912 | |
|---|
| 5913 | self.EndUndo() |
|---|
| 5914 | |
|---|
| 5915 | |
|---|
| 5916 | |
|---|
| 5917 | |
|---|
| 5918 | def DeleteSurrounding(self, code): |
|---|
| 5919 | char = self.GetCharFromCode(code) |
|---|
| 5920 | if char in self.text_object_map: |
|---|
| 5921 | self.SelectATextObject(char) |
|---|
| 5922 | pos = self.ExtendSelectionIfRequired() |
|---|
| 5923 | self.ctrl.ReplaceSelection(self.ctrl.GetSelectedText()[1:-1]) |
|---|
| 5924 | self.ctrl.GotoPos(pos) |
|---|
| 5925 | |
|---|
| 5926 | def EndDelete(self): |
|---|
| 5927 | self.SelectSelection() |
|---|
| 5928 | self.DeleteSelection() |
|---|
| 5929 | |
|---|
| 5930 | def EndDeleteInsert(self): |
|---|
| 5931 | self.SelectSelection() |
|---|
| 5932 | self.DeleteSelection() |
|---|
| 5933 | self.Insert() |
|---|
| 5934 | |
|---|
| 5935 | def DeleteRight(self): |
|---|
| 5936 | self.ctrl.BeginUndoAction |
|---|
| 5937 | self.StartSelection() |
|---|
| 5938 | self.MoveCaretRight() |
|---|
| 5939 | self.SelectSelection() |
|---|
| 5940 | |
|---|
| 5941 | |
|---|
| 5942 | |
|---|
| 5943 | if len(self.ctrl.GetSelectedText()) < self.count: |
|---|
| 5944 | self.ctrl.CharRightExtend() |
|---|
| 5945 | self.DeleteSelection() |
|---|
| 5946 | self.EndUndo() |
|---|
| 5947 | self.CheckLineEnd() |
|---|
| 5948 | |
|---|
| 5949 | def DeleteLeft(self): |
|---|
| 5950 | self.BeginUndo() |
|---|
| 5951 | self.StartSelection() |
|---|
| 5952 | self.MoveCaretLeft() |
|---|
| 5953 | self.SelectSelection() |
|---|
| 5954 | self.DeleteSelection() |
|---|
| 5955 | self.EndUndo() |
|---|
| 5956 | |
|---|
| 5957 | def DeleteRightAndInsert(self): |
|---|
| 5958 | self.DeleteRight() |
|---|
| 5959 | self.Insert() |
|---|
| 5960 | |
|---|
| 5961 | def DeleteLinesAndIndentInsert(self): |
|---|
| 5962 | self.BeginUndo() |
|---|
| 5963 | indent = self.ctrl.GetLineIndentation(self.ctrl.GetCurrentLine()) |
|---|
| 5964 | self.DeleteLine() |
|---|
| 5965 | self.OpenNewLine(True, indent=indent) |
|---|
| 5966 | self.EndUndo() |
|---|
| 5967 | |
|---|
| 5968 | def DeleteLine(self): |
|---|
| 5969 | self.BeginUndo() |
|---|
| 5970 | self.SelectCurrentLine() |
|---|
| 5971 | self.DeleteSelection() |
|---|
| 5972 | self.EndUndo() |
|---|
| 5973 | |
|---|
| 5974 | |
|---|
| 5975 | |
|---|
| 5976 | |
|---|
| 5977 | |
|---|
| 5978 | |
|---|
| 5979 | def GetLineStartPos(self, line): |
|---|
| 5980 | return self.ctrl.GetLineIndentPosition(line) - \ |
|---|
| 5981 | self.ctrl.GetLineIndentation(line) |
|---|
| 5982 | |
|---|
| 5983 | def GotoLineStart(self): |
|---|
| 5984 | self.ctrl.Home() |
|---|
| 5985 | |
|---|
| 5986 | def GotoLineEnd(self, true_end=True): |
|---|
| 5987 | self.ctrl.LineEnd() |
|---|
| 5988 | if not true_end: |
|---|
| 5989 | self.ctrl.CharLeft() |
|---|
| 5990 | |
|---|
| 5991 | def GotoLineIndentPreviousLine(self): |
|---|
| 5992 | line = max(0, self.ctrl.GetCurrentLine()-1) |
|---|
| 5993 | self.GotoLineIndent(line) |
|---|
| 5994 | |
|---|
| 5995 | def GotoLineIndentNextLine(self): |
|---|
| 5996 | line = min(self.ctrl.GetLineCount(), self.ctrl.GetCurrentLine()+1) |
|---|
| 5997 | self.GotoLineIndent(line) |
|---|
| 5998 | |
|---|
| 5999 | def GotoLineIndent(self, line=None): |
|---|
| 6000 | """ |
|---|
| 6001 | Moves caret to first non-whitespace character on "line". |
|---|
| 6002 | |
|---|
| 6003 | If "line" is None current line is used. |
|---|
| 6004 | |
|---|
| 6005 | @param line: Line number |
|---|
| 6006 | |
|---|
| 6007 | """ |
|---|
| 6008 | if line is None: line = self.ctrl.GetCurrentLine() |
|---|
| 6009 | self.ctrl.GotoPos(self.ctrl.GetLineIndentPosition(line)) |
|---|
| 6010 | self.ctrl.ChooseCaretX() |
|---|
| 6011 | |
|---|
| 6012 | def GotoColumn(self, pos=None): |
|---|
| 6013 | """ |
|---|
| 6014 | Moves caret to "pos" on current line. If no pos specified use "count". |
|---|
| 6015 | |
|---|
| 6016 | @param pos: Column position to move caret to. |
|---|
| 6017 | """ |
|---|
| 6018 | if pos is None: pos = self.count |
|---|
| 6019 | line = self.ctrl.GetCurrentLine() |
|---|
| 6020 | lstart = self.ctrl.PositionFromLine(line) |
|---|
| 6021 | lend = self.ctrl.GetLineEndPosition(line) |
|---|
| 6022 | line_len = lend - lstart |
|---|
| 6023 | column = min(line_len, pos) |
|---|
| 6024 | self.ctrl.GotoPos(lstart + column) |
|---|
| 6025 | |
|---|
| 6026 | self.ctrl.ChooseCaretX() |
|---|
| 6027 | |
|---|
| 6028 | def GotoSentenceStart(self, count=None): |
|---|
| 6029 | self.AddJumpPosition() |
|---|
| 6030 | self.Repeat(self._MoveCaretSentenceStart, count) |
|---|
| 6031 | |
|---|
| 6032 | def _MoveCaretSentenceStart(self, pos=None, start_pos=None): |
|---|
| 6033 | """ |
|---|
| 6034 | Internal function to move caret to sentence start. |
|---|
| 6035 | |
|---|
| 6036 | Call GotoSentenceStart instead. |
|---|
| 6037 | """ |
|---|
| 6038 | if pos is None: |
|---|
| 6039 | pos = self.ctrl.GetCurrentPos()-1 |
|---|
| 6040 | if start_pos is None: |
|---|
| 6041 | start_pos = pos |
|---|
| 6042 | char = self.GetUnichrAt(pos) |
|---|
| 6043 | |
|---|
| 6044 | page_length = self.ctrl.GetLength() |
|---|
| 6045 | |
|---|
| 6046 | text = self.ctrl.GetText()[:pos] |
|---|
| 6047 | |
|---|
| 6048 | n = -1 |
|---|
| 6049 | for i in self.SENTENCE_ENDINGS: |
|---|
| 6050 | index = text.rfind(i) |
|---|
| 6051 | if index != -1 and index > n: |
|---|
| 6052 | n = index |
|---|
| 6053 | pos = n |
|---|
| 6054 | |
|---|
| 6055 | if pos < 1: |
|---|
| 6056 | self.ctrl.GotoPos(0) |
|---|
| 6057 | return |
|---|
| 6058 | |
|---|
| 6059 | sentence_end_pos = pos |
|---|
| 6060 | forward_char = self.GetUnichrAt(pos+1) |
|---|
| 6061 | if forward_char in self.SENTENCE_ENDINGS_SUFFIXS: |
|---|
| 6062 | pos += 1 |
|---|
| 6063 | while forward_char in self.SENTENCE_ENDINGS_SUFFIXS: |
|---|
| 6064 | pos += 1 |
|---|
| 6065 | forward_char = self.GetUnichrAt(pos) |
|---|
| 6066 | if forward_char in string.whitespace: |
|---|
| 6067 | while forward_char in string.whitespace: |
|---|
| 6068 | pos += 1 |
|---|
| 6069 | forward_char = self.GetUnichrAt(pos) |
|---|
| 6070 | else: |
|---|
| 6071 | self._MoveCaretSentenceStart(pos-1, start_pos) |
|---|
| 6072 | return |
|---|
| 6073 | |
|---|
| 6074 | if start_pos >= pos: |
|---|
| 6075 | self.ctrl.GotoPos(pos) |
|---|
| 6076 | else: |
|---|
| 6077 | self._MoveCaretSentenceStart(sentence_end_pos-1, start_pos) |
|---|
| 6078 | |
|---|
| 6079 | def GotoNextSentence(self, count=None): |
|---|
| 6080 | self.AddJumpPosition() |
|---|
| 6081 | self.Repeat(self._MoveCaretNextSentence, count) |
|---|
| 6082 | |
|---|
| 6083 | def GotoSentenceEnd(self, count=None): |
|---|
| 6084 | self.Repeat(self._MoveCaretNextSentence, count, False) |
|---|
| 6085 | |
|---|
| 6086 | def GotoSentenceEndCountWhitespace(self, count=None): |
|---|
| 6087 | if count is None: count = self.count |
|---|
| 6088 | |
|---|
| 6089 | if count % 2: |
|---|
| 6090 | include_whitespace = False |
|---|
| 6091 | count = count / 2 + 1 |
|---|
| 6092 | move_left = False |
|---|
| 6093 | else: |
|---|
| 6094 | include_whitespace = True |
|---|
| 6095 | count = count / 2 |
|---|
| 6096 | move_left = True |
|---|
| 6097 | |
|---|
| 6098 | self.Repeat(self._MoveCaretNextSentence, count, include_whitespace) |
|---|
| 6099 | |
|---|
| 6100 | if move_left: |
|---|
| 6101 | self.ctrl.CharLeftExtend() |
|---|
| 6102 | |
|---|
| 6103 | |
|---|
| 6104 | |
|---|
| 6105 | def _MoveCaretNextSentence(self, include_whitespace=True, |
|---|
| 6106 | pos=None, start_pos=None): |
|---|
| 6107 | |
|---|
| 6108 | if pos is None: |
|---|
| 6109 | pos = self.ctrl.GetCurrentPos()+1 |
|---|
| 6110 | if start_pos is None: |
|---|
| 6111 | start_pos = pos |
|---|
| 6112 | char = self.GetUnichrAt(pos) |
|---|
| 6113 | |
|---|
| 6114 | page_length = self.ctrl.GetLength() |
|---|
| 6115 | |
|---|
| 6116 | text = self.ctrl.GetText()[pos:] |
|---|
| 6117 | |
|---|
| 6118 | n = page_length |
|---|
| 6119 | for i in self.SENTENCE_ENDINGS: |
|---|
| 6120 | index = text.find(i) |
|---|
| 6121 | if index != -1 and index < n: |
|---|
| 6122 | n = index |
|---|
| 6123 | pos = pos + n |
|---|
| 6124 | |
|---|
| 6125 | if pos+1 >= page_length: |
|---|
| 6126 | self.ctrl.GotoPos(page_length) |
|---|
| 6127 | return |
|---|
| 6128 | |
|---|
| 6129 | sentence_end_pos = pos |
|---|
| 6130 | forward_char = self.GetUnichrAt(pos+1) |
|---|
| 6131 | if forward_char in self.SENTENCE_ENDINGS_SUFFIXS: |
|---|
| 6132 | pos += 1 |
|---|
| 6133 | while forward_char in self.SENTENCE_ENDINGS_SUFFIXS: |
|---|
| 6134 | pos += 1 |
|---|
| 6135 | forward_char = self.GetUnichrAt(pos) |
|---|
| 6136 | sentence_end_pos = pos-1 |
|---|
| 6137 | if forward_char in string.whitespace: |
|---|
| 6138 | while forward_char in string.whitespace: |
|---|
| 6139 | pos += 1 |
|---|
| 6140 | forward_char = self.GetUnichrAt(pos) |
|---|
| 6141 | else: |
|---|
| 6142 | self._MoveCaretNextSentence(include_whitespace, pos+1, start_pos) |
|---|
| 6143 | return |
|---|
| 6144 | |
|---|
| 6145 | if start_pos <= pos: |
|---|
| 6146 | if include_whitespace: |
|---|
| 6147 | self.ctrl.GotoPos(pos) |
|---|
| 6148 | else: |
|---|
| 6149 | self.ctrl.GotoPos(sentence_end_pos) |
|---|
| 6150 | else: |
|---|
| 6151 | self._MoveCaretNextSentence(include_whitespace, |
|---|
| 6152 | sentence_end_pos, start_pos) |
|---|
| 6153 | |
|---|
| 6154 | def MoveCaretRight(self): |
|---|
| 6155 | self.MoveCaretPos(self.count) |
|---|
| 6156 | |
|---|
| 6157 | |
|---|
| 6158 | |
|---|
| 6159 | |
|---|
| 6160 | |
|---|
| 6161 | |
|---|
| 6162 | |
|---|
| 6163 | |
|---|
| 6164 | |
|---|
| 6165 | |
|---|
| 6166 | |
|---|
| 6167 | |
|---|
| 6168 | |
|---|
| 6169 | def MoveCaretUp(self, count=None): |
|---|
| 6170 | self.Repeat(self.ctrl.LineUp, count) |
|---|
| 6171 | self.CheckLineEnd() |
|---|
| 6172 | |
|---|
| 6173 | def MoveCaretDown(self, count=None): |
|---|
| 6174 | self.Repeat(self.ctrl.LineDown, count) |
|---|
| 6175 | self.CheckLineEnd() |
|---|
| 6176 | |
|---|
| 6177 | def MoveCaretToLine(self, line): |
|---|
| 6178 | current_line = self.ctrl.GetCurrentLine() |
|---|
| 6179 | if line == current_line: |
|---|
| 6180 | return |
|---|
| 6181 | |
|---|
| 6182 | if line < current_line: |
|---|
| 6183 | scroll_func = self.ctrl.LineUp |
|---|
| 6184 | else: |
|---|
| 6185 | scroll_func = self.ctrl.LineDown |
|---|
| 6186 | |
|---|
| 6187 | to_move = abs(current_line - line) |
|---|
| 6188 | |
|---|
| 6189 | for i in range(to_move): |
|---|
| 6190 | scroll_func() |
|---|
| 6191 | |
|---|
| 6192 | |
|---|
| 6193 | def MoveCaretDownAndIndent(self, count=None): |
|---|
| 6194 | self.Repeat(self.ctrl.LineDown, count) |
|---|
| 6195 | self.GotoLineIndent() |
|---|
| 6196 | |
|---|
| 6197 | def MoveCaretLeft(self): |
|---|
| 6198 | self.MoveCaretPos(-self.count) |
|---|
| 6199 | |
|---|
| 6200 | def MoveCaretPos(self, offset): |
|---|
| 6201 | """ |
|---|
| 6202 | Move caret by a given offset |
|---|
| 6203 | """ |
|---|
| 6204 | line, line_pos = self.ctrl.GetCurLine() |
|---|
| 6205 | line_no = self.ctrl.GetCurrentLine() |
|---|
| 6206 | |
|---|
| 6207 | if self.mode == ViHelper.VISUAL: |
|---|
| 6208 | if offset > 0: |
|---|
| 6209 | move_right = True |
|---|
| 6210 | move = self.ctrl.CharRightExtend |
|---|
| 6211 | stop_pos = self.GetLineStartPos(line_no) + \ |
|---|
| 6212 | self.ctrl.LineLength(line_no)-1 |
|---|
| 6213 | else: |
|---|
| 6214 | move_right = False |
|---|
| 6215 | move = self.ctrl.CharLeftExtend |
|---|
| 6216 | stop_pos = self.GetLineStartPos(line_no) |
|---|
| 6217 | else: |
|---|
| 6218 | if offset > 0: |
|---|
| 6219 | move_right = True |
|---|
| 6220 | move = self.ctrl.CharRight |
|---|
| 6221 | stop_pos = self.GetLineStartPos(line_no) + \ |
|---|
| 6222 | self.ctrl.LineLength(line_no)-2 |
|---|
| 6223 | |
|---|
| 6224 | |
|---|
| 6225 | if line_no+1 == self.ctrl.GetLineCount(): |
|---|
| 6226 | stop_pos += 1 |
|---|
| 6227 | else: |
|---|
| 6228 | move_right = False |
|---|
| 6229 | move = self.ctrl.CharLeft |
|---|
| 6230 | stop_pos = self.GetLineStartPos(line_no) |
|---|
| 6231 | |
|---|
| 6232 | for i in range(abs(offset)): |
|---|
| 6233 | if (move_right and self.ctrl.GetCurrentPos() < stop_pos) or \ |
|---|
| 6234 | (not move_right and self.ctrl.GetCurrentPos() > stop_pos): |
|---|
| 6235 | move() |
|---|
| 6236 | else: |
|---|
| 6237 | break |
|---|
| 6238 | |
|---|
| 6239 | |
|---|
| 6240 | |
|---|
| 6241 | |
|---|
| 6242 | |
|---|
| 6243 | |
|---|
| 6244 | |
|---|
| 6245 | |
|---|
| 6246 | |
|---|
| 6247 | |
|---|
| 6248 | |
|---|
| 6249 | |
|---|
| 6250 | |
|---|
| 6251 | def MoveCaretLinePos(self, offset): |
|---|
| 6252 | """ |
|---|
| 6253 | Move caret line position by a given offset |
|---|
| 6254 | |
|---|
| 6255 | Faster but does not maintain line position |
|---|
| 6256 | """ |
|---|
| 6257 | self.ctrl.ChooseCaretX() |
|---|
| 6258 | line = max(self.ctrl.GetCurrentLine() + offset, 0) |
|---|
| 6259 | line = min(line, self.ctrl.GetLineCount()) |
|---|
| 6260 | self.ctrl.GotoLine(line) |
|---|
| 6261 | line_start_pos = self.ctrl.GetCurrentPos() |
|---|
| 6262 | |
|---|
| 6263 | pos = max(index, 0) |
|---|
| 6264 | pos = min(pos, self.ctrl.GetLineEndPosition(line)-line_start_pos) |
|---|
| 6265 | self.ctrl.GotoPos(line_start_pos+pos) |
|---|
| 6266 | |
|---|
| 6267 | |
|---|
| 6268 | def MoveCaretToLinePos(self, line, index): |
|---|
| 6269 | line = max(line, 0) |
|---|
| 6270 | line = min(line, self.ctrl.GetLineCount()) |
|---|
| 6271 | self.ctrl.GotoLine(line) |
|---|
| 6272 | line_start_pos = self.ctrl.GetCurrentPos() |
|---|
| 6273 | pos = max(index, 0) |
|---|
| 6274 | pos = min(pos, self.ctrl.GetLineEndPosition(line)-line_start_pos) |
|---|
| 6275 | self.ctrl.GotoPos(line_start_pos+pos) |
|---|
| 6276 | |
|---|
| 6277 | def SaveCaretPos(self): |
|---|
| 6278 | page = self.ctrl.presenter.getWikiWord() |
|---|
| 6279 | self.previous_positions[page].append(self.ctrl.GetCurrentPos()) |
|---|
| 6280 | self.future_positions[page] = [] |
|---|
| 6281 | |
|---|
| 6282 | |
|---|
| 6283 | def MoveCaretWordEndCountWhitespace(self, count=None): |
|---|
| 6284 | self.Repeat(self._MoveCaretWord, count, |
|---|
| 6285 | { "recursion" : False, "count_whitespace" : True, \ |
|---|
| 6286 | "only_whitespace" : False }) |
|---|
| 6287 | |
|---|
| 6288 | def MoveCaretNextWord(self, count=None): |
|---|
| 6289 | self.Repeat(self.ctrl.WordRight, count) |
|---|
| 6290 | |
|---|
| 6291 | def MoveCaretPreviousWordEnd(self, count=None): |
|---|
| 6292 | |
|---|
| 6293 | self.Repeat(self._MoveCaretWord, count, { |
|---|
| 6294 | "recursion" : False, |
|---|
| 6295 | "count_whitespace" : False, |
|---|
| 6296 | "only_whitespace" : False, |
|---|
| 6297 | "reverse" : True |
|---|
| 6298 | }) |
|---|
| 6299 | |
|---|
| 6300 | def MoveCaretWordEnd(self, count=None): |
|---|
| 6301 | self.Repeat(self._MoveCaretWord, count) |
|---|
| 6302 | |
|---|
| 6303 | def _MoveCaretWord(self, recursion=False, count_whitespace=False, |
|---|
| 6304 | only_whitespace=False, reverse=False): |
|---|
| 6305 | """ |
|---|
| 6306 | wxStyledTextCtrl's WordEnd function behaves differently to |
|---|
| 6307 | vims so it need to be replaced to get equivalent function |
|---|
| 6308 | |
|---|
| 6309 | """ |
|---|
| 6310 | pos = start_pos = self.ctrl.GetCurrentPos() |
|---|
| 6311 | char = self.GetUnichrAt(pos) |
|---|
| 6312 | |
|---|
| 6313 | if char is None: |
|---|
| 6314 | return |
|---|
| 6315 | |
|---|
| 6316 | text_length = self.ctrl.GetTextLength() |
|---|
| 6317 | |
|---|
| 6318 | if reverse: |
|---|
| 6319 | offset = -1 |
|---|
| 6320 | move = self.ctrl.CharLeft |
|---|
| 6321 | move_extend = self.ctrl.CharLeftExtend |
|---|
| 6322 | else: |
|---|
| 6323 | offset = 1 |
|---|
| 6324 | move = self.ctrl.CharRight |
|---|
| 6325 | move_extend = self.ctrl.CharRightExtend |
|---|
| 6326 | |
|---|
| 6327 | |
|---|
| 6328 | |
|---|
| 6329 | if char in string.whitespace: |
|---|
| 6330 | char = self.GetUnichrAt(pos + offset) |
|---|
| 6331 | if char is not None: |
|---|
| 6332 | while char is not None and char in string.whitespace: |
|---|
| 6333 | pos = pos + offset |
|---|
| 6334 | char = self.GetUnichrAt(pos + offset) |
|---|
| 6335 | if not count_whitespace: |
|---|
| 6336 | self._GotoPos(pos) |
|---|
| 6337 | move() |
|---|
| 6338 | self._MoveCaretWord(recursion=True, |
|---|
| 6339 | count_whitespace=count_whitespace, |
|---|
| 6340 | only_whitespace=only_whitespace, |
|---|
| 6341 | reverse=reverse) |
|---|
| 6342 | return |
|---|
| 6343 | |
|---|
| 6344 | |
|---|
| 6345 | elif not only_whitespace and char in self.WORD_BREAK: |
|---|
| 6346 | char = self.GetUnichrAt(pos + offset) |
|---|
| 6347 | if char is not None: |
|---|
| 6348 | while char is not None and char in self.WORD_BREAK: |
|---|
| 6349 | pos = pos + offset |
|---|
| 6350 | char = self.GetUnichrAt(pos + offset) |
|---|
| 6351 | |
|---|
| 6352 | |
|---|
| 6353 | else: |
|---|
| 6354 | char = self.GetUnichrAt(pos + offset) |
|---|
| 6355 | if char is not None: |
|---|
| 6356 | while char is not None and \ |
|---|
| 6357 | ((only_whitespace or char not in self.WORD_BREAK) and \ |
|---|
| 6358 | char not in string.whitespace) or char in ("_"): |
|---|
| 6359 | pos = pos + offset |
|---|
| 6360 | char = self.GetUnichrAt(pos + offset) |
|---|
| 6361 | |
|---|
| 6362 | if pos != start_pos or recursion: |
|---|
| 6363 | self._GotoPos(pos) |
|---|
| 6364 | else: |
|---|
| 6365 | move_extend() |
|---|
| 6366 | self._MoveCaretWord(True, count_whitespace=count_whitespace, |
|---|
| 6367 | only_whitespace=only_whitespace, reverse=reverse) |
|---|
| 6368 | return |
|---|
| 6369 | |
|---|
| 6370 | def MoveCaretToWhitespaceStart(self): |
|---|
| 6371 | start = self.ctrl.GetCurrentPos() |
|---|
| 6372 | while self.ctrl.GetCharAt(start-1) in self.SINGLE_LINE_WHITESPACE: |
|---|
| 6373 | start -= 1 |
|---|
| 6374 | self.ctrl.GotoPos(start) |
|---|
| 6375 | |
|---|
| 6376 | def MoveCaretBackWord(self, count=None): |
|---|
| 6377 | self.Repeat(self._MoveCaretWord, count, { |
|---|
| 6378 | "recursion" : False, |
|---|
| 6379 | "count_whitespace" : False, |
|---|
| 6380 | "only_whitespace" : False, |
|---|
| 6381 | "reverse" : True |
|---|
| 6382 | }) |
|---|
| 6383 | |
|---|
| 6384 | def MoveCaretBackWORD(self, count=None): |
|---|
| 6385 | self.Repeat(self._MoveCaretWord, count, { |
|---|
| 6386 | "recursion" : False, |
|---|
| 6387 | "count_whitespace" : False, |
|---|
| 6388 | "only_whitespace" : True, |
|---|
| 6389 | "reverse" : True |
|---|
| 6390 | }) |
|---|
| 6391 | |
|---|
| 6392 | def MoveCaretNextWORD(self, count=None): |
|---|
| 6393 | """Wordbreaks are spaces""" |
|---|
| 6394 | def func(): |
|---|
| 6395 | self.ctrl.WordRight() |
|---|
| 6396 | while self.GetChar(-1) and not self.GetChar(-1).isspace(): |
|---|
| 6397 | self.ctrl.WordRight() |
|---|
| 6398 | self.Repeat(func, count) |
|---|
| 6399 | |
|---|
| 6400 | def MoveCaretWordEND(self, count=None): |
|---|
| 6401 | self.Repeat(self._MoveCaretWord, count, { |
|---|
| 6402 | "recursion" : False, |
|---|
| 6403 | "count_whitespace" : False, |
|---|
| 6404 | "only_whitespace" : True |
|---|
| 6405 | }) |
|---|
| 6406 | |
|---|
| 6407 | def MoveCaretWordENDCountWhitespace(self, count=None): |
|---|
| 6408 | self.Repeat(self._MoveCaretWord, count, { |
|---|
| 6409 | "recursion" : False, |
|---|
| 6410 | "count_whitespace" : True, |
|---|
| 6411 | "only_whitespace" : True |
|---|
| 6412 | }) |
|---|
| 6413 | |
|---|
| 6414 | def MoveCaretParaUp(self, count=None): |
|---|
| 6415 | self.AddJumpPosition() |
|---|
| 6416 | self.Repeat(self.ctrl.ParaUp, count) |
|---|
| 6417 | |
|---|
| 6418 | def MoveCaretParaDown(self, count=None): |
|---|
| 6419 | self.AddJumpPosition() |
|---|
| 6420 | self.Repeat(self.ctrl.ParaDown, count) |
|---|
| 6421 | |
|---|
| 6422 | def _GotoPos(self, pos): |
|---|
| 6423 | """ |
|---|
| 6424 | Save caret position |
|---|
| 6425 | """ |
|---|
| 6426 | self.ctrl.GotoPos(pos) |
|---|
| 6427 | self.ctrl.ChooseCaretX() |
|---|
| 6428 | |
|---|
| 6429 | def DocumentNavigation(self, key): |
|---|
| 6430 | """ |
|---|
| 6431 | It may be better to seperate this into multiple functions |
|---|
| 6432 | """ |
|---|
| 6433 | if key in [71, (103, 103), 37]: |
|---|
| 6434 | self.AddJumpPosition() |
|---|
| 6435 | |
|---|
| 6436 | |
|---|
| 6437 | if self.true_count: |
|---|
| 6438 | if key in [71, (103, 103)]: |
|---|
| 6439 | |
|---|
| 6440 | self.MoveCaretToLinePos(self.count-1, self.ctrl.GetCurLine()[1]) |
|---|
| 6441 | elif key == 37: |
|---|
| 6442 | max_lines = self.ctrl.GetLineCount() |
|---|
| 6443 | |
|---|
| 6444 | |
|---|
| 6445 | line_percentage = (self.count * max_lines) // 100 |
|---|
| 6446 | self.MoveCaretToLinePos(line_percentage, self.ctrl.GetCurLine()[1]) |
|---|
| 6447 | |
|---|
| 6448 | elif key == 37: |
|---|
| 6449 | |
|---|
| 6450 | self.MatchBraceUnderCaret() |
|---|
| 6451 | |
|---|
| 6452 | elif key == (103, 103): |
|---|
| 6453 | self.ctrl.GotoLine(0) |
|---|
| 6454 | |
|---|
| 6455 | elif key == (71): |
|---|
| 6456 | self.ctrl.GotoLine(self.ctrl.GetLineCount()) |
|---|
| 6457 | |
|---|
| 6458 | def GotoViewportTop(self): |
|---|
| 6459 | self.GotoLineIndent(self.ctrl.GetFirstVisibleLine()) |
|---|
| 6460 | |
|---|
| 6461 | def GotoViewportMiddle(self): |
|---|
| 6462 | self.GotoLineIndent(self.ctrl.GetMiddleVisibleLine()) |
|---|
| 6463 | |
|---|
| 6464 | def GotoViewportBottom(self): |
|---|
| 6465 | self.GotoLineIndent(self.ctrl.GetLastVisibleLine()) |
|---|
| 6466 | |
|---|
| 6467 | def ScrollViewportTop(self): |
|---|
| 6468 | self._PositionViewport(0) |
|---|
| 6469 | |
|---|
| 6470 | def ScrollViewportMiddle(self): |
|---|
| 6471 | self._PositionViewport(0.5) |
|---|
| 6472 | |
|---|
| 6473 | def ScrollViewportBottom(self): |
|---|
| 6474 | self._PositionViewport(1) |
|---|
| 6475 | |
|---|
| 6476 | def ScrollViewportUpHalfScreen(self): |
|---|
| 6477 | self._ScrollViewport(-0.5) |
|---|
| 6478 | |
|---|
| 6479 | def ScrollViewportUpFullScreen(self): |
|---|
| 6480 | |
|---|
| 6481 | |
|---|
| 6482 | self._ScrollViewport(-1) |
|---|
| 6483 | |
|---|
| 6484 | def ScrollViewportDownHalfScreen(self): |
|---|
| 6485 | self._ScrollViewport(0.5) |
|---|
| 6486 | |
|---|
| 6487 | def ScrollViewportDownFullScreen(self): |
|---|
| 6488 | self._ScrollViewport(1) |
|---|
| 6489 | |
|---|
| 6490 | def ScrollViewportLineDown(self): |
|---|
| 6491 | self._ScrollViewportByLines(1) |
|---|
| 6492 | |
|---|
| 6493 | def ScrollViewportLineUp(self): |
|---|
| 6494 | self._ScrollViewportByLines(-1) |
|---|
| 6495 | |
|---|
| 6496 | def Undo(self, count=None): |
|---|
| 6497 | if self.ctrl.CanUndo(): |
|---|
| 6498 | self.visualBell("GREEN") |
|---|
| 6499 | self.Repeat(self._Undo, count) |
|---|
| 6500 | else: |
|---|
| 6501 | self.visualBell("RED") |
|---|
| 6502 | |
|---|
| 6503 | def Redo(self, count=None): |
|---|
| 6504 | if self.ctrl.CanRedo(): |
|---|
| 6505 | self.visualBell("GREEN") |
|---|
| 6506 | self.Repeat(self._Redo, count) |
|---|
| 6507 | else: |
|---|
| 6508 | self.visualBell("RED") |
|---|
| 6509 | |
|---|
| 6510 | |
|---|
| 6511 | def Insert(self): |
|---|
| 6512 | self.BeginUndo(True) |
|---|
| 6513 | self.SetMode(ViHelper.INSERT) |
|---|
| 6514 | |
|---|
| 6515 | def Append(self): |
|---|
| 6516 | if self.ctrl.GetCurrentPos() != self.ctrl.GetLineEndPosition(self.ctrl.GetCurrentLine()): |
|---|
| 6517 | self.ctrl.CharRight() |
|---|
| 6518 | self.Insert() |
|---|
| 6519 | |
|---|
| 6520 | def InsertAtLineStart(self): |
|---|
| 6521 | |
|---|
| 6522 | self.GotoLineIndent(self.ctrl.GetCurrentLine()) |
|---|
| 6523 | self.ctrl.ChooseCaretX() |
|---|
| 6524 | self.Insert() |
|---|
| 6525 | |
|---|
| 6526 | def AppendAtLineEnd(self): |
|---|
| 6527 | self.ctrl.GotoPos(self.ctrl.GetLineEndPosition( |
|---|
| 6528 | self.ctrl.GetCurrentLine())) |
|---|
| 6529 | self.Append() |
|---|
| 6530 | |
|---|
| 6531 | def OpenNewLine(self, above, indent=None): |
|---|
| 6532 | self.BeginUndo(True) |
|---|
| 6533 | self.BeginUndo() |
|---|
| 6534 | |
|---|
| 6535 | if indent is None: |
|---|
| 6536 | indent = self.ctrl.GetLineIndentation(self.ctrl.GetCurrentLine()) |
|---|
| 6537 | |
|---|
| 6538 | if above: |
|---|
| 6539 | self.MoveCaretUp(1) |
|---|
| 6540 | self.GotoLineEnd() |
|---|
| 6541 | self.ctrl.AddText(self.ctrl.GetEOLChar()) |
|---|
| 6542 | self.ctrl.SetLineIndentation(self.ctrl.GetCurrentLine(), indent) |
|---|
| 6543 | self.EndUndo() |
|---|
| 6544 | self.AppendAtLineEnd() |
|---|
| 6545 | |
|---|
| 6546 | def TruncateLine(self): |
|---|
| 6547 | self.ctrl.LineEndExtend() |
|---|
| 6548 | self.ctrl.CharLeftExtend() |
|---|
| 6549 | self.ExtendSelectionIfRequired() |
|---|
| 6550 | self.DeleteSelection() |
|---|
| 6551 | |
|---|
| 6552 | def TruncateLineAndInsert(self): |
|---|
| 6553 | self.TruncateLine() |
|---|
| 6554 | self.Insert() |
|---|