From a5f3f67ade11c22830f226cfe6756e2cec737c04 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sat, 15 Jun 2019 16:53:43 -0300 Subject: [PATCH 1/6] Arch: Minor bugfixes, better doctrings and fixed transparency in OBJ exporter --- src/Mod/Arch/ArchIFC.py | 3 +++ src/Mod/Arch/importDAE.py | 5 ++++- src/Mod/Arch/importIFC.py | 4 +++- src/Mod/Arch/importOBJ.py | 2 +- 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/Mod/Arch/ArchIFC.py b/src/Mod/Arch/ArchIFC.py index a64a4f65d2..45baa0728c 100644 --- a/src/Mod/Arch/ArchIFC.py +++ b/src/Mod/Arch/ArchIFC.py @@ -45,6 +45,7 @@ def getIfcProduct(IfcType): name = "IfcBuildingElementProxy" if name in ArchIFCSchema.IfcProducts: return ArchIFCSchema.IfcProducts[name] + return None def getIfcProductAttribute(ifcProduct, name): @@ -81,6 +82,8 @@ def addIfcProductAttribute(obj, attribute): "Adds a given attribute property" + if not hasattr(obj,"IfcData"): + return IfcData = obj.IfcData if "attributes" not in IfcData: IfcData["attributes"] = "{}" diff --git a/src/Mod/Arch/importDAE.py b/src/Mod/Arch/importDAE.py index 3574c08696..b5082cce5e 100644 --- a/src/Mod/Arch/importDAE.py +++ b/src/Mod/Arch/importDAE.py @@ -189,7 +189,10 @@ def read(filename): def export(exportList,filename,tessellation=1,colors=None): - "called when freecad exports a file" + """export(exportList,filename,tessellation=1,colors=None) -- exports FreeCAD contents to a DAE file. + colors is an optional dictionary of objName:shapeColorTuple or objName:diffuseColorList elements + to be used in non-GUI mode if you want to be able to export colors. Tessellation is used when breaking + curved surfaces into triangles.""" if not checkCollada(): return p = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Arch") diff --git a/src/Mod/Arch/importIFC.py b/src/Mod/Arch/importIFC.py index 8017494b31..1d85dd052f 100644 --- a/src/Mod/Arch/importIFC.py +++ b/src/Mod/Arch/importIFC.py @@ -1466,7 +1466,9 @@ class recycler: def export(exportList,filename,colors=None): - "exports FreeCAD contents to an IFC file" + """export(exportList,filename,colors=None) -- exports FreeCAD contents to an IFC file. + colors is an optional dictionary of objName:shapeColorTuple or objName:diffuseColorList elements + to be used in non-GUI mode if you want to be able to export colors.""" getPreferences() diff --git a/src/Mod/Arch/importOBJ.py b/src/Mod/Arch/importOBJ.py index 5aaef03621..dde94cc9f6 100644 --- a/src/Mod/Arch/importOBJ.py +++ b/src/Mod/Arch/importOBJ.py @@ -220,7 +220,7 @@ def export(exportList,filename,colors=None): outfile = pythonopen(filenamemtl,"w") outfile.write("# FreeCAD v" + ver[0] + "." + ver[1] + " build" + ver[2] + " Arch module\n") outfile.write("# http://www.freecadweb.org\n") - kinds = {"AmbientColor":"Ka ","DiffuseColor":"Kd ","SpecularColor":"Ks ","EmissiveColor":"Ke ","Transparency":"d "} + kinds = {"AmbientColor":"Ka ","DiffuseColor":"Kd ","SpecularColor":"Ks ","EmissiveColor":"Ke ","Transparency":"Tr "} done = [] # store names to avoid duplicates for mat in materials: if isinstance(mat,tuple): From 8d7afb0b615f85c03a1871701f800f5738ba6553 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sat, 15 Jun 2019 17:53:36 -0300 Subject: [PATCH 2/6] AddonManager: Misc fixes from forum testers --- src/Mod/AddonManager/AddonManager.py | 6 ++---- src/Mod/AddonManager/addonmanager_utilities.py | 11 +++++++++++ src/Mod/AddonManager/addonmanager_workers.py | 12 +++++++++--- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/Mod/AddonManager/AddonManager.py b/src/Mod/AddonManager/AddonManager.py index a70bb57f29..eb0f93514e 100644 --- a/src/Mod/AddonManager/AddonManager.py +++ b/src/Mod/AddonManager/AddonManager.py @@ -400,15 +400,13 @@ class CommandAddonManager: "shows or hides the progress bar" if state == True: - self.dialog.listWorkbenches.setEnabled(False) - self.dialog.listMacros.setEnabled(False) + self.dialog.tabWidget.setEnabled(False) self.dialog.buttonInstall.setEnabled(False) self.dialog.buttonUninstall.setEnabled(False) self.dialog.progressBar.show() else: self.dialog.progressBar.hide() - self.dialog.listWorkbenches.setEnabled(True) - self.dialog.listMacros.setEnabled(True) + self.dialog.tabWidget.setEnabled(True) if not (self.firsttime and self.firstmacro): self.dialog.buttonInstall.setEnabled(True) self.dialog.buttonUninstall.setEnabled(True) diff --git a/src/Mod/AddonManager/addonmanager_utilities.py b/src/Mod/AddonManager/addonmanager_utilities.py index b382697672..df9913a130 100644 --- a/src/Mod/AddonManager/addonmanager_utilities.py +++ b/src/Mod/AddonManager/addonmanager_utilities.py @@ -97,6 +97,17 @@ def urlopen(url): return u +def getserver(url): + + """returns the server part of an url""" + + if sys.version_info.major < 3: + from urlparse import urlparse + else: + from urllib.parse import urlparse + return '{uri.scheme}://{uri.netloc}/'.format(uri=urlparse(url)) + + def update_macro_details(old_macro, new_macro): """Update a macro with information from another one diff --git a/src/Mod/AddonManager/addonmanager_workers.py b/src/Mod/AddonManager/addonmanager_workers.py index 9ab6673ad3..06dd731cb4 100644 --- a/src/Mod/AddonManager/addonmanager_workers.py +++ b/src/Mod/AddonManager/addonmanager_workers.py @@ -35,6 +35,7 @@ from addonmanager_macro import Macro from addonmanager_utilities import urlopen from addonmanager_utilities import translate from addonmanager_utilities import symlink +from addonmanager_utilities import getserver MACROS_BLACKLIST = ["BOLTS","WorkFeatures","how to install","PartsLibrary","FCGear"] OBSOLETE = ["assembly2","drawing_dimensioning","cura_engine"] # These addons will print an additional message informing the user @@ -382,12 +383,12 @@ class ShowWorker(QtCore.QThread): self.info_label.emit( message ) self.progressbar_show.emit(False) - l = self.loadImages( message ) + l = self.loadImages( message, url ) if l: self.info_label.emit( l ) self.stop = True - def loadImages(self,message): + def loadImages(self,message,url): "checks if the given page contains images and downloads them" @@ -402,6 +403,11 @@ class ShowWorker(QtCore.QThread): if not os.path.exists(store): os.makedirs(store) for path in imagepaths: + if "?" in path: + # remove everything after the ? + path = path.split("?")[0] + if not path.startswith("http"): + path = getserver(url) + path name = path.split("/")[-1] if name and path.startswith("http"): storename = os.path.join(store,name) @@ -426,7 +432,7 @@ class ShowWorker(QtCore.QThread): pix = pix.fromImage(img.scaled(300,300,QtCore.Qt.KeepAspectRatio,QtCore.Qt.FastTransformation)) pix.save(storename, "jpeg",100) - message = message.replace(path,"file://"+storename.replace("\\","/")) + message = message.replace(path,"file:///"+storename.replace("\\","/")) return message return None From d18d98fe2bc5fcd6172886b97e53088e98c4a73d Mon Sep 17 00:00:00 2001 From: furti Date: Sat, 15 Jun 2019 16:40:25 +0200 Subject: [PATCH 3/6] Add option to colorize ArchFence When "UseOriginalColors" is set to true, the fence will copy the diffuse colors of the original post and section to colorize itself. --- src/Mod/Arch/ArchFence.py | 131 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 125 insertions(+), 6 deletions(-) diff --git a/src/Mod/Arch/ArchFence.py b/src/Mod/Arch/ArchFence.py index 023bb3f741..0aa87a08a9 100644 --- a/src/Mod/Arch/ArchFence.py +++ b/src/Mod/Arch/ArchFence.py @@ -58,6 +58,15 @@ class _Fence(ArchComponent.Component): self.Type = "Fence" + def __getstate__(self): + return (self.sectionFaceNumbers) + + def __setstate__(self, state): + if state is not None and isinstance(state, tuple): + self.sectionFaceNumbers = state[0] + + return None + def execute(self, obj): import Part @@ -97,7 +106,7 @@ class _Fence(ArchComponent.Component): obj, pathwire, downRotation) postShapes = self.calculatePosts(obj, postPlacements) - sectionShapes = self.calculateSections( + sectionShapes, sectionFaceNumbers = self.calculateSections( obj, postPlacements, postLength, sectionLength) allShapes = [] @@ -106,6 +115,8 @@ class _Fence(ArchComponent.Component): compound = Part.makeCompound(allShapes) + self.sectionFaceNumbers = sectionFaceNumbers + self.applyShape(obj, compound, obj.Placement, allowinvalid=True, allownosolid=True) @@ -146,6 +157,11 @@ class _Fence(ArchComponent.Component): shapes = [] + # For the colorization algorithm we have to store the number of faces for each section + # It is possible that a section is clipped. Then the number of faces is not equals to the + # number of faces in the original section + faceNumbers = [] + for i in range(obj.NumberOfSections): startPlacement = postPlacements[i] endPlacement = postPlacements[i + 1] @@ -175,8 +191,9 @@ class _Fence(ArchComponent.Component): sectionCopy.Placement = placement shapes.append(sectionCopy) + faceNumbers.append(len(sectionCopy.Faces)) - return shapes + return (shapes, faceNumbers) def clipSection(self, shape, length, clipLength): import Part @@ -189,14 +206,12 @@ class _Fence(ArchComponent.Component): FreeCAD.Vector(boundBox.XMin, boundBox.YMin, boundBox.ZMin)) rightBox = Part.makeBox(halfLengthToCut, boundBox.YMax + 1, boundBox.ZMax + 1, FreeCAD.Vector(boundBox.XMin + halfLengthToCut + clipLength, boundBox.YMin, boundBox.ZMin)) - + newShape = shape.cut([leftBox, rightBox]) newBoundBox = newShape.BoundBox newShape.translate(FreeCAD.Vector(-newBoundBox.XMin, 0, 0)) - print(newShape.BoundBox) - return newShape.removeSplitter() def calculatePathWire(self, obj): @@ -214,6 +229,17 @@ class _ViewProviderFence(ArchComponent.ViewProviderComponent): def __init__(self, vobj): ArchComponent.ViewProviderComponent.__init__(self, vobj) + self.setProperties(vobj) + + def setProperties(self, vobj): + pl = vobj.PropertiesList + + if not "UseOriginalColors" in pl: + vobj.addProperty("App::PropertyBool", "UseOriginalColors", "Fence", QT_TRANSLATE_NOOP( + "App::Property", "When true, the fence will be colored like the original post and section.")) + + def onDocumentRestored(self, vobj): + self.setProperties(vobj) def getIcon(self): import Arch_rc @@ -234,6 +260,81 @@ class _ViewProviderFence(ArchComponent.ViewProviderComponent): return children + def updateData(self, obj, prop): + colorProps = ["Shape", "Section", "Post", "Path"] + + if prop in colorProps: + self.applyColors(obj) + else: + super().updateData(obj, prop) + + def onChanged(self, vobj, prop): + if prop == "UseOriginalColors": + self.applyColors(vobj.Object) + else: + super().onChanged(vobj, prop) + + def applyColors(self, obj): + if not hasattr(obj.ViewObject, "UseOriginalColors") or not obj.ViewObject.UseOriginalColors: + obj.ViewObject.DiffuseColor = [obj.ViewObject.ShapeColor] + else: + post = obj.Post + section = obj.Section + + numberOfPostFaces = len(post.Shape.Faces) + numberOfSectionFaces = len(section.Shape.Faces) + + if hasattr(obj.Proxy, 'sectionFaceNumbers'): + sectionFaceNumbers = obj.Proxy.sectionFaceNumbers + else: + sectionFaceNumbers = [0] + + if numberOfPostFaces == 0 or sum(sectionFaceNumbers) == 0: + return + + postColors = self.normalizeColors(post, numberOfPostFaces) + defaultSectionColors = self.normalizeColors( + section, numberOfSectionFaces) + + ownColors = [] + + # At first all posts are added to the shape + for i in range(obj.NumberOfPosts): + ownColors.extend(postColors) + + # Next all sections are added + for i in range(obj.NumberOfSections): + actualSectionFaceCount = sectionFaceNumbers[i] + + if actualSectionFaceCount == numberOfSectionFaces: + ownColors.extend(defaultSectionColors) + else: + ownColors.extend(self.normalizeColors( + section, actualSectionFaceCount)) + + viewObject = obj.ViewObject + viewObject.DiffuseColor = ownColors + + def normalizeColors(self, obj, numberOfFaces): + colors = obj.ViewObject.DiffuseColor + numberOfColors = len(colors) + + if numberOfColors == 1: + return colors * numberOfFaces + + colorsToUse = colors.copy() + + if numberOfColors == numberOfFaces: + return colorsToUse + else: + # It is possible, that we have less faces than colors when something got clipped. + # Remove the unneeded colors at the beginning and end + halfNumberOfFacesToRemove = (numberOfColors - numberOfFaces) / 2 + start = int(math.ceil(halfNumberOfFacesToRemove)) + end = start + numberOfFaces + + return colorsToUse[start:end] + class _CommandFence: "the Arch Fence command definition" @@ -330,12 +431,30 @@ if __name__ == '__main__': def buildPost(): post = Part.makeBox(100, 100, 1000, FreeCAD.Vector(0, 0, 0)) - Part.show(post, "Post") + Part.show(post, 'Post') return FreeCAD.ActiveDocument.getObject('Post') + def colorizeFaces(o, color=(0.6, 0.0, 0.0, 0.0), faceIndizes=[2]): + numberOfFaces = len(o.Shape.Faces) + vo = o.ViewObject + + originalColors = vo.DiffuseColor + + if len(originalColors) == 1: + newColors = originalColors * numberOfFaces + else: + newColors = originalColors.copy() + + for i in faceIndizes: + newColors[i] = color + + vo.DiffuseColor = newColors + section = buildSection() path = buildPath() post = buildPost() + colorizeFaces(post) + print(makeFence(section, post, path)) From ac9cd38650d112488dcdb1743e2c9fd62edf1fba Mon Sep 17 00:00:00 2001 From: furti Date: Sat, 15 Jun 2019 17:11:40 +0200 Subject: [PATCH 4/6] Add support for PartDesign:Body colors When the tip of a PartDesign:Body is colorized, the colors are stored on tip level. But when the shape of the whole body is changed the information is stored on body level. To account for this we check if the tip has more than one DiffuseColor set. When not, we use the shape color of the body. --- src/Mod/Arch/ArchFence.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/Mod/Arch/ArchFence.py b/src/Mod/Arch/ArchFence.py index 0aa87a08a9..94d70cb96e 100644 --- a/src/Mod/Arch/ArchFence.py +++ b/src/Mod/Arch/ArchFence.py @@ -317,6 +317,18 @@ class _ViewProviderFence(ArchComponent.ViewProviderComponent): def normalizeColors(self, obj, numberOfFaces): colors = obj.ViewObject.DiffuseColor + + if obj.TypeId == 'PartDesign::Body': + # When colorizing a PartDesign Body we have two options + # 1. The whole body got a shape color, that means the tip has only a single diffuse color set + # so we use the shape color of the body + # 2. "Set colors" was called on the tip and the individual faces where colorized. + # We use the diffuseColors of the tip in that case + tipColors = obj.Tip.ViewObject.DiffuseColor + + if len(tipColors) > 1: + colors = tipColors + numberOfColors = len(colors) if numberOfColors == 1: From 4e5d6be3267849d543e1a8654b39d817a007952c Mon Sep 17 00:00:00 2001 From: wmayer Date: Sat, 15 Jun 2019 23:54:10 +0200 Subject: [PATCH 5/6] fixes #0003979: Pocket with mode 'up to face' doesn't work correctly --- src/Mod/PartDesign/App/FeaturePad.cpp | 9 ++++++ src/Mod/PartDesign/App/FeaturePocket.cpp | 5 ++++ src/Mod/PartDesign/App/FeatureSketchBased.cpp | 30 +++++++++++++++++++ src/Mod/PartDesign/App/FeatureSketchBased.h | 13 ++++++++ 4 files changed, 57 insertions(+) diff --git a/src/Mod/PartDesign/App/FeaturePad.cpp b/src/Mod/PartDesign/App/FeaturePad.cpp index b26599cd25..32fcea5291 100644 --- a/src/Mod/PartDesign/App/FeaturePad.cpp +++ b/src/Mod/PartDesign/App/FeaturePad.cpp @@ -218,6 +218,8 @@ App::DocumentObjectExecReturn *Pad::execute(void) TopExp_Explorer Ex(supportface,TopAbs_WIRE); if (!Ex.More()) supportface = TopoDS_Face(); + +#if 0 BRepFeat_MakePrism PrismMaker; PrismMaker.Init(base, sketchshape, supportface, dir, 2, 1); PrismMaker.Perform(upToFace); @@ -225,6 +227,9 @@ App::DocumentObjectExecReturn *Pad::execute(void) if (!PrismMaker.IsDone()) return new App::DocumentObjectExecReturn("Pad: Up to face: Could not extrude the sketch!"); prism = PrismMaker.Shape(); +#else + generatePrism(prism, method, base, sketchshape, supportface, upToFace, dir, 2, 1); +#endif base.Nullify(); } else { // A support object is always required and we need to use BRepFeat_MakePrism @@ -239,6 +244,7 @@ App::DocumentObjectExecReturn *Pad::execute(void) TopExp_Explorer Ex(supportface,TopAbs_WIRE); if (!Ex.More()) supportface = TopoDS_Face(); +#if 0 BRepFeat_MakePrism PrismMaker; PrismMaker.Init(base, sketchshape, supportface, dir, 2, 1); PrismMaker.Perform(upToFace); @@ -246,6 +252,9 @@ App::DocumentObjectExecReturn *Pad::execute(void) if (!PrismMaker.IsDone()) return new App::DocumentObjectExecReturn("Pad: Up to face: Could not extrude the sketch!"); prism = PrismMaker.Shape(); +#else + generatePrism(prism, method, base, sketchshape, supportface, upToFace, dir, 2, 1); +#endif } } else { generatePrism(prism, sketchshape, method, dir, L, L2, diff --git a/src/Mod/PartDesign/App/FeaturePocket.cpp b/src/Mod/PartDesign/App/FeaturePocket.cpp index 0124db278f..57933f63a1 100644 --- a/src/Mod/PartDesign/App/FeaturePocket.cpp +++ b/src/Mod/PartDesign/App/FeaturePocket.cpp @@ -174,6 +174,7 @@ App::DocumentObjectExecReturn *Pocket::execute(void) TopExp_Explorer Ex(supportface,TopAbs_WIRE); if (!Ex.More()) supportface = TopoDS_Face(); +#if 0 BRepFeat_MakePrism PrismMaker; PrismMaker.Init(base, profileshape, supportface, dir, 0, 1); PrismMaker.Perform(upToFace); @@ -181,6 +182,10 @@ App::DocumentObjectExecReturn *Pocket::execute(void) if (!PrismMaker.IsDone()) return new App::DocumentObjectExecReturn("Pocket: Up to face: Could not extrude the sketch!"); TopoDS_Shape prism = PrismMaker.Shape(); +#else + TopoDS_Shape prism; + generatePrism(prism, method, base, profileshape, supportface, upToFace, dir, 0, 1); +#endif // And the really expensive way to get the SubShape... BRepAlgoAPI_Cut mkCut(base, prism); diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.cpp b/src/Mod/PartDesign/App/FeatureSketchBased.cpp index baaa7363af..5b7900e085 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.cpp +++ b/src/Mod/PartDesign/App/FeatureSketchBased.cpp @@ -34,6 +34,7 @@ # include # include # include +# include # include # include # include @@ -544,6 +545,35 @@ void ProfileBased::generatePrism(TopoDS_Shape& prism, } +void ProfileBased::generatePrism(TopoDS_Shape& prism, + const std::string& method, + const TopoDS_Shape& baseshape, + const TopoDS_Shape& profileshape, + const TopoDS_Face& sketchface, + const TopoDS_Face& uptoface, + const gp_Dir& direction, + Standard_Integer Mode, + Standard_Boolean Modify) +{ + if (method == "UpToFirst" || method == "UpToFace") { + BRepFeat_MakePrism PrismMaker; + TopoDS_Shape base = baseshape; + TopoDS_Face supportface = sketchface; + for (TopExp_Explorer xp(profileshape, TopAbs_FACE); xp.More(); xp.Next()) { + PrismMaker.Init(base, xp.Current(), supportface, direction, Mode, Modify); + PrismMaker.Perform(uptoface); + if (!PrismMaker.IsDone()) + throw Base::RuntimeError("ProfileBased: Up to face: Could not extrude the sketch!"); + + base = PrismMaker.Shape(); + if (Mode == 2) + Mode = 1; + } + + prism = base; + } +} + bool ProfileBased::checkWireInsideFace(const TopoDS_Wire& wire, const TopoDS_Face& face, const gp_Dir& dir) { // Project wire onto the face (face, not surface! So limits of face apply) diff --git a/src/Mod/PartDesign/App/FeatureSketchBased.h b/src/Mod/PartDesign/App/FeatureSketchBased.h index 6309df0976..f5c13789aa 100644 --- a/src/Mod/PartDesign/App/FeatureSketchBased.h +++ b/src/Mod/PartDesign/App/FeatureSketchBased.h @@ -134,6 +134,19 @@ protected: const double L2, const bool midplane, const bool reversed); + /** + * Generate a linear prism + * It will be a stand-alone solid created with BRepFeat_MakePrism + */ + static void generatePrism(TopoDS_Shape& prism, + const std::string& method, + const TopoDS_Shape& baseshape, + const TopoDS_Shape& profileshape, + const TopoDS_Face& sketchface, + const TopoDS_Face& uptoface, + const gp_Dir& direction, + Standard_Integer Mode, + Standard_Boolean Modify); /// Check whether the wire after projection on the face is inside the face static bool checkWireInsideFace(const TopoDS_Wire& wire, From 16949b38cb34f13e7845ae319b575d95575c5a22 Mon Sep 17 00:00:00 2001 From: Yorik van Havre Date: Sat, 15 Jun 2019 23:50:41 -0300 Subject: [PATCH 6/6] AddonManager: Use workbenches icons --- src/Mod/AddonManager/AddonManager.py | 20 ++++++++---- src/Mod/AddonManager/CMakeLists.txt | 16 +++++++++- .../AddonManager/Resources/AddonManager.qrc | 31 +++++++++++++++++++ src/Mod/AddonManager/addonmanager_workers.py | 2 +- 4 files changed, 61 insertions(+), 8 deletions(-) create mode 100644 src/Mod/AddonManager/Resources/AddonManager.qrc diff --git a/src/Mod/AddonManager/AddonManager.py b/src/Mod/AddonManager/AddonManager.py index eb0f93514e..1d8517992c 100644 --- a/src/Mod/AddonManager/AddonManager.py +++ b/src/Mod/AddonManager/AddonManager.py @@ -258,10 +258,16 @@ class CommandAddonManager: from PySide import QtGui self.repos.append(addon_repo) - if addon_repo[2] == 1 : - self.dialog.listWorkbenches.addItem(QtGui.QListWidgetItem(QtGui.QIcon(":/icons/button_valid.svg"),str(addon_repo[0]) + str(" ("+translate("AddonsInstaller","Installed")+")"))) + import AddonManager_rc + addonicon = QtGui.QIcon(":/icons/" + addon_repo[0] + "_workbench_icon.svg") + if addonicon.isNull(): + addonicon = QtGui.QIcon(":/icons/Group.svg") + if addon_repo[2] == 1: + item = QtGui.QListWidgetItem(addonicon,str(addon_repo[0]) + str(" ("+translate("AddonsInstaller","Installed")+")")) + item.setBackground(QtGui.QBrush(QtGui.QColor(0,182,41))) + self.dialog.listWorkbenches.addItem(item) else: - self.dialog.listWorkbenches.addItem(QtGui.QListWidgetItem(QtGui.QIcon(":/icons/Group.svg"),str(addon_repo[0]))) + self.dialog.listWorkbenches.addItem(QtGui.QListWidgetItem(addonicon,str(addon_repo[0]))) def show_information(self, label): @@ -358,7 +364,9 @@ class CommandAddonManager: from PySide import QtGui self.macros.append(macro) if macro.is_installed(): - self.dialog.listMacros.addItem(QtGui.QListWidgetItem(QtGui.QIcon(":/icons/button_valid.svg"), macro.name + str(' (Installed)'))) + item = QtGui.QListWidgetItem(QtGui.QIcon(":/icons/applications-python.svg"), macro.name + str(' (Installed)')) + item.setBackground(QtGui.QBrush(QtGui.QColor(0,182,41))) + self.dialog.listMacros.addItem(item) else: self.dialog.listMacros.addItem(QtGui.QListWidgetItem(QtGui.QIcon(":/icons/applications-python.svg"),macro.name)) @@ -533,7 +541,7 @@ class CommandAddonManager: wb[2] = 0 for macro in self.macros: if macro.is_installed(): - self.dialog.listMacros.addItem(QtGui.QListWidgetItem(QtGui.QIcon(":/icons/button_valid.svg"), macro.name + " ("+translate("AddonsInstaller","Installed")+")")) + self.dialog.listMacros.addItem(item) else: self.dialog.listMacros.addItem(QtGui.QListWidgetItem(QtGui.QIcon(":/icons/applications-python.svg"),+macro.name)) @@ -546,7 +554,7 @@ class CommandAddonManager: w = self.dialog.listWorkbenches.item(i) if w.text().startswith(str(repo)): w.setText(str(repo) + str(" ("+translate("AddonsInstaller","Update available")+")")) - w.setIcon(QtGui.QIcon(":/icons/debug-marker.svg")) + w.setBackground(QtGui.QBrush(QtGui.QColor(182,90,0))) if not repo in self.doUpdate: self.doUpdate.append(repo) diff --git a/src/Mod/AddonManager/CMakeLists.txt b/src/Mod/AddonManager/CMakeLists.txt index b155ae4087..23549f18c6 100644 --- a/src/Mod/AddonManager/CMakeLists.txt +++ b/src/Mod/AddonManager/CMakeLists.txt @@ -1,3 +1,7 @@ +IF (BUILD_GUI) + PYSIDE_WRAP_RC(AddonManager_QRC_SRCS Resources/AddonManager.qrc) +ENDIF (BUILD_GUI) + SET(AddonManager_SRCS Init.py InitGui.py @@ -12,14 +16,24 @@ SET(AddonManager_SRCS SOURCE_GROUP("" FILES ${AddonManager_SRCS}) ADD_CUSTOM_TARGET(AddonManager ALL - SOURCES ${AddonManager_SRCS} + SOURCES ${AddonManager_SRCS} ${AddonManager_QRC_SRCS} ) fc_copy_sources(AddonManager "${CMAKE_BINARY_DIR}/Mod/AddonManager" ${AddonManager_SRCS}) +IF (BUILD_GUI) + fc_target_copy_resource(AddonManager + ${CMAKE_CURRENT_BINARY_DIR} + ${CMAKE_BINARY_DIR}/Mod/AddonManager + AddonManager_rc.py) +ENDIF (BUILD_GUI) + INSTALL( FILES ${AddonManager_SRCS} + ${AddonManager_QRC_SRCS} DESTINATION Mod/AddonManager ) + + diff --git a/src/Mod/AddonManager/Resources/AddonManager.qrc b/src/Mod/AddonManager/Resources/AddonManager.qrc new file mode 100644 index 0000000000..d8f0fde874 --- /dev/null +++ b/src/Mod/AddonManager/Resources/AddonManager.qrc @@ -0,0 +1,31 @@ + + + icons/A2plus_workbench-icon.svg + icons/Airplane_workbench-icon.svg + icons/Arch_Textures_workbench_icon.svg + icons/BIM_workbench_icon.svg + icons/BOLTS_workbench_icon.svg + icons/cfd_workbench_icon.svg + icons/Curves_workbench_icon.svg + icons/Defeaturing_workbench_icon.svg + icons/Dodo_workbench_icon.svg + icons/EM_workbench_icon.svg + icons/ExplodedAssembly_workbench_icon.svg + icons/Fasteners_workbench_icon.svg + icons/Flamingo_workbench_icon.svg + icons/GDT_workbench_icon.svg + icons/Gears_workbench_icon.svg + icons/Glider_workbench_icon.svg + icons/Kicad-StepUp-tools-workbench_icon.svg + icons/Lattice2_workbench_icon.svg + icons/Lithophane_workbench_icon.svg + icons/Manipulator_workbench_icon.svg + icons/PartOMagic_workbench_icon.svg + icons/Plot_workbench_icon.svg + icons/Pyrate_workbench_icon.svg + icons/Reporting_workbench_icon.svg + icons/SheetMetal_workbench_icon.svg + icons/Ship_workbench_icon.svg + icons/Timber_workbench_icon.svg + + diff --git a/src/Mod/AddonManager/addonmanager_workers.py b/src/Mod/AddonManager/addonmanager_workers.py index 06dd731cb4..c5d99fc732 100644 --- a/src/Mod/AddonManager/addonmanager_workers.py +++ b/src/Mod/AddonManager/addonmanager_workers.py @@ -553,7 +553,7 @@ class InstallWorker(QtCore.QThread): try: answer = repo.pull() except: - print("Error updating module",repos[idx][1]," - Please fix manually") + print("Error updating module",self.repos[idx][1]," - Please fix manually") answer = repo.status() print(answer) else: