Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/contributed/sumopy/agilepy/lib_wx/processdialog.py
169689 views
1
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
2
# Copyright (C) 2016-2025 German Aerospace Center (DLR) and others.
3
# SUMOPy module
4
# Copyright (C) 2012-2021 University of Bologna - DICAM
5
# This program and the accompanying materials are made available under the
6
# terms of the Eclipse Public License 2.0 which is available at
7
# https://www.eclipse.org/legal/epl-2.0/
8
# This Source Code may also be made available under the following Secondary
9
# Licenses when the conditions for such availability set forth in the Eclipse
10
# Public License 2.0 are satisfied: GNU General Public License, version 2
11
# or later which is available at
12
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
13
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
14
15
# @file processdialog.py
16
# @author Joerg Schweizer
17
# @date 2012
18
19
20
import wx
21
import os
22
import objpanel
23
from wxmisc import AgileStatusbar
24
25
26
class ProcessDialogMixin:
27
28
def get_status(self):
29
return self.process.status
30
31
def clear_log(self):
32
self.get_logger().w('', 'message')
33
self.get_logger().w('', 'action')
34
35
def copy_options_to_results(self, results):
36
# TODO
37
pass
38
39
def on_save_options(self, event):
40
"""
41
Save current options to file.
42
"""
43
dlg = wx.FileDialog(
44
self, message="Save Options as ...",
45
# defaultDir=os.getcwd(),
46
# defaultFile="",
47
wildcard='Python obj files (*.obj)|*.obj|All files (*.*)|*.*',
48
style=wx.SAVE | wx.CHANGE_DIR
49
)
50
51
# This sets the default filter that the user will initially see. Otherwise,
52
# the first filter in the list will be used by default.
53
dlg.SetFilterIndex(0)
54
55
# Show the dialog and retrieve the user response. If it is the OK response,
56
# process the data.
57
if dlg.ShowModal() == wx.ID_OK:
58
filepath = dlg.GetPath()
59
self.process.save_options(filepath)
60
61
def on_load_options(self, event):
62
"""
63
Load previously saved options from file.
64
"""
65
66
dlg = wx.FileDialog(self, message="Open object",
67
# defaultDir=os.getcwd(),
68
# defaultFile="",
69
wildcard='Python obj files (*.obj)|*.obj|All files (*.*)|*.*',
70
style=wx.OPEN | wx.CHANGE_DIR
71
)
72
73
# Show the dialog and retrieve the user response. If it is the OK response,
74
# process the data.
75
if dlg.ShowModal() == wx.ID_OK:
76
# This returns a Python list of files that were selected.
77
filepath = dlg.GetPath()
78
self.process.load_options(filepath)
79
80
self.restore()
81
82
83
class ProcessDialog(ProcessDialogMixin, objpanel.ObjPanelDialog):
84
def __init__(self, parent,
85
process,
86
attrconfigs=None,
87
tables=None,
88
table=None, id=None, ids=None,
89
groupnames=None, show_groupnames=False,
90
title=None, size=wx.DefaultSize, pos=wx.DefaultPosition,
91
style=wx.DEFAULT_DIALOG_STYLE | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER,
92
choose_id=False, choose_attr=False,
93
func_choose_id=None, func_change_obj=None, panelstyle='default',
94
immediate_apply=True):
95
96
self.process = process
97
if title is None:
98
title = process.get_name()
99
100
buttons, defaultbutton, standartbuttons = self._get_buttons()
101
102
objpanel.ObjPanelDialog.__init__(self, parent, process,
103
attrconfigs=None,
104
id=None, ids=None,
105
groupnames=['options', 'inputparameters'],
106
show_groupnames=False,
107
title=title, size=(800, 400), pos=wx.DefaultPosition,
108
style=wx.DEFAULT_DIALOG_STYLE | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER,
109
choose_id=False, choose_attr=False,
110
func_choose_id=None,
111
func_change_obj=None,
112
panelstyle='default',
113
immediate_apply=immediate_apply,
114
buttons=buttons,
115
standartbuttons=standartbuttons,
116
defaultbutton=defaultbutton,
117
)
118
119
def _get_buttons(self):
120
buttons = [('Run', self.on_run, 'Start the process!'),
121
#('Kill', self.on_kill, 'Kill process in background.'),
122
('Apply', self.on_apply, 'Apply current options, complete them and make them consistent, but do not run.'),
123
('Save Options...', self.on_save_options, self.on_save_options.__doc__),
124
('Load Options...', self.on_load_options, self.on_load_options.__doc__),
125
]
126
defaultbutton = 'Run'
127
standartbuttons = ['cancel', ]
128
129
return buttons, defaultbutton, standartbuttons
130
131
def get_process(self):
132
return self.process
133
134
def on_run(self, event=None):
135
self.on_apply()
136
self.process.run()
137
if self.process.status == 'success':
138
self.Destroy()
139
140
def on_kill(self, event=None):
141
self.process.kill()
142
143
def on_apply(self, event=None):
144
self.process.update_params()
145
self.restore()
146
147
def recreate_panel_proc(self, obj=None,
148
attrconfigs=None,
149
tables=None,
150
table=None, id=None, ids=None,
151
groupnames=None, show_groupnames=False,
152
show_title=True,
153
is_modal=False,
154
immediate_apply=False,
155
panelstyle='default',
156
func_change_obj=None,
157
func_choose_id=None,
158
func_choose_attr=None,
159
**buttonargs):
160
"""
161
Recreates panel and destroys previous contents:
162
attr = a list ith attribute names to be shown
163
groups = list with group names to be shown
164
show_groupnames = the group names are shown
165
together with the respective attributes
166
is_modal = if true the panel will be optimized for dialog window
167
immediate_apply = changes to widgets will be immediately applied to
168
obj attribute without pressing apply
169
buttonargs = a dictionary with arguments for botton creation
170
obj = the object to be displayed
171
id = used if there is only one single id to be displayed
172
ids = used if a selection of ids need to be displayed
173
func_change_obj = function to be called if user clicks on on object
174
with obj as argument
175
func_choose_id = function to be called when user clicks on id(table row)
176
with id as argument
177
func_choose_attr = function to be called when user clicks on attribute
178
with attr as argument. In this case the attribute
179
names of scalars turn into buttons. Array attributes
180
are selected by clicking on the column name.
181
"""
182
# print 'ProcessDialog.recreate_panel',groupnames
183
# for attrconfig in obj.get_attrman().get_configs():
184
# print ' attrconfig.attrname',attrconfig.attrname
185
#self.id = id
186
#self.ids = ids
187
self.obj = obj
188
self.func_change_obj = func_change_obj
189
self.func_choose_id = func_choose_id
190
self.func_choose_attr = func_choose_attr
191
self._show_title = show_title
192
193
if (attrconfigs is None) & (tables in (None, [])) & (table is None):
194
attrconfigs = obj.get_attrman().get_configs()
195
if not self._show_title:
196
# titels of groupname are not shown so just
197
# select attributes at this stage
198
attrconfig_new = []
199
for attrconfig in attrconfigs:
200
# print ' attrconfig.attrname',attrconfig.attrname
201
is_shown = False
202
for groupname in attrconfig.groupnames:
203
# print ' comp:',attrconfig.attrname,groupname,groupname in groupnames
204
if groupname in groupnames:
205
is_shown = True
206
break
207
208
if is_shown:
209
attrconfig_new.append(attrconfig)
210
attrconfigs = attrconfig_new
211
212
tables = None # obj.get_tablemans()
213
214
# print 'is_scalar_panel & is_multitab'
215
216
sizer = self.init_notebook()
217
self.add_scalarpage(attrconfigs=attrconfigs, groupnames=groupnames,
218
id=id, immediate_apply=immediate_apply, panelstyle=panelstyle,
219
is_modal=is_modal, show_title=show_title,
220
show_buttons=False, **buttonargs)
221
222
for table in tables:
223
self.add_tablepage(table, groupnames=groupnames)
224
225
self.show_notebook()
226
sizer = self.GetSizer()
227
self.add_buttons(self, sizer,
228
is_modal=is_modal,
229
**buttonargs)
230
# some widgets like color need this to expand into their maximum space
231
self.restore()
232
return True
233
234
235
class ProcessDialogInteractive(ProcessDialogMixin, wx.Frame):
236
237
"""
238
A frame used for the ObjBrowser Demo
239
240
"""
241
242
def __init__(self, parent,
243
process,
244
title=None,
245
func_close=None,
246
is_close_after_completion=True,
247
):
248
249
if title is None:
250
title = process.get_name()
251
wx.Frame.__init__(self, parent, -1, title=title, pos=wx.DefaultPosition, size=wx.DefaultSize)
252
253
self.parent = parent
254
self.process = process
255
256
self.func_close = func_close
257
# if self.func_close is None:
258
self.is_close_after_completion = is_close_after_completion
259
# else:
260
# self.is_close_after_completion = False
261
#self._is_run = False
262
263
self.Bind(wx.EVT_TIMER, self.on_step)
264
self.timer = wx.Timer(self)
265
# Set up the MenuBar
266
#MenuBar = wx.MenuBar()
267
#file_menu = wx.Menu()
268
#item = file_menu.Append(-1, "&Import CSV...","Import OD data from a CSV text file with format <zonename orig>, <zonename dest>,<number of trips>")
269
#self.Bind(wx.EVT_MENU, self.on_import_csv, item)
270
#item = file_menu.Append(-1, "&Import Exel...","Import OD data from an Exel file.")
271
#self.Bind(wx.EVT_MENU, self.on_import_exel, item)
272
#help_menu = wx.Menu()
273
# item = help_menu.Append(-1, "&About",
274
# "More information About this program")
275
#self.Bind(wx.EVT_MENU, self.on_menu, item)
276
#MenuBar.Append(help_menu, "&Help")
277
# self.SetMenuBar(MenuBar)
278
279
#################################################################
280
# create statusbar
281
#self.statusbar = AgileStatusbar(self)
282
self.statusbar = AgileStatusbar(self, fields=[ # ('action',-4),
283
('message', -10),
284
# ('coords',-1),
285
# ('zoom',-1),
286
('progress', -3),
287
('status', -1),
288
# ('coords',-1),
289
])
290
self.SetStatusBar(self.statusbar)
291
# self.count=0.0
292
293
logger = process.get_logger()
294
self.oldprogressfunc = logger.get_clallbackfunc('progress')
295
logger.add_callback(self.show_progress, 'progress')
296
297
self.oldmessagefunc = logger.get_clallbackfunc('message')
298
logger.add_callback(self.write_message, 'message')
299
300
#################################################################
301
# create toolbar
302
303
# self.init_toolbar(size=size_toolbaricons)
304
305
self.browser = self.make_browser()
306
307
# Create a sizer to manage the Canvas and message window
308
MainSizer = wx.BoxSizer(wx.VERTICAL)
309
MainSizer.Add(self.browser, 4, wx.EXPAND)
310
311
self.SetSizer(MainSizer)
312
self.Bind(wx.EVT_CLOSE, self.on_close)
313
#self.Bind(wx.EVT_IDLE, self.on_idle)
314
315
self.EventsAreBound = False
316
317
# getting all the colors for random objects
318
# wxlib.colourdb.updateColourDB()
319
#self.colors = wxlib.colourdb.getColourList()
320
321
return None
322
323
def _get_buttons(self):
324
if hasattr(self.process, 'step'):
325
buttons = [('Start', self.on_start, 'Start the process!'),
326
('Stop', self.on_stop, 'Stop process.'),
327
('Step', self.on_singlestep, 'Make a single step.'),
328
('Done', self.on_done, 'Stop process and close window.'),
329
]
330
defaultbutton = 'Start'
331
332
else:
333
if self.is_close_after_completion:
334
buttons = [('Run', self.on_start, 'Start the process!'),
335
]
336
else:
337
buttons = [('Run', self.on_start, 'Start the process!'),
338
('Done', self.on_done, 'Finish with process and close window.'),
339
]
340
defaultbutton = 'Run'
341
342
buttons.append(('Cancel', self.on_close, 'Close window, without running the process.'))
343
# standartbuttons=['cancel'] # uses also standard on_cancel :(
344
standartbuttons = []
345
return buttons, defaultbutton, standartbuttons
346
347
# def on_idle(self,event):
348
# print 'on_idle'
349
#
350
# if self._is_run:
351
# self.process.step()
352
# if self.process.status=='success':
353
# self._is_run = False
354
# self.Destroy()
355
356
def on_start(self, event=None):
357
self.browser.apply()
358
if self.process.status != 'running':
359
self.process.update_params()
360
# self.refresh_browser()
361
362
# TODO: check whether to use ALWAYS run to put process in running mode
363
if hasattr(self.process, 'step'):
364
self.process.do()
365
else:
366
self.process.run()
367
368
# no closing function defined
369
if self.is_close_after_completion:
370
self.on_close(event)
371
372
# print 'on_start: after preparation self.process.status=',self.process.status
373
374
if hasattr(self.process, 'step'):
375
self.timer.Start(1)
376
377
# while self.process.status=='running':
378
# print 'call step'
379
# self.process.step()
380
381
# if self.process.status=='running':
382
# # this will call step method in on_idle
383
# self._is_run = True
384
#
385
# elif self.process.status=='preparation':
386
# self.process.update_params()
387
# self.refresh_browser()
388
# self.process.run()
389
390
def on_step(self, event=None):
391
if self.process.status == 'running':
392
# print 'call step'
393
self.process.step()
394
else:
395
print ' Simulation finished'
396
self.timer.Stop()
397
398
def on_stop(self, event=None):
399
self.timer.Stop()
400
401
def on_singlestep(self, event=None):
402
if self.process.status == 'running':
403
if hasattr(self.process, 'step'):
404
wx.FutureCall(1, self.process.step)
405
406
def on_close(self, event=None):
407
# print 'on_close',self.process.status
408
if self.process.status == 'running':
409
self.process.aboard()
410
# print ' aboarded.'
411
412
self.MakeModal(False)
413
# print ' call func_close',self.func_close
414
if self.func_close is not None:
415
self.func_close(self)
416
417
# print ' reput callbacks to main'
418
if self.oldprogressfunc is not None:
419
self.process.get_logger().add_callback(self.oldprogressfunc, 'progress')
420
421
if self.oldmessagefunc is not None:
422
self.process.get_logger().add_callback(self.oldmessagefunc, 'message')
423
424
# print ' call destroy'
425
self.Destroy()
426
# self.Close() # no effect
427
428
def on_done(self, event=None):
429
# print 'on_done',self.process.status
430
self.on_close(event)
431
432
def on_cancel(self, event):
433
"""
434
Apply values, destroy itself and parent
435
"""
436
# print 'on_cancel'
437
self.on_close(event)
438
439
def on_kill(self, event=None):
440
# self.process.kill()
441
pass
442
443
def show_progress(self, percent, **kwargs):
444
"""
445
Shows progress on progress bar. Plug-in funcion for logger.
446
"""
447
# print 'show_progress',percent
448
self.statusbar.set_progress(percent)
449
# self.Refresh()
450
# wx.Yield()
451
# self.Update()
452
453
def write_message(self, text, **kwargs):
454
print 'write_message', text
455
self.statusbar.write_message(text)
456
457
def make_browser(self):
458
459
buttons, defaultbutton, standartbuttons = self._get_buttons()
460
browser = objpanel.ObjPanel(self, self.process,
461
attrconfigs=None,
462
id=None, ids=None,
463
groupnames=['options', 'inputparameters'],
464
func_change_obj=None,
465
show_groupnames=False, show_title=False,
466
is_modal=True,
467
mainframe=None,
468
pos=wx.DefaultPosition,
469
size=wx.DefaultSize,
470
style=wx.MAXIMIZE_BOX | wx.RESIZE_BORDER,
471
immediate_apply=False, # True,
472
panelstyle='default',
473
buttons=buttons,
474
standartbuttons=standartbuttons,
475
defaultbutton=defaultbutton,
476
)
477
return browser
478
479
def refresh_browser(self):
480
"""
481
Deletes previous conents
482
Builds panel for obj
483
Updates path window and history
484
"""
485
# print 'Wizzard.refresh_panel with',obj.ident
486
# remove previous obj panel
487
sizer = self.GetSizer()
488
sizer.Remove(0)
489
self.browser.Destroy()
490
#del self.browser
491
self.browser = self.make_browser()
492
493
sizer.Add(self.browser, 1, wx.GROW)
494
495
self.Refresh()
496
# sizer.Fit(self)
497
sizer.Layout()
498
# add to history
499
500