Browse Source

wxGUI: implement widget for SQL WHERE params

git-svn-id: https://svn.osgeo.org/grass/grass/trunk@72547 15284696-431f-4ddb-bdfa-cd5b030d7da7
Martin Landa 7 years ago
parent
commit
1ef10c774d

+ 69 - 19
gui/wxpython/dbmgr/sqlbuilder.py

@@ -46,7 +46,7 @@ class SQLBuilder(wx.Frame):
     Base class for classes, which builds SQL statements.
     Base class for classes, which builds SQL statements.
     """
     """
 
 
-    def __init__(self, parent, title, vectmap, modeChoices, id=wx.ID_ANY,
+    def __init__(self, parent, title, vectmap, modeChoices=[], id=wx.ID_ANY,
                  layer=1):
                  layer=1):
         wx.Frame.__init__(self, parent, id, title)
         wx.Frame.__init__(self, parent, id, title)
 
 
@@ -68,6 +68,7 @@ class SQLBuilder(wx.Frame):
         self.layer = layer
         self.layer = layer
         self.dbInfo = VectorDBInfo(self.vectmap)
         self.dbInfo = VectorDBInfo(self.vectmap)
         self.tablename = self.dbInfo.GetTable(self.layer)
         self.tablename = self.dbInfo.GetTable(self.layer)
+                
         self.driver, self.database = self.dbInfo.GetDbSettings(self.layer)
         self.driver, self.database = self.dbInfo.GetDbSettings(self.layer)
 
 
         self.colvalues = []     # array with unique values in selected column
         self.colvalues = []     # array with unique values in selected column
@@ -130,7 +131,7 @@ class SQLBuilder(wx.Frame):
         self.btn_clear.SetToolTipString(_("Set SQL statement to default"))
         self.btn_clear.SetToolTipString(_("Set SQL statement to default"))
         self.btn_apply = wx.Button(parent=self.panel, id=wx.ID_APPLY)
         self.btn_apply = wx.Button(parent=self.panel, id=wx.ID_APPLY)
         self.btn_apply.SetToolTipString(
         self.btn_apply.SetToolTipString(
-            _("Apply SQL statement in Attribute Table Manager"))
+            _("Apply SQL statement"))
         self.btn_close = wx.Button(parent=self.panel, id=wx.ID_CLOSE)
         self.btn_close = wx.Button(parent=self.panel, id=wx.ID_CLOSE)
         self.btn_close.SetToolTipString(_("Close the dialog"))
         self.btn_close.SetToolTipString(_("Close the dialog"))
 
 
@@ -230,17 +231,18 @@ class SQLBuilder(wx.Frame):
         columnsizer.Add(self.list_columns, proportion=1,
         columnsizer.Add(self.list_columns, proportion=1,
                         flag=wx.EXPAND)
                         flag=wx.EXPAND)
 
 
-        modesizer = wx.BoxSizer(wx.VERTICAL)
-
-        self.mode = wx.RadioBox(parent=self.panel, id=wx.ID_ANY,
-                                label=" %s " % _("Interactive insertion"),
-                                choices=modeChoices,
-                                style=wx.RA_SPECIFY_COLS,
-                                majorDimension=1)
-
-        self.mode.SetSelection(1)  # default 'values'
-        modesizer.Add(self.mode, proportion=1,
-                      flag=wx.ALIGN_CENTER_HORIZONTAL | wx.EXPAND, border=5)
+        if modeChoices:
+            modesizer = wx.BoxSizer(wx.VERTICAL)
+            
+            self.mode = wx.RadioBox(parent=self.panel, id=wx.ID_ANY,
+                                    label=" %s " % _("Interactive insertion"),
+                                    choices=modeChoices,
+                                    style=wx.RA_SPECIFY_COLS,
+                                    majorDimension=1)
+            
+            self.mode.SetSelection(1)  # default 'values'
+            modesizer.Add(self.mode, proportion=1,
+                          flag=wx.ALIGN_CENTER_HORIZONTAL | wx.EXPAND, border=5)
 
 
         # self.list_columns.SetMinSize((-1,130))
         # self.list_columns.SetMinSize((-1,130))
         # self.list_values.SetMinSize((-1,100))
         # self.list_values.SetMinSize((-1,100))
