~ubuntu-branches/ubuntu/vivid/grass/vivid-proposed

« back to all changes in this revision

Viewing changes to gui/wxpython/iscatt/frame.py

  • Committer: Package Import Robot
  • Author(s): Bas Couwenberg
  • Date: 2015-02-20 23:12:08 UTC
  • mfrom: (8.2.6 experimental)
  • Revision ID: package-import@ubuntu.com-20150220231208-1u6qvqm84v430b10
Tags: 7.0.0-1~exp1
* New upstream release.
* Update python-ctypes-ternary.patch to use if/else instead of and/or.
* Drop check4dev patch, rely on upstream check.
* Add build dependency on libpq-dev to grass-dev for libpq-fe.h.
* Drop patches applied upstream, refresh remaining patches.
* Update symlinks for images switched from jpg to png.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""
 
2
@package iscatt.frame
 
3
 
 
4
@brief Main scatter plot widgets.
 
5
 
 
6
Classes:
 
7
 - frame::IClassIScattPanel
 
8
 - frame::IScattDialog
 
9
 - frame::MapDispIScattPanel
 
10
 - frame::ScatterPlotsPanel
 
11
 - frame::CategoryListCtrl
 
12
 
 
13
(C) 2013 by the GRASS Development Team
 
14
 
 
15
This program is free software under the GNU General Public License
 
16
(>=v2). Read the file COPYING that comes with GRASS for details.
 
17
 
 
18
@author Stepan Turek <stepan.turek seznam.cz> (mentor: Martin Landa)
 
