Ver código fonte

wxGUI/import_export: improve output map name existence validation (#675)

Tomas Zigo 4 anos atrás
pai
commit
a44d242501

+ 73 - 0
gui/wxpython/gui_core/widgets.py

@@ -21,6 +21,7 @@ Classes:
  - widgets::SimpleValidator
  - widgets::SimpleValidator
  - widgets::GenericValidator
  - widgets::GenericValidator
  - widgets::GenericMultiValidator
  - widgets::GenericMultiValidator
+ - widgets::LayersListValidator
  - widgets::GListCtrl
  - widgets::GListCtrl
  - widgets::SearchModuleWidget
  - widgets::SearchModuleWidget
  - widgets::ManageSettingsWidget
  - widgets::ManageSettingsWidget
@@ -979,6 +980,55 @@ class SingleSymbolPanel(wx.Panel):
         self.Refresh()
         self.Refresh()
 
 
 
 
+class LayersListValidator(GenericValidator):
+    """This validator check output map existence"""
+
+    def __init__(self, condition, callback):
+        """Standard constructor.
+
+        :param condition: function which accepts string value and returns T/F
+        :param callback: function which is called when condition is not fulfilled
+        """
+        GenericValidator.__init__(self, condition, callback)
+
+    def Clone(self):
+        """Standard cloner.
+
+        Note that every validator must implement the Clone() method.
+        """
+        return LayersListValidator(self._condition, self._callback)
+
+    def Validate(self, win, validate_all=False):
+        """Validate output map existence"""
+        mapset = grass.gisenv()['MAPSET']
+        maps = grass.list_grouped(type=self._condition)[mapset]
+
+        # Check all selected layers
+        if validate_all:
+            outputs = []
+            data = win.GetLayers()
+
+            if data is None:
+                return False
+
+            for layer, output, list_id in data:
+                if output in maps:
+                    outputs.append(output)
+
+            if outputs:
+                win.output_map = outputs
+                self._callback(layers_list=win)
+                return False
+        else:
+            output_map = win.GetItemText(
+                win.col, win.row)
+            if output_map in maps:
+                win.output_map = output_map
+                self._callback(layers_list=win)
+                return False
+        return True
+
+
 class GListCtrl(ListCtrl, listmix.ListCtrlAutoWidthMixin,
 class GListCtrl(ListCtrl, listmix.ListCtrlAutoWidthMixin,
                 CheckListCtrlMixin):
                 CheckListCtrlMixin):
     """Generic ListCtrl with popup menu to select/deselect all
     """Generic ListCtrl with popup menu to select/deselect all
@@ -1665,6 +1715,10 @@ class LayersList(GListCtrl, listmix.TextEditMixin):
         GListCtrl.__init__(self, parent)
         GListCtrl.__init__(self, parent)
 
 
         self.log = log
         self.log = log
+        self.row = None
+        self.col = None
+        self.output_map = None
+        self.validate = True
 
 
         # setup mixins
         # setup mixins
         listmix.TextEditMixin.__init__(self)
         listmix.TextEditMixin.__init__(self)
@@ -1719,3 +1773,22 @@ class LayersList(GListCtrl, listmix.TextEditMixin):
             layers.append((layer, output, itm[-1]))
             layers.append((layer, output, itm[-1]))
 
 
         return layers
         return layers
+
+    def ValidateOutputMapName(self):
+        """Validate output map name"""
+        wx.CallAfter(self.GetValidator().Validate, self)
+
+    def OpenEditor(self, row, col):
+        """Open editor"""
+        self.col = col
+        self.row = row
+        super().OpenEditor(row, col)
+
+    def CloseEditor(self, event=None):
+        """Close editor"""
+        if event:
+            if event.IsCommandEvent():
+                listmix.TextEditMixin.CloseEditor(self, event)
+                if self.validate:
+                    self.ValidateOutputMapName()
+            event.Skip()

+ 68 - 2
gui/wxpython/modules/import_export.py

@@ -37,10 +37,11 @@ import wx.lib.filebrowsebutton as filebrowse
 from grass.script import core as grass
 from grass.script import core as grass
 from grass.script import task as gtask
 from grass.script import task as gtask
 
 
-from core.gcmd import RunCommand, GMessage, GWarning
+from core.gcmd import GError, GMessage, GWarning, RunCommand
 from gui_core.forms import CmdPanel
 from gui_core.forms import CmdPanel
 from gui_core.gselect import OgrTypeSelect, GdalSelect, SubGroupSelect
 from gui_core.gselect import OgrTypeSelect, GdalSelect, SubGroupSelect
-from gui_core.widgets import LayersList, GListCtrl, GNotebook
+from gui_core.widgets import GListCtrl, GNotebook, LayersList, \
+    LayersListValidator
 from gui_core.wrap import Button, StaticText, StaticBox
 from gui_core.wrap import Button, StaticText, StaticBox
 from core.utils import GetValidLayerName
 from core.utils import GetValidLayerName
 from core.settings import UserSettings, GetDisplayVectSettings
 from core.settings import UserSettings, GetDisplayVectSettings
@@ -100,6 +101,7 @@ class ImportDialog(wx.Dialog):
                 group='cmd',
                 group='cmd',
                 key='overwrite',
                 key='overwrite',
                 subkey='enabled'))
                 subkey='enabled'))
