~ubuntu-branches/ubuntu/maverick/pype/maverick-proposed

« back to all changes in this revision

Viewing changes to pype.py

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2005-09-13 20:51:29 UTC
  • Revision ID: james.westby@ubuntu.com-20050913205129-ph18px3tkx7ay4pv
Tags: upstream-2.1.1
ImportĀ upstreamĀ versionĀ 2.1.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/env python
 
2
 
 
3
#-------------- User changable settings are in configuration.py --------------
 
4
 
 
5
#------------------------------ System Imports -------------------------------
 
6
from __future__ import generators
 
7
 
 
8
import sys
 
9
if not hasattr(sys, 'frozen'):
 
10
    import wxversion;wxversion.ensureMinimal('2.6')
 
11
import os, stat
 
12
import keyword, traceback, cStringIO, imp, fnmatch, re
 
13
import time, pprint
 
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
 
21
import copy
 
22
import inspect
 
23
import textwrap
 
24
import md5
 
25
import compiler
 
26
 
 
27
UNICODE = wxUSE_UNICODE
 
28
 
 
29
#--------------------------- configuration import ----------------------------
 
30
from configuration import *
 
31
 
 
32
#---------------------------- Event Declarations -----------------------------
 
33
 
 
34
class cancelled(Exception):
 
35
        pass
 
36
 
 
37
def isdirty(win):
 
38
    if win.dirty:
 
39
        return True
 
40
 
 
41
    fn = win.root.getAbsolute(win.filename, win.dirname)
 
42
    dirty = 0
 
43
    try:
 
44
        mod = os.stat(fn)[8]
 
45
        dirty += mod != win.mod
 
46
    except:
 
47
        dirty += bool(fn.strip())
 
48
    r = dirty and True or False
 
49
    if r:
 
50
        win.MakeDirty()
 
51
    return r
 
52
 
 
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
 
62
 
 
63
## from plugins import project
 
64
 
 
65
for i in [logger, findbar, lru, filehistory, browser, workspace, todo,
 
66
          findinfiles]:#, project]:
 
67
    i.cancelled = cancelled
 
68
    i.isdirty = isdirty
 
69
 
 
70
#
 
71
VERSION = "2.1.1"
 
72
VERSION_ = "2.1.1"
 
73
 
 
74
if 1:
 
75
    #under an if so that I can collapse the declarations
 
76
 
 
77
    try:
 
78
        True
 
79
    except:
 
80
        True = bool(1)
 
81
        False = not True
 
82
 
 
83
    import string
 
84
    STRINGPRINTABLE = dict.fromkeys(map(ord, string.printable))
 
85
 
 
86
    #keypresses
 
87
    if 1:
 
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",
 
104
        "NUMPAD_DIVIDE"]
 
105
 
 
106
        keyMap = {}
 
107
        #RkeyMap = {}
 
108
        for i in keys:
 
109
            key = eval("WXK_"+i)
 
110
            keyMap[key] = i
 
111
            #RkeyMap[i] = key
 
112
        for i in ["SHIFT", "ALT", "CONTROL", "MENU"]:
 
113
            key = eval("WXK_"+i)
 
114
            keyMap[key] = ''
 
115
        del key
 
116
 
 
117
        def GetKeyPress(evt):
 
118
            keycode = evt.GetKeyCode()
 
119
            keyname = keyMap.get(keycode, None)
 
120
            modifiers = ""
 
121
            for mod, ch in ((evt.ControlDown(), 'Ctrl+'),
 
122
                            (evt.AltDown(),     'Alt+'),
 
123
                            (evt.ShiftDown(),   'Shift+'),
 
124
                            (evt.MetaDown(),    'Meta+')):
 
125
                if mod:
 
126
                    modifiers += ch
 
127
 
 
128
            if keyname is None:
 
129
                if 27 < keycode < 256:
 
130
                    keyname = chr(keycode)
 
131
                else:
 
132
                    keyname = "(%s)unknown" % keycode
 
133
            return modifiers + keyname
 
134
 
 
135
    MENULIST = []
 
136
    MENUPREF = {}
 
137
    OLD_MENUPREF= {}
 
138
    HOTKEY_TO_ID = {}
 
139
 
 
140
    def _spl(n):
 
141
        return (n.split('\t', 1) + [''])[:2]
 
142
 
 
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()
 
147
            if sm:
 
148
                a = recmenu(sm, id)
 
149
                if a:
 
150
                    return '%s->%s'%(menu.GetLabel(), a)
 
151
                return ''
 
152
            elif menu.GetId() == id:
 
153
                return menu.GetLabel()
 
154
            else:
 
155
                return ''
 
156
        elif isinstance(menu, wxMenu) or isinstance(menu, wxMenuPtr):
 
157
            ITEMS = menu.GetMenuItems()
 
158
            for i in ITEMS:
 
159
                a = recmenu(i, id)
 
160
                if a:
 
161
                    return a
 
162
            return ''
 
163
        else:
 
164
            for i in xrange(menu.GetMenuCount()):
 
165
                r = menu.GetMenu(i)
 
166
                if r.FindItemById(id):
 
167
                    return "%s->%s"%(menu.GetLabelTop(i), recmenu(r, id))
 
168
        raise Exception("Item not found.")
 
169
 
 
170
    def menuAdd(root, menu, name, desc, funct, id, kind=wxITEM_NORMAL):
 
171
 
 
172
        a = wxMenuItem(menu, id, 'TEMPORARYNAME', desc, kind)
 
173
        menu.AppendItem(a)
 
174
        EVT_MENU(root, id, funct)
 
175
 
 
176
        ns, oacc = _spl(name)
 
177
        heir = recmenu(menuBar, id)[:-13] + ns
 
178
        if heir in MENUPREF:
 
179
            name, acc = MENUPREF[heir]
 
180
        else:
 
181
            if heir in OLD_MENUPREF:
 
182
                name, acc = MENUPREF[heir] = OLD_MENUPREF[heir]
 
183
            else:
 
184
                name, acc = MENUPREF[heir] = (ns, oacc)
 
185
            MENULIST.append((heir, name, oacc, acc, kind in [wxITEM_NORMAL, wxITEM_CHECK]))
 
186
 
 
187
        if acc:
 
188
            HOTKEY_TO_ID[acc] = id
 
189
 
 
190
        menuBar.SetLabel(id, '%s\t%s'%(name, acc))
 
191
        menuBar.SetHelpString(id, desc)
 
192
 
 
193
    def menuAddM(parent, menu, name, help=''):
 
194
        if isinstance(parent, wxMenu) or isinstance(parent, wxMenuPtr):
 
195
            id = wxNewId()
 
196
            parent.AppendMenu(id, "TEMPORARYNAME", menu, help)
 
197
            heir = recmenu(menuBar, id) + name
 
198
            name, toss = MENUPREF.setdefault(heir, (name, ''))
 
199
 
 
200
            menuBar.SetLabel(id, name)
 
201
            menuBar.SetHelpString(id, help)
 
202
        else:
 
203
            heir = name
 
204
            name, toss = MENUPREF.setdefault(name, (name, ''))
 
205
 
 
206
            parent.Append(menu, name)
 
207
 
 
208
        MENULIST.append((heir, name, '', '', 0))
 
209
 
 
210
    def getIcon():
 
211
        data = getData()
 
212
        stream = cStringIO.StringIO(data)
 
213
        image = wxImageFromStream(stream)
 
214
        bitmap = wxBitmapFromImage(image)
 
215
        icon = wxEmptyIcon()
 
216
        icon.CopyFromBitmap(bitmap)
 
217
        return icon
 
218
 
 
219
    NEWDOCUMENT = 0L
 
220
 
 
221
    #required ids
 
222
    if 1:
 
223
        #style ids
 
224
        PY_S = wxNewId()
 
225
        HT_S = wxNewId()
 
226
        XM_S = wxNewId()
 
227
        CC_S = wxNewId()
 
228
        TX_S = wxNewId()
 
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]))
 
231
 
 
232
        PY_DS = wxNewId()
 
233
        HT_DS = wxNewId()
 
234
        XM_DS = wxNewId()
 
235
        CC_DS = wxNewId()
 
236
        TX_DS = wxNewId()
 
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]))
 
239
 
 
240
        #checkbox ids
 
241
        AUTO = wxNewId()
 
242
        NUM = wxNewId()
 
243
        MARGIN = wxNewId()
 
244
        USETABS = wxNewId()
 
245
        INDENTGUIDE = wxNewId()
 
246
        WRAPL = wxNewId()
 
247
        SAVE_CURSOR = wxNewId()
 
248
        DND_ID = wxNewId()
 
249
        DB_ID = wxNewId()
 
250
        LB_ID = wxNewId()
 
251
        WIDE_ID = wxNewId()
 
252
        TALL_ID = wxNewId()
 
253
        TD_ID = wxNewId()
 
254
        TB_ID = wxNewId()
 
255
        NO_FINDBAR_HISTORY = wxNewId()
 
256
        CLEAR_FINDBAR_HISTORY = wxNewId()
 
257
 
 
258
        ZI = wxNewId()
 
259
 
 
260
        #margin ids
 
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}
 
267
        LL_RMAPPING = {}
 
268
        for i,j in LL_MAPPING.iteritems():
 
269
            LL_RMAPPING[j] = i
 
270
 
 
271
        #line ending ids
 
272
        LE_CRLF = wxNewId()
 
273
        LE_LF   = wxNewId()
 
274
        LE_CR   = wxNewId()
 
275
        LE_MAPPING = {LE_CRLF:wxSTC_EOL_CRLF,
 
276
                        LE_LF:wxSTC_EOL_LF,
 
277
                        LE_CR:wxSTC_EOL_CR}
 
278
        LE_RMAPPING = {}
 
279
        for i,j in LE_MAPPING.iteritems():
 
280
            LE_RMAPPING[j] = i
 
281
 
 
282
        #cursor behavior ids
 
283
 
 
284
        (CARET_MARGIN, CARET_CENTER, CARET_TOP, CARET_TOP_MARGIN, CARET_DEFAULT) = \
 
285
            (wxNewId(), wxNewId(), wxNewId(), wxNewId(), wxNewId())
 
286
 
 
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),
 
293
        }
 
294
 
 
295
        CARET_OPTION_TO_ID = dict([(j[0], (i, j[1])) for i,j in CARET_ID_TO_OPTIONS.iteritems()])
 
296
        
 
297
        #title display ids
 
298
        
 
299
        (TITLE_NONE, TITLE_SHORT_L, TITLE_SHORT_R, TITLE_LONG_L, TITLE_LONG_R) = \
 
300
            (wxNewId(), wxNewId(), wxNewId(), wxNewId(), wxNewId())
 
301
        
 
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"),
 
308
        }
 
309
        
 
310
        TITLE_OPTION_TO_ID = dict([(j[0], (i, j[1], j[2])) for i,j in TITLE_ID_TO_OPTIONS.iteritems()])
 
311
        
 
312
        SITO = (PY_DD, HT_DD, XM_DD, CC_DD, TX_DD) = (wxNewId(), wxNewId(), wxNewId(), wxNewId(), wxNewId())
 
313
        
 
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"),
 
320
        }
 
321
        
 
322
        SITO2= (PY_DD2, HT_DD2, XM_DD2, CC_DD2, TX_DD2) = (wxNewId(), wxNewId(), wxNewId(), wxNewId(), wxNewId())
 
323
        
 
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"),
 
330
        }
 
331
 
 
332
    #bookmark support
 
333
    BOOKMARKNUMBER = 1
 
334
    BOOKMARKSYMBOL = wxSTC_MARK_CIRCLE
 
335
    BOOKMARKMASK = 2
 
336
 
 
337
    #unicode BOM stuff
 
338
    if 1:
 
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'),
 
344
               ('', 'ascii')]
 
345
        ADDBOM = {}
 
346
        ENCODINGS = {}
 
347
        for i,j in BOM:
 
348
            ADDBOM[j] = i
 
349
            ENCODINGS[j] = wxNewId()
 
350
        del i;del j;
 
351
 
 
352
    #font stuff
 
353
    if 1:
 
354
        cn = 'Courier New'
 
355
        if wxPlatform == '__WXMSW__':
 
356
            faces = {'times': cn, 'mono' : cn, 'helv' : cn, 'other': cn,
 
357
                     'size' : 10, 'size2': 9}
 
358
        else:
 
359
            faces = {'times': 'Courier', 'mono' : 'Courier',
 
360
                     'helv' : 'Courier', 'other': 'Courier', 'size' : 10,
 
361
                     'size2': 10 }
 
362
        del cn
 
363
 
 
364
    def makeSubWindow(parent, id, size, orientation, alignment, sash):
 
365
        win = wxSashLayoutWindow(
 
366
                parent, id, wxDefaultPosition, size,
 
367
                wxNO_BORDER|wxSW_3D
 
368
                )
 
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)
 
375
        return win
 
376
 
 
377
    #subwindow ids
 
378
    ID_WINDOW_BOTTOM = wxNewId()
 
379
    ID_WINDOW_RIGHT = wxNewId()
 
380
    
 
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()
 
387
 
 
388
    #subwindow constants
 
389
    SMALL = 10
 
390
    BIG = 10000
 
391
 
 
392
    DB_LOC = {0:(wxLAYOUT_LEFT, wxSASH_RIGHT),
 
393
              1:(wxLAYOUT_RIGHT, wxSASH_LEFT)}
 
394
 
 
395
    LB_LOC = {0:(wxLAYOUT_TOP, wxSASH_BOTTOM),
 
396
              1:(wxLAYOUT_BOTTOM, wxSASH_TOP)}
 
397
 
 
398
    #extension to image map
 
399
    EXT_TO_IMG = {'python':1}
 
400
#
 
401
 
 
402
RESET = {'cursorposn':0,
 
403
         'BM':[],
 
404
         'FOLD':[]}
 
405
 
 
406
sys_excepthook = sys.excepthook
 
407
 
 
408
def my_excepthook(typ, inst, trace):
 
409
    if typ is cancelled:
 
410
        return
 
411
    return sys_excepthook(typ, inst, trace)
 
412
 
 
413
sys.excepthook = my_excepthook
 
414
 
 
415
def veto(*args):
 
416
    args[-1].Veto()
 
417
 
 
418
#---------------------- Frame that contains everything -----------------------
 
419
class MainWindow(wxFrame):
 
420
    def __init__(self,parent,id,title,fnames):
 
421
        self.starting = 1
 
422
        wxFrame.__init__(self,parent,id, title, size = ( 1024, 600 ),
 
423
                         style=wxDEFAULT_FRAME_STYLE|wxNO_FULL_REPAINT_ON_RESIZE)
 
424
 
 
425
        self.SetIcon(getIcon())
 
426
        self.FINDSHOWN = 0
 
427
        path = os.path.join(homedir, 'menus.txt')
 
428
        try:    OLD_MENUPREF.update(self.readAndEvalFile(path))
 
429
        except: pass
 
430
 
 
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
 
438
        self.loadHistory()
 
439
        self.SetSize(LASTSIZE)
 
440
        self.SetPosition(LASTPOSITION)
 
441
        self.restart = 0
 
442
        self.restartt = 0
 
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 --------------------------
 
447
        self.toparse = []
 
448
        self.parsing = 0
 
449
 
 
450
        try:
 
451
            typ = wxITEM_RADIO
 
452
            self.HAS_RADIO = 1
 
