Пример #1
0
    def __init__(
        self,
        parent,
        layerList,
        lmgrStyle=SIMPLE_LMGR_RASTER | SIMPLE_LMGR_VECTOR
        | SIMPLE_LMGR_TB_LEFT,
        toolbarCls=None,
        modal=False,
    ):
        wx.Panel.__init__(self, parent=parent, name="SimpleLayerManager")

        self._style = lmgrStyle
        self._layerList = layerList
        self._checkList = CheckListBox(self, style=wx.LB_EXTENDED)
        if not toolbarCls:
            toolbarCls = SimpleLmgrToolbar
        self._toolbar = toolbarCls(self, lmgrStyle=self._style)

        self._auimgr = wx.aui.AuiManager(self)

        self._modal = modal
        # d.* dialogs are recreated each time, attempt to hide it resulted
        # in completely mysterious memory corruption and crash when opening
        # any dialog with stock labels (wx.ID_OK and so on)

        # needed in order not to change selection when moving layers
        self._blockSelectionChanged = False

        self._checkList.Bind(wx.EVT_LISTBOX,
                             lambda evt: self._selectionChanged())
        self._checkList.Bind(wx.EVT_LISTBOX_DCLICK,
                             self.OnLayerChangeProperties)
        self._checkList.Bind(wx.EVT_CHECKLISTBOX, self.OnLayerChecked)
        self._checkList.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)

        # signal emitted when somethin in layer list changes
        self.opacityChanged = Signal("SimpleLayerManager.opacityChanged")
        self.cmdChanged = Signal("SimpleLayerManager.cmdChanged")
        self.layerAdded = Signal("SimpleLayerManager.layerAdded")
        self.layerRemoved = Signal("SimpleLayerManager.layerRemoved")
        self.layerActivated = Signal("SimpleLayerManager.layerActivated")
        self.layerMovedUp = Signal("SimpleLayerManager.layerMovedUp")
        self.layerMovedDown = Signal("SimpleLayerManager.layerMovedDown")
        # emitted by any change (e.g. for rerendering)
        self.anyChange = Signal("SimpleLayerManager.layerChange")

        self._layout()
        self.SetMinSize((200, -1))
        self._update()
