1"""
2@package dbmgr.manager
3
4@brief GRASS Attribute Table Manager
5
6This program is based on FileHunter, published in 'The wxPython Linux
7Tutorial' on wxPython WIKI pages.
8
9It also uses some functions at
10http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/426407
11
12List of classes:
13 - manager::AttributeManager
14
15(C) 2007-2014 by the GRASS Development Team
16
17This program is free software under the GNU General Public License
18(>=v2). Read the file COPYING that comes with GRASS for details.
19
20@author Jachym Cepicky <jachym.cepicky gmail.com>
21@author Martin Landa <landa.martin gmail.com>
22@author Refactoring by Stepan Turek <stepan.turek seznam.cz> (GSoC 2012, mentor: Martin Landa)
23"""
24
25import sys
26import os
27
28import wx
29from core import globalvar
30if globalvar.wxPythonPhoenix:
31    try:
32        import agw.flatnotebook as FN
33    except ImportError: # if it's not there locally, try the wxPython lib.
34        import wx.lib.agw.flatnotebook as FN
35else:
36    import wx.lib.flatnotebook as FN
37
38import grass.script as grass
39
40
41from core.gcmd import GMessage
42from core.debug import Debug
43from dbmgr.base import DbMgrBase
44from gui_core.widgets import GNotebook
45from gui_core.wrap import Button, ClearButton, CloseButton
46
47
48class AttributeManager(wx.Frame, DbMgrBase):
49
50    def __init__(self, parent, id=wx.ID_ANY,
51                 title=None, vectorName=None, item=None, log=None,
52                 selection=None, **kwargs):
53        """GRASS Attribute Table Manager window
54
55        :param parent: parent window
56        :param id: window id
57        :param title: window title or None for default title
58        :param vectorName: name of vector map
59        :param item: item from Layer Tree
60        :param log: log window
61        :param selection: name of page to be selected
62        :param kwagrs: other wx.Frame's arguments
63        """
64        self.parent = parent
65        try:
66            mapdisplay = self.parent.GetMapDisplay()
67        except:
68            mapdisplay = None
69
70        DbMgrBase.__init__(self, id=id, mapdisplay=mapdisplay,
71                           vectorName=vectorName, item=item,
72                           log=log, statusbar=self,
73                           **kwargs)
74
75        wx.Frame.__init__(self, parent, id, *kwargs)
76
77        # title
78        if not title:
79            title = "%s" % _("GRASS GIS Attribute Table Manager - ")
80            if not self.dbMgrData['editable']:
81                title += _("READONLY - ")
82            title += "<%s>" % (self.dbMgrData['vectName'])
83
84        self.SetTitle(title)
85
86        # icon
87        self.SetIcon(
88            wx.Icon(
89                os.path.join(
90                    globalvar.ICONDIR,
91                    'grass_sql.ico'),
92                wx.BITMAP_TYPE_ICO))
93
94        self.panel = wx.Panel(parent=self, id=wx.ID_ANY)
95
96        if len(self.dbMgrData['mapDBInfo'].layers.keys()) == 0:
97            GMessage(
98                parent=self.parent, message=_(
99                    "Database connection for vector map <%s> "
100                    "is not defined in DB file. "
101                    "You can define new connection in "
102                    "'Manage layers' tab.") %
103                self.dbMgrData['vectName'])
104
105        busy = wx.BusyInfo(_("Please wait, loading attribute data..."),
106                           parent=self.parent)
107        wx.SafeYield()
108        self.CreateStatusBar(number=1)
109
110        self.notebook = GNotebook(self.panel, style=globalvar.FNPageDStyle)
111
112        self.CreateDbMgrPage(parent=self, pageName='browse')
113
114        self.notebook.AddPage(page=self.pages['browse'], text=_("Browse data"),
115                              name='browse')
116        self.pages['browse'].SetTabAreaColour(globalvar.FNPageColor)
117
118        self.CreateDbMgrPage(parent=self, pageName='manageTable')
119
120        self.notebook.AddPage(
121            page=self.pages['manageTable'],
122            text=_("Manage tables"),
123            name='table')
124        self.pages['manageTable'].SetTabAreaColour(globalvar.FNPageColor)
125
126        self.CreateDbMgrPage(parent=self, pageName='manageLayer')
127        self.notebook.AddPage(
128            page=self.pages['manageLayer'],
129            text=_("Manage layers"),
130            name='layers')
131        del busy
132
133        if selection:
134            wx.CallAfter(self.notebook.SetSelectionByName, selection)
135        else:
136            wx.CallAfter(self.notebook.SetSelection, 0)  # select browse tab
137
138        # buttons
139        self.btnClose = CloseButton(parent=self.panel)
140        self.btnClose.SetToolTip(_("Close Attribute Table Manager"))
141        self.btnReload = Button(parent=self.panel, id=wx.ID_REFRESH)
142        self.btnReload.SetToolTip(
143            _("Reload currently selected attribute data"))
144        self.btnReset = ClearButton(parent=self.panel)
145        self.btnReset.SetToolTip(
146            _("Reload all attribute data (drop current selection)"))
147
148        # bind closing to ESC
149        self.Bind(wx.EVT_MENU, self.OnCloseWindow, id=wx.ID_CANCEL)
150        accelTableList = [(wx.ACCEL_NORMAL, wx.WXK_ESCAPE, wx.ID_CANCEL)]
151        accelTable = wx.AcceleratorTable(accelTableList)
152        self.SetAcceleratorTable(accelTable)
153
154        # events
155        self.btnClose.Bind(wx.EVT_BUTTON, self.OnCloseWindow)
156        self.btnReload.Bind(wx.EVT_BUTTON, self.OnReloadData)
157        self.btnReset.Bind(wx.EVT_BUTTON, self.OnReloadDataAll)
158        self.notebook.Bind(
159            FN.EVT_FLATNOTEBOOK_PAGE_CHANGED,
160            self.OnPageChanged)
161        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
162
163        # do layout
164        self._layout()
165
166        # self.SetMinSize(self.GetBestSize())
167        self.SetSize((700, 550))  # FIXME hard-coded size
168        self.SetMinSize(self.GetSize())
169
170    def _layout(self):
171        """Do layout"""
172        # frame body
173        mainSizer = wx.BoxSizer(wx.VERTICAL)
174
175        # buttons
176        btnSizer = wx.BoxSizer(wx.HORIZONTAL)
177        btnSizer.Add(self.btnReset, proportion=1,
178                     flag=wx.ALL, border=5)
179        btnSizer.Add(self.btnReload, proportion=1,
180                     flag=wx.ALL, border=5)
181        btnSizer.Add(self.btnClose, proportion=1,
182                     flag=wx.ALL, border=5)
183
184        mainSizer.Add(self.notebook, proportion=1, flag=wx.EXPAND)
185        mainSizer.Add(btnSizer, flag=wx.ALIGN_RIGHT | wx.ALL, border=5)
186
187        self.panel.SetAutoLayout(True)
188        self.panel.SetSizer(mainSizer)
189        mainSizer.Fit(self.panel)
190        self.Layout()
191
192    def OnCloseWindow(self, event):
193        """Cancel button pressed"""
194        if self.parent and self.parent.GetName() == 'LayerManager':
195            # deregister ATM
196            self.parent.dialogs['atm'].remove(self)
197
198        if not isinstance(event, wx.CloseEvent):
199            self.Destroy()
200
201        event.Skip()
202
203    def OnReloadData(self, event):
204        """Reload data"""
205        if self.pages['browse']:
206            self.pages['browse'].OnDataReload(event)  # TODO replace by signal
207
208    def OnReloadDataAll(self, event):
209        """Reload all data"""
210        if self.pages['browse']:
211            self.pages['browse'].ResetPage()
212
213    def OnPageChanged(self, event):
214        """On page in ATM is changed"""
215        try:
216            if self.pages["browse"]:
217                selPage = self.pages["browse"].selLayer
218                id = self.pages["browse"].layerPage[selPage]['data']
219            else:
220                id = None
221        except KeyError:
222            id = None
223
224        if event.GetSelection() == self.notebook.GetPageIndexByName('browse') and id:
225            win = self.FindWindowById(id)
226            if win:
227                self.log.write(
228                    _("Number of loaded records: %d") %
229                    win.GetItemCount())
230            else:
231                self.log.write("")
232            self.btnReload.Enable()
233            self.btnReset.Enable()
234        else:
235            self.log.write("")
236            self.btnReload.Enable(False)
237            self.btnReset.Enable(False)
238
239        event.Skip()
240
241    def OnTextEnter(self, event):
242        pass
243
244    def UpdateDialog(self, layer):
245        """Updates dialog layout for given layer"""
246        DbMgrBase.UpdateDialog(self, layer=layer)
247        # set current page selection
248        self.notebook.SetSelectionByName('layers')
249