19
"""
 
20
import os
 
21
import sys
 
22
 
 
23
import wx
 
24
import wx.lib.scrolledpanel as scrolled
 
25
import wx.lib.mixins.listctrl as listmix
 
26
 
 
27
from core import globalvar
 
28
from core.gcmd import GException, GError, RunCommand
 
29
 
 
30
from gui_core.gselect import Select
 
31
from gui_core.dialogs import SetOpacityDialog
 
32
from iscatt.controllers import ScattsManager
 
33
from iscatt.toolbars import MainToolbar, EditingToolbar, CategoryToolbar
 
34
from iscatt.iscatt_core import idScattToidBands
 
35
from iscatt.dialogs import ManageBusyCursorMixin, RenameClassDialog
 
36
from iscatt.plots import ScatterPlotWidget
 
37
from iclass.dialogs import ContrastColor
 
38
 
 
39
try:
 
40
    from agw import aui
 
41
except ImportError:
 
42
    import wx.lib.agw.aui as aui
 
43
 
 
44
class IClassIScattPanel(wx.Panel, ManageBusyCursorMixin):
 
45
    def __init__(self, parent, giface, iclass_mapwin = None,
 
46
                 id = wx.ID_ANY):
 
47
 
 
48
        #wx.SplitterWindow.__init__(self, parent = parent, id = id,
 
49
        #                           style = wx.SP_LIVE_UPDATE)
 
50
        wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)
 
51
        ManageBusyCursorMixin.__init__(self, window=self)
 
52
 
 
53
        self.scatt_mgr = self._createScattMgr(guiparent=parent, giface=giface, 
 
54
                                              iclass_mapwin=iclass_mapwin)
 
55
 
 
56
        # toobars
 
57
        self.toolbars = {}
 
58
        self.toolbars['mainToolbar'] = self._createMainToolbar()
 
59
        self.toolbars['editingToolbar'] = EditingToolbar(parent = self, scatt_mgr = self.scatt_mgr)
 
60
        
 
61
        self._createCategoryPanel(self)
 
62
 
 
63
        self.plot_panel = ScatterPlotsPanel(self, self.scatt_mgr)
 
64
 
 
65
        self.mainsizer = wx.BoxSizer(wx.VERTICAL)
 
66
        self.mainsizer.Add(item = self.toolbars['mainToolbar'], proportion = 0, flag = wx.EXPAND)
 
67
        self.mainsizer.Add(item = self.toolbars['editingToolbar'], proportion = 0, flag = wx.EXPAND)
 
68
        self.mainsizer.Add(item = self.catsPanel, proportion = 0, 
 
69
                           flag = wx.EXPAND | wx.LEFT | wx.RIGHT , border = 5)
 
70
        self.mainsizer.Add(item = self.plot_panel, proportion = 1, flag = wx.EXPAND)
 
71
 
 
72
        self.catsPanel.Hide()
 
73
        self.toolbars['editingToolbar'].Hide()
 
74
 
 
75
        self.SetSizer(self.mainsizer)
 
76
        
 
77
        self.scatt_mgr.computingStarted.connect(lambda : self.UpdateCur(busy=True))
 
78
        self.scatt_mgr.renderingStarted.connect(lambda : self.UpdateCur(busy=True))
 
79
        self.scatt_mgr.renderingFinished.connect(lambda : self.UpdateCur(busy=False))
 
80
 
 
81
        #self.SetSashGravity(0.5)
 
82
        #self.SplitHorizontally(self.head_panel, self.plot_panel, -50)
 
83
        self.Layout()
 
84
 
 
85
    def CloseWindow(self):
 
86
        self.scatt_mgr.CleanUp()
 
87
 
 
88
    def UpdateCur(self, busy):
 
89
        self.plot_panel.SetBusy(busy)
 
90
        ManageBusyCursorMixin.UpdateCur(self, busy)
 
91
 
 
92
    def _selCatInIScatt(self):
 
93
         return False
 
94
 
 
95
    def _createMainToolbar(self):
 
96
         return MainToolbar(parent = self, scatt_mgr = self.scatt_mgr)
 
97
 
 
98
    def _createScattMgr(self, guiparent, giface, iclass_mapwin):
 
99
        return ScattsManager(guiparent=self, giface=giface, iclass_mapwin=iclass_mapwin)
 
100
 
 
101
 
 
102
    def NewScatterPlot(self, scatt_id, transpose):
 
103
        return self.plot_panel.NewScatterPlot(scatt_id, transpose)
 
104
 
 
105
    def ShowPlotEditingToolbar(self, show):
 
106
        self.toolbars["editingToolbar"].Show(show)
 
107
        self.Layout()
 
108
 
 
109
    def ShowCategoryPanel(self, show):
 
110
        self.catsPanel.Show(show)
 
111
        
 
112
        #if show:
 
113
        #    self.SetSashSize(5) 
 
114
        #else:
 
115
        #    self.SetSashSize(0)
 
116
        self.plot_panel.SetVirtualSize(self.plot_panel.GetBestVirtualSize())
 
117
        self.Layout()
 
118
 
 
119
    def _createCategoryPanel(self, parent):
 
120
        self.catsPanel = wx.Panel(parent=parent)
 
121
        self.cats_list = CategoryListCtrl(parent=self.catsPanel, 
 
122
                                          cats_mgr=self.scatt_mgr.GetCategoriesManager(),
 
123
                                          sel_cats_in_iscatt=self._selCatInIScatt())
 
124
 
 
125
        self.catsPanel.SetMinSize((-1, 100))
 
126
        self.catsPanel.SetInitialSize((-1, 150))
 
127
 
 
128
        box_capt = wx.StaticBox(parent=self.catsPanel, id=wx.ID_ANY,
 
129
                             label=' %s ' % _("Classes"),)
 
130
        catsSizer = wx.StaticBoxSizer(box_capt, wx.VERTICAL)
 
131
 
 
132
        self.toolbars['categoryToolbar'] = self._createCategoryToolbar(self.catsPanel)
 
133
 
 
134
        catsSizer.Add(item=self.cats_list, proportion=1,  flag=wx.EXPAND | wx.TOP, border = 5)
 
135
        if self.toolbars['categoryToolbar']:
 
136
            catsSizer.Add(item=self.toolbars['categoryToolbar'], proportion=0)
 
137
 
 
138
        self.catsPanel.SetSizer(catsSizer)
 
139
    
 
140
    def _createCategoryToolbar(self, parent):
 
141
        return CategoryToolbar(parent=parent,
 
142
                               scatt_mgr=self.scatt_mgr, 
 
143
                               cats_list=self.cats_list)
 
144
 
 
145
class IScattDialog(wx.Dialog):
 
146
    def __init__(self, parent, giface, title=_("GRASS GIS Interactive Scatter Plot Tool"),
 
147
                 id=wx.ID_ANY, style=wx.DEFAULT_FRAME_STYLE, **kwargs):
 
148
        wx.Dialog.__init__(self, parent, id, style=style, title = title, **kwargs)
 
149
        self.SetIcon(wx.Icon(os.path.join(globalvar.ICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
 
150
 
 
151
        self.iscatt_panel = MapDispIScattPanel(self, giface)
 
152
 
 
153
        mainsizer = wx.BoxSizer(wx.VERTICAL)
 
154
        mainsizer.Add(item=self.iscatt_panel, proportion=1, flag=wx.EXPAND)
 
155
 
 
156
        self.SetSizer(mainsizer)
 
157
 
 
158
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 
159
 
 
160
        self.SetMinSize((300, 300))
 
161
 
 
162
    def OnCloseWindow(self, event):
 
163
        event.Skip()
 
164
        #self.
 
165
 
 
166
class MapDispIScattPanel(IClassIScattPanel):
 
167
    def __init__(self, parent, giface,
 
168
                 id=wx.ID_ANY, **kwargs):
 
169
        IClassIScattPanel.__init__(self, parent=parent, giface=giface,
 
170
                                         id=id, **kwargs)
 
171
 
 
172
    def _createScattMgr(self, guiparent, giface, iclass_mapwin):
 
173
        return ScattsManager(guiparent = self, giface = giface)
 
174
 
 
175
    def _createMainToolbar(self):
 
176
         return MainToolbar(parent = self, scatt_mgr = self.scatt_mgr, opt_tools=['add_group'])
 
177
 
 
178
    def _selCatInIScatt(self):
 
179
         return True
 
180
 
 
181
class ScatterPlotsPanel(scrolled.ScrolledPanel):
 
182
    def __init__(self, parent, scatt_mgr, id=wx.ID_ANY):
 
183
    
 
184
        scrolled.ScrolledPanel.__init__(self, parent)
 
185
        self.SetupScrolling(scroll_x=False, scroll_y=True, scrollToTop=False)
 
186
 
 
187
        self.scatt_mgr = scatt_mgr
 
188
 
 
189
        self.mainPanel = wx.Panel(parent=self, id=wx.ID_ANY)
 
190
 
 
191
        #self._createCategoryPanel()
 
192
        # Fancy gui
 
193
        self._mgr = aui.AuiManager(self.mainPanel)
 
194
        #self._mgr.SetManagedWindow(self)
 
195
 
 
196
        self._mgr.Update()
 
197
 
 
198
        self._doLayout()
 
199
        self.Bind(wx.EVT_SCROLLWIN, self.OnScroll)
 
200
        self.Bind(wx.EVT_SCROLL_CHANGED, self.OnScrollChanged)
 
201
 
 
202
        self.Bind(aui.EVT_AUI_PANE_CLOSE, self.OnPlotPaneClosed)
 
203
 
 
204
        dlgSize = (-1, 400)
 
205
        #self.SetBestSize(dlgSize)
 
206
        #self.SetInitialSize(dlgSize)
 
207
        self.SetAutoLayout(1)
 
208
        #fix goutput's pane size (required for Mac OSX)
 
209
        #if self.gwindow:         
 
210
        #    self.gwindow.SetSashPosition(int(self.GetSize()[1] * .75))
 
211
        self.ignore_scroll = 0
 
212
        self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel)
 
213
 
 
214
        self.scatt_i = 1
 
215
        self.scatt_id_scatt_i = {}
 
216
        self.transpose = {}
 
217
        self.scatts = {}
 
218
 
 
219
        self.Bind(wx.EVT_CLOSE, self.OnClose)
 
220
        
 
221
        self.scatt_mgr.cursorPlotMove.connect(self.CursorPlotMove)
 
222
 
 
223
    def SetBusy(self, busy):
 
224
        for scatt in self.scatts.itervalues():
 
225
            scatt.UpdateCur(busy)
 
226
 
 
227
    def CursorPlotMove(self, x, y, scatt_id):
 
228
 
 
229
        try:
 
230
            x = int(round(x))
 
231
            y = int(round(y))
 
232
            coords = True
 
233
        except:
 
234
            coords = False
 
235
 
 
236
        pane = self._getPane(scatt_id)
 
237
        caption = self._creteCaption(scatt_id)
 
238
        if coords:
 
239
            caption += "   %d, %d" % (x, y)
 
240
 
 
241
        pane.Caption(caption)
 
242
        self._mgr.RefreshCaptions()
 
243
 
 
244
    def _getPane(self, scatt_id):
 
245
        scatt_i = self.scatt_id_scatt_i[scatt_id]
 
246
        name = self._getScatterPlotName(scatt_i)
 
247
        return self._mgr.GetPane(name)
 
248
 
 
249
    def ScatterPlotClosed(self, scatt_id):
 
250
 
 
251
        scatt_i = self.scatt_id_scatt_i[scatt_id]
 
252
 
 
253
        name = self._getScatterPlotName(scatt_i)
 
254
        pane = self._mgr.GetPane(name)
 
255
 
 
256
        del self.scatt_id_scatt_i[scatt_id]
 
257
        del self.scatts[scatt_id]
 
258
 
 
259
        if pane.IsOk(): 
 
260
          self._mgr.ClosePane(pane) 
 
261
        self._mgr.Update() 
 
262
 
 
263
    def OnMouseWheel(self, event):
 
264
        #TODO very ugly find some better solution        
 
265
        self.ignore_scroll = 3
 
266
        event.Skip()
 
267
 
 
268
    def ScrollChildIntoView(self, child):
 
269
        #For aui manager it does not work and returns position always to the top -> deactivated.
 
270
        pass
 
271
 
 
272
    def OnPlotPaneClosed(self, event):
 
273
        if isinstance(event.pane.window, ScatterPlotWidget):
 
274
            event.pane.window.CleanUp()
 
275
 
 
276
    def OnScrollChanged(self, event):
 
277
        wx.CallAfter(self.Layout)
 
278
 
 
279
    def OnScroll(self, event):
 
280
        if self.ignore_scroll > 0:
 
281
            self.ignore_scroll -= 1
 
282
        else:
 
283
            event.Skip()
 
284
 
 
285
        #wx.CallAfter(self._mgr.Update)
 
286
        #wx.CallAfter(self.Layout)
 
287
 
 
288
    def _doLayout(self):
 
289
 
 
290
        mainsizer = wx.BoxSizer(wx.VERTICAL)
 
291
        mainsizer.Add(item = self.mainPanel, proportion = 1, flag = wx.EXPAND)
 
292
        self.SetSizer(mainsizer)
 
293
 
 
294
        self.Layout()
 
295
        self.SetupScrolling()
 
296
 
 
297
    def OnClose(self, event):
 
298
        """Close dialog"""
 
299
        #TODO
 
300
        print "closed"
 
301
        self.scatt_mgr.CleanUp()
 
302
        self.Destroy()
 
303
 
 
304
    def OnSettings(self, event):
 
305
        pass
 
306
 
 
307
    def _newScatterPlotName(self, scatt_id):
 
308
        name = self._getScatterPlotName(self.scatt_i) 
 
309
        self.scatt_id_scatt_i[scatt_id] = self.scatt_i
 
310
        self.scatt_i += 1
 
311
        return name
 
312
 
 
313
    def _getScatterPlotName(self, i):
 
314
        name = "scatter plot %d" % i
 
315
        return name
 
316
 
 
317
    def NewScatterPlot(self, scatt_id, transpose):
 
318
        #TODO needs to be resolved (should be in this class)
 
319
 
 
320
        scatt = ScatterPlotWidget(parent = self.mainPanel, 
 
321
                                  scatt_mgr = self.scatt_mgr, 
 
322
                                  scatt_id = scatt_id, 
 
323
                                  transpose = transpose)
 
324
        scatt.plotClosed.connect(self.ScatterPlotClosed)
 
325
        self.transpose[scatt_id] = transpose
 
326
        
 
327
        caption = self._creteCaption(scatt_id)
 
328
        self._mgr.AddPane(scatt,
 
329
                           aui.AuiPaneInfo().Dockable(True).Floatable(True).
 
330
                           Name(self._newScatterPlotName(scatt_id)).MinSize((-1, 300)).
 
331
                           Caption(caption).
 
332
                           Center().Position(1).MaximizeButton(True).
 
333
                           MinimizeButton(True).CaptionVisible(True).
 
334
                           CloseButton(True).Layer(0))
 
335
 
 
336
        self._mgr.Update()
 
337
  
 
338
        self.SetVirtualSize(self.GetBestVirtualSize())
 
339
        self.Layout()
 
340
 
 
341
        self.scatts[scatt_id] = scatt
 
342
 
 
343
        return scatt
 
344
 
 
345
    def _creteCaption(self, scatt_id):
 
346
 
 
347
        transpose = self.transpose[scatt_id]
 
348
        bands = self.scatt_mgr.GetBands()
 
349
 
 
350
        #TODO too low level
 
351
        b1_id, b2_id = idScattToidBands(scatt_id, len(bands))
 
352
 
 
353
        x_b =  bands[b1_id].split('@')[0]
 
354
        y_b = bands[b2_id].split('@')[0]
 
355
 
 
356
        if transpose:
 
357
            tmp = x_b
 
358
            x_b = y_b
 
359
            y_b = tmp
 
360
 
 
361
        return "%s x: %s y: %s" % (_("scatter plot"), x_b, y_b)
 
362
 
 
363
    def GetScattMgr(self):
 
364
        return  self.scatt_mgr
 
365
 
 
366
class CategoryListCtrl(wx.ListCtrl,
 
367
                       listmix.ListCtrlAutoWidthMixin):
 
368
                       #listmix.TextEditMixin):
 
369
 
 
370
    def __init__(self, parent, cats_mgr, sel_cats_in_iscatt, id = wx.ID_ANY):
 
371
 
 
372
        wx.ListCtrl.__init__(self, parent, id,
 
373
                             style = wx.LC_REPORT|wx.LC_VIRTUAL|wx.LC_HRULES|
 
374
                                     wx.LC_VRULES|wx.LC_SINGLE_SEL|wx.LC_NO_HEADER)
 
375
        self.columns = ((_('Class name'), 'name'), )
 
376
                        #(_('Color'), 'color'))
 
377
 
 
378
        self.sel_cats_in_iscatt = sel_cats_in_iscatt
 
379
 
 
380
        self.Populate(columns = self.columns)
 
381
        
 
382
        self.cats_mgr = cats_mgr
 
383
        self.SetItemCount(len(self.cats_mgr.GetCategories()))
 
384
 
 
385
        self.rightClickedItemIdx = wx.NOT_FOUND
 
386
        
 
387
        listmix.ListCtrlAutoWidthMixin.__init__(self)
 
388
 
 
389
        #listmix.TextEditMixin.__init__(self)
 
390
      
 
391
        self.Bind(wx.EVT_COMMAND_RIGHT_CLICK, self.OnCategoryRightUp) #wxMSW
 
392
        self.Bind(wx.EVT_RIGHT_UP,            self.OnCategoryRightUp) #wxGTK
 
393
 
 
394
        #self.Bind(wx.EVT_LIST_BEGIN_LABEL_EDIT, self.OnEdit)
 
395
        self.Bind(wx.EVT_LIST_ITEM_SELECTED, self.OnSel)
 
396
             
 
397
        self.cats_mgr.setCategoryAttrs.connect(self.Update)
 
398
        self.cats_mgr.deletedCategory.connect(self.Update)
 
399
        self.cats_mgr.addedCategory.connect(self.Update)
 
400
 
 
401
    def Update(self, **kwargs):
 
402
        self.SetItemCount(len(self.cats_mgr.GetCategories()))
 
403
        if len(self.cats_mgr.GetCategories()):
 
404
            self.RefreshItems(0, len(self.cats_mgr.GetCategories()) - 1)
 
405
 
 
406
    def SetVirtualData(self, row, column, text):
 
407
        attr = self.columns[column][1]
 
408
        if attr == 'name':
 
409
            try:
 
410
                text.encode('ascii')
 
411
            except UnicodeEncodeError:
 
412
                GMessage(parent = self, message = _("Please use only ASCII characters."))
 
413
                return
 
414
 
 
415
        cat_id = self.cats_mgr.GetCategories()[row]
 
416
 
 
417
        self.cats_mgr.setCategoryAttrs.disconnect(self.Update)
 
418
        self.cats_mgr.SetCategoryAttrs(cat_id, {attr : text})
 
419
        self.cats_mgr.setCategoryAttrs.connect(self.Update)
 
420
        
 
421
        self.Select(row)
 
422
        
 
423
    def Populate(self, columns):
 
424
        for i, col in enumerate(columns):
 
425
            self.InsertColumn(i, col[0])#wx.LIST_FORMAT_RIGHT
 
426
 
 
427
        #self.SetColumnWidth(0, 100)
 
428
        #self.SetColumnWidth(1, 100)
 
429
        
 
430
    def AddCategory(self):
 
431
 
 
432
        self.cats_mgr.addedCategory.disconnect(self.Update)
 
433
        cat_id = self.cats_mgr.AddCategory()
 
434
        self.cats_mgr.addedCategory.connect(self.Update)
 
435
 
 
436
        if cat_id < 0:
 
437
            GError(_("Maximum limit of categories number was reached."))
 
438
            return
 
439
        self.SetItemCount(len(self.cats_mgr.GetCategories()))
 
440
                        
 
441
    def DeleteCategory(self):
 
442
        indexList = sorted(self.GetSelectedIndices(), reverse = True)
 
443
        cats = []
 
444
        for i in indexList:
 
445
            # remove temporary raster
 
446
            cat_id = self.cats_mgr.GetCategories()[i]
 
447
            
 
448
            cats.append(cat_id)
 
449
 
 
450
            self.cats_mgr.deletedCategory.disconnect(self.Update)
 
451
            self.cats_mgr.DeleteCategory(cat_id)
 
452
            self.cats_mgr.deletedCategory.connect(self.Update)
 
453
            
 
454
        self.SetItemCount(len(self.cats_mgr.GetCategories()))
 
455
        
 
456
    def OnSel(self, event):
 
457
        if self.sel_cats_in_iscatt:
 
458
            indexList = self.GetSelectedIndices()
 
459
            sel_cats = []
 
460
            cats = self.cats_mgr.GetCategories()
 
461
            for i in indexList:
 
462
                sel_cats.append(cats[i])       
 
463
 
 
464
            if sel_cats:
 
465
                self.cats_mgr.SetSelectedCat(sel_cats[0])
 
466
        event.Skip()
 
467
 
 
468
    def GetSelectedIndices(self, state =  wx.LIST_STATE_SELECTED):
 
469
        indices = []
 
470
        lastFound = -1
 
471
        while True:
 
472
            index = self.GetNextItem(lastFound, wx.LIST_NEXT_ALL, state)
 
473
            if index == -1:
 
474
                break
 
475
            else:
 
476
                lastFound = index
 
477
                indices.append(index)
 
478
        return indices        
 
479
 
 
480
    def DeselectAll(self):
 
481
        """Deselect all items"""
 
482
        indexList = self.GetSelectedIndices()
 
483
        for i in indexList:
 
484
            self.Select(i, on = 0)
 
485
         
 
486
        # no highlight
 
487
        self.OnCategorySelected(None)
 
488
        
 
489
    def OnGetItemText(self, item, col):
 
490
        attr = self.columns[col][1]
 
491
        cat_id = self.cats_mgr.GetCategories()[item]
 
492
 
 
493
        return self.cats_mgr.GetCategoryAttrs(cat_id)[attr]
 
494
 
 
495
    def OnGetItemImage(self, item):
 
496
        return -1
 
497
 
 
498
    def OnGetItemAttr(self, item):
 
499
        cat_id = self.cats_mgr.GetCategories()[item]
 
500
 
 
501
        cattr = self.cats_mgr.GetCategoryAttrs(cat_id)
 
502
        
 
503
        if cattr['show']:
 
504
            c = cattr['color']
 
505
            
 
506
            back_c = wx.Colour(*map(int, c.split(':')))
 
507
            text_c = wx.Colour(*ContrastColor(back_c))
 
508
        else:
 
509
            back_c = wx.SystemSettings.GetColour(wx.SYS_COLOUR_INACTIVECAPTION)
 
510
            text_c = wx.SystemSettings.GetColour(wx.SYS_COLOUR_INACTIVECAPTIONTEXT)
 
511
 
 
512
        # if it is in scope of the method, gui falls, using self solved it 
 
513
        self.l = wx.ListItemAttr(colText=text_c, colBack=back_c)
 
514
        return self.l
 
515
 
 
516
    def OnCategoryRightUp(self, event):
 
517
        """Show context menu on right click"""
 
518
        item, flags = self.HitTest((event.GetX(), event.GetY()))
 
519
        if item != wx.NOT_FOUND and flags & wx.LIST_HITTEST_ONITEM:
 
520
            self.rightClickedItemIdx = item
 
521
 
 
522
        # generate popup-menu
 
523
        cat_idx = self.rightClickedItemIdx
 
524
 
 
525
        cats = self.cats_mgr.GetCategories()
 
526
        cat_id = cats[cat_idx]
 
527
        showed = self.cats_mgr.GetCategoryAttrs(cat_id)['show']
 
528
        
 
529
        menu = wx.Menu()
 
530
 
 
531
        item_id = wx.NewId()
 
532
        menu.Append(item_id, text=_("Rename class"))
 
533
        self.Bind(wx.EVT_MENU, self.OnRename, id=item_id)
 
534
 
 
535
        item_id = wx.NewId()
 
536
        menu.Append(item_id, text=_("Set color"))
 
537
        self.Bind(wx.EVT_MENU, self.OnSetColor, id=item_id)
 
538
 
 
539
        item_id = wx.NewId()
 
540
        menu.Append(item_id, text=_("Change opacity level"))
 
541
        self.Bind(wx.EVT_MENU, self.OnPopupOpacityLevel, id=item_id)
 
542
 
 
543
        if showed:
 
544
            text = _("Hide")
 
545
        else:
 
546
            text = _("Show")
 
547
 
 
548
        item_id = wx.NewId()
 
549
        menu.Append(item_id, text = text)
 
550
        self.Bind(wx.EVT_MENU, lambda event : self._setCatAttrs(cat_id=cat_id,
 
551
                                                                attrs={'show' : not showed}), 
 
552
                                                                id=item_id) 
 
553
        
 
554
        menu.AppendSeparator()
 
555
        
 
556
        item_id = wx.NewId()
 
557
        menu.Append(item_id, text=_("Move to top"))
 
558
        self.Bind(wx.EVT_MENU, self.OnMoveTop, id=item_id)
 
559
        if cat_idx == 0:
 
560
            menu.Enable(item_id, False)
 
561
 
 
562
        item_id = wx.NewId()
 
563
        menu.Append(item_id, text=_("Move to bottom"))
 
564
        self.Bind(wx.EVT_MENU, self.OnMoveBottom, id=item_id)
 
565
        if cat_idx == len(cats) - 1:
 
566
            menu.Enable(item_id, False)
 
567
 
 
568
        menu.AppendSeparator()
 
569
 
 
570
        item_id = wx.NewId()
 
571
        menu.Append(item_id, text=_("Move category up"))
 
572
        self.Bind(wx.EVT_MENU, self.OnMoveUp, id=item_id)
 
573
        if cat_idx == 0:
 
574
            menu.Enable(item_id, False)
 
575
 
 
576
        item_id = wx.NewId()
 
577
        menu.Append(item_id, text=_("Move category down"))
 
578
        self.Bind(wx.EVT_MENU, self.OnMoveDown, id=item_id)
 
579
        if cat_idx == len(cats) - 1:
 
580
            menu.Enable(item_id, False)
 
581
 
 
582
        menu.AppendSeparator()
 
583
 
 
584
        item_id = wx.NewId()
 
585
        menu.Append(item_id, text=_("Export class raster"))
 
586
        self.Bind(wx.EVT_MENU, self.OnExportCatRast, id=item_id)
 
587
 
 
588
        self.PopupMenu(menu)
 
589
        menu.Destroy()
 
590
 
 
591
    def OnExportCatRast(self, event):
 
592
        """Export training areas"""
 
593
        #TODO
 
594
        #   GMessage(parent=self, message=_("No class raster to export."))
 
595
        #    return
 
596
 
 
597
        cat_idx = self.rightClickedItemIdx
 
598
        cat_id = self.cats_mgr.GetCategories()[cat_idx]
 
599
 
 
600
        self.cats_mgr.ExportCatRast(cat_id)
 
601
 
 
602
    def OnMoveUp(self, event):
 
603
        cat_idx = self.rightClickedItemIdx
 
604
        cat_id = self.cats_mgr.GetCategories()[cat_idx]
 
605
        self.cats_mgr.ChangePosition(cat_id, cat_idx - 1)
 
606
        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
 
607
 
 
608
    def OnMoveDown(self, event):
 
609
        cat_idx = self.rightClickedItemIdx
 
610
        cat_id = self.cats_mgr.GetCategories()[cat_idx]
 
611
        self.cats_mgr.ChangePosition(cat_id, cat_idx + 1)
 
612
        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
 
613
 
 
614
    def OnMoveTop(self, event):
 
615
        cat_idx = self.rightClickedItemIdx
 
616
        cat_id = self.cats_mgr.GetCategories()[cat_idx]
 
617
        self.cats_mgr.ChangePosition(cat_id, 0)
 
618
        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
 
619
 
 
620
    def OnMoveBottom(self, event):
 
621
        cat_idx = self.rightClickedItemIdx
 
622
        cats = self.cats_mgr.GetCategories()
 
623
        cat_id = cats[cat_idx]
 
624
        self.cats_mgr.ChangePosition(cat_id, len(cats) - 1)
 
625
        self.RefreshItems(0, len(self.cats_mgr.GetCategories()))
 
626
 
 
627
    def OnSetColor(self, event):
 
628
        """Popup opacity level indicator"""
 
629
        cat_idx = self.rightClickedItemIdx
 
630
        cat_id = self.cats_mgr.GetCategories()[cat_idx]
 
631
 
 
632
        col = self.cats_mgr.GetCategoryAttrs(cat_id)['color']
 
633
        col = map(int, col.split(':'))
 
634
 
 
635
        col_data =  wx.ColourData()
 
636
        col_data.SetColour(wx.Colour(*col))
 
637
 
 
638
        dlg = wx.ColourDialog(self, col_data)
 
639
        dlg.GetColourData().SetChooseFull(True)
 
640
 
 
641
        if dlg.ShowModal() == wx.ID_OK:
 
642
            color = dlg.GetColourData().GetColour().Get()
 
643
            color = ':'.join(map(str, color))
 
644
            self.cats_mgr.SetCategoryAttrs(cat_id, {"color" : color})
 
645
 
 
646
        dlg.Destroy()
 
647
 
 
648
    def OnPopupOpacityLevel(self, event):
 
649
        """Popup opacity level indicator"""
 
650
 
 
651
        cat_id = self.cats_mgr.GetCategories()[self.rightClickedItemIdx]
 
652
        cat_attrs = self.cats_mgr.GetCategoryAttrs(cat_id)
 
653
        value = cat_attrs['opacity'] * 100
 
654
        name = cat_attrs['name']
 
655
 
 
656
        dlg = SetOpacityDialog(self, opacity = value,
 
657
                               title = _("Change opacity of class <%s>" % name))
 
658
 
 
659
        dlg.applyOpacity.connect(lambda value:
 
660
                                 self._setCatAttrs(cat_id=cat_id, attrs={'opacity' : value}))
 
661
        dlg.CentreOnParent()
 
662
 
 
663
        if dlg.ShowModal() == wx.ID_OK:
 
664
            self._setCatAttrs(cat_id=cat_id, attrs={'opacity' : value})
 
665
        
 
666
        dlg.Destroy()
 
667
 
 
668
    def OnRename(self, event):
 
669
        cat_id = self.cats_mgr.GetCategories()[self.rightClickedItemIdx]
 
670
        cat_attrs = self.cats_mgr.GetCategoryAttrs(cat_id)
 
671
 
 
672
        dlg = RenameClassDialog(self, old_name=cat_attrs['name'])
 
673
        dlg.CentreOnParent()
 
674
 
 
675
        while True:
 
676
            if dlg.ShowModal() == wx.ID_OK:
 
677
                name = dlg.GetNewName().strip()
 
678
                if not name:
 
679
                    GMessage(parent=self, message=_("Empty name was inserted."))
 
680
                else:
 
681
                    self.cats_mgr.SetCategoryAttrs(cat_id, {"name" : name})
 
682
                    break
 
683
            else:
 
684
                break
 
685
 
 
686
        dlg.Destroy()
 
687
 
 
688
    def _setCatAttrs(self, cat_id, attrs):
 
689
        self.cats_mgr.setCategoryAttrs.disconnect(self.Update)
 
690
        self.cats_mgr.SetCategoryAttrs(cat_id, attrs)
 
691
        self.cats_mgr.setCategoryAttrs.connect(self.Update)