@@ -302,11 +304,12 @@ class SQLBuilder(wx.Frame):
         if showDbInfo:
         if showDbInfo:
             self.pagesizer.Add(databaseboxsizer,
             self.pagesizer.Add(databaseboxsizer,
                                flag=wx.ALL | wx.EXPAND, border=5)
                                flag=wx.ALL | wx.EXPAND, border=5)
-        self.pagesizer.Add(
-            modesizer,
-            proportion=0,
-            flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
-            border=5)
+        if modeChoices:
+            self.pagesizer.Add(
+                modesizer,
+                proportion=0,
+                flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND,
+                border=5)
         self.pagesizer.Add(
         self.pagesizer.Add(
             self.hsizer,
             self.hsizer,
             proportion=1,
             proportion=1,
@@ -329,7 +332,8 @@ class SQLBuilder(wx.Frame):
         #
         #
         # bindings
         # bindings
         #
         #
-        self.mode.Bind(wx.EVT_RADIOBOX, self.OnMode)
+        if modeChoices:
+            self.mode.Bind(wx.EVT_RADIOBOX, self.OnMode)
         # self.text_sql.Bind(wx.EVT_ACTIVATE, self.OnTextSqlActivate)TODO
         # self.text_sql.Bind(wx.EVT_ACTIVATE, self.OnTextSqlActivate)TODO
 
 
         self.btn_unique.Bind(wx.EVT_BUTTON, self.OnUniqueValues)
         self.btn_unique.Bind(wx.EVT_BUTTON, self.OnUniqueValues)
@@ -840,6 +844,52 @@ class SQLBuilderUpdate(SQLBuilder):
             'TRIM': ['TRIM (,)']
             'TRIM': ['TRIM (,)']
         }
         }
 
 
+class SQLBuilderWhere(SQLBuilder):
+    """Class for building SELECT SQL WHERE statement"""
+
+    def __init__(self, parent, vectmap, id=wx.ID_ANY,
+                 layer=1):
+
+        title = _("GRASS SQL Builder (%(type)s) - <%(map)s>") % \
+                {'type': "WHERE", 'map': vectmap}
+
+        super(SQLBuilderWhere, self).__init__(
+            parent, title, vectmap, id=wx.ID_ANY, 
+            layer=layer)
+        
+    def OnClear(self, event):
+        self.text_sql.SetValue('')
+        
+    def OnApply(self, event):
+        self.parent.SetValue(self.text_sql.GetValue())
+
+        if self.close_onapply.IsChecked():
+            self.Destroy()
+
+        event.Skip()
+
+    def _add(self, element, value):
+        """Add element to the query
+
+        :param element: element to add (column, value)
+        """
+        sqlstr = self.text_sql.GetValue()
+        inspoint = self.text_sql.GetInsertionPoint()
+
+        newsqlstr = ''
+        if inspoint > 0 and sqlstr[inspoint-1] != ' ':
+            newsqlstr += ' '
+        newsqlstr += value
+        if inspoint < len(sqlstr):
+            newsqlstr += ' ' if sqlstr[inspoint] != ' ' else ''
+        
+        if newsqlstr:
+            self.text_sql.SetValue(sqlstr[:inspoint] + newsqlstr + sqlstr[inspoint:])
+            self.text_sql.SetInsertionPoint(inspoint + len(newsqlstr))
+                    
+        wx.CallAfter(self.text_sql.SetFocus)
+
+        
 if __name__ == "__main__":
 if __name__ == "__main__":
     if len(sys.argv) not in [3, 4]:
     if len(sys.argv) not in [3, 4]:
         print(__doc__, file=sys.stderr)
         print(__doc__, file=sys.stderr)

