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@714: #------------------------------------------------------------------------------- Laurent@714: # Helpers Laurent@714: #------------------------------------------------------------------------------- Laurent@714: 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@714: #------------------------------------------------------------------------------- Laurent@714: # Browse Locations Dialog Laurent@714: #------------------------------------------------------------------------------- laurent@586: laurent@586: class BrowseLocationsDialog(wx.Dialog): laurent@586: Laurent@714: def __init__(self, parent, var_type, locations): Laurent@714: wx.Dialog.__init__(self, parent, Laurent@714: size=wx.Size(600, 400), title=_('Browse Locations')) laurent@586: Laurent@714: main_sizer = wx.FlexGridSizer(cols=1, hgap=0, rows=3, vgap=10) Laurent@714: main_sizer.AddGrowableCol(0) Laurent@714: main_sizer.AddGrowableRow(1) laurent@586: Laurent@714: locations_label = wx.StaticText(self, label=_('Locations available:')) Laurent@714: main_sizer.AddWindow(locations_label, border=20, Laurent@714: flag=wx.TOP|wx.LEFT|wx.RIGHT|wx.GROW) laurent@586: Laurent@714: self.LocationsTree = wx.TreeCtrl(self, Laurent@714: style=wx.TR_HAS_BUTTONS|wx.TR_SINGLE|wx.SUNKEN_BORDER|wx.TR_HIDE_ROOT|wx.TR_LINES_AT_ROOT) Laurent@714: self.Bind(wx.EVT_TREE_ITEM_ACTIVATED, self.OnLocationsTreeItemActivated, Laurent@714: self.LocationsTree) Laurent@714: main_sizer.AddWindow(self.LocationsTree, border=20, Laurent@714: flag=wx.LEFT|wx.RIGHT|wx.GROW) laurent@586: Laurent@714: button_gridsizer = wx.FlexGridSizer(cols=3, hgap=5, rows=1, vgap=0) Laurent@714: button_gridsizer.AddGrowableCol(2) Laurent@714: button_gridsizer.AddGrowableRow(0) Laurent@714: main_sizer.AddSizer(button_gridsizer, border=20, Laurent@714: flag=wx.BOTTOM|wx.LEFT|wx.RIGHT|wx.GROW) laurent@586: Laurent@714: direction_label = wx.StaticText(self, label=_('Direction:')) Laurent@714: button_gridsizer.AddWindow(direction_label, Laurent@714: flag=wx.ALIGN_CENTER_VERTICAL) laurent@586: Laurent@714: self.DirChoice = wx.ComboBox(self, style=wx.CB_READONLY) Laurent@714: self.Bind(wx.EVT_COMBOBOX, self.OnDirChoice, self.DirChoice) Laurent@714: button_gridsizer.AddWindow(self.DirChoice, Laurent@714: flag=wx.ALIGN_CENTER_VERTICAL) laurent@586: Laurent@714: button_sizer = self.CreateButtonSizer(wx.OK|wx.CANCEL|wx.CENTRE) Laurent@714: self.Bind(wx.EVT_BUTTON, self.OnOK, button_sizer.GetAffirmativeButton()) Laurent@714: button_gridsizer.AddWindow(button_sizer, flag=wx.ALIGN_RIGHT) laurent@586: Laurent@714: self.SetSizer(main_sizer) laurent@586: 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@714: root = self.LocationsTree.AddRoot("") laurent@586: self.GenerateLocationsTreeBranch(root, self.Locations) laurent@586: laurent@586: def GenerateLocationsTreeBranch(self, root, locations): laurent@586: to_delete = [] Laurent@714: item, root_cookie = self.LocationsTree.GetFirstChild(root) 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@714: dialog = wx.MessageDialog(self, _("A location must be selected!"), _("Error"), wx.OK|wx.ICON_ERROR) Laurent@714: dialog.ShowModal() Laurent@714: dialog.Destroy() laurent@586: else: laurent@586: self.EndModal(wx.ID_OK)