~ubuntu-branches/ubuntu/wily/grass/wily

« back to all changes in this revision

Viewing changes to gui/wxpython/gui_core/dialogs.py

Tags: 7.0.0~rc1+ds1-1~exp1
* New upstream release candidate.
* Repack upstream tarball, remove precompiled Python objects.
* Add upstream metadata.
* Update gbp.conf and Vcs-Git URL to use the experimental branch.
* Update watch file for GRASS 7.0.
* Drop build dependencies for Tcl/Tk, add build dependencies:
  python-numpy, libnetcdf-dev, netcdf-bin, libblas-dev, liblapack-dev
* Update Vcs-Browser URL to use cgit instead of gitweb.
* Update paths to use grass70.
* Add configure options: --with-netcdf, --with-blas, --with-lapack,
  remove --with-tcltk-includes.
* Update patches for GRASS 7.
* Update copyright file, changes:
  - Update copyright years
  - Group files by license
  - Remove unused license sections
* Add patches for various typos.
* Fix desktop file with patch instead of d/rules.
* Use minimal dh rules.
* Bump Standards-Version to 3.9.6, no changes.
* Use dpkg-maintscript-helper to replace directories with symlinks.
  (closes: #776349)
* Update my email to use @debian.org address.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""
 
2
@package gui_core.dialogs
 
3
 
 
4
@brief Various dialogs used in wxGUI.
 
5
 
 
6
List of classes:
 
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`
 
24
 
 
25
(C) 2008-2011 by the GRASS Development Team
 
26
 
 
27
This program is free software under the GNU General Public License
 
28
(>=v2). Read the file COPYING that comes with GRASS for details.
 
29
 
 
30
@author Martin Landa <landa.martin gmail.com>
 
31
@author Anna Kratochvilova <kratochanna gmail.com> (GroupDialog, SymbolDialog)
 
32
"""
 
33
 
 
34
import os
 
35
import sys
 
36
import re
 
37
from bisect import bisect
 
38
 
 
39
import wx
 
40
import wx.lib.filebrowsebutton as filebrowse
 
41
import wx.lib.mixins.listctrl as listmix
 
42
 
 
43
from grass.script import core as grass
 
44
from grass.script import task as gtask
 
45
 
 
46
from grass.pydispatch.signal import Signal
 
47
 
 
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, \
 
52
                             SubGroupSelect
 
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
 
57
 
 
58
class SimpleDialog(wx.Dialog):
 
59
    def __init__(self, parent, title, id = wx.ID_ANY,
 
60
                 style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER,
 
61
                 **kwargs):
 
62
        """General dialog to choose given element (location, mapset, vector map, etc.)
 
63
        
 
64
        :param parent: window
 
65
        :param title: window title
 
66
        """
 
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)
 
70
        
 
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()
 
74
                
 
75
        self.__layout()
 
76
        self.warning = _("Required item is not set.")
 
77
 
 
78
    def __layout(self):
 
79
        """Do layout"""
 
80
        self.sizer = wx.BoxSizer(wx.VERTICAL)
 
81
        
 
82
        self.dataSizer = wx.BoxSizer(wx.VERTICAL)
 
83
        
 
84
        # self.informLabel = wx.StaticText(self.panel, id = wx.ID_ANY)
 
85
        # buttons
 
86
        btnSizer = wx.StdDialogButtonSizer()
 
87
        btnSizer.AddButton(self.btnCancel)
 
88
        btnSizer.AddButton(self.btnOK)
 
89
        btnSizer.Realize()
 
90
        
 
91
        self.sizer.Add(item = self.dataSizer, proportion = 1,
 
92
                       flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
 
93
        
 
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)
 
97
 
 
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)
 
102
 
 
103
 
 
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)
 
108
 
 
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.")
 
119
        self._layout()
 
120
        self.SetMinSize(self.GetSize())
 
121
 
 
122
    def _layout(self):
 
123
        """Do layout"""
 
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)
 
129
 
 
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)
 
133
 
 
134
        self.dataSizer.Add(self.element2, proportion = 0,
 
135
                           flag = wx.EXPAND | wx.ALL, border = 1)
 
136
       
 
137
        self.panel.SetSizer(self.sizer)
 
138
        self.sizer.Fit(self)
 
139
 
 
140
    def OnLocation(self, event):
 
141
        """Select mapset given location name"""
 
142
        location = event.GetString()
 
143
        
 
144
        if location:
 
145
            dbase = grass.gisenv()['GISDBASE']
 
146
            self.element2.UpdateItems(dbase = dbase, location = location)
 
147
            self.element2.SetSelection(0)
 
148
            mapset = self.element2.GetStringSelection()
 
149
 
 
150
    def GetValues(self):
 
151
        """Get location, mapset"""
 
152
        return (self.element1.GetValue(), self.element2.GetValue())
 
153
    
 
154
class MapsetDialog(SimpleDialog):
 
155
    """Dialog used to select mapset"""
 
156
    def __init__(self, parent, title = _("Select mapset in GRASS location"),
 
157
                 location = None):
 
158
        SimpleDialog.__init__(self, parent, title)
 
159
 
 
160
        if location:
 
161
            self.SetTitle(self.GetTitle() + ' <%s>' % location)
 
162
        else:
 
163
            self.SetTitle(self.GetTitle() + ' <%s>' % grass.gisenv()['LOCATION_NAME'])
 
164
        
 
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))
 
168
        
 
169
        self.element.SetFocus()
 
170
        self.warning = _("Name of mapset is missing.")
 
171
        
 
172
        self._layout()
 
173
        self.SetMinSize(self.GetSize())
 
174
 
 
175
    def _layout(self):
 
176
        """Do layout"""
 
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)
 
183
        self.sizer.Fit(self)
 
184
 
 
185
    def GetMapset(self):
 
186
        return self.element.GetValue()
 
187
 
 
188
class VectorDialog(SimpleDialog):
 
189
    def __init__(self, parent, title = _("Select vector map"), layerTree = None):
 
190
        """Dialog for selecting existing vector map
 
191
 
 
192
        :param parent: parent window
 
193
        :param title: window title
 
194
        :param layerTree: show only vector maps in given layer tree if not None
 
195
        
 
196
        :return: dialog instance
 
197
        """
 
198
        SimpleDialog.__init__(self, parent, title)
 
199
        
 
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()
 
204
        
 
205
        self.warning = _("Name of vector map is missing.")
 
206
        wx.CallAfter(self._layout)
 
207
        
 
208
    def _layout(self):
 
209
        """Do 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)
 
215
        
 
216
        self.panel.SetSizer(self.sizer)
 
217
        self.sizer.Fit(self)
 
218
 
 
219
    def GetName(self, full = False):
 
220
        """Get name of vector map to be created
 
221
 
 
222
        :param full: True to get fully qualified name
 
223
        """
 
224
        name = self.element.GetValue()
 
225
        if full:
 
226
            if '@' in name:
 
227
                return name
 
228
            else:
 
229
                return name + '@' + grass.gisenv()['MAPSET']
 
230
        
 
231
        return name.split('@', 1)[0]
 
232
 
 
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
 
237
 
 
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)
 
243
        
 
244
        :return: dialog instance
 
245
        """
 
246
        VectorDialog.__init__(self, parent, title)
 
247
        
 
248
        # determine output format
 
249
        if showType:
 
250
            self.ftype = OgrTypeSelect(parent = self, panel = self.panel)
 
251
        else:
 
252
            self.ftype = None
 
253
        
 
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)
 
258
        if disableTable:
 
259
            self.table.Enable(False)
 
260
        
 
261
        if showType:
 
262
            self.keycol = None
 
263
        else:
 
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'))
 
267
            if disableTable:
 
268
                self.keycol.Enable(False)
 
269
        
 
270
        self.addbox = wx.CheckBox(parent = self.panel,
 
271
                                  label = _('Add created map into layer tree'), style = wx.NO_BORDER)
 
272
        if disableAdd:
 
273
            self.addbox.SetValue(True)
 
274
            self.addbox.Enable(False)
 
275
        else:
 
276
            self.addbox.SetValue(UserSettings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
 
277
 
 
278
        self.table.Bind(wx.EVT_CHECKBOX, self.OnTable)
 
279
        
 
280
        self.warning = _("Name of new vector map is missing.")
 
281
        
 
282
    def OnTable(self, event):
 
283
        if self.keycol:
 
284
            self.keycol.Enable(event.IsChecked())
 
285
        
 
286
    def _layout(self):
 
287
        """Do layout"""
 
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)
 
293
        if self.ftype:
 
294
            self.dataSizer.AddSpacer(1)
 
295
            self.dataSizer.Add(item = self.ftype, proportion = 0,
 
296
                               flag = wx.EXPAND | wx.ALL, border = 1)
 
297
        
 
298
        self.dataSizer.Add(item = self.table, proportion = 0,
 
299
                      flag = wx.EXPAND | wx.ALL, border = 1)
 
300
        
 
301
        if self.keycol:
 
302
            keySizer = wx.BoxSizer(wx.HORIZONTAL)
 
303
            keySizer.Add(item = wx.StaticText(parent = self.panel, label = _("Key column:")),
 
304
                         proportion = 0,
 
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)
 
311
            
 
312
        self.dataSizer.AddSpacer(5)
 
313
        
 
314
        self.dataSizer.Add(item = self.addbox, proportion = 0,
 
315
                      flag = wx.EXPAND | wx.ALL, border = 1)
 
316
        
 
317
        self.panel.SetSizer(self.sizer)
 
318
        self.sizer.Fit(self)
 
319
        self.SetMinSize(self.GetSize())
 
320
 
 
321
    def GetKey(self):
 
322
        """Get key column name"""
 
323
        if self.keycol:
 
324
            return self.keycol.GetValue()
 
325
        return UserSettings.Get(group = 'atm', key = 'keycolumn', subkey = 'value')
 
326
    
 
327
    def IsChecked(self, key):
 
328
        """Get dialog properties
 
329
 
 
330
        :param key: window key ('add', 'table')
 
331
 
 
332
        :return: True/False
 
333
        :return: None on error
 
334
        """
 
335
        if key == 'add':
 
336
            return self.addbox.IsChecked()
 
337
        elif key == 'table':
 
338
            return self.table.IsChecked()
 
339
        
 
340
        return None
 
341
    
 
342
    def GetFeatureType(self):
 
343
        """Get feature type for OGR
 
344
 
 
345
        :return: feature type as string
 
346
        :return: None for native format
 
347
        """
 
348
        if self.ftype:
 
349
            return self.ftype.GetType()
 
350
 
 
351
        return None
 
352
 
 
353
 
 
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
 
358
 
 
359
    :param cmd: (prog, \*\*kwargs)
 
360
    :param title: window title
 
361
    :param exceptMap: list of maps to be excepted
 
362
    :param log:
 
363
    :param disableAdd: disable 'add layer' checkbox
 
364
    :param disableTable: disable 'create table' checkbox
 
365
 
 
366
    :return: dialog instance
 
367
    :return: None on error
 
368
    """
 
369
    vExternalOut = grass.parse_command('v.external.out', flags='g')
 
370
    isNative = vExternalOut['format'] == 'native'
 
371
    if cmd[0] == 'v.edit' and not isNative:
 
372
        showType = True
 
373
    else:
 
374
        showType = False
 
375
    dlg = NewVectorDialog(parent, title = title,
 
376
                          disableAdd = disableAdd, disableTable = disableTable,
 
377
                          showType = showType)
 
378
    
 
379
    if dlg.ShowModal() != wx.ID_OK:
 
380
        dlg.Destroy()
 
381
        return None
 
382
 
 
383
    outmap = dlg.GetName()
 
384
    key    = dlg.GetKey()
 
385
    if outmap == exceptMap:
 
386
        GError(parent = parent,
 
387
               message = _("Unable to create vector map <%s>.") % outmap)
 
388
        dlg.Destroy()
 
389
        return None
 
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)
 
394
        dlg.Destroy()
 
395
        return
 
396
        
 
397
    if outmap == '': # should not happen
 
398
        dlg.Destroy()
 
399
        return None
 
400
 
 
401
    # update cmd -> output name defined
 
402
    cmd[1][cmd[2]] = outmap
 
403
    if showType:
 
404
        cmd[1]['type'] = dlg.GetFeatureType()
 
405
        
 
406
    curMapset = grass.gisenv()['MAPSET']
 
407
    if isNative:
 
408
        listOfVectors = grass.list_grouped('vector')[curMapset]
 
409
    else:
 
410
        listOfVectors = RunCommand('v.external',
 
411
                                   quiet = True,
 
412
                                   parent = parent,
 
413
                                   read = True,
 
414
                                   flags = 'l',
 
415
                                   input = vExternalOut['dsn']).splitlines()
 
416
    
 
417
    overwrite = False
 
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:
 
426
            overwrite = True
 
427
        else:
 
428
            dlgOw.Destroy()
 
429
            dlg.Destroy()
 
430
            return None
 
431
        
 
432
    if UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'):
 
433
        overwrite = True
 
434
        
 
435
    ret = RunCommand(prog = cmd[0],
 
436
                     parent = parent,
 
437
                     overwrite = overwrite,
 
438
                     **cmd[1])
 
439
    if ret != 0:
 
440
        dlg.Destroy()
 
441
        return None
 
442
    
 
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,
 
448
                   parent = parent,
 
449
                   input = vExternalOut['dsn'],
 
450
                   layer = outmap)
 
451
        
 
452
    # create attribute table
 
453
    if dlg.table.IsEnabled() and dlg.table.IsChecked():
 
454
        if isNative:
 
455
            sql = 'CREATE TABLE %s (%s INTEGER)' % (outmap, key)
 
456
            
 
457
            RunCommand('db.connect',
 
458
                       flags = 'c')
 
459
            
 
460
            Debug.msg(1, "SQL: %s" % sql)
 
461
            RunCommand('db.execute',
 
462
                       quiet = True,
 
463
                       parent = parent,
 
464
                       input = '-',
 
465
                       stdin = sql)
 
466
            
 
467
            RunCommand('v.db.connect',
 
468
                       quiet = True,
 
469
                       parent = parent,
 
470
                       map = outmap,
 
471
                       table = outmap,
 
472
                       key = key,
 
473
                       layer = '1')
 
474
        # TODO: how to deal with attribute tables for OGR layers?
 
475
            
 
476
    # return fully qualified map name
 
477
    if '@' not in outmap:
 
478
        outmap += '@' + grass.gisenv()['MAPSET']
 
479
    
 
480
    # if giface:
 
481
    #     giface.WriteLog(_("New vector map <%s> created") % outmap)
 
482
        
 
483
    return dlg
 
484
 
 
485
class SavedRegion(wx.Dialog):
 
486
    def __init__(self, parent, title, id = wx.ID_ANY, loadsave = 'load',
 
487
                 **kwargs):
 
488
        """Loading or saving of display extents to saved region file
 
489
 
 
490
        :param loadsave: load or save region?
 
491
        """
 
492
        wx.Dialog.__init__(self, parent, id, title, **kwargs)
 
493
        
 
494
        self.loadsave = loadsave
 
495
        self.wind = ''
 
496
        
 
497
        sizer = wx.BoxSizer(wx.VERTICAL)
 
498
        
 
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,
 
505
                                     type='windows')
 
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)
 
510
        
 
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)
 
514
        
 
515
        sizer.Add(item = box, proportion = 0, flag = wx.GROW | wx.ALIGN_CENTER_VERTICAL | wx.ALL,
 
516
                  border = 5)
 
517
        
 
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)
 
521
        
 
522
        btnsizer = wx.StdDialogButtonSizer()
 
523
        
 
524
        btn = wx.Button(parent = self, id = wx.ID_OK)
 
525
        btn.SetDefault()
 
526
        btnsizer.AddButton(btn)
 
527
        
 
528
        btn = wx.Button(parent = self, id = wx.ID_CANCEL)
 
529
        btnsizer.AddButton(btn)
 
530
        btnsizer.Realize()
 
531
        
 
532
        sizer.Add(item = btnsizer, proportion = 0, flag = wx.ALIGN_RIGHT | wx.ALL, border = 5)
 
533
        
 
534
        self.SetSizer(sizer)
 
535
        sizer.Fit(self)
 
536
        self.Layout()
 
537
 
 
538
    def OnRegion(self, event):
 
539
        value = self._selection.GetValue()
 
540
        if '@' in value:
 
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."))
 
548
        else:
 
549
            self.wind = value
 
550
 
 
551
    def GetName(self):
 
552
        """Return region name"""
 
553
        return self.wind
 
554
 
 
555
 
 
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):
 
561
                     
 
562
        wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = title,
 
563
                            style = style, **kwargs)
 
564
                            
 
565
        self.parent = parent
 
566
        self.defaultGroup = defaultGroup
 
567
        self.defaultSubgroup = defaultSubgroup
 
568
        self.currentGroup = self.defaultGroup
 
569
        self.currentSubgroup = self.defaultGroup
 
570
 
 
571
        self.dataChanged = False
 
572
 
 
573
        # signaling edit subgroup / group mode
 
574
        self.edit_subg = False
 
575
 
 
576
        # sungroup maps dict value - ischecked
 
577
        self.subgmaps = {}
 
578
 
 
579
        # list of group maps
 
580
        self.gmaps = []
 
581
 
 
582
        # pattern chosen for filtering
 
583
        self.flt_pattern = ''
 
584
 
 
585
        self.bodySizer = self._createDialogBody()
 
586
        
 
587
        # buttons
 
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)
 
591
        
 
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"))
 
595
 
 
596
        #btnOk.SetDefault()
 
597
        
 
598
        # sizers & do layout
 
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)
 
608
        btnSizer.Realize()
 
609
        
 
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) 
 
616
        
 
617
        mainSizer.Add(item = btnSizer, proportion = 0,
 
618
                      flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.ALIGN_RIGHT, border = 10)
 
619
 
 
620
        self.SetSizer(mainSizer)
 
621
        mainSizer.Fit(self)
 
622
        
 
623
        btnOk.Bind(wx.EVT_BUTTON, self.OnOk)
 
624
        btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
 
625
        btnClose.Bind(wx.EVT_BUTTON, self.OnClose)
 
626
 
 
627
        # set dialog min size
 
628
        self.SetMinSize(self.GetSize())
 
629
        self.SetSize((-1, 400))
 
630
 
 
631
    def _createDialogBody(self):
 
632
        bodySizer = wx.BoxSizer(wx.VERTICAL)
 
633
        #TODO same text in MapLayersDialogBase
 
634
 
 
635
        filter_tooltip = _("Put here a regular expression."
 
636
                           " Characters '.*' stand for anything,"
 
637
                           " character '^' stands for the beginning"
 
638
                           " and '$' for the end.")
 
639
 
 
640
        # group selection
 
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?
 
649
    
 
650
        bodySizer.Add(item = self.groupSelect, flag = wx.TOP | wx.EXPAND, border = 5)
 
651
 
 
652
        self.subg_chbox = wx.CheckBox(parent = self, id = wx.ID_ANY,
 
653
                                      label = _("Edit/create subgroup"))
 
654
 
 
655
        bodySizer.Add(item = self.subg_chbox,
 
656
                      flag = wx.ALIGN_CENTER_VERTICAL | wx.TOP, border = 10)
 
657
 
 
658
        self.subg_panel = wx.Panel(self)
 
659
        subg_sizer = wx.BoxSizer(wx.VERTICAL)
 
660
 
 
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)
 
665
 
 
666
        self.subGroupSelect = SubGroupSelect(parent = self.subg_panel)
 
667
 
 
668
        subg_sizer.Add(item=self.subGroupSelect, flag=wx.EXPAND | wx.TOP, border = 5)
 
669
 
 
670
        self.subg_panel.SetSizer(subg_sizer)
 
671
 
 
672
        bodySizer.Add(item = self.subg_panel, flag = wx.TOP | wx.EXPAND, border = 5)
 
673
        
 
674
        bodySizer.AddSpacer(10)
 
675
 
 
676
        buttonSizer = wx.BoxSizer(wx.VERTICAL)
 
677
        
 
678
        # layers in group
 
679
        self.gListPanel = wx.Panel(self)
 
680
 
 
681
        gListSizer  = wx.GridBagSizer(vgap=3, hgap=2)
 
682
 
 
683
        self.g_sel_all = wx.CheckBox(parent=self.gListPanel, id=wx.ID_ANY,
 
684
                                  label=_("Select all"))
 
685
 
 
686
        gListSizer.Add(item=self.g_sel_all,
 
687
                       flag=wx.ALIGN_CENTER_VERTICAL,
 
688
                       pos=(0,1))
 
689
 
 
690
        gListSizer.Add(item = wx.StaticText(parent = self.gListPanel, label = _("Pattern:")),
 
691
                      flag = wx.ALIGN_CENTER_VERTICAL,
 
692
                      pos = (1,0))
 
693
        
 
694
        self.gfilter = wx.TextCtrl(parent=self.gListPanel, id=wx.ID_ANY,
 
695
                                  value="",
 
696
                                  size=(250,-1))
 
697
        self.gfilter.SetToolTipString(filter_tooltip)
 
698
        
 
699
 
 
700
        gListSizer.Add(item=self.gfilter,
 
701
                       flag=wx.EXPAND,
 
702
                       pos=(1,1))
 
703
 
 
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))
 
707
 
 
708
        sizer = wx.BoxSizer(wx.HORIZONTAL)
 
709
 
 
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)
 
713
        
 
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)
 
717
        
 
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)
 
722
        
 
723
        gListSizer.Add(item=sizer, flag=wx.EXPAND, pos=(2,1))
 
724
        gListSizer.AddGrowableCol(1)
 
725
        gListSizer.AddGrowableRow(2)
 
726
 
 
727
        self.gListPanel.SetSizer(gListSizer)
 
728
        bodySizer.Add(item=self.gListPanel, proportion=1, flag=wx.EXPAND)
 
729
        
 
730
        # layers in subgroup
 
731
        self.subgListPanel = wx.Panel(self)
 
732
 
 
733
        subgListSizer  = wx.GridBagSizer(vgap=3, hgap=2)
 
734
 
 
735
        # select toggle
 
736
        self.subg_sel_all = wx.CheckBox(parent=self.subgListPanel, id=wx.ID_ANY,
 
737
                                  label=_("Select all"))
 
738
 
 
739
        subgListSizer.Add(item=self.subg_sel_all,
 
740
                          flag=wx.ALIGN_CENTER_VERTICAL,
 
741
                          pos=(0,1))
 
742
 
 
743
        subgListSizer.Add(item = wx.StaticText(parent=self.subgListPanel, label=_("Pattern:")),
 
744
                      flag = wx.ALIGN_CENTER_VERTICAL,
 
745
                      pos = (1,0))
 
746
        
 
747
        self.subgfilter = wx.TextCtrl(parent=self.subgListPanel, id=wx.ID_ANY,
 
748
                                  value="",
 
749
                                  size=(250,-1))
 
750
        self.subgfilter.SetToolTipString(filter_tooltip)
 
751
        
 
752
        subgListSizer.Add(item=self.subgfilter,
 
753
                      flag=wx.EXPAND,
 
754
                      pos=(1,1))
 
755
 
 
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))
 
759
 
 
760
        self.subgListBox = wx.CheckListBox(parent = self.subgListPanel, id = wx.ID_ANY,
 
761
                                           size = (250, 100))
 
762
        self.subgListBox.SetToolTipString(_("Check maps from group to be included into subgroup."))
 
763
 
 
764
        subgListSizer.Add(item=self.subgListBox, flag=wx.EXPAND, pos=(2,1))
 
765
        subgListSizer.AddGrowableCol(1)
 
766
        subgListSizer.AddGrowableRow(2)
 
767
 
 
768
        self.subgListPanel.SetSizer(subgListSizer)
 
769
        bodySizer.Add(item=self.subgListPanel, proportion=1, flag=wx.EXPAND)
 
770
 
 
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)
 
774
 
 
775
        # bindings
 
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)
 
787
 
 
788
        if self.defaultGroup:
 
789
            self.groupSelect.SetValue(self.defaultGroup)
 
790
        
 
791
        if self.defaultSubgroup is not None:
 
792
            self.subGroupSelect.SetValue(self.defaultSubgroup)
 
793
            self.subg_chbox.SetValue(1)
 
794
            self.SubgChbox(True)
 
795
        else:
 
796
            self.subg_chbox.SetValue(0)
 
797
            self.SubgChbox(False)
 
798
        
 
799
        return bodySizer
 
800
 
 
801
    def OnGLayerCheck(self, event):
 
802
        self._checkGSellAll()
 
803
 
 
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
 
809
 
 
810
        event.Skip()
 
811
 
 
812
    def OnGSelAll(self, event):
 
813
        check = event.Checked()
 
814
        if not check:
 
815
            self.gLayerBox.DeselectAll()
 
816
        else:
 
817
            for item in range(self.subgListBox.GetCount()):
 
818
                self.gLayerBox.Select(item)
 
819
 
 
820
        event.Skip()
 
821
 
 
822
    def _checkGSellAll(self):
 
823
        check = False
 
824
 
 
825
        nsel = len(self.gLayerBox.GetSelections())
 
826
        if self.gLayerBox.GetCount() == nsel and \
 
827
           self.gLayerBox.GetCount() != 0:
 
828
            check = True
 
829
 
 
830
        self.g_sel_all.SetValue(check)
 
831
 
 
832
    def _checkSubGSellAll(self):
 
833
        not_all_checked = False
 
834
        if self.subgListBox.GetCount() == 0:
 
835
            not_all_checked = True
 
836
        else:
 
837
            for item in range(self.subgListBox.GetCount()):
 
838
                if not self.subgListBox.IsChecked(item):
 
839
                    not_all_checked = True
 
840
        
 
841
        self.subg_sel_all.SetValue(not not_all_checked)
 
842
 
 
843
    def OnSubgroupFilter(self, event):
 
844
        text = event.GetString()
 
845
        self.gfilter.ChangeValue(text)
 
846
        self.flt_pattern = text 
 
847
 
 
848
        self.FilterGroup()
 
849
        self.FilterSubgroup()
 
850
 
 
851
        event.Skip()
 
852
 
 
853
    def OnGroupFilter(self, event):
 
854
        text = event.GetString()
 
855
        self.subgfilter.ChangeValue(text)
 
856
        self.flt_pattern = text
 
857
 
 
858
        self.FilterGroup()
 
859
        self.FilterSubgroup()
 
860
 
 
861
        event.Skip()
 
862
 
 
863
    def OnSubgLayerCheck(self, event):
 
864
        idx = event.GetInt()
 
865
        m = self.subgListBox.GetString(idx)
 
866
        self.subgmaps[m] = self.subgListBox.IsChecked(idx)
 
867
        self.dataChanged = True
 
868
        self._checkSubGSellAll()
 
869
 
 
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
 
875
 
 
876
    def DisableSubgroupEdit(self):
 
877
        """Disable editation of subgroups in the dialog 
 
878
        
 
879
        .. todo::
 
880
            used by gcp manager, maybe the gcp m should also support subgroups
 
881
        """
 
882
        self.edit_subg = False
 
883
        self.subg_panel.Hide()
 
884
        self.subg_chbox.Hide()
 
885
        self.subgListBox.Hide()
 
886
 
 
887
        self.Layout()
 
888
    
 
889
    def OnSubgChbox(self, event):
 
890
        edit_subg = self.subg_chbox.GetValue()
 
891
        self.SubgChbox(edit_subg)
 
892
 
 
893
    def SubgChbox(self, edit_subg):
 
894
        self._checkChange()
 
895
        if edit_subg:
 
896
            self.edit_subg = edit_subg
 
897
 
 
898
            self.SubGroupSelected()
 
899
            self._subgroupLayout()
 
900
        else:
 
901
            self.edit_subg = edit_subg
 
902
 
 
903
            self.GroupSelected()
 
904
            self._groupLayout()
 
905
 
 
906
        self.SetMinSize(self.GetBestSize())
 
907
 
 
908
    def _groupLayout(self):
 
909
        self.subg_panel.Hide()
 
910
        self.subgListPanel.Hide()
 
911
        self.gListPanel.Show()
 
912
        self.Layout()
 
913
 
 
914
    def _subgroupLayout(self):
 
915
        self.subg_panel.Show()
 
916
        self.subgListPanel.Show()
 
917
        self.gListPanel.Hide()
 
918
        self.Layout()
 
919
 
 
920
    def OnAddLayer(self, event):
 
921
        """Add new layer to listbox"""
 
922
        dlg = MapLayersDialogForGroups(parent = self, title = _("Add selected map layers into group"))
 
923
        
 
924
        if dlg.ShowModal() != wx.ID_OK:
 
925
            dlg.Destroy()
 
926
            return
 
927
        
 
928
        layers = dlg.GetMapLayers()
 
929
        for layer in layers:
 
930
            if layer not in self.gmaps:
 
931
                self.gLayerBox.Append(layer)
 
932
                self.gmaps.append(layer)
 
933
                self.dataChanged = True
 
934
            
 
935
 
 
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)
 
942
            self.gmaps.remove(m)
 
943
            self.dataChanged = True
 
944
                
 
945
    def GetLayers(self):
 
946
        """Get layers"""
 
947
        if self.edit_subg:
 
948
            layers = []
 
949
            for maps, sel in self.subgmaps.iteritems():
 
950
                if sel:
 
951
                    layers.append(maps)
 
952
        else:
 
953
            layers = self.gmaps[:]
 
954
 
 
955
        return layers
 
956
        
 
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)
 
961
 
 
962
    def GroupSelected(self):
 
963
        """Group was selected, check if changes were apllied"""
 
964
        self._checkChange()
 
965
        group, s = self.GetSelectedGroup()
 
966
        maps = list()
 
967
        groups = self.GetExistGroups()
 
968
        if group in groups:
 
969
            maps = self.GetGroupLayers(group)
 
970
        
 
971
        self.subGroupSelect.Insert(group)
 
972
        
 
973
        self.gmaps = maps
 
974
        maps = self._filter(maps)
 
975
 
 
976
        self.ShowGroupLayers(maps)
 
977
        self.currentGroup = group
 
978
 
 
979
        self.SubGroupSelected()
 
980
        self.ClearNotification()
 
981
 
 
982
        self._checkGSellAll()
 
983
 
 
984
    def FilterGroup(self):
 
985
        maps = self._filter(self.gmaps)
 
986
        self.ShowGroupLayers(maps)
 
987
        self._checkGSellAll()
 
988
 
 
989
    def FilterSubgroup(self):
 
990
        maps = self._filter(self.gmaps)
 
991
        self.subgListBox.Set(maps)
 
992
 
 
993
        for i, m in enumerate(maps):
 
994
            if m in self.subgmaps.iterkeys() and self.subgmaps[m]:
 
995
                self.subgListBox.Check(i)
 
996
 
 
997
        self._checkSubGSellAll()
 
998
 
 
999
    def SubGroupSelected(self):
 
1000
        """Subgroup was selected, check if changes were apllied"""
 
1001
        self._checkChange()
 
1002
 
 
1003
        subgroup = self.subGroupSelect.GetValue().strip()
 
1004
        group = self.currentGroup
 
1005
        
 
1006
        gmaps = list()
 
1007
        groups = self.GetExistGroups()
 
1008
 
 
1009
        self.subgmaps = {}
 
1010
        if group in groups:
 
1011
            gmaps = self.GetGroupLayers(group)
 
1012
            if subgroup:
 
1013
                maps = self.GetGroupLayers(group, subgroup)
 
1014
                for m in maps:
 
1015
                    if m in gmaps:
 
1016
                        self.subgmaps[m] = True
 
1017
                    else:
 
1018
                        self.subgmaps[m] = False
 
1019
 
 
1020
        gmaps = self._filter(gmaps)
 
1021
        self.subgListBox.Set(gmaps)
 
1022
 
 
1023
        for i, m in enumerate(gmaps):
 
1024
            if self.subgmaps.has_key(m):
 
1025
                self.subgListBox.Check(i)
 
1026
            else:
 
1027
                self.subgListBox.Check(i, False)
 
1028
 
 
1029
        self._checkSubGSellAll()
 
1030
        self.currentSubgroup = subgroup
 
1031
        self.ClearNotification()
 
1032
 
 
1033
    def _filter(self, data):
 
1034
        """Apply filter for strings in data list"""
 
1035
        flt_data = []
 
1036
        if len(self.flt_pattern) == 0:
 
1037
            flt_data = data[:]
 
1038
            return flt_data
 
1039
        
 
1040
        for dt in data:
 
1041
            try:
 
1042
                if re.compile(self.flt_pattern).search(dt):
 
1043
                    flt_data.append(dt)
 
1044
            except:
 
1045
                pass
 
1046
 
 
1047
        return flt_data
 
1048
 
 
1049
    def _checkChange(self):
 
1050
        if self.edit_subg:
 
1051
            self._checkSubgroupChange()
 
1052
        else:
 
1053
            self._checkGroupChange()
 
1054
 
 
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:
 
1062
                self.ApplyChanges()
 
1063
                
 
1064
            dlg.Destroy()
 
1065
        self.dataChanged = False
 
1066
 
 
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:
 
1074
                self.ApplyChanges()
 
1075
                
 
1076
            dlg.Destroy()
 
1077
        self.dataChanged = False
 
1078
 
 
1079
    def ShowGroupLayers(self, mapList):
 
1080
        """Show map layers in currently selected group"""
 
1081
        self.gLayerBox.Set(mapList)
 
1082
                
 
1083
    def EditGroup(self, group, subgroup=None):
 
1084
        """Edit selected group"""
 
1085
        layersNew = self.GetLayers()
 
1086
        layersOld = self.GetGroupLayers(group, subgroup)
 
1087
        
 
1088
        add = []
 
1089
        remove = []
 
1090
        for layerNew in layersNew:
 
1091
            if layerNew not in layersOld:
 
1092
                add.append(layerNew)
 
1093
                
 
1094
        for layerOld in layersOld:
 
1095
            if layerOld not in layersNew:
 
1096
                remove.append(layerOld)
 
1097
                
 
1098
        kwargs = {}
 
1099
        if subgroup:
 
1100
            kwargs["subgroup"] = subgroup
 
1101
 
 
1102
        ret = None
 
1103
        if remove:
 
1104
            ret = RunCommand('i.group',
 
1105
                             parent = self,
 
1106
                             group = group,
 
1107
                             flags = 'r',
 
1108
                             input = ','.join(remove),
 
1109
                             **kwargs)
 
1110
                        
 
1111
        if add:
 
1112
            ret = RunCommand('i.group',
 
1113
                             parent = self,
 
1114
                             group = group,
 
1115
                             input = ','.join(add),
 
1116
                             **kwargs)
 
1117
                            
 
1118
        return ret
 
1119
        
 
1120
    def CreateNewGroup(self, group, subgroup):
 
1121
        """Create new group"""
 
1122
        layers = self.GetLayers()
 
1123
        if not layers:
 
1124
            GMessage(parent = self,
 
1125
                     message = _("No raster maps selected."))
 
1126
            return 1
 
1127
        
 
1128
        kwargs = {}
 
1129
        if subgroup:
 
1130
            kwargs["subgroup"] = subgroup
 
1131
 
 
1132
        ret = RunCommand('i.group',
 
1133
                          parent = self,
 
1134
                          group = group,
 
1135
                          input = layers,
 
1136
                          **kwargs)
 
1137
        #update subgroup select
 
1138
        self.SubGroupSelected()
 
1139
        return ret
 
1140
 
 
1141
    def GetExistGroups(self):
 
1142
        """Returns existing groups in current mapset"""
 
1143
        return grass.list_grouped('group')[grass.gisenv()['MAPSET']]
 
1144
 
 
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()
 
1149
        
 
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:
 
1156
            if create:
 
1157
                label = _("Group <%s> was successfully created.") % group
 
1158
            else:
 
1159
                label = _("Group <%s> was successfully changed.") % group
 
1160
        else:
 
1161
            if create:
 
1162
                label = _("Creating of new group <%s> failed.") % group
 
1163
            else:
 
1164
                label = _("Changing of group <%s> failed.") % group
 
1165
            
 
1166
        self.infoLabel.SetLabel(label)
 
1167
        wx.FutureCall(4000, self.ClearNotification)
 
1168
        
 
1169
    def GetSelectedGroup(self):
 
1170
        """Return currently selected group (without mapset)"""
 
1171
        g = self.groupSelect.GetValue().split('@')[0]
 
1172
        if self.edit_subg:
 
1173
            s = self.subGroupSelect.GetValue() 
 
1174
        else:
 
1175
            s = None
 
1176
        return g, s
 
1177
 
 
1178
    def GetGroupLayers(self, group, subgroup=None):
 
1179
        """Get layers in group"""
 
1180
        kwargs = dict()
 
1181
        kwargs['group'] = group
 
1182
        if subgroup:
 
1183
            kwargs['subgroup'] = subgroup
 
1184
 
 
1185
        res = RunCommand('i.group',
 
1186
                         parent = self,
 
1187
                         flags = 'g',
 
1188
                         read = True, **kwargs)
 
1189
        if not res:
 
1190
            return []
 
1191
        return res.splitlines()
 
1192
    
 
1193
    def ClearNotification(self):
 
1194
        """Clear notification string"""
 
1195
        self.infoLabel.SetLabel("")
 
1196
       
 
1197
    def ApplyChanges(self):
 
1198
        """Create or edit group"""
 
1199
        group = self.currentGroup
 
1200
        if not group:
 
1201
            GMessage(parent = self,
 
1202
                     message = _("No group selected."))
 
1203
            return False
 
1204
 
 
1205
 
 
1206
        if self.edit_subg and not self.currentSubgroup:
 
1207
            GMessage(parent = self,
 
1208
                     message = _("No subgroup selected."))
 
1209
            return 0
 
1210
        
 
1211
        if self.edit_subg:
 
1212
            subgroup = self.currentSubgroup
 
1213
        else:
 
1214
            subgroup = None
 
1215
 
 
1216
        groups = self.GetExistGroups()
 
1217
        if group in groups:
 
1218
            ret = self.EditGroup(group, subgroup)
 
1219
            self.ShowResult(group = group, returnCode = ret, create = False)
 
1220
            
 
1221
        else:
 
1222
            ret = self.CreateNewGroup(group, subgroup)
 
1223
            self.ShowResult(group = group, returnCode = ret, create = True)
 
1224
            
 
1225
        self.dataChanged = False
 
1226
        
 
1227
        return True
 
1228
        
 
1229
    def OnApply(self, event):
 
1230
        """Apply changes"""
 
1231
        self.ApplyChanges()
 
1232
        
 
1233
    def OnOk(self, event):
 
1234
        """Apply changes and close dialog"""
 
1235
        if self.ApplyChanges():
 
1236
            self.OnClose(event)
 
1237
        
 
1238
    def OnClose(self, event):
 
1239
        """Close dialog"""
 
1240
        if not self.IsModal():
 
1241
            self.Destroy()
 
1242
        event.Skip()
 
1243
        
 
1244
class MapLayersDialogBase(wx.Dialog):
 
1245
    """Base dialog for selecting map layers (raster, vector).
 
1246
 
 
1247
    There are 3 subclasses: MapLayersDialogForGroups, MapLayersDialogForModeler,
 
1248
    MapLayersDialog. Base class contains core functionality.
 
1249
    """
 
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)
 
1254
        
 
1255
        self.parent = parent # GMFrame or ?
 
1256
        
 
1257
        self.applyAddingMapLayers = Signal('MapLayersDialogBase.applyAddingMapLayers')
 
1258
        
 
1259
        self.mainSizer = wx.BoxSizer(wx.VERTICAL)
 
1260
        
 
1261
        # dialog body
 
1262
        self.bodySizer = self._createDialogBody()
 
1263
        self.mainSizer.Add(item = self.bodySizer, proportion = 1,
 
1264
                      flag = wx.EXPAND | wx.ALL, border = 5)
 
1265
        
 
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())
 
1270
 
 
1271
        self._fullyQualifiedNames()
 
1272
        self._modelerDSeries()
 
1273
 
 
1274
        # buttons
 
1275
        btnCancel = wx.Button(parent = self, id = wx.ID_CANCEL)
 
1276
        btnOk = wx.Button(parent = self, id = wx.ID_OK)
 
1277
        btnOk.SetDefault()
 
1278
        
 
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()
 
1285
        
 
1286
        self.mainSizer.Add(item = self.btnSizer, proportion = 0,
 
1287
                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_CENTER, border = 5)
 
1288
 
 
1289
        self.SetSizer(self.mainSizer)
 
1290
        self.mainSizer.Fit(self)
 
1291
 
 
1292
        # set dialog min size
 
1293
        self.SetMinSize(self.GetSize())
 
1294
 
 
1295
    def _modelerDSeries(self):
 
1296
        """Method used only by MapLayersDialogForModeler,
 
1297
        for other subclasses does nothing.
 
1298
        """
 
1299
        pass
 
1300
 
 
1301
    def _addApplyButton(self):
 
1302
        """Method used only by MapLayersDialog,
 
1303
        for other subclasses does nothing.
 
1304
        """
 
1305
        pass
 
1306
 
 
1307
    def _fullyQualifiedNames(self):
 
1308
        """Adds CheckBox which determines is fully qualified names are retuned.
 
1309
        """
 
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)
 
1315
 
 
1316
    def _useFullyQualifiedNames(self):
 
1317
        return self.fullyQualified.IsChecked()
 
1318
 
 
1319
    def _layerTypes(self):
 
1320
        """Determines which layer types can be chosen.
 
1321
 
 
1322
         Valid values:
 
1323
         - raster
 
1324
         - raster3d
 
1325
         - vector
 
1326
         """
 
1327
        return [_('raster'), _('3D raster'), _('vector')]
 
1328
 
 
1329
    def _selectAll(self):
 
1330
        """Check all layers by default"""
 
1331
        return True
 
1332
 
 
1333
    def _createDialogBody(self):
 
1334
        bodySizer = wx.GridBagSizer(vgap = 3, hgap = 3)
 
1335
        
 
1336
        # layer type
 
1337
        bodySizer.Add(item = wx.StaticText(parent = self, label = _("Map type:")),
 
1338
                      flag = wx.ALIGN_CENTER_VERTICAL,
 
1339
                      pos = (0,0))
 
1340
        
 
1341
        self.layerType = wx.Choice(parent = self, id = wx.ID_ANY,
 
1342
                                   choices = self._layerTypes(), size = (100,-1))
 
1343
 
 
1344
        self.layerType.SetSelection(0)
 
1345
            
 
1346
        bodySizer.Add(item = self.layerType,
 
1347
                           pos = (0,1))
 
1348
        self.layerType.Bind(wx.EVT_CHOICE, self.OnChangeParams)
 
1349
 
 
1350
        # select toggle
 
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,
 
1356
                      pos = (0,2))
 
1357
        
 
1358
        # mapset filter
 
1359
        bodySizer.Add(item = wx.StaticText(parent = self, label = _("Mapset:")),
 
1360
                      flag = wx.ALIGN_CENTER_VERTICAL,
 
1361
                      pos = (1,0))
 
1362
        
 
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))
 
1367
        
 
1368
        # map name filter
 
1369
        bodySizer.Add(item = wx.StaticText(parent = self, label = _("Pattern:")),
 
1370
                      flag = wx.ALIGN_CENTER_VERTICAL,
 
1371
                      pos = (2,0))
 
1372
        
 
1373
        self.filter = wx.TextCtrl(parent = self, id = wx.ID_ANY,
 
1374
                                  value = "",
 
1375
                                  size = (250,-1))
 
1376
        bodySizer.Add(item = self.filter,
 
1377
                      flag = wx.EXPAND,
 
1378
                      pos = (2,1), span = (1, 2))
 
1379
 
 
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."))
 
1386
 
 
1387
        # layer list 
 
1388
        bodySizer.Add(item = wx.StaticText(parent = self, label = _("List of maps:")),
 
1389
                      flag = wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_TOP,
 
1390
                      pos = (3,0))
 
1391
        self.layers = wx.CheckListBox(parent = self, id = wx.ID_ANY,
 
1392
                                      size = (250, 100),
 
1393
                                      choices = [])
 
1394
        bodySizer.Add(item = self.layers,
 
1395
                      flag = wx.EXPAND,
 
1396
                      pos = (3,1), span = (1, 2))
 
1397
        
 
1398
        bodySizer.AddGrowableCol(1)
 
1399
        bodySizer.AddGrowableRow(3)
 
1400
        
 
1401
        # bindings
 
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)
 
1406
        
 
1407
        return bodySizer
 
1408
 
 
1409
    def LoadMapLayers(self, type, mapset):
 
1410
        """Load list of map layers
 
1411
 
 
1412
        :param str type: layer type ('raster' or 'vector')
 
1413
        :param str mapset: mapset name
 
1414
        """
 
1415
        self.map_layers = grass.list_grouped(type = type)[mapset]
 
1416
        self.layers.Set(self.map_layers)
 
1417
        
 
1418
        # check all items by default
 
1419
        for item in range(self.layers.GetCount()):
 
1420
            
 
1421
            self.layers.Check(item, check = self._selectAll())
 
1422
        
 
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())
 
1428
        
 
1429
        event.Skip()
 
1430
        
 
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()
 
1437
 
 
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)
 
1441
        
 
1442
        # generate popup-menu
 
1443
        menu = wx.Menu()
 
1444
        menu.Append(self.popupDataID1, _("Select all"))
 
1445
        menu.Append(self.popupDataID2, _("Invert selection"))
 
1446
        menu.Append(self.popupDataID3, _("Deselect all"))
 
1447
        
 
1448
        self.PopupMenu(menu)
 
1449
        menu.Destroy()
 
1450
 
 
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)
 
1455
        
 
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)
 
1461
            else:
 
1462
                self.layers.Check(item, True)
 
1463
        
 
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)
 
1468
        
 
1469
    def OnFilter(self, event):
 
1470
        """Apply filter for map names"""
 
1471
        if len(event.GetString()) == 0:
 
1472
            self.layers.Set(self.map_layers) 
 
1473
            return 
 
1474
        
 
1475
        list = []
 
1476
        for layer in self.map_layers:
 
1477
            try:
 
1478
                if re.compile(event.GetString()).search(layer):
 
1479
                    list.append(layer)
 
1480
            except:
 
1481
                pass
 
1482
        
 
1483
        self.layers.Set(list)
 
1484
        self.OnSelectAll(None)
 
1485
        
 
1486
        event.Skip()
 
1487
        
 
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)
 
1493
        
 
1494
        event.Skip()
 
1495
        
 
1496
    def GetMapLayers(self):
 
1497
        """Return list of checked map layers"""
 
1498
        layerNames = []
 
1499
        for indx in self.layers.GetSelections():
 
1500
            # layers.append(self.layers.GetStringSelec(indx))
 
1501
            pass
 
1502
 
 
1503
        mapset = self.mapset.GetStringSelection()
 
1504
        for item in range(self.layers.GetCount()):
 
1505
            if not self.layers.IsChecked(item):
 
1506
                continue
 
1507
            if self._useFullyQualifiedNames():
 
1508
                layerNames.append(self.layers.GetString(item) + '@' + mapset)
 
1509
            else:
 
1510
                layerNames.append(self.layers.GetString(item))
 
1511
        
 
1512
        return layerNames
 
1513
    
 
1514
    def GetLayerType(self, cmd = False):
 
1515
        """Get selected layer type
 
1516
 
 
1517
        :param bool cmd: True for g.list
 
1518
        """
 
1519
        if not cmd:
 
1520
            return self.layerType.GetStringSelection()
 
1521
        
 
1522
        sel = self.layerType.GetSelection()
 
1523
        if sel == 0:
 
1524
            ltype = 'raster'
 
1525
        elif sel == 1:
 
1526
            ltype = 'raster_3d'
 
1527
        else:
 
1528
            ltype = 'vector'
 
1529
        
 
1530
        return ltype
 
1531
 
 
1532
class MapLayersDialog(MapLayersDialogBase):
 
1533
    """Subclass of MapLayersDialogBase used in Layer Manager. 
 
1534
 
 
1535
    Contains apply button, which sends wxApplyMapLayers event.
 
1536
    """
 
1537
    def __init__(self, parent, title, **kwargs):
 
1538
        MapLayersDialogBase.__init__(self, parent = parent, title = title, **kwargs)
 
1539
 
 
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)
 
1544
 
 
1545
    def OnApply(self, event):
 
1546
        self.applyAddingMapLayers.emit(mapLayers = self.GetMapLayers(),
 
1547
                                       ltype = self.GetLayerType(cmd = True))
 
1548
 
 
1549
class MapLayersDialogForGroups(MapLayersDialogBase):
 
1550
    """Subclass of MapLayersDialogBase used for specyfying maps in an imagery group. 
 
1551
 
 
1552
    Shows only raster maps.
 
1553
    """
 
1554
    def __init__(self, parent, title, **kwargs):
 
1555
        MapLayersDialogBase.__init__(self, parent = parent, title = title, **kwargs)
 
1556
 
 
1557
    def _layerTypes(self):
 
1558
        return [_('raster'),]
 
1559
 
 
1560
    def _selectAll(self):
 
1561
        """Could be overriden"""
 
1562
        return False
 
1563
 
 
1564
    def _fullyQualifiedNames(self):
 
1565
        pass
 
1566
 
 
1567
    def _useFullyQualifiedNames(self):
 
1568
        return True
 
1569
 
 
1570
 
 
1571
class MapLayersDialogForModeler(MapLayersDialogBase):
 
1572
    """Subclass of MapLayersDialogBase used in Modeler. 
 
1573
    """
 
1574
    def __init__(self, parent, title, **kwargs):
 
1575
        MapLayersDialogBase.__init__(self, parent = parent, title = title, **kwargs)
 
1576
 
 
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)
 
1583
 
 
1584
    def GetDSeries(self):
 
1585
        """Used by modeler only
 
1586
 
 
1587
        :return: g.list command
 
1588
        """
 
1589
        if not self.dseries or not self.dseries.IsChecked():
 
1590
            return ''
 
1591
        
 
1592
        cond = 'map in `g.list type=%s ' % self.GetLayerType(cmd = True)
 
1593
        patt = self.filter.GetValue()
 
1594
        if patt:
 
1595
            cond += 'pattern=%s ' % patt
 
1596
        cond += 'mapset=%s`' % self.mapset.GetStringSelection()
 
1597
        
 
1598
        return cond
 
1599
 
 
1600
    
 
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
 
1610
        
 
1611
        self.commandId = -1  # id of running command
 
1612
        
 
1613
        wx.Dialog.__init__(self, parent, id, title, style = style,
 
1614
                           name = "MultiImportDialog")
 
1615
        
 
1616
        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
 
1617
        
 
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")
 
1623
        else:
 
1624
            label = _("List of %s layers") % self.importType.upper()
 
1625
        self.layerBox.SetLabel(" %s - %s " % (label, _("right click to (un)select all")))
 
1626
        
 
1627
        # list of layers
 
1628
        columns = [_('Layer id'),
 
1629
                   _('Layer name'),
 
1630
                   _('Name for output GRASS map (editable)')]
 
1631
        if itype == 'ogr':
 
1632
            columns.insert(2, _('Feature type'))
 
1633
            columns.insert(3, _('Projection match'))
 
1634
 
 
1635
        self.list = LayersList(parent = self.panel, columns = columns)
 
1636
        self.list.LoadData()
 
1637
 
 
1638
        self.optionBox = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
 
1639
                                      label = "%s" % _("Options"))
 
