Exemplo n.º 1
0
class DataCatalogToolbar(BaseToolbar):
    """Main data catalog toolbar
    """
    def __init__(self, parent):
        """Main toolbar constructor
        """

        BaseToolbar.__init__(self, parent)

        self.InitToolbar(self._toolbarData())
        self.filter = TextCtrl(parent=self)
        self.filter.SetSize((120, self.filter.GetBestSize()[1]))
        self.filter.Bind(
            wx.EVT_TEXT,
            lambda event: self.parent.Filter(self.filter.GetValue()))
        self.AddControl(StaticText(self, label=_("Search:")))
        self.AddControl(self.filter)
        help = _(
            "Type to search database by map type or name. "
            "Use prefix 'r:', 'v:' and 'r3:'"
            "to show only raster, vector or 3D raster data, respectively. "
            "Use Python regular expressions to refine your search.")
        self.SetToolShortHelp(self.filter.GetId(), help)
        # realize the toolbar
        self.Realize()

    def _toolbarData(self):
        """Returns toolbar data (name, icon, handler)"""
        # BaseIcons are a set of often used icons. It is possible
        # to reuse icons in ./trunk/gui/icons/grass or add new ones there.
        return self._getToolbarData(
            (("reloadTree", icons["reloadTree"], self.parent.OnReloadTree),
             ("reloadMapset", icons["reloadMapset"],
              self.parent.OnReloadCurrentMapset),
             ("lock", icons['locked'], self.OnSetRestriction, wx.ITEM_CHECK),
             ("addGrassDB", icons['addGrassDB'],
              self.parent.OnAddGrassDB), ("addLocation", icons['addLocation'],
                                          self.parent.OnCreateLocation),
             ("downloadLocation", icons['downloadLocation'],
              self.parent.OnDownloadLocation),
             ("addMapset", icons['addMapset'], self.parent.OnCreateMapset)))

    def OnSetRestriction(self, event):
        if self.GetToolState(self.lock):
            self.SetToolNormalBitmap(self.lock, icons['unlocked'].GetBitmap())
            self.SetToolShortHelp(self.lock, icons['unlocked'].GetLabel())
            self.parent.SetRestriction(restrict=False)
        else:
            self.SetToolNormalBitmap(self.lock, icons['locked'].GetBitmap())
            self.SetToolShortHelp(self.lock, icons['locked'].GetLabel())
            self.parent.SetRestriction(restrict=True)
