From a1edbb092c42c29663712088b08eb19899c1321b Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sun, 28 Jul 2019 13:59:03 -0300 Subject: [PATCH] Tools: added --gui option to fcinfo tool --- src/Tools/fcinfo | 78 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 12 deletions(-) diff --git a/src/Tools/fcinfo b/src/Tools/fcinfo index 9079d345d0..dba861e787 100755 --- a/src/Tools/fcinfo +++ b/src/Tools/fcinfo @@ -30,7 +30,11 @@ __url__ = ["http://www.freecadweb.org"] __doc__ = ''' This utility prints information about a given FreeCAD file (*.FCStd) on screen, including document properties, number of included objects, -object sizes and properties and values +object sizes and properties and values. Its main use is to compare +two files and be able to see the differences in a text-based form. + +If no option is used, fcinfo prints the document properties and a list +of properties of each object found in the given file. Usage: @@ -39,30 +43,42 @@ Usage: Options: -h, --help: Prints this help text - -s, --short: Do not print all the properties contents of objects - -vs --veryshort: Only prints the document info, not objects info + -s, --short: Do not print object properties. Only one line + per object is printed, including its size and SHA1. + This is sufficient to see that an object has + changed, but not what exactly has changed. + -vs --veryshort: Only prints the document info, not objects info. + This is sufficient to see if a file has changed, as + its SHA1 code and timestamp will show it. But won't + show details of what has changed. + -g --gui: Adds visual properties too (if not using -s or -vs) Git usage: This script can be used as a textconv tool for git diff by configuring your git folder as follows: - 1) add to .gitattributes: + 1) add to .gitattributes (or ~/.gitattributes for user-wide): + *.fcstd diff=fcinfo 2) add to .git/config (or ~/.gitconfig for user-wide): + [diff "fcinfo"] textconv = /path/to/fcinfo With this, when committing a .FCStd file with Git, 'git diff' will show you the difference between the two texts obtained by fcinfo - ''' -import sys, zipfile, xml.sax, os, hashlib - +import sys +import zipfile +import xml.sax +import os +import hashlib +import re @@ -70,7 +86,7 @@ class FreeCADFileHandler(xml.sax.ContentHandler): - def __init__(self, zfile, short = 0): # short 0=normal, 1=short, 2=veryshort + def __init__(self, zfile, short = 0): # short: 0=normal, 1=short, 2=veryshort xml.sax.ContentHandler.__init__(self) self.zfile = zfile @@ -95,21 +111,30 @@ class FreeCADFileHandler(xml.sax.ContentHandler): if ("type" in attributes): self.contents[name] = attributes["type"] + elif tag == "ViewProvider": + if ("name" in attributes): + self.obj = self.clean(attributes["name"]) + elif tag == "Part": if self.obj: - s = self.zfile.read(attributes["file"]).__sizeof__() + r = self.zfile.read(attributes["file"]) + s = r.__sizeof__() if s < 1024: s = str(s)+"B" elif s > 1048576: s = str(s/1048576)+"M" else: s = str(s/1024)+"K" - + s += " " + str(hashlib.sha1(r).hexdigest()[:12]) self.contents[self.obj] += " (" + s + ")" elif tag == "Property": self.prop = None - if attributes["name"] not in ["Symbol"]: + # skip "internal" properties, unuseful for a diff + if attributes["name"] not in ["Symbol","AttacherType","MapMode","MapPathParameter","MapReversed", + "AttachmentOffset","SelectionStyle","TightGrid","GridSize","GridSnap", + "GridStyle","Lighting","Deviation","AngularDeflection","BoundingBox", + "Selectable","ShowGrid"]: self.prop = attributes["name"] elif tag in ["String","Uuid","Float","Integer","Bool","Link"]: @@ -122,10 +147,31 @@ class FreeCADFileHandler(xml.sax.ContentHandler): else: self.contents[self.obj+"00000000::"+self.prop] = attributes["value"] + elif tag in ["PropertyVector"]: + if self.prop and self.obj and (self.short == 0): + val = "("+str(float(attributes["valueX"]))+","+str(float(attributes["valueY"]))+","+str(float(attributes["valueZ"]))+")" + self.contents[self.obj+"00000000::"+self.prop] = val + + elif tag in ["PropertyPlacement"]: + if self.prop and self.obj and (self.short == 0): + val = "("+str(float(attributes["Px"]))+","+str(float(attributes["Py"]))+","+str(float(attributes["Pz"]))+")" + val += " ("+str(round(float(attributes["Q0"]),4))+","+str(round(float(attributes["Q1"]),4))+"," + val += str(round(float(attributes["Q2"]),4))+","+str(round(float(attributes["Q3"]),4))+")" + self.contents[self.obj+"00000000::"+self.prop] = val + + elif tag in ["PropertyColor"]: + if self.prop and self.obj and (self.short == 0): + c = int(attributes["value"]) + r = float((c>>24)&0xFF)/255.0 + g = float((c>>16)&0xFF)/255.0 + b = float((c>>8)&0xFF)/255.0 + val = str((r,g,b)) + self.contents[self.obj+"00000000::"+self.prop] = val + elif tag == "Objects": self.count = attributes["Count"] self.obj = None - + # Print all the contents of the document properties items = self.contents.items() items.sort() @@ -188,6 +234,14 @@ if __name__ == '__main__': if not "Document.xml" in zfile.namelist(): sys.exit(1) doc = zfile.read("Document.xml") + if gui and "GuiDocument.xml" in zfile.namelist(): + guidoc = zfile.read("GuiDocument.xml") + guidoc = re.sub(r"<\?xml.*?-->"," ",guidoc,flags=re.MULTILINE|re.DOTALL) + # a valid xml doc can have only one root element. So we need to insert + # all the contents of the GUiDocument tag into the main one + doc = re.sub(r"<\/Document>","",doc,flags=re.MULTILINE|re.DOTALL) + guidoc = re.sub(r""," ",guidoc,flags=re.MULTILINE|re.DOTALL) + doc += guidoc s = os.path.getsize(sys.argv[-1]) if s < 1024: s = str(s)+"B"