[GRASS-SVN] r52474 - grass-addons/grass7/gui/wxpython/wx.vnet/vnet

svn_grass at osgeo.org svn_grass at osgeo.org
Sat Jul 28 03:45:00 PDT 2012


Author: turek
Date: 2012-07-28 03:45:00 -0700 (Sat, 28 Jul 2012)
New Revision: 52474

Modified:
   grass-addons/grass7/gui/wxpython/wx.vnet/vnet/dialogs.py
   grass-addons/grass7/gui/wxpython/wx.vnet/vnet/toolbars.py
   grass-addons/grass7/gui/wxpython/wx.vnet/vnet/widgets.py
Log:
vnet: Undo/redo features added

Modified: grass-addons/grass7/gui/wxpython/wx.vnet/vnet/dialogs.py
===================================================================
--- grass-addons/grass7/gui/wxpython/wx.vnet/vnet/dialogs.py	2012-07-28 09:49:57 UTC (rev 52473)
+++ grass-addons/grass7/gui/wxpython/wx.vnet/vnet/dialogs.py	2012-07-28 10:45:00 UTC (rev 52474)
@@ -8,7 +8,7 @@
  - dialogs::PtsList
  - dialogs::SettingsDialog
  - dialogs::VnetTmpVectMaps
- - dialogs::VnetTmpVectMap
+ - dialogs::TmpVectMap
 
 (C) 2012 by the GRASS Development Team
 
@@ -20,6 +20,7 @@
 
 import os
 import sys
+import types
 import Queue
 try:
     import grass.lib.vector as vectlib
@@ -52,11 +53,13 @@
 from vnet.widgets     import PointsList
 from vnet.toolbars    import MainToolbar, PointListToolbar
 
-#TODOs
-# snaping - react on change of map/layer
+#Main TODOs
+# snapping - react on change of map/layer
 # when layer tree is lmgr is changed, tmp layer is removed from render list 
 # check if has layertree (lmgr)?
+# optimization of map drawing 
 
+
 class VNETDialog(wx.Dialog):
     def __init__(self, parent,
                  id = wx.ID_ANY, title = _("Vector network analysis"),
@@ -71,7 +74,12 @@
         self.cmdParams = {}
         self.snapData = {}
         self.snaping = False
+        self.tmp_result = None #TODO
 
+        self.history = History(self)
+        self.histTmpVectMapNum = 0
+        self.tmpVectMapsToHist = []
+
         self.tmpMaps = VnetTmpVectMaps(parent = self)
 
         self.hiddenTypeCol = None
@@ -93,7 +101,7 @@
         # toobars
         self.toolbars = {}
         self.toolbars['mainToolbar'] = MainToolbar(parent = self)
- 
+
         #
         # Fancy gui
         #
@@ -124,7 +132,7 @@
 
         # adds 2 points into list
         for i in range(2):
-            self.list.AddItem(None)
+            self.list.AddItem()
             self.list.EditCellIndex(i, 1, self.cols[1][1][1 + i]) 
             self.list.CheckItem(i, True)
 
@@ -134,7 +142,7 @@
 
         self.Bind(wx.EVT_CLOSE, self.OnCloseDialog)
 
-        dlgSize = (400, 520)
+        dlgSize = (410, 520)
         self.SetMinSize(dlgSize)
         self.SetInitialSize(dlgSize)
 
@@ -326,7 +334,7 @@
                         ['nlayer', "Node layer number or name:", LayerSelect],
                         ['afcolumn', self.attrCols['afcolumn']['label'], ColumnSelect],
                         ['abcolumn', self.attrCols['abcolumn']['label'], ColumnSelect],
-                        ['ncolumn', self.attrCols['ncolumn']['label'], ColumnSelect]
+                        ['ncolumn', self.attrCols['ncolumn']['label'], ColumnSelect],
                       ]
 
         selPanels = {}
@@ -654,10 +662,13 @@
                      message = msg)
             return            
 
