scipion-pyworkflow 3.10.5__py3-none-any.whl → 3.11.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (127) hide show
  1. pyworkflow/config.py +131 -67
  2. pyworkflow/constants.py +12 -2
  3. pyworkflow/object.py +3 -2
  4. pyworkflow/plugin.py +93 -44
  5. pyworkflow/project/scripts/fix_links.py +4 -1
  6. pyworkflow/resources/showj/arrowDown.png +0 -0
  7. pyworkflow/resources/showj/arrowUp.png +0 -0
  8. pyworkflow/resources/showj/background_section.png +0 -0
  9. pyworkflow/resources/showj/colRowModeOff.png +0 -0
  10. pyworkflow/resources/showj/colRowModeOn.png +0 -0
  11. pyworkflow/resources/showj/delete.png +0 -0
  12. pyworkflow/resources/showj/doc_icon.png +0 -0
  13. pyworkflow/resources/showj/download_icon.png +0 -0
  14. pyworkflow/resources/showj/enabled_gallery.png +0 -0
  15. pyworkflow/resources/showj/galleryViewOff.png +0 -0
  16. pyworkflow/resources/showj/galleryViewOn.png +0 -0
  17. pyworkflow/resources/showj/goto.png +0 -0
  18. pyworkflow/resources/showj/menu.png +0 -0
  19. pyworkflow/resources/showj/separator.png +0 -0
  20. pyworkflow/resources/showj/tableViewOff.png +0 -0
  21. pyworkflow/resources/showj/tableViewOn.png +0 -0
  22. pyworkflow/resources/showj/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  23. pyworkflow/resources/showj/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  24. pyworkflow/resources/showj/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  25. pyworkflow/resources/showj/volumeOff.png +0 -0
  26. pyworkflow/resources/showj/volumeOn.png +0 -0
  27. pyworkflow/viewer.py +23 -1
  28. pyworkflowtests/objects.py +2 -2
  29. pyworkflowtests/protocols.py +1 -3
  30. {scipion_pyworkflow-3.10.5.dist-info → scipion_pyworkflow-3.11.0.dist-info}/METADATA +21 -25
  31. scipion_pyworkflow-3.11.0.dist-info/RECORD +71 -0
  32. {scipion_pyworkflow-3.10.5.dist-info → scipion_pyworkflow-3.11.0.dist-info}/WHEEL +1 -1
  33. scipion_pyworkflow-3.11.0.dist-info/entry_points.txt +2 -0
  34. pyworkflow/apps/__init__.py +0 -29
  35. pyworkflow/apps/pw_manager.py +0 -37
  36. pyworkflow/apps/pw_plot.py +0 -51
  37. pyworkflow/apps/pw_project.py +0 -113
  38. pyworkflow/apps/pw_protocol_list.py +0 -143
  39. pyworkflow/apps/pw_protocol_run.py +0 -51
  40. pyworkflow/apps/pw_run_tests.py +0 -267
  41. pyworkflow/apps/pw_schedule_run.py +0 -322
  42. pyworkflow/apps/pw_sleep.py +0 -37
  43. pyworkflow/apps/pw_sync_data.py +0 -439
  44. pyworkflow/apps/pw_viewer.py +0 -78
  45. pyworkflow/gui/__init__.py +0 -36
  46. pyworkflow/gui/browser.py +0 -726
  47. pyworkflow/gui/canvas.py +0 -1190
  48. pyworkflow/gui/dialog.py +0 -977
  49. pyworkflow/gui/form.py +0 -2637
  50. pyworkflow/gui/graph.py +0 -247
  51. pyworkflow/gui/graph_layout.py +0 -271
  52. pyworkflow/gui/gui.py +0 -566
  53. pyworkflow/gui/matplotlib_image.py +0 -233
  54. pyworkflow/gui/plotter.py +0 -247
  55. pyworkflow/gui/project/__init__.py +0 -25
  56. pyworkflow/gui/project/base.py +0 -192
  57. pyworkflow/gui/project/constants.py +0 -139
  58. pyworkflow/gui/project/labels.py +0 -205
  59. pyworkflow/gui/project/project.py +0 -492
  60. pyworkflow/gui/project/searchprotocol.py +0 -154
  61. pyworkflow/gui/project/searchrun.py +0 -181
  62. pyworkflow/gui/project/steps.py +0 -171
  63. pyworkflow/gui/project/utils.py +0 -332
  64. pyworkflow/gui/project/variables.py +0 -179
  65. pyworkflow/gui/project/viewdata.py +0 -472
  66. pyworkflow/gui/project/viewprojects.py +0 -510
  67. pyworkflow/gui/project/viewprotocols.py +0 -2093
  68. pyworkflow/gui/project/viewprotocols_extra.py +0 -560
  69. pyworkflow/gui/text.py +0 -771
  70. pyworkflow/gui/tooltip.py +0 -185
  71. pyworkflow/gui/tree.py +0 -684
  72. pyworkflow/gui/widgets.py +0 -307
  73. pyworkflow/mapper/__init__.py +0 -26
  74. pyworkflow/mapper/mapper.py +0 -222
  75. pyworkflow/mapper/sqlite.py +0 -1578
  76. pyworkflow/mapper/sqlite_db.py +0 -145
  77. pyworkflow/project/__init__.py +0 -31
  78. pyworkflow/project/config.py +0 -454
  79. pyworkflow/project/manager.py +0 -180
  80. pyworkflow/project/project.py +0 -2010
  81. pyworkflow/protocol/__init__.py +0 -38
  82. pyworkflow/protocol/bibtex.py +0 -48
  83. pyworkflow/protocol/constants.py +0 -87
  84. pyworkflow/protocol/executor.py +0 -455
  85. pyworkflow/protocol/hosts.py +0 -313
  86. pyworkflow/protocol/launch.py +0 -270
  87. pyworkflow/protocol/package.py +0 -42
  88. pyworkflow/protocol/params.py +0 -741
  89. pyworkflow/protocol/protocol.py +0 -2582
  90. pyworkflow/tests/__init__.py +0 -29
  91. pyworkflow/tests/test_utils.py +0 -25
  92. pyworkflow/tests/tests.py +0 -341
  93. pyworkflow/utils/__init__.py +0 -38
  94. pyworkflow/utils/dataset.py +0 -414
  95. pyworkflow/utils/echo.py +0 -104
  96. pyworkflow/utils/graph.py +0 -169
  97. pyworkflow/utils/log.py +0 -284
  98. pyworkflow/utils/path.py +0 -528
  99. pyworkflow/utils/process.py +0 -132
  100. pyworkflow/utils/profiler.py +0 -92
  101. pyworkflow/utils/progressbar.py +0 -154
  102. pyworkflow/utils/properties.py +0 -631
  103. pyworkflow/utils/reflection.py +0 -129
  104. pyworkflow/utils/utils.py +0 -879
  105. pyworkflow/utils/which.py +0 -229
  106. pyworkflow/webservices/__init__.py +0 -8
  107. pyworkflow/webservices/config.py +0 -11
  108. pyworkflow/webservices/notifier.py +0 -162
  109. pyworkflow/webservices/repository.py +0 -59
  110. pyworkflow/webservices/workflowhub.py +0 -74
  111. pyworkflowtests/tests/__init__.py +0 -0
  112. pyworkflowtests/tests/test_canvas.py +0 -72
  113. pyworkflowtests/tests/test_domain.py +0 -45
  114. pyworkflowtests/tests/test_logs.py +0 -74
  115. pyworkflowtests/tests/test_mappers.py +0 -392
  116. pyworkflowtests/tests/test_object.py +0 -507
  117. pyworkflowtests/tests/test_project.py +0 -42
  118. pyworkflowtests/tests/test_protocol_execution.py +0 -135
  119. pyworkflowtests/tests/test_protocol_export.py +0 -78
  120. pyworkflowtests/tests/test_protocol_output.py +0 -158
  121. pyworkflowtests/tests/test_streaming.py +0 -47
  122. pyworkflowtests/tests/test_utils.py +0 -210
  123. scipion_pyworkflow-3.10.5.dist-info/RECORD +0 -140
  124. scipion_pyworkflow-3.10.5.dist-info/dependency_links.txt +0 -1
  125. scipion_pyworkflow-3.10.5.dist-info/entry_points.txt +0 -5
  126. {scipion_pyworkflow-3.10.5.dist-info → scipion_pyworkflow-3.11.0.dist-info/licenses}/LICENSE.txt +0 -0
  127. {scipion_pyworkflow-3.10.5.dist-info → scipion_pyworkflow-3.11.0.dist-info}/top_level.txt +0 -0