1640
        
 
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', '')
 
1646
            if not desc:
 
1647
                desc = f.get('description', '')
 
1648
            if not name and not desc:
 
1649
                continue
 
1650
            if cmd == 'r.in.gdal' and name not in ('o', 'e', 'l', 'k'):
 
1651
                continue
 
1652
            elif cmd == 'r.external' and name not in ('o', 'e', 'r', 'h', 'v'):
 
1653
                continue
 
1654
            elif cmd == 'v.in.ogr' and name not in ('c', 'z', 't', 'o', 'r', 'e', 'w'):
 
1655
                continue
 
1656
            elif cmd == 'v.external' and name not in ('b'):
 
1657
                continue
 
1658
            elif cmd == 'v.in.dxf' and name not in ('e', 't', 'b', 'f', 'i'):
 
1659
                continue
 
1660
            self.options[name] = wx.CheckBox(parent = self.panel, id = wx.ID_ANY,
 
1661
                                             label = desc)
 
1662
        
 
1663
        
 
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'))
 
1667
        
 
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'))
 
1672
        
 
1673
        #
 
1674
        # buttons
 
1675
        #
 
1676
        # cancel
 
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)
 
1680
        # run
 
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)
 
1685
 
 
1686
        self.Bind(wx.EVT_CLOSE, lambda evt: self.Destroy())
 
