Function when a workbench opens a new file.

Here's the place for discussion related to coding in FreeCAD, C++ or Python. Design, interfaces and structures.
Forum rules
Be nice to others! Respect the FreeCAD code of conduct!
keithsloan52
Veteran
Posts: 2756
Joined: Mon Feb 27, 2012 5:31 pm

Re: Function when a workbench opens a new file.

Post by keithsloan52 »

I believe @ickby is the developer for the DocObserver perhaps he/she could comment.
ickby
Veteran
Posts: 3116
Joined: Wed Oct 05, 2011 7:36 am

Re: Function when a workbench opens a new file.

Post by ickby »

I only extended the system sligthly. Have a look at the test cases, there you get a good impression how to use the observers. They are registered in the tests setup method and unregistered in the tests teardown method

With your code I don't get the same error, and the objects are created after opening the file. The only thing I spot is that you define "doc" as a local variable to the function, hence you can't use it in deactivate. You should store the document observer and use the stored object for removing it again.
keithsloan52
Veteran
Posts: 2756
Joined: Mon Feb 27, 2012 5:31 pm

Re: Function when a workbench opens a new file.

Post by keithsloan52 »

Still cannot spot where the problems is here are my version details
OS: Ubuntu 18.04.2 LTS
Word size of OS: 64-bit
Word size of FreeCAD: 64-bit
Version: 0.18.1.
Build type: Release
Python version: 3.6.7
Qt version: 5.9.5
Coin version: 4.0.0a
OCC version: 7.3.0
Locale: English/UnitedKingdom (en_GB)
keithsloan52
Veteran
Posts: 2756
Joined: Mon Feb 27, 2012 5:31 pm

Re: Function when a workbench opens a new file.

Post by keithsloan52 »

ickby wrote: Mon Jun 03, 2019 11:27 am I only extended the system sligthly. Have a look at the test cases, there you get a good impression how to use the observers. They are registered in the tests setup method and unregistered in the tests teardown method

With your code I don't get the same error, and the objects are created after opening the file. The only thing I spot is that you define "doc" as a local variable to the function, hence you can't use it in deactivate. You should store the document observer and use the stored object for removing it again.
Need now to sort this but still no joy, When you tried my code did you put it in InitGui.py? @ickby
keithsloan52
Veteran
Posts: 2756
Joined: Mon Feb 27, 2012 5:31 pm

Re: Function when a workbench opens a new file.

Post by keithsloan52 »

Getting more convinced this is a problem because I am trying to define the workbench in InitGui.py and also the Observer class.
So where else do people put them?
keithsloan52
Veteran
Posts: 2756
Joined: Mon Feb 27, 2012 5:31 pm

Re: Function when a workbench opens a new file.

Post by keithsloan52 »

keithsloan52 wrote: Fri May 31, 2019 9:47 am Okay I am missing something as I get the follow error message

Code: Select all

name 'DocObserver' is not defined
Traceback (most recent call last):
  File "<string>", line 65, in Activated
My code in InitGUI.py looks like

Code: Select all

import FreeCAD

class DocObserver(object):
    def slotCreatedDocument(self, doc):
        mySphere = doc.addObject("Part::Sphere", "Globe")
        mySphere.Radius = 100

class Astro_Workbench ( Workbench ):
    "Astro workbench object"
    def __init__(self):
        self.__class__.Icon = FreeCAD.getResourceDir() + "Mod/Astro/Resources/icons/AstroWorkbench.svg"
        self.__class__.MenuText = "Astro"
        self.__class__.ToolTip = "Astro workbench"

    def Initialize(self):
        def QT_TRANSLATE_NOOP(scope, text):
            return text

        import AstroCommands
        commands=['AddRegionCommand' ]
        toolbarcommands=['AddRegionCommand']

        self.appendToolbar(QT_TRANSLATE_NOOP('Workbench','AstroTools'),toolbarcommands)
        self.appendMenu('Astro',commands)
        #FreeCADGui.addIconPath(":/icons")
        FreeCADGui.addIconPath(FreeCAD.getResourceDir() + \
                              "Mod/Astro/Resources/icons")
        FreeCADGui.addLanguagePath(":/translations")
        #FreeCADGui.addPreferencePage(":/ui/openscadprefs-base.ui","OpenSCAD")

    def Activated(self):
        "This function is executed when the workbench is activated"
        doc=DocObserver()
        App.addDocumentObserver(doc)
        return

    def Deactivated(self):
        "This function is executed when the workbench is deactivated"
        App.removeDocumentObserver(doc)
        return
        
           def GetClassName(self):
        "This is executed whenever the user right-clicks on screen"
        return "Gui::PythonWorkbench"
        "This function is executed when the workbench is deactivated"
        return

    def ContextMenu(self, recipient):
        "This is executed whenever the user right-clicks on screen"
        # "recipient" will be either "view" or "tree"
        #self.appendContextMenu("My commands",self.list) # add commands to the context menu

Gui.addWorkbench(Astro_Workbench())
Will have to give the FreeCAD python console a try I am still on the old fashioned way of doing things
Should the class definitions be nested somehow?
keithsloan52
Veteran
Posts: 2756
Joined: Mon Feb 27, 2012 5:31 pm

Re: Function when a workbench opens a new file.

Post by keithsloan52 »

Don't suppose I could get somebody for example @ickby or @wmayer to check my code as I am at a total loss of what the problem is