+ 37 - 4
gui/wxpython/gui_core/forms.py

@@ -240,7 +240,7 @@ class UpdateThread(Thread):
 
 
             map = layer = None
             map = layer = None
             driver = db = None
             driver = db = None
-            if name in ('LayerSelect', 'ColumnSelect'):
+            if name in ('LayerSelect', 'ColumnSelect', 'SqlWhereSelect'):
                 if p.get('element', '') == 'vector':  # -> vector
                 if p.get('element', '') == 'vector':  # -> vector
                     # get map name
                     # get map name
                     map = p.get('value', '')
                     map = p.get('value', '')
@@ -325,7 +325,7 @@ class UpdateThread(Thread):
 
 
                     if not cparams[map]['dbInfo']:
                     if not cparams[map]['dbInfo']:
                         cparams[map]['dbInfo'] = gselect.VectorDBInfo(map)
                         cparams[map]['dbInfo'] = gselect.VectorDBInfo(map)
-                    self.data[win.GetParent().InsertColumns] = {
+                    self.data[win.GetParent().SetData] = {
                         'vector': map, 'layer': layer,
                         'vector': map, 'layer': layer,
                         'dbInfo': cparams[map]['dbInfo']}
                         'dbInfo': cparams[map]['dbInfo']}
                 else:  # table
                 else:  # table
@@ -397,6 +397,18 @@ class UpdateThread(Thread):
                             'value', ''), 'mapset': pMapset.get(
                             'value', ''), 'mapset': pMapset.get(
                             'value', '')}
                             'value', '')}
 
 
+            elif name == 'SqlWhereSelect':
+                if map:
+                    self.data[win.GetParent().SetData] = {
+                        'vector': map, 'layer': layer }
+                else:  # table
+                    if driver and db:
+                        self.data[win.GetParent().InsertTableColumns] = {
+                            'table': pTable.get('value'),
+                            'driver': driver, 'database': db}
+                    elif pTable:
+                        self.data[win.GetParent().InsertTableColumns] = {
+                            'table': pTable.get('value')}
 
 
 def UpdateDialog(parent, event, eventId, task):
 def UpdateDialog(parent, event, eventId, task):
     return UpdateThread(parent, event, eventId, task)
     return UpdateThread(parent, event, eventId, task)
@@ -1394,7 +1406,8 @@ class CmdPanel(wx.Panel):
                                                'barscale',
                                                'barscale',
                                                'northarrow',
                                                'northarrow',
                                                'datasource',
                                                'datasource',
-                                               'datasource_layer'):
+                                               'datasource_layer',
+                                               'sql_query'):
                     multiple = p.get('multiple', False)
                     multiple = p.get('multiple', False)
                     if p.get('age', '') == 'new':
                     if p.get('age', '') == 'new':
                         mapsets = [grass.gisenv()['MAPSET'], ]
                         mapsets = [grass.gisenv()['MAPSET'], ]
@@ -2060,6 +2073,17 @@ class CmdPanel(wx.Panel):
                             self.OnUpdateValues()  # TODO: replace by signal
                             self.OnUpdateValues()  # TODO: replace by signal
 
 
                         self.win1.OnCheckItem = OnCheckItem
                         self.win1.OnCheckItem = OnCheckItem
+                        
+                elif prompt == 'sql_query':
+                    win = gselect.SqlWhereSelect(
+                        parent=which_panel, param=p)
+                    p['wxId'] = [win.GetTextWin().GetId()]
+                    win.GetTextWin().Bind(wx.EVT_TEXT, self.OnSetValue)
+                    which_sizer.Add(
+                        win,
+                        proportion=0,
+                        flag=wx.EXPAND | wx.BOTTOM | wx.LEFT | wx.RIGHT,
+                        border=5)
 
 
             if self.parent.GetName() == 'MainFrame' and (
             if self.parent.GetName() == 'MainFrame' and (
                     self._giface and hasattr(self._giface, "_model")):
                     self._giface and hasattr(self._giface, "_model")):