Пример #2
0
class SimpleLayerManager(wx.Panel):
    """Simple layer manager class provides similar functionality to
    Layertree, but it's just list, not tree."""
    def __init__(
        self,
        parent,
        layerList,
        lmgrStyle=SIMPLE_LMGR_RASTER | SIMPLE_LMGR_VECTOR
        | SIMPLE_LMGR_TB_LEFT,
        toolbarCls=None,
        modal=False,
    ):
        wx.Panel.__init__(self, parent=parent, name="SimpleLayerManager")

        self._style = lmgrStyle
        self._layerList = layerList
        self._checkList = CheckListBox(self, style=wx.LB_EXTENDED)
        if not toolbarCls:
            toolbarCls = SimpleLmgrToolbar
        self._toolbar = toolbarCls(self, lmgrStyle=self._style)

        self._auimgr = wx.aui.AuiManager(self)

        self._modal = modal
        # d.* dialogs are recreated each time, attempt to hide it resulted
        # in completely mysterious memory corruption and crash when opening
        # any dialog with stock labels (wx.ID_OK and so on)

        # needed in order not to change selection when moving layers
        self._blockSelectionChanged = False

        self._checkList.Bind(wx.EVT_LISTBOX,
                             lambda evt: self._selectionChanged())
        self._checkList.Bind(wx.EVT_LISTBOX_DCLICK,
                             self.OnLayerChangeProperties)
        self._checkList.Bind(wx.EVT_CHECKLISTBOX, self.OnLayerChecked)
        self._checkList.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu)

        # signal emitted when somethin in layer list changes
        self.opacityChanged = Signal("SimpleLayerManager.opacityChanged")
        self.cmdChanged = Signal("SimpleLayerManager.cmdChanged")
        self.layerAdded = Signal("SimpleLayerManager.layerAdded")
        self.layerRemoved = Signal("SimpleLayerManager.layerRemoved")
        self.layerActivated = Signal("SimpleLayerManager.layerActivated")
        self.layerMovedUp = Signal("SimpleLayerManager.layerMovedUp")
        self.layerMovedDown = Signal("SimpleLayerManager.layerMovedDown")
        # emitted by any change (e.g. for rerendering)
        self.anyChange = Signal("SimpleLayerManager.layerChange")

        self._layout()
        self.SetMinSize((200, -1))
        self._update()

    def _layout(self):
        self._auimgr.AddPane(
            self._checkList,
            wx.aui.AuiPaneInfo().Name("checklist").CenterPane().CloseButton(
                False).BestSize((self._checkList.GetBestSize())),
        )
        paneInfo = (wx.aui.AuiPaneInfo().Name("toolbar").Caption(
            _("Toolbar")).ToolbarPane().CloseButton(False).Layer(1).Gripper(
                False).BestSize((self._toolbar.GetBestSize())))
        if self._style & SIMPLE_LMGR_TB_LEFT:
            paneInfo.Left()
        elif self._style & SIMPLE_LMGR_TB_RIGHT:
            paneInfo.Right()
        elif self._style & SIMPLE_LMGR_TB_TOP:
            paneInfo.Top()
        else:
            paneInfo.Bottom()

        self._auimgr.AddPane(self._toolbar, paneInfo)
        self._auimgr.Update()

    def _selectionChanged(self):
        """Selection was changed externally,
        updates selection info in layers."""
        if self._blockSelectionChanged:
            return
        selected = self._checkList.GetSelections()
        for i, layer in enumerate(self._layerList):
            layer.Select(i in selected)

    def UnInit(self):
        """Needs to be called before destroying this window"""
        self._auimgr.UnInit()

    def OnContextMenu(self, event):
        """Show context menu.

        So far offers only copying layer list to clipboard
        """
        if len(self._layerList) < 1:
            event.Skip()
            return

        menu = Menu()
        llist = [layer.name for layer in self._layerList]
        texts = [",".join(llist), ",".join(reversed(llist))]
        labels = [
            _("Copy map names to clipboard (top to bottom)"),
            _("Copy map names to clipboard (bottom to top)"),
        ]
        for label, text in zip(labels, texts):
            id = NewId()
            self.Bind(wx.EVT_MENU,
                      lambda evt, t=text, id=id: self._copyText(t),
                      id=id)

            menu.Append(id, label)

        # show the popup menu
        self.PopupMenu(menu)
        menu.Destroy()
        event.Skip()

    def _copyText(self, text):
        """Helper function for copying

        TODO: move to utils?
        """
        if wx.TheClipboard.Open():
            do = wx.TextDataObject()
            do.SetText(text)
            wx.TheClipboard.SetData(do)
            wx.TheClipboard.Close()

    def OnLayerChecked(self, event):
        """Layer was (un)checked, update layer's info."""
        checkedIdxs = self._checkList.GetCheckedItems()
        for i, layer in enumerate(self._layerList):
            if i in checkedIdxs and not layer.IsActive():
                layer.Activate()
                self.layerActivated.emit(index=i, layer=layer)
            elif i not in checkedIdxs and layer.IsActive():
                layer.Activate(False)
                self.layerActivated.emit(index=i, layer=layer)
        self.anyChange.emit()
        event.Skip()

    def OnAddRaster(self, event):
        """Opens d.rast dialog and adds layer.
        Dummy layer is added first."""
        cmd = ["d.rast"]
        layer = self.AddRaster(name="", cmd=cmd, hidden=True, dialog=None)
        GUI(parent=self, giface=None,
            modal=self._modal).ParseCommand(cmd=cmd,
                                            completed=(self.GetOptData, layer,
                                                       ""))
        event.Skip()

    def OnAddVector(self, event):
        """Opens d.vect dialog and adds layer.
        Dummy layer is added first."""
        cmd = ["d.vect"]

        layer = self.AddVector(name="", cmd=cmd, hidden=True, dialog=None)
        GUI(parent=self, giface=None,
            modal=self._modal).ParseCommand(cmd=cmd,
                                            completed=(self.GetOptData, layer,
                                                       ""))
        event.Skip()

    def OnAddRast3d(self, event):
        """Opens d.rast3d dialog and adds layer.
        Dummy layer is added first."""
        cmd = ["d.rast3d"]
        layer = self.AddRast3d(name="", cmd=cmd, hidden=True, dialog=None)
        GUI(parent=self, giface=None,
            modal=self._modal).ParseCommand(cmd=cmd,
                                            completed=(self.GetOptData, layer,
                                                       ""))
        event.Skip()

    def OnAddRGB(self, event):
        """Opens d.rgb dialog and adds layer.
        Dummy layer is added first."""
        cmd = ["d.rgb"]
        layer = self.AddRGB(name="", cmd=cmd, hidden=True, dialog=None)
        GUI(parent=self, giface=None,
            modal=self._modal).ParseCommand(cmd=cmd,
                                            completed=(self.GetOptData, layer,
                                                       ""))
        event.Skip()

    def OnRemove(self, event):
        """Removes selected layers from list."""
        layers = self._layerList.GetSelectedLayers(activeOnly=False)
        for layer in layers:
            self.layerRemoved.emit(index=self._layerList.GetLayerIndex(layer),
                                   layer=layer)
            self._layerList.RemoveLayer(layer)
        self._update()
        self.anyChange.emit()
        event.Skip()

    def OnLayerUp(self, event):
        """Moves selected layers one step up.

        Note: not completely correct for multiple layers."""
        layers = self._layerList.GetSelectedLayers()
        self._blockSelectionChanged = True
        for layer in layers:
            idx = self._layerList.GetLayerIndex(layer)
            if idx > 0:
                self.layerMovedUp.emit(index=idx, layer=layer)
                self._layerList.MoveLayerUp(layer)
        self._update()
        self._blockSelectionChanged = False
        self.anyChange.emit()
        event.Skip()

    def OnLayerDown(self, event):
        """Moves selected layers one step down.

        Note: not completely correct for multiple layers."""
        layers = self._layerList.GetSelectedLayers()
        self._blockSelectionChanged = True
        for layer in layers:
            idx = self._layerList.GetLayerIndex(layer)
            if idx < len(self._layerList) - 1:
                self.layerMovedDown.emit(
                    index=self._layerList.GetLayerIndex(layer), layer=layer)
                self._layerList.MoveLayerDown(layer)
        self._update()
        self._blockSelectionChanged = False
        self.anyChange.emit()
        event.Skip()

    def OnLayerChangeProperties(self, event):
        """Opens module dialog to edit layer command."""
        layers = self._layerList.GetSelectedLayers()
        if not layers or len(layers) > 1:
            return
        self._layerChangeProperties(layers[0])
        event.Skip()

    def _layerChangeProperties(self, layer):
        """Opens new module dialog or recycles it."""
        GUI(parent=self, giface=None,
            modal=self._modal).ParseCommand(cmd=layer.cmd,
                                            completed=(self.GetOptData, layer,
                                                       ""))

    def OnLayerChangeOpacity(self, event):
        """Opacity of a layer is changing."""
        layers = self._layerList.GetSelectedLayers()
        if not layers or len(layers) > 1:
            return
        layer = layers[0]
        dlg = SetOpacityDialog(self,
                               opacity=layer.opacity,
                               title=_("Set opacity of <%s>") % layer.name)
        dlg.applyOpacity.connect(
            lambda value: self._setLayerOpacity(layer, value))
        dlg.CentreOnParent()

        if dlg.ShowModal() == wx.ID_OK:
            self._setLayerOpacity(layer, dlg.GetOpacity())
        dlg.Destroy()
        event.Skip()

    def _setLayerOpacity(self, layer, value):
        """Sets layer's opacity.'"""
        layer.opacity = value
        self._update()
        self.opacityChanged.emit(index=self._layerList.GetLayerIndex(layer),
                                 layer=layer)
        self.anyChange.emit()

    def _update(self):
        """Updates checklistbox according to layerList structure."""
        items = []
        active = []
        selected = []

        # remove hidden (temporary) layers first
        for layer in reversed(self._layerList):
            if layer.hidden:
                self._layerList.RemoveLayer(layer)

        for layer in self._layerList:
            if layer.opacity < 1:
                items.append("{name} (opacity {opacity}%)".format(
                    name=layer.name, opacity=int(layer.opacity * 100)))
            else:
                items.append(layer.name)
            active.append(layer.IsActive())
            selected.append(layer.IsSelected())

        self._checkList.SetItems(items)
        for i, check in enumerate(active):
            self._checkList.Check(i, check)

        for i, layer in enumerate(self._layerList):
            if selected[i]:
                self._checkList.Select(i)
            else:
                self._checkList.Deselect(i)

    def GetOptData(self, dcmd, layer, params, propwin):
        """Handler for module dialogs."""
        if dcmd:
            layer.cmd = dcmd
            layer.selected = True
            mapName, found = GetLayerNameFromCmd(dcmd)
            if found:
                try:
                    if layer.hidden:
                        layer.hidden = False
                        signal = self.layerAdded
                    else:
                        signal = self.cmdChanged

                    layer.name = mapName
                    signal.emit(index=self._layerList.GetLayerIndex(layer),
                                layer=layer)
                except ValueError as e:
                    self._layerList.RemoveLayer(layer)
                    GError(parent=self, message=str(e), showTraceback=False)

            self._update()
            self.anyChange.emit()

    def AddRaster(self, name, cmd, hidden, dialog):
        """Ads new raster layer."""
        layer = self._layerList.AddNewLayer(name=name,
                                            mapType="raster",
                                            active=True,
                                            cmd=cmd,
                                            hidden=hidden)
        return layer

    def AddRast3d(self, name, cmd, hidden, dialog):
        """Ads new raster3d layer."""
        layer = self._layerList.AddNewLayer(name=name,
                                            mapType="raster_3d",
                                            active=True,
                                            cmd=cmd,
                                            hidden=hidden)
        return layer

    def AddVector(self, name, cmd, hidden, dialog):
        """Ads new vector layer."""
        layer = self._layerList.AddNewLayer(name=name,
                                            mapType="vector",
                                            active=True,
                                            cmd=cmd,
                                            hidden=hidden)
        return layer

    def AddRGB(self, name, cmd, hidden, dialog):
        """Ads new vector layer."""
        layer = self._layerList.AddNewLayer(name=name,
                                            mapType="rgb",
                                            active=True,
                                            cmd=cmd,
                                            hidden=hidden)
        return layer

    def GetLayerInfo(self, layer, key):
        """Just for compatibility, should be removed in the future"""
        value = getattr(layer, key)
        # hack to return empty list, required in OnCancel in forms
        # not sure why it should be empty
        if key == "cmd" and len(value) == 1:
            return []
        return value

    def Delete(self, layer):
        """Just for compatibility, should be removed in the future"""
        self._layerList.RemoveLayer(layer)