示例#1
0
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  # map window 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 = 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)
        self.Bind(wx.EVT_CLOSE, lambda evt: self.Hide())

        # 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 than 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 = 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:
            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 than 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
示例#2
0
class VDigitSettingsDialog(wx.Dialog):
    def __init__(self,
                 parent,
                 giface,
                 title=_("Digitization settings"),
                 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._giface = giface
        self.parent = parent  # MapFrame
        self.digit = self.parent.MapWindow.digit

        # notebook
        notebook = wx.Notebook(parent=self, id=wx.ID_ANY, style=wx.BK_DEFAULT)
        self._createGeneralPage(notebook)
        self._createSymbologyPage(notebook)
        self.digit.SetCategory()
        self._createAttributesPage(notebook)
        self._createQueryPage(notebook)

        # buttons
        btnApply = wx.Button(self, wx.ID_APPLY)
        btnCancel = wx.Button(self, wx.ID_CLOSE)
        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.wx.BoxSizer(wx.HORIZONTAL)
        btnSizer.Add(btnCancel,
                     proportion=0,
                     flag=wx.ALIGN_RIGHT | wx.ALL,
                     border=5)
        btnSizer.Add(btnApply,
                     proportion=0,
                     flag=wx.ALIGN_RIGHT | wx.ALL,
                     border=5)
        btnSizer.Add(btnSave,
                     proportion=0,
                     flag=wx.ALIGN_RIGHT | wx.ALL,
                     border=5)

        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.ALIGN_RIGHT,
                      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=(40, 25))
            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 = 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 = 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")])
        try:
            self.snappingUnit.SetSelection(
                UserSettings.Get(group='vdigit', key="snapping",
                                 subkey='unit'))
        except:
            self.snappingUnit.SetSelection(0)
        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 = 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 lines/boundaries"))
        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)

        #
        # digitize areas box
        #
        box = wx.StaticBox(parent=panel,
                           id=wx.ID_ANY,
                           label=" %s " % _("Digitize areas"))
        sizer = wx.StaticBoxSizer(box, wx.VERTICAL)

        self.closeBoundary = wx.CheckBox(
            parent=panel, label=_("Close boundary (snap to the start node)"))
        self.closeBoundary.SetValue(
            UserSettings.Get(group='vdigit',
                             key='closeBoundary',
                             subkey='enabled'))

        sizer.Add(item=self.closeBoundary,
                  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 = 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 = 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 = 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 = 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)
        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
        if tree:
            item = tree.FindItemByData('maplayer', mapLayer)
        else:
            item = None
        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 = 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.GetLayerInfo(item, key='vdigit') and \
                    'geomAttr' in tree.GetLayerInfo(item, key='vdigit') and \
                    attrb in tree.GetLayerInfo(item, key='vdigit')['geomAttr']:
                check.SetValue(True)
                column.SetStringSelection(
                    tree.GetLayerInfo(
                        item, key='vdigit')['geomAttr'][attrb]['column'])
                if attrb == 'area':
                    type = 'area'
                else:
                    type = 'length'
                unitsIdx = Units.GetUnitsIndex(
                    type,
                    tree.GetLayerInfo(
                        item, key='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))

        gridSizer.AddGrowableCol(0)
        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 (
            (_("Digitize new line segment"), "newSegment"),
            (_("Digitize new line/boundary"), "newLine"),
            (_("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.GetSelection() == 1:  # 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.GetSelection()
        threshold = self.digit.GetDisplay().GetThreshold(value=value,
                                                         units=units)

        if units == 1:  # 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')

        sfile = UserSettings.SaveToFile(fileSettings)
        self._giface.WriteLog(
            _('Vector digitizer settings saved to file <%s>.') % sfile)

        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

        .. todo::
            Needs refactoring
        """
        # TODO: it seems that it needs to be replaced by signal
        # but if it makes sense generally for wxGUI it can be added to giface
        if self.parent.GetLayerManager():
            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='unit',
                         value=self.snappingUnit.GetSelection())
        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._giface.GetLayerTree()
        if tree:
            item = tree.FindItemByData('maplayer', mapLayer)
        else:
            item = None
        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.GetLayerInfo(item, key='vdigit'):
                tree.SetLayerInfo(item,
                                  key='vdigit',
                                  value={'geomAttr': dict()})

            if checked:  # enable
                if key == 'area':
                    type = key
                else:
                    type = 'length'
                unitsKey = Units.GetUnitsKey(type, unitsIdx)
                tree.GetLayerInfo(item, key='vdigit')['geomAttr'][key] = {
                    'column': column,
                    'units': unitsKey
                }
            else:
                if item and tree.GetLayerInfo(
                        item, key='vdigit') and key in tree.GetLayerInfo(
                            item, key='vdigit')['geomAttr']:
                    del tree.GetLayerInfo(item, key='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())

        # close boundary
        UserSettings.Set(group='vdigit',
                         key="closeBoundary",
                         subkey='enabled',
                         value=self.closeBoundary.IsChecked())

        self.digit.UpdateSettings()

        # redraw map if auto-rendering is enabled
        if self.parent.IsAutoRendered():
            self.parent.OnRender(None)