Update of /cvsroot/pythoncard/PythonCard/tools/oneEditor/modules In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv10092/modules Added Files: __init__.py backgroundInfoDialog.py backgroundInfoDialog.rsrc.py colorizer.py dialogInfoDialog.py dialogInfoDialog.rsrc.py menuDialog.py menuDialog.rsrc.py newComponentDialog.py newComponentDialog.rsrc.py propertyEditor.py propertyEditor.rsrc.py resourceOutput.py scriptutils.py stackInfoDialog.py stackInfoDialog.rsrc.py stringDialog.py stringDialog.rsrc.py Log Message: Initial version of a tabbed code editor, with associated (future) resource editor --- NEW FILE: backgroundInfoDialog.py --- """ __version__ = "$Revision: 1.1 $" __date__ = "$Date: 2004/10/03 23:58:01 $" """ from PythonCard import dialog, model, util import os class BackgroundInfoDialog(model.CustomDialog): def __init__(self, aBg, rsrc): model.CustomDialog.__init__(self, aBg) self.parent = aBg # if some special setup is necessary, do it here self.components.fldName.text = rsrc.name self.components.fldTitle.text = rsrc.title self.components.fldPosition.text = str(rsrc.position) self.components.fldSize.text = str(rsrc.size) self.components.chkStatusBar.checked = rsrc.statusBar if rsrc.foregroundColor is not None: #self.components.fldForegroundColor.text = colorDescription(rsrc.foregroundColor) self.components.fldForegroundColor.text = str(rsrc.foregroundColor) if rsrc.backgroundColor is not None: #self.components.fldBackgroundColor.text = colorDescription(rsrc.backgroundColor) self.components.fldBackgroundColor.text = str(rsrc.backgroundColor) if rsrc.image is not None: self.components.fldImage.text = rsrc.image self.components.chkTiled.checked = rsrc.tiled self.components.chkVisible.checked = rsrc.visible self.components.chkResizeable.checked = (rsrc.style != []) if rsrc.icon is not None: self.components.fldIcon.text = rsrc.icon def on_btnForegroundColor_mouseClick(self, event): result = dialog.colorDialog(self, color=util.colorFromString(self.components.fldForegroundColor.text)) if result.accepted: self.components.fldForegroundColor.text = str(result.color) def on_btnBackgroundColor_mouseClick(self, event): result = dialog.colorDialog(self, color=util.colorFromString(self.components.fldBackgroundColor.text)) if result.accepted: self.components.fldBackgroundColor.text = str(result.color) def on_btnFile_mouseClick(self, event): result = dialog.openFileDialog() if result.accepted: path = result.paths[0] filename = util.relativePath(self.parent.filename, path) self.components.fldImage.text = filename def on_btnIconFile_mouseClick(self, event): wildcard = "Icon Files (*.ico)|*.ico|XPM Files (*.xpm)|*.xpm|All Files (*.*)|*.*" result = dialog.openFileDialog(wildcard=wildcard) if result.accepted: path = result.paths[0] filename = util.relativePath(self.parent.filename, path) self.components.fldIcon.text = filename def backgroundInfoDialog(parent, rsrc): dlg = BackgroundInfoDialog(parent, rsrc) result = dlg.showModal() if result.accepted: result.name = dlg.components.fldName.text result.title = dlg.components.fldTitle.text result.position = eval(dlg.components.fldPosition.text) result.size = eval(dlg.components.fldSize.text) result.statusBar = dlg.components.chkStatusBar.checked result.foregroundColor = util.colorFromString(dlg.components.fldForegroundColor.text) result.backgroundColor = util.colorFromString(dlg.components.fldBackgroundColor.text) if dlg.components.fldImage.text != '': result.image = dlg.components.fldImage.text else: result.image = None result.tiled = dlg.components.chkTiled.checked result.visible = dlg.components.chkVisible.checked if dlg.components.chkResizeable.checked: result.style = ['resizeable'] else: result.style = [] if dlg.components.fldIcon.text != '': result.icon = dlg.components.fldIcon.text else: result.icon = None dlg.destroy() return result --- NEW FILE: scriptutils.py --- """ __version__ = "$Revision: 1.1 $" __date__ = "$Date: 2004/10/03 23:58:01 $" modified version of Pythonwin scriptutils.py """ import os, sys import traceback # KEA 2002-05-08 # should probably refactor this so we're not passing around the background def CheckFile(background, pathName): what = "check" background.statusBar.text = what.capitalize()+'ing module...' try: f = open(pathName) except IOError, details: background.statusBar.text = "Cant open file '%s' - %s" % (pathName, details) return try: code = f.read() + "\n" finally: f.close() try: codeObj = compile(code, pathName,'exec') if RunTabNanny(background, pathName): #win32ui.SetStatusText("Python and the TabNanny successfully checked the file '"+os.path.basename(pathName)+"'") background.statusBar.text = "Python and the TabNanny successfully checked the file '"+os.path.basename(pathName)+"'" except SyntaxError: #background.statusBar.text = 'SyntaxError' _HandlePythonFailure(background, what, pathName) def RunTabNanny(background, filename): import cStringIO import tabnanny # Capture the tab-nanny output newout = cStringIO.StringIO() old_out = sys.stderr, sys.stdout sys.stderr = sys.stdout = newout try: tabnanny.check(filename) finally: # Restore output sys.stderr, sys.stdout = old_out data = newout.getvalue() if data: try: lineno = data.split()[1] lineno = int(lineno) _JumpToPosition(background, filename, lineno) try: # Try and display whitespace #GetActiveEditControl().SCISetViewWS(1) pass except: pass #win32ui.SetStatusText("The TabNanny found trouble at line %d" % lineno) background.statusBar.text = "The TabNanny found trouble at line %d" % lineno except (IndexError, TypeError, ValueError): background.statusBar.text = "The tab nanny complained, but I cant see where!" print data return 0 return 1 def _JumpToPosition(background, fileName, lineno, col = 1): #JumpToDocument(fileName, lineno, col) #print fileName, lineno, col doc = background.components.document doc.GotoLine(lineno - 1) if col == 1: pos = doc.PositionFromLine(lineno - 1) doc.SetSelection(pos, doc.GetLineEndPosition(lineno - 1)) doc.SetCurrentPos(pos) else: pos = doc.PositionFromLine(lineno - 1) + col - 1 doc.SetSelection(pos, pos) doc.SetCurrentPos(pos) def _HandlePythonFailure(background, what, syntaxErrorPathName = None): typ, details, tb = sys.exc_info() if typ == SyntaxError: try: msg, (fileName, line, col, text) = details if (not fileName or fileName =="<string>") and syntaxErrorPathName: fileName = syntaxErrorPathName _JumpToPosition(background, fileName, line, col) except (TypeError, ValueError): msg = str(details) #win32ui.SetStatusText('Failed to ' + what + ' - syntax error - %s' % msg) background.statusBar.text = 'Failed to ' + what + ' - syntax error - %s' % msg else: traceback.print_exc() #win32ui.SetStatusText('Failed to ' + what + ' - ' + str(details) ) # KEA 2002-06-03 # this needs to be more robust, but it is better than nothing for # simple indentation errors #try: # see if we have something of the form # (line 10) # for an error message that indicates the line number # the proper solution is to probably get the line number from the # traceback stack frame but I don't know how to do that #print traceback.tb_lineno(tb) try: msg, (fileName, line, col, text) = details _JumpToPosition(background, fileName, line, col) except: pass background.statusBar.text = 'Failed to ' + what + ' - ' + str(details) tb = None # Clean up a cycle. --- NEW FILE: stringDialog.rsrc.py --- {'type':'CustomDialog', 'name':'stringDialog', 'title':'String Editor', 'size':(480, 300), 'components': [ {'type':'List', 'name':'listStrings', 'position':(0, 0), 'size':(185, 185), 'items':[], }, {'type':'Button', 'name':'btnNew', 'position':(5, 190), 'label':'New', }, {'type':'Button', 'name':'btnDelete', 'position':(108, 191), 'label':'Delete', }, {'type':'StaticText', 'name':'stcName', 'position':(200, 10), 'text':'Name:', }, {'type':'StaticText', 'name':'stcValue', 'position':(200, 35), 'text':'Value:', }, {'type':'TextField', 'name':'fldListIndex', 'position':(460, 5), 'visible':0, }, {'type':'TextField', 'name':'fldName', 'position':(260, 5), 'size':(188, -1), }, {'type':'TextArea', 'name':'fldValue', 'position':(260, 35), 'size':(188, 197), }, {'type':'Button', 'name':'btnOK', 'position':(10, 240), 'label':'OK', 'default':1, 'id':5100, }, {'type':'Button', 'name':'btnCancel', 'position':(115, 240), 'label':'Cancel', 'id':5101, }, ] # end components } # end CustomDialog --- NEW FILE: menuDialog.py --- """ __version__ = "$Revision: 1.1 $" __date__ = "$Date: 2004/10/03 23:58:01 $" """ from PythonCard import log, model, resource import os import wx MENULIST_PADDING = '....' def menuItemAttributes(menuItem): desc = " {'type':'MenuItem',\n" desc += " 'name':'%s',\n" % menuItem['name'] # KEA 2002-05-16 # work on string repr to get strings with mixed ' and " to work correctly if menuItem['shortcut'] == '': desc += """ 'label':%s,\n""" % repr(menuItem['label']) else: desc += """ 'label':%s,\n""" % repr(menuItem['label'] + '\t' + menuItem['shortcut']) try: if menuItem['command'] is not None: desc += " 'command':'%s',\n" % menuItem['command'] except: pass try: if not menuItem['enabled']: desc += " 'enabled':0,\n" except: pass try: if menuItem['checkable']: desc += " 'checkable':1,\n" if menuItem['checked']: desc += " 'checked':1,\n" except: pass desc += " },\n" return desc def menuAttributes(menu): desc = " {'type':'Menu',\n" desc += " 'name':'%s',\n" % menu['name'] desc += """ 'label':%s,\n""" % repr(menu['label']) desc += " 'items': [\n" return desc def menuResourceFromList(menuList): #desc = " 'menubar': {'type':'MenuBar',\n" desc = "{'type':'MenuBar',\n" desc += " 'menus': [\n" inMenu = 0 for m in menuList: if m['type'] == 'Menu': if inMenu: # close Menu desc += " ]\n" desc += " },\n" desc += menuAttributes(m) inMenu = 1 else: desc += menuItemAttributes(m) # close Menu desc += " ]\n" desc += " },\n" # close MenuBar desc += " ]\n" desc += "}\n" d = eval(desc) return resource.Resource(d) class MenuDialog(model.CustomDialog): def __init__(self, aBg, rsrc): model.CustomDialog.__init__(self, aBg) self.parent = aBg # if some special setup is necessary, do it here if rsrc is not None: #aBg.printMenubar(rsrc) self.menuList = self.parseMenus(rsrc) else: self.menuList = [] for m in self.menuList: if m['type'] == 'Menu': self.components.listMenus.append(m['label']) else: self.components.listMenus.append(MENULIST_PADDING + m['label']) #self.components.listMenus.items = self.parseMenus(rsrc) # Esc doesn't seem to work, it ends up closing the dialog # so need to work on that self.keyCodes = {wx.WXK_ESCAPE:'ESC', wx.WXK_SPACE:'Space', wx.WXK_DELETE:'Del', wx.WXK_F1:'F1', wx.WXK_F2:'F2', wx.WXK_F3:'F3', wx.WXK_F4:'F4', wx.WXK_F5:'F5', wx.WXK_F6:'F6', wx.WXK_F7:'F7', wx.WXK_F8:'F8', wx.WXK_F9:'F9', wx.WXK_F10:'F10', wx.WXK_F11:'F11', wx.WXK_F12:'F12', } #self.components.fldName.text = rsrc.application.name #self.components.fldTitle.text = rsrc.application.title #self.components.fldPosition.text = str(rsrc.application.position) #self.components.fldSize.text = str(rsrc.application.size) #self.components.chkStatusBar.checked = rsrc.application.statusBar def buildMenu(self, name, label): m = {} m['type'] = 'Menu' m['name'] = name m['label'] = label return m def buildMenuItem(self, name, label, shortcut, command, enabled, checkable, checked): m = {} m['type'] = 'MenuItem' m['name'] = name m['label'] = label m['shortcut'] = shortcut m['command'] = command m['enabled'] = enabled m['checkable'] = checkable m['checked'] = checked return m def parseMenus(self, menubar): menuList = [] for menu in menubar.menus: #menuList.append(menu.label) #print menu.type, menu.name, menu.label menuList.append(self.buildMenu(menu.name, menu.label)) for menuItem in menu.items: itemParts = menuItem.label.split("\t") label = itemParts[0] try: shortcut = itemParts[1] except: shortcut = '' #menuList.append("....%s" % itemParts[0]) #print menuItem.type, menuItem.name, itemParts, menuItem.command, menuItem.enabled, menuItem.checkable, menuItem.checked menuList.append(self.buildMenuItem(menuItem.name, label, shortcut, menuItem.command, menuItem.enabled, menuItem.checkable, menuItem.checked)) return menuList def on_fldShortcut_keyDown(self, event): # this should handle the special key codes keyCode = event.keyCode if keyCode > 32 and keyCode < 127: keyStr = chr(keyCode).upper() elif keyCode in self.keyCodes: keyStr = self.keyCodes[keyCode] else: event.target.text = '' return if event.shiftDown: keyStr = 'Shift+' + keyStr if event.altDown: keyStr = 'Alt+' + keyStr if event.controlDown: keyStr = 'Ctrl+' + keyStr if len(keyStr) > 1: # don't allow just a number or letter # without a modifier # might also need a leading Ctrl or Alt event.target.text = keyStr def on_fldShortcut_keyPress(self, event): pass def on_fldName_loseFocus(self, event): sel = self.components.listMenus.selection try: self.menuList[sel]['name'] = event.target.text log.info(self.menuList[sel]) except: pass def on_fldLabel_loseFocus(self, event): def normalize(label): name = label.replace("&", "").replace(".", "").replace(" ", "") return name sel = self.components.listMenus.selection try: label = event.target.text if self.menuList[sel]['type'] == 'Menu' and self.menuList[sel]['label'] == 'New Menu': oldname = self.menuList[sel]['name'] if oldname == 'menuNewMenu': name = 'menu'+normalize(label) self.menuList[sel]['name'] = name self.components.fldName.text = name elif self.menuList[sel]['type'] == 'MenuItem' and self.menuList[sel]['label'] == 'New Item': oldname = self.menuList[sel]['name'] menuname = 'menuMenu' for i in range(sel+1): if self.menuList[sel-i]['type'] == 'Menu': menuname = self.menuList[sel-i]['name'] break if oldname == menuname+'NewItem': name = menuname+normalize(label) self.menuList[sel]['name'] = name self.components.fldName.text = name self.menuList[sel]['label'] = label if self.menuList[sel]['type'] == 'MenuItem': label = MENULIST_PADDING + label self.components.listMenus.setString(sel, label) log.info(self.menuList[sel]) except: pass def on_fldShortcut_loseFocus(self, event): sel = self.components.listMenus.selection try: if self.menuList[sel]['type'] == 'MenuItem': self.menuList[sel]['shortcut'] = event.target.text log.info(self.menuList[sel]) except: pass def on_fldCommand_loseFocus(self, event): sel = self.components.listMenus.selection try: if self.menuList[sel]['type'] == 'MenuItem': if event.target.text == '': self.menuList[sel]['command'] = None else: self.menuList[sel]['command'] = event.target.text log.info(self.menuList[sel]) except: pass def on_chkEnabled_mouseClick(self, event): sel = self.components.listMenus.selection try: if self.menuList[sel]['type'] == 'MenuItem': self.menuList[sel]['enabled'] = event.target.checked log.info(self.menuList[sel]) except: pass def on_chkCheckable_mouseClick(self, event): sel = self.components.listMenus.selection try: if self.menuList[sel]['type'] == 'MenuItem': self.menuList[sel]['checkable'] = event.target.checked log.info(self.menuList[sel]) except: pass def on_chkChecked_mouseClick(self, event): sel = self.components.listMenus.selection try: if self.menuList[sel]['type'] == 'MenuItem': self.menuList[sel]['checked'] = event.target.checked log.info(self.menuList[sel]) except: pass def displayItemAttributes(self, sel): m = self.menuList[sel] self.components.fldListIndex.text = str(sel) self.components.fldName.text = m['name'] self.components.fldLabel.text = m['label'] if m['type'] == 'MenuItem': self.components.fldShortcut.text = m['shortcut'] if m['command'] is None: self.components.fldCommand.text = '' else: self.components.fldCommand.text = m['command'] self.components.chkEnabled.checked = m['enabled'] self.components.chkCheckable.checked = m['checkable'] self.components.chkChecked.checked = m['checked'] self.components.stcShortcut.visible = 1 self.components.stcCommand.visible = 1 self.components.fldShortcut.visible = 1 self.components.fldCommand.visible = 1 self.components.chkEnabled.visible = 1 self.components.chkCheckable.visible = 1 self.components.chkChecked.visible = 1 else: self.components.stcShortcut.visible = 0 self.components.stcCommand.visible = 0 self.components.fldShortcut.visible = 0 self.components.fldCommand.visible = 0 self.components.chkEnabled.visible = 0 self.components.chkCheckable.visible = 0 self.components.chkChecked.visible = 0 def on_listMenus_select(self, event): self.displayItemAttributes(event.target.selection) def rebuildListMenus(self, sel=-1): self.components.listMenus.clear() for m in self.menuList: if m['type'] == 'Menu': self.components.listMenus.append(m['label']) else: self.components.listMenus.append(MENULIST_PADDING + m['label']) if sel != -1: self.components.listMenus.selection = sel def on_btnUp_mouseClick(self, event): sel = self.components.listMenus.selection # a selection of -1 means no selection # a selection of 0 is the first item in the list if sel > 0: temp = self.menuList[sel] self.menuList[sel] = self.menuList[sel - 1] self.menuList[sel - 1] = temp self.rebuildListMenus(sel - 1) def on_btnDown_mouseClick(self, event): sel = self.components.listMenus.selection if sel != -1 and sel < len(self.menuList) - 1: temp = self.menuList[sel] self.menuList[sel] = self.menuList[sel + 1] self.menuList[sel + 1] = temp self.rebuildListMenus(sel + 1) def on_btnDelete_mouseClick(self, event): sel = self.components.listMenus.selection if sel != -1: del self.menuList[sel] self.components.listMenus.delete(sel) if len(self.menuList) > 0: if sel > 0: sel = sel - 1 self.components.listMenus.selection = sel self.displayItemAttributes(sel) def on_btnNewMenu_mouseClick(self, event): sel = self.components.listMenus.selection self.menuList.append(" ") # extend list if sel == -1: sel = len(self.menuList) - 1 else: self.menuList[sel+1:] = self.menuList[sel:-1] sel = sel+1 self.menuList[sel] = self.buildMenu('menuNewMenu', 'New Menu') self.rebuildListMenus(sel) self.displayItemAttributes(sel) def on_btnNewMenuItem_mouseClick(self, event): sel = self.components.listMenus.selection self.menuList.append(" ") # extend list if sel == -1: sel = len(self.menuList) - 1 else: self.menuList[sel+1:] = self.menuList[sel:-1] sel = sel+1 name = 'menuMenu' for i in range(1, sel+1): if self.menuList[sel-i]['type'] == 'Menu': name = self.menuList[sel-i]['name'] break self.menuList[sel] = self.buildMenuItem(name+'NewItem', 'New Item', '', None, 1, 0, 0) self.rebuildListMenus(sel) self.displayItemAttributes(sel) def menuDialog(parent, rsrc): dlg = MenuDialog(parent, rsrc) result = dlg.showModal() if result.accepted: if len(dlg.menuList) == 0: result.menubar = None else: result.menubar = menuResourceFromList(dlg.menuList) dlg.destroy() return result --- NEW FILE: __init__.py --- # turn modules into a package --- NEW FILE: propertyEditor.py --- #!/usr/bin/python """ __version__ = "$Revision: 1.1 $" __date__ = "$Date: 2004/10/03 23:58:01 $" """ from PythonCard import dialog, font, model, registry, util from PythonCard.event import ChangeListener import resourceOutput import time import os import string import wx # KEA this is a load of dingos' kidneys and needs to be rewritten # 2002-02-22 # now I'm compounding the problem by porting from the original # Property Editor to a PythonCard background class PropertyEditor(model.Background, ChangeListener): def on_initialize(self, event): self._parent = self.GetParent() self._comp = self._parent.components self._updatingComponent = 0 self.autoAttributeUpdate = True ##self.components.addChangeEventListener(self) self._comp.addChangeEventListener(self) self.editItems = [self.components.wField, self.components.wColor, self.components.wFont, self.components.wTextArea, self.components.wChecked, self.components.wPop, self.components.wFile,] # KEA 2001-08-14 # this was causing an assertion error with the hybrid wxPython #self.components.wComponentList.SetSelection(0) if self.components.wComponentList.stringSelection == "": wClass = "" else: wName, wClass = self.components.wComponentList.stringSelection.split(" : ") self.setValidProps(wClass) #self.displayComponents(self.components) self.displayComponents(self._comp) self.visible = True # KEA 2004-08-23 # support updating of attributes without the need # for clicking the Update button def on_wField_closeField(self, event): if self.autoAttributeUpdate: self.updateComponent() def on_wTextArea_closeField(self, event): if self.autoAttributeUpdate: self.updateComponent() def on_wChecked_mouseClick(self, event): if self.autoAttributeUpdate: self.updateComponent() def on_wPop_select(self, event): if self.autoAttributeUpdate: self.updateComponent() def on_wColor_mouseClick(self, event): result = dialog.colorDialog(self, color=util.colorFromString(self.components.wField.text)) if result.accepted: self.components.wField.text = str(result.color) if self.autoAttributeUpdate: self.updateComponent() def on_wFont_mouseClick(self, event): wName, wClass = self.components.wComponentList.stringSelection.split(" : ") ##widget = self.components[wName] widget = self._comp[wName] f = widget.font if f is None: desc = font.fontDescription(widget.GetFont()) f = font.Font(desc) result = dialog.fontDialog(self, f) if result.accepted: #color = dlg.getColor() f = result.font #self.components.wField.SetValue("%s;%s" % (f, color)) self.components.wField.text = "%s" % f if self.autoAttributeUpdate: self.updateComponent() def on_wFile_mouseClick(self, event): path, filename = os.path.split(self.components.wField.text) result = dialog.openFileDialog(self, directory=path, filename=filename) if result.accepted: self.components.wField.text = util.relativePath(self._parent.filename, result.paths[0]) if self.autoAttributeUpdate: self.updateComponent() def addWidgetToComponentList(self, widget): wName = widget.name # KEA 2004-01-25 # just use __name__, the other code must have been something from wxPython 2.3 #wClass = str(widget.__class__).split('.') #self.components.wComponentList.Append(wName + " : " + wClass[len(wClass) - 1]) wClass = widget.__class__.__name__ self.components.wComponentList.Append(wName + " : " + wClass) # KEA 2002-02-23 # need to redo the logic below to avoid asserts in hybrid # versions of wxPython, but also be cleaner def deleteWidgetFromComponentList(self, wName, wClass): i = self.components.wComponentList.GetSelection() j = self.components.wComponentList.FindString(wName + " : " + wClass) if i == -1 or i != j: if j != -1: self.components.wComponentList.Delete(j) else: if j > 0: self.components.wComponentList.SetSelection(j - 1) if j != -1: self.components.wComponentList.Delete(j) if self.components.wComponentList.GetSelection() == -1: self.setValidProps("") self.hideAllBut(self.components.wField) else: wName, wClass = self.components.wComponentList.stringSelection.split(" : ") # deselect the name from properties list self.setValidProps(wClass) propName = self.components.wPropertyList.stringSelection if propName == "": propName = "name" self.components.wPropertyList.stringSelection = "name" self.displayProperty(wName, wClass, propName) def selectComponentList(self, wName, wClass): self.components.wComponentList.stringSelection = wName + " : " + wClass self.setValidProps(wClass) propName = self.components.wPropertyList.stringSelection #print propName if propName == "": propName = "name" self.components.wPropertyList.stringSelection = "name" self.displayProperty(wName, wClass, propName) c = self._parent.components[wName] self._parent.setToolTipDrag(wName, c.position, c.size) def changed(self, event): ##comp = self.components if self._updatingComponent: # KEA 2003-01-04 # hack to speed up updates in place return comp = self._comp wName, wClass = event.getOldValue().split(",") if wName in comp: # new item added self.addWidgetToComponentList(comp[wName]) else: # item deleted self.deleteWidgetFromComponentList(wName, wClass) """ def on_wCopy_mouseClick(self, event): wName, wClass = self.components.wComponentList.stringSelection.split(" : ") # what needs to happen here is to have a method for the Widget class that # will provide a valid resource description, each subclass of widget would # override the method to deal with their specific resource attributes # the Widget class should provide some ordering so that 'type', # 'position', 'size' comes before less commonly used items, the actual # ordering could just be defined in a list, so it is easy to change # also, if the current values match the defaults for a widget attribute # then that attribute should not be provided as part of the output print "this is just a placeholder method right now," print "the resource is not actually copied to the clipboard yet" pprint.pprint(self._comp[wName]) """ def on_wUpdate_mouseClick(self, event): self.updateComponent() def updateComponent(self): # make these attributes of self, since they are duplicated below in displayProperty checkItems = ['enabled', 'visible', 'editable', 'checked', 'default', 'rules', 'labels', 'ticks', 'horizontalScrollbar'] popItems = ['layout', 'border', 'style', 'alignment', 'stringSelection'] cantmodify = ['id', 'name', 'alignment', 'layout', 'style', 'border', 'horizontalScrollbar', \ 'min', 'max', 'columns', 'rules', 'labels', 'ticks'] wName, wClass = self.components.wComponentList.stringSelection.split(" : ") propName = self.components.wPropertyList.stringSelection # KEA 2002-02-23 ##if propName not in cantmodify: #print "updating", wName if propName in checkItems: value = self.components.wChecked.checked elif propName in popItems: value = self.components.wPop.stringSelection elif propName in ('items', 'userdata') or (wClass == 'TextArea' and propName == 'text'): value = self.components.wTextArea.text else: #value = self.components.wField.GetValue() value = self.components.wField.text if propName not in ['label', 'stringSelection', 'text', 'toolTip']: try: value = eval(value) except: pass # KEA 2004-05-10 # need to figure out where to stick validation code # but for now just need to make sure that if we're changing the name # attribute that it is valid, but similar checks will be necessary for # integer fields, a list of items, etc. # also maybe each attribute should have a doc or help string displayed # saying what the attribute does, example values, etc. if propName == 'name': badValue = False # if it isn't valid then display an alert and exit # must start with a letter and only contain alphanumeric characters if value == "" or value[0] not in string.ascii_letters: badValue = True else: alphanumeric = string.ascii_letters + string.digits for c in value: if c not in alphanumeric: badValue = True break if badValue: dialog.alertDialog(None, "Name must start with a letter and only contain letters and numbers.", 'Error: Name is invalid') self.components.wField.setFocus() self.components.wField.setSelection(-1, -1) return # check for duplicate names is done below ##widget = self.components[wName] widget = self._comp[wName] # KEA 2002-02-23 # I can't remember why this is actually necessary if propName == 'size': width, height = value if wClass not in ['BitmapCanvas', 'HtmlWindow']: bestWidth, bestHeight = widget.GetBestSize() if width == -1: width = bestWidth if height == -1: height = bestHeight widget.size = (width, height) #setattr(widget, propName, (width, height)) #print widget.size, propName, width, height else: if (propName in cantmodify) or \ (propName == 'items' and wClass == 'RadioGroup'): order = self._comp.order.index(wName) desc = resourceOutput.widgetAttributes(self._parent, widget) if desc.endswith(',\n'): desc = eval(desc[:-2]) else: desc = eval(desc) if propName == 'name': if value == wName: # user didn't actually change the name return elif value in self._comp: # we already have a component with that name dialog.alertDialog(self, 'Another component already exists with the name ' + value, 'Error: unable to rename component') return if value is None: desc[propName] = 'none' elif propName in ['min', 'max']: desc[propName] = int(value) else: desc[propName] = value # need to experiment with freeze and thaw to avoid # a lot of update events startTime = time.time() # this is going to trigger a changed event # as we delete the old component self._updatingComponent = True del self._comp[wName] if propName == 'name': wName = value # this is going to trigger another changed event # as we create a new component with the changed attribute self._comp[wName] = desc c = self._comp[wName] wx.EVT_LEFT_DOWN(c, self._parent.on_mouseDown) wx.EVT_LEFT_UP(c, self._parent.on_mouseUp) wx.EVT_MOTION(c, self._parent.on_mouseDrag) # now restore the order of the component # have to update the startName in case the name was updated if propName == 'name': self._parent.startName = wName self._comp.order.remove(wName) self._comp.order.insert(order, wName) self._parent.fixComponentOrder(wName) self._updatingComponent = False endTime = time.time() #print "attribute change took:", endTime - startTime else: if wClass in ['Image', 'ImageButton'] and propName == 'file': cwd = os.getcwd() try: os.chdir(self._parent.filename) except: pass setattr(widget, propName, value) os.chdir(cwd) else: setattr(widget, propName, value) #print propName, value # KEA 2002-02-23 self._parent.showSizingHandles(wName) def setValidProps(self, wClass): #print "setValidProps", wClass oldProp = self.components.wPropertyList.stringSelection if wClass == "": self.components.wPropertyList.Clear() else: ##props = self.propList + self.optionalProps[wClass] ##props.sort() ##print "props", props # get the property (attribute) list from the spec klass = registry.Registry.getInstance().getComponentClass(wClass) props = klass._spec.getAttributes().keys() # KEA 2002-03-24 # only show the 'id' attribute for Button # and only when displaying dialog properties if not (self._parent.editingDialog and wClass == 'Button'): props.remove('id') props.sort() ##print "spec props", specProps self.components.wPropertyList.Clear() self.components.wPropertyList.InsertItems(props, 0) if oldProp in props: self.components.wPropertyList.stringSelection = oldProp def hideAllBut(self, widget): for w in self.editItems: if widget.id != w.id: w.visible = False def displayProperty(self, wName, wClass, propName): checkItems = ['enabled', 'visible', 'editable', 'checked', 'default', 'rules', 'labels', 'ticks', 'horizontalScrollbar'] popItems = ['layout', 'border', 'style', 'alignment', 'stringSelection'] self.components.wName.text = propName + ":" ##widget = self.components[wName] widget = self._comp[wName] if propName in ['label', 'stringSelection', 'text', 'toolTip'] or propName in checkItems: value = getattr(widget, propName) else: value = str(getattr(widget, propName)) if propName in checkItems: self.hideAllBut(self.components.wChecked) self.components.wChecked.visible = True self.components.wChecked.checked = value elif propName in popItems: self.hideAllBut(self.components.wPop) self.components.wPop.visible = True self.components.wPop.Clear() if propName == 'stringSelection': for v in widget.items: self.components.wPop.Append(v) else: for v in widget._spec.getAttributes()[propName].values: self.components.wPop.Append(v) try: self.components.wPop.stringSelection = value except: # if value is empty or doesn't already exist pass elif propName in ('items', 'userdata') or (wClass == 'TextArea' and propName == 'text'): #print 'displaying TextArea' self.hideAllBut(self.components.wTextArea) self.components.wTextArea.visible = True self.components.wTextArea.text = value else: self.hideAllBut(self.components.wField) self.components.wField.visible = True if propName == 'foregroundColor' or propName == 'backgroundColor': self.components.wColor.visible = True elif propName == 'font': self.components.wFont.visible = True elif propName == 'file': self.components.wFile.visible = True self.components.wName.text = propName + ":" # KEA 2002-02-23 # I can't remember why this is actually necessary if propName == 'size': width, height = getattr(widget, propName) if wClass not in ['BitmapCanvas', 'HtmlWindow']: bestWidth, bestHeight = widget.GetBestSize() if width == bestWidth: width = -1 if height == bestHeight: height = -1 size = (width, height) value = str(size) self.components.wField.text = value # this should only display if the attribute is settable # so name, alignment, and others are read-only # KEA 2002-02-23 # wUpdate is always visible now self.components.wUpdate.visible = True def on_wComponentList_select(self, event): #print 'selectComponentListEvent: %s\n' % event.GetString() wName, wClass = event.GetString().split(" : ") # change the wPropertiesList to only show relevant properties # either display the name by default or try and preserve the # wPropertiesList selection and display that item, so for example # you could look at size for all widgets, simply by going up and down # the components list self.setValidProps(wClass) propName = self.components.wPropertyList.stringSelection #print propName if propName == "": propName = "name" self.components.wPropertyList.stringSelection = "name" self.displayProperty(wName, wClass, propName) self._parent.showSizingHandles(wName) c = self._parent.components[wName] self._parent.setToolTipDrag(wName, c.position, c.size) def on_wPropertyList_select(self, event): propName = event.GetString() wName, wClass = self.components.wComponentList.stringSelection.split(" : ") if wName != "": self.displayProperty(wName, wClass, propName) def clearComponentList(self): self.components.wComponentList.Clear() self.statusBar.text = '' def clearPropertyList(self): self.components.wPropertyList.Clear() def displayComponents(self, components): self.components.wComponentList.Freeze() self.components.wComponentList.Clear() self._comp = components for c in components.order: if c not in self._parent.sizingHandleNames: self.addWidgetToComponentList(components[c]) self.components.wComponentList.Thaw() self.components.wComponentList.Refresh() self.components.wComponentList.Update() def on_close(self, event): self.visible = False parent = self.GetParent() parent.menuBar.setChecked('menuViewPropertyEditor', 0) --- NEW FILE: propertyEditor.rsrc.py --- {'application':{'type':'Application', 'name':'Template', 'backgrounds': [ {'type':'Background', 'name':'bgTemplate', 'title':'resourceEditor Property Editor', 'size':(405, 270), 'visible':0, 'statusBar':1, 'components': [ {'type':'Button', 'name':'wUpdate', 'position':(320, 195), 'label':'Update', 'visible':0, 'default':1, }, {'type':'Choice', 'name':'wPop', 'position':(130, 130), 'size':(-1, 21), 'items':[], 'visible':0, }, {'type':'CheckBox', 'name':'wChecked', 'position':(130, 132), 'visible':0, 'label':'', }, {'type':'TextArea', 'name':'wTextArea', 'position':(130, 130), 'size':(260, 50), 'visible':0, }, {'type':'Button', 'name':'wFont', 'position':(320, 130), 'label':'Font...', 'visible':0, }, {'type':'Button', 'name':'wColor', 'position':(320, 130), 'label':'Color...', 'visible':0, }, {'type':'Button', 'name':'wFile', 'position':(320, 130), 'label':'File...', 'visible':0, }, {'type':'TextField', 'name':'wField', 'position':(130, 130), 'size':(180, -1), }, {'type':'StaticText', 'name':'wName', 'position':(5, 135), 'size':(120, -1), 'alignment':'right', 'text':'name:', }, {'type':'List', 'name':'wPropertyList', 'position':(225, 20), 'size':(165, 100), 'items':[], }, {'type':'List', 'name':'wComponentList', 'position':(5, 20), 'size':(200, 100), 'items':[], }, {'type':'StaticText', 'name':'Properties', 'position':(228, 3), 'text':'Properties', }, {'type':'StaticText', 'name':'stcNameClass', 'position':(5, 3), 'text':'Name : Class', }, ] # end components } # end background ] # end backgrounds } } --- NEW FILE: stringDialog.py --- """ __version__ = "$Revision: 1.1 $" __date__ = "$Date: 2004/10/03 23:58:01 $" """ from PythonCard import log, model, resource import os import wx NEWSTRING = 'newString' SPACER = ' : ' def stringResourceFromList(stringList): desc = " {\n" for s in stringList: desc += """ %s:%s,\n""" % (repr(s), repr(stringList[s])) # close strings desc += " }\n" d = eval(desc) return resource.Resource(d) class StringDialog(model.CustomDialog): def __init__(self, aBg, stringList): model.CustomDialog.__init__(self, aBg) self.parent = aBg """ # KEA 2004-08-22 # workaround/hack to make sure closeField message # is processed prior to the dialog being closed # this occurs when one of the fields are edited and then # the user clicks Ok # this hack works because we don't process on_close # the first time, but rather delay it by posting a second close message self.closeDialog = False """ # if some special setup is necessary, do it here self.stringList = stringList sortedStrings = self.stringList.keys() sortedStrings.sort() for s in sortedStrings: label = self.getLabelFromKey(s) self.components.listStrings.append(label) def parseStrings(self, rsrc): stringList = {} for s in rsrc.__dict__: stringList[s] = rsrc.__dict__[s] return stringList def getLabelFromKey(self, key): return key + SPACER + self.stringList[key].split('\n')[0] def updateItemLabel(self, n, key): label = self.getLabelFromKey(key) self.components.listStrings.setString(n, label) def getStringSelectionKey(self): return self.components.listStrings.stringSelection.split()[0] def on_fldName_closeField(self, event): print "closeField fldName", event.target.text newName = event.target.text previousName = self.getStringSelectionKey() # if the name changes then we have to check to see # if the dictionary already has a key with the new # name if newName in self.stringList: # replace? pass else: sel = self.components.listStrings.selection self.stringList[newName] = self.stringList[previousName] del self.stringList[previousName] #self.components.listStrings.setString(sel, newName) self.updateItemLabel(sel, newName) def on_fldValue_closeField(self, event): print "closeField fldValue", event.target.text sel = self.components.listStrings.selection name = self.getStringSelectionKey() self.stringList[name] = event.target.text self.updateItemLabel(sel, name) def displayItemAttributes(self, s): self.components.fldName.text = s self.components.fldValue.text = self.stringList[s] def on_listStrings_select(self, event): self.displayItemAttributes(self.getStringSelectionKey()) def on_btnDelete_mouseClick(self, event): sel = self.components.listStrings.selection name = self.getStringSelectionKey() if sel != -1: del self.stringList[name] self.components.listStrings.delete(sel) if len(self.stringList) > 0: if sel > len(self.stringList) - 1: sel = sel - 1 self.components.listStrings.selection = sel self.displayItemAttributes(self.getStringSelectionKey()) def on_btnNew_mouseClick(self, event): s = NEWSTRING if s in self.stringList: self.components.listStrings.stringSelection = self.getLabelFromKey(s) else: self.stringList[s] = '' sel = len(self.stringList) - 1 self.components.listStrings.append(s) self.components.listStrings.stringSelection = s self.updateItemLabel(sel, s) self.displayItemAttributes(self.getStringSelectionKey()) """ # KEA 2004-08-22 # experiment to workaround Mac closeField bug # ignore for now along with the extra debug print statements in closeField # event handlers above def on_mouseClick(self, event): try: print self.closeDialog print event.target.name print event.target.id except: pass if self.closeDialog: event.skip() else: self.closeDialog = True wx.PostEvent(self, event) """ def stringDialog(parent, rsrc): dlg = StringDialog(parent, rsrc) result = dlg.showModal() if result.accepted: result.stringList = stringResourceFromList(dlg.stringList) dlg.destroy() return result --- NEW FILE: menuDialog.rsrc.py --- {'type':'CustomDialog', 'name':'menuDialog', 'title':'Menu Editor', 'size':(480, 300), 'components': [ {'type':'List', 'name':'listMenus', 'position':(0, 0), 'size':(185, 185), 'items':[], }, {'type':'Button', 'name':'btnUp', 'position':(5, 190), 'size':(50, -1), 'label':'Up', }, {'type':'Button', 'name':'btnDown', 'position':(60, 190), 'size':(60, -1), 'label':'Down', }, {'type':'Button', 'name':'btnDelete', 'position':(125, 190), 'size':(60, -1), 'label':'Delete', }, {'type':'StaticText', 'name':'stcName', 'position':(200, 10), 'text':'Name:', }, {'type':'StaticText', 'name':'stcLabel', 'position':(200, 35), 'text':'Label:', }, {'type':'StaticText', 'name':'stcShortcut', 'position':(200, 60), 'text':'Shortcut:', }, {'type':'StaticText', 'name':'stcCommand', 'position':(200, 85), 'text':'Command:', }, {'type':'TextField', 'name':'fldListIndex', 'position':(460, 5), 'visible':False, }, {'type':'TextField', 'name':'fldName', 'position':(275, 5), 'size':(188, -1), }, {'type':'TextField', 'name':'fldLabel', 'position':(275, 30), 'size':(188, -1), }, {'type':'TextField', 'name':'fldShortcut', 'position':(275, 55), 'size':(188, -1), }, {'type':'TextField', 'name':'fldCommand', 'position':(275, 80), 'size':(188, -1), }, {'type':'CheckBox', 'name':'chkEnabled', 'position':(275, 110), 'checked':True, 'label':'Enabled', }, {'type':'CheckBox', 'name':'chkCheckable', 'position':(275, 135), 'label':'Checkable', }, {'type':'CheckBox', 'name':'chkChecked', 'position':(275, 160), 'label':'Checked', }, {'type':'Button', 'name':'btnNewMenu', 'position':(220, 190), 'label':'New Menu', }, {'type':'Button', 'name':'btnNewMenuItem', 'position':(320, 190), 'label':'New MenuItem', }, {'type':'Button', 'id':5100, 'name':'btnOK', 'position':(10, 240), 'default':1, 'label':'OK', }, {'type':'Button', 'id':5101, 'name':'btnCancel', 'position':(115, 240), 'label':'Cancel', }, ] # end components } # end CustomDialog --- NEW FILE: backgroundInfoDialog.rsrc.py --- {'type':'CustomDialog', 'name':'backgroundInfo', 'title':'Background Info', 'size':(370, 380), 'components': [ {'type':'StaticText', 'name':'stcName', 'position':(10, 10), 'text':'Name:', }, {'type':'StaticText', 'name':'stcTitle', 'position':(10, 35), 'text':'Title:', }, {'type':'StaticText', 'name':'stcPosition', 'position':(10, 60), 'text':'Position:', }, {'type':'StaticText', 'name':'stcSize', 'position':(10, 85), 'text':'Size:', }, {'type':'StaticText', 'name':'stcForegroundColor', 'position':(10, 110), 'text':'Foreground color:', }, {'type':'StaticText', 'name':'stcBackgroundColor', 'position':(10, 135), #'size':(90, -1), 'text':'Background color:', }, {'type':'StaticText', 'name':'stcImage', 'position':(10, 160), 'text':'Image:', }, {'type':'StaticText', 'name':'stcIcon', 'position':(10, 210), 'text':'Icon:', }, {'type':'TextField', 'name':'fldName', 'position':(130, 5), }, {'type':'TextField', 'name':'fldTitle', 'position':(130, 30), 'size':(188, -1), }, {'type':'TextField', 'name':'fldPosition', 'position':(130, 55), 'size':(80, -1), }, {'type':'TextField', 'name':'fldSize', 'position':(130, 80), 'size':(80, -1), }, {'type':'TextField', 'name':'fldForegroundColor', 'position':(130, 110), 'size':(100, -1), }, {'type':'Button', 'name':'btnForegroundColor', 'position':(250, 110), 'label':'Color...', }, {'type':'TextField', 'name':'fldBackgroundColor', 'position':(130, 135), 'size':(100, -1), }, {'type':'Button', 'name':'btnBackgroundColor', 'position':(250, 135), 'label':'Color...', }, {'type':'TextField', 'name':'fldImage', 'position':(130, 160), 'size':(100, -1), }, {'type':'Button', 'name':'btnFile', 'position':(250, 160), 'label':'File...', }, {'type':'CheckBox', 'name':'chkTiled', 'position':(130, 185), 'size':(135, -1), 'checked':0, 'label':'Tile image', }, {'type':'TextField', 'name':'fldIcon', 'position':(130, 210), 'size':(100, -1), }, {'type':'Button', 'name':'btnIconFile', 'position':(250, 210), 'label':'File...', }, {'type':'CheckBox', 'name':'chkStatusBar', 'position':(130, 235), 'checked':0, 'label':'Status bar on window', }, {'type':'CheckBox', 'name':'chkVisible', 'position':(130, 260), 'size':(135, -1), 'checked':1, 'label':'Visible at startup', }, {'type':'CheckBox', 'name':'chkResizeable', 'position':(130, 285), 'size':(135, -1), 'checked':0, 'label':'Resizeable', }, {'type':'Button', 'name':'btnOK', 'position':(10, 320), 'label':'OK', 'default':1, 'id':5100, }, {'type':'Button', 'name':'btnCancel', 'position':(115, 320), 'label':'Cancel', 'id':5101, }, ] # end components } # end CustomDialog --- NEW FILE: stackInfoDialog.py --- """ __version__ = "$Revision: 1.1 $" __date__ = "$Date: 2004/10/03 23:58:01 $" """ from PythonCard import model import os class StackInfoDialog(model.CustomDialog): def __init__(self, aBg, rsrc): model.CustomDialog.__init__(self, aBg) self.parent = aBg # if some special setup is necessary, do it here self.components.fldName.text = rsrc.application.name def stackInfoDialog(parent): dlg = StackInfoDialog(parent, parent.rsrc) result = dlg.showModal() result.text = dlg.components.fldName.text dlg.destroy() return result --- NEW FILE: stackInfoDialog.rsrc.py --- {'type':'CustomDialog', 'name':'stackInfo', 'title':'Stack Info', 'size':(270, 100), 'components': [ {'type':'StaticText', 'name':'stcName', 'position':(10, 10), 'size':(45, -1), 'text':'Name:', }, {'type':'TextField', 'name':'fldName', 'position':(60, 5), 'size':(188, -1), }, {'type':'Button', 'name':'btnOK', 'position':(10, 40), 'label':'OK', 'default':1, 'id':5100, }, {'type':'Button', 'name':'btnCancel', 'position':(115, 40), 'label':'Cancel', 'id':5101, }, ] # end components } # end CustomDialog --- NEW FILE: newComponentDialog.rsrc.py --- {'type':'CustomDialog', 'name':'Template', 'title':'Dialog Template', 'size':(300, 170), 'components': [ {'type':'TextField', 'name':'fldName', 'position':(60, 9), 'size':(230, -1), }, {'type':'TextField', 'name':'fldLabelOrText', 'position':(60, 40), 'size':(230, -1), }, {'type':'CheckBox', 'name':'chkHorizontal', 'position':(10, 80), 'label':'Offset Horizontally', }, {'type':'CheckBox', 'name':'chkVertical', 'position':(170, 80), 'label':'Offset Vertically', }, {'type':'Button', 'id':5100, 'name':'btnOK', 'position':(30, 110), 'label':'OK', }, {'type':'Button', 'id':5101, 'name':'btnCancel', 'position':(130, 110), 'label':'Cancel', }, {'type':'StaticText', 'name':'lblLabelOrText', 'position':(5, 40), 'size':(50, -1), 'alignment':'right', 'text':'Label:', }, {'type':'StaticText', 'name':'lblName', 'position':(5, 10), 'size':(50, -1), 'alignment':'right', 'text':'Name:', }, ] # end components } # end CustomDialog --- NEW FILE: dialogInfoDialog.rsrc.py --- {'type':'CustomDialog', 'name':'dialogInfo', 'title':'Dialog Info', 'size':(370, 170), 'components': [ {'type':'StaticText', 'name':'stcName', 'position':(10, 10), 'size':(45, -1), 'text':'Name:', }, {'type':'StaticText', 'name':'stcTitle', 'position':(10, 35), 'size':(45, -1), 'text':'Title:', }, {'type':'StaticText', 'name':'stcPosition', 'position':(10, 60), 'size':(45, -1), 'text':'Position:', }, {'type':'StaticText', 'name':'stcSize', 'position':(10, 85), 'size':(45, -1), 'text':'Size:', }, {'type':'TextField', 'name':'fldName', 'position':(110, 5), 'size':(188, -1), }, {'type':'TextField', 'name':'fldTitle', 'position':(110, 30), 'size':(188, -1), }, {'type':'TextField', 'name':'fldPosition', 'position':(110, 55), 'size':(68, -1), }, {'type':'TextField', 'name':'fldSize', 'position':(110, 80), 'size':(68, -1), }, {'type':'Button', 'name':'btnOK', 'position':(10, 110), 'label':'OK', 'default':1, 'id':5100, }, {'type':'Button', 'name':'btnCancel'... [truncated message content] |