[GRASS-SVN] r67285 - in grass/trunk/gui/wxpython: gui_core modules

svn_grass at osgeo.org svn_grass at osgeo.org
Sun Dec 20 10:13:18 PST 2015


Author: turek
Date: 2015-12-20 10:13:18 -0800 (Sun, 20 Dec 2015)
New Revision: 67285

Modified:
   grass/trunk/gui/wxpython/gui_core/forms.py
   grass/trunk/gui/wxpython/gui_core/gselect.py
   grass/trunk/gui/wxpython/gui_core/widgets.py
   grass/trunk/gui/wxpython/modules/import_export.py
Log:
wx.gui data import: show reprojection dialog

Modified: grass/trunk/gui/wxpython/gui_core/forms.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/forms.py	2015-12-20 16:35:37 UTC (rev 67284)
+++ grass/trunk/gui/wxpython/gui_core/forms.py	2015-12-20 18:13:18 UTC (rev 67285)
@@ -1710,11 +1710,11 @@
                                     flag = wx.EXPAND | wx.ALL, border = 3)
                     porf = self.task.get_param('input', element = 'name', raiseError = False)
                     winDataSource = self.FindWindowById(porf['wxId'][0])
-                    winDataSource.reloadDataRequired.connect(lambda data: self.win1.LoadData(data, False))
+                    winDataSource.reloadDataRequired.connect(lambda listData: self.win1.LoadData(listData, False))
                     p['wxId'] = [self.win1.GetId()]
                     def OnCheckItem(index, flag):
                         layers = list()
-                        for layer, match in self.win1.GetLayers():
+                        for layer, match, listId in self.win1.GetLayers():
                             layers.append(layer)
                         porf = self.task.get_param('layer', element = 'name', raiseError = False)
                         porf['value'] = ','.join(layers)

Modified: grass/trunk/gui/wxpython/gui_core/gselect.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/gselect.py	2015-12-20 16:35:37 UTC (rev 67284)
+++ grass/trunk/gui/wxpython/gui_core/gselect.py	2015-12-20 18:13:18 UTC (rev 67285)
@@ -1738,7 +1738,7 @@
             self.SetDatabase(db)
 
         if not self.dest:
-            self.reloadDataRequired.emit(data=None)
+            self.reloadDataRequired.emit(listData=None, data=None)
             self._reloadLayers()
 
     def OnSettingsChanged(self, data):
@@ -1778,7 +1778,7 @@
             self.dbWidgets['options'].SetValue(data[3])
 
         if not self.dest:
-            self.reloadDataRequired.emit(data=None)
+            self.reloadDataRequired.emit(listData=None, data=None)
             self._reloadLayers()
 
     def AttachSettings(self):
@@ -1913,11 +1913,40 @@
 
     def _reloadLayers(self):
         """Reload list of layers"""
+
+        def hasRastSameProjAsLocation(dsn):
+
+            ret = RunCommand('r.external',
+                             quiet = True,
+                             read = True,
+                             flags = 't',
+                             input = dsn)
+
+            # v.external returns info for individual bands, however projection is shared by all bands ->
+            # (it is possible to take first line)
+            
+            lines = ret.splitlines()
+            projectionMatch = '0'
+            if lines:
+                bandNumber, bandType, projectionMatch = map(lambda x: x.strip(), lines[0].split(','))
+
+            return projectionMatch
+
+        def getProjMatchCaption(projectionMatch):
+
+            if projectionMatch == '0':
+                projectionMatchCaption = _("No")
+            else:
+                projectionMatchCaption = _("Yes")
+
+            return projectionMatchCaption
+
         dsn = self.GetDsn()
         if not dsn:
             return
 
         data = list()
+        listData = list()
         layerId = 1
 
         if self.ogr:
@@ -1927,37 +1956,40 @@
                              flags = 't',
                              input = dsn)
             if not ret:
-                self.reloadDataRequired.emit(data=None)
+                self.reloadDataRequired.emit(listData=None, data=None)
                 return
 
             layerId = 1
             for line in ret.splitlines():
-                layerName, featureType, projection, geometryColumn = map(lambda x: x.strip(), line.split(','))
-                if projection == '0':
-                    projectionMatch = _("No")
-                else:
-                    projectionMatch = _("Yes")
+                layerName, featureType, projectionMatch, geometryColumn = map(lambda x: x.strip(), line.split(','))
+                projectionMatchCaption = getProjMatchCaption(projectionMatch)
                 grassName = GetValidLayerName(layerName)
                 if geometryColumn:
                     featureType = geometryColumn + '/' + featureType
