dialogs.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518
  1. """!
  2. @package iscatt.dialogs
  3. @brief Dialogs widgets.
  4. Classes:
  5. - dialogs::AddScattPlotDialog
  6. - dialogs::ExportCategoryRaster
  7. - dialogs::SettingsDialog
  8. - dialogs::ManageBusyCursorMixin
  9. - dialogs::RenameClassDialog
  10. (C) 2013 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 Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
  14. """
  15. import os
  16. import sys
  17. import wx
  18. from iscatt.iscatt_core import idBandsToidScatt
  19. from gui_core.gselect import Select
  20. import wx.lib.colourselect as csel
  21. import grass.script as grass
  22. from core import globalvar
  23. from core.gcmd import GMessage
  24. from core.settings import UserSettings
  25. from gui_core.dialogs import SimpleDialog
  26. class AddScattPlotDialog(wx.Dialog):
  27. def __init__(self, parent, bands, added_scatts_ids, id = wx.ID_ANY):
  28. wx.Dialog.__init__(self, parent, title = ("Add scatter plots"), id = id)
  29. self.added_scatts_ids = added_scatts_ids
  30. self.bands = bands
  31. self.x_band = None
  32. self.y_band = None
  33. self.added_bands_ids = []
  34. self.sel_bands_ids = []
  35. self._createWidgets()
  36. def _createWidgets(self):
  37. self.labels = {}
  38. self.params = {}
  39. self.band_1_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("x axis:"))
  40. self.band_1_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
  41. choices = self.bands,
  42. style = wx.CB_READONLY, size = (350, 30))
  43. self.band_2_label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("y axis:"))
  44. self.band_2_ch = wx.ComboBox(parent = self, id = wx.ID_ANY,
  45. choices = self.bands,
  46. style = wx.CB_READONLY, size = (350, 30))
  47. self.scattsBox = wx.ListBox(parent = self, id = wx.ID_ANY, size = (-1, 150),
  48. style = wx.LB_MULTIPLE | wx.LB_NEEDED_SB)
  49. # buttons
  50. self.btn_add = wx.Button(parent=self, id=wx.ID_ANY, label = _("Add"))
  51. self.btn_remove = wx.Button(parent=self, id=wx.ID_ANY, label = _("Remove"))
  52. self.btn_close = wx.Button(parent=self, id=wx.ID_CANCEL)
  53. self.btn_ok = wx.Button(parent=self, id=wx.ID_OK, label = _("&OK"))
  54. self._layout()
  55. def _layout(self):
  56. border = wx.BoxSizer(wx.VERTICAL)
  57. dialogSizer = wx.BoxSizer(wx.VERTICAL)
  58. regionSizer = wx.BoxSizer(wx.HORIZONTAL)
  59. dialogSizer.Add(item = self._addSelectSizer(title = self.band_1_label,
  60. sel = self.band_1_ch))
  61. dialogSizer.Add(item = self._addSelectSizer(title = self.band_2_label,
  62. sel = self.band_2_ch))
  63. dialogSizer.Add(item=self.btn_add, proportion=0, flag = wx.TOP, border = 5)
  64. box = wx.StaticBox(self, id = wx.ID_ANY,
  65. label = " %s " % _("Bands of scatter plots to be added (x y):"))
  66. sizer = wx.StaticBoxSizer(box, wx.VERTICAL)
  67. sizer.Add(item=self.scattsBox, proportion=1, flag=wx.EXPAND | wx.TOP, border=5)
  68. sizer.Add(item=self.btn_remove, proportion=0, flag=wx.TOP, border = 5)
  69. dialogSizer.Add(item=sizer, proportion=1, flag = wx.EXPAND | wx.TOP, border = 5)
  70. # buttons
  71. self.btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
  72. self.btnsizer.Add(item = self.btn_close, proportion = 0,
  73. flag = wx.RIGHT | wx.LEFT | wx.ALIGN_CENTER,
  74. border = 10)
  75. self.btnsizer.Add(item = self.btn_ok, proportion = 0,
  76. flag = wx.RIGHT | wx.LEFT | wx.ALIGN_CENTER,
  77. border = 10)
  78. dialogSizer.Add(item = self.btnsizer, proportion = 0,
  79. flag = wx.ALIGN_CENTER | wx.TOP, border = 5)
  80. border.Add(item = dialogSizer, proportion = 0,
  81. flag = wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 10)
  82. self.SetSizer(border)
  83. self.Layout()
  84. self.Fit()
  85. # bindings
  86. self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
  87. self.btn_ok.Bind(wx.EVT_BUTTON, self.OnOk)
  88. self.btn_add.Bind(wx.EVT_BUTTON, self.OnAdd)
  89. self.btn_remove.Bind(wx.EVT_BUTTON, self.OnRemoveLayer)
  90. def OnOk(self, event):
  91. if not self.GetBands():
  92. GMessage(parent=self, message=_("No scatter plots selected."))
  93. return
  94. event.Skip()
  95. def _addSelectSizer(self, title, sel):
  96. """!Helper layout function.
  97. """
  98. selSizer = wx.BoxSizer(orient = wx.VERTICAL)
  99. selTitleSizer = wx.BoxSizer(wx.HORIZONTAL)
  100. selTitleSizer.Add(item = title, proportion = 1,
  101. flag = wx.TOP | wx.EXPAND, border = 5)
  102. selSizer.Add(item = selTitleSizer, proportion = 0,
  103. flag = wx.EXPAND)
  104. selSizer.Add(item = sel, proportion = 1,
  105. flag = wx.EXPAND | wx.TOP| wx.ALIGN_CENTER_VERTICAL,
  106. border = 5)
  107. return selSizer
  108. def GetBands(self):
  109. """!Get layers"""
  110. return self.sel_bands_ids
  111. def OnClose(self, event):
  112. """!Close dialog
  113. """
  114. if not self.IsModal():
  115. self.Destroy()
  116. event.Skip()
  117. def OnRemoveLayer(self, event):
  118. """!Remove layer from listbox"""
  119. while self.scattsBox.GetSelections():
  120. sel = self.scattsBox.GetSelections()[0]
  121. self.scattsBox.Delete(sel)
  122. self.sel_bands_ids.pop(sel)
  123. def OnAdd(self, event):
  124. """!
  125. """
  126. b_x = self.band_1_ch.GetSelection()
  127. b_y = self.band_2_ch.GetSelection()
  128. if b_x < 0 or b_y < 0:
  129. GMessage(parent=self, message=_("Select both x and y bands."))
  130. return
  131. if b_y == b_x:
  132. GMessage(parent=self, message=_("Selected bands must be different."))
  133. return
  134. scatt_id = idBandsToidScatt(b_x, b_y, len(self.bands))
  135. if scatt_id in self.added_scatts_ids:
  136. GMessage(parent=self,
  137. message=_("Scatter plot with same band combination (regardless x y order) "
  138. "is already displayed."))
  139. return
  140. if [b_x, b_y] in self.sel_bands_ids or [b_y, b_x] in self.sel_bands_ids:
  141. GMessage(parent=self,
  142. message=_("Scatter plot with same bands combination (regardless x y order) "
  143. "has been already added into the list."))
  144. return
  145. self.sel_bands_ids.append([b_x, b_y])
  146. b_x_str = self.band_1_ch.GetStringSelection()
  147. b_y_str = self.band_2_ch.GetStringSelection()
  148. text = b_x_str + " " + b_y_str
  149. self.scattsBox.Append(text)
  150. event.Skip()
  151. class ExportCategoryRaster(wx.Dialog):
  152. def __init__(self, parent, title, rasterName = None, id = wx.ID_ANY,
  153. style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
  154. **kwargs):
  155. """!Dialog for export of category raster.
  156. @param parent window
  157. @param rasterName name of vector layer for export
  158. @param title window title
  159. """
  160. wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
  161. self.rasterName = rasterName
  162. self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
  163. self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
  164. self.btnOK = wx.Button(parent = self.panel, id = wx.ID_OK)
  165. self.btnOK.SetDefault()
  166. self.btnOK.Enable(False)
  167. self.btnOK.Bind(wx.EVT_BUTTON, self.OnOK)
  168. self.__layout()
  169. self.vectorNameCtrl.Bind(wx.EVT_TEXT, self.OnTextChanged)
  170. self.OnTextChanged(None)
  171. wx.CallAfter(self.vectorNameCtrl.SetFocus)
  172. def OnTextChanged(self, event):
  173. """!Name of new vector map given.
  174. Enable/diable OK button.
  175. """
  176. file = self.vectorNameCtrl.GetValue()
  177. if len(file) > 0:
  178. self.btnOK.Enable(True)
  179. else:
  180. self.btnOK.Enable(False)
  181. def __layout(self):
  182. """!Do layout"""
  183. sizer = wx.BoxSizer(wx.VERTICAL)
  184. dataSizer = wx.BoxSizer(wx.VERTICAL)
  185. dataSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
  186. label = _("Enter name of new vector map:")),
  187. proportion = 0, flag = wx.ALL, border = 3)
  188. self.vectorNameCtrl = Select(parent = self.panel, type = 'raster',
  189. mapsets = [grass.gisenv()['MAPSET']],
  190. size = globalvar.DIALOG_GSELECT_SIZE)
  191. if self.rasterName:
  192. self.vectorNameCtrl.SetValue(self.rasterName)
  193. dataSizer.Add(item = self.vectorNameCtrl,
  194. proportion = 0, flag = wx.ALL | wx.EXPAND, border = 3)
  195. # buttons
  196. btnSizer = wx.StdDialogButtonSizer()
  197. btnSizer.AddButton(self.btnCancel)
  198. btnSizer.AddButton(self.btnOK)
  199. btnSizer.Realize()
  200. sizer.Add(item = dataSizer, proportion = 1,
  201. flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
  202. sizer.Add(item = btnSizer, proportion = 0,
  203. flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
  204. self.panel.SetSizer(sizer)
  205. sizer.Fit(self)
  206. self.SetMinSize(self.GetSize())
  207. def GetRasterName(self):
  208. """!Returns vector name"""
  209. return self.vectorNameCtrl.GetValue()
  210. def OnOK(self, event):
  211. """!Checks if map exists and can be overwritten."""
  212. overwrite = UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled')
  213. rast_name = self.GetRasterName()
  214. res = grass.find_file(rast_name, element = 'cell')
  215. if res['fullname'] and overwrite is False:
  216. qdlg = wx.MessageDialog(parent = self,
  217. message = _("Raster map <%s> already exists."
  218. " Do you want to overwrite it?" % rast_name) ,
  219. caption = _("Raster <%s> exists" % rast_name),
  220. style = wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION | wx.CENTRE)
  221. if qdlg.ShowModal() == wx.ID_YES:
  222. event.Skip()
  223. qdlg.Destroy()
  224. else:
  225. event.Skip()
  226. class SettingsDialog(wx.Dialog):
  227. def __init__(self, parent, id, title, scatt_mgr, pos=wx.DefaultPosition, size=wx.DefaultSize,
  228. style=wx.DEFAULT_DIALOG_STYLE):
  229. """!Settings dialog"""
  230. wx.Dialog.__init__(self, parent, id, title, pos, size, style)
  231. self.scatt_mgr = scatt_mgr
  232. maxValue = 1e8
  233. self.parent = parent
  234. self.settings = {}
  235. settsLabels = {}
  236. self.settings["show_ellips"] = wx.CheckBox(parent = self, id=wx.ID_ANY,
  237. label = _('Show confidence ellipses'))
  238. show_ellips = UserSettings.Get(group ='scatt', key = "ellipses", subkey = "show_ellips")
  239. self.settings["show_ellips"].SetValue(show_ellips)
  240. self.colorsSetts = {
  241. "sel_pol" : ["selection", _("Selection polygon color:")],
  242. "sel_pol_vertex" : ["selection", _("Color of selection polygon vertex:")],
  243. "sel_area" : ["selection", _("Selected area color:")]
  244. }
  245. for settKey, sett in self.colorsSetts.iteritems():
  246. settsLabels[settKey] = wx.StaticText(parent = self, id = wx.ID_ANY, label = sett[1])
  247. col = UserSettings.Get(group ='scatt', key = sett[0], subkey = settKey)
  248. self.settings[settKey] = csel.ColourSelect(parent = self, id = wx.ID_ANY,
  249. colour = wx.Colour(col[0],
  250. col[1],
  251. col[2],
  252. 255))
  253. self.sizeSetts = {
  254. "snap_tresh" : ["selection", _("Snapping treshold in pixels:")],
  255. "sel_area_opacty" : ["selection", _("Selected area opacity:")]
  256. }
  257. for settKey, sett in self.sizeSetts.iteritems():
  258. settsLabels[settKey] = wx.StaticText(parent = self, id = wx.ID_ANY, label = sett[1])
  259. self.settings[settKey] = wx.SpinCtrl(parent = self, id = wx.ID_ANY, min=0, max = 100)
  260. size = int(UserSettings.Get(group = 'scatt', key = sett[0], subkey = settKey))
  261. self.settings[settKey].SetValue(size)
  262. # buttons
  263. self.btnSave = wx.Button(self, wx.ID_SAVE)
  264. self.btnApply = wx.Button(self, wx.ID_APPLY)
  265. self.btnClose = wx.Button(self, wx.ID_CLOSE)
  266. self.btnApply.SetDefault()
  267. # bindings
  268. self.btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  269. self.btnApply.SetToolTipString(_("Apply changes for the current session"))
  270. self.btnSave.Bind(wx.EVT_BUTTON, self.OnSave)
  271. self.btnSave.SetToolTipString(_("Apply and save changes to user settings file (default for next sessions)"))
  272. self.btnClose.Bind(wx.EVT_BUTTON, self.OnClose)
  273. self.btnClose.SetToolTipString(_("Close dialog"))
  274. #Layout
  275. # Analysis result style layout
  276. self.SetMinSize(self.GetBestSize())
  277. sizer = wx.BoxSizer(wx.VERTICAL)
  278. sel_pol_box = wx.StaticBox(parent = self, id = wx.ID_ANY,
  279. label =" %s " % _("Selection style:"))
  280. selPolBoxSizer = wx.StaticBoxSizer(sel_pol_box, wx.VERTICAL)
  281. gridSizer = wx.GridBagSizer(vgap = 1, hgap = 1)
  282. row = 0
  283. setts = dict(self.colorsSetts.items() + self.sizeSetts.items())
  284. settsOrder = ["sel_pol", "sel_pol_vertex", "sel_area",
  285. "sel_area_opacty", "snap_tresh"]
  286. for settKey in settsOrder:
  287. sett = setts[settKey]
  288. gridSizer.Add(item = settsLabels[settKey], flag = wx.ALIGN_CENTER_VERTICAL, pos =(row, 0))
  289. gridSizer.Add(item = self.settings[settKey],
  290. flag = wx.ALIGN_RIGHT | wx.ALL, border = 5,
  291. pos =(row, 1))
  292. row += 1
  293. gridSizer.AddGrowableCol(1)
  294. selPolBoxSizer.Add(item = gridSizer, flag = wx.EXPAND)
  295. ell_box = wx.StaticBox(parent = self, id = wx.ID_ANY,
  296. label =" %s " % _("Ellipses settings:"))
  297. ellPolBoxSizer = wx.StaticBoxSizer(ell_box, wx.VERTICAL)
  298. gridSizer = wx.GridBagSizer(vgap = 1, hgap = 1)
  299. sett = setts[settKey]
  300. row = 0
  301. gridSizer.Add(item=self.settings["show_ellips"],
  302. flag=wx.ALIGN_CENTER_VERTICAL,
  303. pos=(row, 0))
  304. gridSizer.AddGrowableCol(1)
  305. ellPolBoxSizer.Add(item=gridSizer, flag=wx.EXPAND)
  306. btnSizer = wx.BoxSizer(wx.HORIZONTAL)
  307. btnSizer.Add(self.btnApply, flag=wx.LEFT | wx.RIGHT, border=5)
  308. btnSizer.Add(self.btnSave, flag=wx.LEFT | wx.RIGHT, border=5)
  309. btnSizer.Add(self.btnClose, flag=wx.LEFT | wx.RIGHT, border=5)
  310. sizer.Add(item=selPolBoxSizer, flag=wx.EXPAND | wx.ALL, border=5)
  311. sizer.Add(item=ellPolBoxSizer, flag=wx.EXPAND | wx.ALL, border=5)
  312. sizer.Add(item=btnSizer, flag=wx.EXPAND | wx.ALL, border=5, proportion=0)
  313. self.SetSizer(sizer)
  314. sizer.Fit(self)
  315. def OnSave(self, event):
  316. """!Button 'Save' pressed"""
  317. self.UpdateSettings()
  318. fileSettings = {}
  319. UserSettings.ReadSettingsFile(settings=fileSettings)
  320. fileSettings['scatt'] = UserSettings.Get(group='scatt')
  321. UserSettings.SaveToFile(fileSettings)
  322. self.Close()
  323. def UpdateSettings(self):
  324. chanaged_setts = [];
  325. for settKey, sett in self.colorsSetts.iteritems():
  326. col = tuple(self.settings[settKey].GetColour())
  327. col_s = UserSettings.Get(group='scatt', key=sett[0], subkey=settKey)
  328. if col_s != col:
  329. UserSettings.Set(group='scatt',
  330. key=sett[0],
  331. subkey=settKey,
  332. value=col)
  333. chanaged_setts.append([settKey, sett[0]])
  334. for settKey, sett in self.sizeSetts.iteritems():
  335. val = self.settings[settKey].GetValue()
  336. val_s = UserSettings.Get(group ='scatt', key = sett[0], subkey = settKey)
  337. if val_s != val:
  338. UserSettings.Set(group = 'scatt', key = sett[0], subkey = settKey,
  339. value = val)
  340. chanaged_setts.append([settKey, sett[0]])
  341. val = self.settings['show_ellips'].IsChecked()
  342. val_s = UserSettings.Get(group ='scatt', key='ellipses', subkey='show_ellips')
  343. if val != val_s:
  344. UserSettings.Set(group='scatt', key='ellipses', subkey='show_ellips',
  345. value=val)
  346. chanaged_setts.append(['ellipses', 'show_ellips'])
  347. if chanaged_setts:
  348. self.scatt_mgr.SettingsUpdated(chanaged_setts)
  349. def OnApply(self, event):
  350. """!Button 'Apply' pressed"""
  351. self.UpdateSettings()
  352. #self.Close()
  353. def OnClose(self, event):
  354. """!Button 'Cancel' pressed"""
  355. self.Close()
  356. class ManageBusyCursorMixin:
  357. def __init__(self, window):
  358. self.win = window
  359. self.is_busy = False
  360. self.cur_inside = False
  361. self.win.Bind(wx.EVT_ENTER_WINDOW, self.OnEnter)
  362. self.win.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeave)
  363. def OnLeave(self, event):
  364. self.cur_inside = False
  365. self.busy_cur = None
  366. def OnEnter(self, event):
  367. self.cur_inside = True
  368. if self.is_busy:
  369. self.busy_cur = wx.BusyCursor()
  370. def UpdateCur(self, busy):
  371. self.is_busy = busy
  372. if self.cur_inside and self.is_busy:
  373. self.busy_cur = wx.BusyCursor()
  374. return
  375. self.busy_cur = None
  376. class RenameClassDialog(SimpleDialog):
  377. def __init__(self, parent, old_name, title=("Change class name")):
  378. SimpleDialog.__init__(self, parent, title)
  379. self.name = wx.TextCtrl(self.panel, id = wx.ID_ANY)
  380. self.name.SetValue(old_name)
  381. self.dataSizer.Add(self.name, proportion = 0,
  382. flag = wx.EXPAND | wx.ALL, border = 1)
  383. self.panel.SetSizer(self.sizer)
  384. self.name.SetMinSize((200, -1))
  385. self.sizer.Fit(self)
  386. def GetNewName(self):
  387. return self.name.GetValue()