GRASS Programmer's Manual
6.4.2(2012)
|
00001 """! 00002 @package vdigit 00003 00004 @brief Dialogs for wxGUI vector digitizer 00005 00006 Classes: 00007 - VDigit 00008 - VDigitSettingsDialog 00009 - VDigitCategoryDialog 00010 - CategoryListCtrl 00011 - VDigitZBulkDialog 00012 - VDigitDuplicatesDialog 00013 - CheckListFeature 00014 00015 (C) 2007-2011 by the GRASS Development Team 00016 This program is free software under the GNU General Public License 00017 (>=v2). Read the file COPYING that comes with GRASS for details. 00018 00019 @author Martin Landa <landa.martin gmail.com> 00020 """ 00021 00022 import os 00023 import sys 00024 import string 00025 import copy 00026 import textwrap 00027 import traceback 00028 00029 from threading import Thread 00030 00031 import wx 00032 import wx.lib.colourselect as csel 00033 import wx.lib.mixins.listctrl as listmix 00034 00035 import gcmd 00036 import dbm 00037 from debug import Debug as Debug 00038 import gselect 00039 import globalvar 00040 from units import Units 00041 from preferences import globalSettings as UserSettings 00042 try: 00043 from wxvdigit import IVDigit, GV_LINES 00044 haveVDigit = True 00045 errorMsg = '' 00046 except (ImportError, NameError), err: 00047 haveVDigit = False 00048 errorMsg = err 00049 GV_LINES = -1 00050 class IVDigit: 00051 def __init__(self): 00052 pass 00053 00054 class VDigit(IVDigit): 00055 def __init__(self, mapwindow): 00056 """!Base class of vector digitizer 00057 00058 @param mapwindow reference to mapwindow (mapdisp_window.BufferedWindow) instance 00059 """ 00060 IVDigit.__init__(self, mapwindow) 00061 00062 class VDigitSettingsDialog(wx.Dialog): 00063 def __init__(self, parent, title, style = wx.DEFAULT_DIALOG_STYLE): 00064 """!Standard settings dialog for digitization purposes 00065 """ 00066 wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style) 00067 00068 self.parent = parent # mapdisplay.MapFrame class instance 00069 self.digit = self.parent.MapWindow.digit 00070 00071 # notebook 00072 notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT) 00073 self._createSymbologyPage(notebook) 00074 self.digit.SetCategory() 00075 self._createGeneralPage(notebook) 00076 self._createAttributesPage(notebook) 00077 self._createQueryPage(notebook) 00078 00079 # buttons 00080 btnApply = wx.Button(self, wx.ID_APPLY) 00081 btnCancel = wx.Button(self, wx.ID_CANCEL) 00082 btnSave = wx.Button(self, wx.ID_SAVE) 00083 btnSave.SetDefault() 00084 00085 # bindigs 00086 btnApply.Bind(wx.EVT_BUTTON, self.OnApply) 00087 btnApply.SetToolTipString(_("Apply changes for this session")) 00088 btnApply.SetDefault() 00089 btnSave.Bind(wx.EVT_BUTTON, self.OnSave) 00090 btnSave.SetToolTipString(_("Close dialog and save changes to user settings file")) 00091 btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel) 00092 btnCancel.SetToolTipString(_("Close dialog and ignore changes")) 00093 00094 # sizers 00095 btnSizer = wx.StdDialogButtonSizer() 00096 btnSizer.AddButton(btnCancel) 00097 btnSizer.AddButton(btnApply) 00098 btnSizer.AddButton(btnSave) 00099 btnSizer.Realize() 00100 00101 mainSizer = wx.BoxSizer(wx.VERTICAL) 00102 mainSizer.Add(item = notebook, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5) 00103 mainSizer.Add(item = btnSizer, proportion = 0, 00104 flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5) 00105 00106 self.Bind(wx.EVT_CLOSE, self.OnCancel) 00107 00108 self.SetSizer(mainSizer) 00109 mainSizer.Fit(self) 00110 00111 def _createSymbologyPage(self, notebook): 00112 """!Create notebook page concerning symbology settings""" 00113 panel = wx.Panel(parent = notebook, id = wx.ID_ANY) 00114 notebook.AddPage(page = panel, text = _("Symbology")) 00115 00116 sizer = wx.BoxSizer(wx.VERTICAL) 00117 00118 flexSizer = wx.FlexGridSizer (cols = 3, hgap = 5, vgap = 5) 00119 flexSizer.AddGrowableCol(0) 00120 00121 self.symbology = {} 00122 for label, key in self._symbologyData(): 00123 textLabel = wx.StaticText(panel, wx.ID_ANY, label) 00124 color = csel.ColourSelect(panel, id = wx.ID_ANY, 00125 colour = UserSettings.Get(group = 'vdigit', key = 'symbol', 00126 subkey = [key, 'color']), size = globalvar.DIALOG_COLOR_SIZE) 00127 isEnabled = UserSettings.Get(group = 'vdigit', key = 'symbol', 00128 subkey = [key, 'enabled']) 00129 if isEnabled is not None: 00130 enabled = wx.CheckBox(panel, id = wx.ID_ANY, label = "") 00131 enabled.SetValue(isEnabled) 00132 self.symbology[key] = (enabled, color) 00133 else: 00134 enabled = (1, 1) 00135 self.symbology[key] = (None, color) 00136 00137 flexSizer.Add(textLabel, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) 00138 flexSizer.Add(enabled, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE) 00139 flexSizer.Add(color, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE) 00140 color.SetName("GetColour") 00141 00142 sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 10) 00143 00144 panel.SetSizer(sizer) 00145 00146 return panel 00147 00148 def _createGeneralPage(self, notebook): 00149 """!Create notebook page concerning general settings""" 00150 panel = wx.Panel(parent = notebook, id = wx.ID_ANY) 00151 notebook.AddPage(page = panel, text = _("General")) 00152 00153 border = wx.BoxSizer(wx.VERTICAL) 00154 00155 # 00156 # display section 00157 # 00158 box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Display")) 00159 sizer = wx.StaticBoxSizer(box, wx.VERTICAL) 00160 flexSizer = wx.FlexGridSizer (cols = 3, hgap = 5, vgap = 5) 00161 flexSizer.AddGrowableCol(0) 00162 # line width 00163 text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Line width")) 00164 self.lineWidthValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (75, -1), 00165 initial = UserSettings.Get(group = 'vdigit', key = "lineWidth", subkey = 'value'), 00166 min = 1, max = 1e6) 00167 units = wx.StaticText(parent = panel, id = wx.ID_ANY, size = (115, -1), 00168 label = UserSettings.Get(group = 'vdigit', key = "lineWidth", subkey = 'units'), 00169 style = wx.ALIGN_LEFT) 00170 flexSizer.Add(text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) 00171 flexSizer.Add(self.lineWidthValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE) 00172 flexSizer.Add(units, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 00173 border = 10) 00174 00175 sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1) 00176 border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5) 00177 00178 # 00179 # snapping section 00180 # 00181 box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Snapping")) 00182 sizer = wx.StaticBoxSizer(box, wx.VERTICAL) 00183 flexSizer = wx.FlexGridSizer(cols = 3, hgap = 5, vgap = 5) 00184 flexSizer.AddGrowableCol(0) 00185 00186 # snapping 00187 text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Snapping threshold")) 00188 self.snappingValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (75, -1), 00189 initial = UserSettings.Get(group = 'vdigit', key = "snapping", subkey = 'value'), 00190 min = -1, max = 1e6) 00191 self.snappingValue.Bind(wx.EVT_SPINCTRL, self.OnChangeSnappingValue) 00192 self.snappingValue.Bind(wx.EVT_TEXT, self.OnChangeSnappingValue) 00193 self.snappingUnit = wx.Choice(parent = panel, id = wx.ID_ANY, size = (125, -1), 00194 choices = [_("screen pixels"), _("map units")]) 00195 self.snappingUnit.SetStringSelection(UserSettings.Get(group = 'vdigit', key = "snapping", subkey = 'units')) 00196 self.snappingUnit.Bind(wx.EVT_CHOICE, self.OnChangeSnappingUnits) 00197 flexSizer.Add(text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) 00198 flexSizer.Add(self.snappingValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE) 00199 flexSizer.Add(self.snappingUnit, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE) 00200 00201 vertexSizer = wx.BoxSizer(wx.VERTICAL) 00202 self.snapVertex = wx.CheckBox(parent = panel, id = wx.ID_ANY, 00203 label = _("Snap also to vertex")) 00204 self.snapVertex.SetValue(UserSettings.Get(group = 'vdigit', key = "snapToVertex", subkey = 'enabled')) 00205 vertexSizer.Add(item = self.snapVertex, proportion = 0, flag = wx.EXPAND) 00206 self.mapUnits = self.parent.MapWindow.Map.GetProjInfo()['units'] 00207 self.snappingInfo = wx.StaticText(parent = panel, id = wx.ID_ANY, 00208 label = _("Snapping threshold is %(value).1f %(units)s") % \ 00209 {'value' : self.digit.GetDisplay().GetThreshold(), 00210 'units' : self.mapUnits}) 00211 vertexSizer.Add(item = self.snappingInfo, proportion = 0, 00212 flag = wx.ALL | wx.EXPAND, border = 1) 00213 00214 sizer.Add(item = flexSizer, proportion = 1, flag = wx.EXPAND) 00215 sizer.Add(item = vertexSizer, proportion = 1, flag = wx.EXPAND) 00216 border.Add(item = sizer, proportion = 0, flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5) 00217 00218 # 00219 # select box 00220 # 00221 box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Select vector features")) 00222 # feature type 00223 sizer = wx.StaticBoxSizer(box, wx.VERTICAL) 00224 inSizer = wx.BoxSizer(wx.HORIZONTAL) 00225 self.selectFeature = {} 00226 for feature in ('point', 'line', 00227 'centroid', 'boundary'): 00228 chkbox = wx.CheckBox(parent = panel, label = feature) 00229 self.selectFeature[feature] = chkbox.GetId() 00230 chkbox.SetValue(UserSettings.Get(group = 'vdigit', key = 'selectType', 00231 subkey = [feature, 'enabled'])) 00232 inSizer.Add(item = chkbox, proportion = 0, 00233 flag = wx.EXPAND | wx.ALL, border = 5) 00234 sizer.Add(item = inSizer, proportion = 0, flag = wx.EXPAND) 00235 # threshold 00236 flexSizer = wx.FlexGridSizer (cols = 3, hgap = 5, vgap = 5) 00237 flexSizer.AddGrowableCol(0) 00238 text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Select threshold")) 00239 self.selectThreshValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (75, -1), 00240 initial = UserSettings.Get(group = 'vdigit', key = "selectThresh", subkey = 'value'), 00241 min = 1, max = 1e6) 00242 units = wx.StaticText(parent = panel, id = wx.ID_ANY, size = (115, -1), 00243 label = UserSettings.Get(group = 'vdigit', key = "lineWidth", subkey = 'units'), 00244 style = wx.ALIGN_LEFT) 00245 flexSizer.Add(text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) 00246 flexSizer.Add(self.selectThreshValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE) 00247 flexSizer.Add(units, proportion = 0, flag = wx.ALIGN_RIGHT | wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 00248 border = 10) 00249 00250 self.selectIn = wx.CheckBox(parent = panel, id = wx.ID_ANY, 00251 label = _("Select only features inside of selection bounding box")) 00252 self.selectIn.SetValue(UserSettings.Get(group = 'vdigit', key = "selectInside", subkey = 'enabled')) 00253 self.selectIn.SetToolTipString(_("By default are selected all features overlapping selection bounding box ")) 00254 00255 self.checkForDupl = wx.CheckBox(parent = panel, id = wx.ID_ANY, 00256 label = _("Check for duplicates")) 00257 self.checkForDupl.SetValue(UserSettings.Get(group = 'vdigit', key = "checkForDupl", subkey = 'enabled')) 00258 00259 00260 sizer.Add(item = flexSizer, proportion = 0, flag = wx.EXPAND) 00261 sizer.Add(item = self.selectIn, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 1) 00262 sizer.Add(item = self.checkForDupl, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 1) 00263 border.Add(item = sizer, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5) 00264 00265 # 00266 # digitize lines box 00267 # 00268 box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Digitize line features")) 00269 sizer = wx.StaticBoxSizer(box, wx.VERTICAL) 00270 00271 self.intersect = wx.CheckBox(parent = panel, label = _("Break lines at intersection")) 00272 self.intersect.SetValue(UserSettings.Get(group = 'vdigit', key = 'breakLines', subkey = 'enabled')) 00273 00274 sizer.Add(item = self.intersect, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1) 00275 00276 border.Add(item = sizer, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5) 00277 00278 # 00279 # save-on-exit box 00280 # 00281 box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Save changes")) 00282 # save changes on exit? 00283 sizer = wx.StaticBoxSizer(box, wx.VERTICAL) 00284 self.save = wx.CheckBox(parent = panel, label = _("Save changes on exit")) 00285 self.save.SetValue(UserSettings.Get(group = 'vdigit', key = 'saveOnExit', subkey = 'enabled')) 00286 sizer.Add(item = self.save, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1) 00287 border.Add(item = sizer, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5) 00288 00289 panel.SetSizer(border) 00290 00291 return panel 00292 00293 def _createQueryPage(self, notebook): 00294 """!Create notebook page for query tool""" 00295 panel = wx.Panel(parent = notebook, id = wx.ID_ANY) 00296 notebook.AddPage(page = panel, text = _("Query tool")) 00297 00298 border = wx.BoxSizer(wx.VERTICAL) 00299 00300 # 00301 # query tool box 00302 # 00303 box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Choose query tool")) 00304 sizer = wx.StaticBoxSizer(box, wx.VERTICAL) 00305 00306 LocUnits = self.parent.MapWindow.Map.GetProjInfo()['units'] 00307 00308 self.queryBox = wx.CheckBox(parent = panel, id = wx.ID_ANY, label = _("Select by box")) 00309 self.queryBox.SetValue(UserSettings.Get(group = 'vdigit', key = "query", subkey = 'box')) 00310 00311 sizer.Add(item = self.queryBox, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1) 00312 sizer.Add((0, 5)) 00313 00314 # 00315 # length 00316 # 00317 self.queryLength = wx.RadioButton(parent = panel, id = wx.ID_ANY, label = _("length")) 00318 self.queryLength.Bind(wx.EVT_RADIOBUTTON, self.OnChangeQuery) 00319 sizer.Add(item = self.queryLength, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1) 00320 flexSizer = wx.FlexGridSizer (cols = 4, hgap = 5, vgap = 5) 00321 flexSizer.AddGrowableCol(0) 00322 txt = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Select lines")) 00323 self.queryLengthSL = wx.Choice (parent = panel, id = wx.ID_ANY, 00324 choices = [_("shorter than"), _("longer than")]) 00325 self.queryLengthSL.SetSelection(UserSettings.Get(group = 'vdigit', key = "queryLength", subkey = 'than-selection')) 00326 self.queryLengthValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (100, -1), 00327 initial = 1, 00328 min = 0, max = 1e6) 00329 self.queryLengthValue.SetValue(UserSettings.Get(group = 'vdigit', key = "queryLength", subkey = 'thresh')) 00330 units = wx.StaticText(parent = panel, id = wx.ID_ANY, label = "%s" % LocUnits) 00331 flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) 00332 flexSizer.Add(self.queryLengthSL, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE) 00333 flexSizer.Add(self.queryLengthValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE) 00334 flexSizer.Add(units, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) 00335 sizer.Add(item = flexSizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1) 00336 00337 # 00338 # dangle 00339 # 00340 self.queryDangle = wx.RadioButton(parent = panel, id = wx.ID_ANY, label = _("dangle")) 00341 self.queryDangle.Bind(wx.EVT_RADIOBUTTON, self.OnChangeQuery) 00342 sizer.Add(item = self.queryDangle, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1) 00343 flexSizer = wx.FlexGridSizer (cols = 4, hgap = 5, vgap = 5) 00344 flexSizer.AddGrowableCol(0) 00345 txt = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Select dangles")) 00346 self.queryDangleSL = wx.Choice (parent = panel, id = wx.ID_ANY, 00347 choices = [_("shorter than"), _("longer than")]) 00348 self.queryDangleSL.SetSelection(UserSettings.Get(group = 'vdigit', key = "queryDangle", subkey = 'than-selection')) 00349 self.queryDangleValue = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (100, -1), 00350 initial = 1, 00351 min = 0, max = 1e6) 00352 self.queryDangleValue.SetValue(UserSettings.Get(group = 'vdigit', key = "queryDangle", subkey = 'thresh')) 00353 units = wx.StaticText(parent = panel, id = wx.ID_ANY, label = "%s" % LocUnits) 00354 flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) 00355 flexSizer.Add(self.queryDangleSL, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE) 00356 flexSizer.Add(self.queryDangleValue, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE) 00357 flexSizer.Add(units, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) 00358 sizer.Add(item = flexSizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1) 00359 00360 if UserSettings.Get(group = 'vdigit', key = "query", subkey = 'selection') == 0: 00361 self.queryLength.SetValue(True) 00362 else: 00363 self.queryDangle.SetValue(True) 00364 00365 # enable & disable items 00366 self.OnChangeQuery(None) 00367 00368 border.Add(item = sizer, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5) 00369 00370 panel.SetSizer(border) 00371 00372 return panel 00373 00374 def _createAttributesPage(self, notebook): 00375 """!Create notebook page for attributes""" 00376 panel = wx.Panel(parent = notebook, id = wx.ID_ANY) 00377 notebook.AddPage(page = panel, text = _("Attributes")) 00378 00379 border = wx.BoxSizer(wx.VERTICAL) 00380 00381 # 00382 # add new record 00383 # 00384 box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Digitize new feature")) 00385 sizer = wx.StaticBoxSizer(box, wx.VERTICAL) 00386 00387 # checkbox 00388 self.addRecord = wx.CheckBox(parent = panel, id = wx.ID_ANY, 00389 label = _("Add new record into table")) 00390 self.addRecord.SetValue(UserSettings.Get(group = 'vdigit', key = "addRecord", subkey = 'enabled')) 00391 sizer.Add(item = self.addRecord, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1) 00392 # settings 00393 flexSizer = wx.FlexGridSizer(cols = 2, hgap = 3, vgap = 3) 00394 flexSizer.AddGrowableCol(0) 00395 settings = ((_("Layer"), 1), (_("Category"), 1), (_("Mode"), _("Next to use"))) 00396 # layer 00397 text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Layer")) 00398 self.layer = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (125, -1), 00399 min = 1, max = 1e3) 00400 self.layer.SetValue(int(UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value'))) 00401 flexSizer.Add(item = text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) 00402 flexSizer.Add(item = self.layer, proportion = 0, 00403 flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) 00404 # category number 00405 text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Category number")) 00406 self.category = wx.SpinCtrl(parent = panel, id = wx.ID_ANY, size = (125, -1), 00407 initial = UserSettings.Get(group = 'vdigit', key = "category", subkey = 'value'), 00408 min = -1e9, max = 1e9) 00409 if UserSettings.Get(group = 'vdigit', key = "categoryMode", subkey = 'selection') != 1: 00410 self.category.Enable(False) 00411 flexSizer.Add(item = text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) 00412 flexSizer.Add(item = self.category, proportion = 0, 00413 flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) 00414 # category mode 00415 text = wx.StaticText(parent = panel, id = wx.ID_ANY, label = _("Category mode")) 00416 self.categoryMode = wx.Choice(parent = panel, id = wx.ID_ANY, size = (125, -1), 00417 choices = [_("Next to use"), _("Manual entry"), _("No category")]) 00418 self.categoryMode.SetSelection(UserSettings.Get(group = 'vdigit', key = "categoryMode", subkey = 'selection')) 00419 flexSizer.Add(item = text, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) 00420 flexSizer.Add(item = self.categoryMode, proportion = 0, 00421 flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) 00422 00423 sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1) 00424 border.Add(item = sizer, proportion = 0, 00425 flag = wx.ALL | wx.EXPAND, border = 5) 00426 00427 # 00428 # delete existing record 00429 # 00430 box = wx.StaticBox (parent = panel, id = wx.ID_ANY, label = " %s " % _("Delete existing feature(s)")) 00431 sizer = wx.StaticBoxSizer(box, wx.VERTICAL) 00432 00433 # checkbox 00434 self.deleteRecord = wx.CheckBox(parent = panel, id = wx.ID_ANY, 00435 label = _("Delete record from table")) 00436 self.deleteRecord.SetValue(UserSettings.Get(group = 'vdigit', key = "delRecord", subkey = 'enabled')) 00437 sizer.Add(item = self.deleteRecord, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 1) 00438 border.Add(item = sizer, proportion = 0, 00439 flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5) 00440 00441 # 00442 # geometry attributes (currently only length and area are supported) 00443 # 00444 box = wx.StaticBox (parent = panel, id = wx.ID_ANY, 00445 label = " %s " % _("Geometry attributes")) 00446 sizer = wx.StaticBoxSizer(box, wx.VERTICAL) 00447 gridSizer = wx.GridBagSizer(hgap = 3, vgap = 3) 00448 gridSizer.AddGrowableCol(0) 00449 self.geomAttrb = { 'length' : { 'label' : _('length') }, 00450 'area' : { 'label' : _('area') }, 00451 'perimeter' : { 'label' : _('perimeter') } } 00452 00453 digitToolbar = self.parent.toolbars['vdigit'] 00454 try: 00455 vectorName = digitToolbar.GetLayer().GetName() 00456 except AttributeError: 00457 vectorName = None # no vector selected for editing 00458 layer = UserSettings.Get(group = 'vdigit', key = "layer", subkey = 'value') 00459 mapLayer = self.parent.toolbars['vdigit'].GetLayer() 00460 tree = self.parent.tree 00461 item = tree.FindItemByData('maplayer', mapLayer) 00462 row = 0 00463 for attrb in ['length', 'area', 'perimeter']: 00464 # checkbox 00465 check = wx.CheckBox(parent = panel, id = wx.ID_ANY, 00466 label = self.geomAttrb[attrb]['label']) 00467 ### self.deleteRecord.SetValue(UserSettings.Get(group='vdigit', key="delRecord", subkey='enabled')) 00468 check.Bind(wx.EVT_CHECKBOX, self.OnGeomAttrb) 00469 # column (only numeric) 00470 column = gselect.ColumnSelect(parent = panel, size = (200, -1)) 00471 column.InsertColumns(vector = vectorName, 00472 layer = layer, excludeKey = True, 00473 type = ['integer', 'double precision']) 00474 # units 00475 if attrb == 'area': 00476 choices = Units.GetUnitsList('area') 00477 else: 00478 choices = Units.GetUnitsList('length') 00479 win_units = wx.Choice(parent = panel, id = wx.ID_ANY, 00480 choices = choices, size = (120, -1)) 00481 00482 # default values 00483 check.SetValue(False) 00484 if item and tree.GetPyData(item)[0]['vdigit'] and \ 00485 'geomAttr' in tree.GetPyData(item)[0]['vdigit'] and \ 00486 attrb in tree.GetPyData(item)[0]['vdigit']['geomAttr']: 00487 check.SetValue(True) 00488 column.SetStringSelection(tree.GetPyData(item)[0]['vdigit']['geomAttr'][attrb]['column']) 00489 if attrb == 'area': 00490 type = 'area' 00491 else: 00492 type = 'length' 00493 unitsIdx = Units.GetUnitsIndex(type, 00494 tree.GetPyData(item)[0]['vdigit']['geomAttr'][attrb]['units']) 00495 win_units.SetSelection(unitsIdx) 00496 00497 if not vectorName: 00498 check.Enable(False) 00499 column.Enable(False) 00500 00501 if not check.IsChecked(): 00502 column.Enable(False) 00503 00504 self.geomAttrb[attrb]['check'] = check.GetId() 00505 self.geomAttrb[attrb]['column'] = column.GetId() 00506 self.geomAttrb[attrb]['units'] = win_units.GetId() 00507 00508 gridSizer.Add(item = check, 00509 flag = wx.ALIGN_CENTER_VERTICAL, 00510 pos = (row, 0)) 00511 gridSizer.Add(item = column, 00512 pos = (row, 1)) 00513 gridSizer.Add(item = win_units, 00514 pos = (row, 2)) 00515 row += 1 00516 00517 note = '\n'.join(textwrap.wrap(_("Note: These settings are stored " 00518 "in the workspace not in the vector digitizer " 00519 "preferences."), 55)) 00520 gridSizer.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY, 00521 label = note), 00522 pos = (3, 0), span = (1, 3)) 00523 00524 sizer.Add(item = gridSizer, proportion = 1, 00525 flag = wx.ALL | wx.EXPAND, border = 1) 00526 border.Add(item = sizer, proportion = 0, 00527 flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5) 00528 00529 # bindings 00530 self.Bind(wx.EVT_CHECKBOX, self.OnChangeAddRecord, self.addRecord) 00531 self.Bind(wx.EVT_CHOICE, self.OnChangeCategoryMode, self.categoryMode) 00532 self.Bind(wx.EVT_SPINCTRL, self.OnChangeLayer, self.layer) 00533 00534 panel.SetSizer(border) 00535 00536 return panel 00537 00538 def _symbologyData(self): 00539 """!Data for _createSymbologyPage() 00540 00541 label | checkbox | color 00542 """ 00543 00544 return ( 00545 # ("Background", "symbolBackground"), 00546 (_("Highlight"), "highlight"), 00547 (_("Highlight (duplicates)"), "highlightDupl"), 00548 (_("Point"), "point"), 00549 (_("Line"), "line"), 00550 (_("Boundary (no area)"), "boundaryNo"), 00551 (_("Boundary (one area)"), "boundaryOne"), 00552 (_("Boundary (two areas)"), "boundaryTwo"), 00553 (_("Centroid (in area)"), "centroidIn"), 00554 (_("Centroid (outside area)"), "centroidOut"), 00555 (_("Centroid (duplicate in area)"), "centroidDup"), 00556 (_("Node (one line)"), "nodeOne"), 00557 (_("Node (two lines)"), "nodeTwo"), 00558 (_("Vertex"), "vertex"), 00559 (_("Area (closed boundary + centroid)"), "area"), 00560 (_("Direction"), "direction"),) 00561 00562 def OnGeomAttrb(self, event): 00563 """!Register geometry attributes (enable/disable) 00564 """ 00565 checked = event.IsChecked() 00566 id = event.GetId() 00567 key = None 00568 for attrb, val in self.geomAttrb.iteritems(): 00569 if val['check'] == id: 00570 key = attrb 00571 break 00572 00573 column = self.FindWindowById(self.geomAttrb[key]['column']) 00574 if checked: 00575 column.Enable() 00576 else: 00577 column.Enable(False) 00578 00579 def OnChangeCategoryMode(self, event): 00580 """!Change category mode 00581 """ 00582 mode = event.GetSelection() 00583 UserSettings.Set(group = 'vdigit', key = "categoryMode", subkey = 'selection', value = mode) 00584 if mode == 1: # manual entry 00585 self.category.Enable(True) 00586 elif self.category.IsEnabled(): # disable 00587 self.category.Enable(False) 00588 00589 if mode == 2 and self.addRecord.IsChecked(): # no category 00590 self.addRecord.SetValue(False) 00591 00592 self.digit.SetCategory() 00593 self.category.SetValue(UserSettings.Get(group = 'vdigit', key = 'category', subkey = 'value')) 00594 00595 def OnChangeLayer(self, event): 00596 """!Layer changed 00597 """ 00598 layer = event.GetInt() 00599 if layer > 0: 00600 UserSettings.Set(group = 'vdigit', key = 'layer', subkey = 'value', value = layer) 00601 self.digit.SetCategory() 00602 self.category.SetValue(UserSettings.Get(group = 'vdigit', key = 'category', subkey = 'value')) 00603 00604 event.Skip() 00605 00606 def OnChangeAddRecord(self, event): 00607 """!Checkbox 'Add new record' status changed 00608 """ 00609 self.category.SetValue(self.digit.SetCategory()) 00610 00611 def OnChangeSnappingValue(self, event): 00612 """!Change snapping value - update static text 00613 """ 00614 value = self.snappingValue.GetValue() 00615 00616 if value < 0: 00617 region = self.parent.MapWindow.Map.GetRegion() 00618 res = (region['nsres'] + region['ewres']) / 2. 00619 threshold = self.digit.GetDisplay().GetThreshold(value = res) 00620 else: 00621 if self.snappingUnit.GetStringSelection() == "map units": 00622 threshold = value 00623 else: 00624 threshold = self.digit.GetDisplay().GetThreshold(value = value) 00625 00626 if value == 0: 00627 self.snappingInfo.SetLabel(_("Snapping disabled")) 00628 elif value < 0: 00629 self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s " 00630 "(based on comp. resolution)") % 00631 {'value' : threshold, 00632 'units' : self.mapUnits.lower()}) 00633 else: 00634 self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s") % 00635 {'value' : threshold, 00636 'units' : self.mapUnits.lower()}) 00637 00638 event.Skip() 00639 00640 def OnChangeSnappingUnits(self, event): 00641 """!Snapping units change -> update static text 00642 """ 00643 value = self.snappingValue.GetValue() 00644 units = self.snappingUnit.GetStringSelection() 00645 threshold = self.digit.GetDisplay().GetThreshold(value = value, units = units) 00646 00647 if units == "map units": 00648 self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s") % 00649 {'value' : value, 00650 'units' : self.mapUnits}) 00651 else: 00652 self.snappingInfo.SetLabel(_("Snapping threshold is %(value).1f %(units)s") % 00653 {'value' : threshold, 00654 'units' : self.mapUnits}) 00655 00656 event.Skip() 00657 00658 def OnChangeQuery(self, event): 00659 """!Change query 00660 """ 00661 if self.queryLength.GetValue(): 00662 # length 00663 self.queryLengthSL.Enable(True) 00664 self.queryLengthValue.Enable(True) 00665 self.queryDangleSL.Enable(False) 00666 self.queryDangleValue.Enable(False) 00667 else: 00668 # dangle 00669 self.queryLengthSL.Enable(False) 00670 self.queryLengthValue.Enable(False) 00671 self.queryDangleSL.Enable(True) 00672 self.queryDangleValue.Enable(True) 00673 00674 def OnSave(self, event): 00675 """!Button 'Save' pressed 00676 """ 00677 self.UpdateSettings() 00678 self.parent.toolbars['vdigit'].settingsDialog = None 00679 00680 fileSettings = {} 00681 UserSettings.ReadSettingsFile(settings = fileSettings) 00682 fileSettings['vdigit'] = UserSettings.Get(group = 'vdigit') 00683 00684 file = UserSettings.SaveToFile(fileSettings) 00685 self.parent.GetLayerManager().goutput.WriteLog(_('Vector digitizer settings saved to file <%s>.') % file) 00686 00687 self.Destroy() 00688 00689 event.Skip() 00690 00691 def OnApply(self, event): 00692 """!Button 'Apply' pressed 00693 """ 00694 self.UpdateSettings() 00695 00696 def OnCancel(self, event): 00697 """!Button 'Cancel' pressed 00698 """ 00699 self.parent.toolbars['vdigit'].settingsDialog = None 00700 self.Destroy() 00701 00702 if event: 00703 event.Skip() 00704 00705 def UpdateSettings(self): 00706 """!Update digitizer settings 00707 """ 00708 self.parent.GetLayerManager().WorkspaceChanged() # geometry attributes 00709 # symbology 00710 for key, (enabled, color) in self.symbology.iteritems(): 00711 if enabled: 00712 UserSettings.Set(group = 'vdigit', key = 'symbol', 00713 subkey = [key, 'enabled'], 00714 value = enabled.IsChecked()) 00715 UserSettings.Set(group = 'vdigit', key = 'symbol', 00716 subkey = [key, 'color'], 00717 value = tuple(color.GetColour())) 00718 else: 00719 UserSettings.Set(group = 'vdigit', key = 'symbol', 00720 subkey = [key, 'color'], 00721 value = tuple(color.GetColour())) 00722 # display 00723 UserSettings.Set(group = 'vdigit', key = "lineWidth", subkey = 'value', 00724 value = int(self.lineWidthValue.GetValue())) 00725 00726 # snapping 00727 UserSettings.Set(group = 'vdigit', key = "snapping", subkey = 'value', 00728 value = int(self.snappingValue.GetValue())) 00729 UserSettings.Set(group = 'vdigit', key = "snapping", subkey = 'units', 00730 value = self.snappingUnit.GetStringSelection()) 00731 UserSettings.Set(group = 'vdigit', key = "snapToVertex", subkey = 'enabled', 00732 value = self.snapVertex.IsChecked()) 00733 00734 # digitize new feature 00735 UserSettings.Set(group = 'vdigit', key = "addRecord", subkey = 'enabled', 00736 value = self.addRecord.IsChecked()) 00737 UserSettings.Set(group = 'vdigit', key = "layer", subkey = 'value', 00738 value = int(self.layer.GetValue())) 00739 UserSettings.Set(group = 'vdigit', key = "category", subkey = 'value', 00740 value = int(self.category.GetValue())) 00741 UserSettings.Set(group = 'vdigit', key = "categoryMode", subkey = 'selection', 00742 value = self.categoryMode.GetSelection()) 00743 00744 # delete existing feature 00745 UserSettings.Set(group = 'vdigit', key = "delRecord", subkey = 'enabled', 00746 value = self.deleteRecord.IsChecked()) 00747 00748 # geometry attributes (workspace) 00749 mapLayer = self.parent.toolbars['vdigit'].GetLayer() 00750 tree = self.parent.tree 00751 item = tree.FindItemByData('maplayer', mapLayer) 00752 for key, val in self.geomAttrb.iteritems(): 00753 checked = self.FindWindowById(val['check']).IsChecked() 00754 column = self.FindWindowById(val['column']).GetValue() 00755 unitsIdx = self.FindWindowById(val['units']).GetSelection() 00756 if item and not tree.GetPyData(item)[0]['vdigit']: 00757 tree.GetPyData(item)[0]['vdigit'] = { 'geomAttr' : dict() } 00758 00759 if checked: # enable 00760 if key == 'area': 00761 type = key 00762 else: 00763 type = 'length' 00764 unitsKey = Units.GetUnitsKey(type, unitsIdx) 00765 tree.GetPyData(item)[0]['vdigit']['geomAttr'][key] = { 'column' : column, 00766 'units' : unitsKey } 00767 else: 00768 if item and tree.GetPyData(item)[0]['vdigit'] and \ 00769 key in tree.GetPyData(item)[0]['vdigit']['geomAttr']: 00770 del tree.GetPyData(item)[0]['vdigit']['geomAttr'][key] 00771 00772 # query tool 00773 if self.queryLength.GetValue(): 00774 UserSettings.Set(group = 'vdigit', key = "query", subkey = 'selection', 00775 value = 0) 00776 else: 00777 UserSettings.Set(group = 'vdigit', key = "query", subkey = 'type', 00778 value = 1) 00779 UserSettings.Set(group = 'vdigit', key = "query", subkey = 'box', 00780 value = self.queryBox.IsChecked()) 00781 UserSettings.Set(group = 'vdigit', key = "queryLength", subkey = 'than-selection', 00782 value = self.queryLengthSL.GetSelection()) 00783 UserSettings.Set(group = 'vdigit', key = "queryLength", subkey = 'thresh', 00784 value = int(self.queryLengthValue.GetValue())) 00785 UserSettings.Set(group = 'vdigit', key = "queryDangle", subkey = 'than-selection', 00786 value = self.queryDangleSL.GetSelection()) 00787 UserSettings.Set(group = 'vdigit', key = "queryDangle", subkey = 'thresh', 00788 value = int(self.queryDangleValue.GetValue())) 00789 00790 # select features 00791 for feature in ('point', 'line', 00792 'centroid', 'boundary'): 00793 UserSettings.Set(group = 'vdigit', key = 'selectType', 00794 subkey = [feature, 'enabled'], 00795 value = self.FindWindowById(self.selectFeature[feature]).IsChecked()) 00796 UserSettings.Set(group = 'vdigit', key = "selectThresh", subkey = 'value', 00797 value = int(self.selectThreshValue.GetValue())) 00798 UserSettings.Set(group = 'vdigit', key = "checkForDupl", subkey = 'enabled', 00799 value = self.checkForDupl.IsChecked()) 00800 UserSettings.Set(group = 'vdigit', key = "selectInside", subkey = 'enabled', 00801 value = self.selectIn.IsChecked()) 00802 00803 # on-exit 00804 UserSettings.Set(group = 'vdigit', key = "saveOnExit", subkey = 'enabled', 00805 value = self.save.IsChecked()) 00806 00807 # break lines 00808 UserSettings.Set(group = 'vdigit', key = "breakLines", subkey = 'enabled', 00809 value = self.intersect.IsChecked()) 00810 00811 self.digit.UpdateSettings() 00812 00813 # redraw map if auto-rendering is enabled 00814 if self.parent.statusbarWin['render'].GetValue(): 00815 self.parent.OnRender(None) 00816 00817 class VDigitCategoryDialog(wx.Dialog, listmix.ColumnSorterMixin): 00818 def __init__(self, parent, title, 00819 vectorName, query = None, cats = None, 00820 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs): 00821 """!Dialog used to display/modify categories of vector objects 00822 00823 @param parent 00824 @param title dialog title 00825 @param query {coordinates, qdist} - used by v.edit/v.what 00826 @param cats directory of lines (layer/categories) - used by vdigit 00827 @param style dialog style 00828 """ 00829 self.parent = parent # mapdisplay.BufferedWindow class instance 00830 self.digit = parent.digit 00831 00832 # map name 00833 self.vectorName = vectorName 00834 00835 # line : {layer: [categories]} 00836 self.cats = {} 00837 00838 # do not display dialog if no line is found (-> self.cats) 00839 if cats is None: 00840 if self._getCategories(query[0], query[1]) == 0 or not self.line: 00841 Debug.msg(3, "VDigitCategoryDialog(): nothing found!") 00842 else: 00843 self.cats = cats 00844 for line in cats.keys(): 00845 for layer in cats[line].keys(): 00846 self.cats[line][layer] = list(cats[line][layer]) 00847 00848 layers = [] 00849 for layer in self.digit.GetLayers(): 00850 layers.append(str(layer)) 00851 00852 # make copy of cats (used for 'reload') 00853 self.cats_orig = copy.deepcopy(self.cats) 00854 00855 wx.Dialog.__init__(self, parent = self.parent, id = wx.ID_ANY, title = title, 00856 style = style, **kwargs) 00857 00858 # list of categories 00859 box = wx.StaticBox(parent = self, id = wx.ID_ANY, 00860 label = " %s " % _("List of categories - right-click to delete")) 00861 listSizer = wx.StaticBoxSizer(box, wx.VERTICAL) 00862 self.list = CategoryListCtrl(parent = self, id = wx.ID_ANY, 00863 style = wx.LC_REPORT | 00864 wx.BORDER_NONE | 00865 wx.LC_SORT_ASCENDING | 00866 wx.LC_HRULES | 00867 wx.LC_VRULES) 00868 # sorter 00869 self.fid = self.cats.keys()[0] 00870 self.itemDataMap = self.list.Populate(self.cats[self.fid]) 00871 listmix.ColumnSorterMixin.__init__(self, 2) 00872 self.fidMulti = wx.Choice(parent = self, id = wx.ID_ANY, 00873 size = (150, -1)) 00874 self.fidMulti.Bind(wx.EVT_CHOICE, self.OnFeature) 00875 self.fidText = wx.StaticText(parent = self, id = wx.ID_ANY) 00876 if len(self.cats.keys()) == 1: 00877 self.fidMulti.Show(False) 00878 self.fidText.SetLabel(str(self.fid)) 00879 else: 00880 self.fidText.Show(False) 00881 choices = [] 00882 for fid in self.cats.keys(): 00883 choices.append(str(fid)) 00884 self.fidMulti.SetItems(choices) 00885 self.fidMulti.SetSelection(0) 00886 00887 listSizer.Add(item = self.list, proportion = 1, flag = wx.EXPAND) 00888 00889 # add new category 00890 box = wx.StaticBox(parent = self, id = wx.ID_ANY, 00891 label = " %s " % _("Add new category")) 00892 addSizer = wx.StaticBoxSizer(box, wx.VERTICAL) 00893 flexSizer = wx.FlexGridSizer (cols = 5, hgap = 5, vgap = 5) 00894 flexSizer.AddGrowableCol(3) 00895 00896 layerNewTxt = wx.StaticText(parent = self, id = wx.ID_ANY, 00897 label = "%s:" % _("Layer")) 00898 self.layerNew = wx.Choice(parent = self, id = wx.ID_ANY, size = (75, -1), 00899 choices = layers) 00900 if len(layers) > 0: 00901 self.layerNew.SetSelection(0) 00902 00903 catNewTxt = wx.StaticText(parent = self, id = wx.ID_ANY, 00904 label = "%s:" % _("Category")) 00905 00906 try: 00907 newCat = max(self.cats[self.fid][1]) + 1 00908 except KeyError: 00909 newCat = 1 00910 self.catNew = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (75, -1), 00911 initial = newCat, min = 0, max = 1e9) 00912 btnAddCat = wx.Button(self, wx.ID_ADD) 00913 flexSizer.Add(item = layerNewTxt, proportion = 0, 00914 flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) 00915 flexSizer.Add(item = self.layerNew, proportion = 0, 00916 flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) 00917 flexSizer.Add(item = catNewTxt, proportion = 0, 00918 flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT, 00919 border = 10) 00920 flexSizer.Add(item = self.catNew, proportion = 0, 00921 flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL) 00922 flexSizer.Add(item = btnAddCat, proportion = 0, 00923 flag = wx.EXPAND | wx.ALIGN_RIGHT | wx.FIXED_MINSIZE) 00924 addSizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5) 00925 00926 # buttons 00927 btnApply = wx.Button(self, wx.ID_APPLY) 00928 btnApply.SetToolTipString(_("Apply changes")) 00929 btnCancel = wx.Button(self, wx.ID_CANCEL) 00930 btnCancel.SetToolTipString(_("Ignore changes and close dialog")) 00931 btnOk = wx.Button(self, wx.ID_OK) 00932 btnOk.SetToolTipString(_("Apply changes and close dialog")) 00933 btnOk.SetDefault() 00934 00935 # sizers 00936 btnSizer = wx.StdDialogButtonSizer() 00937 btnSizer.AddButton(btnCancel) 00938 #btnSizer.AddButton(btnReload) 00939 #btnSizer.SetNegativeButton(btnReload) 00940 btnSizer.AddButton(btnApply) 00941 btnSizer.AddButton(btnOk) 00942 btnSizer.Realize() 00943 00944 mainSizer = wx.BoxSizer(wx.VERTICAL) 00945 mainSizer.Add(item = listSizer, proportion = 1, 00946 flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5) 00947 mainSizer.Add(item = addSizer, proportion = 0, 00948 flag = wx.EXPAND | wx.ALIGN_CENTER | 00949 wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5) 00950 fidSizer = wx.BoxSizer(wx.HORIZONTAL) 00951 fidSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY, 00952 label = _("Feature id:")), 00953 proportion = 0, border = 5, 00954 flag = wx.ALIGN_CENTER_VERTICAL) 00955 fidSizer.Add(item = self.fidMulti, proportion = 0, 00956 flag = wx.EXPAND | wx.ALL, border = 5) 00957 fidSizer.Add(item = self.fidText, proportion = 0, 00958 flag = wx.EXPAND | wx.ALL, border = 5) 00959 mainSizer.Add(item = fidSizer, proportion = 0, 00960 flag = wx.EXPAND | wx.ALL, border = 5) 00961 mainSizer.Add(item = btnSizer, proportion = 0, 00962 flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5) 00963 00964 self.SetSizer(mainSizer) 00965 mainSizer.Fit(self) 00966 self.SetAutoLayout(True) 00967 00968 # set min size for dialog 00969 self.SetMinSize(self.GetBestSize()) 00970 00971 # bindings 00972 btnApply.Bind(wx.EVT_BUTTON, self.OnApply) 00973 btnOk.Bind(wx.EVT_BUTTON, self.OnOK) 00974 btnAddCat.Bind(wx.EVT_BUTTON, self.OnAddCat) 00975 btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel) 00976 00977 # list 00978 self.list.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightUp) #wxMSW 00979 self.list.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) #wxGTK 00980 self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnBeginEdit, self.list) 00981 self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnEndEdit, self.list) 00982 self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self.list) 00983 00984 def GetListCtrl(self): 00985 """!Used by ColumnSorterMixin 00986 """ 00987 return self.list 00988 00989 def OnColClick(self, event): 00990 """!Click on column header (order by) 00991 """ 00992 event.Skip() 00993 00994 def OnBeginEdit(self, event): 00995 """!Editing of item started 00996 """ 00997 event.Allow() 00998 00999 def OnEndEdit(self, event): 01000 """!Finish editing of item 01001 """ 01002 itemIndex = event.GetIndex() 01003 layerOld = int (self.list.GetItem(itemIndex, 0).GetText()) 01004 catOld = int (self.list.GetItem(itemIndex, 1).GetText()) 01005 01006 if event.GetColumn() == 0: 01007 layerNew = int(event.GetLabel()) 01008 catNew = catOld 01009 else: 01010 layerNew = layerOld 01011 catNew = int(event.GetLabel()) 01012 01013 try: 01014 if layerNew not in self.cats[self.fid].keys(): 01015 self.cats[self.fid][layerNew] = [] 01016 self.cats[self.fid][layerNew].append(catNew) 01017 self.cats[self.fid][layerOld].remove(catOld) 01018 except: 01019 event.Veto() 01020 self.list.SetStringItem(itemIndex, 0, str(layerNew)) 01021 self.list.SetStringItem(itemIndex, 1, str(catNew)) 01022 dlg = wx.MessageDialog(self, _("Unable to add new layer/category <%(layer)s/%(category)s>.\n" 01023 "Layer and category number must be integer.\n" 01024 "Layer number must be greater than zero.") % 01025 { 'layer': self.layerNew.GetStringSelection(), 01026 'category' : str(self.catNew.GetValue()) }, 01027 _("Error"), wx.OK | wx.ICON_ERROR) 01028 dlg.ShowModal() 01029 dlg.Destroy() 01030 return False 01031 01032 def OnRightDown(self, event): 01033 """!Mouse right button down 01034 """ 01035 x = event.GetX() 01036 y = event.GetY() 01037 item, flags = self.list.HitTest((x, y)) 01038 01039 if item != wx.NOT_FOUND and \ 01040 flags & wx.LIST_HITTEST_ONITEM: 01041 self.list.Select(item) 01042 01043 event.Skip() 01044 01045 def OnRightUp(self, event): 01046 """!Mouse right button up 01047 """ 01048 if not hasattr(self, "popupID1"): 01049 self.popupID1 = wx.NewId() 01050 self.popupID2 = wx.NewId() 01051 self.popupID3 = wx.NewId() 01052 self.Bind(wx.EVT_MENU, self.OnItemDelete, id = self.popupID1) 01053 self.Bind(wx.EVT_MENU, self.OnItemDeleteAll, id = self.popupID2) 01054 self.Bind(wx.EVT_MENU, self.OnReload, id = self.popupID3) 01055 01056 # generate popup-menu 01057 menu = wx.Menu() 01058 menu.Append(self.popupID1, _("Delete selected")) 01059 if self.list.GetFirstSelected() == -1: 01060 menu.Enable(self.popupID1, False) 01061 01062 menu.Append(self.popupID2, _("Delete all")) 01063 menu.AppendSeparator() 01064 menu.Append(self.popupID3, _("Reload")) 01065 01066 self.PopupMenu(menu) 01067 menu.Destroy() 01068 01069 def OnItemSelected(self, event): 01070 """!Item selected 01071 """ 01072 event.Skip() 01073 01074 def OnItemDelete(self, event): 01075 """!Delete selected item(s) from the list (layer/category pair) 01076 """ 01077 item = self.list.GetFirstSelected() 01078 while item != -1: 01079 layer = int (self.list.GetItem(item, 0).GetText()) 01080 cat = int (self.list.GetItem(item, 1).GetText()) 01081 self.list.DeleteItem(item) 01082 self.cats[self.fid][layer].remove(cat) 01083 01084 item = self.list.GetFirstSelected() 01085 01086 event.Skip() 01087 01088 def OnItemDeleteAll(self, event): 01089 """!Delete all items from the list 01090 """ 01091 self.list.DeleteAllItems() 01092 self.cats[self.fid] = {} 01093 01094 event.Skip() 01095 01096 def OnFeature(self, event): 01097 """!Feature id changed (on duplicates) 01098 """ 01099 self.fid = int(event.GetString()) 01100 01101 self.itemDataMap = self.list.Populate(self.cats[self.fid], 01102 update = True) 01103 01104 try: 01105 newCat = max(self.cats[self.fid][1]) + 1 01106 except KeyError: 01107 newCat = 1 01108 01109 self.catNew.SetValue(newCat) 01110 01111 event.Skip() 01112 01113 def _getCategories(self, coords, qdist): 01114 """!Get layer/category pairs for all available 01115 layers 01116 01117 Return True line found or False if not found 01118 """ 01119 ret = gcmd.RunCommand('v.what', 01120 parent = self, 01121 quiet = True, 01122 map = self.vectorName, 01123 east_north = '%f,%f' % \ 01124 (float(coords[0]), float(coords[1])), 01125 distance = qdist) 01126 01127 if not ret: 01128 return False 01129 01130 for item in ret.splitlines(): 01131 litem = item.lower() 01132 if "id:" in litem: # get line id 01133 self.line = int(item.split(':')[1].strip()) 01134 elif "layer:" in litem: # add layer 01135 layer = int(item.split(':')[1].strip()) 01136 if layer not in self.cats.keys(): 01137 self.cats[layer] = [] 01138 elif "category:" in litem: # add category 01139 self.cats[layer].append(int(item.split(':')[1].strip())) 01140 01141 return True 01142 01143 def OnReload(self, event): 01144 """!Reload button pressed 01145 """ 01146 # restore original list 01147 self.cats = copy.deepcopy(self.cats_orig) 01148 01149 # polulate list 01150 self.itemDataMap = self.list.Populate(self.cats[self.fid], 01151 update = True) 01152 01153 event.Skip() 01154 01155 def OnCancel(self, event): 01156 """!Cancel button pressed 01157 """ 01158 self.parent.parent.dialogs['category'] = None 01159 if self.digit: 01160 self.digit.GetDisplay().SetSelected([]) 01161 self.parent.UpdateMap(render = False) 01162 else: 01163 self.parent.parent.OnRender(None) 01164 01165 self.Close() 01166 01167 def OnApply(self, event): 01168 """!Apply button pressed 01169 """ 01170 for fid in self.cats.keys(): 01171 newfid = self.ApplyChanges(fid) 01172 if fid == self.fid and newfid > 0: 01173 self.fid = newfid 01174 01175 def ApplyChanges(self, fid): 01176 """!Apply changes 01177 01178 @param fid feature id 01179 """ 01180 cats = self.cats[fid] 01181 cats_orig = self.cats_orig[fid] 01182 01183 # action : (catsFrom, catsTo) 01184 check = {'catadd': (cats, cats_orig), 01185 'catdel': (cats_orig, cats)} 01186 01187 newfid = -1 01188 01189 # add/delete new category 01190 for action, catsCurr in check.iteritems(): 01191 for layer in catsCurr[0].keys(): 01192 catList = [] 01193 for cat in catsCurr[0][layer]: 01194 if layer not in catsCurr[1].keys() or \ 01195 cat not in catsCurr[1][layer]: 01196 catList.append(cat) 01197 if catList != []: 01198 if action == 'catadd': 01199 add = True 01200 else: 01201 add = False 01202 01203 newfid = self.digit.SetLineCats(fid, layer, 01204 catList, add) 01205 if len(self.cats.keys()) == 1: 01206 self.fidText.SetLabel("%d" % newfid) 01207 else: 01208 choices = self.fidMulti.GetItems() 01209 choices[choices.index(str(fid))] = str(newfid) 01210 self.fidMulti.SetItems(choices) 01211 self.fidMulti.SetStringSelection(str(newfid)) 01212 01213 self.cats[newfid] = self.cats[fid] 01214 del self.cats[fid] 01215 01216 fid = newfid 01217 if self.fid < 0: 01218 wx.MessageBox(parent = self, message = _("Unable to update vector map."), 01219 caption = _("Error"), style = wx.OK | wx.ICON_ERROR) 01220 01221 self.cats_orig[fid] = copy.deepcopy(cats) 01222 01223 return newfid 01224 01225 def OnOK(self, event): 01226 """!OK button pressed 01227 """ 01228 self.OnApply(event) 01229 self.OnCancel(event) 01230 01231 def OnAddCat(self, event): 01232 """!Button 'Add' new category pressed 01233 """ 01234 try: 01235 layer = int(self.layerNew.GetStringSelection()) 01236 cat = int(self.catNew.GetValue()) 01237 if layer <= 0: 01238 raise ValueError 01239 except ValueError: 01240 gcmd.GError(parent = self, 01241 message = _("Unable to add new layer/category <%(layer)s/%(category)s>.\n" 01242 "Layer and category number must be integer.\n" 01243 "Layer number must be greater then zero.") % 01244 {'layer' : str(self.layerNew.GetValue()), 01245 'category' : str(self.catNew.GetValue())}) 01246 return False 01247 01248 if layer not in self.cats[self.fid].keys(): 01249 self.cats[self.fid][layer] = [] 01250 01251 self.cats[self.fid][layer].append(cat) 01252 01253 # reload list 01254 self.itemDataMap = self.list.Populate(self.cats[self.fid], 01255 update = True) 01256 01257 # update category number for add 01258 self.catNew.SetValue(cat + 1) 01259 01260 event.Skip() 01261 01262 return True 01263 01264 def GetLine(self): 01265 """!Get id of selected line of 'None' if no line is selected 01266 """ 01267 return self.cats.keys() 01268 01269 def UpdateDialog(self, query = None, cats = None): 01270 """!Update dialog 01271 01272 @param query {coordinates, distance} - v.what 01273 @param cats directory layer/cats - vdigit 01274 Return True if updated otherwise False 01275 """ 01276 # line: {layer: [categories]} 01277 self.cats = {} 01278 # do not display dialog if no line is found (-> self.cats) 01279 if cats is None: 01280 ret = self._getCategories(query[0], query[1]) 01281 else: 01282 self.cats = cats 01283 for line in cats.keys(): 01284 for layer in cats[line].keys(): 01285 self.cats[line][layer] = list(cats[line][layer]) 01286 ret = 1 01287 if ret == 0 or len(self.cats.keys()) < 1: 01288 Debug.msg(3, "VDigitCategoryDialog(): nothing found!") 01289 return False 01290 01291 # make copy of cats (used for 'reload') 01292 self.cats_orig = copy.deepcopy(self.cats) 01293 01294 # polulate list 01295 self.fid = self.cats.keys()[0] 01296 self.itemDataMap = self.list.Populate(self.cats[self.fid], 01297 update = True) 01298 01299 try: 01300 newCat = max(self.cats[self.fid][1]) + 1 01301 except KeyError: 01302 newCat = 1 01303 self.catNew.SetValue(newCat) 01304 01305 if len(self.cats.keys()) == 1: 01306 self.fidText.Show(True) 01307 self.fidMulti.Show(False) 01308 self.fidText.SetLabel("%d" % self.fid) 01309 else: 01310 self.fidText.Show(False) 01311 self.fidMulti.Show(True) 01312 choices = [] 01313 for fid in self.cats.keys(): 01314 choices.append(str(fid)) 01315 self.fidMulti.SetItems(choices) 01316 self.fidMulti.SetSelection(0) 01317 01318 self.Layout() 01319 01320 return True 01321 01322 class CategoryListCtrl(wx.ListCtrl, 01323 listmix.ListCtrlAutoWidthMixin, 01324 listmix.TextEditMixin): 01325 def __init__(self, parent, id, pos = wx.DefaultPosition, 01326 size = wx.DefaultSize, style = 0): 01327 """!List of layers/categories""" 01328 self.parent = parent 01329 01330 wx.ListCtrl.__init__(self, parent, id, pos, size, style) 01331 01332 listmix.ListCtrlAutoWidthMixin.__init__(self) 01333 listmix.TextEditMixin.__init__(self) 01334 01335 def Populate(self, cats, update = False): 01336 """!Populate the list 01337 """ 01338 itemData = {} # requested by sorter 01339 01340 if not update: 01341 self.InsertColumn(0, _("Layer")) 01342 self.InsertColumn(1, _("Category")) 01343 else: 01344 self.DeleteAllItems() 01345 01346 i = 1 01347 for layer in cats.keys(): 01348 catsList = cats[layer] 01349 for cat in catsList: 01350 index = self.InsertStringItem(sys.maxint, str(catsList[0])) 01351 self.SetStringItem(index, 0, str(layer)) 01352 self.SetStringItem(index, 1, str(cat)) 01353 self.SetItemData(index, i) 01354 itemData[i] = (str(layer), str(cat)) 01355 i = i + 1 01356 01357 if not update: 01358 self.SetColumnWidth(0, 100) 01359 self.SetColumnWidth(1, wx.LIST_AUTOSIZE) 01360 01361 self.currentItem = 0 01362 01363 return itemData 01364 01365 class VDigitZBulkDialog(wx.Dialog): 01366 def __init__(self, parent, title, nselected, style = wx.DEFAULT_DIALOG_STYLE): 01367 """!Dialog used for Z bulk-labeling tool 01368 """ 01369 wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style) 01370 01371 self.parent = parent # mapdisplay.BufferedWindow class instance 01372 01373 # panel = wx.Panel(parent=self, id=wx.ID_ANY) 01374 01375 border = wx.BoxSizer(wx.VERTICAL) 01376 01377 txt = wx.StaticText(parent = self, 01378 label = _("%d lines selected for z bulk-labeling") % nselected); 01379 border.Add(item = txt, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5) 01380 01381 box = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Set value")) 01382 sizer = wx.StaticBoxSizer(box, wx.VERTICAL) 01383 flexSizer = wx.FlexGridSizer (cols = 2, hgap = 5, vgap = 5) 01384 flexSizer.AddGrowableCol(0) 01385 01386 # starting value 01387 txt = wx.StaticText(parent = self, 01388 label = _("Starting value")); 01389 self.value = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (150, -1), 01390 initial = 0, 01391 min = -1e6, max = 1e6) 01392 flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) 01393 flexSizer.Add(self.value, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE) 01394 01395 # step 01396 txt = wx.StaticText(parent = self, 01397 label = _("Step")) 01398 self.step = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (150, -1), 01399 initial = 0, 01400 min = 0, max = 1e6) 01401 flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL) 01402 flexSizer.Add(self.step, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE) 01403 01404 sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1) 01405 border.Add(item = sizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 0) 01406 01407 # buttons 01408 btnCancel = wx.Button(self, wx.ID_CANCEL) 01409 btnOk = wx.Button(self, wx.ID_OK) 01410 btnOk.SetDefault() 01411 01412 # sizers 01413 btnSizer = wx.StdDialogButtonSizer() 01414 btnSizer.AddButton(btnCancel) 01415 btnSizer.AddButton(btnOk) 01416 btnSizer.Realize() 01417 01418 mainSizer = wx.BoxSizer(wx.VERTICAL) 01419 mainSizer.Add(item = border, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5) 01420 mainSizer.Add(item = btnSizer, proportion = 0, 01421 flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5) 01422 01423 self.SetSizer(mainSizer) 01424 mainSizer.Fit(self) 01425 01426 class VDigitDuplicatesDialog(wx.Dialog): 01427 def __init__(self, parent, data, title = _("List of duplicates"), 01428 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, 01429 pos = wx.DefaultPosition): 01430 """!Show duplicated feature ids 01431 """ 01432 wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style, 01433 pos = pos) 01434 01435 self.parent = parent # BufferedWindow 01436 self.data = data 01437 self.winList = [] 01438 01439 # panel = wx.Panel(parent=self, id=wx.ID_ANY) 01440 01441 # notebook 01442 self.notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT) 01443 01444 id = 1 01445 for key in self.data.keys(): 01446 panel = wx.Panel(parent = self.notebook, id = wx.ID_ANY) 01447 self.notebook.AddPage(page = panel, text = " %d " % (id)) 01448 01449 # notebook body 01450 border = wx.BoxSizer(wx.VERTICAL) 01451 01452 win = CheckListFeature(parent = panel, data = list(self.data[key])) 01453 self.winList.append(win.GetId()) 01454 01455 border.Add(item = win, proportion = 1, 01456 flag = wx.ALL | wx.EXPAND, border = 5) 01457 01458 panel.SetSizer(border) 01459 01460 id += 1 01461 01462 # buttons 01463 btnCancel = wx.Button(self, wx.ID_CANCEL) 01464 btnOk = wx.Button(self, wx.ID_OK) 01465 btnOk.SetDefault() 01466 01467 # sizers 01468 btnSizer = wx.StdDialogButtonSizer() 01469 btnSizer.AddButton(btnCancel) 01470 btnSizer.AddButton(btnOk) 01471 btnSizer.Realize() 01472 01473 mainSizer = wx.BoxSizer(wx.VERTICAL) 01474 mainSizer.Add(item = self.notebook, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5) 01475 mainSizer.Add(item = btnSizer, proportion = 0, 01476 flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5) 01477 01478 self.SetSizer(mainSizer) 01479 mainSizer.Fit(self) 01480 self.SetAutoLayout(True) 01481 01482 # set min size for dialog 01483 self.SetMinSize((250, 180)) 01484 01485 def GetUnSelected(self): 01486 """!Get unselected items (feature id) 01487 01488 @return list of ids 01489 """ 01490 ids = [] 01491 for id in self.winList: 01492 wlist = self.FindWindowById(id) 01493 01494 for item in range(wlist.GetItemCount()): 01495 if not wlist.IsChecked(item): 01496 ids.append(int(wlist.GetItem(item, 0).GetText())) 01497 01498 return ids 01499 01500 class CheckListFeature(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.CheckListCtrlMixin): 01501 def __init__(self, parent, data, 01502 pos = wx.DefaultPosition, log = None): 01503 """!List of mapset/owner/group 01504 """ 01505 self.parent = parent 01506 self.data = data 01507 01508 wx.ListCtrl.__init__(self, parent, wx.ID_ANY, 01509 style = wx.LC_REPORT) 01510 01511 listmix.CheckListCtrlMixin.__init__(self) 01512 01513 self.log = log 01514 01515 # setup mixins 01516 listmix.ListCtrlAutoWidthMixin.__init__(self) 01517 01518 self.LoadData(self.data) 01519 01520 def LoadData(self, data): 01521 """!Load data into list 01522 """ 01523 self.InsertColumn(0, _('Feature id')) 01524 self.InsertColumn(1, _('Layer (Categories)')) 01525 01526 for item in data: 01527 index = self.InsertStringItem(sys.maxint, str(item[0])) 01528 self.SetStringItem(index, 1, str(item[1])) 01529 01530 # enable all items by default 01531 for item in range(self.GetItemCount()): 01532 self.CheckItem(item, True) 01533 01534 self.SetColumnWidth(col = 0, width = wx.LIST_AUTOSIZE_USEHEADER) 01535 self.SetColumnWidth(col = 1, width = wx.LIST_AUTOSIZE_USEHEADER) 01536 01537 def OnCheckItem(self, index, flag): 01538 """!Mapset checked/unchecked 01539 """ 01540 pass