453
        except:
 
454
            typ = wxITEM_NORMAL
 
455
            self.HAS_RADIO = 0
 
456
 
 
457
        #EVT_IDLE(self, self.SetPos)
 
458
        #a = wxNewId()
 
459
        #self.T = wxTimer(self, a)
 
460
        #EVT_TIMER(self, a, self.SetPos)
 
461
        #self.T.Start(100)
 
462
 
 
463
        self.sb = wxStatusBar(self, -1)
 
464
        if UNICODE:
 
465
            #to display encoding in unicode supporting platforms
 
466
            self.sb.SetFieldsCount(3)
 
467
            self.sb.SetStatusWidths([-1, 95, 60])
 
468
        else:
 
469
            self.sb.SetFieldsCount(2)
 
470
            self.sb.SetStatusWidths([-1, 95])
 
471
        self.SetStatusBar(self.sb)
 
472
        
 
473
        if TOOLBAR:
 
474
            self._setupToolBar()
 
475
 
 
476
        self.control = MyNB(self, -1, self)
 
477
 
 
478
        # Setting up the menu
 
479
 
 
480
 
 
481
        bottom = makeSubWindow(self, ID_WINDOW_BOTTOM, (BIG, SASH1),
 
482
                               wxLAYOUT_HORIZONTAL,
 
483
                               *LB_LOC[logbarlocn])
 
484
 
 
485
        right = makeSubWindow(self, ID_WINDOW_RIGHT, (SASH2, BIG),
 
486
                              wxLAYOUT_VERTICAL,
 
487
                              *DB_LOC[docbarlocn])
 
488
 
 
489
        self.BOTTOM = bottom
 
490
        self.RIGHT = right
 
491
 
 
492
        self.BOTTOMNB = wxNotebook(bottom, -1)
 
493
        self.RIGHTNB = wxNotebook(right, -1)
 
494
        
 
495
        if TODOBOTTOM:
 
496
            self.todolist = todo.VirtualTodo(self.BOTTOMNB, self)
 
497
            self.BOTTOMNB.AddPage(self.todolist, 'Todo')
 
498
        
 
499
        
 
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")
 
503
 
 
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)
 
508
 
 
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)
 
513
 
 
514
        self.dragger = MyLC(self.RIGHTNB, self)
 
515
 
 
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')
 
519
        if not TODOBOTTOM:
 
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...")
 
525
 
 
526
        self.Bind(EVT_SASH_DRAGGED_RANGE, self.OnSashDrag, id=ID_WINDOW_BOTTOM, id2=ID_WINDOW_RIGHT)
 
527
 
 
528
#------------------------- Insert menus into Menubar -------------------------
 
529
        global menuBar
 
530
        menuBar = wxMenuBar()
 
531
 
 
532
        self.SetMenuBar(menuBar)  # Adding the MenuBar to the Frame content.
 
533
        self.menubar = menuBar
 
534
 
 
535
#--------------------------------- File Menu ---------------------------------
 
536
 
 
537
        filemenu= wxMenu()
 
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())
 
554
 
 
555
#--------------------------------- Edit Menu ---------------------------------
 
556
 
 
557
        editmenu= wxMenu()
 
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())
 
584
 
 
585
#--------------------------------- View Menu ---------------------------------
 
586
 
 
587
        viewmenu= wxMenu()
 
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)
 
602
 
 
603
#------------------------------- Document menu -------------------------------
 
604
 
 
605
        setmenu= wxMenu()
 
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()
 
609
 
 
610
        #-------------------------------- Style subenu -----------------------
 
611
        stylemenu= wxMenu()
 
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)
 
618
 
 
619
        #------------------------------ Encodings submenu --------------------
 
620
        if UNICODE:
 
621
            encmenu= wxMenu()
 
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)
 
626
 
 
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)
 
633
        #
 
634
 
 
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())
 
656
 
 
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)
 
663
 
 
664
#-------------------------------- Shell Menu ---------------------------------
 
665
 
 
666
        ## self.shell = RunShell(self, menuBar, "&Shell")
 
667
 
 
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")
 
673
        for mid in SITO:
 
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")
 
679
        for mid in SITO2:
 
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)
 
682
        
 
683
        optionsmenu.AppendSeparator()
 
684
                #---------------------------- Default Style submenu ------------------
 
685
        stylemenu2= wxMenu()
 
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)
 
692
        
 
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()
 
703
        caretmenu = wxMenu()
 
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())
 
718
        titlemenu = wxMenu()
 
719
        menuAddM(optionsmenu, titlemenu, "Title Options", "Set what information you would like PyPE to display in the title bar")
 
720
        fn = "pype.py"
 
721
        long = "C:\\PyPE\\pype.py"
 
722
        pype = "PyPE %s"%VERSION
 
723
        for i in xrange(5):
 
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)
 
726
            
 
727
 
 
728
#--------------------------------- Help Menu ---------------------------------
 
729
 
 
730
        helpmenu= wxMenu()
 
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)
 
735
 
 
736
#------------------------ A ...few... state variables ------------------------
 
737
 
 
738
        self.Show(true)
 
739
        self.dirname = '.'
 
740
        self.closing = 0
 
741
        self.openfiles = {}
 
742
        self.realfn = {}
 
743
        self.dpm = 0
 
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)
 
761
 
 
762
#------------------------ Drag and drop file support -------------------------
 
763
        self.SetDropTarget(FileDropTarget(self))
 
764
 
 
765
        #set up some events
 
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)
 
770
        self.starting = 0
 
771
        if self.control.GetPageCount() > 0:
 
772
            stc = self.getNumWin()[1]
 
773
            self.OnDocumentChange(stc)
 
774
 
 
775
        #set up some timers
 
776
        tid = wxNewId()
 
777
        self.timer = wxTimer(self, tid)
 
778
        EVT_TIMER(self, tid, self.ex_size)
 
779
        tid = wxNewId()
 
780
        self.timer2 = wxTimer(self, tid)
 
781
        EVT_TIMER(self, tid, self.keyposn)
 
782
        self.timer2.Start(100, wxTIMER_CONTINUOUS)
 
783
 
 
784
#------------------ Open files passed as arguments to PyPE -------------------
 
785
        if not SHOWTALL:
 
786
            self.RIGHT.Hide()
 
787
        if not SHOWWIDE:
 
788
            self.BOTTOM.Hide()
 
789
        
 
790
        if (not SHOWWIDE) or (not SHOWTALL):
 
791
            self.OnSize(None)
 
792
        
 
793
        self.OnDrop(fnames, 0)
 
794
 
 
795
    #...
 
796
 
 
797
    def getglobal(self, nam):
 
798
        return globals()[nam]
 
799
 
 
800
    def getInt(self, title, text, default):
 
801
        dlg = wxTextEntryDialog(self, text, title, str(default))
 
802
        resp = dlg.ShowModal()
 
803
        valu = dlg.GetValue()
 
804
        dlg.Destroy()
 
805
        if resp != wxID_OK:
 
806
            raise cancelled
 
807
        return validate(valu, default)
 
808
 
 
809
    
 
810
    def _setupToolBar(self):
 
811
        
 
812
        size = (16,16)
 
813
        def getBmp(artId, client):
 
814
            bmp = wxArtProvider_GetBitmap(artId, client, size)
 
815
            if not bmp.Ok():
 
816
                bmp = EmptyBitmap(*size)
 
817
            return bmp
 
818
        
 
819
        tb = self.CreateToolBar(
 
820
            wxTB_HORIZONTAL|wxNO_BORDER|wxTB_FLAT|wxTB_TEXT)
 
821
        
 
822
        tb.SetToolBitmapSize(size)
 
823
        
 
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")
 
832
        
 
833
        icon = getBmp(wxART_FILE_SAVE_AS, wxART_TOOLBAR)
 
834
        tb.AddSimpleTool(wxID_SAVEAS, icon, "Save as...", "Save current document as...")
 
835
 
 
836
        tb.AddSeparator()
 
837
 
 
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",
 
849
            "Delete selection")
 
850
 
 
851
        tb.AddSeparator()
 
852
 
 
853
        icon = getBmp(wxART_UNDO, wxART_TOOLBAR)
 
854
        tb.AddSimpleTool(wxID_UNDO, icon, "Undo",
 
855
            "Undo edit")
 
856
        icon = getBmp(wxART_REDO, wxART_TOOLBAR)
 
857
        tb.AddSimpleTool(wxID_REDO, icon, "Redo",
 
858
            "Redo edit (i.e. undo undo edit)")
 
859
 
 
860
        tb.AddSeparator()
 
861
 
 
862
        icon = getBmp(wxART_FIND, wxART_TOOLBAR)
 
863
        tb.AddSimpleTool(pypeID_FINDBAR, icon, "Find",
 
864
            "Find")
 
865
        icon = getBmp(wxART_FIND_AND_REPLACE, wxART_TOOLBAR)
 
866
        tb.AddSimpleTool(pypeID_REPLACEBAR, icon, "Replace",
 
867
            "Find and replace")
 
868
 
 
869
        tb.AddSeparator()
 
870
 
 
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")
 
874
        
 
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")
 
878
 
 
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")
 
882
        
 
883
        tb.AddSeparator()
 
884
        tb.AddSeparator()
 
885
        
 
886
        icon = getBmp(wxART_HELP, wxART_TOOLBAR)
 
887
        tb.AddSimpleTool(wxID_HELP, icon, "Help!",
 
888
            "Opens up the help for PyPE")
 
889
        
 
890
        tb.Realize()
 
891
 
 
892
    def OnDocumentChange(self, stc, forced=False):
 
893
        if not self.starting:
 
894
            start = time.time()
 
895
 
 
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)
 
900
 
 
901
                stc.cached = copy.deepcopy(tpl)
 
902
                h1, stc.kw, stc.tooltips, todo = tpl
 
903
 
 
904
                stc.kw.sort()
 
905
                stc.kw = ' '.join(stc.kw)
 
906
 
 
907
                ex1 = copy.deepcopy(h1)
 
908
                stc.tree1.new_hierarchy(h1)
 
909
                stc.tree2.new_hierarchy(ex1)
 
910
 
 
911
                forced = 1
 
912
            else:
 
913
                todo = copy.deepcopy(stc.cached[-1])
 
914
 
 
915
            self.todolist.NewItemList(todo)
 
916
            self.updateWindowTitle()
 
917
            if forced:
 
918
                self.SetStatusText(("Browsable source tree, autocomplete, tooltips and todo"
 
919
                                    " updated for %s in %.1f seconds.")%(stc.filename, time.time()-start))
 
920
 
 
921
    def updateWindowTitle(self):
 
922
        pype = "PyPE %s"%VERSION
 
923
        stc = None
 
924
        try:
 
925
            num, stc = self.getNumWin()
 
926
        except cancelled:
 
927
            pass
 
928
        if stc is not None:
 
929
            fn, dn = stc.filename, stc.dirname
 
930
            if fn == ' ':
 
931
                fn = "<untitled %i>"%stc.NEWDOCUMENT
 
932
            long = os.path.join(dn, fn)
 
933
            
 
934
            disp = TITLE_OPTION_TO_ID[title_option][1]%locals()
 
935
        else:
 
936
            disp = pype
 
937
        self.SetTitle(disp)
 
938
 
 
939
    def ex_size(self, evt=None):
 
940
        #an attempt to keep the findbar the correct size
 
941
        try:
 
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)
 
948
        except cancelled:
 
949
            pass
 
950
 
 
951
    def keyposn(self, evt=None):
 
952
        #an attempt to keep the line and column indicators correct
 
953
        try:
 
954
            win = self.getNumWin()[1]
 
955
            win.pos_ch(evt)
 
956
        except cancelled:
 
957
            pass
 
958
 
 
959
    def OnSashDrag(self, event):
 
960
        if event.GetDragStatus() == wxSASH_STATUS_OUT_OF_RANGE:
 
961
            return
 
962
 
 
963
        eID = event.GetId()
 
964
 
 
965
        if eID == ID_WINDOW_RIGHT:
 
966
            self.RIGHT.SetDefaultSize((max(event.GetDragRect().width, SMALL), BIG))
 
967
 
 
968
        elif eID == ID_WINDOW_BOTTOM:
 
969
            self.BOTTOM.SetDefaultSize((BIG, max(event.GetDragRect().height, SMALL)))
 
970
 
 
971
        wxLayoutAlgorithm().LayoutWindow(self, self.control)
 
972
        self.control.Refresh()
 
973
 
 
974
        self.ex_size()
 
975
 
 
976
    def OnSize(self, event):
 
977
        wxLayoutAlgorithm().LayoutWindow(self, self.control)
 
978
        self.ex_size()
 
979
 
 
980
    def dialog(self, message, title, styl=wxOK):
 
981
        d= wxMessageDialog(self,message,title,styl)
 
982
        retr = d.ShowModal()
 
983
        d.Destroy()
 
984
        return retr
 
985
 
 
986
    def exceptDialog(self, title="Error"):
 
987
        k = cStringIO.StringIO()
 
988
        traceback.print_exc(file=k)
 
989
        k.seek(0)
 
990
        dlg = wxScrolledMessageDialog(self, k.read(), title)
 
991
        dlg.ShowModal()
 
992
        dlg.Destroy()
 
993
 
 
994
    def OnDrop(self, fnames, error=1):
 
995
        cwd = os.getcwd()
 
996
        for i in fnames:
 
997
            dn, fn = os.path.split(self.getAlmostAbsolute(i, cwd))
 
998
            if self.isOpen(fn, dn):
 
999
                if len(fnames)==1:
 
1000
                    self.selectAbsolute(self.getAbsolute(fn, dn))
 
1001
            else:
 
1002
                self.makeOpen(fn, dn)
 
1003
                try:
 
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)
 
1007
                    else:       a = i
 
1008
                    self.SetStatusText("Opened %s"%a)
 
1009
                except:
 
1010
                    if error:
 
1011
                        self.exceptDialog("File open failed")
 
1012
 
 
1013
        self.redrawvisible()
 
1014
 
 
1015
    def SetStatusText(self, text, number=0, log=1):
 
1016
        if (number == 0) and text:
 
1017
            if log:
 
1018
                print text
 
1019
                text = "[%s] %s"%(time.asctime(), text)
 
1020
        self.sb.SetStatusText(text, number)
 
1021
 
 
1022
    def OnActivation(self, e):
 
1023
        try:
 
1024
            self.control.__iter__
 
1025
        except wxPyDeadObjectError:
 
1026
            e.Skip()
 
1027
            return
 
1028
        try:
 
1029
            self.iter
 
1030
            e.Skip()
 
1031
            return
 
1032
        except:
 
1033
            self.iter = None
 
1034
        for document in self.control.__iter__():
 
1035
            if document.mod != None:
 
1036
                fn = self.getAlmostAbsolute(document.filename, document.dirname)
 
1037
                try:
 
1038
                    mod = os.stat(fn)[8]
 
1039
                except OSError:
 
1040
                    document.MakeDirty(None)
 
1041
                    self.dialog("%s\n"\
 
1042
                                "has been deleted from the disk by an external program.\n"\
 
1043
                                "Unless the file is saved again, data loss may occur."%fn,
 
1044
                                "WARNING!")
 
1045
                    document.mod = None
 
1046
                    continue
 
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.
 
1054
                        document.mod = mod
 
1055
                        document.MakeClean(None)
 
1056
                        continue
 
1057
 
 
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)
 
