1
|
|
|
""" |
2
|
|
|
Orange Canvas Configuration |
3
|
|
|
|
4
|
|
|
""" |
5
|
|
|
|
6
|
|
|
import os |
7
|
|
|
import sys |
8
|
|
|
import logging |
9
|
|
|
import pickle as pickle |
10
|
|
|
import itertools |
11
|
|
|
|
12
|
|
|
import pkg_resources |
13
|
|
|
|
14
|
|
|
from PyQt4.QtGui import ( |
|
|
|
|
15
|
|
|
QPainter, QFont, QFontMetrics, QColor, QPixmap, QIcon |
16
|
|
|
) |
17
|
|
|
|
18
|
|
|
from PyQt4.QtCore import Qt, QCoreApplication, QPoint, QRect |
|
|
|
|
19
|
|
|
|
20
|
|
|
from .utils.settings import Settings, config_slot |
21
|
|
|
|
22
|
|
|
# Import QSettings from qtcompat module (compatibility with PyQt < 4.8.3 |
23
|
|
|
from .utils.qtcompat import QSettings |
24
|
|
|
|
25
|
|
|
log = logging.getLogger(__name__) |
26
|
|
|
|
27
|
|
|
|
28
|
|
|
def init(): |
|
|
|
|
29
|
|
|
""" |
30
|
|
|
Initialize the QCoreApplication.organizationDomain, applicationName, |
31
|
|
|
applicationVersion and the default settings format. Will only run once. |
32
|
|
|
|
33
|
|
|
.. note:: This should not be run before QApplication has been initialized. |
34
|
|
|
Otherwise it can break Qt's plugin search paths. |
35
|
|
|
|
36
|
|
|
""" |
37
|
|
|
dist = pkg_resources.get_distribution("Orange") |
38
|
|
|
version = dist.version |
39
|
|
|
# Use only major.minor |
40
|
|
|
version = ".".join(version.split(".", 2)[:2]) |
41
|
|
|
|
42
|
|
|
QCoreApplication.setOrganizationDomain("biolab.si") |
43
|
|
|
QCoreApplication.setApplicationName("Orange Canvas") |
44
|
|
|
QCoreApplication.setApplicationVersion(version) |
45
|
|
|
QSettings.setDefaultFormat(QSettings.IniFormat) |
46
|
|
|
|
47
|
|
|
# Make it a null op. |
48
|
|
|
global init |
|
|
|
|
49
|
|
|
init = lambda: None |
50
|
|
|
|
51
|
|
|
rc = {} |
52
|
|
|
|
53
|
|
|
|
54
|
|
|
spec = \ |
55
|
|
|
[("startup/show-splash-screen", bool, True, |
56
|
|
|
"Show splash screen at startup"), |
57
|
|
|
|
58
|
|
|
("startup/show-welcome-screen", bool, True, |
59
|
|
|
"Show Welcome screen at startup"), |
60
|
|
|
|
61
|
|
|
("stylesheet", str, "orange", |
62
|
|
|
"QSS stylesheet to use"), |
63
|
|
|
|
64
|
|
|
("schemeinfo/show-at-new-scheme", bool, True, |
65
|
|
|
"Show Workflow Properties when creating a new Workflow"), |
66
|
|
|
|
67
|
|
|
("mainwindow/scheme-margins-enabled", bool, False, |
68
|
|
|
"Show margins around the workflow view"), |
69
|
|
|
|
70
|
|
|
("mainwindow/show-scheme-shadow", bool, True, |
71
|
|
|
"Show shadow around the workflow view"), |
72
|
|
|
|
73
|
|
|
("mainwindow/toolbox-dock-exclusive", bool, True, |
74
|
|
|
"Should the toolbox show only one expanded category at the time"), |
75
|
|
|
|
76
|
|
|
("mainwindow/toolbox-dock-floatable", bool, False, |
77
|
|
|
"Is the canvas toolbox floatable (detachable from the main window)"), |
78
|
|
|
|
79
|
|
|
("mainwindow/toolbox-dock-movable", bool, True, |
80
|
|
|
"Is the canvas toolbox movable (between left and right edge)"), |
81
|
|
|
|
82
|
|
|
("mainwindow/toolbox-dock-use-popover-menu", bool, True, |
83
|
|
|
"Use a popover menu to select a widget when clicking on a category " |
84
|
|
|
"button"), |
85
|
|
|
|
86
|
|
|
("mainwindow/number-of-recent-schemes", int, 15, |
87
|
|
|
"Number of recent workflows to keep in history"), |
88
|
|
|
|
89
|
|
|
("schemeedit/show-channel-names", bool, True, |
90
|
|
|
"Show channel names"), |
91
|
|
|
|
92
|
|
|
("schemeedit/show-link-state", bool, True, |
93
|
|
|
"Show link state hints."), |
94
|
|
|
|
95
|
|
|
("schemeedit/enable-node-animations", bool, True, |
96
|
|
|
"Enable node animations."), |
97
|
|
|
|
98
|
|
|
("schemeedit/freeze-on-load", bool, False, |
99
|
|
|
"Freeze signal propagation when loading a workflow."), |
100
|
|
|
|
101
|
|
|
("quickmenu/trigger-on-double-click", bool, True, |
102
|
|
|
"Show quick menu on double click."), |
103
|
|
|
|
104
|
|
|
("quickmenu/trigger-on-right-click", bool, True, |
105
|
|
|
"Show quick menu on right click."), |
106
|
|
|
|
107
|
|
|
("quickmenu/trigger-on-space-key", bool, True, |
108
|
|
|
"Show quick menu on space key press."), |
109
|
|
|
|
110
|
|
|
("quickmenu/trigger-on-any-key", bool, False, |
111
|
|
|
"Show quick menu on double click."), |
112
|
|
|
|
113
|
|
|
("logging/level", int, 1, "Logging level"), |
114
|
|
|
|
115
|
|
|
("logging/show-on-error", bool, True, "Show log window on error"), |
116
|
|
|
|
117
|
|
|
("logging/dockable", bool, True, "Allow log window to be docked"), |
118
|
|
|
|
119
|
|
|
("output/redirect-stderr", bool, True, |
120
|
|
|
"Redirect and display standard error output"), |
121
|
|
|
|
122
|
|
|
("output/redirect-stdout", bool, True, |
123
|
|
|
"Redirect and display standard output"), |
124
|
|
|
|
125
|
|
|
("output/stay-on-top", bool, True, ""), |
126
|
|
|
|
127
|
|
|
("output/show-on-error", bool, True, "Show output window on error"), |
128
|
|
|
|
129
|
|
|
("output/dockable", bool, True, "Allow output window to be docked"), |
130
|
|
|
|
131
|
|
|
("help/stay-on-top", bool, True, ""), |
132
|
|
|
|
133
|
|
|
("help/dockable", bool, True, "Allow help window to be docked"), |
134
|
|
|
|
135
|
|
|
("help/open-in-external-browser", bool, False, |
136
|
|
|
"Open help in an external browser") |
137
|
|
|
] |
138
|
|
|
|
139
|
|
|
spec = [config_slot(*t) for t in spec] |
140
|
|
|
|
141
|
|
|
|
142
|
|
|
def settings(): |
143
|
|
|
init() |
144
|
|
|
store = QSettings() |
145
|
|
|
settings = Settings(defaults=spec, store=store) |
|
|
|
|
146
|
|
|
return settings |
147
|
|
|
|
148
|
|
|
|
149
|
|
|
def data_dir(): |
150
|
|
|
"""Return the application data directory. If the directory path |
151
|
|
|
does not yet exists then create it. |
152
|
|
|
|
153
|
|
|
""" |
154
|
|
|
from Orange.misc import environ |
155
|
|
|
path = os.path.join(environ.data_dir(), "canvas") |
156
|
|
|
|
157
|
|
|
if not os.path.isdir(path): |
158
|
|
|
os.makedirs(path, exist_ok=True) |
159
|
|
|
return path |
160
|
|
|
|
161
|
|
|
|
162
|
|
|
def cache_dir(): |
163
|
|
|
"""Return the application cache directory. If the directory path |
164
|
|
|
does not yet exists then create it. |
165
|
|
|
|
166
|
|
|
""" |
167
|
|
|
from Orange.misc import environ |
168
|
|
|
path = os.path.join(environ.cache_dir(), "canvas") |
169
|
|
|
|
170
|
|
|
if not os.path.isdir(path): |
171
|
|
|
os.makedirs(path, exist_ok=True) |
172
|
|
|
return path |
173
|
|
|
|
174
|
|
|
|
175
|
|
|
def log_dir(): |
176
|
|
|
""" |
177
|
|
|
Return the application log directory. |
178
|
|
|
""" |
179
|
|
|
init() |
180
|
|
|
if sys.platform == "darwin": |
181
|
|
|
name = str(QCoreApplication.applicationName()) |
182
|
|
|
logdir = os.path.join(os.path.expanduser("~/Library/Logs"), name) |
183
|
|
|
else: |
184
|
|
|
logdir = data_dir() |
185
|
|
|
|
186
|
|
|
if not os.path.exists(logdir): |
187
|
|
|
os.makedirs(logdir) |
188
|
|
|
return logdir |
189
|
|
|
|
190
|
|
|
|
191
|
|
|
def widget_settings_dir(): |
192
|
|
|
""" |
193
|
|
|
Return the widget settings directory. |
194
|
|
|
""" |
195
|
|
|
from Orange.misc import environ |
196
|
|
|
return environ.widget_settings_dir() |
197
|
|
|
|
198
|
|
|
|
199
|
|
|
def open_config(): |
200
|
|
|
global rc |
|
|
|
|
201
|
|
|
app_dir = data_dir() |
202
|
|
|
filename = os.path.join(app_dir, "canvas-rc.pck") |
203
|
|
|
if os.path.exists(filename): |
204
|
|
|
with open(os.path.join(app_dir, "canvas-rc.pck"), "rb") as f: |
205
|
|
|
rc.update(pickle.load(f)) |
206
|
|
|
|
207
|
|
|
|
208
|
|
|
def save_config(): |
209
|
|
|
app_dir = data_dir() |
210
|
|
|
with open(os.path.join(app_dir, "canvas-rc.pck"), "wb") as f: |
211
|
|
|
pickle.dump(rc, f) |
212
|
|
|
|
213
|
|
|
|
214
|
|
|
def recent_schemes(): |
215
|
|
|
"""Return a list of recently accessed schemes. |
216
|
|
|
""" |
217
|
|
|
app_dir = data_dir() |
218
|
|
|
recent_filename = os.path.join(app_dir, "recent.pck") |
219
|
|
|
recent = [] |
220
|
|
|
if os.path.isdir(app_dir) and os.path.isfile(recent_filename): |
221
|
|
|
with open(recent_filename, "rb") as f: |
222
|
|
|
recent = pickle.load(f) |
223
|
|
|
|
224
|
|
|
# Filter out files not found on the file system |
225
|
|
|
recent = [(title, path) for title, path in recent \ |
226
|
|
|
if os.path.exists(path)] |
227
|
|
|
return recent |
228
|
|
|
|
229
|
|
|
|
230
|
|
|
def save_recent_scheme_list(scheme_list): |
231
|
|
|
"""Save the list of recently accessed schemes |
232
|
|
|
""" |
233
|
|
|
app_dir = data_dir() |
234
|
|
|
recent_filename = os.path.join(app_dir, "recent.pck") |
235
|
|
|
|
236
|
|
|
if os.path.isdir(app_dir): |
237
|
|
|
with open(recent_filename, "wb") as f: |
238
|
|
|
pickle.dump(scheme_list, f) |
239
|
|
|
|
240
|
|
|
|
241
|
|
|
WIDGETS_ENTRY = "orange.widgets" |
242
|
|
|
|
243
|
|
|
|
244
|
|
|
# This could also be achieved by declaring the entry point in |
245
|
|
|
# Orange's setup.py, but that would not guaranty this entry point |
246
|
|
|
# is the first in a list. |
247
|
|
|
|
248
|
|
|
def default_entry_point(): |
249
|
|
|
""" |
250
|
|
|
Return a default orange.widgets entry point for loading |
251
|
|
|
default Orange Widgets. |
252
|
|
|
|
253
|
|
|
""" |
254
|
|
|
dist = pkg_resources.get_distribution("Orange") |
255
|
|
|
ep = pkg_resources.EntryPoint("Orange Widgets", "Orange.widgets", |
256
|
|
|
dist=dist) |
257
|
|
|
return ep |
258
|
|
|
|
259
|
|
|
|
260
|
|
|
def widgets_entry_points(): |
261
|
|
|
""" |
262
|
|
|
Return an `EntryPoint` iterator for all 'orange.widget' entry |
263
|
|
|
points plus the default Orange Widgets. |
264
|
|
|
|
265
|
|
|
""" |
266
|
|
|
ep_iter = pkg_resources.iter_entry_points(WIDGETS_ENTRY) |
267
|
|
|
chain = [[default_entry_point()], |
268
|
|
|
ep_iter |
269
|
|
|
] |
270
|
|
|
return itertools.chain(*chain) |
271
|
|
|
|
272
|
|
|
#: Parameters for searching add-on packages in PyPi using xmlrpc api. |
273
|
|
|
ADDON_PYPI_SEARCH_SPEC = {"keywords": "orange3 add-on"} |
274
|
|
|
#: Entry points by which add-ons register with pkg_resources. |
275
|
|
|
ADDON_ENTRY = "orange3.addon" |
276
|
|
|
|
277
|
|
|
|
278
|
|
|
def splash_screen(): |
|
|
|
|
279
|
|
|
""" |
280
|
|
|
""" |
281
|
|
|
pm = QPixmap( |
282
|
|
|
pkg_resources.resource_filename( |
283
|
|
|
__name__, "icons/orange-splash-screen.png") |
284
|
|
|
) |
285
|
|
|
|
286
|
|
|
version = QCoreApplication.applicationVersion() |
287
|
|
|
size = 21 if len(version) < 5 else 16 |
288
|
|
|
font = QFont("Helvetica") |
289
|
|
|
font.setPixelSize(size) |
290
|
|
|
font.setBold(True) |
291
|
|
|
font.setItalic(True) |
292
|
|
|
font.setLetterSpacing(QFont.AbsoluteSpacing, 2) |
293
|
|
|
metrics = QFontMetrics(font) |
294
|
|
|
br = metrics.boundingRect(version).adjusted(-5, 0, 5, 0) |
295
|
|
|
br.moveCenter(QPoint(436, 224)) |
296
|
|
|
|
297
|
|
|
p = QPainter(pm) |
298
|
|
|
p.setRenderHint(QPainter.Antialiasing) |
299
|
|
|
p.setRenderHint(QPainter.TextAntialiasing) |
300
|
|
|
p.setFont(font) |
301
|
|
|
p.setPen(QColor("#231F20")) |
302
|
|
|
p.drawText(br, Qt.AlignCenter, version) |
303
|
|
|
p.end() |
304
|
|
|
return pm, QRect(88, 193, 200, 20) |
305
|
|
|
|
306
|
|
|
|
307
|
|
|
def application_icon(): |
308
|
|
|
""" |
309
|
|
|
Return the main application icon. |
310
|
|
|
""" |
311
|
|
|
path = pkg_resources.resource_filename( |
312
|
|
|
__name__, "icons/orange-canvas.svg" |
313
|
|
|
) |
314
|
|
|
return QIcon(path) |
315
|
|
|
|
316
|
|
|
|
This can be caused by one of the following:
1. Missing Dependencies
This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.
2. Missing __init__.py files
This error could also result from missing
__init__.py
files in your module folders. Make sure that you place one file in each sub-folder.