dialogs.py 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754
  1. """!
  2. @package vdigit.dialogs
  3. @brief wxGUI vector digitizer dialogs
  4. Classes:
  5. - VDigitCategoryDialog
  6. - CategoryListCtrl
  7. - VDigitZBulkDialog
  8. - VDigitDuplicatesDialog
  9. - CheckListFeature
  10. (C) 2007-2011 by the GRASS Development Team
  11. This program is free software under the GNU General Public License
  12. (>=v2). Read the file COPYING that comes with GRASS for details.
  13. @author Martin Landa <landa.martin gmail.com>
  14. """
  15. import sys
  16. import copy
  17. import wx
  18. import wx.lib.mixins.listctrl as listmix
  19. from core.gcmd import RunCommand, GError
  20. from core.debug import Debug
  21. from core.settings import UserSettings
  22. class VDigitCategoryDialog(wx.Dialog, listmix.ColumnSorterMixin):
  23. def __init__(self, parent, title,
  24. vectorName, query = None, cats = None,
  25. style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
  26. """!Dialog used to display/modify categories of vector objects
  27. @param parent
  28. @param title dialog title
  29. @param query {coordinates, qdist} - used by v.edit/v.what
  30. @param cats directory of lines (layer/categories) - used by vdigit
  31. @param style dialog style
  32. """
  33. self.parent = parent # mapdisplay.BufferedWindow class instance
  34. self.digit = parent.digit
  35. # map name
  36. self.vectorName = vectorName
  37. # line : {layer: [categories]}
  38. self.cats = {}
  39. # do not display dialog if no line is found (-> self.cats)
  40. if cats is None:
  41. if self._getCategories(query[0], query[1]) == 0 or not self.line:
  42. Debug.msg(3, "VDigitCategoryDialog(): nothing found!")
  43. else:
  44. self.cats = cats
  45. for line in cats.keys():
  46. for layer in cats[line].keys():
  47. self.cats[line][layer] = list(cats[line][layer])
  48. layers = []
  49. for layer in self.digit.GetLayers():
  50. layers.append(str(layer))
  51. # make copy of cats (used for 'reload')
  52. self.cats_orig = copy.deepcopy(self.cats)
  53. wx.Dialog.__init__(self, parent = self.parent, id = wx.ID_ANY, title = title,
  54. style = style, **kwargs)
  55. # list of categories
  56. box = wx.StaticBox(parent = self, id = wx.ID_ANY,
  57. label = " %s " % _("List of categories - right-click to delete"))
  58. listSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  59. self.list = CategoryListCtrl(parent = self, id = wx.ID_ANY,
  60. style = wx.LC_REPORT |
  61. wx.BORDER_NONE |
  62. wx.LC_SORT_ASCENDING |
  63. wx.LC_HRULES |
  64. wx.LC_VRULES)
  65. # sorter
  66. self.fid = self.cats.keys()[0]
  67. self.itemDataMap = self.list.Populate(self.cats[self.fid])
  68. listmix.ColumnSorterMixin.__init__(self, 2)
  69. self.fidMulti = wx.Choice(parent = self, id = wx.ID_ANY,
  70. size = (150, -1))
  71. self.fidMulti.Bind(wx.EVT_CHOICE, self.OnFeature)
  72. self.fidText = wx.StaticText(parent = self, id = wx.ID_ANY)
  73. if len(self.cats.keys()) == 1:
  74. self.fidMulti.Show(False)
  75. self.fidText.SetLabel(str(self.fid))
  76. else:
  77. self.fidText.Show(False)
  78. choices = []
  79. for fid in self.cats.keys():
  80. choices.append(str(fid))
  81. self.fidMulti.SetItems(choices)
  82. self.fidMulti.SetSelection(0)
  83. listSizer.Add(item = self.list, proportion = 1, flag = wx.EXPAND)
  84. # add new category
  85. box = wx.StaticBox(parent = self, id = wx.ID_ANY,
  86. label = " %s " % _("Add new category"))
  87. addSizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  88. flexSizer = wx.FlexGridSizer (cols = 5, hgap = 5, vgap = 5)
  89. flexSizer.AddGrowableCol(3)
  90. layerNewTxt = wx.StaticText(parent = self, id = wx.ID_ANY,
  91. label = "%s:" % _("Layer"))
  92. self.layerNew = wx.Choice(parent = self, id = wx.ID_ANY, size = (75, -1),
  93. choices = layers)
  94. if len(layers) > 0:
  95. self.layerNew.SetSelection(0)
  96. catNewTxt = wx.StaticText(parent = self, id = wx.ID_ANY,
  97. label = "%s:" % _("Category"))
  98. try:
  99. newCat = max(self.cats[self.fid][1]) + 1
  100. except KeyError:
  101. newCat = 1
  102. self.catNew = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (75, -1),
  103. initial = newCat, min = 0, max = 1e9)
  104. btnAddCat = wx.Button(self, wx.ID_ADD)
  105. flexSizer.Add(item = layerNewTxt, proportion = 0,
  106. flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
  107. flexSizer.Add(item = self.layerNew, proportion = 0,
  108. flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
  109. flexSizer.Add(item = catNewTxt, proportion = 0,
  110. flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_RIGHT | wx.LEFT,
  111. border = 10)
  112. flexSizer.Add(item = self.catNew, proportion = 0,
  113. flag = wx.FIXED_MINSIZE | wx.ALIGN_CENTER_VERTICAL)
  114. flexSizer.Add(item = btnAddCat, proportion = 0,
  115. flag = wx.EXPAND | wx.ALIGN_RIGHT | wx.FIXED_MINSIZE)
  116. addSizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 5)
  117. # buttons
  118. btnApply = wx.Button(self, wx.ID_APPLY)
  119. btnApply.SetToolTipString(_("Apply changes"))
  120. btnCancel = wx.Button(self, wx.ID_CANCEL)
  121. btnCancel.SetToolTipString(_("Ignore changes and close dialog"))
  122. btnOk = wx.Button(self, wx.ID_OK)
  123. btnOk.SetToolTipString(_("Apply changes and close dialog"))
  124. btnOk.SetDefault()
  125. # sizers
  126. btnSizer = wx.StdDialogButtonSizer()
  127. btnSizer.AddButton(btnCancel)
  128. #btnSizer.AddButton(btnReload)
  129. #btnSizer.SetNegativeButton(btnReload)
  130. btnSizer.AddButton(btnApply)
  131. btnSizer.AddButton(btnOk)
  132. btnSizer.Realize()
  133. mainSizer = wx.BoxSizer(wx.VERTICAL)
  134. mainSizer.Add(item = listSizer, proportion = 1,
  135. flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
  136. mainSizer.Add(item = addSizer, proportion = 0,
  137. flag = wx.EXPAND | wx.ALIGN_CENTER |
  138. wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
  139. fidSizer = wx.BoxSizer(wx.HORIZONTAL)
  140. fidSizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
  141. label = _("Feature id:")),
  142. proportion = 0, border = 5,
  143. flag = wx.ALIGN_CENTER_VERTICAL)
  144. fidSizer.Add(item = self.fidMulti, proportion = 0,
  145. flag = wx.EXPAND | wx.ALL, border = 5)
  146. fidSizer.Add(item = self.fidText, proportion = 0,
  147. flag = wx.EXPAND | wx.ALL, border = 5)
  148. mainSizer.Add(item = fidSizer, proportion = 0,
  149. flag = wx.EXPAND | wx.ALL, border = 5)
  150. mainSizer.Add(item = btnSizer, proportion = 0,
  151. flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
  152. self.SetSizer(mainSizer)
  153. mainSizer.Fit(self)
  154. self.SetAutoLayout(True)
  155. # set min size for dialog
  156. self.SetMinSize(self.GetBestSize())
  157. # bindings
  158. btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  159. btnOk.Bind(wx.EVT_BUTTON, self.OnOK)
  160. btnAddCat.Bind(wx.EVT_BUTTON, self.OnAddCat)
  161. btnCancel.Bind(wx.EVT_BUTTON, self.OnCancel)
  162. # list
  163. self.list.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnRightUp) #wxMSW
  164. self.list.Bind(wx.EVT_RIGHT_UP, self.OnRightUp) #wxGTK
  165. self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnBeginEdit, self.list)
  166. self.Bind(wx.EVT_LIST_END_LABEL_EDIT, self.OnEndEdit, self.list)
  167. self.Bind(wx.EVT_LIST_COL_CLICK, self.OnColClick, self.list)
  168. def GetListCtrl(self):
  169. """!Used by ColumnSorterMixin
  170. """
  171. return self.list
  172. def OnColClick(self, event):
  173. """!Click on column header (order by)
  174. """
  175. event.Skip()
  176. def OnBeginEdit(self, event):
  177. """!Editing of item started
  178. """
  179. event.Allow()
  180. def OnEndEdit(self, event):
  181. """!Finish editing of item
  182. """
  183. itemIndex = event.GetIndex()
  184. layerOld = int (self.list.GetItem(itemIndex, 0).GetText())
  185. catOld = int (self.list.GetItem(itemIndex, 1).GetText())
  186. if event.GetColumn() == 0:
  187. layerNew = int(event.GetLabel())
  188. catNew = catOld
  189. else:
  190. layerNew = layerOld
  191. catNew = int(event.GetLabel())
  192. try:
  193. if layerNew not in self.cats[self.fid].keys():
  194. self.cats[self.fid][layerNew] = []
  195. self.cats[self.fid][layerNew].append(catNew)
  196. self.cats[self.fid][layerOld].remove(catOld)
  197. except:
  198. event.Veto()
  199. self.list.SetStringItem(itemIndex, 0, str(layerNew))
  200. self.list.SetStringItem(itemIndex, 1, str(catNew))
  201. dlg = wx.MessageDialog(self, _("Unable to add new layer/category <%(layer)s/%(category)s>.\n"
  202. "Layer and category number must be integer.\n"
  203. "Layer number must be greater then zero.") %
  204. { 'layer': self.layerNew.GetStringSelection(),
  205. 'category' : str(self.catNew.GetValue()) },
  206. _("Error"), wx.OK | wx.ICON_ERROR)
  207. dlg.ShowModal()
  208. dlg.Destroy()
  209. return False
  210. def OnRightDown(self, event):
  211. """!Mouse right button down
  212. """
  213. x = event.GetX()
  214. y = event.GetY()
  215. item, flags = self.list.HitTest((x, y))
  216. if item != wx.NOT_FOUND and \
  217. flags & wx.LIST_HITTEST_ONITEM:
  218. self.list.Select(item)
  219. event.Skip()
  220. def OnRightUp(self, event):
  221. """!Mouse right button up
  222. """
  223. if not hasattr(self, "popupID1"):
  224. self.popupID1 = wx.NewId()
  225. self.popupID2 = wx.NewId()
  226. self.popupID3 = wx.NewId()
  227. self.Bind(wx.EVT_MENU, self.OnItemDelete, id = self.popupID1)
  228. self.Bind(wx.EVT_MENU, self.OnItemDeleteAll, id = self.popupID2)
  229. self.Bind(wx.EVT_MENU, self.OnReload, id = self.popupID3)
  230. # generate popup-menu
  231. menu = wx.Menu()
  232. menu.Append(self.popupID1, _("Delete selected"))
  233. if self.list.GetFirstSelected() == -1:
  234. menu.Enable(self.popupID1, False)
  235. menu.Append(self.popupID2, _("Delete all"))
  236. menu.AppendSeparator()
  237. menu.Append(self.popupID3, _("Reload"))
  238. self.PopupMenu(menu)
  239. menu.Destroy()
  240. def OnItemSelected(self, event):
  241. """!Item selected
  242. """
  243. event.Skip()
  244. def OnItemDelete(self, event):
  245. """!Delete selected item(s) from the list (layer/category pair)
  246. """
  247. item = self.list.GetFirstSelected()
  248. while item != -1:
  249. layer = int (self.list.GetItem(item, 0).GetText())
  250. cat = int (self.list.GetItem(item, 1).GetText())
  251. self.list.DeleteItem(item)
  252. self.cats[self.fid][layer].remove(cat)
  253. item = self.list.GetFirstSelected()
  254. event.Skip()
  255. def OnItemDeleteAll(self, event):
  256. """!Delete all items from the list
  257. """
  258. self.list.DeleteAllItems()
  259. self.cats[self.fid] = {}
  260. event.Skip()
  261. def OnFeature(self, event):
  262. """!Feature id changed (on duplicates)
  263. """
  264. self.fid = int(event.GetString())
  265. self.itemDataMap = self.list.Populate(self.cats[self.fid],
  266. update = True)
  267. try:
  268. newCat = max(self.cats[self.fid][1]) + 1
  269. except KeyError:
  270. newCat = 1
  271. self.catNew.SetValue(newCat)
  272. event.Skip()
  273. def _getCategories(self, coords, qdist):
  274. """!Get layer/category pairs for all available
  275. layers
  276. Return True line found or False if not found
  277. """
  278. ret = RunCommand('v.what',
  279. parent = self,
  280. quiet = True,
  281. map = self.vectorName,
  282. east_north = '%f,%f' % \
  283. (float(coords[0]), float(coords[1])),
  284. distance = qdist)
  285. if not ret:
  286. return False
  287. for item in ret.splitlines():
  288. litem = item.lower()
  289. if "id:" in litem: # get line id
  290. self.line = int(item.split(':')[1].strip())
  291. elif "layer:" in litem: # add layer
  292. layer = int(item.split(':')[1].strip())
  293. if layer not in self.cats.keys():
  294. self.cats[layer] = []
  295. elif "category:" in litem: # add category
  296. self.cats[layer].append(int(item.split(':')[1].strip()))
  297. return True
  298. def OnReload(self, event):
  299. """!Reload button pressed
  300. """
  301. # restore original list
  302. self.cats = copy.deepcopy(self.cats_orig)
  303. # polulate list
  304. self.itemDataMap = self.list.Populate(self.cats[self.fid],
  305. update = True)
  306. event.Skip()
  307. def OnCancel(self, event):
  308. """!Cancel button pressed
  309. """
  310. self.parent.parent.dialogs['category'] = None
  311. if self.digit:
  312. self.digit.GetDisplay().SetSelected([])
  313. self.parent.UpdateMap(render = False)
  314. else:
  315. self.parent.parent.OnRender(None)
  316. self.Close()
  317. def OnApply(self, event):
  318. """!Apply button pressed
  319. """
  320. for fid in self.cats.keys():
  321. newfid = self.ApplyChanges(fid)
  322. if fid == self.fid and newfid > 0:
  323. self.fid = newfid
  324. def ApplyChanges(self, fid):
  325. """!Apply changes
  326. @param fid feature id
  327. """
  328. cats = self.cats[fid]
  329. cats_orig = self.cats_orig[fid]
  330. # action : (catsFrom, catsTo)
  331. check = {'catadd': (cats, cats_orig),
  332. 'catdel': (cats_orig, cats)}
  333. newfid = -1
  334. # add/delete new category
  335. for action, catsCurr in check.iteritems():
  336. for layer in catsCurr[0].keys():
  337. catList = []
  338. for cat in catsCurr[0][layer]:
  339. if layer not in catsCurr[1].keys() or \
  340. cat not in catsCurr[1][layer]:
  341. catList.append(cat)
  342. if catList != []:
  343. if action == 'catadd':
  344. add = True
  345. else:
  346. add = False
  347. newfid = self.digit.SetLineCats(fid, layer,
  348. catList, add)
  349. if len(self.cats.keys()) == 1:
  350. self.fidText.SetLabel("%d" % newfid)
  351. else:
  352. choices = self.fidMulti.GetItems()
  353. choices[choices.index(str(fid))] = str(newfid)
  354. self.fidMulti.SetItems(choices)
  355. self.fidMulti.SetStringSelection(str(newfid))
  356. self.cats[newfid] = self.cats[fid]
  357. del self.cats[fid]
  358. fid = newfid
  359. if self.fid < 0:
  360. wx.MessageBox(parent = self, message = _("Unable to update vector map."),
  361. caption = _("Error"), style = wx.OK | wx.ICON_ERROR)
  362. self.cats_orig[fid] = copy.deepcopy(cats)
  363. return newfid
  364. def OnOK(self, event):
  365. """!OK button pressed
  366. """
  367. self.OnApply(event)
  368. self.OnCancel(event)
  369. def OnAddCat(self, event):
  370. """!Button 'Add' new category pressed
  371. """
  372. try:
  373. layer = int(self.layerNew.GetStringSelection())
  374. cat = int(self.catNew.GetValue())
  375. if layer <= 0:
  376. raise ValueError
  377. except ValueError:
  378. GError(parent = self,
  379. message = _("Unable to add new layer/category <%(layer)s/%(category)s>.\n"
  380. "Layer and category number must be integer.\n"
  381. "Layer number must be greater then zero.") %
  382. {'layer' : str(self.layerNew.GetValue()),
  383. 'category' : str(self.catNew.GetValue())})
  384. return False
  385. if layer not in self.cats[self.fid].keys():
  386. self.cats[self.fid][layer] = []
  387. self.cats[self.fid][layer].append(cat)
  388. # reload list
  389. self.itemDataMap = self.list.Populate(self.cats[self.fid],
  390. update = True)
  391. # update category number for add
  392. self.catNew.SetValue(cat + 1)
  393. event.Skip()
  394. return True
  395. def GetLine(self):
  396. """!Get id of selected line of 'None' if no line is selected
  397. """
  398. return self.cats.keys()
  399. def UpdateDialog(self, query = None, cats = None):
  400. """!Update dialog
  401. @param query {coordinates, distance} - v.what
  402. @param cats directory layer/cats - vdigit
  403. Return True if updated otherwise False
  404. """
  405. # line: {layer: [categories]}
  406. self.cats = {}
  407. # do not display dialog if no line is found (-> self.cats)
  408. if cats is None:
  409. ret = self._getCategories(query[0], query[1])
  410. else:
  411. self.cats = cats
  412. for line in cats.keys():
  413. for layer in cats[line].keys():
  414. self.cats[line][layer] = list(cats[line][layer])
  415. ret = 1
  416. if ret == 0 or len(self.cats.keys()) < 1:
  417. Debug.msg(3, "VDigitCategoryDialog(): nothing found!")
  418. return False
  419. # make copy of cats (used for 'reload')
  420. self.cats_orig = copy.deepcopy(self.cats)
  421. # polulate list
  422. self.fid = self.cats.keys()[0]
  423. self.itemDataMap = self.list.Populate(self.cats[self.fid],
  424. update = True)
  425. try:
  426. newCat = max(self.cats[self.fid][1]) + 1
  427. except KeyError:
  428. newCat = 1
  429. self.catNew.SetValue(newCat)
  430. if len(self.cats.keys()) == 1:
  431. self.fidText.Show(True)
  432. self.fidMulti.Show(False)
  433. self.fidText.SetLabel("%d" % self.fid)
  434. else:
  435. self.fidText.Show(False)
  436. self.fidMulti.Show(True)
  437. choices = []
  438. for fid in self.cats.keys():
  439. choices.append(str(fid))
  440. self.fidMulti.SetItems(choices)
  441. self.fidMulti.SetSelection(0)
  442. self.Layout()
  443. return True
  444. class CategoryListCtrl(wx.ListCtrl,
  445. listmix.ListCtrlAutoWidthMixin,
  446. listmix.TextEditMixin):
  447. def __init__(self, parent, id, pos = wx.DefaultPosition,
  448. size = wx.DefaultSize, style = 0):
  449. """!List of layers/categories"""
  450. self.parent = parent
  451. wx.ListCtrl.__init__(self, parent, id, pos, size, style)
  452. listmix.ListCtrlAutoWidthMixin.__init__(self)
  453. listmix.TextEditMixin.__init__(self)
  454. def Populate(self, cats, update = False):
  455. """!Populate the list
  456. """
  457. itemData = {} # requested by sorter
  458. if not update:
  459. self.InsertColumn(0, _("Layer"))
  460. self.InsertColumn(1, _("Category"))
  461. else:
  462. self.DeleteAllItems()
  463. i = 1
  464. for layer in cats.keys():
  465. catsList = cats[layer]
  466. for cat in catsList:
  467. index = self.InsertStringItem(sys.maxint, str(catsList[0]))
  468. self.SetStringItem(index, 0, str(layer))
  469. self.SetStringItem(index, 1, str(cat))
  470. self.SetItemData(index, i)
  471. itemData[i] = (str(layer), str(cat))
  472. i = i + 1
  473. if not update:
  474. self.SetColumnWidth(0, 100)
  475. self.SetColumnWidth(1, wx.LIST_AUTOSIZE)
  476. self.currentItem = 0
  477. return itemData
  478. class VDigitZBulkDialog(wx.Dialog):
  479. def __init__(self, parent, title, nselected, style = wx.DEFAULT_DIALOG_STYLE):
  480. """!Dialog used for Z bulk-labeling tool
  481. """
  482. wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style)
  483. self.parent = parent # mapdisplay.BufferedWindow class instance
  484. # panel = wx.Panel(parent=self, id=wx.ID_ANY)
  485. border = wx.BoxSizer(wx.VERTICAL)
  486. txt = wx.StaticText(parent = self,
  487. label = _("%d lines selected for z bulk-labeling") % nselected);
  488. border.Add(item = txt, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
  489. box = wx.StaticBox (parent = self, id = wx.ID_ANY, label = " %s " % _("Set value"))
  490. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  491. flexSizer = wx.FlexGridSizer (cols = 2, hgap = 5, vgap = 5)
  492. flexSizer.AddGrowableCol(0)
  493. # starting value
  494. txt = wx.StaticText(parent = self,
  495. label = _("Starting value"));
  496. self.value = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (150, -1),
  497. initial = 0,
  498. min = -1e6, max = 1e6)
  499. flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
  500. flexSizer.Add(self.value, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  501. # step
  502. txt = wx.StaticText(parent = self,
  503. label = _("Step"))
  504. self.step = wx.SpinCtrl(parent = self, id = wx.ID_ANY, size = (150, -1),
  505. initial = 0,
  506. min = 0, max = 1e6)
  507. flexSizer.Add(txt, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
  508. flexSizer.Add(self.step, proportion = 0, flag = wx.ALIGN_CENTER | wx.FIXED_MINSIZE)
  509. sizer.Add(item = flexSizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 1)
  510. border.Add(item = sizer, proportion = 1, flag = wx.ALL | wx.EXPAND, border = 0)
  511. # buttons
  512. btnCancel = wx.Button(self, wx.ID_CANCEL)
  513. btnOk = wx.Button(self, wx.ID_OK)
  514. btnOk.SetDefault()
  515. # sizers
  516. btnSizer = wx.StdDialogButtonSizer()
  517. btnSizer.AddButton(btnCancel)
  518. btnSizer.AddButton(btnOk)
  519. btnSizer.Realize()
  520. mainSizer = wx.BoxSizer(wx.VERTICAL)
  521. mainSizer.Add(item = border, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
  522. mainSizer.Add(item = btnSizer, proportion = 0,
  523. flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
  524. self.SetSizer(mainSizer)
  525. mainSizer.Fit(self)
  526. class VDigitDuplicatesDialog(wx.Dialog):
  527. def __init__(self, parent, data, title = _("List of duplicates"),
  528. style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
  529. pos = wx.DefaultPosition):
  530. """!Show duplicated feature ids
  531. """
  532. wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title, style = style,
  533. pos = pos)
  534. self.parent = parent # BufferedWindow
  535. self.data = data
  536. self.winList = []
  537. # panel = wx.Panel(parent=self, id=wx.ID_ANY)
  538. # notebook
  539. self.notebook = wx.Notebook(parent = self, id = wx.ID_ANY, style = wx.BK_DEFAULT)
  540. id = 1
  541. for key in self.data.keys():
  542. panel = wx.Panel(parent = self.notebook, id = wx.ID_ANY)
  543. self.notebook.AddPage(page = panel, text = " %d " % (id))
  544. # notebook body
  545. border = wx.BoxSizer(wx.VERTICAL)
  546. win = CheckListFeature(parent = panel, data = list(self.data[key]))
  547. self.winList.append(win.GetId())
  548. border.Add(item = win, proportion = 1,
  549. flag = wx.ALL | wx.EXPAND, border = 5)
  550. panel.SetSizer(border)
  551. id += 1
  552. # buttons
  553. btnCancel = wx.Button(self, wx.ID_CANCEL)
  554. btnOk = wx.Button(self, wx.ID_OK)
  555. btnOk.SetDefault()
  556. # sizers
  557. btnSizer = wx.StdDialogButtonSizer()
  558. btnSizer.AddButton(btnCancel)
  559. btnSizer.AddButton(btnOk)
  560. btnSizer.Realize()
  561. mainSizer = wx.BoxSizer(wx.VERTICAL)
  562. mainSizer.Add(item = self.notebook, proportion = 1, flag = wx.EXPAND | wx.ALL, border = 5)
  563. mainSizer.Add(item = btnSizer, proportion = 0,
  564. flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
  565. self.SetSizer(mainSizer)
  566. mainSizer.Fit(self)
  567. self.SetAutoLayout(True)
  568. # set min size for dialog
  569. self.SetMinSize((250, 180))
  570. def GetUnSelected(self):
  571. """!Get unselected items (feature id)
  572. @return list of ids
  573. """
  574. ids = []
  575. for id in self.winList:
  576. wlist = self.FindWindowById(id)
  577. for item in range(wlist.GetItemCount()):
  578. if not wlist.IsChecked(item):
  579. ids.append(int(wlist.GetItem(item, 0).GetText()))
  580. return ids
  581. class CheckListFeature(wx.ListCtrl, listmix.ListCtrlAutoWidthMixin, listmix.CheckListCtrlMixin):
  582. def __init__(self, parent, data,
  583. pos = wx.DefaultPosition, log = None):
  584. """!List of mapset/owner/group
  585. """
  586. self.parent = parent
  587. self.data = data
  588. wx.ListCtrl.__init__(self, parent, wx.ID_ANY,
  589. style = wx.LC_REPORT)
  590. listmix.CheckListCtrlMixin.__init__(self)
  591. self.log = log
  592. # setup mixins
  593. listmix.ListCtrlAutoWidthMixin.__init__(self)
  594. self.LoadData(self.data)
  595. def LoadData(self, data):
  596. """!Load data into list
  597. """
  598. self.InsertColumn(0, _('Feature id'))
  599. self.InsertColumn(1, _('Layer (Categories)'))
  600. for item in data:
  601. index = self.InsertStringItem(sys.maxint, str(item[0]))
  602. self.SetStringItem(index, 1, str(item[1]))
  603. # enable all items by default
  604. for item in range(self.GetItemCount()):
  605. self.CheckItem(item, True)
  606. self.SetColumnWidth(col = 0, width = wx.LIST_AUTOSIZE_USEHEADER)
  607. self.SetColumnWidth(col = 1, width = wx.LIST_AUTOSIZE_USEHEADER)
  608. def OnCheckItem(self, index, flag):
  609. """!Mapset checked/unchecked
  610. """
  611. pass