1063
                    if a == wxID_NO:
 
1064
                        document.mod = None
 
1065
                    else:
 
1066
                        self.OnReload(None, document)
 
1067
        del self.iter
 
1068
        self.redrawvisible()
 
1069
        self.SendSizeEvent()
 
1070
        e.Skip()
 
1071
 
 
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']
 
1083
            history.reverse()
 
1084
            for h in history:
 
1085
                self.fileHistory.AddFileToHistory(h)
 
1086
        if 'lastpath' in self.config:
 
1087
            self.lastpath = self.config['lastpath']
 
1088
 
 
1089
        doc_def = {}
 
1090
        #insert global document defaults here
 
1091
        dct =     {'use_tabs':0,
 
1092
             'spaces_per_tab':8,
 
1093
                     'indent':4,
 
1094
                   'collapse':1,
 
1095
              'marker_margin':1,
 
1096
                'line_margin':1,
 
1097
                   'col_line':78,
 
1098
                   'col_mode':wxSTC_EDGE_LINE,
 
1099
               'indent_guide':0,
 
1100
               'showautocomp':0,
 
1101
                   'wrapmode':wxSTC_WRAP_NONE,
 
1102
                   'sortmode':1,
 
1103
                'save_cursor':0,
 
1104
                'cursor_posn':0,
 
1105
                   'triggers':{},
 
1106
               'findbarprefs':{}}
 
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),
 
1114
                            ## ('usetodo', 0),
 
1115
                            ## ('paths', {}),
 
1116
                            ## ('display2code', {}),
 
1117
                            ## ('displayorder', []),
 
1118
                            ## ('shellcommands', []),
 
1119
                            ('lastopen', []),
 
1120
                            ('LASTUSED', []),
 
1121
                            ('DEFAULTLEXER', 'python'),
 
1122
                            ('FIF_STATE', ([], [], [], 0, 0, 0)),
 
1123
                            ('match_flags', wxFR_DOWN),
 
1124
                            ('pathmarksn', []),
 
1125
                            ('workspaces', {}),
 
1126
                            ('workspace_order', []),
 
1127
                            ('SASH1', 60),
 
1128
                            ('SASH2', 300),
 
1129
                            ('LASTSIZE', (900,600)),
 
1130
                            ('LASTPOSITION', self.GetPositionTuple()),
 
1131
                            ('logbarlocn', 1),
 
1132
                            ('docbarlocn', 1),
 
1133
                            ('dnd_file', 1),
 
1134
                            ('caret_option', 0),
 
1135
                            ('caret_slop', 10),
 
1136
                            ('caret_multiplier', 20),
 
1137
                            ('findbarprefs', {}),
 
1138
                            ('no_findbar_history', 0),
 
1139
                            ('title_option', 0),
 
1140
                            ('document_defaults', doc_def),
 
1141
                            ('DOCUMENT_DEFAULTS', dct),
 
1142
                            ('TODOBOTTOM', 1),
 
1143
                            ('TOOLBAR', 0),
 
1144
                            ('SHOWWIDE', 1),
 
1145
                            ('SHOWTALL', 1),
 
1146
                            ]:
 
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)
 
1153
                            else:
 
1154
                                self.config[nam][k] = v
 
1155
                        elif isinstance(v, dict):
 
1156
                            V = self.config[nam][k]
 
1157
                            for k2,v2 in v.iteritems():
 
1158
                                if k2 not in V:
 
1159
                                    V[k2] = v2
 
1160
            elif isinstance(dflt, dict):
 
1161
                self.config[nam] = dict(dflt)
 
1162
            else:
 
1163
                self.config[nam] = dflt
 
1164
            globals()[nam] = self.config[nam]
 
1165
        globals().update(dct)
 
1166
        globals().update(self.config.setdefault('DOCUMENT_DEFAULTS', dct))
 
1167
 
 
1168
    def saveHistory(self):
 
1169
        history = []
 
1170
        for i in range(self.fileHistory.GetNoHistoryFiles()):
 
1171
            history.append(self.fileHistory.GetHistoryFile(i))
 
1172
        self.config['history'] = history
 
1173
        ## a = []
 
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())
 
1198
        try:
 
1199
            path = os.sep.join([self.configPath, 'history.txt'])
 
1200
            print "Saving history to", path
 
1201
            f = open(path, "w")
 
1202
            f.write(pprint.pformat(self.config))
 
1203
            f.close()
 
1204
            path = os.sep.join([self.configPath, 'menus.txt'])
 
1205
            print "Saving menus to", path
 
1206
            f = open(path, "w")
 
1207
            f.write(pprint.pformat(MENUPREF))
 
1208
            f.close()
 
1209
        except:
 
1210
            self.exceptDialog("Could not save preferences to %s"%path)
 
1211
 
 
1212
    def readAndEvalFile(self, filename):
 
1213
        f = open(filename)
 
1214
        txt = f.read().replace('\r\n','\n')
 
1215
        f.close()
 
1216
        return eval(txt)
 
1217
#------------------------- end cmt-001 - 08/06/2003 --------------------------
 
1218
 
 
1219
    def redrawvisible(self, win=None):
 
1220
 
 
1221
        if (not win) and self.control.GetPageCount() > 0:
 
1222
            num, win = self.getNumWin()
 
1223
        if win:
 
1224
            win.parent.Refresh()
 
1225
#----------------------------- File Menu Methods -----------------------------
 
1226
    def getPositionAbsolute(self, path, newf=0):
 
1227
        ## print path
 
1228
        path = os.path.normcase(path)
 
1229
        dn, fn = self.splitAbsolute(path)
 
1230
        if newf:
 
1231
            try:
 
1232
                v = int(fn[10:-1])
 
1233
            except:
 
1234
                return -1
 
1235
        for i in xrange(self.control.GetPageCount()):
 
1236
            win = self.control.GetPage(i).GetWindow1()
 
1237
            if newf:
 
1238
                if not win.dirname and v == win.NEWDOCUMENT:
 
1239
                    return i
 
1240
            elif path == self.getAbsolute(win.filename, win.dirname):
 
1241
                return i
 
1242
 
 
1243
        return -1
 
1244
 
 
1245
    def selectAbsolute(self, path):
 
1246
        if self.isAbsOpen(path):
 
1247
            i = self.getPositionAbsolute(path)
 
1248
            if i != -1:
 
1249
                self.control.SetSelection(i)
 
1250
 
 
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
 
1255
 
 
1256
    def makeOpen(self, fn, dn):
 
1257
        if fn and dn:
 
1258
            a = self.getAbsolute(fn, dn)
 
1259
            self.openfiles[a] = self.splitAbsolute(a)
 
1260
            self.realfn[a] = self.getAlmostAbsolute(fn, dn)
 
1261
 
 
1262
    def closeOpen(self, fn, dn):
 
1263
        if fn and dn:
 
1264
            a = self.getAbsolute(fn, dn)
 
1265
            del self.openfiles[a]
 
1266
            del self.realfn[a]
 
1267
 
 
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))
 
1274
 
 
1275
    def OnNew(self,e):
 
1276
        self.newTab('', ' ', 1)
 
1277
        self.control.GetPage(self.control.GetSelection()).GetWindow1().opened = 1
 
1278
 
 
1279
    def OnSave(self,e):
 
1280
        wnum, win = self.getNumWin(e)
 
1281
        if win.dirname:
 
1282
            try:
 
1283
                ofn = os.path.join(win.dirname, win.filename)
 
1284
                fil = open(ofn, 'wb')
 
1285
                txt = win.GetText()
 
1286
                fil.write(txt)
 
1287
                fil.close()
 
1288
                if UNICODE: a = "%s as %s"%(ofn, win.enc)
 
1289
                else:       a = ofn
 
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()
 
1294
                win.MakeClean()
 
1295
            except:
 
1296
                self.exceptDialog("Save Failed")
 
1297
                raise cancelled
 
1298
        else:
 
1299
            self.OnSaveAs(e)
 
1300
 
 
1301
    def OnSaveAs(self,e):
 
1302
        wnum, win = self.getNumWin(e)
 
1303
 
 
1304
        dlg = wxFileDialog(self, "Save file as...", os.getcwd(), "", "All files (*.*)|*.*", wxSAVE|wxOVERWRITE_PROMPT)
 
1305
        rslt = dlg.ShowModal()
 
1306
        if rslt == wxID_OK:
 
1307
            fn=dlg.GetFilename()
 
1308
            dn=dlg.GetDirectory()
 
1309
            if sys.platform == 'win32' and dn[1:] == ':':
 
1310
                dn += '\\'
 
1311
            
 
1312
            pth = self.getAlmostAbsolute(fn, dn)
 
1313
            dn, fn = os.path.split(pth)
 
1314
 
 
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!")
 
1318
                    raise cancelled
 
1319
                if self.isOpen(win.filename, win.dirname):
 
1320
                    self.closeOpen(win.filename, win.dirname)
 
1321
 
 
1322
            win.filename = fn
 
1323
            win.dirname = dn
 
1324
            self.makeOpen(fn, dn)
 
1325
            self.fileHistory.AddFileToHistory(pth)
 
1326
            self.OnSave(e)
 
1327
 
 
1328
            #fix the icons and names.
 
1329
            self.dragger._RemoveItem(wnum)
 
1330
            self.dragger._InsertItem(wnum, fn)
 
1331
 
 
1332
            win.MakeDirty()
 
1333
            win.MakeClean()
 
1334
 
 
1335
            self.control.SetPageImage(wnum, EXT_TO_IMG.get(extns.get(fn.split('.')[-1].lower(), 0), 0))
 
1336
            self.control.SetSelection(wnum)
 
1337
        else:
 
1338
            raise cancelled
 
1339
 
 
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)
 
1345
            try:
 
1346
                self.OnSave(e)
 
1347
            except cancelled:
 
1348
                pass
 
1349
        if cnt:
 
1350
            self.control.SetSelection(sel)
 
1351
 
 
1352
    def OnOpen(self,e):
 
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()
 
1358
        dlg.Destroy()
 
1359
 
 
1360
    def FindModule(self, mod):
 
1361
        fndmod = mod.split('.')
 
1362
        lf = len(fndmod)
 
1363
        pth = sys.path[:]
 
1364
        pth[1:1] = [os.getcwd()]
 
1365
        for j in range(lf):
 
1366
            i = fndmod[j]
 
1367
            fdsc = imp.find_module(i, pth)
 
1368
            if not (fdsc[0] is None):
 
1369
                fdsc[0].close()
 
1370
                mod = fdsc[1]
 
1371
                if fdsc[2][2] != imp.PY_SOURCE:
 
1372
                    return self.dialog("%s is not python source"%mod, "not correct format for editing")
 
1373
                return mod
 
1374
            elif fdsc[1]:
 
1375
                pth[1:1] = [fdsc[1]]
 
1376
            else:
 
1377
                raise cancelled
 
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
 
1380
        #from this folder.
 
1381
        return os.sep.join([pth[1], '__init__.py'])
 
1382
 
 
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()
 
1387
        else:
 
1388
            mod = ''
 
1389
        dlg.Destroy()
 
1390
        if mod:
 
1391
            sp = sys.path[:]
 
1392
            sys.path.extend(self.config['modulepaths'])
 
1393
            try:
 
1394
                self.OnDrop([self.FindModule(mod)])
 
1395
            except:
 
1396
                self.dialog("module %s not found"%mod, "not found")
 
1397
            sys.path = sp
 
1398
 
 
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)
 
1408
 
 
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()
 
1413
 
 
1414
        if d:
 
1415
            d, fn = os.path.split(self.getAlmostAbsolute(fn, d))
 
1416
            FN = self.getAbsolute(fn, d)
 
1417
            f=open(FN,'rb')
 
1418
            txt = f.read()
 
1419
            f.close()
 
1420
        else:
 
1421
            FN = ''
 
1422
            txt = ''
 
1423
        
 
1424
        split = wxSplitterWindow(self.control, wxNewId(), style=wxSP_NOBORDER)
 
1425
        split.SetMinimumPaneSize(0)
 
1426
        EVT_SPLITTER_SASH_POS_CHANGING(self, split.GetId(), veto)
 
1427
        
 
1428
        ftype = extns.get(fn.split('.')[-1].lower(), 'python')
 
1429
        if ftype in document_defaults:
 
1430
            print "found filetype-specific defaults", ftype
 
1431
        else:
 
1432
            print "could not find", ftype
 
1433
        state = dict(document_defaults.get(ftype, DOCUMENT_DEFAULTS))
 
1434
        nwin = PythonSTC(self.control, wxNewId(), split)
 
1435
 
 
1436
        nwin.filename = fn
 
1437
        nwin.dirname = d
 
1438
        nwin.changeStyle(stylefile, self.style(fn))
 
1439
        
 
1440
        if d:
 
1441
            nwin.mod = os.stat(FN)[8]
 
1442
            if len(txt) == 0:
 
1443
                nwin.format = eol
 
1444
                nwin.SetText('')
 
1445
            else:
 
1446
                nwin.format = detectLineEndings(txt)
 
1447
                nwin.SetText(txt)
 
1448
 
 
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]
 
1455
 
 
1456
        else:
 
1457
            nwin.mod = None
 
1458
            nwin.format = eol
 
1459
            nwin.SetText(txt)
 
1460
 
 
1461
        ## print 2
 
1462
        if not ((d == '') and (fn == ' ')):
 
1463
            self.fileHistory.AddFileToHistory(os.path.join(d, fn))
 
1464
        
 
1465
        if 'checksum' in state:
 
1466
            if md5.new(txt).hexdigest() != state['checksum']:
 
1467
                state.update(RESET)
 
1468
        
 
1469
        if FN:
 
1470
            self.curdocstates[FN] = state
 
1471
        
 
1472
        nwin.SetSaveState(state)
 
1473
        ## nwin.SetSaveState({})
 
1474
 
 
1475
        ## print 3
 
1476
        if fn == ' ':
 
1477
            ## print 3.5
 
1478
            globals()['NEWDOCUMENT'] += 1
 
1479
            nwin.NEWDOCUMENT = NEWDOCUMENT
 
1480
            fn = '<untitled %i>'%NEWDOCUMENT
 
1481
        ## print 4
 
1482
        split.Initialize(nwin)
 
1483
        ## print 5
 
1484
        self.control.AddPage(split, fn, switch)
 
1485
        ## self.OnRefresh(None, nwin)
 
1486
        self.updateWindowTitle()
 
1487
        return nwin.enc
 
1488
 
 
1489
    def OnReload(self, e, win=None):
 
1490
        if win == None:
 
1491
            num, win = self.getNumWin(e)
 
1492
        if not e is None:
 
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)
 
1494
            a = dlg.ShowModal()
 
1495
            if a == wxID_CANCEL:
 
1496
                raise cancelled
 
1497
            elif a == wxID_NO:
 
1498
                return
 
1499
        try:
 
1500
            FN = self.getAbsolute(win.filename, win.dirname)
 
1501
            fil = open(FN, 'rb')
 
1502
            txt = fil.read()
 
1503
            fil.close()
 
1504
            win.BeginUndoAction()
 
1505
            win.SetText(txt, 0)
 
1506
            win.EndUndoAction()
 
1507
            win.mod = os.stat(FN)[8]
 
1508
            win.SetSavePoint()
 
1509
            win.MakeClean()
 
1510
            self.curdocstates[FN] = {'checksum':md5.new(txt).hexdigest()}
 
