3
#-------------- User changable settings are in configuration.py --------------
5
#------------------------------ System Imports -------------------------------
6
from __future__ import generators
9
if not hasattr(sys, 'frozen'):
10
import wxversion;wxversion.ensureMinimal('2.6')
12
import keyword, traceback, cStringIO, imp, fnmatch, re
14
from wxPython.wx import *
15
from wxPython.stc import *
16
from wxPython.lib.rcsizer import RowColSizer
17
from wxPython.lib.dialogs import wxScrolledMessageDialog
18
import wx.lib.mixins.listctrl as listctrl
19
wxListCtrlAutoWidthMixin, wxColumnSorterMixin, wxTextEditMixin = \
20
listctrl.ListCtrlAutoWidthMixin, listctrl.ColumnSorterMixin, listctrl.TextEditMixin
27
UNICODE = wxUSE_UNICODE
29
#--------------------------- configuration import ----------------------------
30
from configuration import *
32
#---------------------------- Event Declarations -----------------------------
34
class cancelled(Exception):
41
fn = win.root.getAbsolute(win.filename, win.dirname)
45
dirty += mod != win.mod
47
dirty += bool(fn.strip())
48
r = dirty and True or False
53
#plugin-type thing imports
54
from plugins import logger
55
from plugins import findbar
56
from plugins import lru
57
from plugins import filehistory
58
from plugins import browser
59
from plugins import workspace
60
from plugins import todo
61
from plugins import findinfiles
63
## from plugins import project
65
for i in [logger, findbar, lru, filehistory, browser, workspace, todo,
66
findinfiles]:#, project]:
67
i.cancelled = cancelled
75
#under an if so that I can collapse the declarations
84
STRINGPRINTABLE = dict.fromkeys(map(ord, string.printable))
88
keys = ["BACK", "TAB", "RETURN", "ESCAPE", "SPACE", "DELETE", "START",
89
"LBUTTON", "RBUTTON", "CANCEL", "MBUTTON", "CLEAR", "PAUSE",
90
"CAPITAL", "PRIOR", "NEXT", "END", "HOME", "LEFT", "UP", "RIGHT",
91
"DOWN", "SELECT", "PRINT", "EXECUTE", "SNAPSHOT", "INSERT", "HELP",
92
"NUMPAD0", "NUMPAD1", "NUMPAD2", "NUMPAD3", "NUMPAD4", "NUMPAD5",
93
"NUMPAD6", "NUMPAD7", "NUMPAD8", "NUMPAD9", "MULTIPLY", "ADD",
94
"SEPARATOR", "SUBTRACT", "DECIMAL", "DIVIDE", "F1", "F2", "F3", "F4",
95
"F5", "F6", "F7", "F8", "F9", "F10", "F11", "F12", "F13", "F14",
96
"F15", "F16", "F17", "F18", "F19", "F20", "F21", "F22", "F23", "F24",
97
"NUMLOCK", "SCROLL", "PAGEUP", "PAGEDOWN", "NUMPAD_SPACE",
98
"NUMPAD_TAB", "NUMPAD_ENTER", "NUMPAD_F1", "NUMPAD_F2", "NUMPAD_F3",
99
"NUMPAD_F4", "NUMPAD_HOME", "NUMPAD_LEFT", "NUMPAD_UP",
100
"NUMPAD_RIGHT", "NUMPAD_DOWN", "NUMPAD_PRIOR", "NUMPAD_PAGEUP",
101
"NUMPAD_NEXT", "NUMPAD_PAGEDOWN", "NUMPAD_END", "NUMPAD_BEGIN",
102
"NUMPAD_INSERT", "NUMPAD_DELETE", "NUMPAD_EQUAL", "NUMPAD_MULTIPLY",
103
"NUMPAD_ADD", "NUMPAD_SEPARATOR", "NUMPAD_SUBTRACT", "NUMPAD_DECIMAL",
112
for i in ["SHIFT", "ALT", "CONTROL", "MENU"]:
117
def GetKeyPress(evt):
118
keycode = evt.GetKeyCode()
119
keyname = keyMap.get(keycode, None)
121
for mod, ch in ((evt.ControlDown(), 'Ctrl+'),
122
(evt.AltDown(), 'Alt+'),
123
(evt.ShiftDown(), 'Shift+'),
124
(evt.MetaDown(), 'Meta+')):
129
if 27 < keycode < 256:
130
keyname = chr(keycode)
132
keyname = "(%s)unknown" % keycode
133
return modifiers + keyname
141
return (n.split('\t', 1) + [''])[:2]
143
def recmenu(menu, id):
144
#this was a pain in the ass.
145
if isinstance(menu, wxMenuItem) or isinstance(menu, wxMenuItemPtr):
146
sm = menu.GetSubMenu()
150
return '%s->%s'%(menu.GetLabel(), a)
152
elif menu.GetId() == id:
153
return menu.GetLabel()
156
elif isinstance(menu, wxMenu) or isinstance(menu, wxMenuPtr):
157
ITEMS = menu.GetMenuItems()
164
for i in xrange(menu.GetMenuCount()):
166
if r.FindItemById(id):
167
return "%s->%s"%(menu.GetLabelTop(i), recmenu(r, id))
168
raise Exception("Item not found.")
170
def menuAdd(root, menu, name, desc, funct, id, kind=wxITEM_NORMAL):
172
a = wxMenuItem(menu, id, 'TEMPORARYNAME', desc, kind)
174
EVT_MENU(root, id, funct)
176
ns, oacc = _spl(name)
177
heir = recmenu(menuBar, id)[:-13] + ns
179
name, acc = MENUPREF[heir]
181
if heir in OLD_MENUPREF:
182
name, acc = MENUPREF[heir] = OLD_MENUPREF[heir]
184
name, acc = MENUPREF[heir] = (ns, oacc)
185
MENULIST.append((heir, name, oacc, acc, kind in [wxITEM_NORMAL, wxITEM_CHECK]))
188
HOTKEY_TO_ID[acc] = id
190
menuBar.SetLabel(id, '%s\t%s'%(name, acc))
191
menuBar.SetHelpString(id, desc)
193
def menuAddM(parent, menu, name, help=''):
194
if isinstance(parent, wxMenu) or isinstance(parent, wxMenuPtr):
196
parent.AppendMenu(id, "TEMPORARYNAME", menu, help)
197
heir = recmenu(menuBar, id) + name
198
name, toss = MENUPREF.setdefault(heir, (name, ''))
200
menuBar.SetLabel(id, name)
201
menuBar.SetHelpString(id, help)
204
name, toss = MENUPREF.setdefault(name, (name, ''))
206
parent.Append(menu, name)
208
MENULIST.append((heir, name, '', '', 0))
212
stream = cStringIO.StringIO(data)
213
image = wxImageFromStream(stream)
214
bitmap = wxBitmapFromImage(image)
216
icon.CopyFromBitmap(bitmap)
229
lexers = dict(zip([PY_S, HT_S, CC_S, XM_S, TX_S], ['python', 'html', 'cpp', 'xml', 'text']))
230
lexers2 = dict(zip([wxSTC_LEX_PYTHON, wxSTC_LEX_HTML, wxSTC_LEX_CPP, wxSTC_LEX_XML, wxSTC_LEX_NULL], [PY_S, HT_S, CC_S, XM_S, TX_S]))
237
lexers.update(dict(zip([PY_DS, HT_DS, CC_DS, XM_DS, TX_DS], ['python', 'html', 'cpp', 'xml', 'text'])))
238
lexers3 = dict(zip(['python', 'html', 'cpp', 'xml', 'text'], [PY_DS, HT_DS, CC_DS, XM_DS, TX_DS]))
245
INDENTGUIDE = wxNewId()
247
SAVE_CURSOR = wxNewId()
255
NO_FINDBAR_HISTORY = wxNewId()
256
CLEAR_FINDBAR_HISTORY = wxNewId()
261
LL_BACK = wxNewId()# wxSTC_EDGE_BACKGROUND
262
LL_LINE = wxNewId()# wxSTC_EDGE_LINE
263
LL_NONE = wxNewId()# wxSTC_EDGE_NONE
264
LL_MAPPING = {LL_BACK:wxSTC_EDGE_BACKGROUND,
265
LL_LINE:wxSTC_EDGE_LINE,
266
LL_NONE:wxSTC_EDGE_NONE}
268
for i,j in LL_MAPPING.iteritems():
275
LE_MAPPING = {LE_CRLF:wxSTC_EOL_CRLF,
279
for i,j in LE_MAPPING.iteritems():
284
(CARET_MARGIN, CARET_CENTER, CARET_TOP, CARET_TOP_MARGIN, CARET_DEFAULT) = \
285
(wxNewId(), wxNewId(), wxNewId(), wxNewId(), wxNewId())
287
CARET_ID_TO_OPTIONS = {
288
CARET_MARGIN: (0, wxSTC_CARET_EVEN|wxSTC_CARET_SLOP|wxSTC_CARET_STRICT),
289
CARET_CENTER: (1, wxSTC_CARET_EVEN|wxSTC_CARET_STRICT),
290
CARET_TOP: (2, wxSTC_CARET_STRICT),
291
CARET_TOP_MARGIN: (3, wxSTC_CARET_SLOP|wxSTC_CARET_STRICT),
292
CARET_DEFAULT: (4, wxSTC_CARET_EVEN),
295
CARET_OPTION_TO_ID = dict([(j[0], (i, j[1])) for i,j in CARET_ID_TO_OPTIONS.iteritems()])
299
(TITLE_NONE, TITLE_SHORT_L, TITLE_SHORT_R, TITLE_LONG_L, TITLE_LONG_R) = \
300
(wxNewId(), wxNewId(), wxNewId(), wxNewId(), wxNewId())
302
TITLE_ID_TO_OPTIONS = {
303
TITLE_NONE : (0, "%(pype)s", "No file information"),
304
TITLE_SHORT_L : (1, "%(pype)s - %(fn)s", "File name after title"),
305
TITLE_SHORT_R : (2, "%(fn)s - %(pype)s", "File name before title"),
306
TITLE_LONG_L : (3, "%(pype)s - %(fn)s - [%(long)s]", "File and full path after title"),
307
TITLE_LONG_R : (4, "%(fn)s - [%(long)s] - %(pype)s", "File and full path before title"),
310
TITLE_OPTION_TO_ID = dict([(j[0], (i, j[1], j[2])) for i,j in TITLE_ID_TO_OPTIONS.iteritems()])
312
SITO = (PY_DD, HT_DD, XM_DD, CC_DD, TX_DD) = (wxNewId(), wxNewId(), wxNewId(), wxNewId(), wxNewId())
314
SOURCE_ID_TO_OPTIONS = {
315
PY_DD : ('python', "Python"),
316
HT_DD : ('html', "HTML"),
317
XM_DD : ('xml', "XML"),
318
CC_DD : ('cpp', "C/C++"),
319
TX_DD : ('text', "Text"),
322
SITO2= (PY_DD2, HT_DD2, XM_DD2, CC_DD2, TX_DD2) = (wxNewId(), wxNewId(), wxNewId(), wxNewId(), wxNewId())
324
SOURCE_ID_TO_OPTIONS2 = {
325
PY_DD2 : ('python', "Python"),
326
HT_DD2 : ('html', "HTML"),
327
XM_DD2 : ('xml', "XML"),
328
CC_DD2 : ('cpp', "C/C++"),
329
TX_DD2 : ('text', "Text"),
334
BOOKMARKSYMBOL = wxSTC_MARK_CIRCLE
339
BOM = [('+/v8-', 'utf-7'),
340
('\xef\xbb\xbf', 'utf-8'),
341
('\xfe\xff', 'utf-16-be'),
342
('\xff\xfe\xff\xfe', 'utf-16'),
343
('\xff\xfe', 'utf-16-le'),
349
ENCODINGS[j] = wxNewId()
355
if wxPlatform == '__WXMSW__':
356
faces = {'times': cn, 'mono' : cn, 'helv' : cn, 'other': cn,
357
'size' : 10, 'size2': 9}
359
faces = {'times': 'Courier', 'mono' : 'Courier',
360
'helv' : 'Courier', 'other': 'Courier', 'size' : 10,
364
def makeSubWindow(parent, id, size, orientation, alignment, sash):
365
win = wxSashLayoutWindow(
366
parent, id, wxDefaultPosition, size,
369
win.SetDefaultSize(size)
370
win.SetOrientation(orientation)
371
win.SetAlignment(alignment)
372
## win.SetBackgroundColour(wx.Colour(127, 0, 0))
373
win.SetSashVisible(sash, True)
374
## win.SetMinimumSizeX(30)
378
ID_WINDOW_BOTTOM = wxNewId()
379
ID_WINDOW_RIGHT = wxNewId()
381
pypeID_DELETE = wxNewId()
382
pypeID_FINDBAR = wxNewId()
383
pypeID_REPLACEBAR = wxNewId()
384
pypeID_TOGGLE_BOOKMARK = wxNewId()
385
pypeID_NEXT_BOOKMARK = wxNewId()
386
pypeID_PRIOR_BOOKMARK = wxNewId()
392
DB_LOC = {0:(wxLAYOUT_LEFT, wxSASH_RIGHT),
393
1:(wxLAYOUT_RIGHT, wxSASH_LEFT)}
395
LB_LOC = {0:(wxLAYOUT_TOP, wxSASH_BOTTOM),
396
1:(wxLAYOUT_BOTTOM, wxSASH_TOP)}
398
#extension to image map
399
EXT_TO_IMG = {'python':1}
402
RESET = {'cursorposn':0,
406
sys_excepthook = sys.excepthook
408
def my_excepthook(typ, inst, trace):
411
return sys_excepthook(typ, inst, trace)
413
sys.excepthook = my_excepthook
418
#---------------------- Frame that contains everything -----------------------
419
class MainWindow(wxFrame):
420
def __init__(self,parent,id,title,fnames):
422
wxFrame.__init__(self,parent,id, title, size = ( 1024, 600 ),
423
style=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE)
425
self.SetIcon(getIcon())
427
path = os.path.join(homedir, 'menus.txt')
428
try: OLD_MENUPREF.update(self.readAndEvalFile(path))
431
#recent menu relocated to load configuration early on.
432
recentmenu = wxMenu()
433
#--------------------------- cmt-001 - 08/06/2003 ----------------------------
434
#----------------- Adds opened file history to the File menu -----------------
435
self.fileHistory = wxFileHistory()
436
self.fileHistory.UseMenu(recentmenu)
437
self.configPath = homedir
439
self.SetSize(LASTSIZE)
440
self.SetPosition(LASTPOSITION)
443
EVT_MENU_RANGE(self, wxID_FILE1, wxID_FILE9, self.OnFileHistory)
444
self.lastused = lru.lastused(128+len(lastopen), LASTUSED)
445
self.curdocstates = {}
446
#------------------------- end cmt-001 - 08/06/2003 --------------------------
457
#EVT_IDLE(self, self.SetPos)
459
#self.T = wxTimer(self, a)
460
#EVT_TIMER(self, a, self.SetPos)
463
self.sb = wxStatusBar(self, -1)
465
#to display encoding in unicode supporting platforms
466
self.sb.SetFieldsCount(3)
467
self.sb.SetStatusWidths([-1, 95, 60])
469
self.sb.SetFieldsCount(2)
470
self.sb.SetStatusWidths([-1, 95])
471
self.SetStatusBar(self.sb)
476
self.control = MyNB(self, -1, self)
478
# Setting up the menu
481
bottom = makeSubWindow(self, ID_WINDOW_BOTTOM, (BIG, SASH1),
485
right = makeSubWindow(self, ID_WINDOW_RIGHT, (SASH2, BIG),
492
self.BOTTOMNB = wxNotebook(bottom, -1)
493
self.RIGHTNB = wxNotebook(right, -1)
496
self.todolist = todo.VirtualTodo(self.BOTTOMNB, self)
497
self.BOTTOMNB.AddPage(self.todolist, 'Todo')
500
self.BOTTOMNB.AddPage(logger.logger(self.BOTTOMNB), 'Log')
501
## self.BOTTOMNB.AddPage(findinfiles.FindInFiles(self.BOTTOMNB, self), "Find in Files")
502
self.BOTTOMNB.AddPage(findinfiles.FindInFiles(self.BOTTOMNB, self), "Search")
504
self.leftt = wxPanel(self.RIGHTNB)#HiddenPanel(self.RIGHTNB, self, 0)#hierCodeTreePanel(self, self.RIGHTNB)
505
self.leftt.sizer = wxBoxSizer(wxVERTICAL)
506
self.leftt.SetSizer(self.leftt.sizer)
507
self.leftt.SetAutoLayout(True)
509
self.rightt = wxPanel(self.RIGHTNB)#HiddenPanel(self.RIGHTNB, self, 1)#hierCodeTreePanel(self, self.RIGHTNB)
510
self.rightt.sizer = wxBoxSizer(wxVERTICAL)
511
self.rightt.SetSizer(self.rightt.sizer)
512
self.rightt.SetAutoLayout(True)
514
self.dragger = MyLC(self.RIGHTNB, self)
516
## self.RIGHTNB.AddPage(project.Project(self.RIGHTNB, -1, self), 'Project')
517
self.RIGHTNB.AddPage(self.rightt, 'Name')
518
self.RIGHTNB.AddPage(self.leftt, 'Line')
520
self.todolist = todo.VirtualTodo(self.RIGHTNB, self)
521
self.RIGHTNB.AddPage(self.todolist, 'Todo')
522
self.RIGHTNB.AddPage(self.dragger, 'Documents')
523
self.pathmarks = browser.FilesystemBrowser(self.RIGHTNB, self, pathmarksn)
524
self.RIGHTNB.AddPage(self.pathmarks, "Browse...")
526
self.Bind(EVT_SASH_DRAGGED_RANGE, self.OnSashDrag, id=ID_WINDOW_BOTTOM, id2=ID_WINDOW_RIGHT)
528
#------------------------- Insert menus into Menubar -------------------------
530
menuBar = wxMenuBar()
532
self.SetMenuBar(menuBar) # Adding the MenuBar to the Frame content.
533
self.menubar = menuBar
535
#--------------------------------- File Menu ---------------------------------
538
menuAddM(menuBar, filemenu, "&File")
539
menuAdd(self, filemenu, "&New\tCtrl+N", "New file", self.OnNew, wxID_NEW)
540
menuAdd(self, filemenu, "&Open\tCtrl+O", "Open a file", self.OnOpen, wxID_OPEN)
541
menuAdd(self, filemenu, "Open &Module\tAlt+M", "Open a module for editing using the same path search as import would", self.OnOpenModule, wxNewId())
542
menuAdd(self, filemenu, "Open &Last\t", "Open all the documents that were opening before last program exit", self.OnOpenPrevDocs, wxNewId())
543
menuAddM(filemenu, recentmenu, "Open Recent")
544
filemenu.AppendSeparator()
545
menuAdd(self, filemenu, "&Save\tCtrl+S", "Save a file", self.OnSave, wxID_SAVE)
546
menuAdd(self, filemenu, "Save &As", "Save a file as...", self.OnSaveAs, wxID_SAVEAS)
547
menuAdd(self, filemenu, "Sa&ve All", "Save all open files...", self.OnSaveAll, wxNewId())
548
filemenu.AppendSeparator()
549
menuAdd(self, filemenu, "Add Module Search Path", "Add a path to search during subsequent 'Open Module' executions", self.AddSearchPath, wxNewId())
550
menuAdd(self, filemenu, "&Reload", "Reload the current document from disk", self.OnReload, wxID_REVERT)
551
menuAdd(self, filemenu, "&Close\tCtrl+W", "Close the file in this tab", self.OnClose, wxNewId())
552
workspace.WorkspaceMenu(filemenu, self, workspaces, workspace_order)
553
menuAdd(self, filemenu, "E&xit\tAlt+F4", "Terminate the program", self.OnExit, wxNewId())
555
#--------------------------------- Edit Menu ---------------------------------
558
menuAddM(menuBar, editmenu, "&Edit")
559
menuAdd(self, editmenu, "Undo\tCtrl+Z", "Undo last modifications", self.OnUndo, wxID_UNDO)
560
menuAdd(self, editmenu, "Redo\tCtrl+Y", "Redo last modifications", self.OnRedo, wxID_REDO)
561
editmenu.AppendSeparator()
562
menuAdd(self, editmenu, "Select All\tCtrl+A", "Select all text", self.OnSelectAll, wxNewId())
563
menuAdd(self, editmenu, "Cut\tCtrl+X", "Cut selected text", self.OnCut, wxID_CUT)
564
menuAdd(self, editmenu, "Copy\tCtrl+C", "Copy selected text", self.OnCopy, wxID_COPY)
565
menuAdd(self, editmenu, "Paste\tCtrl+V", "Paste selected text", self.OnPaste, wxID_PASTE)
566
menuAdd(self, editmenu, "Delete", "Delete selected text", self.OnDeleteSelection, pypeID_DELETE)
567
editmenu.AppendSeparator()
568
menuAdd(self, editmenu, "Indent Region\tCtrl+]", "Indent region %i spaces%indent", self.OnIndent, wxNewId())
569
menuAdd(self, editmenu, "Dedent Region\tCtrl+[", "Dedent region %i spaces%indent", self.OnDedent, wxNewId())
570
menuAdd(self, editmenu, "Wrap Selected Text\tAlt+W", "Wrap selected text to a specified width", self.OnWrap, wxNewId())
571
editmenu.AppendSeparator()
572
menuAdd(self, editmenu, "Show Find Bar\tCtrl+F", "Shows the find bar at the bottom of the editor", self.OnShowFindbar, pypeID_FINDBAR)
573
menuAdd(self, editmenu, "Show Replace Bar\tCtrl+R", "Shows the replace bar at the bottom of the editor", self.OnShowReplacebar, pypeID_REPLACEBAR)
574
menuAdd(self, editmenu, "Find again\tF3", "Finds the text in the find bar again", self.OnFindAgain, wxNewId())
575
## editmenu.AppendSeparator()
576
## if self.config['usesnippets']:
577
## menuAdd(self, editmenu, "Insert Snippet\tCtrl+return", "Insert the currently selected snippet into the document", self.snippet.OnListBoxDClick, wxNewId())
578
editmenu.AppendSeparator()
579
menuAdd(self, editmenu, "Insert Comment\tCtrl+I", "Insert a centered comment", self.OnInsertComment, wxNewId())
580
menuAdd(self, editmenu, "Comment Selection\tAlt+8", "Comment selected lines", self.OnCommentSelection, wxNewId())
581
menuAdd(self, editmenu, "Uncomment Selection\tAlt+9", "Uncomment selected lines", self.OnUncommentSelection, wxNewId())
582
editmenu.AppendSeparator()
583
menuAdd(self, editmenu, "Perform Trigger", "Performs a trigger epansion if possible", self.OnTriggerExpansion, wxNewId())
585
#--------------------------------- View Menu ---------------------------------
588
menuAddM(menuBar, viewmenu,"&View")
589
menuAdd(self, viewmenu, "Previous Tab\tAlt+,", "View the tab to the left of the one you are currently", self.OnLeft, wxNewId())
590
menuAdd(self, viewmenu, "Next Tab\tAlt+.", "View the tab to the right of the one you are currently", self.OnRight, wxNewId())
591
viewmenu.AppendSeparator()
592
menuAdd(self, viewmenu, "Zoom In\tCtrl++", "Make the text in the editing component bigger", self.OnZoom, ZI)
593
menuAdd(self, viewmenu, "Zoom Out\tCtrl+-", "Make the text in the editing component smaller", self.OnZoom, wxNewId())
594
viewmenu.AppendSeparator()
595
menuAdd(self, viewmenu, "Go to line number\tAlt+G", "Advance to the given line in the currently open document", self.OnGoto, wxNewId())
596
menuAdd(self, viewmenu, "Jump forward", "Advance the cursor to the next quote/bracket", self.OnJumpF, wxNewId())
597
menuAdd(self, viewmenu, "Jump backward", "Advance the cursor to the previous quote/bracket", self.OnJumpB, wxNewId())
598
viewmenu.AppendSeparator()
599
menuAdd(self, viewmenu, "Toggle Bookmark\tCtrl+M", "Create/remove bookmark for this line", self.OnToggleBookmark, pypeID_TOGGLE_BOOKMARK)
600
menuAdd(self, viewmenu, "Next Bookmark\tF2", "Hop to the next bookmark in this file", self.OnNextBookmark, pypeID_NEXT_BOOKMARK)
601
menuAdd(self, viewmenu, "Previous Bookmark\tShift+F2", "Hop to the previous bookmark in this file", self.OnPreviousBookmark, pypeID_PRIOR_BOOKMARK)
603
#------------------------------- Document menu -------------------------------
606
menuAddM(menuBar, setmenu, "&Document")
607
## menuAdd(self, setmenu, "Use Snippets (req restart)", "Enable or disable the use of snippets, requires restart for change to take effect", self.OnSnipToggle, SNIPT, wxITEM_CHECK)
608
## setmenu.AppendSeparator()
610
#-------------------------------- Style subenu -----------------------
612
menuAddM(setmenu, stylemenu, "Syntax Highlighting", "Change the syntax highlighting for the currently open document")
613
menuAdd(self, stylemenu, "Python", "Highlight for Python syntax", self.OnStyleChange, PY_S, typ)
614
menuAdd(self, stylemenu, "HTML", "Highlight for HTML syntax", self.OnStyleChange, HT_S, typ)
615
menuAdd(self, stylemenu, "XML", "Highlight for XML syntax", self.OnStyleChange, XM_S, typ)
616
menuAdd(self, stylemenu, "C/C++", "Highlight for C/C++ syntax", self.OnStyleChange, CC_S, typ)
617
menuAdd(self, stylemenu, "Text", "No Syntax Highlighting", self.OnStyleChange, TX_S, typ)
619
#------------------------------ Encodings submenu --------------------
622
menuAddM(setmenu, encmenu, "Encodings", "Change text encoding")
623
menuAdd(self, encmenu, 'ascii', "Change encoding for the current file to ascii (will use utf-8 if unicode characters found)", self.OnEncChange, ENCODINGS['ascii'], typ)
624
for bom, enc in BOM[:-1]:
625
menuAdd(self, encmenu, enc, "Change encoding for the current file to %s"%enc, self.OnEncChange, ENCODINGS[enc], typ)
627
#----------------------------- Line ending menu ----------------------
628
endingmenu = wxMenu()
629
menuAddM(setmenu, endingmenu, "Line Ending", "Change the line endings on the current document")
630
menuAdd(self, endingmenu, "CRLF (windows)", "Change the line endings for the current document to CRLF/Windows line endings", self.OnLineEndChange, LE_CRLF, typ)
631
menuAdd(self, endingmenu, "LF (*nix)", "Change the line endings for the current document to LF/*nix line endings", self.OnLineEndChange, LE_LF, typ)
632
menuAdd(self, endingmenu, "CR (mac)", "Change the line endings for the current document to CR/Macintosh line endings", self.OnLineEndChange, LE_CR, typ)
635
setmenu.AppendSeparator()
636
menuAdd(self, setmenu, "Show Autocomplete", "Show the autocomplete dropdown while typing", self.OnAutoCompleteToggle, AUTO, wxITEM_CHECK)
637
menuAdd(self, setmenu, "Show line numbers", "Show or hide the line numbers on the current document", self.OnNumberToggle, NUM, wxITEM_CHECK)
638
menuAdd(self, setmenu, "Show margin", "Show or hide the bookmark signifier margin on the current document", self.OnMarginToggle, MARGIN, wxITEM_CHECK)
639
menuAdd(self, setmenu, "Show Indentation Guide", "Show or hide gray indentation guides in indentation", self.OnIndentGuideToggle, INDENTGUIDE, wxITEM_CHECK)
640
menuAdd(self, setmenu, "Save Position", "Remember or forget the last position of the cursor when the current document is closed", self.OnSavePositionToggle, SAVE_CURSOR, wxITEM_CHECK)
641
setmenu.AppendSeparator()
642
## menuAdd(self, setmenu, "Show/hide tree\tCtrl+Shift+G", "Show/hide the hierarchical source tree for the currently open document", self.OnTree, wxNewId())
643
## menuAdd(self, setmenu, "Hide all trees", "Hide the browsable source tree for all open documents", self.OnTreeHide, wxNewId())
644
menuAdd(self, setmenu, "Refresh\tF5", "Refresh the browsable source tree, autocomplete listing, and the tooltips (always accurate, but sometimes slow)", self.OnRefresh, wxNewId())
645
setmenu.AppendSeparator()
646
## menuAdd(self, setmenu, "Sort Tree by Name", "If checked, will sort the items in the browsable source tree by name, otherwise by line number", self.OnTreeSortToggle, SORTBY, wxITEM_CHECK)
647
menuAdd(self, setmenu, "Expand all", "Expand all folded code through the entire document", self.OnExpandAll, wxNewId())
648
menuAdd(self, setmenu, "Fold all", "Fold all expanded code through the entire document", self.OnFoldAll, wxNewId())
649
menuAdd(self, setmenu, "Use Tabs", "New indentation will include tabs", self.OnSetTabToggle, USETABS, wxITEM_CHECK)
650
menuAdd(self, setmenu, "Wrap Long Lines", "Visually continue long lines to the next line", self.OnWrapL, WRAPL, wxITEM_CHECK)
651
setmenu.AppendSeparator()
652
menuAdd(self, setmenu, "Set Triggers", "Sets trigger expansions for the current document", self.OnSetTriggers, wxNewId())
653
menuAdd(self, setmenu, "Set Indent Width", "Set the number of spaces per indentation level", self.OnSetIndent, wxNewId())
654
menuAdd(self, setmenu, "Set Tab Width", "Set the visual width of tabs in the current open document", self.OnSetTabWidth, wxNewId())
655
menuAdd(self, setmenu, "Set Long Line Column", "Set the column number for the long line indicator", self.OnSetLongLinePosition, wxNewId())
657
#------------------------------ Long line submenu --------------------
658
longlinemenu = wxMenu()
659
menuAddM(setmenu, longlinemenu, "Set Long Line Indicator", "Change the mode that signifies long lines")
660
menuAdd(self, longlinemenu, "Background", "Long lines will have a different background color beyond the column limit", self.OnSetLongLineMode, LL_BACK, typ)
661
menuAdd(self, longlinemenu, "Line", "Long lines will have a vertical line at the column limit", self.OnSetLongLineMode, LL_LINE, typ)
662
menuAdd(self, longlinemenu, "None", "Show no long line indicator", self.OnSetLongLineMode, LL_NONE, typ)
664
#-------------------------------- Shell Menu ---------------------------------
666
## self.shell = RunShell(self, menuBar, "&Shell")
668
#------------------------------- Options Menu --------------------------------
669
optionsmenu= wxMenu()
670
menuAddM(menuBar, optionsmenu, "&Options")
671
settingsmenu = wxMenu()
672
menuAddM(optionsmenu, settingsmenu, "Save Settings", "Set the default behavior of documents opened of a given type")
674
lang, desc = SOURCE_ID_TO_OPTIONS[mid]
675
menuAdd(self, settingsmenu, desc, "Save the settings for the current document as the default for %s documents"%desc, self.OnSaveLang, mid)
676
#menuAdd(self, settingsmenu, "", ", self.OnSaveSettings, wxNewId())
677
loadsettingsmenu = wxMenu()
678
menuAddM(optionsmenu, loadsettingsmenu, "Load Settings", "Set the current document behavior to that of the default for documents of a given type")
680
lang, desc = SOURCE_ID_TO_OPTIONS2[mid]
681
menuAdd(self, loadsettingsmenu, desc, "Set the current document behavior to that of the default for %s"%desc, self.OnLoadSavedLang, mid)
683
optionsmenu.AppendSeparator()
684
#---------------------------- Default Style submenu ------------------
686
menuAddM(optionsmenu, stylemenu2, "Default Highlighting", "Set the default syntax highlighting for new or unknown documents")
687
menuAdd(self, stylemenu2, 'Python', "All new or unknown documents will be highlighted as Python", self.OnDefaultStyleChange, PY_DS, typ)
688
menuAdd(self, stylemenu2, 'HTML', "All new or unknown documents will be highlighted as HTML", self.OnDefaultStyleChange, HT_DS, typ)
689
menuAdd(self, stylemenu2, 'XML', "All new or unknown documents will be highlighted as XML", self.OnDefaultStyleChange, XM_DS, typ)
690
menuAdd(self, stylemenu2, 'C/C++', "All new or unknown documents will be highlighted as C/C++", self.OnDefaultStyleChange, CC_DS, typ)
691
menuAdd(self, stylemenu2, 'Text', "All new or unknown documents will be highlighted as Text", self.OnDefaultStyleChange, TX_DS, typ)
693
optionsmenu.AppendSeparator()
694
menuAdd(self, optionsmenu, "Enable File Drops", "Enable drag and drop file support onto the text portion of the editor", self.OnDNDToggle, DND_ID, wxITEM_CHECK)
695
optionsmenu.AppendSeparator()
696
menuAdd(self, optionsmenu, "Editor on top", "When checked, the editor is above the Todos, Log, etc., otherwise it is below (requires restart)", self.OnLogBarToggle, LB_ID, wxITEM_CHECK)
697
menuAdd(self, optionsmenu, "Editor on left", "When checked, the editor is left of the source trees, document list, etc., otherwise it is to the right (requires restart)", self.OnDocBarToggle, DB_ID, wxITEM_CHECK)
698
menuAdd(self, optionsmenu, "Show Wide Tools", "Shows or hides the tabbed tools that are above or below the editor", self.OnShowWideToggle, WIDE_ID, wxITEM_CHECK)
699
menuAdd(self, optionsmenu, "Show Tall Tools", "Shows or hides the tabbed tools that are right or left of the editor", self.OnShowTallToggle, TALL_ID, wxITEM_CHECK)
700
menuAdd(self, optionsmenu, "Wide Todo", "When checked, the todo list will be near the Log tab, when unchecked, will be near the Documenst tab (requires restart)", self.OnTodoToggle, TD_ID, wxITEM_CHECK)
701
menuAdd(self, optionsmenu, "Show Toolbar", "When checked, will show a toolbar (requires restart)", self.OnToolbarToggle, TB_ID, wxITEM_CHECK)
702
optionsmenu.AppendSeparator()
704
menuAddM(optionsmenu, caretmenu, "Caret Options", "Set how your caret behaves while it is moving around")
705
menuAdd(self, caretmenu, "PyPE Classic", "Caret is at least 1 line from the top and bottom, 10 pixels from the right and left", self.OnCaret, CARET_DEFAULT, typ)
706
menuAdd(self, caretmenu, "Margin Respecting", "Caret is at least M lines from the top and bottom, N*M pixels from the right and left", self.OnCaret, CARET_MARGIN, typ)
707
menuAdd(self, caretmenu, "Margin Attached", "Caret is always M lines from the top, and N*M pixels from the right, if possible", self.OnCaret, CARET_TOP_MARGIN, typ)
708
menuAdd(self, caretmenu, "Top Attached", "Caret is always on the top line, if possible", self.OnCaret, CARET_TOP, typ)
709
menuAdd(self, caretmenu, "Centered", "Caret is centered on the display, if possible", self.OnCaret, CARET_CENTER, typ)
710
menuAdd(self, optionsmenu, "Set Caret M value", "Set the number of lines of unapproachable margin, the M value referenced in Caret Options", self.OnCaretM, wxNewId())
711
menuAdd(self, optionsmenu, "Set Caret N value", "Set the multiplier, the N value referenced in Caret Options", self.OnCaretN, wxNewId())
712
optionsmenu.AppendSeparator()
713
menuAdd(self, optionsmenu, "Use Findbar history", "When checked, allows for the find and replace bars to keep history of searches (bars will need to be reopened)", self.OnFindbarHistory, NO_FINDBAR_HISTORY, wxITEM_CHECK)
714
#menuAdd(self, findbarmenu, "Save Find Bar settings", "Save the settings (without history) of the current find/replace bar as the default for any document without preferences", self.OnFinbarDefault, wxNewId())
715
menuAdd(self, optionsmenu, "Clear Find Bar history", "Clears the find/replace history on the current document", self.OnFindbarClear, CLEAR_FINDBAR_HISTORY)
716
optionsmenu.AppendSeparator()
717
menuAdd(self, optionsmenu, "Change Menus and Hotkeys", "Change the name of menu items and their hotkeys, any changes will require a restart to take effect", self.OnChangeMenu, wxNewId())
719
menuAddM(optionsmenu, titlemenu, "Title Options", "Set what information you would like PyPE to display in the title bar")
721
long = "C:\\PyPE\\pype.py"
722
pype = "PyPE %s"%VERSION
724
title_id, proto, desc = TITLE_OPTION_TO_ID[i]
725
menuAdd(self, titlemenu, desc, "Set the title like: "+proto%locals(), self.OnChangeTitle, title_id, typ)
728
#--------------------------------- Help Menu ---------------------------------
731
menuAddM(menuBar, helpmenu, "&Help")
732
menuAdd(self, helpmenu, "About...", "About this piece of software", self.OnAbout, wxID_ABOUT)
733
helpmenu.AppendSeparator()
734
menuAdd(self, helpmenu, "PyPE Help\tF1", "View the help", self.OnHelp, wxID_HELP)
736
#------------------------ A ...few... state variables ------------------------
744
self.menubar.Check(AUTO, showautocomp)
745
self.menubar.Check(WRAPL, wrapmode != wxSTC_WRAP_NONE)
746
self.menubar.Check(DND_ID, dnd_file)
747
self.menubar.Check(LB_ID, logbarlocn)
748
self.menubar.Check(DB_ID, docbarlocn)
749
self.menubar.Check(WIDE_ID, SHOWWIDE)
750
self.menubar.Check(TALL_ID, SHOWTALL)
751
self.menubar.Check(TD_ID, TODOBOTTOM)
752
self.menubar.Check(TB_ID, TOOLBAR)
753
self.menubar.Check(USETABS, use_tabs)
754
self.menubar.Check(INDENTGUIDE, indent_guide)
755
self.menubar.Check(lexers3[DEFAULTLEXER], 1)
756
self.menubar.Check(SAVE_CURSOR, save_cursor)
757
self.menubar.Check(CARET_OPTION_TO_ID[caret_option][0], 1)
758
self.menubar.Check(TITLE_OPTION_TO_ID[title_option][0], 1)
759
self.menubar.Check(NO_FINDBAR_HISTORY, not no_findbar_history)
760
self.menubar.FindItemById(CLEAR_FINDBAR_HISTORY).Enable(not no_findbar_history)
762
#------------------------ Drag and drop file support -------------------------
763
self.SetDropTarget(FileDropTarget(self))
766
EVT_CLOSE(self, self.OnExit)
767
EVT_SIZE(self, self.OnSize)
768
EVT_ACTIVATE(self, self.OnActivation)
769
EVT_KEY_DOWN(self, self.OnKeyPressed)
771
if self.control.GetPageCount() > 0:
772
stc = self.getNumWin()[1]
773
self.OnDocumentChange(stc)
777
self.timer = wxTimer(self, tid)
778
EVT_TIMER(self, tid, self.ex_size)
780
self.timer2 = wxTimer(self, tid)
781
EVT_TIMER(self, tid, self.keyposn)
782
self.timer2.Start(100, wxTIMER_CONTINUOUS)
784
#------------------ Open files passed as arguments to PyPE -------------------
790
if (not SHOWWIDE) or (not SHOWTALL):
793
self.OnDrop(fnames, 0)
797
def getglobal(self, nam):
798
return globals()[nam]
800
def getInt(self, title, text, default):
801
dlg = wxTextEntryDialog(self, text, title, str(default))
802
resp = dlg.ShowModal()
803
valu = dlg.GetValue()
807
return validate(valu, default)
810
def _setupToolBar(self):
813
def getBmp(artId, client):
814
bmp = wxArtProvider_GetBitmap(artId, client, size)
816
bmp = EmptyBitmap(*size)
819
tb = self.CreateToolBar(
820
wxTB_HORIZONTAL|wxNO_BORDER|wxTB_FLAT|wxTB_TEXT)
822
tb.SetToolBitmapSize(size)
824
icon = getBmp(wxART_NORMAL_FILE, wxART_TOOLBAR)
825
tb.AddSimpleTool(wxID_NEW, icon, "New Document",
826
"Create a new empty document")
827
icon = getBmp(wxART_FILE_OPEN, wxART_TOOLBAR)
828
tb.AddSimpleTool(wxID_OPEN, icon, "Open",
829
"Open an existing document")
830
icon = getBmp(wxART_FILE_SAVE, wxART_TOOLBAR)
831
tb.AddSimpleTool(wxID_SAVE, icon, "Save", "Save current document")
833
icon = getBmp(wxART_FILE_SAVE_AS, wxART_TOOLBAR)
834
tb.AddSimpleTool(wxID_SAVEAS, icon, "Save as...", "Save current document as...")
838
icon = getBmp(wxART_CUT, wxART_TOOLBAR)
839
tb.AddSimpleTool(wxID_CUT, icon, "Cut",
840
"Cut selection to the clibboard")
841
icon = getBmp(wxART_COPY, wxART_TOOLBAR)
842
tb.AddSimpleTool(wxID_COPY, icon, "Copy",
843
"Copy selection to the clibboard")
844
icon = getBmp(wxART_PASTE, wxART_TOOLBAR)
845
tb.AddSimpleTool(wxID_PASTE, icon, "Paste",
846
"Paste current clibboard contents")
847
icon = getBmp(wxART_DELETE, wxART_TOOLBAR)
848
tb.AddSimpleTool(pypeID_DELETE, icon, "Delete",
853
icon = getBmp(wxART_UNDO, wxART_TOOLBAR)
854
tb.AddSimpleTool(wxID_UNDO, icon, "Undo",
856
icon = getBmp(wxART_REDO, wxART_TOOLBAR)
857
tb.AddSimpleTool(wxID_REDO, icon, "Redo",
858
"Redo edit (i.e. undo undo edit)")
862
icon = getBmp(wxART_FIND, wxART_TOOLBAR)
863
tb.AddSimpleTool(pypeID_FINDBAR, icon, "Find",
865
icon = getBmp(wxART_FIND_AND_REPLACE, wxART_TOOLBAR)
866
tb.AddSimpleTool(pypeID_REPLACEBAR, icon, "Replace",
871
icon = getBmp(wxART_ADD_BOOKMARK, wxART_TOOLBAR)
872
tb.AddSimpleTool(pypeID_TOGGLE_BOOKMARK, icon, "Toggle Bookmark",
873
"Create or Remove a bookmark at the current line")
875
icon = getBmp(wxART_GO_DOWN, wxART_TOOLBAR)
876
tb.AddSimpleTool(pypeID_NEXT_BOOKMARK, icon, "Next Bookmark",
877
"Go to the next bookmark in this file")
879
icon = getBmp(wxART_GO_UP, wxART_TOOLBAR)
880
tb.AddSimpleTool(pypeID_PRIOR_BOOKMARK, icon, "Previous Bookmark",
881
"Go to the previous bookmark in this file")
886
icon = getBmp(wxART_HELP, wxART_TOOLBAR)
887
tb.AddSimpleTool(wxID_HELP, icon, "Help!",
888
"Opens up the help for PyPE")
892
def OnDocumentChange(self, stc, forced=False):
893
if not self.starting:
896
if stc.cached is None or forced:
897
stc.ConvertEOLs(fmt_mode[stc.format])
898
out = wxStyledTextCtrl.GetText(stc).replace('\t', stc.GetTabWidth()*' ')
899
tpl = fast_parser(out, stc.format, 3, lambda:None)
901
stc.cached = copy.deepcopy(tpl)
902
h1, stc.kw, stc.tooltips, todo = tpl
905
stc.kw = ' '.join(stc.kw)
907
ex1 = copy.deepcopy(h1)
908
stc.tree1.new_hierarchy(h1)
909
stc.tree2.new_hierarchy(ex1)
913
todo = copy.deepcopy(stc.cached[-1])
915
self.todolist.NewItemList(todo)
916
self.updateWindowTitle()
918
self.SetStatusText(("Browsable source tree, autocomplete, tooltips and todo"
919
" updated for %s in %.1f seconds.")%(stc.filename, time.time()-start))
921
def updateWindowTitle(self):
922
pype = "PyPE %s"%VERSION
925
num, stc = self.getNumWin()
929
fn, dn = stc.filename, stc.dirname
931
fn = "<untitled %i>"%stc.NEWDOCUMENT
932
long = os.path.join(dn, fn)
934
disp = TITLE_OPTION_TO_ID[title_option][1]%locals()
939
def ex_size(self, evt=None):
940
#an attempt to keep the findbar the correct size
942
win = self.getNumWin()[1]
943
if win.parent.IsSplit():
944
size = (win.parent.GetWindow2().GetAdjustedBestSize())[1]+5
945
win.parent.SetSashPosition(-size)
946
win.tree1.OnSize(None)
947
win.tree2.OnSize(None)
951
def keyposn(self, evt=None):
952
#an attempt to keep the line and column indicators correct
954
win = self.getNumWin()[1]
959
def OnSashDrag(self, event):
960
if event.GetDragStatus() == wxSASH_STATUS_OUT_OF_RANGE:
965
if eID == ID_WINDOW_RIGHT:
966
self.RIGHT.SetDefaultSize((max(event.GetDragRect().width, SMALL), BIG))
968
elif eID == ID_WINDOW_BOTTOM:
969
self.BOTTOM.SetDefaultSize((BIG, max(event.GetDragRect().height, SMALL)))
971
wxLayoutAlgorithm().LayoutWindow(self, self.control)
972
self.control.Refresh()
976
def OnSize(self, event):
977
wxLayoutAlgorithm().LayoutWindow(self, self.control)
980
def dialog(self, message, title, styl=wxOK):
981
d= wxMessageDialog(self,message,title,styl)
986
def exceptDialog(self, title="Error"):
987
k = cStringIO.StringIO()
988
traceback.print_exc(file=k)
990
dlg = wxScrolledMessageDialog(self, k.read(), title)
994
def OnDrop(self, fnames, error=1):
997
dn, fn = os.path.split(self.getAlmostAbsolute(i, cwd))
998
if self.isOpen(fn, dn):
1000
self.selectAbsolute(self.getAbsolute(fn, dn))
1002
self.makeOpen(fn, dn)
1004
a = self.newTab(dn, fn, len(fnames)==1)
1005
i = os.path.join(dn, fn)
1006
if UNICODE: a = "%s as %s"%(i, a)
1008
self.SetStatusText("Opened %s"%a)
1011
self.exceptDialog("File open failed")
1013
self.redrawvisible()
1015
def SetStatusText(self, text, number=0, log=1):
1016
if (number == 0) and text:
1019
text = "[%s] %s"%(time.asctime(), text)
1020
self.sb.SetStatusText(text, number)
1022
def OnActivation(self, e):
1024
self.control.__iter__
1025
except wxPyDeadObjectError:
1034
for document in self.control.__iter__():
1035
if document.mod != None:
1036
fn = self.getAlmostAbsolute(document.filename, document.dirname)
1038
mod = os.stat(fn)[8]
1040
document.MakeDirty(None)
1042
"has been deleted from the disk by an external program.\n"\
1043
"Unless the file is saved again, data loss may occur."%fn,
1047
if mod != document.mod:
1048
if open(fn, 'rb').read() == document.GetText():
1049
#Compare the actual text, just to make sure...
1050
#Fixes a problem with PyPE being open during daylight
1051
#savings time changes.
1052
#Also fixes an issue when an identical file is saved
1053
#over a currently-being-edited file.
1055
document.MakeClean(None)
1058
document.MakeDirty(None)
1059
a = self.dialog("%s\n"\
1060
"has been modified by an external program.\n"\
1061
"Would you like to reload the file from disk?"%fn,
1062
"WARNING!", wxYES_NO)
1066
self.OnReload(None, document)
1068
self.redrawvisible()
1069
self.SendSizeEvent()
1072
#--------------------------- cmt-001 - 08/06/2003 ----------------------------
1073
#--------------------- Saving and loading of preferences ---------------------
1074
def loadHistory(self):
1075
if not os.path.exists(self.configPath):
1076
os.mkdir(self.configPath)
1077
path = os.path.join(self.configPath, 'history.txt')
1078
print "Loading history from", path
1079
try: self.config = self.readAndEvalFile(path)
1080
except: self.config = {}
1081
if 'history' in self.config:
1082
history = self.config['history']
1085
self.fileHistory.AddFileToHistory(h)
1086
if 'lastpath' in self.config:
1087
self.lastpath = self.config['lastpath']
1090
#insert global document defaults here
1091
dct = {'use_tabs':0,
1098
'col_mode':wxSTC_EDGE_LINE,
1101
'wrapmode':wxSTC_WRAP_NONE,
1107
doc_def['python'] = dict(dct)
1108
doc_def['cpp'] = dict(dct)
1109
doc_def['html'] = dict(dct)
1110
doc_def['xml'] = dict(dct)
1111
doc_def['text'] = dict(dct)
1112
for (nam, dflt) in [('modulepaths', []),
1113
## ('usesnippets', 0),
1116
## ('display2code', {}),
1117
## ('displayorder', []),
1118
## ('shellcommands', []),
1121
('DEFAULTLEXER', 'python'),
1122
('FIF_STATE', ([], [], [], 0, 0, 0)),
1123
('match_flags', wxFR_DOWN),
1126
('workspace_order', []),
1129
('LASTSIZE', (900,600)),
1130
('LASTPOSITION', self.GetPositionTuple()),
1134
('caret_option', 0),
1136
('caret_multiplier', 20),
1137
('findbarprefs', {}),
1138
('no_findbar_history', 0),
1139
('title_option', 0),
1140
('document_defaults', doc_def),
1141
('DOCUMENT_DEFAULTS', dct),
1147
if nam in self.config:
1148
if isinstance(dflt, dict):
1149
for k,v in dflt.iteritems():
1150
if k not in self.config[nam]:
1151
if isinstance(v, dict):
1152
self.config[nam][k] = dict(v)
1154
self.config[nam][k] = v
1155
elif isinstance(v, dict):
1156
V = self.config[nam][k]
1157
for k2,v2 in v.iteritems():
1160
elif isinstance(dflt, dict):
1161
self.config[nam] = dict(dflt)
1163
self.config[nam] = dflt
1164
globals()[nam] = self.config[nam]
1165
globals().update(dct)
1166
globals().update(self.config.setdefault('DOCUMENT_DEFAULTS', dct))
1168
def saveHistory(self):
1170
for i in range(self.fileHistory.GetNoHistoryFiles()):
1171
history.append(self.fileHistory.GetHistoryFile(i))
1172
self.config['history'] = history
1174
## for i in self.shell.order:
1175
## a.append(self.shell.menu[i])
1176
## self.config['shellcommands'] = a
1177
self.config['match_flags'] = match_flags
1178
self.config['pathmarksn'] = self.pathmarks.op.GetLabels()
1179
self.config['workspaces'] = workspaces
1180
self.config['workspace_order'] = workspace_order
1181
self.config['logbarlocn'] = logbarlocn
1182
self.config['docbarlocn'] = docbarlocn
1183
self.config['dnd_file'] = dnd_file
1184
self.config['caret_option'] = caret_option
1185
self.config['caret_slop'] = caret_slop
1186
self.config['caret_multiplier'] = caret_multiplier
1187
self.config['findbarprefs'] = findbarprefs
1188
self.config['no_findbar_history'] = no_findbar_history
1189
self.config['title_option'] = title_option
1190
self.config['TODOBOTTOM'] = TODOBOTTOM
1191
self.config['TOOLBAR'] = TOOLBAR
1192
self.config['SHOWWIDE'] = SHOWWIDE
1193
self.config['SHOWTALL'] = SHOWTALL
1194
## if self.config['usesnippets'] and (not self.restart):
1195
## self.config['display2code'] = self.snippet.display2code
1196
## self.config['displayorder'] = self.snippet.displayorder
1197
self.config['lastpath'] = self.config.get('lp', os.getcwd())
1199
path = os.sep.join([self.configPath, 'history.txt'])
1200
print "Saving history to", path
1202
f.write(pprint.pformat(self.config))
1204
path = os.sep.join([self.configPath, 'menus.txt'])
1205
print "Saving menus to", path
1207
f.write(pprint.pformat(MENUPREF))
1210
self.exceptDialog("Could not save preferences to %s"%path)
1212
def readAndEvalFile(self, filename):
1214
txt = f.read().replace('\r\n','\n')
1217
#------------------------- end cmt-001 - 08/06/2003 --------------------------
1219
def redrawvisible(self, win=None):
1221
if (not win) and self.control.GetPageCount() > 0:
1222
num, win = self.getNumWin()
1224
win.parent.Refresh()
1225
#----------------------------- File Menu Methods -----------------------------
1226
def getPositionAbsolute(self, path, newf=0):
1228
path = os.path.normcase(path)
1229
dn, fn = self.splitAbsolute(path)
1235
for i in xrange(self.control.GetPageCount()):
1236
win = self.control.GetPage(i).GetWindow1()
1238
if not win.dirname and v == win.NEWDOCUMENT:
1240
elif path == self.getAbsolute(win.filename, win.dirname):
1245
def selectAbsolute(self, path):
1246
if self.isAbsOpen(path):
1247
i = self.getPositionAbsolute(path)
1249
self.control.SetSelection(i)
1251
def isOpen(self, fn, dn):
1252
return dn and fn and (self.getAbsolute(fn, dn) in self.openfiles)
1253
def isAbsOpen(self, path):
1254
return path in self.openfiles
1256
def makeOpen(self, fn, dn):
1258
a = self.getAbsolute(fn, dn)
1259
self.openfiles[a] = self.splitAbsolute(a)
1260
self.realfn[a] = self.getAlmostAbsolute(fn, dn)
1262
def closeOpen(self, fn, dn):
1264
a = self.getAbsolute(fn, dn)
1265
del self.openfiles[a]
1268
def getAbsolute(self, fn, dn):
1269
return os.path.normcase(os.path.normpath(os.path.realpath(os.path.join(dn, fn))))
1270
def getAlmostAbsolute(self, fn, dn):
1271
return os.path.normpath(os.path.realpath(os.path.join(dn, fn)))
1272
def splitAbsolute(self, path):
1273
return os.path.split(os.path.normcase(path))
1276
self.newTab('', ' ', 1)
1277
self.control.GetPage(self.control.GetSelection()).GetWindow1().opened = 1
1280
wnum, win = self.getNumWin(e)
1283
ofn = os.path.join(win.dirname, win.filename)
1284
fil = open(ofn, 'wb')
1288
if UNICODE: a = "%s as %s"%(ofn, win.enc)
1290
win.mod = os.stat(ofn)[8]
1291
self.SetStatusText("Correctly saved %s"%a)
1292
self.curdocstates[ofn] = win.GetSaveState()
1293
self.curdocstates[ofn]['checksum'] = md5.new(txt).hexdigest()
1296
self.exceptDialog("Save Failed")
1301
def OnSaveAs(self,e):
1302
wnum, win = self.getNumWin(e)
1304
dlg = wxFileDialog(self, "Save file as...", os.getcwd(), "", "All files (*.*)|*.*", wxSAVE|wxOVERWRITE_PROMPT)
1305
rslt = dlg.ShowModal()
1307
fn=dlg.GetFilename()
1308
dn=dlg.GetDirectory()
1309
if sys.platform == 'win32' and dn[1:] == ':':
1312
pth = self.getAlmostAbsolute(fn, dn)
1313
dn, fn = os.path.split(pth)
1315
if win.filename != fn or win.dirname != dn:
1316
if self.isOpen(fn, dn):
1317
self.dialog("Another file with that name and path is already open.\nSave aborted to prevent data corruption.", "Save Aborted!")
1319
if self.isOpen(win.filename, win.dirname):
1320
self.closeOpen(win.filename, win.dirname)
1324
self.makeOpen(fn, dn)
1325
self.fileHistory.AddFileToHistory(pth)
1328
#fix the icons and names.
1329
self.dragger._RemoveItem(wnum)
1330
self.dragger._InsertItem(wnum, fn)
1335
self.control.SetPageImage(wnum, EXT_TO_IMG.get(extns.get(fn.split('.')[-1].lower(), 0), 0))
1336
self.control.SetSelection(wnum)
1340
def OnSaveAll(self, e):
1341
sel = self.control.GetSelection()
1342
cnt = self.control.GetPageCount()
1343
for i in xrange(cnt):
1344
self.control.SetSelection(i)
1350
self.control.SetSelection(sel)
1353
wd = self.config.get('lastpath', os.getcwd())
1354
dlg = wxFileDialog(self, "Choose a/some file(s)...", wd, "", wildcard, wxOPEN|wxMULTIPLE|wxHIDE_READONLY)
1355
if dlg.ShowModal() == wxID_OK:
1356
self.OnDrop(dlg.GetPaths())
1357
self.config['lp'] = dlg.GetDirectory()
1360
def FindModule(self, mod):
1361
fndmod = mod.split('.')
1364
pth[1:1] = [os.getcwd()]
1367
fdsc = imp.find_module(i, pth)
1368
if not (fdsc[0] is None):
1371
if fdsc[2][2] != imp.PY_SOURCE:
1372
return self.dialog("%s is not python source"%mod, "not correct format for editing")
1375
pth[1:1] = [fdsc[1]]
1378
#If we are outside the loop, this means that the current 'module'
1379
#that we are on is a folder-module. We can easily load the __init__.py
1381
return os.sep.join([pth[1], '__init__.py'])
1383
def OnOpenModule(self,e):
1384
dlg = wxTextEntryDialog(self, 'Enter the module name you would like to open', 'Open module...')
1385
if dlg.ShowModal() == wxID_OK:
1386
mod = dlg.GetValue()
1392
sys.path.extend(self.config['modulepaths'])
1394
self.OnDrop([self.FindModule(mod)])
1396
self.dialog("module %s not found"%mod, "not found")
1399
def OnOpenPrevDocs(self, e):
1400
if "lastopen" in self.config:
1401
self.OnDrop(self.config['lastopen'], 1)
1402
def AddSearchPath(self, e):
1403
dlg = wxDirDialog(self, "Choose a path", "", style=wxDD_DEFAULT_STYLE|wxDD_NEW_DIR_BUTTON)
1404
if dlg.ShowModal() == wxID_OK:
1405
path = os.path.normcase(os.path.normpath(dlg.GetPath()))
1406
if not (path in self.config['modulepaths']) and not (path in sys.path):
1407
self.config['modulepaths'].append(path)
1409
def newTab(self, d, fn, switch=0):
1410
if 'lastpath' in self.config:
1411
del self.config['lastpath']
1412
#ctrlwidth, ctrlh = self.control.GetSizeTuple()
1415
d, fn = os.path.split(self.getAlmostAbsolute(fn, d))
1416
FN = self.getAbsolute(fn, d)
1424
split = wxSplitterWindow(self.control, wxNewId(), style=wxSP_NOBORDER)
1425
split.SetMinimumPaneSize(0)
1426
EVT_SPLITTER_SASH_POS_CHANGING(self, split.GetId(), veto)
1428
ftype = extns.get(fn.split('.')[-1].lower(), 'python')
1429
if ftype in document_defaults:
1430
print "found filetype-specific defaults", ftype
1432
print "could not find", ftype
1433
state = dict(document_defaults.get(ftype, DOCUMENT_DEFAULTS))
1434
nwin = PythonSTC(self.control, wxNewId(), split)
1438
nwin.changeStyle(stylefile, self.style(fn))
1441
nwin.mod = os.stat(FN)[8]
1446
nwin.format = detectLineEndings(txt)
1449
#if FN in self.config['LASTOPEN']:
1450
# state = self.config['LASTOPEN'][FN]
1451
if FN in self.lastused:
1452
state.update(self.lastused[FN])
1453
## print "found saved state"
1454
del self.lastused[FN]
1462
if not ((d == '') and (fn == ' ')):
1463
self.fileHistory.AddFileToHistory(os.path.join(d, fn))
1465
if 'checksum' in state:
1466
if md5.new(txt).hexdigest() != state['checksum']:
1470
self.curdocstates[FN] = state
1472
nwin.SetSaveState(state)
1473
## nwin.SetSaveState({})
1478
globals()['NEWDOCUMENT'] += 1
1479
nwin.NEWDOCUMENT = NEWDOCUMENT
1480
fn = '<untitled %i>'%NEWDOCUMENT
1482
split.Initialize(nwin)
1484
self.control.AddPage(split, fn, switch)
1485
## self.OnRefresh(None, nwin)
1486
self.updateWindowTitle()
1489
def OnReload(self, e, win=None):
1491
num, win = self.getNumWin(e)
1493
dlg = wxMessageDialog(self, "%s was modified after last save.\nReloading from disk will destroy all changes.\n\nContinue anyway?"%win.filename, 'File was modified, data loss may occur!', wxYES_NO|wxCANCEL)
1495
if a == wxID_CANCEL:
1500
FN = self.getAbsolute(win.filename, win.dirname)
1501
fil = open(FN, 'rb')
1504
win.BeginUndoAction()
1507
win.mod = os.stat(FN)[8]
1510
self.curdocstates[FN] = {'checksum':md5.new(txt).hexdigest()}
1511
self.OnRefresh(None, win)
1513
self.dialog("Error encountered while trying to reload from disk.", "Reload failed")
1515
def sharedsave(self, win):
1518
nam = "<untitled %i>"%win.NEWDOCUMENT
1519
a = self.dialog("%s was modified after last save.\nSave changes before closing?"%nam,\
1520
"Save changes?", wxYES_NO|wxCANCEL)
1521
if a == wxID_CANCEL:
1529
def OnClose(self, e, wnum=None, win=None):
1530
if wnum is None or win is None:
1531
wnum, win = self.getNumWin(e)
1533
fn = self.getAbsolute(win.filename, win.dirname)
1536
for i, w in enumerate(self.control):
1538
self.control.SetSelection(i)
1540
saved = self.sharedsave(win)
1541
elif self.isOpen(win.filename, win.dirname):
1542
self.curdocstates[fn].update(win.GetSaveState())
1544
if self.isOpen(win.filename, win.dirname):
1545
self.lastused[fn] = self.curdocstates.pop(fn, {})
1546
self.closeOpen(win.filename, win.dirname)
1547
self.SetStatusText("Closed %s"%self.getAlmostAbsolute(win.filename, win.dirname))
1549
self.SetStatusText("Closed unnamed file without saving")
1550
self.control.DeletePage(wnum)
1551
self.updateWindowTitle()
1557
sel = self.control.GetSelection()
1558
cnt = self.control.GetPageCount()
1560
for i in xrange(cnt):
1561
win = self.control.GetPage(i).GetWindow1()
1564
self.control.SetSelection(i)
1565
self.sharedsave(win)
1568
try: return e.Veto()
1569
except: return e.Skip()
1573
for win in self.control:
1575
sav.append(self.getAlmostAbsolute(win.filename, win.dirname))
1576
LASTOPEN.append((self.getAbsolute(win.filename, win.dirname), win.GetSaveState()))
1579
if 'LASTOPEN' in self.config:
1580
del self.config['LASTOPEN']
1581
#saving document state
1582
self.config['lastopen'] = sav
1583
self.config['LASTUSED'] = self.lastused.items() + LASTOPEN
1584
self.config['LASTSIZE'] = self.GetSizeTuple()
1585
self.config['LASTPOSITION'] = self.GetPositionTuple()
1586
self.config['SASH1'] = self.BOTTOM.GetSizeTuple()[1]
1587
self.config['SASH2'] = self.RIGHT.GetSizeTuple()[0]
1590
self.control.SetSelection(sel)
1591
return self.Close(True)
1593
#--------------------------- cmt-001 - 08/06/2003 ----------------------------
1594
#------------- Open the file selected from the file history menu -------------
1595
def OnFileHistory(self, e):
1596
fileNum = e.GetId() - wxID_FILE1
1597
path = self.fileHistory.GetHistoryFile(fileNum)
1599
#------------------------- end cmt-001 - 08/06/2003 --------------------------
1601
#----------------------------- Edit Menu Methods -----------------------------
1602
def OneCmd(self, funct_name,evt):
1603
wnum, win = self.getNumWin(evt)
1604
getattr(win, funct_name)()
1606
def OnUndo(self, e):
1607
self.OneCmd('Undo',e)
1608
def OnRedo(self, e):
1609
self.OneCmd('Redo',e)
1610
def OnSelectAll(self, e):
1611
self.OneCmd('SelectAll',e)
1613
self.OneCmd('Cut',e)
1614
def OnCopy(self, e):
1615
self.OneCmd('Copy',e)
1616
def OnPaste(self, e):
1617
self.OneCmd('Paste',e)
1618
def OnDeleteSelection(self, e):
1619
self.OneCmd('DeleteSelection',e)
1620
def OnWrap(self, e):
1621
wnum, win = self.getNumWin(e)
1623
valu = self.getInt('Wrap to how many columns?', '', col_line)
1626
x,y = win.GetSelection()
1629
lnstart = win.LineFromPosition(x)
1630
lnend = win.LineFromPosition(y-1)
1634
for ln in xrange(lnstart, lnend+1):
1635
lin = win.GetLine(ln)
1638
paragraphs.append(win.format.join(textwrap.wrap(' '.join(lines), valu)))
1639
paragraphs.append(lin.rstrip('\r\n'))
1642
lines.append(lin.strip())
1644
paragraphs.append(win.format.join(textwrap.wrap(' '.join(lines), valu)))
1646
x = win.GetLineEndPosition(lnstart)-len(lines[0])
1647
y = win.GetLineEndPosition(lnend)
1648
#win.SetSelection(x, y)
1649
win.ReplaceSelection(win.format.join(paragraphs))
1651
def Dent(self, win, incr):
1652
x,y = win.GetSelection()
1654
lnstart = win.GetCurrentLine()
1657
a = win.GetLineIndentation(lnstart)%(abs(incr))
1660
pos = win.GetCurrentPos()
1661
col = win.GetColumn(pos)
1663
a = max(linestart+col+incr, linestart)
1665
lnstart = win.LineFromPosition(x)
1666
lnend = win.LineFromPosition(y-1)
1667
win.BeginUndoAction()
1668
for ln in xrange(lnstart, lnend+1):
1669
count = win.GetLineIndentation(ln)
1671
m += cmp(0, incr)*(m%incr)
1673
win.SetLineIndentation(ln, m)
1675
pos = pos + (m-count) - min(0, col + (m-count))
1676
win.SetSelection(pos, pos)
1680
p = win.GetLineEndPosition(lnstart-1) + len(win.format)
1681
win.SetSelection(p, win.GetLineEndPosition(lnend))
1684
def OnIndent(self, e):
1685
wnum, win = self.getNumWin(e)
1686
self.Dent(win, win.GetIndent())
1687
def OnDedent(self, e):
1688
wnum, win = self.getNumWin(e)
1689
self.Dent(win, -win.GetIndent())
1690
def OnInsertComment(self, e):
1691
wnum, win = self.getNumWin(e)
1692
dlg = wxTextEntryDialog(self, '', 'Enter a comment.', '')
1693
resp = dlg.ShowModal()
1694
valu = dlg.GetValue()
1700
st = '%s%s %s %s%s'%('#', b[:a/2], valu, b[a/2:], win.format)
1701
lin = win.GetCurrentLine()
1703
win.InsertText(win.GetLineEndPosition(lin-1)+len(win.format), st)
1705
win.InsertText(0, st)
1710
def OnCommentSelection(self, e):
1711
wnum, win = self.getNumWin(e)
1712
sel = win.GetSelection()
1713
start = win.LineFromPosition(sel[0])
1714
end = win.LineFromPosition(sel[1])
1715
if end > start and win.GetColumn(sel[1]) == 0:
1718
win.BeginUndoAction()
1719
for lineNumber in range(start, end + 1):
1720
firstChar = win.GetLineIndentPosition(lineNumber)
1721
lastChar = win.GetLineEndPosition(lineNumber)
1722
ranga = win.GetTextRange(firstChar,lastChar)
1723
if len(ranga.strip()) != 0:
1724
if win.GetLexer() == wxSTC_LEX_CPP:
1725
win.InsertText(firstChar, '// ')
1726
## elif win.GetLexer() in (wxSTC_LEX_HTML, wxSTC_LEX_XML):
1727
## win.InsertText(lastChar, ' -->')
1728
## win.InsertText(firstChar, '<!-- ')
1730
win.InsertText(firstChar, '## ')
1731
win.SetCurrentPos(win.PositionFromLine(start))
1732
win.SetAnchor(win.GetLineEndPosition(end))
1735
def OnUncommentSelection(self, e):
1736
wnum, win = self.getNumWin(e)
1737
sel = win.GetSelection()
1738
start = win.LineFromPosition(sel[0])
1739
end = win.LineFromPosition(sel[1])
1740
if end > start and win.GetColumn(sel[1]) == 0:
1743
win.BeginUndoAction()
1744
for lineNumber in range(start, end + 1):
1745
firstChar = win.GetLineIndentPosition(lineNumber)
1746
lastChar = win.GetLineEndPosition(lineNumber)
1747
texta = win.GetTextRange(firstChar,lastChar)
1750
if len(texta.strip()) != 0:
1751
if win.GetLexer() == wxSTC_LEX_CPP:
1752
if texta.startswith('// '):
1754
elif texta.startswith('//'):
1756
## elif win.GetLexer() in (wxSTC_LEX_HTML, wxSTC_LEX_XML):
1757
## if texta.startswith('<!-- '):
1759
## elif texta.startswith('<!--'):
1763
## if texta.endswith(' -->'):
1764
## rangeb = (lastChar-4, lastChar)
1765
## elif texta.endswith('-->'):
1766
## rangeb = (lastChar-3, lastChar)
1768
if texta.startswith('## '):
1770
elif texta.startswith('##'):
1772
elif texta.startswith('#'):
1776
win.SetSelection(*rangeb)
1777
win.ReplaceSelection("")
1779
win.SetSelection(firstChar,firstChar+lengtha)
1780
win.ReplaceSelection("")
1782
win.SetCurrentPos(win.PositionFromLine(start))
1783
win.SetAnchor(win.GetLineEndPosition(end))
1786
def OnTriggerExpansion(self, e):
1787
num, win = self.getNumWin(e)
1790
#----------------------- Find and Replace Bar Display ------------------------
1791
def getNumWin(self, e=None):
1792
num = self.control.GetSelection()
1794
return num, self.control.GetPage(num).GetWindow1()
1801
def OnShowFindbar(self, evt):
1802
num, win = self.getNumWin(evt)
1803
if win.parent.IsSplit() and not isinstance(win.parent.GetWindow2(), findbar.FindBar):
1804
win.parent.GetWindow2().close()
1806
if not win.parent.IsSplit():
1807
bar = findbar.FindBar(win.parent, self)
1808
win.parent.SplitHorizontally(win, bar, -(bar.GetBestSize())[1]-5)
1810
bar = win.parent.GetWindow2()
1811
focused = self.FindFocus()
1812
hasfocus = (focused == bar) or (focused and focused.GetParent() == bar)
1819
def OnShowReplacebar(self, evt):
1820
num, win = self.getNumWin(evt)
1821
if win.parent.IsSplit() and isinstance(win.parent.GetWindow2(), findbar.FindBar):
1822
win.parent.GetWindow2().close()
1823
if not win.parent.IsSplit():
1824
bar = findbar.ReplaceBar(win.parent, self)
1825
win.parent.SplitHorizontally(win, bar, -(bar.GetBestSize())[1]-5)
1829
def commonbar(self, win):
1830
st,end = win.GetSelection()
1831
box = win.parent.GetWindow2().box1
1832
if st == end and box.GetLastPosition() == 0:
1833
gcp = win.GetCurrentPos()
1834
st = win.WordStartPosition(gcp, 1)
1835
end = win.WordEndPosition(gcp, 1)
1837
x = win.GetTextRange(st, end)
1840
except UnicodeError:
1842
if not isinstance(x, unicode):
1843
rx = x.encode('string-escape')
1847
win.SetSelection(st, end)
1850
if isinstance(box, wxTextCtrl):
1851
box.SetSelection(0, box.GetLastPosition())
1853
box.SetMark(0, box.GetLastPosition())
1855
def OnFindAgain(self, evt):
1856
num, win = self.getNumWin(evt)
1857
if win.parent.IsSplit():
1858
win.parent.GetWindow2().OnFindN(evt)
1861
#----------------------------- View Menu Methods -----------------------------
1863
def Maximize(self, b):
1865
wxPostEvent(wxSizeEvent((0,0), self.GetId()))
1867
def OnZoom(self, e):
1868
wnum, win = self.getNumWin(e)
1869
if e.GetId() == ZI:incr = 1
1871
win.SetZoom(win.GetZoom()+incr)
1873
def OnGoto(self, e):
1875
wnum, win = self.getNumWin(e)
1876
valu = self.getInt('Which line would you like to advance to?', '', win.LineFromPosition(win.GetSelection()[0])+1)
1878
if valu < win.GetLineCount():
1879
linepos = win.GetLineEndPosition(valu)
1880
win.EnsureVisible(valu)
1881
win.SetSelection(linepos-len(win.GetLine(valu))+len(win.format), linepos)
1882
win.ScrollToColumn(0)
1884
def OnJumpF(self, e):
1885
num, win = self.getNumWin(e)
1888
def OnJumpB(self, e):
1889
num, win = self.getNumWin(e)
1892
def OnRefresh(self, e, win=None):
1894
num, win = self.getNumWin(e)
1895
self.OnDocumentChange(win, True)
1897
def OnToggleBookmark (self, e):
1898
wnum, win = self.getNumWin(e)
1899
lineNo = win.GetCurrentLine()
1900
if win.MarkerGet(lineNo) & BOOKMARKMASK:
1901
win.MarkerDelete(lineNo, BOOKMARKNUMBER)
1903
win.MarkerAdd(lineNo, BOOKMARKNUMBER)
1905
def OnNextBookmark (self, e):
1906
wnum, win = self.getNumWin(e)
1907
lineNo = win.GetCurrentLine()
1908
newLineNo = win.MarkerNext(lineNo + 1, BOOKMARKMASK)
1910
win.GotoLine(newLineNo)
1912
lineNo = win.GetLineCount()
1913
newLineNo = win.MarkerNext(0, BOOKMARKMASK)
1915
win.GotoLine(newLineNo)
1916
win.EnsureVisible(win.GetCurrentLine())
1917
win.EnsureCaretVisible()
1919
def OnPreviousBookmark (self, e):
1920
wnum, win = self.getNumWin(e)
1921
lineNo = win.GetCurrentLine()
1922
newLineNo = win.MarkerPrevious(lineNo - 1, BOOKMARKMASK)
1924
win.GotoLine(newLineNo)
1926
lineNo = win.GetLineCount()
1927
newLineNo = win.MarkerPrevious(lineNo, BOOKMARKMASK)
1929
win.GotoLine(newLineNo)
1930
win.EnsureVisible(win.GetCurrentLine())
1931
win.EnsureCaretVisible()
1933
def OnLeft(self, e):
1934
self.control.AdvanceSelection(False)
1936
def OnRight(self, e):
1937
self.control.AdvanceSelection(True)
1939
#--------------------------- Document Menu Methods ---------------------------
1941
def OnStyleChange(self,e):
1942
wnum, win = self.getNumWin(e)
1943
win.changeStyle(stylefile, lexers[e.GetId()])
1945
def style(self, fn):
1946
ext = fn.split('.')[-1].lower()
1947
return extns.get(ext, DEFAULTLEXER)
1949
def OnEncChange(self, e):
1950
num, win = self.getNumWin(e)
1952
newenc = self.menubar.GetLabel(mid)
1954
if oldenc != newenc:
1955
win.enc = newenc.strip()
1956
self.SetStatusText("encoding changed to %s for %s"%(win.enc,
1957
win.filename.strip() or self.control.GetPageText(num).strip(' *')))
1958
self.SetStatusText(win.enc, 2)
1960
def OnLineEndChange(self, e):
1961
n, win = self.getNumWin(e)
1963
newend = LE_MAPPING[endid]
1964
oldend = win.GetEOLMode()
1965
if oldend != newend:
1966
win.format = fmt_Rmode[newend]
1967
win.ConvertEOLs(newend)
1968
win.SetEOLMode(newend)
1970
def OnAutoCompleteToggle(self, event):
1971
# Images are specified with a appended "?type"
1972
#for i in range(len(kw)):
1973
# if kw[i] in keyword.kwlist:
1974
# kw[i] = kw[i]# + "?1"
1975
n, win = self.getNumWin(event)
1976
win.showautocomp = (win.showautocomp+1)%2
1978
def OnNumberToggle(self, e):
1979
n, win = self.getNumWin(e)
1980
win.SetMarginWidth(0, (win.GetMarginWidth(0)+40)%80)
1982
def OnMarginToggle(self, e):
1983
n, win = self.getNumWin(e)
1984
win.SetMarginWidth(1, (win.GetMarginWidth(1)+16)%32)
1986
def OnIndentGuideToggle(self, e):
1987
n, win = self.getNumWin(e)
1988
win.SetIndentationGuides((win.GetIndentationGuides()+1)%2)
1989
def OnSavePositionToggle(self, e):
1990
n, win = self.getNumWin(e)
1991
win.save_cursor = (1+win.save_cursor)%2
1993
def OnExpandAll(self, e):
1994
n, win = self.getNumWin(e)
1995
lc = win.GetLineCount()
1996
win.ShowLines(0, lc-1)
1997
for line in xrange(lc):
1998
if win.GetFoldLevel(line) & wxSTC_FOLDLEVELHEADERFLAG:
1999
win.SetFoldExpanded(line, 1)
2001
def OnFoldAll(self, e):
2002
n, win = self.getNumWin(e)
2003
#these next two lines are to allow
2004
#win.GetFoldLevel() to be accurate
2005
win.HideLines(0, win.GetLineCount()-1)
2009
#toss all the old folds
2012
lc = win.GetLineCount()
2014
for line in xrange(lc):
2015
if win.GetFoldLevel(line) & wxSTC_FOLDLEVELHEADERFLAG:
2019
a = win.GetLastChild(line, -1)
2020
win.HideLines(line+1,a)
2021
win.SetFoldExpanded(line, 0)
2023
def OnSetTabToggle(self, e):
2024
n, win = self.getNumWin(e)
2025
a = win.GetUseTabs()
2026
win.SetUseTabs((a+1)%2)
2027
win.SetProperty("tab.timmy.whinge.level", str(a))
2029
def OnWrapL(self, e):
2030
wnum, win = self.getNumWin(e)
2031
self.WrapToggle(win)
2033
def WrapToggle(self, win):
2034
#tossing the current home/end key configuration, as it will change
2035
win.CmdKeyClear(wxSTC_KEY_HOME,0)
2036
win.CmdKeyClear(wxSTC_KEY_HOME,wxSTC_SCMOD_SHIFT)
2037
win.CmdKeyClear(wxSTC_KEY_HOME,wxSTC_SCMOD_ALT)
2038
win.CmdKeyClear(wxSTC_KEY_HOME,wxSTC_SCMOD_ALT|wxSTC_SCMOD_SHIFT)
2039
win.CmdKeyClear(wxSTC_KEY_END,0)
2040
win.CmdKeyClear(wxSTC_KEY_END,wxSTC_SCMOD_SHIFT)
2041
win.CmdKeyClear(wxSTC_KEY_END,wxSTC_SCMOD_ALT)
2042
win.CmdKeyClear(wxSTC_KEY_END,wxSTC_SCMOD_ALT|wxSTC_SCMOD_SHIFT)
2044
if win.GetWrapMode() == wxSTC_WRAP_NONE:
2045
win.SetWrapMode(wxSTC_WRAP_WORD)
2047
#making home and end work like we expect them to when lines are wrapped
2048
win.CmdKeyAssign(wxSTC_KEY_HOME, 0, wxSTC_CMD_HOMEDISPLAY)
2049
win.CmdKeyAssign(wxSTC_KEY_HOME, wxSTC_SCMOD_SHIFT, wxSTC_CMD_HOMEDISPLAYEXTEND)
2050
win.CmdKeyAssign(wxSTC_KEY_HOME, wxSTC_SCMOD_ALT, wxSTC_CMD_VCHOME)
2051
win.CmdKeyAssign(wxSTC_KEY_HOME, wxSTC_SCMOD_ALT|wxSTC_SCMOD_SHIFT, wxSTC_CMD_VCHOMEEXTEND)
2052
win.CmdKeyAssign(wxSTC_KEY_END, 0, wxSTC_CMD_LINEENDDISPLAY)
2053
win.CmdKeyAssign(wxSTC_KEY_END, wxSTC_SCMOD_SHIFT, wxSTC_CMD_LINEENDDISPLAYEXTEND)
2054
win.CmdKeyAssign(wxSTC_KEY_END, wxSTC_SCMOD_ALT, wxSTC_CMD_LINEEND)
2055
win.CmdKeyAssign(wxSTC_KEY_END, wxSTC_SCMOD_ALT|wxSTC_SCMOD_SHIFT, wxSTC_CMD_LINEENDEXTEND)
2057
win.SetWrapMode(wxSTC_WRAP_NONE)
2059
#making home and end work like we expect them to when lines are not wrapped
2060
win.CmdKeyAssign(wxSTC_KEY_HOME, 0, wxSTC_CMD_VCHOME)
2061
win.CmdKeyAssign(wxSTC_KEY_HOME, wxSTC_SCMOD_SHIFT, wxSTC_CMD_VCHOMEEXTEND)
2062
win.CmdKeyAssign(wxSTC_KEY_HOME, wxSTC_SCMOD_ALT, wxSTC_CMD_HOMEDISPLAY)
2063
win.CmdKeyAssign(wxSTC_KEY_HOME, wxSTC_SCMOD_ALT|wxSTC_SCMOD_SHIFT, wxSTC_CMD_HOMEDISPLAYEXTEND)
2064
win.CmdKeyAssign(wxSTC_KEY_END, 0, wxSTC_CMD_LINEEND)
2065
win.CmdKeyAssign(wxSTC_KEY_END, wxSTC_SCMOD_SHIFT, wxSTC_CMD_LINEENDEXTEND)
2066
win.CmdKeyAssign(wxSTC_KEY_END, wxSTC_SCMOD_ALT, wxSTC_CMD_LINEENDDISPLAY)
2067
win.CmdKeyAssign(wxSTC_KEY_END, wxSTC_SCMOD_ALT|wxSTC_SCMOD_SHIFT, wxSTC_CMD_LINEENDDISPLAYEXTEND)
2069
def OnSetTriggers(self, e):
2070
num, win = self.getNumWin(e)
2072
a = TriggerDialog(self, win, win.triggers)
2075
def OnSetIndent(self, e):
2076
n, win = self.getNumWin(e)
2077
rslt = self.getInt("How many spaces per indent level?", "Enter an integer > 0.",
2081
def OnSetTabWidth(self, e):
2082
n, win = self.getNumWin(e)
2083
rslt = self.getInt("How many spaces per tab?",
2084
"How many spaces should a tab character,\n"\
2085
"'\\t' represent? Enter an integer > 0.",
2088
win.SetTabWidth(rslt)
2090
def OnSetLongLinePosition(self, e):
2091
n, win = self.getNumWin(e)
2092
rslt = self.getInt("Long Line Indicator",
2093
"At what column would you like a long line\n"\
2094
"signifier to be displayed? Enter an integer > 0.",
2095
win.GetEdgeColumn())
2097
win.SetEdgeColumn(rslt)
2099
def OnSetLongLineMode(self, e):
2100
n, win = self.getNumWin(e)
2102
win.SetEdgeMode(LL_MAPPING[eid])
2103
#--------------------------- Options Menu Methods ----------------------------
2105
def OnSaveLang(self, e):
2107
lang, desc = SOURCE_ID_TO_OPTIONS.get(mid, ('python', ''))
2108
n, win = self.getNumWin()
2109
dct = win.GetSaveState()
2112
document_defaults[lang].update(dct)
2113
self.SetStatusText("Updated document defaults for " + desc)
2115
def OnLoadSavedLang(self, e):
2117
lang, desc = SOURCE_ID_TO_OPTIONS2.get(mid, ('python', ''))
2118
n, win = self.getNumWin()
2119
dct = win.GetSaveState()
2120
dct.update(document_defaults[lang])
2121
s,e = win.GetSelection()
2122
win.SetSaveState(dct)
2123
win.SetSelection(s,e)
2124
self.control.updateChecks(win)
2125
self.SetStatusText("Updated document settings to %s for %s"%(desc, os.path.join(win.dirname, win.filename)))
2127
def OnDefaultStyleChange(self, e):
2128
dl = lexers[e.GetId()]
2129
self.config['DEFAULTLEXER'] = dl
2130
globals()['DEFAULTLEXER'] = dl
2132
def OnSaveSettings(self, e):
2134
n, win = self.getNumWin()
2135
dct = win.GetSaveState()
2139
globals().update(dct)
2140
self.config['DOCUMENT_DEFAULTS'] = dct
2142
def OnDNDToggle(self, e):
2144
dnd_file = (dnd_file + 1)%2
2146
def OnLogBarToggle(self, e):
2148
logbarlocn = (logbarlocn + 1)%2
2150
def OnDocBarToggle(self, e):
2152
docbarlocn = (docbarlocn + 1)%2
2154
def OnShowWideToggle(self, e):
2156
SHOWWIDE = (SHOWWIDE + 1)%2
2163
def OnShowTallToggle(self, e):
2165
SHOWTALL = (SHOWTALL + 1)%2
2172
def OnTodoToggle(self, e):
2174
TODOBOTTOM = (TODOBOTTOM + 1)%2
2176
def OnToolbarToggle(self, e):
2178
TOOLBAR = (TOOLBAR + 1)%2
2180
def OnCaret(self, e):
2183
caret_option, flags = CARET_ID_TO_OPTIONS[i]
2186
def OnCaretM(self, e):
2188
caret_slop = self.getInt("Set Caret M Value", "", caret_slop)
2191
def OnCaretN(self, e):
2192
global caret_multiplier
2193
caret_multiplier = self.getInt("Set Caret N Value", "", caret_multiplier)
2196
def SharedCaret(self):
2197
_, flags = CARET_OPTION_TO_ID[caret_option]
2198
for win in self.control:
2199
win.SetXCaretPolicy(flags, caret_slop*caret_multiplier)
2200
win.SetYCaretPolicy(flags, caret_slop)
2201
win.SetSelection(*win.GetSelection())
2203
def OnFinbarDefault(self, e):
2204
n, win = self.getNumWin()
2205
if win.GetParent().IsSplit():
2206
win.GetParent().GetWindow2().savePreferences()
2207
a = dict(win.findbarprefs)
2213
def OnFindbarClear(self, e):
2214
n, win = self.getNumWin()
2215
if win.GetParent().IsSplit():
2216
bar = win.GetParent().GetWindow2()
2218
bar.box1.SetValue("")
2219
if not isinstance(bar, findbar.FindBar):
2221
bar.box2.SetValue("")
2223
win.findbarprefs['replace'] = []
2225
win.findbarprefs['find'] = []
2226
win.findbarprefs['replace'] = []
2228
def OnFindbarHistory(self, e):
2229
global no_findbar_history
2230
no_findbar_history = (no_findbar_history + 1) % 2
2231
self.menubar.FindItemById(CLEAR_FINDBAR_HISTORY).Enable(not no_findbar_history)
2233
def OnChangeMenu(self, e):
2234
MenuItemDialog(self, self).ShowModal()
2236
def OnChangeTitle(self, e):
2239
title_option, _, _ = TITLE_ID_TO_OPTIONS[i]
2240
self.updateWindowTitle()
2242
#----------------------------- Help Menu Methods -----------------------------
2243
def OnAbout(self, e):
2245
You're wondering what this editor is all about, right? Easy, this edior was
2246
written to scratch an itch. I (Josiah Carlson), was looking for an editor
2247
that had the features I wanted, I couldn't find one. So I wrote one. And
2250
PyPE %s (Python Programmers Editor)
2251
http://come.to/josiah
2252
PyPE is copyright 2003-2005 Josiah Carlson.
2253
Contributions are copyright their respective authors.
2255
This software is licensed under the GPL (GNU General Public License) as it
2256
appears here: http://www.gnu.org/copyleft/gpl.html It is also included with
2257
this software as gpl.txt.
2259
If you do not also receive a copy of gpl.txt with your version of this
2260
software, please inform the me of the violation at the web page near the top
2261
of this document."""%VERSION
2262
self.dialog(txt.replace(' ', ''), "About...")
2264
def OnHelp(self, e):
2265
a = open(os.path.join(runpath, 'readme.txt'), 'rb')
2268
dlg = wxScrolledMessageDialog(self, txt, "Help!")
2271
#-------------------------- Hot Key support madness --------------------------
2272
def OnKeyPressed(self, event):
2275
keypressed = GetKeyPress(event)
2277
if showpress: print "keypressed", keypressed
2278
key = event.KeyCode()
2279
wnum = self.control.GetSelection()
2280
pagecount = self.control.GetPageCount()
2282
win = self.control.GetPage(wnum).GetWindow1()
2284
if keypressed in HOTKEY_TO_ID:
2285
menuid = HOTKEY_TO_ID[keypressed]
2286
wxPostEvent(self, wxMenuEvent(wxEVT_COMMAND_MENU_SELECTED, menuid))
2291
#when 'enter' is pressed, indentation needs to happen.
2293
#will indent the current line to be equivalent to the line above
2294
#unless a ':' is at the end of the previous, then will indent
2295
#configuration.indent more.
2296
if win.AutoCompActive():
2297
return win.AutoCompComplete()
2298
if win.CallTipActive():
2301
#get information about the current cursor position
2302
linenum = win.GetCurrentLine()
2303
pos = win.GetCurrentPos()
2304
col = win.GetColumn(pos)
2305
linestart = win.PositionFromLine(linenum)
2306
line = win.GetLine(linenum)[:pos-linestart]
2308
#get info about the current line's indentation
2309
ind = win.GetLineIndentation(linenum)
2313
lang = extns.get(win.filename.split('.')[-1].lower(), DEFAULTLEXER)
2317
if win.GetUseTabs():
2318
win.ReplaceSelection(win.format+(col*' ').replace(win.GetTabWidth()*' ', '\t'))
2320
win.ReplaceSelection(win.format+(col*' '))
2323
win.ReplaceSelection(win.format)
2326
## print "indent on return for cpp"
2327
dmap = {'{':1, '}':-1}
2329
xtra += dmap.get(ch, 0)
2331
if line.split()[:1] == ['return']:
2334
#insert other indentation per language here.
2336
else: #if language is python
2337
print "indent on return for python"
2340
if (line.find(':')>-1):
2341
for i in xrange(linestart, min(pos, win.GetTextLength())):
2342
styl = win.GetStyleAt(i)
2343
#print styl, win.GetCharAt(i)
2345
if (styl==10) and (win.GetCharAt(i) == colon):
2348
#it is a comment, ignore the character
2350
elif (styl == 0) and (win.GetCharAt(i) in [ord(i) for i in ' \t\r\n']):
2351
#is not a comment, but is the space before a comment
2352
#or the end of a line, ignore the character
2355
#this is not a comment or some innocuous other character
2356
#this is a docstring or otherwise, no additional indent
2358
#commenting the break fixes stuff like this
2362
#This deals with ending single and multi-line definitions properly.
2365
for i in ['def', 'class', 'if', 'else', 'elif', 'while',
2366
'for', 'try', 'except', 'finally']:
2371
if found: found = min(found)
2373
if (found > -1) and\
2374
(win.GetStyleAt(win.GetLineEndPosition(linenum)-len(line)+found)==5) and\
2375
(win.GetLineIndentation(linenum) == found):
2376
ind = win.GetLineIndentation(linenum)
2379
line = win.GetLine(linenum)
2380
#if we were to do indentation for ()[]{}, it would be here
2385
if (line.find(i) > -1):
2390
#print "finding stuff"
2396
if win.GetStyleAt(start+linestart-1)==10:
2397
seq.append((start, i))
2398
a = line[start:].find(i)
2400
cl = {')':'(', ']': '[', '}': '{',
2401
'(':'', '[': '', '{': ''}
2403
#print "making tree"
2408
stk.append((po, ch))
2410
if cl[ch] == stk[-1][1]:
2411
#proper closing of something
2414
#probably a syntax error
2415
#does it matter what is done?
2419
#Probably closing something on another line, should probably find
2420
#the indent level of the opening, but that looks to be a hard
2421
#problem, and multiple lines would need to be checked for the
2422
#location of the closing item.
2423
#This would require an incremental line-by-line stepping back.
2424
#Almost like what was done for ['def', 'class', 'if', 'while', 'for']
2425
#and ':'. However, there is no guarantee that there is a proper
2426
#start, and we could end up parsing the entire file...a few times
2427
#over. Incremental backwards things end up doing worst case
2428
#O(n^2) line parsings.
2430
#People can use the improved single-line dedent with crtl+[.
2434
#print "stack remaining", stk
2438
if (ls[:6] == 'return') or (ls[:4] == 'pass'):
2443
if win.GetUseTabs():
2444
a = a.replace(win.GetTabWidth()*' ', '\t')
2445
win.ReplaceSelection(win.format+a)
2447
for i in xrange(xtra):
2448
self.OnIndent(event)
2450
for i in xrange(-xtra):
2451
self.OnDedent(event)
2454
if not (win.GetStyleAt(win.GetCurrentPos())):
2456
if win.CallTipActive():
2457
good = STRINGPRINTABLE
2458
if (key in good) or (key in (WXK_SHIFT, WXK_CONTROL, WXK_ALT)):
2460
#if key in (48, 57) and event.ShiftDown():
2461
# win.CallTipCancel()
2462
#else it is something in the arguments that is OK.
2465
if (not win.CallTipActive()) and event.ShiftDown() and (key == ord('9')):
2466
win.CallTipSetBackground(wxColour(255, 255, 232))
2467
cur, colpos, word = self.getLeftFunct(win)
2468
tip = '\n'.join(win.tooltips.get(word, []))
2470
win.CallTipShow(win.GetCurrentPos(),tip)
2471
elif win.showautocomp and bool(win.kw) and (not win.AutoCompActive()) and (ord('A') <= key) and (key <= ord('Z')):
2472
#if win.CallTipActive():
2473
# win.CallTipCancel()
2474
cur, colpos, word = self.getLeftFunct(win)
2475
indx = win.kw.find(word)
2476
if (not word) or ((indx > -1) and ((win.kw[indx-1] == ' ') or (indx==0))):
2477
win.AutoCompSetIgnoreCase(False)
2478
win.AutoCompShow(colpos-cur, win.kw)
2482
def getLeftFunct(self, win):
2483
t = ' .,;:([)]}\'"\\<>%^&+-=*/|`'
2484
bad = dict(zip(t, [0]*len(t)))
2485
line = win.GetLine(win.GetCurrentLine())
2486
colpos = win.GetColumn(win.GetCurrentPos())
2488
while (cur >= 0) and not (line[cur:cur+1] in bad):
2491
return cur, colpos, line[cur:colpos]
2493
#------------- Ahh, Styled Text Control, you make this possible. -------------
2494
class PythonSTC(wxStyledTextCtrl):
2495
def __init__(self, notebook, ID, parent):
2496
wxStyledTextCtrl.__init__(self, parent, ID)#, style = wxNO_FULL_REPAINT_ON_RESIZE)
2497
self.SetEndAtLastLine(False)
2499
self.MarkerDefine(BOOKMARKNUMBER, BOOKMARKSYMBOL, 'blue', 'blue')
2501
_, flags = CARET_OPTION_TO_ID[caret_option]
2502
self.SetXCaretPolicy(flags, caret_slop*caret_multiplier)
2503
self.SetYCaretPolicy(flags, caret_slop)
2505
self.tree1 = hierCodeTreePanel(notebook.root, notebook.root.leftt)
2507
self.tree1.tree.SORTTREE = 0
2508
self.tree1.parent.sizer.Layout()
2509
self.tree2 = hierCodeTreePanel(notebook.root, notebook.root.rightt)
2511
self.tree2.tree.SORTTREE = 1
2512
self.tree1.parent.sizer.Layout()
2518
self.parent = parent
2519
self.notebook = notebook #should also be equal to self.parent.parent
2520
self.root = self.notebook.root
2524
#Text is included in the original, but who drags text? Below for dnd file support.
2525
if dnd_file: self.SetDropTarget(FileDropTarget(self.root))
2527
#for command comlpetion
2528
self.SetKeyWords(0, " ".join(keyword.kwlist))
2530
self.SetMargins(0,0)
2531
self.SetViewWhiteSpace(False)
2532
self.SetBackSpaceUnIndents(1)
2533
#self.SetBufferedDraw(False)
2534
#self.SetViewEOL(True)
2536
self.SetMarginType(0, wxSTC_MARGIN_NUMBER)
2537
#self.StyleSetSpec(wxSTC_STYLE_LINENUMBER, "size:%(size)d,face:%(mono)s" % faces)
2539
# Setup a margin to hold fold markers
2540
#I agree, what is this value?
2541
#self.SetFoldFlags(16) ### WHAT IS THIS VALUE? WHAT ARE THE OTHER FLAGS? DOES IT MATTER?
2543
self.SetProperty("fold", "1")
2544
self.SetMarginType(2, wxSTC_MARGIN_SYMBOL)
2545
self.SetMarginMask(2, wxSTC_MASK_FOLDERS)
2546
self.SetMarginSensitive(2, True)
2547
self.SetMarginWidth(2, 12)
2549
if collapse_style: # simple folder marks, like the old version
2550
self.MarkerDefine(wxSTC_MARKNUM_FOLDER, wxSTC_MARK_BOXPLUS, "navy", "white")
2551
self.MarkerDefine(wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_BOXMINUS, "navy", "white")
2552
# Set these to an invisible mark
2553
self.MarkerDefine(wxSTC_MARKNUM_FOLDEROPENMID, wxSTC_MARK_BACKGROUND, "white", "black")
2554
self.MarkerDefine(wxSTC_MARKNUM_FOLDERMIDTAIL, wxSTC_MARK_BACKGROUND, "white", "black")
2555
self.MarkerDefine(wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_BACKGROUND, "white", "black")
2556
self.MarkerDefine(wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_BACKGROUND, "white", "black")
2558
else: # more involved "outlining" folder marks
2559
self.MarkerDefine(wxSTC_MARKNUM_FOLDEREND, wxSTC_MARK_BOXPLUSCONNECTED, "white", "black")
2560
self.MarkerDefine(wxSTC_MARKNUM_FOLDEROPENMID, wxSTC_MARK_BOXMINUSCONNECTED, "white", "black")
2561
self.MarkerDefine(wxSTC_MARKNUM_FOLDERMIDTAIL, wxSTC_MARK_TCORNER, "white", "black")
2562
self.MarkerDefine(wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_LCORNER, "white", "black")
2563
self.MarkerDefine(wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_VLINE, "white", "black")
2564
self.MarkerDefine(wxSTC_MARKNUM_FOLDER, wxSTC_MARK_BOXPLUS, "white", "black")
2565
self.MarkerDefine(wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_BOXMINUS, "white", "black")
2568
# Make some styles, The lexer defines what each style is used for, we
2569
# just have to define what each style looks like. This set is adapted from
2570
# Scintilla sample property files.
2572
#And good wxPython users who have seen some demos know the above was copied
2573
#and pasted, along with a lot of sample code, right out of the demo. The
2576
# Global default styles for all languages
2577
self.StyleSetSpec(wxSTC_STYLE_DEFAULT, "fore:#000000,face:%(mono)s,back:#FFFFFF,size:%(size)d" % faces)
2578
self.StyleSetSpec(wxSTC_STYLE_LINENUMBER, "back:#C0C0C0,face:Lucida Console,size:%(size2)d" % faces)
2579
self.StyleSetSpec(wxSTC_STYLE_CONTROLCHAR, "face:%(other)s" % faces)
2580
self.StyleSetSpec(wxSTC_STYLE_BRACELIGHT, "fore:#003000,face:%(mono)s,back:#80E0E0"% faces)
2581
self.StyleSetSpec(wxSTC_STYLE_BRACEBAD, "fore:#E0FFE0,face:%(mono)s,back:#FF0000"% faces)
2584
self.SetSelBackground(1, '#B0B0FF')
2586
#again, some state variables
2590
self.AutoCompStops(' .,;:()[]{}\'"\\<>%^&+-=*/|`')
2592
EVT_STC_UPDATEUI(self, ID, self.OnUpdateUI)
2593
EVT_STC_MARGINCLICK(self, ID, self.OnMarginClick)
2594
EVT_KEY_DOWN(self, self.root.OnKeyPressed)
2595
#EVT_CHAR(self, self.root.OnKeyPressed)
2596
EVT_KEY_UP(self, self.key_up)
2598
EVT_STC_CHARADDED(self, ID, self.added)
2599
EVT_STC_CHANGE(self, ID, self.cha)
2600
#unavailable in 2.5.1.2, didn't work in previous versions of wxPython
2601
# EVT_STC_POSCHANGED(self, ID, self.pos)
2602
EVT_STC_SAVEPOINTREACHED(self, ID, self.MakeClean)
2603
EVT_STC_SAVEPOINTLEFT(self, ID, self.MakeDirty)
2604
self.SetModEventMask(wxSTC_MOD_INSERTTEXT|wxSTC_MOD_DELETETEXT|wxSTC_PERFORMED_USER|wxSTC_PERFORMED_UNDO|wxSTC_PERFORMED_REDO)
2607
self.CmdKeyClear(ord('T'), wxSTC_SCMOD_CTRL)
2609
self.CmdKeyClear(ord('Z'), wxSTC_SCMOD_CTRL)
2610
self.CmdKeyClear(ord('Y'), wxSTC_SCMOD_CTRL)
2611
self.CmdKeyClear(ord('X'), wxSTC_SCMOD_CTRL)
2612
self.CmdKeyClear(ord('C'), wxSTC_SCMOD_CTRL)
2613
self.CmdKeyClear(ord('V'), wxSTC_SCMOD_CTRL)
2614
self.CmdKeyClear(ord('A'), wxSTC_SCMOD_CTRL)
2617
#print "position changed event"
2618
#for some reason I never get called
2622
#print "changed event"
2626
#print "save reached"
2633
def key_up(self, e):
2634
if self.GetModify(): self.MakeDirty()
2635
else: self.MakeClean()
2639
def pos_ch(self, e):
2640
lin = self.GetCurrentLine()+1
2641
col = self.GetColumn(self.GetCurrentPos())
2642
self.root.SetStatusText("L%i C%i"%(lin, col), 1)
2651
gcp = self.GetCurrentPos()
2652
for p in xrange(gcp-1, -1, -1):
2653
if not full and p < gcp-1:
2655
ch = self.GetCharAt(p)
2657
ch = (chr((ch>>8)&255)+chr(ch&255)).decode('utf-16-be')
2661
tr = tr.get(ch, None)
2663
## print "ran off of triggers!", ch, gcp-p-1
2665
elif type(tr) is tuple:
2666
self.SetSelection(p, p+c)
2667
self.ReplaceSelection(tr[0])
2669
self.SetSelection(p,p)
2670
self.InsertText(p, tr[1])
2675
def jump(self, direction):
2676
#1 forward, -1 backward
2677
if direction not in (1,-1):
2681
chars2, chars3 = '({[:,\'"', ')}]\'"'
2682
if self.GetLexer() in (wxSTC_LEX_HTML, wxSTC_LEX_XML):
2683
chars2 = chars2 + '>'
2684
chars3 = chars3 + '<'
2685
#chars2 are things that we want to be to the right of
2686
#chars3 are things that we want to be to the left of
2687
chars1 = chars2 + chars3
2689
#cursor position information
2690
linenum = self.GetCurrentLine()
2691
pos = self.GetCurrentPos()
2695
it = xrange(pos, self.GetTextLength())
2697
it = xrange(pos-1, -1, -1)
2699
#updates information cross-lines
2701
ch = self.GetTextRange(p, p+1)
2702
if ch not in chars1:
2705
if direction == 1: #if we are heading to the right
2706
#if we want to be to the right of line[p], make it so
2710
#else if this character is just to the right of where we are at, skip it
2713
#else if we want to be to the left of line[p], make it so
2716
else: #else we are heading to the left
2717
#if we want to be to the left of line[p], make it so
2720
#else if this character is just to the left of where we are at, skip it
2723
#else if we want to be to the right of line[p], make it so
2730
self.SetSelection(p, p)
2732
#------------------------- persistant document state -------------------------
2733
def GetSaveState(self):
2736
if self.GetParent().IsSplit():
2737
self.GetParent().GetWindow2().savePreferences()
2740
'use_tabs':self.GetUseTabs(),
2741
'spaces_per_tab':self.GetTabWidth(),
2742
'indent':self.GetIndent(),
2743
'marker_margin':bool(self.GetMarginWidth(1)),
2744
'line_margin':bool(self.GetMarginWidth(0)),
2745
'col_line':self.GetEdgeColumn(),
2746
'col_mode':self.GetEdgeMode(),
2747
'indent_guide':self.GetIndentationGuides(),
2748
'showautocomp':self.showautocomp,
2749
'wrapmode':self.GetWrapMode(),
2750
## 'sortmode':self.tree.tree.SORTTREE,
2751
'save_cursor':self.save_cursor,
2752
'cursor_posn':self.GetCurrentPos(),
2753
'findbarprefs':self.findbarprefs,
2754
'triggers':self.triggers,
2756
for line in xrange(self.GetLineCount()):
2757
if self.MarkerGet(line) & BOOKMARKMASK:
2760
if (self.GetFoldLevel(line) & wxSTC_FOLDLEVELHEADERFLAG) and\
2761
(not self.GetFoldExpanded(line)):
2766
def SetSaveState(self, saved):
2767
self.SetUseTabs(saved['use_tabs'])
2768
self.SetProperty("tab.timmy.whinge.level", "10"[bool(saved['use_tabs'])])
2769
self.SetTabWidth(saved['spaces_per_tab'])
2770
self.SetIndent(saved['indent'])
2771
self.SetMarginWidth(0, 40*saved['line_margin'])
2772
self.SetMarginWidth(1, 16*saved['marker_margin'])
2773
self.SetEdgeColumn(saved['col_line'])
2774
self.SetEdgeMode(saved['col_mode'])
2775
self.SetIndentationGuides(saved['indent_guide'])
2776
self.showautocomp = saved['showautocomp']
2777
self.findbarprefs = dict(saved.get('findbarprefs', {}))
2778
self.triggers = dict(saved['triggers'])
2779
if self.GetWrapMode() != saved['wrapmode']:
2780
self.root.WrapToggle(self)
2781
## self.tree.tree.SORTTREE = saved.get('sortmode', sortmode)
2782
self.save_cursor = saved['save_cursor']
2783
for bml in saved.get('BM', []):
2784
self.MarkerAdd(bml, BOOKMARKNUMBER)
2785
for exl in saved.get('FOLD', []):
2786
a = self.GetLastChild(exl, -1)
2787
self.HideLines(exl+1,a)
2788
self.SetFoldExpanded(exl, 0)
2793
if self.save_cursor:
2794
a = saved.get('cursor_posn', 0)
2795
self.SetSelection(a,a)
2796
self.EnsureCaretVisible()
2797
self.ScrollToColumn(0)
2799
#-------------------- fix for SetText for the 'dirty bit' --------------------
2800
def SetText(self, txt, emptyundo=1):
2801
self.SetEOLMode(fmt_mode[self.format])
2804
for bom, enc in BOM:
2805
if txt[:len(bom)] == bom:
2807
txt = txt[len(bom):]
2810
if self.enc != 'ascii':
2811
try: txt = txt.decode(self.enc)
2813
#print "failed text decoding"
2814
self.root.dialog("There has been a unicode decoding error."
2815
"The cause of this error is unknown to PyPE."
2816
"To prevent loss or corruption of data, it"
2817
"is suggested that you close the document,"
2818
"do not save. Then try to open the document"
2819
"with the application you originally created"
2820
"it with. If PyPE was the original creator,"
2821
"and only editor of the document, please"
2822
"contact the author and submit a bug report.",
2823
"Unicode decoding error.")
2825
wxStyledTextCtrl.SetText(self, txt)
2826
self.ConvertEOLs(fmt_mode[self.format])
2829
self.EmptyUndoBuffer()
2833
self.ConvertEOLs(fmt_mode[self.format])
2835
if self.enc == 'ascii':
2837
return wxStyledTextCtrl.GetText(self).encode(self.enc)
2839
#Previously non-unicode ascii file has had unicode characters
2840
#inserted. Must encode into some sort of unicode format.
2842
self.root.SetStatusText(self.enc, 2)
2843
return ADDBOM[self.enc] + wxStyledTextCtrl.GetText(self).encode(self.enc)
2844
return wxStyledTextCtrl.GetText(self)
2846
#----- Takes care of the little '*' modified next to the open file name ------
2847
def MakeDirty(self, e=None):
2848
if (not self.dirty) and self.opened:
2852
f = '<untitled %i>'%self.NEWDOCUMENT
2854
for i in self.notebook:
2858
self.notebook.SetPageText(c, '* '+f)
2859
self.root.redrawvisible(self)
2863
def MakeClean(self, e=None):
2868
f = '<untitled %i>'%self.NEWDOCUMENT
2870
for i in self.notebook:
2874
self.notebook.SetPageText(c, f)
2876
self.root.redrawvisible(self)
2884
def do(self, funct, dirty=1):
2885
if dirty: self.MakeDirty(None)
2887
self.root.redrawvisible(self)
2889
def Cut(self): self.do(wxStyledTextCtrl.Cut)
2890
def Paste(self): self.do(wxStyledTextCtrl.Paste)
2891
def DeleteSelection(self): self.do(wxStyledTextCtrl.DeleteBack)
2892
def Undo(self): self.do(wxStyledTextCtrl.Undo)
2893
def Redo(self): self.do(wxStyledTextCtrl.Redo)
2895
#--------- Ahh, the style change code...isn't it great? Not really. ---------
2896
def changeStyle(self, stylefile, language):
2898
#from StyleSupport import initSTC
2899
from STCStyleEditor import initSTC
2900
initSTC(self, stylefile, language)
2903
#self.root.exceptDialog("Style Change failed, assuming plain text")
2904
self.root.SetStatusText("Style Change failed, assuming plain text")
2906
#----------------- Defaults, in case the other code was bad. -----------------
2907
#for some default font styles
2909
self.SetLexer(wxSTC_LEX_NULL)
2914
##self.StyleSetSpec(wxSTC_P_DEFAULT, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
2916
##self.StyleSetSpec(wxSTC_P_COMMENTLINE, "fore:#007F00,face:%(mono)s,back:#E0FFE0,size:%(size)d" % faces)
2918
##self.StyleSetSpec(wxSTC_P_NUMBER, "fore:#007F7F,face:%(times)s,size:%(size)d" % faces)
2920
##self.StyleSetSpec(wxSTC_P_STRING, "fore:#7F007F,face:%(times)s,size:%(size)d" % faces)
2921
### Single quoted string
2922
##self.StyleSetSpec(wxSTC_P_CHARACTER, "fore:#7F007F,face:%(times)s,size:%(size)d" % faces)
2924
##self.StyleSetSpec(wxSTC_P_WORD, "fore:#F0B000,face:%(mono)s,size:%(size)d,bold" % faces)
2926
##self.StyleSetSpec(wxSTC_P_TRIPLE, "fore:#603000,face:%(times)s,back:#FFFFE0,size:%(size)d" % faces)
2927
### Triple double quotes
2928
##self.StyleSetSpec(wxSTC_P_TRIPLEDOUBLE, "fore:#603000,face:%(times)s,back:#FFFFE0,size:%(size)d" % faces)
2929
### Class name definition
2930
##self.StyleSetSpec(wxSTC_P_CLASSNAME, "fore:#0000FF,face:%(times)s,size:%(size)d,bold" % faces)
2931
### Function or method name definition
2932
##self.StyleSetSpec(wxSTC_P_DEFNAME, "fore:#0000FF,face:%(times)s,size:%(size)d,bold" % faces)
2934
##self.StyleSetSpec(wxSTC_P_OPERATOR, "face:%(times)s,size:%(size)d" % faces)
2936
##self.StyleSetSpec(wxSTC_P_IDENTIFIER, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
2938
##self.StyleSetSpec(wxSTC_P_COMMENTBLOCK, "fore:#7F7F7F,face:%(times)s,size:%(size)d" % faces)
2939
### End of line where string is not closed
2940
##self.StyleSetSpec(wxSTC_P_STRINGEOL, "fore:#000000,face:%(mono)s,back:#E0C0E0,eol,size:%(size)d" % faces)
2942
##self.SetCaretForeground("BLACK")
2944
### prototype for registering some images for use in the AutoComplete box.
2945
###self.RegisterImage(1, images.getSmilesBitmap())
2947
if self.filename.lower().split('.')[-1:] in (['pyx'], ['pyi']):
2949
self.SetKeyWords(0, ' '.join(keyword.kwlist) + ' struct union enum extern include ctypedef cdef char short int long float double unsigned')
2951
#------------ copied and pasted from the wxStyledTextCtrl_2 demo -------------
2952
def OnUpdateUI(self, evt):
2953
# check for matching braces
2957
caretPos = self.GetCurrentPos()
2959
charBefore = self.GetCharAt(caretPos - 1)
2960
styleBefore = self.GetStyleAt(caretPos - 1)
2963
if charBefore and chr(charBefore) in "[]{}()" and styleBefore == wxSTC_P_OPERATOR:
2964
braceAtCaret = caretPos - 1
2967
if braceAtCaret < 0:
2968
charAfter = self.GetCharAt(caretPos)
2969
styleAfter = self.GetStyleAt(caretPos)
2970
if charAfter and chr(charAfter) in "[]{}()" and styleAfter == wxSTC_P_OPERATOR:
2971
braceAtCaret = caretPos
2973
if braceAtCaret >= 0:
2974
braceOpposite = self.BraceMatch(braceAtCaret)
2976
if braceAtCaret != -1 and braceOpposite == -1:
2977
self.BraceBadLight(braceAtCaret)
2979
self.BraceHighlight(braceAtCaret, braceOpposite)
2980
#pt = self.PointFromPosition(braceOpposite)
2981
#self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
2983
#self.Refresh(False)
2985
def OnMarginClick(self, evt):
2986
# fold and unfold as needed
2987
if evt.GetMargin() == 2:
2988
lineClicked = self.LineFromPosition(evt.GetPosition())
2989
if self.GetFoldLevel(lineClicked) & wxSTC_FOLDLEVELHEADERFLAG:
2991
self.SetFoldExpanded(lineClicked, True)
2992
self.Expand(lineClicked, True, True, 1)
2993
elif evt.GetControl():
2994
if self.GetFoldExpanded(lineClicked):
2995
self.SetFoldExpanded(lineClicked, False)
2996
self.Expand(lineClicked, False, True, 0)
2998
self.SetFoldExpanded(lineClicked, True)
2999
self.Expand(lineClicked, True, True, 100)
3001
self.ToggleFold(lineClicked)
3004
lineCount = self.GetLineCount()
3007
# find out if we are folding or unfolding
3008
for lineNum in range(lineCount):
3009
if self.GetFoldLevel(lineNum) & wxSTC_FOLDLEVELHEADERFLAG:
3010
expanding = not self.GetFoldExpanded(lineNum)
3014
while lineNum < lineCount:
3015
level = self.GetFoldLevel(lineNum)
3016
if level & wxSTC_FOLDLEVELHEADERFLAG and \
3017
(level & wxSTC_FOLDLEVELNUMBERMASK) == wxSTC_FOLDLEVELBASE:
3020
self.SetFoldExpanded(lineNum, True)
3021
lineNum = self.Expand(lineNum, True)
3022
lineNum = lineNum - 1
3024
lastChild = self.GetLastChild(lineNum, -1)
3025
self.SetFoldExpanded(lineNum, False)
3026
if lastChild > lineNum:
3027
self.HideLines(lineNum+1, lastChild)
3029
lineNum = lineNum + 1
3031
def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
3032
lastChild = self.GetLastChild(line, level)
3034
while line <= lastChild:
3037
self.ShowLines(line, line)
3039
self.HideLines(line, line)
3042
self.ShowLines(line, line)
3045
level = self.GetFoldLevel(line)
3047
if level & wxSTC_FOLDLEVELHEADERFLAG:
3050
self.SetFoldExpanded(line, True)
3052
self.SetFoldExpanded(line, False)
3053
line = self.Expand(line, doExpand, force, visLevels-1)
3056
if doExpand and self.GetFoldExpanded(line):
3057
line = self.Expand(line, True, force, visLevels-1)
3059
line = self.Expand(line, False, force, visLevels-1)
3065
#-------------- end of copied code from wxStyledTextCtrl_2 demo --------------
3066
#(really I copied alot more, but that part I didn't modify at all, I
3067
#wanted to understand it, but it just worked, so there was no need)
3069
#------------------------- Ahh, the tabbed notebook --------------------------
3070
class MyNB(wxNotebook):
3071
def __init__(self, root, id, parent):
3072
#the left-tab, while being nice, turns the text sideways, ick.
3073
wxNotebook.__init__(self, parent, id, style=
3081
self.AssignImageList(IMGLIST2)
3083
#for some reason, the notebook needs the next line...the text control
3085
EVT_KEY_DOWN(self, self.root.OnKeyPressed)
3086
EVT_NOTEBOOK_PAGE_CHANGED(self, self.GetId(), self.OnPageChanged)
3087
self.SetDropTarget(FileDropTarget(self.root))
3091
count = self.GetPageCount()
3094
r = self.GetPage(cur).GetWindow1()
3098
def OnPageChanged(self, event):
3105
old = event.GetOldSelection()
3106
new = event.GetSelection()
3108
owin = self.GetPage(old).GetWindow1()
3112
self.root.dragger._SelectItem(new)
3113
win = self.GetPage(new).GetWindow1()
3114
#fix for dealing with current paths. They are wonderful.
3117
os.chdir(win.dirname)
3120
self.updateChecks(win)
3121
#width = self.GetClientSize()[0]
3123
#if win.GetWrapMode() == wxSTC_WRAP_NONE:
3124
# self.parent.SetStatusText("", 1)
3126
# self.parent.SetStatusText("WRAP",1)
3127
self.root.OnDocumentChange(win, None)
3131
_, flags = CARET_OPTION_TO_ID[caret_option]
3132
win.SetXCaretPolicy(flags, caret_slop*caret_multiplier)
3133
win.SetYCaretPolicy(flags, caret_slop)
3135
self.root.timer.Start(10, wxTIMER_ONE_SHOT)
3142
def updateChecks(self, win):
3144
self.root.SetStatusText(win.enc, 2)
3145
if self.root.HAS_RADIO:
3146
self.root.menubar.Check(ENCODINGS[win.enc], 1)
3147
if self.root.HAS_RADIO:
3148
self.root.menubar.Check(lexers2[win.GetLexer()], 1)
3149
self.root.menubar.Check(LL_RMAPPING[win.GetEdgeMode()], 1)
3150
for m,cid in ((0, NUM), (1, MARGIN)):
3151
self.root.menubar.Check(cid, bool(win.GetMarginWidth(m)))
3152
self.root.menubar.Check(INDENTGUIDE, win.GetIndentationGuides())
3153
self.root.menubar.Check(USETABS, win.GetUseTabs())
3154
self.root.menubar.Check(AUTO, win.showautocomp)
3155
self.root.menubar.Check(WRAPL, win.GetWrapMode() != wxSTC_WRAP_NONE)
3156
## self.root.menubar.Check(SORTBY, win.tree.tree.SORTTREE)
3157
self.root.menubar.Check(LE_RMAPPING[win.GetEOLMode()], 1)
3158
self.root.menubar.Check(SAVE_CURSOR, win.save_cursor)
3160
#----------------- This deals with the tab swapping support. -----------------
3163
## def swapPages(self, p1, p2, moveleft):
3166
## if not (moveleft or (p1-p2==1)):
3168
## page = self.GetPage(mn)
3169
## text = self.GetPageText(mn)[:]
3170
## self.RemovePage(mn)
3171
## self.InsertPage(mx, page, text, 1)
3173
def RemovePage(self, index):
3174
self.root.dragger._RemoveItem(index)
3175
wxNotebook.RemovePage(self, index)
3177
def DeletePage(self, index):
3178
self.root.dragger._RemoveItem(index)
3179
page = self.GetPage(index)
3180
stc = page.GetWindow1()
3185
wxNotebook.DeletePage(self, index)
3187
def AddPage(self, page, text, switch=0):
3188
which = EXT_TO_IMG.get(extns.get(text.split('.')[-1].lower(), 0), 0)
3189
self.root.dragger._AddItem(text)
3190
wxNotebook.AddPage(self, page, text, switch, which)
3191
if switch or self.GetPageCount() == 1:
3192
## self.root.OnDocumentChange(page.GetWindow1())
3193
self.root.dragger._SelectItem(self.GetPageCount()-1)
3195
def InsertPage(self, posn, page, text, switch=0):
3196
which = EXT_TO_IMG.get(extns.get(text.split('.')[-1].lower(), 0), 0)
3197
self.root.dragger._InsertItem(posn, text)
3198
wxNotebook.InsertPage(self, posn, page, text, switch, which)
3199
if self.GetSelection() == posn:
3200
self.root.OnDocumentChange(page.GetWindow1())
3202
def SetPageText(self, posn, text):
3203
self.root.dragger._RenameItem(posn, text)
3204
wxNotebook.SetPageText(self, posn, text)
3206
class MyLC(wxTreeCtrl):
3207
class FileDropTarget(wxFileDropTarget):
3208
def __init__(self, parent, root):
3209
wxFileDropTarget.__init__(self)
3210
self.parent = parent
3212
def OnDropFiles(self, x, y, filenames):
3213
if len(filenames) != 1:
3215
for filename in filenames:
3216
dn, fn = os.path.split(filename)
3217
filename = self.root.getAbsolute(fn, dn)
3218
unt = (filename[:10] == '<untitled ' and filename[-1:] == '>')
3219
if unt or self.root.isAbsOpen(filename):
3220
#relocate to the end
3221
i = self.root.getPositionAbsolute(filename, unt)
3222
selected = self.root.control.GetSelection()
3224
p = self.root.control.GetPage(i)
3225
t = self.root.control.GetPageText(i)
3226
self.root.control.RemovePage(i)
3227
self.root.control.AddPage(p, t, selected==i)
3229
dn, fn = os.path.split(self.root.getAlmostAbsolute(fn, dn))
3230
self.root.newTab(dn, fn)
3234
selindex = [i[0] for i in self.parent.getAllRectangles()].index(self.parent.selected)
3239
l = self.parent.getAllRectangles()
3242
for p, (item, rect) in enumerate(l):
3244
if y >= rect.y and y < rect.y+rect.height:
3247
filename = filenames[0]
3248
dn, fn = os.path.split(filename)
3249
unt = (filename[:10] == '<untitled ' and filename[-1:] == '>')
3251
filename = self.root.getAlmostAbsolute(fn, dn)
3252
dn, fn = os.path.split(filename)
3254
if not unt and not self.root.isOpen(fn, dn):
3256
cp = self.root.control.GetPageCount()
3257
self.root.newTab(dn, fn, switch=1)
3260
cp = self.root.getPositionAbsolute(self.root.getAbsolute(fn, dn), unt)
3265
#remove from original location, insert at destination
3266
p = self.root.control.GetPage(cp)
3267
t = self.root.control.GetPageText(cp)
3269
self.root.starting = 1
3270
self.root.control.RemovePage(cp)
3271
if i >= self.root.control.GetPageCount():
3272
self.root.control.AddPage(p, t)
3274
self.root.control.InsertPage(i, p, t)
3276
self.root.control.SetSelection(min(i, self.root.control.GetPageCount()-1))
3278
self.root.starting = 0
3280
def __init__(self, parent, root):
3282
wxTreeCtrl.__init__(self, parent, tID, style=wxTR_HIDE_ROOT|\
3283
wxTR_NO_LINES|wxTR_NO_BUTTONS)
3286
self.rootnode = self.AddRoot("Unseen Root")
3287
self.SetDropTarget(self.FileDropTarget(self, root))
3288
self.AssignImageList(IMGLIST1)
3290
## EVT_TREE_ITEM_ACTIVATED(self, tID, self.OnTreeItemActivated)
3291
EVT_TREE_BEGIN_DRAG(self, tID, self.OnTreeBeginDrag)
3292
EVT_TREE_SEL_CHANGED(self, tID, self.OnTreeSelectionChanged)
3294
def getAllRectangles(self):
3295
count = self.GetChildrenCount(self.rootnode)
3297
while len(lst) < count:
3299
(item, cookie) = self.GetFirstChild(self.rootnode)
3301
(item, cookie) = self.GetNextChild(self.rootnode, cookie)
3302
lst.append((item, self.GetBoundingRect(item)))
3305
def OnTreeItemActivated(self, event):
3306
item = event.GetItem()
3307
lst = self.getAllRectangles()
3309
for i, (itemi, toss) in enumerate(lst):
3318
self.root.control.SetSelection(posn)
3320
def OnTreeBeginDrag(self, event):
3321
item = event.GetItem()
3322
lst = self.getAllRectangles()
3324
for i, (itemi, toss) in enumerate(lst):
3333
a = self.root.control.GetPage(posn).GetWindow1()
3334
data = os.path.join(a.dirname, a.filename).encode('ascii')
3336
data = '<untitled %i>'%a.NEWDOCUMENT
3337
d = wxFileDataObject()
3339
## print d.GetFilenames()
3340
a = wxDropSource(self)
3342
a.DoDragDrop(wxDrag_AllowMove|wxDrag_CopyOnly)
3344
def OnTreeSelectionChanged(self, event):
3346
self.selected = item = event.GetItem()
3347
items = [i[0] for i in self.getAllRectangles()]
3349
indx = items.index(item)
3350
self.root.control.SetSelection(indx)
3354
def _RemoveItem(self, index):
3355
chlist = self.getAllRectangles()
3356
self.Delete(chlist[index][0])
3358
def _AddItem(self, label):
3359
which = EXT_TO_IMG.get(extns.get(label.split('.')[-1].lower(), 0), 0)
3360
self.AppendItem(self.rootnode, label, which)
3362
def _InsertItem(self, index, label):
3363
if index == self.GetChildrenCount(self.rootnode, False):
3364
self._AddItem(label)
3366
which = EXT_TO_IMG.get(extns.get(label.split('.')[-1].lower(), 0), 0)
3367
self.InsertItemBefore(self.rootnode, index, label, which)
3369
def _SelectItem(self, index):
3370
chlist = self.getAllRectangles()
3371
if index < len(chlist):
3372
self.SelectItem(chlist[index][0])
3374
def _RenameItem(self, index, label):
3375
self.SetItemText(self.getAllRectangles()[index][0], label)
3377
class FileDropTarget(wxFileDropTarget):
3378
def __init__(self, root):
3379
wxFileDropTarget.__init__(self)
3381
def OnDropFiles(self, x, y, filenames):
3382
self.root.OnDrop(filenames)
3384
class TextDropTarget(wxTextDropTarget):
3385
def __init__(self, parent):
3386
wxTextDropTarget.__init__(self)
3387
self.parent = parent
3389
def OnDropText(self, x, y, text):
3390
self.parent.OnDropText(text)
3391
#This is so that you can keep your document unchanged while adding
3395
#I use a tree control embedded in a panel so that the control expands to
3396
#use the full amount of space.
3397
class hierCodeTreePanel(wxPanel):
3398
class TreeCtrl(wxTreeCtrl):
3399
def __init__(self, parent, tid):
3400
wxTreeCtrl.__init__(self, parent, tid, style=wxTR_DEFAULT_STYLE|wxTR_HAS_BUTTONS|wxTR_HIDE_ROOT)
3403
il = wxImageList(isz[0], isz[1])
3404
self.images = [wxArtProvider_GetBitmap(wxART_FOLDER, wxART_OTHER, isz),
3405
wxArtProvider_GetBitmap(wxART_FILE_OPEN, wxART_OTHER, isz),
3406
wxArtProvider_GetBitmap(wxART_NORMAL_FILE, wxART_OTHER, isz)]
3407
for i in self.images:
3409
self.SetImageList(il)
3412
def OnCompareItems(self, item1, item2):
3414
return cmp(self.GetItemData(item1).GetData(),\
3415
self.GetItemData(item2).GetData())
3417
return cmp(self.GetItemData(item1).GetData()[1],\
3418
self.GetItemData(item2).GetData()[1])
3420
def __init__(self, root, parent):
3421
# Use the WANTS_CHARS style so the panel doesn't eat the Return key.
3422
wxPanel.__init__(self, parent, -1, style=wxWANTS_CHARS)
3423
self.parent = parent
3424
EVT_SIZE(self, self.OnSize)
3430
self.tree = self.TreeCtrl(self, tID)
3431
self.tree.troot = self.tree.AddRoot("Unseen Root")
3433
#self.tree.Expand(self.root)
3434
EVT_LEFT_DCLICK(self, self.OnLeftDClick)
3435
EVT_TREE_ITEM_ACTIVATED(self, tID, self.OnActivate)
3437
def new_hierarchy(self, hier):
3438
self.tree.DeleteAllItems()
3439
root = [self.tree.troot]
3441
D = {'c':wxColour(0, 0, 200),
3442
'd':wxColour(200, 0, 0)}
3446
name, line_no, leading, children = cur.pop()
3447
item_no = self.tree.AppendItem(root[-1], name)
3448
self.tree.SetPyData(item_no, line_no)
3449
self.tree.SetItemTextColour(item_no, D[name[0]])
3453
self.tree.SetItemImage(item_no, 0, wxTreeItemIcon_Normal)
3454
self.tree.SetItemImage(item_no, 1, wxTreeItemIcon_Expanded)
3456
root.append(item_no)
3459
self.tree.SetItemImage(item_no, 2, wxTreeItemIcon_Normal)
3460
self.tree.SetItemImage(item_no, 2, wxTreeItemIcon_Selected)
3461
self.tree.SortChildren(root[-1])
3464
def OnSize(self, event):
3465
w,h = self.parent.GetClientSizeTuple()
3466
self.tree.SetDimensions(0, 0, w, h)
3467
self.parent.sizer.Layout()
3469
def OnLeftDClick(self, event):
3470
#pity this doesn't do what it should.
3471
num, win = self.root.getNumWin(event)
3474
def OnActivate(self, event):
3475
num, win = self.root.getNumWin(event)
3476
dat = self.tree.GetItemData(event.GetItem()).GetData()
3482
linepos = win.GetLineEndPosition(ln)
3483
win.EnsureVisible(ln)
3484
win.SetSelection(linepos-len(win.GetLine(ln))+len(win.format), linepos)
3485
win.ScrollToColumn(0)
3489
wxPanel.Show(self, True)
3491
self.parent.sizer.Add(self)
3498
self.parent.sizer.Detach(self)
3502
class TriggerDialog(wxDialog):
3503
class TriggerListCtrl(wxListCtrl, wxTextEditMixin):
3505
def __init__(self, parent, stc, dct):
3506
wxDialog.__init__(self, parent, -1, "Title",
3507
style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER,
3510
self.parent = parent
3512
EVT_CLOSE(self, self.OnClose)
3514
def addbutton(sizer, name, fcn, id):
3515
it = wxButton(self, id, name)
3516
sizer.Add(it, 0, wxRIGHT, border=5)
3517
EVT_BUTTON(self, id, fcn)
3520
sizer = wxBoxSizer(wxVERTICAL)
3522
#description/help text
3523
sizer.Add(wxStaticText(self, -1, '''\
3524
When editing a document, any time you type the string in the 'enter' column,
3525
the string in the 'left' column replaces it, and the string in the 'right'
3526
column is inserted to the right of the cursor.
3528
See the help for example uses.
3530
One may want to use such functionality for single or double quotes: '', ""
3531
parens or square/curly/pointy braces: (), [], {}, <>
3532
or even html tag expansion: ahref->"<a href='http://", "'></a>"
3534
Double-click to edit an entry in-place.
3536
If one entry in the 'enter' column is a suffix of another, the suffix item
3537
will be removed. Watch the log for such entries.
3539
NOTE: If any of your entries begins with a single or double quote, and is a
3540
valid Python string definition, then it will be interpreted as the string
3541
defined (allowing for escaped tabs, line endings, unicode characters, etc.).'''.replace(32*' ', '')
3542
), 0, wxLEFT|wxRIGHT, border=5)
3544
#wxListCtrl with editor
3545
self.list = self.TriggerListCtrl(self, -1, style=wxLC_REPORT|wxBORDER_NONE)
3546
wxTextEditMixin.__init__(self.list)
3547
self.list.InsertColumn(0, "enter");self.list.SetColumnWidth(0, 160)
3548
self.list.InsertColumn(1, "left");self.list.SetColumnWidth(1, 80)
3549
self.list.InsertColumn(2, "right");self.list.SetColumnWidth(2, 80)
3552
sizer.Add(self.list, 2, flag=wxGROW|wxALL, border=5)
3554
buttons = wxBoxSizer(wxHORIZONTAL)
3556
addbutton(buttons, "New Trigger", self.OnNew, wxNewId())
3557
addbutton(buttons, "Delete Trigger", self.OnDelete, wxNewId())
3558
buttons.Add(wxStaticText(self, -1, ' '), 1, wxGROW)
3560
addbutton(buttons, "OK", self.OnOK, wxOK)
3561
addbutton(buttons, "Cancel", self.OnCancel, wxCANCEL)
3562
sizer.Add(buttons, 0, wxALIGN_CENTER|wxLEFT, border=5)
3565
self.SetSizer(sizer)
3567
def ResetData(self, data):
3568
def reconstruct(suf, x):
3569
if type(x) is tuple:
3570
yield suf, x[0], x[1]
3571
elif type(x) is dict:
3572
for key,value in x.iteritems():
3573
for i,j,k in reconstruct(key+suf, value):
3576
self.list.DeleteAllItems()
3577
for x in reconstruct('', data):
3584
if not isinstance(L, unicode):
3585
Lx = L.encode('string-escape')
3590
indx = self.list.InsertStringItem(65536, 'X')
3591
self.list.SetStringItem(indx, 0, i)
3592
self.list.SetStringItem(indx, 1, j)
3593
self.list.SetStringItem(indx, 2, k)
3595
def OnNew(self, evt):
3596
index = self.list.InsertStringItem(65536, 'X')
3597
self.list.SetStringItem(index, 0, 'X')
3598
self.list.SetStringItem(index, 1, 'X')
3599
self.list.SetStringItem(index, 2, 'X')
3601
def OnDelete(self, evt):
3602
selected = self.list.GetNextItem(-1, state=wxLIST_STATE_SELECTED)
3604
self.list.DeleteItem(selected)
3606
def OnClose(self, evt):
3609
def OnOK(self, evt):
3611
for row in xrange(self.list.GetItemCount()):
3612
#handle string escapes
3613
item = [self.list.GetItem(row, 0).GetText(),
3614
self.list.GetItem(row, 1).GetText(),
3615
self.list.GetItem(row, 2).GetText()]
3618
if i and i[0] in ['"', "'"]:
3620
i = [j for j in compiler.parse(str(i)).getChildren()[:1] if isinstance(j, basestring)][0]
3621
except Exception, e:
3628
if len(l) or len(r):
3629
print "null trigger has nonnull replacements (%r, %r)"%(l,r)
3631
if len(l) + len(r) == 0:
3632
print "nonnull trigger %r has null replacements"%p
3636
for le,ch in enumerate(p[::-1]):
3638
if type(n) is tuple:
3640
print "duplicate trigger %r with replacements (%r, %r), and is now removed"%(p, l, r)
3642
print "trigger %r with replacements (%r, %r) is a suffix of %r, and is now removed"%(p[-le-1:], n[0], n[1], p)
3651
print "trigger %r with replacements (%r, %r) is a suffix of some entry, and is now removed"%(p, l, r)
3655
self.stc.triggers = d
3658
def OnCancel(self, evt):
3661
class KeySink(wxWindow):
3662
def __init__(self, parent, defa, curr):
3663
wxWindow.__init__(self, parent, -1, style=wxWANTS_CHARS)
3664
self.SetBackgroundColour(wxBLUE)
3665
self.haveFocus = False
3670
EVT_PAINT(self, self.OnPaint)
3671
EVT_SET_FOCUS(self, self.OnSetFocus)
3672
EVT_KILL_FOCUS(self, self.OnKillFocus)
3673
EVT_MOUSE_EVENTS(self, self.OnMouse)
3674
EVT_KEY_DOWN(self, self.OnKey)
3676
def OnPaint(self, evt):
3677
dc = wxPaintDC(self)
3678
rect = self.GetClientRect()
3679
dc.SetTextForeground(wxWHITE)
3680
dc.DrawLabel("Click here and enter your key combination.\n"
3681
"Default: %s Current: %s"%(self.defa, self.curr),
3682
rect, wxALIGN_CENTER | wxALIGN_TOP)
3684
dc.SetTextForeground(wxGREEN)
3685
dc.DrawLabel("Have Focus", rect, wxALIGN_RIGHT | wxALIGN_BOTTOM)
3687
dc.SetTextForeground(wxRED)
3688
dc.DrawLabel("Need Focus!", rect, wxALIGN_RIGHT | wxALIGN_BOTTOM)
3690
def OnSetFocus(self, evt):
3691
self.haveFocus = True
3694
def OnKillFocus(self, evt):
3695
self.haveFocus = False
3698
def OnMouse(self, evt):
3699
if evt.ButtonDown():
3702
def OnKey(self, evt):
3703
self.GetParent().text.SetValue(GetKeyPress(evt))
3705
class GetKeyDialog(wxDialog):
3706
def __init__(self, parent, defa, curr):
3707
wxDialog.__init__(self, parent, -1, "Enter key combination",
3708
style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER,
3710
self.parent = parent
3712
self.keysink = KeySink(self, defa, curr)
3714
self.text = wxTextCtrl(self, -1, curr, style=wxTE_READONLY|wxTE_LEFT)
3716
buttons = wxBoxSizer(wxHORIZONTAL)
3717
ok = wxButton(self, wxOK, "OK")
3718
cancel = wxButton(self, wxCANCEL, "Cancel")
3720
buttons.Add(cancel, 0)
3722
sizer = wxBoxSizer(wxVERTICAL)
3723
sizer.Add(self.keysink, 1, wxGROW)
3724
sizer.Add(self.text, 0, wxGROW)
3725
sizer.Add(buttons, 0, wxALIGN_RIGHT)
3727
self.SetSizer(sizer)
3728
EVT_BUTTON(self, wxOK, self.OnOK)
3729
EVT_BUTTON(self, wxCANCEL, self.OnCancel)
3730
EVT_CLOSE(self, self.OnClose)
3732
def OnClose(self, evt):
3735
def OnOK(self, evt):
3736
self.parent.accelerator = self.text.GetValue()
3739
def OnCancel(self, evt):
3740
self.parent.accelerator = ""
3743
class MenuItemDialog(wxDialog):
3744
class VirtualMenu(wxPanel):
3745
class virtualMenu(wxListCtrl, wxListCtrlAutoWidthMixin):
3746
def __init__(self, parent):
3747
wxListCtrl.__init__(self, parent, -1,
3748
style=wxLC_REPORT|wxLC_VIRTUAL|wxLC_HRULES|wxLC_VRULES|wxLC_SINGLE_SEL)
3749
wxListCtrlAutoWidthMixin.__init__(self)
3751
self.parent = parent
3754
self.InsertColumn(0, "Default Menu Heirarchy")
3755
self.InsertColumn(1, "Current Name")
3756
self.InsertColumn(2, "Default Hotkey")
3757
self.InsertColumn(3, "Current Hotkey")
3758
self.SetColumnWidth(0, 250)
3759
self.SetColumnWidth(1, 150)
3760
self.SetColumnWidth(2, 100)
3763
self.SetItemCount(0)
3765
EVT_LIST_ITEM_SELECTED(self, self.GetId(), self.OnItemSelected)
3766
EVT_LIST_ITEM_ACTIVATED(self, self.GetId(), self.OnItemActivated)
3768
def OnItemActivated(self, event):
3769
inum = event.GetIndex()
3770
item = self.items[inum]
3771
dlg = wxTextEntryDialog(self,
3772
"Enter the new name of the menu item\n"\
3773
"Default: %s Current: %s"%(item[0].split('->')[-1], item[1]),\
3774
"What should the item be called?")
3775
dlg.SetValue(item[1])
3776
rslt = dlg.ShowModal()
3778
name = dlg.GetValue()
3784
if item[0].find('->') == -1 or not item[4]:
3785
self.items[inum] = (item[0], name, '', '', 0)
3786
return self.RefreshItem(inum)
3787
dlg = GetKeyDialog(self, item[2], item[3])
3789
if not self.accelerator:
3791
self.items[inum] = (item[0], name, item[2], self.accelerator, 1)
3792
self.RefreshItem(inum)
3794
def getColumnText(self, index, col):
3795
return self.items[index][col]
3797
def OnGetItemText(self, item, col):
3798
return self.items[item][col]
3800
def OnGetItemImage(self, item):
3803
def OnGetItemAttr(self, item):
3806
def OnItemSelected(self, evt):
3807
self.sel = evt.GetIndex()
3809
def __init__(self, parent):
3810
wxPanel.__init__(self, parent, -1, style=wxWANTS_CHARS)
3811
self.vm = self.virtualMenu(self)
3812
self.refresh(MENULIST)
3814
self.parent = parent
3816
EVT_SIZE(self, self.OnSize)
3818
def refresh(self, items):
3820
self.vm.SetItemCount(0)
3821
self.vm.items = items
3822
self.vm.SetItemCount(len(items))
3823
if self.vm.sel is not None:
3824
self.vm.EnsureVisible(self.vm.sel)
3826
def OnSize(self, event):
3827
w,h = self.GetClientSizeTuple()
3828
self.vm.SetDimensions(0, 0, w, h)
3830
def __init__(self, parent, root):
3831
wxDialog.__init__(self, parent, -1, "Menu item names and hotkey bindings.",
3832
size=(640,480), style=wxRESIZE_BORDER|wxDEFAULT_DIALOG_STYLE)
3835
self.vmu = self.VirtualMenu(self)
3836
sizer = wxBoxSizer(wxVERTICAL)
3838
sizer.Add(wxStaticText(self, -1,
3839
"Double click on an entry to change the name and/or hotkey. Most any hotkey should work fine. Give it a try.\n"
3840
"Name changes with accelerators should work fine, as long as there are no accelerator key collisions."))
3841
sizer.Add(self.vmu, 1, wxGROW)
3843
s2 = wxBoxSizer(wxHORIZONTAL)
3845
ok = wxButton(self, wxOK, "OK")
3846
clear = wxButton(self, wxNewId(), "Clear Hotkey")
3847
revert = wxButton(self, wxNewId(), "Revert Name and Hotkey")
3848
cancel = wxButton(self, wxCANCEL, "Cancel")
3854
sizer.Add(s2, 0, wxALIGN_RIGHT)
3856
self.SetSizer(sizer)
3857
self.SetAutoLayout(True)
3859
EVT_BUTTON(self, wxOK, self.OnOK)
3860
EVT_BUTTON(self, clear.GetId(), self.OnClear)
3861
EVT_BUTTON(self, revert.GetId(), self.OnRevert)
3862
EVT_BUTTON(self, wxCANCEL, self.OnCancel)
3864
def OnOK(self, evt):
3869
for heir, cn, da, ca, hk in self.vmu.vm.items:
3870
if MENUPREF[heir] != (cn, ca):
3872
nmu[heir] = (cn, ca)
3875
MENUPREF.update(nmu)
3876
MENULIST[:] = self.vmu.vm.items
3877
self.root.dialog("You must restart in order for your\n"
3878
"menu item changes to go into effect.",
3882
def OnClear(self, evt):
3886
items[indx] = items[indx][:3] + ('', items[indx][4])
3887
IL.RefreshItem(indx)
3889
def OnRevert(self, evt):
3894
items[indx] = (item[0], item[0].split('->')[-1], item[2], item[2], item[4])
3895
IL.RefreshItem(indx)
3897
def OnCancel(self, evt):
3901
#--------------------------- And the main...*sigh* ---------------------------
3903
VS = wx.VERSION_STRING
3907
global IMGLIST1, IMGLIST2, root
3908
app = wxPySimpleApp()
3909
IMGLIST1 = wxImageList(16, 16)
3910
IMGLIST2 = wxImageList(16, 16)
3911
for il in (IMGLIST1, IMGLIST2):
3912
il.AddIcon(wxIcon('icons/blank.ico', wxBITMAP_TYPE_ICO))
3913
il.AddIcon(wxIcon('icons/py.ico', wxBITMAP_TYPE_ICO))
3916
if len(sys.argv)>1 and (sys.argv[1] == '--last'):
3918
filehistory.root = root = app.frame = MainWindow(None, -1, "PyPE", sys.argv[1+opn:])
3919
root.updateWindowTitle()
3920
app.SetTopWindow(app.frame)
3923
app.frame.OnOpenPrevDocs(None)
3924
app.frame.SendSizeEvent()
3927
if __name__ == '__main__':