-                data.append((layerId, layerName, featureType, projectionMatch, grassName))
+                listData.append((layerId, layerName, featureType, projectionMatchCaption, grassName))
+                data.append((layerId, layerName, featureType, int(projectionMatch), grassName))
                 layerId += 1
         else:
             if self._sourceType == 'file':
                 baseName = os.path.basename(dsn)
                 grassName = GetValidLayerName(baseName.split('.', -1)[0])
-                data.append((layerId, baseName, grassName))
+                projectionMatch = hasRastSameProjAsLocation(dsn)
+                projectionMatchCaption = getProjMatchCaption(projectionMatch)
+                listData.append((layerId, baseName, projectionMatchCaption, grassName))
+                data.append((layerId, baseName, int(projectionMatch), grassName))
             elif self._sourceType == 'dir':
                 ext = self.dirWidgets['extension'].GetValue()
                 for filename in glob.glob(os.path.join(dsn, "%s") % self._getExtPatternGlob(ext)):
                     baseName = os.path.basename(filename)
-
                     grassName = GetValidLayerName(baseName.split('.', -1)[0])
-                    data.append((layerId, baseName, grassName))
+                    projectionMatch = hasRastSameProjAsLocation(dsn)
+                    projectionMatchCaption = getProjMatchCaption(projectionMatch)
+                    listData.append((layerId, baseName, projectionMatchCaption, grassName))
+                    data.append((layerId, baseName,  int(projectionMatch), grassName))
                     layerId += 1
         
         # emit signal
-        self.reloadDataRequired.emit(data=data)
+        self.reloadDataRequired.emit(listData=listData, data=data)
 
     def ExtensionChanged(self, event):
         if not self.dest:

Modified: grass/trunk/gui/wxpython/gui_core/widgets.py
===================================================================
--- grass/trunk/gui/wxpython/gui_core/widgets.py	2015-12-20 16:35:37 UTC (rev 67284)
+++ grass/trunk/gui/wxpython/gui_core/widgets.py	2015-12-20 18:13:18 UTC (rev 67285)
@@ -921,7 +921,51 @@
 
         event.Skip()
 
+    def GetData(self, checked=None):
+        """Get list data"""
+        data = []
+        checkedList = []
+        
+        item = -1
+        while True:
+            
+            row = []
+            item = self.GetNextItem(item)
+            if item == -1:
+                break
 
+            isChecked = self.IsChecked(item)
+            if checked is not None and  checked != isChecked:
+                continue
+
+            checkedList.append(isChecked)
+
+            for i in range(self.GetColumnCount()):
+                row.append(self.GetItem(item, i).GetText())
+            
+            row.append(item)
+            data.append(tuple(row))
+
+        if checked is not None:
+            return tuple(data)
+        else:
+            return (tuple(data), tuple(checkedList))
+
+    def LoadData(self, data=None, selectOne=True):
+        """Load data into list"""
+        self.DeleteAllItems()
+        if data is None:
+            return
+        
+        for item in data:
+            index = self.InsertStringItem(sys.maxint, str(item[0]))
+            for i in range(1, self.GetColumnCount()):
+                self.SetStringItem(index, i, item[i])
+        
+        # check by default only on one item
+        if len(data) == 1 and selectOne:
+            self.CheckItem(index, True)
+
 class SearchModuleWidget(wx.Panel):
     """Search module widget (used e.g. in SearchModuleWindow)
 
@@ -1465,29 +1509,14 @@
         for i in range(len(columns)):
             self.InsertColumn(i, columns[i])
         
-        if len(columns) == 3:
-            width = (65, 200)
+        if len(columns) == 4:
+            width = (65, 200, 90)
         else:
             width = (65, 180, 90, 70)
         
         for i in range(len(width)):
             self.SetColumnWidth(col = i, width = width[i])
-        
-    def LoadData(self, data = None, selectOne = True):
-        """Load data into list"""
-        self.DeleteAllItems()
-        if data is None:
-            return
-        
-        for item in data:
-            index = self.InsertStringItem(sys.maxint, str(item[0]))
-            for i in range(1, self.GetColumnCount()):
-                self.SetStringItem(index, i, item[i])
-        
-        # check by default only on one item
-        if len(data) == 1 and selectOne:
-            self.CheckItem(index, True)
-        
+                
     def OnLeftDown(self, event):
         """Allow editing only output name
         
@@ -1509,21 +1538,19 @@
             event.Skip()
         
     def GetLayers(self):
-        """Get list of layers (layer name, output name)"""
-        data = []
-        item = -1
-        while True:
-            item = self.GetNextItem(item)
-            if item == -1:
-                break
-            if not self.IsChecked(item):
-                continue
-            # layer / output name
-            layer = self.GetItem(item, 1).GetText()
-            ftype = self.GetItem(item, 2).GetText()
+        """Get list of layers (layer name, output name, list id)"""
+        layers = []
+
+        data = self.GetData(checked=True);
+
+        for itm in data:
+
+            layer = itm[1]
+            ftype = itm[2]
             if '/' in ftype:
                 layer += '|%s' % ftype.split('/', 1)[0]