1511
            self.OnRefresh(None, win)
 
1512
        except:
 
1513
            self.dialog("Error encountered while trying to reload from disk.", "Reload failed")
 
1514
 
 
1515
    def sharedsave(self, win):
 
1516
        nam = win.filename
 
1517
        if not win.dirname:
 
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:
 
1522
            raise cancelled
 
1523
        elif a == wxID_NO:
 
1524
            return 0
 
1525
        else:
 
1526
            self.OnSave(None)
 
1527
            return 1
 
1528
 
 
1529
    def OnClose(self, e, wnum=None, win=None):
 
1530
        if wnum is None or win is None:
 
1531
            wnum, win = self.getNumWin(e)
 
1532
        
 
1533
        fn = self.getAbsolute(win.filename, win.dirname)
 
1534
        
 
1535
        if isdirty(win):
 
1536
            for i, w in enumerate(self.control):
 
1537
                if w is win:
 
1538
                    self.control.SetSelection(i)
 
1539
                    break
 
1540
            saved = self.sharedsave(win)
 
1541
        elif self.isOpen(win.filename, win.dirname):
 
1542
            self.curdocstates[fn].update(win.GetSaveState())
 
1543
 
 
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))
 
1548
        else:
 
1549
            self.SetStatusText("Closed unnamed file without saving")
 
1550
        self.control.DeletePage(wnum)
 
1551
        self.updateWindowTitle()
 
1552
 
 
1553
    def OnExit(self,e):
 
1554
        if self.closing:
 
1555
            return e.Skip()
 
1556
        self.closing = 1
 
1557
        sel = self.control.GetSelection()
 
1558
        cnt = self.control.GetPageCount()
 
1559
        try:
 
1560
            for i in xrange(cnt):
 
1561
                win = self.control.GetPage(i).GetWindow1()
 
1562
 
 
1563
                if isdirty(win):
 
1564
                    self.control.SetSelection(i)
 
1565
                    self.sharedsave(win)
 
1566
        except cancelled:
 
1567
            self.closing = 0
 
1568
            try:    return e.Veto()
 
1569
            except: return e.Skip()
 
1570
 
 
1571
        LASTOPEN = []
 
1572
        sav = []
 
1573
        for win in self.control:
 
1574
            if win.dirname:
 
1575
                sav.append(self.getAlmostAbsolute(win.filename, win.dirname))
 
1576
                LASTOPEN.append((self.getAbsolute(win.filename, win.dirname), win.GetSaveState()))
 
1577
 
 
1578
 
 
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]
 
1588
        self.saveHistory()
 
1589
        if sel > -1:
 
1590
            self.control.SetSelection(sel)
 
1591
        return self.Close(True)
 
1592
 
 
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)
 
1598
        self.OnDrop([path])
 
1599
#------------------------- end cmt-001 - 08/06/2003 --------------------------
 
1600
 
 
1601
#----------------------------- Edit Menu Methods -----------------------------
 
1602
    def OneCmd(self, funct_name,evt):
 
1603
        wnum, win = self.getNumWin(evt)
 
1604
        getattr(win, funct_name)()
 
1605
 
 
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)
 
1612
    def OnCut(self, 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)
 
1622
 
 
1623
        valu = self.getInt('Wrap to how many columns?', '', col_line)
 
1624
 
 
1625
        win.MakeDirty()
 
1626
        x,y = win.GetSelection()
 
1627
        if x==y:
 
1628
            return
 
1629
        lnstart = win.LineFromPosition(x)
 
1630
        lnend = win.LineFromPosition(y-1)
 
1631
 
 
1632
        paragraphs = []
 
1633
        lines = []
 
1634
        for ln in xrange(lnstart, lnend+1):
 
1635
            lin = win.GetLine(ln)
 
1636
            if not lin.strip():
 
1637
                if lines:
 
1638
                    paragraphs.append(win.format.join(textwrap.wrap(' '.join(lines), valu)))
 
1639
                paragraphs.append(lin.rstrip('\r\n'))
 
1640
                lines = []
 
1641
            else:
 
1642
                lines.append(lin.strip())
 
1643
        if lines:
 
1644
            paragraphs.append(win.format.join(textwrap.wrap(' '.join(lines), valu)))
 
1645
 
 
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))
 
1650
 
 
1651
    def Dent(self, win, incr):
 
1652
        x,y = win.GetSelection()
 
1653
        if x==y:
 
1654
            lnstart = win.GetCurrentLine()
 
1655
            lnend = lnstart
 
1656
            if incr < 0:
 
1657
                a = win.GetLineIndentation(lnstart)%(abs(incr))
 
1658
                if a:
 
1659
                    incr = -a
 
1660
            pos = win.GetCurrentPos()
 
1661
            col = win.GetColumn(pos)
 
1662
            linestart = pos-col
 
1663
            a = max(linestart+col+incr, linestart)
 
1664
        else:
 
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)
 
1670
            m = (count+incr)
 
1671
            m += cmp(0, incr)*(m%incr)
 
1672
            m = max(m, 0)
 
1673
            win.SetLineIndentation(ln, m)
 
1674
        if x==y:
 
1675
            pos = pos + (m-count) - min(0, col + (m-count))
 
1676
            win.SetSelection(pos, pos)
 
1677
        else:
 
1678
            p = 0
 
1679
            if lnstart != 0:
 
1680
                p = win.GetLineEndPosition(lnstart-1) + len(win.format)
 
1681
            win.SetSelection(p, win.GetLineEndPosition(lnend))
 
1682
        win.EndUndoAction()
 
1683
 
 
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()
 
1695
        dlg.Destroy()
 
1696
        if resp == wxID_OK:
 
1697
            k = len(valu)
 
1698
            a = col_line-3-k
 
1699
            b = a*'-'
 
1700
            st = '%s%s %s %s%s'%('#', b[:a/2], valu, b[a/2:], win.format)
 
1701
            lin = win.GetCurrentLine()
 
1702
            if lin>0:
 
1703
                win.InsertText(win.GetLineEndPosition(lin-1)+len(win.format), st)
 
1704
            else:
 
1705
                win.InsertText(0, st)
 
1706
            win.MakeDirty()
 
1707
        else:
 
1708
            e.Skip()
 
1709
 
 
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:
 
1716
            end = end - 1
 
1717
        win.MakeDirty()
 
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, '<!-- ')
 
1729
                else:
 
1730
                    win.InsertText(firstChar, '## ')
 
1731
        win.SetCurrentPos(win.PositionFromLine(start))
 
1732
        win.SetAnchor(win.GetLineEndPosition(end))
 
1733
        win.EndUndoAction()
 
1734
 
 
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:
 
1741
            end = end - 1
 
1742
        win.MakeDirty()
 
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)
 
1748
            lengtha = 0
 
1749
            rangeb = None
 
1750
            if len(texta.strip()) != 0:
 
1751
                if win.GetLexer() == wxSTC_LEX_CPP:
 
1752
                    if texta.startswith('// '):
 
1753
                        lengtha = 3
 
1754
                    elif texta.startswith('//'):
 
1755
                        lengtha = 2
 
1756
                ## elif win.GetLexer() in (wxSTC_LEX_HTML, wxSTC_LEX_XML):
 
1757
                    ## if texta.startswith('<!-- '):
 
1758
                        ## lengtha = 5
 
1759
                    ## elif texta.startswith('<!--'):
 
1760
                        ## lengtha = 4
 
1761
                    
 
1762
                    ## if lengtha:
 
1763
                        ## if texta.endswith(' -->'):
 
1764
                            ## rangeb = (lastChar-4, lastChar)
 
1765
                        ## elif texta.endswith('-->'):
 
1766
                            ## rangeb = (lastChar-3, lastChar)
 
1767
                else:
 
1768
                    if texta.startswith('## '):
 
1769
                        lengtha = 3
 
1770
                    elif texta.startswith('##'):
 
1771
                        lengtha = 2
 
1772
                    elif texta.startswith('#'):
 
1773
                        lengtha = 1
 
1774
            if lengtha:
 
1775
                if rangeb:
 
1776
                    win.SetSelection(*rangeb)
 
1777
                    win.ReplaceSelection("")
 
1778
                
 
1779
                win.SetSelection(firstChar,firstChar+lengtha)
 
1780
                win.ReplaceSelection("")
 
1781
 
 
1782
        win.SetCurrentPos(win.PositionFromLine(start))
 
1783
        win.SetAnchor(win.GetLineEndPosition(end))
 
1784
        win.EndUndoAction()
 
1785
    
 
1786
    def OnTriggerExpansion(self, e):
 
1787
        num, win = self.getNumWin(e)
 
1788
        win.added(None)
 
1789
 
 
1790
#----------------------- Find and Replace Bar Display ------------------------
 
1791
    def getNumWin(self, e=None):
 
1792
        num = self.control.GetSelection()
 
1793
        if num >= 0:
 
1794
            return num, self.control.GetPage(num).GetWindow1()
 
1795
        if e:
 
1796
            e.Skip()
 
1797
        raise cancelled
 
1798
 
 
1799
        return data
 
1800
 
 
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()
 
1805
        
 
1806
        if not win.parent.IsSplit():
 
1807
            bar = findbar.FindBar(win.parent, self)
 
1808
            win.parent.SplitHorizontally(win, bar, -(bar.GetBestSize())[1]-5)
 
1809
 
 
1810
        bar = win.parent.GetWindow2()
 
1811
        focused = self.FindFocus()
 
1812
        hasfocus = (focused == bar) or (focused and focused.GetParent() == bar)
 
1813
 
 
1814
        self.commonbar(win)
 
1815
 
 
1816
        if hasfocus:
 
1817
            bar.OnFindN(evt)
 
1818
 
 
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)
 
1826
 
 
1827
        self.commonbar(win)
 
1828
 
 
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)
 
1836
        if st != end:
 
1837
            x = win.GetTextRange(st, end)
 
1838
            try:
 
1839
                x = str(x)
 
1840
            except UnicodeError:
 
1841
                pass
 
1842
            if not isinstance(x, unicode):
 
1843
                rx = x.encode('string-escape')
 
1844
                if rx != x:
 
1845
                    x = repr(x)
 
1846
            box.SetValue(x)
 
1847
            win.SetSelection(st, end)
 
1848
 
 
1849
        box.SetFocus()
 
1850
        if isinstance(box, wxTextCtrl):
 
1851
            box.SetSelection(0, box.GetLastPosition())
 
1852
        else:
 
1853
            box.SetMark(0, box.GetLastPosition())
 
1854
 
 
1855
    def OnFindAgain(self, evt):
 
1856
        num, win = self.getNumWin(evt)
 
1857
        if win.parent.IsSplit():
 
1858
            win.parent.GetWindow2().OnFindN(evt)
 
1859
        win.SetFocus()
 
1860
 
 
1861
#----------------------------- View Menu Methods -----------------------------
 
1862
 
 
1863
    def Maximize(self, b):
 
1864
        wxFrame.Maximize(b)
 
1865
        wxPostEvent(wxSizeEvent((0,0), self.GetId()))
 
1866
 
 
1867
    def OnZoom(self, e):
 
1868
        wnum, win = self.getNumWin(e)
 
1869
        if e.GetId() == ZI:incr = 1
 
1870
        else:              incr = -1
 
1871
        win.SetZoom(win.GetZoom()+incr)
 
1872
 
 
1873
    def OnGoto(self, e):
 
1874
 
 
1875
        wnum, win = self.getNumWin(e)
 
1876
        valu = self.getInt('Which line would you like to advance to?', '', win.LineFromPosition(win.GetSelection()[0])+1)
 
1877
        valu -= 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)
 
1883
    
 
1884
    def OnJumpF(self, e):
 
1885
        num, win = self.getNumWin(e)
 
1886
        win.jump(1)
 
1887
        
 
1888
    def OnJumpB(self, e):
 
1889
        num, win = self.getNumWin(e)
 
1890
        win.jump(-1)
 
1891
 
 
1892
    def OnRefresh(self, e, win=None):
 
1893
        if win is None:
 
1894
            num, win = self.getNumWin(e)
 
1895
        self.OnDocumentChange(win, True)
 
1896
 
 
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)
 
1902
        else:
 
1903
            win.MarkerAdd(lineNo, BOOKMARKNUMBER)
 
1904
 
 
1905
    def OnNextBookmark  (self, e):
 
1906
        wnum, win = self.getNumWin(e)
 
1907
        lineNo = win.GetCurrentLine()
 
1908
        newLineNo = win.MarkerNext(lineNo + 1, BOOKMARKMASK)
 
1909
        if newLineNo != -1:
 
1910
            win.GotoLine(newLineNo)
 
1911
        else:
 
1912
            lineNo = win.GetLineCount()
 
1913
            newLineNo = win.MarkerNext(0, BOOKMARKMASK)
 
1914
            if newLineNo != -1:
 
1915
                win.GotoLine(newLineNo)
 
1916
        win.EnsureVisible(win.GetCurrentLine())
 
1917
        win.EnsureCaretVisible()
 
1918
 
 
1919
    def OnPreviousBookmark (self, e):
 
1920
        wnum, win = self.getNumWin(e)
 
1921
        lineNo = win.GetCurrentLine()
 
1922
        newLineNo = win.MarkerPrevious(lineNo - 1, BOOKMARKMASK)
 
1923
        if newLineNo != -1:
 
1924
            win.GotoLine(newLineNo)
 
1925
        else:
 
1926
            lineNo = win.GetLineCount()
 
1927
            newLineNo = win.MarkerPrevious(lineNo, BOOKMARKMASK)
 
1928
            if newLineNo != -1:
 
1929
                win.GotoLine(newLineNo)
 
1930
        win.EnsureVisible(win.GetCurrentLine())
 
1931
        win.EnsureCaretVisible()
 
1932
 
 
1933
    def OnLeft(self, e):
 
1934
        self.control.AdvanceSelection(False)
 
1935
 
 
1936
    def OnRight(self, e):
 
1937
        self.control.AdvanceSelection(True)
 
1938
    
 
1939
#--------------------------- Document Menu Methods ---------------------------
 
1940
 
 
1941
    def OnStyleChange(self,e):
 
1942
        wnum, win = self.getNumWin(e)
 
1943
        win.changeStyle(stylefile, lexers[e.GetId()])
 
1944
 
 
1945
    def style(self, fn):
 
1946
        ext = fn.split('.')[-1].lower()
 
1947
        return extns.get(ext, DEFAULTLEXER)
 
1948
 
 
1949
    def OnEncChange(self, e):
 
1950
        num, win = self.getNumWin(e)
 
1951
        mid = e.GetId()
 
1952
        newenc = self.menubar.GetLabel(mid)
 
1953
        oldenc = win.enc
 
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)
 
1959
 
 
1960
    def OnLineEndChange(self, e):
 
1961
        n, win = self.getNumWin(e)
 
1962
        endid = e.GetId()
 
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)
 
1969
 
 
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
 
1977
 
 
1978
    def OnNumberToggle(self, e):
 
1979
        n, win = self.getNumWin(e)
 
1980
        win.SetMarginWidth(0, (win.GetMarginWidth(0)+40)%80)
 
1981
 
 
1982
    def OnMarginToggle(self, e):
 
1983
        n, win = self.getNumWin(e)
 
1984
        win.SetMarginWidth(1, (win.GetMarginWidth(1)+16)%32)
 
1985
 
 
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
 
