-
Notifications
You must be signed in to change notification settings - Fork 5
/
mplugin.py
354 lines (273 loc) · 11.5 KB
/
mplugin.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
# mplugin.py ---
#
# Filename: mplugin.py
# Description:
# Author:
# Maintainer:
# Created: Tue Oct 2 17:25:41 2012 (+0530)
# Version:
# Last-Updated: Thu Jul 18 10:51:48 2013 (+0530)
# By: subha
# Update #: 297
# URL:
# Keywords:
# Compatibility:
#
#
# Commentary:
#
# This is to be the base class for all MOOSE GUI plugins.
#
#
# Change log:
#
#
#
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3, or
# (at your option) any later version.
#
# This program 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
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street, Fifth
# Floor, Boston, MA 02110-1301, USA.
#
#
# Code:
from PyQt4 import QtGui,QtCore,Qt
import moose
class MoosePluginBase(QtCore.QObject):
"""Moose GUI plugin base class.
A GUI plugin for MOOSE should extend MoosePlugin class. It has to
implement the methods described here.
We keep _toolBars, _menus and _views as protected member
variables. Derived classes should populate/update these according
to their needs. The idea is that if a base class is populating any
of these, those entries are generic enough for the derived classes
to use. So a derived class should append their specific entries to
these lists in stead of overriding the getToolBars(), getMenus()
and getViews() functions.
"""
modelRootChanged = QtCore.pyqtSignal(object, name='modelRootChanged')
dataRootChanged = QtCore.pyqtSignal(object, name='dataRootChanged')
def __init__(self, root='/', mainwindow=None):
"""Create a plugin object whose model is the tree rooted at
`root` and whose widgets will be displayed in `mainwindow`.
"""
QtCore.QObject.__init__(self, mainwindow)
self._views = []
self._menus = []
self._toolBars = []
self.mainWindow = mainwindow
self.modelRoot = root
self.dataRoot = moose.Neutral('/data').path
def getPreviousPlugin(self):
"""Returns the plugin object that the gui is supposed to
switch to when going to a smaller scale."""
raise NotImplementedError('method must be reimplemented in subclass')
def getNextPlugin(self):
"""Returns the plugin object that the gui is supposed to
switch to when going to a larger scale."""
raise NotImplementedError('method must be reimplemented in subclass')
def getAdjacentPlugins(self):
"""Return a list of plugins that are valid transitions from this plugin"""
raise NotImplementedError('method must be reimplemented in subclass')
def getViews(self):
"""Return the view widgets available from this plugin."""
raise NotImplementedError('method must be reimplemented in subclass')
def getCurrentView(self):
"""Return the current view of this plugin."""
raise NotImplementedError('method must be reimplemented in subclass')
def setCurrentView(self, view):
"""Set current view (e.g., editor/plot/run).
Return true if successful, otherwise return False.
"""
if view == 'editor':
self.currentView = self.getEditorView()
elif view == 'plot':
self.currentView = self.getPlotView()
elif view == 'run':
self.currentView = self.getRunView()
else:
return False
return True
def getMenus(self):
return self._menus
def getToolBars(self):
return self._toolBars
# def close(self):
# for view in self._views:
# view.close()
def getEditorView(self):
raise NotImplementedError('method must be implemented in derived class')
def getPlotView(self):
raise NotImplementedError('method must be implemented in derived class')
def getRunView(self):
raise NotImplementedError('method must be implemented in derived class')
def setModelRoot(self, root):
#print("Default setModelRoot called.")
self.modelRoot = moose.element(root).path
self.getEditorView().getCentralWidget().setModelRoot(self.modelRoot)
self.getPlotView().getCentralWidget().setModelRoot(self.modelRoot)
self.modelRootChanged.emit(self.modelRoot)
def setDataRoot(self, root):
self.dataRoot = moose.Neutral(root).path
self.getPlotView().setDataRoot(self.dataRoot)
self.dataRootChanged.emit(self.dataRoot)
class ViewBase(QtCore.QObject):
"""Base class for each view: Editor, Plot, Run.
A view is a mode in a of a plugin. Each view provides
a list of toolbars to be displayed on top.
a list of widgets to be docked on the sides.
a list of menus to be added to the menubar.
a central widget to be displayed at the centre of the main window.
"""
def __init__(self, plugin):
QtCore.QObject.__init__(self, plugin)
self._menus = []
self._toolPanes = []
self._toolBars = []
self._centralWidget = None
self.plugin = plugin
def getToolPanes(self):
"""Return a list of widgets to be displayed as dock widgets."""
raise NotImplementedError('method must be reimplemented in subclass')
def getToolBars(self):
"""Return list of toolbars for this view."""
return self._toolBars
def getMenus(self):
"""Return the menus for this view."""
return self._menus
def getPreferences(self):
"""Return a widget for setting preferences"""
raise NotImplementedError('method must be reimplemented in subclass')
def getCentralWidget(self):
"""Return a widget for central widget of mainwindow."""
raise NotImplementedError('method must be reimplemented in subclass')
class EditorBase(ViewBase):
"""Base class for editor view.
This is the default view of a plugin. It should essentially
display a loaded model in an appropriate visual form.
It is ultimately intended to allow editing of the model, but that
is not a strict requirement.
"""
def __init__(self, plugin):
ViewBase.__init__(self, plugin)
def getToolPanes(self):
return self._toolPanes
def getLibraryPane(self):
"""TODO: display everything under library as a tree"""
raise NotImplementedError('method must be reimplemented in subclass')
def getSelectionPane(self):
"""TODO: provide a widget to apply selection rules"""
raise NotImplementedError('method must be reimplemented in subclass')
def getOperationsPane(self):
"""TODO: provide a widget to apply operations on selected
elements."""
raise NotImplementedError('method must be reimplemented in subclass')
class PlotBase(ViewBase):
"""Base class for plot configuration view.
In each plugin, this should provide utility to setup the plotting
of object fields. This is supposed to be used by intermediate
users.
"""
def __init__(self, *args):
ViewBase.__init__(self, *args)
def getSelectionPane(self):
"""TODO: provide a widget to apply selection rules"""
raise NotImplementedError('method must be reimplemented in subclass')
def getOperationsPane(self):
"""TODO: provide a widget to apply operations on selected
elements."""
raise NotImplementedError('method must be reimplemented in subclass')
class RunBase(ViewBase):
"""Base class for runtime view.
When the simulation runs, this view displays the runtime
visualization and controls for the simulation.
"""
def __init__(self, plugin, *args):
super(RunBase, self).__init__(plugin)
class EditorWidgetBase(QtGui.QWidget):
"""Base class for central widget displayed in editor view.
The widget should display the model components in the tree rooted
at `modelRoot` in appropriate visual representation.
`updateModelView` function should do the actual creation and laying
out of the visual objects.
Signals: editObject - emitted
with currently selected element's path as argument. Should be
connected to whatever slot is responsible for firing the object
editor in top level.
"""
editObject = QtCore.pyqtSignal('PyQt_PyObject')
def __init__(self, *args):
QtGui.QWidget.__init__(self, *args)
self.modelRoot = '/'
self._menus = []
self._toolBars = []
self._insertActions = []
self._insertMapper = None
def getInsertActions(self, classlist):
"""Create actions to be used in menus/toolbars for inserting class
instances. This function needs to be called only once. This
also creates the signal mapping from the insert actions.
Returns: (mapper, actions)
mapper is a QSignalMapper and actions is a list of QAction
objects. The triggering of any action in `actions` list causes
the `mapper` to emit a mapped(action-name) signal. This can be
connected to a slot in the editor's slot for inserting
elements. For MooseTreeWidget, this is the insertElement slot
(see default.py and mtree.py).
"""
if len(self._insertActions) == 0:
self._insertMapper = QtCore.QSignalMapper(self)
for classname in classlist:
action = QtGui.QAction(classname, self)
self._insertMapper.setMapping(action, QtCore.QString(classname))
self.connect(action,
QtCore.SIGNAL('triggered()'),
self._insertMapper,
QtCore.SLOT('map()'))
doc = moose.element('/classes/%s' % (classname)).docs
doc = doc.split('Description:')[-1].split('Name:')[0].strip()
action.setToolTip(doc)
self._insertActions.append(action)
return self._insertMapper, self._insertActions
def setModelRoot(self, path):
"""Set the root of the model tree to be displayed.
This calls `updateModelView` which should update the scene to
represent current model tree.
This function can be a slot for connecting actions that should
cause a change in modelRoot.
"""
self.modelRoot = path
self.updateModelView()
def updateModelView(self):
"""Update view by going through the model.
When model root is changed, this function is called. It should
update the scene to represent the current model tree rooted at
modelRoot.
"""
raise NotImplementedError('must be implemented in derived class.')
def getMenus(self):
return self._menus
def getToolBars(self):
return self._toolBars
def elementInsertedSlot(self, mobj):
self.editObject.emit(mobj.path)
def objectEditSlot(self, mobj):
"""Emits an `editObject(str)` signal with moose element path of currently selected tree item as
argument"""
self.editObject.emit(moose.element(mobj).path)
def sizeHint(self):
return self.size()
def getCurrentMobj(self):
raise NotImplementedError('should be reimplemented in subclass')
#
# mplugin.py ends here