Exemplo n.º 2
0
class RegionDef(BaseClass, wx.Dialog):
    """Page for setting default region extents and resolution
    """

    def __init__(self, parent, id=wx.ID_ANY, size=(800, 600), title=_(
            "Set default region extent and resolution"), location=None):
        wx.Dialog.__init__(self, parent, id, title, size=size)
        panel = wx.Panel(self, id=wx.ID_ANY)

        self.SetIcon(
            wx.Icon(
                os.path.join(
                    globalvar.ICONDIR,
                    'grass.ico'),
                wx.BITMAP_TYPE_ICO))

        self.parent = parent
        self.location = location

        #
        # default values
        #
        # 2D
        self.north = 1.0
        self.south = 0.0
        self.east = 1.0
        self.west = 0.0
        self.nsres = 1.0
        self.ewres = 1.0
        # 3D
        self.top = 1.0
        self.bottom = 0.0
        #         self.nsres3 = 1.0
        #         self.ewres3 = 1.0
        self.tbres = 1.0

        #
        # inputs
        #
        # 2D
        self.tnorth = self.MakeTextCtrl(
            text=str(
                self.north), size=(
                150, -1), parent=panel)
        self.tsouth = self.MakeTextCtrl(
            str(self.south),
            size=(150, -1),
            parent=panel)
        self.twest = self.MakeTextCtrl(
            str(self.west),
            size=(150, -1),
            parent=panel)
        self.teast = self.MakeTextCtrl(
            str(self.east),
            size=(150, -1),
            parent=panel)
        self.tnsres = self.MakeTextCtrl(
            str(self.nsres),
            size=(150, -1),
            parent=panel)
        self.tewres = self.MakeTextCtrl(
            str(self.ewres),
            size=(150, -1),
            parent=panel)

        #
        # labels
        #
        self.lrows = self.MakeLabel(parent=panel)
        self.lcols = self.MakeLabel(parent=panel)
        self.lcells = self.MakeLabel(parent=panel)

        #
        # buttons
        #
        self.bset = self.MakeButton(
            text=_("&Set region"),
            id=wx.ID_OK, parent=panel)
        self.bcancel = Button(panel, id=wx.ID_CANCEL)
        self.bset.SetDefault()

        #
        # image
        #
        self.img = wx.Image(os.path.join(globalvar.IMGDIR, "qgis_world.png"),
                            wx.BITMAP_TYPE_PNG).ConvertToBitmap()

        #
        # set current working environment to PERMANENT mapset
        # in selected location in order to set default region (WIND)
        #
        envval = {}
        ret = RunCommand('g.gisenv',
                         read=True)
        if ret:
            for line in ret.splitlines():
                key, val = line.split('=')
                envval[key] = val
            self.currlocation = envval['LOCATION_NAME'].strip("';")
            self.currmapset = envval['MAPSET'].strip("';")
            if self.currlocation != self.location or self.currmapset != 'PERMANENT':
                RunCommand('g.gisenv',
                           set='LOCATION_NAME=%s' % self.location)
                RunCommand('g.gisenv',
                           set='MAPSET=PERMANENT')
        else:
            dlg = wx.MessageBox(
                parent=self,
                message=_('Invalid location selected.'),
                caption=_("Error"),
                style=wx.ID_OK | wx.ICON_ERROR)
            return

        #
        # get current region settings
        #
        region = {}
        ret = RunCommand('g.region',
                         read=True,
                         flags='gp3')
        if ret:
            for line in ret.splitlines():
                key, val = line.split('=')
                region[key] = float(val)
        else:
            dlg = wx.MessageBox(
                parent=self,
                message=_("Invalid region"),
                caption=_("Error"),
                style=wx.ID_OK | wx.ICON_ERROR)
            dlg.ShowModal()
            dlg.Destroy()
            return

        #
        # update values
        # 2D
        self.north = float(region['n'])
        self.south = float(region['s'])
        self.east = float(region['e'])
        self.west = float(region['w'])
        self.nsres = float(region['nsres'])
        self.ewres = float(region['ewres'])
        self.rows = int(region['rows'])
        self.cols = int(region['cols'])
        self.cells = int(region['cells'])
        # 3D
        self.top = float(region['t'])
        self.bottom = float(region['b'])
        #         self.nsres3 = float(region['nsres3'])
        #         self.ewres3 = float(region['ewres3'])
        self.tbres = float(region['tbres'])
        self.depth = int(region['depths'])
        self.cells3 = int(region['cells3'])

        #
        # 3D box collapsable
        #
        self.infoCollapseLabelExp = _("Click here to show 3D settings")
        self.infoCollapseLabelCol = _("Click here to hide 3D settings")
        self.settings3D = wx.CollapsiblePane(parent=panel,
                                             label=self.infoCollapseLabelExp,
                                             style=wx.CP_DEFAULT_STYLE |
                                             wx.CP_NO_TLW_RESIZE | wx.EXPAND)
        self.MakeSettings3DPaneContent(self.settings3D.GetPane())
        self.settings3D.Collapse(False)  # FIXME
        self.Bind(
            wx.EVT_COLLAPSIBLEPANE_CHANGED,
            self.OnSettings3DPaneChanged,
            self.settings3D)

        #
        # set current region settings
        #
        self.tnorth.SetValue(str(self.north))
        self.tsouth.SetValue(str(self.south))
        self.twest.SetValue(str(self.west))
        self.teast.SetValue(str(self.east))
        self.tnsres.SetValue(str(self.nsres))
        self.tewres.SetValue(str(self.ewres))
        self.ttop.SetValue(str(self.top))
        self.tbottom.SetValue(str(self.bottom))
        #         self.tnsres3.SetValue(str(self.nsres3))
        #         self.tewres3.SetValue(str(self.ewres3))
        self.ttbres.SetValue(str(self.tbres))
        self.lrows.SetLabel(_("Rows: %d") % self.rows)
        self.lcols.SetLabel(_("Cols: %d") % self.cols)
        self.lcells.SetLabel(_("Cells: %d") % self.cells)

        #
        # bindings
        #
        self.Bind(wx.EVT_BUTTON, self.OnSetButton, self.bset)
        self.Bind(wx.EVT_BUTTON, self.OnCancel, self.bcancel)
        self.tnorth.Bind(wx.EVT_TEXT, self.OnValue)
        self.tsouth.Bind(wx.EVT_TEXT, self.OnValue)
        self.teast.Bind(wx.EVT_TEXT, self.OnValue)
        self.twest.Bind(wx.EVT_TEXT, self.OnValue)
        self.tnsres.Bind(wx.EVT_TEXT, self.OnValue)
        self.tewres.Bind(wx.EVT_TEXT, self.OnValue)
        self.ttop.Bind(wx.EVT_TEXT, self.OnValue)
        self.tbottom.Bind(wx.EVT_TEXT, self.OnValue)
        #         self.tnsres3.Bind(wx.EVT_TEXT,  self.OnValue)
        #         self.tewres3.Bind(wx.EVT_TEXT,  self.OnValue)
        self.ttbres.Bind(wx.EVT_TEXT, self.OnValue)

        self.__DoLayout(panel)
        self.SetMinSize(self.GetBestSize())
        self.minWindowSize = self.GetMinSize()
        wx.CallAfter(self.settings3D.Collapse, True)

    def MakeSettings3DPaneContent(self, pane):
        """Create 3D region settings pane"""
        border = wx.BoxSizer(wx.VERTICAL)
        gridSizer = wx.GridBagSizer(vgap=0, hgap=0)

        # inputs
        self.ttop = TextCtrl(parent=pane, id=wx.ID_ANY, value=str(self.top),
                             size=(150, -1))
        self.tbottom = TextCtrl(
            parent=pane, id=wx.ID_ANY, value=str(
                self.bottom), size=(
                150, -1))
        self.ttbres = TextCtrl(
            parent=pane, id=wx.ID_ANY, value=str(
                self.tbres), size=(
                150, -1))
        #         self.tnsres3 = wx.TextCtrl(parent = pane, id = wx.ID_ANY, value = str(self.nsres3),
        #                                    size = (150, -1))
        #         self.tewres3  =  wx.TextCtrl(parent = pane, id = wx.ID_ANY, value = str(self.ewres3),
        #                                    size = (150, -1))

        # labels
        self.ldepth = StaticText(
            parent=pane,
            label=_("Depth: %d") %
            self.depth)
        self.lcells3 = StaticText(
            parent=pane,
            label=_("3D Cells: %d") %
            self.cells3)

        # top
        gridSizer.Add(StaticText(parent=pane, label=_("Top")),
                      flag=wx.ALIGN_CENTER |
                      wx.LEFT | wx.RIGHT | wx.TOP, border=5,
                      pos=(0, 1))
        gridSizer.Add(self.ttop,
                      flag=wx.ALIGN_CENTER_HORIZONTAL |
                      wx.ALL, border=5, pos=(1, 1))
        # bottom
        gridSizer.Add(StaticText(parent=pane, label=_("Bottom")),
                      flag=wx.ALIGN_CENTER |
                      wx.LEFT | wx.RIGHT | wx.TOP, border=5,
                      pos=(0, 2))
        gridSizer.Add(self.tbottom,
                      flag=wx.ALIGN_CENTER_HORIZONTAL |
                      wx.ALL, border=5, pos=(1, 2))
        # tbres
        gridSizer.Add(
            StaticText(
                parent=pane,
                label=_("T-B resolution")),
            flag=wx.ALIGN_CENTER | wx.LEFT | wx.RIGHT | wx.TOP,
            border=5,
            pos=(
                0,
                3))
        gridSizer.Add(self.ttbres,
                      flag=wx.ALIGN_CENTER_HORIZONTAL |
                      wx.ALL, border=5, pos=(1, 3))

        # res
        #         gridSizer.Add(item = wx.StaticText(parent = pane, label = _("3D N-S resolution")),
        #                       flag = wx.ALIGN_CENTER |
        #                       wx.LEFT | wx.RIGHT | wx.TOP, border = 5,
        #                       pos = (2, 1))
        #         gridSizer.Add(item = self.tnsres3,
        #                       flag = wx.ALIGN_CENTER_HORIZONTAL |
        #                       wx.ALL, border = 5, pos = (3, 1))
        #         gridSizer.Add(item = wx.StaticText(parent = pane, label = _("3D E-W resolution")),
        #                       flag = wx.ALIGN_CENTER |
        #                       wx.LEFT | wx.RIGHT | wx.TOP, border = 5,
        #                       pos = (2, 3))
        #         gridSizer.Add(item = self.tewres3,
        #                       flag = wx.ALIGN_CENTER_HORIZONTAL |
        #                       wx.ALL, border = 5, pos = (3, 3))

        # rows/cols/cells
        gridSizer.Add(self.ldepth,
                      flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
                      wx.ALL, border=5, pos=(2, 1))

        gridSizer.Add(self.lcells3,
                      flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
                      wx.ALL, border=5, pos=(2, 2))

        border.Add(gridSizer, proportion=1,
                   flag=wx.ALL | wx.ALIGN_CENTER | wx.EXPAND, border=5)

        pane.SetSizer(border)
        border.Fit(pane)

    def OnSettings3DPaneChanged(self, event):
        """Collapse 3D settings box"""

        if self.settings3D.IsExpanded():
            self.settings3D.SetLabel(self.infoCollapseLabelCol)
            self.Layout()
            self.SetSize(self.GetBestSize())
            self.SetMinSize(self.GetSize())
        else:
            self.settings3D.SetLabel(self.infoCollapseLabelExp)
            self.Layout()
            self.SetSize(self.minWindowSize)
            self.SetMinSize(self.minWindowSize)

        self.SendSizeEvent()

    def __DoLayout(self, panel):
        """Window layout"""
        frameSizer = wx.BoxSizer(wx.VERTICAL)
        gridSizer = wx.GridBagSizer(vgap=0, hgap=0)
        settings3DSizer = wx.BoxSizer(wx.VERTICAL)
        buttonSizer = wx.BoxSizer(wx.HORIZONTAL)

        # north
        gridSizer.Add(self.MakeLabel(text=_("North"), parent=panel),
                      flag=wx.ALIGN_BOTTOM | wx.ALIGN_CENTER_HORIZONTAL |
                      wx.TOP | wx.LEFT | wx.RIGHT, border=5, pos=(0, 2))
        gridSizer.Add(self.tnorth,
                      flag=wx.ALIGN_CENTER_HORIZONTAL |
                      wx.ALIGN_CENTER_VERTICAL |
                      wx.ALL, border=5, pos=(1, 2))
        # west
        gridSizer.Add(self.MakeLabel(text=_("West"), parent=panel),
                      flag=wx.ALIGN_RIGHT |
                      wx.ALIGN_CENTER_VERTICAL |
                      wx.LEFT | wx.TOP | wx.BOTTOM, border=5, pos=(2, 0))
        gridSizer.Add(self.twest,
                      flag=wx.ALIGN_RIGHT |
                      wx.ALIGN_CENTER_VERTICAL |
                      wx.ALL, border=5, pos=(2, 1))

        gridSizer.Add(
            wx.StaticBitmap(
                panel, wx.ID_ANY, self.img, (-1, -1),
                (self.img.GetWidth(),
                 self.img.GetHeight())),
            flag=wx.ALIGN_CENTER | wx.ALIGN_CENTER_VERTICAL | wx.ALL, border=5,
            pos=(2, 2))

        # east
        gridSizer.Add(self.teast,
                      flag=wx.ALIGN_CENTER_HORIZONTAL |
                      wx.ALIGN_CENTER_VERTICAL |
                      wx.ALL, border=5, pos=(2, 3))
        gridSizer.Add(self.MakeLabel(text=_("East"), parent=panel),
                      flag=wx.ALIGN_LEFT |
                      wx.ALIGN_CENTER_VERTICAL |
                      wx.RIGHT | wx.TOP | wx.BOTTOM, border=5, pos=(2, 4))
        # south
        gridSizer.Add(self.tsouth,
                      flag=wx.ALIGN_CENTER_HORIZONTAL |
                      wx.ALIGN_CENTER_VERTICAL |
                      wx.ALL, border=5, pos=(3, 2))
        gridSizer.Add(self.MakeLabel(text=_("South"), parent=panel),
                      flag=wx.ALIGN_TOP | wx.ALIGN_CENTER_HORIZONTAL |
                      wx.LEFT | wx.RIGHT | wx.BOTTOM, border=5, pos=(4, 2))
        # ns-res
        gridSizer.Add(self.MakeLabel(text=_("N-S resolution"), parent=panel),
                      flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
                      wx.TOP | wx.LEFT | wx.RIGHT, border=5, pos=(5, 1))
        gridSizer.Add(self.tnsres,
                      flag=wx.ALIGN_RIGHT |
                      wx.ALIGN_CENTER_VERTICAL |
                      wx.ALL, border=5, pos=(6, 1))
        # ew-res
        gridSizer.Add(self.MakeLabel(text=_("E-W resolution"), parent=panel),
                      flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
                      wx.TOP | wx.LEFT | wx.RIGHT, border=5, pos=(5, 3))
        gridSizer.Add(self.tewres,
                      flag=wx.ALIGN_RIGHT |
                      wx.ALIGN_CENTER_VERTICAL |
                      wx.ALL, border=5, pos=(6, 3))
        # rows/cols/cells
        gridSizer.Add(self.lrows,
                      flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
                      wx.ALL, border=5, pos=(7, 1))

        gridSizer.Add(self.lcells,
                      flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
                      wx.ALL, border=5, pos=(7, 2))

        gridSizer.Add(self.lcols,
                      flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_CENTER |
                      wx.ALL, border=5, pos=(7, 3))

        # 3D
        settings3DSizer.Add(self.settings3D,
                            flag=wx.ALL,
                            border=5)

        # buttons
        buttonSizer.Add(self.bcancel, proportion=1,
                        flag=wx.ALIGN_RIGHT |
                        wx.ALIGN_CENTER_VERTICAL |
                        wx.ALL, border=10)
        buttonSizer.Add(self.bset, proportion=1,
                        flag=wx.ALIGN_CENTER |
                        wx.ALIGN_CENTER_VERTICAL |
                        wx.ALL, border=10)

        frameSizer.Add(gridSizer, proportion=1,
                       flag=wx.ALL | wx.ALIGN_CENTER, border=5)
        frameSizer.Add(settings3DSizer, proportion=0,
                       flag=wx.ALL | wx.ALIGN_CENTER, border=5)
        frameSizer.Add(buttonSizer, proportion=0,
                       flag=wx.ALL | wx.ALIGN_RIGHT, border=5)

        self.SetAutoLayout(True)
        panel.SetSizer(frameSizer)
        frameSizer.Fit(panel)
        self.Layout()

    def OnValue(self, event):
        """Set given value"""
        try:
            if event.GetId() == self.tnorth.GetId():
                self.north = float(event.GetString())
            elif event.GetId() == self.tsouth.GetId():
                self.south = float(event.GetString())
            elif event.GetId() == self.teast.GetId():
                self.east = float(event.GetString())
            elif event.GetId() == self.twest.GetId():
                self.west = float(event.GetString())
            elif event.GetId() == self.tnsres.GetId():
                self.nsres = float(event.GetString())
            elif event.GetId() == self.tewres.GetId():
                self.ewres = float(event.GetString())
            elif event.GetId() == self.ttop.GetId():
                self.top = float(event.GetString())
            elif event.GetId() == self.tbottom.GetId():
                self.bottom = float(event.GetString())
            #             elif event.GetId() == self.tnsres3.GetId():
            #                 self.nsres3 = float(event.GetString())
            #             elif event.GetId() == self.tewres3.GetId():
            #                 self.ewres3 = float(event.GetString())
            elif event.GetId() == self.ttbres.GetId():
                self.tbres = float(event.GetString())

            self.__UpdateInfo()

        except ValueError as e:
            if len(event.GetString()) > 0 and event.GetString() != '-':
                dlg = wx.MessageBox(parent=self,
                                    message=_("Invalid value: %s") % e,
                                    caption=_("Error"),
                                    style=wx.OK | wx.ICON_ERROR)
                # reset values
                self.tnorth.SetValue(str(self.north))
                self.tsouth.SetValue(str(self.south))
                self.teast.SetValue(str(self.east))
                self.twest.SetValue(str(self.west))
                self.tnsres.SetValue(str(self.nsres))
                self.tewres.SetValue(str(self.ewres))
                self.ttop.SetValue(str(self.top))
                self.tbottom.SetValue(str(self.bottom))
                self.ttbres.SetValue(str(self.tbres))
                # self.tnsres3.SetValue(str(self.nsres3))
                # self.tewres3.SetValue(str(self.ewres3))

        event.Skip()

    def __UpdateInfo(self):
        """Update number of rows/cols/cells"""
        try:
            rows = int((self.north - self.south) / self.nsres)
            cols = int((self.east - self.west) / self.ewres)
        except ZeroDivisionError:
            return
        self.rows = rows
        self.cols = cols
        self.cells = self.rows * self.cols

        try:
            depth = int((self.top - self.bottom) / self.tbres)
        except ZeroDivisionError:
            return
        self.depth = depth
        self.cells3 = self.rows * self.cols * self.depth

        # 2D
        self.lrows.SetLabel(_("Rows: %d") % self.rows)
        self.lcols.SetLabel(_("Cols: %d") % self.cols)
        self.lcells.SetLabel(_("Cells: %d") % self.cells)
        # 3D
        self.ldepth.SetLabel(_("Depth: %d" % self.depth))
        self.lcells3.SetLabel(_("3D Cells: %d" % self.cells3))

    def OnSetButton(self, event=None):
        """Set default region"""
        ret = RunCommand('g.region',
                         flags='sa',
                         n=self.north,
                         s=self.south,
                         e=self.east,
                         w=self.west,
                         nsres=self.nsres,
                         ewres=self.ewres,
                         t=self.top,
                         b=self.bottom,
                         tbres=self.tbres)
        if ret == 0:
            self.Destroy()

    def OnCancel(self, event):
        self.Destroy()
