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