github respository https://github.com/KeithSloan/FreeCAD_Python_GDML

branch with problem default.

With GDML workbench installed if I switch the the GDML workbench I get the error

Code: Select all

Activated
Gui::PythonWorkbench
name 'MyObserver' is not defined
Traceback (most recent call last):
  File "<string>", line 84, in Activated
ickby
Veteran
Posts: 3116
Joined: Wed Oct 05, 2011 7:36 am

Re: Function when a workbench opens a new file.

Post by ickby »

the problem seems to be that the classes created in the InitGui.py are not usable... I really don't know why, I have no clue where their definition goes too and how theys are accessbile... maybe werner knows more? But as a workaround you could make the observer a inner class of the workbench, this works:

Code: Select all

# GDML wrkbench gui init module
#
# Gathering all the information to start FreeCAD
# This is the second one of three init scripts, the third one
# runs when the gui is up

#***************************************************************************
#*   (c) Juergen Riegel (juergen.riegel@web.de) 2002                       *
#*                                                                         *
#*   This file is part of the FreeCAD CAx development system.              *
#*                                                                         *
#*   This program is free software; you can redistribute it and/or modify  *
#*   it under the terms of the GNU Lesser General Public License (LGPL)    *
#*   as published by the Free Software Foundation; either version 2 of     *
#*   the License, or (at your option) any later version.                   *
#*   for detail see the LICENCE text file.                                 *
#*                                                                         *
#*   FreeCAD is distributed in the hope that it will be useful,            *
#*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
#*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
#*   GNU Lesser General Public License for more details.                   *
#*                                                                         *
#*   You should have received a copy of the GNU Library General Public     *
#*   License along with FreeCAD; if not, write to the Free Software        *
#*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
#*   USA                                                                   *
#*                                                                         *
#*   Juergen Riegel 2002                                                   *
#*                                                                         *
#* Also copyright Keith Sloan                                              * 
#***************************************************************************/

#import FreeCAD
from FreeCAD import *
from importGDML import processGDML
import PartGui
import GDMLCommands, GDMLResources

class GDML_Workbench ( Workbench ):

    class MyObserver():
        def __init__(self):
            self.signal = []
        def slotCreatedDocument(self, doc):
            processGDML(FreeCAD.getResourceDir() + "Mod/Resources/Default.GDML")
		
    "GDML workbench object"
    def __init__(self):
        self.__class__.Icon = FreeCAD.getResourceDir() + "Mod/GDML/Resources/icons/GDMLWorkbench.svg"
        self.__class__.MenuText = "GDML"
        self.__class__.ToolTip = "GDML workbench"
        #self.obs = MyObserver()

    def Initialize(self):
        def QT_TRANSLATE_NOOP(scope, text):
            return text
        
        #import GDMLCommands, GDMLResources
        commands=['CycleCommand','BoxCommand','ConeCommand','ElTubeCommand', \
                  'EllipsoidCommand','SphereCommand', \
                  'TrapCommand','TubeCommand']
        toolbarcommands=['CycleCommand','BoxCommand','ConeCommand', \
                         'ElTubeCommand', 'EllipsoidCommand','SphereCommand', \
                         'TrapCommand','TubeCommand']

        parttoolbarcommands = ['Part_Cut','Part_Fuse','Part_Common']

        self.appendToolbar(QT_TRANSLATE_NOOP('Workbench','GDMLTools'),toolbarcommands)
        self.appendMenu('GDML',commands)
        self.appendToolbar(QT_TRANSLATE_NOOP('Workbech','GDML Part tools'),parttoolbarcommands)
        #FreeCADGui.addIconPath(":/icons")
        FreeCADGui.addIconPath(FreeCAD.getResourceDir() + \
                              "Mod/GDML/Resources/icons")
        FreeCADGui.addLanguagePath(":/translations")
        FreeCADGui.addPreferencePage(":/ui/GDML-base.ui","GDML")
        #print(FreeCAD.getResourceDir() + "Mod/Resources/ui/GDML-base.ui")

    def Activated(self):
        "This function is executed when the workbench is activated"
        print ("Activated")
        print(self.GetClassName())
        #MyObserver()
        #App.addDocumentObserver(self.doc)
        self.obs = self.MyObserver()
        App.addDocumentObserver(self.obs)
        return

    def Deactivated(self):
        "This function is executed when the workbench is deactivated"
        App.removeDocumentObserver(self.obs)
        return
    
    def GetClassName(self):
        return "Gui::PythonWorkbench"

class testClass():
    def __init__(self):
        self.signal = []


Gui.addWorkbench(GDML_Workbench())

ickby
Veteran
Posts: 3116
Joined: Wed Oct 05, 2011 7:36 am

Re: Function when a workbench opens a new file.

Post by ickby »

I also found that it is not enough to import things in the init file for the observer, e.g. the processGDML must be imported in the function itself to be accessible:

Code: Select all

class GDML_Workbench ( Workbench ):

    class MyObserver():
        def __init__(self):
            self.signal = []
        def slotCreatedDocument(self, doc):
            from importGDML import processGDML
            processGDML(FreeCAD.getResourceDir() + "Mod/Resources/Default.GDML")
From there on I cannot test anymore as I do not have lxml available.
keithsloan52
Veteran
Posts: 2756
Joined: Mon Feb 27, 2012 5:31 pm

Re: Function when a workbench opens a new file.

Post by keithsloan52 »

Many thanks - now works a treat.
Post Reply