-        if not self.tmpMaps.HasTmpVectMap("vnet_tmp_result"):
-            self.tmp_result = self.tmpMaps.AddTmpVectMap("vnet_tmp_result")
-            if not self.tmp_result:
-                    return          
+        self.SaveAnInputToHist()
+
+        if self.tmp_result:
+            self.tmp_result.DeleteRenderLayer()
+        self.tmp_result = self.NewTmpVectMapToHist('vnet_tmp_result')
+        if not self.tmp_result:
+                return          
         elif not self.tmp_result.VectLayerState(layer = 1):
                 return 
 
@@ -719,6 +730,9 @@
     def _vnetPathRunAnDone(self, cmd, returncode):
         """!Called when v.net.path analysis is done"""
         grass.try_remove(self.coordsTmpFile)
+
+        self._saveHistStep()
+
         self.tmp_result.SaveVectLayerState(layer = 1)
 
         cmd = self.GetLayerStyle()
@@ -775,7 +789,7 @@
             cmdParams.append("from_layer=1")
             cmdParams.append("to_layer=1")
         elif self.currAnModule == "v.net.flow":#TODO
-            self.vnetFlowTmpCut = self.tmpMaps.AddTmpVectMap("vnet_tmp_flow_cut")
+            self.vnetFlowTmpCut = self.NewTmpVectMapToHist("vnet_tmp_flow_cut")
             if not self.vnetFlowTmpCut:
                 return
             cmdParams.append("cut=" +  self.vnetFlowTmpCut.GetVectMapName())         
@@ -822,6 +836,8 @@
         self.tmpMaps.RemoveTmpMap(self.tmpInPtsConnected)
         grass.try_remove(self.tmpPtsAsciiFile)
 
+        self._saveHistStep()
+
         self.tmp_result.SaveVectLayerState(layer = 1)
         cmd = self.GetLayerStyle()
         self.tmp_result.AddRenderLayer(cmd)
@@ -988,7 +1004,7 @@
                        overwrite = True,
                        vect = [self.tmp_result.GetVectMapName(), addedMap])
 
-            cmd = self.GetLayerStyle()
+            cmd = self.GetLayerStyle()#TOFO get rid of insert
             cmd.insert(0, 'd.vect')
             cmd.append('map=%s' % addedMap)
             if  self.mapWin.tree.FindItemByData(key = 'name', value = addedMap) is None: 
@@ -997,9 +1013,8 @@
                                           lcmd = cmd,
                                           lchecked = True)
 
-            #self.mapWin.UpdateMap(render=True, renderVector=True)
+            #self.mapWin.UpdateMap(render=True, renderVector=True) 
 
-
     def OnSettings(self, event):
         """!Displays vnet settings dialog"""
         dlg = SettingsDialog(parent=self, id=wx.ID_ANY, title=_('Settings'))
@@ -1150,6 +1165,80 @@
         self.snapPts.AddRenderLayer() 
         self.mapWin.UpdateMap(render = True, renderVector = True)
 
