"""! @package vdigit @brief Dialogs for wxGUI vector digitizer Classes: - VDigit - VDigitSettingsDialog - VDigitCategoryDialog - CategoryListCtrl - VDigitZBulkDialog - VDigitDuplicatesDialog - CheckListFeature (C) 2007-2011 by the GRASS Development Team This program is free software under the GNU General Public License (>=v2). Read the file COPYING that comes with GRASS for details. @author Martin Landa """ import os import sys import string import copy import textwrap import traceback from threading import Thread import wx import wx.lib.colourselect as csel import wx.lib.mixins.listctrl as listmix import gcmd import dbm from debug import Debug as Debug import gselect import globalvar from units import Units from preferences import globalSettings as UserSettings try: from wxvdigit import IVDigit, GV_LINES haveVDigit = True errorMsg = '' except ImportError, err: haveVDigit = False errorMsg = err GV_LINES = -1 class IVDigit: def __init__(self): pass class VDigit(IVDigit): def __init__(self, mapwindow): """!Base class of vector digitizer @param mapwindow reference to mapwindow (mapdisp_window.BufferedWindow) instance """ IVDigit.__init__(self, mapwindow) class VDigitSettingsDialog(wx.Dialog): def __init__(self, parent, title, style = wx.DEFAULT_DIALOG_STYLE): """!Standard settings dialog for digitization purposes """ wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style) self.parent = parent # mapdisplay.MapFrame class instance self.digit = self.parent.MapWindow.digit # notebook notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT) self._createSymbologyPage(notebook) self.digit.SetCategory() self._createGeneralPage(notebook) self._createAttributesPage(notebook) self._createQueryPage(notebook) # buttons btnApply = wx.Button(self, wx.ID_APPLY) btnCancel = wx.Button(self, wx.ID_CANCEL) btnSave = wx.Button(self, wx.ID_SAVE) btnSave.SetDefault() # bindigs btnApply.Bind(wx.EVT_BUTTON, self.OnApply) btnApply.SetToolTipString(_("Apply changes for this session")) btnApply.SetDefault() btnSave.Bind(wx.EVT_BUTTON, self.OnSave) btnSave.SetToolTipString(_("Close dialog and save changes to user settings file")) btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel) btnCancel.SetToolTipString(_("Close dialog and ignore changes")) # sizers btnSizer = wx.StdDialogButtonSizer() btnSizer.AddButton(btnCancel) btnSizer.AddButton(btnApply) btnSizer.AddButton(btnSave) btnSizer.Realize() mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add(item = notebook, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5) mainSizer.Add(item = btnSizer, proportion = 0, flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5) self.Bind(wx.EVT_CLOSE, self.OnCancel) self.SetSizer(mainSizer) mainSizer.Fit(self) def _createSymbologyPage(self, notebook): """!Create notebook page concerning symbology settings""" panel = wx.Panel(parent = notebook, id = wx.ID_ANY) notebook.AddPage(page = panel, text = _("Symbology")) sizer = wx.BoxSizer(wx.VERTICAL) flexSizer = wx.FlexGridSizer (cols = 3, hgap = 5, vgap = 5) flexSizer.AddGrowableCol(0) self.symbology = {} for label, key in self._symbologyData(): textLabel = wx.StaticText(panel, wx.ID_ANY, label) color = csel.ColourSelect(panel, id = wx.ID_ANY, colour = UserSettings.Get(group = 'vdigit', key = 'symbol', subkey = [key, 'color']), size = globalvar.DIALOG_COLOR_SIZE) isEnabled = UserSettings.Get(group = 'vdigit', key = 'symbol', subkey = [key, 'enabled']) if isEnabled is not None: enabled = wx.CheckBox(panel, id = wx.ID_ANY, label = "") enabled.SetValue(isEnabled) self.symbology[key] = (enabled, color) else: enabled = (1, 1) self.symbology[key] = (None, color) flexSizer.Add(textLabel, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) flexSizer.Add(enabled, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE) flexSizer.Add(color, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE) color.SetName("GetColour") sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 10) panel.SetSizer(sizer) return panel def _createGeneralPage(self, notebook): """!Create notebook page concerning general settings""" panel = wx.Panel(parent = notebook, id = wx.ID_ANY) notebook.AddPage(page = panel, text = _("General")) border = wx.BoxSizer(wx.VERTICAL) # # display section # box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Display")) sizer = wx.StaticBoxSizer(box, wx.VERTICAL) flexSizer = wx.FlexGridSizer (cols = 3, hgap = 5, vgap = 5) flexSizer.AddGrowableCol(0) # line width text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Line width")) self.lineWidthValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (75, -1), initial = UserSettings.Get(group = 'vdigit', key = "lineWidth", subkey = 'value'), min = 1, max = 1e6) units = wx.StaticText(parent = panel, id = wx.ID_ANY, size = (115, -1), label = UserSettings.Get(group = 'vdigit', key = "lineWidth", subkey = 'units'), style = wx.ALIGN_LEFT) flexSizer.Add(text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) flexSizer.Add(self.lineWidthValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE) flexSizer.Add(units, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border = 10) sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1) border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5) # # snapping section # box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Snapping")) sizer = wx.StaticBoxSizer(box, wx.VERTICAL) flexSizer = wx.FlexGridSizer(cols = 3, hgap = 5, vgap = 5) flexSizer.AddGrowableCol(0) # snapping text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Snapping threshold")) self.snappingValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (75, -1), initial = UserSettings.Get(group = 'vdigit', key = "snapping", subkey = 'value'), min = -1, max = 1e6) self.snappingValue.Bind(wx.EVT_SPINCTRL, self.OnChangeSnappingValue) self.snappingValue.Bind(wx.EVT_TEXT, self.OnChangeSnappingValue) self.snappingUnit = wx.Choice(parent = panel, id = wx.ID_ANY, size = (125, -1), choices = [_("screen pixels"), _("map units")]) self.snappingUnit.SetStringSelection(UserSettings.Get(group = 'vdigit', key = "snapping", subkey = 'units')) self.snappingUnit.Bind(wx.EVT_CHOICE, self.OnChangeSnappingUnits) flexSizer.Add(text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) flexSizer.Add(self.snappingValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE) flexSizer.Add(self.snappingUnit, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE) vertexSizer = wx.BoxSizer(wx.VERTICAL) self.snapVertex = wx.CheckBox(parent = panel, id = wx.ID_ANY, label = _("Snap also to vertex")) self.snapVertex.SetValue(UserSettings.Get(group = 'vdigit', key = "snapToVertex", subkey = 'enabled')) vertexSizer.Add(item = self.snapVertex, proportion = 0, flag = wx.EXPAND) self.mapUnits = self.parent.MapWindow.Map.GetProjInfo()['units'] self.snappingInfo = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Snapping threshold is %(value).1f %(units)s") % \ {'value' : self.digit.GetDisplay().GetThreshold(), 'units' : self.mapUnits}) vertexSizer.Add(item = self.snappingInfo, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1) sizer.Add(item = flexSizer, proportion = 1, flag = wx.EXPAND) sizer.Add(item = vertexSizer, proportion = 1, flag = wx.EXPAND) border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5) # # select box # box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Select vector features")) # feature type sizer = wx.StaticBoxSizer(box, wx.VERTICAL) inSizer = wx.BoxSizer(wx.HORIZONTAL) self.selectFeature = {} for feature in ('point', 'line', 'centroid', 'boundary'): chkbox = wx.CheckBox(parent = panel, label = feature) self.selectFeature[feature] = chkbox.GetId() chkbox.SetValue(UserSettings.Get(group = 'vdigit', key = 'selectType', subkey = [feature, 'enabled'])) inSizer.Add(item = chkbox, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 5) sizer.Add(item = inSizer, proportion = 0, flag = wx.EXPAND) # threshold flexSizer = wx.FlexGridSizer (cols = 3, hgap = 5, vgap = 5) flexSizer.AddGrowableCol(0) text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Select threshold")) self.selectThreshValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (75, -1), initial = UserSettings.Get(group = 'vdigit', key = "selectThresh", subkey = 'value'), min = 1, max = 1e6) units = wx.StaticText(parent = panel, id = wx.ID_ANY, size = (115, -1), label = UserSettings.Get(group = 'vdigit', key = "lineWidth", subkey = 'units'), style = wx.ALIGN_LEFT) flexSizer.Add(text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) flexSizer.Add(self.selectThreshValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE) flexSizer.Add(units, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL | wx.LEFT, border = 10) self.selectIn = wx.CheckBox(parent = panel, id = wx.ID_ANY, label = _("Select only features inside of selection bounding box")) self.selectIn.SetValue(UserSettings.Get(group = 'vdigit', key = "selectInside", subkey = 'enabled')) self.selectIn.SetToolTipString(_("By default are selected all features overlapping selection bounding box ")) self.checkForDupl = wx.CheckBox(parent = panel, id = wx.ID_ANY, label = _("Check for duplicates")) self.checkForDupl.SetValue(UserSettings.Get(group = 'vdigit', key = "checkForDupl", subkey = 'enabled')) sizer.Add(item = flexSizer, proportion = 0, flag = wx.EXPAND) sizer.Add(item = self.selectIn, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 1) sizer.Add(item = self.checkForDupl, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 1) border.Add(item = sizer, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5) # # digitize lines box # box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Digitize line features")) sizer = wx.StaticBoxSizer(box, wx.VERTICAL) self.intersect = wx.CheckBox(parent = panel, label = _("Break lines at intersection")) self.intersect.SetValue(UserSettings.Get(group = 'vdigit', key = 'breakLines', subkey = 'enabled')) sizer.Add(item = self.intersect, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1) border.Add(item = sizer, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5) # # save-on-exit box # box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Save changes")) # save changes on exit? sizer = wx.StaticBoxSizer(box, wx.VERTICAL) self.save = wx.CheckBox(parent = panel, label = _("Save changes on exit")) self.save.SetValue(UserSettings.Get(group = 'vdigit', key = 'saveOnExit', subkey = 'enabled')) sizer.Add(item = self.save, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1) border.Add(item = sizer, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5) panel.SetSizer(border) return panel def _createQueryPage(self, notebook): """!Create notebook page for query tool""" panel = wx.Panel(parent = notebook, id = wx.ID_ANY) notebook.AddPage(page = panel, text = _("Query tool")) border = wx.BoxSizer(wx.VERTICAL) # # query tool box # box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Choose query tool")) sizer = wx.StaticBoxSizer(box, wx.VERTICAL) LocUnits = self.parent.MapWindow.Map.GetProjInfo()['units'] self.queryBox = wx.CheckBox(parent = panel, id = wx.ID_ANY, label = _("Select by box")) self.queryBox.SetValue(UserSettings.Get(group = 'vdigit', key = "query", subkey = 'box')) sizer.Add(item = self.queryBox, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1) sizer.Add((0, 5)) # # length # self.queryLength = wx.RadioButton(parent = panel, id = wx.ID_ANY, label = _("length")) self.queryLength.Bind(wx.EVT_RADIOBUTTON, self.OnChangeQuery) sizer.Add(item = self.queryLength, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1) flexSizer = wx.FlexGridSizer (cols = 4, hgap = 5, vgap = 5) flexSizer.AddGrowableCol(0) txt = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Select lines")) self.queryLengthSL = wx.Choice (parent = panel, id = wx.ID_ANY, choices = [_("shorter than"), _("longer than")]) self.queryLengthSL.SetSelection(UserSettings.Get(group = 'vdigit', key = "queryLength", subkey = 'than-selection')) self.queryLengthValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (100, -1), initial = 1, min = 0, max = 1e6) self.queryLengthValue.SetValue(UserSettings.Get(group = 'vdigit', key = "queryLength", subkey = 'thresh')) units = wx.StaticText(parent = panel, id = wx.ID_ANY, label = "%s" % LocUnits) flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) flexSizer.Add(self.queryLengthSL, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE) flexSizer.Add(self.queryLengthValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE) flexSizer.Add(units, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) sizer.Add(item = flexSizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1) # # dangle # self.queryDangle = wx.RadioButton(parent = panel, id = wx.ID_ANY, label = _("dangle")) self.queryDangle.Bind(wx.EVT_RADIOBUTTON, self.OnChangeQuery) sizer.Add(item = self.queryDangle, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1) flexSizer = wx.FlexGridSizer (cols = 4, hgap = 5, vgap = 5) flexSizer.AddGrowableCol(0) txt = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Select dangles")) self.queryDangleSL = wx.Choice (parent = panel, id = wx.ID_ANY, choices = [_("shorter than"), _("longer than")]) self.queryDangleSL.SetSelection(UserSettings.Get(group = 'vdigit', key = "queryDangle", subkey = 'than-selection')) self.queryDangleValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (100, -1), initial = 1, min = 0, max = 1e6) self.queryDangleValue.SetValue(UserSettings.Get(group = 'vdigit', key = "queryDangle", subkey = 'thresh')) units = wx.StaticText(parent = panel, id = wx.ID_ANY, label = "%s" % LocUnits) flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) flexSizer.Add(self.queryDangleSL, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE) flexSizer.Add(self.queryDangleValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE) flexSizer.Add(units, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) sizer.Add(item = flexSizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1) if UserSettings.Get(group = 'vdigit', key = "query", subkey = 'selection') == 0: self.queryLength.SetValue(True) else: self.queryDangle.SetValue(True) # enable & disable items self.OnChangeQuery(None) border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5) panel.SetSizer(border) return panel def _createAttributesPage(self, notebook): """!Create notebook page for attributes""" panel = wx.Panel(parent = notebook, id = wx.ID_ANY) notebook.AddPage(page = panel, text = _("Attributes")) border = wx.BoxSizer(wx.VERTICAL) # # add new record # box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Digitize new feature")) sizer = wx.StaticBoxSizer(box, wx.VERTICAL) # checkbox self.addRecord = wx.CheckBox(parent = panel, id = wx.ID_ANY, label = _("Add new record into table")) self.addRecord.SetValue(UserSettings.Get(group = 'vdigit', key = "addRecord", subkey = 'enabled')) sizer.Add(item = self.addRecord, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1) # settings flexSizer = wx.FlexGridSizer(cols = 2, hgap = 3, vgap = 3) flexSizer.AddGrowableCol(0) settings = ((_("Layer"), 1), (_("Category"), 1), (_("Mode"), _("Next to use"))) # layer text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Layer")) self.layer = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (125, -1), min = 1, max = 1e3) self.layer.SetValue(int(UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value'))) flexSizer.Add(item = text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) flexSizer.Add(item = self.layer, proportion = 0, flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) # category number text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Category number")) self.category = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (125, -1), initial = UserSettings.Get(group = 'vdigit', key = "category", subkey = 'value'), min = -1e9, max = 1e9) if UserSettings.Get(group = 'vdigit', key = "categoryMode", subkey = 'selection') != 1: self.category.Enable(False) flexSizer.Add(item = text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) flexSizer.Add(item = self.category, proportion = 0, flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) # category mode text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Category mode")) self.categoryMode = wx.Choice(parent = panel, id = wx.ID_ANY, size = (125, -1), choices = [_("Next to use"), _("Manual entry"), _("No category")]) self.categoryMode.SetSelection(UserSettings.Get(group = 'vdigit', key = "categoryMode", subkey = 'selection')) flexSizer.Add(item = text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) flexSizer.Add(item = self.categoryMode, proportion = 0, flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1) border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5) # # delete existing record # box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Delete existing feature(s)")) sizer = wx.StaticBoxSizer(box, wx.VERTICAL) # checkbox self.deleteRecord = wx.CheckBox(parent = panel, id = wx.ID_ANY, label = _("Delete record from table")) self.deleteRecord.SetValue(UserSettings.Get(group = 'vdigit', key = "delRecord", subkey = 'enabled')) sizer.Add(item = self.deleteRecord, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1) border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5) # # geometry attributes (currently only length and area are supported) # box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Geometry attributes")) sizer = wx.StaticBoxSizer(box, wx.VERTICAL) gridSizer = wx.GridBagSizer(hgap = 3, vgap = 3) gridSizer.AddGrowableCol(0) self.geomAttrb = { 'length' : { 'label' : _('length') }, 'area' : { 'label' : _('area') }, 'perimeter' : { 'label' : _('perimeter') } } digitToolbar = self.parent.toolbars['vdigit'] try: vectorName = digitToolbar.GetLayer().GetName() except AttributeError: vectorName = None # no vector selected for editing layer = UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value') mapLayer = self.parent.toolbars['vdigit'].GetLayer() tree = self.parent.tree item = tree.FindItemByData('maplayer', mapLayer) row = 0 for attrb in ['length', 'area', 'perimeter']: # checkbox check = wx.CheckBox(parent = panel, id = wx.ID_ANY, label = self.geomAttrb[attrb]['label']) ### self.deleteRecord.SetValue(UserSettings.Get(group='vdigit', key="delRecord", subkey='enabled')) check.Bind(wx.EVT_CHECKBOX, self.OnGeomAttrb) # column (only numeric) column = gselect.ColumnSelect(parent = panel, size = (200, -1)) column.InsertColumns(vector = vectorName, layer = layer, excludeKey = True, type = ['integer', 'double precision']) # units if attrb == 'area': choices = Units.GetUnitsList('area') else: choices = Units.GetUnitsList('length') win_units = wx.Choice(parent = panel, id = wx.ID_ANY, choices = choices, size = (120, -1)) # default values check.SetValue(False) if item and tree.GetPyData(item)[0]['vdigit'] and \ 'geomAttr' in tree.GetPyData(item)[0]['vdigit'] and \ attrb in tree.GetPyData(item)[0]['vdigit']['geomAttr']: check.SetValue(True) column.SetStringSelection(tree.GetPyData(item)[0]['vdigit']['geomAttr'][attrb]['column']) if attrb == 'area': type = 'area' else: type = 'length' unitsIdx = Units.GetUnitsIndex(type, tree.GetPyData(item)[0]['vdigit']['geomAttr'][attrb]['units']) win_units.SetSelection(unitsIdx) if not vectorName: check.Enable(False) column.Enable(False) if not check.IsChecked(): column.Enable(False) self.geomAttrb[attrb]['check'] = check.GetId() self.geomAttrb[attrb]['column'] = column.GetId() self.geomAttrb[attrb]['units'] = win_units.GetId() gridSizer.Add(item = check, flag = wx.ALIGN_CENTER_VERTICAL, pos = (row, 0)) gridSizer.Add(item = column, pos = (row, 1)) gridSizer.Add(item = win_units, pos = (row, 2)) row += 1 note = '\n'.join(textwrap.wrap(_("Note: These settings are stored " "in the workspace not in the vector digitizer " "preferences."), 55)) gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY, label = note), pos = (3, 0), span = (1, 3)) sizer.Add(item = gridSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1) border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5) # bindings self.Bind(wx.EVT_CHECKBOX, self.OnChangeAddRecord, self.addRecord) self.Bind(wx.EVT_CHOICE, self.OnChangeCategoryMode, self.categoryMode) self.Bind(wx.EVT_SPINCTRL, self.OnChangeLayer, self.layer) panel.SetSizer(border) return panel def _symbologyData(self): """!Data for _createSymbologyPage() label | checkbox | color """ return ( # ("Background", "symbolBackground"), (_("Highlight"), "highlight"), (_("Highlight (duplicates)"), "highlightDupl"), (_("Point"), "point"), (_("Line"), "line"), (_("Boundary (no area)"), "boundaryNo"), (_("Boundary (one area)"), "boundaryOne"), (_("Boundary (two areas)"), "boundaryTwo"), (_("Centroid (in area)"), "centroidIn"), (_("Centroid (outside area)"), "centroidOut"), (_("Centroid (duplicate in area)"), "centroidDup"), (_("Node (one line)"), "nodeOne"), (_("Node (two lines)"), "nodeTwo"), (_("Vertex"), "vertex"), (_("Area (closed boundary + centroid)"), "area"), (_("Direction"), "direction"),) def OnGeomAttrb(self, event): """!Register geometry attributes (enable/disable) """ checked = event.IsChecked() id = event.GetId() key = None for attrb, val in self.geomAttrb.iteritems(): if val['check'] == id: key = attrb break column = self.FindWindowById(self.geomAttrb[key]['column']) if checked: column.Enable() else: column.Enable(False) def OnChangeCategoryMode(self, event): """!Change category mode """ mode = event.GetSelection() UserSettings.Set(group = 'vdigit', key = "categoryMode", subkey = 'selection', value = mode) if mode == 1: # manual entry self.category.Enable(True) elif self.category.IsEnabled(): # disable self.category.Enable(False) if mode == 2 and self.addRecord.IsChecked(): # no category self.addRecord.SetValue(False) self.digit.SetCategory() self.category.SetValue(UserSettings.Get(group = 'vdigit', key = 'category', subkey = 'value')) def OnChangeLayer(self, event): """!Layer changed """ layer = event.GetInt() if layer > 0: UserSettings.Set(group = 'vdigit', key = 'layer', subkey = 'value', value = layer) self.digit.SetCategory() self.category.SetValue(UserSettings.Get(group = 'vdigit', key = 'category', subkey = 'value')) event.Skip() def OnChangeAddRecord(self, event): """!Checkbox 'Add new record' status changed """ pass # self.category.SetValue(self.digit.SetCategory()) def OnChangeSnappingValue(self, event): """!Change snapping value - update static text """ value = self.snappingValue.GetValue() if value < 0: region = self.parent.MapWindow.Map.GetRegion() res = (region['nsres'] + region['ewres']) / 2. threshold = self.digit.GetDisplay().GetThreshold(value = res) else: if self.snappingUnit.GetStringSelection() == "map units": threshold = value else: threshold = self.digit.GetDisplay().GetThreshold(value = value) if value == 0: self.snappingInfo.SetLabel(_("Snapping disabled")) elif value < 0: self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s " "(based on comp. resolution)") % {'value' : threshold, 'units' : self.mapUnits.lower()}) else: self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s") % {'value' : threshold, 'units' : self.mapUnits.lower()}) event.Skip() def OnChangeSnappingUnits(self, event): """!Snapping units change -> update static text """ value = self.snappingValue.GetValue() units = self.snappingUnit.GetStringSelection() threshold = self.digit.GetDisplay().GetThreshold(value = value, units = units) if units == "map units": self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s") % {'value' : value, 'units' : self.mapUnits}) else: self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s") % {'value' : threshold, 'units' : self.mapUnits}) event.Skip() def OnChangeQuery(self, event): """!Change query """ if self.queryLength.GetValue(): # length self.queryLengthSL.Enable(True) self.queryLengthValue.Enable(True) self.queryDangleSL.Enable(False) self.queryDangleValue.Enable(False) else: # dangle self.queryLengthSL.Enable(False) self.queryLengthValue.Enable(False) self.queryDangleSL.Enable(True) self.queryDangleValue.Enable(True) def OnSave(self, event): """!Button 'Save' pressed """ self.UpdateSettings() self.parent.toolbars['vdigit'].settingsDialog = None fileSettings = {} UserSettings.ReadSettingsFile(settings = fileSettings) fileSettings['vdigit'] = UserSettings.Get(group = 'vdigit') file = UserSettings.SaveToFile(fileSettings) self.parent.GetLayerManager().goutput.WriteLog(_('Vector digitizer settings saved to file <%s>.') % file) self.Destroy() event.Skip() def OnApply(self, event): """!Button 'Apply' pressed """ self.UpdateSettings() def OnCancel(self, event): """!Button 'Cancel' pressed """ self.parent.toolbars['vdigit'].settingsDialog = None self.Destroy() if event: event.Skip() def UpdateSettings(self): """!Update digitizer settings """ self.parent.GetLayerManager().WorkspaceChanged() # geometry attributes # symbology for key, (enabled, color) in self.symbology.iteritems(): if enabled: UserSettings.Set(group = 'vdigit', key = 'symbol', subkey = [key, 'enabled'], value = enabled.IsChecked()) UserSettings.Set(group = 'vdigit', key = 'symbol', subkey = [key, 'color'], value = tuple(color.GetColour())) else: UserSettings.Set(group = 'vdigit', key = 'symbol', subkey = [key, 'color'], value = tuple(color.GetColour())) # display UserSettings.Set(group = 'vdigit', key = "lineWidth", subkey = 'value', value = int(self.lineWidthValue.GetValue())) # snapping UserSettings.Set(group = 'vdigit', key = "snapping", subkey = 'value', value = int(self.snappingValue.GetValue())) UserSettings.Set(group = 'vdigit', key = "snapping", subkey = 'units', value = self.snappingUnit.GetStringSelection()) UserSettings.Set(group = 'vdigit', key = "snapToVertex", subkey = 'enabled', value = self.snapVertex.IsChecked()) # digitize new feature UserSettings.Set(group = 'vdigit', key = "addRecord", subkey = 'enabled', value = self.addRecord.IsChecked()) UserSettings.Set(group = 'vdigit', key = "layer", subkey = 'value', value = int(self.layer.GetValue())) UserSettings.Set(group = 'vdigit', key = "category", subkey = 'value', value = int(self.category.GetValue())) UserSettings.Set(group = 'vdigit', key = "categoryMode", subkey = 'selection', value = self.categoryMode.GetSelection()) # delete existing feature UserSettings.Set(group = 'vdigit', key = "delRecord", subkey = 'enabled', value = self.deleteRecord.IsChecked()) # geometry attributes (workspace) mapLayer = self.parent.toolbars['vdigit'].GetLayer() tree = self.parent.tree item = tree.FindItemByData('maplayer', mapLayer) for key, val in self.geomAttrb.iteritems(): checked = self.FindWindowById(val['check']).IsChecked() column = self.FindWindowById(val['column']).GetValue() unitsIdx = self.FindWindowById(val['units']).GetSelection() if item and not tree.GetPyData(item)[0]['vdigit']: tree.GetPyData(item)[0]['vdigit'] = { 'geomAttr' : dict() } if checked: # enable if key == 'area': type = key else: type = 'length' unitsKey = Units.GetUnitsKey(type, unitsIdx) tree.GetPyData(item)[0]['vdigit']['geomAttr'][key] = { 'column' : column, 'units' : unitsKey } else: if item and tree.GetPyData(item)[0]['vdigit'] and \ key in tree.GetPyData(item)[0]['vdigit']['geomAttr']: del tree.GetPyData(item)[0]['vdigit']['geomAttr'][key] # query tool if self.queryLength.GetValue(): UserSettings.Set(group = 'vdigit', key = "query", subkey = 'selection', value = 0) else: UserSettings.Set(group = 'vdigit', key = "query", subkey = 'type', value = 1) UserSettings.Set(group = 'vdigit', key = "query", subkey = 'box', value = self.queryBox.IsChecked()) UserSettings.Set(group = 'vdigit', key = "queryLength", subkey = 'than-selection', value = self.queryLengthSL.GetSelection()) UserSettings.Set(group = 'vdigit', key = "queryLength", subkey = 'thresh', value = int(self.queryLengthValue.GetValue())) UserSettings.Set(group = 'vdigit', key = "queryDangle", subkey = 'than-selection', value = self.queryDangleSL.GetSelection()) UserSettings.Set(group = 'vdigit', key = "queryDangle", subkey = 'thresh', value = int(self.queryDangleValue.GetValue())) # select features for feature in ('point', 'line', 'centroid', 'boundary'): UserSettings.Set(group = 'vdigit', key = 'selectType', subkey = [feature, 'enabled'], value = self.FindWindowById(self.selectFeature[feature]).IsChecked()) UserSettings.Set(group = 'vdigit', key = "selectThresh", subkey = 'value', value = int(self.selectThreshValue.GetValue())) UserSettings.Set(group = 'vdigit', key = "checkForDupl", subkey = 'enabled', value = self.checkForDupl.IsChecked()) UserSettings.Set(group = 'vdigit', key = "selectInside", subkey = 'enabled', value = self.selectIn.IsChecked()) # on-exit UserSettings.Set(group = 'vdigit', key = "saveOnExit", subkey = 'enabled', value = self.save.IsChecked()) # break lines UserSettings.Set(group = 'vdigit', key = "breakLines", subkey = 'enabled', value = self.intersect.IsChecked()) self.digit.UpdateSettings() # redraw map if auto-rendering is enabled if self.parent.IsAutoRendered(): self.parent.OnRender(None) class VDigitCategoryDialog(wx.Dialog, listmix.ColumnSorterMixin): def __init__(self, parent, title, vectorName, query = None, cats = None, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs): """!Dialog used to display/modify categories of vector objects @param parent @param title dialog title @param query {coordinates, qdist} - used by v.edit/v.what @param cats directory of lines (layer/categories) - used by vdigit @param style dialog style """ self.parent = parent # mapdisplay.BufferedWindow class instance self.digit = parent.digit # map name self.vectorName = vectorName # line : {layer: [categories]} self.cats = {} # do not display dialog if no line is found (-> self.cats) if cats is None: if self._getCategories(query[0], query[1]) == 0 or not self.line: Debug.msg(3, "VDigitCategoryDialog(): nothing found!") else: self.cats = cats for line in cats.keys(): for layer in cats[line].keys(): self.cats[line][layer] = list(cats[line][layer]) layers = [] for layer in self.digit.GetLayers(): layers.append(str(layer)) # make copy of cats (used for 'reload') self.cats_orig = copy.deepcopy(self.cats) wx.Dialog.__init__(self, parent = self.parent, id = wx.ID_ANY, title = title, style = style, **kwargs) # list of categories box = wx.StaticBox(parent = self, id = wx.ID_ANY, label = " %s " % _("List of categories - right-click to delete")) listSizer = wx.StaticBoxSizer(box, wx.VERTICAL) self.list = CategoryListCtrl(parent = self, id = wx.ID_ANY, style = wx.LC_REPORT | wx.BORDER_NONE | wx.LC_SORT_ASCENDING | wx.LC_HRULES | wx.LC_VRULES) # sorter self.fid = self.cats.keys()[0] self.itemDataMap = self.list.Populate(self.cats[self.fid]) listmix.ColumnSorterMixin.__init__(self, 2) self.fidMulti = wx.Choice(parent = self, id = wx.ID_ANY, size = (150, -1)) self.fidMulti.Bind(wx.EVT_CHOICE, self.OnFeature) self.fidText = wx.StaticText(parent = self, id = wx.ID_ANY) if len(self.cats.keys()) == 1: self.fidMulti.Show(False) self.fidText.SetLabel(str(self.fid)) else: self.fidText.Show(False) choices = [] for fid in self.cats.keys(): choices.append(str(fid)) self.fidMulti.SetItems(choices) self.fidMulti.SetSelection(0) listSizer.Add(item = self.list, proportion = 1, flag = wx.EXPAND) # add new category box = wx.StaticBox(parent = self, id = wx.ID_ANY, label = " %s " % _("Add new category")) addSizer = wx.StaticBoxSizer(box, wx.VERTICAL) flexSizer = wx.FlexGridSizer (cols = 5, hgap = 5, vgap = 5) flexSizer.AddGrowableCol(3) layerNewTxt = wx.StaticText(parent = self, id = wx.ID_ANY, label = "%s:" % _("Layer")) self.layerNew = wx.Choice(parent = self, id = wx.ID_ANY, size = (75, -1), choices = layers) if len(layers) > 0: self.layerNew.SetSelection(0) catNewTxt = wx.StaticText(parent = self, id = wx.ID_ANY, label = "%s:" % _("Category")) try: newCat = max(self.cats[self.fid][1]) + 1 except KeyError: newCat = 1 self.catNew = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (75, -1), initial = newCat, min = 0, max = 1e9) btnAddCat = wx.Button(self, wx.ID_ADD) flexSizer.Add(item = layerNewTxt, proportion = 0, flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) flexSizer.Add(item = self.layerNew, proportion = 0, flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) flexSizer.Add(item = catNewTxt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, border = 10) flexSizer.Add(item = self.catNew, proportion = 0, flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) flexSizer.Add(item = btnAddCat, proportion = 0, flag = wx.EXPAND | wx.ALIGN_RIGHT | wx.FIXED_MINSIZE) addSizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5) # buttons btnApply = wx.Button(self, wx.ID_APPLY) btnApply.SetToolTipString(_("Apply changes")) btnCancel = wx.Button(self, wx.ID_CANCEL) btnCancel.SetToolTipString(_("Ignore changes and close dialog")) btnOk = wx.Button(self, wx.ID_OK) btnOk.SetToolTipString(_("Apply changes and close dialog")) btnOk.SetDefault() # sizers btnSizer = wx.StdDialogButtonSizer() btnSizer.AddButton(btnCancel) #btnSizer.AddButton(btnReload) #btnSizer.SetNegativeButton(btnReload) btnSizer.AddButton(btnApply) btnSizer.AddButton(btnOk) btnSizer.Realize() mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add(item = listSizer, proportion = 1, flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5) mainSizer.Add(item = addSizer, proportion = 0, flag = wx.EXPAND | wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5) fidSizer = wx.BoxSizer(wx.HORIZONTAL) fidSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Feature id:")), proportion = 0, border = 5, flag = wx.ALIGN_CENTER_VERTICAL) fidSizer.Add(item = self.fidMulti, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 5) fidSizer.Add(item = self.fidText, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 5) mainSizer.Add(item = fidSizer, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 5) mainSizer.Add(item = btnSizer, proportion = 0, flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5) self.SetSizer(mainSizer) mainSizer.Fit(self) self.SetAutoLayout(True) # set min size for dialog self.SetMinSize(self.GetBestSize()) # bindings btnApply.Bind(wx.EVT_BUTTON, self.OnApply) btnOk.Bind(wx.EVT_BUTTON, self.OnOK) btnAddCat.Bind(wx.EVT_BUTTON, self.OnAddCat) btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel) # list self.list.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightUp) #wxMSW self.list.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) #wxGTK self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnBeginEdit, self.list) self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnEndEdit, self.list) self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self.list) def GetListCtrl(self): """!Used by ColumnSorterMixin """ return self.list def OnColClick(self, event): """!Click on column header (order by) """ event.Skip() def OnBeginEdit(self, event): """!Editing of item started """ event.Allow() def OnEndEdit(self, event): """!Finish editing of item """ itemIndex = event.GetIndex() layerOld = int (self.list.GetItem(itemIndex, 0).GetText()) catOld = int (self.list.GetItem(itemIndex, 1).GetText()) if event.GetColumn() == 0: layerNew = int(event.GetLabel()) catNew = catOld else: layerNew = layerOld catNew = int(event.GetLabel()) try: if layerNew not in self.cats[self.fid].keys(): self.cats[self.fid][layerNew] = [] self.cats[self.fid][layerNew].append(catNew) self.cats[self.fid][layerOld].remove(catOld) except: event.Veto() self.list.SetStringItem(itemIndex, 0, str(layerNew)) self.list.SetStringItem(itemIndex, 1, str(catNew)) dlg = wx.MessageDialog(self, _("Unable to add new layer/category <%(layer)s/%(category)s>.\n" "Layer and category number must be integer.\n" "Layer number must be greater then zero.") % { 'layer': self.layerNew.GetStringSelection(), 'category' : str(self.catNew.GetValue()) }, _("Error"), wx.OK | wx.ICON_ERROR) dlg.ShowModal() dlg.Destroy() return False def OnRightDown(self, event): """!Mouse right button down """ x = event.GetX() y = event.GetY() item, flags = self.list.HitTest((x, y)) if item != wx.NOT_FOUND and \ flags & wx.LIST_HITTEST_ONITEM: self.list.Select(item) event.Skip() def OnRightUp(self, event): """!Mouse right button up """ if not hasattr(self, "popupID1"): self.popupID1 = wx.NewId() self.popupID2 = wx.NewId() self.popupID3 = wx.NewId() self.Bind(wx.EVT_MENU, self.OnItemDelete, id = self.popupID1) self.Bind(wx.EVT_MENU, self.OnItemDeleteAll, id = self.popupID2) self.Bind(wx.EVT_MENU, self.OnReload, id = self.popupID3) # generate popup-menu menu = wx.Menu() menu.Append(self.popupID1, _("Delete selected")) if self.list.GetFirstSelected() == -1: menu.Enable(self.popupID1, False) menu.Append(self.popupID2, _("Delete all")) menu.AppendSeparator() menu.Append(self.popupID3, _("Reload")) self.PopupMenu(menu) menu.Destroy() def OnItemSelected(self, event): """!Item selected """ event.Skip() def OnItemDelete(self, event): """!Delete selected item(s) from the list (layer/category pair) """ item = self.list.GetFirstSelected() while item != -1: layer = int (self.list.GetItem(item, 0).GetText()) cat = int (self.list.GetItem(item, 1).GetText()) self.list.DeleteItem(item) self.cats[self.fid][layer].remove(cat) item = self.list.GetFirstSelected() event.Skip() def OnItemDeleteAll(self, event): """!Delete all items from the list """ self.list.DeleteAllItems() self.cats[self.fid] = {} event.Skip() def OnFeature(self, event): """!Feature id changed (on duplicates) """ self.fid = int(event.GetString()) self.itemDataMap = self.list.Populate(self.cats[self.fid], update = True) try: newCat = max(self.cats[self.fid][1]) + 1 except KeyError: newCat = 1 self.catNew.SetValue(newCat) event.Skip() def _getCategories(self, coords, qdist): """!Get layer/category pairs for all available layers Return True line found or False if not found """ ret = gcmd.RunCommand('v.what', parent = self, quiet = True, map = self.vectorName, east_north = '%f,%f' % \ (float(coords[0]), float(coords[1])), distance = qdist) if not ret: return False for item in ret.splitlines(): litem = item.lower() if "id:" in litem: # get line id self.line = int(item.split(':')[1].strip()) elif "layer:" in litem: # add layer layer = int(item.split(':')[1].strip()) if layer not in self.cats.keys(): self.cats[layer] = [] elif "category:" in litem: # add category self.cats[layer].append(int(item.split(':')[1].strip())) return True def OnReload(self, event): """!Reload button pressed """ # restore original list self.cats = copy.deepcopy(self.cats_orig) # polulate list self.itemDataMap = self.list.Populate(self.cats[self.fid], update = True) event.Skip() def OnCancel(self, event): """!Cancel button pressed """ self.parent.parent.dialogs['category'] = None if self.digit: self.digit.GetDisplay().SetSelected([]) self.parent.UpdateMap(render = False) else: self.parent.parent.OnRender(None) self.Close() def OnApply(self, event): """!Apply button pressed """ for fid in self.cats.keys(): newfid = self.ApplyChanges(fid) if fid == self.fid and newfid > 0: self.fid = newfid def ApplyChanges(self, fid): """!Apply changes @param fid feature id """ cats = self.cats[fid] cats_orig = self.cats_orig[fid] # action : (catsFrom, catsTo) check = {'catadd': (cats, cats_orig), 'catdel': (cats_orig, cats)} newfid = -1 # add/delete new category for action, catsCurr in check.iteritems(): for layer in catsCurr[0].keys(): catList = [] for cat in catsCurr[0][layer]: if layer not in catsCurr[1].keys() or \ cat not in catsCurr[1][layer]: catList.append(cat) if catList != []: if action == 'catadd': add = True else: add = False newfid = self.digit.SetLineCats(fid, layer, catList, add) if len(self.cats.keys()) == 1: self.fidText.SetLabel("%d" % newfid) else: choices = self.fidMulti.GetItems() choices[choices.index(str(fid))] = str(newfid) self.fidMulti.SetItems(choices) self.fidMulti.SetStringSelection(str(newfid)) self.cats[newfid] = self.cats[fid] del self.cats[fid] fid = newfid if self.fid < 0: wx.MessageBox(parent = self, message = _("Unable to update vector map."), caption = _("Error"), style = wx.OK | wx.ICON_ERROR) self.cats_orig[fid] = copy.deepcopy(cats) return newfid def OnOK(self, event): """!OK button pressed """ self.OnApply(event) self.OnCancel(event) def OnAddCat(self, event): """!Button 'Add' new category pressed """ try: layer = int(self.layerNew.GetStringSelection()) cat = int(self.catNew.GetValue()) if layer <= 0: raise ValueError except ValueError: gcmd.GError(parent = self, message = _("Unable to add new layer/category <%(layer)s/%(category)s>.\n" "Layer and category number must be integer.\n" "Layer number must be greater then zero.") % {'layer' : str(self.layerNew.GetValue()), 'category' : str(self.catNew.GetValue())}) return False if layer not in self.cats[self.fid].keys(): self.cats[self.fid][layer] = [] self.cats[self.fid][layer].append(cat) # reload list self.itemDataMap = self.list.Populate(self.cats[self.fid], update = True) # update category number for add self.catNew.SetValue(cat + 1) event.Skip() return True def GetLine(self): """!Get id of selected line of 'None' if no line is selected """ return self.cats.keys() def UpdateDialog(self, query = None, cats = None): """!Update dialog @param query {coordinates, distance} - v.what @param cats directory layer/cats - vdigit Return True if updated otherwise False """ # line: {layer: [categories]} self.cats = {} # do not display dialog if no line is found (-> self.cats) if cats is None: ret = self._getCategories(query[0], query[1]) else: self.cats = cats for line in cats.keys(): for layer in cats[line].keys(): self.cats[line][layer] = list(cats[line][layer]) ret = 1 if ret == 0 or len(self.cats.keys()) < 1: Debug.msg(3, "VDigitCategoryDialog(): nothing found!") return False # make copy of cats (used for 'reload') self.cats_orig = copy.deepcopy(self.cats) # polulate list self.fid = self.cats.keys()[0] self.itemDataMap = self.list.Populate(self.cats[self.fid], update = True) try: newCat = max(self.cats[self.fid][1]) + 1 except KeyError: newCat = 1 self.catNew.SetValue(newCat) if len(self.cats.keys()) == 1: self.fidText.Show(True) self.fidMulti.Show(False) self.fidText.SetLabel("%d" % self.fid) else: self.fidText.Show(False) self.fidMulti.Show(True) choices = [] for fid in self.cats.keys(): choices.append(str(fid)) self.fidMulti.SetItems(choices) self.fidMulti.SetSelection(0) self.Layout() return True class CategoryListCtrl(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.TextEditMixin): def __init__(self, parent, id, pos = wx.DefaultPosition, size = wx.DefaultSize, style = 0): """!List of layers/categories""" self.parent = parent wx.ListCtrl.__init__(self, parent, id, pos, size, style) listmix.ListCtrlAutoWidthMixin.__init__(self) listmix.TextEditMixin.__init__(self) def Populate(self, cats, update = False): """!Populate the list """ itemData = {} # requested by sorter if not update: self.InsertColumn(0, _("Layer")) self.InsertColumn(1, _("Category")) else: self.DeleteAllItems() i = 1 for layer in cats.keys(): catsList = cats[layer] for cat in catsList: index = self.InsertStringItem(sys.maxint, str(catsList[0])) self.SetStringItem(index, 0, str(layer)) self.SetStringItem(index, 1, str(cat)) self.SetItemData(index, i) itemData[i] = (str(layer), str(cat)) i = i + 1 if not update: self.SetColumnWidth(0, 100) self.SetColumnWidth(1, wx.LIST_AUTOSIZE) self.currentItem = 0 return itemData class VDigitZBulkDialog(wx.Dialog): def __init__(self, parent, title, nselected, style = wx.DEFAULT_DIALOG_STYLE): """!Dialog used for Z bulk-labeling tool """ wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style) self.parent = parent # mapdisplay.BufferedWindow class instance # panel = wx.Panel(parent=self, id=wx.ID_ANY) border = wx.BoxSizer(wx.VERTICAL) txt = wx.StaticText(parent = self, label = _("%d lines selected for z bulk-labeling") % nselected); border.Add(item = txt, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5) box = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Set value")) sizer = wx.StaticBoxSizer(box, wx.VERTICAL) flexSizer = wx.FlexGridSizer (cols = 2, hgap = 5, vgap = 5) flexSizer.AddGrowableCol(0) # starting value txt = wx.StaticText(parent = self, label = _("Starting value")); self.value = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (150, -1), initial = 0, min = -1e6, max = 1e6) flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) flexSizer.Add(self.value, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE) # step txt = wx.StaticText(parent = self, label = _("Step")) self.step = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (150, -1), initial = 0, min = 0, max = 1e6) flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) flexSizer.Add(self.step, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE) sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1) border.Add(item = sizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 0) # buttons btnCancel = wx.Button(self, wx.ID_CANCEL) btnOk = wx.Button(self, wx.ID_OK) btnOk.SetDefault() # sizers btnSizer = wx.StdDialogButtonSizer() btnSizer.AddButton(btnCancel) btnSizer.AddButton(btnOk) btnSizer.Realize() mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add(item = border, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5) mainSizer.Add(item = btnSizer, proportion = 0, flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5) self.SetSizer(mainSizer) mainSizer.Fit(self) class VDigitDuplicatesDialog(wx.Dialog): def __init__(self, parent, data, title = _("List of duplicates"), style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, pos = wx.DefaultPosition): """!Show duplicated feature ids """ wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style, pos = pos) self.parent = parent # BufferedWindow self.data = data self.winList = [] # panel = wx.Panel(parent=self, id=wx.ID_ANY) # notebook self.notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT) id = 1 for key in self.data.keys(): panel = wx.Panel(parent = self.notebook, id = wx.ID_ANY) self.notebook.AddPage(page = panel, text = " %d " % (id)) # notebook body border = wx.BoxSizer(wx.VERTICAL) win = CheckListFeature(parent = panel, data = list(self.data[key])) self.winList.append(win.GetId()) border.Add(item = win, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5) panel.SetSizer(border) id += 1 # buttons btnCancel = wx.Button(self, wx.ID_CANCEL) btnOk = wx.Button(self, wx.ID_OK) btnOk.SetDefault() # sizers btnSizer = wx.StdDialogButtonSizer() btnSizer.AddButton(btnCancel) btnSizer.AddButton(btnOk) btnSizer.Realize() mainSizer = wx.BoxSizer(wx.VERTICAL) mainSizer.Add(item = self.notebook, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5) mainSizer.Add(item = btnSizer, proportion = 0, flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5) self.SetSizer(mainSizer) mainSizer.Fit(self) self.SetAutoLayout(True) # set min size for dialog self.SetMinSize((250, 180)) def GetUnSelected(self): """!Get unselected items (feature id) @return list of ids """ ids = [] for id in self.winList: wlist = self.FindWindowById(id) for item in range(wlist.GetItemCount()): if not wlist.IsChecked(item): ids.append(int(wlist.GetItem(item, 0).GetText())) return ids class CheckListFeature(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.CheckListCtrlMixin): def __init__(self, parent, data, pos = wx.DefaultPosition, log = None): """!List of mapset/owner/group """ self.parent = parent self.data = data wx.ListCtrl.__init__(self, parent, wx.ID_ANY, style = wx.LC_REPORT) listmix.CheckListCtrlMixin.__init__(self) self.log = log # setup mixins listmix.ListCtrlAutoWidthMixin.__init__(self) self.LoadData(self.data) def LoadData(self, data): """!Load data into list """ self.InsertColumn(0, _('Feature id')) self.InsertColumn(1, _('Layer (Categories)')) for item in data: index = self.InsertStringItem(sys.maxint, str(item[0])) self.SetStringItem(index, 1, str(item[1])) # enable all items by default for item in range(self.GetItemCount()): self.CheckItem(item, True) self.SetColumnWidth(col = 0, width = wx.LIST_AUTOSIZE_USEHEADER) self.SetColumnWidth(col = 1, width = wx.LIST_AUTOSIZE_USEHEADER) def OnCheckItem(self, index, flag): """!Mapset checked/unchecked """ pass