2
@package gui_core.dialogs
4
@brief Various dialogs used in wxGUI.
7
- :class:`SimpleDialog`
8
- :class:`LocationDialog`
9
- :class:`MapsetDialog`
10
- :class:`VectorDialog`
11
- :class:`NewVectorDialog`
12
- :class:`SavedRegion`
13
- :class:`GroupDialog`
14
- :class:`MapLayersDialog`
15
- :class:`ImportDialog`
16
- :class:`GdalImportDialog`
17
- :class:`GdalOutputDialog`
18
- :class:`DxfImportDialog`
19
- :class:`LayersList` (used by MultiImport)
20
- :class:`SetOpacityDialog`
21
- :class:`ImageSizeDialog`
22
- :class:`SqlQueryFrame`
23
- :class:`SymbolDialog`
25
(C) 2008-2011 by the GRASS Development Team
27
This program is free software under the GNU General Public License
28
(>=v2). Read the file COPYING that comes with GRASS for details.
30
@author Martin Landa <landa.martin gmail.com>
31
@author Anna Kratochvilova <kratochanna gmail.com> (GroupDialog, SymbolDialog)
37
from bisect import bisect
40
import wx.lib.filebrowsebutton as filebrowse
41
import wx.lib.mixins.listctrl as listmix
43
from grass.script import core as grass
44
from grass.script import task as gtask
46
from grass.pydispatch.signal import Signal
48
from core import globalvar
49
from core.gcmd import GError, RunCommand, GMessage
50
from gui_core.gselect import LocationSelect, MapsetSelect, Select, \
51
OgrTypeSelect, GdalSelect, MapsetSelect, \
53
from gui_core.widgets import SingleSymbolPanel, GListCtrl, SimpleValidator
54
from core.utils import GetValidLayerName, _
55
from core.settings import UserSettings, GetDisplayVectSettings
56
from core.debug import Debug
58
class SimpleDialog(wx.Dialog):
59
def __init__(self, parent, title, id = wx.ID_ANY,
60
style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
62
"""General dialog to choose given element (location, mapset, vector map, etc.)
65
:param title: window title
67
wx.Dialog.__init__(self, parent, id, title, style = style, **kwargs)
68
self.SetExtraStyle(wx.WS_EX_VALIDATE_RECURSIVELY)
69
self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
71
self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
72
self.btnOK = wx.Button(parent = self.panel, id = wx.ID_OK)
73
self.btnOK.SetDefault()
76
self.warning = _("Required item is not set.")
80
self.sizer = wx.BoxSizer(wx.VERTICAL)
82
self.dataSizer = wx.BoxSizer(wx.VERTICAL)
84
# self.informLabel = wx.StaticText(self.panel, id = wx.ID_ANY)
86
btnSizer = wx.StdDialogButtonSizer()
87
btnSizer.AddButton(self.btnCancel)
88
btnSizer.AddButton(self.btnOK)
91
self.sizer.Add(item = self.dataSizer, proportion = 1,
92
flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
94
# self.sizer.Add(item = self.informLabel, proportion = 0, flag = wx.ALL, border = 5)
95
self.sizer.Add(item = btnSizer, proportion = 0,
96
flag = wx.EXPAND | wx.ALL, border = 5)
98
def ValidatorCallback(self, win):
99
GMessage(parent = self, message = self.warning)
100
# self.informLabel.SetForegroundColour(wx.Colour(255, 0, 0))
101
# self.informLabel.SetLabel(self.warning)
104
class LocationDialog(SimpleDialog):
105
"""Dialog used to select location"""
106
def __init__(self, parent, title = _("Select GRASS location and mapset")):
107
SimpleDialog.__init__(self, parent, title)
109
self.element1 = LocationSelect(parent = self.panel, id = wx.ID_ANY,
110
size = globalvar.DIALOG_GSELECT_SIZE,
111
validator = SimpleValidator(callback = self.ValidatorCallback))
112
self.element1.Bind(wx.EVT_TEXT, self.OnLocation)
113
self.element2 = MapsetSelect(parent = self.panel, id = wx.ID_ANY,
114
size = globalvar.DIALOG_GSELECT_SIZE,
115
setItems = False, skipCurrent = True,
116
validator = SimpleValidator(callback = self.ValidatorCallback))
117
self.element1.SetFocus()
118
self.warning = _("Location or mapset is not defined.")
120
self.SetMinSize(self.GetSize())
124
self.dataSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
125
label = _("Name of GRASS location:")),
126
proportion = 0, flag = wx.ALL, border = 1)
127
self.dataSizer.Add(self.element1, proportion = 0,
128
flag = wx.EXPAND | wx.ALL, border = 1)
130
self.dataSizer.Add(wx.StaticText(parent = self.panel, id = wx.ID_ANY,
131
label = _("Name of mapset:")), proportion = 0,
132
flag = wx.EXPAND | wx.ALL, border = 1)
134
self.dataSizer.Add(self.element2, proportion = 0,
135
flag = wx.EXPAND | wx.ALL, border = 1)
137
self.panel.SetSizer(self.sizer)
140
def OnLocation(self, event):
141
"""Select mapset given location name"""
142
location = event.GetString()
145
dbase = grass.gisenv()['GISDBASE']
146
self.element2.UpdateItems(dbase = dbase, location = location)
147
self.element2.SetSelection(0)
148
mapset = self.element2.GetStringSelection()
151
"""Get location, mapset"""
152
return (self.element1.GetValue(), self.element2.GetValue())
154
class MapsetDialog(SimpleDialog):
155
"""Dialog used to select mapset"""
156
def __init__(self, parent, title = _("Select mapset in GRASS location"),
158
SimpleDialog.__init__(self, parent, title)
161
self.SetTitle(self.GetTitle() + ' <%s>' % location)
163
self.SetTitle(self.GetTitle() + ' <%s>' % grass.gisenv()['LOCATION_NAME'])
165
self.element = MapsetSelect(parent = self.panel, id = wx.ID_ANY, skipCurrent = True,
166
size = globalvar.DIALOG_GSELECT_SIZE,
167
validator = SimpleValidator(callback = self.ValidatorCallback))
169
self.element.SetFocus()
170
self.warning = _("Name of mapset is missing.")
173
self.SetMinSize(self.GetSize())
177
self.dataSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
178
label = _("Name of mapset:")),
179
proportion = 0, flag = wx.ALL, border = 1)
180
self.dataSizer.Add(self.element, proportion = 0,
181
flag = wx.EXPAND | wx.ALL, border = 1)
182
self.panel.SetSizer(self.sizer)
186
return self.element.GetValue()
188
class VectorDialog(SimpleDialog):
189
def __init__(self, parent, title = _("Select vector map"), layerTree = None):
190
"""Dialog for selecting existing vector map
192
:param parent: parent window
193
:param title: window title
194
:param layerTree: show only vector maps in given layer tree if not None
196
:return: dialog instance
198
SimpleDialog.__init__(self, parent, title)
200
self.element = Select(parent = self.panel, id = wx.ID_ANY, size = globalvar.DIALOG_GSELECT_SIZE,
201
type = 'vector', layerTree = layerTree,
202
validator = SimpleValidator(callback = self.ValidatorCallback))
203
self.element.SetFocus()
205
self.warning = _("Name of vector map is missing.")
206
wx.CallAfter(self._layout)
210
self.dataSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
211
label = _("Name of vector map:")),
212
proportion = 0, flag = wx.ALL, border = 1)
213
self.dataSizer.Add(item = self.element, proportion = 0,
214
flag = wx.EXPAND | wx.ALL, border = 1)
216
self.panel.SetSizer(self.sizer)
219
def GetName(self, full = False):
220
"""Get name of vector map to be created
222
:param full: True to get fully qualified name
224
name = self.element.GetValue()
229
return name + '@' + grass.gisenv()['MAPSET']
231
return name.split('@', 1)[0]
233
class NewVectorDialog(VectorDialog):
234
def __init__(self, parent, title = _("Create new vector map"),
235
disableAdd = False, disableTable = False, showType = False):
236
"""Dialog for creating new vector map
238
:param parent: parent window
239
:param title: window title
240
:param disableAdd: disable 'add layer' checkbox
241
:param disableTable: disable 'create table' checkbox
242
:param showType: True to show feature type selector (used for creating new empty OGR layers)
244
:return: dialog instance
246
VectorDialog.__init__(self, parent, title)
248
# determine output format
250
self.ftype = OgrTypeSelect(parent = self, panel = self.panel)
254
# create attribute table
255
self.table = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
256
label = _("Create attribute table"))
257
self.table.SetValue(True)
259
self.table.Enable(False)
264
self.keycol = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY,
265
size = globalvar.DIALOG_SPIN_SIZE)
266
self.keycol.SetValue(UserSettings.Get(group = 'atm', key = 'keycolumn', subkey = 'value'))
268
self.keycol.Enable(False)
270
self.addbox = wx.CheckBox(parent = self.panel,
271
label = _('Add created map into layer tree'), style = wx.NO_BORDER)
273
self.addbox.SetValue(True)
274
self.addbox.Enable(False)
276
self.addbox.SetValue(UserSettings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
278
self.table.Bind(wx.EVT_CHECKBOX, self.OnTable)
280
self.warning = _("Name of new vector map is missing.")
282
def OnTable(self, event):
284
self.keycol.Enable(event.IsChecked())
288
self.dataSizer.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
289
label = _("Name for new vector map:")),
290
proportion = 0, flag = wx.ALL, border = 1)
291
self.dataSizer.Add(item = self.element, proportion = 0,
292
flag = wx.EXPAND | wx.ALL, border = 1)
294
self.dataSizer.AddSpacer(1)
295
self.dataSizer.Add(item = self.ftype, proportion = 0,
296
flag = wx.EXPAND | wx.ALL, border = 1)
298
self.dataSizer.Add(item = self.table, proportion = 0,
299
flag = wx.EXPAND | wx.ALL, border = 1)
302
keySizer = wx.BoxSizer(wx.HORIZONTAL)
303
keySizer.Add(item = wx.StaticText(parent = self.panel, label = _("Key column:")),
305
flag = wx.ALIGN_CENTER_VERTICAL)
306
keySizer.AddSpacer(10)
307
keySizer.Add(item = self.keycol, proportion = 0,
308
flag = wx.ALIGN_RIGHT)
309
self.dataSizer.Add(item = keySizer, proportion = 1,
310
flag = wx.EXPAND | wx.ALL, border = 1)
312
self.dataSizer.AddSpacer(5)
314
self.dataSizer.Add(item = self.addbox, proportion = 0,
315
flag = wx.EXPAND | wx.ALL, border = 1)
317
self.panel.SetSizer(self.sizer)
319
self.SetMinSize(self.GetSize())
322
"""Get key column name"""
324
return self.keycol.GetValue()
325
return UserSettings.Get(group = 'atm', key = 'keycolumn', subkey = 'value')
327
def IsChecked(self, key):
328
"""Get dialog properties
330
:param key: window key ('add', 'table')
333
:return: None on error
336
return self.addbox.IsChecked()
338
return self.table.IsChecked()
342
def GetFeatureType(self):
343
"""Get feature type for OGR
345
:return: feature type as string
346
:return: None for native format
349
return self.ftype.GetType()
354
def CreateNewVector(parent, cmd, title = _('Create new vector map'),
355
exceptMap=None, giface=None,
356
disableAdd = False, disableTable = False):
357
"""Create new vector map layer
359
:param cmd: (prog, \*\*kwargs)
360
:param title: window title
361
:param exceptMap: list of maps to be excepted
363
:param disableAdd: disable 'add layer' checkbox
364
:param disableTable: disable 'create table' checkbox
366
:return: dialog instance
367
:return: None on error
369
vExternalOut = grass.parse_command('v.external.out', flags='g')
370
isNative = vExternalOut['format'] == 'native'
371
if cmd[0] == 'v.edit' and not isNative:
375
dlg = NewVectorDialog(parent, title = title,
376
disableAdd = disableAdd, disableTable = disableTable,
379
if dlg.ShowModal() != wx.ID_OK:
383
outmap = dlg.GetName()
385
if outmap == exceptMap:
386
GError(parent = parent,
387
message = _("Unable to create vector map <%s>.") % outmap)
390
if dlg.table.IsEnabled() and not key:
391
GError(parent = parent,
392
message = _("Invalid or empty key column.\n"
393
"Unable to create vector map <%s>.") % outmap)
397
if outmap == '': # should not happen
401
# update cmd -> output name defined
402
cmd[1][cmd[2]] = outmap
404
cmd[1]['type'] = dlg.GetFeatureType()
406
curMapset = grass.gisenv()['MAPSET']
408
listOfVectors = grass.list_grouped('vector')[curMapset]
410
listOfVectors = RunCommand('v.external',
415
input = vExternalOut['dsn']).splitlines()
418
if not UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled') and \
419
outmap in listOfVectors:
420
dlgOw = wx.MessageDialog(parent, message = _("Vector map <%s> already exists "
421
"in the current mapset. "
422
"Do you want to overwrite it?") % outmap,
423
caption = _("Overwrite?"),
424
style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
425
if dlgOw.ShowModal() == wx.ID_YES:
432
if UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'):
435
ret = RunCommand(prog = cmd[0],
437
overwrite = overwrite,
443
if not isNative and \
444
not grass.find_file(outmap, element = 'vector', mapset = curMapset)['fullname']:
445
# create link for OGR layers
446
RunCommand('v.external',
447
overwrite = overwrite,
449
input = vExternalOut['dsn'],
452
# create attribute table
453
if dlg.table.IsEnabled() and dlg.table.IsChecked():
455
sql = 'CREATE TABLE %s (%s INTEGER)' % (outmap, key)
457
RunCommand('db.connect',
460
Debug.msg(1, "SQL: %s" % sql)
461
RunCommand('db.execute',
467
RunCommand('v.db.connect',
474
# TODO: how to deal with attribute tables for OGR layers?
476
# return fully qualified map name
477
if '@' not in outmap:
478
outmap += '@' + grass.gisenv()['MAPSET']
481
# giface.WriteLog(_("New vector map <%s> created") % outmap)
485
class SavedRegion(wx.Dialog):
486
def __init__(self, parent, title, id = wx.ID_ANY, loadsave = 'load',
488
"""Loading or saving of display extents to saved region file
490
:param loadsave: load or save region?
492
wx.Dialog.__init__(self, parent, id, title, **kwargs)
494
self.loadsave = loadsave
497
sizer = wx.BoxSizer(wx.VERTICAL)
499
box = wx.BoxSizer(wx.HORIZONTAL)
500
label = wx.StaticText(parent = self, id = wx.ID_ANY)
501
box.Add(item = label, proportion = 0, flag = wx.ALIGN_CENTRE | wx.ALL, border = 5)
502
if loadsave == 'load':
503
label.SetLabel(_("Load region:"))
504
self._selection = Select(parent=self, size=globalvar.DIALOG_GSELECT_SIZE,
506
elif loadsave == 'save':
507
label.SetLabel(_("Save region:"))
508
self._selection = Select(parent=self, size=globalvar.DIALOG_GSELECT_SIZE,
509
type='windows', mapsets=[grass.gisenv()['MAPSET']], fullyQualified = False)
511
box.Add(item=self._selection, proportion=0, flag=wx.ALIGN_CENTRE | wx.ALL, border=5)
512
self._selection.SetFocus()
513
self._selection.Bind(wx.EVT_TEXT, self.OnRegion)
515
sizer.Add(item = box, proportion = 0, flag = wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
518
line = wx.StaticLine(parent = self, id = wx.ID_ANY, size = (20, -1), style = wx.LI_HORIZONTAL)
519
sizer.Add(item = line, proportion = 0,
520
flag = wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.LEFT | wx.RIGHT, border = 5)
522
btnsizer = wx.StdDialogButtonSizer()
524
btn = wx.Button(parent = self, id = wx.ID_OK)
526
btnsizer.AddButton(btn)
528
btn = wx.Button(parent = self, id = wx.ID_CANCEL)
529
btnsizer.AddButton(btn)
532
sizer.Add(item = btnsizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
538
def OnRegion(self, event):
539
value = self._selection.GetValue()
541
value = value.rsplit('@', 1)[0]
542
if not grass.legal_name(value):
543
GMessage(parent=self,
544
message=_("Name cannot begin with '.' "
545
"and must not contain space, quotes, "
546
"'/', '\'', '@', ',', '=', '*', "
547
"and all other non-alphanumeric characters."))
552
"""Return region name"""
556
class GroupDialog(wx.Dialog):
557
"""Dialog for creating/editing groups"""
558
def __init__(self, parent = None, defaultGroup = None, defaultSubgroup = None,
559
title = _("Create or edit imagery groups"),
560
style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
562
wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title,
563
style = style, **kwargs)
566
self.defaultGroup = defaultGroup
567
self.defaultSubgroup = defaultSubgroup
568
self.currentGroup = self.defaultGroup
569
self.currentSubgroup = self.defaultGroup
571
self.dataChanged = False
573
# signaling edit subgroup / group mode
574
self.edit_subg = False
576
# sungroup maps dict value - ischecked
582
# pattern chosen for filtering
583
self.flt_pattern = ''
585
self.bodySizer = self._createDialogBody()
588
btnOk = wx.Button(parent = self, id = wx.ID_OK)
589
btnApply = wx.Button(parent = self, id = wx.ID_APPLY)
590
btnClose = wx.Button(parent = self, id = wx.ID_CANCEL)
592
btnOk.SetToolTipString(_("Apply changes to selected group and close dialog"))
593
btnApply.SetToolTipString(_("Apply changes to selected group"))
594
btnClose.SetToolTipString(_("Close dialog, changes are not applied"))
599
# btnSizer = wx.BoxSizer(wx.HORIZONTAL)
600
# btnSizer.Add(item = btnClose, proportion = 0,
601
# flag = wx.RIGHT | wx.ALIGN_RIGHT | wx.EXPAND, border = 5)
602
# btnSizer.Add(item = btnApply, proportion = 0,
603
# flag = wx.LEFT, border = 5)
604
btnSizer = wx.StdDialogButtonSizer()
605
btnSizer.AddButton(btnOk)
606
btnSizer.AddButton(btnApply)
607
btnSizer.AddButton(btnClose)
610
mainSizer = wx.BoxSizer(wx.VERTICAL)
611
mainSizer.Add(item = self.bodySizer, proportion = 1,
612
flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 10)
613
mainSizer.Add(item = wx.StaticLine(parent = self, id = wx.ID_ANY,
614
style = wx.LI_HORIZONTAL), proportion = 0,
615
flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 10)
617
mainSizer.Add(item = btnSizer, proportion = 0,
618
flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.ALIGN_RIGHT, border = 10)
620
self.SetSizer(mainSizer)
623
btnOk.Bind(wx.EVT_BUTTON, self.OnOk)
624
btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
625
btnClose.Bind(wx.EVT_BUTTON, self.OnClose)
627
# set dialog min size
628
self.SetMinSize(self.GetSize())
629
self.SetSize((-1, 400))
631
def _createDialogBody(self):
632
bodySizer = wx.BoxSizer(wx.VERTICAL)
633
#TODO same text in MapLayersDialogBase
635
filter_tooltip = _("Put here a regular expression."
636
" Characters '.*' stand for anything,"
637
" character '^' stands for the beginning"
638
" and '$' for the end.")
641
bodySizer.Add(item = wx.StaticText(parent = self, id = wx.ID_ANY,
642
label = _("Select existing group or "
643
"enter name of new group:")),
644
flag = wx.ALIGN_CENTER_VERTICAL | wx.TOP, border = 10)
645
self.groupSelect = Select(parent = self, type = 'group',
646
mapsets = [grass.gisenv()['MAPSET']],
647
size = globalvar.DIALOG_GSELECT_SIZE,
648
fullyQualified = False) # searchpath?
650
bodySizer.Add(item = self.groupSelect, flag = wx.TOP | wx.EXPAND, border = 5)
652
self.subg_chbox = wx.CheckBox(parent = self, id = wx.ID_ANY,
653
label = _("Edit/create subgroup"))
655
bodySizer.Add(item = self.subg_chbox,
656
flag = wx.ALIGN_CENTER_VERTICAL | wx.TOP, border = 10)
658
self.subg_panel = wx.Panel(self)
659
subg_sizer = wx.BoxSizer(wx.VERTICAL)
661
subg_sizer.Add(item = wx.StaticText(parent=self.subg_panel, id = wx.ID_ANY,
662
label = _("Select existing subgroup or "
663
"enter name of new subgroup:")),
664
flag = wx.ALIGN_CENTER_VERTICAL)
666
self.subGroupSelect = SubGroupSelect(parent = self.subg_panel)
668
subg_sizer.Add(item=self.subGroupSelect, flag=wx.EXPAND | wx.TOP, border = 5)
670
self.subg_panel.SetSizer(subg_sizer)
672
bodySizer.Add(item = self.subg_panel, flag = wx.TOP | wx.EXPAND, border = 5)
674
bodySizer.AddSpacer(10)
676
buttonSizer = wx.BoxSizer(wx.VERTICAL)
679
self.gListPanel = wx.Panel(self)
681
gListSizer = wx.GridBagSizer(vgap=3, hgap=2)
683
self.g_sel_all = wx.CheckBox(parent=self.gListPanel, id=wx.ID_ANY,
684
label=_("Select all"))
686
gListSizer.Add(item=self.g_sel_all,
687
flag=wx.ALIGN_CENTER_VERTICAL,
690
gListSizer.Add(item = wx.StaticText(parent = self.gListPanel, label = _("Pattern:")),
691
flag = wx.ALIGN_CENTER_VERTICAL,
694
self.gfilter = wx.TextCtrl(parent=self.gListPanel, id=wx.ID_ANY,
697
self.gfilter.SetToolTipString(filter_tooltip)
700
gListSizer.Add(item=self.gfilter,
704
gListSizer.Add(item = wx.StaticText(parent = self.gListPanel,
705
label = _("List of maps:")),
706
flag = wx.ALIGN_CENTER_VERTICAL | wx.BOTTOM, border = 5, pos=(2,0))
708
sizer = wx.BoxSizer(wx.HORIZONTAL)
710
self.gLayerBox = wx.ListBox(parent = self.gListPanel, id = wx.ID_ANY, size = (-1, 150),
711
style = wx.LB_MULTIPLE | wx.LB_NEEDED_SB)
712
sizer.Add(item = self.gLayerBox, proportion = 1, flag = wx.EXPAND)
714
self.addLayer = wx.Button(self.gListPanel, id = wx.ID_ADD)
715
self.addLayer.SetToolTipString(_("Select map layers and add them to the list."))
716
buttonSizer.Add(item = self.addLayer, flag = wx.BOTTOM, border = 10)
718
self.removeLayer = wx.Button(self.gListPanel, id = wx.ID_REMOVE)
719
self.removeLayer.SetToolTipString(_("Remove selected layer(s) from list."))
720
buttonSizer.Add(item = self.removeLayer)
721
sizer.Add(item = buttonSizer, flag = wx.LEFT, border = 5)
723
gListSizer.Add(item=sizer, flag=wx.EXPAND, pos=(2,1))
724
gListSizer.AddGrowableCol(1)
725
gListSizer.AddGrowableRow(2)
727
self.gListPanel.SetSizer(gListSizer)
728
bodySizer.Add(item=self.gListPanel, proportion=1, flag=wx.EXPAND)
731
self.subgListPanel = wx.Panel(self)
733
subgListSizer = wx.GridBagSizer(vgap=3, hgap=2)
736
self.subg_sel_all = wx.CheckBox(parent=self.subgListPanel, id=wx.ID_ANY,
737
label=_("Select all"))
739
subgListSizer.Add(item=self.subg_sel_all,
740
flag=wx.ALIGN_CENTER_VERTICAL,
743
subgListSizer.Add(item = wx.StaticText(parent=self.subgListPanel, label=_("Pattern:")),
744
flag = wx.ALIGN_CENTER_VERTICAL,
747
self.subgfilter = wx.TextCtrl(parent=self.subgListPanel, id=wx.ID_ANY,
750
self.subgfilter.SetToolTipString(filter_tooltip)
752
subgListSizer.Add(item=self.subgfilter,
756
subgListSizer.Add(item = wx.StaticText(parent = self.subgListPanel,
757
label = _("List of maps:")),
758
flag = wx.ALIGN_CENTER_VERTICAL | wx.BOTTOM, border = 5, pos=(2,0))
760
self.subgListBox = wx.CheckListBox(parent = self.subgListPanel, id = wx.ID_ANY,
762
self.subgListBox.SetToolTipString(_("Check maps from group to be included into subgroup."))
764
subgListSizer.Add(item=self.subgListBox, flag=wx.EXPAND, pos=(2,1))
765
subgListSizer.AddGrowableCol(1)
766
subgListSizer.AddGrowableRow(2)
768
self.subgListPanel.SetSizer(subgListSizer)
769
bodySizer.Add(item=self.subgListPanel, proportion=1, flag=wx.EXPAND)
771
self.infoLabel = wx.StaticText(parent=self, id=wx.ID_ANY)
772
bodySizer.Add(item = self.infoLabel,
773
flag = wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.BOTTOM, border = 5)
776
self.gfilter.Bind(wx.EVT_TEXT, self.OnGroupFilter)
777
self.subgfilter.Bind(wx.EVT_TEXT, self.OnSubgroupFilter)
778
self.gLayerBox.Bind(wx.EVT_LISTBOX, self.OnGLayerCheck)
779
self.subgListBox.Bind(wx.EVT_CHECKLISTBOX, self.OnSubgLayerCheck)
780
self.groupSelect.GetTextCtrl().Bind(wx.EVT_TEXT, self.OnGroupSelected)
781
self.addLayer.Bind(wx.EVT_BUTTON, self.OnAddLayer)
782
self.removeLayer.Bind(wx.EVT_BUTTON, self.OnRemoveLayer)
783
self.subg_chbox.Bind(wx.EVT_CHECKBOX, self.OnSubgChbox)
784
self.subGroupSelect.Bind(wx.EVT_TEXT, lambda event : self.SubGroupSelected())
785
self.subg_sel_all.Bind(wx.EVT_CHECKBOX, self.OnSubgSelAll)
786
self.g_sel_all.Bind(wx.EVT_CHECKBOX, self.OnGSelAll)
788
if self.defaultGroup:
789
self.groupSelect.SetValue(self.defaultGroup)
791
if self.defaultSubgroup is not None:
792
self.subGroupSelect.SetValue(self.defaultSubgroup)
793
self.subg_chbox.SetValue(1)
796
self.subg_chbox.SetValue(0)
797
self.SubgChbox(False)
801
def OnGLayerCheck(self, event):
802
self._checkGSellAll()
804
def OnSubgSelAll(self, event):
805
check = event.Checked()
806
for item in range(self.subgListBox.GetCount()):
807
self.CheckSubgItem(item, check)
808
self.dataChanged = True
812
def OnGSelAll(self, event):
813
check = event.Checked()
815
self.gLayerBox.DeselectAll()
817
for item in range(self.subgListBox.GetCount()):
818
self.gLayerBox.Select(item)
822
def _checkGSellAll(self):
825
nsel = len(self.gLayerBox.GetSelections())
826
if self.gLayerBox.GetCount() == nsel and \
827
self.gLayerBox.GetCount() != 0:
830
self.g_sel_all.SetValue(check)
832
def _checkSubGSellAll(self):
833
not_all_checked = False
834
if self.subgListBox.GetCount() == 0:
835
not_all_checked = True
837
for item in range(self.subgListBox.GetCount()):
838
if not self.subgListBox.IsChecked(item):
839
not_all_checked = True
841
self.subg_sel_all.SetValue(not not_all_checked)
843
def OnSubgroupFilter(self, event):
844
text = event.GetString()
845
self.gfilter.ChangeValue(text)
846
self.flt_pattern = text
849
self.FilterSubgroup()
853
def OnGroupFilter(self, event):
854
text = event.GetString()
855
self.subgfilter.ChangeValue(text)
856
self.flt_pattern = text
859
self.FilterSubgroup()
863
def OnSubgLayerCheck(self, event):
865
m = self.subgListBox.GetString(idx)
866
self.subgmaps[m] = self.subgListBox.IsChecked(idx)
867
self.dataChanged = True
868
self._checkSubGSellAll()
870
def CheckSubgItem(self, idx, val):
871
m = self.subgListBox.GetString(idx)
872
self.subgListBox.Check(idx, val)
873
self.subgmaps[m] = val
874
self.dataChanged = val
876
def DisableSubgroupEdit(self):
877
"""Disable editation of subgroups in the dialog
880
used by gcp manager, maybe the gcp m should also support subgroups
882
self.edit_subg = False
883
self.subg_panel.Hide()
884
self.subg_chbox.Hide()
885
self.subgListBox.Hide()
889
def OnSubgChbox(self, event):
890
edit_subg = self.subg_chbox.GetValue()
891
self.SubgChbox(edit_subg)
893
def SubgChbox(self, edit_subg):
896
self.edit_subg = edit_subg
898
self.SubGroupSelected()
899
self._subgroupLayout()
901
self.edit_subg = edit_subg
906
self.SetMinSize(self.GetBestSize())
908
def _groupLayout(self):
909
self.subg_panel.Hide()
910
self.subgListPanel.Hide()
911
self.gListPanel.Show()
914
def _subgroupLayout(self):
915
self.subg_panel.Show()
916
self.subgListPanel.Show()
917
self.gListPanel.Hide()
920
def OnAddLayer(self, event):
921
"""Add new layer to listbox"""
922
dlg = MapLayersDialogForGroups(parent = self, title = _("Add selected map layers into group"))
924
if dlg.ShowModal() != wx.ID_OK:
928
layers = dlg.GetMapLayers()
930
if layer not in self.gmaps:
931
self.gLayerBox.Append(layer)
932
self.gmaps.append(layer)
933
self.dataChanged = True
936
def OnRemoveLayer(self, event):
937
"""Remove layer from listbox"""
938
while self.gLayerBox.GetSelections():
939
sel = self.gLayerBox.GetSelections()[0]
940
m = self.gLayerBox.GetString(sel)
941
self.gLayerBox.Delete(sel)
943
self.dataChanged = True
949
for maps, sel in self.subgmaps.iteritems():
953
layers = self.gmaps[:]
957
def OnGroupSelected(self, event):
958
"""Text changed in group selector"""
959
# callAfter must be called to close popup before other actions
960
wx.CallAfter(self.GroupSelected)
962
def GroupSelected(self):
963
"""Group was selected, check if changes were apllied"""
965
group, s = self.GetSelectedGroup()
967
groups = self.GetExistGroups()
969
maps = self.GetGroupLayers(group)
971
self.subGroupSelect.Insert(group)
974
maps = self._filter(maps)
976
self.ShowGroupLayers(maps)
977
self.currentGroup = group
979
self.SubGroupSelected()
980
self.ClearNotification()
982
self._checkGSellAll()
984
def FilterGroup(self):
985
maps = self._filter(self.gmaps)
986
self.ShowGroupLayers(maps)
987
self._checkGSellAll()
989
def FilterSubgroup(self):
990
maps = self._filter(self.gmaps)
991
self.subgListBox.Set(maps)
993
for i, m in enumerate(maps):
994
if m in self.subgmaps.iterkeys() and self.subgmaps[m]:
995
self.subgListBox.Check(i)
997
self._checkSubGSellAll()
999
def SubGroupSelected(self):
1000
"""Subgroup was selected, check if changes were apllied"""
1003
subgroup = self.subGroupSelect.GetValue().strip()
1004
group = self.currentGroup
1007
groups = self.GetExistGroups()
1011
gmaps = self.GetGroupLayers(group)
1013
maps = self.GetGroupLayers(group, subgroup)
1016
self.subgmaps[m] = True
1018
self.subgmaps[m] = False
1020
gmaps = self._filter(gmaps)
1021
self.subgListBox.Set(gmaps)
1023
for i, m in enumerate(gmaps):
1024
if self.subgmaps.has_key(m):
1025
self.subgListBox.Check(i)
1027
self.subgListBox.Check(i, False)
1029
self._checkSubGSellAll()
1030
self.currentSubgroup = subgroup
1031
self.ClearNotification()
1033
def _filter(self, data):
1034
"""Apply filter for strings in data list"""
1036
if len(self.flt_pattern) == 0:
1042
if re.compile(self.flt_pattern).search(dt):
1049
def _checkChange(self):
1051
self._checkSubgroupChange()
1053
self._checkGroupChange()
1055
def _checkGroupChange(self):
1056
if self.currentGroup and self.dataChanged:
1057
dlg = wx.MessageDialog(self, message = _("Group <%s> was changed, "
1058
"do you want to apply changes?") % self.currentGroup,
1059
caption = _("Unapplied changes"),
1060
style = wx.YES_NO | wx.ICON_QUESTION | wx.YES_DEFAULT)
1061
if dlg.ShowModal() == wx.ID_YES:
1065
self.dataChanged = False
1067
def _checkSubgroupChange(self):
1068
if self.currentSubgroup and self.dataChanged:
1069
dlg = wx.MessageDialog(self, message = _("Subgroup <%s> was changed, "
1070
"do you want to apply changes?") % self.currentSubgroup,
1071
caption = _("Unapplied changes"),
1072
style = wx.YES_NO | wx.ICON_QUESTION | wx.YES_DEFAULT)
1073
if dlg.ShowModal() == wx.ID_YES:
1077
self.dataChanged = False
1079
def ShowGroupLayers(self, mapList):
1080
"""Show map layers in currently selected group"""
1081
self.gLayerBox.Set(mapList)
1083
def EditGroup(self, group, subgroup=None):
1084
"""Edit selected group"""
1085
layersNew = self.GetLayers()
1086
layersOld = self.GetGroupLayers(group, subgroup)
1090
for layerNew in layersNew:
1091
if layerNew not in layersOld:
1092
add.append(layerNew)
1094
for layerOld in layersOld:
1095
if layerOld not in layersNew:
1096
remove.append(layerOld)
1100
kwargs["subgroup"] = subgroup
1104
ret = RunCommand('i.group',
1108
input = ','.join(remove),
1112
ret = RunCommand('i.group',
1115
input = ','.join(add),
1120
def CreateNewGroup(self, group, subgroup):
1121
"""Create new group"""
1122
layers = self.GetLayers()
1124
GMessage(parent = self,
1125
message = _("No raster maps selected."))
1130
kwargs["subgroup"] = subgroup
1132
ret = RunCommand('i.group',
1137
#update subgroup select
1138
self.SubGroupSelected()
1141
def GetExistGroups(self):
1142
"""Returns existing groups in current mapset"""
1143
return grass.list_grouped('group')[grass.gisenv()['MAPSET']]
1145
def GetExistSubgroups(self, group):
1146
"""Returns existing subgroups in a group"""
1147
return RunCommand('i.group', group=group,
1148
read=True, flags='sg').splitlines()
1150
def ShowResult(self, group, returnCode, create):
1151
"""Show if operation was successfull."""
1152
group += '@' + grass.gisenv()['MAPSET']
1153
if returnCode is None:
1154
label = _("No changes to apply in group <%s>.") % group
1155
elif returnCode == 0:
1157
label = _("Group <%s> was successfully created.") % group
1159
label = _("Group <%s> was successfully changed.") % group
1162
label = _("Creating of new group <%s> failed.") % group
1164
label = _("Changing of group <%s> failed.") % group
1166
self.infoLabel.SetLabel(label)
1167
wx.FutureCall(4000, self.ClearNotification)
1169
def GetSelectedGroup(self):
1170
"""Return currently selected group (without mapset)"""
1171
g = self.groupSelect.GetValue().split('@')[0]
1173
s = self.subGroupSelect.GetValue()
1178
def GetGroupLayers(self, group, subgroup=None):
1179
"""Get layers in group"""
1181
kwargs['group'] = group
1183
kwargs['subgroup'] = subgroup
1185
res = RunCommand('i.group',
1188
read = True, **kwargs)
1191
return res.splitlines()
1193
def ClearNotification(self):
1194
"""Clear notification string"""
1195
self.infoLabel.SetLabel("")
1197
def ApplyChanges(self):
1198
"""Create or edit group"""
1199
group = self.currentGroup
1201
GMessage(parent = self,
1202
message = _("No group selected."))
1206
if self.edit_subg and not self.currentSubgroup:
1207
GMessage(parent = self,
1208
message = _("No subgroup selected."))
1212
subgroup = self.currentSubgroup
1216
groups = self.GetExistGroups()
1218
ret = self.EditGroup(group, subgroup)
1219
self.ShowResult(group = group, returnCode = ret, create = False)
1222
ret = self.CreateNewGroup(group, subgroup)
1223
self.ShowResult(group = group, returnCode = ret, create = True)
1225
self.dataChanged = False
1229
def OnApply(self, event):
1233
def OnOk(self, event):
1234
"""Apply changes and close dialog"""
1235
if self.ApplyChanges():
1238
def OnClose(self, event):
1240
if not self.IsModal():
1244
class MapLayersDialogBase(wx.Dialog):
1245
"""Base dialog for selecting map layers (raster, vector).
1247
There are 3 subclasses: MapLayersDialogForGroups, MapLayersDialogForModeler,
1248
MapLayersDialog. Base class contains core functionality.
1250
def __init__(self, parent, title,
1251
style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
1252
wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title,
1253
style = style, **kwargs)
1255
self.parent = parent # GMFrame or ?
1257
self.applyAddingMapLayers = Signal('MapLayersDialogBase.applyAddingMapLayers')
1259
self.mainSizer = wx.BoxSizer(wx.VERTICAL)
1262
self.bodySizer = self._createDialogBody()
1263
self.mainSizer.Add(item = self.bodySizer, proportion = 1,
1264
flag = wx.EXPAND | wx.ALL, border = 5)
1266
# update list of layer to be loaded
1267
self.map_layers = [] # list of map layers (full list type/mapset)
1268
self.LoadMapLayers(self.GetLayerType(cmd = True),
1269
self.mapset.GetStringSelection())
1271
self._fullyQualifiedNames()
1272
self._modelerDSeries()
1275
btnCancel = wx.Button(parent = self, id = wx.ID_CANCEL)
1276
btnOk = wx.Button(parent = self, id = wx.ID_OK)
1279
# sizers & do layout
1280
self.btnSizer = wx.StdDialogButtonSizer()
1281
self.btnSizer.AddButton(btnCancel)
1282
self.btnSizer.AddButton(btnOk)
1283
self._addApplyButton()
1284
self.btnSizer.Realize()
1286
self.mainSizer.Add(item = self.btnSizer, proportion = 0,
1287
flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
1289
self.SetSizer(self.mainSizer)
1290
self.mainSizer.Fit(self)
1292
# set dialog min size
1293
self.SetMinSize(self.GetSize())
1295
def _modelerDSeries(self):
1296
"""Method used only by MapLayersDialogForModeler,
1297
for other subclasses does nothing.
1301
def _addApplyButton(self):
1302
"""Method used only by MapLayersDialog,
1303
for other subclasses does nothing.
1307
def _fullyQualifiedNames(self):
1308
"""Adds CheckBox which determines is fully qualified names are retuned.
1310
self.fullyQualified = wx.CheckBox(parent = self, id = wx.ID_ANY,
1311
label = _("Use fully-qualified map names"))
1312
self.fullyQualified.SetValue(True)
1313
self.mainSizer.Add(item = self.fullyQualified, proportion = 0,
1314
flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 5)
1316
def _useFullyQualifiedNames(self):
1317
return self.fullyQualified.IsChecked()
1319
def _layerTypes(self):
1320
"""Determines which layer types can be chosen.
1327
return [_('raster'), _('3D raster'), _('vector')]
1329
def _selectAll(self):
1330
"""Check all layers by default"""
1333
def _createDialogBody(self):
1334
bodySizer = wx.GridBagSizer(vgap = 3, hgap = 3)
1337
bodySizer.Add(item = wx.StaticText(parent = self, label = _("Map type:")),
1338
flag = wx.ALIGN_CENTER_VERTICAL,
1341
self.layerType = wx.Choice(parent = self, id = wx.ID_ANY,
1342
choices = self._layerTypes(), size = (100,-1))
1344
self.layerType.SetSelection(0)
1346
bodySizer.Add(item = self.layerType,
1348
self.layerType.Bind(wx.EVT_CHOICE, self.OnChangeParams)
1351
self.toggle = wx.CheckBox(parent = self, id = wx.ID_ANY,
1352
label = _("Select toggle"))
1353
self.toggle.SetValue(self._selectAll())
1354
bodySizer.Add(item = self.toggle,
1355
flag = wx.ALIGN_CENTER_VERTICAL,
1359
bodySizer.Add(item = wx.StaticText(parent = self, label = _("Mapset:")),
1360
flag = wx.ALIGN_CENTER_VERTICAL,
1363
self.mapset = MapsetSelect(parent = self, searchPath = True)
1364
self.mapset.SetStringSelection(grass.gisenv()['MAPSET'])
1365
bodySizer.Add(item = self.mapset,
1366
pos = (1,1), span = (1, 2))
1369
bodySizer.Add(item = wx.StaticText(parent = self, label = _("Pattern:")),
1370
flag = wx.ALIGN_CENTER_VERTICAL,
1373
self.filter = wx.TextCtrl(parent = self, id = wx.ID_ANY,
1376
bodySizer.Add(item = self.filter,
1378
pos = (2,1), span = (1, 2))
1380
self.filter.SetFocus()
1381
#TODO same text in GroupDialog
1382
self.filter.SetToolTipString(_("Put here a regular expression."
1383
" Characters '.*' stand for anything,"
1384
" character '^' stands for the beginning"
1385
" and '$' for the end."))
1388
bodySizer.Add(item = wx.StaticText(parent = self, label = _("List of maps:")),
1389
flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_TOP,
1391
self.layers = wx.CheckListBox(parent = self, id = wx.ID_ANY,
1394
bodySizer.Add(item = self.layers,
1396
pos = (3,1), span = (1, 2))
1398
bodySizer.AddGrowableCol(1)
1399
bodySizer.AddGrowableRow(3)
1402
self.mapset.Bind(wx.EVT_TEXT, self.OnChangeParams)
1403
self.layers.Bind(wx.EVT_RIGHT_DOWN, self.OnMenu)
1404
self.filter.Bind(wx.EVT_TEXT, self.OnFilter)
1405
self.toggle.Bind(wx.EVT_CHECKBOX, self.OnToggle)
1409
def LoadMapLayers(self, type, mapset):
1410
"""Load list of map layers
1412
:param str type: layer type ('raster' or 'vector')
1413
:param str mapset: mapset name
1415
self.map_layers = grass.list_grouped(type = type)[mapset]
1416
self.layers.Set(self.map_layers)
1418
# check all items by default
1419
for item in range(self.layers.GetCount()):
1421
self.layers.Check(item, check = self._selectAll())
1423
def OnChangeParams(self, event):
1424
"""Filter parameters changed by user"""
1425
# update list of layer to be loaded
1426
self.LoadMapLayers(self.GetLayerType(cmd = True),
1427
self.mapset.GetStringSelection())
1431
def OnMenu(self, event):
1432
"""Table description area, context menu"""
1433
if not hasattr(self, "popupID1"):
1434
self.popupDataID1 = wx.NewId()
1435
self.popupDataID2 = wx.NewId()
1436
self.popupDataID3 = wx.NewId()
1438
self.Bind(wx.EVT_MENU, self.OnSelectAll, id = self.popupDataID1)
1439
self.Bind(wx.EVT_MENU, self.OnSelectInvert, id = self.popupDataID2)
1440
self.Bind(wx.EVT_MENU, self.OnDeselectAll, id = self.popupDataID3)
1442
# generate popup-menu
1444
menu.Append(self.popupDataID1, _("Select all"))
1445
menu.Append(self.popupDataID2, _("Invert selection"))
1446
menu.Append(self.popupDataID3, _("Deselect all"))
1448
self.PopupMenu(menu)
1451
def OnSelectAll(self, event):
1452
"""Select all map layer from list"""
1453
for item in range(self.layers.GetCount()):
1454
self.layers.Check(item, True)
1456
def OnSelectInvert(self, event):
1457
"""Invert current selection"""
1458
for item in range(self.layers.GetCount()):
1459
if self.layers.IsChecked(item):
1460
self.layers.Check(item, False)
1462
self.layers.Check(item, True)
1464
def OnDeselectAll(self, event):
1465
"""Select all map layer from list"""
1466
for item in range(self.layers.GetCount()):
1467
self.layers.Check(item, False)
1469
def OnFilter(self, event):
1470
"""Apply filter for map names"""
1471
if len(event.GetString()) == 0:
1472
self.layers.Set(self.map_layers)
1476
for layer in self.map_layers:
1478
if re.compile(event.GetString()).search(layer):
1483
self.layers.Set(list)
1484
self.OnSelectAll(None)
1488
def OnToggle(self, event):
1489
"""Select toggle (check or uncheck all layers)"""
1490
check = event.Checked()
1491
for item in range(self.layers.GetCount()):
1492
self.layers.Check(item, check)
1496
def GetMapLayers(self):
1497
"""Return list of checked map layers"""
1499
for indx in self.layers.GetSelections():
1500
# layers.append(self.layers.GetStringSelec(indx))
1503
mapset = self.mapset.GetStringSelection()
1504
for item in range(self.layers.GetCount()):
1505
if not self.layers.IsChecked(item):
1507
if self._useFullyQualifiedNames():
1508
layerNames.append(self.layers.GetString(item) + '@' + mapset)
1510
layerNames.append(self.layers.GetString(item))
1514
def GetLayerType(self, cmd = False):
1515
"""Get selected layer type
1517
:param bool cmd: True for g.list
1520
return self.layerType.GetStringSelection()
1522
sel = self.layerType.GetSelection()
1532
class MapLayersDialog(MapLayersDialogBase):
1533
"""Subclass of MapLayersDialogBase used in Layer Manager.
1535
Contains apply button, which sends wxApplyMapLayers event.
1537
def __init__(self, parent, title, **kwargs):
1538
MapLayersDialogBase.__init__(self, parent = parent, title = title, **kwargs)
1540
def _addApplyButton(self):
1541
btnApply = wx.Button(parent = self, id = wx.ID_APPLY)
1542
self.btnSizer.AddButton(btnApply)
1543
btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
1545
def OnApply(self, event):
1546
self.applyAddingMapLayers.emit(mapLayers = self.GetMapLayers(),
1547
ltype = self.GetLayerType(cmd = True))
1549
class MapLayersDialogForGroups(MapLayersDialogBase):
1550
"""Subclass of MapLayersDialogBase used for specyfying maps in an imagery group.
1552
Shows only raster maps.
1554
def __init__(self, parent, title, **kwargs):
1555
MapLayersDialogBase.__init__(self, parent = parent, title = title, **kwargs)
1557
def _layerTypes(self):
1558
return [_('raster'),]
1560
def _selectAll(self):
1561
"""Could be overriden"""
1564
def _fullyQualifiedNames(self):
1567
def _useFullyQualifiedNames(self):
1571
class MapLayersDialogForModeler(MapLayersDialogBase):
1572
"""Subclass of MapLayersDialogBase used in Modeler.
1574
def __init__(self, parent, title, **kwargs):
1575
MapLayersDialogBase.__init__(self, parent = parent, title = title, **kwargs)
1577
def _modelerDSeries(self):
1578
self.dseries = wx.CheckBox(parent = self, id = wx.ID_ANY,
1579
label = _("Dynamic series (%s)") % 'g.list')
1580
self.dseries.SetValue(False)
1581
self.mainSizer.Add(item = self.dseries, proportion = 0,
1582
flag = wx.EXPAND | wx.LEFT | wx.RIGHT, border = 5)
1584
def GetDSeries(self):
1585
"""Used by modeler only
1587
:return: g.list command
1589
if not self.dseries or not self.dseries.IsChecked():
1592
cond = 'map in `g.list type=%s ' % self.GetLayerType(cmd = True)
1593
patt = self.filter.GetValue()
1595
cond += 'pattern=%s ' % patt
1596
cond += 'mapset=%s`' % self.mapset.GetStringSelection()
1601
class ImportDialog(wx.Dialog):
1602
"""Dialog for bulk import of various data (base class)"""
1603
def __init__(self, parent, giface, itype,
1604
id = wx.ID_ANY, title = _("Multiple import"),
1605
style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER):
1606
self.parent = parent # GMFrame
1607
self._giface = giface # used to add layers
1608
self.importType = itype
1609
self.options = dict() # list of options
1611
self.commandId = -1 # id of running command
1613
wx.Dialog.__init__(self, parent, id, title, style = style,
1614
name = "MultiImportDialog")
1616
self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
1618
self.layerBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY)
1619
if self.importType == 'gdal':
1620
label = _("List of raster layers")
1621
elif self.importType == 'ogr':
1622
label = _("List of vector layers")
1624
label = _("List of %s layers") % self.importType.upper()
1625
self.layerBox.SetLabel(" %s - %s " % (label, _("right click to (un)select all")))
1628
columns = [_('Layer id'),
1630
_('Name for output GRASS map (editable)')]
1632
columns.insert(2, _('Feature type'))
1633
columns.insert(3, _('Projection match'))
1635
self.list = LayersList(parent = self.panel, columns = columns)
1636
self.list.LoadData()
1638
self.optionBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
1639
label = "%s" % _("Options"))
1641
cmd = self._getCommand()
1642
task = gtask.parse_interface(cmd)
1643
for f in task.get_options()['flags']:
1644
name = f.get('name', '')
1645
desc = f.get('label', '')
1647
desc = f.get('description', '')
1648
if not name and not desc:
1650
if cmd == 'r.in.gdal' and name not in ('o', 'e', 'l', 'k'):
1652
elif cmd == 'r.external' and name not in ('o', 'e', 'r', 'h', 'v'):
1654
elif cmd == 'v.in.ogr' and name not in ('c', 'z', 't', 'o', 'r', 'e', 'w'):
1656
elif cmd == 'v.external' and name not in ('b'):
1658
elif cmd == 'v.in.dxf' and name not in ('e', 't', 'b', 'f', 'i'):
1660
self.options[name] = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
1664
self.overwrite = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
1665
label = _("Allow output files to overwrite existing files"))
1666
self.overwrite.SetValue(UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'))
1668
self.add = wx.CheckBox(parent = self.panel, id = wx.ID_ANY)
1669
self.closeOnFinish = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
1670
label = _("Close dialog on finish"))
1671
self.closeOnFinish.SetValue(UserSettings.Get(group = 'cmd', key = 'closeDlg', subkey = 'enabled'))
1677
self.btn_close = wx.Button(parent = self.panel, id = wx.ID_CLOSE)
1678
self.btn_close.SetToolTipString(_("Close dialog"))
1679
self.btn_close.Bind(wx.EVT_BUTTON, self.OnClose)
1681
self.btn_run = wx.Button(parent = self.panel, id = wx.ID_OK, label = _("&Import"))
1682
self.btn_run.SetToolTipString(_("Import selected layers"))
1683
self.btn_run.SetDefault()
1684
self.btn_run.Bind(wx.EVT_BUTTON, self.OnRun)
1686
self.Bind(wx.EVT_CLOSE, lambda evt: self.Destroy())
1690
dialogSizer = wx.BoxSizer(wx.VERTICAL)
1693
dialogSizer.Add(item = self.dsnInput, proportion = 0,
1697
# list of DXF layers
1699
layerSizer = wx.StaticBoxSizer(self.layerBox, wx.HORIZONTAL)
1701
layerSizer.Add(item = self.list, proportion = 1,
1702
flag = wx.ALL | wx.EXPAND, border = 5)
1704
dialogSizer.Add(item = layerSizer, proportion = 1,
1705
flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
1708
optionSizer = wx.StaticBoxSizer(self.optionBox, wx.VERTICAL)
1709
for key in self.options.keys():
1710
optionSizer.Add(item = self.options[key], proportion = 0)
1712
dialogSizer.Add(item = optionSizer, proportion = 0,
1713
flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
1715
dialogSizer.Add(item = self.overwrite, proportion = 0,
1716
flag = wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
1718
dialogSizer.Add(item = self.add, proportion = 0,
1719
flag = wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
1721
dialogSizer.Add(item = self.closeOnFinish, proportion = 0,
1722
flag = wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
1726
btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
1728
btnsizer.Add(item = self.btn_close, proportion = 0,
1729
flag = wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER,
1732
btnsizer.Add(item = self.btn_run, proportion = 0,
1733
flag = wx.RIGHT | wx.ALIGN_CENTER,
1736
dialogSizer.Add(item = btnsizer, proportion = 0,
1737
flag = wx.ALIGN_CENTER_VERTICAL | wx.BOTTOM | wx.ALIGN_RIGHT,
1740
# dialogSizer.SetSizeHints(self.panel)
1741
self.panel.SetAutoLayout(True)
1742
self.panel.SetSizer(dialogSizer)
1743
dialogSizer.Fit(self.panel)
1745
# auto-layout seems not work here - FIXME
1746
size = wx.Size(globalvar.DIALOG_GSELECT_SIZE[0] + 225, 550)
1747
self.SetMinSize(size)
1748
self.SetSize((size.width, size.height + 100))
1749
# width = self.GetSize()[0]
1750
# self.list.SetColumnWidth(col = 1, width = width / 2 - 50)
1753
def _getCommand(self):
1757
def OnClose(self, event = None):
1761
def OnRun(self, event):
1762
"""Import/Link data (each layes as separate vector map)"""
1765
def AddLayers(self, returncode, cmd = None):
1766
"""Add imported/linked layers into layer tree"""
1767
if not self.add.IsChecked() or returncode != 0:
1770
# TODO: if importing map creates more map the folowing does not work
1771
# * do nothing if map does not exist or
1772
# * try to determine names using regexp or
1773
# * persuade import tools to report map names
1775
layer, output = self.list.GetLayers()[self.commandId]
1777
if '@' not in output:
1778
name = output + '@' + grass.gisenv()['MAPSET']
1782
# add imported layers into layer tree
1783
# an alternative would be emit signal (mapCreated) and (optionally)
1784
# connect to this signal
1785
llist = self._giface.GetLayerList()
1786
if self.importType == 'gdal':
1789
if UserSettings.Get(group = 'rasterLayer', key = 'opaque', subkey = 'enabled'):
1792
llist.AddLayer(ltype='raster',
1793
name=name, checked=True,
1796
llist.AddLayer(ltype='vector',
1797
name=name, checked=True,
1799
'map=%s' % name] + GetDisplayVectSettings())
1801
self._giface.GetMapWindow().ZoomToMap()
1803
def OnAbort(self, event):
1804
"""Abort running import
1811
def OnCmdDone(self, cmd, returncode):
1812
"""Do what has to be done after importing"""
1816
class GdalImportDialog(ImportDialog):
1817
def __init__(self, parent, giface, ogr = False, link = False):
1818
"""Dialog for bulk import of various raster/vector data
1821
Split into GdalImportDialog and OgrImportDialog
1823
:param parent: parent window
1824
:param ogr: True for OGR (vector) otherwise GDAL (raster)
1825
:param link: True for linking data otherwise importing data
1827
self._giface = giface
1832
ImportDialog.__init__(self, parent, giface=giface, itype='ogr')
1834
self.SetTitle(_("Link external vector data"))
1836
self.SetTitle(_("Import vector data"))
1838
ImportDialog.__init__(self, parent, giface=giface, itype='gdal')
1840
self.SetTitle(_("Link external raster data"))
1842
self.SetTitle(_("Import raster data"))
1844
self.dsnInput = GdalSelect(parent = self, panel = self.panel,
1845
ogr = ogr, link = link)
1846
self.dsnInput.reloadDataRequired.connect(lambda data: self.list.LoadData(data))
1848
mightNotWork = _("this might not work for multiple bands")
1850
self.add.SetLabel(_("Add linked layers into layer tree"
1851
" ({mightNotWork})".format(mightNotWork=mightNotWork)))
1853
self.add.SetLabel(_("Add imported layers into layer tree"
1854
" ({mightNotWork})".format(mightNotWork=mightNotWork)))
1856
self.add.SetValue(UserSettings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
1859
self.btn_run.SetLabel(_("&Link"))
1860
self.btn_run.SetToolTipString(_("Link selected layers"))
1862
self.btn_run.SetLabel(_("&Import"))
1863
self.btn_run.SetToolTipString(_("Import selected layers"))
1867
def OnRun(self, event):
1868
"""Import/Link data (each layes as separate vector map)"""
1870
data = self.list.GetLayers()
1872
GMessage(_("No layers selected. Operation canceled."),
1876
dsn = self.dsnInput.GetDsn()
1877
ext = self.dsnInput.GetFormatExt()
1879
# determine data driver for PostGIS links
1881
if self.importType == 'ogr' and \
1882
self.dsnInput.GetType() == 'db' and \
1883
self.dsnInput.GetFormat() == 'PostgreSQL' and \
1884
'GRASS_VECTOR_OGR' not in os.environ:
1886
os.environ['GRASS_VECTOR_OGR'] = '1'
1888
for layer, output in data:
1889
if self.importType == 'ogr':
1890
if ext and layer.rfind(ext) > -1:
1891
layer = layer.replace('.' + ext, '')
1893
layer, geometry = layer.split('|', 1)
1897
cmd = ['v.external',
1899
'output=%s' % output,
1905
'output=%s' % output,
1906
'geometry=%s' % geometry]
1908
if self.dsnInput.GetType() == 'dir':
1909
idsn = os.path.join(dsn, layer)
1914
cmd = ['r.external',
1916
'output=%s' % output]
1920
'output=%s' % output]
1922
if self.overwrite.IsChecked():
1923
cmd.append('--overwrite')
1925
for key in self.options.keys():
1926
if self.options[key].IsChecked():
1927
cmd.append('-%s' % key)
1929
if UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled') and \
1930
'--overwrite' not in cmd:
1931
cmd.append('--overwrite')
1933
# run in Layer Manager
1934
self._giface.RunCmd(cmd, onDone=self.OnCmdDone)
1936
def OnCmdDone(self, cmd, returncode):
1937
"""Load layers and close if required"""
1938
if not hasattr(self, 'AddLayers'):
1941
self.AddLayers(cmd, returncode)
1944
os.environ.pop('GRASS_VECTOR_OGR')
1946
if returncode == 0 and self.closeOnFinish.IsChecked():
1949
def _getCommand(self):
1964
class GdalOutputDialog(wx.Dialog):
1965
def __init__(self, parent, id = wx.ID_ANY, ogr = False,
1966
style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, *kwargs):
1967
"""Dialog for setting output format for rasters/vectors
1970
Split into GdalOutputDialog and OgrOutputDialog
1972
:param parent: parent window
1973
:param id: window id
1974
:param ogr: True for OGR (vector) otherwise GDAL (raster)
1975
:param style: window style
1976
:param *kwargs: other wx.Dialog's arguments
1978
self.parent = parent # GMFrame
1980
wx.Dialog.__init__(self, parent, id = id, style = style, *kwargs)
1982
self.SetTitle(_("Define output format for vector data"))
1984
self.SetTitle(_("Define output format for raster data"))
1986
self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
1989
self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
1990
self.btnCancel.SetToolTipString(_("Close dialog"))
1991
self.btnOk = wx.Button(parent = self.panel, id = wx.ID_OK)
1992
self.btnOk.SetToolTipString(_("Set external format and close dialog"))
1993
self.btnOk.SetDefault()
1995
self.dsnInput = GdalSelect(parent = self, panel = self.panel,
1997
exclude = ['file', 'protocol'], dest = True)
1999
self.Bind(wx.EVT_BUTTON, self.OnCancel, self.btnCancel)
2000
self.Bind(wx.EVT_BUTTON, self.OnOK, self.btnOk)
2005
dialogSizer = wx.BoxSizer(wx.VERTICAL)
2007
dialogSizer.Add(item = self.dsnInput, proportion = 1,
2010
btnSizer = wx.BoxSizer(orient = wx.HORIZONTAL)
2011
btnSizer.Add(item = self.btnCancel, proportion = 0,
2012
flag = wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER,
2014
btnSizer.Add(item = self.btnOk, proportion = 0,
2015
flag = wx.RIGHT | wx.ALIGN_CENTER,
2018
dialogSizer.Add(item = btnSizer, proportion = 0,
2019
flag = wx.ALIGN_CENTER_VERTICAL | wx.BOTTOM | wx.TOP | wx.ALIGN_RIGHT,
2022
self.panel.SetAutoLayout(True)
2023
self.panel.SetSizer(dialogSizer)
2024
dialogSizer.Fit(self.panel)
2026
size = wx.Size(globalvar.DIALOG_GSELECT_SIZE[0] + 225, self.GetBestSize()[1] + 35)
2027
self.SetMinSize(size)
2028
self.SetSize((size.width, size.height))
2031
def OnCancel(self, event):
2034
def OnOK(self, event):
2035
if self.dsnInput.GetType() == 'native':
2036
RunCommand('v.external.out',
2040
dsn = self.dsnInput.GetDsn()
2041
frmt = self.dsnInput.GetFormat()
2042
options = self.dsnInput.GetOptions()
2044
GMessage(_("No data source selected."), parent=self)
2047
RunCommand('v.external.out',
2049
output = dsn, format = frmt,
2053
class DxfImportDialog(ImportDialog):
2054
"""Dialog for bulk import of DXF layers"""
2055
def __init__(self, parent, giface):
2056
ImportDialog.__init__(self, parent, giface=giface, itype='dxf',
2057
title = _("Import DXF layers"))
2058
self._giface = giface
2059
self.dsnInput = filebrowse.FileBrowseButton(parent = self.panel, id = wx.ID_ANY,
2060
size = globalvar.DIALOG_GSELECT_SIZE, labelText = '',
2061
dialogTitle = _('Choose DXF file to import'),
2062
buttonText = _('Browse'),
2063
startDirectory = os.getcwd(), fileMode = 0,
2064
changeCallback = self.OnSetDsn,
2065
fileMask = "DXF File (*.dxf)|*.dxf")
2067
self.add.SetLabel(_("Add imported layers into layer tree"))
2069
self.add.SetValue(UserSettings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
2073
def _getCommand(self):
2077
def OnRun(self, event):
2078
"""Import/Link data (each layes as separate vector map)"""
2079
data = self.list.GetLayers()
2081
GMessage(_("No layers selected."), parent=self)
2087
inputDxf = self.dsnInput.GetValue()
2089
for layer, output in data:
2091
'input=%s' % inputDxf,
2092
'layers=%s' % layer,
2093
'output=%s' % output]
2095
for key in self.options.keys():
2096
if self.options[key].IsChecked():
2097
cmd.append('-%s' % key)
2099
if self.overwrite.IsChecked() or \
2100
UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'):
2101
cmd.append('--overwrite')
2103
# run in Layer Manager
2104
self._giface.RunCmd(cmd, onDone=self.OnCmdDone)
2106
def OnCmdDone(self, cmd, returncode):
2107
"""Load layers and close if required"""
2108
if not hasattr(self, 'AddLayers'):
2111
self.AddLayers(cmd, returncode)
2113
if self.closeOnFinish.IsChecked():
2116
def OnSetDsn(self, event):
2117
"""Input DXF file defined, update list of layer widget"""
2118
path = event.GetString()
2123
ret = RunCommand('v.in.dxf',
2130
self.list.LoadData()
2133
for line in ret.splitlines():
2134
layerId = line.split(':')[0].split(' ')[1]
2135
layerName = line.split(':')[1].strip()
2136
grassName = GetValidLayerName(layerName)
2137
data.append((layerId, layerName.strip(), grassName.strip()))
2139
self.list.LoadData(data)
2142
class LayersList(GListCtrl, listmix.TextEditMixin):
2143
"""List of layers to be imported (dxf, shp...)"""
2144
def __init__(self, parent, columns, log = None):
2145
GListCtrl.__init__(self, parent)
2150
listmix.TextEditMixin.__init__(self)
2152
for i in range(len(columns)):
2153
self.InsertColumn(i, columns[i])
2155
if len(columns) == 3:
2158
width = (65, 180, 90, 70)
2160
for i in range(len(width)):
2161
self.SetColumnWidth(col = i, width = width[i])
2163
def LoadData(self, data = None):
2164
"""Load data into list"""
2165
self.DeleteAllItems()
2170
index = self.InsertStringItem(sys.maxint, str(item[0]))
2171
for i in range(1, len(item)):
2172
self.SetStringItem(index, i, item[i])
2174
# check by default only on one item
2176
self.CheckItem(index, True)
2178
def OnLeftDown(self, event):
2179
"""Allow editing only output name
2181
Code taken from TextEditMixin class.
2183
x, y = event.GetPosition()
2187
for n in range(self.GetColumnCount()):
2188
loc = loc + self.GetColumnWidth(n)
2191
col = bisect(colLocs, x + self.GetScrollPos(wx.HORIZONTAL)) - 1
2193
if col == self.GetColumnCount() - 1:
2194
listmix.TextEditMixin.OnLeftDown(self, event)
2198
def GetLayers(self):
2199
"""Get list of layers (layer name, output name)"""
2203
item = self.GetNextItem(item)
2206
if not self.IsChecked(item):
2208
# layer / output name
2209
layer = self.GetItem(item, 1).GetText()
2210
ftype = self.GetItem(item, 2).GetText()
2212
layer += '|%s' % ftype.split('/', 1)[0]
2213
output = self.GetItem(item, self.GetColumnCount() - 1).GetText()
2214
data.append((layer, output))
2218
class SetOpacityDialog(wx.Dialog):
2219
"""Set opacity of map layers.
2220
Dialog expects opacity between 0 and 1 and returns this range, too.
2222
def __init__(self, parent, id = wx.ID_ANY, title = _("Set Map Layer Opacity"),
2223
size = wx.DefaultSize, pos = wx.DefaultPosition,
2224
style = wx.DEFAULT_DIALOG_STYLE, opacity = 1):
2226
self.parent = parent # GMFrame
2227
self.opacity = opacity # current opacity
2229
super(SetOpacityDialog, self).__init__(parent, id = id, pos = pos,
2230
size = size, style = style, title = title)
2232
self.applyOpacity = Signal('SetOpacityDialog.applyOpacity')
2233
panel = wx.Panel(parent = self, id = wx.ID_ANY)
2235
sizer = wx.BoxSizer(wx.VERTICAL)
2237
box = wx.GridBagSizer(vgap = 5, hgap = 5)
2238
self.value = wx.Slider(panel, id = wx.ID_ANY, value = int(self.opacity * 100),
2239
style = wx.SL_HORIZONTAL | wx.SL_AUTOTICKS | \
2240
wx.SL_TOP | wx.SL_LABELS,
2241
minValue = 0, maxValue = 100,
2244
box.Add(item = self.value,
2245
flag = wx.ALIGN_CENTRE, pos = (0, 0), span = (1, 2))
2246
box.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
2247
label = _("transparent")),
2249
box.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
2250
label = _("opaque")),
2251
flag = wx.ALIGN_RIGHT,
2254
sizer.Add(item = box, proportion = 0,
2255
flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5)
2257
line = wx.StaticLine(parent = panel, id = wx.ID_ANY,
2258
style = wx.LI_HORIZONTAL)
2259
sizer.Add(item = line, proportion = 0,
2260
flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5)
2263
btnsizer = wx.StdDialogButtonSizer()
2265
btnOK = wx.Button(parent = panel, id = wx.ID_OK)
2267
btnsizer.AddButton(btnOK)
2269
btnCancel = wx.Button(parent = panel, id = wx.ID_CANCEL)
2270
btnsizer.AddButton(btnCancel)
2272
btnApply = wx.Button(parent = panel, id = wx.ID_APPLY)
2273
btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
2274
btnsizer.AddButton(btnApply)
2277
sizer.Add(item = btnsizer, proportion = 0,
2278
flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5)
2280
panel.SetSizer(sizer)
2283
self.SetSize(self.GetBestSize())
2287
def GetOpacity(self):
2288
"""Button 'OK' pressed"""
2289
# return opacity value
2290
opacity = float(self.value.GetValue()) / 100
2293
def OnApply(self, event):
2294
self.applyOpacity.emit(value = self.GetOpacity())
2297
def GetImageHandlers(image):
2298
"""Get list of supported image handlers"""
2301
for h in image.GetHandlers():
2302
lext.append(h.GetExtension())
2306
filetype += "PNG file (*.png)|*.png|"
2307
ltype.append({ 'type' : wx.BITMAP_TYPE_PNG,
2309
filetype += "BMP file (*.bmp)|*.bmp|"
2310
ltype.append({ 'type' : wx.BITMAP_TYPE_BMP,
2313
filetype += "GIF file (*.gif)|*.gif|"
2314
ltype.append({ 'type' : wx.BITMAP_TYPE_GIF,
2318
filetype += "JPG file (*.jpg)|*.jpg|"
2319
ltype.append({ 'type' : wx.BITMAP_TYPE_JPEG,
2323
filetype += "PCX file (*.pcx)|*.pcx|"
2324
ltype.append({ 'type' : wx.BITMAP_TYPE_PCX,
2328
filetype += "PNM file (*.pnm)|*.pnm|"
2329
ltype.append({ 'type' : wx.BITMAP_TYPE_PNM,
2333
filetype += "TIF file (*.tif)|*.tif|"
2334
ltype.append({ 'type' : wx.BITMAP_TYPE_TIF,
2338
filetype += "XPM file (*.xpm)|*.xpm"
2339
ltype.append({ 'type' : wx.BITMAP_TYPE_XPM,
2342
return filetype, ltype
2344
class ImageSizeDialog(wx.Dialog):
2345
"""Set size for saved graphic file"""
2346
def __init__(self, parent, id = wx.ID_ANY, title = _("Set image size"),
2347
style = wx.DEFAULT_DIALOG_STYLE, **kwargs):
2348
self.parent = parent
2350
wx.Dialog.__init__(self, parent, id = id, style = style, title = title, **kwargs)
2352
self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
2354
self.box = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
2355
label = ' % s' % _("Image size"))
2357
size = self.parent.GetWindow().GetClientSize()
2358
self.width = wx.SpinCtrl(parent = self.panel, id = wx.ID_ANY,
2359
style = wx.SP_ARROW_KEYS)
2360
self.width.SetRange(20, 1e6)
2361
self.width.SetValue(size.width)
2362
wx.CallAfter(self.width.SetFocus)
2363
self.height = wx.SpinCtrl(parent = self.panel, id = wx.ID_ANY,
2364
style = wx.SP_ARROW_KEYS)
2365
self.height.SetRange(20, 1e6)
2366
self.height.SetValue(size.height)
2367
self.template = wx.Choice(parent = self.panel, id = wx.ID_ANY,
2377
self.btnOK = wx.Button(parent = self.panel, id = wx.ID_OK)
2378
self.btnOK.SetDefault()
2379
self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
2381
self.template.Bind(wx.EVT_CHOICE, self.OnTemplate)
2384
self.SetSize(self.GetBestSize())
2388
sizer = wx.BoxSizer(wx.VERTICAL)
2391
box = wx.StaticBoxSizer(self.box, wx.HORIZONTAL)
2392
fbox = wx.FlexGridSizer(cols = 2, vgap = 5, hgap = 5)
2393
fbox.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
2394
label = _("Width:")),
2395
flag = wx.ALIGN_CENTER_VERTICAL)
2396
fbox.Add(item = self.width)
2397
fbox.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
2398
label = _("Height:")),
2399
flag = wx.ALIGN_CENTER_VERTICAL)
2400
fbox.Add(item = self.height)
2401
fbox.Add(item = wx.StaticText(parent = self.panel, id = wx.ID_ANY,
2402
label = _("Template:")),
2403
flag = wx.ALIGN_CENTER_VERTICAL)
2404
fbox.Add(item = self.template)
2406
box.Add(item = fbox, proportion = 1,
2407
flag = wx.EXPAND | wx.ALL, border = 5)
2408
sizer.Add(item = box, proportion = 1,
2409
flag=wx.EXPAND | wx.ALL, border = 3)
2412
btnsizer = wx.StdDialogButtonSizer()
2413
btnsizer.AddButton(self.btnOK)
2414
btnsizer.AddButton(self.btnCancel)
2417
sizer.Add(item = btnsizer, proportion = 0,
2418
flag = wx.EXPAND | wx.ALIGN_RIGHT | wx.ALL, border=5)
2420
self.panel.SetSizer(sizer)
2421
sizer.Fit(self.panel)
2424
def GetValues(self):
2425
"""Get width/height values"""
2426
return self.width.GetValue(), self.height.GetValue()
2428
def OnTemplate(self, event):
2429
"""Template selected"""
2430
sel = event.GetString()
2432
width, height = self.parent.GetWindow().GetClientSize()
2434
width, height = map(int, sel.split('x'))
2435
self.width.SetValue(width)
2436
self.height.SetValue(height)
2438
class SqlQueryFrame(wx.Frame):
2439
def __init__(self, parent, id = wx.ID_ANY,
2440
title = _("GRASS GIS SQL Query Utility"),
2442
"""SQL Query Utility window
2444
self.parent = parent
2446
wx.Frame.__init__(self, parent = parent, id = id, title = title, *kwargs)
2447
self.SetIcon(wx.Icon(os.path.join(globalvar.ICONDIR, 'grass_sql.ico'), wx.BITMAP_TYPE_ICO))
2448
self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
2450
self.sqlBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
2451
label = _(" SQL statement "))
2452
self.sql = wx.TextCtrl(parent = self.panel, id = wx.ID_ANY,
2453
style = wx.TE_MULTILINE)
2455
self.btnApply = wx.Button(parent = self.panel, id = wx.ID_APPLY)
2456
self.btnCancel = wx.Button(parent = self.panel, id = wx.ID_CANCEL)
2457
self.Bind(wx.EVT_BUTTON, self.OnCloseWindow, self.btnCancel)
2461
self.SetMinSize(wx.Size(300, 150))
2462
self.SetSize(wx.Size(500, 200))
2466
sizer = wx.BoxSizer(wx.VERTICAL)
2468
sqlSizer = wx.StaticBoxSizer(self.sqlBox, wx.HORIZONTAL)
2469
sqlSizer.Add(item = self.sql, proportion = 1,
2472
btnSizer = wx.StdDialogButtonSizer()
2473
btnSizer.AddButton(self.btnApply)
2474
btnSizer.AddButton(self.btnCancel)
2477
sizer.Add(item = sqlSizer, proportion = 1,
2478
flag = wx.EXPAND | wx.ALL, border = 5)
2479
sizer.Add(item = btnSizer, proportion = 0,
2480
flag = wx.EXPAND | wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
2482
self.panel.SetSizer(sizer)
2486
def OnCloseWindow(self, event):
2491
class SymbolDialog(wx.Dialog):
2492
"""Dialog for GRASS symbols selection.
2494
Dialog is called in gui_core::forms module.
2496
def __init__(self, parent, symbolPath, currentSymbol = None, title = _("Symbols")):
2497
"""Dialog constructor.
2499
It is assumed that symbolPath contains folders with symbols.
2501
:param parent: dialog parent
2502
:param symbolPath: absolute path to symbols
2503
:param currentSymbol: currently selected symbol (e.g. 'basic/x')
2504
:param title: dialog title
2506
wx.Dialog.__init__(self, parent = parent, title = title, id = wx.ID_ANY)
2508
self.symbolPath = symbolPath
2509
self.currentSymbol = currentSymbol # default basic/x
2510
self.selected = None
2511
self.selectedDir = None
2516
mainPanel = wx.Panel(self, id = wx.ID_ANY)
2517
mainSizer = wx.BoxSizer(wx.VERTICAL)
2518
vSizer = wx.BoxSizer( wx.VERTICAL)
2519
fgSizer = wx.FlexGridSizer(rows = 2, vgap = 5, hgap = 5)
2520
self.folderChoice = wx.Choice(mainPanel, id = wx.ID_ANY, choices = os.listdir(self.symbolPath))
2521
self.folderChoice.Bind(wx.EVT_CHOICE, self.OnFolderSelect)
2523
fgSizer.Add(item = wx.StaticText(mainPanel, id = wx.ID_ANY, label = _("Symbol directory:")),
2525
flag = wx.ALIGN_CENTER_VERTICAL)
2527
fgSizer.Add(item = self.folderChoice, proportion = 0,
2528
flag = wx.ALIGN_CENTER, border = 0)
2530
self.infoLabel = wx.StaticText(mainPanel, id = wx.ID_ANY)
2531
fgSizer.Add(wx.StaticText(mainPanel, id = wx.ID_ANY, label = _("Symbol name:")),
2532
flag = wx.ALIGN_CENTRE_VERTICAL)
2533
fgSizer.Add(self.infoLabel, proportion = 0,
2534
flag = wx.ALIGN_CENTRE_VERTICAL)
2535
vSizer.Add(fgSizer, proportion = 0, flag = wx.ALL, border = 5)
2537
self.panels = self._createSymbolPanels(mainPanel)
2538
for panel in self.panels:
2539
vSizer.Add(panel, proportion = 0, flag = wx.ALL | wx.EXPAND, border = 5)
2541
mainSizer.Add(vSizer, proportion = 1, flag = wx.ALL| wx.EXPAND, border = 5)
2542
self.btnCancel = wx.Button(parent = mainPanel, id = wx.ID_CANCEL)
2543
self.btnOK = wx.Button(parent = mainPanel, id = wx.ID_OK)
2544
self.btnOK.SetDefault()
2545
self.btnOK.Enable(False)
2548
btnSizer = wx.StdDialogButtonSizer()
2549
btnSizer.AddButton(self.btnCancel)
2550
btnSizer.AddButton(self.btnOK)
2552
mainSizer.Add(item = btnSizer, proportion = 0,
2553
flag = wx.EXPAND | wx.ALL, border = 5)
2555
# show panel with the largest number of images and fit size
2557
for folder in os.listdir(self.symbolPath):
2558
count.append(len(os.listdir(os.path.join(self.symbolPath, folder))))
2560
index = count.index(max(count))
2561
self.folderChoice.SetSelection(index)
2562
self.OnFolderSelect(None)
2563
self.infoLabel.Show()
2565
mainPanel.SetSizerAndFit(mainSizer)
2566
self.SetSize(self.GetBestSize())
2568
# show currently selected symbol
2569
if self.currentSymbol:
2571
self.selectedDir, self.selected = os.path.split(self.currentSymbol)
2572
self.folderChoice.SetStringSelection(self.selectedDir)
2574
panelIdx = self.folderChoice.GetSelection()
2575
for panel in self.symbolPanels[panelIdx]:
2576
if panel.GetName() == self.selected:
2579
self.folderChoice.SetSelection(0)
2581
self.OnFolderSelect(None)
2583
def _createSymbolPanels(self, parent):
2584
"""Creates multiple panels with symbols.
2586
Panels are shown/hidden according to selected folder."""
2587
folders = os.listdir(self.symbolPath)
2590
self.symbolPanels = []
2592
for folder in folders:
2593
panel = wx.Panel(parent, style = wx.BORDER_RAISED)
2594
sizer = wx.GridSizer(cols = 6, vgap = 3, hgap = 3)
2595
images = self._getSymbols(path = os.path.join(self.symbolPath, folder))
2599
iP = SingleSymbolPanel(parent = panel, symbolPath = img)
2600
iP.symbolSelectionChanged.connect(self.SelectionChanged)
2601
sizer.Add(item = iP, proportion = 0, flag = wx.ALIGN_CENTER)
2602
symbolPanels.append(iP)
2604
panel.SetSizerAndFit(sizer)
2606
panels.append(panel)
2607
self.symbolPanels.append(symbolPanels)
2611
def _getSymbols(self, path):
2612
# we assume that images are in subfolders (1 level only)
2614
for image in os.listdir(path):
2615
imageList.append(os.path.join(path, image))
2617
return sorted(imageList)
2619
def OnFolderSelect(self, event):
2620
"""Selected folder with symbols changed."""
2621
idx = self.folderChoice.GetSelection()
2622
for i in range(len(self.panels)):
2623
sizer = self.panels[i].GetContainingSizer()
2624
sizer.Show(self.panels[i], i == idx, recursive = True)
2627
if self.selectedDir == self.folderChoice.GetStringSelection():
2629
self.infoLabel.SetLabel(self.selected)
2631
self.btnOK.Disable()
2632
self.infoLabel.SetLabel('')
2634
def SelectionChanged(self, name, doubleClick):
2635
"""Selected symbol changed."""
2637
self.EndModal(wx.ID_OK)
2639
for i in range(len(self.panels)):
2640
for panel in self.symbolPanels[i]:
2641
if panel.GetName() != name:
2646
self.selected = name
2647
self.selectedDir = self.folderChoice.GetStringSelection()
2649
self.infoLabel.SetLabel(name)
2651
def GetSelectedSymbolName(self):
2652
"""Returns currently selected symbol name (e.g. 'basic/x').
2654
# separator must be '/' and not dependent on OS
2655
return self.selectedDir + '/' + self.selected
2657
def GetSelectedSymbolPath(self):
2658
"""Returns currently selected symbol full path.
2660
return os.path.join(self.symbolPath, self.selectedDir, self.selected)
2663
class TextEntryDialog(wx.Dialog):
2664
"""Simple dialog with text field.
2666
It differs from wx.TextEntryDialog because it allows adding validator.
2668
def __init__(self, parent, message, caption='',
2669
defaultValue='', validator=wx.DefaultValidator,
2670
style=wx.OK | wx.CANCEL, **kwargs):
2671
wx.Dialog.__init__(self, parent=parent, id=wx.ID_ANY, title=caption, **kwargs)
2673
vbox = wx.BoxSizer(wx.VERTICAL)
2675
stline = wx.StaticText(self, id=wx.ID_ANY, label=message)
2676
vbox.Add(item=stline, proportion=0, flag=wx.EXPAND | wx.ALL, border=10)
2678
self._textCtrl = wx.TextCtrl(self, id=wx.ID_ANY, size = (300, -1),
2679
value=defaultValue, validator=validator)
2680
vbox.Add(item=self._textCtrl, proportion=0, flag=wx.EXPAND | wx.LEFT | wx.RIGHT, border=10)
2681
self._textCtrl.SetFocus()
2683
sizer = self.CreateSeparatedButtonSizer(style)
2684
vbox.Add(item=sizer, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
2686
self.SetSizerAndFit(vbox)
2689
return self._textCtrl.GetValue()
2691
def SetValue(self, value):
2692
self._textCtrl.SetValue(value)
2695
class HyperlinkDialog(wx.Dialog):
2696
"""Dialog for displaying message with hyperlink."""
2697
def __init__(self, parent, title, message, hyperlink,
2698
hyperlinkLabel=None, style=wx.OK):
2701
:param parent: gui parent
2702
:param title: dialog title
2703
:param message: message
2704
:param hyperlink: url
2705
:param hyperlinkLabel: label shown instead of url
2706
:param style: button style
2708
wx.Dialog.__init__(self, parent=parent, id=wx.ID_ANY, title=title,
2709
style=wx.DEFAULT_DIALOG_STYLE)
2711
sizer = wx.BoxSizer(wx.VERTICAL)
2713
label = wx.StaticText(self, label=message)
2714
sizer.Add(item=label, proportion=0, flag=wx.ALIGN_CENTRE|wx.ALL, border=10)
2715
hyperlinkLabel = hyperlinkLabel if hyperlinkLabel else hyperlink
2716
hyperlinkCtrl = wx.HyperlinkCtrl(self, id=wx.ID_ANY,
2717
label=hyperlinkLabel, url=hyperlink,
2718
style=wx.HL_ALIGN_LEFT|wx.HL_CONTEXTMENU)
2719
sizer.Add(item=hyperlinkCtrl, proportion=0, flag=wx.EXPAND|wx.ALL, border=10)
2721
btnsizer = self.CreateSeparatedButtonSizer(style)
2722
sizer.Add(item=btnsizer, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
2724
self.SetSizer(sizer)