scipion-pyworkflow 3.10.6__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.
- pyworkflow/config.py +131 -67
- pyworkflow/constants.py +2 -1
- pyworkflow/plugin.py +93 -44
- pyworkflow/resources/showj/arrowDown.png +0 -0
- pyworkflow/resources/showj/arrowUp.png +0 -0
- pyworkflow/resources/showj/background_section.png +0 -0
- pyworkflow/resources/showj/colRowModeOff.png +0 -0
- pyworkflow/resources/showj/colRowModeOn.png +0 -0
- pyworkflow/resources/showj/delete.png +0 -0
- pyworkflow/resources/showj/doc_icon.png +0 -0
- pyworkflow/resources/showj/download_icon.png +0 -0
- pyworkflow/resources/showj/enabled_gallery.png +0 -0
- pyworkflow/resources/showj/galleryViewOff.png +0 -0
- pyworkflow/resources/showj/galleryViewOn.png +0 -0
- pyworkflow/resources/showj/goto.png +0 -0
- pyworkflow/resources/showj/menu.png +0 -0
- pyworkflow/resources/showj/separator.png +0 -0
- pyworkflow/resources/showj/tableViewOff.png +0 -0
- pyworkflow/resources/showj/tableViewOn.png +0 -0
- pyworkflow/resources/showj/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- pyworkflow/resources/showj/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- pyworkflow/resources/showj/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- pyworkflow/resources/showj/volumeOff.png +0 -0
- pyworkflow/resources/showj/volumeOn.png +0 -0
- pyworkflow/viewer.py +23 -1
- pyworkflowtests/protocols.py +1 -3
- {scipion_pyworkflow-3.10.6.dist-info → scipion_pyworkflow-3.11.0.dist-info}/METADATA +13 -27
- scipion_pyworkflow-3.11.0.dist-info/RECORD +71 -0
- {scipion_pyworkflow-3.10.6.dist-info → scipion_pyworkflow-3.11.0.dist-info}/WHEEL +1 -1
- pyworkflow/apps/__init__.py +0 -29
- pyworkflow/apps/pw_manager.py +0 -37
- pyworkflow/apps/pw_plot.py +0 -51
- pyworkflow/apps/pw_project.py +0 -113
- pyworkflow/apps/pw_protocol_list.py +0 -143
- pyworkflow/apps/pw_protocol_run.py +0 -51
- pyworkflow/apps/pw_run_tests.py +0 -267
- pyworkflow/apps/pw_schedule_run.py +0 -322
- pyworkflow/apps/pw_sleep.py +0 -37
- pyworkflow/apps/pw_sync_data.py +0 -439
- pyworkflow/apps/pw_viewer.py +0 -78
- pyworkflow/gui/__init__.py +0 -36
- pyworkflow/gui/browser.py +0 -726
- pyworkflow/gui/canvas.py +0 -1190
- pyworkflow/gui/dialog.py +0 -977
- pyworkflow/gui/form.py +0 -2637
- pyworkflow/gui/graph.py +0 -247
- pyworkflow/gui/graph_layout.py +0 -271
- pyworkflow/gui/gui.py +0 -566
- pyworkflow/gui/matplotlib_image.py +0 -233
- pyworkflow/gui/plotter.py +0 -247
- pyworkflow/gui/project/__init__.py +0 -25
- pyworkflow/gui/project/base.py +0 -192
- pyworkflow/gui/project/constants.py +0 -139
- pyworkflow/gui/project/labels.py +0 -205
- pyworkflow/gui/project/project.py +0 -492
- pyworkflow/gui/project/searchprotocol.py +0 -154
- pyworkflow/gui/project/searchrun.py +0 -181
- pyworkflow/gui/project/steps.py +0 -171
- pyworkflow/gui/project/utils.py +0 -332
- pyworkflow/gui/project/variables.py +0 -179
- pyworkflow/gui/project/viewdata.py +0 -472
- pyworkflow/gui/project/viewprojects.py +0 -510
- pyworkflow/gui/project/viewprotocols.py +0 -2093
- pyworkflow/gui/project/viewprotocols_extra.py +0 -559
- pyworkflow/gui/text.py +0 -771
- pyworkflow/gui/tooltip.py +0 -185
- pyworkflow/gui/tree.py +0 -684
- pyworkflow/gui/widgets.py +0 -307
- pyworkflow/mapper/__init__.py +0 -26
- pyworkflow/mapper/mapper.py +0 -222
- pyworkflow/mapper/sqlite.py +0 -1581
- pyworkflow/mapper/sqlite_db.py +0 -145
- pyworkflow/project/__init__.py +0 -31
- pyworkflow/project/config.py +0 -454
- pyworkflow/project/manager.py +0 -180
- pyworkflow/project/project.py +0 -2007
- pyworkflow/protocol/__init__.py +0 -38
- pyworkflow/protocol/bibtex.py +0 -48
- pyworkflow/protocol/constants.py +0 -87
- pyworkflow/protocol/executor.py +0 -471
- pyworkflow/protocol/hosts.py +0 -314
- pyworkflow/protocol/launch.py +0 -270
- pyworkflow/protocol/package.py +0 -42
- pyworkflow/protocol/params.py +0 -741
- pyworkflow/protocol/protocol.py +0 -2641
- pyworkflow/tests/__init__.py +0 -29
- pyworkflow/tests/test_utils.py +0 -25
- pyworkflow/tests/tests.py +0 -341
- pyworkflow/utils/__init__.py +0 -38
- pyworkflow/utils/dataset.py +0 -414
- pyworkflow/utils/echo.py +0 -104
- pyworkflow/utils/graph.py +0 -169
- pyworkflow/utils/log.py +0 -284
- pyworkflow/utils/path.py +0 -528
- pyworkflow/utils/process.py +0 -153
- pyworkflow/utils/profiler.py +0 -92
- pyworkflow/utils/progressbar.py +0 -154
- pyworkflow/utils/properties.py +0 -631
- pyworkflow/utils/reflection.py +0 -129
- pyworkflow/utils/utils.py +0 -879
- pyworkflow/utils/which.py +0 -229
- pyworkflow/webservices/__init__.py +0 -8
- pyworkflow/webservices/config.py +0 -11
- pyworkflow/webservices/notifier.py +0 -162
- pyworkflow/webservices/repository.py +0 -59
- pyworkflow/webservices/workflowhub.py +0 -74
- pyworkflowtests/tests/__init__.py +0 -0
- pyworkflowtests/tests/test_canvas.py +0 -72
- pyworkflowtests/tests/test_domain.py +0 -45
- pyworkflowtests/tests/test_logs.py +0 -74
- pyworkflowtests/tests/test_mappers.py +0 -392
- pyworkflowtests/tests/test_object.py +0 -507
- pyworkflowtests/tests/test_project.py +0 -42
- pyworkflowtests/tests/test_protocol_execution.py +0 -142
- pyworkflowtests/tests/test_protocol_export.py +0 -78
- pyworkflowtests/tests/test_protocol_output.py +0 -158
- pyworkflowtests/tests/test_streaming.py +0 -47
- pyworkflowtests/tests/test_utils.py +0 -210
- scipion_pyworkflow-3.10.6.dist-info/RECORD +0 -140
- scipion_pyworkflow-3.10.6.dist-info/dependency_links.txt +0 -1
- {scipion_pyworkflow-3.10.6.dist-info → scipion_pyworkflow-3.11.0.dist-info}/entry_points.txt +0 -0
- {scipion_pyworkflow-3.10.6.dist-info → scipion_pyworkflow-3.11.0.dist-info}/licenses/LICENSE.txt +0 -0
- {scipion_pyworkflow-3.10.6.dist-info → scipion_pyworkflow-3.11.0.dist-info}/top_level.txt +0 -0
@@ -1,510 +0,0 @@
|
|
1
|
-
# **************************************************************************
|
2
|
-
# *
|
3
|
-
# * Authors: J.M. De la Rosa Trevin (delarosatrevin@scilifelab.se) [1]
|
4
|
-
# *
|
5
|
-
# * [1] SciLifeLab, Stockholm University
|
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, see <https://www.gnu.org/licenses/>.
|
19
|
-
# *
|
20
|
-
# * All comments concerning this program package may be sent to the
|
21
|
-
# * e-mail address 'scipion@cnb.csic.es'
|
22
|
-
# *
|
23
|
-
# **************************************************************************
|
24
|
-
import datetime
|
25
|
-
import logging
|
26
|
-
|
27
|
-
REFRESH_WAIT_SEC = 60
|
28
|
-
logger = logging.getLogger(__name__)
|
29
|
-
|
30
|
-
import os
|
31
|
-
import tkinter as tk
|
32
|
-
import tkinter.font as tkFont
|
33
|
-
|
34
|
-
import pyworkflow as pw
|
35
|
-
from pyworkflow.project import Project
|
36
|
-
from pyworkflow.utils.utils import prettyDate, prettyTime
|
37
|
-
from pyworkflow.utils.path import getHomePath
|
38
|
-
|
39
|
-
from pyworkflow.project import Manager
|
40
|
-
from pyworkflow.gui.text import TaggedText
|
41
|
-
from pyworkflow.gui.dialog import askString, askYesNo, showError
|
42
|
-
|
43
|
-
from pyworkflow.gui import Message, Window, cfgEntryBgColor, ToolTip
|
44
|
-
from pyworkflow.gui.browser import FileBrowserWindow
|
45
|
-
from pyworkflow.gui.widgets import IconButton, HotButton, Button
|
46
|
-
from pyworkflow.utils.properties import Icon
|
47
|
-
|
48
|
-
|
49
|
-
class ProjectsView(tk.Frame):
|
50
|
-
_PROJ_CONTAINER = "projectsframe"
|
51
|
-
|
52
|
-
def __init__(self, parent, windows, **args):
|
53
|
-
tk.Frame.__init__(self, parent, bg=pw.Config.SCIPION_BG_COLOR, **args)
|
54
|
-
self.windows = windows
|
55
|
-
self.manager = windows.manager
|
56
|
-
self.root = windows.root
|
57
|
-
self.lastLoad = None
|
58
|
-
|
59
|
-
# Bind to root "focus in"
|
60
|
-
self.root.bind("<FocusIn>", self._onWindowFocusIn)
|
61
|
-
smallSize = pw.Config.SCIPION_FONT_SIZE - 2
|
62
|
-
fontName = pw.Config.SCIPION_FONT_NAME
|
63
|
-
|
64
|
-
self.projNameFont = tkFont.Font(size=pw.Config.SCIPION_FONT_SIZE+2, family=fontName,
|
65
|
-
weight='bold')
|
66
|
-
self.projDateFont = tkFont.Font(size=smallSize, family=fontName)
|
67
|
-
self.projDelFont = tkFont.Font(size=smallSize, family=fontName,
|
68
|
-
weight='bold')
|
69
|
-
self.manager = Manager()
|
70
|
-
|
71
|
-
self.filter = tk.StringVar()
|
72
|
-
self.filterBox = None
|
73
|
-
self.addActionsFrame()
|
74
|
-
|
75
|
-
self.columnconfigure(0, weight=1)
|
76
|
-
self.rowconfigure(1, weight=1)
|
77
|
-
text = TaggedText(self, width=40, height=15, bd=0, bg=pw.Config.SCIPION_BG_COLOR)
|
78
|
-
text.grid(row=1, columnspan=2, column=0, sticky='news')
|
79
|
-
text.setReadOnly(True)
|
80
|
-
self.text = text
|
81
|
-
self.filterBox.focus_set()
|
82
|
-
|
83
|
-
# Content load happens automatically _onWindowFocusIn
|
84
|
-
|
85
|
-
def _onWindowFocusIn(self, event):
|
86
|
-
""" Refresh on windows get focus """
|
87
|
-
if event.widget == self.root:
|
88
|
-
# Get the delta from the last time refreshed
|
89
|
-
delta = REFRESH_WAIT_SEC if self.lastLoad is None else (datetime.datetime.now() - self.lastLoad).seconds
|
90
|
-
if delta >= REFRESH_WAIT_SEC:
|
91
|
-
self.createProjectList()
|
92
|
-
|
93
|
-
def addActionsFrame(self):
|
94
|
-
""" Add the "toolbar" for actions like create project, import
|
95
|
-
project or filter"""
|
96
|
-
# Add the create project button
|
97
|
-
bg = pw.Config.SCIPION_BG_COLOR
|
98
|
-
btnFrame = tk.Frame(self, bg=bg)
|
99
|
-
btn = HotButton(btnFrame, text=Message.LABEL_CREATE_PROJECT,
|
100
|
-
font=self.projNameFont,
|
101
|
-
command=self._onCreateProject)
|
102
|
-
btn.grid(row=0, column=0, sticky='nw', padx=10, pady=10)
|
103
|
-
# Add the Import project button
|
104
|
-
btn = Button(btnFrame, text=Message.LABEL_IMPORT_PROJECT,
|
105
|
-
font=self.projNameFont,
|
106
|
-
command=self._onImportProject)
|
107
|
-
btn.grid(row=0, column=1, sticky='nw', padx=10, pady=10)
|
108
|
-
btnFrame.grid(row=0, column=0, sticky='nw')
|
109
|
-
|
110
|
-
# Add a filter box
|
111
|
-
# Add the Import project button
|
112
|
-
btn = tk.Label(btnFrame, bg=bg, text="Filter:", font=self.projNameFont)
|
113
|
-
btn.grid(row=0, column=2, sticky='nse', padx=10, pady=10)
|
114
|
-
self.filterBox = tk.Entry(btnFrame, font=self.projNameFont, textvariable=self.filter)
|
115
|
-
self.filterBox.grid(row=0, column=3, sticky='ne', padx=10, pady=12)
|
116
|
-
self.filterBox.bind('<Return>', self._onFilter)
|
117
|
-
self.filterBox.bind('<KP_Enter>', self._onFilter)
|
118
|
-
self.filterBox.bind("<F5>", self.createProjectList)
|
119
|
-
ToolTip(self.filterBox, "Return/enter to filter. F5 to refresh the list")
|
120
|
-
|
121
|
-
|
122
|
-
def createProjectList(self, event=None):
|
123
|
-
"""Load the list of projects"""
|
124
|
-
|
125
|
-
self.lastLoad = datetime.datetime.now()
|
126
|
-
r = 0
|
127
|
-
text = self.text
|
128
|
-
text.setReadOnly(False)
|
129
|
-
text.clear()
|
130
|
-
parent = tk.Frame(text, bg=pw.Config.SCIPION_BG_COLOR, name=self._PROJ_CONTAINER)
|
131
|
-
parent.columnconfigure(0, weight=1)
|
132
|
-
colors = [pw.Config.SCIPION_BG_COLOR, '#EAEBFF']
|
133
|
-
for i, p in enumerate(self.manager.listProjects()):
|
134
|
-
try:
|
135
|
-
# Add creation time to project info
|
136
|
-
# Add if it's a link
|
137
|
-
p.index = "index%s" % i
|
138
|
-
|
139
|
-
# Consider the filter
|
140
|
-
if not self._doesProjectMatchFilter(p):
|
141
|
-
continue
|
142
|
-
|
143
|
-
frame = self.createProjectLabel(parent, p, color=colors[i % 2])
|
144
|
-
frame.grid(row=r, column=0, padx=10, pady=5, sticky='new')
|
145
|
-
r += 1
|
146
|
-
|
147
|
-
except Exception as ex:
|
148
|
-
logger.error("Couldn't load project %s" % p.getName(), exc_info=True)
|
149
|
-
|
150
|
-
text.window_create(tk.INSERT, window=parent)
|
151
|
-
text.bindWidget(parent)
|
152
|
-
text.setReadOnly(True)
|
153
|
-
|
154
|
-
def createProjectLabel(self, parent, projInfo, color):
|
155
|
-
frame = tk.Frame(parent, bg=color, name=projInfo.index)
|
156
|
-
# ROW1
|
157
|
-
# Project name
|
158
|
-
label = tk.Label(frame, text=projInfo.projName, anchor='nw', bg=color,
|
159
|
-
justify=tk.LEFT, font=self.projNameFont, cursor='hand1', width=50)
|
160
|
-
label.grid(row=0, column=0, padx=2, pady=2, sticky='nw')
|
161
|
-
label.bind('<Button-1>', lambda e: self.openProject(projInfo.projName))
|
162
|
-
|
163
|
-
# ROW2
|
164
|
-
# Timestamp line
|
165
|
-
dateMsg = '%s%s %s%s' % (Message.LABEL_MODIFIED, prettyDate(projInfo.mTime),
|
166
|
-
Message.LABEL_CREATED, prettyTime(projInfo.cTime, time=False))
|
167
|
-
dateLabel = tk.Label(frame, text=dateMsg, font=self.projDateFont, bg=color)
|
168
|
-
dateLabel.grid(row=1, column=0, sticky='nw')
|
169
|
-
# Delete action
|
170
|
-
delLabel = tk.Label(frame, text=Message.LABEL_DELETE_PROJECT, font=self.projDelFont, bg=color, cursor='hand1')
|
171
|
-
delLabel.grid(row=1, column=1, padx=10)
|
172
|
-
delLabel.bind('<Button-1>', lambda e: self.deleteProject(projInfo))
|
173
|
-
# Rename action
|
174
|
-
mvLabel = tk.Label(frame, text=Message.LABEL_RENAME_PROJECT, font=self.projDelFont, bg=color, cursor='hand1')
|
175
|
-
mvLabel.grid(row=1, column=2)
|
176
|
-
mvLabel.bind('<Button-1>', lambda e: self.renameProject(projInfo.projName))
|
177
|
-
|
178
|
-
# ROW3
|
179
|
-
if projInfo.isLink():
|
180
|
-
linkMsg = 'link --> ' + projInfo.realPath()
|
181
|
-
lblLink = tk.Label(frame, text=linkMsg, font=self.projDateFont, bg=color, fg='grey', justify=tk.LEFT)
|
182
|
-
lblLink.grid(row=2, column=0, columnspan=3, sticky='w')
|
183
|
-
|
184
|
-
return frame
|
185
|
-
|
186
|
-
def createNewProject(self, projName, projLocation):
|
187
|
-
proj = self.manager.createProject(projName, location=projLocation)
|
188
|
-
self.createProjectList()
|
189
|
-
self.openProject(proj.getShortName())
|
190
|
-
|
191
|
-
def _onCreateProject(self, e=None):
|
192
|
-
projWindow = ProjectCreateWindow("Create project", self)
|
193
|
-
projWindow.show()
|
194
|
-
|
195
|
-
def _onImportProject(self, e=None):
|
196
|
-
importProjWindow = ProjectImportWindow("Import project", self)
|
197
|
-
importProjWindow.show()
|
198
|
-
|
199
|
-
def _onFilter(self, e=None):
|
200
|
-
self.createProjectList()
|
201
|
-
|
202
|
-
def _setFocusToList(self, e=None):
|
203
|
-
self.text.focus_set()
|
204
|
-
|
205
|
-
def _doesProjectMatchFilter(self, project):
|
206
|
-
""" Returns true if the project matches the filter"""
|
207
|
-
# Lets' use the name anc creation date for now:
|
208
|
-
searchString = "~".join([project.getName().lower(),
|
209
|
-
prettyDate(project.mTime),
|
210
|
-
prettyTime(project.cTime, time=False)])
|
211
|
-
|
212
|
-
return self.filter.get().lower() in searchString
|
213
|
-
|
214
|
-
def importProject(self, projLocation, copyFiles, projName, searchLocation):
|
215
|
-
|
216
|
-
self.manager.importProject(projLocation, copyFiles, projName, searchLocation)
|
217
|
-
self.createProjectList()
|
218
|
-
self.openProject(projName)
|
219
|
-
|
220
|
-
def openProject(self, projName):
|
221
|
-
from subprocess import Popen
|
222
|
-
script = pw.join(pw.APPS, 'pw_project.py')
|
223
|
-
Popen([pw.PYTHON, script, projName])
|
224
|
-
|
225
|
-
def deleteProject(self, projInfo):
|
226
|
-
|
227
|
-
projName = projInfo.projName
|
228
|
-
|
229
|
-
if askYesNo(Message.TITLE_DELETE_PROJECT,
|
230
|
-
"Project *%s*. " % projName + Message.MESSAGE_DELETE_PROJECT, self.root):
|
231
|
-
|
232
|
-
logger.info("User agreed to delete project %s" % projName)
|
233
|
-
self.manager.deleteProject(projName)
|
234
|
-
|
235
|
-
#Delete the frame
|
236
|
-
self.text.children[self._PROJ_CONTAINER].children[projInfo.index].grid_forget()
|
237
|
-
|
238
|
-
|
239
|
-
def renameProject(self, projName):
|
240
|
-
newName = askString("Rename project %s" % projName, "Enter new name:", self.root)
|
241
|
-
if not newName or newName == projName:
|
242
|
-
return
|
243
|
-
if self.manager.hasProject(newName):
|
244
|
-
showError("Rename cancelled",
|
245
|
-
"Project name already exists: %s" % newName, self.root)
|
246
|
-
return
|
247
|
-
self.manager.renameProject(projName, newName)
|
248
|
-
self.createProjectList()
|
249
|
-
|
250
|
-
|
251
|
-
class ProjectCreateWindow(Window):
|
252
|
-
""" Windows to create a project. """
|
253
|
-
|
254
|
-
def __init__(self, title, parent=None, weight=True, minsize=(400, 110),
|
255
|
-
icon=Icon.SCIPION_ICON, **args):
|
256
|
-
"""
|
257
|
-
We assume the parent should be of ProjectsView
|
258
|
-
"""
|
259
|
-
Window.__init__(self, title, parent.windows, weight=weight,
|
260
|
-
icon=icon, minsize=minsize, enableQueue=True)
|
261
|
-
self.root['background'] = pw.Config.SCIPION_BG_COLOR
|
262
|
-
|
263
|
-
self.parent = parent
|
264
|
-
self.projectsPath = self.parent.manager.PROJECTS
|
265
|
-
self.projName = tk.StringVar()
|
266
|
-
self.projName.set('')
|
267
|
-
self.projLocation = tk.StringVar()
|
268
|
-
self.projLocation.set(self.projectsPath)
|
269
|
-
|
270
|
-
content = tk.Frame(self.root)
|
271
|
-
content.columnconfigure(0, weight=1)
|
272
|
-
content.columnconfigure(1, weight=3)
|
273
|
-
content.config(bg=pw.Config.SCIPION_BG_COLOR)
|
274
|
-
content.grid(row=0, column=0, sticky='news', padx=5, pady=5)
|
275
|
-
|
276
|
-
# Info line
|
277
|
-
labelInfo = tk.Label(content, text="Spaces will be replaced by underscores!", bg=pw.Config.SCIPION_BG_COLOR, bd=0)
|
278
|
-
labelInfo.grid(row=0, sticky=tk.W, padx=5, pady=5)
|
279
|
-
# Project name line
|
280
|
-
labelName = tk.Label(content, text=Message.LABEL_PROJECT + ' name', bg=pw.Config.SCIPION_BG_COLOR, bd=0)
|
281
|
-
labelName.grid(row=1, sticky=tk.W, padx=5, pady=5)
|
282
|
-
entryName = tk.Entry(content, bg=cfgEntryBgColor, width=20, textvariable=self.projName)
|
283
|
-
entryName.grid(row=1, column=1, columnspan=2, sticky=tk.EW, padx=5, pady=5)
|
284
|
-
entryName.bind("<Return>", self._create)
|
285
|
-
entryName.bind("<KP_Enter>", self._create)
|
286
|
-
# Project location line
|
287
|
-
labelLocation = tk.Label(content, text=Message.LABEL_PROJECT + ' location', bg=pw.Config.SCIPION_BG_COLOR, bd=0)
|
288
|
-
labelLocation.grid(row=2, column=0, sticky='nw', padx=5, pady=5)
|
289
|
-
|
290
|
-
self.entryBrowse = tk.Entry(content, bg=cfgEntryBgColor, width=40, textvariable=self.projLocation)
|
291
|
-
self.entryBrowse.grid(row=2, column=1, sticky='nw', padx=5, pady=5)
|
292
|
-
self.btnBrowse = IconButton(content, 'Browse', Icon.ACTION_BROWSE,
|
293
|
-
highlightthickness=0, command=self._browsePath)
|
294
|
-
self.btnBrowse.grid(row=2, column=2, sticky='e', padx=5, pady=5)
|
295
|
-
|
296
|
-
self.initial_focus = entryName
|
297
|
-
self.initial_focus.focus()
|
298
|
-
|
299
|
-
btnFrame = tk.Frame(content)
|
300
|
-
btnFrame.columnconfigure(0, weight=1)
|
301
|
-
btnFrame.grid(row=3, column=0, sticky='sew', padx=5, pady=(0, 5), columnspan=2)
|
302
|
-
btnFrame.config(bg=pw.Config.SCIPION_BG_COLOR)
|
303
|
-
|
304
|
-
# Create buttons
|
305
|
-
btnCreate = HotButton(btnFrame, 'Create', Icon.BUTTON_SELECT, command=self._create)
|
306
|
-
btnCreate.grid(row=0, column=0, sticky='e', padx=5, pady=5)
|
307
|
-
btnCancel = Button(btnFrame, 'Cancel', Icon.BUTTON_CANCEL, command=self.close)
|
308
|
-
btnCancel.grid(row=0, column=1, sticky='e', padx=5, pady=5)
|
309
|
-
|
310
|
-
def _browsePath(self, e=None):
|
311
|
-
def onSelect(obj):
|
312
|
-
self.projLocation.set(obj.getPath())
|
313
|
-
|
314
|
-
v = self.projLocation.get().strip()
|
315
|
-
path = None
|
316
|
-
if v:
|
317
|
-
v = os.path.dirname(v)
|
318
|
-
if os.path.exists(v):
|
319
|
-
path = v
|
320
|
-
if not path:
|
321
|
-
path = self.projectsPath
|
322
|
-
|
323
|
-
browser = FileBrowserWindow("Browsing", self, path=path, onSelect=onSelect, onlyFolders=True)
|
324
|
-
browser.show()
|
325
|
-
|
326
|
-
def _create(self, e=None):
|
327
|
-
projName = self.projName.get().strip()
|
328
|
-
projLocation = self.projLocation.get().strip()
|
329
|
-
|
330
|
-
# Validate that project name is not empty
|
331
|
-
if not projName:
|
332
|
-
showError("Validation error", "Project name is empty", self.root)
|
333
|
-
# Validate that project location is not empty
|
334
|
-
elif not projLocation:
|
335
|
-
showError("Validation error", "Project location is empty", self.root)
|
336
|
-
# Validate that project location exists
|
337
|
-
elif not os.path.exists(projLocation):
|
338
|
-
showError("Validation error", "Project location does not exist", self.root)
|
339
|
-
# Validate that project location is a directory
|
340
|
-
elif not os.path.isdir(projLocation):
|
341
|
-
showError("Validation error", "Project location is not a directory", self.root)
|
342
|
-
# Validate that project path (location + name) does not exists
|
343
|
-
elif os.path.exists(os.path.join(projLocation, projName)):
|
344
|
-
showError("Validation error", "Project path already exists", self.root)
|
345
|
-
else:
|
346
|
-
self.parent.createNewProject(projName, projLocation)
|
347
|
-
self.close()
|
348
|
-
|
349
|
-
|
350
|
-
class ProjectImportWindow(Window):
|
351
|
-
""" Windows to import a project. """
|
352
|
-
|
353
|
-
def __init__(self, title, parent=None, weight=True, minsize=(400, 150),
|
354
|
-
icon=Icon.SCIPION_ICON, **args):
|
355
|
-
"""
|
356
|
-
We assume the parent should be ProjectsView
|
357
|
-
"""
|
358
|
-
Window.__init__(self, title, parent.windows, weight=weight,
|
359
|
-
icon=icon, minsize=minsize, enableQueue=True)
|
360
|
-
self.root['background'] = pw.Config.SCIPION_BG_COLOR
|
361
|
-
self.parent = parent
|
362
|
-
# Dirty hack, need to add a slash for the explorer to pick up the right default path.
|
363
|
-
self.projectsPath = getHomePath() + "/"
|
364
|
-
self.projLocation = tk.StringVar()
|
365
|
-
self.projLocation.set(self.projectsPath)
|
366
|
-
|
367
|
-
self.projName = tk.StringVar()
|
368
|
-
self.projName.set('')
|
369
|
-
|
370
|
-
self.searchLocation = tk.StringVar()
|
371
|
-
self.searchLocation.set('')
|
372
|
-
|
373
|
-
content = tk.Frame(self.root)
|
374
|
-
content.columnconfigure(0, weight=1)
|
375
|
-
content.columnconfigure(1, weight=1)
|
376
|
-
content.config(bg=pw.Config.SCIPION_BG_COLOR)
|
377
|
-
content.grid(row=0, column=0, sticky='news',
|
378
|
-
padx=5, pady=5)
|
379
|
-
|
380
|
-
# Path explorer
|
381
|
-
labelProjectLocation = tk.Label(content, text="Project location", bg=pw.Config.SCIPION_BG_COLOR, bd=0)
|
382
|
-
labelProjectLocation.grid(row=0, column=0, sticky='nw', padx=5, pady=5)
|
383
|
-
# it seems tk.Entry does not uses default font...grrrr!!
|
384
|
-
self.entryBrowse = tk.Entry(content, bg=cfgEntryBgColor, width=40,
|
385
|
-
textvariable=self.projLocation, font=self.font)
|
386
|
-
self.entryBrowse.grid(row=0, column=1, sticky='nw', padx=5, pady=5)
|
387
|
-
self.btnBrowse = IconButton(content, 'Browse', Icon.ACTION_BROWSE, highlightthickness=0,
|
388
|
-
command=self._browseProjectLocation)
|
389
|
-
self.btnBrowse.grid(row=0, column=2, sticky='e', padx=5, pady=5)
|
390
|
-
|
391
|
-
# Copy files check
|
392
|
-
labelCheck = tk.Label(content, text="Copy project", bg=pw.Config.SCIPION_BG_COLOR, borderwidth=0)
|
393
|
-
labelCheck.grid(row=1, column=0, sticky='nw', padx=5, pady=5)
|
394
|
-
|
395
|
-
self.tkCheckVar = tk.IntVar()
|
396
|
-
btnCheck = tk.Checkbutton(content, variable=self.tkCheckVar, highlightthickness=0, activebackground=pw.Config.SCIPION_BG_COLOR,
|
397
|
-
bg=pw.Config.SCIPION_BG_COLOR, bd=0)
|
398
|
-
btnCheck.grid(row=1, column=1, sticky='nw', padx=0, pady=5)
|
399
|
-
|
400
|
-
btnCopyHelp = IconButton(content, Message.LABEL_BUTTON_HELP, Icon.ACTION_HELP, highlightthickness=0,
|
401
|
-
command=lambda: self.showInfo(
|
402
|
-
'If checked, \"Project location\" will be copied. Otherwise a soft link to it will be created.'))
|
403
|
-
btnCopyHelp.grid(row=1, column=3, sticky='e', padx=2, pady=2)
|
404
|
-
|
405
|
-
# Project name
|
406
|
-
labelName = tk.Label(content, text='Project name (Optional)', bg=pw.Config.SCIPION_BG_COLOR, bd=0)
|
407
|
-
labelName.grid(row=2, column=0, sticky='nw', padx=5, pady=5)
|
408
|
-
entryName = tk.Entry(content, bg='white', width=20, textvariable=self.projName, font=self.font)
|
409
|
-
entryName.grid(row=2, column=1, sticky='nw', padx=5, pady=5)
|
410
|
-
|
411
|
-
# Path to search for raw data and restore broken links.
|
412
|
-
labelSearchLocation = tk.Label(content, text="Raw files location (Optional)", bg=pw.Config.SCIPION_BG_COLOR, bd=0)
|
413
|
-
labelSearchLocation.grid(row=3, column=0, sticky='nw', padx=5, pady=5)
|
414
|
-
|
415
|
-
self.entrySearchLocation = tk.Entry(content, bg='white', width=40,
|
416
|
-
textvariable=self.searchLocation, font=self.font)
|
417
|
-
self.entrySearchLocation.grid(row=3, column=1, sticky='nw', padx=5, pady=5)
|
418
|
-
self.btnSearch = IconButton(content, 'Browse', Icon.ACTION_BROWSE,
|
419
|
-
highlightthickness=0, command=self._browseSearchLocation)
|
420
|
-
self.btnSearch.grid(row=3, column=2, sticky='e', padx=5, pady=5)
|
421
|
-
btnSearchHelp = IconButton(content, Message.LABEL_BUTTON_HELP, Icon.ACTION_HELP, highlightthickness=0,
|
422
|
-
command=lambda: self.showInfo(
|
423
|
-
'Optional: Folder where raw files, binaries (movies, micrographs,..) can be found. Used to repair broken links.'))
|
424
|
-
btnSearchHelp.grid(row=3, column=3, sticky='e', padx=2, pady=2)
|
425
|
-
|
426
|
-
self.initial_focus = entryName
|
427
|
-
self.initial_focus.focus()
|
428
|
-
btnCheck.select()
|
429
|
-
|
430
|
-
btnFrame = tk.Frame(content)
|
431
|
-
btnFrame.columnconfigure(0, weight=1)
|
432
|
-
btnFrame.grid(row=4, column=0, sticky='sew', padx=5, pady=(0, 5), columnspan=2)
|
433
|
-
btnFrame.config(bg=pw.Config.SCIPION_BG_COLOR)
|
434
|
-
|
435
|
-
# Create buttons
|
436
|
-
btnSelect = HotButton(btnFrame, 'Import', Icon.BUTTON_SELECT, command=self._select)
|
437
|
-
btnSelect.grid(row=0, column=0, sticky='e', padx=5, pady=5)
|
438
|
-
btnCancel = Button(btnFrame, 'Cancel', Icon.BUTTON_CANCEL, command=self.close)
|
439
|
-
btnCancel.grid(row=0, column=1, sticky='e', padx=5, pady=5)
|
440
|
-
|
441
|
-
def _browseProjectLocation(self, e=None):
|
442
|
-
self._browsePath(self.projLocation)
|
443
|
-
|
444
|
-
def _browseSearchLocation(self, e=None):
|
445
|
-
self._browsePath(self.searchLocation)
|
446
|
-
|
447
|
-
def _browsePath(self, location):
|
448
|
-
def onSelect(obj):
|
449
|
-
location.set(obj.getPath())
|
450
|
-
|
451
|
-
v = location.get().strip()
|
452
|
-
path = None
|
453
|
-
if v:
|
454
|
-
v = os.path.dirname(v)
|
455
|
-
if os.path.exists(v):
|
456
|
-
path = v
|
457
|
-
if not path:
|
458
|
-
path = self.projectsPath
|
459
|
-
|
460
|
-
browser = FileBrowserWindow("Browsing",
|
461
|
-
self, path=path,
|
462
|
-
onSelect=onSelect,
|
463
|
-
onlyFolders=True)
|
464
|
-
browser.show()
|
465
|
-
|
466
|
-
def _select(self):
|
467
|
-
projName = self.projName.get().strip()
|
468
|
-
projLocation = self.projLocation.get().strip()
|
469
|
-
copyFiles = self.tkCheckVar.get() != 0
|
470
|
-
searchLocation = self.searchLocation.get().strip()
|
471
|
-
manager = Manager()
|
472
|
-
|
473
|
-
# If project name is empty we will use the same name as the source
|
474
|
-
if not projName:
|
475
|
-
projName = os.path.basename(projLocation)
|
476
|
-
|
477
|
-
errorMessage = ''
|
478
|
-
|
479
|
-
# Validate that project location is not empty
|
480
|
-
if not projLocation:
|
481
|
-
errorMessage = "Project location is empty\n"
|
482
|
-
|
483
|
-
# Validate that project location exists
|
484
|
-
elif not os.path.exists(projLocation):
|
485
|
-
errorMessage += "Project location does not exist\n"
|
486
|
-
|
487
|
-
# Validate that project location is a directory
|
488
|
-
elif not os.path.isdir(projLocation):
|
489
|
-
errorMessage += "Project location is not a directory\n"
|
490
|
-
# Validate that the project location is a scipion project folder
|
491
|
-
elif not os.path.exists(os.path.join(projLocation, Project.getDbName())):
|
492
|
-
errorMessage += "Project location doesn't look like a scipion folder\n"
|
493
|
-
|
494
|
-
# Validate that there isn't already a project with the same name
|
495
|
-
if manager.hasProject(projName):
|
496
|
-
errorMessage += "Project [%s] already exists\n" % projName
|
497
|
-
|
498
|
-
# Validate that search location exists
|
499
|
-
if searchLocation:
|
500
|
-
if not os.path.exists(searchLocation):
|
501
|
-
errorMessage += "Raw files location does not exist\n"
|
502
|
-
# Validate that search location is a directory
|
503
|
-
elif not os.path.isdir(searchLocation):
|
504
|
-
errorMessage += "Raw files location is not a directory\n"
|
505
|
-
|
506
|
-
if errorMessage:
|
507
|
-
showError("Validation error", errorMessage, self.root)
|
508
|
-
else:
|
509
|
-
self.parent.importProject(projLocation, copyFiles, projName, searchLocation)
|
510
|
-
self.close()
|