summaryrefslogtreecommitdiff
path: root/BCT/PhoneControlsExtractor/PhoneControlsExtractor.py
diff options
context:
space:
mode:
authorGravatar Mike Barnett <mbarnett@microsoft.com>2011-07-06 15:40:48 -0700
committerGravatar Mike Barnett <mbarnett@microsoft.com>2011-07-06 15:40:48 -0700
commit728dce3c4c11205ee0eabbc5df166eab261d501f (patch)
treef8c06033e715ae7265a30e50ffae7c990b317d2a /BCT/PhoneControlsExtractor/PhoneControlsExtractor.py
parentfeafae60495fd982a94d70323452232b7e3dfce4 (diff)
parenta4f4e0ba9b1a333e8fefdfe292e18abc305edcd2 (diff)
Merge
Diffstat (limited to 'BCT/PhoneControlsExtractor/PhoneControlsExtractor.py')
-rw-r--r--BCT/PhoneControlsExtractor/PhoneControlsExtractor.py152
1 files changed, 152 insertions, 0 deletions
diff --git a/BCT/PhoneControlsExtractor/PhoneControlsExtractor.py b/BCT/PhoneControlsExtractor/PhoneControlsExtractor.py
new file mode 100644
index 00000000..4686e574
--- /dev/null
+++ b/BCT/PhoneControlsExtractor/PhoneControlsExtractor.py
@@ -0,0 +1,152 @@
+import sys
+import getopt
+import os
+from xml.dom import minidom
+import xml.dom
+
+CONTROL_NAMES= ["Button", "CheckBox", "RadioButton"]
+
+# TODO maybe a control is enabled but its parent is not, must take this into account
+# TODO a possible solution is to tie the enabled value to that of the parent in the app until it is either overriden
+# TODO (by directly manipulating the control's enabled value) or the parent becomes enabled
+
+CONTAINER_CONTROL_NAMES= ["Canvas", "Grid", "StackPanel"]
+
+staticControlsMap= {}
+
+def showUsage():
+ print "PhoneControlsExtractor -- extract control information from phone application pages"
+ print "Usage:"
+ print "\tPhoneControlsExtractor --pages <application_directory> --output <info_output_file>\n"
+ print "Options:"
+ print "\t--pages <application_directory>: point to location of .xaml files detailing pages. Short form: -p"
+ print "\t--output <info_output_file>: file to write with control info. Short form: -o\n"
+
+def isPageFile(file):
+ # not the best way, find out the actual exceptions
+ try:
+ minidom.parse(file)
+ file.seek(0)
+ return True
+ except Exception:
+ return False
+
+def removeBlankElements(xmlNode):
+ blankNodes= []
+ for child in xmlNode.childNodes:
+ if child.nodeType == xml.dom.Node.TEXT_NODE and child.data.strip() == "":
+ blankNodes.append(child)
+ elif child.hasChildNodes():
+ removeBlankElements(child)
+
+ for node in blankNodes:
+ node.parentNode.removeChild(node)
+ node.unlink()
+
+def getControlNodes(xmlNode):
+ controlNodes= []
+ if (xmlNode.nodeType == xml.dom.Node.ELEMENT_NODE and xmlNode.localName in CONTROL_NAMES):
+ controlNodes.insert(0,xmlNode)
+
+ for child in xmlNode.childNodes:
+ controlNodes= controlNodes + getControlNodes(child)
+
+ return controlNodes
+
+def addControlToMap(parentPage, controlNode):
+ pageControls=[]
+ newControl={}
+ try:
+ pageControls= staticControlsMap[parentPage]
+ except KeyError:
+ pass
+
+ newControl["Type"]= controlNode.localName
+ newControl["Name"]= controlNode.getAttribute("Name")
+ if (controlNode.hasAttribute("IsEnabled")):
+ newControl["IsEnabled"]= controlNode.getAttribute("IsEnabled")
+ else:
+ newControl["IsEnabled"]= "true"
+
+ if (controlNode.hasAttribute("Visibility")):
+ newControl["Visibility"]= controlNode.getAttribute("Visibility")
+ else:
+ newControl["Visibility"]= "Visible"
+
+ # TODO it is possible that more events are of interest, we should add as we discover them in existing applications
+ newControl["Click"] = controlNode.getAttribute("Click")
+ newControl["Checked"] = controlNode.getAttribute("Checked")
+ newControl["Unchecked"] = controlNode.getAttribute("Unchecked")
+ pageControls.append(newControl)
+ staticControlsMap[parentPage]= pageControls
+
+def extractPhoneControlsFromPage(pageFile):
+ # maybe it is not a page file
+ if not isPageFile(pageFile):
+ return
+
+ pageFileXML= minidom.parse(pageFile)
+ removeBlankElements(pageFileXML)
+ controls= getControlNodes(pageFileXML)
+ for control in controls:
+ ownerPage=""
+ parent= control
+ while not parent == None:
+ a=""
+ if parent.localName == "PhoneApplicationPage":
+ ownerPage= parent.getAttribute("x:Class")
+ parent= parent.parentNode
+ addControlToMap(ownerPage, control)
+
+def outputPhoneControls(outputFileName):
+ outputFile= open(outputFileName, "w")
+
+ # Output format is one line per
+ # <pageClassName>,<controlClassName>,<controlName (as in field name)>,<IsEnabledValue>,<VisibilityValue>,<ClickValue>,<CheckedValue>,<UncheckedValue>#
+ for page in staticControlsMap.keys():
+ for control in staticControlsMap[page]:
+ isEnabled= control["IsEnabled"]
+ visibility= control["Visibility"]
+ click= control["Click"]
+ checked= control["Checked"]
+ unchecked= control["Unchecked"]
+ outputFile.write(page + "," + control["Type"] + "," + control["Name"] + "," + isEnabled + "," + visibility + "," + click + "," + checked + "," + unchecked + "#\n")
+
+ outputFile.close()
+
+def extractPhoneControls(sourceDir):
+ fileList= [os.path.normcase(fileName) for fileName in os.listdir(sourceDir)]
+ fileList= [os.path.join(sourceDir, fileName) for fileName in fileList if os.path.splitext(fileName)[1] == ".xaml"]
+ for fileName in fileList:
+ pageFile= open(fileName, "r")
+ extractPhoneControlsFromPage(pageFile)
+ pageFile.close()
+
+ # TODO dump controls into a config file that can be passed to BCT
+
+def main():
+ pagesDir= ""
+ outputFile= ""
+ try:
+ opts, args= getopt.getopt(sys.argv[1:], "p:o:", ["pages=","output="])
+ except geopt.error, msg:
+ print msg
+ showUsage()
+ sys.exit(2)
+
+ if not len(opts) == 2:
+ print "Missing options"
+ showUsage()
+ sys.exit(2)
+
+ for o, a in opts:
+ if o in ["-p","--pages"]:
+ pagesDir= a
+ if o in ["-o", "--output"]:
+ outputFile= a
+
+ extractPhoneControls(pagesDir)
+ outputPhoneControls(outputFile)
+
+if __name__ == "__main__":
+ main() \ No newline at end of file