Exemplo n.º 3
0
    def UpdateDialog(self,
                     map=None,
                     query=None,
                     cats=None,
                     fid=-1,
                     action=None):
        """Update dialog

        :param map: name of vector map
        :param query:
        :param cats:
        :param fid: feature id
        :param action: add, update, display or None

        :return: True if updated
        :return: False
        """
        if action:
            self.action = action
            if action == 'display':
                enabled = False
            else:
                enabled = True
            self.closeDialog.Enable(enabled)
            self.FindWindowById(wx.ID_OK).Enable(enabled)

        if map:
            self.map = map
            # get layer/table/column information
            self.mapDBInfo = VectorDBInfo(self.map)

        if not self.mapDBInfo:
            return False

        self.mapDBInfo.Reset()

        layers = self.mapDBInfo.layers.keys()  # get available layers

        # id of selected line
        if query:  # select by position
            data = self.mapDBInfo.SelectByPoint(query[0], query[1])
            self.cats = {}
            if data and 'Layer' in data:
                idx = 0
                for layer in data['Layer']:
                    layer = int(layer)
                    if data['Id'][idx] is not None:
                        tfid = int(data['Id'][idx])
                    else:
                        tfid = 0  # Area / Volume
                    if tfid not in self.cats:
                        self.cats[tfid] = {}
                    if layer not in self.cats[tfid]:
                        self.cats[tfid][layer] = []
                    cat = int(data['Category'][idx])
                    self.cats[tfid][layer].append(cat)
                    idx += 1
        else:
            self.cats = cats

        if fid > 0:
            self.fid = fid
        elif len(self.cats.keys()) > 0:
            self.fid = list(self.cats.keys())[0]
        else:
            self.fid = -1

        if len(self.cats.keys()) == 1:
            self.fidMulti.Show(False)
            self.fidText.Show(True)
            if self.fid > 0:
                self.fidText.SetLabel("%d" % self.fid)
            else:
                self.fidText.SetLabel(_("Unknown"))
        else:
            self.fidMulti.Show(True)
            self.fidText.Show(False)
            choices = []
            for tfid in self.cats.keys():
                choices.append(str(tfid))
            self.fidMulti.SetItems(choices)
            self.fidMulti.SetStringSelection(str(self.fid))

        # reset notebook
        self.notebook.DeleteAllPages()

        for layer in layers:  # for each layer
            if not query:  # select by layer/cat
                if self.fid > 0 and layer in self.cats[self.fid]:
                    for cat in self.cats[self.fid][layer]:
                        nselected = self.mapDBInfo.SelectFromTable(
                            layer,
                            where="%s=%d" %
                            (self.mapDBInfo.layers[layer]['key'], cat))
                else:
                    nselected = 0

            # if nselected <= 0 and self.action != "add":
            #    continue # nothing selected ...

            if self.action == "add":
                if nselected <= 0:
                    if layer in self.cats[self.fid]:
                        table = self.mapDBInfo.layers[layer]["table"]
                        key = self.mapDBInfo.layers[layer]["key"]
                        columns = self.mapDBInfo.tables[table]
                        for name in columns.keys():
                            if name == key:
                                for cat in self.cats[self.fid][layer]:
                                    self.mapDBInfo.tables[table][name][
                                        'values'].append(cat)
                            else:
                                self.mapDBInfo.tables[table][name][
                                    'values'].append(None)
                else:  # change status 'add' -> 'update'
                    self.action = "update"

            table = self.mapDBInfo.layers[layer]["table"]
            key = self.mapDBInfo.layers[layer]["key"]
            columns = self.mapDBInfo.tables[table]

            for idx in range(len(columns[key]['values'])):
                for name in columns.keys():
                    if name == key:
                        cat = int(columns[name]['values'][idx])
                        break

                # use scrolled panel instead (and fix initial max height of the
                # window to 480px)
                panel = scrolled.ScrolledPanel(parent=self.notebook,
                                               id=wx.ID_ANY,
                                               size=(-1, 150))
                panel.SetupScrolling(scroll_x=False)

                self.notebook.AddPage(page=panel,
                                      text=" %s %d / %s %d" %
                                      (_("Layer"), layer, _("Category"), cat))

                # notebook body
                border = wx.BoxSizer(wx.VERTICAL)

                flexSizer = wx.FlexGridSizer(cols=3, hgap=3, vgap=3)
                flexSizer.AddGrowableCol(2)
                # columns (sorted by index)
                names = [''] * len(columns.keys())
                for name in columns.keys():
                    names[columns[name]['index']] = name

                for name in names:
                    if name == key:  # skip key column (category)
                        continue

                    vtype = columns[name]['type'].lower()
                    ctype = columns[name]['ctype']

                    if columns[name]['values'][idx] is not None:
                        if not isinstance(columns[name]['ctype'],
                                          six.string_types):
                            value = str(columns[name]['values'][idx])
                        else:
                            value = columns[name]['values'][idx]
                    else:
                        value = ''

                    colName = StaticText(parent=panel,
                                         id=wx.ID_ANY,
                                         label=name)
                    colType = StaticText(parent=panel,
                                         id=wx.ID_ANY,
                                         label="[%s]:" % vtype)
                    colValue = TextCtrl(parent=panel,
                                        id=wx.ID_ANY,
                                        value=value)
                    colValue.SetName(name)
                    if ctype == int:
                        colValue.SetValidator(IntegerValidator())
                    elif ctype == float:
                        colValue.SetValidator(FloatValidator())

                    self.Bind(wx.EVT_TEXT, self.OnSQLStatement, colValue)
                    if self.action == 'display':
                        colValue.SetWindowStyle(wx.TE_READONLY)

                    flexSizer.Add(colName,
                                  proportion=0,
                                  flag=wx.ALIGN_CENTER_VERTICAL)
                    flexSizer.Add(colType,
                                  proportion=0,
                                  flag=wx.ALIGN_CENTER_VERTICAL
                                  | wx.ALIGN_RIGHT)
                    flexSizer.Add(colValue,
                                  proportion=1,
                                  flag=wx.EXPAND | wx.ALIGN_CENTER_VERTICAL)
                    # add widget reference to self.columns
                    columns[name]['ids'].append(
                        colValue.GetId())  # name, type, values, id
                # for each attribute (including category) END
                border.Add(flexSizer,
                           proportion=1,
                           flag=wx.ALL | wx.EXPAND,
                           border=5)
                panel.SetSizer(border)
            # for each category END
        # for each layer END

        if self.notebook.GetPageCount() == 0:
            self.noFoundMsg.Show(True)
        else:
            self.noFoundMsg.Show(False)

        self.Layout()

        return True