1687
 
 
1688
    def doLayout(self):
 
1689
        """Do layout"""
 
1690
        dialogSizer = wx.BoxSizer(wx.VERTICAL)
 
1691
        
 
1692
        # dsn input
 
1693
        dialogSizer.Add(item = self.dsnInput, proportion = 0,
 
1694
                        flag = wx.EXPAND)
 
1695
        
 
1696
        #
 
1697
        # list of DXF layers
 
1698
        #
 
1699
        layerSizer = wx.StaticBoxSizer(self.layerBox, wx.HORIZONTAL)
 
1700
 
 
1701
        layerSizer.Add(item = self.list, proportion = 1,
 
1702
                      flag = wx.ALL | wx.EXPAND, border = 5)
 
1703
        
 
1704
        dialogSizer.Add(item = layerSizer, proportion = 1,
 
1705
                        flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
 
1706
 
 
1707
        # options
 
1708
        optionSizer = wx.StaticBoxSizer(self.optionBox, wx.VERTICAL)
 
1709
        for key in self.options.keys():
 
1710
            optionSizer.Add(item = self.options[key], proportion = 0)
 
1711
            
 
1712
        dialogSizer.Add(item = optionSizer, proportion = 0,
 
1713
                        flag = wx.LEFT | wx.RIGHT | wx.BOTTOM | wx.EXPAND, border = 5)
 
1714
        
 
1715
        dialogSizer.Add(item = self.overwrite, proportion = 0,
 
1716
                        flag = wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
 
1717
        
 
1718
        dialogSizer.Add(item = self.add, proportion = 0,
 
1719
                        flag = wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
 
1720
        
 
1721
        dialogSizer.Add(item = self.closeOnFinish, proportion = 0,
 
1722
                        flag = wx.LEFT | wx.RIGHT | wx.BOTTOM, border = 5)
 
1723
        #
 
1724
        # buttons
 
1725
        #
 
1726
        btnsizer = wx.BoxSizer(orient = wx.HORIZONTAL)
 
1727
        
 
1728
        btnsizer.Add(item = self.btn_close, proportion = 0,
 
1729
                     flag = wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER,
 
1730
                     border = 10)
 
1731
        
 
1732
        btnsizer.Add(item = self.btn_run, proportion = 0,
 
1733
                     flag = wx.RIGHT | wx.ALIGN_CENTER,
 
1734
                     border = 10)
 
1735
        
 
1736
        dialogSizer.Add(item = btnsizer, proportion = 0,
 
1737
                        flag = wx.ALIGN_CENTER_VERTICAL | wx.BOTTOM | wx.ALIGN_RIGHT,
 
1738
                        border = 10)
 
1739
        
 
1740
        # dialogSizer.SetSizeHints(self.panel)
 
1741
        self.panel.SetAutoLayout(True)
 
1742
        self.panel.SetSizer(dialogSizer)
 
1743
        dialogSizer.Fit(self.panel)
 
1744
        
 
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)
 
1751
        self.Layout()
 
1752
 
 
1753
    def _getCommand(self):
 
1754
        """Get command"""
 
1755
        return ''
 
1756
    
 
1757
    def OnClose(self, event = None):
 
1758
        """Close dialog"""
 
1759
        self.Close()
 
1760
 
 
1761
    def OnRun(self, event):
 
1762
        """Import/Link data (each layes as separate vector map)"""
 
1763
        pass
 
1764
 
 
1765
    def AddLayers(self, returncode, cmd = None):
 
1766
        """Add imported/linked layers into layer tree"""
 
1767
        if not self.add.IsChecked() or returncode != 0:
 
1768
            return
 
1769
 
 
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
 
1774
        self.commandId += 1
 
1775
        layer, output = self.list.GetLayers()[self.commandId]
 
1776
        
 
1777
        if '@' not in output:
 
1778
            name = output + '@' + grass.gisenv()['MAPSET']
 
1779
        else:
 
1780
            name = output
 
1781
        
 
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':
 
1787
            cmd = ['d.rast',
 
1788
                   'map=%s' % name]
 
1789
            if UserSettings.Get(group = 'rasterLayer', key = 'opaque', subkey = 'enabled'):
 
1790
                cmd.append('-n')
 
1791
 
 
1792
            llist.AddLayer(ltype='raster',
 
1793
                           name=name, checked=True,
 
1794
                           cmd=cmd)
 
1795
        else:
 
1796
            llist.AddLayer(ltype='vector',
 
1797
                           name=name, checked=True,
 
1798
                           cmd=['d.vect',
 
1799
                                'map=%s' % name] + GetDisplayVectSettings())
 
1800
 
 
1801
        self._giface.GetMapWindow().ZoomToMap()
 
1802
 
 
1803
    def OnAbort(self, event):
 
1804
        """Abort running import
 
1805
 
 
1806
        .. todo::
 
1807
            not yet implemented
 
1808
        """
 
1809
        pass
 
1810
 
 
1811
    def OnCmdDone(self, cmd, returncode):
 
1812
        """Do what has to be done after importing"""
 
1813
        pass
 
1814
 
 
1815
 
 
1816
class GdalImportDialog(ImportDialog):
 
1817
    def __init__(self, parent, giface, ogr = False, link = False):
 
1818
        """Dialog for bulk import of various raster/vector data
 
1819
 
 
1820
        .. todo::
 
1821
            Split into GdalImportDialog and OgrImportDialog
 
1822
 
 
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
 
1826
        """
 
1827
        self._giface = giface
 
1828
        self.link = link
 
1829
        self.ogr  = ogr
 
1830
        
 
1831
        if ogr:
 
1832
            ImportDialog.__init__(self, parent, giface=giface, itype='ogr')
 
1833
            if link:
 
1834
                self.SetTitle(_("Link external vector data"))
 
1835
            else:
 
1836
                self.SetTitle(_("Import vector data"))
 
1837
        else:
 
1838
            ImportDialog.__init__(self, parent, giface=giface, itype='gdal') 
 
1839
            if link:
 
1840
                self.SetTitle(_("Link external raster data"))
 
1841
            else:
 
1842
                self.SetTitle(_("Import raster data"))
 
1843
        
 
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))
 