@@ -1,179 +0,0 @@
1
- # **************************************************************************
2
- # *
3
- # * Authors: Pablo Conesa (scipion@cnb.csic.es)
4
- # *
5
- # * Unidad de Bioinformatica of Centro Nacional de Biotecnologia , CSIC
6
- # *
7
- # * This program is free software; you can redistribute it and/or modify
8
- # * it under the terms of the GNU General Public License as published by
9
- # * the Free Software Foundation; either version 3 of the License, or
10
- # * (at your option) any later version.
11
- # *
12
- # * This program is distributed in the hope that it will be useful,
13
- # * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
- # * GNU General Public License for more details.
16
- # *
17
- # * You should have received a copy of the GNU General Public License
18
- # * along with this program; if not, write to the Free Software
19
- # * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
20
- # * 02111-1307 USA
21
- # *
22
- # * All comments concerning this program package may be sent to the
23
- # * e-mail address 'scipion@cnb.csic.es'
24
- # *
25
- # **************************************************************************
26
- """
27
- Module for editing variables
28
- """
29
-
30
- import tkinter as tk
31
-
32
- from pyworkflow import Config, Variable, VariablesRegistry, VarTypes
33
- from pyworkflow.gui import Icon, configureWeigths, getDefaultFont, askPath
34
- from pyworkflow.gui.tree import TreeProvider
35
- import pyworkflow.gui.dialog as dialog
36
-
37
-
38
- class VariablesTreeProvider(TreeProvider):
39
- """ Populate Tree from Labels. """
40
- def __init__(self):
41
- TreeProvider.__init__(self)
42
- self._parentDict = {}
43
-
44
- def getColumns(self):
45
- return [('Name', 300), ('Value', 500), ('Default?', 60), ('DefaultV',200),('Description', 400), ('Source', 150)]
46
-
47
- def getObjectInfo(self, variable: Variable):
48
-
49
- return {'key': variable.name, 'parent': None,
50
- 'text': variable.name, 'values': (variable.value, "is default" if variable.isDefault else "Declared",
51
- variable.default, variable.description, variable.source),
52
- }
53
-
54
-
55
- def getObjects(self):
56
- return VariablesRegistry.__iter__()
57
-
58
-
59
- class VariablesDialog(dialog.ToolbarListDialog):
60
- """
61
- This dialog will allow editing variables coming either from pyworkflow or the plugins
62
- """
63
- def __init__(self, parent, **kwargs):
64
- """ From kwargs:
65
- message: message tooltip to show when browsing.
66
- selected: the item that should be selected.
67
- validateSelectionCallback:
68
- a callback function to validate selected items.
69
- allowSelect: if set to False, the 'Select' button will not
70
- be shown.
71
- """
72
- toolbarButtons = [
73
- # dialog.ToolbarButton('Add', self._addLabel, Icon.ACTION_NEW),
74
- dialog.ToolbarButton('Edit', self._editVariable, Icon.ACTION_EDIT),
75
- dialog.ToolbarButton('Set to default', self._setToDefault, Icon.ACTION_DELETE)
76
- ]
77
-
78
- helpMsg =("Use this form to change core and plugin's variables. If \"Default\" is true, it currently is the default value and is not present in the config file. All changes here "
79
- "will be persisted in the general %s config file. \"Source\" field tells you where the variable is defined."% Config.SCIPION_CONFIG)
80
-
81
- dialog.ToolbarListDialog.__init__(self, parent,
82
- "Edit config variables",
83
- VariablesTreeProvider(),
84
- helpMsg,
85
- toolbarButtons,
86
- allowsEmptySelection=True,
87
- itemDoubleClick=self._editVariable,
88
- cancelButton=False,
89
- buttons=[('Save', dialog.RESULT_YES),
90
- ('Cancel', dialog.RESULT_CANCEL)],
91
- **kwargs)
92
-
93
-
94
- def apply(self):
95
- VariablesRegistry.save(Config.SCIPION_CONFIG)
96
- def _editVariable(self, e=None):
97
- selection = self.tree.getSelectedObjects()
98
- if selection:
99
- variable = selection[0]
100
- dlg = EditVariableDialog(self, "Edit variable", variable)
101
- if dlg.resultYes():
102
- self.refresh()
103
-
104
- def _setToDefault(self, e=None):
105
- selection = self.tree.getSelectedObjects()
106
- if selection:
107
- varsStr = '\n'.join('- %s' % v.name for v in selection)
108
- if dialog.askYesNo(" The variables will be set it to its default value.",
109
- "Are you sure to reset the %s"
110
- "value?\n" % varsStr, self):
111
- for variable in selection:
112
- variable.setToDefault()
113
- self.tree.update()
114
-
115
-
116
- class EditVariableDialog(dialog.Dialog):
117
- """ Dialog to edit a variable """
118
- def __init__(self, parent, title, variable:Variable, **kwargs):
119
- self.variable = variable
120
- dialog.Dialog.__init__(self, parent, title)
121
-
122
- def body(self, bodyFrame):
123
- bodyFrame.config(bg=Config.SCIPION_BG_COLOR)
124
- configureWeigths(bodyFrame, 1, 1)
125
-
126
- # Name
127
- label_text = tk.Label(bodyFrame, text=self.variable.name, bg=Config.SCIPION_BG_COLOR, bd=0)
128
- label_text.grid(row=0, column=0, sticky='nw', padx=(15, 10), pady=15)
129
-
130
- # Description
131
- label_text = tk.Label(bodyFrame, text=self.variable.description, bg=Config.SCIPION_BG_COLOR, bd=0)
132
- label_text.grid(row=0, column=1, sticky='nw', padx=(15, 10), pady=15)
133
-
134
- # Value
135
- label_text = tk.Label(bodyFrame, text="Value", bg=Config.SCIPION_BG_COLOR, bd=0)
136
- label_text.grid(row=2, column=0, sticky='nw', padx=(15, 10), pady=15)
137
-
138
- # Value Entry
139
- if self.variable.var_type == VarTypes.INTEGER:
140
- var=tk.IntVar()
141
- else:
142
- var = tk.StringVar()
143
-
144
- var.set(self.variable.value)
145
- self.valueVar = var
146
- self.valueLabel = tk.Entry(bodyFrame, width=30, textvariable=var, font=getDefaultFont())
147
- self.valueLabel.grid(row=2, column=1, sticky='news', padx=5, pady=5)
148
-
149
- if self.variable.var_type in [VarTypes.PATH, VarTypes.FOLDER, VarTypes.FILENAME]:
150
- self._addButton(bodyFrame, self.buttonClicked, icon=Icon.ACTION_BROWSE, row=2, col=2,tooltip="Click to browse file system for a file or folder")
151
-
152
- def buttonClicked(self, e):
153
- """ Callback for when the wizard button has been clicked"""
154
-
155
- var_type = self.variable.var_type
156
-
157
- if var_type in [VarTypes.PATH, VarTypes.FOLDER, VarTypes.FILENAME]:
158
-
159
- onlyFolders = (var_type == VarTypes.FOLDER)
160
- returnBaseName = (var_type ==var_type.FILENAME)
161
- path = self.valueVar.get() if not returnBaseName else "."
162
-
163
- value =askPath(path=path, master=self, onlyFolders=onlyFolders, returnBaseName=returnBaseName)
164
- self.valueVar.set(value)
165
- def apply(self):
166
- self.variable.setValue(self.valueVar.get())
167
-
168
- def validate(self):
169
-
170
- validationMsg = None
171
-
172
- if len(self.valueVar.get().strip()) == 0:
173
- validationMsg = "Value name can't be empty.\n"
174
-
175
- if validationMsg is not None:
176
- dialog.showError("Validation error", validationMsg, self)
177
- return False
178
-
179
- return True
@@ -1,472 +0,0 @@
1
- #!/usr/bin/env python
2
- # **************************************************************************
3
- # *
4
- # * Authors: J.M. De la Rosa Trevin (delarosatrevin@scilifelab.se) [1]
5
- # *
6
- # * [1] SciLifeLab, Stockholm University
7
- # *
8
- # * This program is free software: you can redistribute it and/or modify
9
- # * it under the terms of the GNU General Public License as published by
10
- # * the Free Software Foundation, either version 3 of the License, or
11
- # * (at your option) any later version.
12
- # *
13
- # * This program is distributed in the hope that it will be useful,
14
- # * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- # * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
- # * GNU General Public License for more details.
17
- # *
18
- # * You should have received a copy of the GNU General Public License
19
- # * along with this program. If not, see <https://www.gnu.org/licenses/>.
20
- # *
21
- # * All comments concerning this program package may be sent to the
22
- # * e-mail address 'scipion@cnb.csic.es'
23
- # *
24
- # **************************************************************************
25
- """
26
- Data-oriented view of the project objects.
27
- """
28
-
29
-
30
- import tkinter as tk
31
- import tkinter.ttk as ttk
32
- import tkinter.font as tkFont
33
-
34
- from pyworkflow import Config
35
- import pyworkflow.utils as pwutils
36
- import pyworkflow.viewer as pwviewer
37
-
38
- import pyworkflow.gui as gui
39
- from pyworkflow.gui.tree import Tree
40
- from pyworkflow.gui.dialog import EditObjectDialog
41
- from pyworkflow.gui.text import TaggedText
42
- from pyworkflow.gui import Canvas, RoundedTextBox
43
- from pyworkflow.gui.graph import LevelTree
44
- from pyworkflow.gui.form import getObjectLabel
45
- from pyworkflow.constants import DATA_TAG
46
-
47
-
48
-
49
-
50
- def populateTree(tree, elements, parentId=''):
51
- for node in elements:
52
- if hasattr(node, 'count'):
53
- t = node.getName()
54
- if node.count:
55
- t += ' (%d)' % node.count
56
- node.nodeId = tree.insert(parentId, 'end', node.getName(),
57
- text=t, tags=DATA_TAG)
58
- populateTree(tree, node.getChildren(), node.nodeId)
59
- if node.count:
60
- tree.see(node.nodeId)
61
- tree.item(node.nodeId, tags=('non-empty', DATA_TAG))
62
-
63
-
64
- class ProjectDataView(tk.Frame):
65
- def __init__(self, parent, windows, **args):
66
- tk.Frame.__init__(self, parent, **args)
67
- # Load global configuration
68
- self.windows = windows
69
- self.project = windows.project
70
- self.root = windows.root
71
- self.getImage = windows.getImage
72
- self.settings = windows.getSettings()
73
- self.showGraph = self.settings.getRunsView()
74
- self.style = ttk.Style()
75
-
76
- self.root.bind("<F5>", self.refreshData)
77
- self.__autoRefresh = None
78
- self.__autoRefreshCounter = 3 # start by 3 secs
79
-
80
- self._dataGraph = windows.project.getSourceGraph(True)
81
-
82
- c = self._createContent()
83
-
84
- gui.configureWeigths(self)
85
- c.grid(row=0, column=0, sticky='news')
86
-
87
- def _createContent(self):
88
- """ Create the Data View for the Project.
89
- It has two panes:
90
- Left: containing the Protocol classes tree
91
- Right: containing the Data list
92
- """
93
- p = tk.PanedWindow(self, orient=tk.HORIZONTAL, bg=Config.SCIPION_BG_COLOR)
94
-
95
- # Left pane, contains Data tree
96
- leftFrame = tk.Frame(p, bg=Config.SCIPION_BG_COLOR)
97
- bgColor = '#eaebec'
98
- self._createDataTree(leftFrame, bgColor)
99
- gui.configureWeigths(leftFrame)
100
-
101
- # Right pane
102
- rightFrame = tk.Frame(p, bg=Config.SCIPION_BG_COLOR)
103
- rightFrame.columnconfigure(0, weight=1)
104
- rightFrame.rowconfigure(1, weight=1)
105
- # rightFrame.rowconfigure(0, minsize=label.winfo_reqheight())
106
- self._fillRightPane(rightFrame)
107
-
108
- # Add sub-windows to PanedWindows
109
- p.add(leftFrame, padx=5, pady=5)
110
- p.add(rightFrame, padx=5, pady=5)
111
- p.paneconfig(leftFrame, minsize=300)
112
- p.paneconfig(rightFrame, minsize=400)
113
-
114
- return p
115
-
116
- def _createDataTree(self, parent, bgColor):
117
- """Create a tree on the left panel to store how
118
- many object are from each type and the hierarchy.
119
- """
120
- defaultFont = gui.getDefaultFont()
121
- self.style.configure("W.Treeview",
122
- background=pwutils.Color.ALT_COLOR,
123
- borderwidth=0,
124
- rowheight=defaultFont.metrics()['linespace'])
125
- self.dataTree = Tree(parent, show='tree', style='W.Treeview')
126
- self.dataTree.column('#0', minwidth=300)
127
- self.dataTree.tag_configure('protocol',
128
- image=self.getImage(pwutils.Icon.PRODUCTION))
129
- self.dataTree.tag_configure('protocol_base',
130
- image=self.getImage(pwutils.Icon.GROUP))
131
- f = tkFont.Font(family='helvetica', size='10', weight='bold')
132
- self.dataTree.tag_configure('non-empty', font=f)
133
- self.dataTree.grid(row=0, column=0, sticky='news')
134
-
135
- # bind click events
136
- self.dataTree.tag_bind(DATA_TAG, '<Double-1>', self._dataItemClick)
137
- self.dataTree.tag_bind(DATA_TAG, '<Return>', self._dataItemClick)
138
- self.dataTree.tag_bind(DATA_TAG, '<KP_Enter>', self._dataItemClick)
139
-
140
- # Program automatic refresh
141
- self.dataTree.after(3000, self._automaticRefreshData)
142
-
143
- self._updateDataTree()
144
-
145
- def _updateDataTree(self):
146
-
147
- def createClassNode(classObj):
148
- """ Add the object class to hierarchy and
149
- any needed subclass. """
150
- className = classObj.__name__
151
- classNode = classesGraph.getNode(className)
152
-
153
- if not classNode:
154
- classNode = classesGraph.createNode(className)
155
- if className != 'EMObject' and classObj.__bases__:
156
- baseClass = classObj.__bases__[0]
157
- for b in classObj.__bases__:
158
- if b.__name__ == 'EMObject':
159
- baseClass = b
160
- break
161
- parent = createClassNode(baseClass)
162
- parent.addChild(classNode)
163
- classNode.count = 0
164
-
165
- return classNode
166
-
167
- classesGraph = pwutils.Graph()
168
-
169
- self.dataTree.clear()
170
- for node in self._dataGraph.getNodes():
171
- if node.pointer:
172
- classNode = createClassNode(node.pointer.get().getClass())
173
- classNode.count += 1
174
-
175
- populateTree(self.dataTree, classesGraph.getRootNodes())
176
-
177
- def _fillRightPane(self, parent):
178
- """
179
- # Create the right Pane that will be composed by:
180
- # a Action Buttons TOOLBAR in the top
181
- # and another vertical Pane with:
182
- # Runs History (at Top)
183
- # Selected run info (at Bottom)
184
- """
185
- # Create the Action Buttons TOOLBAR
186
- toolbar = tk.Frame(parent, bg=Config.SCIPION_BG_COLOR)
187
- toolbar.grid(row=0, column=0, sticky='news')
188
- gui.configureWeigths(toolbar)
189
- # toolbar.columnconfigure(0, weight=1)
190
- toolbar.columnconfigure(1, weight=1)
191
-
192
- self.runsToolbar = tk.Frame(toolbar, bg=Config.SCIPION_BG_COLOR)
193
- self.runsToolbar.grid(row=0, column=0, sticky='sw')
194
- # On the left of the toolbar will be other
195
- # actions that can be applied to all runs (refresh, graph view...)
196
- self.allToolbar = tk.Frame(toolbar, bg=Config.SCIPION_BG_COLOR)
197
- self.allToolbar.grid(row=0, column=10, sticky='se')
198
- # self.createActionToolbar()
199
-
200
- # Create the Run History tree
201
- v = ttk.PanedWindow(parent, orient=tk.VERTICAL)
202
- # runsFrame = ttk.Labelframe(v, text=' History ', width=500, height=500)
203
- runsFrame = tk.Frame(v, bg=Config.SCIPION_BG_COLOR)
204
- self._createDataGraph(runsFrame)
205
- gui.configureWeigths(runsFrame)
206
-
207
- # Create the Selected Run Info
208
- infoFrame = tk.Frame(v)
209
- gui.configureWeigths(infoFrame)
210
- self._infoText = TaggedText(infoFrame, bg=Config.SCIPION_BG_COLOR,
211
- handlers={'sci-open': self._openProtocolFormFromId})
212
- self._infoText.grid(row=0, column=0, sticky='news')
213
-
214
- v.add(runsFrame, weight=3)
215
- v.add(infoFrame, weight=1)
216
- v.grid(row=1, column=0, sticky='news')
217
-
218
- # TODO(josemi): check that the call to RoundedTextBox is correct
219
- # It looks suspicious because RoundedTextBox() needs 5 arguments, not 3
220
- def _createNode(self, canvas, node, y):
221
- """ Create Data node to be painted in the graph. """
222
- node.selected = False
223
- node.box = RoundedTextBox(canvas, node, y)
224
- return node.box
225
-
226
- def _createDataItem(self, canvas, node, y):
227
- if node.pointer is None:
228
- nodeText = "Project"
229
- else:
230
- label = getObjectLabel(node.pointer, self.project.mapper)
231
- nodeText = (label[:25]+'...') if len(label) > 25 else label
232
-
233
- textColor = 'black'
234
- color = '#ADD8E6' # Lightblue
235
- item = self._dataCanvas.createTextbox(nodeText, 100, y, bgColor=color,
236
- textColor=textColor)
237
-
238
- # Get the dataId
239
- if not node.isRoot():
240
- dataId = node.pointer.get().getObjId()
241
-
242
- if dataId in self.settings.dataSelection:
243
- item.setSelected(True)
244
-
245
- return item
246
-
247
- def _createDataGraph(self, parent):
248
- """ This will be the upper part of the right panel.
249
- It will contain the Data Graph with their relations.
250
- """
251
- self._dataCanvas = Canvas(parent, width=600, height=500)
252
- self._dataCanvas.grid(row=0, column=0, sticky='nsew')
253
- self._dataCanvas.onClickCallback = self._onClick
254
- self._dataCanvas.onDoubleClickCallback = self._onDoubleClick
255
- self._dataCanvas.onRightClickCallback = self._onRightClick
256
-
257
- self._updateDataGraph()
258
-
259
- def _updateDataGraph(self):
260
- lt = LevelTree(self._dataGraph)
261
- self._dataCanvas.clear()
262
- lt.setCanvas(self._dataCanvas)
263
- lt.paint(self._createDataItem)
264
- self._dataCanvas.updateScrollRegion()
265
-
266
- def _dataItemClick(self, e=None):
267
- # Get the tree widget that originated the event
268
- # from the left pane data tree
269
- tree = e.widget
270
- dataClassName = tree.getFirst()
271
-
272
- if dataClassName is not None:
273
- self._loopData(lambda item: self._selectItemByClass(item, dataClassName))
274
-
275
- def _selectObject(self, pobj):
276
- obj = pobj.get()
277
- objValue = pobj.getObjValue()
278
- self._selected = obj
279
- self._infoText.setReadOnly(False)
280
- self._infoText.setText('*Label:* ' + getObjectLabel(pobj, self.project.mapper))
281
- self._infoText.addText('*Info:* ' + str(obj))
282
- self._infoText.addText('*Created by:*')
283
- self._infoText.addText(' - %s (%s)'
284
- % (objValue.getObjectTag(objValue),
285
- obj.getObjCreation()))
286
-
287
- # Get the consumers (this will get the data!!)
288
- derivedData = self.project.getSourceChilds(objValue)
289
-
290
- if derivedData is not None and len(derivedData) > 0:
291
- self._infoText.addText('*Consumed by:*')
292
-
293
- for data in derivedData:
294
- # Get the protocol
295
- protocol = self.project.getObject(data.getObjParentId())
296
- self._infoText.addText(' - ' + protocol.getObjectTag(protocol))
297
-
298
- if obj.getObjComment():
299
- self._infoText.addText('*Comments:* ' + obj.getObjComment())
300
- self._infoText.setReadOnly(True)
301
-
302
- def _onClick(self, e=None):
303
- self._deselectAll()
304
-
305
- if e.node.pointer:
306
- self.toggleItemSelection(e, True)
307
- self._selectObject(e.node.pointer)
308
-
309
- def _invertSelection(self):
310
-
311
- self._loopData(self._invertAction)
312
-
313
- def _deselectAll(self):
314
-
315
- self._loopData(self._deselectItemAction)
316
-
317
- def _selectAll(self):
318
-
319
- self._loopData(self._selectItemAction)
320
-
321
- def _selectItemAction(self, item):
322
- self.toggleItemSelection(item, True)
323
-
324
- def _selectItemByClass(self, item, className):
325
-
326
- if not item.node.isRoot():
327
-
328
- data = item.node.pointer.get()
329
- self.toggleItemSelection(
330
- item, isinstance(data, self.domain.getObjects()[className]))
331
-
332
- def _invertAction(self, item):
333
- self.toggleItemSelection(item, not item.getSelected())
334
-
335
- def _deselectItemAction(self, item):
336
- self.toggleItemSelection(item, False)
337
-
338
- def toggleItemSelection(self, item, select):
339
- if item.node.isRoot():
340
- return
341
- selection = self.settings.dataSelection
342
- runSelection = self.settings.runSelection
343
- dataId = item.node.pointer.get().getObjId()
344
- protocolId = item.node.pointer.getObjValue().getObjId()
345
-
346
- if not select:
347
- try:
348
- if dataId in selection:
349
- selection.remove(dataId)
350
- if protocolId in runSelection:
351
- runSelection.remove(protocolId)
352
- except ValueError:
353
- print("id not in selection")
354
- else:
355
- selection.append(dataId)
356
- runSelection.append(protocolId)
357
-
358
- item.setSelected(select)
359
-
360
- def _loopData(self, action):
361
- results = []
362
- # Loop through all the items
363
- for key, item in self._dataCanvas.items.items():
364
- result = action(item)
365
- if result is not None:
366
- results.append(result)
367
-
368
- return results
369
-
370
- def _onDoubleClick(self, item=None, e=None):
371
- if item.node.pointer:
372
- self._selectObject(e.node.pointer)
373
- self._viewObject(e.node.pointer.get().getObjId())
374
- return
375
- # self._selectObject(e.node.pointer)
376
- # # Graph the first viewer available for this type of object
377
- # ViewerClass = findViewers(self._selected.getClassName(), DESKTOP_TKINTER)[0] #
378
- # viewer = ViewerClass(project=self.project)
379
- # viewer.visualize(self._selected)
380
-
381
- def _viewObject(self, objId):
382
- """ Call appropriate viewer for objId. """
383
- obj = self.project.getObject(int(objId))
384
- viewerClasses = self.domain.findViewers(obj.getClassName(),
385
- pwviewer.DESKTOP_TKINTER)
386
- if not viewerClasses:
387
- return # TODO: protest nicely
388
- viewer = viewerClasses[0](project=self.project, parent=self.windows)
389
- viewer.visualize(obj)
390
-
391
- def _openScipionLink(self, id):
392
- """ So far only protocols are coming through links"""
393
- self._openProtocolFormFromId(id)
394
-
395
- def _openProtocolFormFromId(self, protId):
396
-
397
- prot = self.project.getObject(int(protId))
398
- self._openProtocolForm(prot)
399
-
400
- def _openProtocolForm(self, prot):
401
- """Open the Protocol GUI Form given a Protocol instance"""
402
- title = pwutils.Message.TITLE_NAME_RUN + prot.getClassName()
403
- w = gui.form.FormWindow(title, prot, self._executeSaveProtocol,
404
- self.windows)
405
- w.adjustSize()
406
- w.show(center=True)
407
-
408
- def _executeSaveProtocol(self, prot, onlySave=False):
409
- if onlySave:
410
- self.project.saveProtocol(prot)
411
- msg = pwutils.Message.LABEL_SAVED_FORM
412
- # msg = "Protocol successfully saved."
413
- else:
414
- self.project.launchProtocol(prot)
415
- # Select the launched protocol to display its summary, methods..etc
416
- # self._selection.clear()
417
- # self._selection.append(prot.getObjId())
418
- # self._updateSelection()
419
- # clear lastStatus to force re-load the logs
420
- # self._lastStatus = None
421
- msg = ""
422
-
423
- return msg
424
-
425
- def _onRightClick(self, item=None, e=None):
426
- return []
427
- #
428
- # (pwutils.Message.LABEL_EDIT, self._editObject, pwutils.Icon.ACTION_EDIT),
429
- # ('Go to protocol', self._goToProtocol, pwutils.Icon.ACTION_SEARCH)
430
- # ]
431
-
432
- def _editObject(self, e=None):
433
- """Open the Edit GUI Form given an instance"""
434
- EditObjectDialog(self, pwutils.Message.TITLE_EDIT_OBJECT,
435
- self._selected, self.project.mapper)
436
-
437
- def _goToProtocol(self):
438
- """Switch to protocols view selecting the correspondent protocol"""
439
-
440
- def refreshData(self, e=None, initRefreshCounter=True):
441
- """ Refresh the status of displayed data.
442
- Params:
443
- e: Tk event input
444
- initRefreshCounter: if True the refresh counter will be set to 3 secs
445
- then only case when False is from _automaticRefreshData where the
446
- refresh time is doubled each time to avoid refreshing too often.
447
- """
448
- self._dataGraph = self.windows.project.getSourceGraph(True)
449
- self._updateDataTree()
450
- self._updateDataGraph()
451
-
452
- if initRefreshCounter:
453
- self.__autoRefreshCounter = 3 # start by 3 secs
454
- if self.__autoRefresh:
455
- self.dataTree.after_cancel(self.__autoRefresh)
456
- self.__autoRefresh = self.dataTree.after(
457
- self.__autoRefreshCounter*1000, self._automaticRefreshData)
458
-
459
- def _automaticRefreshData(self, e=None):
460
- """ Schedule automatic refresh increasing the time between refreshes.
461
- """
462
- self.refreshData(initRefreshCounter=False)
463
- secs = self.__autoRefreshCounter
464
- # double the number of seconds up to 30 min
465
- self.__autoRefreshCounter = min(2*secs, 1800)
466
- self.__autoRefresh = self.dataTree.after(secs*1000,
467
- self._automaticRefreshData)
468
-
469
-
470
- class DataTextBox(RoundedTextBox):
471
- def __init__(self, canvas, text, x, y, bgColor, textColor='black'):
472
- RoundedTextBox.__init__(self, canvas, text, x, y, bgColor, textColor)