class ImportDialog(wx.Dialog): """Dialog for bulk import of various data (base class)""" def __init__(self, parent, giface, itype, id=wx.ID_ANY, title=_("Multiple import"), style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER): self.parent = parent # GMFrame self._giface = giface # used to add layers self.importType = itype self.options = dict() # list of options self.options_par = dict() self.commandId = -1 # id of running command wx.Dialog.__init__(self, parent, id, title, style=style, name="MultiImportDialog") self.panel = wx.Panel(parent=self, id=wx.ID_ANY) self.layerBox = StaticBox(parent=self.panel, id=wx.ID_ANY) if self.importType == 'gdal': label = _("List of raster layers") elif self.importType == 'ogr': label = _("List of vector layers") else: label = _("List of %s layers") % self.importType.upper() self.layerBox.SetLabel(" %s - %s " % (label, _("right click to (un)select all"))) # list of layers columns = [ _('Layer id'), _('Layer name'), _('Name for output GRASS map (editable)') ] 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() self.override = wx.CheckBox( parent=self.panel, id=wx.ID_ANY, label=_( "Override projection check (use current location's projection)" )) self.overwrite = wx.CheckBox( parent=self.panel, id=wx.ID_ANY, label=_("Allow output files to overwrite existing files")) self.overwrite.SetValue( UserSettings.Get(group='cmd', key='overwrite', subkey='enabled')) self.overwrite.Bind(wx.EVT_CHECKBOX, self.OnCheckOverwrite) if UserSettings.Get(group='cmd', key='overwrite', subkey='enabled'): self.list.validate = False self.add = wx.CheckBox(parent=self.panel, id=wx.ID_ANY) self.closeOnFinish = wx.CheckBox(parent=self.panel, id=wx.ID_ANY, label=_("Close dialog on finish")) self.closeOnFinish.SetValue( UserSettings.Get(group='cmd', key='closeDlg', subkey='enabled')) # # buttons # # cancel self.btn_close = CloseButton(parent=self.panel) self.btn_close.SetToolTip(_("Close dialog")) self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose) # run self.btn_run = Button(parent=self.panel, id=wx.ID_OK, label=_("&Import")) self.btn_run.SetToolTip(_("Import selected layers")) self.btn_run.SetDefault() self.btn_run.Bind(wx.EVT_BUTTON, self.OnRun) self.Bind(wx.EVT_CLOSE, lambda evt: self.Destroy()) self.notebook = GNotebook(parent=self, style=globalvar.FNPageDStyle) self.notebook.AddPage(page=self.panel, text=_('Source settings'), name='source') self.createSettingsPage() def createSettingsPage(self): self._blackList = { 'enabled': True, 'items': { self._getCommand(): { 'params': self._getBlackListedParameters(), 'flags': self._getBlackListedFlags() } } } grass_task = gtask.parse_interface(self._getCommand(), blackList=self._blackList) self.advancedPagePanel = CmdPanel(parent=self, giface=None, task=grass_task, frame=None) self.notebook.AddPage(page=self.advancedPagePanel, text=_('Import settings'), name='settings') def doLayout(self): """Do layout""" dialogSizer = wx.BoxSizer(wx.VERTICAL) # dsn input dialogSizer.Add(self.dsnInput, proportion=0, flag=wx.EXPAND) # # list of DXF layers # layerSizer = wx.StaticBoxSizer(self.layerBox, wx.HORIZONTAL) layerSizer.Add(self.list, proportion=1, flag=wx.ALL | wx.EXPAND, border=5) dialogSizer.Add(layerSizer, proportion=1, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5) dialogSizer.Add(self.override, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5) dialogSizer.Add(self.overwrite, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5) dialogSizer.Add(self.add, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5) dialogSizer.Add(self.closeOnFinish, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5) # # buttons # btnsizer = wx.BoxSizer(orient=wx.HORIZONTAL) btnsizer.Add(self.btn_close, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER, border=10) btnsizer.Add(self.btn_run, proportion=0, flag=wx.RIGHT | wx.ALIGN_CENTER, border=10) dialogSizer.Add(btnsizer, proportion=0, flag=wx.BOTTOM | wx.ALIGN_RIGHT, border=10) # dialogSizer.SetSizeHints(self.panel) self.panel.SetAutoLayout(True) self.panel.SetSizer(dialogSizer) dialogSizer.Fit(self.panel) # auto-layout seems not work here - FIXME size = wx.Size(globalvar.DIALOG_GSELECT_SIZE[0] + 322, 550) self.SetMinSize(size) self.SetSize((size.width, size.height + 100)) # width = self.GetSize()[0] # self.list.SetColumnWidth(col = 1, width = width / 2 - 50) self.Layout() def _getCommand(self): """Get command""" raise NotImplementedError() def _getBlackListedParameters(self): """Get parameters which will not be showed in Settings page""" raise NotImplementedError() def _getBlackListedFlags(self): """Get flags which will not be showed in Settings page""" 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(): if not self.list.GetValidator().\ Validate(win=self.list, validate_all=True): return False return True def OnClose(self, event=None): """Close dialog""" self.Close() def OnRun(self, event): """Import/Link data (each layes as separate vector map)""" 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): """Add imported/linked layers into layer tree""" if not self.add.IsChecked() or returncode != 0: return # TODO: if importing map creates more map the following does not work # * do nothing if map does not exist or # * try to determine names using regexp or # * persuade import tools to report map names self.commandId += 1 layer, output = self.list.GetLayers()[self.commandId][:2] if '@' not in output: name = output + '@' + grass.gisenv()['MAPSET'] else: name = output # add imported layers into layer tree # an alternative would be emit signal (mapCreated) and (optionally) # connect to this signal llist = self._giface.GetLayerList() if self.importType == 'gdal': if userData: nBands = int(userData.get('nbands', 1)) else: nBands = 1 if UserSettings.Get(group='rasterLayer', key='opaque', subkey='enabled'): nFlag = True else: nFlag = False for i in range(1, nBands + 1): nameOrig = name if nBands > 1: mapName, mapsetName = name.split('@') mapName += '.%d' % i name = mapName + '@' + mapsetName cmd = ['d.rast', 'map=%s' % name] if nFlag: cmd.append('-n') llist.AddLayer(ltype='raster', name=name, checked=True, cmd=cmd) name = nameOrig else: llist.AddLayer(ltype='vector', name=name, checked=True, cmd=['d.vect', 'map=%s' % name] + GetDisplayVectSettings()) self._giface.GetMapWindow().ZoomToMap() def OnAbort(self, event): """Abort running import .. todo:: not yet implemented """ pass def OnCmdDone(self, event): """Do what has to be done after importing""" pass def _getLayersToReprojetion(self, projMatch_idx, grassName_idx): """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) 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 not self.link and \ differentProjLayers and \ not self.override.IsChecked(): # '-o' not in self.getSettingsPageCmd(): dlg = ReprojectionDialog(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 getSettingsPageCmd(self): return self.advancedPagePanel.createCmd(ignoreErrors=True, ignoreRequired=True)
class AttributeManager(wx.Frame, DbMgrBase): def __init__(self, parent, id=wx.ID_ANY, title=None, vectorName=None, item=None, log=None, selection=None, **kwargs): """GRASS Attribute Table Manager window :param parent: parent window :param id: window id :param title: window title or None for default title :param vectorName: name of vector map :param item: item from Layer Tree :param log: log window :param selection: name of page to be selected :param kwagrs: other wx.Frame's arguments """ self.parent = parent try: mapdisplay = self.parent.GetMapDisplay() except: mapdisplay = None DbMgrBase.__init__(self, id=id, mapdisplay=mapdisplay, vectorName=vectorName, item=item, log=log, statusbar=self, **kwargs) wx.Frame.__init__(self, parent, id, *kwargs) # title if not title: title = "%s" % _("GRASS GIS Attribute Table Manager - ") if not self.dbMgrData['editable']: title += _("READONLY - ") title += "<%s>" % (self.dbMgrData['vectName']) self.SetTitle(title) # icon self.SetIcon( wx.Icon(os.path.join(globalvar.ICONDIR, 'grass_sql.ico'), wx.BITMAP_TYPE_ICO)) self.panel = wx.Panel(parent=self, id=wx.ID_ANY) if len(self.dbMgrData['mapDBInfo'].layers.keys()) == 0: GMessage(parent=self.parent, message=_("Database connection for vector map <%s> " "is not defined in DB file. " "You can define new connection in " "'Manage layers' tab.") % self.dbMgrData['vectName']) busy = wx.BusyInfo(_("Please wait, loading attribute data..."), parent=self.parent) wx.SafeYield() self.CreateStatusBar(number=1) self.notebook = GNotebook(self.panel, style=globalvar.FNPageDStyle) self.CreateDbMgrPage(parent=self, pageName='browse') self.notebook.AddPage(page=self.pages['browse'], text=_("Browse data"), name='browse') self.pages['browse'].SetTabAreaColour(globalvar.FNPageColor) self.CreateDbMgrPage(parent=self, pageName='manageTable') self.notebook.AddPage(page=self.pages['manageTable'], text=_("Manage tables"), name='table') self.pages['manageTable'].SetTabAreaColour(globalvar.FNPageColor) self.CreateDbMgrPage(parent=self, pageName='manageLayer') self.notebook.AddPage(page=self.pages['manageLayer'], text=_("Manage layers"), name='layers') del busy if selection: wx.CallAfter(self.notebook.SetSelectionByName, selection) else: wx.CallAfter(self.notebook.SetSelection, 0) # select browse tab # buttons self.btnClose = CloseButton(parent=self.panel) self.btnClose.SetToolTip(_("Close Attribute Table Manager")) self.btnReload = Button(parent=self.panel, id=wx.ID_REFRESH) self.btnReload.SetToolTip( _("Reload currently selected attribute data")) self.btnReset = ClearButton(parent=self.panel) self.btnReset.SetToolTip( _("Reload all attribute data (drop current selection)")) # bind closing to ESC self.Bind(wx.EVT_MENU, self.OnCloseWindow, id=wx.ID_CANCEL) accelTableList = [(wx.ACCEL_NORMAL, wx.WXK_ESCAPE, wx.ID_CANCEL)] accelTable = wx.AcceleratorTable(accelTableList) self.SetAcceleratorTable(accelTable) # events self.btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow) self.btnReload.Bind(wx.EVT_BUTTON, self.OnReloadData) self.btnReset.Bind(wx.EVT_BUTTON, self.OnReloadDataAll) self.notebook.Bind(FN.EVT_FLATNOTEBOOK_PAGE_CHANGED, self.OnPageChanged) self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) # do layout self._layout() # self.SetMinSize(self.GetBestSize()) self.SetSize((700, 550)) # FIXME hard-coded size self.SetMinSize(self.GetSize()) def _layout(self): """Do layout""" # frame body mainSizer = wx.BoxSizer(wx.VERTICAL) # buttons btnSizer = wx.BoxSizer(wx.HORIZONTAL) btnSizer.Add(self.btnReset, proportion=1, flag=wx.ALL, border=5) btnSizer.Add(self.btnReload, proportion=1, flag=wx.ALL, border=5) btnSizer.Add(self.btnClose, proportion=1, flag=wx.ALL, border=5) mainSizer.Add(self.notebook, proportion=1, flag=wx.EXPAND) mainSizer.Add(btnSizer, flag=wx.ALIGN_RIGHT | wx.ALL, border=5) self.panel.SetAutoLayout(True) self.panel.SetSizer(mainSizer) mainSizer.Fit(self.panel) self.Layout() def OnCloseWindow(self, event): """Cancel button pressed""" if self.parent and self.parent.GetName() == 'LayerManager': # deregister ATM self.parent.dialogs['atm'].remove(self) if not isinstance(event, wx.CloseEvent): self.Destroy() event.Skip() def OnReloadData(self, event): """Reload data""" if self.pages['browse']: self.pages['browse'].OnDataReload(event) # TODO replace by signal def OnReloadDataAll(self, event): """Reload all data""" if self.pages['browse']: self.pages['browse'].ResetPage() def OnPageChanged(self, event): """On page in ATM is changed""" try: if self.pages["browse"]: selPage = self.pages["browse"].selLayer id = self.pages["browse"].layerPage[selPage]['data'] else: id = None except KeyError: id = None if event.GetSelection() == self.notebook.GetPageIndexByName( 'browse') and id: win = self.FindWindowById(id) if win: self.log.write( _("Number of loaded records: %d") % win.GetItemCount()) else: self.log.write("") self.btnReload.Enable() self.btnReset.Enable() else: self.log.write("") self.btnReload.Enable(False) self.btnReset.Enable(False) event.Skip() def OnTextEnter(self, event): pass def UpdateDialog(self, layer): """Updates dialog layout for given layer""" DbMgrBase.UpdateDialog(self, layer=layer) # set current page selection self.notebook.SetSelectionByName('layers')
class SQLBuilder(wx.Frame): """SQLBuider class Base class for classes, which builds SQL statements. """ def __init__(self, parent, title, vectmap, modeChoices=[], id=wx.ID_ANY, layer=1): wx.Frame.__init__(self, parent, id, title) self.SetIcon( wx.Icon(os.path.join(globalvar.ICONDIR, "grass_sql.ico"), wx.BITMAP_TYPE_ICO)) self.parent = parent # variables self.vectmap = vectmap # fullname if "@" not in self.vectmap: self.vectmap = grass.find_file(self.vectmap, element="vector")["fullname"] if not self.vectmap: grass.fatal(_("Vector map <%s> not found") % vectmap) self.mapname, self.mapset = self.vectmap.split("@", 1) # db info self.layer = layer self.dbInfo = VectorDBInfo(self.vectmap) self.tablename = self.dbInfo.GetTable(self.layer) self.driver, self.database = self.dbInfo.GetDbSettings(self.layer) self.colvalues = [] # array with unique values in selected column self.panel = wx.Panel(parent=self, id=wx.ID_ANY) # statusbar self.statusbar = self.CreateStatusBar(number=1) self._doLayout(modeChoices) self.panel.SetAutoLayout(True) self.panel.SetSizer(self.pagesizer) self.pagesizer.Fit(self.panel) self.SetMinSize((400, 600)) self.SetClientSize(self.panel.GetSize()) self.CenterOnParent() def _doLayout(self, modeChoices, showDbInfo=False): """Do dialog layout""" self.pagesizer = wx.BoxSizer(wx.VERTICAL) # dbInfo if showDbInfo: databasebox = StaticBox(parent=self.panel, id=wx.ID_ANY, label=" %s " % _("Database connection")) databaseboxsizer = wx.StaticBoxSizer(databasebox, wx.VERTICAL) databaseboxsizer.Add( CreateDbInfoDesc(self.panel, self.dbInfo, layer=self.layer), proportion=1, flag=wx.EXPAND | wx.ALL, border=3, ) # # text areas # # sql box sqlbox = StaticBox(parent=self.panel, id=wx.ID_ANY, label=" %s " % _("Query")) sqlboxsizer = wx.StaticBoxSizer(sqlbox, wx.VERTICAL) self.text_sql = TextCtrl( parent=self.panel, id=wx.ID_ANY, value="", size=(-1, 50), style=wx.TE_MULTILINE, ) self.text_sql.SetInsertionPointEnd() wx.CallAfter(self.text_sql.SetFocus) sqlboxsizer.Add(self.text_sql, flag=wx.EXPAND) # # buttons # self.btn_clear = ClearButton(parent=self.panel) self.btn_clear.SetToolTip(_("Set SQL statement to default")) self.btn_apply = ApplyButton(parent=self.panel) self.btn_apply.SetToolTip(_("Apply SQL statement")) self.btn_close = CloseButton(parent=self.panel) self.btn_close.SetToolTip(_("Close the dialog")) self.btn_logic = { "is": [ "=", ], "isnot": [ "!=", ], "like": [ "LIKE", ], "gt": [ ">", ], "ge": [ ">=", ], "lt": [ "<", ], "le": [ "<=", ], "or": [ "OR", ], "not": [ "NOT", ], "and": [ "AND", ], "brac": [ "()", ], "prc": [ "%", ], } self.btn_logicpanel = wx.Panel(parent=self.panel, id=wx.ID_ANY) for key, value in six.iteritems(self.btn_logic): btn = Button(parent=self.btn_logicpanel, id=wx.ID_ANY, label=value[0]) self.btn_logic[key].append(btn.GetId()) self.buttonsizer = wx.FlexGridSizer(cols=4, hgap=5, vgap=5) self.buttonsizer.Add(self.btn_clear) self.buttonsizer.Add(self.btn_apply) self.buttonsizer.Add(self.btn_close) btn_logicsizer = wx.GridBagSizer(5, 5) btn_logicsizer.Add(self.FindWindowById(self.btn_logic["is"][1]), pos=(0, 0)) btn_logicsizer.Add(self.FindWindowById(self.btn_logic["isnot"][1]), pos=(1, 0)) btn_logicsizer.Add(self.FindWindowById(self.btn_logic["like"][1]), pos=(2, 0)) btn_logicsizer.Add(self.FindWindowById(self.btn_logic["gt"][1]), pos=(0, 1)) btn_logicsizer.Add(self.FindWindowById(self.btn_logic["ge"][1]), pos=(1, 1)) btn_logicsizer.Add(self.FindWindowById(self.btn_logic["or"][1]), pos=(2, 1)) btn_logicsizer.Add(self.FindWindowById(self.btn_logic["lt"][1]), pos=(0, 2)) btn_logicsizer.Add(self.FindWindowById(self.btn_logic["le"][1]), pos=(1, 2)) btn_logicsizer.Add(self.FindWindowById(self.btn_logic["not"][1]), pos=(2, 2)) btn_logicsizer.Add(self.FindWindowById(self.btn_logic["brac"][1]), pos=(0, 3)) btn_logicsizer.Add(self.FindWindowById(self.btn_logic["prc"][1]), pos=(1, 3)) btn_logicsizer.Add(self.FindWindowById(self.btn_logic["and"][1]), pos=(2, 3)) self.btn_logicpanel.SetSizer(btn_logicsizer) # # list boxes (columns, values) # self.hsizer = wx.BoxSizer(wx.HORIZONTAL) columnsbox = StaticBox(parent=self.panel, id=wx.ID_ANY, label=" %s " % _("Columns")) columnsizer = wx.StaticBoxSizer(columnsbox, wx.VERTICAL) self.list_columns = wx.ListBox( parent=self.panel, id=wx.ID_ANY, choices=self.dbInfo.GetColumns(self.tablename), style=wx.LB_MULTIPLE, ) columnsizer.Add(self.list_columns, proportion=1, flag=wx.EXPAND) 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.EXPAND, border=5) # self.list_columns.SetMinSize((-1,130)) # self.list_values.SetMinSize((-1,100)) self.valuespanel = wx.Panel(parent=self.panel, id=wx.ID_ANY) valuesbox = StaticBox(parent=self.valuespanel, id=wx.ID_ANY, label=" %s " % _("Values")) valuesizer = wx.StaticBoxSizer(valuesbox, wx.VERTICAL) self.list_values = wx.ListBox( parent=self.valuespanel, id=wx.ID_ANY, choices=self.colvalues, style=wx.LB_MULTIPLE, ) valuesizer.Add(self.list_values, proportion=1, flag=wx.EXPAND) self.valuespanel.SetSizer(valuesizer) self.btn_unique = Button(parent=self.valuespanel, id=wx.ID_ANY, label=_("Get all values")) self.btn_unique.Enable(False) self.btn_uniquesample = Button(parent=self.valuespanel, id=wx.ID_ANY, label=_("Get sample")) self.btn_uniquesample.SetToolTip( _("Get first 256 unique values as sample")) self.btn_uniquesample.Enable(False) buttonsizer3 = wx.BoxSizer(wx.HORIZONTAL) buttonsizer3.Add(self.btn_uniquesample, proportion=0, flag=wx.RIGHT, border=5) buttonsizer3.Add(self.btn_unique, proportion=0) valuesizer.Add(buttonsizer3, proportion=0, flag=wx.TOP, border=5) # go to gotosizer = wx.BoxSizer(wx.HORIZONTAL) self.goto = TextCtrl(parent=self.valuespanel, id=wx.ID_ANY, style=wx.TE_PROCESS_ENTER) gotosizer.Add( StaticText(parent=self.valuespanel, id=wx.ID_ANY, label=_("Go to:")), proportion=0, flag=wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, border=5, ) gotosizer.Add(self.goto, proportion=1, flag=wx.EXPAND) valuesizer.Add(gotosizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=5) self.hsizer.Add(columnsizer, proportion=1, flag=wx.EXPAND) self.hsizer.Add(self.valuespanel, proportion=1, flag=wx.EXPAND) self.close_onapply = wx.CheckBox(parent=self.panel, id=wx.ID_ANY, label=_("Close dialog on apply")) self.close_onapply.SetValue(True) if showDbInfo: self.pagesizer.Add(databaseboxsizer, flag=wx.ALL | 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.hsizer, proportion=1, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5, ) # self.pagesizer.Add(self.btn_uniqe,0,wx.ALIGN_LEFT|wx.TOP,border=5) # self.pagesizer.Add(self.btn_uniqesample,0,wx.ALIGN_LEFT|wx.TOP,border=5) self.pagesizer.Add(self.btn_logicpanel, proportion=0, flag=wx.ALIGN_CENTER_HORIZONTAL) self.pagesizer.Add(sqlboxsizer, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=5) self.pagesizer.Add(self.buttonsizer, proportion=0, flag=wx.ALIGN_RIGHT | wx.ALL, border=5) self.pagesizer.Add( self.close_onapply, proportion=0, flag=wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border=5, ) # # bindings # if modeChoices: self.mode.Bind(wx.EVT_RADIOBOX, self.OnMode) # self.text_sql.Bind(wx.EVT_ACTIVATE, self.OnTextSqlActivate)TODO self.btn_unique.Bind(wx.EVT_BUTTON, self.OnUniqueValues) self.btn_uniquesample.Bind(wx.EVT_BUTTON, self.OnSampleValues) for key, value in six.iteritems(self.btn_logic): self.FindWindowById(value[1]).Bind(wx.EVT_BUTTON, self.OnAddMark) self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose) self.btn_clear.Bind(wx.EVT_BUTTON, self.OnClear) self.btn_apply.Bind(wx.EVT_BUTTON, self.OnApply) self.list_columns.Bind(wx.EVT_LISTBOX, self.OnAddColumn) self.list_values.Bind(wx.EVT_LISTBOX, self.OnAddValue) self.goto.Bind(wx.EVT_TEXT, self.OnGoTo) self.goto.Bind(wx.EVT_TEXT_ENTER, self.OnAddValue) def OnUniqueValues(self, event, justsample=False): """Get unique values""" vals = [] try: idx = self.list_columns.GetSelections()[0] column = self.list_columns.GetString(idx) except: self.list_values.Clear() return self.list_values.Clear() sql = "SELECT DISTINCT {column} FROM {table} ORDER BY {column}".format( column=column, table=self.tablename) if justsample: sql += " LIMIT {}".format(255) data = grass.db_select(sql=sql, database=self.database, driver=self.driver, sep="{_sep_}") if not data: return desc = self.dbInfo.GetTableDesc(self.dbInfo.GetTable( self.layer))[column] i = 0 items = [] for item in data: # sorted(set(map(lambda x: desc['ctype'](x[0]), data))): if desc["type"] not in ("character", "text"): items.append(str(item[0])) else: items.append("'{}'".format(GetUnicodeValue(item[0]))) i += 1 self.list_values.AppendItems(items) def OnSampleValues(self, event): """Get sample values""" self.OnUniqueValues(None, True) def OnAddColumn(self, event): """Add column name to the query""" idx = self.list_columns.GetSelections() for i in idx: column = self.list_columns.GetString(i) self._add(element="column", value=column) if not self.btn_uniquesample.IsEnabled(): self.btn_uniquesample.Enable(True) self.btn_unique.Enable(True) def OnAddValue(self, event): """Add value""" selection = self.list_values.GetSelections() if not selection: event.Skip() return idx = selection[0] value = self.list_values.GetString(idx) idx = self.list_columns.GetSelections()[0] column = self.list_columns.GetString(idx) ctype = self.dbInfo.GetTableDesc(self.dbInfo.GetTable( self.layer))[column]["type"] self._add(element="value", value=value) def OnGoTo(self, event): # clear all previous selections for item in self.list_values.GetSelections(): self.list_values.Deselect(item) gotoText = event.GetString() lenLimit = len(gotoText) found = idx = 0 string = False for item in self.list_values.GetItems(): if idx == 0 and item.startswith("'"): string = True if string: item = item[1:-1] # strip "'" if item[:lenLimit] == gotoText: found = idx break idx += 1 if found > 0: self.list_values.SetSelection(found) def OnAddMark(self, event): """Add mark""" mark = None if self.btn_logicpanel and self.btn_logicpanel.IsShown(): btns = self.btn_logic elif self.btn_arithmeticpanel and self.btn_arithmeticpanel.IsShown(): btns = self.btn_arithmetic for key, value in six.iteritems(btns): if event.GetId() == value[1]: mark = value[0] break self._add(element="mark", value=mark) def GetSQLStatement(self): """Return SQL statement""" return self.text_sql.GetValue().strip().replace("\n", " ") def OnClose(self, event): self.Destroy() event.Skip()