[GRASS-SVN] r30850 - in grass/trunk/gui/wxpython: gui_modules icons
vdigit
svn_grass at osgeo.org
svn_grass at osgeo.org
Thu Apr 3 08:22:37 EDT 2008
Author: martinl
Date: 2008-04-03 08:22:37 -0400 (Thu, 03 Apr 2008)
New Revision: 30850
Added:
grass/trunk/gui/wxpython/vdigit/undo.cpp
Modified:
grass/trunk/gui/wxpython/gui_modules/digit.py
grass/trunk/gui/wxpython/gui_modules/mapdisp.py
grass/trunk/gui/wxpython/gui_modules/toolbars.py
grass/trunk/gui/wxpython/gui_modules/wxgui_utils.py
grass/trunk/gui/wxpython/icons/icon.py
grass/trunk/gui/wxpython/vdigit/digit.cpp
grass/trunk/gui/wxpython/vdigit/digit.h
grass/trunk/gui/wxpython/vdigit/line.cpp
Log:
wxGUI: very basic undo implementation for vdigit. TODO: add Vect_restore_line() to Vlib
Modified: grass/trunk/gui/wxpython/gui_modules/digit.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/digit.py 2008-04-03 08:14:54 UTC (rev 30849)
+++ grass/trunk/gui/wxpython/gui_modules/digit.py 2008-04-03 12:22:37 UTC (rev 30850)
@@ -80,7 +80,8 @@
@param settings initial settings of digitization tool
"""
self.map = None
-
+ self.mapWindow = mapwindow
+
Debug.msg (3, "AbstractDigit.__init__(): map=%s" % \
self.map)
@@ -739,6 +740,12 @@
return [1,]
+ def Undo(self, level=-1):
+ """Undo not implemented here"""
+ wx.MessageBox(parent=self.mapWindow, message=_("Undondo is not implemented in vedit component. "
+ "Use vdigit instead."),
+ caption=_("Message"), style=wx.ID_OK | wx.ICON_INFORMATION | wx.CENTRE)
+
class VDigit(AbstractDigit):
"""
Prototype of digitization class based on v.digit reimplementation
@@ -758,6 +765,11 @@
except (ImportError, NameError):
self.digit = None
+ self.toolbar = mapwindow.parent.digittoolbar
+
+ def __del__(self):
+ del self.digit
+
def AddPoint (self, map, point, x, y, z=None):
"""Add new point/centroid
@@ -784,6 +796,8 @@
if ret == -1:
raise gcmd.DigitError, _("Adding new feature to vector map <%s> failed.") % map
+
+ self.toolbar.EnableUndo()
def AddLine (self, map, line, coords):
"""Add line/boundary
@@ -816,7 +830,8 @@
if ret == -1:
raise gcmd.DigitError, _("Adding new feature to vector map <%s> failed.") % map
-
+ self.toolbar.EnableUndo()
+
def DeleteSelectedLines(self):
"""Delete selected features
@@ -824,6 +839,9 @@
"""
nlines = self.digit.DeleteLines(UserSettings.Get(group='vdigit', key='delRecord', subkey='enabled'))
+ if nlines > 0:
+ self.toolbar.EnableUndo()
+
return nlines
def MoveSelectedLines(self, move):
@@ -836,6 +854,9 @@
nlines = self.digit.MoveLines(move[0], move[1], 0.0, # TODO 3D
str(UserSettings.Get(group='vdigit', key="backgroundMap", subkey='value')), snap, thresh)
+ if nlines > 0:
+ self.toolbar.EnableUndo()
+
return nlines
def MoveSelectedVertex(self, coords, move):
@@ -849,44 +870,76 @@
"""
snap, thresh = self.__getSnapThreshold()
- return self.digit.MoveVertex(coords[0], coords[1], 0.0, # TODO 3D
- move[0], move[1], 0.0,
- str(UserSettings.Get(group='vdigit', key="backgroundMap", subkey='value')), snap,
- self.driver.GetThreshold(type='selectThresh'), thresh)
+ moved = self.digit.MoveVertex(coords[0], coords[1], 0.0, # TODO 3D
+ move[0], move[1], 0.0,
+ str(UserSettings.Get(group='vdigit', key="backgroundMap", subkey='value')), snap,
+ self.driver.GetThreshold(type='selectThresh'), thresh)
+ if moved:
+ self.toolbar.EnableUndo()
+
+ return moved
+
def AddVertex(self, coords):
"""Add new vertex to the selected line/boundary on position 'coords'
@param coords coordinates to add vertex
+
+ @return 1 vertex added
+ @return 0 nothing changed
+ @return -1 on failure
"""
- return self.digit.ModifyLineVertex(1, coords[0], coords[1], 0.0, # TODO 3D
- self.driver.GetThreshold(type='selectThresh'))
+ added = self.digit.ModifyLineVertex(1, coords[0], coords[1], 0.0, # TODO 3D
+ self.driver.GetThreshold(type='selectThresh'))
+ if added > 0:
+ self.toolbar.EnableUndo()
+
+ return added
+
def RemoveVertex(self, coords):
"""Remove vertex from the selected line/boundary on position 'coords'
@param coords coordinates to remove vertex
+
+ @return 1 vertex removed
+ @return 0 nothing changed
+ @return -1 on failure
"""
- return self.digit.ModifyLineVertex(0, coords[0], coords[1], 0.0, # TODO 3D
- self.driver.GetThreshold(type='selectThresh'))
+ deleted = self.digit.ModifyLineVertex(0, coords[0], coords[1], 0.0, # TODO 3D
+ self.driver.GetThreshold(type='selectThresh'))
+ if deleted > 0:
+ self.toolbar.EnableUndo()
+
+ return deleted
+
+
def SplitLine(self, coords):
"""Split selected line/boundary on position 'coords'
@param coords coordinates to split line
- @return 1 line splitted
- @return 0 no action
+ @return 1 line modified
+ @return 0 nothing changed
@return -1 error
"""
- return self.digit.SplitLine(coords[0], coords[1], 0.0, # TODO 3D
- self.driver.GetThreshold('selectThresh'))
+ ret = self.digit.SplitLine(coords[0], coords[1], 0.0, # TODO 3D
+ self.driver.GetThreshold('selectThresh'))
+ if ret > 0:
+ self.toolbar.EnableUndo()
+
+ return ret
+
def EditLine(self, line, coords):
"""Edit existing line/boundary
@param line id of line to be modified
@param coords list of coordinates of modified line
+
+ @return feature id of new line
+ @return -1 on error
"""
try:
lineid = line[0]
@@ -900,49 +953,116 @@
snap, thresh = self.__getSnapThreshold()
- return self.digit.RewriteLine(lineid, listCoords,
- str(UserSettings.Get(group='vdigit', key="backgroundMap", subkey='value')), snap, thresh)
+ ret = self.digit.RewriteLine(lineid, listCoords,
+ str(UserSettings.Get(group='vdigit', key="backgroundMap", subkey='value')), snap, thresh)
+ if ret > 0:
+ self.toolbar.EnableUndo()
+
+ return ret
+
def FlipLine(self):
- """Flip selected lines/boundaries"""
- return self.digit.FlipLines()
+ """Flip selected lines/boundaries
+ @return number of modified lines
+ @return -1 on error
+ """
+ ret = self.digit.FlipLines()
+
+ if ret > 0:
+ self.toolbar.EnableUndo()
+
+ return ret
+
def MergeLine(self):
- """Merge selected lines/boundaries"""
- return self.digit.MergeLines()
+ """Merge selected lines/boundaries
+ @return number of modified lines
+ @return -1 on error
+ """
+ ret = self.digit.MergeLines()
+
+ if ret > 0:
+ self.toolbar.EnableUndo()
+
+ return ret
+
def BreakLine(self):
- """Break selected lines/boundaries"""
- return self.digit.BreakLines()
+ """Break selected lines/boundaries
+ @return number of modified lines
+ @return -1 on error
+ """
+ ret = self.digit.BreakLines()
+
+ if ret > 0:
+ self.toolbar.EnableUndo()
+
+ return ret
+
def SnapLine(self):
- """Snap selected lines/boundaries"""
+ """Snap selected lines/boundaries
+
+ @return on success
+ @return -1 on error
+ """
snap, thresh = self.__getSnapThreshold()
- return self.digit.SnapLines(thresh)
+ ret = self.digit.SnapLines(thresh)
+
+ if ret == 0:
+ self.toolbar.EnableUndo()
+ return ret
+
def ConnectLine(self):
- """Connect selected lines/boundaries"""
+ """Connect selected lines/boundaries
+
+ @return 1 lines connected
+ @return 0 lines not connected
+ @return -1 on error
+ """
snap, thresh = self.__getSnapThreshold()
- return self.digit.ConnectLines(thresh)
+ ret = self.digit.ConnectLines(thresh)
+ if ret > 0:
+ self.toolbar.EnableUndo()
+
+ return ret
+
def CopyLine(self, ids=None):
"""Copy features from (background) vector map
@param ids list of line ids to be copied
+
+ @return number of copied features
+ @return -1 on error
"""
- return self.digit.CopyLines(ids, str(UserSettings.Get(group='vdigit', key='backgroundMap', subkey='value')))
+ ret = self.digit.CopyLines(ids, str(UserSettings.Get(group='vdigit', key='backgroundMap', subkey='value')))
+ if ret > 0:
+ self.toolbar.EnableUndo()
+
+ return ret
+
def CopyCats(self, cats, ids):
"""Copy given categories to objects with id listed in ids
@param cats list of cats to be copied
@param ids ids of lines to be modified
+
+ @return number of modified features
+ @return -1 on error
"""
if len(cats) == 0 or len(ids) == 0:
- return False
+ return 0
- return self.digit.CopyCats(cats, ids)
+ ret = self.digit.CopyCats(cats, ids)
+ if ret > 0:
+ self.toolbar.EnableUndo()
+
+ return ret
+
def SelectLinesByQuery(self, pos1, pos2):
"""Select features by query
@@ -983,9 +1103,17 @@
@param layer layer number (-1 for first selected line)
@param cats list of categories
@param add if True to add, otherwise do delete categories
+
+ @return new feature id (feature need to be rewritten)
+ @return -1 on error
"""
- return self.digit.SetLineCats(line, layer, cats, add)
+ ret = self.digit.SetLineCats(line, layer, cats, add)
+ if ret > 0:
+ self.toolbar.EnableUndo()
+
+ return ret
+
def GetLayers(self):
"""Get list of layers"""
return self.digit.GetLayers()
@@ -1000,8 +1128,33 @@
@return number of modified features
@return -1 on error
"""
- return self.digit.TypeConvLines()
+ ret = self.digit.TypeConvLines()
+ if ret > 0:
+ self.toolbar.EnableUndo()
+
+ return ret
+
+ def Undo(self, level=-1):
+ """Undo action
+
+ @param level levels to undo
+
+ @return id of current changeset
+ """
+ try:
+ ret = self.digit.Undo(level)
+ except SystemExit:
+ ret = -2
+
+ if ret == -2:
+ raise gcmd.DigitError, _("Undo failed, data corrupted.")
+
+ self.mapWindow.UpdateMap(render=False)
+
+ if ret < 0: # disable undo tool
+ self.toolbar.EnableUndo(False)
+
def __getSnapThreshold(self):
"""Get snap mode and threshold value
@@ -1031,7 +1184,10 @@
def __init__(self, mapwindow):
VDigit.__init__(self, mapwindow)
self.type = 'vdigit'
-
+
+ def __del__(self):
+ VDigit.__del__(self)
+
class AbstractDisplayDriver:
"""Abstract classs for display driver"""
def __init__(self, parent, mapwindow):
Modified: grass/trunk/gui/wxpython/gui_modules/mapdisp.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/mapdisp.py 2008-04-03 08:14:54 UTC (rev 30849)
+++ grass/trunk/gui/wxpython/gui_modules/mapdisp.py 2008-04-03 12:22:37 UTC (rev 30850)
@@ -2049,7 +2049,7 @@
# We ONLY want to set extents here. Don't mess with resolution. Leave that
# for user to set explicitly with g.region
new = self.Map.AlignResolution()
-
+
cmdRegion = ["g.region", "--o",
"n=%f" % new['n'],
"s=%f" % new['s'],
@@ -2170,7 +2170,7 @@
drawing window.
"""
- def __init__(self, parent=None, id=wx.ID_ANY, title="GRASS GIS - Map display",
+ def __init__(self, parent=None, id=wx.ID_ANY, title=_("GRASS GIS - Map display"),
pos=wx.DefaultPosition, size=wx.DefaultSize,
style=wx.DEFAULT_FRAME_STYLE, toolbars=["map"],
tree=None, notebook=None, gismgr=None, page=None,
Modified: grass/trunk/gui/wxpython/gui_modules/toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/toolbars.py 2008-04-03 08:14:54 UTC (rev 30849)
+++ grass/trunk/gui/wxpython/gui_modules/toolbars.py 2008-04-03 12:22:37 UTC (rev 30850)
@@ -43,12 +43,9 @@
@return list of ids (of added tools)
"""
- ids = []
for tool in toolData:
- ids.append(self.CreateTool(parent, toolbar, *tool))
-
- return ids
-
+ self.CreateTool(parent, toolbar, *tool)
+
def ToolbarData(self):
"""Toolbar data"""
@@ -63,16 +60,15 @@
bmpDisabled=wx.NullBitmap
- id = wx.NewId()
if label:
- tool = toolbar.AddLabelTool(id, label, bitmap,
+ toolWin = toolbar.AddLabelTool(tool, label, bitmap,
bmpDisabled, kind,
shortHelp, longHelp)
- parent.Bind(wx.EVT_TOOL, handler, tool)
+ parent.Bind(wx.EVT_TOOL, handler, toolWin)
else: # add separator
toolbar.AddSeparator()
- return id
+ return tool
class MapToolbar(AbstractToolbar):
"""
@@ -86,7 +82,7 @@
self.toolbar = wx.ToolBar(parent=self.mapdisplay, id=wx.ID_ANY)
self.toolbar.SetToolBitmapSize(globalvar.toolbarSize)
- self.pointerId = self.InitToolbar(self.mapdisplay, self.toolbar, self.ToolbarData())[4]
+ self.InitToolbar(self.mapdisplay, self.toolbar, self.ToolbarData())
# optional tools
self.combo = wx.ComboBox(parent=self.toolbar, id=wx.ID_ANY, value='Tools',
@@ -101,9 +97,20 @@
def ToolbarData(self):
"""Toolbar data"""
- self.displaymap = self.rendermap = self.erase = \
- self.pointer = self.query = self.pan = self.zoomin = self.zoomout = \
- self.zoomback = self.zoommenu = self.analyze = self.dec = self.savefile = self.printmap = None
+ self.displaymap = wx.NewId()
+ self.rendermap = wx.NewId()
+ self.erase = wx.NewId()
+ self.pointer = wx.NewId()
+ self.query = wx.NewId()
+ self.pan = wx.NewId()
+ self.zoomin = wx.NewId()
+ self.zoomout = wx.NewId()
+ self.zoomback = wx.NewId()
+ self.zoommenu = wx.NewId()
+ self.analyze = wx.NewId()
+ self.dec = wx.NewId()
+ self.savefile = wx.NewId()
+ self.printmap = wx.NewId()
# tool, label, bitmap, kind, shortHelp, longHelp, handler
return (
@@ -187,9 +194,15 @@
def ToolbarData(self):
"""Toolbar data"""
- self.displaymap = self.rendermap = self.erase = \
- self.gcpset = self.query = self.pan = self.zoomin = self.zoomout = \
- self.zoomback = self.zoommenu = self.analyze = self.dec = self.savefile = self.printmap =None
+ self.displaymap = wx.NewId()
+ self.rendermap = wx.NewId()
+ self.erase = wx.NewId()
+ self.gcpset = wx.NewId()
+ self.pan = wx.NewId()
+ self.zoomin = wx.NewId()
+ self.zoomout = wx.NewId()
+ self.zoomback = wx.NewId()
+ self.zoommenu = wx.NewId()
# tool, label, bitmap, kind, shortHelp, longHelp, handler
return (
@@ -257,13 +270,12 @@
# only one dialog can be open
self.settingsDialog = None
- # create toolbars (two rows)
+ # create toolbars (two rows optionaly)
self.toolbar = []
self.numOfRows = 1 # number of rows for toolbar
for row in range(0, self.numOfRows):
self.toolbar.append(wx.ToolBar(parent=self.parent, id=wx.ID_ANY))
self.toolbar[row].SetToolBitmapSize(globalvar.toolbarSize)
- self.toolbar[row].SetToolBitmapSize(wx.Size(24,24))
self.toolbar[row].Bind(wx.EVT_TOOL, self.OnTool)
# create toolbar
@@ -280,6 +292,9 @@
for row in range(0, self.numOfRows):
self.toolbar[row].Realize()
+ # disable undo/redo
+ self.toolbar[0].EnableTool(self.undo, False)
+
# toogle to pointer by default
self.OnTool(None)
@@ -289,11 +304,21 @@
"""
data = []
if row is None or row == 0:
- self.addPoint = self.addLine = self.addBoundary = self.addCentroid = None
- self.moveVertex = self.addVertex = self.removeVertex = None
- self.splitLine = self.editLine = self.moveLine = self.deleteLine = None
- self.additionalTools = None
- self.displayCats = self.displayAttr = self.copyCats = None
+ self.addPoint = wx.NewId()
+ self.addLine = wx.NewId()
+ self.addBoundary = wx.NewId()
+ self.addCentroid = wx.NewId()
+ self.moveVertex = wx.NewId()
+ self.addVertex = wx.NewId()
+ self.removeVertex = wx.NewId()
+ self.splitLine = wx.NewId()
+ self.editLine = wx.NewId()
+ self.moveLine = wx.NewId()
+ self.deleteLine = wx.NewId()
+ self.additionalTools = wx.NewId()
+ self.displayCats = wx.NewId()
+ self.displayAttr = wx.NewId()
+ self.copyCats = wx.NewId()
data = [("", "", "", "", "", "", ""),
(self.addPoint, "digAddPoint", Icons["digAddPoint"].GetBitmap(),
@@ -344,12 +369,17 @@
self.OnAdditionalToolMenu)]
if row is None or row == 1:
- self.undo = self.settings = self.exit = None
+ self.undo = wx.NewId()
+ self.settings = wx.NewId()
+ self.exit = wx.NewId()
data.append(("", "", "", "", "", "", ""))
data.append((self.undo, "digUndo", Icons["digUndo"].GetBitmap(),
wx.ITEM_NORMAL, Icons["digUndo"].GetLabel(), Icons["digUndo"].GetDesc(),
self.OnUndo))
+ # data.append((self.undo, "digRedo", Icons["digRedo"].GetBitmap(),
+ # wx.ITEM_NORMAL, Icons["digRedo"].GetLabel(), Icons["digRedo"].GetDesc(),
+ # self.OnRedo))
data.append((self.settings, "digSettings", Icons["digSettings"].GetBitmap(),
wx.ITEM_NORMAL, Icons["digSettings"].GetLabel(), Icons["digSettings"].GetDesc(),
self.OnSettings))
@@ -361,7 +391,7 @@
def OnTool(self, event):
"""Tool selected -> toggle tool to pointer"""
- id = self.parent.maptoolbar.pointerId
+ id = self.parent.maptoolbar.pointer
self.parent.maptoolbar.toolbar.ToggleTool(id, True)
self.parent.maptoolbar.mapdisplay.OnPointer(event)
if event:
@@ -481,14 +511,23 @@
self.parent.MapWindow.mouse['box'] = 'point'
def OnUndo(self, event):
- """Undo changes
+ """Undo previous changes"""
+ self.parent.digit.Undo()
- @todo
- """
- wx.MessageBox(parent=self.parent, message=_("Undo is not implemented yet."),
- caption=_("Message"), style=wx.ID_OK | wx.ICON_INFORMATION)
event.Skip()
+ def EnableUndo(self, enable=True):
+ """Enable 'Undo' in toolbar
+
+ @param enable False for disable
+ """
+ if enable:
+ if self.toolbar[0].GetToolEnabled(self.undo) is False:
+ self.toolbar[0].EnableTool(self.undo, True)
+ else:
+ if self.toolbar[0].GetToolEnabled(self.undo) is True:
+ self.toolbar[0].EnableTool(self.undo, False)
+
def OnSettings(self, event):
"""Show settings dialog"""
@@ -702,7 +741,6 @@
if not self.parent.MapWindow.resize:
self.parent.MapWindow.UpdateMap(render=True)
-
return True
def StopEditing (self, layerSelected):
@@ -730,6 +768,7 @@
self.parent.MapWindow.pdcVector = None
self.parent.digit.driver.SetDevice(None)
+ self.parent.digit.__del__() # FIXME: destructor is not called here (del)
self.parent.digit = None
return True
Modified: grass/trunk/gui/wxpython/gui_modules/wxgui_utils.py
===================================================================
--- grass/trunk/gui/wxpython/gui_modules/wxgui_utils.py 2008-04-03 08:14:54 UTC (rev 30849)
+++ grass/trunk/gui/wxpython/gui_modules/wxgui_utils.py 2008-04-03 12:22:37 UTC (rev 30850)
@@ -89,7 +89,7 @@
# init associated map display
self.mapdisplay = mapdisp.MapFrame(self,
- id=wx.ID_ANY, pos=wx.DefaultPosition, size=(640,480),
+ id=wx.ID_ANY, pos=wx.DefaultPosition, size=(680, 520),
style=wx.DEFAULT_FRAME_STYLE,
tree=self, notebook=self.notebook,
gismgr=self.gismgr, page=self.treepg,
Modified: grass/trunk/gui/wxpython/icons/icon.py
===================================================================
--- grass/trunk/gui/wxpython/icons/icon.py 2008-04-03 08:14:54 UTC (rev 30849)
+++ grass/trunk/gui/wxpython/icons/icon.py 2008-04-03 12:22:37 UTC (rev 30850)
@@ -302,8 +302,8 @@
"digAdditionalTools" : MetaIcon (img=icons_img["digAdditionalTools"], label="Additional tools " \
"(copy, flip, connect, etc.)",
desc="Left: Select; Middle: Unselect; Right: Confirm"),
- "digUndo" : MetaIcon (img=icons_img["digUndo"], label="Undo",
- desc="Undo previous changes (not implemented yet)"),
+ "digUndo" : MetaIcon (img=icons_img["digUndo"], label="Undo",
+ desc="Undo previous changes"),
# analyze raster
"analyze" : MetaIcon (img=icons_img["analyze"], label="Analyze map"),
"measure" : MetaIcon (img=icons_img["measure"], label="Measure distance"),
Modified: grass/trunk/gui/wxpython/vdigit/digit.cpp
===================================================================
--- grass/trunk/gui/wxpython/vdigit/digit.cpp 2008-04-03 08:14:54 UTC (rev 30849)
+++ grass/trunk/gui/wxpython/vdigit/digit.cpp 2008-04-03 12:22:37 UTC (rev 30850)
@@ -30,6 +30,21 @@
InitCats();
}
+ changesetCurrent = -2; // initial value for undo/redo
+ changesetDead = -2;
+
// avoid GUI crash
// Vect_set_fatal_error(GV_FATAL_PRINT);
}
+
+/**
+ Digit class destructor
+
+ Frees changeset structure
+*/
+Digit::~Digit()
+{
+ for(int changeset = 0; changeset < (int) changesets.size(); changeset++) {
+ FreeChangeset(changeset);
+ }
+}
Modified: grass/trunk/gui/wxpython/vdigit/digit.h
===================================================================
--- grass/trunk/gui/wxpython/vdigit/digit.h 2008-04-03 08:14:54 UTC (rev 30849)
+++ grass/trunk/gui/wxpython/vdigit/digit.h 2008-04-03 12:22:37 UTC (rev 30850)
@@ -3,6 +3,7 @@
#define GSQL_MAX 4000
+#include <vector>
#include <map>
class Digit
@@ -16,8 +17,27 @@
int SetCategory(int, int);
struct Map_info** OpenBackgroundVectorMap(const char *);
+ /* undo/redo */
+ enum action_type { ADD, DELETE };
+ struct action_meta {
+ action_type type;
+ int line;
+ /* TODO: replace by new Vect_restore_line() */
+ int ltype; // line type
+ struct line_pnts *Points;
+ struct line_cats *Cats;
+ };
+ std::map<int, std::vector<action_meta> > changesets;
+ int changesetCurrent; /* first changeset to apply */
+ int changesetDead; /* first dead changeset */
+
+ int AddActionToChangeset(int, action_type, int);
+ int ApplyChangeset(int, bool);
+ void FreeChangeset(int);
+
public:
Digit(DisplayDriver *);
+ ~Digit();
int InitCats();
@@ -57,6 +77,8 @@
std::map<int, std::vector<int> > GetLineCats(int);
int SetLineCats(int, int, std::vector<int>, bool);
std::vector<int> GetLayers();
+
+ int Undo(int);
};
#endif /* __DIGIT_H__ */
Modified: grass/trunk/gui/wxpython/vdigit/line.cpp
===================================================================
--- grass/trunk/gui/wxpython/vdigit/line.cpp 2008-04-03 08:14:54 UTC (rev 30849)
+++ grass/trunk/gui/wxpython/vdigit/line.cpp 2008-04-03 12:22:37 UTC (rev 30850)
@@ -41,6 +41,8 @@
size_t i;
size_t npoints;
+ int newline;
+
struct line_pnts *Points;
struct line_cats *Cats;
@@ -57,7 +59,7 @@
}
G_debug(2, "wxDigit.AddLine(): npoints=%d, layer=%d, cat=%d, snap=%d",
- npoints, layer, cat, snap);
+ (int) npoints, layer, cat, snap);
/* TODO: 3D */
if (!(type & GV_POINTS) && !(type & GV_LINES)) {
@@ -119,10 +121,14 @@
threshold, (snap == SNAP) ? 0 : 1);
}
- if (Vect_write_line(display->mapInfo, type, Points, Cats) < 0) {
+ newline = Vect_write_line(display->mapInfo, type, Points, Cats);
+ if (newline < 0) {
return -1;
}
+ /* register changeset */
+ AddActionToChangeset(changesets.size(), ADD, newline);
+
Vect_destroy_line_struct(Points);
Vect_destroy_cats_struct(Cats);
@@ -265,6 +271,7 @@
{
int ret;
int n_dblinks;
+ int changeset;
struct line_cats *Cats, *Cats_del;
// struct ilist *List;
@@ -310,6 +317,12 @@
Vect_destroy_cats_struct(Cats);
}
+ /* register changeset */
+ changeset = changesets.size();
+ for (int i = 0; i < display->selected->n_values; i++) {
+ AddActionToChangeset(changeset, DELETE, display->selected->value[i]);
+ }
+
ret = Vedit_delete_lines(display->mapInfo, display->selected);
if (ret > 0 && delete_records) {
Added: grass/trunk/gui/wxpython/vdigit/undo.cpp
===================================================================
--- grass/trunk/gui/wxpython/vdigit/undo.cpp (rev 0)
+++ grass/trunk/gui/wxpython/vdigit/undo.cpp 2008-04-03 12:22:37 UTC (rev 30850)
@@ -0,0 +1,191 @@
+/**
+ \file undo.cpp
+
+ \brief Undo/Redo functionality
+
+ \todo Implement Vect_restore_line() in Vlib
+
+ This program is free software under the GNU General Public
+ License (>=v2). Read the file COPYING that comes with GRASS
+ for details.
+
+ (C) 2008 by The GRASS development team
+
+ \author Martin Landa <landa.martin gmail.com>
+
+ \date 2008
+*/
+
+#include "driver.h"
+#include "digit.h"
+
+/**
+ \brief Undo/Redo operations
+
+ \param level level for undo/redo
+
+ \return id of current chanset
+ \return -2 on error
+*/
+int Digit::Undo(int level)
+{
+ int changesetLast;
+
+ changesetLast = (int) changesets.size() - 1;
+
+ if (changesetLast < 0)
+ return changesetLast;
+
+ if (changesetCurrent == -2) { /* value uninitialized */
+ changesetCurrent = changesetLast;
+ }
+
+ if (level > 0 && changesetCurrent < 0) {
+ changesetCurrent = 0;
+ }
+
+ G_debug(2, "Digit.Undo(): changeset_last=%d changeset_dead=%d, changeset_current=%d, level=%d",
+ changesetLast, changesetDead, changesetCurrent, level);
+
+ if (level < 0) { /* undo */
+ if (changesetCurrent + level < -1)
+ return changesetCurrent;
+ for (int changeset = changesetCurrent; changeset > changesetCurrent + level; --changeset) {
+ ApplyChangeset(changeset, true);
+ }
+ }
+ else if (level > 0) { /* redo */
+ if (changesetCurrent + level > (int) changesets.size())
+ return changesetCurrent;
+ for (int changeset = changesetCurrent; changeset < changesetCurrent + level; ++changeset) {
+ ApplyChangeset(changeset, false);
+ }
+ }
+
+ changesetCurrent += level;
+
+ G_debug(2, "Digit.Undo(): changeset_dead=%d, changeset_current=%d",
+ changesetDead, changesetCurrent);
+
+ return (changesetDead >= changesetCurrent) ? -1 : changesetCurrent;
+}
+
+/**
+ \brief Apply changeset (undo/redo changeset)
+
+ \param changeset changeset id
+ \param undo if true -> undo otherwise redo
+
+ \return 1 changeset applied
+ \return 0 changeset not applied
+ \return -1 on error
+*/
+int Digit::ApplyChangeset(int changeset, bool undo)
+{
+ int ret;
+
+ if (changeset < 0 || changeset > (int) changesets.size())
+ return -1;
+
+ ret = 0;
+ std::vector<action_meta> action = changesets[changeset];
+ for (std::vector<action_meta>::const_iterator i = action.begin(), e = action.end();
+ i != e; ++i) {
+ if ((undo && (*i).type == ADD) ||
+ (!undo && (*i).type == DELETE)) {
+ if (Vect_line_alive(display->mapInfo, (*i).line)) {
+ G_debug(3, "Digit.ApplyChangeset(): changeset=%d, action=add, line=%d -> deleted",
+ changeset, (*i).line);
+ Vect_delete_line(display->mapInfo, (*i).line);
+ if (!ret)
+ ret = 1;
+ }
+ else {
+ G_debug(3, "Digit.ApplyChangeset(): changeset=%d, action=add, line=%d dead",
+ changeset, (*i).line);
+ }
+ }
+ else { /* DELETE */
+ if (!Vect_line_alive(display->mapInfo, (*i).line)) {
+ G_debug(3, "Digit.ApplyChangeset(): changeset=%d, action=delete, line=%d -> added",
+ changeset, (*i).line);
+ if (Vect_write_line(display->mapInfo, (*i).ltype, (*i).Points, (*i).Cats) < 0)
+ return -1;
+ if (!ret)
+ ret = 1;
+ }
+ else {
+ G_debug(3, "Digit.ApplyChangeset(): changeset=%d, action=delete, line=%d alive",
+ changeset, (*i).line);
+ }
+ }
+ }
+
+ if (changeset < (int) changesets.size() - 1)
+ changesetDead = changeset;
+
+ return ret;
+}
+
+/**
+ \brief Add action to changeset
+
+ \todo Use Vect_restore_line() (TODO) instead!
+
+ \param type action type (ADD, DELETE)
+
+ \return 0 on success
+ \return -1 on error
+*/
+int Digit::AddActionToChangeset(int changeset, Digit::action_type type, int line)
+{
+ int ltype;
+ struct line_pnts *Points;
+ struct line_cats *Cats;
+
+ if (!display->mapInfo) {
+ return -1;
+ }
+
+ Points = Vect_new_line_struct();
+ Cats = Vect_new_cats_struct();
+
+ /* do copy */
+ if (!Vect_line_alive(display->mapInfo, line))
+ return -1;
+
+ ltype = Vect_read_line(display->mapInfo, Points, Cats, line);
+
+ action_meta data = { type, line, ltype, Points, Cats };
+ if (changesets.find(changeset) == changesets.end()) {
+ changesets[changeset] = std::vector<action_meta>();
+ changesetCurrent = changeset;
+ }
+ changesets[changeset].push_back(data);
+ G_debug (3, "Digit.AddActionToChangeset(): changeset=%d, type=%d, line=%d",
+ changeset, type, line);
+
+ return 0;
+}
+
+/**
+ \brief Free changeset structures
+
+ \param changeset changeset id
+*/
+void Digit::FreeChangeset(int changeset)
+{
+ if (changesets.find(changeset) == changesets.end())
+ return;
+
+ std::vector<action_meta> action = changesets[changeset];
+ for (std::vector<action_meta>::iterator i = action.begin(), e = action.end();
+ i != e; ++i) {
+ Vect_destroy_line_struct((*i).Points);
+ Vect_destroy_cats_struct((*i).Cats);
+ (*i).Points = NULL;
+ (*i).Cats = NULL;
+ }
+
+ return;
+}
More information about the grass-commit
mailing list