2 @package vdigit.dialogs
4 @brief wxGUI vector digitizer dialogs
7 - dialogs::VDigitCategoryDialog
8 - dialogs::CategoryListCtrl
9 - dialogs::VDigitZBulkDialog
10 - dialogs::VDigitDuplicatesDialog
11 - dialogs::CheckListFeature
13 (C) 2007-2011 by the GRASS Development Team
15 This program is free software under the GNU General Public License
16 (>=v2). Read the file COPYING that comes with GRASS for details.
18 @author Martin Landa <landa.martin gmail.com>
25 import wx.lib.mixins.listctrl
as listmix
33 vectorName, query =
None, cats =
None,
34 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
35 """!Dialog used to display/modify categories of vector objects
38 @param title dialog title
39 @param query {coordinates, qdist} - used by v.edit/v.what
40 @param cats directory of lines (layer/categories) - used by vdigit
41 @param style dialog style
55 Debug.msg(3,
"VDigitCategoryDialog(): nothing found!")
58 for line
in cats.keys():
59 for layer
in cats[line].keys():
60 self.
cats[line][layer] =
list(cats[line][layer])
63 for layer
in self.digit.GetLayers():
64 layers.append(str(layer))
69 wx.Dialog.__init__(self, parent = self.
parent, id = wx.ID_ANY, title = title,
70 style = style, **kwargs)
73 box = wx.StaticBox(parent = self, id = wx.ID_ANY,
74 label =
" %s " % _(
"List of categories - right-click to delete"))
75 listSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
77 style = wx.LC_REPORT |
79 wx.LC_SORT_ASCENDING |
83 self.
fid = self.cats.keys()[0]
85 listmix.ColumnSorterMixin.__init__(self, 2)
86 self.
fidMulti = wx.Choice(parent = self, id = wx.ID_ANY,
88 self.fidMulti.Bind(wx.EVT_CHOICE, self.
OnFeature)
89 self.
fidText = wx.StaticText(parent = self, id = wx.ID_ANY)
90 if len(self.cats.keys()) == 1:
91 self.fidMulti.Show(
False)
92 self.fidText.SetLabel(str(self.
fid))
94 self.fidText.Show(
False)
96 for fid
in self.cats.keys():
97 choices.append(str(fid))
98 self.fidMulti.SetItems(choices)
99 self.fidMulti.SetSelection(0)
101 listSizer.Add(item = self.
list, proportion = 1, flag = wx.EXPAND)
104 box = wx.StaticBox(parent = self, id = wx.ID_ANY,
105 label =
" %s " % _(
"Add new category"))
106 addSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
107 flexSizer = wx.FlexGridSizer (cols = 5, hgap = 5, vgap = 5)
108 flexSizer.AddGrowableCol(3)
110 layerNewTxt = wx.StaticText(parent = self, id = wx.ID_ANY,
111 label =
"%s:" % _(
"Layer"))
112 self.
layerNew = wx.Choice(parent = self, id = wx.ID_ANY, size = (75, -1),
115 self.layerNew.SetSelection(0)
117 catNewTxt = wx.StaticText(parent = self, id = wx.ID_ANY,
118 label =
"%s:" % _(
"Category"))
124 self.
catNew = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (75, -1),
125 initial = newCat, min = 0, max = 1e9)
126 btnAddCat = wx.Button(self, wx.ID_ADD)
127 flexSizer.Add(item = layerNewTxt, proportion = 0,
128 flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
129 flexSizer.Add(item = self.
layerNew, proportion = 0,
130 flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
131 flexSizer.Add(item = catNewTxt, proportion = 0,
132 flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT,
134 flexSizer.Add(item = self.
catNew, proportion = 0,
135 flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
136 flexSizer.Add(item = btnAddCat, proportion = 0,
137 flag = wx.EXPAND | wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
138 addSizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
141 btnApply = wx.Button(self, wx.ID_APPLY)
142 btnApply.SetToolTipString(_(
"Apply changes"))
143 btnCancel = wx.Button(self, wx.ID_CANCEL)
144 btnCancel.SetToolTipString(_(
"Ignore changes and close dialog"))
145 btnOk = wx.Button(self, wx.ID_OK)
146 btnOk.SetToolTipString(_(
"Apply changes and close dialog"))
150 btnSizer = wx.StdDialogButtonSizer()
151 btnSizer.AddButton(btnCancel)
154 btnSizer.AddButton(btnApply)
155 btnSizer.AddButton(btnOk)
158 mainSizer = wx.BoxSizer(wx.VERTICAL)
159 mainSizer.Add(item = listSizer, proportion = 1,
160 flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
161 mainSizer.Add(item = addSizer, proportion = 0,
162 flag = wx.EXPAND | wx.ALIGN_CENTER |
163 wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
164 fidSizer = wx.BoxSizer(wx.HORIZONTAL)
165 fidSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
166 label = _(
"Feature id:")),
167 proportion = 0, border = 5,
168 flag = wx.ALIGN_CENTER_VERTICAL)
169 fidSizer.Add(item = self.
fidMulti, proportion = 0,
170 flag = wx.EXPAND | wx.ALL, border = 5)
171 fidSizer.Add(item = self.
fidText, proportion = 0,
172 flag = wx.EXPAND | wx.ALL, border = 5)
173 mainSizer.Add(item = fidSizer, proportion = 0,
174 flag = wx.EXPAND | wx.ALL, border = 5)
175 mainSizer.Add(item = btnSizer, proportion = 0,
176 flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
178 self.SetSizer(mainSizer)
180 self.SetAutoLayout(
True)
183 self.SetMinSize(self.GetBestSize())
186 btnApply.Bind(wx.EVT_BUTTON, self.
OnApply)
187 btnOk.Bind(wx.EVT_BUTTON, self.
OnOK)
188 btnAddCat.Bind(wx.EVT_BUTTON, self.
OnAddCat)
189 btnCancel.Bind(wx.EVT_BUTTON, self.
OnCancel)
192 self.list.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.
OnRightUp)
193 self.list.Bind(wx.EVT_RIGHT_UP, self.
OnRightUp)
195 self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.
OnEndEdit, self.
list)
199 """!Used by ColumnSorterMixin
204 """!Click on column header (order by)
209 """!Editing of item started
214 """!Finish editing of item
216 itemIndex = event.GetIndex()
217 layerOld = int (self.list.GetItem(itemIndex, 0).GetText())
218 catOld = int (self.list.GetItem(itemIndex, 1).GetText())
220 if event.GetColumn() == 0:
221 layerNew = int(event.GetLabel())
225 catNew = int(event.GetLabel())
228 if layerNew
not in self.
cats[self.
fid].keys():
229 self.
cats[self.
fid][layerNew] = []
230 self.
cats[self.
fid][layerNew].append(catNew)
231 self.
cats[self.
fid][layerOld].remove(catOld)
234 self.list.SetStringItem(itemIndex, 0, str(layerNew))
235 self.list.SetStringItem(itemIndex, 1, str(catNew))
236 dlg = wx.MessageDialog(self, _(
"Unable to add new layer/category <%(layer)s/%(category)s>.\n"
237 "Layer and category number must be integer.\n"
238 "Layer number must be greater than zero.") %
239 {
'layer': self.layerNew.GetStringSelection(),
240 'category' : str(self.catNew.GetValue()) },
241 _(
"Error"), wx.OK | wx.ICON_ERROR)
247 """!Mouse right button down
251 item, flags = self.list.HitTest((x, y))
253 if item != wx.NOT_FOUND
and \
254 flags & wx.LIST_HITTEST_ONITEM:
255 self.list.Select(item)
260 """!Mouse right button up
262 if not hasattr(self,
"popupID1"):
272 menu.Append(self.
popupID1, _(
"Delete selected"))
273 if self.list.GetFirstSelected() == -1:
276 menu.Append(self.
popupID2, _(
"Delete all"))
277 menu.AppendSeparator()
278 menu.Append(self.
popupID3, _(
"Reload"))
289 """!Delete selected item(s) from the list (layer/category pair)
291 item = self.list.GetFirstSelected()
293 layer = int (self.list.GetItem(item, 0).GetText())
294 cat = int (self.list.GetItem(item, 1).GetText())
295 self.list.DeleteItem(item)
296 self.
cats[self.
fid][layer].remove(cat)
298 item = self.list.GetFirstSelected()
303 """!Delete all items from the list
305 self.list.DeleteAllItems()
311 """!Feature id changed (on duplicates)
313 self.
fid = int(event.GetString())
323 self.catNew.SetValue(newCat)
327 def _getCategories(self, coords, qdist):
328 """!Get layer/category pairs for all available
331 Return True line found or False if not found
337 east_north =
'%f,%f' % \
338 (float(coords[0]), float(coords[1])),
344 for item
in ret.splitlines():
347 self.
line = int(item.split(
':')[1].strip())
348 elif "layer:" in litem:
349 layer = int(item.split(
':')[1].strip())
350 if layer
not in self.cats.keys():
351 self.
cats[layer] = []
352 elif "category:" in litem:
353 self.
cats[layer].append(int(item.split(
':')[1].strip()))
358 """!Reload button pressed
370 """!Cancel button pressed
372 self.parent.parent.dialogs[
'category'] =
None
374 self.digit.GetDisplay().SetSelected([])
375 self.parent.UpdateMap(render =
False)
377 self.parent.parent.OnRender(
None)
382 """!Apply button pressed
384 for fid
in self.cats.keys():
386 if fid == self.
fid and newfid > 0:
392 @param fid feature id
394 cats = self.
cats[fid]
398 check = {
'catadd': (cats, cats_orig),
399 'catdel': (cats_orig, cats)}
404 for action, catsCurr
in check.iteritems():
405 for layer
in catsCurr[0].keys():
407 for cat
in catsCurr[0][layer]:
408 if layer
not in catsCurr[1].keys()
or \
409 cat
not in catsCurr[1][layer]:
412 if action ==
'catadd':
417 newfid = self.digit.SetLineCats(fid, layer,
419 if len(self.cats.keys()) == 1:
420 self.fidText.SetLabel(
"%d" % newfid)
422 choices = self.fidMulti.GetItems()
423 choices[choices.index(str(fid))] = str(newfid)
424 self.fidMulti.SetItems(choices)
425 self.fidMulti.SetStringSelection(str(newfid))
432 wx.MessageBox(parent = self, message = _(
"Unable to update vector map."),
433 caption = _(
"Error"), style = wx.OK | wx.ICON_ERROR)
435 self.
cats_orig[fid] = copy.deepcopy(cats)
440 """!OK button pressed
446 """!Button 'Add' new category pressed
449 layer = int(self.layerNew.GetStringSelection())
450 cat = int(self.catNew.GetValue())
454 GError(parent = self,
455 message = _(
"Unable to add new layer/category <%(layer)s/%(category)s>.\n"
456 "Layer and category number must be integer.\n"
457 "Layer number must be greater than zero.") %
458 {
'layer' : str(self.layerNew.GetValue()),
459 'category' : str(self.catNew.GetValue())})
462 if layer
not in self.
cats[self.
fid].keys():
463 self.
cats[self.
fid][layer] = []
465 self.
cats[self.
fid][layer].append(cat)
472 self.catNew.SetValue(cat + 1)
479 """!Get id of selected line of 'None' if no line is selected
481 return self.cats.keys()
486 @param query {coordinates, distance} - v.what
487 @param cats directory layer/cats - vdigit
488 Return True if updated otherwise False
497 for line
in cats.keys():
498 for layer
in cats[line].keys():
499 self.
cats[line][layer] =
list(cats[line][layer])
501 if ret == 0
or len(self.cats.keys()) < 1:
502 Debug.msg(3,
"VDigitCategoryDialog(): nothing found!")
509 self.
fid = self.cats.keys()[0]
517 self.catNew.SetValue(newCat)
519 if len(self.cats.keys()) == 1:
520 self.fidText.Show(
True)
521 self.fidMulti.Show(
False)
522 self.fidText.SetLabel(
"%d" % self.
fid)
524 self.fidText.Show(
False)
525 self.fidMulti.Show(
True)
527 for fid
in self.cats.keys():
528 choices.append(str(fid))
529 self.fidMulti.SetItems(choices)
530 self.fidMulti.SetSelection(0)
537 listmix.ListCtrlAutoWidthMixin,
538 listmix.TextEditMixin):
539 def __init__(self, parent, id, pos = wx.DefaultPosition,
540 size = wx.DefaultSize, style = 0):
541 """!List of layers/categories"""
544 wx.ListCtrl.__init__(self, parent, id, pos, size, style)
546 listmix.ListCtrlAutoWidthMixin.__init__(self)
547 listmix.TextEditMixin.__init__(self)
550 """!Populate the list
555 self.InsertColumn(0, _(
"Layer"))
556 self.InsertColumn(1, _(
"Category"))
558 self.DeleteAllItems()
561 for layer
in cats.keys():
562 catsList = cats[layer]
564 index = self.InsertStringItem(sys.maxint, str(catsList[0]))
565 self.SetStringItem(index, 0, str(layer))
566 self.SetStringItem(index, 1, str(cat))
567 self.SetItemData(index, i)
568 itemData[i] = (str(layer), str(cat))
572 self.SetColumnWidth(0, 100)
573 self.SetColumnWidth(1, wx.LIST_AUTOSIZE)
580 def __init__(self, parent, title, nselected, style = wx.DEFAULT_DIALOG_STYLE):
581 """!Dialog used for Z bulk-labeling tool
583 wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style)
589 border = wx.BoxSizer(wx.VERTICAL)
591 txt = wx.StaticText(parent = self,
592 label = _(
"%d lines selected for z bulk-labeling") % nselected);
593 border.Add(item = txt, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
595 box = wx.StaticBox (parent = self, id = wx.ID_ANY, label =
" %s " % _(
"Set value"))
596 sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
597 flexSizer = wx.FlexGridSizer (cols = 2, hgap = 5, vgap = 5)
598 flexSizer.AddGrowableCol(0)
601 txt = wx.StaticText(parent = self,
602 label = _(
"Starting value"));
603 self.
value = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (150, -1),
605 min = -1e6, max = 1e6)
606 flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
607 flexSizer.Add(self.
value, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
610 txt = wx.StaticText(parent = self,
612 self.
step = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (150, -1),
615 flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
616 flexSizer.Add(self.
step, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
618 sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
619 border.Add(item = sizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 0)
622 btnCancel = wx.Button(self, wx.ID_CANCEL)
623 btnOk = wx.Button(self, wx.ID_OK)
627 btnSizer = wx.StdDialogButtonSizer()
628 btnSizer.AddButton(btnCancel)
629 btnSizer.AddButton(btnOk)
632 mainSizer = wx.BoxSizer(wx.VERTICAL)
633 mainSizer.Add(item = border, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
634 mainSizer.Add(item = btnSizer, proportion = 0,
635 flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
637 self.SetSizer(mainSizer)
641 def __init__(self, parent, data, title = _(
"List of duplicates"),
642 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
643 pos = wx.DefaultPosition):
644 """!Show duplicated feature ids
646 wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style,
656 self.
notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
659 for key
in self.data.keys():
660 panel = wx.Panel(parent = self.
notebook, id = wx.ID_ANY)
661 self.notebook.AddPage(page = panel, text =
" %d " % (id))
664 border = wx.BoxSizer(wx.VERTICAL)
667 self.winList.append(win.GetId())
669 border.Add(item = win, proportion = 1,
670 flag = wx.ALL | wx.EXPAND, border = 5)
672 panel.SetSizer(border)
677 btnCancel = wx.Button(self, wx.ID_CANCEL)
678 btnOk = wx.Button(self, wx.ID_OK)
682 btnSizer = wx.StdDialogButtonSizer()
683 btnSizer.AddButton(btnCancel)
684 btnSizer.AddButton(btnOk)
687 mainSizer = wx.BoxSizer(wx.VERTICAL)
688 mainSizer.Add(item = self.
notebook, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
689 mainSizer.Add(item = btnSizer, proportion = 0,
690 flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
692 self.SetSizer(mainSizer)
694 self.SetAutoLayout(
True)
697 self.SetMinSize((250, 180))
700 """!Get unselected items (feature id)
706 wlist = self.FindWindowById(id)
708 for item
in range(wlist.GetItemCount()):
709 if not wlist.IsChecked(item):
710 ids.append(int(wlist.GetItem(item, 0).GetText()))
714 class CheckListFeature(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.CheckListCtrlMixin):
716 pos = wx.DefaultPosition, log =
None):
717 """!List of mapset/owner/group
722 wx.ListCtrl.__init__(self, parent, wx.ID_ANY,
723 style = wx.LC_REPORT)
725 listmix.CheckListCtrlMixin.__init__(self)
730 listmix.ListCtrlAutoWidthMixin.__init__(self)
735 """!Load data into list
737 self.InsertColumn(0, _(
'Feature id'))
738 self.InsertColumn(1, _(
'Layer (Categories)'))
741 index = self.InsertStringItem(sys.maxint, str(item[0]))
742 self.SetStringItem(index, 1, str(item[1]))
745 for item
in range(self.GetItemCount()):
746 self.CheckItem(item,
True)
748 self.SetColumnWidth(col = 0, width = wx.LIST_AUTOSIZE_USEHEADER)
749 self.SetColumnWidth(col = 1, width = wx.LIST_AUTOSIZE_USEHEADER)
752 """!Mapset checked/unchecked
def OnItemSelected
Item selected.
def GetLine
Get id of selected line of 'None' if no line is selected.
def __init__
List of layers/categories.
def OnApply
Apply button pressed.
def UpdateDialog
Update dialog.
def OnCancel
Cancel button pressed.
def OnReload
Reload button pressed.
def OnItemDeleteAll
Delete all items from the list.
def GetUnSelected
Get unselected items (feature id)
def OnBeginEdit
Editing of item started.
def OnColClick
Click on column header (order by)
def LoadData
Load data into list.
def OnRightUp
Mouse right button up.
def __init__
Dialog used to display/modify categories of vector objects.
def Populate
Populate the list.
def __init__
Dialog used for Z bulk-labeling tool.
def __init__
Show duplicated feature ids.
def _getCategories
Get layer/category pairs for all available layers.
def GetListCtrl
Used by ColumnSorterMixin.
def ApplyChanges
Apply changes.
def __init__
List of mapset/owner/group.
def OnFeature
Feature id changed (on duplicates)
def OnItemDelete
Delete selected item(s) from the list (layer/category pair)
def OnEndEdit
Finish editing of item.
def OnRightDown
Mouse right button down.
def OnAddCat
Button 'Add' new category pressed.
def OnOK
OK button pressed.
def OnCheckItem
Mapset checked/unchecked.
def RunCommand
Run GRASS command.