dialogs.py 96 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559
  1. """!
  2. @package gui_core.dialogs
  3. @brief Various dialogs used in wxGUI.
  4. List of classes:
  5. - dialogs::SimpleDialog
  6. - dialogs::LocationDialog
  7. - dialogs::MapsetDialog
  8. - dialogs::NewVectorDialog
  9. - dialogs::SavedRegion
  10. - dialogs::DecorationDialog
  11. - dialogs::TextLayerDialog
  12. - dialogs::GroupDialog
  13. - dialogs::MapLayersDialog
  14. - dialogs::ImportDialog
  15. - dialogs::GdalImportDialog
  16. - dialogs::GdalOutputDialog
  17. - dialogs::DxfImportDialog
  18. - dialogs::LayersList (used by MultiImport)
  19. - dialogs::SetOpacityDialog
  20. - dialogs::ImageSizeDialog
  21. - dialogs::SqlQueryFrame
  22. - dialogs::SymbolDialog
  23. (C) 2008-2011 by the GRASS Development Team
  24. This program is free software under the GNU General Public License
  25. (>=v2). Read the file COPYING that comes with GRASS for details.
  26. @author Martin Landa <landa.martin gmail.com>
  27. @author Anna Kratochvilova <kratochanna gmail.com> (GroupDialog, SymbolDialog)
  28. """
  29. import os
  30. import sys
  31. import re
  32. from bisect import bisect
  33. import wx
  34. import wx.lib.filebrowsebutton as filebrowse
  35. import wx.lib.mixins.listctrl as listmix
  36. from wx.lib.newevent import NewEvent
  37. from grass.script import core as grass
  38. from grass.script import task as gtask
  39. from core import globalvar
  40. from core.gcmd import GError, RunCommand, GMessage
  41. from gui_core.gselect import LocationSelect, MapsetSelect, Select, OgrTypeSelect, GdalSelect, MapsetSelect
  42. from gui_core.forms import GUI
  43. from gui_core.widgets import SingleSymbolPanel, EVT_SYMBOL_SELECTION_CHANGED, GListCtrl, SimpleValidator
  44. from core.utils import GetLayerNameFromCmd, GetValidLayerName
  45. from core.settings import UserSettings, GetDisplayVectSettings
  46. from core.debug import Debug
  47. wxApplyMapLayers, EVT_APPLY_MAP_LAYERS = NewEvent()
  48. wxApplyOpacity, EVT_APPLY_OPACITY = NewEvent()
  49. class SimpleDialog(wx.Dialog):
  50. def __init__(self, parent, title, id = wx.ID_ANY,
  51. style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
  52. **kwargs):
  53. """!General dialog to choose given element (location, mapset, vector map, etc.)
  54. @param parent window
  55. @param title window title
  56. """
  57. wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
  58. self.SetExtraStyle(wx.WS_EX_VALIDATE_RECURSIVELY)
  59. self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
  60. self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
  61. self.btnOK = wx.Button(parent = self.panel, id = wx.ID_OK)
  62. self.btnOK.SetDefault()
  63. self.__layout()
  64. self.warning = _("Required item is not set.")
  65. def __layout(self):
  66. """!Do layout"""
  67. self.sizer = wx.BoxSizer(wx.VERTICAL)
  68. self.dataSizer = wx.BoxSizer(wx.VERTICAL)
  69. # self.informLabel = wx.StaticText(self.panel, id = wx.ID_ANY)
  70. # buttons
  71. btnSizer = wx.StdDialogButtonSizer()
  72. btnSizer.AddButton(self.btnCancel)
  73. btnSizer.AddButton(self.btnOK)
  74. btnSizer.Realize()
  75. self.sizer.Add(item = self.dataSizer, proportion = 1,
  76. flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
  77. # self.sizer.Add(item = self.informLabel, proportion = 0, flag = wx.ALL, border = 5)
  78. self.sizer.Add(item = btnSizer, proportion = 0,
  79. flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
  80. def ValidatorCallback(self, win):
  81. GMessage(parent = self, message = self.warning)
  82. # self.informLabel.SetForegroundColour(wx.Color(255, 0, 0))
  83. # self.informLabel.SetLabel(self.warning)
  84. class LocationDialog(SimpleDialog):
  85. """!Dialog used to select location"""
  86. def __init__(self, parent, title = _("Select GRASS location and mapset")):
  87. SimpleDialog.__init__(self, parent, title)
  88. self.element1 = LocationSelect(parent = self.panel, id = wx.ID_ANY,
  89. size = globalvar.DIALOG_GSELECT_SIZE,
  90. validator = SimpleValidator(callback = self.ValidatorCallback))
  91. self.element1.Bind(wx.EVT_TEXT, self.OnLocation)
  92. self.element2 = MapsetSelect(parent = self.panel, id = wx.ID_ANY,
  93. size = globalvar.DIALOG_GSELECT_SIZE,
  94. setItems = False, skipCurrent = True,
  95. validator = SimpleValidator(callback = self.ValidatorCallback))
  96. self.element1.SetFocus()
  97. self.warning = _("Location or mapset is missing.")
  98. self._layout()
  99. self.SetMinSize(self.GetSize())
  100. def _layout(self):
  101. """!Do layout"""
  102. self.dataSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
  103. label = _("Name of GRASS location:")),
  104. proportion = 0, flag = wx.ALL, border = 1)
  105. self.dataSizer.Add(self.element1, proportion = 0,
  106. flag = wx.EXPAND | wx.ALL, border = 1)
  107. self.dataSizer.Add(wx.StaticText(parent = self.panel, id = wx.ID_ANY,
  108. label = _("Name of mapset:")), proportion = 0,
  109. flag = wx.EXPAND | wx.ALL, border = 1)
  110. self.dataSizer.Add(self.element2, proportion = 0,
  111. flag = wx.EXPAND | wx.ALL, border = 1)
  112. self.panel.SetSizer(self.sizer)
  113. self.sizer.Fit(self)
  114. def OnLocation(self, event):
  115. """!Select mapset given location name"""
  116. location = event.GetString()
  117. if location:
  118. dbase = grass.gisenv()['GISDBASE']
  119. self.element2.UpdateItems(dbase = dbase, location = location)
  120. self.element2.SetSelection(0)
  121. mapset = self.element2.GetStringSelection()
  122. def GetValues(self):
  123. """!Get location, mapset"""
  124. return (self.element1.GetValue(), self.element2.GetValue())
  125. class MapsetDialog(SimpleDialog):
  126. """!Dialog used to select mapset"""
  127. def __init__(self, parent, title = _("Select mapset in GRASS location"),
  128. location = None):
  129. SimpleDialog.__init__(self, parent, title)
  130. if location:
  131. self.SetTitle(self.GetTitle() + ' <%s>' % location)
  132. else:
  133. self.SetTitle(self.GetTitle() + ' <%s>' % grass.gisenv()['LOCATION_NAME'])
  134. self.element = MapsetSelect(parent = self.panel, id = wx.ID_ANY, skipCurrent = True,
  135. size = globalvar.DIALOG_GSELECT_SIZE,
  136. validator = SimpleValidator(callback = self.ValidatorCallback))
  137. self.element.SetFocus()
  138. self.warning = _("Name of mapset is missing.")
  139. self._layout()
  140. self.SetMinSize(self.GetSize())
  141. def _layout(self):
  142. """!Do layout"""
  143. self.dataSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
  144. label = _("Name of mapset:")),
  145. proportion = 0, flag = wx.ALL, border = 1)
  146. self.dataSizer.Add(self.element, proportion = 0,
  147. flag = wx.EXPAND | wx.ALL, border = 1)
  148. self.panel.SetSizer(self.sizer)
  149. self.sizer.Fit(self)
  150. def GetMapset(self):
  151. return self.element.GetValue()
  152. class NewVectorDialog(SimpleDialog):
  153. def __init__(self, parent, title = _("Create new vector map"),
  154. disableAdd = False, disableTable = False, showType = False):
  155. """!Dialog for creating new vector map
  156. @param parent parent window
  157. @param title window title
  158. @param disableAdd disable 'add layer' checkbox
  159. @param disableTable disable 'create table' checkbox
  160. @param showType True to show feature type selector (used for creating new empty OGR layers)
  161. @return dialog instance
  162. """
  163. SimpleDialog.__init__(self, parent, title)
  164. self.element = Select(parent = self.panel, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
  165. type = 'vector', mapsets = [grass.gisenv()['MAPSET'],],
  166. validator = SimpleValidator(callback = self.ValidatorCallback))
  167. self.element.SetFocus()
  168. # determine output format
  169. if showType:
  170. self.ftype = OgrTypeSelect(parent = self, panel = self.panel)
  171. else:
  172. self.ftype = None
  173. self.table = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
  174. label = _("Create attribute table"))
  175. self.table.SetValue(True)
  176. if disableTable:
  177. self.table.Enable(False)
  178. if showType:
  179. self.keycol = None
  180. else:
  181. self.keycol = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY,
  182. size = globalvar.DIALOG_SPIN_SIZE)
  183. self.keycol.SetValue(UserSettings.Get(group = 'atm', key = 'keycolumn', subkey = 'value'))
  184. if disableTable:
  185. self.keycol.Enable(False)
  186. self.addbox = wx.CheckBox(parent = self.panel,
  187. label = _('Add created map into layer tree'), style = wx.NO_BORDER)
  188. if disableAdd:
  189. self.addbox.SetValue(True)
  190. self.addbox.Enable(False)
  191. else:
  192. self.addbox.SetValue(UserSettings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
  193. self.table.Bind(wx.EVT_CHECKBOX, self.OnTable)
  194. self.warning = _("Name of new vector map is missing.")
  195. self._layout()
  196. self.SetMinSize(self.GetSize())
  197. def OnTable(self, event):
  198. if self.keycol:
  199. self.keycol.Enable(event.IsChecked())
  200. def _layout(self):
  201. """!Do layout"""
  202. self.dataSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
  203. label = _("Name for new vector map:")),
  204. proportion = 0, flag = wx.ALL, border = 1)
  205. self.dataSizer.Add(item = self.element, proportion = 0,
  206. flag = wx.EXPAND | wx.ALL, border = 1)
  207. if self.ftype:
  208. self.dataSizer.AddSpacer(1)
  209. self.dataSizer.Add(item = self.ftype, proportion = 0,
  210. flag = wx.EXPAND | wx.ALL, border = 1)
  211. self.dataSizer.Add(item = self.table, proportion = 0,
  212. flag = wx.EXPAND | wx.ALL, border = 1)
  213. if self.keycol:
  214. keySizer = wx.BoxSizer(wx.HORIZONTAL)
  215. keySizer.Add(item = wx.StaticText(parent = self.panel, label = _("Key column:")),
  216. proportion = 0,
  217. flag = wx.ALIGN_CENTER_VERTICAL)
  218. keySizer.AddSpacer(10)
  219. keySizer.Add(item = self.keycol, proportion = 0,
  220. flag = wx.ALIGN_RIGHT)
  221. self.dataSizer.Add(item = keySizer, proportion = 1,
  222. flag = wx.EXPAND | wx.ALL, border = 1)
  223. self.dataSizer.AddSpacer(5)
  224. self.dataSizer.Add(item = self.addbox, proportion = 0,
  225. flag = wx.EXPAND | wx.ALL, border = 1)
  226. self.panel.SetSizer(self.sizer)
  227. self.sizer.Fit(self)
  228. def GetName(self, full = False):
  229. """!Get name of vector map to be created
  230. @param full True to get fully qualified name
  231. """
  232. name = self.element.GetValue()
  233. if full:
  234. if '@' in name:
  235. return name
  236. else:
  237. return name + '@' + grass.gisenv()['MAPSET']
  238. return name.split('@', 1)[0]
  239. def GetKey(self):
  240. """!Get key column name"""
  241. if self.keycol:
  242. return self.keycol.GetValue()
  243. return UserSettings.Get(group = 'atm', key = 'keycolumn', subkey = 'value')
  244. def IsChecked(self, key):
  245. """!Get dialog properties
  246. @param key window key ('add', 'table')
  247. @return True/False
  248. @return None on error
  249. """
  250. if key == 'add':
  251. return self.addbox.IsChecked()
  252. elif key == 'table':
  253. return self.table.IsChecked()
  254. return None
  255. def GetFeatureType(self):
  256. """!Get feature type for OGR
  257. @return feature type as string
  258. @return None for native format
  259. """
  260. if self.ftype:
  261. return self.ftype.GetType()
  262. return None
  263. def CreateNewVector(parent, cmd, title = _('Create new vector map'),
  264. exceptMap = None, log = None,
  265. disableAdd = False, disableTable = False):
  266. """!Create new vector map layer
  267. @param cmd (prog, **kwargs)
  268. @param title window title
  269. @param exceptMap list of maps to be excepted
  270. @param log
  271. @param disableAdd disable 'add layer' checkbox
  272. @param disableTable disable 'create table' checkbox
  273. @return dialog instance
  274. @return None on error
  275. """
  276. vExternalOut = grass.parse_command('v.external.out', flags = 'g')
  277. isNative = vExternalOut['format'] == 'native'
  278. if cmd[0] == 'v.edit' and not isNative:
  279. showType = True
  280. else:
  281. showType = False
  282. dlg = NewVectorDialog(parent, title = title,
  283. disableAdd = disableAdd, disableTable = disableTable,
  284. showType = showType)
  285. if dlg.ShowModal() != wx.ID_OK:
  286. dlg.Destroy()
  287. return None
  288. outmap = dlg.GetName()
  289. key = dlg.GetKey()
  290. if outmap == exceptMap:
  291. GError(parent = parent,
  292. message = _("Unable to create vector map <%s>.") % outmap)
  293. dlg.Destroy()
  294. return None
  295. if dlg.table.IsEnabled() and not key:
  296. GError(parent = parent,
  297. message = _("Invalid or empty key column.\n"
  298. "Unable to create vector map <%s>.") % outmap)
  299. dlg.Destroy()
  300. return
  301. if outmap == '': # should not happen
  302. dlg.Destroy()
  303. return None
  304. # update cmd -> output name defined
  305. cmd[1][cmd[2]] = outmap
  306. if showType:
  307. cmd[1]['type'] = dlg.GetFeatureType()
  308. if isNative:
  309. listOfVectors = grass.list_grouped('vect')[grass.gisenv()['MAPSET']]
  310. else:
  311. listOfVectors = RunCommand('v.external',
  312. quiet = True,
  313. parent = parent,
  314. read = True,
  315. flags = 'l',
  316. dsn = vExternalOut['dsn']).splitlines()
  317. overwrite = False
  318. if not UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled') and \
  319. outmap in listOfVectors:
  320. dlgOw = wx.MessageDialog(parent, message = _("Vector map <%s> already exists "
  321. "in the current mapset. "
  322. "Do you want to overwrite it?") % outmap,
  323. caption = _("Overwrite?"),
  324. style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
  325. if dlgOw.ShowModal() == wx.ID_YES:
  326. overwrite = True
  327. else:
  328. dlgOw.Destroy()
  329. dlg.Destroy()
  330. return None
  331. if UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'):
  332. overwrite = True
  333. ret = RunCommand(prog = cmd[0],
  334. parent = parent,
  335. overwrite = overwrite,
  336. **cmd[1])
  337. if ret != 0:
  338. dlg.Destroy()
  339. return None
  340. if not isNative:
  341. # create link for OGR layers
  342. RunCommand('v.external',
  343. overwrite = overwrite,
  344. parent = parent,
  345. dsn = vExternalOut['dsn'],
  346. layer = outmap)
  347. # create attribute table
  348. if dlg.table.IsEnabled() and dlg.table.IsChecked():
  349. if isNative:
  350. sql = 'CREATE TABLE %s (%s INTEGER)' % (outmap, key)
  351. RunCommand('db.connect',
  352. flags = 'c')
  353. Debug.msg(1, "SQL: %s" % sql)
  354. RunCommand('db.execute',
  355. quiet = True,
  356. parent = parent,
  357. input = '-',
  358. stdin = sql)
  359. RunCommand('v.db.connect',
  360. quiet = True,
  361. parent = parent,
  362. map = outmap,
  363. table = outmap,
  364. key = key,
  365. layer = '1')
  366. # TODO: how to deal with attribute tables for OGR layers?
  367. # return fully qualified map name
  368. if '@' not in outmap:
  369. outmap += '@' + grass.gisenv()['MAPSET']
  370. if log:
  371. log.WriteLog(_("New vector map <%s> created") % outmap)
  372. return dlg
  373. class SavedRegion(wx.Dialog):
  374. def __init__(self, parent, title, id = wx.ID_ANY, loadsave = 'load',
  375. **kwargs):
  376. """!Loading or saving of display extents to saved region file
  377. @param loadsave load or save region?
  378. """
  379. wx.Dialog.__init__(self, parent, id, title, **kwargs)
  380. self.loadsave = loadsave
  381. self.wind = ''
  382. sizer = wx.BoxSizer(wx.VERTICAL)
  383. box = wx.BoxSizer(wx.HORIZONTAL)
  384. label = wx.StaticText(parent = self, id = wx.ID_ANY)
  385. box.Add(item = label, proportion = 0, flag = wx.ALIGN_CENTRE | wx.ALL, border = 5)
  386. if loadsave == 'load':
  387. label.SetLabel(_("Load region:"))
  388. selection = Select(parent = self, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
  389. type = 'windows')
  390. elif loadsave == 'save':
  391. label.SetLabel(_("Save region:"))
  392. selection = Select(parent = self, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
  393. type = 'windows', mapsets = [grass.gisenv()['MAPSET']], fullyQualified = False)
  394. box.Add(item = selection, proportion = 0, flag = wx.ALIGN_CENTRE | wx.ALL, border = 5)
  395. selection.SetFocus()
  396. selection.Bind(wx.EVT_TEXT, self.OnRegion)
  397. sizer.Add(item = box, proportion = 0, flag = wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
  398. border = 5)
  399. line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL)
  400. sizer.Add(item = line, proportion = 0,
  401. flag = wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT, border = 5)
  402. btnsizer = wx.StdDialogButtonSizer()
  403. btn = wx.Button(parent = self, id = wx.ID_OK)
  404. btn.SetDefault()
  405. btnsizer.AddButton(btn)
  406. btn = wx.Button(parent = self, id = wx.ID_CANCEL)
  407. btnsizer.AddButton(btn)
  408. btnsizer.Realize()
  409. sizer.Add(item = btnsizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
  410. self.SetSizer(sizer)
  411. sizer.Fit(self)
  412. self.Layout()
  413. def OnRegion(self, event):
  414. self.wind = event.GetString()
  415. def GetName(self):
  416. """!Return region name"""
  417. return self.wind
  418. class DecorationDialog(wx.Dialog):
  419. """!Controls setting options and displaying/hiding map overlay
  420. decorations
  421. """
  422. def __init__(self, parent, ovlId, title, cmd, name = None,
  423. pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_DIALOG_STYLE,
  424. checktxt = '', ctrltxt = ''):
  425. wx.Dialog.__init__(self, parent, wx.ID_ANY, title, pos, size, style)
  426. self.ovlId = ovlId # PseudoDC id
  427. self.cmd = cmd
  428. self.name = name # overlay name
  429. self.parent = parent # MapFrame
  430. sizer = wx.BoxSizer(wx.VERTICAL)
  431. box = wx.BoxSizer(wx.HORIZONTAL)
  432. self.chkbox = wx.CheckBox(parent = self, id = wx.ID_ANY, label = checktxt)
  433. if self.parent.Map.GetOverlay(self.ovlId) is None:
  434. self.chkbox.SetValue(True)
  435. else:
  436. self.chkbox.SetValue(self.parent.MapWindow.overlays[self.ovlId]['layer'].IsActive())
  437. box.Add(item = self.chkbox, proportion = 0,
  438. flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
  439. sizer.Add(item = box, proportion = 0,
  440. flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
  441. box = wx.BoxSizer(wx.HORIZONTAL)
  442. optnbtn = wx.Button(parent = self, id = wx.ID_ANY, label = _("Set options"))
  443. box.Add(item = optnbtn, proportion = 0, flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
  444. sizer.Add(item = box, proportion = 0,
  445. flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
  446. if self.name == 'legend':
  447. box = wx.BoxSizer(wx.HORIZONTAL)
  448. resize = wx.ToggleButton(parent = self, id = wx.ID_ANY, label = _("Set size and position"))
  449. resize.SetToolTipString(_("Click and drag on the map display to set legend"
  450. " size and position and then press OK"))
  451. resize.SetName('resize')
  452. resize.Disable()
  453. box.Add(item = resize, proportion = 0, flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
  454. sizer.Add(item = box, proportion = 0,
  455. flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
  456. box = wx.BoxSizer(wx.HORIZONTAL)
  457. label = wx.StaticText(parent = self, id = wx.ID_ANY,
  458. label = _("Drag %s with mouse in pointer mode to position.\n"
  459. "Double-click to change options." % ctrltxt))
  460. if self.name == 'legend':
  461. label.SetLabel(label.GetLabel() + _('\nDefine raster map name for legend in '
  462. 'properties dialog.'))
  463. box.Add(item = label, proportion = 0,
  464. flag = wx.ALIGN_CENTRE|wx.ALL, border = 5)
  465. sizer.Add(item = box, proportion = 0,
  466. flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
  467. line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20,-1), style = wx.LI_HORIZONTAL)
  468. sizer.Add(item = line, proportion = 0,
  469. flag = wx.GROW|wx.ALIGN_CENTER_VERTICAL|wx.ALL, border = 5)
  470. # buttons
  471. btnsizer = wx.StdDialogButtonSizer()
  472. self.btnOK = wx.Button(parent = self, id = wx.ID_OK)
  473. self.btnOK.SetDefault()
  474. if self.name == 'legend':
  475. self.btnOK.Enable(False)
  476. btnsizer.AddButton(self.btnOK)
  477. btnCancel = wx.Button(parent = self, id = wx.ID_CANCEL)
  478. btnsizer.AddButton(btnCancel)
  479. btnsizer.Realize()
  480. sizer.Add(item = btnsizer, proportion = 0,
  481. flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5)
  482. #
  483. # bindings
  484. #
  485. self.Bind(wx.EVT_BUTTON, self.OnOptions, optnbtn)
  486. if self.name == 'legend':
  487. self.Bind(wx.EVT_TOGGLEBUTTON, self.OnResize, resize)
  488. self.Bind(wx.EVT_BUTTON, self.OnCancel, btnCancel)
  489. self.Bind(wx.EVT_BUTTON, self.OnOK, self.btnOK)
  490. self.SetSizer(sizer)
  491. sizer.Fit(self)
  492. # create overlay if doesn't exist
  493. self._createOverlay()
  494. if len(self.parent.MapWindow.overlays[self.ovlId]['cmd']) > 1:
  495. if name == 'legend':
  496. mapName, found = GetLayerNameFromCmd(self.parent.MapWindow.overlays[self.ovlId]['cmd'])
  497. if found:
  498. # enable 'OK' and 'Resize' button
  499. self.btnOK.Enable()
  500. if not self.parent.IsPaneShown('3d'):
  501. self.FindWindowByName('resize').Enable()
  502. # set title
  503. self.SetTitle(_('Legend of raster map <%s>') % \
  504. mapName)
  505. def _createOverlay(self):
  506. """!Creates overlay"""
  507. if not self.parent.GetMap().GetOverlay(self.ovlId):
  508. self.newOverlay = self.parent.Map.AddOverlay(id = self.ovlId, ltype = self.name,
  509. command = self.cmd,
  510. active = False, render = False, hidden = True)
  511. prop = { 'layer' : self.newOverlay,
  512. 'params' : None,
  513. 'propwin' : None,
  514. 'cmd' : self.cmd,
  515. 'coords': (0, 0),
  516. 'pdcType': 'image' }
  517. self.parent.MapWindow2D.overlays[self.ovlId] = prop
  518. if self.parent.MapWindow3D:
  519. self.parent.MapWindow3D.overlays[self.ovlId] = prop
  520. else:
  521. if self.parent.MapWindow.overlays[self.ovlId]['propwin'] == None:
  522. return
  523. self.parent.MapWindow.overlays[self.ovlId]['propwin'].get_dcmd = self.GetOptData
  524. def OnOptions(self, event):
  525. """!Sets option for decoration map overlays
  526. """
  527. if self.parent.MapWindow.overlays[self.ovlId]['propwin'] is None:
  528. # build properties dialog
  529. GUI(parent = self.parent).ParseCommand(cmd = self.cmd,
  530. completed = (self.GetOptData, self.name, ''))
  531. else:
  532. if self.parent.MapWindow.overlays[self.ovlId]['propwin'].IsShown():
  533. self.parent.MapWindow.overlays[self.ovlId]['propwin'].SetFocus()
  534. else:
  535. self.parent.MapWindow.overlays[self.ovlId]['propwin'].Show()
  536. def OnResize(self, event):
  537. if self.FindWindowByName('resize').GetValue():
  538. self.parent.SwitchTool(self.parent.toolbars['map'], event)
  539. self.parent.MapWindow.SetCursor(self.parent.cursors["cross"])
  540. self.parent.MapWindow.mouse['use'] = 'legend'
  541. self.parent.MapWindow.mouse['box'] = 'box'
  542. self.parent.MapWindow.pen = wx.Pen(colour = 'Black', width = 2, style = wx.SHORT_DASH)
  543. else:
  544. self.parent.MapWindow.SetCursor(self.parent.cursors["default"])
  545. self.parent.MapWindow.mouse['use'] = 'pointer'
  546. def OnCancel(self, event):
  547. """!Cancel dialog"""
  548. if self.name == 'legend' and self.FindWindowByName('resize').GetValue():
  549. self.FindWindowByName('resize').SetValue(False)
  550. self.OnResize(None)
  551. self.parent.dialogs['barscale'] = None
  552. if event and hasattr(self, 'newOverlay'):
  553. self.parent.Map.DeleteOverlay(self.newOverlay)
  554. self.Destroy()
  555. def OnOK(self, event):
  556. """!Button 'OK' pressed"""
  557. # enable or disable overlay
  558. self.parent.Map.GetOverlay(self.ovlId).SetActive(self.chkbox.IsChecked())
  559. # update map
  560. if self.parent.IsPaneShown('3d'):
  561. self.parent.MapWindow.UpdateOverlays()
  562. self.parent.MapWindow.UpdateMap()
  563. # close dialog
  564. self.OnCancel(None)
  565. def GetOptData(self, dcmd, layer, params, propwin):
  566. """!Process decoration layer data"""
  567. # update layer data
  568. if params:
  569. self.parent.MapWindow.overlays[self.ovlId]['params'] = params
  570. if dcmd:
  571. self.parent.MapWindow.overlays[self.ovlId]['cmd'] = dcmd
  572. self.parent.MapWindow.overlays[self.ovlId]['propwin'] = propwin
  573. # change parameters for item in layers list in render.Map
  574. # "Use mouse..." (-m) flag causes GUI freeze and is pointless here, trac #119
  575. try:
  576. self.parent.MapWindow.overlays[self.ovlId]['cmd'].remove('-m')
  577. except ValueError:
  578. pass
  579. self.parent.Map.ChangeOverlay(id = self.ovlId, ltype = self.name,
  580. command = self.parent.MapWindow.overlays[self.ovlId]['cmd'],
  581. active = self.parent.MapWindow.overlays[self.ovlId]['layer'].IsActive(),
  582. render = False, hidden = True)
  583. if self.name == 'legend':
  584. if params and not self.btnOK.IsEnabled():
  585. self.btnOK.Enable()
  586. if not self.parent.IsPaneShown('3d'):
  587. self.FindWindowByName('resize').Enable()
  588. class TextLayerDialog(wx.Dialog):
  589. """
  590. Controls setting options and displaying/hiding map overlay decorations
  591. """
  592. def __init__(self, parent, ovlId, title, name = 'text',
  593. pos = wx.DefaultPosition, size = wx.DefaultSize, style = wx.DEFAULT_DIALOG_STYLE):
  594. wx.Dialog.__init__(self, parent, wx.ID_ANY, title, pos, size, style)
  595. from wx.lib.expando import ExpandoTextCtrl, EVT_ETC_LAYOUT_NEEDED
  596. self.ovlId = ovlId
  597. self.parent = parent
  598. if self.ovlId in self.parent.MapWindow.textdict.keys():
  599. self.currText = self.parent.MapWindow.textdict[self.ovlId]['text']
  600. self.currFont = self.parent.MapWindow.textdict[self.ovlId]['font']
  601. self.currClr = self.parent.MapWindow.textdict[self.ovlId]['color']
  602. self.currRot = self.parent.MapWindow.textdict[self.ovlId]['rotation']
  603. self.currCoords = self.parent.MapWindow.textdict[self.ovlId]['coords']
  604. self.currBB = self.parent.MapWindow.textdict[self.ovlId]['bbox']
  605. else:
  606. self.currClr = wx.BLACK
  607. self.currText = ''
  608. self.currFont = self.GetFont()
  609. self.currRot = 0.0
  610. self.currCoords = [10, 10]
  611. self.currBB = wx.Rect()
  612. self.sizer = wx.BoxSizer(wx.VERTICAL)
  613. box = wx.GridBagSizer(vgap = 5, hgap = 5)
  614. # show/hide
  615. self.chkbox = wx.CheckBox(parent = self, id = wx.ID_ANY,
  616. label = _('Show text object'))
  617. if self.parent.Map.GetOverlay(self.ovlId) is None:
  618. self.chkbox.SetValue(True)
  619. else:
  620. self.chkbox.SetValue(self.parent.MapWindow.overlays[self.ovlId]['layer'].IsActive())
  621. box.Add(item = self.chkbox, span = (1,2),
  622. flag = wx.ALIGN_LEFT|wx.ALL, border = 5,
  623. pos = (0, 0))
  624. # text entry
  625. label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Enter text:"))
  626. box.Add(item = label,
  627. flag = wx.ALIGN_CENTER_VERTICAL,
  628. pos = (1, 0))
  629. self.textentry = ExpandoTextCtrl(parent = self, id = wx.ID_ANY, value = "", size = (300,-1))
  630. self.textentry.SetFont(self.currFont)
  631. self.textentry.SetForegroundColour(self.currClr)
  632. self.textentry.SetValue(self.currText)
  633. # get rid of unneeded scrollbar when text box first opened
  634. self.textentry.SetClientSize((300,-1))
  635. box.Add(item = self.textentry,
  636. pos = (1, 1))
  637. # rotation
  638. label = wx.StaticText(parent = self, id = wx.ID_ANY, label = _("Rotation:"))
  639. box.Add(item = label,
  640. flag = wx.ALIGN_CENTER_VERTICAL,
  641. pos = (2, 0))
  642. self.rotation = wx.SpinCtrl(parent = self, id = wx.ID_ANY, value = "", pos = (30, 50),
  643. size = (75,-1), style = wx.SP_ARROW_KEYS)
  644. self.rotation.SetRange(-360, 360)
  645. self.rotation.SetValue(int(self.currRot))
  646. box.Add(item = self.rotation,
  647. flag = wx.ALIGN_RIGHT,
  648. pos = (2, 1))
  649. # font
  650. fontbtn = wx.Button(parent = self, id = wx.ID_ANY, label = _("Set font"))
  651. box.Add(item = fontbtn,
  652. flag = wx.ALIGN_RIGHT,
  653. pos = (3, 1))
  654. self.sizer.Add(item = box, proportion = 1,
  655. flag = wx.ALL, border = 10)
  656. # note
  657. box = wx.BoxSizer(wx.HORIZONTAL)
  658. label = wx.StaticText(parent = self, id = wx.ID_ANY,
  659. label = _("Drag text with mouse in pointer mode "
  660. "to position.\nDouble-click to change options"))
  661. box.Add(item = label, proportion = 0,
  662. flag = wx.ALIGN_CENTRE | wx.ALL, border = 5)
  663. self.sizer.Add(item = box, proportion = 0,
  664. flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER | wx.ALL, border = 5)
  665. line = wx.StaticLine(parent = self, id = wx.ID_ANY,
  666. size = (20,-1), style = wx.LI_HORIZONTAL)
  667. self.sizer.Add(item = line, proportion = 0,
  668. flag = wx.EXPAND | wx.ALIGN_CENTRE | wx.ALL, border = 5)
  669. btnsizer = wx.StdDialogButtonSizer()
  670. btn = wx.Button(parent = self, id = wx.ID_OK)
  671. btn.SetDefault()
  672. btnsizer.AddButton(btn)
  673. btn = wx.Button(parent = self, id = wx.ID_CANCEL)
  674. btnsizer.AddButton(btn)
  675. btnsizer.Realize()
  676. self.sizer.Add(item = btnsizer, proportion = 0,
  677. flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
  678. self.SetSizer(self.sizer)
  679. self.sizer.Fit(self)
  680. # bindings
  681. self.Bind(EVT_ETC_LAYOUT_NEEDED, self.OnRefit, self.textentry)
  682. self.Bind(wx.EVT_BUTTON, self.OnSelectFont, fontbtn)
  683. self.Bind(wx.EVT_TEXT, self.OnText, self.textentry)
  684. self.Bind(wx.EVT_SPINCTRL, self.OnRotation, self.rotation)
  685. def OnRefit(self, event):
  686. """!Resize text entry to match text"""
  687. self.sizer.Fit(self)
  688. def OnText(self, event):
  689. """!Change text string"""
  690. self.currText = event.GetString()
  691. def OnRotation(self, event):
  692. """!Change rotation"""
  693. self.currRot = event.GetInt()
  694. event.Skip()
  695. def OnSelectFont(self, event):
  696. """!Change font"""
  697. data = wx.FontData()
  698. data.EnableEffects(True)
  699. data.SetColour(self.currClr) # set colour
  700. data.SetInitialFont(self.currFont)
  701. dlg = wx.FontDialog(self, data)
  702. if dlg.ShowModal() == wx.ID_OK:
  703. data = dlg.GetFontData()
  704. self.currFont = data.GetChosenFont()
  705. self.currClr = data.GetColour()
  706. self.textentry.SetFont(self.currFont)
  707. self.textentry.SetForegroundColour(self.currClr)
  708. self.Layout()
  709. dlg.Destroy()
  710. def GetValues(self):
  711. """!Get text properties"""
  712. return { 'text' : self.currText,
  713. 'font' : self.currFont,
  714. 'color' : self.currClr,
  715. 'rotation' : self.currRot,
  716. 'coords' : self.currCoords,
  717. 'active' : self.chkbox.IsChecked() }
  718. class GroupDialog(wx.Dialog):
  719. """!Dialog for creating/editing groups"""
  720. def __init__(self, parent = None, defaultGroup = None,
  721. title = _("Create or edit imagery groups"),
  722. style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
  723. wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title,
  724. style = style, **kwargs)
  725. self.parent = parent
  726. self.defaultGroup = defaultGroup
  727. self.currentGroup = self.defaultGroup
  728. self.groupChanged = False
  729. self.bodySizer = self._createDialogBody()
  730. # buttons
  731. btnOk = wx.Button(parent = self, id = wx.ID_OK)
  732. btnApply = wx.Button(parent = self, id = wx.ID_APPLY)
  733. btnClose = wx.Button(parent = self, id = wx.ID_CANCEL)
  734. btnOk.SetToolTipString(_("Apply changes to selected group and close dialog"))
  735. btnApply.SetToolTipString(_("Apply changes to selected group"))
  736. btnClose.SetToolTipString(_("Close dialog, changes are not applied"))
  737. btnOk.SetDefault()
  738. # sizers & do layout
  739. # btnSizer = wx.BoxSizer(wx.HORIZONTAL)
  740. # btnSizer.Add(item = btnClose, proportion = 0,
  741. # flag = wx.RIGHT | wx.ALIGN_RIGHT | wx.EXPAND, border = 5)
  742. # btnSizer.Add(item = btnApply, proportion = 0,
  743. # flag = wx.LEFT, border = 5)
  744. btnSizer = wx.StdDialogButtonSizer()
  745. btnSizer.AddButton(btnOk)
  746. btnSizer.AddButton(btnApply)
  747. btnSizer.AddButton(btnClose)
  748. btnSizer.Realize()
  749. mainSizer = wx.BoxSizer(wx.VERTICAL)
  750. mainSizer.Add(item = self.bodySizer, proportion = 1,
  751. flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 10)
  752. mainSizer.Add(item = wx.StaticLine(parent = self, id = wx.ID_ANY,
  753. style = wx.LI_HORIZONTAL), proportion = 0,
  754. flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 10)
  755. mainSizer.Add(item = btnSizer, proportion = 0,
  756. flag = wx.ALL | wx.ALIGN_RIGHT, border = 10)
  757. self.SetSizer(mainSizer)
  758. mainSizer.Fit(self)
  759. btnOk.Bind(wx.EVT_BUTTON, self.OnOk)
  760. btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  761. btnClose.Bind(wx.EVT_BUTTON, self.OnClose)
  762. # set dialog min size
  763. self.SetMinSize(self.GetSize())
  764. def _createDialogBody(self):
  765. bodySizer = wx.BoxSizer(wx.VERTICAL)
  766. # group selection
  767. bodySizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
  768. label = _("Select the group you want to edit or "
  769. "enter name of new group:")),
  770. flag = wx.ALIGN_CENTER_VERTICAL | wx.TOP, border = 10)
  771. self.groupSelect = Select(parent = self, type = 'group',
  772. mapsets = [grass.gisenv()['MAPSET']],
  773. size = globalvar.DIALOG_GSELECT_SIZE) # searchpath?
  774. bodySizer.Add(item = self.groupSelect, flag = wx.TOP | wx.EXPAND, border = 5)
  775. bodySizer.AddSpacer(10)
  776. # layers in group
  777. bodySizer.Add(item = wx.StaticText(parent = self, label = _("Raster maps in selected group:")),
  778. flag = wx.ALIGN_CENTER_VERTICAL | wx.BOTTOM, border = 5)
  779. buttonSizer = wx.BoxSizer(wx.VERTICAL)
  780. listSizer = wx.BoxSizer(wx.HORIZONTAL)
  781. self.layerBox = wx.ListBox(parent = self, id = wx.ID_ANY, size = (-1, 150),
  782. style = wx.LB_MULTIPLE | wx.LB_NEEDED_SB)
  783. listSizer.Add(item = self.layerBox, proportion = 1, flag = wx.EXPAND)
  784. self.addLayer = wx.Button(self, id = wx.ID_ADD)
  785. self.addLayer.SetToolTipString(_("Select map layers and add them to the list."))
  786. buttonSizer.Add(item = self.addLayer, flag = wx.BOTTOM, border = 10)
  787. self.removeLayer = wx.Button(self, id = wx.ID_REMOVE)
  788. self.removeLayer.SetToolTipString(_("Remove selected layer(s) from list."))
  789. buttonSizer.Add(item = self.removeLayer)
  790. listSizer.Add(item = buttonSizer, flag = wx.LEFT, border = 5)
  791. bodySizer.Add(item = listSizer, proportion = 1, flag = wx.EXPAND)
  792. self.infoLabel = wx.StaticText(parent = self, id = wx.ID_ANY)
  793. bodySizer.Add(item = self.infoLabel,
  794. flag = wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.BOTTOM, border = 5)
  795. self.subGroup = wx.CheckBox(parent = self, id = wx.ID_ANY,
  796. label = _("Define also sub-group (same name as group)"))
  797. self.subGroup.SetValue(True) # most of imagery modules requires also subgroup
  798. bodySizer.Add(item = self.subGroup, flag = wx.BOTTOM | wx.EXPAND, border = 5)
  799. # bindings
  800. self.groupSelect.GetTextCtrl().Bind(wx.EVT_TEXT, self.OnGroupSelected)
  801. self.addLayer.Bind(wx.EVT_BUTTON, self.OnAddLayer)
  802. self.removeLayer.Bind(wx.EVT_BUTTON, self.OnRemoveLayer)
  803. if self.defaultGroup:
  804. self.groupSelect.SetValue(self.defaultGroup)
  805. return bodySizer
  806. def OnAddLayer(self, event):
  807. """!Add new layer to listbox"""
  808. dlg = MapLayersDialogForGroups(parent = self, title = _("Add selected map layers into group"))
  809. if dlg.ShowModal() != wx.ID_OK:
  810. dlg.Destroy()
  811. return
  812. layers = dlg.GetMapLayers()
  813. for layer in layers:
  814. if layer not in self.GetLayers():
  815. self.layerBox.Append(layer)
  816. self.groupChanged = True
  817. def OnRemoveLayer(self, event):
  818. """!Remove layer from listbox"""
  819. while self.layerBox.GetSelections():
  820. sel = self.layerBox.GetSelections()[0]
  821. self.layerBox.Delete(sel)
  822. self.groupChanged = True
  823. def GetLayers(self):
  824. """!Get layers"""
  825. return self.layerBox.GetItems()
  826. def OnGroupSelected(self, event):
  827. """!Text changed in group selector"""
  828. # callAfter must be called to close popup before other actions
  829. wx.CallAfter(self.GroupSelected)
  830. def GroupSelected(self):
  831. """!Group was selected, check if changes were apllied"""
  832. group = self.GetSelectedGroup()
  833. if self.currentGroup and self.groupChanged:
  834. dlg = wx.MessageDialog(self, message = _("Group <%s> was changed, "
  835. "do you want to apply changes?") % self.currentGroup,
  836. caption = _("Unapplied changes"),
  837. style = wx.YES_NO | wx.ICON_QUESTION | wx.YES_DEFAULT)
  838. if dlg.ShowModal() == wx.ID_YES:
  839. self.ApplyChanges()
  840. dlg.Destroy()
  841. maps = list()
  842. groups = self.GetExistGroups()
  843. if group in groups:
  844. maps = self.GetGroupLayers(group)
  845. self.ShowGroupLayers(maps)
  846. self.currentGroup = group
  847. self.groupChanged = False
  848. self.ClearNotification()
  849. def ShowGroupLayers(self, mapList):
  850. """!Show map layers in currently selected group"""
  851. self.layerBox.Set(mapList)
  852. def EditGroup(self, group):
  853. """!Edit selected group"""
  854. layersNew = self.GetLayers()
  855. layersOld = self.GetGroupLayers(group)
  856. add = []
  857. remove = []
  858. for layerNew in layersNew:
  859. if layerNew not in layersOld:
  860. add.append(layerNew)
  861. for layerOld in layersOld:
  862. if layerOld not in layersNew:
  863. remove.append(layerOld)
  864. kwargs = {}
  865. if self.subGroup.IsChecked():
  866. kwargs['subgroup'] = group
  867. ret = None
  868. if remove:
  869. ret = RunCommand('i.group',
  870. parent = self,
  871. group = group,
  872. flags = 'r',
  873. input = ','.join(remove),
  874. **kwargs)
  875. if add:
  876. ret = RunCommand('i.group',
  877. parent = self,
  878. group = group,
  879. input = ','.join(add),
  880. **kwargs)
  881. return ret
  882. def CreateNewGroup(self, group):
  883. """!Create new group"""
  884. layers = self.GetLayers()
  885. if not layers:
  886. GMessage(parent = self,
  887. message = _("No raster maps selected."))
  888. return 1
  889. kwargs = {}
  890. if self.subGroup.IsChecked():
  891. kwargs['subgroup'] = group
  892. return RunCommand('i.group',
  893. parent = self,
  894. group = group,
  895. input = layers,
  896. **kwargs)
  897. def GetExistGroups(self):
  898. """!Returns existing groups in current mapset"""
  899. return grass.list_grouped('group')[grass.gisenv()['MAPSET']]
  900. def ShowResult(self, group, returnCode, create):
  901. """!Show if operation was successfull."""
  902. group += '@' + grass.gisenv()['MAPSET']
  903. if returnCode is None:
  904. label = _("No changes to apply in group <%s>.") % group
  905. elif returnCode == 0:
  906. if create:
  907. label = _("Group <%s> was successfully created.") % group
  908. else:
  909. label = _("Group <%s> was successfully changed.") % group
  910. else:
  911. if create:
  912. label = _("Creating of new group <%s> failed.") % group
  913. else:
  914. label = _("Changing of group <%s> failed.") % group
  915. self.infoLabel.SetLabel(label)
  916. wx.FutureCall(4000, self.ClearNotification)
  917. def GetSelectedGroup(self):
  918. """!Return currently selected group (without mapset)"""
  919. return self.groupSelect.GetValue().split('@')[0]
  920. def GetGroupLayers(self, group):
  921. """!Get layers in group"""
  922. kwargs = dict()
  923. kwargs['group'] = group
  924. if self.subGroup.IsChecked():
  925. kwargs['subgroup'] = group
  926. res = RunCommand('i.group',
  927. parent = self,
  928. flags = 'g',
  929. read = True, **kwargs)
  930. if not res:
  931. return []
  932. return res.splitlines()
  933. def ClearNotification(self):
  934. """!Clear notification string"""
  935. self.infoLabel.SetLabel("")
  936. def ApplyChanges(self):
  937. """!Create or edit group"""
  938. group = self.currentGroup
  939. if not group:
  940. GMessage(parent = self,
  941. message = _("No group selected."))
  942. return False
  943. groups = self.GetExistGroups()
  944. if group in groups:
  945. ret = self.EditGroup(group)
  946. self.ShowResult(group = group, returnCode = ret, create = False)
  947. else:
  948. ret = self.CreateNewGroup(group)
  949. self.ShowResult(group = group, returnCode = ret, create = True)
  950. self.groupChanged = False
  951. return True
  952. def OnApply(self, event):
  953. """!Apply changes"""
  954. self.ApplyChanges()
  955. def OnOk(self, event):
  956. """!Apply changes and close dialog"""
  957. if self.ApplyChanges():
  958. self.OnClose(event)
  959. def OnClose(self, event):
  960. """!Close dialog"""
  961. if not self.IsModal():
  962. self.Destroy()
  963. event.Skip()
  964. class MapLayersDialogBase(wx.Dialog):
  965. """!Base dialog for selecting map layers (raster, vector).
  966. There are 3 subclasses: MapLayersDialogForGroups, MapLayersDialogForModeler,
  967. MapLayersDialog. Base class contains core functionality.
  968. """
  969. def __init__(self, parent, title,
  970. style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
  971. wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title,
  972. style = style, **kwargs)
  973. self.parent = parent # GMFrame or ?
  974. self.mainSizer = wx.BoxSizer(wx.VERTICAL)
  975. # dialog body
  976. self.bodySizer = self._createDialogBody()
  977. self.mainSizer.Add(item = self.bodySizer, proportion = 1,
  978. flag = wx.EXPAND | wx.ALL, border = 5)
  979. # update list of layer to be loaded
  980. self.map_layers = [] # list of map layers (full list type/mapset)
  981. self.LoadMapLayers(self.GetLayerType(cmd = True),
  982. self.mapset.GetStringSelection())
  983. self._fullyQualifiedNames()
  984. self._modelerDSeries()
  985. # buttons
  986. btnCancel = wx.Button(parent = self, id = wx.ID_CANCEL)
  987. btnOk = wx.Button(parent = self, id = wx.ID_OK)
  988. btnOk.SetDefault()
  989. # sizers & do layout
  990. self.btnSizer = wx.StdDialogButtonSizer()
  991. self.btnSizer.AddButton(btnCancel)
  992. self.btnSizer.AddButton(btnOk)
  993. self._addApplyButton()
  994. self.btnSizer.Realize()
  995. self.mainSizer.Add(item = self.btnSizer, proportion = 0,
  996. flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
  997. self.SetSizer(self.mainSizer)
  998. self.mainSizer.Fit(self)
  999. # set dialog min size
  1000. self.SetMinSize(self.GetSize())
  1001. def _modelerDSeries(self):
  1002. """!Method used only by MapLayersDialogForModeler,
  1003. for other subclasses does nothing.
  1004. """
  1005. pass
  1006. def _addApplyButton(self):
  1007. """!Method used only by MapLayersDialog,
  1008. for other subclasses does nothing.
  1009. """
  1010. pass
  1011. def _fullyQualifiedNames(self):
  1012. """!Adds CheckBox which determines is fully qualified names are retuned.
  1013. """
  1014. self.fullyQualified = wx.CheckBox(parent = self, id = wx.ID_ANY,
  1015. label = _("Use fully-qualified map names"))
  1016. self.fullyQualified.SetValue(True)
  1017. self.mainSizer.Add(item = self.fullyQualified, proportion = 0,
  1018. flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 5)
  1019. def _useFullyQualifiedNames(self):
  1020. return self.fullyQualified.IsChecked()
  1021. def _layerTypes(self):
  1022. """!Determines which layer types can be chosen.
  1023. Valid values:
  1024. - raster
  1025. - raster3d
  1026. - vector
  1027. """
  1028. return [_('raster'), _('3D raster'), _('vector')]
  1029. def _selectAll(self):
  1030. """!Check all layers by default"""
  1031. return True
  1032. def _createDialogBody(self):
  1033. bodySizer = wx.GridBagSizer(vgap = 3, hgap = 3)
  1034. bodySizer.AddGrowableCol(1)
  1035. bodySizer.AddGrowableRow(3)
  1036. # layer type
  1037. bodySizer.Add(item = wx.StaticText(parent = self, label = _("Map type:")),
  1038. flag = wx.ALIGN_CENTER_VERTICAL,
  1039. pos = (0,0))
  1040. self.layerType = wx.Choice(parent = self, id = wx.ID_ANY,
  1041. choices = self._layerTypes(), size = (100,-1))
  1042. self.layerType.SetSelection(0)
  1043. bodySizer.Add(item = self.layerType,
  1044. pos = (0,1))
  1045. self.layerType.Bind(wx.EVT_CHOICE, self.OnChangeParams)
  1046. # select toggle
  1047. self.toggle = wx.CheckBox(parent = self, id = wx.ID_ANY,
  1048. label = _("Select toggle"))
  1049. self.toggle.SetValue(self._selectAll())
  1050. bodySizer.Add(item = self.toggle,
  1051. flag = wx.ALIGN_CENTER_VERTICAL,
  1052. pos = (0,2))
  1053. # mapset filter
  1054. bodySizer.Add(item = wx.StaticText(parent = self, label = _("Mapset:")),
  1055. flag = wx.ALIGN_CENTER_VERTICAL,
  1056. pos = (1,0))
  1057. self.mapset = MapsetSelect(parent = self, searchPath = True)
  1058. self.mapset.SetStringSelection(grass.gisenv()['MAPSET'])
  1059. bodySizer.Add(item = self.mapset,
  1060. pos = (1,1), span = (1, 2))
  1061. # map name filter
  1062. bodySizer.Add(item = wx.StaticText(parent = self, label = _("Pattern:")),
  1063. flag = wx.ALIGN_CENTER_VERTICAL,
  1064. pos = (2,0))
  1065. self.filter = wx.TextCtrl(parent = self, id = wx.ID_ANY,
  1066. value = "",
  1067. size = (250,-1))
  1068. bodySizer.Add(item = self.filter,
  1069. flag = wx.EXPAND,
  1070. pos = (2,1), span = (1, 2))
  1071. self.filter.SetFocus()
  1072. self.filter.SetToolTipString(_("Put here a regular expression."
  1073. " Characters '.*' stand for anything,"
  1074. " character '^' stands for the beginning"
  1075. " and '$' for the end."))
  1076. # layer list
  1077. bodySizer.Add(item = wx.StaticText(parent = self, label = _("List of maps:")),
  1078. flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_TOP,
  1079. pos = (3,0))
  1080. self.layers = wx.CheckListBox(parent = self, id = wx.ID_ANY,
  1081. size = (250, 100),
  1082. choices = [])
  1083. bodySizer.Add(item = self.layers,
  1084. flag = wx.EXPAND,
  1085. pos = (3,1), span = (1, 2))
  1086. # bindings
  1087. self.mapset.Bind(wx.EVT_COMBOBOX, self.OnChangeParams)
  1088. self.layers.Bind(wx.EVT_RIGHT_DOWN, self.OnMenu)
  1089. self.filter.Bind(wx.EVT_TEXT, self.OnFilter)
  1090. self.toggle.Bind(wx.EVT_CHECKBOX, self.OnToggle)
  1091. return bodySizer
  1092. def LoadMapLayers(self, type, mapset):
  1093. """!Load list of map layers
  1094. @param type layer type ('raster' or 'vector')
  1095. @param mapset mapset name
  1096. """
  1097. self.map_layers = grass.mlist_grouped(type = type)[mapset]
  1098. self.layers.Set(self.map_layers)
  1099. # check all items by default
  1100. for item in range(self.layers.GetCount()):
  1101. self.layers.Check(item, check = self._selectAll())
  1102. def OnChangeParams(self, event):
  1103. """!Filter parameters changed by user"""
  1104. # update list of layer to be loaded
  1105. self.LoadMapLayers(self.GetLayerType(cmd = True),
  1106. self.mapset.GetStringSelection())
  1107. event.Skip()
  1108. def OnMenu(self, event):
  1109. """!Table description area, context menu"""
  1110. if not hasattr(self, "popupID1"):
  1111. self.popupDataID1 = wx.NewId()
  1112. self.popupDataID2 = wx.NewId()
  1113. self.popupDataID3 = wx.NewId()
  1114. self.Bind(wx.EVT_MENU, self.OnSelectAll, id = self.popupDataID1)
  1115. self.Bind(wx.EVT_MENU, self.OnSelectInvert, id = self.popupDataID2)
  1116. self.Bind(wx.EVT_MENU, self.OnDeselectAll, id = self.popupDataID3)
  1117. # generate popup-menu
  1118. menu = wx.Menu()
  1119. menu.Append(self.popupDataID1, _("Select all"))
  1120. menu.Append(self.popupDataID2, _("Invert selection"))
  1121. menu.Append(self.popupDataID3, _("Deselect all"))
  1122. self.PopupMenu(menu)
  1123. menu.Destroy()
  1124. def OnSelectAll(self, event):
  1125. """!Select all map layer from list"""
  1126. for item in range(self.layers.GetCount()):
  1127. self.layers.Check(item, True)
  1128. def OnSelectInvert(self, event):
  1129. """!Invert current selection"""
  1130. for item in range(self.layers.GetCount()):
  1131. if self.layers.IsChecked(item):
  1132. self.layers.Check(item, False)
  1133. else:
  1134. self.layers.Check(item, True)
  1135. def OnDeselectAll(self, event):
  1136. """!Select all map layer from list"""
  1137. for item in range(self.layers.GetCount()):
  1138. self.layers.Check(item, False)
  1139. def OnFilter(self, event):
  1140. """!Apply filter for map names"""
  1141. if len(event.GetString()) == 0:
  1142. self.layers.Set(self.map_layers)
  1143. return
  1144. list = []
  1145. for layer in self.map_layers:
  1146. try:
  1147. if re.compile(event.GetString()).search(layer):
  1148. list.append(layer)
  1149. except:
  1150. pass
  1151. self.layers.Set(list)
  1152. self.OnSelectAll(None)
  1153. event.Skip()
  1154. def OnToggle(self, event):
  1155. """!Select toggle (check or uncheck all layers)"""
  1156. check = event.Checked()
  1157. for item in range(self.layers.GetCount()):
  1158. self.layers.Check(item, check)
  1159. event.Skip()
  1160. def GetMapLayers(self):
  1161. """!Return list of checked map layers"""
  1162. layerNames = []
  1163. for indx in self.layers.GetSelections():
  1164. # layers.append(self.layers.GetStringSelec(indx))
  1165. pass
  1166. mapset = self.mapset.GetStringSelection()
  1167. for item in range(self.layers.GetCount()):
  1168. if not self.layers.IsChecked(item):
  1169. continue
  1170. if self._useFullyQualifiedNames():
  1171. layerNames.append(self.layers.GetString(item) + '@' + mapset)
  1172. else:
  1173. layerNames.append(self.layers.GetString(item))
  1174. return layerNames
  1175. def GetLayerType(self, cmd = False):
  1176. """!Get selected layer type
  1177. @param cmd True for g.mlist
  1178. """
  1179. if not cmd:
  1180. return self.layerType.GetStringSelection()
  1181. sel = self.layerType.GetSelection()
  1182. if sel == 0:
  1183. ltype = 'rast'
  1184. elif sel == 1:
  1185. ltype = 'rast3d'
  1186. else:
  1187. ltype = 'vect'
  1188. return ltype
  1189. class MapLayersDialog(MapLayersDialogBase):
  1190. """!Subclass of MapLayersDialogBase used in Layer Manager.
  1191. Contains apply button, which sends wxApplyMapLayers event.
  1192. """
  1193. def __init__(self, parent, title, **kwargs):
  1194. MapLayersDialogBase.__init__(self, parent = parent, title = title, **kwargs)
  1195. def _addApplyButton(self):
  1196. btnApply = wx.Button(parent = self, id = wx.ID_APPLY)
  1197. self.btnSizer.AddButton(btnApply)
  1198. btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  1199. def OnApply(self, event):
  1200. event = wxApplyMapLayers(mapLayers = self.GetMapLayers(), ltype = self.GetLayerType(cmd = True))
  1201. wx.PostEvent(self, event)
  1202. class MapLayersDialogForGroups(MapLayersDialogBase):
  1203. """!Subclass of MapLayersDialogBase used for specyfying maps in an imagery group.
  1204. Shows only raster maps.
  1205. """
  1206. def __init__(self, parent, title, **kwargs):
  1207. MapLayersDialogBase.__init__(self, parent = parent, title = title, **kwargs)
  1208. def _layerTypes(self):
  1209. return [_('raster'),]
  1210. def _selectAll(self):
  1211. """!Could be overriden"""
  1212. return False
  1213. def _fullyQualifiedNames(self):
  1214. pass
  1215. def _useFullyQualifiedNames(self):
  1216. return True
  1217. class MapLayersDialogForModeler(MapLayersDialogBase):
  1218. """!Subclass of MapLayersDialogBase used in Modeler.
  1219. """
  1220. def __init__(self, parent, title, **kwargs):
  1221. MapLayersDialogBase.__init__(self, parent = parent, title = title, **kwargs)
  1222. def _modelerDSeries(self):
  1223. self.dseries = wx.CheckBox(parent = self, id = wx.ID_ANY,
  1224. label = _("Dynamic series (%s)") % 'g.mlist')
  1225. self.dseries.SetValue(False)
  1226. self.mainSizer.Add(item = self.dseries, proportion = 0,
  1227. flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 5)
  1228. def GetDSeries(self):
  1229. """!Used by modeler only
  1230. @return g.mlist command
  1231. """
  1232. if not self.dseries or not self.dseries.IsChecked():
  1233. return ''
  1234. cond = 'map in `g.mlist type=%s ' % self.GetLayerType(cmd = True)
  1235. patt = self.filter.GetValue()
  1236. if patt:
  1237. cond += 'pattern=%s ' % patt
  1238. cond += 'mapset=%s`' % self.mapset.GetStringSelection()
  1239. return cond
  1240. class ImportDialog(wx.Dialog):
  1241. """!Dialog for bulk import of various data (base class)"""
  1242. def __init__(self, parent, itype,
  1243. id = wx.ID_ANY, title = _("Multiple import"),
  1244. style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
  1245. self.parent = parent # GMFrame
  1246. self.importType = itype
  1247. self.options = dict() # list of options
  1248. self.commandId = -1 # id of running command
  1249. wx.Dialog.__init__(self, parent, id, title, style = style,
  1250. name = "MultiImportDialog")
  1251. self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
  1252. self.layerBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY)
  1253. if self.importType == 'gdal':
  1254. label = _("List of raster layers")
  1255. elif self.importType == 'ogr':
  1256. label = _("List of vector layers")
  1257. else:
  1258. label = _("List of %s layers") % self.importType.upper()
  1259. self.layerBox.SetLabel(" %s - %s " % (label, _("right click to (un)select all")))
  1260. # list of layers
  1261. columns = [_('Layer id'),
  1262. _('Layer name'),
  1263. _('Name for output GRASS map (editable)')]
  1264. if itype == 'ogr':
  1265. columns.insert(2, _('Feature type'))
  1266. columns.insert(3, _('Projection match'))
  1267. self.list = LayersList(parent = self.panel, columns = columns)
  1268. self.list.LoadData()
  1269. self.optionBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
  1270. label = "%s" % _("Options"))
  1271. cmd = self._getCommand()
  1272. task = gtask.parse_interface(cmd)
  1273. for f in task.get_options()['flags']:
  1274. name = f.get('name', '')
  1275. desc = f.get('label', '')
  1276. if not desc:
  1277. desc = f.get('description', '')
  1278. if not name and not desc:
  1279. continue
  1280. if cmd == 'r.in.gdal' and name not in ('o', 'e', 'l', 'k'):
  1281. continue
  1282. elif cmd == 'r.external' and name not in ('o', 'e', 'r', 'h', 'v'):
  1283. continue
  1284. elif cmd == 'v.in.ogr' and name not in ('c', 'z', 't', 'o', 'r', 'e', 'w'):
  1285. continue
  1286. elif cmd == 'v.external' and name not in ('b'):
  1287. continue
  1288. elif cmd == 'v.in.dxf' and name not in ('e', 't', 'b', 'f', 'i'):
  1289. continue
  1290. self.options[name] = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
  1291. label = desc)
  1292. self.overwrite = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
  1293. label = _("Allow output files to overwrite existing files"))
  1294. self.overwrite.SetValue(UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'))
  1295. self.add = wx.CheckBox(parent = self.panel, id = wx.ID_ANY)
  1296. self.closeOnFinish = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
  1297. label = _("Close dialog on finish"))
  1298. self.closeOnFinish.SetValue(UserSettings.Get(group = 'cmd', key = 'closeDlg', subkey = 'enabled'))
  1299. #
  1300. # buttons
  1301. #
  1302. # cancel
  1303. self.btn_close = wx.Button(parent = self.panel, id = wx.ID_CLOSE)
  1304. self.btn_close.SetToolTipString(_("Close dialog"))
  1305. self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
  1306. # run
  1307. self.btn_run = wx.Button(parent = self.panel, id = wx.ID_OK, label = _("&Import"))
  1308. self.btn_run.SetToolTipString(_("Import selected layers"))
  1309. self.btn_run.SetDefault()
  1310. self.btn_run.Enable(False)
  1311. self.btn_run.Bind(wx.EVT_BUTTON, self.OnRun)
  1312. def doLayout(self):
  1313. """!Do layout"""
  1314. dialogSizer = wx.BoxSizer(wx.VERTICAL)
  1315. # dsn input
  1316. dialogSizer.Add(item = self.dsnInput, proportion = 0,
  1317. flag = wx.EXPAND)
  1318. #
  1319. # list of DXF layers
  1320. #
  1321. layerSizer = wx.StaticBoxSizer(self.layerBox, wx.HORIZONTAL)
  1322. layerSizer.Add(item = self.list, proportion = 1,
  1323. flag = wx.ALL | wx.EXPAND, border = 5)
  1324. dialogSizer.Add(item = layerSizer, proportion = 1,
  1325. flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
  1326. # options
  1327. optionSizer = wx.StaticBoxSizer(self.optionBox, wx.VERTICAL)
  1328. for key in self.options.keys():
  1329. optionSizer.Add(item = self.options[key], proportion = 0)
  1330. dialogSizer.Add(item = optionSizer, proportion = 0,
  1331. flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
  1332. dialogSizer.Add(item = self.overwrite, proportion = 0,
  1333. flag = wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
  1334. dialogSizer.Add(item = self.add, proportion = 0,
  1335. flag = wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
  1336. dialogSizer.Add(item = self.closeOnFinish, proportion = 0,
  1337. flag = wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
  1338. #
  1339. # buttons
  1340. #
  1341. btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
  1342. btnsizer.Add(item = self.btn_close, proportion = 0,
  1343. flag = wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER,
  1344. border = 10)
  1345. btnsizer.Add(item = self.btn_run, proportion = 0,
  1346. flag = wx.RIGHT | wx.ALIGN_CENTER,
  1347. border = 10)
  1348. dialogSizer.Add(item = btnsizer, proportion = 0,
  1349. flag = wx.ALIGN_CENTER_VERTICAL | wx.BOTTOM | wx.ALIGN_RIGHT,
  1350. border = 10)
  1351. # dialogSizer.SetSizeHints(self.panel)
  1352. self.panel.SetAutoLayout(True)
  1353. self.panel.SetSizer(dialogSizer)
  1354. dialogSizer.Fit(self.panel)
  1355. # auto-layout seems not work here - FIXME
  1356. size = wx.Size(globalvar.DIALOG_GSELECT_SIZE[0] + 225, 550)
  1357. self.SetMinSize(size)
  1358. self.SetSize((size.width, size.height + 100))
  1359. # width = self.GetSize()[0]
  1360. # self.list.SetColumnWidth(col = 1, width = width / 2 - 50)
  1361. self.Layout()
  1362. def _getCommand(self):
  1363. """!Get command"""
  1364. return ''
  1365. def OnClose(self, event = None):
  1366. """!Close dialog"""
  1367. self.Close()
  1368. def OnRun(self, event):
  1369. """!Import/Link data (each layes as separate vector map)"""
  1370. pass
  1371. def AddLayers(self, returncode, cmd = None):
  1372. """!Add imported/linked layers into layer tree"""
  1373. if not self.add.IsChecked() or returncode != 0:
  1374. return
  1375. self.commandId += 1
  1376. maptree = self.parent.GetLayerTree()
  1377. layer, output = self.list.GetLayers()[self.commandId]
  1378. if '@' not in output:
  1379. name = output + '@' + grass.gisenv()['MAPSET']
  1380. else:
  1381. name = output
  1382. # add imported layers into layer tree
  1383. if self.importType == 'gdal':
  1384. cmd = ['d.rast',
  1385. 'map=%s' % name]
  1386. if UserSettings.Get(group = 'rasterLayer', key = 'opaque', subkey = 'enabled'):
  1387. cmd.append('-n')
  1388. item = maptree.AddLayer(ltype = 'raster',
  1389. lname = name, lchecked = False,
  1390. lcmd = cmd, multiple = False)
  1391. else:
  1392. item = maptree.AddLayer(ltype = 'vector',
  1393. lname = name, lchecked = False,
  1394. lcmd = ['d.vect',
  1395. 'map=%s' % name] + GetDisplayVectSettings(),
  1396. multiple = False)
  1397. maptree.mapdisplay.MapWindow.ZoomToMap()
  1398. def OnAbort(self, event):
  1399. """!Abort running import
  1400. @todo not yet implemented
  1401. """
  1402. pass
  1403. class GdalImportDialog(ImportDialog):
  1404. def __init__(self, parent, giface, ogr = False, link = False):
  1405. """!Dialog for bulk import of various raster/vector data
  1406. @todo Split into GdalImportDialog and OgrImportDialog
  1407. @param parent parent window
  1408. @param ogr True for OGR (vector) otherwise GDAL (raster)
  1409. @param link True for linking data otherwise importing data
  1410. """
  1411. self._giface = giface
  1412. self.link = link
  1413. self.ogr = ogr
  1414. if ogr:
  1415. ImportDialog.__init__(self, parent, itype = 'ogr')
  1416. if link:
  1417. self.SetTitle(_("Link external vector data"))
  1418. else:
  1419. self.SetTitle(_("Import vector data"))
  1420. else:
  1421. ImportDialog.__init__(self, parent, itype = 'gdal')
  1422. if link:
  1423. self.SetTitle(_("Link external raster data"))
  1424. else:
  1425. self.SetTitle(_("Import raster data"))
  1426. self.dsnInput = GdalSelect(parent = self, panel = self.panel,
  1427. ogr = ogr, link = link)
  1428. if link:
  1429. self.add.SetLabel(_("Add linked layers into layer tree"))
  1430. else:
  1431. self.add.SetLabel(_("Add imported layers into layer tree"))
  1432. self.add.SetValue(UserSettings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
  1433. if link:
  1434. self.btn_run.SetLabel(_("&Link"))
  1435. self.btn_run.SetToolTipString(_("Link selected layers"))
  1436. else:
  1437. self.btn_run.SetLabel(_("&Import"))
  1438. self.btn_run.SetToolTipString(_("Import selected layers"))
  1439. self.doLayout()
  1440. def OnRun(self, event):
  1441. """!Import/Link data (each layes as separate vector map)"""
  1442. self.commandId = -1
  1443. data = self.list.GetLayers()
  1444. if not data:
  1445. GMessage(_("No layers selected. Operation canceled."),
  1446. parent = self)
  1447. return
  1448. dsn = self.dsnInput.GetDsn()
  1449. ext = self.dsnInput.GetFormatExt()
  1450. # determine data driver for PostGIS links
  1451. popOGR = False
  1452. if self.importType == 'ogr' and \
  1453. self.dsnInput.GetType() == 'db' and \
  1454. self.dsnInput.GetFormat() == 'PostgreSQL' and \
  1455. 'GRASS_VECTOR_OGR' not in os.environ:
  1456. popOGR = True
  1457. os.environ['GRASS_VECTOR_OGR'] = '1'
  1458. for layer, output in data:
  1459. if self.importType == 'ogr':
  1460. if ext and layer.rfind(ext) > -1:
  1461. layer = layer.replace('.' + ext, '')
  1462. if self.link:
  1463. cmd = ['v.external',
  1464. 'dsn=%s' % dsn,
  1465. 'output=%s' % output,
  1466. 'layer=%s' % layer]
  1467. else:
  1468. cmd = ['v.in.ogr',
  1469. 'dsn=%s' % dsn,
  1470. 'layer=%s' % layer,
  1471. 'output=%s' % output]
  1472. else: # gdal
  1473. if self.dsnInput.GetType() == 'dir':
  1474. idsn = os.path.join(dsn, layer)
  1475. else:
  1476. idsn = dsn
  1477. if self.link:
  1478. cmd = ['r.external',
  1479. 'input=%s' % idsn,
  1480. 'output=%s' % output]
  1481. else:
  1482. cmd = ['r.in.gdal',
  1483. 'input=%s' % idsn,
  1484. 'output=%s' % output]
  1485. if self.overwrite.IsChecked():
  1486. cmd.append('--overwrite')
  1487. for key in self.options.keys():
  1488. if self.options[key].IsChecked():
  1489. cmd.append('-%s' % key)
  1490. if UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled') and \
  1491. '--overwrite' not in cmd:
  1492. cmd.append('--overwrite')
  1493. # run in Layer Manager
  1494. self._giface.RunCmd(cmd, switchPage = True, onDone = self.AddLayers)
  1495. if popOGR:
  1496. os.environ.pop('GRASS_VECTOR_OGR')
  1497. if self.closeOnFinish.IsChecked():
  1498. self.Close()
  1499. def _getCommand(self):
  1500. """!Get command"""
  1501. if self.link:
  1502. if self.ogr:
  1503. return 'v.external'
  1504. else:
  1505. return 'r.external'
  1506. else:
  1507. if self.ogr:
  1508. return 'v.in.ogr'
  1509. else:
  1510. return 'r.in.gdal'
  1511. return ''
  1512. class GdalOutputDialog(wx.Dialog):
  1513. def __init__(self, parent, id = wx.ID_ANY, ogr = False,
  1514. style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, *kwargs):
  1515. """!Dialog for setting output format for rasters/vectors
  1516. @todo Split into GdalOutputDialog and OgrOutputDialog
  1517. @param parent parent window
  1518. @param id window id
  1519. @param ogr True for OGR (vector) otherwise GDAL (raster)
  1520. @param style window style
  1521. @param *kwargs other wx.Dialog's arguments
  1522. """
  1523. self.parent = parent # GMFrame
  1524. self.ogr = ogr
  1525. wx.Dialog.__init__(self, parent, id = id, style = style, *kwargs)
  1526. if self.ogr:
  1527. self.SetTitle(_("Define output format for vector data"))
  1528. else:
  1529. self.SetTitle(_("Define output format for raster data"))
  1530. self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
  1531. # buttons
  1532. self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
  1533. self.btnCancel.SetToolTipString(_("Close dialog"))
  1534. self.btnOk = wx.Button(parent = self.panel, id = wx.ID_OK)
  1535. self.btnOk.SetToolTipString(_("Set external format and close dialog"))
  1536. self.btnOk.SetDefault()
  1537. self.btnOk.Enable(False)
  1538. self.dsnInput = GdalSelect(parent = self, panel = self.panel,
  1539. ogr = ogr,
  1540. exclude = ['file', 'protocol'], dest = True)
  1541. self.Bind(wx.EVT_BUTTON, self.OnCancel, self.btnCancel)
  1542. self.Bind(wx.EVT_BUTTON, self.OnOK, self.btnOk)
  1543. self._layout()
  1544. def _layout(self):
  1545. dialogSizer = wx.BoxSizer(wx.VERTICAL)
  1546. dialogSizer.Add(item = self.dsnInput, proportion = 0,
  1547. flag = wx.EXPAND)
  1548. btnSizer = wx.BoxSizer(orient = wx.HORIZONTAL)
  1549. btnSizer.Add(item = self.btnCancel, proportion = 0,
  1550. flag = wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER,
  1551. border = 10)
  1552. btnSizer.Add(item = self.btnOk, proportion = 0,
  1553. flag = wx.RIGHT | wx.ALIGN_CENTER,
  1554. border = 10)
  1555. dialogSizer.Add(item = btnSizer, proportion = 0,
  1556. flag = wx.ALIGN_CENTER_VERTICAL | wx.BOTTOM | wx.TOP | wx.ALIGN_RIGHT,
  1557. border = 10)
  1558. self.panel.SetAutoLayout(True)
  1559. self.panel.SetSizer(dialogSizer)
  1560. dialogSizer.Fit(self.panel)
  1561. size = wx.Size(globalvar.DIALOG_GSELECT_SIZE[0] + 225, self.GetBestSize()[1])
  1562. self.SetMinSize(size)
  1563. self.SetSize((size.width, size.height))
  1564. self.Layout()
  1565. def OnCancel(self, event):
  1566. self.Destroy()
  1567. def OnOK(self, event):
  1568. if self.dsnInput.GetType() == 'native':
  1569. RunCommand('v.external.out',
  1570. parent = self,
  1571. flags = 'r')
  1572. else:
  1573. dsn = self.dsnInput.GetDsn()
  1574. frmt = self.dsnInput.GetFormat()
  1575. options = self.dsnInput.GetOptions()
  1576. RunCommand('v.external.out',
  1577. parent = self,
  1578. dsn = dsn, format = frmt,
  1579. options = options)
  1580. self.Close()
  1581. class DxfImportDialog(ImportDialog):
  1582. """!Dialog for bulk import of DXF layers"""
  1583. def __init__(self, parent, giface):
  1584. ImportDialog.__init__(self, parent, itype = 'dxf',
  1585. title = _("Import DXF layers"))
  1586. self._giface = giface
  1587. self.dsnInput = filebrowse.FileBrowseButton(parent = self.panel, id = wx.ID_ANY,
  1588. size = globalvar.DIALOG_GSELECT_SIZE, labelText = '',
  1589. dialogTitle = _('Choose DXF file to import'),
  1590. buttonText = _('Browse'),
  1591. startDirectory = os.getcwd(), fileMode = 0,
  1592. changeCallback = self.OnSetDsn,
  1593. fileMask = "DXF File (*.dxf)|*.dxf")
  1594. self.add.SetLabel(_("Add imported layers into layer tree"))
  1595. self.add.SetValue(UserSettings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
  1596. self.doLayout()
  1597. def _getCommand(self):
  1598. """!Get command"""
  1599. return 'v.in.dxf'
  1600. def OnRun(self, event):
  1601. """!Import/Link data (each layes as separate vector map)"""
  1602. data = self.list.GetLayers()
  1603. # hide dialog
  1604. self.Hide()
  1605. inputDxf = self.dsnInput.GetValue()
  1606. for layer, output in data:
  1607. cmd = ['v.in.dxf',
  1608. 'input=%s' % inputDxf,
  1609. 'layers=%s' % layer,
  1610. 'output=%s' % output]
  1611. for key in self.options.keys():
  1612. if self.options[key].IsChecked():
  1613. cmd.append('-%s' % key)
  1614. if self.overwrite.IsChecked() or \
  1615. UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'):
  1616. cmd.append('--overwrite')
  1617. # run in Layer Manager
  1618. self._giface.RunCmd(cmd, switchPage = True, onDone = self.AddLayers)
  1619. self.OnCancel()
  1620. def OnSetDsn(self, event):
  1621. """!Input DXF file defined, update list of layer widget"""
  1622. path = event.GetString()
  1623. if not path:
  1624. return
  1625. data = list()
  1626. ret = RunCommand('v.in.dxf',
  1627. quiet = True,
  1628. parent = self,
  1629. read = True,
  1630. flags = 'l',
  1631. input = path)
  1632. if not ret:
  1633. self.list.LoadData()
  1634. self.btn_run.Enable(False)
  1635. return
  1636. for line in ret.splitlines():
  1637. layerId = line.split(':')[0].split(' ')[1]
  1638. layerName = line.split(':')[1].strip()
  1639. grassName = GetValidLayerName(layerName)
  1640. data.append((layerId, layerName.strip(), grassName.strip()))
  1641. self.list.LoadData(data)
  1642. if len(data) > 0:
  1643. self.btn_run.Enable(True)
  1644. else:
  1645. self.btn_run.Enable(False)
  1646. class LayersList(GListCtrl, listmix.TextEditMixin):
  1647. """!List of layers to be imported (dxf, shp...)"""
  1648. def __init__(self, parent, columns, log = None):
  1649. GListCtrl.__init__(self, parent)
  1650. self.log = log
  1651. # setup mixins
  1652. listmix.TextEditMixin.__init__(self)
  1653. for i in range(len(columns)):
  1654. self.InsertColumn(i, columns[i])
  1655. if len(columns) == 3:
  1656. width = (65, 200)
  1657. else:
  1658. width = (65, 180, 90, 70)
  1659. for i in range(len(width)):
  1660. self.SetColumnWidth(col = i, width = width[i])
  1661. def LoadData(self, data = None):
  1662. """!Load data into list"""
  1663. self.DeleteAllItems()
  1664. if data is None:
  1665. return
  1666. for item in data:
  1667. index = self.InsertStringItem(sys.maxint, str(item[0]))
  1668. for i in range(1, len(item)):
  1669. self.SetStringItem(index, i, "%s" % str(item[i]))
  1670. # check by default only on one item
  1671. if len(data) == 1:
  1672. self.CheckItem(index, True)
  1673. def OnLeftDown(self, event):
  1674. """!Allow editing only output name
  1675. Code taken from TextEditMixin class.
  1676. """
  1677. x, y = event.GetPosition()
  1678. colLocs = [0]
  1679. loc = 0
  1680. for n in range(self.GetColumnCount()):
  1681. loc = loc + self.GetColumnWidth(n)
  1682. colLocs.append(loc)
  1683. col = bisect(colLocs, x + self.GetScrollPos(wx.HORIZONTAL)) - 1
  1684. if col == self.GetColumnCount() - 1:
  1685. listmix.TextEditMixin.OnLeftDown(self, event)
  1686. else:
  1687. event.Skip()
  1688. def GetLayers(self):
  1689. """!Get list of layers (layer name, output name)"""
  1690. data = []
  1691. item = -1
  1692. while True:
  1693. item = self.GetNextItem(item)
  1694. if item == -1:
  1695. break
  1696. if not self.IsChecked(item):
  1697. continue
  1698. # layer / output name
  1699. data.append((self.GetItem(item, 1).GetText(),
  1700. self.GetItem(item, self.GetColumnCount() - 1).GetText()))
  1701. return data
  1702. class SetOpacityDialog(wx.Dialog):
  1703. """!Set opacity of map layers"""
  1704. def __init__(self, parent, id = wx.ID_ANY, title = _("Set Map Layer Opacity"),
  1705. size = wx.DefaultSize, pos = wx.DefaultPosition,
  1706. style = wx.DEFAULT_DIALOG_STYLE, opacity = 100):
  1707. self.parent = parent # GMFrame
  1708. self.opacity = opacity # current opacity
  1709. super(SetOpacityDialog, self).__init__(parent, id = id, pos = pos,
  1710. size = size, style = style, title = title)
  1711. panel = wx.Panel(parent = self, id = wx.ID_ANY)
  1712. sizer = wx.BoxSizer(wx.VERTICAL)
  1713. box = wx.GridBagSizer(vgap = 5, hgap = 5)
  1714. self.value = wx.Slider(panel, id = wx.ID_ANY, value = self.opacity,
  1715. style = wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | \
  1716. wx.SL_TOP | wx.SL_LABELS,
  1717. minValue = 0, maxValue = 100,
  1718. size = (350, -1))
  1719. box.Add(item = self.value,
  1720. flag = wx.ALIGN_CENTRE, pos = (0, 0), span = (1, 2))
  1721. box.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
  1722. label = _("transparent")),
  1723. pos = (1, 0))
  1724. box.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
  1725. label = _("opaque")),
  1726. flag = wx.ALIGN_RIGHT,
  1727. pos = (1, 1))
  1728. sizer.Add(item = box, proportion = 0,
  1729. flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5)
  1730. line = wx.StaticLine(parent = panel, id = wx.ID_ANY,
  1731. style = wx.LI_HORIZONTAL)
  1732. sizer.Add(item = line, proportion = 0,
  1733. flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5)
  1734. # buttons
  1735. btnsizer = wx.StdDialogButtonSizer()
  1736. btnOK = wx.Button(parent = panel, id = wx.ID_OK)
  1737. btnOK.SetDefault()
  1738. btnsizer.AddButton(btnOK)
  1739. btnCancel = wx.Button(parent = panel, id = wx.ID_CANCEL)
  1740. btnsizer.AddButton(btnCancel)
  1741. btnApply = wx.Button(parent = panel, id = wx.ID_APPLY)
  1742. btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
  1743. btnsizer.AddButton(btnApply)
  1744. btnsizer.Realize()
  1745. sizer.Add(item = btnsizer, proportion = 0,
  1746. flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5)
  1747. panel.SetSizer(sizer)
  1748. sizer.Fit(panel)
  1749. self.SetSize(self.GetBestSize())
  1750. self.Layout()
  1751. def GetOpacity(self):
  1752. """!Button 'OK' pressed"""
  1753. # return opacity value
  1754. opacity = float(self.value.GetValue()) / 100
  1755. return opacity
  1756. def OnApply(self, event):
  1757. event = wxApplyOpacity(value = self.GetOpacity())
  1758. wx.PostEvent(self, event)
  1759. def GetImageHandlers(image):
  1760. """!Get list of supported image handlers"""
  1761. lext = list()
  1762. ltype = list()
  1763. for h in image.GetHandlers():
  1764. lext.append(h.GetExtension())
  1765. filetype = ''
  1766. if 'png' in lext:
  1767. filetype += "PNG file (*.png)|*.png|"
  1768. ltype.append({ 'type' : wx.BITMAP_TYPE_PNG,
  1769. 'ext' : 'png' })
  1770. filetype += "BMP file (*.bmp)|*.bmp|"
  1771. ltype.append({ 'type' : wx.BITMAP_TYPE_BMP,
  1772. 'ext' : 'bmp' })
  1773. if 'gif' in lext:
  1774. filetype += "GIF file (*.gif)|*.gif|"
  1775. ltype.append({ 'type' : wx.BITMAP_TYPE_GIF,
  1776. 'ext' : 'gif' })
  1777. if 'jpg' in lext:
  1778. filetype += "JPG file (*.jpg)|*.jpg|"
  1779. ltype.append({ 'type' : wx.BITMAP_TYPE_JPEG,
  1780. 'ext' : 'jpg' })
  1781. if 'pcx' in lext:
  1782. filetype += "PCX file (*.pcx)|*.pcx|"
  1783. ltype.append({ 'type' : wx.BITMAP_TYPE_PCX,
  1784. 'ext' : 'pcx' })
  1785. if 'pnm' in lext:
  1786. filetype += "PNM file (*.pnm)|*.pnm|"
  1787. ltype.append({ 'type' : wx.BITMAP_TYPE_PNM,
  1788. 'ext' : 'pnm' })
  1789. if 'tif' in lext:
  1790. filetype += "TIF file (*.tif)|*.tif|"
  1791. ltype.append({ 'type' : wx.BITMAP_TYPE_TIF,
  1792. 'ext' : 'tif' })
  1793. if 'xpm' in lext:
  1794. filetype += "XPM file (*.xpm)|*.xpm"
  1795. ltype.append({ 'type' : wx.BITMAP_TYPE_XPM,
  1796. 'ext' : 'xpm' })
  1797. return filetype, ltype
  1798. class ImageSizeDialog(wx.Dialog):
  1799. """!Set size for saved graphic file"""
  1800. def __init__(self, parent, id = wx.ID_ANY, title = _("Set image size"),
  1801. style = wx.DEFAULT_DIALOG_STYLE, **kwargs):
  1802. self.parent = parent
  1803. wx.Dialog.__init__(self, parent, id = id, style = style, title = title, **kwargs)
  1804. self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
  1805. self.box = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
  1806. label = ' % s' % _("Image size"))
  1807. size = self.parent.GetWindow().GetClientSize()
  1808. self.width = wx.SpinCtrl(parent = self.panel, id = wx.ID_ANY,
  1809. style = wx.SP_ARROW_KEYS)
  1810. self.width.SetRange(20, 1e6)
  1811. self.width.SetValue(size.width)
  1812. wx.CallAfter(self.width.SetFocus)
  1813. self.height = wx.SpinCtrl(parent = self.panel, id = wx.ID_ANY,
  1814. style = wx.SP_ARROW_KEYS)
  1815. self.height.SetRange(20, 1e6)
  1816. self.height.SetValue(size.height)
  1817. self.template = wx.Choice(parent = self.panel, id = wx.ID_ANY,
  1818. size = (125, -1),
  1819. choices = [ "",
  1820. "640x480",
  1821. "800x600",
  1822. "1024x768",
  1823. "1280x960",
  1824. "1600x1200",
  1825. "1920x1440" ])
  1826. self.btnOK = wx.Button(parent = self.panel, id = wx.ID_OK)
  1827. self.btnOK.SetDefault()
  1828. self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
  1829. self.template.Bind(wx.EVT_CHOICE, self.OnTemplate)
  1830. self._layout()
  1831. self.SetSize(self.GetBestSize())
  1832. def _layout(self):
  1833. """!Do layout"""
  1834. sizer = wx.BoxSizer(wx.VERTICAL)
  1835. # body
  1836. box = wx.StaticBoxSizer(self.box, wx.HORIZONTAL)
  1837. fbox = wx.FlexGridSizer(cols = 2, vgap = 5, hgap = 5)
  1838. fbox.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
  1839. label = _("Width:")),
  1840. flag = wx.ALIGN_CENTER_VERTICAL)
  1841. fbox.Add(item = self.width)
  1842. fbox.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
  1843. label = _("Height:")),
  1844. flag = wx.ALIGN_CENTER_VERTICAL)
  1845. fbox.Add(item = self.height)
  1846. fbox.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
  1847. label = _("Template:")),
  1848. flag = wx.ALIGN_CENTER_VERTICAL)
  1849. fbox.Add(item = self.template)
  1850. box.Add(item = fbox, proportion = 1,
  1851. flag = wx.EXPAND | wx.ALL, border = 5)
  1852. sizer.Add(item = box, proportion = 1,
  1853. flag=wx.EXPAND | wx.ALL, border = 3)
  1854. # buttons
  1855. btnsizer = wx.StdDialogButtonSizer()
  1856. btnsizer.AddButton(self.btnOK)
  1857. btnsizer.AddButton(self.btnCancel)
  1858. btnsizer.Realize()
  1859. sizer.Add(item = btnsizer, proportion = 0,
  1860. flag = wx.EXPAND | wx.ALIGN_RIGHT | wx.ALL, border=5)
  1861. self.panel.SetSizer(sizer)
  1862. sizer.Fit(self.panel)
  1863. self.Layout()
  1864. def GetValues(self):
  1865. """!Get width/height values"""
  1866. return self.width.GetValue(), self.height.GetValue()
  1867. def OnTemplate(self, event):
  1868. """!Template selected"""
  1869. sel = event.GetString()
  1870. if not sel:
  1871. width, height = self.parent.GetWindow().GetClientSize()
  1872. else:
  1873. width, height = map(int, sel.split('x'))
  1874. self.width.SetValue(width)
  1875. self.height.SetValue(height)
  1876. class SqlQueryFrame(wx.Frame):
  1877. def __init__(self, parent, id = wx.ID_ANY,
  1878. title = _("GRASS GIS SQL Query Utility"),
  1879. *kwargs):
  1880. """!SQL Query Utility window
  1881. """
  1882. self.parent = parent
  1883. wx.Frame.__init__(self, parent = parent, id = id, title = title, *kwargs)
  1884. self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass_sql.ico'), wx.BITMAP_TYPE_ICO))
  1885. self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
  1886. self.sqlBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
  1887. label = _(" SQL statement "))
  1888. self.sql = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY,
  1889. style = wx.TE_MULTILINE)
  1890. self.btnApply = wx.Button(parent = self.panel, id = wx.ID_APPLY)
  1891. self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
  1892. self.Bind(wx.EVT_BUTTON, self.OnCloseWindow, self.btnCancel)
  1893. self._layout()
  1894. self.SetMinSize(wx.Size(300, 150))
  1895. self.SetSize(wx.Size(500, 200))
  1896. def _layout(self):
  1897. """!Do layout"""
  1898. sizer = wx.BoxSizer(wx.VERTICAL)
  1899. sqlSizer = wx.StaticBoxSizer(self.sqlBox, wx.HORIZONTAL)
  1900. sqlSizer.Add(item = self.sql, proportion = 1,
  1901. flag = wx.EXPAND)
  1902. btnSizer = wx.StdDialogButtonSizer()
  1903. btnSizer.AddButton(self.btnApply)
  1904. btnSizer.AddButton(self.btnCancel)
  1905. btnSizer.Realize()
  1906. sizer.Add(item = sqlSizer, proportion = 1,
  1907. flag = wx.EXPAND | wx.ALL, border = 5)
  1908. sizer.Add(item = btnSizer, proportion = 0,
  1909. flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
  1910. self.panel.SetSizer(sizer)
  1911. self.Layout()
  1912. def OnCloseWindow(self, event):
  1913. """!Close window
  1914. """
  1915. self.Close()
  1916. class SymbolDialog(wx.Dialog):
  1917. """!Dialog for GRASS symbols selection.
  1918. Dialog is called in gui_core::forms module.
  1919. """
  1920. def __init__(self, parent, symbolPath, currentSymbol = None, title = _("Symbols")):
  1921. """!Dialog constructor.
  1922. It is assumed that symbolPath contains folders with symbols.
  1923. @param parent dialog parent
  1924. @param symbolPath absolute path to symbols
  1925. @param currentSymbol currently selected symbol (e.g. 'basic/x')
  1926. @param title dialog title
  1927. """
  1928. wx.Dialog.__init__(self, parent = parent, title = title, id = wx.ID_ANY)
  1929. self.symbolPath = symbolPath
  1930. self.currentSymbol = currentSymbol # default basic/x
  1931. self.selected = None
  1932. self.selectedDir = None
  1933. self._layout()
  1934. def _layout(self):
  1935. mainPanel = wx.Panel(self, id = wx.ID_ANY)
  1936. mainSizer = wx.BoxSizer(wx.VERTICAL)
  1937. vSizer = wx.BoxSizer( wx.VERTICAL)
  1938. fgSizer = wx.FlexGridSizer(rows = 2, vgap = 5, hgap = 5)
  1939. self.folderChoice = wx.Choice(mainPanel, id = wx.ID_ANY, choices = os.listdir(self.symbolPath))
  1940. self.folderChoice.Bind(wx.EVT_CHOICE, self.OnFolderSelect)
  1941. fgSizer.Add(item = wx.StaticText(mainPanel, id = wx.ID_ANY, label = _("Symbol directory:")),
  1942. proportion = 0,
  1943. flag = wx.ALIGN_CENTER_VERTICAL)
  1944. fgSizer.Add(item = self.folderChoice, proportion = 0,
  1945. flag = wx.ALIGN_CENTER, border = 0)
  1946. self.infoLabel = wx.StaticText(mainPanel, id = wx.ID_ANY)
  1947. fgSizer.Add(wx.StaticText(mainPanel, id = wx.ID_ANY, label = _("Symbol name:")),
  1948. flag = wx.ALIGN_CENTRE_VERTICAL)
  1949. fgSizer.Add(self.infoLabel, proportion = 0,
  1950. flag = wx.ALIGN_CENTRE_VERTICAL)
  1951. vSizer.Add(fgSizer, proportion = 0, flag = wx.ALL, border = 5)
  1952. self.panels = self._createSymbolPanels(mainPanel)
  1953. for panel in self.panels:
  1954. vSizer.Add(panel, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
  1955. panel.Bind(EVT_SYMBOL_SELECTION_CHANGED, self.SelectionChanged)
  1956. mainSizer.Add(vSizer, proportion = 1, flag = wx.ALL| wx.EXPAND, border = 5)
  1957. self.btnCancel = wx.Button(parent = mainPanel, id = wx.ID_CANCEL)
  1958. self.btnOK = wx.Button(parent = mainPanel, id = wx.ID_OK)
  1959. self.btnOK.SetDefault()
  1960. self.btnOK.Enable(False)
  1961. # buttons
  1962. btnSizer = wx.StdDialogButtonSizer()
  1963. btnSizer.AddButton(self.btnCancel)
  1964. btnSizer.AddButton(self.btnOK)
  1965. btnSizer.Realize()
  1966. mainSizer.Add(item = btnSizer, proportion = 0,
  1967. flag = wx.EXPAND | wx.ALL, border = 5)
  1968. # show panel with the largest number of images and fit size
  1969. count = []
  1970. for folder in os.listdir(self.symbolPath):
  1971. count.append(len(os.listdir(os.path.join(self.symbolPath, folder))))
  1972. index = count.index(max(count))
  1973. self.folderChoice.SetSelection(index)
  1974. self.OnFolderSelect(None)
  1975. self.infoLabel.Show()
  1976. mainPanel.SetSizerAndFit(mainSizer)
  1977. self.SetSize(self.GetBestSize())
  1978. # show currently selected symbol
  1979. if self.currentSymbol:
  1980. # set directory
  1981. self.selectedDir, self.selected = os.path.split(self.currentSymbol)
  1982. self.folderChoice.SetStringSelection(self.selectedDir)
  1983. # select symbol
  1984. panelIdx = self.folderChoice.GetSelection()
  1985. for panel in self.symbolPanels[panelIdx]:
  1986. if panel.GetName() == self.selected:
  1987. panel.Select()
  1988. else:
  1989. self.folderChoice.SetSelection(0)
  1990. self.OnFolderSelect(None)
  1991. def _createSymbolPanels(self, parent):
  1992. """!Creates multiple panels with symbols.
  1993. Panels are shown/hidden according to selected folder."""
  1994. folders = os.listdir(self.symbolPath)
  1995. panels = []
  1996. self.symbolPanels = []
  1997. for folder in folders:
  1998. panel = wx.Panel(parent, style = wx.BORDER_RAISED)
  1999. sizer = wx.GridSizer(cols = 6, vgap = 3, hgap = 3)
  2000. images = self._getSymbols(path = os.path.join(self.symbolPath, folder))
  2001. symbolPanels = []
  2002. for img in images:
  2003. iP = SingleSymbolPanel(parent = panel, symbolPath = img)
  2004. sizer.Add(item = iP, proportion = 0, flag = wx.ALIGN_CENTER)
  2005. symbolPanels.append(iP)
  2006. panel.SetSizerAndFit(sizer)
  2007. panel.Hide()
  2008. panels.append(panel)
  2009. self.symbolPanels.append(symbolPanels)
  2010. return panels
  2011. def _getSymbols(self, path):
  2012. # we assume that images are in subfolders (1 level only)
  2013. imageList = []
  2014. for image in os.listdir(path):
  2015. imageList.append(os.path.join(path, image))
  2016. return sorted(imageList)
  2017. def OnFolderSelect(self, event):
  2018. """!Selected folder with symbols changed."""
  2019. idx = self.folderChoice.GetSelection()
  2020. for i in range(len(self.panels)):
  2021. sizer = self.panels[i].GetContainingSizer()
  2022. sizer.Show(self.panels[i], i == idx, recursive = True)
  2023. sizer.Layout()
  2024. if self.selectedDir == self.folderChoice.GetStringSelection():
  2025. self.btnOK.Enable()
  2026. self.infoLabel.SetLabel(self.selected)
  2027. else:
  2028. self.btnOK.Disable()
  2029. self.infoLabel.SetLabel('')
  2030. def SelectionChanged(self, event):
  2031. """!Selected symbol changed."""
  2032. if event.doubleClick:
  2033. self.EndModal(wx.ID_OK)
  2034. # deselect all
  2035. for i in range(len(self.panels)):
  2036. for panel in self.symbolPanels[i]:
  2037. if panel.GetName() != event.name:
  2038. panel.Deselect()
  2039. self.btnOK.Enable()
  2040. self.selected = event.name
  2041. self.selectedDir = self.folderChoice.GetStringSelection()
  2042. self.infoLabel.SetLabel(event.name)
  2043. def GetSelectedSymbolName(self):
  2044. """!Returns currently selected symbol name (e.g. 'basic/x').
  2045. """
  2046. # separator must be '/' and not dependent on OS
  2047. return self.selectedDir + '/' + self.selected
  2048. def GetSelectedSymbolPath(self):
  2049. """!Returns currently selected symbol full path.
  2050. """
  2051. return os.path.join(self.symbolPath, self.selectedDir, self.selected)