@@ -2110,6 +2134,7 @@ class CmdPanel(wx.Panel):
         pDbase = None
         pDbase = None
         pLocation = None
         pLocation = None
         pMapset = None
         pMapset = None
+        pSqlWhere = []
         for p in self.task.params:
         for p in self.task.params:
             if self.task.blackList['enabled'] and self.task.get_name() in self.task.blackList['items'] and \
             if self.task.blackList['enabled'] and self.task.get_name() in self.task.blackList['items'] and \
                p.get('name', '') in self.task.blackList['items'][self.task.get_name()]['params']:
                p.get('name', '') in self.task.blackList['items'][self.task.get_name()]['params']:
@@ -2157,6 +2182,8 @@ class CmdPanel(wx.Panel):
                 pLocation = p
                 pLocation = p
             elif prompt == 'mapset':
             elif prompt == 'mapset':
                 pMapset = p
                 pMapset = p
+            elif prompt == 'sql_query':
+                pSqlWhere.append(p)
 
 
         # collect ids
         # collect ids
         pColumnIds = []
         pColumnIds = []
@@ -2168,16 +2195,22 @@ class CmdPanel(wx.Panel):
         pSigFileIds = []
         pSigFileIds = []
         for p in pSigFile:
         for p in pSigFile:
             pSigFileIds += p['wxId']
             pSigFileIds += p['wxId']
-
+        pSqlWhereIds = []
+        for p in pSqlWhere:
+            pSqlWhereIds += p['wxId']
+        
         # set wxId-bindings
         # set wxId-bindings
         if pMap:
         if pMap:
             pMap['wxId-bind'] = []
             pMap['wxId-bind'] = []
             if pLayer:
             if pLayer:
                 pMap['wxId-bind'] += pLayerIds
                 pMap['wxId-bind'] += pLayerIds
             pMap['wxId-bind'] += copy.copy(pColumnIds)
             pMap['wxId-bind'] += copy.copy(pColumnIds)
+            pMap['wxId-bind'] += copy.copy(pSqlWhereIds)
         if pLayer:
         if pLayer:
             for p in pLayer:
             for p in pLayer:
                 p['wxId-bind'] = copy.copy(pColumnIds)
                 p['wxId-bind'] = copy.copy(pColumnIds)
+                p['wxId-bind'] += copy.copy(pSqlWhereIds)
+
 
 
         if pDriver and pTable:
         if pDriver and pTable:
             pDriver['wxId-bind'] = pTable['wxId']
             pDriver['wxId-bind'] = pTable['wxId']

+ 59 - 2
gui/wxpython/gui_core/gselect.py

@@ -27,8 +27,9 @@ Classes:
  - :class:`VectorCategorySelect`
  - :class:`VectorCategorySelect`
  - :class:`SignatureSelect`
  - :class:`SignatureSelect`
  - :class:`SeparatorSelect`
  - :class:`SeparatorSelect`
+ - :class:`SqlWhereSelect`
 
 
-(C) 2007-2014 by the GRASS Development Team
+(C) 2007-2018 by the GRASS Development Team
 
 
 This program is free software under the GNU General Public License
 This program is free software under the GNU General Public License
 (>=v2). Read the file COPYING that comes with GRASS for details.
 (>=v2). Read the file COPYING that comes with GRASS for details.
@@ -74,7 +75,7 @@ except ImportError as e:
 
 
 from gui_core.widgets import ManageSettingsWidget, CoordinatesValidator
 from gui_core.widgets import ManageSettingsWidget, CoordinatesValidator
 
 
-from core.gcmd import RunCommand, GError, GMessage, GWarning
+from core.gcmd import RunCommand, GError, GMessage, GWarning, GException
 from core.utils    import GetListOfLocations, GetListOfMapsets, \
 from core.utils    import GetListOfLocations, GetListOfMapsets, \
     GetFormats, rasterFormatExtension, vectorFormatExtension
     GetFormats, rasterFormatExtension, vectorFormatExtension
 from core.utils import GetSettingsPath, GetValidLayerName, ListSortLower
 from core.utils import GetSettingsPath, GetValidLayerName, ListSortLower