+
+
+    def OnUndo(self, event):
+        histStepData = self.history.GetPrev()
+
+        self.toolbars['mainToolbar'].UpdateUndoRedo()
+
+        if histStepData:
+            self._updateHistStepData(histStepData)
+
+    def OnRedo(self, event):
+        histStepData = self.history.GetNext()
+
+        self.toolbars['mainToolbar'].UpdateUndoRedo()
+        if histStepData:
+            self._updateHistStepData(histStepData)
+
+    def _saveHistStep(self):
+
+        self.history.SaveHistStep()
+        self.toolbars['mainToolbar'].UpdateUndoRedo()
+
+    def _updateHistStepData(self, histStepData):#TODO need optimization
+        #TODO ischecked?
+        self.currAnModule = histStepData["vnet_modules"]["curr_module"]
+        anChoice = self.toolbars['mainToolbar'].anChoice
+        anChoice.SetStringSelection(self.vnetParams[self.currAnModule]["label"]) #TODO
+
+        while self.list.GetSelected() != wx.NOT_FOUND:
+            self.list.DeleteItem()
+
+        i = 0
+        for pt, ptData in  histStepData["points"].iteritems():
+            coords = ptData["coords"]
+            self.list.AddItem()
+            item = self.pointsToDraw.GetItem(i)
+            item.SetCoords(coords)
+            i += 1
+
+        mapsNames = histStepData["tmp_data"]["maps"]
+        for vectMapName in mapsNames:
+            if "vnet_tmp_result" in vectMapName:
+                self.tmp_result.DeleteRenderLayer()
+                self.tmp_result  = self.tmpMaps.GetTmpVectMap(vectMapName)
+
+                cmd = self.GetLayerStyle()
+                self.tmp_result.AddRenderLayer(cmd)
+
+        self.mapWin.UpdateMap(render=True, renderVector=True)
+
+    def NewTmpVectMapToHist(self, prefMapName):
+
+        mapName = prefMapName + str(self.histTmpVectMapNum)
+        self.histTmpVectMapNum += 1
+        tmpMap = self.tmpMaps.AddTmpVectMap(mapName)
+        if not tmpMap:
+            return tmpMap
+           
+        self.tmpVectMapsToHist.append(tmpMap.GetVectMapName())
+        self.history.Add(key = "tmp_data", subkey = "maps",  value = self.tmpVectMapsToHist)
+
+        return tmpMap
+
+    def SaveAnInputToHist(self):
+
+        pts = self.pointsToDraw.GetAllItems()
+        self.tmpVectMapsToHist = []
+        for iPt, pt in enumerate(pts):
+            coords = pt.GetCoords()
+            ptName = "pt" + str(iPt)
+            self.history.Add(key = "points", subkey = [ptName, "coords"], value = coords)
+
+        self.history.Add(key = "vnet_modules", subkey = "curr_module", value = self.currAnModule)
+
     def _initVnetParams(self):
         """!Initializes parameters for different v.net.* modules """
 