1992
 
 
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)
 
2000
 
 
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)
 
2006
        try: wxYield()
 
2007
        except: pass
 
2008
 
 
2009
        #toss all the old folds
 
2010
        self.OnExpandAll(e)
 
2011
 
 
2012
        lc = win.GetLineCount()
 
2013
        lines = []
 
2014
        for line in xrange(lc):
 
2015
            if win.GetFoldLevel(line) & wxSTC_FOLDLEVELHEADERFLAG:
 
2016
                lines.append(line)
 
2017
        lines.reverse()
 
2018
        for line in lines:
 
2019
            a = win.GetLastChild(line, -1)
 
2020
            win.HideLines(line+1,a)
 
2021
            win.SetFoldExpanded(line, 0)
 
2022
 
 
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))
 
2028
 
 
2029
    def OnWrapL(self, e):
 
2030
        wnum, win = self.getNumWin(e)
 
2031
        self.WrapToggle(win)
 
2032
 
 
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)
 
2043
 
 
2044
        if win.GetWrapMode() == wxSTC_WRAP_NONE:
 
2045
            win.SetWrapMode(wxSTC_WRAP_WORD)
 
2046
 
 
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)
 
2056
        else:
 
2057
            win.SetWrapMode(wxSTC_WRAP_NONE)
 
2058
 
 
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)
 
2068
 
 
2069
    def OnSetTriggers(self, e):
 
2070
        num, win = self.getNumWin(e)
 
2071
        print win.triggers
 
2072
        a = TriggerDialog(self, win, win.triggers)
 
2073
        a.ShowModal()
 
2074
 
 
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.",
 
2078
                           win.GetIndent())
 
2079
        win.SetIndent(rslt)
 
2080
 
 
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.",
 
2086
                           win.GetTabWidth())
 
2087
 
 
2088
        win.SetTabWidth(rslt)
 
2089
 
 
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())
 
2096
 
 
2097
        win.SetEdgeColumn(rslt)
 
2098
 
 
2099
    def OnSetLongLineMode(self, e):
 
2100
        n, win = self.getNumWin(e)
 
2101
        eid = e.GetId()
 
2102
        win.SetEdgeMode(LL_MAPPING[eid])
 
2103
#--------------------------- Options Menu Methods ----------------------------
 
2104
 
 
2105
    def OnSaveLang(self, e):
 
2106
        mid = e.GetId()
 
2107
        lang, desc = SOURCE_ID_TO_OPTIONS.get(mid, ('python', ''))
 
2108
        n, win = self.getNumWin()
 
2109
        dct = win.GetSaveState()
 
2110
        del dct['BM']
 
2111
        del dct['FOLD']
 
2112
        document_defaults[lang].update(dct)
 
2113
        self.SetStatusText("Updated document defaults for " + desc)
 
2114
    
 
2115
    def OnLoadSavedLang(self, e):
 
2116
        mid = e.GetId()
 
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)))
 
2126
    
 
2127
    def OnDefaultStyleChange(self, e):
 
2128
        dl = lexers[e.GetId()]
 
2129
        self.config['DEFAULTLEXER'] = dl
 
2130
        globals()['DEFAULTLEXER'] = dl
 
2131
    
 
2132
    def OnSaveSettings(self, e):
 
2133
        #unused right now.
 
2134
        n, win = self.getNumWin()
 
2135
        dct = win.GetSaveState()
 
2136
        del dct['BM']
 
2137
        del dct['FOLD']
 
2138
 
 
2139
        globals().update(dct)
 
2140
        self.config['DOCUMENT_DEFAULTS'] = dct
 
2141
 
 
2142
    def OnDNDToggle(self, e):
 
2143
        global dnd_file
 
2144
        dnd_file = (dnd_file + 1)%2
 
2145
 
 
2146
    def OnLogBarToggle(self, e):
 
2147
        global logbarlocn
 
2148
        logbarlocn = (logbarlocn + 1)%2
 
2149
 
 
2150
    def OnDocBarToggle(self, e):
 
2151
        global docbarlocn
 
2152
        docbarlocn = (docbarlocn + 1)%2
 
2153
    
 
2154
    def OnShowWideToggle(self, e):
 
2155
        global SHOWWIDE
 
2156
        SHOWWIDE = (SHOWWIDE + 1)%2
 
2157
        if SHOWWIDE:
 
2158
            self.BOTTOM.Show()
 
2159
        else:
 
2160
            self.BOTTOM.Hide()
 
2161
        self.OnSize(None)
 
2162
        
 
2163
    def OnShowTallToggle(self, e):
 
2164
        global SHOWTALL
 
2165
        SHOWTALL = (SHOWTALL + 1)%2
 
2166
        if SHOWTALL:
 
2167
            self.RIGHT.Show()
 
2168
        else:
 
2169
            self.RIGHT.Hide()
 
2170
        self.OnSize(None)
 
2171
    
 
2172
    def OnTodoToggle(self, e):
 
2173
        global TODOBOTTOM
 
2174
        TODOBOTTOM = (TODOBOTTOM + 1)%2
 
2175
    
 
2176
    def OnToolbarToggle(self, e):
 
2177
        global TOOLBAR
 
2178
        TOOLBAR = (TOOLBAR + 1)%2
 
2179
 
 
2180
    def OnCaret(self, e):
 
2181
        global caret_option
 
2182
        i = e.GetId()
 
2183
        caret_option, flags = CARET_ID_TO_OPTIONS[i]
 
2184
        self.SharedCaret()
 
2185
 
 
2186
    def OnCaretM(self, e):
 
2187
        global caret_slop
 
2188
        caret_slop = self.getInt("Set Caret M Value", "", caret_slop)
 
2189
        self.SharedCaret()
 
2190
 
 
2191
    def OnCaretN(self, e):
 
2192
        global caret_multiplier
 
2193
        caret_multiplier = self.getInt("Set Caret N Value", "", caret_multiplier)
 
2194
        self.SharedCaret()
 
2195
 
 
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())
 
2202
    
 
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)
 
2208
        del a['find']
 
2209
        del a['replace']
 
2210
        global findbarprefs
 
2211
        findbarprefs = a
 
2212
    
 
2213
    def OnFindbarClear(self, e):
 
2214
        n, win = self.getNumWin()
 
2215
        if win.GetParent().IsSplit():
 
2216
            bar = win.GetParent().GetWindow2()
 
2217
            bar.box1.Clear()
 
2218
            bar.box1.SetValue("")
 
2219
            if not isinstance(bar, findbar.FindBar):
 
2220
                bar.box2.Clear()
 
2221
                bar.box2.SetValue("")
 
2222
            else:
 
2223
                win.findbarprefs['replace'] = []
 
2224
        else:
 
2225
            win.findbarprefs['find'] = []
 
2226
            win.findbarprefs['replace'] = []
 
2227
    
 
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)
 
2232
    
 
2233
    def OnChangeMenu(self, e):
 
2234
        MenuItemDialog(self, self).ShowModal()
 
2235
    
 
2236
    def OnChangeTitle(self, e):
 
2237
        global title_option
 
2238
        i = e.GetId()
 
2239
        title_option, _, _ = TITLE_ID_TO_OPTIONS[i]
 
2240
        self.updateWindowTitle()
 
2241
        
 
2242
#----------------------------- Help Menu Methods -----------------------------
 
2243
    def OnAbout(self, e):
 