-            output = self.GetItem(item, self.GetColumnCount() - 1).GetText()
-            data.append((layer, output))
-        
-        return data
+            output = itm[self.GetColumnCount() - 1]
+            layers.append((layer, output, itm[-1]))
+
+        return layers
+

Modified: grass/trunk/gui/wxpython/modules/import_export.py
===================================================================
--- grass/trunk/gui/wxpython/modules/import_export.py	2015-12-20 16:35:37 UTC (rev 67284)
+++ grass/trunk/gui/wxpython/modules/import_export.py	2015-12-20 18:13:18 UTC (rev 67285)
@@ -8,6 +8,7 @@
  - :class:`GdalImportDialog`
  - :class:`GdalOutputDialog`
  - :class:`DxfImportDialog`
+ - :class:`ReprojectionDialog`
 
 (C) 2008-2015 by the GRASS Development Team
 
@@ -29,7 +30,7 @@
 from core import globalvar
 from core.gcmd import RunCommand, GMessage, GWarning
 from gui_core.gselect import OgrTypeSelect, GdalSelect, SubGroupSelect
-from gui_core.widgets import LayersList
+from gui_core.widgets import LayersList, GListCtrl
 from core.utils import GetValidLayerName, _
 from core.settings import UserSettings, GetDisplayVectSettings
 
@@ -67,6 +68,8 @@
         if itype == 'ogr':
             columns.insert(2, _('Feature type'))
             columns.insert(3, _('Projection match'))
+        elif itype == 'gdal':
+            columns.insert(2, _('Projection match'))
 
         self.list = LayersList(parent = self.panel, columns = columns)
         self.list.LoadData()
@@ -231,7 +234,7 @@
         # * try to determine names using regexp or
         # * persuade import tools to report map names
         self.commandId += 1
-        layer, output = self.list.GetLayers()[self.commandId]
+        layer, output = self.list.GetLayers()[self.commandId][:2]
         
         if '@' not in output:
             name = output + '@' + grass.gisenv()['MAPSET']
