FreeCAD
219 строк · 7.8 Кб
1# ***************************************************************************
2# * (c) 2009 Yorik van Havre <yorik@uncreated.net> *
3# * (c) 2010 Ken Cline <cline@frii.com> *
4# * (c) 2019 Eliud Cabrera Castillo <e.cabrera-castillo@tum.de> *
5# * *
6# * This file is part of the FreeCAD CAx development system. *
7# * *
8# * This program is free software; you can redistribute it and/or modify *
9# * it under the terms of the GNU Lesser General Public License (LGPL) *
10# * as published by the Free Software Foundation; either version 2 of *
11# * the License, or (at your option) any later version. *
12# * for detail see the LICENCE text file. *
13# * *
14# * FreeCAD is distributed in the hope that it will be useful, *
15# * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17# * GNU Library General Public License for more details. *
18# * *
19# * You should have received a copy of the GNU Library General Public *
20# * License along with FreeCAD; if not, write to the Free Software *
21# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 *
22# * USA *
23# * *
24# ***************************************************************************
25"""Provides the base classes for newer Draft Gui Commands."""
26## @package gui_base
27# \ingroup draftguitools
28# \brief Provides the base classes for newer Draft Gui Commands.
29
30## \addtogroup draftguitools
31# @{
32import FreeCAD as App
33import FreeCADGui as Gui
34import draftutils.todo as todo
35
36from draftutils.messages import _toolmsg, _log
37
38
39class GuiCommandSimplest:
40"""Simplest base class for GuiCommands.
41
42This class only sets up the command name and the document object
43to use for the command.
44When it is executed, it logs the command name to the log file,
45and prints the command name to the console.
46
47It implements the `IsActive` method, which must return `True`
48when the command should be available.
49It should return `True` when there is an active document,
50otherwise the command (button or menu) should be disabled.
51
52This class is meant to be inherited by other GuiCommand classes
53to quickly log the command name, and set the correct document object.
54
55Parameter
56---------
57name: str, optional
58It defaults to `'None'`.
59The name of the action that is being run,
60for example, `'Heal'`, `'Flip dimensions'`,
61`'Line'`, `'Circle'`, etc.
62
63doc: App::Document, optional
64It defaults to the value of `App.activeDocument()`.
65The document object itself, which indicates where the actions
66of the command will be executed.
67
68Attributes
69----------
70command_name: str
71This is the command name, which is assigned by `name`.
72
73doc: App::Document
74This is the document object itself, which is assigned by `doc`.
75
76This attribute should be used by functions to make sure
77that the operations are performed in the correct document
78and not in other documents.
79To set the active document we can use
80
81>>> App.setActiveDocument(self.doc.Name)
82"""
83
84def __init__(self, name="None", doc=App.activeDocument()):
85self.command_name = name
86self.doc = doc
87
88def IsActive(self):
89"""Return True when this command should be available.
90
91It is `True` when there is a document.
92"""
93if App.activeDocument():
94return True
95else:
96return False
97
98def Activated(self):
99"""Execute when the command is called.
100
101Log the command name to the log file and console.
102Also update the `doc` attribute.
103"""
104self.doc = App.activeDocument()
105_log("Document: {}".format(self.doc.Label))
106_log("GuiCommand: {}".format(self.command_name))
107_toolmsg("{}".format(16*"-"))
108_toolmsg("GuiCommand: {}".format(self.command_name))
109
110
111class GuiCommandNeedsSelection(GuiCommandSimplest):
112"""Base class for GuiCommands that need a selection to be available.
113
114It re-implements the `IsActive` method to return `True`
115when there is both an active document and an active selection.
116
117It inherits `GuiCommandSimplest` to set up the document
118and other behavior. See this class for more information.
119"""
120
121def IsActive(self):
122"""Return True when this command should be available.
123
124It is `True` when there is a selection.
125"""
126if App.activeDocument() and Gui.Selection.getSelection():
127return True
128else:
129return False
130
131
132class GuiCommandBase:
133"""Generic class that is the basis of all Gui commands.
134
135This class should eventually replace `DraftTools.DraftTool`,
136once all functionality in that class is merged here.
137
138Attributes
139----------
140commit_list : list of 2-element tuples
141Each tuple is made of a string, and a list of strings.
142::
143commit_list = [(string1, list1), (string2, list2), ...]
144
145The string is a simple header, for example, a command name,
146that indicates what is being executed.
147
148Each string in the list of strings represents a Python instruction
149which will be executed in a delayed fashion
150by `todo.ToDo.delayCommit()`
151::
152list1 = ["a = FreeCAD.Vector()",
153"pl = FreeCAD.Placement()",
154"Draft.autogroup(obj)"]
155
156commit_list = [("Something", list1)]
157
158This is used when the 3D view has event callbacks that crash
159Coin3D.
160If this is not needed, those commands could be called in the
161body of the command without problem.
162::
163>>> a = FreeCAD.Vector()
164>>> pl = FreeCAD.Placement()
165>>> Draft.autogroup(obj)
166"""
167
168def __init__(self):
169self.call = None
170self.commit_list = []
171self.doc = None
172App.activeDraftCommand = None
173self.view = None
174self.planetrack = None
175
176def IsActive(self):
177"""Return True when this command should be available."""
178if App.ActiveDocument:
179return True
180else:
181return False
182
183def finish(self):
184"""Terminate the active command by committing the list of commands.
185
186It also perform some other tasks like terminating
187the plane tracker and the snapper.
188"""
189App.activeDraftCommand = None
190if self.planetrack:
191self.planetrack.finalize()
192if hasattr(Gui, "Snapper"):
193Gui.Snapper.off()
194if self.call:
195try:
196self.view.removeEventCallback("SoEvent", self.call)
197except RuntimeError:
198# the view has been deleted already
199pass
200self.call = None
201if self.commit_list:
202todo.ToDo.delayCommit(self.commit_list)
203self.commit_list = []
204
205def commit(self, name, func):
206"""Store actions to be committed to the document.
207
208Parameters
209----------
210name : str
211A string that indicates what is being committed.
212
213func : list of strings
214Each element of the list should be a Python command
215that will be executed.
216"""
217self.commit_list.append((name, func))
218
219## @}
220