2244
        txt = """
 
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
 
2248
        here it is.
 
2249
 
 
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.
 
2254
 
 
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.
 
2258
 
 
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...")
 
2263
 
 
2264
    def OnHelp(self, e):
 
2265
        a = open(os.path.join(runpath, 'readme.txt'), 'rb')
 
2266
        txt = a.read()
 
2267
        a.close()
 
2268
        dlg = wxScrolledMessageDialog(self, txt, "Help!")
 
2269
        dlg.ShowModal()
 
2270
        dlg.Destroy()
 
2271
#-------------------------- Hot Key support madness --------------------------
 
2272
    def OnKeyPressed(self, event):
 
2273
        showpress=0
 
2274
 
 
2275
        keypressed = GetKeyPress(event)
 
2276
 
 
2277
        if showpress: print "keypressed", keypressed
 
2278
        key = event.KeyCode()
 
2279
        wnum = self.control.GetSelection()
 
2280
        pagecount = self.control.GetPageCount()
 
2281
        if wnum > -1:
 
2282
            win = self.control.GetPage(wnum).GetWindow1()
 
2283
 
 
2284
        if keypressed in HOTKEY_TO_ID:
 
2285
            menuid = HOTKEY_TO_ID[keypressed]
 
2286
            wxPostEvent(self, wxMenuEvent(wxEVT_COMMAND_MENU_SELECTED, menuid))
 
2287
 
 
2288
        else:
 
2289
            if pagecount:
 
2290
                if (key==13):
 
2291
                    #when 'enter' is pressed, indentation needs to happen.
 
2292
                    #
 
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():
 
2299
                        win.CallTipCancel()
 
2300
 
 
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]
 
2307
 
 
2308
                    #get info about the current line's indentation
 
2309
                    ind = win.GetLineIndentation(linenum)                    
 
2310
                    
 
2311
                    xtra = 0
 
2312
                    
 
2313
                    lang = extns.get(win.filename.split('.')[-1].lower(), DEFAULTLEXER)
 
2314
                    
 
2315
                    if col <= ind:
 
2316
                        xtra = None
 
2317
                        if win.GetUseTabs():
 
2318
                            win.ReplaceSelection(win.format+(col*' ').replace(win.GetTabWidth()*' ', '\t'))
 
2319
                        else:
 
2320
                            win.ReplaceSelection(win.format+(col*' '))
 
2321
                    elif not pos:
 
2322
                        xtra = None
 
2323
                        win.ReplaceSelection(win.format)
 
2324
                    
 
2325
                    elif lang == 'cpp':
 
2326
                        ## print "indent on return for cpp"
 
2327
                        dmap = {'{':1, '}':-1}
 
2328
                        for ch in line:
 
2329
                            xtra += dmap.get(ch, 0)
 
2330
                        
 
2331
                        if line.split()[:1] == ['return']:
 
2332
                            xtra -= 1
 
2333
                    
 
2334
                    #insert other indentation per language here.
 
2335
                    
 
2336
                    else: #if language is python
 
2337
                        print "indent on return for python"
 
2338
                        colon = ord(':')
 
2339
                        
 
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)
 
2344
                                if not xtra:
 
2345
                                    if (styl==10) and (win.GetCharAt(i) == colon):
 
2346
                                        xtra = 1
 
2347
                                elif (styl == 1):
 
2348
                                    #it is a comment, ignore the character
 
2349
                                    pass
 
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
 
2353
                                    pass
 
2354
                                else:
 
2355
                                    #this is not a comment or some innocuous other character
 
2356
                                    #this is a docstring or otherwise, no additional indent
 
2357
                                    xtra = 0
 
2358
                                    #commenting the break fixes stuff like this
 
2359
                                    # for i in blah[:]:
 
2360
                                    #break
 
2361
                            if xtra:
 
2362
                                #This deals with ending single and multi-line definitions properly.
 
2363
                                while linenum >= 0:
 
2364
                                    found = []
 
2365
                                    for i in ['def', 'class', 'if', 'else', 'elif', 'while',
 
2366
                                            'for', 'try', 'except', 'finally']:
 
2367
                                        a = line.find(i)
 
2368
                                        if (a > -1):
 
2369
                                            found.append(a)
 
2370
                                    #print 'fnd', found
 
2371
                                    if found: found = min(found)
 
2372
                                    else:     found = -1
 
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)
 
2377
                                        break
 
2378
                                    linenum -= 1
 
2379
                                    line = win.GetLine(linenum)
 
2380
                        #if we were to do indentation for ()[]{}, it would be here
 
2381
                        if not xtra:
 
2382
                            #yep, right here.
 
2383
                            fnd = 0
 
2384
                            for i in "(){}[]":
 
2385
                                if (line.find(i) > -1):
 
2386
                                    fnd = 1
 
2387
                                    break
 
2388
                            if fnd:
 
2389
                                seq = []
 
2390
                                #print "finding stuff"
 
2391
                                for i in "(){}[]":
 
2392
                                    a = line.find(i)
 
2393
                                    start = 0
 
2394
                                    while a > -1:
 
2395
                                        start += a+1
 
2396
                                        if win.GetStyleAt(start+linestart-1)==10:
 
2397
                                            seq.append((start, i))
 
2398
                                        a = line[start:].find(i)
 
2399
                                seq.sort()
 
2400
                                cl = {')':'(', ']': '[', '}': '{',
 
2401
                                    '(':'',  '[': '',  '{': ''}
 
2402
                                stk = []
 
2403
                                #print "making tree"
 
2404
                                for po, ch in seq:
 
2405
                                    #print ch,
 
2406
                                    if not cl[ch]:
 
2407
                                        #standard opening
 
2408
                                        stk.append((po, ch))
 
2409
                                    elif stk:
 
2410
                                        if cl[ch] == stk[-1][1]:
 
2411
                                            #proper closing of something
 
2412
                                            stk.pop()
 
2413
                                        else:
 
2414
                                            #probably a syntax error
 
2415
                                            #does it matter what is done?
 
2416
                                            stk = []
 
2417
                                            break
 
2418
                                    else:
 
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.
 
2429
            #Fuck that.
 
2430
            #People can use the improved single-line dedent with crtl+[.
 
2431
                                        stk = []
 
2432
                                        break
 
2433
                                if stk:
 
2434
                                    #print "stack remaining", stk
 
2435
                                    ind = stk[-1][0]
 
2436
                        if not xtra:
 
2437
                            ls = line.lstrip()
 
2438
                            if (ls[:6] == 'return') or (ls[:4] == 'pass'):
 
2439
                                xtra = -1
 
2440
                    
 
2441
                    if xtra != None:
 
2442
                        a = ind*' '
 
2443
                        if win.GetUseTabs():
 
2444
                            a = a.replace(win.GetTabWidth()*' ', '\t')
 
2445
                        win.ReplaceSelection(win.format+a)
 
2446
                        if xtra > 0:
 
2447
                            for i in xrange(xtra):
 
2448
                                self.OnIndent(event)
 
2449
                        elif xtra < 0:
 
2450
                            for i in xrange(-xtra):
 
2451
                                self.OnDedent(event)
 
2452
                else:
 
2453
                    event.Skip()
 
2454
                    if not (win.GetStyleAt(win.GetCurrentPos())):
 
2455
                        #3, 13, 6, 7
 
2456
                        if win.CallTipActive():
 
2457
                            good = STRINGPRINTABLE
 
2458
                            if (key in good) or (key in (WXK_SHIFT, WXK_CONTROL, WXK_ALT)):
 
2459
                                pass
 
2460
                                #if key in (48, 57) and event.ShiftDown():
 
2461
                                #    win.CallTipCancel()
 
2462
                                #else it is something in the arguments that is OK.
 
2463
                            else:
 
2464
                                win.CallTipCancel()
 
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, []))
 
2469
                            if tip:
 
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)
 
2479
            else:
 
2480
                return event.Skip()
 
2481
 
 
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())
 
2487
        cur = colpos-1
 
2488
        while (cur >= 0) and not (line[cur:cur+1] in bad):
 
2489
            cur -= 1
 
2490
        cur += 1
 
2491
        return cur, colpos, line[cur:colpos]
 
2492
 
 
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)
 
2498
        self.cached = None
 
2499
        self.MarkerDefine(BOOKMARKNUMBER, BOOKMARKSYMBOL, 'blue', 'blue')
 
2500
 
 
2501
        _, flags = CARET_OPTION_TO_ID[caret_option]
 
2502
        self.SetXCaretPolicy(flags, caret_slop*caret_multiplier)
 
2503
        self.SetYCaretPolicy(flags, caret_slop)
 
2504
 
 
2505
        self.tree1 = hierCodeTreePanel(notebook.root, notebook.root.leftt)
 
2506
        self.tree1.Hide()
 
2507
        self.tree1.tree.SORTTREE = 0
 
2508
        self.tree1.parent.sizer.Layout()
 
2509
        self.tree2 = hierCodeTreePanel(notebook.root, notebook.root.rightt)
 
2510
        self.tree2.Hide()
 
2511
        self.tree2.tree.SORTTREE = 1
 
2512
        self.tree1.parent.sizer.Layout()
 
2513
 
 
2514
        self.hierarchy = []
 
2515
        self.kw = []
 
2516
        self.tooltips = {}
 
2517
 
 
2518
        self.parent = parent
 
2519
        self.notebook = notebook #should also be equal to self.parent.parent
 
2520
        self.root = self.notebook.root
 
2521
        self.dirty = 0
 
2522
        self.refresh = 0
 
2523
 
 
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))
 
2526
 
 
2527
        #for command comlpetion
 
2528
        self.SetKeyWords(0, " ".join(keyword.kwlist))
 
2529
 
 
2530
        self.SetMargins(0,0)
 
2531
        self.SetViewWhiteSpace(False)
 
2532
        self.SetBackSpaceUnIndents(1)
 
2533
        #self.SetBufferedDraw(False)
 
2534
        #self.SetViewEOL(True)
 
2535
 
 
2536
        self.SetMarginType(0, wxSTC_MARGIN_NUMBER)
 
2537
        #self.StyleSetSpec(wxSTC_STYLE_LINENUMBER, "size:%(size)d,face:%(mono)s" % faces)
 
2538
 
 
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?
 
2542
 
 
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)
 
2548
 
 
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")
 
2557
 
 
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")
 
2566
 
 
2567
 
 
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.
 
2571
 
 
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
 
2574
        #demo r0XX0rs.
 
2575
 
 
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)
 
2582
 
 
2583
        #various settings
 
2584
        self.SetSelBackground(1, '#B0B0FF')
 
2585
 
 
2586
        #again, some state variables
 
2587
        self.filename = ''
 
2588
        self.dirname = ''
 
2589
        self.opened = 0
 
2590
        self.AutoCompStops(' .,;:()[]{}\'"\\<>%^&+-=*/|`')
 
2591
 
 
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)
 
2597
 
 
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)
 
2605
 
 
2606
        if REM_SWAP:
 
2607
            self.CmdKeyClear(ord('T'), wxSTC_SCMOD_CTRL)
 
2608
 
 
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)
 
2615
 
 
2616
    def pos(self, e):
 
2617
        #print "position changed event"
 
2618
        #for some reason I never get called
 
2619
        self.pos_ch(e)
 
2620
 
 
2621
    def cha(self, e):
 
2622
        #print "changed event"
 
2623
        self.key_up(e)
 
2624
 
 
2625
    def save(self, e):
 
2626
        #print "save reached"
 
2627
        self.key_up(e)
 
2628
 
 
2629
    def savel(self, e):
 
2630
        #print "save left"
 
2631
        self.key_up(e)
 
2632
 
 
2633
    def key_up(self, e):
 
2634
        if self.GetModify(): self.MakeDirty()
 
2635
        else:                self.MakeClean()
 
2636
        self.pos_ch(e)
 
2637
        #e.Skip()
 
2638
    
 
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)
 
2643
        if e:
 
2644
            e.Skip()
 
2645
 
 
2646
    def added(self, e):
 
2647
        try:
 
2648
            full = e is None
 
2649
            tr = self.triggers
 
2650
            c = 0
 
2651
            gcp = self.GetCurrentPos()
 
2652
            for p in xrange(gcp-1, -1, -1):
 
2653
                if not full and p < gcp-1:
 
2654
                    break
 
2655
                ch = self.GetCharAt(p)
 
2656
                if UNICODE:
 
2657
                    ch = (chr((ch>>8)&255)+chr(ch&255)).decode('utf-16-be')
 
2658
                else:
 
2659
                    ch = chr(ch)
 
2660
                c += 1
 
2661
                tr = tr.get(ch, None)
 
2662
                if tr is None:
 
2663
                    ## print "ran off of triggers!", ch, gcp-p-1
 
2664
                    break
 
2665
                elif type(tr) is tuple:
 
2666
                    self.SetSelection(p, p+c)
 
2667
                    self.ReplaceSelection(tr[0])
 
2668
                    p += len(tr[0])
 
2669
                    self.SetSelection(p,p)
 
2670
                    self.InsertText(p, tr[1])
 
2671
                    break
 
2672
        finally:
 
2673
            self.key_up(e)
 
2674
    
 
2675
    def jump(self, direction):
 
2676
        #1 forward, -1 backward
 
2677
        if direction not in (1,-1):
 
2678
            return
 
2679
 
 
2680
        #set up characters
 
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
 
2688
        
 
2689
        #cursor position information
 
2690
        linenum = self.GetCurrentLine()
 
2691
        pos = self.GetCurrentPos()
 
2692
        
 
2693
        #iterator setup
 
2694
        if direction == 1:
 
2695
            it = xrange(pos, self.GetTextLength())
 
2696
        else:
 
2697
            it = xrange(pos-1, -1, -1)
 
2698
        
 
2699
        #updates information cross-lines
 
2700
        for p in it:
 
2701
            ch = self.GetTextRange(p, p+1)
 
2702
            if ch not in chars1:
 
2703
                continue
 
2704
            
 
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
 
2707
                if ch in chars2:
 
2708
                    p += 1
 
2709
                    break
 
2710
                #else if this character is just to the right of where we are at, skip it
 
2711
                elif p == pos:
 
2712
                    continue
 
2713
                #else if we want to be to the left of line[p], make it so
 
2714
                elif ch in chars3:
 
2715
                    break
 
2716
            else: #else we are heading to the left
 
2717
                #if we want to be to the left of line[p], make it so
 
2718
                if ch in chars3:
 
2719
                    break
 
2720
                #else if this character is just to the left of where we are at, skip it
 
2721
                elif p == pos-1:
 
2722
                    continue
 
2723
                #else if we want to be to the right of line[p], make it so
 
2724
                elif ch in chars2:
 
2725
                    p += 1
 
2726
                    break
 
2727
            
 
2728
        else:
 
2729
            return
 
2730
        self.SetSelection(p, p)
 
2731
 
 
2732
#------------------------- persistant document state -------------------------
 
2733
    def GetSaveState(self):
 
2734
        BM = []
 
2735
        FOLD = []
 
2736
        if self.GetParent().IsSplit():
 
2737
            self.GetParent().GetWindow2().savePreferences()
 
2738
        ret =  {'BM':BM,
 
2739
                'FOLD':FOLD,
 
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,
 
2755
               }
 
2756
        for line in xrange(self.GetLineCount()):
 
2757
            if self.MarkerGet(line) & BOOKMARKMASK:
 
2758
                BM.append(line)
 
2759
 
 
2760
            if (self.GetFoldLevel(line) & wxSTC_FOLDLEVELHEADERFLAG) and\
 
2761
            (not self.GetFoldExpanded(line)):
 
2762
                FOLD.append(line)
 
2763
        FOLD.reverse()
 
2764
        return ret
 
2765
 
 
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)
 
2789
 
 
2790
        try: wxYield()
 
2791
        except: pass
 
2792
 
 
2793
        if self.save_cursor:
 
2794
            a = saved.get('cursor_posn', 0)
 
2795
            self.SetSelection(a,a)
 
2796
            self.EnsureCaretVisible()
 
2797
            self.ScrollToColumn(0)
 
2798
 
 
2799
#-------------------- fix for SetText for the 'dirty bit' --------------------
 
2800
    def SetText(self, txt, emptyundo=1):
 
2801
        self.SetEOLMode(fmt_mode[self.format])
 
2802
        self.enc = 'ascii'
 
2803
        if UNICODE:
 
2804
            for bom, enc in BOM:
 
2805
                if txt[:len(bom)] == bom:
 
2806
                    self.enc = enc
 
2807
                    txt = txt[len(bom):]
 
2808
                    #print "chose", enc
 
2809
                    break
 
2810
            if self.enc != 'ascii':
 
2811
                try:    txt = txt.decode(self.enc)
 
2812
                except:
 
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.")
 
2824
                    self.enc = ascii
 
2825
        wxStyledTextCtrl.SetText(self, txt)
 
2826
        self.ConvertEOLs(fmt_mode[self.format])
 
2827
        self.opened = 1
 
2828
        if emptyundo:
 
2829
            self.EmptyUndoBuffer()
 
2830
            self.SetSavePoint()
 
2831
 
 
2832
    def GetText(self):
 
2833
        self.ConvertEOLs(fmt_mode[self.format])
 
2834
        if UNICODE:
 
2835
            if self.enc == 'ascii':
 
2836
                try:
 
2837
                    return wxStyledTextCtrl.GetText(self).encode(self.enc)
 
2838
                except:
 
2839
                    #Previously non-unicode ascii file has had unicode characters
 
2840
                    #inserted.  Must encode into some sort of unicode format.
 
2841
                    self.enc = 'utf-8'
 
2842
                    self.root.SetStatusText(self.enc, 2)
 
2843
            return ADDBOM[self.enc] + wxStyledTextCtrl.GetText(self).encode(self.enc)
 
2844
        return wxStyledTextCtrl.GetText(self)
 
2845
 
 
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:
 
2849
            self.dirty = 1
 
2850
            f = self.filename
 
2851
            if f == ' ':
 
2852
                f = '<untitled %i>'%self.NEWDOCUMENT
 
2853
            c = 0
 
2854
            for i in self.notebook:
 
2855
                if i == self:
 
2856
                    break
 
2857
                c += 1
 
2858
            self.notebook.SetPageText(c, '* '+f)
 
2859
            self.root.redrawvisible(self)
 
2860
        if e:
 
2861
            e.Skip()
 
2862
 
 
2863
    def MakeClean(self, e=None):
 
2864
        if self.dirty:
 
2865
            self.dirty = 0
 
2866
            f = self.filename
 
2867
            if f == ' ':
 
2868
                f = '<untitled %i>'%self.NEWDOCUMENT
 
2869
            c = 0
 
2870
            for i in self.notebook:
 
2871
                if i == self:
 
2872
                    break
 
2873
                c += 1
 
2874
            self.notebook.SetPageText(c, f)
 
2875
            self.SetSavePoint()
 
2876
            self.root.redrawvisible(self)
 
2877
        if e:
 
2878
            e.Skip()
 
2879
 
 
2880
 
 
2881
    def nada(self, e):
 
2882
        pass
 
2883
 
 
2884
    def do(self, funct, dirty=1):
 
2885
        if dirty: self.MakeDirty(None)
 
2886
        funct(self)
 
2887
        self.root.redrawvisible(self)
 
2888
 
 
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)
 
2894
 
 
2895
#--------- Ahh, the style change code...isn't it great?  Not really. ---------
 
2896
    def changeStyle(self, stylefile, language):
 
2897
        try:
 
2898
            #from StyleSupport import initSTC
 
2899
            from STCStyleEditor import initSTC
 
2900
            initSTC(self, stylefile, language)
 
2901
            
 
2902
        except:
 
2903
            #self.root.exceptDialog("Style Change failed, assuming plain text")
 
2904
            self.root.SetStatusText("Style Change failed, assuming plain text")
 
2905
 
 
2906
#----------------- Defaults, in case the other code was bad. -----------------
 
2907
            #for some default font styles
 
2908
 
 
2909
            self.SetLexer(wxSTC_LEX_NULL)
 
2910
 
 
2911
            ### Python styles
 
2912
            ##
 
2913
            ### White space
 
2914
            ##self.StyleSetSpec(wxSTC_P_DEFAULT, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
 
2915
            ### Comment
 
2916
            ##self.StyleSetSpec(wxSTC_P_COMMENTLINE, "fore:#007F00,face:%(mono)s,back:#E0FFE0,size:%(size)d" % faces)
 
2917
            ### Number
 
2918
            ##self.StyleSetSpec(wxSTC_P_NUMBER, "fore:#007F7F,face:%(times)s,size:%(size)d" % faces)
 
2919
            ### String
 
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)
 
2923
            ### Keyword
 
2924
            ##self.StyleSetSpec(wxSTC_P_WORD, "fore:#F0B000,face:%(mono)s,size:%(size)d,bold" % faces)
 
2925
            ### Triple quotes
 
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)
 
2933
            ### Operators
 
2934
            ##self.StyleSetSpec(wxSTC_P_OPERATOR, "face:%(times)s,size:%(size)d" % faces)
 
2935
            ### Identifiers
 
2936
            ##self.StyleSetSpec(wxSTC_P_IDENTIFIER, "fore:#000000,face:%(helv)s,size:%(size)d" % faces)
 
2937
            ### Comment-blocks
 
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)
 
2941
            ##
 
2942
            ##self.SetCaretForeground("BLACK")
 
2943
            ##
 
2944
            ### prototype for registering some images for use in the AutoComplete box.
 
2945
            ###self.RegisterImage(1, images.getSmilesBitmap())
 
2946
 
 
2947
        if self.filename.lower().split('.')[-1:] in (['pyx'], ['pyi']):
 
2948
            #it is pyrex!
 
2949
            self.SetKeyWords(0, ' '.join(keyword.kwlist) + ' struct union enum extern include ctypedef cdef char short int long float double unsigned')
 
2950
 
 
2951
#------------ copied and pasted from the wxStyledTextCtrl_2 demo -------------
 
2952
    def OnUpdateUI(self, evt):
 
2953
        # check for matching braces
 
2954
        braceAtCaret = -1
 
2955
        braceOpposite = -1
 
2956
        charBefore = None
 
2957
        caretPos = self.GetCurrentPos()
 
2958
        if caretPos > 0:
 
2959
            charBefore = self.GetCharAt(caretPos - 1)
 
2960
            styleBefore = self.GetStyleAt(caretPos - 1)
 
2961
 
 
2962
        # check before
 
2963
        if charBefore and chr(charBefore) in "[]{}()" and styleBefore == wxSTC_P_OPERATOR:
 
2964
            braceAtCaret = caretPos - 1
 
2965
 
 
2966
        # check after
 
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
 
2972
 
 
2973
        if braceAtCaret >= 0:
 
2974
            braceOpposite = self.BraceMatch(braceAtCaret)
 
2975
 
 
2976
        if braceAtCaret != -1  and braceOpposite == -1:
 
2977
            self.BraceBadLight(braceAtCaret)
 
2978
        else:
 
2979
            self.BraceHighlight(braceAtCaret, braceOpposite)
 
2980
            #pt = self.PointFromPosition(braceOpposite)
 
2981
            #self.Refresh(True, wxRect(pt.x, pt.y, 5,5))
 
2982
            #print pt
 
2983
            #self.Refresh(False)
 
2984
 
 
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:
 
2990
                if evt.GetShift():
 
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)
 
2997
                    else:
 
2998
                        self.SetFoldExpanded(lineClicked, True)
 
2999
                        self.Expand(lineClicked, True, True, 100)
 
3000
                else:
 
3001
                    self.ToggleFold(lineClicked)
 
3002
 
 
3003
    def FoldAll(self):
 
3004
        lineCount = self.GetLineCount()
 
3005
        expanding = True
 
3006
 
 
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)
 
3011
                break;
 
3012
 
 
3013
        lineNum = 0
 
3014
        while lineNum < lineCount:
 
3015
            level = self.GetFoldLevel(lineNum)
 
3016
            if level & wxSTC_FOLDLEVELHEADERFLAG and \
 
3017
               (level & wxSTC_FOLDLEVELNUMBERMASK) == wxSTC_FOLDLEVELBASE:
 
3018
 
 
3019
                if expanding:
 
3020
                    self.SetFoldExpanded(lineNum, True)
 
3021
                    lineNum = self.Expand(lineNum, True)
 
3022
                    lineNum = lineNum - 1
 
3023
                else:
 
3024
                    lastChild = self.GetLastChild(lineNum, -1)
 
3025
                    self.SetFoldExpanded(lineNum, False)
 
3026
                    if lastChild > lineNum:
 
3027
                        self.HideLines(lineNum+1, lastChild)
 
3028
 
 
3029
            lineNum = lineNum + 1
 
3030
 
 
3031
    def Expand(self, line, doExpand, force=False, visLevels=0, level=-1):
 
3032
        lastChild = self.GetLastChild(line, level)
 
3033
        line = line + 1
 
3034
        while line <= lastChild:
 
3035
            if force:
 
3036
                if visLevels > 0:
 
3037
                    self.ShowLines(line, line)
 
3038
                else:
 
3039
                    self.HideLines(line, line)
 
3040
            else:
 
3041
                if doExpand:
 
3042
                    self.ShowLines(line, line)
 
3043
 
 
3044
            if level == -1:
 
3045
                level = self.GetFoldLevel(line)
 
3046
 
 
3047
            if level & wxSTC_FOLDLEVELHEADERFLAG:
 
3048
                if force:
 
3049
                    if visLevels > 1:
 
3050
                        self.SetFoldExpanded(line, True)
 
3051
                    else:
 
3052
                        self.SetFoldExpanded(line, False)
 
3053
                    line = self.Expand(line, doExpand, force, visLevels-1)
 
3054
 
 
3055
                else:
 
3056
                    if doExpand and self.GetFoldExpanded(line):
 
3057
                        line = self.Expand(line, True, force, visLevels-1)
 
3058
                    else:
 
3059
                        line = self.Expand(line, False, force, visLevels-1)
 
3060
            else:
 
3061
                line = line + 1;
 
3062
 
 
3063
        return line
 
3064
 
 
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)
 
3068
 
 
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=
 
3074
                            wxNB_TOP
 
3075
                            #wxNB_BOTTOM
 
3076
                            #wxNB_LEFT
 
3077
                            #wxNB_RIGHT
 
3078
                            )
 
3079
 
 
3080
        self.root = root
 
3081
        self.AssignImageList(IMGLIST2)
 
3082
 
 
3083
        #for some reason, the notebook needs the next line...the text control
 
3084
        #doesn't.
 
3085
        EVT_KEY_DOWN(self, self.root.OnKeyPressed)
 
3086
        EVT_NOTEBOOK_PAGE_CHANGED(self, self.GetId(), self.OnPageChanged)
 
3087
        self.SetDropTarget(FileDropTarget(self.root))
 
3088
        self.calling = 0
 
3089
 
 
3090
    def __iter__(self):
 
3091
        count = self.GetPageCount()
 
3092
        cur = 0
 
3093
        while cur < count:
 
3094
            r = self.GetPage(cur).GetWindow1()
 
3095
            yield r
 
3096
            cur += 1
 
3097
 
 
3098
    def OnPageChanged(self, event):
 
3099
        if self.calling:
 
3100
            return
 
3101
 
 
3102
        try:
 
3103
            self.calling = 1
 
3104
 
 
3105
            old = event.GetOldSelection()
 
3106
            new = event.GetSelection()
 
3107
            if old > -1:
 
3108
                owin = self.GetPage(old).GetWindow1()
 
3109
                owin.tree1.Hide()
 
3110
                owin.tree2.Hide()
 
3111
            if new > -1:
 
3112
                self.root.dragger._SelectItem(new)
 
3113
                win = self.GetPage(new).GetWindow1()
 
3114
                #fix for dealing with current paths.  They are wonderful.
 
3115
                if win.dirname:
 
3116
                    try:
 
3117
                        os.chdir(win.dirname)
 
3118
                    except:
 
3119
                        pass
 
3120
                self.updateChecks(win)
 
3121
                #width = self.GetClientSize()[0]
 
3122
                #split = win.parent
 
3123
                #if win.GetWrapMode() == wxSTC_WRAP_NONE:
 
3124
                #    self.parent.SetStatusText("", 1)
 
3125
                #else:
 
3126
                #    self.parent.SetStatusText("WRAP",1)
 
3127
                self.root.OnDocumentChange(win, None)
 
3128
                win.tree1.Show()
 
3129
                win.tree2.Show()
 
3130
 
 
3131
                _, flags = CARET_OPTION_TO_ID[caret_option]
 
3132
                win.SetXCaretPolicy(flags, caret_slop*caret_multiplier)
 
3133
                win.SetYCaretPolicy(flags, caret_slop)
 
3134
 
 
3135
            self.root.timer.Start(10, wxTIMER_ONE_SHOT)
 
3136
            if event:
 
3137
                event.Skip()
 
3138
 
 
3139
        finally:
 
3140
            self.calling = 0
 
3141
    
 
3142
    def updateChecks(self, win):
 
3143
        if UNICODE:
 
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)
 
3159
 
 
3160
#----------------- This deals with the tab swapping support. -----------------
 
3161
    if 0:
 
3162
        pass
 
3163
    ## def swapPages(self, p1, p2, moveleft):
 
3164
        ## mn = min(p1,p2)
 
3165
        ## mx = max(p1,p2)
 
3166
        ## if not (moveleft or (p1-p2==1)):
 
3167
            ## mn, mx = mx, mn
 
3168
        ## page = self.GetPage(mn)
 
3169
        ## text = self.GetPageText(mn)[:]
 
3170
        ## self.RemovePage(mn)
 
3171
        ## self.InsertPage(mx, page, text, 1)
 
3172
 
 
3173
    def RemovePage(self, index):
 
3174
        self.root.dragger._RemoveItem(index)
 
3175
        wxNotebook.RemovePage(self, index)
 
3176
 
 
3177
    def DeletePage(self, index):
 
3178
        self.root.dragger._RemoveItem(index)
 
3179
        page = self.GetPage(index)
 
3180
        stc = page.GetWindow1()
 
3181
        stc.tree1.Hide()
 
3182
        stc.tree1.Destroy()
 
3183
        stc.tree2.Hide()
 
3184
        stc.tree2.Destroy()
 
3185
        wxNotebook.DeletePage(self, index)
 
3186
 
 
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)
 
3194
 
 
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())
 
3201
        
 
3202
    def SetPageText(self, posn, text):
 
3203
        self.root.dragger._RenameItem(posn, text)
 
3204
        wxNotebook.SetPageText(self, posn, text)
 
3205
 
 
3206
class MyLC(wxTreeCtrl):
 
3207
    class FileDropTarget(wxFileDropTarget):
 
3208
        def __init__(self, parent, root):
 
3209
            wxFileDropTarget.__init__(self)
 
3210
            self.parent = parent
 
3211
            self.root = root
 
3212
        def OnDropFiles(self, x, y, filenames):
 
3213
            if len(filenames) != 1:
 
3214
                #append documents
 
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()
 
3223
                        if i != -1:
 
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)
 
3228
                    else:
 
3229
                        dn, fn = os.path.split(self.root.getAlmostAbsolute(fn, dn))
 
3230
                        self.root.newTab(dn, fn)
 
3231
                return
 
3232
 
 
3233
            try:
 
3234
                selindex = [i[0] for i in self.parent.getAllRectangles()].index(self.parent.selected)
 
3235
            except:
 
3236
                selindex = -1
 
3237
 
 
3238
 
 
3239
            l = self.parent.getAllRectangles()
 
3240
            i = -1
 
3241
 
 
3242
            for p, (item, rect) in enumerate(l):
 
3243
                if l is not None:
 
3244
                    if y >= rect.y and y < rect.y+rect.height:
 
3245
                        i = p
 
3246
 
 
3247
            filename = filenames[0]
 
3248
            dn, fn = os.path.split(filename)
 
3249
            unt = (filename[:10] == '<untitled ' and filename[-1:] == '>')
 
3250
            if not unt:
 
3251
                filename = self.root.getAlmostAbsolute(fn, dn)
 
3252
                dn, fn = os.path.split(filename)
 
3253
            new = 0
 
3254
            if not unt and not self.root.isOpen(fn, dn):
 
3255
                new = 1
 
3256
                cp = self.root.control.GetPageCount()
 
3257
                self.root.newTab(dn, fn, switch=1)
 
3258
                return
 
3259
            else:
 
3260
                cp = self.root.getPositionAbsolute(self.root.getAbsolute(fn, dn), unt)
 
3261
 
 
3262
            if i == -1:
 
3263
                i = len(l)
 
3264
            if i != cp:
 
3265
                #remove from original location, insert at destination
 
3266
                p = self.root.control.GetPage(cp)
 
3267
                t = self.root.control.GetPageText(cp)
 
3268
                try:
 
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)
 
3273
                    else:
 
3274
                        self.root.control.InsertPage(i, p, t)
 
3275
                    if cp == selindex:
 
3276
                        self.root.control.SetSelection(min(i, self.root.control.GetPageCount()-1))
 
3277
                finally:
 
3278
                    self.root.starting = 0
 
3279
 
 
3280
    def __init__(self, parent, root):
 
3281
        tID = wxNewId()
 
3282
        wxTreeCtrl.__init__(self, parent, tID, style=wxTR_HIDE_ROOT|\
 
3283
                            wxTR_NO_LINES|wxTR_NO_BUTTONS)
 
3284
 
 
3285
        self.root = root
 
3286
        self.rootnode = self.AddRoot("Unseen Root")
 
3287
        self.SetDropTarget(self.FileDropTarget(self, root))
 
3288
        self.AssignImageList(IMGLIST1)
 
3289
 
 
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)
 
3293
 
 
3294
    def getAllRectangles(self):
 
3295
        count = self.GetChildrenCount(self.rootnode)
 
3296
        lst = []
 
3297
        while len(lst) < count:
 
3298
            if len(lst) == 0:
 
3299
                (item, cookie) = self.GetFirstChild(self.rootnode)
 
3300
            else:
 
3301
                (item, cookie) = self.GetNextChild(self.rootnode, cookie)
 
3302
            lst.append((item, self.GetBoundingRect(item)))
 
3303
        return lst
 
3304
 
 
3305
    def OnTreeItemActivated(self, event):
 
3306
        item = event.GetItem()
 
3307
        lst = self.getAllRectangles()
 
3308
        posn = -1
 
3309
        for i, (itemi, toss) in enumerate(lst):
 
3310
            if item == itemi:
 
3311
                posn = i
 
3312
                break
 
3313
 
 
3314
        if posn == -1:
 
3315
            print "BAH2!"
 
3316
            event.Skip()
 
3317
 
 
3318
        self.root.control.SetSelection(posn)
 
3319
 
 
3320
    def OnTreeBeginDrag(self, event):
 
3321
        item = event.GetItem()
 
3322
        lst = self.getAllRectangles()
 
3323
        posn = -1
 
3324
        for i, (itemi, toss) in enumerate(lst):
 
3325
            if item == itemi:
 
3326
                posn = i
 
3327
                break
 
3328
 
 
3329
        if posn == -1:
 
3330
            ## print "BAH!"
 
3331
            event.Skip()
 
3332
 
 
3333
        a = self.root.control.GetPage(posn).GetWindow1()
 
3334
        data = os.path.join(a.dirname, a.filename).encode('ascii')
 
3335
        if data == ' ':
 
3336
            data = '<untitled %i>'%a.NEWDOCUMENT
 
3337
        d = wxFileDataObject()
 
3338
        d.AddFile(data)
 
3339
        ## print d.GetFilenames()
 
3340
        a = wxDropSource(self)
 
3341
        a.SetData(d)
 
3342
        a.DoDragDrop(wxDrag_AllowMove|wxDrag_CopyOnly)
 
3343
 
 
3344
    def OnTreeSelectionChanged(self, event):
 
3345
 
 
3346
        self.selected = item = event.GetItem()
 
3347
        items = [i[0] for i in self.getAllRectangles()]
 
3348
        try:
 
3349
            indx = items.index(item)
 
3350
            self.root.control.SetSelection(indx)
 
3351
        except:
 
3352
            pass
 
3353
 
 
3354
    def _RemoveItem(self, index):
 
3355
        chlist = self.getAllRectangles()
 
3356
        self.Delete(chlist[index][0])
 
3357
 
 
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)
 
3361
 
 
3362
    def _InsertItem(self, index, label):
 
3363
        if index == self.GetChildrenCount(self.rootnode, False):
 
3364
            self._AddItem(label)
 
3365
        else:
 
3366
            which = EXT_TO_IMG.get(extns.get(label.split('.')[-1].lower(), 0), 0)
 
3367
            self.InsertItemBefore(self.rootnode, index, label, which)
 
3368
 
 
3369
    def _SelectItem(self, index):
 
3370
        chlist = self.getAllRectangles()
 
3371
        if index < len(chlist):
 
3372
            self.SelectItem(chlist[index][0])
 
3373
        
 
3374
    def _RenameItem(self, index, label):
 
3375
        self.SetItemText(self.getAllRectangles()[index][0], label)
 
3376
 
 
3377
class FileDropTarget(wxFileDropTarget):
 
3378
    def __init__(self, root):
 
3379
        wxFileDropTarget.__init__(self)
 
3380
        self.root = root
 
3381
    def OnDropFiles(self, x, y, filenames):
 
3382
        self.root.OnDrop(filenames)
 
3383
 
 
3384
class TextDropTarget(wxTextDropTarget):
 
3385
    def __init__(self, parent):
 
3386
        wxTextDropTarget.__init__(self)
 
3387
        self.parent = parent
 
3388
 
 
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
 
3392
        #code snippets.
 
3393
        return False
 
3394
 
 
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)
 
3401
 
 
3402
            isz = (16,16)
 
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:
 
3408
                il.Add(i)
 
3409
            self.SetImageList(il)
 
3410
            self.il = il
 
3411
 
 
3412
        def OnCompareItems(self, item1, item2):
 
3413
            if self.SORTTREE:
 
3414
                return cmp(self.GetItemData(item1).GetData(),\
 
3415
                           self.GetItemData(item2).GetData())
 
3416
            else:
 
3417
                return cmp(self.GetItemData(item1).GetData()[1],\
 
3418
                           self.GetItemData(item2).GetData()[1])
 
3419
 
 
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)
 
3425
 
 
3426
        self.root = root
 
3427
 
 
3428
        tID = wxNewId()
 
3429
 
 
3430
        self.tree = self.TreeCtrl(self, tID)
 
3431
        self.tree.troot = self.tree.AddRoot("Unseen Root")
 
3432
 
 
3433
        #self.tree.Expand(self.root)
 
3434
        EVT_LEFT_DCLICK(self, self.OnLeftDClick)
 
3435
        EVT_TREE_ITEM_ACTIVATED(self, tID, self.OnActivate)
 
3436
 
 
3437
    def new_hierarchy(self, hier):
 
3438
        self.tree.DeleteAllItems()
 
3439
        root = [self.tree.troot]
 
3440
        stk = [hier]
 
3441
        D = {'c':wxColour(0, 0, 200),
 
3442
             'd':wxColour(200, 0, 0)}
 
3443
        while stk:
 
3444
            cur = stk.pop()
 
3445
            while cur:
 
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]])
 
3450
                icons = 1
 
3451
                if children:
 
3452
                    if icons:
 
3453
                        self.tree.SetItemImage(item_no, 0, wxTreeItemIcon_Normal)
 
3454
                        self.tree.SetItemImage(item_no, 1, wxTreeItemIcon_Expanded)
 
3455
                    stk.append(cur)
 
3456
                    root.append(item_no)
 
3457
                    cur = children
 
3458
                elif icons:
 
3459
                    self.tree.SetItemImage(item_no, 2, wxTreeItemIcon_Normal)
 
3460
                    self.tree.SetItemImage(item_no, 2, wxTreeItemIcon_Selected)
 
3461
            self.tree.SortChildren(root[-1])
 
3462
            root.pop()
 
3463
 
 
3464
    def OnSize(self, event):
 
3465
        w,h = self.parent.GetClientSizeTuple()
 
3466
        self.tree.SetDimensions(0, 0, w, h)
 
3467
        self.parent.sizer.Layout()
 
3468
 
 
3469
    def OnLeftDClick(self, event):
 
3470
        #pity this doesn't do what it should.
 
3471
        num, win = self.root.getNumWin(event)
 
3472
        win.SetFocus()
 
3473
 
 
3474
    def OnActivate(self, event):
 
3475
        num, win = self.root.getNumWin(event)
 
3476
        dat = self.tree.GetItemData(event.GetItem()).GetData()
 
3477
        if dat == None:
 
3478
            return event.Skip()
 
3479
        ln = dat[1]-1
 
3480
        #print ln
 
3481
        #print dir(win)
 
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)
 
3486
        win.SetFocus()
 
3487
 
 
3488
    def Show(self):
 
3489
        wxPanel.Show(self, True)
 
3490
        try:
 
3491
            self.parent.sizer.Add(self)
 
3492
        except:
 
3493
            pass
 
3494
        self.OnSize(None)
 
3495
    def Hide(self):
 
3496
        wxPanel.Hide(self)
 
3497
        try:
 
3498
            self.parent.sizer.Detach(self)
 
3499
        except:
 
3500
            pass
 
3501
 
 
3502
class TriggerDialog(wxDialog):
 
3503
    class TriggerListCtrl(wxListCtrl, wxTextEditMixin):
 
3504
        pass
 
3505
    def __init__(self, parent, stc, dct):
 
3506
        wxDialog.__init__(self, parent, -1, "Title",
 
3507
                          style=wxDEFAULT_DIALOG_STYLE|wxRESIZE_BORDER,
 
3508
                          size=(800, 400))
 
3509
        self.stc = stc
 
3510
        self.parent = parent
 
3511
        self.dct = dct
 
3512
        EVT_CLOSE(self, self.OnClose)
 
3513
        
 
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)
 
3518
        
 
3519
        
 
3520
        sizer = wxBoxSizer(wxVERTICAL)
 
3521
        
 
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.
 
3527
                                
 
3528
                                See the help for example uses.
 
3529
                                
 
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>"
 
3533
                                
 
3534
                                Double-click to edit an entry in-place.
 
3535
                                
 
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.
 
3538
                                
 
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)
 
3543
        
 
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)
 
3550
        self.ResetData(dct)
 
3551
        
 
3552
        sizer.Add(self.list, 2, flag=wxGROW|wxALL, border=5)
 
3553
        
 
3554
        buttons = wxBoxSizer(wxHORIZONTAL)
 
3555
        #new/delete
 
3556
        addbutton(buttons, "New Trigger", self.OnNew, wxNewId())
 
3557
        addbutton(buttons, "Delete Trigger", self.OnDelete, wxNewId())
 
3558
        buttons.Add(wxStaticText(self, -1, '     '), 1, wxGROW)
 
3559
        #OK/cancel
 
3560
        addbutton(buttons, "OK", self.OnOK, wxOK)
 
3561
        addbutton(buttons, "Cancel", self.OnCancel, wxCANCEL)
 
3562
        sizer.Add(buttons, 0, wxALIGN_CENTER|wxLEFT, border=5)
 
3563
        
 
3564
        sizer.Fit(self)
 
3565
        self.SetSizer(sizer)
 
3566
 
 
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):
 
3574
                        yield i,j,k
 
3575
        
 
3576
        self.list.DeleteAllItems()
 
3577
        for x in reconstruct('', data):
 
3578
            x_ = []
 
3579
            for L in x:
 
3580
                try:
 
3581
                    L = str(L)
 
3582
                except:
 
3583
                    pass
 
3584
                if not isinstance(L, unicode):
 
3585
                    Lx = L.encode('string-escape')
 
3586
                    if Lx != L:
 
3587
                        L = repr(L)
 
3588
                x_.append(L)
 
3589
            i,j,k = x_
 
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)
 
3594
 
 
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')
 
3600
 
 
3601
    def OnDelete(self, evt):
 
3602
        selected = self.list.GetNextItem(-1, state=wxLIST_STATE_SELECTED)
 
3603
        if selected != -1:
 
3604
            self.list.DeleteItem(selected)
 
3605
 
 
3606
    def OnClose(self, evt):
 
3607
        self.OnCancel(evt)
 
3608
 
 
3609
    def OnOK(self, evt):
 
3610
        d = {}
 
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()]
 
3616
            item_ = []
 
3617
            for i in item:
 
3618
                if i and i[0] in ['"', "'"]:
 
3619
                    try:
 
3620
                        i = [j for j in compiler.parse(str(i)).getChildren()[:1] if isinstance(j, basestring)][0]
 
3621
                    except Exception, e:
 
3622
                        pass
 
3623
                item_.append(i)
 
3624
            
 
3625
            p, l, r = item_
 
3626
            
 
3627
            if not p:
 
3628
                if len(l) or len(r):
 
3629
                    print "null trigger has nonnull replacements (%r, %r)"%(l,r)
 
3630
                continue
 
3631
            if len(l) + len(r) == 0:
 
3632
                print "nonnull trigger %r has null replacements"%p
 
3633
            pr = None
 
3634
            x = d
 
3635
            good = 1
 
3636
            for le,ch in enumerate(p[::-1]):
 
3637
                n = x.get(ch, None)
 
3638
                if type(n) is tuple:
 
3639
                    if p[-le-1:] == p:
 
3640
                        print "duplicate trigger %r with replacements (%r, %r), and is now removed"%(p, l, r)
 
3641
                        break
 
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)
 
3643
                    n = None
 
3644
                
 
3645
                if n is None:
 
3646
                    n = x[ch] = {}
 
3647
                
 
3648
                pr, x = x, n
 
3649
            else:
 
3650
                if len(x) != 0:
 
3651
                    print "trigger %r with replacements (%r, %r) is a suffix of some entry, and is now removed"%(p, l, r)
 
3652
                    continue
 
3653
                pr[p[0]] = (l,r)
 
3654
        
 
3655
        self.stc.triggers = d
 
3656
        self.Destroy()
 
3657
 
 
3658
    def OnCancel(self, evt):
 
3659
        self.Destroy()
 
3660
 
 
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
 
3666
        self.defa = defa
 
3667
        self.curr = curr
 
3668
 
 
3669
 
 
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)
 
3675
 
 
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)
 
3683
        if self.haveFocus:
 
3684
            dc.SetTextForeground(wxGREEN)
 
3685
            dc.DrawLabel("Have Focus", rect, wxALIGN_RIGHT | wxALIGN_BOTTOM)
 
3686
        else:
 
3687
            dc.SetTextForeground(wxRED)
 
3688
            dc.DrawLabel("Need Focus!", rect, wxALIGN_RIGHT | wxALIGN_BOTTOM)
 
3689
 
 
3690
    def OnSetFocus(self, evt):
 
3691
        self.haveFocus = True
 
3692
        self.Refresh()
 
3693
 
 
3694
    def OnKillFocus(self, evt):
 
3695
        self.haveFocus = False
 
3696
        self.Refresh()
 
3697
 
 
3698
    def OnMouse(self, evt):
 
3699
        if evt.ButtonDown():
 
3700
            self.SetFocus()
 
3701
 
 
3702
    def OnKey(self, evt):
 
3703
        self.GetParent().text.SetValue(GetKeyPress(evt))
 
3704
 
 
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,
 
3709
                          size=(320, 240))
 
3710
        self.parent = parent
 
3711
 
 
3712
        self.keysink = KeySink(self, defa, curr)
 
3713
 
 
3714
        self.text = wxTextCtrl(self, -1, curr, style=wxTE_READONLY|wxTE_LEFT)
 
3715
 
 
3716
        buttons = wxBoxSizer(wxHORIZONTAL)
 
3717
        ok = wxButton(self, wxOK, "OK")
 
3718
        cancel = wxButton(self, wxCANCEL, "Cancel")
 
3719
        buttons.Add(ok, 0)
 
3720
        buttons.Add(cancel, 0)
 
3721
 
 
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)
 
3726
 
 
3727
        self.SetSizer(sizer)
 
3728
        EVT_BUTTON(self, wxOK, self.OnOK)
 
3729
        EVT_BUTTON(self, wxCANCEL, self.OnCancel)
 
3730
        EVT_CLOSE(self, self.OnClose)
 
3731
 
 
3732
    def OnClose(self, evt):
 
3733
        self.OnCancel(evt)
 
3734
 
 
3735
    def OnOK(self, evt):
 
3736
        self.parent.accelerator = self.text.GetValue()
 
3737
        self.Destroy()
 
3738
 
 
3739
    def OnCancel(self, evt):
 
3740
        self.parent.accelerator = ""
 
3741
        self.Destroy()
 
3742
 
 
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)
 
3750
 
 
3751
                self.parent = parent
 
3752
                self.sel = None
 
3753
 
 
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)
 
3761
 
 
3762
                self.items = []
 
3763
                self.SetItemCount(0)
 
3764
 
 
3765
                EVT_LIST_ITEM_SELECTED(self, self.GetId(), self.OnItemSelected)
 
3766
                EVT_LIST_ITEM_ACTIVATED(self, self.GetId(), self.OnItemActivated)
 
3767
 
 
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()
 
3777
                if rslt == wxID_OK:
 
3778
                    name = dlg.GetValue()
 
3779
                else:
 
3780
                    name = None
 
3781
                dlg.Destroy()
 
3782
                if not name:
 
3783
                    return
 
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])
 
3788
                dlg.ShowModal()
 
3789
                if not self.accelerator:
 
3790
                    return
 
3791
                self.items[inum] = (item[0], name, item[2], self.accelerator, 1)
 
3792
                self.RefreshItem(inum)
 
3793
 
 
3794
            def getColumnText(self, index, col):
 
3795
                return self.items[index][col]
 
3796
 
 
3797
            def OnGetItemText(self, item, col):
 
3798
                return self.items[item][col]
 
3799
 
 
3800
            def OnGetItemImage(self, item):
 
3801
                return -1
 
3802
 
 
3803
            def OnGetItemAttr(self, item):
 
3804
                return None
 
3805
 
 
3806
            def OnItemSelected(self, evt):
 
3807
                self.sel = evt.GetIndex()
 
3808
 
 
3809
        def __init__(self, parent):
 
3810
            wxPanel.__init__(self, parent, -1, style=wxWANTS_CHARS)
 
3811
            self.vm = self.virtualMenu(self)
 
3812
            self.refresh(MENULIST)
 
3813
 
 
3814
            self.parent = parent
 
3815
 
 
3816
            EVT_SIZE(self, self.OnSize)
 
3817
 
 
3818
        def refresh(self, items):
 
3819
            self.vm.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)
 
3825
 
 
3826
        def OnSize(self, event):
 
3827
            w,h = self.GetClientSizeTuple()
 
3828
            self.vm.SetDimensions(0, 0, w, h)
 
3829
 
 
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)
 
3833
 
 
3834
        self.root = root
 
3835
        self.vmu = self.VirtualMenu(self)
 
3836
        sizer = wxBoxSizer(wxVERTICAL)
 
3837
 
 
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)
 
3842
 
 
3843
        s2 = wxBoxSizer(wxHORIZONTAL)
 
3844
 
 
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")
 
3849
 
 
3850
        s2.Add(ok)
 
3851
        s2.Add(clear)
 
3852
        s2.Add(revert)
 
3853
        s2.Add(cancel)
 
3854
        sizer.Add(s2, 0, wxALIGN_RIGHT)
 
3855
 
 
3856
        self.SetSizer(sizer)
 
3857
        self.SetAutoLayout(True)
 
3858
 
 
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)
 
3863
 
 
3864
    def OnOK(self, evt):
 
3865
        global MENUPREF
 
3866
        global MENULIST
 
3867
        nmu = {}
 
3868
        changed = 0
 
3869
        for heir, cn, da, ca, hk in self.vmu.vm.items:
 
3870
            if MENUPREF[heir] != (cn, ca):
 
3871
                changed = 1
 
3872
            nmu[heir] = (cn, ca)
 
3873
        if changed:
 
3874
            MENUPREF.clear()
 
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.",
 
3879
                             "Restart Required")
 
3880
        self.Destroy()
 
3881
 
 
3882
    def OnClear(self, evt):
 
3883
        IL = self.vmu.vm
 
3884
        items = IL.items
 
3885
        indx = IL.sel
 
3886
        items[indx] = items[indx][:3] + ('', items[indx][4])
 
3887
        IL.RefreshItem(indx)
 
3888
 
 
3889
    def OnRevert(self, evt):
 
3890
        IL = self.vmu.vm
 
3891
        items = IL.items
 
3892
        indx = IL.sel
 
3893
        item = items[indx]
 
3894
        items[indx] = (item[0], item[0].split('->')[-1], item[2], item[2], item[4])
 
3895
        IL.RefreshItem(indx)
 
3896
 
 
3897
    def OnCancel(self, evt):
 
3898
        self.Destroy()
 
3899
 
 
3900
 
 
3901
#--------------------------- And the main...*sigh* ---------------------------
 
3902
import wx
 
3903
VS = wx.VERSION_STRING
 
3904
del wx
 
3905
 
 
3906
def main():
 
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))
 
3914
 
 
3915
    opn=0
 
3916
    if len(sys.argv)>1 and (sys.argv[1] == '--last'):
 
3917
        opn=1
 
3918
    filehistory.root = root = app.frame = MainWindow(None, -1, "PyPE", sys.argv[1+opn:])
 
3919
    root.updateWindowTitle()
 
3920
    app.SetTopWindow(app.frame)
 
3921
    app.frame.Show(1)
 
3922
    if opn:
 
3923
        app.frame.OnOpenPrevDocs(None)
 
3924
    app.frame.SendSizeEvent()
 
3925
    app.MainLoop()
 
3926
 
 
3927
if __name__ == '__main__':
 
3928
    main()