1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603
|
#-----------------------------------------------------------------------------
# Name: wxPythonEditorModels.py
# Purpose:
#
# Author: Riaan Booysen
#
# Created: 2002/02/09
# RCS-ID: $Id: wxPythonEditorModels.py,v 1.15 2005/05/18 12:05:11 riaan Exp $
# Copyright: (c) 2002 - 2005
# Licence: GPL
#-----------------------------------------------------------------------------
print 'importing Models.wxPythonEditorModels'
import re, string, os, imp, sys, new
import wx
import Preferences, Utils
import EditorHelper
from PythonEditorModels import ClassModel, BaseAppModel, ModuleModel
from Companions import BaseCompanions, FrameCompanions, WizardCompanions
import sourceconst
(imgAppModel, imgFrameModel, imgDialogModel, imgMiniFrameModel,
imgMDIParentModel, imgMDIChildModel, imgPopupWindowModel,
imgPopupTransientWindowModel, imgFramePanelModel,
imgWizardModel, imgPyWizardPageModel, imgWizardPageSimpleModel,
) = EditorHelper.imgIdxRange(12)
class _your_frame_attrs_: pass
# def __repr__(self):return `self.__dict__`
class BaseFrameModel(ClassModel):
""" Base class for all frame type models that can be opened in the Designer
This class is responsible for parsing the _init_* methods generated by the
Designer and maintaining other special values like window id declarations
"""
modelIdentifier = 'Frames'
dialogLook = False
Companion = BaseCompanions.DesignTimeCompanion
def __init__(self, data, name, main, editor, saved, app=None):
ClassModel.__init__(self, data, name, main, editor, saved, app)
self.designerTool = None
self.specialAttrs = {}
self.defCreateClass = sourceconst.defCreateClass
self.defClass = sourceconst.defClass
self.defImport = sourceconst.defImport
self.defWindowIds = sourceconst.defWindowIds
self.defSrcVals = {}
def renameMain(self, oldName, newName):
""" Rename the main class of the module """
ClassModel.renameMain(self, oldName, newName)
if self.getModule().functions.has_key('create'):
self.getModule().replaceFunctionBody('create',
[' return %s(parent)'%newName, ''])
def renameCtrl(self, oldName, newName):
# Currently DesignerView maintains ctrls
pass
def new(self, params):
""" Create a new frame module """
paramLst = []
for param in params.keys():
paramLst.append(Preferences.cgKeywordArgFormat %{'keyword': param,
'value': params[param]})
# XXX Refactor line wrappers to Utils and wrap this
paramStr = 'self, ' + ', '.join(paramLst)
srcValsDict = {'modelIdent': self.modelIdentifier,
'main': self.main,
'idNames': Utils.windowIdentifier(self.main, ''),
'idIdent': sourceconst.init_ctrls,
'idCount': 1, 'defaultName': self.defaultName,
'params': paramStr}
srcValsDict.update(self.defSrcVals)
self.data = (sourceconst.defSig + self.defImport + \
self.defCreateClass + self.defWindowIds + \
self.defClass) % srcValsDict
self.savedAs = False
self.modified = True
self.initModule()
self.notify()
def identifyCollectionMethods(self):
""" Return a list of all _init_* methods in the class """
results = []
module = self.getModule()
if module.classes.has_key(self.main):
main = module.classes[self.main]
for meth in main.methods.keys():
if len(meth) > len('_init_') and meth[:6] == '_init_':
results.append(meth)
return results
def allObjects(self):
views = ['Data', 'Designer']
order = []
objs = {}
for view in views:
order.extend(self.views[view].objectOrder)
objs.update(self.views[view].objects)
return order, objs
def readDesignerMethod(self, meth, codeBody):
""" Create a new ObjectCollection by parsing the given method body """
from Views import ObjCollection
import methodparse
# Collection method
if ObjCollection.isInitCollMeth(meth):
ctrlName = methodparse.ctrlNameFromMeth(meth)
try:
res = Utils.split_seq(codeBody, '', string.strip)
inits, body, fins = res[:3]
except ValueError:
raise 'Collection body %s not in init, body, fin form' % meth
allInitialisers, unmatched = methodparse.parseMixedBody(\
[methodparse.EventParse, methodparse.CollectionItemInitParse],body)
creators = allInitialisers.get(methodparse.CollectionItemInitParse, [])
collectionInits = []
properties = []
events = allInitialisers.get(methodparse.EventParse, [])
methodparse.decorateParseItems(creators + events, ctrlName, self.main)
# Normal method
else:
inits = []
fins = []
allInitialisers, unmatched = methodparse.parseMixedBody(\
[methodparse.ConstructorParse, methodparse.EventParse,
methodparse.CollectionInitParse, methodparse.PropertyParse],
codeBody)
creators = allInitialisers.get(methodparse.ConstructorParse, [])
collectionInits = allInitialisers.get(methodparse.CollectionInitParse, [])
properties = allInitialisers.get(methodparse.PropertyParse, [])
events = allInitialisers.get(methodparse.EventParse, [])
newObjColl = ObjCollection.ObjectCollection()
newObjColl.setup(creators, properties, events, collectionInits, inits, fins)
if unmatched:
wx.LogWarning('The following lines were not used by the Designer '\
'and will be lost:\n')
for line in unmatched:
wx.LogWarning(line)
wx.LogWarning('\nThere were unprocessed lines in the source code of '\
'method: %s\nIf this was unexpected, it is advised '\
'that you cancel this Designer session and correct '\
'the problem before continuing.'%meth)
return newObjColl
def readSpecialAttrs(self, mod, cls):
""" Read special attributes from __init__ method.
All instance attributes defined between the top of the __init__ method
and the _init_ctrls() method call will be available to the Designer
as valid names bound to properties.
For an attribute to qualify, it has to have a simple deduceable type;
Python builtin or wxPython objects.
If for example the attribute is bound to a variable passed in as a
parameter, you have to first initialise it to a literal of the same
type. This value will be used at design time.
e.g. def __init__(self, parent, myFrameCaption):
self.frameCaption = 'Design time frame caption'
self.frameCaption = myFrameCaption
self._init_ctrls(parent)
Now you may add this attribute as a parameter or property value
in the source by hand.
In the Inspector property values recognised as special attributes
will display as bold values and cannot be edited (yet).
"""
initMeth = cls.methods['__init__']
# determine end of attrs and possible external attrs init
startline = initMeth.start
extAttrInitLine = -1
extAttrInitName = ''
for idx in range(startline, initMeth.end):
line = mod.source[idx].strip()
if line.startswith('self._init_ctrls('):
endline = idx
break
elif line.find('_AttrMixin.__init__(self') != -1:
extAttrInitLine = idx
extAttrInitName = line.split('.__init__')[0]
else:
raise 'self._init_ctrls not found in __init__'
# build list of attrs
attrs = []
def readAttrsFromSrc(attrs, attributes, source, startline, endline):
for attr, blocks in attributes.items():
for block in blocks:
if startline <= block.start <= endline and attr not in attrs:
linePos = block.start-1
line = source[linePos]
val = line[line.find('=')+1:].strip()
# handle lines continued with ,
while val.endswith(','):
linePos += 1
val += source[linePos].strip()
attrs.append( (attr, val) )
if extAttrInitName:
if not mod.from_imports_names.has_key(extAttrInitName):
raise '%s.__init__ called, but not imported in the form: '\
'from [ModuleName] import %s'%(extAttrInitName, extAttrInitName)
# try to load external attrs
extModName = mod.from_imports_names[extAttrInitName]
extModFilename = os.path.join(os.path.dirname(self.filename),
extModName+'.py')
from Explorers.Explorer import openEx
try:
data = openEx(extModFilename).load()
except Exception, error:
raise 'Problem loading %s: File expected at: %s'%(extModName,
extModFilename)
exModModel = ModuleModel(data, extModFilename, self.editor, 1)
extModule = exModModel.getModule()
extClass = extModule.classes[extAttrInitName]
extMeth = extClass.methods['__init__']
readAttrsFromSrc(attrs, extClass.attributes, extModule.source,
extMeth.start, extMeth.end)
readAttrsFromSrc(attrs, cls.attributes, mod.source, startline, endline)
import PaletteMapping
# build a dictionary that can be passed to eval
evalNS = _your_frame_attrs_()
for attr, code in attrs:
if hasattr(evalNS, attr):
continue
try:
val = PaletteMapping.evalCtrl(code)
except Exception, err:
print str(err)
continue
else:
setattr(evalNS, attr, val)
return {'self': evalNS}
def readCustomClasses(self, mod, cls):
""" Read definition for Custom Classes
Custom Classes can be defined as a class attribute named _custom_classes
containing a dictionary defining wxPython classes and their custom
equivalents, e.g.
_custom_classes = {'wx.TreeCtrl': ['MyTreeCtrl', 'AdvancedTreeCtrl']}
These custom classes will then be available to the Designer
and will act as equivalent to the corresponding wxPython class,
but will generate source for the custom definition.
One implication is that you loose the constructor. Because Boa
will generate the creation code for the object, the constructor
signature has to be the same as the wxPython class.
"""
res = {}
if cls.class_attributes.has_key('_custom_classes'):
try:
import PaletteMapping
cls_attr = cls.class_attributes['_custom_classes'][0]
attr_val = cls_attr.signature
srcline = cls_attr.start
# multiline parser ;)
while 1:
try:
custClasses = PaletteMapping.evalCtrl(attr_val)
assert type(custClasses) == type({})
break
except SyntaxError, err:
if err[0] == 'unexpected EOF while parsing':
attr_val = attr_val + mod.source[srcline].strip()
srcline = srcline + 1
else:
raise
except Exception, err:
raise '_custom_classes is not valid: '+str(err)
for wxClassName, customs in custClasses.items():
wxClass = PaletteMapping.evalCtrl(wxClassName)
res[wxClassName] = wxClass
for custom in customs:
# to combine frame attrs with custom classes a phony
# self object is created to resolve the class name
# during frame creation
if custom.startswith('self.'):
if not 'self' in res:
res['self'] = _your_frame_attrs_()
setattr(res['self'], custom[5:], wxClass)
else:
res[custom] = wxClass
return res
def readComponents(self):
""" Setup object collection dict by parsing all designer controlled methods """
module = self.getModule()
# Parse all _init_* methods
self.objectCollections = {}
if module.classes.has_key(self.main):
main = module.classes[self.main]
self.specialAttrs = self.readSpecialAttrs(module, main)
self.customClasses = self.readCustomClasses(module, main)
self.resources = self.readResources(module, main,
specialAttrs=self.specialAttrs)
for oc in self.identifyCollectionMethods():
codeSpan = main.methods[oc]
codeBody = module.source[codeSpan.start : codeSpan.end]
self.objectCollections[oc] = self.readDesignerMethod(oc, codeBody)
# XXX Hack: This should not be necessary !!
for prop in self.objectCollections[oc].properties[:]:
if prop.asText() in ('self.%s()'%sourceconst.init_utils,
'self.%s()'%sourceconst.init_sizers):
self.objectCollections[oc].properties.remove(prop)
# Set the model's constructor
if self.objectCollections.has_key(sourceconst.init_ctrls):
try:
self.mainConstr = \
self.objectCollections[sourceconst.init_ctrls].creators[0]
except IndexError:
raise 'Inherited __init__ method missing'
else:
raise 'Main class "%s" not found. Please fix file header or class name.'%self.main
def removeWindowIds(self, colMeth):
""" Remove a method's corresponding window ids from the source code """
# find windowids in source
winIdIdx = -1
reWinIds = re.compile(sourceconst.srchWindowIds % colMeth)
module = self.getModule()
for idx in range(len(module.source)):
match = reWinIds.match(module.source[idx])
if match:
# XX always 2 lines? check this
del module.source[idx]
del module.source[idx]
module.renumber(-2, idx)
break
def writeWindowIds(self, colMeth, companions):
""" Write a method's corresponding window ids to the source code """
# To integrate efficiently with Designer.SaveCtrls this method
# modifies module.source but doesn't refresh anything
# find windowids in source
winIdIdx = -1
winIdLen = 2
reWinIds = re.compile(sourceconst.srchWindowIdsCont % colMeth)
module = self.getModule()
for idx in range(len(module.source)):
line = module.source[idx]
match = reWinIds.match(line)
if match:
startLine = line
startIdx = idx
while startIdx > 0 and startLine[0] != '[':
startIdx = startIdx - 1
startLine = module.source[startIdx]
winIdIdx = startIdx
winIdLen = idx - startIdx + 2
break
# build window id list
lst = []
for comp in companions:
if winIdIdx == -1:
comp.updateWindowIds()
comp.addIds(lst)
lst.sort()
if lst:
lines = []
if len(lst) > 1 and Preferences.cgWrapLines:
# build win ids spanning multiple lines
line = '['+lst[0]+', '
for seg in lst[1:]:
newLine = line+seg +', '
if len(newLine) >= Preferences.cgLineWrapWidth:
lines.append(line)
line = ' '+seg+', '
else:
line = newLine
lines.append(line)
lines.append((sourceconst.defWindowIdsCont %
{'idIdent': colMeth, 'idCount': len(lst)}).strip())
else:
lines.append((sourceconst.defWindowIds % {
'idNames': ', '.join(lst), 'idIdent': colMeth,
'idCount': len(lst)}).strip())
lines.append('')
if winIdIdx == -1:
# No window id definitions could be found add one above class def
insPt = module.classes[self.main].block.start - 1
module.source[insPt:insPt] = lines
module.renumber(len(lines), insPt)
else:
module.source[winIdIdx:winIdIdx + winIdLen] = lines
module.renumber(len(lines)-winIdLen, winIdIdx)
def update(self):
ClassModel.update(self)
def getSimpleRunnerSrc(self):
""" Return template of source code that will run this module type as
a stand-alone file """
return sourceconst.simpleAppFrameRunSrc
class FrameModel(BaseFrameModel):
modelIdentifier = 'Frame'
defaultName = 'wx.Frame'
bitmap = 'wx.Frame.png'
imgIdx = imgFrameModel
Companion = FrameCompanions.FrameDTC
class DialogModel(BaseFrameModel):
modelIdentifier = 'Dialog'
defaultName = 'wx.Dialog'
bitmap = 'wx.Dialog.png'
imgIdx = imgDialogModel
dialogLook = True
Companion = FrameCompanions.DialogDTC
def getSimpleRunnerSrc(self):
return sourceconst.simpleAppDialogRunSrc
class MiniFrameModel(BaseFrameModel):
modelIdentifier = 'MiniFrame'
defaultName = 'wx.MiniFrame'
bitmap = 'wx.MiniFrame.png'
imgIdx = imgMiniFrameModel
Companion = FrameCompanions.MiniFrameDTC
class MDIParentModel(BaseFrameModel):
modelIdentifier = 'MDIParent'
defaultName = 'wx.MDIParentFrame'
bitmap = 'wx.MDIParentFrame.png'
imgIdx = imgMDIParentModel
Companion = FrameCompanions.MDIParentFrameDTC
class MDIChildModel(BaseFrameModel):
modelIdentifier = 'MDIChild'
defaultName = 'wx.MDIChildFrame'
bitmap = 'wx.MDIChildFrame.png'
imgIdx = imgMDIChildModel
dialogLook = True
Companion = FrameCompanions.MDIChildFrameDTC
class PopupWindowModel(BaseFrameModel):
modelIdentifier = 'PopupWindow'
defaultName = 'wx.PopupWindow'
bitmap = 'wx.PopupWindow.png'
imgIdx = imgPopupWindowModel
dialogLook = True
Companion = FrameCompanions.PopupWindowDTC
def getSimpleRunnerSrc(self):
return sourceconst.simpleAppPopupRunSrc
class PopupTransientWindowModel(BaseFrameModel):
modelIdentifier = 'PopupTransientWindow'
defaultName = 'wx.PopupTransientWindow'
bitmap = 'wx.PopupTransientWindow.png'
imgIdx = imgPopupTransientWindowModel
dialogLook = True
Companion = FrameCompanions.PopupWindowDTC
def getSimpleRunnerSrc(self):
return sourceconst.simpleAppPopupRunSrc
class AppModel(BaseAppModel):
modelIdentifier = 'App'
defaultName = 'wx.App'
bitmap = 'wx.App.png'
imgIdx = imgAppModel
def renameMain(self, oldName, newName):
BaseAppModel.renameMain(self, oldName, newName)
self.getModule().replaceFunctionBody('main',
[' application = %s(0)'%newName, ' application.MainLoop()', ''])
def new(self, mainModule):
self.data = (sourceconst.defEnvPython + sourceconst.defSig + \
sourceconst.defImport + sourceconst.defApp) % {
'modelIdent': self.modelIdentifier,
'main': sourceconst.boaClass,
'mainModule': mainModule}
self.saved = False
self.modified = True
self.update()
self.notify()
class FramePanelModel(BaseFrameModel):
modelIdentifier = 'FramePanel'
defaultName = 'wx.Panel'
bitmap = 'wx.FramePanel.png'
imgIdx = imgFramePanelModel
dialogLook = True
Companion = FrameCompanions.FramePanelDTC
def __init__(self, data, name, main, editor, saved, app=None):
BaseFrameModel.__init__(self, data, name, main, editor, saved, app)
self.defCreateClass = ''
# can this be any uglier (or shorter ;) ?
self.defClass = sourceconst.defClass.replace('parent',
'parent, id, pos, size, style, name', 1)
def getSimpleRunnerSrc(self):
return ''
sourceconst.defWizardImport = sourceconst.wsfix('\nimport wx.wizard\n')
class WizardModel(DialogModel):
modelIdentifier = 'Wizard'
defaultName = 'wx.Wizard'
bitmap = 'wx.wizard.Wizard.png'
imgIdx = imgWizardModel
dialogLook = True
Companion = WizardCompanions.WizardDTC
def __init__(self, data, name, main, editor, saved, app=None):
DialogModel.__init__(self, data, name, main, editor, saved, app)
self.defImport = sourceconst.defImport.strip()+sourceconst.defWizardImport
def getSimpleRunnerSrc(self):
return ''
sourceconst.defPyWizPageClass = sourceconst.defClass+sourceconst.wsfix('''
\tdef GetNext(self):
\t\treturn None
\tdef GetPrev(self):
\t\treturn None
''')
class PyWizardPageModel(FramePanelModel):
modelIdentifier = 'PyWizardPage'
defaultName = 'wx.PyWizardPage'
bitmap = 'wx.wizard.PyWizardPage.png'
imgIdx = imgPyWizardPageModel
dialogLook = True
Companion = WizardCompanions.PyWizardPageDTC
def __init__(self, data, name, main, editor, saved, app=None):
FramePanelModel.__init__(self, data, name, main, editor, saved, app)
self.defClass = sourceconst.defPyWizPageClass
self.defImport = sourceconst.defImport.strip()+sourceconst.defWizardImport
self.defWindowIds = ''
def getSimpleRunnerSrc(self):
return ''
class WizardPageSimpleModel(FramePanelModel):
modelIdentifier = 'WizardPageSimple'
defaultName = 'wx.WizardPageSimple'
bitmap = 'wx.wizard.WizardPageSimple.png'
imgIdx = imgWizardPageSimpleModel
dialogLook = True
Companion = WizardCompanions.WizardPageSimpleDTC
def __init__(self, data, name, main, editor, saved, app=None):
FramePanelModel.__init__(self, data, name, main, editor, saved, app)
self.defClass = sourceconst.defClass
self.defImport = sourceconst.defImport.strip()+sourceconst.defWizardImport
self.defWindowIds = ''
def getSimpleRunnerSrc(self):
return ''
|