1847
 
 
1848
        mightNotWork = _("this might not work for multiple bands")
 
1849
        if link:
 
1850
            self.add.SetLabel(_("Add linked layers into layer tree"
 
1851
                                " ({mightNotWork})".format(mightNotWork=mightNotWork)))
 
1852
        else:
 
1853
            self.add.SetLabel(_("Add imported layers into layer tree"
 
1854
                                " ({mightNotWork})".format(mightNotWork=mightNotWork)))
 
1855
        
 
1856
        self.add.SetValue(UserSettings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
 
1857
 
 
1858
        if link:
 
1859
            self.btn_run.SetLabel(_("&Link"))
 
1860
            self.btn_run.SetToolTipString(_("Link selected layers"))
 
1861
        else:
 
1862
            self.btn_run.SetLabel(_("&Import"))
 
1863
            self.btn_run.SetToolTipString(_("Import selected layers"))
 
1864
        
 
1865
        self.doLayout()
 
1866
 
 
1867
    def OnRun(self, event):
 
1868
        """Import/Link data (each layes as separate vector map)"""
 
1869
        self.commandId = -1
 
1870
        data = self.list.GetLayers()
 
1871
        if not data:
 
1872
            GMessage(_("No layers selected. Operation canceled."),
 
1873
                     parent = self)
 
1874
            return
 
1875
        
 
1876
        dsn  = self.dsnInput.GetDsn()
 
1877
        ext  = self.dsnInput.GetFormatExt()
 
1878
        
 
1879
        # determine data driver for PostGIS links
 
1880
        self.popOGR = False
 
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:
 
1885
            self.popOGR = True
 
1886
            os.environ['GRASS_VECTOR_OGR'] = '1'
 
1887
        
 
1888
        for layer, output in data:
 
1889
            if self.importType == 'ogr':
 
1890
                if ext and layer.rfind(ext) > -1:
 
1891
                    layer = layer.replace('.' + ext, '')
 
1892
                if '|' in layer:
 
1893
                    layer, geometry = layer.split('|', 1)
 
1894
                else:
 
1895
                    geometry = None
 
1896
                if self.link:
 
1897
                    cmd = ['v.external',
 
1898
                           'input=%s' % dsn,
 
1899
                           'output=%s' % output,
 
1900
                           'layer=%s' % layer]
 
1901
                else:
 
1902
                    cmd = ['v.in.ogr',
 
1903
                           'input=%s' % dsn,
 
1904
                           'layer=%s' % layer,
 
1905
                           'output=%s' % output,
 
1906
                           'geometry=%s' % geometry]
 
1907
            else: # gdal
 
1908
                if self.dsnInput.GetType() == 'dir':
 
1909
                    idsn = os.path.join(dsn, layer)
 
1910
                else:
 
1911
                    idsn = dsn
 
1912
                
 
1913
                if self.link:
 
1914
                    cmd = ['r.external',
 
1915
                           'input=%s' % idsn,
 
1916
                           'output=%s' % output]
 
1917
                else:
 
1918
                    cmd = ['r.in.gdal',
 
1919
                           'input=%s' % idsn,
 
1920
                           'output=%s' % output]
 
1921
            
 
1922
            if self.overwrite.IsChecked():
 
1923
                cmd.append('--overwrite')
 
1924
            
 
1925
            for key in self.options.keys():
 
1926
                if self.options[key].IsChecked():
 
1927
                    cmd.append('-%s' % key)
 
1928
            
 
1929
            if UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled') and \
 
1930
                    '--overwrite' not in cmd:
 
1931
                cmd.append('--overwrite')
 
1932
            
 
1933
            # run in Layer Manager
 
1934
            self._giface.RunCmd(cmd, onDone=self.OnCmdDone)
 
1935
 
 
1936
    def OnCmdDone(self, cmd, returncode):
 
1937
        """Load layers and close if required"""
 
1938
        if not hasattr(self, 'AddLayers'):
 
1939
            return
 
1940
 
 
1941
        self.AddLayers(cmd, returncode)
 
1942
 
 
1943
        if self.popOGR:
 
1944
            os.environ.pop('GRASS_VECTOR_OGR')
 
1945
 
 
1946
        if returncode == 0 and self.closeOnFinish.IsChecked():
 
1947
            self.Close()
 
1948
 
 
1949
    def _getCommand(self):
 
1950
        """Get command"""
 
1951
        if self.link:
 
1952
            if self.ogr:
 
1953
                return 'v.external'
 
1954
            else:
 
1955
                return 'r.external'
 
1956
        else:
 
1957
            if self.ogr:
 
1958
                return 'v.in.ogr'
 
1959
            else:
 
1960
                return 'r.in.gdal'
 
1961
        
 
1962
        return ''
 
1963
 
 
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
 
1968
 
 
1969
        .. todo::
 
1970
            Split into GdalOutputDialog and OgrOutputDialog
 
1971
 
 
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
 
1977
        """
 
1978
        self.parent = parent # GMFrame 
 
1979
        self.ogr = ogr
 
1980
        wx.Dialog.__init__(self, parent, id = id, style = style, *kwargs)
 
1981
        if self.ogr:
 
1982
            self.SetTitle(_("Define output format for vector data"))
 
1983
        else:
 
1984
            self.SetTitle(_("Define output format for raster data"))
 
1985
        
 
1986
        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
 
1987
 
 
1988
        # buttons
 
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()
 
1994
        
 
1995
        self.dsnInput = GdalSelect(parent = self, panel = self.panel,
 
1996
                                   ogr = ogr,
 
1997
                                   exclude = ['file', 'protocol'], dest = True)
 
1998
        
 
1999
        self.Bind(wx.EVT_BUTTON, self.OnCancel, self.btnCancel)
 
2000
        self.Bind(wx.EVT_BUTTON, self.OnOK, self.btnOk)
 
2001
        
 
2002
        self._layout()
 
2003
 
 
2004
    def _layout(self):
 
2005
        dialogSizer = wx.BoxSizer(wx.VERTICAL)
 
2006
        
 
2007
        dialogSizer.Add(item = self.dsnInput, proportion = 1,
 
2008
                        flag = wx.EXPAND)
 
2009
 
 
2010
        btnSizer = wx.BoxSizer(orient = wx.HORIZONTAL)
 
2011
        btnSizer.Add(item = self.btnCancel, proportion = 0,
 
2012
                     flag = wx.LEFT | wx.RIGHT | wx.ALIGN_CENTER,
 
2013
                     border = 10)
 
2014
        btnSizer.Add(item = self.btnOk, proportion = 0,
 
2015
                     flag = wx.RIGHT | wx.ALIGN_CENTER,
 
2016
                     border = 10)
 
2017
        
 
2018
        dialogSizer.Add(item = btnSizer, proportion = 0,
 
2019
                        flag = wx.ALIGN_CENTER_VERTICAL | wx.BOTTOM | wx.TOP | wx.ALIGN_RIGHT,
 
2020
                        border = 10)
 
2021
        
 
2022
        self.panel.SetAutoLayout(True)
 
2023
        self.panel.SetSizer(dialogSizer)
 
2024
        dialogSizer.Fit(self.panel)
 
2025
 
 
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))
 
2029
        self.Layout()
 
2030
        
 
2031
    def OnCancel(self, event):
 
2032
        self.Destroy()
 
2033
        
 
2034
    def OnOK(self, event):
 
2035
        if self.dsnInput.GetType() == 'native':
 
2036
            RunCommand('v.external.out',
 
2037
                       parent = self,
 
2038
                       flags = 'r')
 
2039
        else:
 
2040
            dsn = self.dsnInput.GetDsn()
 
2041
            frmt = self.dsnInput.GetFormat()
 
2042
            options = self.dsnInput.GetOptions()
 
2043
            if not dsn:
 
2044
                GMessage(_("No data source selected."), parent=self)
 
2045
                return
 
2046
            
 
2047
            RunCommand('v.external.out',
 
2048
                       parent = self,
 
2049
                       output = dsn, format = frmt,
 
2050
                       options = options)
 
2051
        self.Close()
 
2052
        
 
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")
 
2066
        
 
2067
        self.add.SetLabel(_("Add imported layers into layer tree"))
 
2068
        
 
2069
        self.add.SetValue(UserSettings.Get(group = 'cmd', key = 'addNewLayer', subkey = 'enabled'))
 
2070
        
 
2071
        self.doLayout()
 
2072
 
 
2073
    def _getCommand(self):
 
2074
        """Get command"""
 
2075
        return 'v.in.dxf'
 
2076
    
 
2077
    def OnRun(self, event):
 
2078
        """Import/Link data (each layes as separate vector map)"""
 
2079
        data = self.list.GetLayers()
 
2080
        if not data:
 
2081
            GMessage(_("No layers selected."), parent=self)
 
2082
            return
 
2083
        
 
2084
        # hide dialog
 
2085
        self.Hide()
 
2086
        
 
2087
        inputDxf = self.dsnInput.GetValue()
 
2088
        
 
2089
        for layer, output in data:
 
2090
            cmd = ['v.in.dxf',
 
2091
                   'input=%s' % inputDxf,
 
2092
                   'layers=%s' % layer,
 
2093
                   'output=%s' % output]
 
2094
 
 
2095
            for key in self.options.keys():
 
2096
                if self.options[key].IsChecked():
 
2097
                    cmd.append('-%s' % key)
 
2098
            
 
2099
            if self.overwrite.IsChecked() or \
 
2100
                    UserSettings.Get(group = 'cmd', key = 'overwrite', subkey = 'enabled'):
 
2101
                cmd.append('--overwrite')
 
2102
            
 
2103
            # run in Layer Manager
 
2104
            self._giface.RunCmd(cmd, onDone=self.OnCmdDone)
 
2105
 
 
2106
    def OnCmdDone(self, cmd, returncode):
 
2107
        """Load layers and close if required"""
 
2108
        if not hasattr(self, 'AddLayers'):
 
2109
            return
 
2110
 
 
2111
        self.AddLayers(cmd, returncode)
 
2112
 
 
2113
        if self.closeOnFinish.IsChecked():
 
2114
            self.Close()
 
2115
 
 
2116
    def OnSetDsn(self, event):
 
2117
        """Input DXF file defined, update list of layer widget"""
 
2118
        path = event.GetString()
 
2119
        if not path:
 
2120
            return 
 
2121
        
 
2122
        data = list()        
 
2123
        ret = RunCommand('v.in.dxf',
 
2124
                         quiet = True,
 
2125
                         parent = self,
 
2126
                         read = True,
 
2127
                         flags = 'l',
 
2128
                         input = path)
 
2129
        if not ret:
 
2130
            self.list.LoadData()
 
2131
            return
 
2132
            
 
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()))
 
2138
        
 
2139
        self.list.LoadData(data)
 
2140
 
 
2141
 
 
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)
 
2146
        
 
2147
        self.log = log
 
2148
        
 
2149
        # setup mixins
 
2150
        listmix.TextEditMixin.__init__(self)
 
2151
        
 
2152
        for i in range(len(columns)):
 
2153
            self.InsertColumn(i, columns[i])
 
2154
        
 
2155
        if len(columns) == 3:
 
2156
            width = (65, 200)
 
2157
        else:
 
2158
            width = (65, 180, 90, 70)
 
2159
        
 
2160
        for i in range(len(width)):
 
2161
            self.SetColumnWidth(col = i, width = width[i])
 
2162
        
 
2163
    def LoadData(self, data = None):
 
2164
        """Load data into list"""
 
2165
        self.DeleteAllItems()
 
2166
        if data is None:
 
2167
            return
 
2168
        
 
2169
        for item in data:
 
2170
            index = self.InsertStringItem(sys.maxint, str(item[0]))
 
2171
            for i in range(1, len(item)):
 
2172
                self.SetStringItem(index, i, item[i])
 
2173
        
 
2174
        # check by default only on one item
 
2175
        if len(data) == 1:
 
2176
            self.CheckItem(index, True)
 
2177
        
 
2178
    def OnLeftDown(self, event):
 
2179
        """Allow editing only output name
 
2180
        
 
2181
        Code taken from TextEditMixin class.
 
2182
        """
 
2183
        x, y = event.GetPosition()
 
2184
        
 
2185
        colLocs = [0]
 
2186
        loc = 0
 
2187
        for n in range(self.GetColumnCount()):
 
2188
            loc = loc + self.GetColumnWidth(n)
 
2189
            colLocs.append(loc)
 
2190
        
 
2191
        col = bisect(colLocs, x + self.GetScrollPos(wx.HORIZONTAL)) - 1
 
2192
        
 
2193
        if col == self.GetColumnCount() - 1:
 
2194
            listmix.TextEditMixin.OnLeftDown(self, event)
 
2195
        else:
 
2196
            event.Skip()
 
2197
        
 
2198
    def GetLayers(self):
 
2199
        """Get list of layers (layer name, output name)"""
 
2200
        data = []
 
2201
        item = -1
 
2202
        while True:
 
2203
            item = self.GetNextItem(item)
 
2204
            if item == -1:
 
2205
                break
 
2206
            if not self.IsChecked(item):
 
2207
                continue
 
2208
            # layer / output name
 
2209
            layer = self.GetItem(item, 1).GetText()
 
2210
            ftype = self.GetItem(item, 2).GetText()
 
2211
            if '/' in ftype:
 
2212
                layer += '|%s' % ftype.split('/', 1)[0]
 
2213
            output = self.GetItem(item, self.GetColumnCount() - 1).GetText()
 
2214
            data.append((layer, output))
 
2215
        
 
2216
        return data
 
2217
 
 
2218
class SetOpacityDialog(wx.Dialog):
 
2219
    """Set opacity of map layers.
 
2220
    Dialog expects opacity between 0 and 1 and returns this range, too.    
 
2221
    """
 
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):
 
2225
 
 
2226
        self.parent = parent    # GMFrame
 
2227
        self.opacity = opacity  # current opacity
 
2228
 
 
2229
        super(SetOpacityDialog, self).__init__(parent, id = id, pos = pos,
 
2230
                                               size = size, style = style, title = title)
 
2231
 
 
2232
        self.applyOpacity = Signal('SetOpacityDialog.applyOpacity')
 
2233
        panel = wx.Panel(parent = self, id = wx.ID_ANY)
 
2234
        
 
2235
        sizer = wx.BoxSizer(wx.VERTICAL)
 
2236
 
 
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,
 
2242
                               size = (350, -1))
 
2243
 
 
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")),
 
2248
                pos = (1, 0))
 
2249
        box.Add(item = wx.StaticText(parent = panel, id = wx.ID_ANY,
 
2250
                                   label = _("opaque")),
 
2251
                flag = wx.ALIGN_RIGHT,
 
2252
                pos = (1, 1))
 
2253
 
 
2254
        sizer.Add(item = box, proportion = 0,
 
2255
                  flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5)
 
2256
 
 
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)
 
2261
 
 
2262
        # buttons
 
2263
        btnsizer = wx.StdDialogButtonSizer()
 
2264
 
 
2265
        btnOK = wx.Button(parent = panel, id = wx.ID_OK)
 
2266
        btnOK.SetDefault()
 
2267
        btnsizer.AddButton(btnOK)
 
2268
 
 
2269
        btnCancel = wx.Button(parent = panel, id = wx.ID_CANCEL)
 
2270
        btnsizer.AddButton(btnCancel)
 
2271
 
 
2272
        btnApply = wx.Button(parent = panel, id = wx.ID_APPLY)
 
2273
        btnApply.Bind(wx.EVT_BUTTON, self.OnApply)
 
2274
        btnsizer.AddButton(btnApply)
 
2275
        btnsizer.Realize()
 
2276
 
 
2277
        sizer.Add(item = btnsizer, proportion = 0,
 
2278
                  flag = wx.EXPAND | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border = 5)
 
2279
 
 
2280
        panel.SetSizer(sizer)
 
2281
        sizer.Fit(panel)
 
2282
 
 
2283
        self.SetSize(self.GetBestSize())
 
2284
 
 
2285
        self.Layout()
 
2286
 
 
2287
    def GetOpacity(self):
 
2288
        """Button 'OK' pressed"""
 
2289
        # return opacity value
 
2290
        opacity = float(self.value.GetValue()) / 100
 
2291
        return opacity
 
2292
 
 
2293
    def OnApply(self, event):
 
2294
        self.applyOpacity.emit(value = self.GetOpacity())
 
2295
 
 
2296
 
 
2297
def GetImageHandlers(image):
 
2298
    """Get list of supported image handlers"""
 
2299
    lext = list()
 
2300
    ltype = list()
 
2301
    for h in image.GetHandlers():
 
2302
        lext.append(h.GetExtension())
 
2303
        
 
2304
    filetype = ''
 
2305
    if 'png' in lext:
 
2306
        filetype += "PNG file (*.png)|*.png|"
 
2307
        ltype.append({ 'type' : wx.BITMAP_TYPE_PNG,
 
2308
                       'ext'  : 'png' })
 
2309
    filetype +=  "BMP file (*.bmp)|*.bmp|"
 
2310
    ltype.append({ 'type' : wx.BITMAP_TYPE_BMP,
 
2311
                   'ext'  : 'bmp' })
 
2312
    if 'gif' in lext:
 
2313
        filetype += "GIF file (*.gif)|*.gif|"
 
2314
        ltype.append({ 'type' : wx.BITMAP_TYPE_GIF,
 
2315
                       'ext'  : 'gif' })
 
2316
        
 
2317
    if 'jpg' in lext:
 
2318
        filetype += "JPG file (*.jpg)|*.jpg|"
 
2319
        ltype.append({ 'type' : wx.BITMAP_TYPE_JPEG,
 
2320
                       'ext'  : 'jpg' })
 
2321
 
 
2322
    if 'pcx' in lext:
 
2323
        filetype += "PCX file (*.pcx)|*.pcx|"
 
2324
        ltype.append({ 'type' : wx.BITMAP_TYPE_PCX,
 
2325
                       'ext'  : 'pcx' })
 
2326
        
 
2327
    if 'pnm' in lext:
 
2328
        filetype += "PNM file (*.pnm)|*.pnm|"
 
2329
        ltype.append({ 'type' : wx.BITMAP_TYPE_PNM,
 
2330
                       'ext'  : 'pnm' })
 
2331
 
 
2332
    if 'tif' in lext:
 
2333
        filetype += "TIF file (*.tif)|*.tif|"
 
2334
        ltype.append({ 'type' : wx.BITMAP_TYPE_TIF,
 
2335
                       'ext'  : 'tif' })
 
2336
 
 
2337
    if 'xpm' in lext:
 
2338
        filetype += "XPM file (*.xpm)|*.xpm"
 
2339
        ltype.append({ 'type' : wx.BITMAP_TYPE_XPM,
 
2340
                       'ext'  : 'xpm' })
 
2341
    
 
2342
    return filetype, ltype
 
2343
 
 
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
 
2349
        
 
2350
        wx.Dialog.__init__(self, parent, id = id, style = style, title = title, **kwargs)
 
2351
        
 
2352
        self.panel = wx.Panel(parent = self, id = wx.ID_ANY)
 
2353
        
 
2354
        self.box = wx.StaticBox(parent = self.panel, id = wx.ID_ANY,
 
2355
                                label = ' % s' % _("Image size"))
 
2356
        
 
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,
 
2368
                                  size = (125, -1),
 
2369
                                  choices = [ "",
 
2370
                                              "640x480",
 
2371
                                              "800x600",
 
2372
                                              "1024x768",
 
2373
                                              "1280x960",
 
2374
                                              "1600x1200",
 
2375
                                              "1920x1440" ])
 
2376
        
 
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)
 
2380
        
 
2381
        self.template.Bind(wx.EVT_CHOICE, self.OnTemplate)
 
2382
        
 
2383
        self._layout()
 
2384
        self.SetSize(self.GetBestSize())
 
2385
        
 
2386
    def _layout(self):
 
2387
        """Do layout"""
 
2388
        sizer = wx.BoxSizer(wx.VERTICAL)
 
2389
        
 
2390
        # body
 
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)
 
2405
        
 
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)
 
2410
        
 
2411
        # buttons
 
2412
        btnsizer = wx.StdDialogButtonSizer()
 
2413
        btnsizer.AddButton(self.btnOK)
 
2414
        btnsizer.AddButton(self.btnCancel)
 
2415
        btnsizer.Realize()
 
2416
 
 
2417
        sizer.Add(item = btnsizer, proportion = 0,
 
2418
                  flag = wx.EXPAND | wx.ALIGN_RIGHT | wx.ALL, border=5)
 
2419
        
 
2420
        self.panel.SetSizer(sizer)
 
2421
        sizer.Fit(self.panel)
 
2422
        self.Layout()
 
2423
    
 
2424
    def GetValues(self):
 
2425
        """Get width/height values"""
 
2426
        return self.width.GetValue(), self.height.GetValue()
 
2427
    
 
2428
    def OnTemplate(self, event):
 
2429
        """Template selected"""
 
2430
        sel = event.GetString()
 
2431
        if not sel:
 
2432
            width, height = self.parent.GetWindow().GetClientSize()
 
2433
        else:
 
2434
            width, height = map(int, sel.split('x'))
 
2435
        self.width.SetValue(width)
 
2436
        self.height.SetValue(height)
 
2437
        
 
2438
class SqlQueryFrame(wx.Frame):
 
2439
    def __init__(self, parent, id = wx.ID_ANY,
 
2440
                 title = _("GRASS GIS SQL Query Utility"),
 
2441
                 *kwargs):
 
2442
        """SQL Query Utility window
 
2443
        """
 
2444
        self.parent = parent
 
2445
 
 
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)
 
2449
        
 
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)
 
2454
        
 
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)
 
2458
        
 
2459
        self._layout()
 
2460
 
 
2461
        self.SetMinSize(wx.Size(300, 150))
 
2462
        self.SetSize(wx.Size(500, 200))
 
2463
        
 
2464
    def _layout(self):
 
2465
        """Do layout"""
 
2466
        sizer = wx.BoxSizer(wx.VERTICAL)
 
2467
        
 
2468
        sqlSizer = wx.StaticBoxSizer(self.sqlBox, wx.HORIZONTAL)
 
2469
        sqlSizer.Add(item = self.sql, proportion = 1,
 
2470
                     flag = wx.EXPAND)
 
2471
 
 
2472
        btnSizer = wx.StdDialogButtonSizer()
 
2473
        btnSizer.AddButton(self.btnApply)
 
2474
        btnSizer.AddButton(self.btnCancel)
 
2475
        btnSizer.Realize()
 
2476
        
 
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)
 
2481
       
 
2482
        self.panel.SetSizer(sizer)
 
2483
        
 
2484
        self.Layout()
 
2485
 
 
2486
    def OnCloseWindow(self, event):
 
2487
        """Close window
 
2488
        """
 
2489
        self.Close()
 
2490
 
 
2491
class SymbolDialog(wx.Dialog):
 
2492
    """Dialog for GRASS symbols selection.
 
2493
    
 
2494
    Dialog is called in gui_core::forms module.
 
2495
    """
 
2496
    def __init__(self, parent, symbolPath, currentSymbol = None, title = _("Symbols")):
 
2497
        """Dialog constructor.
 
2498
        
 
2499
        It is assumed that symbolPath contains folders with symbols.
 
2500
        
 
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
 
2505
        """
 
2506
        wx.Dialog.__init__(self, parent = parent, title = title, id = wx.ID_ANY)
 
2507
        
 
2508
        self.symbolPath = symbolPath
 
2509
        self.currentSymbol = currentSymbol # default basic/x
 
2510
        self.selected = None
 
2511
        self.selectedDir = None
 
2512
        
 
2513
        self._layout()
 
2514
        
 
2515
    def _layout(self):
 
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)
 
2522
        
 
2523
        fgSizer.Add(item = wx.StaticText(mainPanel, id = wx.ID_ANY, label = _("Symbol directory:")),
 
2524
                   proportion = 0,
 
2525
                   flag = wx.ALIGN_CENTER_VERTICAL)
 
2526
                   
 
2527
        fgSizer.Add(item = self.folderChoice, proportion = 0,
 
2528
                   flag = wx.ALIGN_CENTER, border = 0)
 
2529
                   
 
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)
 
2536
        
 
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)
 
2540
        
 
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)
 
2546
        
 
2547
        # buttons
 
2548
        btnSizer = wx.StdDialogButtonSizer()
 
2549
        btnSizer.AddButton(self.btnCancel)
 
2550
        btnSizer.AddButton(self.btnOK)
 
2551
        btnSizer.Realize()
 
2552
        mainSizer.Add(item = btnSizer, proportion = 0,
 
2553
                      flag = wx.EXPAND | wx.ALL, border = 5)
 
2554
                      
 
2555
        # show panel with the largest number of images and fit size
 
2556
        count = []
 
2557
        for folder in os.listdir(self.symbolPath):
 
2558
            count.append(len(os.listdir(os.path.join(self.symbolPath, folder))))
 
2559
            
 
2560
        index = count.index(max(count))
 
2561
        self.folderChoice.SetSelection(index)
 
2562
        self.OnFolderSelect(None)
 
2563
        self.infoLabel.Show()
 
2564
        
 
2565
        mainPanel.SetSizerAndFit(mainSizer)
 
2566
        self.SetSize(self.GetBestSize())
 
2567
        
 
2568
        # show currently selected symbol
 
2569
        if self.currentSymbol:
 
2570
            # set directory
 
2571
            self.selectedDir, self.selected = os.path.split(self.currentSymbol)
 
2572
            self.folderChoice.SetStringSelection(self.selectedDir)
 
2573
            # select symbol
 
2574
            panelIdx = self.folderChoice.GetSelection()
 
2575
            for panel in self.symbolPanels[panelIdx]:
 
2576
                if panel.GetName() == self.selected:
 
2577
                    panel.Select()
 
2578
        else:
 
2579
            self.folderChoice.SetSelection(0)
 
2580
            
 
2581
        self.OnFolderSelect(None)
 
2582
        
 
2583
    def _createSymbolPanels(self, parent):
 
2584
        """Creates multiple panels with symbols.
 
2585
        
 
2586
        Panels are shown/hidden according to selected folder."""
 
2587
        folders = os.listdir(self.symbolPath)
 
2588
        
 
2589
        panels = []
 
2590
        self.symbolPanels = []
 
2591
        
 
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))
 
2596
        
 
2597
            symbolPanels = []
 
2598
            for img in images:
 
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)
 
2603
            
 
2604
            panel.SetSizerAndFit(sizer)
 
2605
            panel.Hide()
 
2606
            panels.append(panel)
 
2607
            self.symbolPanels.append(symbolPanels)
 
2608
            
 
2609
        return panels
 
2610
        
 
2611
    def _getSymbols(self, path):
 
2612
        # we assume that images are in subfolders (1 level only)
 
2613
        imageList = []
 
2614
        for image in os.listdir(path):
 
2615
            imageList.append(os.path.join(path, image))
 
2616
                
 
2617
        return sorted(imageList)
 
2618
            
 
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)
 
2625
            sizer.Layout()
 
2626
        
 
2627
        if self.selectedDir == self.folderChoice.GetStringSelection():
 
2628
            self.btnOK.Enable()
 
2629
            self.infoLabel.SetLabel(self.selected)
 
2630
        else:
 
2631
            self.btnOK.Disable()
 
2632
            self.infoLabel.SetLabel('')
 
2633
        
 
2634
    def SelectionChanged(self, name, doubleClick):
 
2635
        """Selected symbol changed."""
 
2636
        if doubleClick:
 
2637
            self.EndModal(wx.ID_OK)
 
2638
        # deselect all
 
2639
        for i in range(len(self.panels)):
 
2640
            for panel in self.symbolPanels[i]:
 
2641
                if panel.GetName() != name:
 
2642
                    panel.Deselect()
 
2643
                
 
2644
        self.btnOK.Enable()
 
2645
        
 
2646
        self.selected = name
 
2647
        self.selectedDir = self.folderChoice.GetStringSelection()
 
2648
        
 
2649
        self.infoLabel.SetLabel(name)
 
2650
        
 
2651
    def GetSelectedSymbolName(self):
 
2652
        """Returns currently selected symbol name (e.g. 'basic/x').
 
2653
        """
 
2654
        # separator must be '/' and not dependent on OS
 
2655
        return self.selectedDir + '/' + self.selected
 
2656
 
 
2657
    def GetSelectedSymbolPath(self):
 
2658
        """Returns currently selected symbol full path.
 
2659
        """
 
2660
        return os.path.join(self.symbolPath, self.selectedDir, self.selected)
 
2661
 
 
2662
 
 
2663
class TextEntryDialog(wx.Dialog):
 
2664
    """Simple dialog with text field. 
 
2665
 
 
2666
    It differs from wx.TextEntryDialog because it allows adding validator.
 
2667
    """
 
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)
 
2672
 
 
2673
        vbox = wx.BoxSizer(wx.VERTICAL)
 
2674
 
 
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)
 
2677
 
 
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()
 
2682
 
 
2683
        sizer = self.CreateSeparatedButtonSizer(style)
 
2684
        vbox.Add(item=sizer, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
 
2685
 
 
2686
        self.SetSizerAndFit(vbox)
 
2687
        
 
2688
    def GetValue(self):
 
2689
        return self._textCtrl.GetValue()
 
2690
 
 
2691
    def SetValue(self, value):
 
2692
        self._textCtrl.SetValue(value)
 
2693
 
 
2694
 
 
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):
 
2699
        """Constructor
 
2700
 
 
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
 
2707
        """
 
2708
        wx.Dialog.__init__(self, parent=parent, id=wx.ID_ANY, title=title,
 
2709
                           style=wx.DEFAULT_DIALOG_STYLE)
 
2710
 
 
2711
        sizer = wx.BoxSizer(wx.VERTICAL)
 
2712
 
 
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)        
 
2720
 
 
2721
        btnsizer = self.CreateSeparatedButtonSizer(style)
 
2722
        sizer.Add(item=btnsizer, proportion=1, flag=wx.EXPAND | wx.ALL, border=10)
 
2723
    
 
2724
        self.SetSizer(sizer)
 
2725
        sizer.Fit(self)