@@ -885,6 +886,8 @@ class VectorDBInfo:
 
 
         :param layer: vector layer number
         :param layer: vector layer number
         """
         """
+        if layer not in self.layers:
+            raise GException(_("No table linked to layer <{}>.".format(layer)))
         return self.layers[layer]['table']
         return self.layers[layer]['table']
 
 
     def GetDbSettings(self, layer):
     def GetDbSettings(self, layer):
@@ -2711,3 +2714,57 @@ class SeparatorSelect(wx.ComboBox):
                                               **kwargs)
                                               **kwargs)
         self.SetName("SeparatorSelect")
         self.SetName("SeparatorSelect")
         self.SetItems(['pipe', 'comma', 'space', 'tab', 'newline'])
         self.SetItems(['pipe', 'comma', 'space', 'tab', 'newline'])
+
+
+class SqlWhereSelect(wx.Panel):
+
+    def __init__(self, parent, **kwargs):
+        """Widget to define SQL WHERE condition.
+
+        :param parent: parent window
+        """
+        super(SqlWhereSelect, self).__init__(parent=parent, id=wx.ID_ANY)
+        self.parent = parent
+
+        self.sqlField = wx.TextCtrl(parent=self, id=wx.ID_ANY,
+                                    size=globalvar.DIALOG_TEXTCTRL_SIZE)
+        self.GetChildren()[0].SetName("SqlWhereSelect")
+        icon = wx.Bitmap(
+            os.path.join(
+                globalvar.ICONDIR,
+                "grass",
+                "table.png"))
+        self.buttonInsSql = buttons.ThemedGenBitmapButton(
+            parent=self, id=wx.ID_ANY, bitmap=icon, size=globalvar.DIALOG_COLOR_SIZE)
+        self.buttonInsSql.Bind(wx.EVT_BUTTON, self._onClick)
+
+        self._doLayout()
+
+
+    def _doLayout(self):
+        self.dialogSizer = wx.BoxSizer(wx.HORIZONTAL)
+        self.dialogSizer.Add(self.sqlField,
+                             proportion=1,
+                             flag=wx.EXPAND)
+        self.dialogSizer.Add(self.buttonInsSql)
+        self.SetSizer(self.dialogSizer)
+
+    def GetTextWin(self):
+        return self.sqlField
+
+    def _onClick(self, event):
+        from dbmgr.sqlbuilder import SQLBuilderWhere
+        try:
+            win = SQLBuilderWhere(parent=self,
+                                  vectmap=self.vector_map,
+                                  layer=self.vector_layer)
+            win.Show()
+        except GException as e:
+            GMessage(parent=self.parent, message='{}'.format(e))
+        
+    def SetData(self, vector, layer):
+        self.vector_map = vector
+        self.vector_layer = int(layer) # TODO: support layer names
+
+    def SetValue(self, value):
+        self.sqlField.SetValue(value)

+ 1 - 0
lib/gis/parser_standard_options.c

@@ -151,6 +151,7 @@ struct Option *G_define_standard_option(int opt)
     case G_OPT_DB_WHERE:
     case G_OPT_DB_WHERE:
 	Opt->key = "where";
 	Opt->key = "where";
 	Opt->type = TYPE_STRING;
 	Opt->type = TYPE_STRING;
+        Opt->gisprompt = "old,sql_query,sql_query";
 	Opt->key_desc = "sql_query";
 	Opt->key_desc = "sql_query";
 	Opt->required = NO;
 	Opt->required = NO;
 	Opt->label = _("WHERE conditions of SQL statement without 'where' keyword");
 	Opt->label = _("WHERE conditions of SQL statement without 'where' keyword");