daboide Commit Revision 602 Date: 2006-07-31 17:55:23 -0700 (Mon, 31 Jul 2006) Author: ed
Changed: U trunk/ClassDesigner.py U trunk/ClassDesignerFormMixin.py
Log: Re-vamped the way that method code is stored when using the Class Designer. Instead of being embedded in a CDATA section of the XML, it is now saved in a separate .py file with a name similar to that of the .cdxml file. For example, if your design is saved in a file named "myCoolDesign.cdxml', the code for that file will be in a file named 'myCoolDesign-code.py'.
This code file is a normal Python script file that can be edited with the editor of your choice. It does contain some comment lines that, if altered, will break the link back to the object to which the code belongs. As long as you don't mess with those lines, though, you can edit the code in your favorite editor, and when you re-open the class, your changes will be included.
This is in answer to those who have their own editors they prefer for working with Python code. Let me know what you think!
Diff: Modified: trunk/ClassDesigner.py =================================================================== --- trunk/ClassDesigner.py 2006-07-28 23:33:41 UTC (rev 601) +++ trunk/ClassDesigner.py 2006-08-01 00:55:23 UTC (rev 602) @@ -23,7 +23,8 @@ from ClassDesignerControlMixin import ClassDesignerControlMixin as cmix from ClassDesignerCustomPropertyDialog import ClassDesignerCustomPropertyDialog import ClassDesignerMenu -from dabo.lib.xmltodict import xmltodict +import dabo.lib.xmltodict as xtd +import dabo.lib.DesignerUtils as desUtil from dabo.lib.utils import dictStringify from ClassDesignerExceptions import PropertyUpdateException @@ -390,8 +391,8 @@ except: pass ret = mf and (mf._initialStateDict == mfCurrDict) return ret - - + + def openClass(self, pth): """Called when the user selects the 'Open' menu and selects a saved XML file. We need to open the file, and confirm that it is @@ -400,9 +401,16 @@ """ xml = open(pth).read() try: - clsd = xmltodict(xml) + clsd = xtd.xmltodict(xml) except: raise IOError, _("This does not appear to be a valid class file.") + # Get the associated code file, if any + codePth = "%s-code.py" % os.path.splitext(pth)[0] + try: + codeDict = desUtil.parseCodeFile(open(codePth).read()) + desUtil.addCodeToClassDict(clsd, codeDict) + except StandardError, e: + print "Failed to parse code file:", e # See if it is a full form-based class, or an individual component. isFormClass = (clsd["name"] == "dForm") @@ -2178,7 +2186,7 @@ self.addToMRU(self._customClassCaption, pth, self.addCustomClass) xml = open(pth).read() try: - clsd = xmltodict(xml) + clsd = xtd.xmltodict(xml) except: raise IOError, _("This does not appear to be a valid class file.") # We need to replace the 'designerClass' attribute so that
Modified: trunk/ClassDesignerFormMixin.py =================================================================== --- trunk/ClassDesignerFormMixin.py 2006-07-28 23:33:41 UTC (rev 601) +++ trunk/ClassDesignerFormMixin.py 2006-08-01 00:55:23 UTC (rev 602) @@ -17,7 +17,8 @@ from ClassDesignerComponents import LayoutBorderSizer from ClassDesignerComponents import LayoutGridSizer from ClassDesignerComponents import LayoutSaverMixin -from dabo.lib.xmltodict import dicttoxml +import dabo.lib.xmltodict as xtd +import dabo.lib.DesignerUtils as desUtil dui = dabo.ui class ClassDesignerFormMixin(LayoutSaverMixin): @@ -191,12 +192,39 @@ cd = propDict.get("code", {}) cd.update({"importStatements": imp}) propDict["code"] = cd - xml = dicttoxml(propDict) + + propDict, codeDict = self._extractCodeFromPropDict(propDict) + xml = xtd.dicttoxml(propDict) # Try opening the file. If it is read-only, it will raise an - # IOError that the calling method can catch. + # IOErrorrror that the calling method can catch. open(self._classFile, "wb").write(xml) + # Now write out the code file + cfName = "%s-code.py" % os.path.splitext(self._classFile)[0] + open(cfName, "wb").write(self._createDesignerCode(codeDict)) - + + def _createDesignerCode(self, cd): + """Given a dict of code, create the Python script containing that code.""" + ret = """### Dabo Class Designer code. You many freely edit the code, +### but do not change the comments containing: +### 'Dabo Code ID: XXXX', +### as these are needed to link the code to the objects.\n\n""" + codeHeaderTemplate = desUtil.getCodeObjectSeperator() + "%s" + body = [] + for codeKey, mthds in cd.items(): + # Sort the methods alphabetically + mthNames = mthds.keys() + mthNames.sort() + code = "" + for mthd in mthNames: + code += mthds[mthd].strip() + while not code.endswith("\n\n"): + code += "\n" + hdr = codeHeaderTemplate % codeKey + body.append("%s\n%s" % (hdr, code)) + return ret + "\n\n".join(body) + + def onSaveClassDesign(self, evt): """Save the contents of the designer, excluding the outer form, as a separate class that can be used in other designs. @@ -244,10 +272,44 @@ self.app.flushCodeEditor() topObj.__setattr__(LayoutSaverMixin.classFlagProp, clsFile) propDict = self.getClassDesignerDict(topObj) - xml = dicttoxml(propDict) + xml = xtd.dicttoxml(propDict) # Try opening the file. If it is read-only, it will raise an # IOError that the calling method can catch. open(clsFile, "wb").write(xml) + + + def _extractCodeFromPropDict(self, pd, cd=None, prntName=None): + """Extract all 'code' keys into a separate dict. Remove them from the + passed dict. Add 'code-ID' attributes to any dicts with code. + Return a 2-tuple of dicts: the original dict with the code extracted, and the + code dict with each code-ID as the key. + """ + if cd is None: + cd = {} + if prntName is None: + prntName = "top" + nm = pd.get("name", "NONAME") + atts = pd.get("attributes", {}) + kids = pd.get("children", []) + code = pd.get("code", {}) + pd["code"] = {} + if code: + # Add it to the code dict + codeIDbase = codeID = atts.get("code-ID", "%s-%s" % (nm, prntName)) + while cd.has_key(codeID): + codeID = "%s-%s" % (codeIDbase, random.randrange(999)) + pd["attributes"].update({"code-ID": codeID}) + cd[codeID] = code + pd["children"] = [] + isSizer = (atts["designerClass"] in ("LayoutGridSizer", + "LayoutSizer", "LayoutBorderSizer")) + if isSizer: + # Pass the parent name instead of the sizer name + nm = prntName + for kid in kids: + kd, cd = self._extractCodeFromPropDict(kid, cd, nm) + pd["children"].append(kd) + return (pd, cd) def getClassDesignerDict(self, obj): @@ -275,7 +337,8 @@ if not self._classFile or not os.path.isfile(self._classFile): # Nothing was saved return - pth = os.path.split(self._classFile)[0] + + pth = os.path.split(os.path.abspath(self._classFile))[0] # Set the app's HomeDirectory to the location of the cdxml file. self.Application.HomeDirectory = pth if pth not in sys.path:
©2006 Ed Leafe |
|