Path: blob/main/tools/contributed/sumopy/agilepy/lib_wx/objpanel.py
169689 views
#!/usr/bin/env python1# Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2# Copyright (C) 2016-2025 German Aerospace Center (DLR) and others.3# SUMOPy module4# Copyright (C) 2012-2021 University of Bologna - DICAM5# This program and the accompanying materials are made available under the6# terms of the Eclipse Public License 2.0 which is available at7# https://www.eclipse.org/legal/epl-2.0/8# This Source Code may also be made available under the following Secondary9# Licenses when the conditions for such availability set forth in the Eclipse10# Public License 2.0 are satisfied: GNU General Public License, version 211# or later which is available at12# https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html13# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later1415# @file objpanel.py16# @author Joerg Schweizer17# @date 20121819# cd /home/joerg/projects/sumopy/tools/sumopy/wxpython20# python objpanel.py2122import string23import random24from agilepy.lib_base.misc import filepathlist_to_filepathstring, filepathstring_to_filepathlist25from wxmisc import KEYMAP, AgilePopupMenu, AgileToolbarMixin, get_tablecolors26import agilepy.lib_base.exports as ex27import time28from agilepy.lib_base.logger import Logger29import agilepy.lib_base.classman as cm30import wx.py as py # pyshell31from collections import OrderedDict32import wx.lib.colourselect as coloursel33import wx.lib.editor as editor34from wx.lib import scrolledpanel, hyperlink, colourdb, masked35import wx.grid as gridlib36import wx.lib as wxlib37import wx38import numpy as np39import sys40import os41import types42if __name__ == '__main__':43# search SUMOPy in local directory (where this file is located)44try:45APPDIR = os.path.dirname(os.path.abspath(__file__))46except:47APPDIR = os.path.dirname(os.path.abspath(sys.argv[0]))48sys.path.append(os.path.join(APPDIR, '..', '..'))495051# from processdialog import ProcessDialog # no! uses objectpanel5253havePopupWindow = 154if wx.Platform == '__WXMAC__':55havePopupWindow = 056wx.PopupWindow = wx.PopupTransientWindow = wx.Window575859if __name__ == '__main__':60APPDIR = os.path.join(os.path.dirname(__file__), "..", "..")61sys.path.append(APPDIR)6263IMAGEDIR = os.path.join(os.path.dirname(__file__), 'images')646566# used for demo:67wildcards_all = "All files (*.*)|*.*"6869provider = wx.SimpleHelpProvider()70wx.HelpProvider_Set(provider)7172METATYPES_LINKSTYLE = ('obj', 'id', 'tabid', 'ids')7374NUMERICTYPES = cm.NUMERICTYPES # (types.BooleanType,types.FloatType,types.IntType,types.LongType,types.ComplexType)75STRINGTYPES = cm.STRINGTYPES # (types.StringType,types.UnicodeType)767778def list_to_str(l, lb='', rb='', sep=','):79# print 'list_to_str',l,len(l)80if len(l) == 0:81return lb+rb82else:83s = lb84for e in l[:-1]:85s += unicode(e)+sep86# print ' returns',s+unicode(l[-1])+rb87return s+unicode(l[-1])+rb888990def is_list_flat(l):91if type(l) not in (types.ListType, types.TupleType): # STRINGTYPES:92# not a list93return False9495is_flat = True96for e in l:97if hasattr(e, '__iter__'):98is_flat = False99break100return is_flat101102103def str_to_list(s, lb='[', rb=']'):104"""105Tries to convert a string to a flat list.106Attention, this conversion is extremely tolerant.107For example:108s='bus,bike' and s="['bus','bike']" will return the same result.109s='5,2.5' and s="['5','2.5']" will also return the same result110trying to convert numbers in integers or floats111"""112s = s.strip()113if len(s) >= 2:114if (s[0] == lb) & (s[-1] == rb): # are there braces115sl = s[1:-1].split(',')116else:117sl = s.split(',') # no braces, but could still be a list118else:119sl = s.split(',')120121if (len(sl) == 1) & (sl[0] == ''):122return []123124l = []125for e in sl:126l.append(str_to_obj(e))127# print 'str_to_list',s,l128return l129130131def str_to_tuple(s):132return str_to_list(s, lb='(', rb=')')133134135def str_to_obj(s):136"""137Only for flat objects at the moment138"""139# print 'str_to_obj',type(s),s140s = s.strip()141if len(s) == 0:142return ''143144if s[0] == s[-1]:145if s[0] in("'", '"'):146s = s[1:-1]147# print 'str_to_obj',s,len(s),type(s),s.isdigit(),s.isalnum()148if s.isdigit():149return string.atoi(s)150else:151try:152return string.atof(s)153except:154return s155156157def str_to_obj_nested(s):158"""159NOT WORKING, NOT IN USE160Only for flat objects at the moment161"""162# print 'str_to_obj',s163x = str_to_list(s)164# print ' ',x165if x is None:166x = str_to_tuple(s)167if x is None:168# if type(s) == types.StringType:169if s.isdigit():170return string.atoi(s)171elif s.isalnum():172return s173else:174try:175return string.atof(s)176except:177return s178else:179return x180181else:182return x183184185class AttrBase:186"""187Mixin class that provides methods to support text representation188of attributes189"""190191def num_to_text(self, value, attr, obj):192"""193Returns string of a numeric value taking account of formating194info for this defined in obj.195"""196pass197198def color_to_ffffff(self, color):199"""200Returns a 3- tuple with values for rgb between 0 and 255.201Takes an array or list with rgb values between 0.0 and 1.0.202"""203# print 'color_to_ffffff',color204return (color[0], color[1], color[2])205206def ffffff_to_color(self, ffffff):207"""208Returns an array with rgb values between 0.0 and 1.0.209Returns a 3- tople with values for rgb between 0 and 255.210211"""212# print 'ffffff_to_color',ffffff,type(ffffff),type(array(ffffff,float)/255.0)213return np.array(ffffff, float)/255.0214# return np.array(ffffff,int)215216217class WidgetContainer:218"""219Contains one or several widgets representing a scalar attribute.220Should be overwritten to accomodate various interactive datatypes.221Default is simple text.222223"""224225def __init__(self, parent, attrconf, mainframe=None, color_bg=None,226panelstyle='default', immediate_apply=False,227equalchar=':'):228"""229Parent is the ScalarPanel panel,230attr is the attribute name in parent.obj231"""232self.parent = parent233self.panelstyle = panelstyle234self.immediate_apply = immediate_apply235self._attrconf = attrconf236self.equalchar = equalchar237238self.mainframe = mainframe239240if color_bg is None:241self.color_bg = wx.NamedColour('grey85')242else:243self.color_bg = color_bg244245# self.widgets=[]246# self.untitwidget=None247# self.valuewidget=None248# self.bitmapwidget=None249250self.create_widgets(self.define_widgetset())251252253# -------------------------------------------------------------------------------254# the following methods are usually overwritten to create255# attribute specific widgets256257258def define_widgetset(self):259"""260Generates the widgets representing this attribute.261To be overwritten.262"""263return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),264('value', self.create_valuewidget(), wx.EXPAND), ]265266def get_valuewidget_write(self):267"""268Returns instance of editable widget269To be overwritten.270"""271# if non is returned attribute is not editable272# even though permission is set to write273return None274275def get_valuewidget_read(self):276"""277Returns instance of non-editable widget278To be overwritten.279"""280281#text = '%s%s'%(self._attrconf.format_value(),self._attrconf.format_unit())282text = self.format_value_obj(show_unit=True, show_parentesis=False)283# if not editable, no unitwidgetcontainer will be created so we need unit284# if len(text)>40:285# text=text[:10]+'...'+text[-10:]286#widget=wx.StaticText(self.parent, -1, text,style=wx.ALIGN_RIGHT)287# ,style= wx.ALIGN_RIGHT288#widget=wx.StaticText(self.parent, -1,'TEST!',style=wx.ALIGN_RIGHT)289# print ' value,widget',string_value,widget290291# no, showed only first character292#widget = editor.Editor(self.parent, -1, style=wx.SUNKEN_BORDER)293# widget.SetText(text)294# print 'get_valuewidget_read',self._attrconf.attrname295# print ' text RET',text.find('n'),':\n',text296if text.find('n') > 0:297widget = wx.TextCtrl(self.parent, -1, str(text), style=wx.ALIGN_LEFT | wx.TE_MULTILINE | wx.TE_READONLY)298else:299widget = wx.TextCtrl(self.parent, -1, str(text), style=wx.ALIGN_LEFT | wx.TE_READONLY)300# self.set_textevents(widget)301302widget.Enable(False)303304return widget305306def get_widgetvalue(self):307"""308Returnes current value from valuewidget.309Depends on attribute type and hence widgettype.310To be overwritten.311"""312return None # self.widgets['value'][0].GetLabel()313314def set_widgetvalue(self, value):315"""316Sets value for valuewidget.317Depends on attribute type and hence widgettype.318To be overwritten.319"""320text = str(value)321# if len(text)>40:322# text=text[:10]+'...'+text[-10:]323if hasattr(self.widgets['value'][0], 'SetValue'):324self.widgets['value'][0].SetValue(text)325326# OR?327# if self._attrconf.is_writable():328# self.widgets['value'][0].SetValue(value)329# else:330331# OR?332# if hasattr(self.widgets['value'][0],'SetValue'):333# self.widgets['value'][0].SetValue(str(value))334# elif hasattr(self.widgets['value'][0],'SetText'):335# print 'set_widgetvalue mixin',type(value),value336# self.widgets['value'][0].SetText(str(value))337# self.valuewidget.SetLabel(str(value))338339# -------------------------------------------------------------------------------340# these methods are normally not overwritten341342def create_valuewidget(self):343"""344Returns widget representing the value of attribute.345Dependent on read or write access the346get_valuewidget_write or get_valuewidget_read347will be called to generate the widget.348"""349# print 'create_valuewidget for',self._attrconf.attrname,'is_writable=',self._attrconf.is_writable()350351if self._attrconf.is_writable():352# in write mode unit widget should be created separately353widget = self.get_valuewidget_write()354if widget is None:355# print ' editable valuewidget not available'356widget = self.get_valuewidget_read()357else:358widget = self.get_valuewidget_read()359360self.set_tooltip(widget)361self.extend_widgetsize(widget)362self.valuewidget = widget363return widget364365def create_namewidget(self):366# if self._attrconf.get_obj().ident =='vehicles':367# print 'create_namewidget',self._attrconf.get_obj().ident,self._attrconf.attrname,self._attrconf.get_name(),type(self._attrconf.get_name())368widget = wx.StaticText(self.parent, -1,369self._attrconf.get_name().title()+self.equalchar,370style=wx.ALIGN_RIGHT # |wx.SIMPLE_BORDER #wx.STATIC_BORDER #371)372widget.SetBackgroundColour(self.color_bg)373self.extend_widgetsize(widget)374# widget.SetMinSize((-1,20))375376#377378self.set_tooltip(widget)379380return widget381382def create_unitwidget(self):383if self._attrconf.has_unit():384widget = wx.StaticText(self.parent, -1,385self._attrconf.format_unit(),386style=wx.ALIGN_LEFT # |wx.SIMPLE_BORDER #wx.STATIC_BORDER #| #387)388widget.SetBackgroundColour(self.color_bg)389self.extend_widgetsize(widget)390# print 'create_unitwidget', self.config_attr['unit']391return widget392393else:394return (0, 0)395396def extend_widgetsize(self, widget, xborder=3, yborder=3):397"""398Extends the widget by incresing its minimum size by border in pixels.399"""400s = widget.GetSize()401widget.SetMinSize((s[0]+xborder, s[1]+yborder))402403def create_widgets(self, widgetdata):404"""405Generates the widgets representing this attribute.406"""407self.widgets = {}408self.widgetnames = []409for name, widget, align in widgetdata:410self.widgets[name] = (widget, align)411self.widgetnames.append(name)412413def get_widgetnames(self):414"""415Returns a list with names of widgets, representing this attribute.416"""417return self.widgetnames418419def get_widgetsinfo(self, widgetnames=[]):420"""421Returns a list of widget infos representing this attribute422according to the widgetnames.423One widget info is a tuple with widget object and desired alignment424within the panel.425If widgetnames is empty then all widgets are returned in the426order defined in get_widgetnames.427"""428429if len(widgetnames) == 0:430widgetnames = self.get_widgetnames()431432widgetsinfo = []433for name in widgetnames:434widgetsinfo.append(self.widgets.get(name, ((0, 0), 0)))435436return widgetsinfo437438def apply_obj_to_valuewidget(self):439"""440Value of obj is read and applied to value widget.441To be overwritten.442"""443value = self.get_value_obj()444# print 'apply_obj_to_valuewidget',self._attrconf.attrname, value445self.set_widgetvalue(value)446447def get_value_obj(self):448"""449Reads current value from object.450"""451if self._attrconf.is_colattr():452return self._attrconf[self.parent.id]453else:454return self._attrconf.get_value()455456def set_value_obj(self, value):457"""458Sets given value to object.459"""460# print 'set_value_obj',self._attrconf.attrname,self.parent.id, self._attrconf.is_colattr()461if self._attrconf.is_colattr(): # parent is holding the row id462self._attrconf[self.parent.id] = value463else:464self._attrconf.set_value(value)465466def format_value_obj(self, show_unit=False, show_parentesis=False):467"""468Return formatted value of object.469"""470471if self._attrconf.is_colattr(): # parent is holding the row id472return self._attrconf.format_value(self.parent.id,473show_unit=show_unit,474show_parentesis=show_parentesis)475else:476# print 'format_value_obj',self._attrconf.attrname, self._attrconf.format_value( )477return self._attrconf.format_value(show_unit=show_unit,478show_parentesis=show_parentesis)479480def apply_valuewidget_to_obj(self, value=None):481"""482Applies current value widget to object attribute.483484Makes no sense for static text.485If no value argument is given then the get_widgetvalue method is486called to recover widget value.487"""488# pass489# in general values maust be transferred from widget to490# attribute of objet in the correct way.491492# self._attrconf.get_value()493if self._attrconf.is_writable():494if value is None: # value not given495value = self.get_widgetvalue()496497if value is not None:498# value returned by widget is valid499# print 'apply_valuewidget_to_obj',value,self.parent.obj.ident,self.attr500self.set_value_obj(value)501502def set_textevents(self, widget):503"""504Sets events to text input widhets505"""506# print 'set_textevents',widget507# print ' immediate_apply',self.immediate_apply508if self.immediate_apply:509widget.Bind(wx.EVT_KILL_FOCUS, self.on_apply_immediate)510#widget.Bind(wx.EVT_CHAR, self.on_apply_immediate)511512def on_apply_immediate(self, event):513"""514A key has been pressed in valuewidget and it is requested515to apply it immediately to the object516"""517# print 'on_apply_immediate'518self.apply_valuewidget_to_obj()519520def get_obj(self):521"""522Returns object to be displayed on panel.523"""524return self._attrconf.get_obj()525526# def get_pentable(self):527# """528# Returns pentable instance529# """530# return self.parent.get_pentable()531532def get_objvalue(self):533"""534Read current value from object and convert into string.535Depends on attribute type and hence widgettype.536To be overwritten.537"""538if self._attrconf.is_colattr():539value = self._attrconf[self.parent.id]540541else:542# print 'get_objvalue',self.attr,self.parent.obj543value = self._attrconf.get_value()544545# print ' value=',value546return value547548def set_tooltip(self, widget=None):549550# TODO : check for global tooltip on/off551infostr = '%s (%s)' % (self._attrconf.get_name(), self._attrconf.attrname)552if self._attrconf.has_info():553# print 'set_tooltip',self.attr,self.config_attr['info']554for infoline in self._attrconf.get_info().split('\n'):555infostr += '\n '+infoline.strip()556widget.SetToolTipString(infostr)557widget.SetHelpText(infostr)558559560class NumericWidgetContainer(AttrBase, WidgetContainer):561"""562Contains one or several widgets representing a scalar numeric attribute.563564"""565566def define_widgetset(self):567"""568Generates the widgets representing this attribute.569"""570if self._attrconf.has_unit():571# print 'define_widgetset num +unit',self._attrconf.attrname572return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),573('value', self.create_valuewidget(), wx.EXPAND),574('unit', self.create_unitwidget(), wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), ]575else:576# print 'define_widgetset num ',self._attrconf.attrname577return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),578('value', self.create_valuewidget(), wx.EXPAND)]579580def get_valuewidget_read(self):581"""582Returns instance of non-editable widget583To be overwritten.584"""585widget = self.get_valuewidget_write()586widget.Enable(False)587# Here just the plain static text widget is returned588589# printformat=self.get_printformat_fortran(self.attr,self.parent.obj,main=self.mainframe)590591#value = printformat%value592593# add unit if exist594# print 'get_valuewidget_read with unit:',self.parent.obj.get_unit(self.attr)595# if self.parent.obj.get_unit(self.attr)!='':596# value+=' '+self.parent.obj.get_unit(self.attr)597598# print 'create_valuewidget: '+value,self.attr599#widget=wx.StaticText(self.parent, wx.ID_ANY, self.format_value_obj(),style=wx.ALIGN_RIGHT)600601return widget602603def get_valuewidget_write(self):604"""605Return widget to edit numeric value of attribute606This is effectively the parametrisation of the masked.NumCtrl widget.607"""608value = self.get_value_obj()609# strange way to convert numpy type numbers into native python numbers610if type(value) not in (types.IntType, types.LongType, types.FloatType, types.ComplexType):611value = value.tolist()612# print 'NumericWidgetContainer.get_valuewidget_write ',value,type(value),self._attrconf.digits_fraction613614# if self._attrconf.digits_fraction is None:615# self._attrconf.digits_fraction = 3616617# print ' panelstyle=',self.panelstyle618# print ' value=',value619# numpy returns dtype... even for scalars620# make sure to convert value in a native python scalar621# if value is None:622# value=NaN623# elif type(value) not in (types.IntType, types.LongType, types.FloatType):624# value=value.tolist()625626# if self.config_attr['min'] is None:627allow_negative = True628# else:629# allow_negative = self.config_attr['min'] < 0.0630631#min = self.config_attr['min']632#max = self.config_attr['max']633634# if min is None:635# if value<0:636# min = -5*value637# else:638# min = 0639#640# if max is None:641# max = 5*abs(value)642643if np.isinf(value):644widget = wx.StaticText(self.parent, -1,645value.__repr__(),646style=wx.ALIGN_LEFT # |wx.SIMPLE_BORDER #wx.STATIC_BORDER #| #647)648# widget.SetBackgroundColour(self.color_bg)649self.extend_widgetsize(widget)650# print 'create_unitwidget', self.config_attr['unit']651return widget652653# if self.panelstyle == 'fancy': #'instrumental':654# print 'NumericWidgetContainer.get_valuewidget_write fancy mode'655# print 'TODO: no bindings yet for immediate apply'656# slider = wx.Slider(self.parent, wx.ID_ANY,657# value,658# min, max,659# style=wx.SL_HORIZONTAL| wx.SL_AUTOTICKS660# #style=wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | wx.SL_LABELS661# )662#663# slider.SetTickFreq(5, 1)664# return slider665666# else:667668widget = wx.TextCtrl(self.parent, -1, str(value), style=wx.ALIGN_RIGHT)669# standard numerical widget670# widget = masked.Ctrl(self.parent, id = -1,671# value = value,672# #integerWidth=None,673# fractionWidth = self._attrconf.digits_fraction,674# autoSize = True,675# controlType=masked.controlTypes.NUMBER,676# style= wx.ALIGN_RIGHT677# )678# widget = masked.NumCtrl(679# self.parent, id = -1,680# value = value,681# pos = wx.DefaultPosition,682# size = wx.DefaultSize,683# style = 0,684# validator = wx.DefaultValidator,685# name = "masked.number",686# integerWidth = 10,687# fractionWidth = 0,688# allowNone = False,689# allowNegative = True,690# useParensForNegatives = False,691# groupDigits = False,692# groupChar = ',',693# decimalChar = '.',694# min = None,695# max = None,696# limited = False,697# #limitOnFieldChange = False,698# selectOnEntry = True,699# foregroundColour = "Black",700# signedForegroundColour = "Red",701# emptyBackgroundColour = "White",702# validBackgroundColour = "White",703# invalidBackgroundColour = "Yellow",704# autoSize = False#True705# )706self.set_textevents(widget)707return widget708709def get_widgetvalue(self):710"""711Returnes current value from valuewidget.712Depends on attribute type and hence widgettype.713To be overwritten.714"""715return float(self.valuewidget.GetValue())716717def set_widgetvalue(self, value):718"""719Sets value for valuewidget.720Depends on attribute type and hence widgettype.721To be overwritten.722"""723if 1: # self._attrconf.is_writable():724# set value to label725# numpy returns dtype... even for scalars726# make sure to convert value in a native python scalar727if type(value) not in (types.IntType, types.LongType, types.FloatType):728value = value.tolist()729self.valuewidget.SetValue(str(value))730731732class IntegerWidgetContainer(NumericWidgetContainer):733"""734Contains one or several widgets representing a scalar numeric attribute.735736"""737738def get_valuewidget_write(self):739"""740Return widget to edit numeric value of attribute741This is effectively the parametrisation of the masked.NumCtrl widget.742"""743# if self.panelstyle == 'instrumental':744# # return a spin control in instrumental style745# sc = wx.SpinCtrl(self.parent, wx.ID_ANY, "", (30, 50))746# sc.SetRange(self.config_attr['min'],self.config_attr['max'])747# sc.SetValue(value)748# return sc749# else:750# use standard numerical masked text otherwise751return NumericWidgetContainer.get_valuewidget_write(self)752753def get_widgetvalue(self):754"""755Returnes current value from valuewidget.756Depends on attribute type and hence widgettype.757To be overwritten.758"""759return int(self.valuewidget.GetValue())760761762class BooleanWidgetContainer(AttrBase, WidgetContainer):763"""764Contains one or several widgets representing a boolean attribute.765766"""767768def define_widgetset(self):769"""770Generates the widgets representing this attribute.771"""772return [('name', self.create_namewidget(), wx.ALIGN_RIGHT),773('value', self.create_valuewidget(), wx.EXPAND),774('unit', self.create_unitwidget(), wx.ALIGN_LEFT), ]775776def get_valuewidget_read(self):777"""778Returns instance of non-editable widget779To be overwritten.780"""781widget = self.get_valuewidget_write()782widget.Enable(False)783784return widget785786def get_valuewidget_write(self):787"""788Return widget to edit numeric value of attribute789This is effectively the parametrisation of the masked.NumCtrl widget.790"""791# print 'get_numeditwidget',value792793widget = wx.CheckBox(self.parent, -1)794if self.immediate_apply:795self.parent.Bind(wx.EVT_CHECKBOX, self.on_apply_immediate, widget)796value = self.get_value_obj()797widget.SetValue(value)798return widget799800def get_widgetvalue(self):801"""802Returnes current value from valuewidget.803Depends on attribute type and hence widgettype.804To be overwritten.805"""806return self.valuewidget.GetValue()807808def set_widgetvalue(self, value):809"""810Sets value for valuewidget.811Depends on attribute type and hence widgettype.812To be overwritten.813"""814# if self._attrconf.is_writable():815self.valuewidget.SetValue(value)816817818class ChoiceWidgetContainer(WidgetContainer):819"""820Contains widget to select one item from a choice list.821822"""823824def define_widgetset(self):825"""826Generates the widgets representing this attribute.827"""828if type(self._attrconf.choices) in (OrderedDict, types.DictionaryType):829self._choicevalues = self._attrconf.choices.values()830self._choicenames = self._attrconf.choices.keys()831else:832self._choicevalues = list(self._attrconf.choices)833self._choicenames = list(self._attrconf.choices)834# if type(self._attrconf.choices) in [types.ListType,types.TupleType,numpy.ndarray]:835836if self._attrconf.has_unit() & self._attrconf.is_writable():837return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),838('value', self.create_valuewidget(), wx.EXPAND),839('unit', self.create_unitwidget(), wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), ]840else:841return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),842('value', self.create_valuewidget(), wx.EXPAND)]843844def get_valuewidget_read(self):845"""846Return widget to read only numeric value of attribute847This is effectively the parametrisation of the masked.NumCtrl widget.848"""849value = self.get_value_obj()850# print 'ChoiceWidgetContainer.get_valuewidget_read',value,type(value)851# print ' choices',self._attrconf.choices852853if type(self._attrconf.choices) in (OrderedDict, types.DictionaryType):854#value = self._attrconf.choices[value]855value = self._choicenames[self._choicevalues.index(value)]856# print ' value =',value857widget = wx.TextCtrl(self.parent, -1, value, style=wx.ALIGN_RIGHT)858widget.Enable(False)859return widget860861def get_valuewidget_write(self):862"""863Return widget to edit numeric value of attribute864This is effectively the parametrisation of the masked.NumCtrl widget.865"""866867value = self.get_value_obj()868# print 'ChoiceWidgetContainer.get_valuewidget_read',self._attrconf.attrname, value,type(value)869# print ' choices',self._attrconf.choices870# print ' self._choicenames',self._choicenames871# print ' self._choicevalues',self._choicevalues872widget = wx.Choice(self.parent, -1, (100, 50), choices=self._choicenames)873if self.immediate_apply:874self.parent.Bind(wx.EVT_CHOICE, self.on_apply_immediate, widget)875if value in self._choicevalues:876ind = self._choicevalues.index(value)877else:878ind = 0879widget.SetSelection(ind)880881return widget882883def get_widgetvalue(self):884"""885Returnes current value from valuewidget.886Depends on attribute type and hence widgettype.887To be overwritten.888"""889val = self.valuewidget.GetSelection()890# if self._choicevalues.count(val)>0:891return self._choicevalues[val]892# else:893# return val894895def set_widgetvalue(self, val):896"""897Sets value for valuewidget.898Depends on attribute type and hence widgettype.899To be overwritten.900"""901# print 'set_widgetvalue',self._attrconf.attrname, val,self._choicevalues902# if self._choicevalues.count(val)>0:903#ind = self._choicevalues.index(val)904# self.valuewidget.SetSelection(ind)905# else:906# self.valuewidget.SetValue(val)907908try:909#ind = self._choicenames.index(value)910ind = self._choicevalues.index(val)911except:912print 'WARNING in ChoiceWidgetContainer.set_widgetvalue: %s with value "%s" not in choice list' % (self._attrconf.attrname, val)913return914# print ' ind',ind,self.valuewidget915if self._attrconf.is_writable():916self.valuewidget.SetSelection(ind)917else:918self.valuewidget.SetValue(self._choicenames[ind])919920921class ChecklistWidgetContainer(ChoiceWidgetContainer):922"""923Contains widchet to chosse several items from a choice list.924925"""926927def get_valuewidget_read(self):928"""929Return widget to read only numeric value of attribute930This is effectively the parametrisation of the masked.NumCtrl widget.931"""932# this is a list:933values = self.get_value_obj()934# print 'ChoiceWidgetContainer.get_valuewidget_read',value,type(value)935# print ' choices',self._attrconf.choices936937# mal values in list with .choices dictionary938if (len(values) > 0) & (type(self._attrconf.choices) in (OrderedDict, types.DictionaryType)):939#value = self._attrconf.choices[value]940values = []941for val in self.get_value_obj():942if val in self._choicevalues:943values.append(self._choicenames[self._choicevalues.index(val)])944945# print ' value =',value946widget = wx.TextCtrl(self.parent, -1, list_to_str(values, sep=self._attrconf.sep), style=wx.ALIGN_RIGHT)947widget.Enable(False)948return widget949950def get_valuewidget_write(self):951"""952Return widget to edit numeric value of attribute953This is effectively the parametrisation of the masked.NumCtrl widget.954"""955956value = self.get_value_obj()957# print 'ChoiceWidgetContainer.get_valuewidget_write',self._attrconf.attrname, value,type(value),self.immediate_apply958# print ' choices',self._attrconf.choices959# print ' self._choicenames',self._choicenames960# print ' self._choicevalues',self._choicevalues961962widget = wx.CheckListBox(self.parent, -1, (80, 50), wx.DefaultSize, self._choicenames)963#wx.ComboBox(self.parent,choices = self._choicenames)964# print 'widget',widget,'dir:',dir(widget)965966if self.immediate_apply:967968# ATTENTION: this does not work because self.parent is not969# a panel, but a windoe, without EvtListBox !!!970#self.parent.Bind(wx.EVT_LISTBOX, self.parent.EvtListBox, widget)971self.parent.Bind(wx.EVT_CHECKLISTBOX, self.on_apply_immediate, widget)972973self.set_checkbox(widget, value)974975return widget976977def get_widgetvalue(self):978"""979Returnes current value from valuewidget.980Depends on attribute type and hence widgettype.981To be overwritten.982"""983values = []984# print 'get_widgetvalue Checked',self.valuewidget.Checked985for ind in self.valuewidget.Checked:986values.append(self._choicevalues[ind])987988return values989990def set_checkbox(self, widget, values):991# print 'set_checkbox',values992is_set = False993for val in values: # values must be a list994# print ' test',val,val in self._choicevalues995if val in self._choicevalues:996# print ' select ind',self._choicevalues.index(val)997ind = self._choicevalues.index(val)998widget.Check(ind, True)999is_set = True10001001def set_widgetvalue(self, val):1002"""1003Sets value for valuewidget.1004Depends on attribute type and hence widgettype.1005To be overwritten.1006"""1007if self._attrconf.is_writable():1008self.set_checkbox(self.valuewidget, val)1009else:1010self.valuewidget.SetValue(str(val))101110121013class TextWidgetContainer(WidgetContainer):1014"""1015Contains one or several widgets representing a text attribute.10161017"""10181019def define_widgetset(self):1020"""1021Generates the widgets representing this attribute.1022"""1023if self._attrconf.has_unit() & self._attrconf.is_writable():1024return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),1025('value', self.create_valuewidget(), wx.EXPAND),1026('unit', self.create_unitwidget(), wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), ]1027else:1028return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),1029('value', self.create_valuewidget(), wx.EXPAND)]10301031def get_valuewidget_read(self):1032"""1033Return widget to read only numeric value of attribute1034This is effectively the parametrisation of the masked.NumCtrl widget.1035"""1036# print 'TextWidgetContainer.get_valuewidget_read'1037# widget=self.get_valuewidget_write()1038value = self.get_value_obj()1039widget = wx.TextCtrl(self.parent, -1, value, style=wx.ALIGN_RIGHT | wx.TE_READONLY)1040widget.Enable(False)10411042return widget10431044def get_valuewidget_write(self):1045"""1046Return widget to edit numeric value of attribute1047This is effectively the parametrisation of the masked.NumCtrl widget.1048"""10491050value = self.get_value_obj()1051# print 'get_editwidget text',value,type(value)10521053widget = wx.TextCtrl(self.parent, -1, value, style=wx.ALIGN_RIGHT)1054self.set_textevents(widget)1055return widget1056#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)10571058def get_widgetvalue(self):1059"""1060Returnes current value from valuewidget.1061Depends on attribute type and hence widgettype.1062To be overwritten.1063"""1064return self.widgets['value'][0].GetValue()10651066def set_widgetvalue(self, value):1067"""1068Sets value for valuewidget.1069Depends on attribute type and hence widgettype.1070To be overwritten.1071"""1072# print 'set_widgetvalue',dir(self.widgets['value'][0])1073self.widgets['value'][0].SetValue(value)107410751076class DatetimeWidgetContainer(IntegerWidgetContainer):1077"""1078Contains one or several widgets representing a time and date attributes.10791080"""10811082def define_widgetset(self):1083"""1084Generates the widgets representing this attribute.1085"""1086if self._attrconf.has_unit() & self._attrconf.is_writable():1087return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),1088('value', self.create_valuewidget(), wx.EXPAND),1089('unit', self.create_unitwidget(), wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), ]1090else:1091return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),1092('value', self.create_valuewidget(), wx.EXPAND)]10931094def get_valuewidget_read(self):1095"""1096Return widget to read only numeric value of attribute1097This is effectively the parametrisation of the masked.NumCtrl widget.1098"""1099# print 'TextWidgetContainer.get_valuewidget_read'1100# widget=self.get_valuewidget_write()1101dtime = self.get_value_obj()1102#time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.gmtime())1103value = time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime(dtime))11041105widget = wx.TextCtrl(self.parent, -1, value, style=wx.ALIGN_RIGHT | wx.TE_READONLY)1106widget.Enable(False)11071108return widget110911101111class ListWidgetContainer(WidgetContainer):1112"""1113Contains one or several widgets representing a text attribute.11141115"""11161117def define_widgetset(self):1118"""1119Generates the widgets representing this attribute.1120"""1121if self._attrconf.has_unit() & self._attrconf.is_writable():1122return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),1123('value', self.create_valuewidget(), wx.EXPAND),1124('unit', self.create_unitwidget(), wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), ]1125else:1126return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),1127('value', self.create_valuewidget(), wx.EXPAND)]11281129# def get_valuewidget_read(self):1130# """1131# Return widget to read only numeric value of attribute1132# This is effectively the parametrisation of the masked.NumCtrl widget.1133# """1134# value = self.get_value_obj()1135# #print 'ListWidgetContainer',value1136#1137# widget = wx.TextCtrl( self.parent, -1, list_to_str(list(value)),style= wx.ALIGN_RIGHT|wx.TE_MULTILINE|wx.TE_READONLY)1138# self.set_textevents(widget)1139# widget.Enable(False)1140# return widget11411142def get_valuewidget_write(self):1143"""1144Return widget to edit numeric value of attribute1145This is effectively the parametrisation of the masked.NumCtrl widget.1146"""1147if self._attrconf.get_metatype() == 'list':1148sep = self._attrconf.sep1149is_ok = True # assuming that List configs are flat1150else:1151sep = ','1152is_ok = is_list_flat(self.get_value_obj())11531154value = list_to_str(self.get_value_obj(), sep=sep)1155if is_ok:1156widget = wx.TextCtrl(self.parent, -1, value, style=wx.ALIGN_LEFT | wx.TE_MULTILINE)1157else: # only flat lists can be edited :(1158widget = wx.TextCtrl(self.parent, -1, value, style=wx.ALIGN_RIGHT | wx.TE_MULTILINE)1159widget.Enable(False)11601161self.set_textevents(widget)1162return widget11631164def get_widgetvalue(self):1165"""1166Returnes current value from valuewidget.1167Depends on attribute type and hence widgettype.1168To be overwritten.1169"""1170# print 'get_widgetvalue', self.widgets['value'][0].GetValue()1171# print ' returns', str_to_list(self.widgets['value'][0].GetValue())1172if self._attrconf.get_metatype() == 'list':1173return self._attrconf.get_value_from_string(self.widgets['value'][0].GetValue())1174else:1175return str_to_list(self.widgets['value'][0].GetValue())11761177def set_widgetvalue(self, value):1178"""1179Sets value for valuewidget.1180Depends on attribute type and hence widgettype.1181To be overwritten.1182"""1183# print 'set_widgetvalue',value,is_list_flat(value)1184if self._attrconf.get_metatype() == 'list':1185sep = self._attrconf.sep11861187else:1188sep = ','11891190if is_list_flat(value): # &self._attrconf.is_editable():1191self.widgets['value'][0].SetValue(list_to_str(value, sep=sep))1192else: # only flat lists can be edited :(1193self.widgets['value'][0].SetValue(repr(value, sep=sep))119411951196class ObjWidgetContainer(AttrBase, WidgetContainer):1197"""1198Contains one or several widgets representing an obj attribute.11991200"""12011202def define_widgetset(self):1203"""1204Generates the widgets representing this attribute.1205"""1206# print 'define_widgetset',self._attrconf.attrname, self._attrconf.get_value()12071208return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),1209('value', self.create_valuewidget(), wx.EXPAND),1210]12111212def get_valuewidget_read(self):1213"""1214Returns instance of non-editable widget1215To be overwritten.1216"""1217# print 'get_valuewidget_read',self._attrconf.attrname1218# print 'get_numeditwidget',value1219# Here just the plain static text widget is returned1220#obj = self._attrconf.get_value()1221#METATYPES_LINKSTYLE = ('obj','id','tabid','ids')1222mt = self._attrconf.get_metatype()1223obj = value = self.get_value_obj()1224# print ' value',value,type(obj),str(obj),mt1225if mt == 'obj':1226text = str(obj.format_ident())12271228elif mt == 'id':1229if value == -1:1230# id not yet assigned1231widget = wx.TextCtrl(self.parent, -1, '-', style=wx.ALIGN_RIGHT | wx.TE_READONLY)1232widget.Enable(False)1233return widget1234else:1235text = self._attrconf.get_linktab().format_id(value)12361237elif mt == 'ids':1238if value is None:1239# id not yet assigned1240widget = wx.TextCtrl(self.parent, -1, '', style=wx.ALIGN_RIGHT | wx.TE_READONLY)1241widget.Enable(False)1242return widget1243else:1244text = self._attrconf.get_linktab().format_ids(value)1245# print ' text',text,type(text)1246#1247# elif mt == 'tabid':1248# text = str(obj)1249else:1250text = str(obj)12511252# print 'create_valuewidget: '+value,self.attr1253#widget=wx.StaticText(self.parent, -1,text,style=wx.ALIGN_RIGHT)1254widget = hyperlink.HyperLinkCtrl(self.parent, wx.ID_ANY, text, URL=text)1255widget.AutoBrowse(False)12561257widget.Bind(hyperlink.EVT_HYPERLINK_LEFT, self.on_objlink)12581259return widget12601261def get_valuewidget_write(self):1262"""1263Return widget to edit numeric value of attribute1264"""12651266# print 'get_valuewidget_write',self._attrconf.attrname1267# Here just the plain static text widget is returned1268#obj = self._attrconf.get_value()1269#METATYPES_LINKSTYLE = ('obj','id','tabid','ids')1270mt = self._attrconf.get_metatype()1271obj = value = self.get_value_obj()1272linktab = self._attrconf.get_linktab()1273# print ' value',value,type(value),str(obj),mt1274if mt == 'id':1275#text = self._attrconf.get_linktab().format_id(value)1276choices = linktab.format_id(linktab.get_ids()).split(',')1277if len(choices) > 0:1278widget = wx.Choice(self.parent, -1, (100, 50), choices=choices)1279ind = choices.index(linktab.format_id(value))1280if value == -1:1281# no id specified, use first one1282widget.SetSelection(0)1283else:1284widget.SetSelection(ind)1285else:1286# there are no ids to point to1287widget = wx.TextCtrl(self.parent, -1, '-', style=wx.ALIGN_RIGHT | wx.TE_READONLY)1288widget.Enable(False)1289return widget12901291if mt == 'obj':1292text = str(obj.format_ident())12931294elif mt == 'ids':1295text = self._attrconf.get_linktab().format_ids(value)1296#1297# elif mt == 'tabid':1298# text = str(obj)1299else:1300text = str(obj)13011302# print 'create_valuewidget: '+value,self.attr1303#widget=wx.StaticText(self.parent, -1,text,style=wx.ALIGN_RIGHT)1304widget = hyperlink.HyperLinkCtrl(self.parent, wx.ID_ANY, text, URL=text)1305widget.AutoBrowse(False)13061307widget.Bind(hyperlink.EVT_HYPERLINK_LEFT, self.on_objlink)13081309return widget13101311def on_objlink(self, event):1312# print 'on_objlink:',self.get_objvalue().ident13131314value = self.get_objvalue()1315mt = self._attrconf.get_metatype()13161317if self.parent.func_change_obj:1318if mt == 'obj':1319if type(value) == types.InstanceType:1320# print ' ident?',hasattr(value,'ident')1321if hasattr(value, 'ident'):1322navitimer = wx.FutureCall(1, self.parent.func_change_obj, value)13231324elif mt == 'id':1325linktab = self._attrconf.get_linktab()1326navitimer = wx.FutureCall(1, self.parent.func_change_obj, linktab, value) # here value is id13271328elif mt == 'ids':1329linktab = self._attrconf.get_linktab()1330navitimer = wx.FutureCall(1, self.parent.func_change_obj, linktab,1331None, value) # here value is list with ids13321333elif mt == 'tabid':1334linktab, id = value1335navitimer = wx.FutureCall(1, self.parent.func_change_obj, linktab, id)13361337# if self._attrconf.is_colattr(): # parent is holding the row id1338#self._attrconf[self.parent.id] = value1339else:1340#navitimer = wx.FutureCall(1, self.parent.func_change_obj,self.get_objvalue())1341pass13421343event.Skip()13441345def get_widgetvalue(self):1346"""1347Returnes current value from valuewidget.1348Depends on attribute type and hence widgettype.1349To be overwritten.1350"""1351mt = self._attrconf.get_metatype()1352val = self.valuewidget.GetStringSelection() # GetString1353# print 'get_widgetvalue', val,mt1354# print ' ',dir(self.valuewidget)1355# if self._choicevalues.count(val)>0:1356if mt == 'id':1357if val == '-':1358return -11359else:1360return self._attrconf.get_linktab().get_id_from_formatted(val)1361else:1362return self.valuewidget.GetValue()13631364def set_widgetvalue(self, val):1365"""1366Sets value for valuewidget.1367Depends on attribute type and hence widgettype.1368To be overwritten.1369"""1370# print 'set_widgetvalue',self._attrconf.attrname, val, self._attrconf.is_writable()1371# if self._choicevalues.count(val)>0:1372#ind = self._choicevalues.index(val)1373# self.valuewidget.SetSelection(ind)1374# else:1375# self.valuewidget.SetValue(val)13761377# try:1378# #ind = self._choicenames.index(value)1379# ind = self._choicevalues.index(val)1380# except:1381# print 'WARNING in ChoiceWidgetContainer.set_widgetvalue: %s with value "%s" not in choice list'%(self._attrconf.attrname,val)1382# return1383# print ' ind',ind,self.valuewidget1384if self._attrconf.is_writable():1385self.valuewidget.SetStringSelection(self._attrconf.get_linktab().format_id(val))1386# self.valuewidget.SetSelection(ind)1387else:1388pass1389# self.valuewidget.SetValue(val)139013911392class ColorWidgetContainer(AttrBase, TextWidgetContainer):1393def define_widgetset(self):1394"""1395Generates the widgets representing this attribute.1396"""1397return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),1398('value', self.create_valuewidget(), wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), # wx.EXPAND1399#('unit', self.create_unitwidget(), wx.ALIGN_LEFT|wx.ALIGN_CENTER_VERTICAL),1400]14011402def get_valuewidget_write(self):1403"""1404Return widget to edit numeric value of attribute1405"""14061407value = self.get_value_obj()1408# print 'ColorWidgetContainer.get_valuewidget_write',self._attrconf.attrname,value,type(value)14091410#widget = wx.TextCtrl( self.parent, -1, str(value),style= wx.ALIGN_RIGHT)1411cint = np.array(np.array(value)*255, np.int32)1412# wx.Colour(cint[0],cint[1],cint[2],cint[3])1413widget = coloursel.ColourSelect(1414self.parent, -1, "", wx.Colour(cint[0], cint[1], cint[2], cint[3]), size=wx.DefaultSize)1415# self.set_textevents(widget)1416# widget.Enable(True)1417if self.immediate_apply:1418widget.Bind(coloursel.EVT_COLOURSELECT, self.on_colorselect)1419return widget14201421def on_colorselect(self, event):1422self.apply_valuewidget_to_obj()14231424def get_valuewidget_read(self):1425"""1426Return widget to edit numeric value of attribute1427"""14281429value = self.get_value_obj()1430# print 'get_editwidget text',value,type(value)14311432#widget = wx.TextCtrl( self.parent, -1, str(value),style= wx.ALIGN_RIGHT)1433cint = np.array(np.array(value)*255, np.int32)1434widget = coloursel.ColourSelect(1435self.parent, -1, "", wx.Colour(cint[0], cint[1], cint[2], cint[3]), size=wx.DefaultSize)1436# self.set_textevents(widget)1437widget.Enable(False)1438return widget14391440def get_widgetvalue(self):1441"""1442Returnes current value from valuewidget.1443Depends on attribute type and hence widgettype.1444To be overwritten.1445"""14461447c = self.widgets['value'][0].GetColour()1448# print 'ColorWidgetContainer.get_widgetvalue',self._attrconf.attrname, c, type(c),type(c) == types.InstanceType#types.ClassType1449#color = np.array([c.Red(),c.Green(),c.Blue(),c.Alpha()],np.float32)/255.01450return np.array([c.Red(), c.Green(), c.Blue(), c.Alpha()], np.float32)/255.014511452def set_widgetvalue(self, value):1453"""1454Sets value for valuewidget.1455Depends on attribute type and hence widgettype.1456To be overwritten.1457"""1458cint = np.array(np.array(value)*255, np.int32)1459self.widgets['value'][0].SetValue(wx.Colour(cint[0], cint[1], cint[2], cint[3]))146014611462class FilepathWidgetContainer(AttrBase, TextWidgetContainer):1463def define_widgetset(self):1464"""1465Generates the widgets representing this attribute.1466"""1467return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),1468('value', self.create_valuewidget(), wx.EXPAND),1469('unit', self.create_unitwidget(), wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), ]14701471def get_valuewidget_read(self):1472"""1473Return widget to read only numeric value of attribute1474This is effectively the parametrisation of the masked.NumCtrl widget.1475"""1476# print 'TextWidgetContainer.get_valuewidget_read'1477# widget=self.get_valuewidget_write()1478value = self.get_value_obj()1479widget = wx.TextCtrl(self.parent, -1, value, style=wx.ALIGN_LEFT | wx.TE_READONLY)1480widget.Enable(False)14811482return widget14831484def get_valuewidget_write(self):1485"""1486Return widget to edit numeric value of attribute1487This is effectively the parametrisation of the masked.NumCtrl widget.1488"""14891490value = self.get_value_obj()1491# print 'get_editwidget text',value,type(value)14921493widget = wx.TextCtrl(self.parent, -1, value, style=wx.ALIGN_LEFT)1494self.set_textevents(widget)1495return widget1496#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)14971498def create_unitwidget(self):1499#widget = wx.Button(self.parent, wx.ID_OPEN)1500bitmap = wx.ArtProvider.GetBitmap(wx.ART_FILE_OPEN, wx.ART_TOOLBAR)1501widget = wx.BitmapButton(self.parent, -1, bitmap, (12, 12),1502(bitmap.GetWidth()+6, bitmap.GetHeight()+6))1503widget.Bind(wx.EVT_BUTTON, self.on_fileopen)1504# print 'create_unitwidget',self._attrconf.attrname,widget1505return widget15061507def on_fileopen(self, event):1508# print 'on_fileopen',self._attrconf.attrname1509# if type(self._attrconf.get_default())==types.StringType:1510# defaultname = self._attrconf.get_default()1511# else:1512# defaultname = os.getcwd()1513wildcards_all = "All files (*.*)|*.*"1514if hasattr(self._attrconf, 'wildcards'):1515wildcards = self._attrconf.wildcards+"|"+wildcards_all1516else:1517wildcards = wildcards_all15181519# guess default value1520filepath = self.get_objvalue()1521if type(filepath) not in STRINGTYPES:1522filepath = ""1523dirpath = os.path.expanduser("~") # os.getcwd()1524else:1525if len(filepath) == 0:1526dirpath = os.path.expanduser("~") # os.getcwd()1527else:1528dirpath = os.path.dirname(filepath)15291530# print 'on_fileopen dirpath',dirpath1531dlg = wx.FileDialog(self.parent, message="Open file",1532defaultDir=dirpath,1533#defaultFile= filepath,1534wildcard=wildcards,1535style=wx.OPEN | wx.CHANGE_DIR1536)15371538# Show the dialog and retrieve the user response. If it is the OK response,1539# process the data.1540if dlg.ShowModal() == wx.ID_OK:1541filepath = dlg.GetPath()15421543# print 'on_fileopen set filepath',filepath1544self.set_widgetvalue(filepath)1545if self.immediate_apply:1546self.apply_valuewidget_to_obj()1547# print ' self.get_widgetvalue()',self.get_widgetvalue()1548dlg.Destroy()154915501551class FilepathsWidgetContainer(FilepathWidgetContainer):15521553def on_fileopen(self, event):1554# print 'FilepathsWidgetContainer.on_fileopen',self._attrconf.attrname1555# if type(self._attrconf.get_default())==types.StringType:1556# defaultname = self._attrconf.get_default()1557# else:1558# defaultname = os.getcwd()15591560wildcards_all = "All files (*.*)|*.*"1561if hasattr(self._attrconf, 'wildcards'):1562wildcards = self._attrconf.wildcards+"|"+wildcards_all1563else:1564wildcards = wildcards_all15651566# guess default value1567filepath = self.get_objvalue()1568# print ' filepath',filepath,type(filepath)1569if type(filepath) not in STRINGTYPES:1570filepath = ""1571dirpath = dirpath = os.path.expanduser("~") # os.getcwd()1572else:1573if len(filepath) == 0:1574dirpath = dirpath = os.path.expanduser("~") # os.getcwd()1575else:1576# take directory of first filepath1577dirpath = os.path.dirname(filepath.split(',')[0])15781579# print ' dirpath',dirpath1580# print ' filepath',filepath1581dlg = wx.FileDialog(self.parent, message="Open file",1582defaultDir=dirpath,1583#defaultFile= filepath,1584wildcard=wildcards,1585style=wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR1586)15871588# Show the dialog and retrieve the user response. If it is the OK response,1589# process the data.1590if dlg.ShowModal() == wx.ID_OK:1591# This returns a Python list of files that were selected.1592filepaths = dlg.GetPaths()1593# print 'You selected %d files:' % len(paths)15941595# print 'on_fileopen set filepath',filepath1596# self.set_widgetvalue(filepathlist_to_filepathstring(filepaths))15971598# save path as comma separated string, but not with special primes1599self.set_widgetvalue(','.join(filepaths))1600if self.immediate_apply:1601self.apply_valuewidget_to_obj()1602# print ' self.get_widgetvalue()',self.get_widgetvalue()1603dlg.Destroy()160416051606class DirpathWidgetContainer(AttrBase, TextWidgetContainer):1607def define_widgetset(self):1608"""1609Generates the widgets representing this attribute.1610"""1611return [('name', self.create_namewidget(), wx.ALIGN_RIGHT | wx.ALIGN_CENTER_VERTICAL),1612('value', self.create_valuewidget(), wx.EXPAND),1613('unit', self.create_unitwidget(), wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL), ]16141615def create_unitwidget(self):1616if self._attrconf.is_writable():1617#widget = wx.Button(self.parent, wx.ID_OPEN)1618bitmap = wx.ArtProvider.GetBitmap(wx.ART_FOLDER_OPEN, wx.ART_TOOLBAR)1619widget = wx.BitmapButton(self.parent, -1, bitmap, (12, 12),1620(bitmap.GetWidth()+6, bitmap.GetHeight()+6))1621widget.Bind(wx.EVT_BUTTON, self.on_diropen)1622# print 'create_unitwidget',self._attrconf.attrname,widget1623return widget1624else:1625return (0, 0)16261627def on_diropen(self, event):1628dlg = wx.DirDialog(self.parent, message="Open directory",1629#style=wx.DD_DEFAULT_STYLE| wx.DD_DIR_MUST_EXIST| wx.DD_CHANGE_DIR1630style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER | wx.DD_CHANGE_DIR1631)16321633if dlg.ShowModal() == wx.ID_OK:1634dirpath = dlg.GetPath()1635self.set_widgetvalue(dirpath)1636if self.immediate_apply:1637self.apply_valuewidget_to_obj()1638# print ' self.get_widgetvalue()',self.get_widgetvalue()1639dlg.Destroy()164016411642class ScalarPanel(wx.Panel):1643"""1644Interactively displays scalar attributes of object on a parent panel.1645"""16461647def __init__(self, parent, attrconfigs=[], id=None,1648func_change_obj=None,1649mainframe=None, panelstyle='default', immediate_apply=None):1650# wx.Panel.__init__(self,parent,-1,style=wx.WANTS_CHARS)1651wx.Panel.__init__(self, parent, -1, size=(-1, 300))1652#wx.scrolledpanel.ScrolledPanel.__init__(self, parent,wx.ID_ANY)1653#self.maxWidth = 10001654#self.maxHeight = 10001655#self.SetVirtualSize((self.maxWidth, self.maxHeight))1656# self.SetScrollRate(10,10)16571658# parent must be panel, scrolled panel or similar1659self.parent = parent16601661self.id = id16621663# target obj1664#self.obj = obj16651666self.func_change_obj = func_change_obj1667self.mainframe = mainframe1668#self.panelstyle = panelstyle1669#self.immediate_apply = immediate_apply16701671# background colors for lines shading:1672self.tablecolors = get_tablecolors()16731674# print 'ScalarPanel.__init__ id=',self.id#,parent,self.obj1675# print ' immediate_apply=',immediate_apply16761677self.widgetcontainers = []16781679self.create_attrs(attrconfigs, immediate_apply=immediate_apply, panelstyle=panelstyle)1680self.SetAutoLayout(True)1681self.Refresh()16821683# def get_pentable(self):1684# """1685# Returns pentable used for this panel1686# """1687# return self.parent.get_pentable()16881689def create_attrs(self, attrconfigs, immediate_apply=False, panelstyle='default'):1690"""1691Go through list with attribute names and create widgets and1692put them in a grid sizer.1693"""1694# print '\n\ncreate_attrs',len(attrconfigs)1695# print ' mt=',self.obj.get_config(attrs[0])['metatype']16961697# self.add_id_named(name,id,colors=color)1698# get widgets1699# id=11700i = 01701for attrconfig in attrconfigs:17021703# generates alternating colors (currently not in use)1704color_bg = self.tablecolors[divmod(i, len(self.tablecolors))[1]]1705container = self.get_widgetcontainer(attrconfig, color_bg=color_bg,1706immediate_apply=immediate_apply,1707panelstyle=panelstyle)1708self.widgetcontainers.append(container)1709# self.add_id_named(attr,widgetcontainers=container)1710# self.create_ids(id,widgetcontainers=container)1711i += 117121713# now ask for widget names and try to align them1714widgetnames = []1715for container in self.widgetcontainers:1716names = container.get_widgetnames()17171718if len(widgetnames) == 0:1719widgetnames = names1720else:1721widgetnames = self._align(widgetnames, names)17221723# print ' result of alignment:',attr,names,widgetnames1724# widgetnames.index...17251726# now dimensions of grid are known, so configure sizer1727# print 'grid size=',len(attrs), len(widgetnames)1728sizer = wx.FlexGridSizer(len(attrconfigs), len(widgetnames), vgap=2, hgap=0)1729sizer.AddGrowableCol(1)1730# print 'widgetnames',widgetnames1731# throw widgets into sizer1732for container in self.widgetcontainers:1733# print 'build grid for attr',container._attrconf.attrname1734# container=self.get_value_named('widgetcontainers',attr)1735# print 'attr',attr,widgetnames1736widgetsinfo = container.get_widgetsinfo(widgetnames)1737# print ' widgetsinfo=',widgetsinfo1738for widget, align in widgetsinfo:1739# print ' add widget align=',widget,align1740sizer.Add(widget, 0, align)17411742# works on panel...1743#parent.SetHelpText('The Agile Panel')1744self.SetAutoLayout(True)1745self.SetSizer(sizer)1746sizer.Fit(self)17471748def get_widgetcontainer(self, attrconf, **args):1749"""1750Figures out what widget container, containing a set of widgets,1751would be the most aprobriate to represent this attribute.1752"""1753# print '\n\nScalarPanel.get_widgetcontainer',attrconf.attrname17541755# config=self.obj.get_config(attr)1756# get type list (full depth)1757# t=attrconfig.get_default()17581759# take top level type1760# tt=t[0]1761tt = type(attrconf.get_default())17621763# get metatype1764mt = attrconf.get_metatype()17651766# print ' default,mt,tt',attrconf.get_default(),type(attrconf.get_default()),mt,tt,mt in METATYPES_LINKSTYLE17671768# if config.has_key('choices'):1769# # pop up with a choices list1770# return ChoiceWidgetContainer(self,attr,**args)17711772# check if this is an id within a referenced object1773# if mt=='id':1774# return IdWidgetContainer(self,attr,**args)1775#1776# check if widgets for metatypes are availlable1777# elif mt=='color':1778# #print ' ->WidgetContainer'1779# return ColorWidgetContainer(self,attr,**args)17801781# elif mt=='pentype':1782# return PentypeContainer(self,attr,**args)17831784if mt in METATYPES_LINKSTYLE:1785return ObjWidgetContainer(self, attrconf, **args)17861787elif mt == 'color':1788return ColorWidgetContainer(self, attrconf, **args)17891790elif (mt == 'list') & hasattr(attrconf, 'choices'):1791return ChecklistWidgetContainer(self, attrconf, **args)17921793elif (mt == 'list'):1794return ListWidgetContainer(self, attrconf, **args)17951796elif hasattr(attrconf, 'choices'):1797return ChoiceWidgetContainer(self, attrconf, **args)17981799elif mt == 'filepath':1800return FilepathWidgetContainer(self, attrconf, **args)18011802elif mt == 'filepaths':1803return FilepathsWidgetContainer(self, attrconf, **args)18041805elif mt == 'dirpath':1806return DirpathWidgetContainer(self, attrconf, **args)1807elif mt == 'datetime':1808return DatetimeWidgetContainer(self, attrconf, **args)18091810# elif mt == 'number':1811if tt in (types.IntType, types.LongType):1812return IntegerWidgetContainer(self, attrconf, **args)1813elif tt in (types.FloatType, types.ComplexType):1814return NumericWidgetContainer(self, attrconf, **args)18151816# check now native types18171818elif tt in (types.BooleanType,):1819return BooleanWidgetContainer(self, attrconf, **args)18201821elif tt in STRINGTYPES:1822return TextWidgetContainer(self, attrconf, **args)18231824# elif tt in (types.InstanceType,types.ClassType):1825# return ObjWidgetContainer(self,attrconf,**args)18261827elif tt in (types.ListType, types.TupleType):1828return ListWidgetContainer(self, attrconf, **args)18291830else:1831# else means use a the base class that can display anything1832return WidgetContainer(self, attrconf, **args)1833# else:1834# # else means use a the base class that can display anything1835# return WidgetContainer(self,attr,self,**args)18361837def apply(self):1838"""1839Widget values are copied to object1840"""1841for widgetcontainer in self.widgetcontainers:1842widgetcontainer.apply_valuewidget_to_obj()1843# this is to update widgets of function values1844# self.restore()18451846def restore(self):1847"""1848Object values are copied into widgets.1849"""1850for widgetcontainer in self.widgetcontainers:1851widgetcontainer.apply_obj_to_valuewidget()18521853def _align(self, widgetnames, names):1854"""1855tries to align widgetnames with a new list of names1856"""1857# print '_align'1858names_prepend = []1859i = 018601861while (len(names_prepend) == 0) & (i < len(names)):1862if widgetnames.count(names[i]) > 0:1863names_prepend = names[:i]1864i += 118651866# print ' names_prepend',names_prepend1867newnames = widgetnames1868for name in names_prepend:1869self._prepend_name(newnames, name)18701871for name in names:1872self._append_name(newnames, name)18731874return newnames18751876def _append_name(self, names, name):1877"""1878Appends name if not in list1879"""1880if names.count(name) == 0:1881names.append(name)18821883def _prepend_name(self, names, name):1884"""1885Predends name if not in list1886"""1887if names.count(name) == 0:1888names.insert(name, 0)188918901891class ScalarPanelScrolled(wxlib.scrolledpanel.ScrolledPanel, ScalarPanel):1892"""1893Interactively displays scalar attributes of object on a parent panel.1894"""18951896def __init__(self, parent, attrconfigs=[], id=None,1897func_change_obj=None,1898mainframe=None, is_modal=False,1899panelstyle='default', immediate_apply=None):1900# wx.Panel.__init__(self,parent,-1,style=wx.WANTS_CHARS)1901# wx.Panel.__init__(self,parent,-1)1902if is_modal:1903wxlib.scrolledpanel.ScrolledPanel.__init__(self, parent, wx.ID_ANY, size=(600, 400))1904else:1905wxlib.scrolledpanel.ScrolledPanel.__init__(self, parent, wx.ID_ANY, size=wx.DefaultSize)1906#self.maxWidth = 20001907#self.maxHeight = 3001908#self.SetVirtualSize((self.maxWidth, self.maxHeight))1909self.SetScrollRate(10, 10)19101911# parent must be panel, scrolled panel or similar1912self.parent = parent19131914self.id = id19151916# target obj1917#self.obj = obj19181919self.func_change_obj = func_change_obj1920self.mainframe = mainframe1921#self.panelstyle = panelstyle1922#self.immediate_apply = immediate_apply19231924# background colors for lines shading:1925self.tablecolors = get_tablecolors()19261927# print 'ScalarPanel.__init__'#,parent,self.obj1928# print ' immediate_apply=',immediate_apply19291930self.widgetcontainers = []19311932self.create_attrs(attrconfigs, immediate_apply=immediate_apply, panelstyle=panelstyle)1933# self.SetAutoLayout(True)1934# self.AutoLayout()1935# self.Refresh()1936# self.SetAutoLayout(1)1937# self.SetupScrolling()19381939self.Refresh()1940# self.Layout()19411942# self.SetupScrolling()19431944# self.Refresh()1945# self.Layout()194619471948class TableGrid(AttrBase, gridlib.PyGridTableBase):19491950"""1951This is all it takes to make a custom data table to plug into a1952wxGrid. There are many more methods that can be overridden, but1953the ones shown below are the required ones. This table simply1954provides strings containing the row and column values.1955"""19561957def __init__(self, parent, tab, attrconfigs, ids, show_ids=False, **args):1958gridlib.PyGridTableBase.__init__(self)19591960self.odd = gridlib.GridCellAttr()1961self.odd.SetBackgroundColour("sky blue")1962self.even = gridlib.GridCellAttr()1963self.even.SetBackgroundColour("sea green")19641965# target obj1966self.tab = tab1967self.parent = parent19681969# print 'gridlib.PyGridTableBase\n'#,dir(gridlib.PyGridTableBase)1970self.ids = ids1971self.show_ids = show_ids1972self.attrconfigs = attrconfigs19731974# print 'TableGrid: attrs,ids=',len(self.attrconfigs),'X',len(self.ids)19751976col = 01977self.colnames = []1978self.celltypes = []1979# self.cellattrs=[]1980# print ' make header'1981for attrconf in attrconfigs:1982if hasattr(attrconf, 'symbol'):1983symbol = attrconf.symbol1984else:1985symbol = attrconf.get_name()1986unit = attrconf.format_unit(show_parentesis=True)1987if len(unit) > 0:1988if len(symbol) > 7:1989symbol += '\n'+unit1990else:1991symbol += ' '+unit1992# print ' symbol',symbol1993self.colnames.append(symbol)1994self.celltypes.append(self.get_celltype(attrconf))1995col += 11996# print ' done: header'19971998def get_celltype(self, attrconf):1999"""2000Returns type code string of a wx cell.2001http://permalink.gmane.org/gmane.comp.python.wxpython/1026602002"""2003# config=self.obj.get_config(attr)2004# tt=config['type'][0]2005# check fist if widgets for metatypes are availlable2006# if mt=='color':2007# #print ' ->WidgetContainer'2008# return 'color'2009# #return WidgetContainer(self,attr,parent,**args)20102011# if config.has_key('choices'):2012# choicestring=wxGRID_VALUE_CHOICE+':'2013# for c in config['choices']:2014# choicestring+=c+','2015# choicestring=choicestring[:-1]2016# return choicestring20172018# check now native types2019# if len(config['type'])==1:2020mt = attrconf.metatype2021tt = type(attrconf.get_default())2022# print 'get_celltype',attrconf.attrname,mt,tt,hasattr(attrconf,'choices'),attrconf.is_writable()20232024if mt == 'objs':2025return gridlib.GRID_VALUE_STRING20262027elif mt == 'id':2028obj = attrconf.get_linktab()2029if attrconf.is_writable():2030if hasattr(attrconf, 'choices'):2031if len(attrconf.choices) < 200:2032# print ' choices=',attrconf.choices2033# (types.ListType, types.TupleType):2034if type(attrconf.choices) in (OrderedDict, types.DictionaryType):2035# print ' GridCellChoiceEditor',attrconf.choices,':'+','.join(attrconf.choices.keys())2036return gridlib.GRID_VALUE_CHOICE+':'+','.join(attrconf.choices.keys())2037else:2038# print ' GridCellChoiceEditor',attrconf.choices,':'+','.join(attrconf.choices)2039return gridlib.GRID_VALUE_CHOICE+':'+','.join(attrconf.choices)20402041#gridlib.GridCellChoiceEditor(['what','ever'], allowOthers=True)2042else:2043return gridlib.GRID_VALUE_STRING # still display a string with choice20442045elif len(obj) < 200:2046# print ' GridCellChoiceEditor',attrconf.attrname,':'+obj.format_ids(obj.get_ids())2047return gridlib.GRID_VALUE_CHOICE+':'+obj.format_ids(obj.get_ids())2048else:2049return gridlib.GRID_VALUE_STRING20502051return gridlib.GRID_VALUE_STRING20522053elif mt == 'tabid':2054return gridlib.GRID_VALUE_STRING20552056elif mt == 'ids':2057return gridlib.GRID_VALUE_STRING20582059elif hasattr(attrconf, 'choices'):2060if attrconf.is_writable():2061if len(attrconf.choices) < 200:2062# print ' dir(gridlib)',dir(gridlib)2063# (types.ListType, types.TupleType):2064if type(attrconf.choices) in (OrderedDict, types.DictionaryType):2065# print ' GridCellChoiceEditor',attrconf.choices,':'+','.join(attrconf.choices.keys())2066return gridlib.GRID_VALUE_CHOICE+':'+','.join(attrconf.choices.keys())2067else:2068# print ' GridCellChoiceEditor',attrconf.choices,':'+','.join(attrconf.choices)2069return gridlib.GRID_VALUE_CHOICE+':'+','.join(attrconf.choices)20702071#gridlib.GridCellChoiceEditor(['what','ever'], allowOthers=True)2072else:2073return gridlib.GRID_VALUE_STRING2074else:2075return gridlib.GRID_VALUE_STRING20762077elif tt in (types.LongType, types.IntType):2078if (hasattr(attrconf, 'min') & hasattr(attrconf, 'max')):2079return gridlib.GRID_VALUE_NUMBER+':'\2080+ str(attrconf.min)+','+str(attrconf.max)2081else:2082return gridlib.GRID_VALUE_NUMBER20832084elif tt in (types.FloatType, types.ComplexType):2085if (hasattr(attrconf, 'digits_integer') & hasattr(attrconf, 'digits_fraction')):2086return gridlib.GRID_VALUE_FLOAT+':'\2087+ str(attrconf.digits_integer)+','\2088+ str(attrconf.digits_fraction)2089else:2090return gridlib.GRID_VALUE_FLOAT20912092elif tt in STRINGTYPES:2093return gridlib.GRID_VALUE_STRING20942095elif tt in (types.BooleanType,):2096return gridlib.GRID_VALUE_BOOL20972098else:2099# else means use a the base class that can display anything2100return gridlib.GRID_VALUE_STRING21012102def GetNumberRows(self):2103return len(self.ids)21042105def GetNumberCols(self):2106return len(self.attrconfigs)21072108def IsEmptyCell(self, row, col):2109return (row > len(self.ids)) | (col > len(self.attrconfigs))21102111def GetValue(self, row, col):2112"""2113Returns object value to be displayed in the cell.2114"""2115# TODO: this should be all handled by format_value of the attrconf !!!!2116# try:2117if 1:2118rowid, attrconf = self.get_id_attrconf(row, col)2119if (rowid is None) | (attrconf is None):2120return 'Err'2121# attrconf=self.attrconfigs[col]2122val = self.get_objvalue(row, col)2123mt = attrconf.metatype21242125# print 'GetValue',self.ids[row],attrconf.attrname,val,mt,hasattr(attrconf,'choices'),attrconf.is_writable()21262127if mt == 'objs':2128return val.format_ident()21292130elif mt == 'id':2131# print ' id=',val,idtext2132# print ' linktab',attrconf.get_linktab(),idtext2133if val == -1:2134return '-'21352136if hasattr(attrconf, 'choices'):2137# this is for backwards compatibility2138# choices should no longer osed to index id2139# instead, the format_ids method should be used2140# (types.ListType, types.TupleType):2141if type(attrconf.choices) in (OrderedDict, types.DictionaryType):2142if attrconf.choices.values().count(val) > 0:2143ind = attrconf.choices.values().index(val)2144# print ' return',attrconf.choices.keys()[ind]2145return attrconf.choices.keys()[ind]2146else:2147return attrconf.get_linktab().format_ids([val])2148else:2149# print ' GridCellChoiceEditor',attrconf.choices,':'+','.join(attrconf.choices)2150return attrconf.get_linktab().format_ids([val])21512152else:2153# print ' return ',attrconf.get_linktab().format_ids([val])2154return attrconf.get_linktab().format_ids([val])21552156elif mt == 'ids':2157# print ' ids=',val,attrconf.get_linktab().format_ids(val)2158if val is None:2159return ''2160else:2161return attrconf.get_linktab().format_ids(val)21622163elif mt == 'tabid':2164obj, _id = val2165return obj.format_ident_row(_id)21662167elif mt == 'tabidlist':2168return attrconf.format_value(rowid) # <<<<<<<< should work for all types !!!21692170elif hasattr(attrconf, 'choices'):2171# print ' attrconf.choices',attrconf.choices2172if type(attrconf.choices) in (OrderedDict, types.DictionaryType): # (types.ListType, types.TupleType):2173if attrconf.choices.values().count(val) > 0:2174ind = attrconf.choices.values().index(val)2175# print ' return',attrconf.choices.keys()[ind]2176return attrconf.choices.keys()[ind]2177else:2178return val2179else:2180if attrconf.choices.count(val) > 0:2181ind = attrconf.choices.index(val)2182# print ' return',attrconf.choices[ind]2183return attrconf.choices[ind]2184else:2185return val21862187elif mt == 'color': # special config for colors2188# done by cell backgroundcolor2189return ''21902191# elif config.has_key('do_init_arrayobj'):2192# if config['do_init_arrayobj']:2193# return val.ident2194# else:2195# return val21962197else:2198return val21992200else:2201return 'Err'2202# except IndexError:2203# return 'Err'22042205def get_objvalue(self, row, col):2206"""2207Returns value of referred object according to row and col of grid2208"""2209return self.attrconfigs[col][self.ids[row]]22102211def get_valueconfigs(self):2212return self.attrconfigs22132214def get_id_attrconf(self, row, col):2215if (col >= 0) & (col < len(self.attrconfigs)):2216if (row >= 0) & (row < len(self.ids)):2217return self.ids[row], self.attrconfigs[col]2218else:2219return None, self.attrconfigs[col]2220else:2221if (row >= 0) & (row < len(self.ids)):2222return self.ids[row], None2223else:2224return None, None22252226# def get_perm(self, attrconf,id):2227# """2228# Return read write permission2229# """2230# # TODO: must be enhanced with grid specific rw2231# #print 'get_perm',id, attr2232# return attrconf.get_perm()22332234def SetValue(self, row, col, value):2235"""2236Transfer of cell value to object.2237"""2238id, attrconf = self.get_id_attrconf(row, col)2239if attrconf is not None:22402241if attrconf.is_writable():2242mt = attrconf.metatype2243# print 'SetValue(%d, %d, "%s").\n' % (row, col, value)22442245# print ' attrconf',id,attrconf.attrname, attrconf.is_writable(),hasattr(attrconf,'choices')2246# attr=self.attrs[col]2247tt = type(attrconf.get_default())2248if hasattr(attrconf, 'choices'):2249# print ' type(attrconf.choices)',type(attrconf.choices),type(attrconf.choices) in (OrderedDict, types.DictionaryType)2250# (types.ListType, types.TupleType):2251if type(attrconf.choices) in (OrderedDict, types.DictionaryType):2252# print ' set choices[value]',attrconf.choices[value]2253if attrconf.choices.has_key(value):2254attrconf[id] = attrconf.choices[value]2255else:2256attrconf[id] = value22572258else:2259# print ' set value',value2260attrconf[id] = value2261elif mt == 'id':2262attrconf[id] = attrconf.get_linktab().get_id_from_formatted(value)22632264elif (tt in NUMERICTYPES):2265# set only values of types that are allowed for the grid2266# TODO: this grid types data must be organized more central2267attrconf[id] = value2268else:2269# TODO: for other types, like color or arrays, this must be done beforehand2270print 'WARNING in SetValue: cannot write to this type:', tt2271else:2272# readonly2273pass2274# print 'SetValue(%d, %d, "%s") read only.\n' % (row, col, value)22752276# --------------------------------------------------2277# Some optional methods22782279# Called when the grid needs to display labels2280def GetColLabelValue(self, col):2281if (col > -1) & (col < len(self.colnames)):2282return self.colnames[col]2283else:2284return '-'22852286def GetRowLabelValue(self, col):2287return self.FormatRowLabel(self.tab, self.ids[col])22882289def FormatRowLabel(self, tab, id):2290# if tab.is_keyindex():2291# label = str(tab.get_key_from_id(id))2292# else:2293label = str(id)2294return label22952296# if size is None:2297# return label2298# else:2299# if size>=len(label):2300# return (size*' '+label)[-size:]2301# else:2302# return label23032304# def ComputeRowLabelSize(self):2305# size = 02306# tab = self.tab2307# for id in self.ids:2308# l = len(self.FormatLabel( tab, id))2309# if l>size:2310# size=l2311# print 'ComputeRowLabelSize',size*162312# return size*16# TODO here should be the font size as multiplier23132314def ComputeColLabelSize(self):2315"""2316Compute the maximum number of lines required for column labelling2317"""2318# print 'ComputeColLabelSize',self.colnames2319lines = 02320for name in self.colnames:2321l = name.count('\n')2322if l > lines:2323lines = l2324size = (lines+1)*322325# print ' size=',size2326return size # TODO here should be the font size as multiplier23272328def CanHaveAttributes(self):2329# TODO: if the story with returning the attribute2330# for each cell is getting too slow we might want to restrict this2331# to cases when we actually need to modify the attribute2332# as for example with colors2333return True23342335def GetAttr(self, row, col, flag=0):2336# print 'GetAttr row,col,flag',row,col,flag2337attrconf = self.attrconfigs[col]2338# print ' self.ids',self.ids2339id = self.ids[row]2340# config=self.obj.get_config(attr)2341tt = type(attrconf.get_default())2342mt = attrconf.metatype2343val = attrconf[id]2344# print 'GetAttr',attrconf.attrname,val#,config['type'][-1]2345# define cell attribute for this column2346cellattr = gridlib.GridCellAttr()23472348if attrconf.is_readonly():2349cellattr.SetReadOnly(True)23502351if mt == 'color': # special config for colors23522353cint = np.array(np.array(val)*255, np.int32)23542355# print ' cint=',cint2356# cellattr.SetBackgroundColour(wx.Colour(cint[0],cint[1],cint[2],cint[3]))2357cellattr.SetBackgroundColour(wx.Colour(*cint))23582359# elif config['metatype']=='penstyle':2360# cellattr.SetRenderer(PenstyleRenderer(self.obj.get_pentable()))23612362# check whether to make a hyperlink in blue to an instance2363# if len(config['type'])==1:2364# if (tt in (types.InstanceType,types.ClassType)):2365# if hasattr(val,'ident'):2366# print ' is configurator object',val.ident2367if mt in METATYPES_LINKSTYLE:2368cellattr.SetTextColour('blue')2369# no!!cellattr.SetFlags (wx.TEXT_ATTR_FONT_UNDERLINE)2370cellattr.SetReadOnly(False)23712372return cellattr23732374# Called to determine the kind of editor/renderer to use by2375# default, doesn't necessarily have to be the same type used2376# natively by the editor/renderer if they know how to convert.23772378def GetTypeName(self, row, col):2379if (col > -1) & (col < len(self.celltypes)):2380return self.celltypes[col]2381else:2382return wx._mainframe # this can do anything23832384# Called to determine how the data can be fetched and stored by the2385# editor and renderer. This allows you to enforce some type-safety2386# in the grid.23872388def CanGetValueAs(self, row, col, typeName):23892390colType = self.celltypes[col].split(':')[0]2391if typeName == colType:2392return True2393else:2394return False23952396def CanSetValueAs(self, row, col, typeName):2397#id, attr = self.get_id_attrconf( row, col )2398# print 'CanSetValueAs',id, attr2399return self.CanGetValueAs(row, col, typeName)240024012402# ---------------------------------------------------------------------------24032404# class TablePanel(wx.Panel):2405# def __init__(self, parent, tab, **args):2406# wx.Panel.__init__(self, parent, -1)2407# grid = TableFrame(self,tab, **args)2408# self.Sizer = wx.BoxSizer()2409# self.Sizer.Add(grid, 1, wx.EXPAND)2410#2411# #grid.SetReadOnly(5,5, True)2412# def restore(self):2413# pass2414# #self.grid.restore()241524162417class TabPanel(AttrBase, gridlib.Grid):2418def __init__(self, parent, tab, objpanel=None, attrconfigs=None, ids=None, show_ids=True,2419func_change_obj=None,2420func_choose_id=None,2421func_choose_attr=None,2422func_apply=None,2423mainframe=None, **args):2424"""2425parent: parent widget, containing the grid2426tab: table containing the actual data of an object2427"""2428# TODO: Attention: parent is always the main object panel24292430# print ' gridlib.Grid',dir(gridlib.Grid)2431gridlib.Grid.__init__(self, parent, -1) # , style =wx.EXPAND| wx.ALL)#wx.EAST | wx.WEST) )24322433# parent must be panel, scrolled panel or similar2434self.parent = parent2435self.tab = tab2436self._objpanel = objpanel2437self.func_change_obj = func_change_obj2438self.func_choose_id = func_choose_id2439self.func_choose_attr = func_choose_attr2440self.func_apply = func_apply2441self.mainframe = mainframe24422443if ids is None:2444# show all ids2445ids = tab.get_ids() # ordered=True24462447if attrconfigs is None:2448# show all array type attributes2449attrconfigs = tab.get_colconfigs()24502451# print 'init TablePanel',tab.get_ident(),ids2452# print ' start init TableGrid',len(ids),len(attrconfigs)2453# this table contains the gui functionalily of the grid2454table = TableGrid(self, tab, attrconfigs=attrconfigs, ids=ids,2455show_ids=show_ids, **args)2456# print ' end init TableGrid'2457# The second parameter means that the grid is to take ownership of the2458# table and will destroy it when done. Otherwise you would need to keep2459# a reference to it and call its Destroy method later.2460self.SetTable(table, True)2461# print ' done SetTable'2462# self.SetRowLabelSize(16)2463# self.SetColLabelSize(16)2464# self.SetRowLabelSize(table.ComputeRowLabelSize())2465self.SetColLabelSize(table.ComputeColLabelSize())2466# print ' done SetColLabelSize'2467#self.AutoSize ()24682469# for col in xrange(len(attrconfigs)):2470# self.AutoSizeColLabelSize (col)24712472# these operations are nice but slow for huge tables!!2473if len(ids) < 100:2474self.AutoSizeColumns(True)2475# print ' done AutoSizeColumns'2476if len(ids) < 100:2477self.AutoSizeRows(True)2478# print ' done AutoSizeRows'24792480# self.Bind(gridlib.EVT_GRID_CELL_CHANGE, self.on_cell_change) #works, but not used24812482# EVT_GRID_CELL_RIGHT_CLICK(self, self.OnRightDown) #added2483gridlib.EVT_GRID_CELL_RIGHT_CLICK(self, self.on_contextmenu) # added2484self.Bind(gridlib.EVT_GRID_LABEL_RIGHT_CLICK, self.on_contextmenu_label)24852486# does not seem to work2487gridlib.EVT_GRID_CELL_LEFT_DCLICK(self, self.on_edit_cell)2488gridlib.EVT_GRID_CELL_LEFT_CLICK(self, self.on_click_cell)24892490gridlib.EVT_GRID_LABEL_LEFT_DCLICK(self, self.OnLabelLeftDoubleClick)2491# ??gridlib.EVT_GRID_LABEL_LEFT_CLICK(self, self.OnLabelLeftClick)2492#EVT_CONTEXT_MENU(self, self.on_contextmenu)2493#self.Bind(wx.EVT_CONTEXT_MENU, self.on_contextmenu)2494# print ' done init TabPanel'2495# def on_contextmenu(self, event):2496# print '\non_contextmenu!!!'24972498def Reset(self):2499"""reset the view based on the data in the table. Call2500this when rows are added or destroyed"""2501# self._table.ResetView(self)2502self.AdjustScrollbars()2503self.ForceRefresh()25042505def logw(self, s):2506"""2507Write to logger if existent print otherwise2508"""2509pass25102511def on_cell_change(self, event):2512Row = event.GetRow()2513Col = event.GetCol()25142515# All cells have a value, regardless of the editor.2516# print 'Changed cell: (%u, %u)' % (Row, Col)2517# print 'value: %s' % self.grid1.GetCellValue(Row, Col)25182519def get_obj(self):2520"""2521Returns object wich is represented by this table.2522"""2523return self.tab.get_obj()25242525def on_contextmenu(self, event):2526# print "on_contextmenu (%d,%d) %s\n" %\2527# (event.GetRow(), event.GetCol(), event.GetPosition())2528menu = AgilePopupMenu(self.parent)25292530# tell popup menue in which cell it has been called2531# in this way a later event can retrieve cell coordinates2532menu.set_row(event.GetRow())2533menu.set_col(event.GetCol())2534menu.append_item('edit...', self.on_edit_cell_from_popupmenu,2535info='Edit data of this cell')25362537# Popup the menu. If an item is selected then its handler2538# will be called before PopupMenu returns.2539self.parent.PopupMenu(menu)2540menu.Destroy()25412542def on_edit_cell_from_popupmenu(self, event):2543"""Start cell editor"""2544popupmenu = event.GetEventObject()25452546table = self.GetTable()2547id, attrconf = table.get_id_attrconf(popupmenu.get_row(), popupmenu.get_col())2548# print 'on_edit_cell EventObject=',id, attrconf.attrname#popupmenu2549if (id >= 0) & (attrconf is not None):25502551# dlg = ObjPanelDialog(self,self.tab.get_obj(),table = self.tab,id,attrconfigs=[attrconf,], size=(350, 200),2552# #style = wxCAPTION | wxSYSTEM_MENU | wxTHICK_FRAME2553# style = wx.DEFAULT_DIALOG_STYLE2554# )25552556dlg = ObjPanelDialog(self,2557self.tab.get_obj(),2558attrconfigs=[attrconf, ],2559#tables = None,2560table=self.tab, id=id, ids=None,2561#groupnames = None,2562# title = '', size = wx.DefaultSize, pos = wx.DefaultPosition,\2563style=wx.DEFAULT_DIALOG_STYLE,2564# choose_id=False, choose_attr=False,2565# func_choose_id=None,func_change_obj=None,2566func_apply=self.func_apply,2567#panelstyle = 'default',2568#immediate_apply = False2569)25702571dlg.CenterOnScreen()25722573# this does not return until the dialog is closed.2574val = dlg.ShowModal()25752576if val == wx.ID_OK:2577# apply current widget values2578dlg.apply()2579else:2580# print ">>>>>>>>>You pressed Cancel\n"2581pass25822583dlg.Destroy()25842585event.Skip()2586self.ForceRefresh()2587#sz = miniframe.GetBestSize()2588#miniframe.SetSize( (sz.width+20, sz.height+20) )25892590def on_contextmenu_label(self, event):2591# print "on_contextmenu_label (%d,%d) %s\n" %\2592# (event.GetRow(), event.GetCol(), event.GetPosition())2593menu = AgilePopupMenu(self.parent)25942595# tell popup menue in which cell it has been called2596# in this way a later event can retrieve cell coordinates2597col = event.GetCol()2598row = event.GetRow()2599menu.set_row(row)2600menu.set_col(col)2601if col < 0:26022603# popup row options menu2604self._contextfunctions = {}2605# print ' configs',self.tab.get_configs(is_all=True)2606for config in self.tab.get_configs(filtergroupnames=['rowfunctions'], is_private=True): # (is_all=True):2607# print ' ',config.attrname,config.groupnames,'rowfunctions' in config.groupnames2608# if 'rowfunctions' in config.groupnames:2609item, _id = menu.append_item(config.get_name(), self.on_select_rowfunction, info=config.get_info())2610#item,id = menu.append_item( config.name,config.get_function(), info=config.info)2611self._contextfunctions[_id] = config.get_function()2612# print ' append ',config.name,_id2613#menu.append_item( config.name,self.on_select_contextmenu, info=config.info)26142615# default2616menu.append_item('Export to CSV...', self.on_export_csv,2617info='Export entire table in CSV format.')26182619# Menu on_highlight events2620#self.parent.Bind(wx.EVT_MENU_HIGHLIGHT_ALL, self.on_)26212622# Popup the menu. If an item is selected then its handler2623# will be called before PopupMenu returns.26242625self.parent.PopupMenu(menu)2626menu.Destroy()26272628def on_dummy(self, event):2629# event.Skip()2630pass26312632def on_select_rowfunction(self, event):2633popupmenu = event.GetEventObject()2634# Show how to get menu item info from this event handler2635table = self.GetTable()2636row = popupmenu.get_row()2637col = popupmenu.get_col()2638_id, attrconf = table.get_id_attrconf(row, col)2639id_menu = event.GetId()2640# print 'on_select_contextmenu id_menu,_id, attrconf',id_menu,_id, attrconf2641# print ' GetSelection',event.GetSelection()2642# print ' GetString',event.GetString()26432644# print ' GetId',id_menu,event.Id2645# print ' GetClientObject',event.GetClientObject()26462647# call selected row function with row _id2648self._contextfunctions[id_menu](_id)26492650# item = popupmenu.get_menuitem_from_id(event.GetId())# OK but not neede2651# if self._rowfunctions.has_keid_menu:2652# funcname = item.GetText()2653# #help = item.GetHelp()2654# #??? menu id->name->function??????????2655# print 'on_select_contextmenu: found function:',funcname#,getattr(table,funcname)2656# self._rowfunctions[_id]2657# else:2658# print 'on_select_contextmenu: No function found'26592660event.Skip()2661# self.ForceRefresh()2662# self.grid.AutoSizeColumn(col)2663self.Reset()2664self.Refresh()2665self.ForceRefresh()26662667#del table2668newtable = TableGrid(self, self.tab, attrconfigs=self.tab.get_colconfigs(),2669ids=self.tab.get_ids(), show_ids=table.show_ids)2670del table2671# The second parameter means that the grid is to take ownership of the2672# table and will destroy it when done. Otherwise you would need to keep2673# a reference to it and call its Destroy method later.2674self.SetTable(newtable, True)26752676return None26772678def on_export_csv(self, event):2679wildcards_all = "CSV file (*.csv,*.txt)|*.csv;*.CSV;*.txt;*.TXT|All files (*.*)|*.*"2680# if hasattr(attrconf,'wildcards'):2681# wildcards = attrconf.wildcards+"|"+wildcards_all2682# else:2683# wildcards = wildcards_all2684dlg = wx.FileDialog(self.parent, message="Export table %s to CSV" % self.tab.get_name(),2685# defaultDir=os.getcwd(),2686defaultFile="",2687wildcard=wildcards_all,2688style=wx.SAVE | wx.CHANGE_DIR2689)26902691if dlg.ShowModal() == wx.ID_OK:2692# This returns a Python list of files that were selected.2693path = dlg.GetPath()2694print 'on_export_csv', type(path), path2695if type(path) in STRINGTYPES:2696self.tab.export_csv(path, sep=',',2697attrconfigs=self.GetTable().get_valueconfigs(),2698groupnames=None, is_header=True)26992700def on_click_cell(self, event):2701"""2702Action for first click on cell.2703"""2704# check if there is something to navigate2705if self.CanEnableCellControl():2706table = self.GetTable()2707id, attrconf = table.get_id_attrconf(event.GetRow(), event.GetCol())2708mt = attrconf.metatype2709# config=table.obj.get_config(attr)2710# print 'on_click_cell ,id,attrconf',id, attrconf.get_name(),mt2711# print ' func_change_obj=',self.func_change_obj2712# if hasattr(attrconf,'attrname'):2713# print ' attrconf.attrname=',attrconf.attrname27142715# navigate!2716value = attrconf[id]2717# print ' value ' , value, type(value)2718if mt == 'obj':2719if type(value) == types.InstanceType:2720# print ' ident?',hasattr(value,'ident')2721if hasattr(value, 'ident'):2722navitimer = wx.FutureCall(1, self.func_change_obj, value)27232724else:2725event.Skip()2726else:2727event.Skip()27282729elif mt == 'id':2730if attrconf.is_readonly():2731linktab = attrconf.get_linktab()2732# print ' FutureCall',linktab, value2733if value != -1:2734navitimer = wx.FutureCall(1, self.func_change_obj, linktab, value) # here value is id2735else:2736event.Skip()2737else:2738event.Skip()27392740elif mt == 'tabid':2741if value is not None:2742linktab, id = value2743navitimer = wx.FutureCall(1, self.func_change_obj, linktab, id) # here value is id2744else:2745event.Skip()27462747elif mt == 'ids':2748if value is not None:2749linktab = attrconf.get_linktab()2750navitimer = wx.FutureCall(1, self.func_change_obj, linktab, None, value) # here value is ids list2751else:2752event.Skip()2753else:2754event.Skip()2755# elif config.has_key('do_init_arrayobj'):2756# if config['do_init_arrayobj']:2757# navitimer = wx.FutureCall(1, self.func_change_obj,table.obj[attr,id])2758# else:2759# event.Skip()27602761else:2762event.Skip()27632764def on_edit_cell(self, event):2765"""2766Decide how to to edit the cell. Possibilities are:2767- popup with special editing windows2768- in-cell editing2769"""2770table = self.GetTable()2771id, attrconf = table.get_id_attrconf(event.GetRow(), event.GetCol())27722773# check first if there are callback functions2774if self.func_choose_id is not None:2775# call self.func_choose_id2776#2777wx.FutureCall(1, self.func_choose_id, id, attrconf)2778# event.Skip()2779return27802781elif self.func_choose_attr is not None:2782# call self.func_choose_id2783wx.FutureCall(1, self.func_choose_attr, attrconf)2784# event.Skip()2785return27862787if self.CanEnableCellControl():27882789#self.logw(' func_choose_id id=%d,attr=%s,ident=%s='%(id, attr,table.obj.ident))2790# print 'on_edit_cell',attrconf.attrname2791# print ' obj=',table.obj27922793# print ' config=',config27942795metatype = attrconf.metatype27962797if metatype == 'color': # special config for colors2798dlg = wx.ColourDialog(self.parent)27992800# Ensure the full colour dialog is displayed,2801# not the abbreviated version.2802dlg.GetColourData().SetChooseFull(True)28032804if dlg.ShowModal() == wx.ID_OK:2805# If the user selected OK, then the dialog's wx.ColourData will2806# contain valid information. Fetch the data ...2807c = dlg.GetColourData().GetColour()28082809# print 'on_edit_cell:'2810# print ' wxc=',[wxc.Red(),wxc.Green(),wxc.Blue()]2811# print ' table.obj[attr, id]=',table.obj[attr, id],type(table.obj[attr, id])2812# 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()] ))28132814# self.ffffff_to_color([wxc.Red(),wxc.Green(),wxc.Blue()] )2815attrconf[id] = np.array([c.Red(), c.Green(), c.Blue(), c.Alpha()], np.float32)/255.02816self.SetCellBackgroundColour(event.GetRow(), event.GetCol(), c)2817self.ForceRefresh()2818if self.func_apply is not None:2819wx.FutureCall(1, self.func_apply, table, id, None)28202821# Once the dialog is destroyed, Mr. wx.ColourData is no longer your2822# friend. Don't use it again!2823dlg.Destroy()2824# event.Skip()2825# cellattr.SetBackgroundColour(obj[])28262827elif metatype == 'filepath':2828filepath = self.on_fileopen(attrconf)2829if filepath is not None:2830attrconf[id] = filepath2831self.ForceRefresh()2832if self.func_apply is not None:2833wx.FutureCall(1, self.func_apply, table, id, None)28342835elif metatype == 'dirpath':2836dirpath = self.on_diropen(attrconf)2837if dirpath is not None:2838attrconf[id] = dirpath2839self.ForceRefresh()2840if self.func_apply is not None:2841wx.FutureCall(1, self.func_apply, table, id, None)2842# elif metatype == 'penstyle':2843# #Penstyles(table.obj.get_pentable())2844# #penstyles=Penstyles(table.obj.get_pentable())2845#2846# dlg = PenstyleDialog(self.parent,2847# table.obj.get_pentable(),2848# size = (300,400),2849# #choose_id=True,2850# #func_change_obj=self.on_edit_linestyle2851# )2852#2853# if dlg.ShowModal() == wx.ID_OK:2854# attr_current,idc_current=dlg.get_current_attrconf_id()2855# table.obj[attr, id]=idc_current2856#2857# self.ForceRefresh()2858# dlg.Destroy()2859# event.Skip()28602861else:2862self.EnableCellEditControl()2863# try this ...2864# if self.func_apply is not None:2865# wx.FutureCall(1,self.func_apply, table, id, None)2866# ...put this in apply method28672868def on_fileopen(self, attrconf):2869# print 'on_fileopen',self._attrconf.attrname2870# if type(self._attrconf.get_default())==types.StringType:2871# defaultname = self._attrconf.get_default()2872# else:2873# defaultname = os.getcwd()2874wildcards_all = "All files (*.*)|*.*"2875if hasattr(attrconf, 'wildcards'):2876wildcards = attrconf.wildcards+"|"+wildcards_all2877else:2878wildcards = wildcards_all2879dlg = wx.FileDialog(self.parent, message="Open file",2880# defaultDir=os.getcwd(),2881defaultFile="",2882wildcard=wildcards,2883style=wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR2884)28852886if dlg.ShowModal() == wx.ID_OK:2887# This returns a Python list of files that were selected.2888paths = dlg.GetPaths()2889# print 'You selected %d files:' % len(paths)2890if len(paths) == 1:2891return paths[0]2892elif len(paths) > 1:2893return paths2894else:2895return None2896else:2897return None28982899def on_diropen(self, attrconf):2900dlg = wx.DirDialog(self.parent, message="Open directory",2901style=wx.DD_DEFAULT_STYLE | wx.DD_DIR_MUST_EXIST | wx.DD_CHANGE_DIR2902)29032904if dlg.ShowModal() == wx.ID_OK:2905return dlg.GetPath()2906else:2907return None29082909def on_edit_cell_miniframe(self, event):2910"""Start miniframe cell editor"""2911EventObject = event.GetEventObject()29122913table = self.GetTable()2914id, attrconf = table.get_id_attrconf(event.GetRow(), event.GetCol())2915#miniframe=DataMiniFrame( self, table.obj, id =id, attrs = [attr])2916print 'on_edit_cell_miniframe EventObject=', id, attrconf2917dlg = ObjPanelDialog(self, table.obj, id, attrconfigs=[attrconf], size=(350, 200),2918#style = wxCAPTION | wxSYSTEM_MENU | wxTHICK_FRAME2919func_apply=self.func_apply,2920style=wx.DEFAULT_DIALOG_STYLE2921)2922dlg.CenterOnScreen()29232924# this does not return until the dialog is closed.2925val = dlg.ShowModal()29262927if val == wx.ID_OK:2928# apply current widget values2929dlg.apply()2930else:2931# print ">>>>>>>>>You pressed Cancel\n"2932pass29332934dlg.Destroy()29352936evt.Skip()29372938self.ForceRefresh()2939#sz = miniframe.GetBestSize()2940#miniframe.SetSize( (sz.width+20, sz.height+20) )2941# self.Refresh()#no29422943def OnLabelLeftDoubleClick(self, evt):2944# print "OnLabelLeftDoubleClick: (%d,%d) %s\n" %\2945# (evt.GetRow(), evt.GetCol(), evt.GetPosition())2946if evt.GetRow() >= 0:2947table = self.GetTable()2948# click has been on row labels = ids2949id = table.ids[evt.GetRow()]29502951if self.func_choose_id is None:29522953# print ' call ScalarPanel editor for ID=',id29542955dlg = ObjPanelDialog(self, self.tab.get_obj(), id=id, # table = self.tab,2956#title = '',2957#size=(350, 200),2958#style = wx.DEFAULT_DIALOG_STYLE2959func_apply=self.func_apply,2960)29612962dlg.CenterOnScreen()29632964# this does not return until the dialog is closed.2965val = dlg.ShowModal()29662967if val == wx.ID_OK:2968# apply current widget values2969dlg.apply()2970if self._objpanel:2971self._objpanel.restore() # thi will also update scalars on objpanel2972self.ForceRefresh()2973else:2974# print ">>>>>>>>>You pressed Cancel\n"2975pass29762977dlg.Destroy()29782979else:2980# call self.func_choose_id2981wx.FutureCall(1, self.func_choose_id, id, '')29822983evt.Skip()29842985def OnRightDown(self, event):2986print "hello", self.GetSelectedRows()29872988def apply(self):2989"""2990Widget values are copied to object2991"""29922993# grid always updated2994# but there may be callback functions2995# which expects a return with current selection2996pass2997# self.ForceRefresh()29982999col = self.GetGridCursorCol()3000row = self.GetGridCursorRow()30013002table = self.GetTable()3003id, attrconf = table.get_id_attrconf(row, col)30043005if self.func_apply is not None:3006wx.FutureCall(1, self.func_apply, table, id, None)30073008#self.logw('grid.apply row%d col %d'%(row,col))3009if self.func_choose_id is not None:3010# call self.func_choose_id3011wx.FutureCall(1, self.func_choose_id, id, attrconf)3012return30133014elif self.func_choose_attr is not None:3015# call self.func_choose_id3016wx.FutureCall(1, self.func_choose_attr, attrconf)3017return30183019def get_current_attrconf_id(self):3020"""3021Return current attribute and id3022"""3023col = self.GetGridCursorCol()3024row = self.GetGridCursorRow()30253026table = self.GetTable()3027id, attrconf = table.get_id_attrconf(row, col)30283029return attrconf, id30303031def restore(self):3032"""3033Object values are copied into widgets.3034"""3035# grid always updated3036pass3037# self.ForceRefresh()303830393040class ObjPanelMixin:3041"""3042Common methods for panels3043"""30443045def init_panel(self, parent, mainframe=None):3046"""3047Initialization of general panel, independent by which type of3048widow the panel is actually represented30493050parent = parent widget30513052"""30533054self.parent = parent3055self.mainframe = mainframe3056self.widgets = None30573058# list with widgets containing data3059# these widgets must have an apply and restore method3060# which is calle when the respective buttons are pressed.3061self.datawidgets = []30623063# self.pentable=pentable30643065# def get_pentable(self):3066# """3067# Returns pentable used for this panel3068# """3069# if self.pentable is None:3070# return self.obj.get_pentable()3071# else:3072# return self.pentable30733074def get_obj(self):3075return self.obj30763077def get_id(self):3078return self.id30793080def clear(self):3081for widget in self.datawidgets:3082widget.Destroy()30833084def recreate_panel(self, obj, id=None, ids=None, groupnames=None, **kwargs):3085# print '\nrecreate_panel:',obj.format_ident(), id , ids, groupnames30863087# print ' args =',kwargs3088self.obj = obj3089self.id = id3090self.ids = ids30913092# print ' n_colconfigs =',len(obj.get_colconfigs(filtergroupnames = groupnames))3093# print ' n_configs =',len(obj.get_configs(filtergroupnames = groupnames))3094if (id is None) & (ids is None):30953096if obj.managertype == 'table':3097# print ' managertype',obj.managertype,obj.get_attrsman()3098if len(obj.get_colconfigs(filtergroupnames=groupnames)) > 0:3099self.recreate_panel_table(groupnames=groupnames, **kwargs)3100else:3101self.recreate_panel_scalar(groupnames=groupnames, **kwargs)3102else:3103self.recreate_panel_scalar(groupnames=groupnames, **kwargs)3104else:3105if ids is not None:3106# table with specific ids3107self.recreate_panel_table(groupnames=groupnames, **kwargs)3108else:3109# scalar panel for single id3110self.recreate_panel_scalar(groupnames=groupnames, **kwargs)31113112def recreate_panel_table(self, attrconfigs=None,3113groupnames=None, show_groupnames=False,3114show_title=True,3115is_modal=False,3116immediate_apply=False,3117panelstyle='default',3118func_change_obj=None,3119func_choose_id=None,3120func_choose_attr=None,3121func_apply=None,3122is_scrolled=True,3123**buttonargs):3124"""3125Recreates panel and destroys previous contents:3126attr = a list ith attribute names to be shown3127groups = list with group names to be shown3128show_groupnames = the group names are shown3129together with the respective attributes3130is_modal = if true the panel will be optimized for dialog window3131immediate_apply = changes to widgets will be immediately applied to3132obj attribute without pressing apply3133buttonargs = a dictionary with arguments for botton creation3134obj = the object to be displayed3135func_change_obj = function to be called if user clicks on on object3136with obj as argument3137func_choose_id = function to be called when user clicks on id(table row)3138with id as argument3139func_choose_attr = function to be called when user clicks on attribute3140with attr as argument. In this case the attribute3141names of scalars turn into buttons. Array attributes3142are selected by clicking on the column name.3143func_apply = is executed when apply button is pressed, and after widget values3144have been applied. Arguments are: obj, id, ids3145"""3146#3147# print 'recreate_panel_table:',self.obj.ident,immediate_apply, func_apply,groupnames31483149self.func_change_obj = func_change_obj3150self.func_choose_id = func_choose_id3151self.func_choose_attr = func_choose_attr3152self.func_apply = func_apply3153self._show_title = show_title31543155# if is_scrolled is None:3156# is_scrolled = not is_modal #for dialog windows use non crolled panels by default31573158attrsman = self.obj.get_attrsman()3159attrconfigs_scalar = attrsman.get_configs(structs=cm.STRUCTS_SCALAR, filtergroupnames=groupnames)3160# print ' attrconfigs_scalar',attrconfigs_scalar3161# if obj.managertype=='table': # obj is a single table3162# print ' is_scalar_panel & is_singletab:'3163table = self.obj31643165#attrconfigs_scalar = attrsman.get_configs( structs = cm.STRUCTS_SCALAR)31663167if len(attrconfigs_scalar) > 0:3168# print ' create a panel with scalars and a table below'3169self.make_scalartablepanel(self, attrconfigs_scalar, table, objpanel=self,3170attrconfigs=None,3171immediate_apply=immediate_apply, panelstyle=panelstyle,3172is_modal=is_modal, show_title=show_title,3173is_scrolled=is_scrolled, **buttonargs)31743175else:3176# print ' create only a table, without scalars'#,attrsman.get_colconfigs(filtergroupnames = groupnames)3177self.make_tablepanel(self, table, objpanel=self, attrconfigs=None, groupnames=groupnames,3178immediate_apply=immediate_apply, panelstyle=panelstyle,3179is_modal=is_modal, show_title=show_title,3180is_scrolled=is_scrolled, **buttonargs)31813182self.restore()3183return True31843185def recreate_panel_scalar(self, attrconfigs=None,3186groupnames=None, show_groupnames=False,3187show_title=True,3188is_modal=False,3189immediate_apply=False,3190panelstyle='default',3191func_change_obj=None,3192func_choose_id=None,3193func_choose_attr=None,3194func_apply=None,3195is_scrolled=True,3196**buttonargs):3197"""3198Recreates panel and destroys previous contents:3199attr = a list ith attribute names to be shown3200groups = list with group names to be shown3201show_groupnames = the group names are shown3202together with the respective attributes3203is_modal = if true the panel will be optimized for dialog window3204immediate_apply = changes to widgets will be immediately applied to3205obj attribute without pressing apply3206buttonargs = a dictionary with arguments for botton creation3207obj = the object to be displayed3208func_change_obj = function to be called if user clicks on on object3209with obj as argument3210func_choose_id = function to be called when user clicks on id(table row)3211with id as argument3212func_choose_attr = function to be called when user clicks on attribute3213with attr as argument. In this case the attribute3214names of scalars turn into buttons. Array attributes3215are selected by clicking on the column name.3216func_apply = is executed when apply button is pressed, and after widget values3217have been applied. Arguments are: obj, id, ids3218"""3219#3220# print 'recreate_panel_scalar:',self.obj.ident, func_apply,groupnames32213222self.func_change_obj = func_change_obj3223self.func_choose_id = func_choose_id3224self.func_choose_attr = func_choose_attr3225self.func_apply = func_apply3226self._show_title = show_title32273228# print ' ',self.obj.managertype,self.obj.get_attrsman()32293230# if is_scrolled is None:3231# is_scrolled = not is_modal #for dialog windows use non crolled panels by default32323233attrsman = self.obj.get_attrsman()3234attrconfigs_scalar = attrsman.get_configs(structs=cm.STRUCTS_SCALAR, filtergroupnames=groupnames)3235if self.id is not None:3236attrconfigs_scalar += attrsman.get_colconfigs()3237# print ' just one scalar obj panel',buttonargs.keys()3238# print ' groupnames', groupnames3239# create vertical main sizer3240# print ' attrconfigs_scalar',attrconfigs_scalar3241# print ' cm.STRUCTS_SCALAR',cm.STRUCTS_SCALAR3242self.make_scalarpanel(self, attrconfigs_scalar, id=self.id, # groupnames=groupnames,3243immediate_apply=immediate_apply, panelstyle=panelstyle,3244is_modal=is_modal, show_title=show_title,3245is_scrolled=is_scrolled, **buttonargs)32463247# self.restore()3248return True32493250def add_scalarpage(self, attrconfigs=None, groupnames=None,3251id=None, immediate_apply=False, panelstyle='default',3252is_modal=False, show_title=False,3253show_buttons=True, is_scrolled=True, **buttonargs):3254"""3255Add a new page to the notebook.3256"""3257# print 'add_scalarpage',groupnames,attrconfigs3258# print ' args',args3259pan = wx.Panel(self.nb, -1)3260#pan = wx.Window(self, -1)3261widget = self.make_scalarpanel(pan, attrconfigs, # groupnames=groupnames,3262id=id, immediate_apply=immediate_apply, panelstyle=panelstyle,3263is_modal=is_modal, show_title=show_title,3264show_buttons=show_buttons, is_scrolled=is_scrolled, **buttonargs)32653266# Add network tab with editor3267p = self.nb.AddPage(pan, 'General')3268self.pages[self.obj.get_ident()] = pan3269# self.nb.SetSelection(p)32703271return pan32723273def add_tablepage(self, table, groupnames=None):3274"""3275Add a new page to the notebook.3276"""3277# print 'context.add_view',ViewClass3278# print ' args',args3279widget = self.add_table(self.nb, table, objpanel=self, groupnames=groupnames, show_title=False)3280self.tablewidgets.append(widget) # need that later for refresh3281# Add network tab with editor3282# print '\nadd_tablepage name',type(table.get_name()),table.get_name(),table3283# try:3284# print ' try:',table.name.attrname3285# except:3286# print ' ok'32873288p = self.nb.AddPage(widget, table.get_name())3289self.pages[table.format_ident()] = widget3290# self.nb.SetSelection(p)32913292return widget32933294def make_scalartablepanel(self, parent, attrconfigs_scalar, table, objpanel=None, attrconfigs=None, groupnames=None,3295id=None, immediate_apply=False, panelstyle='default',3296is_modal=False, show_title=False,3297show_buttons=True, is_scrolled=True, **buttonargs):3298# print 'make_scalarpanellll',attrconfigs_scalar3299sizer = wx.BoxSizer(wx.VERTICAL)3300if show_title:3301self.add_title(sizer, id=id)33023303splitter = wx.SplitterWindow(parent, -1, style=wx.SP_LIVE_UPDATE |3304wx.SP_BORDER | wx.SP_3DBORDER, size=wx.DefaultSize)3305splitter.SetMinimumPaneSize(10)33063307scalarpanel = self.add_scalars(splitter, attrconfigs_scalar, # groupnames = groupnames,3308id=id, immediate_apply=immediate_apply,3309panelstyle=panelstyle, is_modal=False, is_scrolled=is_scrolled)33103311# if datawidget is not None:3312#sizer.Add(datawidget, 1, wx.EXPAND|wx.TOP|wx.LEFT,5)3313#sizer.Add(datawidget, 1,0)3314# datawidget.Layout()33153316tablepanel = self.add_table(splitter, table, objpanel=objpanel, ids=self.ids,3317attrconfigs=attrconfigs, groupnames=groupnames)3318# if datawidget is not None:3319#sizer.Add(datawidget, 1, wx.EXPAND|wx.ALL, 5)3320#sizer.Add(datawidget, 0, wx.EXPAND)3321#sizer.Add(datawidget, 2,0,0)3322# datawidget.Layout()33233324splitter.SplitHorizontally(scalarpanel, tablepanel, -100)3325splitter.SetSashPosition(100, True)3326sizer.Add(splitter, 1, wx.GROW, 5)33273328if show_buttons:3329self.add_buttons(parent, sizer, is_modal=is_modal, **buttonargs)3330# sizer.SetSizeHints(self)3331parent.SetSizer(sizer)3332sizer.Fit(parent)33333334def make_tablepanel(self, parent, tab, objpanel=None, attrconfigs=None, groupnames=None,3335id=None, immediate_apply=False, panelstyle='default',3336is_modal=False, show_title=False,3337show_buttons=True, is_scrolled=True, **buttonargs):3338# print 'make_tablepanel',groupnames3339sizer = wx.BoxSizer(wx.VERTICAL)3340if show_title:3341self.add_title(sizer, id=id)33423343datawidget = self.add_table(parent, tab, ids=self.ids, objpanel=objpanel,3344attrconfigs=attrconfigs, groupnames=groupnames)33453346if datawidget is not None:3347sizer.Add(datawidget, 1, wx.EXPAND | wx.ALL, 5)33483349if show_buttons:3350self.add_buttons(parent, sizer, is_modal=is_modal, **buttonargs)3351parent.SetSizer(sizer)3352sizer.Fit(parent)33533354def make_scalarpanel(self, parent, attrconfigs=None,3355id=None, immediate_apply=False, panelstyle='default',3356is_modal=False, show_title=False,3357show_buttons=True, is_scrolled=True, **buttonargs):33583359# TODO: Attention: parent is always self3360# print 'make_scalarpanellll', attrconfigs3361sizer = wx.BoxSizer(wx.VERTICAL)3362if show_title:3363self.add_title(sizer, id=id)33643365datawidget = self.add_scalars(parent, attrconfigs,3366id=id, immediate_apply=immediate_apply,3367panelstyle=panelstyle, is_modal=is_modal, is_scrolled=is_scrolled)33683369if datawidget is not None:3370sizer.Add(datawidget, 1, wx.EXPAND | wx.ALL, 5)33713372if show_buttons:3373self.add_buttons(parent, sizer, is_modal=is_modal, **buttonargs)3374parent.SetSizer(sizer)3375sizer.Fit(parent)33763377# self.SetAutoLayout(True)3378# self.AutoLayout()3379# self.Refresh()3380self.SetAutoLayout(1)33813382self.Refresh()3383self.Layout()33843385def add_scalars(self, parent, attrconfigs,3386id=None, immediate_apply=False, panelstyle='default',3387is_modal=False, is_scrolled=True):3388"""3389Add all scalar attributes to panel.3390"""33913392# print 'add_scalars for attrconfigs',attrconfigs,is_scrolled33933394if attrconfigs is not None:3395if (not is_scrolled):3396datawidget = ScalarPanel(parent, attrconfigs, id=id,3397func_change_obj=self.func_change_obj,3398immediate_apply=immediate_apply,3399panelstyle=panelstyle,3400mainframe=self.mainframe)3401else:3402datawidget = ScalarPanelScrolled(parent, attrconfigs, id=id,3403func_change_obj=self.func_change_obj,3404immediate_apply=immediate_apply,3405panelstyle=panelstyle,3406is_modal=is_modal,3407mainframe=self.mainframe)3408self.datawidgets.append(datawidget) # used for apply and resore34093410return datawidget34113412def add_tables(self, sizer, tables, groupnames, show_title=False):34133414for table in tables:3415self.add_hline(sizer)3416self.add_table(sizer, table, groupnames=groupnames, show_title=show_title)34173418def add_table(self, parent, tab, ids=None, objpanel=None, attrconfigs=None, groupnames=None):3419"""3420Add all array-type attributes to panel.3421"""3422# TODO: group selection3423# TODO: Attention: parent is always self34243425if attrconfigs is None:3426# This could be done way earlier!!!3427attrconfigs = tab.get_colconfigs(filtergroupnames=groupnames)34283429# print 'add_table=',tab.get_name(),len(tab.get_colconfigs())34303431# check if there are attributes3432if (attrconfigs is not None) & (attrconfigs != []):3433#panel=wx.Panel(self.parent, -1,wx.DefaultPosition,wx.DefaultSize,wx.SUNKEN_BORDER|wx.WANTS_CHARS)3434# panel.SetAutoLayout(True)3435datawidget = TabPanel(parent, tab, attrconfigs=attrconfigs, ids=ids, objpanel=objpanel,3436func_change_obj=self.func_change_obj,3437func_choose_id=self.func_choose_id,3438func_choose_attr=self.func_choose_attr,3439func_apply=self.func_apply,3440mainframe=self.mainframe)3441# panel.Refresh()3442# datawidget=ScalarPanel(self,attrs)3443# self.datawidgets.append(datawidget)34443445self.datawidgets.append(datawidget) # used for apply and resore3446return datawidget34473448def add_buttons(self, parent, sizer,3449is_modal=False,3450standartbuttons=['apply', 'restore', 'cancel'],3451buttons=[],3452defaultbutton='apply',3453):3454"""3455Add a button row to sizer3456"""34573458# print '\nadd_buttons is_modal',is_modal3459# print ' standartbuttons',standartbuttons3460# print ' buttons',buttons3461if parent is None:3462parent = self3463# print 'add_buttons'3464# print ' buttons=',buttons3465self.data_standartbuttons = {3466'apply': ('Apply', self.on_apply, 'Apply current values'),3467'restore': ('Restore', self.on_restore, 'Restore previous values'),3468'ok': ('OK', self.on_ok, 'Apply and close window'),3469'cancel': ('Cancel', self.on_cancel, 'Cancel and close window')3470}34713472# compose button row on bottom of panel3473allbuttons = []34743475# add custom buttons3476allbuttons += buttons3477# print '\n allbuttons',allbuttons3478# print ' buttons',buttons,len(buttons),is_modal&(len(buttons)==0)3479if is_modal & (len(buttons) == 0):3480# if in dialog mode use only OK and cancel by default3481standartbuttons = []34823483# add standart buttons3484# print ' standartbuttons=',standartbuttons3485for key in standartbuttons:3486# print ' append:',key3487allbuttons.append(self.data_standartbuttons[key])34883489if (len(allbuttons) > 0) | is_modal:3490self.add_hline(sizer)34913492# Init the context help button.3493# And even include help text about the help button :-)34943495if is_modal & (len(buttons) == 0):3496# standartbuttons=[]3497# print 'add_buttons modal buttons',buttons3498btnsizer = wx.StdDialogButtonSizer()3499# standartbuttons=[]3500#helpbutton = wx.ContextHelpButton(self.parent)3501#helpbutton.SetHelpText(' Click to put application\n into context sensitive help mode.')3502#btnsizer.AddButton(helpbutton )35033504else:3505if defaultbutton == '':3506defaultbutton = 'Apply'3507# print 'add_buttons ',allbuttons3508btnsizer = wx.BoxSizer(wx.HORIZONTAL)35093510# add help button35113512# print ' allbuttons',allbuttons3513# create button widgets3514for (name, function, info) in allbuttons:35153516b = wx.Button(parent, -1, name, (2, 2))3517self.Bind(wx.EVT_BUTTON, function, b)3518b.SetHelpText(info)3519if defaultbutton == name:3520b.SetDefault()3521if is_modal & (len(buttons) == 0):3522# print ' create button modal',name,is_modal3523btnsizer.AddButton(b)3524else:3525# print ' create button',name,is_modal3526btnsizer.Add(b)35273528if is_modal & (len(buttons) == 0):3529# print ' Add OK and CANCEL'3530# add OK and CANCEL if panel appears in separate window3531b = wx.Button(parent, wx.ID_OK)3532b.SetHelpText('Apply values and close window')3533#self.Bind(wx.EVT_BUTTON, self.on_ok_modal, b)3534if defaultbutton == '':3535# set apply button default if there is no other default3536b.SetDefault()3537btnsizer.AddButton(b)3538# print 'Add OK',b35393540# add cancel3541b = wx.Button(parent, wx.ID_CANCEL)3542b.SetHelpText('Ignore modifications and close window')3543btnsizer.AddButton(b)3544# print 'Add cancel',b35453546btnsizer.Realize()3547# else:3548# btnsizer.Realize()3549# if wx.Platform != "__WXMSW__":3550# btn = wx.ContextHelpButton(self)3551# btnsizer.AddButton(btn)35523553# btnsizer.Realize()35543555#b = csel.ColourSelect(self.parent, -1, 'test', (255,0,0), size = wx.DefaultSize)3556# sizer.Add(b)3557# add buttomrow to main3558#sizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL|wx.ALL, 5)35593560#widget=wx.StaticText(self.parent, -1,'That is it!!')3561# sizer.Add(widget)35623563# TEST3564#btnsizer = wx.StdDialogButtonSizer()35653566# if wx.Platform != "__WXMSW__":3567# btn = wx.ContextHelpButton(self)3568# btnsizer.AddButton(btn)35693570## btn = wx.Button(self, wx.ID_OK)3571## btn.SetHelpText("The OK button completes the dialog")3572# btn.SetDefault()3573# btnsizer.AddButton(btn)3574##3575## btn = wx.Button(self, wx.ID_CANCEL)3576## btn.SetHelpText("The Cancel button cnacels the dialog. (Cool, huh?)")3577# btnsizer.AddButton(btn)3578# btnsizer.Realize()3579###35803581sizer.Add(btnsizer, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)35823583def add_hline(self, sizer, hspace=5):3584"""3585Add a horizontal line to sizer3586"""3587line = wx.StaticLine(self, -1, size=(20, -1), style=wx.LI_HORIZONTAL)3588sizer.Add(line, 0, wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.RIGHT | wx.CENTER, hspace)35893590def add_title(self, sizer, title=None, id=None, fontsize=12):3591"""3592Add a title to the option panel.3593If no title is given, the titel will be derived from the object name3594and id if given.3595"""3596# print 'add_title',self.obj.get_name()3597if title is None:3598fontsize = 143599if id is None:3600title = self.obj.get_name().title()3601else:3602title = self.obj.get_name().title()+' ['+str(id)+']'36033604#p=wx.Panel( self, wx.NewId(), wx.DefaultPosition,style=wx.SUNKEN_BORDER)3605titlewidget = wx.StaticText(self, wx.NewId(), title)3606font = wx.Font(fontsize, wx.SWISS, wx.NORMAL, wx.NORMAL)3607titlewidget.SetFont(font)3608# sizer.Add((5,5))3609# sizer.Add((5,5))3610# self.add_hline(sizer)3611# sizer.Add((20,20))3612sizer.Add(titlewidget, 0, wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL, 10)3613# sizer.Add((10,10))3614self.add_hline(sizer, 15)36153616def add_group(self, sizer, groupname):3617"""3618Add a group to the option panel.36193620This method does diaplay the entire group in a group3621widget.3622"""3623pass36243625def on_apply(self, event):3626"""3627Apply widget contents to object3628"""3629self.apply()36303631def on_restore(self, event):3632"""3633Copy object values to widget contents3634"""3635self.restore()36363637# def on_ok_modal(self,event):3638# """ NO! valueas are rtead out from calling function3639# Apply values, and continues withy modal windoe event handling3640# """3641# self.apply()3642# event.Skip()36433644def on_ok(self, event):3645"""3646Apply values, destroy itself and parent3647"""3648# print 'on_ok...'36493650# check if we must execute some callbacks if ids or attributes3651# have been selected3652# for widget in self.datawidgets:3653# if hasattr(widget,'on_ok')3654# else:3655self.apply()36563657self.Close()3658# self.parent.Destroy()3659# self.Destroy()36603661def on_cancel(self, event):3662"""3663Destroy itself and parent3664"""3665# print 'OP.on_cancel'3666self.Close()36673668def apply(self):3669"""3670Widget values are copied to object3671"""3672# print 'apply',self.obj.ident,self.datawidgets,self.func_apply3673for widget in self.datawidgets:3674# print ' widget',widget3675widget.apply()3676widget.restore()36773678if self.func_apply is not None:3679# print ' call self.func_choose_id',self.obj, self.id, self.ids3680#3681#wx.FutureCall(1,self.func_apply, self.obj, self.id, self.ids)3682wx.CallAfter(self.func_apply, self.obj, self.id, self.ids)3683# event.Skip()3684return36853686def restore(self):3687"""3688Object values are copied into widgets.3689"""3690for widget in self.datawidgets:3691widget.restore()36923693# def OnSetFocus(self, evt):3694# print "OnSetFocus"3695# evt.Skip()3696# def OnKillFocus(self, evt):3697# print "OnKillFocus"3698# evt.Skip()3699# def OnWindowDestroy(self, evt):3700# print "OnWindowDestroy"3701# evt.Skip()370237033704class ObjPanelDialog(ObjPanelMixin, wx.Dialog):3705def __init__(self, parent,3706obj, id=None, ids=None,3707attrconfigs=None,3708#tables = None,3709table=None,3710groupnames=None, show_groupnames=False,3711title='', size=wx.DefaultSize, pos=wx.DefaultPosition,\3712style=wx.DEFAULT_DIALOG_STYLE | wx.MAXIMIZE_BOX | wx.RESIZE_BORDER,3713choose_id=False, choose_attr=False,3714func_choose_id=None, func_change_obj=None, func_apply=None,3715panelstyle='default',3716immediate_apply=False,3717**buttonargs):37183719# print 'ObjPanelDialog.__init__',choose_id,choose_attr,table37203721# print ' buttonargs,groupnames',buttonargs,groupnames3722# print ' size=',size3723# Instead of calling wx.Dialog.__init__ we precreate the dialog3724# so we can set an extra style that must be set before3725# creation, and then we create the GUI dialog using the Create3726# method.3727pre = wx.PreDialog()3728pre.SetExtraStyle(wx.DIALOG_EX_CONTEXTHELP)37293730if title == '':3731title = 'Dialog for: '+obj.get_name()3732pre.Create(parent, -1, title, pos, size=size, style=style)37333734# This next step is the most important, it turns this Python3735# object into the real wrapper of the dialog (instead of pre)3736# as far as the wxPython extension is concerned.3737self.PostCreate(pre)3738self.init_panel(parent)37393740if choose_id:3741self.recreate_panel(obj,3742id=id, ids=ids,3743attrconfigs=attrconfigs,3744#tables = tables,3745#table =table,3746groupnames=groupnames, show_groupnames=show_groupnames,3747show_title=False, is_modal=True,3748immediate_apply=immediate_apply,3749panelstyle=panelstyle,3750func_choose_id=self.on_choose_id, func_apply=func_apply,3751func_change_obj=func_change_obj,3752**buttonargs3753)37543755elif choose_attr:3756self.recreate_panel(obj, id=id, ids=ids,3757attrconfigs=attrconfigs,3758#tables = tables,3759#table =table,3760groupnames=groupnames, show_groupnames=show_groupnames,3761show_title=False, is_modal=True,3762immediate_apply=immediate_apply,3763panelstyle=panelstyle,3764func_choose_attr=self.on_choose_attr, func_apply=func_apply,3765func_change_obj=func_change_obj,3766**buttonargs3767)37683769else:3770# print ' normal mode without special callbacks',self.recreate_panel3771self.recreate_panel(obj, id=id, ids=ids,3772attrconfigs=attrconfigs,3773#tables = tables,3774#table =table,3775groupnames=groupnames, show_groupnames=show_groupnames,3776show_title=False, is_modal=True,3777immediate_apply=immediate_apply,3778panelstyle=panelstyle,3779func_choose_id=func_choose_id,3780func_change_obj=func_change_obj, func_apply=func_apply,3781**buttonargs3782)37833784self.id_chosen = -13785self.attrconf_chosen = None37863787# self.recreate_panel(attrconfigs=attrconfigs,groups=groups,is_modal=True,3788# immediate_apply=immediate_apply, panelstyle=panelstyle)37893790# self.SetSize(self.GetSize())3791# self.SetSize(wx.DefaultSize)3792# self.SetSize(size)3793self.SetAutoLayout(1)3794self.Refresh()37953796def on_choose_id(self, id, attrconf=None):3797self.id_chosen = id3798self.attrconf_chosen = attrconf3799self.EndModal(wx.ID_OK)38003801def get_current_attrconf_id(self):3802"""3803Returns selected or current attribute and id3804"""3805# print 'get_current_attrconf_id',self.attrconf_chosen,self.id_chosen3806if (self.id_chosen == -1) & (self.attrconf_chosen == ''):3807# on_choose_id has not yet determined id3808# do though datawidgets and3809for widget in self.datawidgets:3810# print ' widget',widget3811if hasattr(widget, 'get_current_attrconf_id'):3812return widget.get_current_attrconf_id()38133814return self.attrconf_chosen, self.id_chosen38153816else:3817return self.attrconf_chosen, self.id_chosen38183819# def get_valueconf_chosen(self):3820# return self.attrconf_chosen38213822# class ObjPanel(ObjPanelMixin,wxlib.scrolledpanel.ScrolledPanel):382338243825class ObjPanel(ObjPanelMixin, wx.Panel):3826"""3827Interactively displays attributes of object on a panel.3828"""38293830def __init__(self, parent, obj=None,3831id=None, ids=None,3832attrconfigs=None,3833#tables = None,3834#table = None,3835groupnames=None,3836func_change_obj=None, func_apply=None,3837show_groupnames=False, show_title=True, is_modal=False,3838mainframe=None,3839pos=wx.DefaultPosition, size=wx.DefaultSize, style=wx.MAXIMIZE_BOX | wx.RESIZE_BORDER,3840immediate_apply=False, panelstyle='default', **buttonargs):38413842wx.Panel.__init__(self, parent, -1, pos, size, wx.SUNKEN_BORDER | wx.WANTS_CHARS)3843if obj is None:3844obj = cm.BaseObjman('empty')3845#wxlib.scrolledpanel.ScrolledPanel.__init__(self, parent,wx.ID_ANY,size=size)3846#self.maxWidth = 1003847#self.maxHeight = 1003848# self.SetVirtualSize((300,-1))3849# self.SetScrollRate(20,20)38503851self.init_panel(parent, mainframe=mainframe)3852# (re)create panel widgets3853# print 'ObjPanel.__init__',obj.ident,id,func_apply,groupnames3854self.recreate_panel(obj, id=id, ids=ids,3855attrconfigs=attrconfigs,3856groupnames=groupnames, show_groupnames=show_groupnames,3857show_title=show_title, is_modal=is_modal,3858immediate_apply=immediate_apply,3859panelstyle=panelstyle,3860func_change_obj=func_change_obj,3861func_apply=func_apply,3862**buttonargs)38633864# optionpanel.GetSize()38653866# self.SetAutoLayout(1)386738683869class TablePanel(ObjPanelMixin, wx.Panel):3870"""3871Common methods for panels3872"""38733874def __init__(self, parent, table,3875attrconfigs=None,3876id=None, ids=None,3877groupnames=None,3878func_change_obj=None, func_apply=None,3879show_groupnames=False, show_title=True, is_modal=False,3880mainframe=None, pos=wx.DefaultPosition, size=wx.DefaultSize,3881immediate_apply=False, panelstyle='default', **buttonargs):38823883wx.Panel.__init__(self, parent, -1, pos, size, wx.SUNKEN_BORDER)38843885self.init_panel(parent, mainframe=mainframe)3886# (re)create panel widgets3887# print 'TablePanel. __init__',table.get_name()3888self.recreate_panel(table,3889attrconfigs=attrconfigs,3890# ids=ids,3891groupnames=groupnames, show_groupnames=show_groupnames,3892show_title=show_title, is_modal=is_modal,3893immediate_apply=immediate_apply, func_apply=func_apply,3894panelstyle=panelstyle,3895func_change_obj=func_change_obj,3896**buttonargs)38973898# optionpanel.GetSize()38993900self.SetAutoLayout(1)39013902def recreate_panel(self, obj, # obj is table3903attrconfigs=None,3904# ids=None,3905groupnames=None, show_groupnames=False,3906show_title=True,3907is_modal=False,3908immediate_apply=False,3909panelstyle='default',3910func_change_obj=None,3911func_choose_id=None,3912func_choose_attr=None,3913func_apply=None,3914**buttonargs):3915"""3916Recreates panel and destroys previous contents:3917attr = a list ith attribute names to be shown3918groups = list with group names to be shown3919show_groupnames = the group names are shown3920together with the respective attributes3921is_modal = if true the panel will be optimized for dialog window3922immediate_apply = changes to widgets will be immediately applied to3923obj attribute without pressing apply3924buttonargs = a dictionary with arguments for botton creation3925obj = the object to be displayed3926id = used if there is only one single id to be displayed3927ids = used if a selection of ids need to be displayed3928func_change_obj = function to be called if user clicks on on object3929with obj as argument3930func_choose_id = function to be called when user clicks on id(table row)3931with id as argument3932func_choose_attr = function to be called when user clicks on attribute3933with attr as argument. In this case the attribute3934names of scalars turn into buttons. Array attributes3935are selected by clicking on the column name.3936"""3937#self.id = id3938#self.ids = ids3939self.obj = obj3940self.func_change_obj = func_change_obj3941self.func_choose_id = func_choose_id3942self.func_choose_attr = func_choose_attr3943self.func_apply = func_apply39443945# print '\n\nrecreate_panel name for id,ids=',obj.get_name(),ids3946# print ' attrs,groups=',attrs,groups3947# print ' immediate_apply',immediate_apply3948# this will be looked up by widgets to decide how to react to an input3949#self.immediate_apply = immediate_apply39503951# remove previous contents3952# ids_widgetcontainers=self.get_ids()3953# self.parent.DestroyChildren()3954#del self[ids_widgetcontainers]39553956# create vertical main sizer3957sizer = wx.BoxSizer(wx.VERTICAL)3958if show_title:3959self.add_title(sizer)39603961# show table with one or several ids3962self.add_table(sizer, obj, attrconfigs=attrconfigs,3963ids=ids, groupnames=groupnames, show_title=False)39643965self.SetSizer(sizer)3966sizer.Fit(self)39673968# some widgets like color need this to expand into their maximum space3969self.restore()397039713972class NaviPanelMixin:3973def add_hist(self, obj, id=None, ids=None, kwargs={}):3974"""3975Add a new obj to history list.3976The forward history will be eliminated.3977"""3978# print 'add_hist',self.hist,self.ind_hist39793980n_hist = len(self.hist)3981if n_hist == 0:3982# first entry3983self.ind_hist = 039843985else:3986self.hist = self.hist[:self.ind_hist+1]3987# print ' hist[:self.ind_hist+1]',self.hist[:self.ind_hist+1]39883989self.hist.append((obj, id, ids, kwargs))3990self.ind_hist = len(self.hist)-13991# print ' hist,self.ind_hist',self.hist,self.ind_hist39923993def get_hist(self, ind_delta=-1):3994"""3995Getting hist with changing pointer3996"""3997ind = self.ind_hist + ind_delta3998# 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)39994000if (ind < len(self.hist)) & (ind >= 0):4001self.ind_hist = ind4002# print ' OK self.ind_hist',self.ind_hist,self.hist[ind]4003return self.hist[ind]4004else:4005# print ' Fail self.ind_hist',self.ind_hist4006return None, None, None, None40074008def get_history(self, ind_delta=-1):4009"""4010Getting hist without changing pointer4011"""4012ind = self.ind_hist + ind_delta4013# print 'get_history',self.ind_hist,ind_delta,(ind < len(self.hist)) & (ind >= 0)40144015if (ind < len(self.hist)) & (ind >= 0):4016# self.ind_hist=ind4017return self.hist[ind]4018else:4019return None, None, None, None40204021def on_change_obj(self, event):4022# print 'Navicanvas.on_change_obj'4023obj = event.GetObj()4024self.refresh_panel(obj)4025event.Skip()40264027def change_obj(self, obj, id=None, ids=None, **kwargs):40284029if len(kwargs) == 0:4030# this is to recover kw arguments i.e. callbacks4031obj_last, id_last, ids_last, kwargs_last = self.get_history(0)4032if kwargs_last is not None:4033kwargs = kwargs_last40344035if self.func_apply is not None:4036kwargs['func_apply'] = self.func_apply40374038# print 'Navipanel.change_obj',obj.format_ident(),id,ids,kwargs.keys()40394040if hasattr(obj, 'get_ident'):4041self.refresh_panel(obj, id=id, ids=ids, **kwargs)4042self.add_hist(obj, id, ids, kwargs)40434044def get_obj(self):4045"""4046Returns currently displayed object4047"""4048return self.objpanel.obj40494050def refresh_panel(self, obj=None, id=None, ids=None, **kwargs):4051"""4052Deletes previous conents4053Builds panel for obj4054Updates path window and history4055"""40564057if obj is None:4058if self.get_obj() == self._defaultobj:4059return None # no changes4060else:4061obj = self._defaultobj40624063# print 'Navicanvas.refresh_panel with',obj.ident,kwargs40644065if id is not None:4066self.path.SetValue(obj.format_ident_row_abs(id))40674068elif ids is not None:4069# no id provided, just show identification string4070self.path.SetValue(obj.format_ident_abs())40714072else: # object and id provided: compose string with id4073self.path.SetValue(obj.format_ident_abs())40744075# self.path.SetSize((len(self.path.GetValue())*10,-1))4076# self.path.SetSize((-1,-1))4077# remove previous obj panel4078sizer = self.GetSizer()4079sizer.Remove(1)4080self.objpanel.Destroy()4081#del self.objpanel40824083# build new obj panel4084# self.objpanel=ObjPanel(self,obj,id=id,attrs=self.attrs,groups=self.groups,4085# func_change_obj=self.change_obj,4086# is_modal=self.is_modal,4087# mainframe=self.mainframe,4088# immediate_apply=self.immediate_apply,4089# **self.buttonargs)4090attrconfigs = obj.get_attrsman().get_configs()4091# for attrconfig in obj.get_configs()#attrconfigs:4092# if '_private' not in attrconfig.groups:4093# attrconfigs.append(attrconfig)40944095args = {'attrconfigs': attrconfigs,4096# 'tables' : None,4097# 'table' : None,4098'id': id, 'ids': ids,4099'groupnames': self.groupnames,4100'func_change_obj': self.change_obj,4101'show_groupnames': False, 'show_title': True, 'is_modal': self.is_modal,4102'mainframe': self.mainframe, 'pos': wx.DefaultPosition, 'size': wx.DefaultSize,4103'immediate_apply': self.immediate_apply, 'panelstyle': 'default'4104}41054106args.update(self.buttonargs)4107args.update(kwargs)41084109# print ' make ObjPanel\n args =',args41104111self.objpanel = ObjPanel(self, obj=obj, **args)4112# if id is not None:4113# self.objpanel=ObjPanel(self,obj,id=id,func_change_obj=self.change_obj)4114# else:4115# self.objpanel=ObjPanel(self,obj,func_change_obj=self.change_obj)4116sizer.Add(self.objpanel, 1, wx.GROW)41174118self.Refresh()4119# sizer.Fit(self)4120sizer.Layout()4121# add to history4122return None41234124def on_change_path(self, event):4125"""4126Key stroke on path field. Change object when return is pressed.4127"""4128keycode = event.GetKeyCode()4129if keycode == wx.WXK_RETURN:4130# print 'change path to',self.path.GetValue()4131# self.refresh_panel(obj)4132pass4133else:4134event.Skip()41354136# def recreate_panel(self,obj):4137# """4138# Removes previous contents and displays attributes on panel.4139# """4140# pass41414142def on_go_back(self, event):4143# print 'on_go_back'4144# print ' hist=',self.hist4145obj, id, ids, kwargs = self.get_hist(-1)4146# if obj is not None:4147# print ' done: obj, hist, ind_hist',obj.ident,self.hist,self.ind_hist4148# else:4149# print ' failed: hist, ind_hist',self.hist,self.ind_hist41504151if obj is not None:4152# print ' refresh_panel with',obj.ident4153self.refresh_panel(obj, id, ids, **kwargs)4154event.Skip()41554156def on_go_forward(self, event):4157obj, id, ids, kwargs = self.get_hist(+1)4158# print 'on_go_forward to obj',obj41594160# if obj is not None:4161# print ' Done:obj.ident,self.hist,self.ind_hist',obj.ident,self.hist,self.ind_hist4162# else:4163# print ' Failed:self.hist,self.ind_hist',self.hist,self.ind_hist41644165if obj is not None:4166# print ' refresh_panel with',obj.ident4167self.refresh_panel(obj, id, ids, **kwargs)4168event.Skip()41694170def on_go_up(self, event):41714172obj = self.objpanel.get_obj()4173_id = self.objpanel.get_id()41744175# this is to recover kw arguments i.e. callbacks4176obj_last, id_last, ids_last, kwargs_last = self.get_history(0)4177if kwargs_last is not None:4178kwargs = kwargs_last4179else:4180kwargs = {}41814182parent = obj.get_parent()4183# print 'on_go_up',obj,id,parent4184if _id is None:4185# show parent object4186if type(parent) == types.InstanceType:4187if hasattr(parent, 'ident'):4188self.refresh_panel(parent, None, None, **kwargs)4189self.add_hist(parent, None, None, kwargs)4190else:4191# show table object if table row id has been previously4192self.refresh_panel(obj, None, None, **kwargs)4193self.add_hist(obj, None, None, kwargs)41944195event.Skip()41964197def on_go_home(self, event):4198obj = self.objpanel.get_obj()4199root = obj.get_root()4200if type(root) == types.InstanceType:4201if hasattr(root, 'ident'):4202self.refresh_panel(root)4203event.Skip()4204# print 'on_go_home'42054206def on_enter_window(self, evt):4207# print 'on_enter_window'4208self.SetFocus()42094210def init_navbar(self, obj, _id=None):4211"""4212Initialize toolbar which consist of navigation buttons4213"""4214bottonsize = (32, 32)4215bottonborder = 104216toolbarborder = 142174218# toolbar4219self.toolbar = wx.BoxSizer(wx.HORIZONTAL)42204221# self.init_toolbar()4222#bottons = []4223bitmap = wx.ArtProvider_GetBitmap(wx.ART_GO_BACK, wx.ART_TOOLBAR)4224b = wx.BitmapButton(self, -1, bitmap, bottonsize,4225(bitmap.GetWidth()+bottonborder, bitmap.GetHeight()+bottonborder))4226b.SetToolTipString("Go back in browser history.")4227self.Bind(wx.EVT_BUTTON, self.on_go_back, b)4228self.toolbar.Add(b, flag=wx.ALL, border=toolbarborder)4229# bottons.append(b)4230#self.toolbar.Add(b, flag=wx.ALL, border=toolbarborder)42314232bitmap = wx.ArtProvider_GetBitmap(wx.ART_GO_FORWARD, wx.ART_TOOLBAR)4233b = wx.BitmapButton(self, -1, bitmap, bottonsize,4234(bitmap.GetWidth()+bottonborder, bitmap.GetHeight()+bottonborder))4235b.SetToolTipString("Go forward in browser history.")4236self.Bind(wx.EVT_BUTTON, self.on_go_forward, b)4237self.toolbar.Add(b, 0, wx.EXPAND, border=toolbarborder)4238# bottons.append(b)42394240bitmap = wx.ArtProvider_GetBitmap(wx.ART_GO_UP, wx.ART_TOOLBAR)4241b = wx.BitmapButton(self, -1, bitmap, bottonsize,4242(bitmap.GetWidth()+bottonborder, bitmap.GetHeight()+bottonborder))4243b.SetToolTipString("Go up to parent object.")4244self.Bind(wx.EVT_BUTTON, self.on_go_up, b)4245self.toolbar.Add(b, 0, wx.EXPAND, border=toolbarborder)42464247# self.add_tool(4248# 'up',self.on_go_up,4249# wx.ArtProvider.GetBitmap(wx.ART_GO_UP, wx.ART_TOOLBAR, tsize),4250# 'show panel of parent instance')42514252bitmap = wx.ArtProvider_GetBitmap(wx.ART_GO_HOME, wx.ART_TOOLBAR)4253b = wx.BitmapButton(self, -1, bitmap, bottonsize,4254(bitmap.GetWidth()+bottonborder, bitmap.GetHeight()+bottonborder))4255b.SetToolTipString("Go to main object, the mother of all objects.")4256self.Bind(wx.EVT_BUTTON, self.on_go_home, b)4257self.toolbar.Add(b, 0, wx.EXPAND, border=toolbarborder)42584259# self.add_tool(4260# 'home',self.on_go_home,4261# wx.ArtProvider.GetBitmap(wx.ART_GO_HOME, wx.ART_TOOLBAR, tsize),4262# 'show panel of root instance')42634264# size=(-1, -1))#,size=(300, -1))4265self.path = wx.TextCtrl(self, -1, self.get_ident_abs(obj, _id), style=wx.TE_RIGHT)4266#self.path=wx.TextCtrl(self.toolbar, -1, obj.format_ident_abs(), style=wx.TE_RIGHT)4267# wx.EVT_ENTER_WINDOW(self.path,self.on_enter_window)4268# self.add_tool('path',widget=self.path)4269self.path.Bind(wx.EVT_CHAR, self.on_change_path)4270#self.toolbar.Add(self.path, flag=wx.ALL, border=toolbarborder)4271self.toolbar.Add(self.path, 1, wx.EXPAND, border=toolbarborder)4272#self.toolbar.AddControl(wx.TextCtrl(self.toolbar, -1, "Toolbar controls!!", size=(150, -1)))42734274# self.toolbar.AddSeparator()4275bitmap = wx.Bitmap(os.path.join(IMAGEDIR, 'fig_menu_icon.png'), wx.BITMAP_TYPE_PNG)4276b = wx.BitmapButton(self, -1, bitmap, bottonsize,4277(bitmap.GetWidth()+bottonborder, bitmap.GetHeight()+bottonborder))4278b.SetToolTipString("Object browser menu. Click for actions on this object")4279#b = wx.Button(self, label="Show/Hide")4280self.Bind(wx.EVT_BUTTON, self.popup_menu, b)4281self.toolbar.Add(b)42824283# panel.SetAutoLayout(True)4284# panel.SetSizer(buttons)42854286self.toolbar.Fit(self)42874288# only for frames4289# self.SetToolBar(self.toolbar)42904291def popup_menu(self, event):4292#btn = event.GetEventObject()4293#drawing = self._canvas.get_drawing()42944295# Create the popup menu4296self._popupmenu = AgilePopupMenu(self)4297self._popupmenu.append_item(4298'Export to CSV...',4299self.on_export_csv,4300info='Export current object in CSV format.',4301#check= drawobj.is_visible(),4302)43034304if ex.IS_EXCEL:4305self._popupmenu.append_item(4306'Export to Excel...',4307self.on_export_excel,4308info='Export current object in EXCEL format.',4309#check= drawobj.is_visible(),4310)43114312self.PopupMenu(self._popupmenu)4313self._popupmenu.Destroy()4314event.Skip()43154316def on_export_excel(self, event):4317print 'on_export_excel'4318obj = self.objpanel.get_obj()43194320#dirpath = self.get_scenario().get_workdirpath()4321#defaultFile = self.get_scenario().get_rootfilename()+'.rou.xml'4322wildcards_all = 'Excel files (*.xls)|*.xls|All files (*.*)|*.*'4323dlg = wx.FileDialog(None, message='Export object to Excel file',4324# defaultDir=dirpath,4325# defaultFile=defaultFile,4326wildcard=wildcards_all, style=wx.SAVE | wx.CHANGE_DIR)4327if dlg.ShowModal() == wx.ID_OK:4328filepath = dlg.GetPath()4329ex.export_excel(filepath, obj, ids=None, attrconfigs=None, groupnames=None,4330is_header=True, is_ident=False, is_timestamp=True,4331show_parentesis=True, name_id='ID', is_export_not_save=True)4332else:4333return43344335def on_export_csv(self, event):4336print 'on_export_csv'4337obj = self.objpanel.get_obj()43384339#dirpath = self.get_scenario().get_workdirpath()4340#defaultFile = self.get_scenario().get_rootfilename()+'.rou.xml'4341wildcards_all = 'CSV files (*.csv)|*.csv|Text files (*.txt)|*.txt|All files (*.*)|*.*'4342dlg = wx.FileDialog(None, message='Export object to CSV file',4343# defaultDir=dirpath,4344# defaultFile=defaultFile,4345wildcard=wildcards_all, style=wx.SAVE | wx.CHANGE_DIR)4346if dlg.ShowModal() == wx.ID_OK:4347filepath = dlg.GetPath()4348obj.export_csv(filepath, sep=',',4349attrconfigs=None, groupnames=None,4350is_header=True, is_ident=False, is_timestamp=True,4351show_parentesis=True)4352else:4353return43544355def get_ident_abs(self, obj, _id):4356if _id is not None:4357return obj.format_ident_row_abs(_id)43584359else:4360return obj.format_ident_abs()43614362def init_objpanel(self, obj, id=None, ids=None, attrconfigs=None, groupnames=None,4363is_modal=True, mainframe=None, func_apply=None,4364immediate_apply=False, panelstyle='default', **buttonargs):4365"""4366Initializes object panel, bu also stores parameters such as4367mode, groups etc4368"""4369self.attrconfigs = attrconfigs4370self.groupnames = groupnames4371self.is_modal = is_modal4372self.mainframe = mainframe4373self.immediate_apply = immediate_apply4374self.panelstyle = panelstyle4375self.buttonargs = buttonargs4376# self.objpanel=ObjPanel(self,obj,id=id,ids=ids,attrs=attrs,groups=groups,4377# func_change_obj=self.change_obj,4378# is_modal=is_modal,4379# mainframe=mainframe,4380# immediate_apply=immediate_apply, panelstyle=panelstyle,4381# **buttonargs)4382self.objpanel = ObjPanel(self, obj=obj,4383attrconfigs=self.attrconfigs,4384#tables = None,4385#table = None,4386id=id, ids=ids,4387groupnames=groupnames,4388func_change_obj=self.change_obj,4389show_groupnames=False, show_title=True, is_modal=self.is_modal,4390mainframe=self.mainframe, pos=wx.DefaultPosition, size=wx.DefaultSize,4391func_apply=func_apply,4392immediate_apply=self.immediate_apply, panelstyle='default',4393**self.buttonargs)43944395def init_hist(self):4396"""4397Initialize history variables4398"""4399self.hist = []4400self.ind_hist = -1440144024403class NaviPanel(NaviPanelMixin, wx.Panel):4404"""44054406Interactively navigates through objects and displays attributes4407on a panel.4408"""44094410def __init__(self, parent, obj, id=None, mainframe=None, func_apply=None, **args):4411if obj is None:4412obj = cm.BaseObjman('empty')4413wx.Panel.__init__(self, parent, -1, wx.DefaultPosition, wx.DefaultSize)4414# print 'NaviPanel',obj.ident,id,func_apply,args4415sizer = wx.BoxSizer(wx.VERTICAL)4416# define a default object which is shown when4417# refresh is called without arguments4418self._defaultobj = obj4419self.func_apply = func_apply4420# initialize history4421self.init_hist()44224423# make navigation toolbar4424self.init_navbar(obj, id)44254426# create initial panel4427self.init_objpanel(obj, id=id, mainframe=mainframe, is_modal=False, func_apply=func_apply, **args)44284429sizer.Add(self.toolbar, 0, wx.ALL | wx.ALIGN_LEFT | wx.GROW, 4) # from NaviPanelTest4430sizer.Add(self.objpanel, 1, wx.GROW) # from NaviPanelTest44314432# finish panel setup4433self.SetSizer(sizer)4434sizer.Fit(self)4435# add to history4436# self.add_hist(obj,id,None,args)4437# self.SetSize(parent.GetSize())443844394440class ObjBrowserMainframe(wx.Frame):44414442"""4443A frame used for the ObjBrowser Demo44444445"""44464447def __init__(self, parent, wxid, title, position, size, obj=None, _id=None, table=None):4448wx.Frame.__init__(self, parent, wxid, title, position, size)4449# print 'ObjBrowserMainframe',obj.ident,_id4450# Set up the MenuBar4451MenuBar = wx.MenuBar()44524453file_menu = wx.Menu()4454item = file_menu.Append(-1, "&Open...", "Open an object from file.")4455self.Bind(wx.EVT_MENU, self.OnLoad, item)4456item = file_menu.Append(-1, "&Save as", "Save an object under file.")4457self.Bind(wx.EVT_MENU, self.OnSave, item)4458item = file_menu.Append(-1, "&Close", "Close this frame")4459self.Bind(wx.EVT_MENU, self.OnQuit, item)44604461MenuBar.Append(file_menu, "&File")44624463help_menu = wx.Menu()4464item = help_menu.Append(-1, "&About",4465"More information About this program")4466self.Bind(wx.EVT_MENU, self.OnAbout, item)4467MenuBar.Append(help_menu, "&Help")44684469self.SetMenuBar(MenuBar)44704471self.CreateStatusBar()44724473# Create Browser widget here4474#browser = wx.Panel(self, -1, wx.DefaultPosition, size = wx.DefaultSize)4475#browser = ObjPanel(self,obj, id=10)4476if obj is not None:4477# print ' init ObjPanel'4478#self.browser = ObjPanel(self, obj)4479self.browser = NaviPanel(self, obj, _id)4480elif table is not None:4481# print ' init TablePanel'4482self.browser = TablePanel(self, table)4483else:4484obj = cm.BaseObjman('empty')4485self.browser = NaviPanel(self, obj, _id)4486#browser = TablePanel(self,obj)4487# self.MsgWindow = wx.TextCtrl(self, wx.ID_ANY,4488# "Look Here for output from events\n",4489# style = (wx.TE_MULTILINE |4490# wx.TE_READONLY |4491# wx.SUNKEN_BORDER)4492# )44934494# TODO:INTERESTING:4495# wxTextCtrl *control = new wxTextCtrl(...);4496# wxStreamToTextRedirector redirect(control);4497# // all output to cout goes into the text control until the exit from4498# // current scope44994500#self.MsgWindow = py.crust.Crust(self, intro='Check it out!')4501self.MsgWindow = py.shell.Shell(self)4502# Create a sizer to manage the Canvas and message window4503MainSizer = wx.BoxSizer(wx.VERTICAL)4504MainSizer.Add(self.browser, 4, wx.EXPAND)4505MainSizer.Add(self.MsgWindow, 1, wx.EXPAND | wx.ALL, 5)45064507self.SetSizer(MainSizer)4508self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)45094510self.EventsAreBound = False45114512# getting all the colors for random objects4513wxlib.colourdb.updateColourDB()4514self.colors = wxlib.colourdb.getColourList()45154516self.__init_specific()45174518return None45194520def __init_specific(self):4521pass45224523def OnAbout(self, event):4524dlg = wx.MessageDialog(self,4525"This is a small program to demonstrate\n"4526"the use of the Objbrowser\n",4527"About Me",4528wx.OK | wx.ICON_INFORMATION)4529dlg.ShowModal()4530dlg.Destroy()45314532def OnLoad(self, event):45334534dlg = wx.FileDialog(self, message="Open object",4535defaultDir=os.getcwd(),4536# defaultFile="",4537wildcard=wildcards_all,4538style=wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR4539)45404541# Show the dialog and retrieve the user response. If it is the OK response,4542# process the data.4543if dlg.ShowModal() == wx.ID_OK:4544# This returns a Python list of files that were selected.4545paths = dlg.GetPaths()4546# print 'You selected %d files:' % len(paths)4547if len(paths) > 0:4548filepath = paths[0]4549obj = cm.load_obj(filepath)45504551MainSizer = self.GetSizer()4552MainSizer.Remove(0)4553MainSizer.Remove(1)45544555self.browser.Destroy()4556self.MsgWindow.Destroy()45574558# build new obj panel4559self.browser = ObjPanel(self, obj)4560# sizer.Add(self.objpanel,0,wx.GROW)45614562#self.browser = wx.Panel(self, -1)4563#button = wx.Button(self.browser, 1003, "Close Me")4564#button.SetPosition((15, 15))45654566# sizer.Add(panel,1,wx.GROW)45674568self.MsgWindow = py.shell.Shell(self)4569# Create a sizer to manage the Canvas and message window4570MainSizer.Add(self.browser, 4, wx.EXPAND)4571MainSizer.Add(self.MsgWindow, 1, wx.EXPAND | wx.ALL, 5)45724573self.Refresh()4574MainSizer.Layout()45754576def OnSave(self, event):4577dlg = wx.FileDialog(4578self, message="Save file as ...", defaultDir=os.getcwd(),4579# defaultFile="",4580wildcard=wildcards_all, style=wx.SAVE4581)45824583# This sets the default filter that the user will initially see. Otherwise,4584# the first filter in the list will be used by default.4585dlg.SetFilterIndex(0)45864587# Show the dialog and retrieve the user response. If it is the OK response,4588# process the data.4589if dlg.ShowModal() == wx.ID_OK:4590filepath = dlg.GetPath()4591cm.save_obj(self.browser.get_obj(), filepath)45924593def OnQuit(self, event):4594self.Close(True)45954596def OnCloseWindow(self, event):4597self.Destroy()459845994600class ObjBrowserApp(wx.App):4601"""46024603"""46044605def __init__(self, obj, _id=None, output=False, logger=None, **kwargs):4606if obj is None:4607obj = cm.BaseObjman('empty')4608self._obj = obj4609self._id = _id4610# print 'ObjBrowserApp.__init__',obj.ident, _id4611self._logger = logger4612wx.App.__init__(self, output, **kwargs)46134614def OnInit(self):4615wx.InitAllImageHandlers()4616#DrawFrame = BuildDrawFrame()4617#frame = ObjBrowserMainframe(None, -1, "Object browser",wx.DefaultPosition,(700,700),obj=self._obj, _id = self._id)46184619frame = ObjBrowserMainframe(None, -1, 'Object browser', wx.DefaultPosition,4620size=wx.DefaultSize, obj=self._obj, table=None)4621#title ='Object browser',4622#appname = 'Object browser app',4623#logger = self._logger,4624#appdir = '',4625# is_maximize = False, is_centerscreen = True,4626#pos=wx.DefaultPosition, size=wx.DefaultSize,4627# style=wx.DEFAULT_FRAME_STYLE,4628#name='Object browser frame',4629#size_toolbaricons = (24,24)4630# )4631self.SetTopWindow(frame)4632frame.Show()46334634return True463546364637class TableBrowserApp(wx.App):4638"""46394640"""46414642def __init__(self, tab, **kwargs):4643self._tab = tab4644# print 'ViewerApp.__init__',self._net46454646wx.App.__init__(self, **kwargs)46474648def OnInit(self):4649wx.InitAllImageHandlers()4650#DrawFrame = BuildDrawFrame()4651frame = ObjBrowserMainframe(None, -1, "Table browser", wx.DefaultPosition, (700, 700), table=self._tab)46524653self.SetTopWindow(frame)4654frame.Show()46554656return True465746584659def objbrowser(obj, _id=None):4660app = ObjBrowserApp(obj, _id=_id, output=False) # put in True if you want output to go to its own window.4661# print 'call MainLoop'4662app.MainLoop()466346644665###############################################################################4666if __name__ == '__main__':46674668from agilepy.lib_base.test_classman_classes import *4669# no from agilepy.lib_base.classman import *4670from agilepy.lib_base.classman import load_obj, save_obj4671############4672# make up a test class4673n_test = 0 # <<<<<<<<<<<<<<<<<<4674############4675_id = None46764677if n_test == 0:4678# simple scalar parameters, no table4679obj = TestClass()4680print 'obj.ident', obj.ident46814682elif n_test == 1:4683obj = TestTableObjMan()46844685elif n_test == -1:4686obj = TestTableObjManNocols()46874688elif n_test == 2:4689obj = demand46904691elif n_test == 3:4692obj = lines46934694elif n_test == 4:4695_id = 14696obj = TestTableObjMan()4697elif n_test == 5:4698obj = drawing4699elif n_test == -5:4700save_obj(drawing, 'test_drawing.obj')4701print '\nreload'+60*'.'4702obj = load_obj('test_drawing.obj')4703obj.get_attrsman().print_attrs()47044705elif n_test == 6:4706obj = polylines4707objbrowser(obj, _id=_id)470847094710