@@ -295,7 +298,7 @@
         """Dialog for bulk import of various raster/vector data
 
         .. todo::
-            Split into GdalImportDialog and OgrImportDialog
+            Split into GdalImportDialog and OgrImportDialog, split importing logic from gui code
 
         :param parent: parent window
         :param ogr: True for OGR (vector) otherwise GDAL (raster)
@@ -304,7 +307,9 @@
         self._giface = giface
         self.link = link
         self.ogr  = ogr
-        
+
+        self.layersData = []
+
         if ogr:
             ImportDialog.__init__(self, parent, giface=giface, itype='ogr')
             if link:
@@ -321,7 +326,7 @@
         self.dsnInput = GdalSelect(parent = self, panel = self.panel,
                                    ogr = ogr, link = link)
         self.dsnInput.AttachSettings()
-        self.dsnInput.reloadDataRequired.connect(lambda data: self.list.LoadData(data))
+        self.dsnInput.reloadDataRequired.connect(self.reload)
 
         if link:
             self.add.SetLabel(_("Add linked layers into layer tree"))
@@ -339,10 +344,22 @@
 
         self.doLayout()
 
+    def reload(self, data, listData):
+
+        self.list.LoadData(listData);
+        self.layersData = data;
+
     def OnRun(self, event):
         """Import/Link data (each layes as separate vector map)"""
         self.commandId = -1
         data = self.list.GetLayers()
+
+
+        data = self._getLayersToReprojetion()
+
+        if data is None:
+            return;
+
         if not data:
             GMessage(_("No layers selected. Operation canceled."),
                      parent = self)
@@ -360,9 +377,10 @@
             self.popOGR = True
             os.environ['GRASS_VECTOR_OGR'] = '1'
         
-        for layer, output in data:
+        for layer, output, listId in data:
             userData = {}
             if self.importType == 'ogr':
+
                 if ext and layer.rfind(ext) > -1:
                     layer = layer.replace('.' + ext, '')
                 if '|' in layer:
@@ -374,6 +392,12 @@
                            'input=%s' % dsn,
                            'output=%s' % output,
                            'layer=%s' % layer]
+
+                elif self.layersData[listId][3] == 0:
+                    cmd = ['v.import',
+                           'input=%s' % dsn,
+                           'layer=%s' % layer,
+                           'output=%s' % output]
                 else:
                     cmd = ['v.in.ogr',
                            'input=%s' % dsn,
@@ -430,6 +454,49 @@
             # run in Layer Manager
             self._giface.RunCmd(cmd, onDone = self.OnCmdDone, userData = userData)
 
+
+    def _getLayersToReprojetion(self):
+        """If there are layers with different projection from loation projection, 
+           show dialog to user to explicitly select layers which will be reprojected..."""
+        differentProjLayers = []
+        data = self.list.GetData(checked=True)
+
+        if self.importType == 'ogr':
+                projMatch_idx = 3
+                grassName_idx = 4
+        else:#gdal
+                projMatch_idx = 2
+                grassName_idx = 3
+
+        for itm in data:
+
+            layerId = itm[-1]
+
+            # select only layers with different projetion
+            if self.layersData[layerId][projMatch_idx] == 0:
+                dt = [itm[0], itm[grassName_idx]]
+                differentProjLayers.append(tuple(dt))
+        
+        layers = self.list.GetLayers()
+        
+        if differentProjLayers:
+
+            dlg = RerojectionDialog(
+                parent=self, giface=self._giface, data=differentProjLayers)
+                
+            ret = dlg.ShowModal()
+
+            if ret == wx.ID_OK:
+
+                # do not import unchecked layers
+                for itm in reversed(list(dlg.GetData(checked=False))):
+                    idx = itm[-1]
+                    layers.pop(idx)
+            else:
+                return None;
+
+        return layers
+
     def OnCmdDone(self, event):
         """Load layers and close if required"""
         if not hasattr(self, 'AddLayers'):
@@ -635,3 +702,95 @@
             data.append((layerId, layerName.strip(), grassName.strip()))
         
         self.list.LoadData(data)
+
+class RerojectionDialog(wx.Dialog):
+    """ """
+    def __init__(self, parent, giface, data,
+                 id = wx.ID_ANY, title = _("Reprojection"),
+                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
+        self.parent = parent    # GMFrame 
+        self._giface = giface  # used to add layers
+        
+        wx.Dialog.__init__(self, parent, id, title, style = style,
+                           name = "MultiImportDialog")
+
+
+        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
+
+        # list of layers
+        columns = [_('Layer id'),
+                   _('Name for output GRASS map')]
+
+        self.list = GListCtrl(parent = self.panel)
+
+        for i in range(len(columns)):
+            self.list.InsertColumn(i, columns[i])
+        
+        width = (65, 180)
+        
+        for i in range(len(width)):
+            self.list.SetColumnWidth(col=i, width=width[i])
+
+        self.list.LoadData(data)
+
+        self.layerBox = wx.StaticBox(parent=self.panel, id=wx.ID_ANY)
+
+        self.labelText = wx.StaticText(parent=self.panel, id=wx.ID_ANY, label=_("Projection of following layers do not match with projection of current location. "))
+        
+        label = _("Layers to be reprojected")
+        self.layerBox.SetLabel(" %s - %s " % (label, _("right click to (un)select all")))
+
+        #
+        # buttons
+        #
+        # cancel
+        self.btn_close = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
+
+        # run
+        self.btn_run = wx.Button(parent = self.panel, id = wx.ID_OK, label = _("&Import && reproject"))
+        self.btn_run.SetToolTipString(_("Reproject selected layers"))
+        self.btn_run.SetDefault()
+
+        self.doLayout()
+
+    def doLayout(self):
+        """Do layout"""
+        dialogSizer = wx.BoxSizer(wx.VERTICAL)
+
+        dialogSizer.Add(item = self.labelText,
+                        flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        layerSizer = wx.StaticBoxSizer(self.layerBox, wx.HORIZONTAL)
+
+
+        layerSizer.Add(item = self.list, proportion = 1,
+                      flag = wx.ALL | wx.EXPAND, border = 5)
+        
+        dialogSizer.Add(item = layerSizer, proportion = 1,
+                        flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
+
+        #
+        # buttons
+        #
+        btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
+        
+        btnsizer.Add(item = self.btn_close, proportion = 0,
+                     flag = wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER,
+                     border = 10)
+        
+        btnsizer.Add(item = self.btn_run, proportion = 0,
+                     flag = wx.RIGHT | wx.ALIGN_CENTER,
+                     border = 10)
+        
+        dialogSizer.Add(item = btnsizer, proportion = 0,
+                        flag = wx.ALIGN_CENTER_VERTICAL | wx.BOTTOM | wx.ALIGN_RIGHT,
+                        border = 10)
+   
+        self.panel.SetSizer(dialogSizer)
+        dialogSizer.Fit(self.panel)
+
+        self.Layout()
+
+    def GetData(self, checked):
+
+        return self.list.GetData(checked)



More information about the grass-commit mailing list