Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
eclipse
GitHub Repository: eclipse/sumo
Path: blob/main/tools/contributed/sumopy/agilepy/lib_wx/objpanel.py
169689 views
1
#!/usr/bin/env python
2
# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3
# Copyright (C) 2016-2025 German Aerospace Center (DLR) and others.
4
# SUMOPy module
5
# Copyright (C) 2012-2021 University of Bologna - DICAM
6
# This program and the accompanying materials are made available under the
7
# terms of the Eclipse Public License 2.0 which is available at
8
# https://www.eclipse.org/legal/epl-2.0/
9
# This Source Code may also be made available under the following Secondary
10
# Licenses when the conditions for such availability set forth in the Eclipse
11
# Public License 2.0 are satisfied: GNU General Public License, version 2
12
# or later which is available at
13
# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
14
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
15
16
# @file objpanel.py
17
# @author Joerg Schweizer
18
# @date 2012
19
20
# cd /home/joerg/projects/sumopy/tools/sumopy/wxpython
21
# python objpanel.py
22
23
import string
24
import random
25
from agilepy.lib_base.misc import filepathlist_to_filepathstring, filepathstring_to_filepathlist
26
from wxmisc import KEYMAP, AgilePopupMenu, AgileToolbarMixin, get_tablecolors
27
import agilepy.lib_base.exports as ex
28
import time
29
from agilepy.lib_base.logger import Logger
30
import agilepy.lib_base.classman as cm
31
import wx.py as py # pyshell
32
from collections import OrderedDict
33
import wx.lib.colourselect as coloursel
34
import wx.lib.editor as editor
35
from wx.lib import scrolledpanel, hyperlink, colourdb, masked
36
import wx.grid as gridlib
37
import wx.lib as wxlib
38
import wx
39
import numpy as np
40
import sys
41
import os
42
import types
43
if __name__ == '__main__':
44
# search SUMOPy in local directory (where this file is located)
45
try:
46
APPDIR = os.path.dirname(os.path.abspath(__file__))
47
except:
48
APPDIR = os.path.dirname(os.path.abspath(sys.argv[0]))
49
sys.path.append(os.path.join(APPDIR, '..', '..'))
50
51
52
# from processdialog import ProcessDialog # no! uses objectpanel
53
54
havePopupWindow = 1
55
if wx.Platform == '__WXMAC__':
56
havePopupWindow = 0
57
wx.PopupWindow = wx.PopupTransientWindow = wx.Window
58
59
60
if __name__ == '__main__':
61
APPDIR = os.path.join(os.path.dirname(__file__), "..", "..")
62
sys.path.append(APPDIR)
63
64
IMAGEDIR = os.path.join(os.path.dirname(__file__), 'images')
65
66
67
# used for demo:
68
wildcards_all = "All files (*.*)|*.*"
69
70
provider = wx.SimpleHelpProvider()
71
wx.HelpProvider_Set(provider)
72
73
METATYPES_LINKSTYLE = ('obj', 'id', 'tabid', 'ids')
74
75
NUMERICTYPES = cm.NUMERICTYPES # (types.BooleanType,types.FloatType,types.IntType,types.LongType,types.ComplexType)
76
STRINGTYPES = cm.STRINGTYPES # (types.StringType,types.UnicodeType)
77
78
79
def list_to_str(l, lb='', rb='', sep=','):
80
# print 'list_to_str',l,len(l)
81
if len(l) == 0:
82
return lb+rb
83
else:
84
s = lb
85
for e in l[:-1]:
86
s += unicode(e)+sep
87
# print ' returns',s+unicode(l[-1])+rb
88
return s+unicode(l[-1])+rb
89
90
91
def is_list_flat(l):
92
if type(l) not in (types.ListType, types.TupleType): # STRINGTYPES:
93
# not a list
94
return False
95
96
is_flat = True
97
for e in l:
98
if hasattr(e, '__iter__'):
99
is_flat = False
100
break
101
return is_flat
102
103
104
def str_to_list(s, lb='[', rb=']'):
105
"""
106
Tries to convert a string to a flat list.
107
Attention, this conversion is extremely tolerant.
108
For example:
109
s='bus,bike' and s="['bus','bike']" will return the same result.
110
s='5,2.5' and s="['5','2.5']" will also return the same result
111
trying to convert numbers in integers or floats
112
"""
113
s = s.strip()
114
if len(s) >= 2:
115
if (s[0] == lb) & (s[-1] == rb): # are there braces
116
sl = s[1:-1].split(',')
117
else:
118
sl = s.split(',') # no braces, but could still be a list
119
else:
120
sl = s.split(',')
121
122
if (len(sl) == 1) & (sl[0] == ''):
123
return []
124
125
l = []
126
for e in sl:
127
l.append(str_to_obj(e))
128
# print 'str_to_list',s,l
129
return l
130
131
132
def str_to_tuple(s):
133
return str_to_list(s, lb='(', rb=')')
134
135
136
def str_to_obj(s):
137
"""
138
Only for flat objects at the moment
139
"""
140
# print 'str_to_obj',type(s),s
141
s = s.strip()
142
if len(s) == 0:
143
return ''
144
145
if s[0] == s[-1]:
146
if s[0] in("'", '"'):
147
s = s[1:-1]
148
# print 'str_to_obj',s,len(s),type(s),s.isdigit(),s.isalnum()
149
if s.isdigit():
150
return string.atoi(s)
151
else:
152
try:
153
return string.atof(s)
154
except:
155
return s
156
157
158
def str_to_obj_nested(s):
159
"""
160
NOT WORKING, NOT IN USE
161
Only for flat objects at the moment
162
"""
163
# print 'str_to_obj',s
164
x = str_to_list(s)
165
# print ' ',x
166
if x is None:
167
x = str_to_tuple(s)
168
if x is None:
169
# if type(s) == types.StringType:
170
if s.isdigit():
171
return string.atoi(s)
172
elif s.isalnum():
173
return s
174
else:
175
try:
176
return string.atof(s)
177
except:
178
return s
179
else:
180
return x
181
182
else:
183
return x
184
185
186
class AttrBase:
187
"""
188
Mixin class that provides methods to support text representation
189
of attributes
190
"""
191
192
def num_to_text(self, value, attr, obj):
193
"""
194
Returns string of a numeric value taking account of formating
195
info for this defined in obj.
196
"""
197
pass
198
199
def color_to_ffffff(self, color):
200
"""
201
Returns a 3- tuple with values for rgb between 0 and 255.
202
Takes an array or list with rgb values between 0.0 and 1.0.
203
"""
204
# print 'color_to_ffffff',color
205
return (color[0], color[1], color[2])
206
207
def ffffff_to_color(self, ffffff):
208
"""
209
Returns an array with rgb values between 0.0 and 1.0.
210
Returns a 3- tople with values for rgb between 0 and 255.
211
212
"""
213
# print 'ffffff_to_color',ffffff,type(ffffff),type(array(ffffff,float)/255.0)
214
return np.array(ffffff, float)/255.0
215
# return np.array(ffffff,int)
216
217
218
class WidgetContainer:
219
"""
220
Contains one or several widgets representing a scalar attribute.
221
Should be overwritten to accomodate various interactive datatypes.
222
Default is simple text.
223
224
"""
225
226
def __init__(self, parent, attrconf, mainframe=None, color_bg=None,
227
panelstyle='default', immediate_apply=False,
228
equalchar=':'):
229
"""
230
Parent is the ScalarPanel panel,
231
attr is the attribute name in parent.obj
232
"""
233
self.parent = parent
234
self.panelstyle = panelstyle
235
self.immediate_apply = immediate_apply
236
self._attrconf = attrconf
237
self.equalchar = equalchar
238
239
self.mainframe = mainframe
240
241
if color_bg is None:
242
self.color_bg = wx.NamedColour('grey85')
243
else:
244
self.color_bg = color_bg
245
246
# self.widgets=[]
247
# self.untitwidget=None
248
# self.valuewidget=None
249
# self.bitmapwidget=None
250
251
self.create_widgets(self.define_widgetset())
252
253
254
# -------------------------------------------------------------------------------
255
# the following methods are usually overwritten to create
256
# attribute specific widgets
257
258
259
def define_widgetset(self):
260
"""
261
Generates the widgets representing this attribute.
262
To be overwritten.
263
"""
264
return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),
265
('value', self.create_valuewidget(), wx.EXPAND), ]
266
267
def get_valuewidget_write(self):
268
"""
269
Returns instance of editable widget
270
To be overwritten.
271
"""
272
# if non is returned attribute is not editable
273
# even though permission is set to write
274
return None
275
276
def get_valuewidget_read(self):
277
"""
278
Returns instance of non-editable widget
279
To be overwritten.
280
"""
281
282
#text = '%s%s'%(self._attrconf.format_value(),self._attrconf.format_unit())
283
text = self.format_value_obj(show_unit=True, show_parentesis=False)
284
# if not editable, no unitwidgetcontainer will be created so we need unit
285
# if len(text)>40:
286
# text=text[:10]+'...'+text[-10:]
287
#widget=wx.StaticText(self.parent, -1, text,style=wx.ALIGN_RIGHT)
288
# ,style= wx.ALIGN_RIGHT
289
#widget=wx.StaticText(self.parent, -1,'TEST!',style=wx.ALIGN_RIGHT)
290
# print ' value,widget',string_value,widget
291
292
# no, showed only first character
293
#widget = editor.Editor(self.parent, -1, style=wx.SUNKEN_BORDER)
294
# widget.SetText(text)
295
# print 'get_valuewidget_read',self._attrconf.attrname
296
# print ' text RET',text.find('n'),':\n',text
297
if text.find('n') > 0:
298
widget = wx.TextCtrl(self.parent, -1, str(text), style=wx.ALIGN_LEFT | wx.TE_MULTILINE | wx.TE_READONLY)
299
else:
300
widget = wx.TextCtrl(self.parent, -1, str(text), style=wx.ALIGN_LEFT | wx.TE_READONLY)
301
# self.set_textevents(widget)
302
303
widget.Enable(False)
304
305
return widget
306
307
def get_widgetvalue(self):
308
"""
309
Returnes current value from valuewidget.
310
Depends on attribute type and hence widgettype.
311
To be overwritten.
312
"""
313
return None # self.widgets['value'][0].GetLabel()
314
315
def set_widgetvalue(self, value):
316
"""
317
Sets value for valuewidget.
318
Depends on attribute type and hence widgettype.
319
To be overwritten.
320
"""
321
text = str(value)
322
# if len(text)>40:
323
# text=text[:10]+'...'+text[-10:]
324
if hasattr(self.widgets['value'][0], 'SetValue'):
325
self.widgets['value'][0].SetValue(text)
326
327
# OR?
328
# if self._attrconf.is_writable():
329
# self.widgets['value'][0].SetValue(value)
330
# else:
331
332
# OR?
333
# if hasattr(self.widgets['value'][0],'SetValue'):
334
# self.widgets['value'][0].SetValue(str(value))
335
# elif hasattr(self.widgets['value'][0],'SetText'):
336
# print 'set_widgetvalue mixin',type(value),value
337
# self.widgets['value'][0].SetText(str(value))
338
# self.valuewidget.SetLabel(str(value))
339
340
# -------------------------------------------------------------------------------
341
# these methods are normally not overwritten
342
343
def create_valuewidget(self):
344
"""
345
Returns widget representing the value of attribute.
346
Dependent on read or write access the
347
get_valuewidget_write or get_valuewidget_read
348
will be called to generate the widget.
349
"""
350
# print 'create_valuewidget for',self._attrconf.attrname,'is_writable=',self._attrconf.is_writable()
351
352
if self._attrconf.is_writable():
353
# in write mode unit widget should be created separately
354
widget = self.get_valuewidget_write()
355
if widget is None:
356
# print ' editable valuewidget not available'
357
widget = self.get_valuewidget_read()
358
else:
359
widget = self.get_valuewidget_read()
360
361
self.set_tooltip(widget)
362
self.extend_widgetsize(widget)
363
self.valuewidget = widget
364
return widget
365
366
def create_namewidget(self):
367
# if self._attrconf.get_obj().ident =='vehicles':
368
# print 'create_namewidget',self._attrconf.get_obj().ident,self._attrconf.attrname,self._attrconf.get_name(),type(self._attrconf.get_name())
369
widget = wx.StaticText(self.parent, -1,
370
self._attrconf.get_name().title()+self.equalchar,
371
style=wx.ALIGN_RIGHT # |wx.SIMPLE_BORDER #wx.STATIC_BORDER #
372
)
373
widget.SetBackgroundColour(self.color_bg)
374
self.extend_widgetsize(widget)
375
# widget.SetMinSize((-1,20))
376
377
#
378
379
self.set_tooltip(widget)
380
381
return widget
382
383
def create_unitwidget(self):
384
if self._attrconf.has_unit():
385
widget = wx.StaticText(self.parent, -1,
386
self._attrconf.format_unit(),
387
style=wx.ALIGN_LEFT # |wx.SIMPLE_BORDER #wx.STATIC_BORDER #| #
388
)
389
widget.SetBackgroundColour(self.color_bg)
390
self.extend_widgetsize(widget)
391
# print 'create_unitwidget', self.config_attr['unit']
392
return widget
393
394
else:
395
return (0, 0)
396
397
def extend_widgetsize(self, widget, xborder=3, yborder=3):
398
"""
399
Extends the widget by incresing its minimum size by border in pixels.
400
"""
401
s = widget.GetSize()
402
widget.SetMinSize((s[0]+xborder, s[1]+yborder))
403
404
def create_widgets(self, widgetdata):
405
"""
406
Generates the widgets representing this attribute.
407
"""
408
self.widgets = {}
409
self.widgetnames = []
410
for name, widget, align in widgetdata:
411
self.widgets[name] = (widget, align)
412
self.widgetnames.append(name)
413
414
def get_widgetnames(self):
415
"""
416
Returns a list with names of widgets, representing this attribute.
417
"""
418
return self.widgetnames
419
420
def get_widgetsinfo(self, widgetnames=[]):
421
"""
422
Returns a list of widget infos representing this attribute
423
according to the widgetnames.
424
One widget info is a tuple with widget object and desired alignment
425
within the panel.
426
If widgetnames is empty then all widgets are returned in the
427
order defined in get_widgetnames.
428
"""
429
430
if len(widgetnames) == 0:
431
widgetnames = self.get_widgetnames()
432
433
widgetsinfo = []
434
for name in widgetnames:
435
widgetsinfo.append(self.widgets.get(name, ((0, 0), 0)))
436
437
return widgetsinfo
438
439
def apply_obj_to_valuewidget(self):
440
"""
441
Value of obj is read and applied to value widget.
442
To be overwritten.
443
"""
444
value = self.get_value_obj()
445
# print 'apply_obj_to_valuewidget',self._attrconf.attrname, value
446
self.set_widgetvalue(value)
447
448
def get_value_obj(self):
449
"""
450
Reads current value from object.
451
"""
452
if self._attrconf.is_colattr():
453
return self._attrconf[self.parent.id]
454
else:
455
return self._attrconf.get_value()
456
457
def set_value_obj(self, value):
458
"""
459
Sets given value to object.
460
"""
461
# print 'set_value_obj',self._attrconf.attrname,self.parent.id, self._attrconf.is_colattr()
462
if self._attrconf.is_colattr(): # parent is holding the row id
463
self._attrconf[self.parent.id] = value
464
else:
465
self._attrconf.set_value(value)
466
467
def format_value_obj(self, show_unit=False, show_parentesis=False):
468
"""
469
Return formatted value of object.
470
"""
471
472
if self._attrconf.is_colattr(): # parent is holding the row id
473
return self._attrconf.format_value(self.parent.id,
474
show_unit=show_unit,
475
show_parentesis=show_parentesis)
476
else:
477
# print 'format_value_obj',self._attrconf.attrname, self._attrconf.format_value( )
478
return self._attrconf.format_value(show_unit=show_unit,
479
show_parentesis=show_parentesis)
480
481
def apply_valuewidget_to_obj(self, value=None):
482
"""
483
Applies current value widget to object attribute.
484
485
Makes no sense for static text.
486
If no value argument is given then the get_widgetvalue method is
487
called to recover widget value.
488
"""
489
# pass
490
# in general values maust be transferred from widget to
491
# attribute of objet in the correct way.
492
493
# self._attrconf.get_value()
494
if self._attrconf.is_writable():
495
if value is None: # value not given
496
value = self.get_widgetvalue()
497
498
if value is not None:
499
# value returned by widget is valid
500
# print 'apply_valuewidget_to_obj',value,self.parent.obj.ident,self.attr
501
self.set_value_obj(value)
502
503
def set_textevents(self, widget):
504
"""
505
Sets events to text input widhets
506
"""
507
# print 'set_textevents',widget
508
# print ' immediate_apply',self.immediate_apply
509
if self.immediate_apply:
510
widget.Bind(wx.EVT_KILL_FOCUS, self.on_apply_immediate)
511
#widget.Bind(wx.EVT_CHAR, self.on_apply_immediate)
512
513
def on_apply_immediate(self, event):
514
"""
515
A key has been pressed in valuewidget and it is requested
516
to apply it immediately to the object
517
"""
518
# print 'on_apply_immediate'
519
self.apply_valuewidget_to_obj()
520
521
def get_obj(self):
522
"""
523
Returns object to be displayed on panel.
524
"""
525
return self._attrconf.get_obj()
526
527
# def get_pentable(self):
528
# """
529
# Returns pentable instance
530
# """
531
# return self.parent.get_pentable()
532
533
def get_objvalue(self):
534
"""
535
Read current value from object and convert into string.
536
Depends on attribute type and hence widgettype.
537
To be overwritten.
538
"""
539
if self._attrconf.is_colattr():
540
value = self._attrconf[self.parent.id]
541
542
else:
543
# print 'get_objvalue',self.attr,self.parent.obj
544
value = self._attrconf.get_value()
545
546
# print ' value=',value
547
return value
548
549
def set_tooltip(self, widget=None):
550
551
# TODO : check for global tooltip on/off
552
infostr = '%s (%s)' % (self._attrconf.get_name(), self._attrconf.attrname)
553
if self._attrconf.has_info():
554
# print 'set_tooltip',self.attr,self.config_attr['info']
555
for infoline in self._attrconf.get_info().split('\n'):
556
infostr += '\n '+infoline.strip()
557
widget.SetToolTipString(infostr)
558
widget.SetHelpText(infostr)
559
560
561
class NumericWidgetContainer(AttrBase, WidgetContainer):
562
"""
563
Contains one or several widgets representing a scalar numeric attribute.
564
565
"""
566
567
def define_widgetset(self):
568
"""
569
Generates the widgets representing this attribute.
570
"""
571
if self._attrconf.has_unit():
572
# print 'define_widgetset num +unit',self._attrconf.attrname
573
return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),
574
('value', self.create_valuewidget(), wx.EXPAND),
575
('unit', self.create_unitwidget(), wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), ]
576
else:
577
# print 'define_widgetset num ',self._attrconf.attrname
578
return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),
579
('value', self.create_valuewidget(), wx.EXPAND)]
580
581
def get_valuewidget_read(self):
582
"""
583
Returns instance of non-editable widget
584
To be overwritten.
585
"""
586
widget = self.get_valuewidget_write()
587
widget.Enable(False)
588
# Here just the plain static text widget is returned
589
590
# printformat=self.get_printformat_fortran(self.attr,self.parent.obj,main=self.mainframe)
591
592
#value = printformat%value
593
594
# add unit if exist
595
# print 'get_valuewidget_read with unit:',self.parent.obj.get_unit(self.attr)
596
# if self.parent.obj.get_unit(self.attr)!='':
597
# value+=' '+self.parent.obj.get_unit(self.attr)
598
599
# print 'create_valuewidget: '+value,self.attr
600
#widget=wx.StaticText(self.parent, wx.ID_ANY, self.format_value_obj(),style=wx.ALIGN_RIGHT)
601
602
return widget
603
604
def get_valuewidget_write(self):
605
"""
606
Return widget to edit numeric value of attribute
607
This is effectively the parametrisation of the masked.NumCtrl widget.
608
"""
609
value = self.get_value_obj()
610
# strange way to convert numpy type numbers into native python numbers
611
if type(value) not in (types.IntType, types.LongType, types.FloatType, types.ComplexType):
612
value = value.tolist()
613
# print 'NumericWidgetContainer.get_valuewidget_write ',value,type(value),self._attrconf.digits_fraction
614
615
# if self._attrconf.digits_fraction is None:
616
# self._attrconf.digits_fraction = 3
617
618
# print ' panelstyle=',self.panelstyle
619
# print ' value=',value
620
# numpy returns dtype... even for scalars
621
# make sure to convert value in a native python scalar
622
# if value is None:
623
# value=NaN
624
# elif type(value) not in (types.IntType, types.LongType, types.FloatType):
625
# value=value.tolist()
626
627
# if self.config_attr['min'] is None:
628
allow_negative = True
629
# else:
630
# allow_negative = self.config_attr['min'] < 0.0
631
632
#min = self.config_attr['min']
633
#max = self.config_attr['max']
634
635
# if min is None:
636
# if value<0:
637
# min = -5*value
638
# else:
639
# min = 0
640
#
641
# if max is None:
642
# max = 5*abs(value)
643
644
if np.isinf(value):
645
widget = wx.StaticText(self.parent, -1,
646
value.__repr__(),
647
style=wx.ALIGN_LEFT # |wx.SIMPLE_BORDER #wx.STATIC_BORDER #| #
648
)
649
# widget.SetBackgroundColour(self.color_bg)
650
self.extend_widgetsize(widget)
651
# print 'create_unitwidget', self.config_attr['unit']
652
return widget
653
654
# if self.panelstyle == 'fancy': #'instrumental':
655
# print 'NumericWidgetContainer.get_valuewidget_write fancy mode'
656
# print 'TODO: no bindings yet for immediate apply'
657
# slider = wx.Slider(self.parent, wx.ID_ANY,
658
# value,
659
# min, max,
660
# style=wx.SL_HORIZONTAL| wx.SL_AUTOTICKS
661
# #style=wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS
662
# )
663
#
664
# slider.SetTickFreq(5, 1)
665
# return slider
666
667
# else:
668
669
widget = wx.TextCtrl(self.parent, -1, str(value), style=wx.ALIGN_RIGHT)
670
# standard numerical widget
671
# widget = masked.Ctrl(self.parent, id = -1,
672
# value = value,
673
# #integerWidth=None,
674
# fractionWidth = self._attrconf.digits_fraction,
675
# autoSize = True,
676
# controlType=masked.controlTypes.NUMBER,
677
# style= wx.ALIGN_RIGHT
678
# )
679
# widget = masked.NumCtrl(
680
# self.parent, id = -1,
681
# value = value,
682
# pos = wx.DefaultPosition,
683
# size = wx.DefaultSize,
684
# style = 0,
685
# validator = wx.DefaultValidator,
686
# name = "masked.number",
687
# integerWidth = 10,
688
# fractionWidth = 0,
689
# allowNone = False,
690
# allowNegative = True,
691
# useParensForNegatives = False,
692
# groupDigits = False,
693
# groupChar = ',',
694
# decimalChar = '.',
695
# min = None,
696
# max = None,
697
# limited = False,
698
# #limitOnFieldChange = False,
699
# selectOnEntry = True,
700
# foregroundColour = "Black",
701
# signedForegroundColour = "Red",
702
# emptyBackgroundColour = "White",
703
# validBackgroundColour = "White",
704
# invalidBackgroundColour = "Yellow",
705
# autoSize = False#True
706
# )
707
self.set_textevents(widget)
708
return widget
709
710
def get_widgetvalue(self):
711
"""
712
Returnes current value from valuewidget.
713
Depends on attribute type and hence widgettype.
714
To be overwritten.
715
"""
716
return float(self.valuewidget.GetValue())
717
718
def set_widgetvalue(self, value):
719
"""
720
Sets value for valuewidget.
721
Depends on attribute type and hence widgettype.
722
To be overwritten.
723
"""
724
if 1: # self._attrconf.is_writable():
725
# set value to label
726
# numpy returns dtype... even for scalars
727
# make sure to convert value in a native python scalar
728
if type(value) not in (types.IntType, types.LongType, types.FloatType):
729
value = value.tolist()
730
self.valuewidget.SetValue(str(value))
731
732
733
class IntegerWidgetContainer(NumericWidgetContainer):
734
"""
735
Contains one or several widgets representing a scalar numeric attribute.
736
737
"""
738
739
def get_valuewidget_write(self):
740
"""
741
Return widget to edit numeric value of attribute
742
This is effectively the parametrisation of the masked.NumCtrl widget.
743
"""
744
# if self.panelstyle == 'instrumental':
745
# # return a spin control in instrumental style
746
# sc = wx.SpinCtrl(self.parent, wx.ID_ANY, "", (30, 50))
747
# sc.SetRange(self.config_attr['min'],self.config_attr['max'])
748
# sc.SetValue(value)
749
# return sc
750
# else:
751
# use standard numerical masked text otherwise
752
return NumericWidgetContainer.get_valuewidget_write(self)
753
754
def get_widgetvalue(self):
755
"""
756
Returnes current value from valuewidget.
757
Depends on attribute type and hence widgettype.
758
To be overwritten.
759
"""
760
return int(self.valuewidget.GetValue())
761
762
763
class BooleanWidgetContainer(AttrBase, WidgetContainer):
764
"""
765
Contains one or several widgets representing a boolean attribute.
766
767
"""
768
769
def define_widgetset(self):
770
"""
771
Generates the widgets representing this attribute.
772
"""
773
return [('name', self.create_namewidget(), wx.ALIGN_RIGHT),
774
('value', self.create_valuewidget(), wx.EXPAND),
775
('unit', self.create_unitwidget(), wx.ALIGN_LEFT), ]
776
777
def get_valuewidget_read(self):
778
"""
779
Returns instance of non-editable widget
780
To be overwritten.
781
"""
782
widget = self.get_valuewidget_write()
783
widget.Enable(False)
784
785
return widget
786
787
def get_valuewidget_write(self):
788
"""
789
Return widget to edit numeric value of attribute
790
This is effectively the parametrisation of the masked.NumCtrl widget.
791
"""
792
# print 'get_numeditwidget',value
793
794
widget = wx.CheckBox(self.parent, -1)
795
if self.immediate_apply:
796
self.parent.Bind(wx.EVT_CHECKBOX, self.on_apply_immediate, widget)
797
value = self.get_value_obj()
798
widget.SetValue(value)
799
return widget
800
801
def get_widgetvalue(self):
802
"""
803
Returnes current value from valuewidget.
804
Depends on attribute type and hence widgettype.
805
To be overwritten.
806
"""
807
return self.valuewidget.GetValue()
808
809
def set_widgetvalue(self, value):
810
"""
811
Sets value for valuewidget.
812
Depends on attribute type and hence widgettype.
813
To be overwritten.
814
"""
815
# if self._attrconf.is_writable():
816
self.valuewidget.SetValue(value)
817
818
819
class ChoiceWidgetContainer(WidgetContainer):
820
"""
821
Contains widget to select one item from a choice list.
822
823
"""
824
825
def define_widgetset(self):
826
"""
827
Generates the widgets representing this attribute.
828
"""
829
if type(self._attrconf.choices) in (OrderedDict, types.DictionaryType):
830
self._choicevalues = self._attrconf.choices.values()
831
self._choicenames = self._attrconf.choices.keys()
832
else:
833
self._choicevalues = list(self._attrconf.choices)
834
self._choicenames = list(self._attrconf.choices)
835
# if type(self._attrconf.choices) in [types.ListType,types.TupleType,numpy.ndarray]:
836
837
if self._attrconf.has_unit() & self._attrconf.is_writable():
838
return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),
839
('value', self.create_valuewidget(), wx.EXPAND),
840
('unit', self.create_unitwidget(), wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), ]
841
else:
842
return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),
843
('value', self.create_valuewidget(), wx.EXPAND)]
844
845
def get_valuewidget_read(self):
846
"""
847
Return widget to read only numeric value of attribute
848
This is effectively the parametrisation of the masked.NumCtrl widget.
849
"""
850
value = self.get_value_obj()
851
# print 'ChoiceWidgetContainer.get_valuewidget_read',value,type(value)
852
# print ' choices',self._attrconf.choices
853
854
if type(self._attrconf.choices) in (OrderedDict, types.DictionaryType):
855
#value = self._attrconf.choices[value]
856
value = self._choicenames[self._choicevalues.index(value)]
857
# print ' value =',value
858
widget = wx.TextCtrl(self.parent, -1, value, style=wx.ALIGN_RIGHT)
859
widget.Enable(False)
860
return widget
861
862
def get_valuewidget_write(self):
863
"""
864
Return widget to edit numeric value of attribute
865
This is effectively the parametrisation of the masked.NumCtrl widget.
866
"""
867
868
value = self.get_value_obj()
869
# print 'ChoiceWidgetContainer.get_valuewidget_read',self._attrconf.attrname, value,type(value)
870
# print ' choices',self._attrconf.choices
871
# print ' self._choicenames',self._choicenames
872
# print ' self._choicevalues',self._choicevalues
873
widget = wx.Choice(self.parent, -1, (100, 50), choices=self._choicenames)
874
if self.immediate_apply:
875
self.parent.Bind(wx.EVT_CHOICE, self.on_apply_immediate, widget)
876
if value in self._choicevalues:
877
ind = self._choicevalues.index(value)
878
else:
879
ind = 0
880
widget.SetSelection(ind)
881
882
return widget
883
884
def get_widgetvalue(self):
885
"""
886
Returnes current value from valuewidget.
887
Depends on attribute type and hence widgettype.
888
To be overwritten.
889
"""
890
val = self.valuewidget.GetSelection()
891
# if self._choicevalues.count(val)>0:
892
return self._choicevalues[val]
893
# else:
894
# return val
895
896
def set_widgetvalue(self, val):
897
"""
898
Sets value for valuewidget.
899
Depends on attribute type and hence widgettype.
900
To be overwritten.
901
"""
902
# print 'set_widgetvalue',self._attrconf.attrname, val,self._choicevalues
903
# if self._choicevalues.count(val)>0:
904
#ind = self._choicevalues.index(val)
905
# self.valuewidget.SetSelection(ind)
906
# else:
907
# self.valuewidget.SetValue(val)
908
909
try:
910
#ind = self._choicenames.index(value)
911
ind = self._choicevalues.index(val)
912
except:
913
print 'WARNING in ChoiceWidgetContainer.set_widgetvalue: %s with value "%s" not in choice list' % (self._attrconf.attrname, val)
914
return
915
# print ' ind',ind,self.valuewidget
916
if self._attrconf.is_writable():
917
self.valuewidget.SetSelection(ind)
918
else:
919
self.valuewidget.SetValue(self._choicenames[ind])
920
921
922
class ChecklistWidgetContainer(ChoiceWidgetContainer):
923
"""
924
Contains widchet to chosse several items from a choice list.
925
926
"""
927
928
def get_valuewidget_read(self):
929
"""
930
Return widget to read only numeric value of attribute
931
This is effectively the parametrisation of the masked.NumCtrl widget.
932
"""
933
# this is a list:
934
values = self.get_value_obj()
935
# print 'ChoiceWidgetContainer.get_valuewidget_read',value,type(value)
936
# print ' choices',self._attrconf.choices
937
938
# mal values in list with .choices dictionary
939
if (len(values) > 0) & (type(self._attrconf.choices) in (OrderedDict, types.DictionaryType)):
940
#value = self._attrconf.choices[value]
941
values = []
942
for val in self.get_value_obj():
943
if val in self._choicevalues:
944
values.append(self._choicenames[self._choicevalues.index(val)])
945
946
# print ' value =',value
947
widget = wx.TextCtrl(self.parent, -1, list_to_str(values, sep=self._attrconf.sep), style=wx.ALIGN_RIGHT)
948
widget.Enable(False)
949
return widget
950
951
def get_valuewidget_write(self):
952
"""
953
Return widget to edit numeric value of attribute
954
This is effectively the parametrisation of the masked.NumCtrl widget.
955
"""
956
957
value = self.get_value_obj()
958
# print 'ChoiceWidgetContainer.get_valuewidget_write',self._attrconf.attrname, value,type(value),self.immediate_apply
959
# print ' choices',self._attrconf.choices
960
# print ' self._choicenames',self._choicenames
961
# print ' self._choicevalues',self._choicevalues
962
963
widget = wx.CheckListBox(self.parent, -1, (80, 50), wx.DefaultSize, self._choicenames)
964
#wx.ComboBox(self.parent,choices = self._choicenames)
965
# print 'widget',widget,'dir:',dir(widget)
966
967
if self.immediate_apply:
968
969
# ATTENTION: this does not work because self.parent is not
970
# a panel, but a windoe, without EvtListBox !!!
971
#self.parent.Bind(wx.EVT_LISTBOX, self.parent.EvtListBox, widget)
972
self.parent.Bind(wx.EVT_CHECKLISTBOX, self.on_apply_immediate, widget)
973
974
self.set_checkbox(widget, value)
975
976
return widget
977
978
def get_widgetvalue(self):
979
"""
980
Returnes current value from valuewidget.
981
Depends on attribute type and hence widgettype.
982
To be overwritten.
983
"""
984
values = []
985
# print 'get_widgetvalue Checked',self.valuewidget.Checked
986
for ind in self.valuewidget.Checked:
987
values.append(self._choicevalues[ind])
988
989
return values
990
991
def set_checkbox(self, widget, values):
992
# print 'set_checkbox',values
993
is_set = False
994
for val in values: # values must be a list
995
# print ' test',val,val in self._choicevalues
996
if val in self._choicevalues:
997
# print ' select ind',self._choicevalues.index(val)
998
ind = self._choicevalues.index(val)
999
widget.Check(ind, True)
1000
is_set = True
1001
1002
def set_widgetvalue(self, val):
1003
"""
1004
Sets value for valuewidget.
1005
Depends on attribute type and hence widgettype.
1006
To be overwritten.
1007
"""
1008
if self._attrconf.is_writable():
1009
self.set_checkbox(self.valuewidget, val)
1010
else:
1011
self.valuewidget.SetValue(str(val))
1012
1013
1014
class TextWidgetContainer(WidgetContainer):
1015
"""
1016
Contains one or several widgets representing a text attribute.
1017
1018
"""
1019
1020
def define_widgetset(self):
1021
"""
1022
Generates the widgets representing this attribute.
1023
"""
1024
if self._attrconf.has_unit() & self._attrconf.is_writable():
1025
return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),
1026
('value', self.create_valuewidget(), wx.EXPAND),
1027
('unit', self.create_unitwidget(), wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), ]
1028
else:
1029
return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),
1030
('value', self.create_valuewidget(), wx.EXPAND)]
1031
1032
def get_valuewidget_read(self):
1033
"""
1034
Return widget to read only numeric value of attribute
1035
This is effectively the parametrisation of the masked.NumCtrl widget.
1036
"""
1037
# print 'TextWidgetContainer.get_valuewidget_read'
1038
# widget=self.get_valuewidget_write()
1039
value = self.get_value_obj()
1040
widget = wx.TextCtrl(self.parent, -1, value, style=wx.ALIGN_RIGHT | wx.TE_READONLY)
1041
widget.Enable(False)
1042
1043
return widget
1044
1045
def get_valuewidget_write(self):
1046
"""
1047
Return widget to edit numeric value of attribute
1048
This is effectively the parametrisation of the masked.NumCtrl widget.
1049
"""
1050
1051
value = self.get_value_obj()
1052
# print 'get_editwidget text',value,type(value)
1053
1054
widget = wx.TextCtrl(self.parent, -1, value, style=wx.ALIGN_RIGHT)
1055
self.set_textevents(widget)
1056
return widget
1057
#self.MultiLine = wx.TextCtrl(parent = panel, id = -1, pos = (38, 70), size = (410, 90), style = wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_AUTO_URL)
1058
1059
def get_widgetvalue(self):
1060
"""
1061
Returnes current value from valuewidget.
1062
Depends on attribute type and hence widgettype.
1063
To be overwritten.
1064
"""
1065
return self.widgets['value'][0].GetValue()
1066
1067
def set_widgetvalue(self, value):
1068
"""
1069
Sets value for valuewidget.
1070
Depends on attribute type and hence widgettype.
1071
To be overwritten.
1072
"""
1073
# print 'set_widgetvalue',dir(self.widgets['value'][0])
1074
self.widgets['value'][0].SetValue(value)
1075
1076
1077
class DatetimeWidgetContainer(IntegerWidgetContainer):
1078
"""
1079
Contains one or several widgets representing a time and date attributes.
1080
1081
"""
1082
1083
def define_widgetset(self):
1084
"""
1085
Generates the widgets representing this attribute.
1086
"""
1087
if self._attrconf.has_unit() & self._attrconf.is_writable():
1088
return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),
1089
('value', self.create_valuewidget(), wx.EXPAND),
1090
('unit', self.create_unitwidget(), wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), ]
1091
else:
1092
return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),
1093
('value', self.create_valuewidget(), wx.EXPAND)]
1094
1095
def get_valuewidget_read(self):
1096
"""
1097
Return widget to read only numeric value of attribute
1098
This is effectively the parametrisation of the masked.NumCtrl widget.
1099
"""
1100
# print 'TextWidgetContainer.get_valuewidget_read'
1101
# widget=self.get_valuewidget_write()
1102
dtime = self.get_value_obj()
1103
#time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime())
1104
value = time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime(dtime))
1105
1106
widget = wx.TextCtrl(self.parent, -1, value, style=wx.ALIGN_RIGHT | wx.TE_READONLY)
1107
widget.Enable(False)
1108
1109
return widget
1110
1111
1112
class ListWidgetContainer(WidgetContainer):
1113
"""
1114
Contains one or several widgets representing a text attribute.
1115
1116
"""
1117
1118
def define_widgetset(self):
1119
"""
1120
Generates the widgets representing this attribute.
1121
"""
1122
if self._attrconf.has_unit() & self._attrconf.is_writable():
1123
return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),
1124
('value', self.create_valuewidget(), wx.EXPAND),
1125
('unit', self.create_unitwidget(), wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), ]
1126
else:
1127
return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),
1128
('value', self.create_valuewidget(), wx.EXPAND)]
1129
1130
# def get_valuewidget_read(self):
1131
# """
1132
# Return widget to read only numeric value of attribute
1133
# This is effectively the parametrisation of the masked.NumCtrl widget.
1134
# """
1135
# value = self.get_value_obj()
1136
# #print 'ListWidgetContainer',value
1137
#
1138
# widget = wx.TextCtrl( self.parent, -1, list_to_str(list(value)),style= wx.ALIGN_RIGHT|wx.TE_MULTILINE|wx.TE_READONLY)
1139
# self.set_textevents(widget)
1140
# widget.Enable(False)
1141
# return widget
1142
1143
def get_valuewidget_write(self):
1144
"""
1145
Return widget to edit numeric value of attribute
1146
This is effectively the parametrisation of the masked.NumCtrl widget.
1147
"""
1148
if self._attrconf.get_metatype() == 'list':
1149
sep = self._attrconf.sep
1150
is_ok = True # assuming that List configs are flat
1151
else:
1152
sep = ','
1153
is_ok = is_list_flat(self.get_value_obj())
1154
1155
value = list_to_str(self.get_value_obj(), sep=sep)
1156
if is_ok:
1157
widget = wx.TextCtrl(self.parent, -1, value, style=wx.ALIGN_LEFT | wx.TE_MULTILINE)
1158
else: # only flat lists can be edited :(
1159
widget = wx.TextCtrl(self.parent, -1, value, style=wx.ALIGN_RIGHT | wx.TE_MULTILINE)
1160
widget.Enable(False)
1161
1162
self.set_textevents(widget)
1163
return widget
1164
1165
def get_widgetvalue(self):
1166
"""
1167
Returnes current value from valuewidget.
1168
Depends on attribute type and hence widgettype.
1169
To be overwritten.
1170
"""
1171
# print 'get_widgetvalue', self.widgets['value'][0].GetValue()
1172
# print ' returns', str_to_list(self.widgets['value'][0].GetValue())
1173
if self._attrconf.get_metatype() == 'list':
1174
return self._attrconf.get_value_from_string(self.widgets['value'][0].GetValue())
1175
else:
1176
return str_to_list(self.widgets['value'][0].GetValue())
1177
1178
def set_widgetvalue(self, value):
1179
"""
1180
Sets value for valuewidget.
1181
Depends on attribute type and hence widgettype.
1182
To be overwritten.
1183
"""
1184
# print 'set_widgetvalue',value,is_list_flat(value)
1185
if self._attrconf.get_metatype() == 'list':
1186
sep = self._attrconf.sep
1187
1188
else:
1189
sep = ','
1190
1191
if is_list_flat(value): # &self._attrconf.is_editable():
1192
self.widgets['value'][0].SetValue(list_to_str(value, sep=sep))
1193
else: # only flat lists can be edited :(
1194
self.widgets['value'][0].SetValue(repr(value, sep=sep))
1195
1196
1197
class ObjWidgetContainer(AttrBase, WidgetContainer):
1198
"""
1199
Contains one or several widgets representing an obj attribute.
1200
1201
"""
1202
1203
def define_widgetset(self):
1204
"""
1205
Generates the widgets representing this attribute.
1206
"""
1207
# print 'define_widgetset',self._attrconf.attrname, self._attrconf.get_value()
1208
1209
return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),
1210
('value', self.create_valuewidget(), wx.EXPAND),
1211
]
1212
1213
def get_valuewidget_read(self):
1214
"""
1215
Returns instance of non-editable widget
1216
To be overwritten.
1217
"""
1218
# print 'get_valuewidget_read',self._attrconf.attrname
1219
# print 'get_numeditwidget',value
1220
# Here just the plain static text widget is returned
1221
#obj = self._attrconf.get_value()
1222
#METATYPES_LINKSTYLE = ('obj','id','tabid','ids')
1223
mt = self._attrconf.get_metatype()
1224
obj = value = self.get_value_obj()
1225
# print ' value',value,type(obj),str(obj),mt
1226
if mt == 'obj':
1227
text = str(obj.format_ident())
1228
1229
elif mt == 'id':
1230
if value == -1:
1231
# id not yet assigned
1232
widget = wx.TextCtrl(self.parent, -1, '-', style=wx.ALIGN_RIGHT | wx.TE_READONLY)
1233
widget.Enable(False)
1234
return widget
1235
else:
1236
text = self._attrconf.get_linktab().format_id(value)
1237
1238
elif mt == 'ids':
1239
if value is None:
1240
# id not yet assigned
1241
widget = wx.TextCtrl(self.parent, -1, '', style=wx.ALIGN_RIGHT | wx.TE_READONLY)
1242
widget.Enable(False)
1243
return widget
1244
else:
1245
text = self._attrconf.get_linktab().format_ids(value)
1246
# print ' text',text,type(text)
1247
#
1248
# elif mt == 'tabid':
1249
# text = str(obj)
1250
else:
1251
text = str(obj)
1252
1253
# print 'create_valuewidget: '+value,self.attr
1254
#widget=wx.StaticText(self.parent, -1,text,style=wx.ALIGN_RIGHT)
1255
widget = hyperlink.HyperLinkCtrl(self.parent, wx.ID_ANY, text, URL=text)
1256
widget.AutoBrowse(False)
1257
1258
widget.Bind(hyperlink.EVT_HYPERLINK_LEFT, self.on_objlink)
1259
1260
return widget
1261
1262
def get_valuewidget_write(self):
1263
"""
1264
Return widget to edit numeric value of attribute
1265
"""
1266
1267
# print 'get_valuewidget_write',self._attrconf.attrname
1268
# Here just the plain static text widget is returned
1269
#obj = self._attrconf.get_value()
1270
#METATYPES_LINKSTYLE = ('obj','id','tabid','ids')
1271
mt = self._attrconf.get_metatype()
1272
obj = value = self.get_value_obj()
1273
linktab = self._attrconf.get_linktab()
1274
# print ' value',value,type(value),str(obj),mt
1275
if mt == 'id':
1276
#text = self._attrconf.get_linktab().format_id(value)
1277
choices = linktab.format_id(linktab.get_ids()).split(',')
1278
if len(choices) > 0:
1279
widget = wx.Choice(self.parent, -1, (100, 50), choices=choices)
1280
ind = choices.index(linktab.format_id(value))
1281
if value == -1:
1282
# no id specified, use first one
1283
widget.SetSelection(0)
1284
else:
1285
widget.SetSelection(ind)
1286
else:
1287
# there are no ids to point to
1288
widget = wx.TextCtrl(self.parent, -1, '-', style=wx.ALIGN_RIGHT | wx.TE_READONLY)
1289
widget.Enable(False)
1290
return widget
1291
1292
if mt == 'obj':
1293
text = str(obj.format_ident())
1294
1295
elif mt == 'ids':
1296
text = self._attrconf.get_linktab().format_ids(value)
1297
#
1298
# elif mt == 'tabid':
1299
# text = str(obj)
1300
else:
1301
text = str(obj)
1302
1303
# print 'create_valuewidget: '+value,self.attr
1304
#widget=wx.StaticText(self.parent, -1,text,style=wx.ALIGN_RIGHT)
1305
widget = hyperlink.HyperLinkCtrl(self.parent, wx.ID_ANY, text, URL=text)
1306
widget.AutoBrowse(False)
1307
1308
widget.Bind(hyperlink.EVT_HYPERLINK_LEFT, self.on_objlink)
1309
1310
return widget
1311
1312
def on_objlink(self, event):
1313
# print 'on_objlink:',self.get_objvalue().ident
1314
1315
value = self.get_objvalue()
1316
mt = self._attrconf.get_metatype()
1317
1318
if self.parent.func_change_obj:
1319
if mt == 'obj':
1320
if type(value) == types.InstanceType:
1321
# print ' ident?',hasattr(value,'ident')
1322
if hasattr(value, 'ident'):
1323
navitimer = wx.FutureCall(1, self.parent.func_change_obj, value)
1324
1325
elif mt == 'id':
1326
linktab = self._attrconf.get_linktab()
1327
navitimer = wx.FutureCall(1, self.parent.func_change_obj, linktab, value) # here value is id
1328
1329
elif mt == 'ids':
1330
linktab = self._attrconf.get_linktab()
1331
navitimer = wx.FutureCall(1, self.parent.func_change_obj, linktab,
1332
None, value) # here value is list with ids
1333
1334
elif mt == 'tabid':
1335
linktab, id = value
1336
navitimer = wx.FutureCall(1, self.parent.func_change_obj, linktab, id)
1337
1338
# if self._attrconf.is_colattr(): # parent is holding the row id
1339
#self._attrconf[self.parent.id] = value
1340
else:
1341
#navitimer = wx.FutureCall(1, self.parent.func_change_obj,self.get_objvalue())
1342
pass
1343
1344
event.Skip()
1345
1346
def get_widgetvalue(self):
1347
"""
1348
Returnes current value from valuewidget.
1349
Depends on attribute type and hence widgettype.
1350
To be overwritten.
1351
"""
1352
mt = self._attrconf.get_metatype()
1353
val = self.valuewidget.GetStringSelection() # GetString
1354
# print 'get_widgetvalue', val,mt
1355
# print ' ',dir(self.valuewidget)
1356
# if self._choicevalues.count(val)>0:
1357
if mt == 'id':
1358
if val == '-':
1359
return -1
1360
else:
1361
return self._attrconf.get_linktab().get_id_from_formatted(val)
1362
else:
1363
return self.valuewidget.GetValue()
1364
1365
def set_widgetvalue(self, val):
1366
"""
1367
Sets value for valuewidget.
1368
Depends on attribute type and hence widgettype.
1369
To be overwritten.
1370
"""
1371
# print 'set_widgetvalue',self._attrconf.attrname, val, self._attrconf.is_writable()
1372
# if self._choicevalues.count(val)>0:
1373
#ind = self._choicevalues.index(val)
1374
# self.valuewidget.SetSelection(ind)
1375
# else:
1376
# self.valuewidget.SetValue(val)
1377
1378
# try:
1379
# #ind = self._choicenames.index(value)
1380
# ind = self._choicevalues.index(val)
1381
# except:
1382
# print 'WARNING in ChoiceWidgetContainer.set_widgetvalue: %s with value "%s" not in choice list'%(self._attrconf.attrname,val)
1383
# return
1384
# print ' ind',ind,self.valuewidget
1385
if self._attrconf.is_writable():
1386
self.valuewidget.SetStringSelection(self._attrconf.get_linktab().format_id(val))
1387
# self.valuewidget.SetSelection(ind)
1388
else:
1389
pass
1390
# self.valuewidget.SetValue(val)
1391
1392
1393
class ColorWidgetContainer(AttrBase, TextWidgetContainer):
1394
def define_widgetset(self):
1395
"""
1396
Generates the widgets representing this attribute.
1397
"""
1398
return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),
1399
('value', self.create_valuewidget(), wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), # wx.EXPAND
1400
#('unit', self.create_unitwidget(), wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL),
1401
]
1402
1403
def get_valuewidget_write(self):
1404
"""
1405
Return widget to edit numeric value of attribute
1406
"""
1407
1408
value = self.get_value_obj()
1409
# print 'ColorWidgetContainer.get_valuewidget_write',self._attrconf.attrname,value,type(value)
1410
1411
#widget = wx.TextCtrl( self.parent, -1, str(value),style= wx.ALIGN_RIGHT)
1412
cint = np.array(np.array(value)*255, np.int32)
1413
# wx.Colour(cint[0],cint[1],cint[2],cint[3])
1414
widget = coloursel.ColourSelect(
1415
self.parent, -1, "", wx.Colour(cint[0], cint[1], cint[2], cint[3]), size=wx.DefaultSize)
1416
# self.set_textevents(widget)
1417
# widget.Enable(True)
1418
if self.immediate_apply:
1419
widget.Bind(coloursel.EVT_COLOURSELECT, self.on_colorselect)
1420
return widget
1421
1422
def on_colorselect(self, event):
1423
self.apply_valuewidget_to_obj()
1424
1425
def get_valuewidget_read(self):
1426
"""
1427
Return widget to edit numeric value of attribute
1428
"""
1429
1430
value = self.get_value_obj()
1431
# print 'get_editwidget text',value,type(value)
1432
1433
#widget = wx.TextCtrl( self.parent, -1, str(value),style= wx.ALIGN_RIGHT)
1434
cint = np.array(np.array(value)*255, np.int32)
1435
widget = coloursel.ColourSelect(
1436
self.parent, -1, "", wx.Colour(cint[0], cint[1], cint[2], cint[3]), size=wx.DefaultSize)
1437
# self.set_textevents(widget)
1438
widget.Enable(False)
1439
return widget
1440
1441
def get_widgetvalue(self):
1442
"""
1443
Returnes current value from valuewidget.
1444
Depends on attribute type and hence widgettype.
1445
To be overwritten.
1446
"""
1447
1448
c = self.widgets['value'][0].GetColour()
1449
# print 'ColorWidgetContainer.get_widgetvalue',self._attrconf.attrname, c, type(c),type(c) == types.InstanceType#types.ClassType
1450
#color = np.array([c.Red(),c.Green(),c.Blue(),c.Alpha()],np.float32)/255.0
1451
return np.array([c.Red(), c.Green(), c.Blue(), c.Alpha()], np.float32)/255.0
1452
1453
def set_widgetvalue(self, value):
1454
"""
1455
Sets value for valuewidget.
1456
Depends on attribute type and hence widgettype.
1457
To be overwritten.
1458
"""
1459
cint = np.array(np.array(value)*255, np.int32)
1460
self.widgets['value'][0].SetValue(wx.Colour(cint[0], cint[1], cint[2], cint[3]))
1461
1462
1463
class FilepathWidgetContainer(AttrBase, TextWidgetContainer):
1464
def define_widgetset(self):
1465
"""
1466
Generates the widgets representing this attribute.
1467
"""
1468
return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),
1469
('value', self.create_valuewidget(), wx.EXPAND),
1470
('unit', self.create_unitwidget(), wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), ]
1471
1472
def get_valuewidget_read(self):
1473
"""
1474
Return widget to read only numeric value of attribute
1475
This is effectively the parametrisation of the masked.NumCtrl widget.
1476
"""
1477
# print 'TextWidgetContainer.get_valuewidget_read'
1478
# widget=self.get_valuewidget_write()
1479
value = self.get_value_obj()
1480
widget = wx.TextCtrl(self.parent, -1, value, style=wx.ALIGN_LEFT | wx.TE_READONLY)
1481
widget.Enable(False)
1482
1483
return widget
1484
1485
def get_valuewidget_write(self):
1486
"""
1487
Return widget to edit numeric value of attribute
1488
This is effectively the parametrisation of the masked.NumCtrl widget.
1489
"""
1490
1491
value = self.get_value_obj()
1492
# print 'get_editwidget text',value,type(value)
1493
1494
widget = wx.TextCtrl(self.parent, -1, value, style=wx.ALIGN_LEFT)
1495
self.set_textevents(widget)
1496
return widget
1497
#self.MultiLine = wx.TextCtrl(parent = panel, id = -1, pos = (38, 70), size = (410, 90), style = wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_AUTO_URL)
1498
1499
def create_unitwidget(self):
1500
#widget = wx.Button(self.parent, wx.ID_OPEN)
1501
bitmap = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR)
1502
widget = wx.BitmapButton(self.parent, -1, bitmap, (12, 12),
1503
(bitmap.GetWidth()+6, bitmap.GetHeight()+6))
1504
widget.Bind(wx.EVT_BUTTON, self.on_fileopen)
1505
# print 'create_unitwidget',self._attrconf.attrname,widget
1506
return widget
1507
1508
def on_fileopen(self, event):
1509
# print 'on_fileopen',self._attrconf.attrname
1510
# if type(self._attrconf.get_default())==types.StringType:
1511
# defaultname = self._attrconf.get_default()
1512
# else:
1513
# defaultname = os.getcwd()
1514
wildcards_all = "All files (*.*)|*.*"
1515
if hasattr(self._attrconf, 'wildcards'):
1516
wildcards = self._attrconf.wildcards+"|"+wildcards_all
1517
else:
1518
wildcards = wildcards_all
1519
1520
# guess default value
1521
filepath = self.get_objvalue()
1522
if type(filepath) not in STRINGTYPES:
1523
filepath = ""
1524
dirpath = os.path.expanduser("~") # os.getcwd()
1525
else:
1526
if len(filepath) == 0:
1527
dirpath = os.path.expanduser("~") # os.getcwd()
1528
else:
1529
dirpath = os.path.dirname(filepath)
1530
1531
# print 'on_fileopen dirpath',dirpath
1532
dlg = wx.FileDialog(self.parent, message="Open file",
1533
defaultDir=dirpath,
1534
#defaultFile= filepath,
1535
wildcard=wildcards,
1536
style=wx.OPEN | wx.CHANGE_DIR
1537
)
1538
1539
# Show the dialog and retrieve the user response. If it is the OK response,
1540
# process the data.
1541
if dlg.ShowModal() == wx.ID_OK:
1542
filepath = dlg.GetPath()
1543
1544
# print 'on_fileopen set filepath',filepath
1545
self.set_widgetvalue(filepath)
1546
if self.immediate_apply:
1547
self.apply_valuewidget_to_obj()
1548
# print ' self.get_widgetvalue()',self.get_widgetvalue()
1549
dlg.Destroy()
1550
1551
1552
class FilepathsWidgetContainer(FilepathWidgetContainer):
1553
1554
def on_fileopen(self, event):
1555
# print 'FilepathsWidgetContainer.on_fileopen',self._attrconf.attrname
1556
# if type(self._attrconf.get_default())==types.StringType:
1557
# defaultname = self._attrconf.get_default()
1558
# else:
1559
# defaultname = os.getcwd()
1560
1561
wildcards_all = "All files (*.*)|*.*"
1562
if hasattr(self._attrconf, 'wildcards'):
1563
wildcards = self._attrconf.wildcards+"|"+wildcards_all
1564
else:
1565
wildcards = wildcards_all
1566
1567
# guess default value
1568
filepath = self.get_objvalue()
1569
# print ' filepath',filepath,type(filepath)
1570
if type(filepath) not in STRINGTYPES:
1571
filepath = ""
1572
dirpath = dirpath = os.path.expanduser("~") # os.getcwd()
1573
else:
1574
if len(filepath) == 0:
1575
dirpath = dirpath = os.path.expanduser("~") # os.getcwd()
1576
else:
1577
# take directory of first filepath
1578
dirpath = os.path.dirname(filepath.split(',')[0])
1579
1580
# print ' dirpath',dirpath
1581
# print ' filepath',filepath
1582
dlg = wx.FileDialog(self.parent, message="Open file",
1583
defaultDir=dirpath,
1584
#defaultFile= filepath,
1585
wildcard=wildcards,
1586
style=wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR
1587
)
1588
1589
# Show the dialog and retrieve the user response. If it is the OK response,
1590
# process the data.
1591
if dlg.ShowModal() == wx.ID_OK:
1592
# This returns a Python list of files that were selected.
1593
filepaths = dlg.GetPaths()
1594
# print 'You selected %d files:' % len(paths)
1595
1596
# print 'on_fileopen set filepath',filepath
1597
# self.set_widgetvalue(filepathlist_to_filepathstring(filepaths))
1598
1599
# save path as comma separated string, but not with special primes
1600
self.set_widgetvalue(','.join(filepaths))
1601
if self.immediate_apply:
1602
self.apply_valuewidget_to_obj()
1603
# print ' self.get_widgetvalue()',self.get_widgetvalue()
1604
dlg.Destroy()
1605
1606
1607
class DirpathWidgetContainer(AttrBase, TextWidgetContainer):
1608
def define_widgetset(self):
1609
"""
1610
Generates the widgets representing this attribute.
1611
"""
1612
return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),
1613
('value', self.create_valuewidget(), wx.EXPAND),
1614
('unit', self.create_unitwidget(), wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), ]
1615
1616
def create_unitwidget(self):
1617
if self._attrconf.is_writable():
1618
#widget = wx.Button(self.parent, wx.ID_OPEN)
1619
bitmap = wx.ArtProvider.GetBitmap(wx.ART_FOLDER_OPEN, wx.ART_TOOLBAR)
1620
widget = wx.BitmapButton(self.parent, -1, bitmap, (12, 12),
1621
(bitmap.GetWidth()+6, bitmap.GetHeight()+6))
1622
widget.Bind(wx.EVT_BUTTON, self.on_diropen)
1623
# print 'create_unitwidget',self._attrconf.attrname,widget
1624
return widget
1625
else:
1626
return (0, 0)
1627
1628
def on_diropen(self, event):
1629
dlg = wx.DirDialog(self.parent, message="Open directory",
1630
#style=wx.DD_DEFAULT_STYLE| wx.DD_DIR_MUST_EXIST| wx.DD_CHANGE_DIR
1631
style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER | wx.DD_CHANGE_DIR
1632
)
1633
1634
if dlg.ShowModal() == wx.ID_OK:
1635
dirpath = dlg.GetPath()
1636
self.set_widgetvalue(dirpath)
1637
if self.immediate_apply:
1638
self.apply_valuewidget_to_obj()
1639
# print ' self.get_widgetvalue()',self.get_widgetvalue()
1640
dlg.Destroy()
1641
1642
1643
class ScalarPanel(wx.Panel):
1644
"""
1645
Interactively displays scalar attributes of object on a parent panel.
1646
"""
1647
1648
def __init__(self, parent, attrconfigs=[], id=None,
1649
func_change_obj=None,
1650
mainframe=None, panelstyle='default', immediate_apply=None):
1651
# wx.Panel.__init__(self,parent,-1,style=wx.WANTS_CHARS)
1652
wx.Panel.__init__(self, parent, -1, size=(-1, 300))
1653
#wx.scrolledpanel.ScrolledPanel.__init__(self, parent,wx.ID_ANY)
1654
#self.maxWidth = 1000
1655
#self.maxHeight = 1000
1656
#self.SetVirtualSize((self.maxWidth, self.maxHeight))
1657
# self.SetScrollRate(10,10)
1658
1659
# parent must be panel, scrolled panel or similar
1660
self.parent = parent
1661
1662
self.id = id
1663
1664
# target obj
1665
#self.obj = obj
1666
1667
self.func_change_obj = func_change_obj
1668
self.mainframe = mainframe
1669
#self.panelstyle = panelstyle
1670
#self.immediate_apply = immediate_apply
1671
1672
# background colors for lines shading:
1673
self.tablecolors = get_tablecolors()
1674
1675
# print 'ScalarPanel.__init__ id=',self.id#,parent,self.obj
1676
# print ' immediate_apply=',immediate_apply
1677
1678
self.widgetcontainers = []
1679
1680
self.create_attrs(attrconfigs, immediate_apply=immediate_apply, panelstyle=panelstyle)
1681
self.SetAutoLayout(True)
1682
self.Refresh()
1683
1684
# def get_pentable(self):
1685
# """
1686
# Returns pentable used for this panel
1687
# """
1688
# return self.parent.get_pentable()
1689
1690
def create_attrs(self, attrconfigs, immediate_apply=False, panelstyle='default'):
1691
"""
1692
Go through list with attribute names and create widgets and
1693
put them in a grid sizer.
1694
"""
1695
# print '\n\ncreate_attrs',len(attrconfigs)
1696
# print ' mt=',self.obj.get_config(attrs[0])['metatype']
1697
1698
# self.add_id_named(name,id,colors=color)
1699
# get widgets
1700
# id=1
1701
i = 0
1702
for attrconfig in attrconfigs:
1703
1704
# generates alternating colors (currently not in use)
1705
color_bg = self.tablecolors[divmod(i, len(self.tablecolors))[1]]
1706
container = self.get_widgetcontainer(attrconfig, color_bg=color_bg,
1707
immediate_apply=immediate_apply,
1708
panelstyle=panelstyle)
1709
self.widgetcontainers.append(container)
1710
# self.add_id_named(attr,widgetcontainers=container)
1711
# self.create_ids(id,widgetcontainers=container)
1712
i += 1
1713
1714
# now ask for widget names and try to align them
1715
widgetnames = []
1716
for container in self.widgetcontainers:
1717
names = container.get_widgetnames()
1718
1719
if len(widgetnames) == 0:
1720
widgetnames = names
1721
else:
1722
widgetnames = self._align(widgetnames, names)
1723
1724
# print ' result of alignment:',attr,names,widgetnames
1725
# widgetnames.index...
1726
1727
# now dimensions of grid are known, so configure sizer
1728
# print 'grid size=',len(attrs), len(widgetnames)
1729
sizer = wx.FlexGridSizer(len(attrconfigs), len(widgetnames), vgap=2, hgap=0)
1730
sizer.AddGrowableCol(1)
1731
# print 'widgetnames',widgetnames
1732
# throw widgets into sizer
1733
for container in self.widgetcontainers:
1734
# print 'build grid for attr',container._attrconf.attrname
1735
# container=self.get_value_named('widgetcontainers',attr)
1736
# print 'attr',attr,widgetnames
1737
widgetsinfo = container.get_widgetsinfo(widgetnames)
1738
# print ' widgetsinfo=',widgetsinfo
1739
for widget, align in widgetsinfo:
1740
# print ' add widget align=',widget,align
1741
sizer.Add(widget, 0, align)
1742
1743
# works on panel...
1744
#parent.SetHelpText('The Agile Panel')
1745
self.SetAutoLayout(True)
1746
self.SetSizer(sizer)
1747
sizer.Fit(self)
1748
1749
def get_widgetcontainer(self, attrconf, **args):
1750
"""
1751
Figures out what widget container, containing a set of widgets,
1752
would be the most aprobriate to represent this attribute.
1753
"""
1754
# print '\n\nScalarPanel.get_widgetcontainer',attrconf.attrname
1755
1756
# config=self.obj.get_config(attr)
1757
# get type list (full depth)
1758
# t=attrconfig.get_default()
1759
1760
# take top level type
1761
# tt=t[0]
1762
tt = type(attrconf.get_default())
1763
1764
# get metatype
1765
mt = attrconf.get_metatype()
1766
1767
# print ' default,mt,tt',attrconf.get_default(),type(attrconf.get_default()),mt,tt,mt in METATYPES_LINKSTYLE
1768
1769
# if config.has_key('choices'):
1770
# # pop up with a choices list
1771
# return ChoiceWidgetContainer(self,attr,**args)
1772
1773
# check if this is an id within a referenced object
1774
# if mt=='id':
1775
# return IdWidgetContainer(self,attr,**args)
1776
#
1777
# check if widgets for metatypes are availlable
1778
# elif mt=='color':
1779
# #print ' ->WidgetContainer'
1780
# return ColorWidgetContainer(self,attr,**args)
1781
1782
# elif mt=='pentype':
1783
# return PentypeContainer(self,attr,**args)
1784
1785
if mt in METATYPES_LINKSTYLE:
1786
return ObjWidgetContainer(self, attrconf, **args)
1787
1788
elif mt == 'color':
1789
return ColorWidgetContainer(self, attrconf, **args)
1790
1791
elif (mt == 'list') & hasattr(attrconf, 'choices'):
1792
return ChecklistWidgetContainer(self, attrconf, **args)
1793
1794
elif (mt == 'list'):
1795
return ListWidgetContainer(self, attrconf, **args)
1796
1797
elif hasattr(attrconf, 'choices'):
1798
return ChoiceWidgetContainer(self, attrconf, **args)
1799
1800
elif mt == 'filepath':
1801
return FilepathWidgetContainer(self, attrconf, **args)
1802
1803
elif mt == 'filepaths':
1804
return FilepathsWidgetContainer(self, attrconf, **args)
1805
1806
elif mt == 'dirpath':
1807
return DirpathWidgetContainer(self, attrconf, **args)
1808
elif mt == 'datetime':
1809
return DatetimeWidgetContainer(self, attrconf, **args)
1810
1811
# elif mt == 'number':
1812
if tt in (types.IntType, types.LongType):
1813
return IntegerWidgetContainer(self, attrconf, **args)
1814
elif tt in (types.FloatType, types.ComplexType):
1815
return NumericWidgetContainer(self, attrconf, **args)
1816
1817
# check now native types
1818
1819
elif tt in (types.BooleanType,):
1820
return BooleanWidgetContainer(self, attrconf, **args)
1821
1822
elif tt in STRINGTYPES:
1823
return TextWidgetContainer(self, attrconf, **args)
1824
1825
# elif tt in (types.InstanceType,types.ClassType):
1826
# return ObjWidgetContainer(self,attrconf,**args)
1827
1828
elif tt in (types.ListType, types.TupleType):
1829
return ListWidgetContainer(self, attrconf, **args)
1830
1831
else:
1832
# else means use a the base class that can display anything
1833
return WidgetContainer(self, attrconf, **args)
1834
# else:
1835
# # else means use a the base class that can display anything
1836
# return WidgetContainer(self,attr,self,**args)
1837
1838
def apply(self):
1839
"""
1840
Widget values are copied to object
1841
"""
1842
for widgetcontainer in self.widgetcontainers:
1843
widgetcontainer.apply_valuewidget_to_obj()
1844
# this is to update widgets of function values
1845
# self.restore()
1846
1847
def restore(self):
1848
"""
1849
Object values are copied into widgets.
1850
"""
1851
for widgetcontainer in self.widgetcontainers:
1852
widgetcontainer.apply_obj_to_valuewidget()
1853
1854
def _align(self, widgetnames, names):
1855
"""
1856
tries to align widgetnames with a new list of names
1857
"""
1858
# print '_align'
1859
names_prepend = []
1860
i = 0
1861
1862
while (len(names_prepend) == 0) & (i < len(names)):
1863
if widgetnames.count(names[i]) > 0:
1864
names_prepend = names[:i]
1865
i += 1
1866
1867
# print ' names_prepend',names_prepend
1868
newnames = widgetnames
1869
for name in names_prepend:
1870
self._prepend_name(newnames, name)
1871
1872
for name in names:
1873
self._append_name(newnames, name)
1874
1875
return newnames
1876
1877
def _append_name(self, names, name):
1878
"""
1879
Appends name if not in list
1880
"""
1881
if names.count(name) == 0:
1882
names.append(name)
1883
1884
def _prepend_name(self, names, name):
1885
"""
1886
Predends name if not in list
1887
"""
1888
if names.count(name) == 0:
1889
names.insert(name, 0)
1890
1891
1892
class ScalarPanelScrolled(wxlib.scrolledpanel.ScrolledPanel, ScalarPanel):
1893
"""
1894
Interactively displays scalar attributes of object on a parent panel.
1895
"""
1896
1897
def __init__(self, parent, attrconfigs=[], id=None,
1898
func_change_obj=None,
1899
mainframe=None, is_modal=False,
1900
panelstyle='default', immediate_apply=None):
1901
# wx.Panel.__init__(self,parent,-1,style=wx.WANTS_CHARS)
1902
# wx.Panel.__init__(self,parent,-1)
1903
if is_modal:
1904
wxlib.scrolledpanel.ScrolledPanel.__init__(self, parent, wx.ID_ANY, size=(600, 400))
1905
else:
1906
wxlib.scrolledpanel.ScrolledPanel.__init__(self, parent, wx.ID_ANY, size=wx.DefaultSize)
1907
#self.maxWidth = 2000
1908
#self.maxHeight = 300
1909
#self.SetVirtualSize((self.maxWidth, self.maxHeight))
1910
self.SetScrollRate(10, 10)
1911
1912
# parent must be panel, scrolled panel or similar
1913
self.parent = parent
1914
1915
self.id = id
1916
1917
# target obj
1918
#self.obj = obj
1919
1920
self.func_change_obj = func_change_obj
1921
self.mainframe = mainframe
1922
#self.panelstyle = panelstyle
1923
#self.immediate_apply = immediate_apply
1924
1925
# background colors for lines shading:
1926
self.tablecolors = get_tablecolors()
1927
1928
# print 'ScalarPanel.__init__'#,parent,self.obj
1929
# print ' immediate_apply=',immediate_apply
1930
1931
self.widgetcontainers = []
1932
1933
self.create_attrs(attrconfigs, immediate_apply=immediate_apply, panelstyle=panelstyle)
1934
# self.SetAutoLayout(True)
1935
# self.AutoLayout()
1936
# self.Refresh()
1937
# self.SetAutoLayout(1)
1938
# self.SetupScrolling()
1939
1940
self.Refresh()
1941
# self.Layout()
1942
1943
# self.SetupScrolling()
1944
1945
# self.Refresh()
1946
# self.Layout()
1947
1948
1949
class TableGrid(AttrBase, gridlib.PyGridTableBase):
1950
1951
"""
1952
This is all it takes to make a custom data table to plug into a
1953
wxGrid. There are many more methods that can be overridden, but
1954
the ones shown below are the required ones. This table simply
1955
provides strings containing the row and column values.
1956
"""
1957
1958
def __init__(self, parent, tab, attrconfigs, ids, show_ids=False, **args):
1959
gridlib.PyGridTableBase.__init__(self)
1960
1961
self.odd = gridlib.GridCellAttr()
1962
self.odd.SetBackgroundColour("sky blue")
1963
self.even = gridlib.GridCellAttr()
1964
self.even.SetBackgroundColour("sea green")
1965
1966
# target obj
1967
self.tab = tab
1968
self.parent = parent
1969
1970
# print 'gridlib.PyGridTableBase\n'#,dir(gridlib.PyGridTableBase)
1971
self.ids = ids
1972
self.show_ids = show_ids
1973
self.attrconfigs = attrconfigs
1974
1975
# print 'TableGrid: attrs,ids=',len(self.attrconfigs),'X',len(self.ids)
1976
1977
col = 0
1978
self.colnames = []
1979
self.celltypes = []
1980
# self.cellattrs=[]
1981
# print ' make header'
1982
for attrconf in attrconfigs:
1983
if hasattr(attrconf, 'symbol'):
1984
symbol = attrconf.symbol
1985
else:
1986
symbol = attrconf.get_name()
1987
unit = attrconf.format_unit(show_parentesis=True)
1988
if len(unit) > 0:
1989
if len(symbol) > 7:
1990
symbol += '\n'+unit
1991
else:
1992
symbol += ' '+unit
1993
# print ' symbol',symbol
1994
self.colnames.append(symbol)
1995
self.celltypes.append(self.get_celltype(attrconf))
1996
col += 1
1997
# print ' done: header'
1998
1999
def get_celltype(self, attrconf):
2000
"""
2001
Returns type code string of a wx cell.
2002
http://permalink.gmane.org/gmane.comp.python.wxpython/102660
2003
"""
2004
# config=self.obj.get_config(attr)
2005
# tt=config['type'][0]
2006
# check fist if widgets for metatypes are availlable
2007
# if mt=='color':
2008
# #print ' ->WidgetContainer'
2009
# return 'color'
2010
# #return WidgetContainer(self,attr,parent,**args)
2011
2012
# if config.has_key('choices'):
2013
# choicestring=wxGRID_VALUE_CHOICE+':'
2014
# for c in config['choices']:
2015
# choicestring+=c+','
2016
# choicestring=choicestring[:-1]
2017
# return choicestring
2018
2019
# check now native types
2020
# if len(config['type'])==1:
2021
mt = attrconf.metatype
2022
tt = type(attrconf.get_default())
2023
# print 'get_celltype',attrconf.attrname,mt,tt,hasattr(attrconf,'choices'),attrconf.is_writable()
2024
2025
if mt == 'objs':
2026
return gridlib.GRID_VALUE_STRING
2027
2028
elif mt == 'id':
2029
obj = attrconf.get_linktab()
2030
if attrconf.is_writable():
2031
if hasattr(attrconf, 'choices'):
2032
if len(attrconf.choices) < 200:
2033
# print ' choices=',attrconf.choices
2034
# (types.ListType, types.TupleType):
2035
if type(attrconf.choices) in (OrderedDict, types.DictionaryType):
2036
# print ' GridCellChoiceEditor',attrconf.choices,':'+','.join(attrconf.choices.keys())
2037
return gridlib.GRID_VALUE_CHOICE+':'+','.join(attrconf.choices.keys())
2038
else:
2039
# print ' GridCellChoiceEditor',attrconf.choices,':'+','.join(attrconf.choices)
2040
return gridlib.GRID_VALUE_CHOICE+':'+','.join(attrconf.choices)
2041
2042
#gridlib.GridCellChoiceEditor(['what','ever'], allowOthers=True)
2043
else:
2044
return gridlib.GRID_VALUE_STRING # still display a string with choice
2045
2046
elif len(obj) < 200:
2047
# print ' GridCellChoiceEditor',attrconf.attrname,':'+obj.format_ids(obj.get_ids())
2048
return gridlib.GRID_VALUE_CHOICE+':'+obj.format_ids(obj.get_ids())
2049
else:
2050
return gridlib.GRID_VALUE_STRING
2051
2052
return gridlib.GRID_VALUE_STRING
2053
2054
elif mt == 'tabid':
2055
return gridlib.GRID_VALUE_STRING
2056
2057
elif mt == 'ids':
2058
return gridlib.GRID_VALUE_STRING
2059
2060
elif hasattr(attrconf, 'choices'):
2061
if attrconf.is_writable():
2062
if len(attrconf.choices) < 200:
2063
# print ' dir(gridlib)',dir(gridlib)
2064
# (types.ListType, types.TupleType):
2065
if type(attrconf.choices) in (OrderedDict, types.DictionaryType):
2066
# print ' GridCellChoiceEditor',attrconf.choices,':'+','.join(attrconf.choices.keys())
2067
return gridlib.GRID_VALUE_CHOICE+':'+','.join(attrconf.choices.keys())
2068
else:
2069
# print ' GridCellChoiceEditor',attrconf.choices,':'+','.join(attrconf.choices)
2070
return gridlib.GRID_VALUE_CHOICE+':'+','.join(attrconf.choices)
2071
2072
#gridlib.GridCellChoiceEditor(['what','ever'], allowOthers=True)
2073
else:
2074
return gridlib.GRID_VALUE_STRING
2075
else:
2076
return gridlib.GRID_VALUE_STRING
2077
2078
elif tt in (types.LongType, types.IntType):
2079
if (hasattr(attrconf, 'min') & hasattr(attrconf, 'max')):
2080
return gridlib.GRID_VALUE_NUMBER+':'\
2081
+ str(attrconf.min)+','+str(attrconf.max)
2082
else:
2083
return gridlib.GRID_VALUE_NUMBER
2084
2085
elif tt in (types.FloatType, types.ComplexType):
2086
if (hasattr(attrconf, 'digits_integer') & hasattr(attrconf, 'digits_fraction')):
2087
return gridlib.GRID_VALUE_FLOAT+':'\
2088
+ str(attrconf.digits_integer)+','\
2089
+ str(attrconf.digits_fraction)
2090
else:
2091
return gridlib.GRID_VALUE_FLOAT
2092
2093
elif tt in STRINGTYPES:
2094
return gridlib.GRID_VALUE_STRING
2095
2096
elif tt in (types.BooleanType,):
2097
return gridlib.GRID_VALUE_BOOL
2098
2099
else:
2100
# else means use a the base class that can display anything
2101
return gridlib.GRID_VALUE_STRING
2102
2103
def GetNumberRows(self):
2104
return len(self.ids)
2105
2106
def GetNumberCols(self):
2107
return len(self.attrconfigs)
2108
2109
def IsEmptyCell(self, row, col):
2110
return (row > len(self.ids)) | (col > len(self.attrconfigs))
2111
2112
def GetValue(self, row, col):
2113
"""
2114
Returns object value to be displayed in the cell.
2115
"""
2116
# TODO: this should be all handled by format_value of the attrconf !!!!
2117
# try:
2118
if 1:
2119
rowid, attrconf = self.get_id_attrconf(row, col)
2120
if (rowid is None) | (attrconf is None):
2121
return 'Err'
2122
# attrconf=self.attrconfigs[col]
2123
val = self.get_objvalue(row, col)
2124
mt = attrconf.metatype
2125
2126
# print 'GetValue',self.ids[row],attrconf.attrname,val,mt,hasattr(attrconf,'choices'),attrconf.is_writable()
2127
2128
if mt == 'objs':
2129
return val.format_ident()
2130
2131
elif mt == 'id':
2132
# print ' id=',val,idtext
2133
# print ' linktab',attrconf.get_linktab(),idtext
2134
if val == -1:
2135
return '-'
2136
2137
if hasattr(attrconf, 'choices'):
2138
# this is for backwards compatibility
2139
# choices should no longer osed to index id
2140
# instead, the format_ids method should be used
2141
# (types.ListType, types.TupleType):
2142
if type(attrconf.choices) in (OrderedDict, types.DictionaryType):
2143
if attrconf.choices.values().count(val) > 0:
2144
ind = attrconf.choices.values().index(val)
2145
# print ' return',attrconf.choices.keys()[ind]
2146
return attrconf.choices.keys()[ind]
2147
else:
2148
return attrconf.get_linktab().format_ids([val])
2149
else:
2150
# print ' GridCellChoiceEditor',attrconf.choices,':'+','.join(attrconf.choices)
2151
return attrconf.get_linktab().format_ids([val])
2152
2153
else:
2154
# print ' return ',attrconf.get_linktab().format_ids([val])
2155
return attrconf.get_linktab().format_ids([val])
2156
2157
elif mt == 'ids':
2158
# print ' ids=',val,attrconf.get_linktab().format_ids(val)
2159
if val is None:
2160
return ''
2161
else:
2162
return attrconf.get_linktab().format_ids(val)
2163
2164
elif mt == 'tabid':
2165
obj, _id = val
2166
return obj.format_ident_row(_id)
2167
2168
elif mt == 'tabidlist':
2169
return attrconf.format_value(rowid) # <<<<<<<< should work for all types !!!
2170
2171
elif hasattr(attrconf, 'choices'):
2172
# print ' attrconf.choices',attrconf.choices
2173
if type(attrconf.choices) in (OrderedDict, types.DictionaryType): # (types.ListType, types.TupleType):
2174
if attrconf.choices.values().count(val) > 0:
2175
ind = attrconf.choices.values().index(val)
2176
# print ' return',attrconf.choices.keys()[ind]
2177
return attrconf.choices.keys()[ind]
2178
else:
2179
return val
2180
else:
2181
if attrconf.choices.count(val) > 0:
2182
ind = attrconf.choices.index(val)
2183
# print ' return',attrconf.choices[ind]
2184
return attrconf.choices[ind]
2185
else:
2186
return val
2187
2188
elif mt == 'color': # special config for colors
2189
# done by cell backgroundcolor
2190
return ''
2191
2192
# elif config.has_key('do_init_arrayobj'):
2193
# if config['do_init_arrayobj']:
2194
# return val.ident
2195
# else:
2196
# return val
2197
2198
else:
2199
return val
2200
2201
else:
2202
return 'Err'
2203
# except IndexError:
2204
# return 'Err'
2205
2206
def get_objvalue(self, row, col):
2207
"""
2208
Returns value of referred object according to row and col of grid
2209
"""
2210
return self.attrconfigs[col][self.ids[row]]
2211
2212
def get_valueconfigs(self):
2213
return self.attrconfigs
2214
2215
def get_id_attrconf(self, row, col):
2216
if (col >= 0) & (col < len(self.attrconfigs)):
2217
if (row >= 0) & (row < len(self.ids)):
2218
return self.ids[row], self.attrconfigs[col]
2219
else:
2220
return None, self.attrconfigs[col]
2221
else:
2222
if (row >= 0) & (row < len(self.ids)):
2223
return self.ids[row], None
2224
else:
2225
return None, None
2226
2227
# def get_perm(self, attrconf,id):
2228
# """
2229
# Return read write permission
2230
# """
2231
# # TODO: must be enhanced with grid specific rw
2232
# #print 'get_perm',id, attr
2233
# return attrconf.get_perm()
2234
2235
def SetValue(self, row, col, value):
2236
"""
2237
Transfer of cell value to object.
2238
"""
2239
id, attrconf = self.get_id_attrconf(row, col)
2240
if attrconf is not None:
2241
2242
if attrconf.is_writable():
2243
mt = attrconf.metatype
2244
# print 'SetValue(%d, %d, "%s").\n' % (row, col, value)
2245
2246
# print ' attrconf',id,attrconf.attrname, attrconf.is_writable(),hasattr(attrconf,'choices')
2247
# attr=self.attrs[col]
2248
tt = type(attrconf.get_default())
2249
if hasattr(attrconf, 'choices'):
2250
# print ' type(attrconf.choices)',type(attrconf.choices),type(attrconf.choices) in (OrderedDict, types.DictionaryType)
2251
# (types.ListType, types.TupleType):
2252
if type(attrconf.choices) in (OrderedDict, types.DictionaryType):
2253
# print ' set choices[value]',attrconf.choices[value]
2254
if attrconf.choices.has_key(value):
2255
attrconf[id] = attrconf.choices[value]
2256
else:
2257
attrconf[id] = value
2258
2259
else:
2260
# print ' set value',value
2261
attrconf[id] = value
2262
elif mt == 'id':
2263
attrconf[id] = attrconf.get_linktab().get_id_from_formatted(value)
2264
2265
elif (tt in NUMERICTYPES):
2266
# set only values of types that are allowed for the grid
2267
# TODO: this grid types data must be organized more central
2268
attrconf[id] = value
2269
else:
2270
# TODO: for other types, like color or arrays, this must be done beforehand
2271
print 'WARNING in SetValue: cannot write to this type:', tt
2272
else:
2273
# readonly
2274
pass
2275
# print 'SetValue(%d, %d, "%s") read only.\n' % (row, col, value)
2276
2277
# --------------------------------------------------
2278
# Some optional methods
2279
2280
# Called when the grid needs to display labels
2281
def GetColLabelValue(self, col):
2282
if (col > -1) & (col < len(self.colnames)):
2283
return self.colnames[col]
2284
else:
2285
return '-'
2286
2287
def GetRowLabelValue(self, col):
2288
return self.FormatRowLabel(self.tab, self.ids[col])
2289
2290
def FormatRowLabel(self, tab, id):
2291
# if tab.is_keyindex():
2292
# label = str(tab.get_key_from_id(id))
2293
# else:
2294
label = str(id)
2295
return label
2296
2297
# if size is None:
2298
# return label
2299
# else:
2300
# if size>=len(label):
2301
# return (size*' '+label)[-size:]
2302
# else:
2303
# return label
2304
2305
# def ComputeRowLabelSize(self):
2306
# size = 0
2307
# tab = self.tab
2308
# for id in self.ids:
2309
# l = len(self.FormatLabel( tab, id))
2310
# if l>size:
2311
# size=l
2312
# print 'ComputeRowLabelSize',size*16
2313
# return size*16# TODO here should be the font size as multiplier
2314
2315
def ComputeColLabelSize(self):
2316
"""
2317
Compute the maximum number of lines required for column labelling
2318
"""
2319
# print 'ComputeColLabelSize',self.colnames
2320
lines = 0
2321
for name in self.colnames:
2322
l = name.count('\n')
2323
if l > lines:
2324
lines = l
2325
size = (lines+1)*32
2326
# print ' size=',size
2327
return size # TODO here should be the font size as multiplier
2328
2329
def CanHaveAttributes(self):
2330
# TODO: if the story with returning the attribute
2331
# for each cell is getting too slow we might want to restrict this
2332
# to cases when we actually need to modify the attribute
2333
# as for example with colors
2334
return True
2335
2336
def GetAttr(self, row, col, flag=0):
2337
# print 'GetAttr row,col,flag',row,col,flag
2338
attrconf = self.attrconfigs[col]
2339
# print ' self.ids',self.ids
2340
id = self.ids[row]
2341
# config=self.obj.get_config(attr)
2342
tt = type(attrconf.get_default())
2343
mt = attrconf.metatype
2344
val = attrconf[id]
2345
# print 'GetAttr',attrconf.attrname,val#,config['type'][-1]
2346
# define cell attribute for this column
2347
cellattr = gridlib.GridCellAttr()
2348
2349
if attrconf.is_readonly():
2350
cellattr.SetReadOnly(True)
2351
2352
if mt == 'color': # special config for colors
2353
2354
cint = np.array(np.array(val)*255, np.int32)
2355
2356
# print ' cint=',cint
2357
# cellattr.SetBackgroundColour(wx.Colour(cint[0],cint[1],cint[2],cint[3]))
2358
cellattr.SetBackgroundColour(wx.Colour(*cint))
2359
2360
# elif config['metatype']=='penstyle':
2361
# cellattr.SetRenderer(PenstyleRenderer(self.obj.get_pentable()))
2362
2363
# check whether to make a hyperlink in blue to an instance
2364
# if len(config['type'])==1:
2365
# if (tt in (types.InstanceType,types.ClassType)):
2366
# if hasattr(val,'ident'):
2367
# print ' is configurator object',val.ident
2368
if mt in METATYPES_LINKSTYLE:
2369
cellattr.SetTextColour('blue')
2370
# no!!cellattr.SetFlags (wx.TEXT_ATTR_FONT_UNDERLINE)
2371
cellattr.SetReadOnly(False)
2372
2373
return cellattr
2374
2375
# Called to determine the kind of editor/renderer to use by
2376
# default, doesn't necessarily have to be the same type used
2377
# natively by the editor/renderer if they know how to convert.
2378
2379
def GetTypeName(self, row, col):
2380
if (col > -1) & (col < len(self.celltypes)):
2381
return self.celltypes[col]
2382
else:
2383
return wx._mainframe # this can do anything
2384
2385
# Called to determine how the data can be fetched and stored by the
2386
# editor and renderer. This allows you to enforce some type-safety
2387
# in the grid.
2388
2389
def CanGetValueAs(self, row, col, typeName):
2390
2391
colType = self.celltypes[col].split(':')[0]
2392
if typeName == colType:
2393
return True
2394
else:
2395
return False
2396
2397
def CanSetValueAs(self, row, col, typeName):
2398
#id, attr = self.get_id_attrconf( row, col )
2399
# print 'CanSetValueAs',id, attr
2400
return self.CanGetValueAs(row, col, typeName)
2401
2402
2403
# ---------------------------------------------------------------------------
2404
2405
# class TablePanel(wx.Panel):
2406
# def __init__(self, parent, tab, **args):
2407
# wx.Panel.__init__(self, parent, -1)
2408
# grid = TableFrame(self,tab, **args)
2409
# self.Sizer = wx.BoxSizer()
2410
# self.Sizer.Add(grid, 1, wx.EXPAND)
2411
#
2412
# #grid.SetReadOnly(5,5, True)
2413
# def restore(self):
2414
# pass
2415
# #self.grid.restore()
2416
2417
2418
class TabPanel(AttrBase, gridlib.Grid):
2419
def __init__(self, parent, tab, objpanel=None, attrconfigs=None, ids=None, show_ids=True,
2420
func_change_obj=None,
2421
func_choose_id=None,
2422
func_choose_attr=None,
2423
func_apply=None,
2424
mainframe=None, **args):
2425
"""
2426
parent: parent widget, containing the grid
2427
tab: table containing the actual data of an object
2428
"""
2429
# TODO: Attention: parent is always the main object panel
2430
2431
# print ' gridlib.Grid',dir(gridlib.Grid)
2432
gridlib.Grid.__init__(self, parent, -1) # , style =wx.EXPAND| wx.ALL)#wx.EAST | wx.WEST) )
2433
2434
# parent must be panel, scrolled panel or similar
2435
self.parent = parent
2436
self.tab = tab
2437
self._objpanel = objpanel
2438
self.func_change_obj = func_change_obj
2439
self.func_choose_id = func_choose_id
2440
self.func_choose_attr = func_choose_attr
2441
self.func_apply = func_apply
2442
self.mainframe = mainframe
2443
2444
if ids is None:
2445
# show all ids
2446
ids = tab.get_ids() # ordered=True
2447
2448
if attrconfigs is None:
2449
# show all array type attributes
2450
attrconfigs = tab.get_colconfigs()
2451
2452
# print 'init TablePanel',tab.get_ident(),ids
2453
# print ' start init TableGrid',len(ids),len(attrconfigs)
2454
# this table contains the gui functionalily of the grid
2455
table = TableGrid(self, tab, attrconfigs=attrconfigs, ids=ids,
2456
show_ids=show_ids, **args)
2457
# print ' end init TableGrid'
2458
# The second parameter means that the grid is to take ownership of the
2459
# table and will destroy it when done. Otherwise you would need to keep
2460
# a reference to it and call its Destroy method later.
2461
self.SetTable(table, True)
2462
# print ' done SetTable'
2463
# self.SetRowLabelSize(16)
2464
# self.SetColLabelSize(16)
2465
# self.SetRowLabelSize(table.ComputeRowLabelSize())
2466
self.SetColLabelSize(table.ComputeColLabelSize())
2467
# print ' done SetColLabelSize'
2468
#self.AutoSize ()
2469
2470
# for col in xrange(len(attrconfigs)):
2471
# self.AutoSizeColLabelSize (col)
2472
2473
# these operations are nice but slow for huge tables!!
2474
if len(ids) < 100:
2475
self.AutoSizeColumns(True)
2476
# print ' done AutoSizeColumns'
2477
if len(ids) < 100:
2478
self.AutoSizeRows(True)
2479
# print ' done AutoSizeRows'
2480
2481
# self.Bind(gridlib.EVT_GRID_CELL_CHANGE, self.on_cell_change) #works, but not used
2482
2483
# EVT_GRID_CELL_RIGHT_CLICK(self, self.OnRightDown) #added
2484
gridlib.EVT_GRID_CELL_RIGHT_CLICK(self, self.on_contextmenu) # added
2485
self.Bind(gridlib.EVT_GRID_LABEL_RIGHT_CLICK, self.on_contextmenu_label)
2486
2487
# does not seem to work
2488
gridlib.EVT_GRID_CELL_LEFT_DCLICK(self, self.on_edit_cell)
2489
gridlib.EVT_GRID_CELL_LEFT_CLICK(self, self.on_click_cell)
2490
2491
gridlib.EVT_GRID_LABEL_LEFT_DCLICK(self, self.OnLabelLeftDoubleClick)
2492
# ??gridlib.EVT_GRID_LABEL_LEFT_CLICK(self, self.OnLabelLeftClick)
2493
#EVT_CONTEXT_MENU(self, self.on_contextmenu)
2494
#self.Bind(wx.EVT_CONTEXT_MENU, self.on_contextmenu)
2495
# print ' done init TabPanel'
2496
# def on_contextmenu(self, event):
2497
# print '\non_contextmenu!!!'
2498
2499
def Reset(self):
2500
"""reset the view based on the data in the table. Call
2501
this when rows are added or destroyed"""
2502
# self._table.ResetView(self)
2503
self.AdjustScrollbars()
2504
self.ForceRefresh()
2505
2506
def logw(self, s):
2507
"""
2508
Write to logger if existent print otherwise
2509
"""
2510
pass
2511
2512
def on_cell_change(self, event):
2513
Row = event.GetRow()
2514
Col = event.GetCol()
2515
2516
# All cells have a value, regardless of the editor.
2517
# print 'Changed cell: (%u, %u)' % (Row, Col)
2518
# print 'value: %s' % self.grid1.GetCellValue(Row, Col)
2519
2520
def get_obj(self):
2521
"""
2522
Returns object wich is represented by this table.
2523
"""
2524
return self.tab.get_obj()
2525
2526
def on_contextmenu(self, event):
2527
# print "on_contextmenu (%d,%d) %s\n" %\
2528
# (event.GetRow(), event.GetCol(), event.GetPosition())
2529
menu = AgilePopupMenu(self.parent)
2530
2531
# tell popup menue in which cell it has been called
2532
# in this way a later event can retrieve cell coordinates
2533
menu.set_row(event.GetRow())
2534
menu.set_col(event.GetCol())
2535
menu.append_item('edit...', self.on_edit_cell_from_popupmenu,
2536
info='Edit data of this cell')
2537
2538
# Popup the menu. If an item is selected then its handler
2539
# will be called before PopupMenu returns.
2540
self.parent.PopupMenu(menu)
2541
menu.Destroy()
2542
2543
def on_edit_cell_from_popupmenu(self, event):
2544
"""Start cell editor"""
2545
popupmenu = event.GetEventObject()
2546
2547
table = self.GetTable()
2548
id, attrconf = table.get_id_attrconf(popupmenu.get_row(), popupmenu.get_col())
2549
# print 'on_edit_cell EventObject=',id, attrconf.attrname#popupmenu
2550
if (id >= 0) & (attrconf is not None):
2551
2552
# dlg = ObjPanelDialog(self,self.tab.get_obj(),table = self.tab,id,attrconfigs=[attrconf,], size=(350, 200),
2553
# #style = wxCAPTION | wxSYSTEM_MENU | wxTHICK_FRAME
2554
# style = wx.DEFAULT_DIALOG_STYLE
2555
# )
2556
2557
dlg = ObjPanelDialog(self,
2558
self.tab.get_obj(),
2559
attrconfigs=[attrconf, ],
2560
#tables = None,
2561
table=self.tab, id=id, ids=None,
2562
#groupnames = None,
2563
# title = '', size = wx.DefaultSize, pos = wx.DefaultPosition,\
2564
style=wx.DEFAULT_DIALOG_STYLE,
2565
# choose_id=False, choose_attr=False,
2566
# func_choose_id=None,func_change_obj=None,
2567
func_apply=self.func_apply,
2568
#panelstyle = 'default',
2569
#immediate_apply = False
2570
)
2571
2572
dlg.CenterOnScreen()
2573
2574
# this does not return until the dialog is closed.
2575
val = dlg.ShowModal()
2576
2577
if val == wx.ID_OK:
2578
# apply current widget values
2579
dlg.apply()
2580
else:
2581
# print ">>>>>>>>>You pressed Cancel\n"
2582
pass
2583
2584
dlg.Destroy()
2585
2586
event.Skip()
2587
self.ForceRefresh()
2588
#sz = miniframe.GetBestSize()
2589
#miniframe.SetSize( (sz.width+20, sz.height+20) )
2590
2591
def on_contextmenu_label(self, event):
2592
# print "on_contextmenu_label (%d,%d) %s\n" %\
2593
# (event.GetRow(), event.GetCol(), event.GetPosition())
2594
menu = AgilePopupMenu(self.parent)
2595
2596
# tell popup menue in which cell it has been called
2597
# in this way a later event can retrieve cell coordinates
2598
col = event.GetCol()
2599
row = event.GetRow()
2600
menu.set_row(row)
2601
menu.set_col(col)
2602
if col < 0:
2603
2604
# popup row options menu
2605
self._contextfunctions = {}
2606
# print ' configs',self.tab.get_configs(is_all=True)
2607
for config in self.tab.get_configs(filtergroupnames=['rowfunctions'], is_private=True): # (is_all=True):
2608
# print ' ',config.attrname,config.groupnames,'rowfunctions' in config.groupnames
2609
# if 'rowfunctions' in config.groupnames:
2610
item, _id = menu.append_item(config.get_name(), self.on_select_rowfunction, info=config.get_info())
2611
#item,id = menu.append_item( config.name,config.get_function(), info=config.info)
2612
self._contextfunctions[_id] = config.get_function()
2613
# print ' append ',config.name,_id
2614
#menu.append_item( config.name,self.on_select_contextmenu, info=config.info)
2615
2616
# default
2617
menu.append_item('Export to CSV...', self.on_export_csv,
2618
info='Export entire table in CSV format.')
2619
2620
# Menu on_highlight events
2621
#self.parent.Bind(wx.EVT_MENU_HIGHLIGHT_ALL, self.on_)
2622
2623
# Popup the menu. If an item is selected then its handler
2624
# will be called before PopupMenu returns.
2625
2626
self.parent.PopupMenu(menu)
2627
menu.Destroy()
2628
2629
def on_dummy(self, event):
2630
# event.Skip()
2631
pass
2632
2633
def on_select_rowfunction(self, event):
2634
popupmenu = event.GetEventObject()
2635
# Show how to get menu item info from this event handler
2636
table = self.GetTable()
2637
row = popupmenu.get_row()
2638
col = popupmenu.get_col()
2639
_id, attrconf = table.get_id_attrconf(row, col)
2640
id_menu = event.GetId()
2641
# print 'on_select_contextmenu id_menu,_id, attrconf',id_menu,_id, attrconf
2642
# print ' GetSelection',event.GetSelection()
2643
# print ' GetString',event.GetString()
2644
2645
# print ' GetId',id_menu,event.Id
2646
# print ' GetClientObject',event.GetClientObject()
2647
2648
# call selected row function with row _id
2649
self._contextfunctions[id_menu](_id)
2650
2651
# item = popupmenu.get_menuitem_from_id(event.GetId())# OK but not neede
2652
# if self._rowfunctions.has_keid_menu:
2653
# funcname = item.GetText()
2654
# #help = item.GetHelp()
2655
# #??? menu id->name->function??????????
2656
# print 'on_select_contextmenu: found function:',funcname#,getattr(table,funcname)
2657
# self._rowfunctions[_id]
2658
# else:
2659
# print 'on_select_contextmenu: No function found'
2660
2661
event.Skip()
2662
# self.ForceRefresh()
2663
# self.grid.AutoSizeColumn(col)
2664
self.Reset()
2665
self.Refresh()
2666
self.ForceRefresh()
2667
2668
#del table
2669
newtable = TableGrid(self, self.tab, attrconfigs=self.tab.get_colconfigs(),
2670
ids=self.tab.get_ids(), show_ids=table.show_ids)
2671
del table
2672
# The second parameter means that the grid is to take ownership of the
2673
# table and will destroy it when done. Otherwise you would need to keep
2674
# a reference to it and call its Destroy method later.
2675
self.SetTable(newtable, True)
2676
2677
return None
2678
2679
def on_export_csv(self, event):
2680
wildcards_all = "CSV file (*.csv,*.txt)|*.csv;*.CSV;*.txt;*.TXT|All files (*.*)|*.*"
2681
# if hasattr(attrconf,'wildcards'):
2682
# wildcards = attrconf.wildcards+"|"+wildcards_all
2683
# else:
2684
# wildcards = wildcards_all
2685
dlg = wx.FileDialog(self.parent, message="Export table %s to CSV" % self.tab.get_name(),
2686
# defaultDir=os.getcwd(),
2687
defaultFile="",
2688
wildcard=wildcards_all,
2689
style=wx.SAVE | wx.CHANGE_DIR
2690
)
2691
2692
if dlg.ShowModal() == wx.ID_OK:
2693
# This returns a Python list of files that were selected.
2694
path = dlg.GetPath()
2695
print 'on_export_csv', type(path), path
2696
if type(path) in STRINGTYPES:
2697
self.tab.export_csv(path, sep=',',
2698
attrconfigs=self.GetTable().get_valueconfigs(),
2699
groupnames=None, is_header=True)
2700
2701
def on_click_cell(self, event):
2702
"""
2703
Action for first click on cell.
2704
"""
2705
# check if there is something to navigate
2706
if self.CanEnableCellControl():
2707
table = self.GetTable()
2708
id, attrconf = table.get_id_attrconf(event.GetRow(), event.GetCol())
2709
mt = attrconf.metatype
2710
# config=table.obj.get_config(attr)
2711
# print 'on_click_cell ,id,attrconf',id, attrconf.get_name(),mt
2712
# print ' func_change_obj=',self.func_change_obj
2713
# if hasattr(attrconf,'attrname'):
2714
# print ' attrconf.attrname=',attrconf.attrname
2715
2716
# navigate!
2717
value = attrconf[id]
2718
# print ' value ' , value, type(value)
2719
if mt == 'obj':
2720
if type(value) == types.InstanceType:
2721
# print ' ident?',hasattr(value,'ident')
2722
if hasattr(value, 'ident'):
2723
navitimer = wx.FutureCall(1, self.func_change_obj, value)
2724
2725
else:
2726
event.Skip()
2727
else:
2728
event.Skip()
2729
2730
elif mt == 'id':
2731
if attrconf.is_readonly():
2732
linktab = attrconf.get_linktab()
2733
# print ' FutureCall',linktab, value
2734
if value != -1:
2735
navitimer = wx.FutureCall(1, self.func_change_obj, linktab, value) # here value is id
2736
else:
2737
event.Skip()
2738
else:
2739
event.Skip()
2740
2741
elif mt == 'tabid':
2742
if value is not None:
2743
linktab, id = value
2744
navitimer = wx.FutureCall(1, self.func_change_obj, linktab, id) # here value is id
2745
else:
2746
event.Skip()
2747
2748
elif mt == 'ids':
2749
if value is not None:
2750
linktab = attrconf.get_linktab()
2751
navitimer = wx.FutureCall(1, self.func_change_obj, linktab, None, value) # here value is ids list
2752
else:
2753
event.Skip()
2754
else:
2755
event.Skip()
2756
# elif config.has_key('do_init_arrayobj'):
2757
# if config['do_init_arrayobj']:
2758
# navitimer = wx.FutureCall(1, self.func_change_obj,table.obj[attr,id])
2759
# else:
2760
# event.Skip()
2761
2762
else:
2763
event.Skip()
2764
2765
def on_edit_cell(self, event):
2766
"""
2767
Decide how to to edit the cell. Possibilities are:
2768
- popup with special editing windows
2769
- in-cell editing
2770
"""
2771
table = self.GetTable()
2772
id, attrconf = table.get_id_attrconf(event.GetRow(), event.GetCol())
2773
2774
# check first if there are callback functions
2775
if self.func_choose_id is not None:
2776
# call self.func_choose_id
2777
#
2778
wx.FutureCall(1, self.func_choose_id, id, attrconf)
2779
# event.Skip()
2780
return
2781
2782
elif self.func_choose_attr is not None:
2783
# call self.func_choose_id
2784
wx.FutureCall(1, self.func_choose_attr, attrconf)
2785
# event.Skip()
2786
return
2787
2788
if self.CanEnableCellControl():
2789
2790
#self.logw(' func_choose_id id=%d,attr=%s,ident=%s='%(id, attr,table.obj.ident))
2791
# print 'on_edit_cell',attrconf.attrname
2792
# print ' obj=',table.obj
2793
2794
# print ' config=',config
2795
2796
metatype = attrconf.metatype
2797
2798
if metatype == 'color': # special config for colors
2799
dlg = wx.ColourDialog(self.parent)
2800
2801
# Ensure the full colour dialog is displayed,
2802
# not the abbreviated version.
2803
dlg.GetColourData().SetChooseFull(True)
2804
2805
if dlg.ShowModal() == wx.ID_OK:
2806
# If the user selected OK, then the dialog's wx.ColourData will
2807
# contain valid information. Fetch the data ...
2808
c = dlg.GetColourData().GetColour()
2809
2810
# print 'on_edit_cell:'
2811
# print ' wxc=',[wxc.Red(),wxc.Green(),wxc.Blue()]
2812
# print ' table.obj[attr, id]=',table.obj[attr, id],type(table.obj[attr, id])
2813
# print ' ffffff_to_color=',self.ffffff_to_color( [wxc.Red(),wxc.Green(),wxc.Blue()] ),type(self.ffffff_to_color( [wxc.Red(),wxc.Green(),wxc.Blue()] ))
2814
2815
# self.ffffff_to_color([wxc.Red(),wxc.Green(),wxc.Blue()] )
2816
attrconf[id] = np.array([c.Red(), c.Green(), c.Blue(), c.Alpha()], np.float32)/255.0
2817
self.SetCellBackgroundColour(event.GetRow(), event.GetCol(), c)
2818
self.ForceRefresh()
2819
if self.func_apply is not None:
2820
wx.FutureCall(1, self.func_apply, table, id, None)
2821
2822
# Once the dialog is destroyed, Mr. wx.ColourData is no longer your
2823
# friend. Don't use it again!
2824
dlg.Destroy()
2825
# event.Skip()
2826
# cellattr.SetBackgroundColour(obj[])
2827
2828
elif metatype == 'filepath':
2829
filepath = self.on_fileopen(attrconf)
2830
if filepath is not None:
2831
attrconf[id] = filepath
2832
self.ForceRefresh()
2833
if self.func_apply is not None:
2834
wx.FutureCall(1, self.func_apply, table, id, None)
2835
2836
elif metatype == 'dirpath':
2837
dirpath = self.on_diropen(attrconf)
2838
if dirpath is not None:
2839
attrconf[id] = dirpath
2840
self.ForceRefresh()
2841
if self.func_apply is not None:
2842
wx.FutureCall(1, self.func_apply, table, id, None)
2843
# elif metatype == 'penstyle':
2844
# #Penstyles(table.obj.get_pentable())
2845
# #penstyles=Penstyles(table.obj.get_pentable())
2846
#
2847
# dlg = PenstyleDialog(self.parent,
2848
# table.obj.get_pentable(),
2849
# size = (300,400),
2850
# #choose_id=True,
2851
# #func_change_obj=self.on_edit_linestyle
2852
# )
2853
#
2854
# if dlg.ShowModal() == wx.ID_OK:
2855
# attr_current,idc_current=dlg.get_current_attrconf_id()
2856
# table.obj[attr, id]=idc_current
2857
#
2858
# self.ForceRefresh()
2859
# dlg.Destroy()
2860
# event.Skip()
2861
2862
else:
2863
self.EnableCellEditControl()
2864
# try this ...
2865
# if self.func_apply is not None:
2866
# wx.FutureCall(1,self.func_apply, table, id, None)
2867
# ...put this in apply method
2868
2869
def on_fileopen(self, attrconf):
2870
# print 'on_fileopen',self._attrconf.attrname
2871
# if type(self._attrconf.get_default())==types.StringType:
2872
# defaultname = self._attrconf.get_default()
2873
# else:
2874
# defaultname = os.getcwd()
2875
wildcards_all = "All files (*.*)|*.*"
2876
if hasattr(attrconf, 'wildcards'):
2877
wildcards = attrconf.wildcards+"|"+wildcards_all
2878
else:
2879
wildcards = wildcards_all
2880
dlg = wx.FileDialog(self.parent, message="Open file",
2881
# defaultDir=os.getcwd(),
2882
defaultFile="",
2883
wildcard=wildcards,
2884
style=wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR
2885
)
2886
2887
if dlg.ShowModal() == wx.ID_OK:
2888
# This returns a Python list of files that were selected.
2889
paths = dlg.GetPaths()
2890
# print 'You selected %d files:' % len(paths)
2891
if len(paths) == 1:
2892
return paths[0]
2893
elif len(paths) > 1:
2894
return paths
2895
else:
2896
return None
2897
else:
2898
return None
2899
2900
def on_diropen(self, attrconf):
2901
dlg = wx.DirDialog(self.parent, message="Open directory",
2902
style=wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST | wx.DD_CHANGE_DIR
2903
)
2904
2905
if dlg.ShowModal() == wx.ID_OK:
2906
return dlg.GetPath()
2907
else:
2908
return None
2909
2910
def on_edit_cell_miniframe(self, event):
2911
"""Start miniframe cell editor"""
2912
EventObject = event.GetEventObject()
2913
2914
table = self.GetTable()
2915
id, attrconf = table.get_id_attrconf(event.GetRow(), event.GetCol())
2916
#miniframe=DataMiniFrame( self, table.obj, id =id, attrs = [attr])
2917
print 'on_edit_cell_miniframe EventObject=', id, attrconf
2918
dlg = ObjPanelDialog(self, table.obj, id, attrconfigs=[attrconf], size=(350, 200),
2919
#style = wxCAPTION | wxSYSTEM_MENU | wxTHICK_FRAME
2920
func_apply=self.func_apply,
2921
style=wx.DEFAULT_DIALOG_STYLE
2922
)
2923
dlg.CenterOnScreen()
2924
2925
# this does not return until the dialog is closed.
2926
val = dlg.ShowModal()
2927
2928
if val == wx.ID_OK:
2929
# apply current widget values
2930
dlg.apply()
2931
else:
2932
# print ">>>>>>>>>You pressed Cancel\n"
2933
pass
2934
2935
dlg.Destroy()
2936
2937
evt.Skip()
2938
2939
self.ForceRefresh()
2940
#sz = miniframe.GetBestSize()
2941
#miniframe.SetSize( (sz.width+20, sz.height+20) )
2942
# self.Refresh()#no
2943
2944
def OnLabelLeftDoubleClick(self, evt):
2945
# print "OnLabelLeftDoubleClick: (%d,%d) %s\n" %\
2946
# (evt.GetRow(), evt.GetCol(), evt.GetPosition())
2947
if evt.GetRow() >= 0:
2948
table = self.GetTable()
2949
# click has been on row labels = ids
2950
id = table.ids[evt.GetRow()]
2951
2952
if self.func_choose_id is None:
2953
2954
# print ' call ScalarPanel editor for ID=',id
2955
2956
dlg = ObjPanelDialog(self, self.tab.get_obj(), id=id, # table = self.tab,
2957
#title = '',
2958
#size=(350, 200),
2959
#style = wx.DEFAULT_DIALOG_STYLE
2960
func_apply=self.func_apply,
2961
)
2962
2963
dlg.CenterOnScreen()
2964
2965
# this does not return until the dialog is closed.
2966
val = dlg.ShowModal()
2967
2968
if val == wx.ID_OK:
2969
# apply current widget values
2970
dlg.apply()
2971
if self._objpanel:
2972
self._objpanel.restore() # thi will also update scalars on objpanel
2973
self.ForceRefresh()
2974
else:
2975
# print ">>>>>>>>>You pressed Cancel\n"
2976
pass
2977
2978
dlg.Destroy()
2979
2980
else:
2981
# call self.func_choose_id
2982
wx.FutureCall(1, self.func_choose_id, id, '')
2983
2984
evt.Skip()
2985
2986
def OnRightDown(self, event):
2987
print "hello", self.GetSelectedRows()
2988
2989
def apply(self):
2990
"""
2991
Widget values are copied to object
2992
"""
2993
2994
# grid always updated
2995
# but there may be callback functions
2996
# which expects a return with current selection
2997
pass
2998
# self.ForceRefresh()
2999
3000
col = self.GetGridCursorCol()
3001
row = self.GetGridCursorRow()
3002
3003
table = self.GetTable()
3004
id, attrconf = table.get_id_attrconf(row, col)
3005
3006
if self.func_apply is not None:
3007
wx.FutureCall(1, self.func_apply, table, id, None)
3008
3009
#self.logw('grid.apply row%d col %d'%(row,col))
3010
if self.func_choose_id is not None:
3011
# call self.func_choose_id
3012
wx.FutureCall(1, self.func_choose_id, id, attrconf)
3013
return
3014
3015
elif self.func_choose_attr is not None:
3016
# call self.func_choose_id
3017
wx.FutureCall(1, self.func_choose_attr, attrconf)
3018
return
3019
3020
def get_current_attrconf_id(self):
3021
"""
3022
Return current attribute and id
3023
"""
3024
col = self.GetGridCursorCol()
3025
row = self.GetGridCursorRow()
3026
3027
table = self.GetTable()
3028
id, attrconf = table.get_id_attrconf(row, col)
3029
3030
return attrconf, id
3031
3032
def restore(self):
3033
"""
3034
Object values are copied into widgets.
3035
"""
3036
# grid always updated
3037
pass
3038
# self.ForceRefresh()
3039
3040
3041
class ObjPanelMixin:
3042
"""
3043
Common methods for panels
3044
"""
3045
3046
def init_panel(self, parent, mainframe=None):
3047
"""
3048
Initialization of general panel, independent by which type of
3049
widow the panel is actually represented
3050
3051
parent = parent widget
3052
3053
"""
3054
3055
self.parent = parent
3056
self.mainframe = mainframe
3057
self.widgets = None
3058
3059
# list with widgets containing data
3060
# these widgets must have an apply and restore method
3061
# which is calle when the respective buttons are pressed.
3062
self.datawidgets = []
3063
3064
# self.pentable=pentable
3065
3066
# def get_pentable(self):
3067
# """
3068
# Returns pentable used for this panel
3069
# """
3070
# if self.pentable is None:
3071
# return self.obj.get_pentable()
3072
# else:
3073
# return self.pentable
3074
3075
def get_obj(self):
3076
return self.obj
3077
3078
def get_id(self):
3079
return self.id
3080
3081
def clear(self):
3082
for widget in self.datawidgets:
3083
widget.Destroy()
3084
3085
def recreate_panel(self, obj, id=None, ids=None, groupnames=None, **kwargs):
3086
# print '\nrecreate_panel:',obj.format_ident(), id , ids, groupnames
3087
3088
# print ' args =',kwargs
3089
self.obj = obj
3090
self.id = id
3091
self.ids = ids
3092
3093
# print ' n_colconfigs =',len(obj.get_colconfigs(filtergroupnames = groupnames))
3094
# print ' n_configs =',len(obj.get_configs(filtergroupnames = groupnames))
3095
if (id is None) & (ids is None):
3096
3097
if obj.managertype == 'table':
3098
# print ' managertype',obj.managertype,obj.get_attrsman()
3099
if len(obj.get_colconfigs(filtergroupnames=groupnames)) > 0:
3100
self.recreate_panel_table(groupnames=groupnames, **kwargs)
3101
else:
3102
self.recreate_panel_scalar(groupnames=groupnames, **kwargs)
3103
else:
3104
self.recreate_panel_scalar(groupnames=groupnames, **kwargs)
3105
else:
3106
if ids is not None:
3107
# table with specific ids
3108
self.recreate_panel_table(groupnames=groupnames, **kwargs)
3109
else:
3110
# scalar panel for single id
3111
self.recreate_panel_scalar(groupnames=groupnames, **kwargs)
3112
3113
def recreate_panel_table(self, attrconfigs=None,
3114
groupnames=None, show_groupnames=False,
3115
show_title=True,
3116
is_modal=False,
3117
immediate_apply=False,
3118
panelstyle='default',
3119
func_change_obj=None,
3120
func_choose_id=None,
3121
func_choose_attr=None,
3122
func_apply=None,
3123
is_scrolled=True,
3124
**buttonargs):
3125
"""
3126
Recreates panel and destroys previous contents:
3127
attr = a list ith attribute names to be shown
3128
groups = list with group names to be shown
3129
show_groupnames = the group names are shown
3130
together with the respective attributes
3131
is_modal = if true the panel will be optimized for dialog window
3132
immediate_apply = changes to widgets will be immediately applied to
3133
obj attribute without pressing apply
3134
buttonargs = a dictionary with arguments for botton creation
3135
obj = the object to be displayed
3136
func_change_obj = function to be called if user clicks on on object
3137
with obj as argument
3138
func_choose_id = function to be called when user clicks on id(table row)
3139
with id as argument
3140
func_choose_attr = function to be called when user clicks on attribute
3141
with attr as argument. In this case the attribute
3142
names of scalars turn into buttons. Array attributes
3143
are selected by clicking on the column name.
3144
func_apply = is executed when apply button is pressed, and after widget values
3145
have been applied. Arguments are: obj, id, ids
3146
"""
3147
#
3148
# print 'recreate_panel_table:',self.obj.ident,immediate_apply, func_apply,groupnames
3149
3150
self.func_change_obj = func_change_obj
3151
self.func_choose_id = func_choose_id
3152
self.func_choose_attr = func_choose_attr
3153
self.func_apply = func_apply
3154
self._show_title = show_title
3155
3156
# if is_scrolled is None:
3157
# is_scrolled = not is_modal #for dialog windows use non crolled panels by default
3158
3159
attrsman = self.obj.get_attrsman()
3160
attrconfigs_scalar = attrsman.get_configs(structs=cm.STRUCTS_SCALAR, filtergroupnames=groupnames)
3161
# print ' attrconfigs_scalar',attrconfigs_scalar
3162
# if obj.managertype=='table': # obj is a single table
3163
# print ' is_scalar_panel & is_singletab:'
3164
table = self.obj
3165
3166
#attrconfigs_scalar = attrsman.get_configs( structs = cm.STRUCTS_SCALAR)
3167
3168
if len(attrconfigs_scalar) > 0:
3169
# print ' create a panel with scalars and a table below'
3170
self.make_scalartablepanel(self, attrconfigs_scalar, table, objpanel=self,
3171
attrconfigs=None,
3172
immediate_apply=immediate_apply, panelstyle=panelstyle,
3173
is_modal=is_modal, show_title=show_title,
3174
is_scrolled=is_scrolled, **buttonargs)
3175
3176
else:
3177
# print ' create only a table, without scalars'#,attrsman.get_colconfigs(filtergroupnames = groupnames)
3178
self.make_tablepanel(self, table, objpanel=self, attrconfigs=None, groupnames=groupnames,
3179
immediate_apply=immediate_apply, panelstyle=panelstyle,
3180
is_modal=is_modal, show_title=show_title,
3181
is_scrolled=is_scrolled, **buttonargs)
3182
3183
self.restore()
3184
return True
3185
3186
def recreate_panel_scalar(self, attrconfigs=None,
3187
groupnames=None, show_groupnames=False,
3188
show_title=True,
3189
is_modal=False,
3190
immediate_apply=False,
3191
panelstyle='default',
3192
func_change_obj=None,
3193
func_choose_id=None,
3194
func_choose_attr=None,
3195
func_apply=None,
3196
is_scrolled=True,
3197
**buttonargs):
3198
"""
3199
Recreates panel and destroys previous contents:
3200
attr = a list ith attribute names to be shown
3201
groups = list with group names to be shown
3202
show_groupnames = the group names are shown
3203
together with the respective attributes
3204
is_modal = if true the panel will be optimized for dialog window
3205
immediate_apply = changes to widgets will be immediately applied to
3206
obj attribute without pressing apply
3207
buttonargs = a dictionary with arguments for botton creation
3208
obj = the object to be displayed
3209
func_change_obj = function to be called if user clicks on on object
3210
with obj as argument
3211
func_choose_id = function to be called when user clicks on id(table row)
3212
with id as argument
3213
func_choose_attr = function to be called when user clicks on attribute
3214
with attr as argument. In this case the attribute
3215
names of scalars turn into buttons. Array attributes
3216
are selected by clicking on the column name.
3217
func_apply = is executed when apply button is pressed, and after widget values
3218
have been applied. Arguments are: obj, id, ids
3219
"""
3220
#
3221
# print 'recreate_panel_scalar:',self.obj.ident, func_apply,groupnames
3222
3223
self.func_change_obj = func_change_obj
3224
self.func_choose_id = func_choose_id
3225
self.func_choose_attr = func_choose_attr
3226
self.func_apply = func_apply
3227
self._show_title = show_title
3228
3229
# print ' ',self.obj.managertype,self.obj.get_attrsman()
3230
3231
# if is_scrolled is None:
3232
# is_scrolled = not is_modal #for dialog windows use non crolled panels by default
3233
3234
attrsman = self.obj.get_attrsman()
3235
attrconfigs_scalar = attrsman.get_configs(structs=cm.STRUCTS_SCALAR, filtergroupnames=groupnames)
3236
if self.id is not None:
3237
attrconfigs_scalar += attrsman.get_colconfigs()
3238
# print ' just one scalar obj panel',buttonargs.keys()
3239
# print ' groupnames', groupnames
3240
# create vertical main sizer
3241
# print ' attrconfigs_scalar',attrconfigs_scalar
3242
# print ' cm.STRUCTS_SCALAR',cm.STRUCTS_SCALAR
3243
self.make_scalarpanel(self, attrconfigs_scalar, id=self.id, # groupnames=groupnames,
3244
immediate_apply=immediate_apply, panelstyle=panelstyle,
3245
is_modal=is_modal, show_title=show_title,
3246
is_scrolled=is_scrolled, **buttonargs)
3247
3248
# self.restore()
3249
return True
3250
3251
def add_scalarpage(self, attrconfigs=None, groupnames=None,
3252
id=None, immediate_apply=False, panelstyle='default',
3253
is_modal=False, show_title=False,
3254
show_buttons=True, is_scrolled=True, **buttonargs):
3255
"""
3256
Add a new page to the notebook.
3257
"""
3258
# print 'add_scalarpage',groupnames,attrconfigs
3259
# print ' args',args
3260
pan = wx.Panel(self.nb, -1)
3261
#pan = wx.Window(self, -1)
3262
widget = self.make_scalarpanel(pan, attrconfigs, # groupnames=groupnames,
3263
id=id, immediate_apply=immediate_apply, panelstyle=panelstyle,
3264
is_modal=is_modal, show_title=show_title,
3265
show_buttons=show_buttons, is_scrolled=is_scrolled, **buttonargs)
3266
3267
# Add network tab with editor
3268
p = self.nb.AddPage(pan, 'General')
3269
self.pages[self.obj.get_ident()] = pan
3270
# self.nb.SetSelection(p)
3271
3272
return pan
3273
3274
def add_tablepage(self, table, groupnames=None):
3275
"""
3276
Add a new page to the notebook.
3277
"""
3278
# print 'context.add_view',ViewClass
3279
# print ' args',args
3280
widget = self.add_table(self.nb, table, objpanel=self, groupnames=groupnames, show_title=False)
3281
self.tablewidgets.append(widget) # need that later for refresh
3282
# Add network tab with editor
3283
# print '\nadd_tablepage name',type(table.get_name()),table.get_name(),table
3284
# try:
3285
# print ' try:',table.name.attrname
3286
# except:
3287
# print ' ok'
3288
3289
p = self.nb.AddPage(widget, table.get_name())
3290
self.pages[table.format_ident()] = widget
3291
# self.nb.SetSelection(p)
3292
3293
return widget
3294
3295
def make_scalartablepanel(self, parent, attrconfigs_scalar, table, objpanel=None, attrconfigs=None, groupnames=None,
3296
id=None, immediate_apply=False, panelstyle='default',
3297
is_modal=False, show_title=False,
3298
show_buttons=True, is_scrolled=True, **buttonargs):
3299
# print 'make_scalarpanellll',attrconfigs_scalar
3300
sizer = wx.BoxSizer(wx.VERTICAL)
3301
if show_title:
3302
self.add_title(sizer, id=id)
3303
3304
splitter = wx.SplitterWindow(parent, -1, style=wx.SP_LIVE_UPDATE |
3305
wx.SP_BORDER | wx.SP_3DBORDER, size=wx.DefaultSize)
3306
splitter.SetMinimumPaneSize(10)
3307
3308
scalarpanel = self.add_scalars(splitter, attrconfigs_scalar, # groupnames = groupnames,
3309
id=id, immediate_apply=immediate_apply,
3310
panelstyle=panelstyle, is_modal=False, is_scrolled=is_scrolled)
3311
3312
# if datawidget is not None:
3313
#sizer.Add(datawidget, 1, wx.EXPAND|wx.TOP|wx.LEFT,5)
3314
#sizer.Add(datawidget, 1,0)
3315
# datawidget.Layout()
3316
3317
tablepanel = self.add_table(splitter, table, objpanel=objpanel, ids=self.ids,
3318
attrconfigs=attrconfigs, groupnames=groupnames)
3319
# if datawidget is not None:
3320
#sizer.Add(datawidget, 1, wx.EXPAND|wx.ALL, 5)
3321
#sizer.Add(datawidget, 0, wx.EXPAND)
3322
#sizer.Add(datawidget, 2,0,0)
3323
# datawidget.Layout()
3324
3325
splitter.SplitHorizontally(scalarpanel, tablepanel, -100)
3326
splitter.SetSashPosition(100, True)
3327
sizer.Add(splitter, 1, wx.GROW, 5)
3328
3329
if show_buttons:
3330
self.add_buttons(parent, sizer, is_modal=is_modal, **buttonargs)
3331
# sizer.SetSizeHints(self)
3332
parent.SetSizer(sizer)
3333
sizer.Fit(parent)
3334
3335
def make_tablepanel(self, parent, tab, objpanel=None, attrconfigs=None, groupnames=None,
3336
id=None, immediate_apply=False, panelstyle='default',
3337
is_modal=False, show_title=False,
3338
show_buttons=True, is_scrolled=True, **buttonargs):
3339
# print 'make_tablepanel',groupnames
3340
sizer = wx.BoxSizer(wx.VERTICAL)
3341
if show_title:
3342
self.add_title(sizer, id=id)
3343
3344
datawidget = self.add_table(parent, tab, ids=self.ids, objpanel=objpanel,
3345
attrconfigs=attrconfigs, groupnames=groupnames)
3346
3347
if datawidget is not None:
3348
sizer.Add(datawidget, 1, wx.EXPAND | wx.ALL, 5)
3349
3350
if show_buttons:
3351
self.add_buttons(parent, sizer, is_modal=is_modal, **buttonargs)
3352
parent.SetSizer(sizer)
3353
sizer.Fit(parent)
3354
3355
def make_scalarpanel(self, parent, attrconfigs=None,
3356
id=None, immediate_apply=False, panelstyle='default',
3357
is_modal=False, show_title=False,
3358
show_buttons=True, is_scrolled=True, **buttonargs):
3359
3360
# TODO: Attention: parent is always self
3361
# print 'make_scalarpanellll', attrconfigs
3362
sizer = wx.BoxSizer(wx.VERTICAL)
3363
if show_title:
3364
self.add_title(sizer, id=id)
3365
3366
datawidget = self.add_scalars(parent, attrconfigs,
3367
id=id, immediate_apply=immediate_apply,
3368
panelstyle=panelstyle, is_modal=is_modal, is_scrolled=is_scrolled)
3369
3370
if datawidget is not None:
3371
sizer.Add(datawidget, 1, wx.EXPAND | wx.ALL, 5)
3372
3373
if show_buttons:
3374
self.add_buttons(parent, sizer, is_modal=is_modal, **buttonargs)
3375
parent.SetSizer(sizer)
3376
sizer.Fit(parent)
3377
3378
# self.SetAutoLayout(True)
3379
# self.AutoLayout()
3380
# self.Refresh()
3381
self.SetAutoLayout(1)
3382
3383
self.Refresh()
3384
self.Layout()
3385
3386
def add_scalars(self, parent, attrconfigs,
3387
id=None, immediate_apply=False, panelstyle='default',
3388
is_modal=False, is_scrolled=True):
3389
"""
3390
Add all scalar attributes to panel.
3391
"""
3392
3393
# print 'add_scalars for attrconfigs',attrconfigs,is_scrolled
3394
3395
if attrconfigs is not None:
3396
if (not is_scrolled):
3397
datawidget = ScalarPanel(parent, attrconfigs, id=id,
3398
func_change_obj=self.func_change_obj,
3399
immediate_apply=immediate_apply,
3400
panelstyle=panelstyle,
3401
mainframe=self.mainframe)
3402
else:
3403
datawidget = ScalarPanelScrolled(parent, attrconfigs, id=id,
3404
func_change_obj=self.func_change_obj,
3405
immediate_apply=immediate_apply,
3406
panelstyle=panelstyle,
3407
is_modal=is_modal,
3408
mainframe=self.mainframe)
3409
self.datawidgets.append(datawidget) # used for apply and resore
3410
3411
return datawidget
3412
3413
def add_tables(self, sizer, tables, groupnames, show_title=False):
3414
3415
for table in tables:
3416
self.add_hline(sizer)
3417
self.add_table(sizer, table, groupnames=groupnames, show_title=show_title)
3418
3419
def add_table(self, parent, tab, ids=None, objpanel=None, attrconfigs=None, groupnames=None):
3420
"""
3421
Add all array-type attributes to panel.
3422
"""
3423
# TODO: group selection
3424
# TODO: Attention: parent is always self
3425
3426
if attrconfigs is None:
3427
# This could be done way earlier!!!
3428
attrconfigs = tab.get_colconfigs(filtergroupnames=groupnames)
3429
3430
# print 'add_table=',tab.get_name(),len(tab.get_colconfigs())
3431
3432
# check if there are attributes
3433
if (attrconfigs is not None) & (attrconfigs != []):
3434
#panel=wx.Panel(self.parent, -1,wx.DefaultPosition,wx.DefaultSize,wx.SUNKEN_BORDER|wx.WANTS_CHARS)
3435
# panel.SetAutoLayout(True)
3436
datawidget = TabPanel(parent, tab, attrconfigs=attrconfigs, ids=ids, objpanel=objpanel,
3437
func_change_obj=self.func_change_obj,
3438
func_choose_id=self.func_choose_id,
3439
func_choose_attr=self.func_choose_attr,
3440
func_apply=self.func_apply,
3441
mainframe=self.mainframe)
3442
# panel.Refresh()
3443
# datawidget=ScalarPanel(self,attrs)
3444
# self.datawidgets.append(datawidget)
3445
3446
self.datawidgets.append(datawidget) # used for apply and resore
3447
return datawidget
3448
3449
def add_buttons(self, parent, sizer,
3450
is_modal=False,
3451
standartbuttons=['apply', 'restore', 'cancel'],
3452
buttons=[],
3453
defaultbutton='apply',
3454
):
3455
"""
3456
Add a button row to sizer
3457
"""
3458
3459
# print '\nadd_buttons is_modal',is_modal
3460
# print ' standartbuttons',standartbuttons
3461
# print ' buttons',buttons
3462
if parent is None:
3463
parent = self
3464
# print 'add_buttons'
3465
# print ' buttons=',buttons
3466
self.data_standartbuttons = {
3467
'apply': ('Apply', self.on_apply, 'Apply current values'),
3468
'restore': ('Restore', self.on_restore, 'Restore previous values'),
3469
'ok': ('OK', self.on_ok, 'Apply and close window'),
3470
'cancel': ('Cancel', self.on_cancel, 'Cancel and close window')
3471
}
3472
3473
# compose button row on bottom of panel
3474
allbuttons = []
3475
3476
# add custom buttons
3477
allbuttons += buttons
3478
# print '\n allbuttons',allbuttons
3479
# print ' buttons',buttons,len(buttons),is_modal&(len(buttons)==0)
3480
if is_modal & (len(buttons) == 0):
3481
# if in dialog mode use only OK and cancel by default
3482
standartbuttons = []
3483
3484
# add standart buttons
3485
# print ' standartbuttons=',standartbuttons
3486
for key in standartbuttons:
3487
# print ' append:',key
3488
allbuttons.append(self.data_standartbuttons[key])
3489
3490
if (len(allbuttons) > 0) | is_modal:
3491
self.add_hline(sizer)
3492
3493
# Init the context help button.
3494
# And even include help text about the help button :-)
3495
3496
if is_modal & (len(buttons) == 0):
3497
# standartbuttons=[]
3498
# print 'add_buttons modal buttons',buttons
3499
btnsizer = wx.StdDialogButtonSizer()
3500
# standartbuttons=[]
3501
#helpbutton = wx.ContextHelpButton(self.parent)
3502
#helpbutton.SetHelpText(' Click to put application\n into context sensitive help mode.')
3503
#btnsizer.AddButton(helpbutton )
3504
3505
else:
3506
if defaultbutton == '':
3507
defaultbutton = 'Apply'
3508
# print 'add_buttons ',allbuttons
3509
btnsizer = wx.BoxSizer(wx.HORIZONTAL)
3510
3511
# add help button
3512
3513
# print ' allbuttons',allbuttons
3514
# create button widgets
3515
for (name, function, info) in allbuttons:
3516
3517
b = wx.Button(parent, -1, name, (2, 2))
3518
self.Bind(wx.EVT_BUTTON, function, b)
3519
b.SetHelpText(info)
3520
if defaultbutton == name:
3521
b.SetDefault()
3522
if is_modal & (len(buttons) == 0):
3523
# print ' create button modal',name,is_modal
3524
btnsizer.AddButton(b)
3525
else:
3526
# print ' create button',name,is_modal
3527
btnsizer.Add(b)
3528
3529
if is_modal & (len(buttons) == 0):
3530
# print ' Add OK and CANCEL'
3531
# add OK and CANCEL if panel appears in separate window
3532
b = wx.Button(parent, wx.ID_OK)
3533
b.SetHelpText('Apply values and close window')
3534
#self.Bind(wx.EVT_BUTTON, self.on_ok_modal, b)
3535
if defaultbutton == '':
3536
# set apply button default if there is no other default
3537
b.SetDefault()
3538
btnsizer.AddButton(b)
3539
# print 'Add OK',b
3540
3541
# add cancel
3542
b = wx.Button(parent, wx.ID_CANCEL)
3543
b.SetHelpText('Ignore modifications and close window')
3544
btnsizer.AddButton(b)
3545
# print 'Add cancel',b
3546
3547
btnsizer.Realize()
3548
# else:
3549
# btnsizer.Realize()
3550
# if wx.Platform != "__WXMSW__":
3551
# btn = wx.ContextHelpButton(self)
3552
# btnsizer.AddButton(btn)
3553
3554
# btnsizer.Realize()
3555
3556
#b = csel.ColourSelect(self.parent, -1, 'test', (255,0,0), size = wx.DefaultSize)
3557
# sizer.Add(b)
3558
# add buttomrow to main
3559
#sizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)
3560
3561
#widget=wx.StaticText(self.parent, -1,'That is it!!')
3562
# sizer.Add(widget)
3563
3564
# TEST
3565
#btnsizer = wx.StdDialogButtonSizer()
3566
3567
# if wx.Platform != "__WXMSW__":
3568
# btn = wx.ContextHelpButton(self)
3569
# btnsizer.AddButton(btn)
3570
3571
## btn = wx.Button(self, wx.ID_OK)
3572
## btn.SetHelpText("The OK button completes the dialog")
3573
# btn.SetDefault()
3574
# btnsizer.AddButton(btn)
3575
##
3576
## btn = wx.Button(self, wx.ID_CANCEL)
3577
## btn.SetHelpText("The Cancel button cnacels the dialog. (Cool, huh?)")
3578
# btnsizer.AddButton(btn)
3579
# btnsizer.Realize()
3580
###
3581
3582
sizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
3583
3584
def add_hline(self, sizer, hspace=5):
3585
"""
3586
Add a horizontal line to sizer
3587
"""
3588
line = wx.StaticLine(self, -1, size=(20, -1), style=wx.LI_HORIZONTAL)
3589
sizer.Add(line, 0, wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.CENTER, hspace)
3590
3591
def add_title(self, sizer, title=None, id=None, fontsize=12):
3592
"""
3593
Add a title to the option panel.
3594
If no title is given, the titel will be derived from the object name
3595
and id if given.
3596
"""
3597
# print 'add_title',self.obj.get_name()
3598
if title is None:
3599
fontsize = 14
3600
if id is None:
3601
title = self.obj.get_name().title()
3602
else:
3603
title = self.obj.get_name().title()+' ['+str(id)+']'
3604
3605
#p=wx.Panel( self, wx.NewId(), wx.DefaultPosition,style=wx.SUNKEN_BORDER)
3606
titlewidget = wx.StaticText(self, wx.NewId(), title)
3607
font = wx.Font(fontsize, wx.SWISS, wx.NORMAL, wx.NORMAL)
3608
titlewidget.SetFont(font)
3609
# sizer.Add((5,5))
3610
# sizer.Add((5,5))
3611
# self.add_hline(sizer)
3612
# sizer.Add((20,20))
3613
sizer.Add(titlewidget, 0, wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL, 10)
3614
# sizer.Add((10,10))
3615
self.add_hline(sizer, 15)
3616
3617
def add_group(self, sizer, groupname):
3618
"""
3619
Add a group to the option panel.
3620
3621
This method does diaplay the entire group in a group
3622
widget.
3623
"""
3624
pass
3625
3626
def on_apply(self, event):
3627
"""
3628
Apply widget contents to object
3629
"""
3630
self.apply()
3631
3632
def on_restore(self, event):
3633
"""
3634
Copy object values to widget contents
3635
"""
3636
self.restore()
3637
3638
# def on_ok_modal(self,event):
3639
# """ NO! valueas are rtead out from calling function
3640
# Apply values, and continues withy modal windoe event handling
3641
# """
3642
# self.apply()
3643
# event.Skip()
3644
3645
def on_ok(self, event):
3646
"""
3647
Apply values, destroy itself and parent
3648
"""
3649
# print 'on_ok...'
3650
3651
# check if we must execute some callbacks if ids or attributes
3652
# have been selected
3653
# for widget in self.datawidgets:
3654
# if hasattr(widget,'on_ok')
3655
# else:
3656
self.apply()
3657
3658
self.Close()
3659
# self.parent.Destroy()
3660
# self.Destroy()
3661
3662
def on_cancel(self, event):
3663
"""
3664
Destroy itself and parent
3665
"""
3666
# print 'OP.on_cancel'
3667
self.Close()
3668
3669
def apply(self):
3670
"""
3671
Widget values are copied to object
3672
"""
3673
# print 'apply',self.obj.ident,self.datawidgets,self.func_apply
3674
for widget in self.datawidgets:
3675
# print ' widget',widget
3676
widget.apply()
3677
widget.restore()
3678
3679
if self.func_apply is not None:
3680
# print ' call self.func_choose_id',self.obj, self.id, self.ids
3681
#
3682
#wx.FutureCall(1,self.func_apply, self.obj, self.id, self.ids)
3683
wx.CallAfter(self.func_apply, self.obj, self.id, self.ids)
3684
# event.Skip()
3685
return
3686
3687
def restore(self):
3688
"""
3689
Object values are copied into widgets.
3690
"""
3691
for widget in self.datawidgets:
3692
widget.restore()
3693
3694
# def OnSetFocus(self, evt):
3695
# print "OnSetFocus"
3696
# evt.Skip()
3697
# def OnKillFocus(self, evt):
3698
# print "OnKillFocus"
3699
# evt.Skip()
3700
# def OnWindowDestroy(self, evt):
3701
# print "OnWindowDestroy"
3702
# evt.Skip()
3703
3704
3705
class ObjPanelDialog(ObjPanelMixin, wx.Dialog):
3706
def __init__(self, parent,
3707
obj, id=None, ids=None,
3708
attrconfigs=None,
3709
#tables = None,
3710
table=None,
3711
groupnames=None, show_groupnames=False,
3712
title='', size=wx.DefaultSize, pos=wx.DefaultPosition,\
3713
style=wx.DEFAULT_DIALOG_STYLE | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER,
3714
choose_id=False, choose_attr=False,
3715
func_choose_id=None, func_change_obj=None, func_apply=None,
3716
panelstyle='default',
3717
immediate_apply=False,
3718
**buttonargs):
3719
3720
# print 'ObjPanelDialog.__init__',choose_id,choose_attr,table
3721
3722
# print ' buttonargs,groupnames',buttonargs,groupnames
3723
# print ' size=',size
3724
# Instead of calling wx.Dialog.__init__ we precreate the dialog
3725
# so we can set an extra style that must be set before
3726
# creation, and then we create the GUI dialog using the Create
3727
# method.
3728
pre = wx.PreDialog()
3729
pre.SetExtraStyle(wx.DIALOG_EX_CONTEXTHELP)
3730
3731
if title == '':
3732
title = 'Dialog for: '+obj.get_name()
3733
pre.Create(parent, -1, title, pos, size=size, style=style)
3734
3735
# This next step is the most important, it turns this Python
3736
# object into the real wrapper of the dialog (instead of pre)
3737
# as far as the wxPython extension is concerned.
3738
self.PostCreate(pre)
3739
self.init_panel(parent)
3740
3741
if choose_id:
3742
self.recreate_panel(obj,
3743
id=id, ids=ids,
3744
attrconfigs=attrconfigs,
3745
#tables = tables,
3746
#table =table,
3747
groupnames=groupnames, show_groupnames=show_groupnames,
3748
show_title=False, is_modal=True,
3749
immediate_apply=immediate_apply,
3750
panelstyle=panelstyle,
3751
func_choose_id=self.on_choose_id, func_apply=func_apply,
3752
func_change_obj=func_change_obj,
3753
**buttonargs
3754
)
3755
3756
elif choose_attr:
3757
self.recreate_panel(obj, id=id, ids=ids,
3758
attrconfigs=attrconfigs,
3759
#tables = tables,
3760
#table =table,
3761
groupnames=groupnames, show_groupnames=show_groupnames,
3762
show_title=False, is_modal=True,
3763
immediate_apply=immediate_apply,
3764
panelstyle=panelstyle,
3765
func_choose_attr=self.on_choose_attr, func_apply=func_apply,
3766
func_change_obj=func_change_obj,
3767
**buttonargs
3768
)
3769
3770
else:
3771
# print ' normal mode without special callbacks',self.recreate_panel
3772
self.recreate_panel(obj, id=id, ids=ids,
3773
attrconfigs=attrconfigs,
3774
#tables = tables,
3775
#table =table,
3776
groupnames=groupnames, show_groupnames=show_groupnames,
3777
show_title=False, is_modal=True,
3778
immediate_apply=immediate_apply,
3779
panelstyle=panelstyle,
3780
func_choose_id=func_choose_id,
3781
func_change_obj=func_change_obj, func_apply=func_apply,
3782
**buttonargs
3783
)
3784
3785
self.id_chosen = -1
3786
self.attrconf_chosen = None
3787
3788
# self.recreate_panel(attrconfigs=attrconfigs,groups=groups,is_modal=True,
3789
# immediate_apply=immediate_apply, panelstyle=panelstyle)
3790
3791
# self.SetSize(self.GetSize())
3792
# self.SetSize(wx.DefaultSize)
3793
# self.SetSize(size)
3794
self.SetAutoLayout(1)
3795
self.Refresh()
3796
3797
def on_choose_id(self, id, attrconf=None):
3798
self.id_chosen = id
3799
self.attrconf_chosen = attrconf
3800
self.EndModal(wx.ID_OK)
3801
3802
def get_current_attrconf_id(self):
3803
"""
3804
Returns selected or current attribute and id
3805
"""
3806
# print 'get_current_attrconf_id',self.attrconf_chosen,self.id_chosen
3807
if (self.id_chosen == -1) & (self.attrconf_chosen == ''):
3808
# on_choose_id has not yet determined id
3809
# do though datawidgets and
3810
for widget in self.datawidgets:
3811
# print ' widget',widget
3812
if hasattr(widget, 'get_current_attrconf_id'):
3813
return widget.get_current_attrconf_id()
3814
3815
return self.attrconf_chosen, self.id_chosen
3816
3817
else:
3818
return self.attrconf_chosen, self.id_chosen
3819
3820
# def get_valueconf_chosen(self):
3821
# return self.attrconf_chosen
3822
3823
# class ObjPanel(ObjPanelMixin,wxlib.scrolledpanel.ScrolledPanel):
3824
3825
3826
class ObjPanel(ObjPanelMixin, wx.Panel):
3827
"""
3828
Interactively displays attributes of object on a panel.
3829
"""
3830
3831
def __init__(self, parent, obj=None,
3832
id=None, ids=None,
3833
attrconfigs=None,
3834
#tables = None,
3835
#table = None,
3836
groupnames=None,
3837
func_change_obj=None, func_apply=None,
3838
show_groupnames=False, show_title=True, is_modal=False,
3839
mainframe=None,
3840
pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.MAXIMIZE_BOX | wx.RESIZE_BORDER,
3841
immediate_apply=False, panelstyle='default', **buttonargs):
3842
3843
wx.Panel.__init__(self, parent, -1, pos, size, wx.SUNKEN_BORDER | wx.WANTS_CHARS)
3844
if obj is None:
3845
obj = cm.BaseObjman('empty')
3846
#wxlib.scrolledpanel.ScrolledPanel.__init__(self, parent,wx.ID_ANY,size=size)
3847
#self.maxWidth = 100
3848
#self.maxHeight = 100
3849
# self.SetVirtualSize((300,-1))
3850
# self.SetScrollRate(20,20)
3851
3852
self.init_panel(parent, mainframe=mainframe)
3853
# (re)create panel widgets
3854
# print 'ObjPanel.__init__',obj.ident,id,func_apply,groupnames
3855
self.recreate_panel(obj, id=id, ids=ids,
3856
attrconfigs=attrconfigs,
3857
groupnames=groupnames, show_groupnames=show_groupnames,
3858
show_title=show_title, is_modal=is_modal,
3859
immediate_apply=immediate_apply,
3860
panelstyle=panelstyle,
3861
func_change_obj=func_change_obj,
3862
func_apply=func_apply,
3863
**buttonargs)
3864
3865
# optionpanel.GetSize()
3866
3867
# self.SetAutoLayout(1)
3868
3869
3870
class TablePanel(ObjPanelMixin, wx.Panel):
3871
"""
3872
Common methods for panels
3873
"""
3874
3875
def __init__(self, parent, table,
3876
attrconfigs=None,
3877
id=None, ids=None,
3878
groupnames=None,
3879
func_change_obj=None, func_apply=None,
3880
show_groupnames=False, show_title=True, is_modal=False,
3881
mainframe=None, pos=wx.DefaultPosition, size=wx.DefaultSize,
3882
immediate_apply=False, panelstyle='default', **buttonargs):
3883
3884
wx.Panel.__init__(self, parent, -1, pos, size, wx.SUNKEN_BORDER)
3885
3886
self.init_panel(parent, mainframe=mainframe)
3887
# (re)create panel widgets
3888
# print 'TablePanel. __init__',table.get_name()
3889
self.recreate_panel(table,
3890
attrconfigs=attrconfigs,
3891
# ids=ids,
3892
groupnames=groupnames, show_groupnames=show_groupnames,
3893
show_title=show_title, is_modal=is_modal,
3894
immediate_apply=immediate_apply, func_apply=func_apply,
3895
panelstyle=panelstyle,
3896
func_change_obj=func_change_obj,
3897
**buttonargs)
3898
3899
# optionpanel.GetSize()
3900
3901
self.SetAutoLayout(1)
3902
3903
def recreate_panel(self, obj, # obj is table
3904
attrconfigs=None,
3905
# ids=None,
3906
groupnames=None, show_groupnames=False,
3907
show_title=True,
3908
is_modal=False,
3909
immediate_apply=False,
3910
panelstyle='default',
3911
func_change_obj=None,
3912
func_choose_id=None,
3913
func_choose_attr=None,
3914
func_apply=None,
3915
**buttonargs):
3916
"""
3917
Recreates panel and destroys previous contents:
3918
attr = a list ith attribute names to be shown
3919
groups = list with group names to be shown
3920
show_groupnames = the group names are shown
3921
together with the respective attributes
3922
is_modal = if true the panel will be optimized for dialog window
3923
immediate_apply = changes to widgets will be immediately applied to
3924
obj attribute without pressing apply
3925
buttonargs = a dictionary with arguments for botton creation
3926
obj = the object to be displayed
3927
id = used if there is only one single id to be displayed
3928
ids = used if a selection of ids need to be displayed
3929
func_change_obj = function to be called if user clicks on on object
3930
with obj as argument
3931
func_choose_id = function to be called when user clicks on id(table row)
3932
with id as argument
3933
func_choose_attr = function to be called when user clicks on attribute
3934
with attr as argument. In this case the attribute
3935
names of scalars turn into buttons. Array attributes
3936
are selected by clicking on the column name.
3937
"""
3938
#self.id = id
3939
#self.ids = ids
3940
self.obj = obj
3941
self.func_change_obj = func_change_obj
3942
self.func_choose_id = func_choose_id
3943
self.func_choose_attr = func_choose_attr
3944
self.func_apply = func_apply
3945
3946
# print '\n\nrecreate_panel name for id,ids=',obj.get_name(),ids
3947
# print ' attrs,groups=',attrs,groups
3948
# print ' immediate_apply',immediate_apply
3949
# this will be looked up by widgets to decide how to react to an input
3950
#self.immediate_apply = immediate_apply
3951
3952
# remove previous contents
3953
# ids_widgetcontainers=self.get_ids()
3954
# self.parent.DestroyChildren()
3955
#del self[ids_widgetcontainers]
3956
3957
# create vertical main sizer
3958
sizer = wx.BoxSizer(wx.VERTICAL)
3959
if show_title:
3960
self.add_title(sizer)
3961
3962
# show table with one or several ids
3963
self.add_table(sizer, obj, attrconfigs=attrconfigs,
3964
ids=ids, groupnames=groupnames, show_title=False)
3965
3966
self.SetSizer(sizer)
3967
sizer.Fit(self)
3968
3969
# some widgets like color need this to expand into their maximum space
3970
self.restore()
3971
3972
3973
class NaviPanelMixin:
3974
def add_hist(self, obj, id=None, ids=None, kwargs={}):
3975
"""
3976
Add a new obj to history list.
3977
The forward history will be eliminated.
3978
"""
3979
# print 'add_hist',self.hist,self.ind_hist
3980
3981
n_hist = len(self.hist)
3982
if n_hist == 0:
3983
# first entry
3984
self.ind_hist = 0
3985
3986
else:
3987
self.hist = self.hist[:self.ind_hist+1]
3988
# print ' hist[:self.ind_hist+1]',self.hist[:self.ind_hist+1]
3989
3990
self.hist.append((obj, id, ids, kwargs))
3991
self.ind_hist = len(self.hist)-1
3992
# print ' hist,self.ind_hist',self.hist,self.ind_hist
3993
3994
def get_hist(self, ind_delta=-1):
3995
"""
3996
Getting hist with changing pointer
3997
"""
3998
ind = self.ind_hist + ind_delta
3999
# print 'get_hist ind_hist,ind_delta,ind,len(self.hist),ok',self.ind_hist,ind_delta,ind,len(self.hist),(ind < len(self.hist)) & (ind >= 0)
4000
4001
if (ind < len(self.hist)) & (ind >= 0):
4002
self.ind_hist = ind
4003
# print ' OK self.ind_hist',self.ind_hist,self.hist[ind]
4004
return self.hist[ind]
4005
else:
4006
# print ' Fail self.ind_hist',self.ind_hist
4007
return None, None, None, None
4008
4009
def get_history(self, ind_delta=-1):
4010
"""
4011
Getting hist without changing pointer
4012
"""
4013
ind = self.ind_hist + ind_delta
4014
# print 'get_history',self.ind_hist,ind_delta,(ind < len(self.hist)) & (ind >= 0)
4015
4016
if (ind < len(self.hist)) & (ind >= 0):
4017
# self.ind_hist=ind
4018
return self.hist[ind]
4019
else:
4020
return None, None, None, None
4021
4022
def on_change_obj(self, event):
4023
# print 'Navicanvas.on_change_obj'
4024
obj = event.GetObj()
4025
self.refresh_panel(obj)
4026
event.Skip()
4027
4028
def change_obj(self, obj, id=None, ids=None, **kwargs):
4029
4030
if len(kwargs) == 0:
4031
# this is to recover kw arguments i.e. callbacks
4032
obj_last, id_last, ids_last, kwargs_last = self.get_history(0)
4033
if kwargs_last is not None:
4034
kwargs = kwargs_last
4035
4036
if self.func_apply is not None:
4037
kwargs['func_apply'] = self.func_apply
4038
4039
# print 'Navipanel.change_obj',obj.format_ident(),id,ids,kwargs.keys()
4040
4041
if hasattr(obj, 'get_ident'):
4042
self.refresh_panel(obj, id=id, ids=ids, **kwargs)
4043
self.add_hist(obj, id, ids, kwargs)
4044
4045
def get_obj(self):
4046
"""
4047
Returns currently displayed object
4048
"""
4049
return self.objpanel.obj
4050
4051
def refresh_panel(self, obj=None, id=None, ids=None, **kwargs):
4052
"""
4053
Deletes previous conents
4054
Builds panel for obj
4055
Updates path window and history
4056
"""
4057
4058
if obj is None:
4059
if self.get_obj() == self._defaultobj:
4060
return None # no changes
4061
else:
4062
obj = self._defaultobj
4063
4064
# print 'Navicanvas.refresh_panel with',obj.ident,kwargs
4065
4066
if id is not None:
4067
self.path.SetValue(obj.format_ident_row_abs(id))
4068
4069
elif ids is not None:
4070
# no id provided, just show identification string
4071
self.path.SetValue(obj.format_ident_abs())
4072
4073
else: # object and id provided: compose string with id
4074
self.path.SetValue(obj.format_ident_abs())
4075
4076
# self.path.SetSize((len(self.path.GetValue())*10,-1))
4077
# self.path.SetSize((-1,-1))
4078
# remove previous obj panel
4079
sizer = self.GetSizer()
4080
sizer.Remove(1)
4081
self.objpanel.Destroy()
4082
#del self.objpanel
4083
4084
# build new obj panel
4085
# self.objpanel=ObjPanel(self,obj,id=id,attrs=self.attrs,groups=self.groups,
4086
# func_change_obj=self.change_obj,
4087
# is_modal=self.is_modal,
4088
# mainframe=self.mainframe,
4089
# immediate_apply=self.immediate_apply,
4090
# **self.buttonargs)
4091
attrconfigs = obj.get_attrsman().get_configs()
4092
# for attrconfig in obj.get_configs()#attrconfigs:
4093
# if '_private' not in attrconfig.groups:
4094
# attrconfigs.append(attrconfig)
4095
4096
args = {'attrconfigs': attrconfigs,
4097
# 'tables' : None,
4098
# 'table' : None,
4099
'id': id, 'ids': ids,
4100
'groupnames': self.groupnames,
4101
'func_change_obj': self.change_obj,
4102
'show_groupnames': False, 'show_title': True, 'is_modal': self.is_modal,
4103
'mainframe': self.mainframe, 'pos': wx.DefaultPosition, 'size': wx.DefaultSize,
4104
'immediate_apply': self.immediate_apply, 'panelstyle': 'default'
4105
}
4106
4107
args.update(self.buttonargs)
4108
args.update(kwargs)
4109
4110
# print ' make ObjPanel\n args =',args
4111
4112
self.objpanel = ObjPanel(self, obj=obj, **args)
4113
# if id is not None:
4114
# self.objpanel=ObjPanel(self,obj,id=id,func_change_obj=self.change_obj)
4115
# else:
4116
# self.objpanel=ObjPanel(self,obj,func_change_obj=self.change_obj)
4117
sizer.Add(self.objpanel, 1, wx.GROW)
4118
4119
self.Refresh()
4120
# sizer.Fit(self)
4121
sizer.Layout()
4122
# add to history
4123
return None
4124
4125
def on_change_path(self, event):
4126
"""
4127
Key stroke on path field. Change object when return is pressed.
4128
"""
4129
keycode = event.GetKeyCode()
4130
if keycode == wx.WXK_RETURN:
4131
# print 'change path to',self.path.GetValue()
4132
# self.refresh_panel(obj)
4133
pass
4134
else:
4135
event.Skip()
4136
4137
# def recreate_panel(self,obj):
4138
# """
4139
# Removes previous contents and displays attributes on panel.
4140
# """
4141
# pass
4142
4143
def on_go_back(self, event):
4144
# print 'on_go_back'
4145
# print ' hist=',self.hist
4146
obj, id, ids, kwargs = self.get_hist(-1)
4147
# if obj is not None:
4148
# print ' done: obj, hist, ind_hist',obj.ident,self.hist,self.ind_hist
4149
# else:
4150
# print ' failed: hist, ind_hist',self.hist,self.ind_hist
4151
4152
if obj is not None:
4153
# print ' refresh_panel with',obj.ident
4154
self.refresh_panel(obj, id, ids, **kwargs)
4155
event.Skip()
4156
4157
def on_go_forward(self, event):
4158
obj, id, ids, kwargs = self.get_hist(+1)
4159
# print 'on_go_forward to obj',obj
4160
4161
# if obj is not None:
4162
# print ' Done:obj.ident,self.hist,self.ind_hist',obj.ident,self.hist,self.ind_hist
4163
# else:
4164
# print ' Failed:self.hist,self.ind_hist',self.hist,self.ind_hist
4165
4166
if obj is not None:
4167
# print ' refresh_panel with',obj.ident
4168
self.refresh_panel(obj, id, ids, **kwargs)
4169
event.Skip()
4170
4171
def on_go_up(self, event):
4172
4173
obj = self.objpanel.get_obj()
4174
_id = self.objpanel.get_id()
4175
4176
# this is to recover kw arguments i.e. callbacks
4177
obj_last, id_last, ids_last, kwargs_last = self.get_history(0)
4178
if kwargs_last is not None:
4179
kwargs = kwargs_last
4180
else:
4181
kwargs = {}
4182
4183
parent = obj.get_parent()
4184
# print 'on_go_up',obj,id,parent
4185
if _id is None:
4186
# show parent object
4187
if type(parent) == types.InstanceType:
4188
if hasattr(parent, 'ident'):
4189
self.refresh_panel(parent, None, None, **kwargs)
4190
self.add_hist(parent, None, None, kwargs)
4191
else:
4192
# show table object if table row id has been previously
4193
self.refresh_panel(obj, None, None, **kwargs)
4194
self.add_hist(obj, None, None, kwargs)
4195
4196
event.Skip()
4197
4198
def on_go_home(self, event):
4199
obj = self.objpanel.get_obj()
4200
root = obj.get_root()
4201
if type(root) == types.InstanceType:
4202
if hasattr(root, 'ident'):
4203
self.refresh_panel(root)
4204
event.Skip()
4205
# print 'on_go_home'
4206
4207
def on_enter_window(self, evt):
4208
# print 'on_enter_window'
4209
self.SetFocus()
4210
4211
def init_navbar(self, obj, _id=None):
4212
"""
4213
Initialize toolbar which consist of navigation buttons
4214
"""
4215
bottonsize = (32, 32)
4216
bottonborder = 10
4217
toolbarborder = 1
4218
4219
# toolbar
4220
self.toolbar = wx.BoxSizer(wx.HORIZONTAL)
4221
4222
# self.init_toolbar()
4223
#bottons = []
4224
bitmap = wx.ArtProvider_GetBitmap(wx.ART_GO_BACK, wx.ART_TOOLBAR)
4225
b = wx.BitmapButton(self, -1, bitmap, bottonsize,
4226
(bitmap.GetWidth()+bottonborder, bitmap.GetHeight()+bottonborder))
4227
b.SetToolTipString("Go back in browser history.")
4228
self.Bind(wx.EVT_BUTTON, self.on_go_back, b)
4229
self.toolbar.Add(b, flag=wx.ALL, border=toolbarborder)
4230
# bottons.append(b)
4231
#self.toolbar.Add(b, flag=wx.ALL, border=toolbarborder)
4232
4233
bitmap = wx.ArtProvider_GetBitmap(wx.ART_GO_FORWARD, wx.ART_TOOLBAR)
4234
b = wx.BitmapButton(self, -1, bitmap, bottonsize,
4235
(bitmap.GetWidth()+bottonborder, bitmap.GetHeight()+bottonborder))
4236
b.SetToolTipString("Go forward in browser history.")
4237
self.Bind(wx.EVT_BUTTON, self.on_go_forward, b)
4238
self.toolbar.Add(b, 0, wx.EXPAND, border=toolbarborder)
4239
# bottons.append(b)
4240
4241
bitmap = wx.ArtProvider_GetBitmap(wx.ART_GO_UP, wx.ART_TOOLBAR)
4242
b = wx.BitmapButton(self, -1, bitmap, bottonsize,
4243
(bitmap.GetWidth()+bottonborder, bitmap.GetHeight()+bottonborder))
4244
b.SetToolTipString("Go up to parent object.")
4245
self.Bind(wx.EVT_BUTTON, self.on_go_up, b)
4246
self.toolbar.Add(b, 0, wx.EXPAND, border=toolbarborder)
4247
4248
# self.add_tool(
4249
# 'up',self.on_go_up,
4250
# wx.ArtProvider.GetBitmap(wx.ART_GO_UP, wx.ART_TOOLBAR, tsize),
4251
# 'show panel of parent instance')
4252
4253
bitmap = wx.ArtProvider_GetBitmap(wx.ART_GO_HOME, wx.ART_TOOLBAR)
4254
b = wx.BitmapButton(self, -1, bitmap, bottonsize,
4255
(bitmap.GetWidth()+bottonborder, bitmap.GetHeight()+bottonborder))
4256
b.SetToolTipString("Go to main object, the mother of all objects.")
4257
self.Bind(wx.EVT_BUTTON, self.on_go_home, b)
4258
self.toolbar.Add(b, 0, wx.EXPAND, border=toolbarborder)
4259
4260
# self.add_tool(
4261
# 'home',self.on_go_home,
4262
# wx.ArtProvider.GetBitmap(wx.ART_GO_HOME, wx.ART_TOOLBAR, tsize),
4263
# 'show panel of root instance')
4264
4265
# size=(-1, -1))#,size=(300, -1))
4266
self.path = wx.TextCtrl(self, -1, self.get_ident_abs(obj, _id), style=wx.TE_RIGHT)
4267
#self.path=wx.TextCtrl(self.toolbar, -1, obj.format_ident_abs(), style=wx.TE_RIGHT)
4268
# wx.EVT_ENTER_WINDOW(self.path,self.on_enter_window)
4269
# self.add_tool('path',widget=self.path)
4270
self.path.Bind(wx.EVT_CHAR, self.on_change_path)
4271
#self.toolbar.Add(self.path, flag=wx.ALL, border=toolbarborder)
4272
self.toolbar.Add(self.path, 1, wx.EXPAND, border=toolbarborder)
4273
#self.toolbar.AddControl(wx.TextCtrl(self.toolbar, -1, "Toolbar controls!!", size=(150, -1)))
4274
4275
# self.toolbar.AddSeparator()
4276
bitmap = wx.Bitmap(os.path.join(IMAGEDIR, 'fig_menu_icon.png'), wx.BITMAP_TYPE_PNG)
4277
b = wx.BitmapButton(self, -1, bitmap, bottonsize,
4278
(bitmap.GetWidth()+bottonborder, bitmap.GetHeight()+bottonborder))
4279
b.SetToolTipString("Object browser menu. Click for actions on this object")
4280
#b = wx.Button(self, label="Show/Hide")
4281
self.Bind(wx.EVT_BUTTON, self.popup_menu, b)
4282
self.toolbar.Add(b)
4283
4284
# panel.SetAutoLayout(True)
4285
# panel.SetSizer(buttons)
4286
4287
self.toolbar.Fit(self)
4288
4289
# only for frames
4290
# self.SetToolBar(self.toolbar)
4291
4292
def popup_menu(self, event):
4293
#btn = event.GetEventObject()
4294
#drawing = self._canvas.get_drawing()
4295
4296
# Create the popup menu
4297
self._popupmenu = AgilePopupMenu(self)
4298
self._popupmenu.append_item(
4299
'Export to CSV...',
4300
self.on_export_csv,
4301
info='Export current object in CSV format.',
4302
#check= drawobj.is_visible(),
4303
)
4304
4305
if ex.IS_EXCEL:
4306
self._popupmenu.append_item(
4307
'Export to Excel...',
4308
self.on_export_excel,
4309
info='Export current object in EXCEL format.',
4310
#check= drawobj.is_visible(),
4311
)
4312
4313
self.PopupMenu(self._popupmenu)
4314
self._popupmenu.Destroy()
4315
event.Skip()
4316
4317
def on_export_excel(self, event):
4318
print 'on_export_excel'
4319
obj = self.objpanel.get_obj()
4320
4321
#dirpath = self.get_scenario().get_workdirpath()
4322
#defaultFile = self.get_scenario().get_rootfilename()+'.rou.xml'
4323
wildcards_all = 'Excel files (*.xls)|*.xls|All files (*.*)|*.*'
4324
dlg = wx.FileDialog(None, message='Export object to Excel file',
4325
# defaultDir=dirpath,
4326
# defaultFile=defaultFile,
4327
wildcard=wildcards_all, style=wx.SAVE | wx.CHANGE_DIR)
4328
if dlg.ShowModal() == wx.ID_OK:
4329
filepath = dlg.GetPath()
4330
ex.export_excel(filepath, obj, ids=None, attrconfigs=None, groupnames=None,
4331
is_header=True, is_ident=False, is_timestamp=True,
4332
show_parentesis=True, name_id='ID', is_export_not_save=True)
4333
else:
4334
return
4335
4336
def on_export_csv(self, event):
4337
print 'on_export_csv'
4338
obj = self.objpanel.get_obj()
4339
4340
#dirpath = self.get_scenario().get_workdirpath()
4341
#defaultFile = self.get_scenario().get_rootfilename()+'.rou.xml'
4342
wildcards_all = 'CSV files (*.csv)|*.csv|Text files (*.txt)|*.txt|All files (*.*)|*.*'
4343
dlg = wx.FileDialog(None, message='Export object to CSV file',
4344
# defaultDir=dirpath,
4345
# defaultFile=defaultFile,
4346
wildcard=wildcards_all, style=wx.SAVE | wx.CHANGE_DIR)
4347
if dlg.ShowModal() == wx.ID_OK:
4348
filepath = dlg.GetPath()
4349
obj.export_csv(filepath, sep=',',
4350
attrconfigs=None, groupnames=None,
4351
is_header=True, is_ident=False, is_timestamp=True,
4352
show_parentesis=True)
4353
else:
4354
return
4355
4356
def get_ident_abs(self, obj, _id):
4357
if _id is not None:
4358
return obj.format_ident_row_abs(_id)
4359
4360
else:
4361
return obj.format_ident_abs()
4362
4363
def init_objpanel(self, obj, id=None, ids=None, attrconfigs=None, groupnames=None,
4364
is_modal=True, mainframe=None, func_apply=None,
4365
immediate_apply=False, panelstyle='default', **buttonargs):
4366
"""
4367
Initializes object panel, bu also stores parameters such as
4368
mode, groups etc
4369
"""
4370
self.attrconfigs = attrconfigs
4371
self.groupnames = groupnames
4372
self.is_modal = is_modal
4373
self.mainframe = mainframe
4374
self.immediate_apply = immediate_apply
4375
self.panelstyle = panelstyle
4376
self.buttonargs = buttonargs
4377
# self.objpanel=ObjPanel(self,obj,id=id,ids=ids,attrs=attrs,groups=groups,
4378
# func_change_obj=self.change_obj,
4379
# is_modal=is_modal,
4380
# mainframe=mainframe,
4381
# immediate_apply=immediate_apply, panelstyle=panelstyle,
4382
# **buttonargs)
4383
self.objpanel = ObjPanel(self, obj=obj,
4384
attrconfigs=self.attrconfigs,
4385
#tables = None,
4386
#table = None,
4387
id=id, ids=ids,
4388
groupnames=groupnames,
4389
func_change_obj=self.change_obj,
4390
show_groupnames=False, show_title=True, is_modal=self.is_modal,
4391
mainframe=self.mainframe, pos=wx.DefaultPosition, size=wx.DefaultSize,
4392
func_apply=func_apply,
4393
immediate_apply=self.immediate_apply, panelstyle='default',
4394
**self.buttonargs)
4395
4396
def init_hist(self):
4397
"""
4398
Initialize history variables
4399
"""
4400
self.hist = []
4401
self.ind_hist = -1
4402
4403
4404
class NaviPanel(NaviPanelMixin, wx.Panel):
4405
"""
4406
4407
Interactively navigates through objects and displays attributes
4408
on a panel.
4409
"""
4410
4411
def __init__(self, parent, obj, id=None, mainframe=None, func_apply=None, **args):
4412
if obj is None:
4413
obj = cm.BaseObjman('empty')
4414
wx.Panel.__init__(self, parent, -1, wx.DefaultPosition, wx.DefaultSize)
4415
# print 'NaviPanel',obj.ident,id,func_apply,args
4416
sizer = wx.BoxSizer(wx.VERTICAL)
4417
# define a default object which is shown when
4418
# refresh is called without arguments
4419
self._defaultobj = obj
4420
self.func_apply = func_apply
4421
# initialize history
4422
self.init_hist()
4423
4424
# make navigation toolbar
4425
self.init_navbar(obj, id)
4426
4427
# create initial panel
4428
self.init_objpanel(obj, id=id, mainframe=mainframe, is_modal=False, func_apply=func_apply, **args)
4429
4430
sizer.Add(self.toolbar, 0, wx.ALL | wx.ALIGN_LEFT | wx.GROW, 4) # from NaviPanelTest
4431
sizer.Add(self.objpanel, 1, wx.GROW) # from NaviPanelTest
4432
4433
# finish panel setup
4434
self.SetSizer(sizer)
4435
sizer.Fit(self)
4436
# add to history
4437
# self.add_hist(obj,id,None,args)
4438
# self.SetSize(parent.GetSize())
4439
4440
4441
class ObjBrowserMainframe(wx.Frame):
4442
4443
"""
4444
A frame used for the ObjBrowser Demo
4445
4446
"""
4447
4448
def __init__(self, parent, wxid, title, position, size, obj=None, _id=None, table=None):
4449
wx.Frame.__init__(self, parent, wxid, title, position, size)
4450
# print 'ObjBrowserMainframe',obj.ident,_id
4451
# Set up the MenuBar
4452
MenuBar = wx.MenuBar()
4453
4454
file_menu = wx.Menu()
4455
item = file_menu.Append(-1, "&Open...", "Open an object from file.")
4456
self.Bind(wx.EVT_MENU, self.OnLoad, item)
4457
item = file_menu.Append(-1, "&Save as", "Save an object under file.")
4458
self.Bind(wx.EVT_MENU, self.OnSave, item)
4459
item = file_menu.Append(-1, "&Close", "Close this frame")
4460
self.Bind(wx.EVT_MENU, self.OnQuit, item)
4461
4462
MenuBar.Append(file_menu, "&File")
4463
4464
help_menu = wx.Menu()
4465
item = help_menu.Append(-1, "&About",
4466
"More information About this program")
4467
self.Bind(wx.EVT_MENU, self.OnAbout, item)
4468
MenuBar.Append(help_menu, "&Help")
4469
4470
self.SetMenuBar(MenuBar)
4471
4472
self.CreateStatusBar()
4473
4474
# Create Browser widget here
4475
#browser = wx.Panel(self, -1, wx.DefaultPosition, size = wx.DefaultSize)
4476
#browser = ObjPanel(self,obj, id=10)
4477
if obj is not None:
4478
# print ' init ObjPanel'
4479
#self.browser = ObjPanel(self, obj)
4480
self.browser = NaviPanel(self, obj, _id)
4481
elif table is not None:
4482
# print ' init TablePanel'
4483
self.browser = TablePanel(self, table)
4484
else:
4485
obj = cm.BaseObjman('empty')
4486
self.browser = NaviPanel(self, obj, _id)
4487
#browser = TablePanel(self,obj)
4488
# self.MsgWindow = wx.TextCtrl(self, wx.ID_ANY,
4489
# "Look Here for output from events\n",
4490
# style = (wx.TE_MULTILINE |
4491
# wx.TE_READONLY |
4492
# wx.SUNKEN_BORDER)
4493
# )
4494
4495
# TODO:INTERESTING:
4496
# wxTextCtrl *control = new wxTextCtrl(...);
4497
# wxStreamToTextRedirector redirect(control);
4498
# // all output to cout goes into the text control until the exit from
4499
# // current scope
4500
4501
#self.MsgWindow = py.crust.Crust(self, intro='Check it out!')
4502
self.MsgWindow = py.shell.Shell(self)
4503
# Create a sizer to manage the Canvas and message window
4504
MainSizer = wx.BoxSizer(wx.VERTICAL)
4505
MainSizer.Add(self.browser, 4, wx.EXPAND)
4506
MainSizer.Add(self.MsgWindow, 1, wx.EXPAND | wx.ALL, 5)
4507
4508
self.SetSizer(MainSizer)
4509
self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
4510
4511
self.EventsAreBound = False
4512
4513
# getting all the colors for random objects
4514
wxlib.colourdb.updateColourDB()
4515
self.colors = wxlib.colourdb.getColourList()
4516
4517
self.__init_specific()
4518
4519
return None
4520
4521
def __init_specific(self):
4522
pass
4523
4524
def OnAbout(self, event):
4525
dlg = wx.MessageDialog(self,
4526
"This is a small program to demonstrate\n"
4527
"the use of the Objbrowser\n",
4528
"About Me",
4529
wx.OK | wx.ICON_INFORMATION)
4530
dlg.ShowModal()
4531
dlg.Destroy()
4532
4533
def OnLoad(self, event):
4534
4535
dlg = wx.FileDialog(self, message="Open object",
4536
defaultDir=os.getcwd(),
4537
# defaultFile="",
4538
wildcard=wildcards_all,
4539
style=wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR
4540
)
4541
4542
# Show the dialog and retrieve the user response. If it is the OK response,
4543
# process the data.
4544
if dlg.ShowModal() == wx.ID_OK:
4545
# This returns a Python list of files that were selected.
4546
paths = dlg.GetPaths()
4547
# print 'You selected %d files:' % len(paths)
4548
if len(paths) > 0:
4549
filepath = paths[0]
4550
obj = cm.load_obj(filepath)
4551
4552
MainSizer = self.GetSizer()
4553
MainSizer.Remove(0)
4554
MainSizer.Remove(1)
4555
4556
self.browser.Destroy()
4557
self.MsgWindow.Destroy()
4558
4559
# build new obj panel
4560
self.browser = ObjPanel(self, obj)
4561
# sizer.Add(self.objpanel,0,wx.GROW)
4562
4563
#self.browser = wx.Panel(self, -1)
4564
#button = wx.Button(self.browser, 1003, "Close Me")
4565
#button.SetPosition((15, 15))
4566
4567
# sizer.Add(panel,1,wx.GROW)
4568
4569
self.MsgWindow = py.shell.Shell(self)
4570
# Create a sizer to manage the Canvas and message window
4571
MainSizer.Add(self.browser, 4, wx.EXPAND)
4572
MainSizer.Add(self.MsgWindow, 1, wx.EXPAND | wx.ALL, 5)
4573
4574
self.Refresh()
4575
MainSizer.Layout()
4576
4577
def OnSave(self, event):
4578
dlg = wx.FileDialog(
4579
self, message="Save file as ...", defaultDir=os.getcwd(),
4580
# defaultFile="",
4581
wildcard=wildcards_all, style=wx.SAVE
4582
)
4583
4584
# This sets the default filter that the user will initially see. Otherwise,
4585
# the first filter in the list will be used by default.
4586
dlg.SetFilterIndex(0)
4587
4588
# Show the dialog and retrieve the user response. If it is the OK response,
4589
# process the data.
4590
if dlg.ShowModal() == wx.ID_OK:
4591
filepath = dlg.GetPath()
4592
cm.save_obj(self.browser.get_obj(), filepath)
4593
4594
def OnQuit(self, event):
4595
self.Close(True)
4596
4597
def OnCloseWindow(self, event):
4598
self.Destroy()
4599
4600
4601
class ObjBrowserApp(wx.App):
4602
"""
4603
4604
"""
4605
4606
def __init__(self, obj, _id=None, output=False, logger=None, **kwargs):
4607
if obj is None:
4608
obj = cm.BaseObjman('empty')
4609
self._obj = obj
4610
self._id = _id
4611
# print 'ObjBrowserApp.__init__',obj.ident, _id
4612
self._logger = logger
4613
wx.App.__init__(self, output, **kwargs)
4614
4615
def OnInit(self):
4616
wx.InitAllImageHandlers()
4617
#DrawFrame = BuildDrawFrame()
4618
#frame = ObjBrowserMainframe(None, -1, "Object browser",wx.DefaultPosition,(700,700),obj=self._obj, _id = self._id)
4619
4620
frame = ObjBrowserMainframe(None, -1, 'Object browser', wx.DefaultPosition,
4621
size=wx.DefaultSize, obj=self._obj, table=None)
4622
#title ='Object browser',
4623
#appname = 'Object browser app',
4624
#logger = self._logger,
4625
#appdir = '',
4626
# is_maximize = False, is_centerscreen = True,
4627
#pos=wx.DefaultPosition, size=wx.DefaultSize,
4628
# style=wx.DEFAULT_FRAME_STYLE,
4629
#name='Object browser frame',
4630
#size_toolbaricons = (24,24)
4631
# )
4632
self.SetTopWindow(frame)
4633
frame.Show()
4634
4635
return True
4636
4637
4638
class TableBrowserApp(wx.App):
4639
"""
4640
4641
"""
4642
4643
def __init__(self, tab, **kwargs):
4644
self._tab = tab
4645
# print 'ViewerApp.__init__',self._net
4646
4647
wx.App.__init__(self, **kwargs)
4648
4649
def OnInit(self):
4650
wx.InitAllImageHandlers()
4651
#DrawFrame = BuildDrawFrame()
4652
frame = ObjBrowserMainframe(None, -1, "Table browser", wx.DefaultPosition, (700, 700), table=self._tab)
4653
4654
self.SetTopWindow(frame)
4655
frame.Show()
4656
4657
return True
4658
4659
4660
def objbrowser(obj, _id=None):
4661
app = ObjBrowserApp(obj, _id=_id, output=False) # put in True if you want output to go to its own window.
4662
# print 'call MainLoop'
4663
app.MainLoop()
4664
4665
4666
###############################################################################
4667
if __name__ == '__main__':
4668
4669
from agilepy.lib_base.test_classman_classes import *
4670
# no from agilepy.lib_base.classman import *
4671
from agilepy.lib_base.classman import load_obj, save_obj
4672
############
4673
# make up a test class
4674
n_test = 0 # <<<<<<<<<<<<<<<<<<
4675
############
4676
_id = None
4677
4678
if n_test == 0:
4679
# simple scalar parameters, no table
4680
obj = TestClass()
4681
print 'obj.ident', obj.ident
4682
4683
elif n_test == 1:
4684
obj = TestTableObjMan()
4685
4686
elif n_test == -1:
4687
obj = TestTableObjManNocols()
4688
4689
elif n_test == 2:
4690
obj = demand
4691
4692
elif n_test == 3:
4693
obj = lines
4694
4695
elif n_test == 4:
4696
_id = 1
4697
obj = TestTableObjMan()
4698
elif n_test == 5:
4699
obj = drawing
4700
elif n_test == -5:
4701
save_obj(drawing, 'test_drawing.obj')
4702
print '\nreload'+60*'.'
4703
obj = load_obj('test_drawing.obj')
4704
obj.get_attrsman().print_attrs()
4705
4706
elif n_test == 6:
4707
obj = polylines
4708
objbrowser(obj, _id=_id)
4709
4710