+        self.overwrite.Bind(wx.EVT_CHECKBOX, self.OnCheckOverwrite)
 
 
         self.add = wx.CheckBox(parent=self.panel, id=wx.ID_ANY)
         self.add = wx.CheckBox(parent=self.panel, id=wx.ID_ANY)
         self.closeOnFinish = wx.CheckBox(parent=self.panel, id=wx.ID_ANY,
         self.closeOnFinish = wx.CheckBox(parent=self.panel, id=wx.ID_ANY,
@@ -241,6 +243,36 @@ class ImportDialog(wx.Dialog):
         """Get flags which will not be showed in Settings page"""
         """Get flags which will not be showed in Settings page"""
         raise NotImplementedError()
         raise NotImplementedError()
 
 
+    def _nameValidationFailed(self, layers_list):
+        """Output map name validation callback
+
+        :param layers_list: LayersList class instance
+        """
+        if isinstance(layers_list.output_map, list):
+            maps = [
+                '<{}>'.format(m) for m in layers_list.output_map]
+            message = _(
+                "Output map names %(names)s exist. "
+            ) % {
+                'names': ', '.join(maps)}
+        else:
+            message = _(
+                "Output map name <%(name)s> exist. "
+                ) % {
+                'name': layers_list.output_map}
+        GError(parent=self, message=message, caption=_("Invalid name"))
+
+    def _validateOutputMapName(self):
+        """Enable/disable output map name validation according the
+        overwrite state"""
+        if not self.overwrite.IsChecked() or \
+           UserSettings.Get(group='cmd', key='overwrite',
+                            subkey='enabled'):
+            if not self.list.GetValidator().\
+               Validate(win=self.list, validate_all=True):
+                return False
+        return True
+
     def OnClose(self, event=None):
     def OnClose(self, event=None):
         """Close dialog"""
         """Close dialog"""
         self.Close()
         self.Close()
@@ -249,6 +281,13 @@ class ImportDialog(wx.Dialog):
         """Import/Link data (each layes as separate vector map)"""
         """Import/Link data (each layes as separate vector map)"""
         pass
         pass
 
 
+    def OnCheckOverwrite(self, event):
+        """Check/uncheck overwrite checkbox widget"""
+        if self.overwrite.IsChecked():
+            self.list.validate = False
+        else:
+            self.list.validate = True
+
     def AddLayers(self, returncode, cmd=None, userData=None):
     def AddLayers(self, returncode, cmd=None, userData=None):
         """Add imported/linked layers into layer tree"""
         """Add imported/linked layers into layer tree"""
         if not self.add.IsChecked() or returncode != 0:
         if not self.add.IsChecked() or returncode != 0:
@@ -387,6 +426,12 @@ class GdalImportDialog(ImportDialog):
         self.layersData = []
         self.layersData = []
 
 
         ImportDialog.__init__(self, parent, giface=giface, itype='gdal')
         ImportDialog.__init__(self, parent, giface=giface, itype='gdal')
+
+        self.list.SetValidator(
+            LayersListValidator(
+                condition='raster',
+                callback=self._nameValidationFailed))
+
         if link:
         if link:
             self.SetTitle(_("Link external raster data"))
             self.SetTitle(_("Link external raster data"))
         else:
         else:
@@ -437,6 +482,9 @@ class GdalImportDialog(ImportDialog):
                      parent=self)
                      parent=self)
             return
             return
 
 
+        if not self._validateOutputMapName():
+            return
+
         dsn = self.dsnInput.GetDsn()
         dsn = self.dsnInput.GetDsn()
         ext = self.dsnInput.GetFormatExt()
         ext = self.dsnInput.GetFormatExt()
 
 
@@ -528,6 +576,12 @@ class OgrImportDialog(ImportDialog):
         self.layersData = []
         self.layersData = []
 
 
         ImportDialog.__init__(self, parent, giface=giface, itype='ogr')
         ImportDialog.__init__(self, parent, giface=giface, itype='ogr')
+
+        self.list.SetValidator(
+            LayersListValidator(
+                condition='vector',
+                callback=self._nameValidationFailed))
+
         if link:
         if link:
             self.SetTitle(_("Link external vector data"))
             self.SetTitle(_("Link external vector data"))
         else:
         else:
@@ -578,6 +632,9 @@ class OgrImportDialog(ImportDialog):
                      parent=self)
                      parent=self)
             return
             return
 
 
+        if not self._validateOutputMapName():
+            return
+
         dsn = self.dsnInput.GetDsn()
         dsn = self.dsnInput.GetDsn()
         ext = self.dsnInput.GetFormatExt()
         ext = self.dsnInput.GetFormatExt()
 
 
@@ -757,6 +814,12 @@ class DxfImportDialog(ImportDialog):
     def __init__(self, parent, giface):
     def __init__(self, parent, giface):
         ImportDialog.__init__(self, parent, giface=giface, itype='dxf',
         ImportDialog.__init__(self, parent, giface=giface, itype='dxf',
                               title=_("Import DXF layers"))
                               title=_("Import DXF layers"))
+
+        self.list.SetValidator(
+            LayersListValidator(
+                condition='vector',
+                callback=self._nameValidationFailed))
+
         self._giface = giface
         self._giface = giface
         self.dsnInput = filebrowse.FileBrowseButton(
         self.dsnInput = filebrowse.FileBrowseButton(
             parent=self.panel,
             parent=self.panel,
@@ -787,6 +850,9 @@ class DxfImportDialog(ImportDialog):
             GMessage(_("No layers selected."), parent=self)
             GMessage(_("No layers selected."), parent=self)
             return
             return
 
 
+        if not self._validateOutputMapName():
+            return
+
         # hide dialog
         # hide dialog
         self.Hide()
         self.Hide()