GRASS Programmer's Manual  6.5.svn(2012)-r51648
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
gmodeler/dialogs.py
Go to the documentation of this file.
00001 """!
00002 @package gmodeler.dialogs
00003 
00004 @brief wxGUI Graphical Modeler - dialogs
00005 
00006 Classes:
00007  - dialogs::ModelDataDialog
00008  - dialogs::ModelSearchDialog
00009  - dialogs::ModelRelationDialog
00010  - dialogs::ModelItemDialog
00011  - dialogs::ModelLoopDialog
00012  - dialogs::ModelConditionDialog
00013  - dialogs::ModelListCtrl
00014  - dialogs::ValiableListCtrl
00015  - dialogs::ItemListCtrl
00016  - dialogs::ItemCheckListCtrl
00017 
00018 (C) 2010-2011 by the GRASS Development Team
00019 
00020 This program is free software under the GNU General Public License
00021 (>=v2). Read the file COPYING that comes with GRASS for details.
00022 
00023 @author Martin Landa <landa.martin gmail.com>
00024 """
00025 
00026 import os
00027 import sys
00028 
00029 import wx
00030 import wx.lib.mixins.listctrl as listmix
00031 
00032 from core                 import globalvar
00033 from core                 import utils
00034 from gui_core.widgets     import GNotebook
00035 from core.gcmd            import GError, EncodeString
00036 from gui_core.dialogs     import ElementDialog, MapLayersDialog
00037 from gui_core.ghelp       import SearchModuleWindow
00038 from gui_core.prompt      import GPromptSTC
00039 from gui_core.forms       import CmdPanel
00040 from gui_core.gselect     import Select
00041 from gmodeler.model       import *
00042 
00043 from grass.script import task as gtask
00044 
00045 class ModelDataDialog(ElementDialog):
00046     """!Data item properties dialog"""
00047     def __init__(self, parent, shape, id = wx.ID_ANY, title = _("Data properties"),
00048                  style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
00049         self.parent = parent
00050         self.shape = shape
00051         
00052         label, etype = self._getLabel()
00053         ElementDialog.__init__(self, parent, title, label = label, etype = etype)
00054                 
00055         self.element = Select(parent = self.panel)
00056         self.element.SetValue(shape.GetValue())
00057         
00058         self.Bind(wx.EVT_BUTTON, self.OnOK,     self.btnOK)
00059         self.Bind(wx.EVT_BUTTON, self.OnCancel, self.btnCancel)
00060         
00061         self.PostInit()
00062         
00063         if shape.GetValue():
00064             self.btnOK.Enable()
00065         
00066         self._layout()
00067         self.SetMinSize(self.GetSize())
00068         
00069     def _getLabel(self):
00070         etype = False
00071         prompt = self.shape.GetPrompt()
00072         if prompt == 'raster':
00073             label = _('Name of raster map:')
00074         elif prompt == 'vector':
00075             label = _('Name of vector map:')
00076         else:
00077             etype = True
00078             label = _('Name of element:')
00079 
00080         return label, etype
00081     
00082     def _layout(self):
00083         """!Do layout"""
00084         self.dataSizer.Add(self.element, proportion=0,
00085                       flag=wx.EXPAND | wx.ALL, border=1)
00086         
00087         self.panel.SetSizer(self.sizer)
00088         self.sizer.Fit(self)
00089 
00090     def OnOK(self, event):
00091         """!Ok pressed"""
00092         self.shape.SetValue(self.GetElement())
00093         if self.etype:
00094             elem = self.GetType()
00095             if elem == 'rast':
00096                 self.shape.SetPrompt('raster')
00097             elif elem == 'vect':
00098                 self.shape.SetPrompt('raster')
00099         
00100         self.parent.canvas.Refresh()
00101         self.parent.SetStatusText('', 0)
00102         self.shape.SetPropDialog(None)
00103         
00104         if self.IsModal():
00105             event.Skip() 
00106         else:
00107             self.Destroy()
00108     
00109     def OnCancel(self, event):
00110         """!Cancel pressed"""
00111         self.shape.SetPropDialog(None)
00112         if self.IsModal():
00113             event.Skip()
00114         else:
00115             self.Destroy()
00116 
00117 class ModelSearchDialog(wx.Dialog):
00118     def __init__(self, parent, id = wx.ID_ANY, title = _("Add new GRASS module to the model"),
00119                  style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
00120         """!Graphical modeler module search window
00121         
00122         @param parent parent window
00123         @param id window id
00124         @param title window title
00125         @param kwargs wx.Dialogs' arguments
00126         """
00127         self.parent = parent
00128         
00129         wx.Dialog.__init__(self, parent = parent, id = id, title = title, **kwargs)
00130         self.SetName("ModelerDialog")
00131         self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
00132         
00133         self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
00134         
00135         self.cmdBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
00136                                    label=" %s " % _("Command"))
00137         
00138         self.cmd_prompt = GPromptSTC(parent = self)
00139         self.search = SearchModuleWindow(parent = self.panel, cmdPrompt = self.cmd_prompt, showTip = True)
00140         wx.CallAfter(self.cmd_prompt.SetFocus)
00141         
00142         # get commands
00143         items = self.cmd_prompt.GetCommandItems()
00144         
00145         self.btnCancel = wx.Button(self.panel, wx.ID_CANCEL)
00146         self.btnOk     = wx.Button(self.panel, wx.ID_OK)
00147         self.btnOk.SetDefault()
00148         self.btnOk.Enable(False)
00149 
00150         self.cmd_prompt.Bind(wx.EVT_KEY_UP, self.OnText)
00151         self.search.searchChoice.Bind(wx.EVT_CHOICE, self.OnText)
00152         self.Bind(wx.EVT_BUTTON, self.OnOk, self.btnOk)
00153         
00154         self._layout()
00155         
00156         self.SetSize((500, 275))
00157         
00158     def _layout(self):
00159         cmdSizer = wx.StaticBoxSizer(self.cmdBox, wx.VERTICAL)
00160         cmdSizer.Add(item = self.cmd_prompt, proportion = 1,
00161                      flag = wx.EXPAND)
00162         
00163         btnSizer = wx.StdDialogButtonSizer()
00164         btnSizer.AddButton(self.btnCancel)
00165         btnSizer.AddButton(self.btnOk)
00166         btnSizer.Realize()
00167         
00168         mainSizer = wx.BoxSizer(wx.VERTICAL)
00169         mainSizer.Add(item = self.search, proportion = 0,
00170                       flag = wx.EXPAND | wx.ALL, border = 3)
00171         mainSizer.Add(item = cmdSizer, proportion = 1,
00172                       flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.TOP, border = 3)
00173         mainSizer.Add(item = btnSizer, proportion = 0,
00174                       flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
00175         
00176         self.panel.SetSizer(mainSizer)
00177         mainSizer.Fit(self.panel)
00178         
00179         self.Layout()
00180 
00181     def GetPanel(self):
00182         """!Get dialog panel"""
00183         return self.panel
00184 
00185     def GetCmd(self):
00186         """!Get command"""
00187         line = self.cmd_prompt.GetCurLine()[0].strip()
00188         if len(line) == 0:
00189             list()
00190         
00191         try:
00192             cmd = utils.split(str(line))
00193         except UnicodeError:
00194             cmd = utils.split(utils.EncodeString((line)))
00195             
00196         return cmd
00197     
00198     def OnOk(self, event):
00199         """!Button 'OK' pressed"""
00200         self.btnOk.SetFocus()
00201         cmd = self.GetCmd()
00202         
00203         if len(cmd) < 1:
00204             GError(parent = self,
00205                    message = _("Command not defined.\n\n"
00206                                "Unable to add new action to the model."))
00207             return
00208         
00209         if cmd[0] not in globalvar.grassCmd:
00210             GError(parent = self,
00211                    message = _("'%s' is not a GRASS module.\n\n"
00212                                "Unable to add new action to the model.") % cmd[0])
00213             return
00214         
00215         self.EndModal(wx.ID_OK)
00216         
00217     def OnText(self, event):
00218         """!Text in prompt changed"""
00219         if self.cmd_prompt.AutoCompActive():
00220             event.Skip()
00221             return
00222         
00223         if isinstance(event, wx.KeyEvent):
00224             entry = self.cmd_prompt.GetTextLeft()
00225         elif isinstance(event, wx.stc.StyledTextEvent):
00226             entry = event.GetText()
00227         else:
00228             entry = event.GetString()
00229         
00230         if entry:
00231             self.btnOk.Enable()
00232         else:
00233             self.btnOk.Enable(False)
00234             
00235         event.Skip()
00236         
00237     def Reset(self):
00238         """!Reset dialog"""
00239         self.search.Reset()
00240         self.cmd_prompt.OnCmdErase(None)
00241         self.btnOk.Enable(False)
00242         self.cmd_prompt.SetFocus()
00243 
00244 class ModelRelationDialog(wx.Dialog):
00245     """!Relation properties dialog"""
00246     def __init__(self, parent, shape, id = wx.ID_ANY, title = _("Relation properties"),
00247                  style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
00248         self.parent = parent
00249         self.shape = shape
00250         
00251         options = self._getOptions()
00252         if not options:
00253             self.valid = False
00254             return
00255         
00256         self.valid = True
00257         wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
00258         self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
00259         
00260         self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
00261         
00262         self.fromBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
00263                                     label = " %s " % _("From"))
00264         self.toBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
00265                                   label = " %s " % _("To"))
00266         
00267         self.option = wx.ComboBox(parent = self.panel, id = wx.ID_ANY,
00268                                   style = wx.CB_READONLY,
00269                                   choices = options)
00270         self.option.Bind(wx.EVT_COMBOBOX, self.OnOption)
00271         
00272         self.btnCancel = wx.Button(self.panel, wx.ID_CANCEL)
00273         self.btnOk     = wx.Button(self.panel, wx.ID_OK)
00274         self.btnOk.Enable(False)
00275         
00276         self._layout()
00277 
00278     def _layout(self):
00279         mainSizer = wx.BoxSizer(wx.VERTICAL)
00280 
00281         fromSizer = wx.StaticBoxSizer(self.fromBox, wx.VERTICAL)
00282         self._layoutShape(shape = self.shape.GetFrom(), sizer = fromSizer)
00283         toSizer = wx.StaticBoxSizer(self.toBox, wx.VERTICAL)
00284         self._layoutShape(shape = self.shape.GetTo(), sizer = toSizer)
00285 
00286         btnSizer = wx.StdDialogButtonSizer()
00287         btnSizer.AddButton(self.btnCancel)
00288         btnSizer.AddButton(self.btnOk)
00289         btnSizer.Realize()
00290         
00291         mainSizer.Add(item = fromSizer, proportion = 0,
00292                       flag = wx.EXPAND | wx.ALL, border = 5)
00293         mainSizer.Add(item = toSizer, proportion = 0,
00294                       flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
00295         mainSizer.Add(item = btnSizer, proportion = 0,
00296                       flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
00297         
00298         self.panel.SetSizer(mainSizer)
00299         mainSizer.Fit(self.panel)
00300         
00301         self.Layout()
00302         self.SetSize(self.GetBestSize())
00303         
00304     def _layoutShape(self, shape, sizer):
00305         if isinstance(shape, ModelData):
00306             sizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
00307                                            label = _("Data: %s") % shape.GetLog()),
00308                       proportion = 1, flag = wx.EXPAND | wx.ALL,
00309                       border = 5)
00310         elif isinstance(shape, ModelAction):
00311             gridSizer = wx.GridBagSizer (hgap = 5, vgap = 5)
00312             gridSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
00313                                                label = _("Command:")),
00314                           pos = (0, 0))
00315             gridSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
00316                                                label = shape.GetName()),
00317                           pos = (0, 1))
00318             gridSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
00319                                                label = _("Option:")),
00320                           flag = wx.ALIGN_CENTER_VERTICAL,
00321                           pos = (1, 0))
00322             gridSizer.Add(item = self.option,
00323                           pos = (1, 1))
00324             sizer.Add(item = gridSizer,
00325                       proportion = 1, flag = wx.EXPAND | wx.ALL,
00326                       border = 5)
00327             
00328     def _getOptions(self):
00329         """!Get relevant options"""
00330         items = []
00331         fromShape = self.shape.GetFrom()
00332         if not isinstance(fromShape, ModelData):
00333             GError(parent = self.parent,
00334                    message = _("Relation doesn't start with data item.\n"
00335                                "Unable to add relation."))
00336             return items
00337         
00338         toShape = self.shape.GetTo()
00339         if not isinstance(toShape, ModelAction):
00340             GError(parent = self.parent,
00341                    message = _("Relation doesn't point to GRASS command.\n"
00342                                "Unable to add relation."))
00343             return items
00344         
00345         prompt = fromShape.GetPrompt()
00346         task = toShape.GetTask()
00347         for p in task.get_options()['params']:
00348             if p.get('prompt', '') == prompt and \
00349                     'name' in p:
00350                 items.append(p['name'])
00351         
00352         if not items:
00353             GError(parent = self.parent,
00354                    message = _("No relevant option found.\n"
00355                                "Unable to add relation."))
00356         return items
00357     
00358     def GetOption(self):
00359         """!Get selected option"""
00360         return self.option.GetStringSelection()
00361     
00362     def IsValid(self):
00363         """!Check if relation is valid"""
00364         return self.valid
00365     
00366     def OnOption(self, event):
00367         """!Set option"""
00368         if event.GetString():
00369             self.btnOk.Enable()
00370         else:
00371             self.btnOk.Enable(False)
00372 
00373 class ModelItemDialog(wx.Dialog):
00374     """!Abstract item properties dialog"""
00375     def __init__(self, parent, shape, title, id = wx.ID_ANY,
00376                  style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
00377         self.parent = parent
00378         self.shape = shape
00379         
00380         wx.Dialog.__init__(self, parent, id, title = title, style = style, **kwargs)
00381         
00382         self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
00383         
00384         self.condBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
00385                                     label=" %s " % _("Condition"))
00386         self.condText = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY,
00387                                     value = shape.GetText())
00388         
00389         self.itemList = ItemCheckListCtrl(parent = self.panel,
00390                                           window = self,
00391                                           columns = [_("ID"), _("Name"),
00392                                                      _("Command")],
00393                                           shape = shape)
00394         self.itemList.Populate(self.parent.GetModel().GetItems())
00395         
00396         self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
00397         self.btnOk     = wx.Button(parent = self.panel, id = wx.ID_OK)
00398         self.btnOk.SetDefault()
00399         
00400     def _layout(self):
00401         """!Do layout (virtual method)"""
00402         pass
00403     
00404     def GetCondition(self):
00405         """!Get loop condition"""
00406         return self.condText.GetValue()
00407 
00408 class ModelLoopDialog(ModelItemDialog):
00409     """!Loop properties dialog"""
00410     def __init__(self, parent, shape, id = wx.ID_ANY, title = _("Loop properties"),
00411                  style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
00412         ModelItemDialog.__init__(self, parent, shape, title,
00413                                  style = style, **kwargs)
00414         
00415         self.listBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
00416                                     label=" %s " % _("List of items in loop"))
00417         
00418         self.btnSeries = wx.Button(parent = self.panel, id = wx.ID_ANY,
00419                                    label = _("Series"))
00420         self.btnSeries.SetToolTipString(_("Define map series as condition for the loop"))
00421         self.btnSeries.Bind(wx.EVT_BUTTON, self.OnSeries)
00422         
00423         self._layout()
00424         self.SetMinSize(self.GetSize())
00425         self.SetSize((500, 400))
00426         
00427     def _layout(self):
00428         """!Do layout"""
00429         sizer = wx.BoxSizer(wx.VERTICAL)
00430         
00431         condSizer = wx.StaticBoxSizer(self.condBox, wx.HORIZONTAL)
00432         condSizer.Add(item = self.condText, proportion = 1,
00433                       flag = wx.ALL, border = 3)
00434         condSizer.Add(item = self.btnSeries, proportion = 0,
00435                       flag = wx.EXPAND)
00436 
00437         listSizer = wx.StaticBoxSizer(self.listBox, wx.VERTICAL)
00438         listSizer.Add(item = self.itemList, proportion = 1,
00439                       flag = wx.EXPAND | wx.ALL, border = 3)
00440         
00441         btnSizer = wx.StdDialogButtonSizer()
00442         btnSizer.AddButton(self.btnCancel)
00443         btnSizer.AddButton(self.btnOk)
00444         btnSizer.Realize()
00445 
00446         sizer.Add(item = condSizer, proportion = 0,
00447                   flag = wx.EXPAND | wx.ALL, border = 3)
00448         sizer.Add(item = listSizer, proportion = 1,
00449                   flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 3)
00450         sizer.Add(item = btnSizer, proportion=0,
00451                   flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
00452         
00453         self.panel.SetSizer(sizer)
00454         sizer.Fit(self.panel)
00455         
00456         self.Layout()
00457         
00458     def GetItems(self):
00459         """!Get list of selected actions"""
00460         return self.itemList.GetItems()
00461 
00462     def OnSeries(self, event):
00463         """!Define map series as condition"""
00464         dialog = MapLayersDialog(parent = self, title = _("Define series of maps"), modeler = True)
00465         if dialog.ShowModal() != wx.ID_OK:
00466             dialog.Destroy()
00467             return
00468         
00469         cond = dialog.GetDSeries()
00470         if not cond:
00471             cond = 'map in %s' % map(lambda x: str(x), dialog.GetMapLayers())
00472         
00473         self.condText.SetValue(cond)
00474                                
00475         dialog.Destroy()
00476 
00477 class ModelConditionDialog(ModelItemDialog):
00478     """!Condition properties dialog"""
00479     def __init__(self, parent, shape, id = wx.ID_ANY, title = _("If-else properties"),
00480                  style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
00481         ModelItemDialog.__init__(self, parent, shape, title,
00482                                  style = style, **kwargs)
00483         
00484         self.listBoxIf = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
00485                                       label=" %s " % _("List of items in 'if' block"))
00486         self.itemListIf = self.itemList
00487         self.itemListIf.SetName('IfBlockList')
00488         
00489         self.listBoxElse = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
00490                                         label=" %s " % _("List of items in 'else' block"))
00491         self.itemListElse = ItemCheckListCtrl(parent = self.panel,
00492                                               window = self,
00493                                               columns = [_("ID"), _("Name"),
00494                                                          _("Command")],
00495                                               shape = shape)
00496         self.itemListElse.SetName('ElseBlockList')
00497         self.itemListElse.Populate(self.parent.GetModel().GetItems())
00498         
00499         self._layout()
00500         self.SetMinSize(self.GetSize())
00501         self.SetSize((500, 400))
00502         
00503     def _layout(self):
00504         """!Do layout"""
00505         sizer = wx.BoxSizer(wx.VERTICAL)
00506         
00507         condSizer = wx.StaticBoxSizer(self.condBox, wx.VERTICAL)
00508         condSizer.Add(item = self.condText, proportion = 1,
00509                       flag = wx.EXPAND)
00510         
00511         listIfSizer = wx.StaticBoxSizer(self.listBoxIf, wx.VERTICAL)
00512         listIfSizer.Add(item = self.itemListIf, proportion = 1,
00513                         flag = wx.EXPAND)
00514         listElseSizer = wx.StaticBoxSizer(self.listBoxElse, wx.VERTICAL)
00515         listElseSizer.Add(item = self.itemListElse, proportion = 1,
00516                           flag = wx.EXPAND)
00517         
00518         btnSizer = wx.StdDialogButtonSizer()
00519         btnSizer.AddButton(self.btnCancel)
00520         btnSizer.AddButton(self.btnOk)
00521         btnSizer.Realize()
00522 
00523         sizer.Add(item = condSizer, proportion = 0,
00524                   flag = wx.EXPAND | wx.ALL, border = 3)
00525         sizer.Add(item = listIfSizer, proportion = 1,
00526                   flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 3)
00527         sizer.Add(item = listElseSizer, proportion = 1,
00528                   flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 3)
00529         sizer.Add(item = btnSizer, proportion=0,
00530                   flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border=5)
00531         
00532         self.panel.SetSizer(sizer)
00533         sizer.Fit(self.panel)
00534         
00535         self.Layout()
00536 
00537     def OnCheckItemIf(self, index, flag):
00538         """!Item in if-block checked/unchecked"""
00539         if flag is False:
00540             return
00541         
00542         aId = int(self.itemListIf.GetItem(index, 0).GetText())
00543         if aId in self.itemListElse.GetItems()['checked']:
00544             self.itemListElse.CheckItemById(aId, False)
00545             
00546     def OnCheckItemElse(self, index, flag):
00547         """!Item in else-block checked/unchecked"""
00548         if flag is False:
00549             return
00550         
00551         aId = int(self.itemListElse.GetItem(index, 0).GetText())
00552         if aId in self.itemListIf.GetItems()['checked']:
00553             self.itemListIf.CheckItemById(aId, False)
00554         
00555     def GetItems(self):
00556         """!Get items"""
00557         return { 'if'   : self.itemListIf.GetItems(),
00558                  'else' : self.itemListElse.GetItems() }
00559 
00560 class ModelListCtrl(wx.ListCtrl,
00561                     listmix.ListCtrlAutoWidthMixin,
00562                     listmix.TextEditMixin,
00563                     listmix.ColumnSorterMixin):
00564     def __init__(self, parent, columns, id = wx.ID_ANY,
00565                  style = wx.LC_REPORT | wx.BORDER_NONE |
00566                  wx.LC_SORT_ASCENDING |wx.LC_HRULES |
00567                  wx.LC_VRULES, **kwargs):
00568         """!List of model variables"""
00569         self.parent = parent
00570         self.columns = columns
00571         self.shape = None
00572         try:
00573             self.frame  = parent.parent
00574         except AttributeError:
00575             self.frame = None
00576         
00577         wx.ListCtrl.__init__(self, parent, id = id, style = style, **kwargs)
00578         listmix.ListCtrlAutoWidthMixin.__init__(self)
00579         listmix.TextEditMixin.__init__(self)
00580         listmix.ColumnSorterMixin.__init__(self, 4)
00581         
00582         i = 0
00583         for col in columns:
00584             self.InsertColumn(i, col)
00585             self.SetColumnWidth(i, wx.LIST_AUTOSIZE_USEHEADER)
00586             i += 1
00587         
00588         self.itemDataMap = {} # requested by sorter
00589         self.itemCount   = 0
00590         
00591         self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnBeginEdit)
00592         self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnEndEdit)
00593         self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick)
00594         self.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightUp) #wxMSW
00595         self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)            #wxGTK
00596                 
00597     def OnBeginEdit(self, event):
00598         """!Editing of item started"""
00599         event.Allow()
00600 
00601     def OnEndEdit(self, event):
00602         """!Finish editing of item"""
00603         pass
00604     
00605     def OnColClick(self, event):
00606         """!Click on column header (order by)"""
00607         event.Skip()
00608 
00609 class VariableListCtrl(ModelListCtrl):
00610     def __init__(self, parent, columns, **kwargs):
00611         """!List of model variables"""
00612         ModelListCtrl.__init__(self, parent, columns, **kwargs)
00613 
00614         self.SetColumnWidth(2, 200) # default value
00615 
00616     def GetListCtrl(self):
00617         """!Used by ColumnSorterMixin"""
00618         return self
00619     
00620     def GetData(self):
00621         """!Get list data"""
00622         return self.itemDataMap
00623     
00624     def Populate(self, data):
00625         """!Populate the list"""
00626         self.itemDataMap = dict()
00627         i = 0
00628         for name, values in data.iteritems():
00629             self.itemDataMap[i] = [name, values['type'],
00630                                    values.get('value', ''),
00631                                    values.get('description', '')]
00632             i += 1
00633         
00634         self.itemCount = len(self.itemDataMap.keys())
00635         self.DeleteAllItems()
00636         i = 0
00637         for name, vtype, value, desc in self.itemDataMap.itervalues():
00638             index = self.InsertStringItem(sys.maxint, name)
00639             self.SetStringItem(index, 0, name)
00640             self.SetStringItem(index, 1, vtype)
00641             self.SetStringItem(index, 2, value)
00642             self.SetStringItem(index, 3, desc)
00643             self.SetItemData(index, i)
00644             i += 1
00645         
00646     def Append(self, name, vtype, value, desc):
00647         """!Append new item to the list
00648 
00649         @return None on success
00650         @return error string
00651         """
00652         for iname, ivtype, ivalue, idesc in self.itemDataMap.itervalues():
00653             if iname == name:
00654                 return _("Variable <%s> already exists in the model. "
00655                          "Adding variable failed.") % name
00656         
00657         index = self.InsertStringItem(sys.maxint, name)
00658         self.SetStringItem(index, 0, name)
00659         self.SetStringItem(index, 1, vtype)
00660         self.SetStringItem(index, 2, value)
00661         self.SetStringItem(index, 3, desc)
00662         self.SetItemData(index, self.itemCount)
00663         
00664         self.itemDataMap[self.itemCount] = [name, vtype, value, desc]
00665         self.itemCount += 1
00666         
00667         return None
00668 
00669     def OnRemove(self, event):
00670         """!Remove selected variable(s) from the model"""
00671         item = self.GetFirstSelected()
00672         while item != -1:
00673             self.DeleteItem(item)
00674             del self.itemDataMap[item]
00675             item = self.GetFirstSelected()
00676         self.parent.UpdateModelVariables()
00677         
00678         event.Skip()
00679         
00680     def OnRemoveAll(self, event):
00681         """!Remove all variable(s) from the model"""
00682         dlg = wx.MessageBox(parent=self,
00683                             message=_("Do you want to delete all variables from "
00684                                       "the model?"),
00685                             caption=_("Delete variables"),
00686                             style=wx.YES_NO | wx.CENTRE)
00687         if dlg != wx.YES:
00688             return
00689         
00690         self.DeleteAllItems()
00691         self.itemDataMap = dict()
00692         
00693         self.parent.UpdateModelVariables()
00694         
00695     def OnEndEdit(self, event):
00696         """!Finish editing of item"""
00697         itemIndex = event.GetIndex()
00698         columnIndex = event.GetColumn()
00699         nameOld = self.GetItem(itemIndex, 0).GetText()
00700 
00701         if columnIndex == 0: # TODO
00702             event.Veto()
00703         
00704         self.itemDataMap[itemIndex][columnIndex] = event.GetText()
00705         
00706         self.parent.UpdateModelVariables()
00707 
00708     def OnReload(self, event):
00709         """!Reload list of variables"""
00710         self.Populate(self.parent.parent.GetModel().GetVariables())
00711 
00712     def OnRightUp(self, event):
00713         """!Mouse right button up"""
00714         if not hasattr(self, "popupID1"):
00715             self.popupID1 = wx.NewId()
00716             self.popupID2 = wx.NewId()
00717             self.popupID3 = wx.NewId()
00718             self.Bind(wx.EVT_MENU, self.OnRemove,    id = self.popupID1)
00719             self.Bind(wx.EVT_MENU, self.OnRemoveAll, id = self.popupID2)
00720             self.Bind(wx.EVT_MENU, self.OnReload,    id = self.popupID3)
00721         
00722         # generate popup-menu
00723         menu = wx.Menu()
00724         menu.Append(self.popupID1, _("Delete selected"))
00725         menu.Append(self.popupID2, _("Delete all"))
00726         if self.GetFirstSelected() == -1:
00727             menu.Enable(self.popupID1, False)
00728             menu.Enable(self.popupID2, False)
00729         
00730         menu.AppendSeparator()
00731         menu.Append(self.popupID3, _("Reload"))
00732         
00733         self.PopupMenu(menu)
00734         menu.Destroy()
00735 
00736 class ItemListCtrl(ModelListCtrl):
00737     def __init__(self, parent, columns, disablePopup = False, **kwargs):
00738         """!List of model actions"""
00739         self.disablePopup = disablePopup
00740                 
00741         ModelListCtrl.__init__(self, parent, columns, **kwargs)
00742         self.SetColumnWidth(1, 100)
00743         self.SetColumnWidth(2, 65)
00744         
00745     def GetListCtrl(self):
00746         """!Used by ColumnSorterMixin"""
00747         return self
00748     
00749     def GetData(self):
00750         """!Get list data"""
00751         return self.itemDataMap
00752     
00753     def Populate(self, data):
00754         """!Populate the list"""
00755         self.itemDataMap = dict()
00756         
00757         if self.shape:
00758             if isinstance(self.shape, ModelCondition):
00759                 if self.GetName() == 'ElseBlockList':
00760                     shapeItems = map(lambda x: x.GetId(), self.shape.GetItems()['else'])
00761                 else:
00762                     shapeItems = map(lambda x: x.GetId(), self.shape.GetItems()['if'])
00763             else:
00764                 shapeItems = map(lambda x: x.GetId(), self.shape.GetItems())
00765         else:
00766             shapeItems = list()
00767         
00768         i = 0
00769         if len(self.columns) == 3: # ItemCheckList
00770             checked = list()
00771         for action in data:
00772             if isinstance(action, ModelData) or \
00773                     action == self.shape:
00774                 continue
00775             
00776             if len(self.columns) == 3:
00777                 self.itemDataMap[i] = [str(action.GetId()),
00778                                        action.GetName(),
00779                                        action.GetLog()]
00780                 aId = action.GetBlockId()
00781                 if action.GetId() in shapeItems:
00782                     checked.append(aId)
00783                 else:
00784                     checked.append(None)
00785             else:
00786                 bId = action.GetBlockId()
00787                 if not bId:
00788                     bId = ''
00789                 self.itemDataMap[i] = [str(action.GetId()),
00790                                        action.GetName(),
00791                                        ','.join(map(str, bId)),
00792                                        action.GetLog()]
00793             
00794             i += 1
00795         
00796         self.itemCount = len(self.itemDataMap.keys())
00797         self.DeleteAllItems()
00798         i = 0
00799         if len(self.columns) == 3:
00800             for aid, name, desc in self.itemDataMap.itervalues():
00801                 index = self.InsertStringItem(sys.maxint, aid)
00802                 self.SetStringItem(index, 0, aid)
00803                 self.SetStringItem(index, 1, name)
00804                 self.SetStringItem(index, 2, desc)
00805                 self.SetItemData(index, i)
00806                 if checked[i]:
00807                     self.CheckItem(index, True)
00808                 i += 1
00809         else:
00810             for aid, name, inloop, desc in self.itemDataMap.itervalues():
00811                 index = self.InsertStringItem(sys.maxint, aid)
00812                 self.SetStringItem(index, 0, aid)
00813                 self.SetStringItem(index, 1, name)
00814                 self.SetStringItem(index, 2, inloop)
00815                 self.SetStringItem(index, 3, desc)
00816                 self.SetItemData(index, i)
00817                 i += 1
00818                 
00819     def OnRemove(self, event):
00820         """!Remove selected action(s) from the model"""
00821         model = self.frame.GetModel()
00822         canvas = self.frame.GetCanvas()
00823         
00824         item = self.GetFirstSelected()
00825         while item != -1:
00826             self.DeleteItem(item)
00827             del self.itemDataMap[item]
00828             
00829             aId = self.GetItem(item, 0).GetText()
00830             action = model.GetItem(int(aId))
00831             if not action:
00832                 item = self.GetFirstSelected()
00833                 continue
00834             
00835             model.RemoveItem(action)
00836             canvas.GetDiagram().RemoveShape(action)
00837             self.frame.ModelChanged()
00838             
00839             item = self.GetFirstSelected()
00840         
00841         canvas.Refresh()
00842         
00843         event.Skip()
00844     
00845     def OnRemoveAll(self, event):
00846         """!Remove all variable(s) from the model"""
00847         deleteDialog = wx.MessageBox(parent=self,
00848                                      message=_("Selected data records (%d) will permanently deleted "
00849                                                "from table. Do you want to delete them?") % \
00850                                          (len(self.listOfSQLStatements)),
00851                                      caption=_("Delete records"),
00852                                      style=wx.YES_NO | wx.CENTRE)
00853         if deleteDialog != wx.YES:
00854             return False
00855         
00856         self.DeleteAllItems()
00857         self.itemDataMap = dict()
00858 
00859         self.parent.UpdateModelVariables()
00860 
00861     def OnEndEdit(self, event):
00862         """!Finish editing of item"""
00863         itemIndex = event.GetIndex()
00864         columnIndex = event.GetColumn()
00865         
00866         self.itemDataMap[itemIndex][columnIndex] = event.GetText()
00867         
00868         aId = int(self.GetItem(itemIndex, 0).GetText())
00869         action = self.frame.GetModel().GetItem(aId)
00870         if not action:
00871             event.Veto()
00872         if columnIndex == 0:
00873             action.SetId(int(event.GetText()))
00874         
00875         self.frame.ModelChanged()
00876 
00877     def OnReload(self, event = None):
00878         """!Reload list of actions"""
00879         self.Populate(self.frame.GetModel().GetItems())
00880 
00881     def OnRightUp(self, event):
00882         """!Mouse right button up"""
00883         if self.disablePopup:
00884             return
00885         
00886         if not hasattr(self, "popupID1"):
00887             self.popupID1 = wx.NewId()
00888             self.popupID2 = wx.NewId()
00889             self.popupID3 = wx.NewId()
00890             self.popupID4 = wx.NewId()
00891             self.Bind(wx.EVT_MENU, self.OnRemove,    id = self.popupID1)
00892             self.Bind(wx.EVT_MENU, self.OnRemoveAll, id = self.popupID2)
00893             self.Bind(wx.EVT_MENU, self.OnReload,    id = self.popupID3)
00894             self.Bind(wx.EVT_MENU, self.OnNormalize, id = self.popupID4)
00895 
00896         # generate popup-menu
00897         menu = wx.Menu()
00898         menu.Append(self.popupID1, _("Delete selected"))
00899         menu.Append(self.popupID2, _("Delete all"))
00900         if self.GetFirstSelected() == -1:
00901             menu.Enable(self.popupID1, False)
00902             menu.Enable(self.popupID2, False)
00903         
00904         menu.AppendSeparator()
00905         menu.Append(self.popupID4, _("Normalize"))
00906         menu.Append(self.popupID3, _("Reload"))
00907         
00908         self.PopupMenu(menu)
00909         menu.Destroy()
00910     
00911     def OnNormalize(self, event):
00912         """!Update id of actions"""
00913         model = self.frame.GetModel()
00914         
00915         aId = 1
00916         for item in model.GetItems():
00917             item.SetId(aId)
00918             aId += 1
00919         
00920         self.OnReload(None)
00921         self.frame.GetCanvas().Refresh()
00922         self.frame.ModelChanged()
00923 
00924 class ItemCheckListCtrl(ItemListCtrl, listmix.CheckListCtrlMixin):
00925     def __init__(self, parent, shape, columns, window = None, **kwargs):
00926         self.parent = parent
00927         self.window = window
00928         
00929         ItemListCtrl.__init__(self, parent, columns, disablePopup = True, **kwargs)
00930         listmix.CheckListCtrlMixin.__init__(self)
00931         self.SetColumnWidth(0, 50)
00932         
00933         self.shape  = shape
00934         
00935     def OnBeginEdit(self, event):
00936         """!Disable editing"""
00937         event.Veto()
00938         
00939     def OnCheckItem(self, index, flag):
00940         """!Item checked/unchecked"""
00941         name = self.GetName()
00942         if name == 'IfBlockList' and self.window:
00943             self.window.OnCheckItemIf(index, flag)
00944         elif name == 'ElseBlockList' and self.window:
00945             self.window.OnCheckItemElse(index, flag)
00946         
00947     def GetItems(self):
00948         """!Get list of selected actions"""
00949         ids = { 'checked'   : list(),
00950                 'unchecked' : list() }
00951         for i in range(self.GetItemCount()):
00952             iId = int(self.GetItem(i, 0).GetText())
00953             if self.IsChecked(i):
00954                 ids['checked'].append(iId)
00955             else:
00956                 ids['unchecked'].append(iId)
00957             
00958         return ids
00959 
00960     def CheckItemById(self, aId, flag):
00961         """!Check/uncheck given item by id"""
00962         for i in range(self.GetItemCount()):
00963             iId = int(self.GetItem(i, 0).GetText())
00964             if iId == aId:
00965                 self.CheckItem(i, flag)
00966                 break