laurent@586: # laurent@586: #Copyright (C) 2007: Edouard TISSERANT and Laurent BESSARD laurent@586: # laurent@586: #See COPYING file for copyrights details. laurent@586: # laurent@586: #This library is free software; you can redistribute it and/or laurent@586: #modify it under the terms of the GNU General Public laurent@586: #License as published by the Free Software Foundation; either laurent@586: #version 2.1 of the License, or (at your option) any later version. laurent@586: # laurent@586: #This library is distributed in the hope that it will be useful, laurent@586: #but WITHOUT ANY WARRANTY; without even the implied warranty of laurent@586: #MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU laurent@586: #General Public License for more details. laurent@586: # laurent@586: #You should have received a copy of the GNU General Public laurent@586: #License along with this library; if not, write to the Free Software laurent@586: #Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA laurent@586: laurent@586: import os laurent@586: laurent@586: import wx laurent@586: laurent@586: from plcopen.structures import LOCATIONDATATYPES Edouard@681: from PLCControler import LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP, LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY laurent@586: laurent@586: CWD = os.path.split(os.path.split(os.path.realpath(__file__))[0])[0] laurent@586: laurent@586: def GetDirChoiceOptions(): laurent@586: _ = lambda x : x laurent@586: return [(_("All"), [LOCATION_VAR_INPUT, LOCATION_VAR_OUTPUT, LOCATION_VAR_MEMORY]), laurent@586: (_("Input"), [LOCATION_VAR_INPUT]), laurent@586: (_("Output"), [LOCATION_VAR_OUTPUT]), laurent@586: (_("Memory"), [LOCATION_VAR_MEMORY])] laurent@586: DIRCHOICE_OPTIONS_FILTER = dict([(_(option), filter) for option, filter in GetDirChoiceOptions()]) laurent@586: laurent@586: # turn LOCATIONDATATYPES inside-out laurent@586: LOCATION_SIZES = {} laurent@586: for size, types in LOCATIONDATATYPES.iteritems(): laurent@586: for type in types: laurent@586: LOCATION_SIZES[type] = size laurent@586: laurent@586: [ID_BROWSELOCATIONSDIALOG, ID_BROWSELOCATIONSDIALOGLOCATIONSTREE, laurent@586: ID_BROWSELOCATIONSDIALOGDIRCHOICE, ID_BROWSELOCATIONSDIALOGSTATICTEXT1, laurent@586: ID_BROWSELOCATIONSDIALOGSTATICTEXT2, laurent@586: ] = [wx.NewId() for _init_ctrls in range(5)] laurent@586: laurent@586: class BrowseLocationsDialog(wx.Dialog): laurent@586: laurent@586: if wx.VERSION < (2, 6, 0): laurent@586: def Bind(self, event, function, id = None): laurent@586: if id is not None: laurent@586: event(self, id, function) laurent@586: else: laurent@586: event(self, function) laurent@586: laurent@586: def _init_coll_MainSizer_Items(self, parent): laurent@586: parent.AddWindow(self.staticText1, 0, border=20, flag=wx.TOP|wx.LEFT|wx.RIGHT|wx.GROW) laurent@586: parent.AddWindow(self.LocationsTree, 0, border=20, flag=wx.LEFT|wx.RIGHT|wx.GROW) laurent@586: parent.AddSizer(self.ButtonGridSizer, 0, border=20, flag=wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.GROW) laurent@586: laurent@586: def _init_coll_MainSizer_Growables(self, parent): laurent@586: parent.AddGrowableCol(0) laurent@586: parent.AddGrowableRow(1) laurent@586: laurent@586: def _init_coll_ButtonGridSizer_Items(self, parent): laurent@586: parent.AddWindow(self.staticText2, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL) laurent@586: parent.AddWindow(self.DirChoice, 0, border=0, flag=wx.ALIGN_CENTER_VERTICAL) laurent@586: parent.AddSizer(self.ButtonSizer, 0, border=0, flag=wx.ALIGN_RIGHT) laurent@586: laurent@586: def _init_coll_ButtonGridSizer_Growables(self, parent): laurent@586: parent.AddGrowableCol(2) laurent@586: parent.AddGrowableRow(0) laurent@586: laurent@586: def _init_sizers(self): laurent@586: self.MainSizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10) laurent@586: self.ButtonGridSizer = wx.FlexGridSizer(cols=3, hgap=5, rows=1, vgap=0) laurent@586: laurent@586: self._init_coll_MainSizer_Items(self.MainSizer) laurent@586: self._init_coll_MainSizer_Growables(self.MainSizer) laurent@586: self._init_coll_ButtonGridSizer_Items(self.ButtonGridSizer) laurent@586: self._init_coll_ButtonGridSizer_Growables(self.ButtonGridSizer) laurent@586: laurent@586: self.SetSizer(self.MainSizer) laurent@586: laurent@586: def _init_ctrls(self, prnt): laurent@586: wx.Dialog.__init__(self, id=ID_BROWSELOCATIONSDIALOG, laurent@586: name='BrowseLocationsDialog', parent=prnt, laurent@586: size=wx.Size(600, 400), style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER, laurent@586: title=_('Browse Locations')) laurent@586: laurent@586: self.staticText1 = wx.StaticText(id=ID_BROWSELOCATIONSDIALOGSTATICTEXT1, laurent@586: label=_('Locations available:'), name='staticText1', parent=self, laurent@586: pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) laurent@586: laurent@586: if wx.Platform == '__WXMSW__': laurent@586: treestyle = wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER laurent@586: else: laurent@586: treestyle = wx.TR_HAS_BUTTONS|wx.TR_HIDE_ROOT|wx.TR_SINGLE|wx.SUNKEN_BORDER laurent@586: self.LocationsTree = wx.TreeCtrl(id=ID_BROWSELOCATIONSDIALOGLOCATIONSTREE, laurent@586: name='LocationsTree', parent=self, pos=wx.Point(0, 0), laurent@586: size=wx.Size(0, 0), style=treestyle) laurent@586: self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnLocationsTreeItemActivated, laurent@586: id=ID_BROWSELOCATIONSDIALOGLOCATIONSTREE) laurent@586: laurent@586: self.staticText2 = wx.StaticText(id=ID_BROWSELOCATIONSDIALOGSTATICTEXT2, laurent@586: label=_('Direction:'), name='staticText2', parent=self, laurent@586: pos=wx.Point(0, 0), size=wx.DefaultSize, style=0) laurent@586: laurent@586: self.DirChoice = wx.ComboBox(id=ID_BROWSELOCATIONSDIALOGDIRCHOICE, laurent@586: name='DirChoice', parent=self, pos=wx.Point(0, 0), laurent@586: size=wx.DefaultSize, style=wx.CB_READONLY) laurent@586: self.Bind(wx.EVT_COMBOBOX, self.OnDirChoice, id=ID_BROWSELOCATIONSDIALOGDIRCHOICE) laurent@586: laurent@586: self.ButtonSizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE) laurent@586: if wx.VERSION >= (2, 5, 0): laurent@586: self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetAffirmativeButton().GetId()) laurent@586: else: laurent@586: self.Bind(wx.EVT_BUTTON, self.OnOK, id=self.ButtonSizer.GetChildren()[0].GetSizer().GetChildren()[0].GetWindow().GetId()) laurent@586: laurent@586: self._init_sizers() laurent@586: laurent@586: def __init__(self, parent, var_type, locations): laurent@586: self._init_ctrls(parent) laurent@586: self.VarType = var_type laurent@586: self.Locations = locations laurent@586: laurent@586: # Define Tree item icon list laurent@586: self.TreeImageList = wx.ImageList(16, 16) laurent@586: self.TreeImageDict = {} laurent@586: laurent@586: # Icons for items laurent@586: for imgname, itemtype in [ Edouard@681: ("CONFIGURATION", LOCATION_CONFNODE), laurent@586: ("RESOURCE", LOCATION_MODULE), laurent@586: ("PROGRAM", LOCATION_GROUP), laurent@586: ("VAR_INPUT", LOCATION_VAR_INPUT), laurent@586: ("VAR_OUTPUT", LOCATION_VAR_OUTPUT), laurent@586: ("VAR_LOCAL", LOCATION_VAR_MEMORY)]: laurent@586: self.TreeImageDict[itemtype]=self.TreeImageList.Add(wx.Bitmap(os.path.join(CWD, 'Images', '%s.png'%imgname))) laurent@586: laurent@586: # Assign icon list to TreeCtrls laurent@586: self.LocationsTree.SetImageList(self.TreeImageList) laurent@586: laurent@586: # Set a options for the choice laurent@586: for option, filter in GetDirChoiceOptions(): laurent@586: self.DirChoice.Append(_(option)) laurent@586: self.DirChoice.SetStringSelection(_("All")) laurent@586: self.RefreshFilter() laurent@586: laurent@586: self.RefreshLocationsTree() laurent@586: laurent@586: def RefreshFilter(self): laurent@586: self.Filter = DIRCHOICE_OPTIONS_FILTER[self.DirChoice.GetStringSelection()] laurent@586: laurent@586: def RefreshLocationsTree(self): laurent@586: root = self.LocationsTree.GetRootItem() laurent@586: if not root.IsOk(): laurent@586: if wx.Platform == '__WXMSW__': Edouard@681: root = self.LocationsTree.AddRoot(_('ConfNodes')) laurent@586: else: laurent@586: root = self.LocationsTree.AddRoot("") laurent@586: self.GenerateLocationsTreeBranch(root, self.Locations) laurent@586: self.LocationsTree.Expand(root) laurent@586: laurent@586: def GenerateLocationsTreeBranch(self, root, locations): laurent@586: to_delete = [] laurent@586: if wx.VERSION >= (2, 6, 0): laurent@586: item, root_cookie = self.LocationsTree.GetFirstChild(root) laurent@586: else: laurent@586: item, root_cookie = self.LocationsTree.GetFirstChild(root, 0) laurent@586: for loc_infos in locations: laurent@586: infos = loc_infos.copy() Edouard@681: if infos["type"] in [LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP] or\ laurent@586: infos["type"] in self.Filter and (infos["IEC_type"] == self.VarType or laurent@586: infos["IEC_type"] is None and LOCATION_SIZES[self.VarType] == infos["size"]): laurent@586: children = [child for child in infos.pop("children")] laurent@586: if not item.IsOk(): laurent@586: item = self.LocationsTree.AppendItem(root, infos["name"]) laurent@586: if wx.Platform != '__WXMSW__': laurent@586: item, root_cookie = self.LocationsTree.GetNextChild(root, root_cookie) laurent@586: else: laurent@586: self.LocationsTree.SetItemText(item, infos["name"]) laurent@586: self.LocationsTree.SetPyData(item, infos) laurent@586: self.LocationsTree.SetItemImage(item, self.TreeImageDict[infos["type"]]) laurent@586: self.GenerateLocationsTreeBranch(item, children) laurent@586: item, root_cookie = self.LocationsTree.GetNextChild(root, root_cookie) laurent@586: while item.IsOk(): laurent@586: to_delete.append(item) laurent@586: item, root_cookie = self.LocationsTree.GetNextChild(root, root_cookie) laurent@586: for item in to_delete: laurent@586: self.LocationsTree.Delete(item) laurent@586: laurent@586: def OnLocationsTreeItemActivated(self, event): laurent@586: infos = self.LocationsTree.GetPyData(event.GetItem()) Edouard@681: if infos["type"] not in [LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP]: laurent@586: wx.CallAfter(self.EndModal, wx.ID_OK) laurent@586: event.Skip() laurent@586: laurent@586: def OnDirChoice(self, event): laurent@586: self.RefreshFilter() laurent@586: self.RefreshLocationsTree() laurent@586: laurent@586: def GetValues(self): laurent@586: selected = self.LocationsTree.GetSelection() laurent@586: return self.LocationsTree.GetPyData(selected) laurent@586: laurent@586: def OnOK(self, event): laurent@586: selected = self.LocationsTree.GetSelection() laurent@586: var_infos = None laurent@586: if selected.IsOk(): laurent@586: var_infos = self.LocationsTree.GetPyData(selected) Edouard@681: if var_infos is None or var_infos["type"] in [LOCATION_CONFNODE, LOCATION_MODULE, LOCATION_GROUP]: laurent@586: message = wx.MessageDialog(self, _("A location must be selected!"), _("Error"), wx.OK|wx.ICON_ERROR) laurent@586: message.ShowModal() laurent@586: message.Destroy() laurent@586: else: laurent@586: self.EndModal(wx.ID_OK)