@@ -1287,7 +1376,7 @@
         initSettings = [
                         ['res_style', 'line_width', 5],
                         ['res_style', 'line_color', (192,0,0)],
-                        ['point_symbol', 'point_size', 10],
+                        ['point_symbol', 'point_size', 10],             
                         ['point_symbol', 'point_width', 2],
                         ['point_colors', "unused", (131,139,139)],
                         ['point_colors', "used1cat", (192,0,0)],
@@ -1342,7 +1431,7 @@
 
         PointsList.__init__(self, parent = parent, cols = cols, id =  id)      
 
-    def AddItem(self, event):
+    def AddItem(self, event = None):
         """!
         Appends an point to list
         """       
@@ -1354,18 +1443,17 @@
         self.dialog.mapWin.UpdateMap(render=False, renderVector=False)
 
 
-    def DeleteItem(self, event):
+    def DeleteItem(self, event = None):
         """!
         Deletes selected point in list
         """
-
         key = self.GetItemData(self.selected)
-        PointsList.DeleteItem(self, event)
-
         if self.selected != wx.NOT_FOUND:
             item = self.dialog.pointsToDraw.GetItem(key)
             self.dialog.pointsToDraw.DeleteItem(item)
 
+        PointsList.DeleteItem(self, event)
+
     def OnItemSelected(self, event):
         """
         Item selected
@@ -1590,7 +1678,7 @@
 
         self.parent.SetPointDrawSettings()
 
-        if not hasattr(self.parent.tmp_result, "GetRenderLayer"):
+        if not self.parent.tmpMaps.HasTmpVectMap("vnet_tmp_result"):
             self.parent.mapWin.UpdateMap(render=False, renderVector=False)
         elif self.parent.tmp_result.GetRenderLayer():
             cmd = self.parent.GetLayerStyle()
@@ -1691,7 +1779,7 @@
         else:
             fullName = mapName + "@" + currMapSet
 
-        newVectMap = VnetTmpVectMap(self, fullName)
+        newVectMap = TmpVectMap(self, fullName)
         self.tmpMaps.append(newVectMap)
 
         return newVectMap
@@ -1704,6 +1792,13 @@
                 return True
         return False
 
+    def GetTmpVectMap(self, vectMapName):
+
+        for vectMap in self.tmpMaps:
+            if vectMap.GetVectMapName() == vectMapName.strip():
+                return vectMap
+        return None
+
     def RemoveTmpMap(self, vectMap):
 
         RunCommand('g.remove', 
@@ -1724,7 +1819,7 @@
                 update = True
         return update
 
-class VnetTmpVectMap:
+class TmpVectMap:
     def __init__(self, parent, fullName):
         """!Represents one temporary map"""
         self.fullName = fullName
@@ -1776,11 +1871,14 @@
 
     def SaveVectLayerState(self, layer):
     
-         self.layersHash[layer] = self.GetLayerHash(layer = layer)
+         self.layersHash[layer] = self._getLayerHash(layer = layer)
         
     def VectLayerState(self, layer):
 
-        if self.layersHash[layer] != self.GetLayerHash(layer = layer):
+        if  not self.layersHash:#TODO 
+            return True
+
+        if self.layersHash[layer] != self._getLayerHash(layer = layer):
             dlg = wx.MessageDialog(parent = self.parent.parent,
                                    message = _("Layer %d in map %s was changed outside " +
                                                 "of vector network analysis tool. " +
@@ -1798,7 +1896,7 @@
             
         return True
 
-    def GetLayerHash(self, layer):
+    def _getLayerHash(self, layer):
         info = RunCommand("v.info",
                            map = self.fullName,
                            layer = layer,
@@ -1812,6 +1910,228 @@
 
         return m.digest()
 
+class History:
+    def __init__(self, parent):
+
+        self.maxHistSteps = 10
+        self.currHistStep = 0
+        self.histStepsNum = 0
+        self.currHistStepData = {}
+
+        self.newHistStepData = {}
+        self.histFile = grass.tempfile()
+
+        # key/value separator
+        self.sep = ';'
+
+    def __del__(self):
+        grass.try_remove(self.histFile)
+
+    def GetNext(self):
+
+        self.currHistStepData.clear()
+        self.currHistStep -= 1
+        return self._getHistStepData(self.currHistStep)
+
+    def GetPrev(self):
+
+        self.currHistStepData.clear()
+        self.currHistStep += 1 
+        return self._getHistStepData(self.currHistStep)
+
+    def GetCurrHistStep(self):
+        return self.currHistStep
+
+    def GetStepsNum(self):
+        return self.histStepsNum
+
+    def Add(self, key, subkey, value):#TODO
+
+        if key not in self.newHistStepData:
+            self.newHistStepData[key] = {}
+
+        if type(subkey) == types.ListType:
+            if subkey[0] not in self.newHistStepData[key]:
+                self.newHistStepData[key][subkey[0]] = {}
+            self.newHistStepData[key][subkey[0]][subkey[1]] = value
+        else:
+            self.newHistStepData[key][subkey] = value
+
+    def SaveHistStep(self):
+
+        self.currHistStep = 0 #TODO
+
+        newHistFile = grass.tempfile()
+        newHist = open(newHistFile, "w")
+
+        self._saveNewHistStep(newHist)
+
+        oldHist = open(self.histFile)
+        self._savePreviusHist(newHist, oldHist)
+
+        oldHist.close()
+        newHist.close()
+        grass.try_remove(self.histFile)
+        self.histFile = newHistFile
+
+        self.newHistStepData.clear() 
+
+    def _savePreviusHist(self, newHist, oldHist):          
+  
+        newHistStep = False
+        histStepNum = 1
+        for line in oldHist.readlines():
+            if not line.strip():
+                newHistStep = True
+                continue
+            if newHistStep:
+                line = line.split("=")
+                line[1] = str(histStepNum)
+                line = "=".join(line) 
+
+                if histStepNum >= self.maxHistSteps:
+                    self.histStepsNum = histStepNum + 1
+                    return
+                histStepNum += 1
+                newHistStep = False
+                newHist.write('%s%s%s' % (os.linesep, line, os.linesep))
+            else:
+                newHist.write('%s' % line)                
+        self.histStepsNum = histStepNum + 1
+            
+    def _saveNewHistStep(self, newHist):
+ 
+        newHist.write('%s%s%s' % (os.linesep, "history step=0", os.linesep))  
+        for key in self.newHistStepData.keys():
+            subkeys =  self.newHistStepData[key].keys()
+            newHist.write('%s%s' % (key, self.sep))
+            for idx in range(len(subkeys)):
+                value =  self.newHistStepData[key][subkeys[idx]]
+                if type(value) == types.DictType:
+                    if idx > 0:
+                        newHist.write('%s%s%s' % (os.linesep, key, self.sep))
+                    newHist.write('%s%s' % (subkeys[idx], self.sep))
+                    kvalues =  self.newHistStepData[key][subkeys[idx]].keys()
+                    srange = range(len(kvalues))
+                    for sidx in srange:
+                        svalue = self._parseValue(self.newHistStepData[key][subkeys[idx]][kvalues[sidx]])
+                        newHist.write('%s%s%s' % (kvalues[sidx], self.sep, svalue))
+                        if sidx < len(kvalues) - 1:
+                            newHist.write('%s' % self.sep)
+                else:
+                    if idx > 0 and \
+                            type( self.newHistStepData[key][subkeys[idx - 1]]) == types.DictType:
+                        newHist.write('%s%s%s' % (os.linesep, key, self.sep))
+                    value = self._parseValue(self.newHistStepData[key][subkeys[idx]])
+                    newHist.write('%s%s%s' % (subkeys[idx], self.sep, value))
+                    if idx < len(subkeys) - 1 and \
+                            type(self.newHistStepData[key][subkeys[idx + 1]]) != types.DictType:
+                        newHist.write('%s' % self.sep)
+            newHist.write(os.linesep)
+        self.histStepsNum = 1
+
+    def _parseValue(self, value, read = False):
+
+        if read: # -> read data (cast values)
+
+            if value:
+                if value[0] == '[' and value[-1] == ']':# TODO
+                    value = value[1:-1].split(',')
+                    value = map(self._castValue, value)
+                    return value
+
+            if value == 'True':
+                value = True
+            elif value == 'False':
+                value = False
+            elif value == 'None':
+                value = None
+            elif ':' in value: # -> color
+                try:
+                    value = tuple(map(int, value.split(':')))
+                except ValueError: # -> string
+                    pass
+            else:
+                try:
+                    value = int(value)
+                except ValueError:
+                    try:
+                        value = float(value)
+                    except ValueError:
+                        pass
+        else: # -> write data
+            if type(value) == type(()): # -> color
+                value = str(value[0]) + ':' +\
+                    str(value[1]) + ':' + \
+                    str(value[2])
+                
+        return value
+
+    def _castValue(self, value):
+        try:
+            value = int(value)
+        except ValueError:
+            try:
+                value = float(value)
+            except ValueError:
+                value = value[1:-1]
+
+        return value
+
+    def _getHistStepData(self, histStep):          
+        
+        hist = open(self.histFile)
+
+        newHistStep = False
+        isSearchedHistStep = False
+        for line in hist.readlines():
+
+            if  not line.strip() and isSearchedHistStep:
+                 break
+            elif not line.strip():
+                newHistStep = True
+                continue
+            elif isSearchedHistStep:
+                self._parseLine(line)
+
+            if newHistStep:
+                line = line.split("=")
+                if int(line[1]) == histStep:
+                    isSearchedHistStep = True
+                newHistStep = False
+
+        hist.close()
+        return self.currHistStepData
+
+    def _parseLine(self, line):
+
+            line = line.rstrip('%s' % os.linesep).split(self.sep)
+            key = line[0]
+            kv = line[1:]
+            idx = 0
+            subkeyMaster = None
+            if len(kv) % 2 != 0: # multiple (e.g. nviz)
+                subkeyMaster = kv[0]
+                del kv[0]
+            idx = 0
+            while idx < len(kv):
+                if subkeyMaster:
+                    subkey = [subkeyMaster, kv[idx]]
+                else:
+                    subkey = kv[idx]
+                value = kv[idx+1]
+                value = self._parseValue(value, read = True)
+                if key not in self.currHistStepData:
+                    self.currHistStepData[key] = {}
+
+                if type(subkey) == types.ListType:
+                    if subkey[0] not in self.currHistStepData[key]:
+                        self.currHistStepData[key][subkey[0]] = {}
+                    self.currHistStepData[key][subkey[0]][subkey[1]] = value
+                else:
+                    self.currHistStepData[key][subkey] = value
+                idx += 2
+
 #TODO ugly hack - just for GMConsole to be satisfied 
 class CmdPanelHack:
      def createCmd(self, ignoreErrors = False, ignoreRequired = False):

Modified: grass-addons/grass7/gui/wxpython/wx.vnet/vnet/toolbars.py
===================================================================
--- grass-addons/grass7/gui/wxpython/wx.vnet/vnet/toolbars.py	2012-07-28 09:49:57 UTC (rev 52473)
+++ grass-addons/grass7/gui/wxpython/wx.vnet/vnet/toolbars.py	2012-07-28 10:45:00 UTC (rev 52474)
@@ -74,8 +74,8 @@
             choices.append(self.parent.vnetParams[moduleName]['label'])
 
         self.anChoice = wx.ComboBox(parent = self, id = wx.ID_ANY,
-                                 choices = choices,
-                                 style = wx.CB_READONLY, size = (200, -1))
+                                    choices = choices,
+                                    style = wx.CB_READONLY, size = (180, -1))
         self.anChoice.SetSelection(0)
                
         self.anChoiceId = self.AddControl(self.anChoice)
@@ -85,6 +85,7 @@
         self.anChoice.Hide()
         self.anChoice.Show()
 
+        self.UpdateUndoRedo()
         # realize the toolbar
         self.Realize()
 
@@ -94,6 +95,10 @@
         icons = {
                  'run' : MetaIcon(img = 'execute',
                                   label = _('Execute analysis')),
+                 'undo' : MetaIcon(img = 'undo',
+                                  label = _('Go to previous analysis result')),
+                 'redo' : MetaIcon(img = 'redo',
+                                  label = _('Go to next analysis result')),
                  'showResult'   : MetaIcon(img = 'layer-add',
                                     label = _("Show analysis result")),
                  'saveTempLayer' : MetaIcon(img = 'map-export',
@@ -105,7 +110,11 @@
                                      ("run", icons['run'],
                                       self.parent.OnAnalyze),
                                       #("showResult", icons['showResult'], TODO
-                                      #self.parent.OnShowResult, wx.ITEM_CHECK),                                    
+                                      #self.parent.OnShowResult, wx.ITEM_CHECK),      
+                                     ("undo", icons['undo'], 
+                                      self.parent.OnUndo), 
+                                     ("redo", icons['redo'], 
+                                      self.parent.OnRedo),                               
                                      ("saveTempLayer", icons['saveTempLayer'],
                                       self.parent.OnSaveTmpLayer),
                                      ('settings', icons["settings"],
@@ -113,3 +122,15 @@
                                      ("quit", BaseIcons['quit'],
                                       self.parent.OnCloseDialog)
                                     ))
+
+    def UpdateUndoRedo(self):
+
+        if self.parent.history.GetCurrHistStep() >= self.parent.history.GetStepsNum() - 2:
+           self.Enable("undo", False)
+        else:
+           self.Enable("undo", True)
+
+        if self.parent.history.GetCurrHistStep() <= 0:
+           self.Enable("redo", False)
+        else:
+           self.Enable("redo", True)   
\ No newline at end of file

Modified: grass-addons/grass7/gui/wxpython/wx.vnet/vnet/widgets.py
===================================================================
--- grass-addons/grass7/gui/wxpython/wx.vnet/vnet/widgets.py	2012-07-28 09:49:57 UTC (rev 52473)
+++ grass-addons/grass7/gui/wxpython/wx.vnet/vnet/widgets.py	2012-07-28 10:45:00 UTC (rev 52474)
@@ -223,7 +223,7 @@
 
     def ClearItem(self, event):
         """"! Clears all values in selected item of points list and unchecks it."""
-        if self.selected == wx.NOT_FOUN:
+        if self.selected == wx.NOT_FOUND:
             return
         index = self.selected
         i = 0



More information about the grass-commit mailing list