瀏覽代碼

wxGUI: update data catalog - allow editing outside of current mapset

git-svn-id: https://svn.osgeo.org/grass/grass/trunk@68256 15284696-431f-4ddb-bdfa-cd5b030d7da7
Anna Petrášová 9 年之前
父節點
當前提交
89114e711e

二進制
gui/icons/grass/locked.png


二進制
gui/icons/grass/unlocked.png


+ 4 - 0
gui/wxpython/datacatalog/catalog.py

@@ -84,3 +84,7 @@ class DataCatalog(wx.Panel):
     def OnReloadCurrentMapset(self, event):
     def OnReloadCurrentMapset(self, event):
         """Reload current mapset tree only"""
         """Reload current mapset tree only"""
         self.tree.ReloadCurrentMapset()
         self.tree.ReloadCurrentMapset()
+
+    def SetRestriction(self, restrict):
+        """Allow editing other mapsets or restrict editing to current mapset"""
+        self.tree.SetRestriction(restrict)

+ 7 - 2
gui/wxpython/datacatalog/frame.py

@@ -26,6 +26,7 @@ from core.globalvar import ICONDIR
 from datacatalog.tree import DataCatalogTree
 from datacatalog.tree import DataCatalogTree
 from datacatalog.toolbars import DataCatalogToolbar
 from datacatalog.toolbars import DataCatalogToolbar
 
 
+
 class DataCatalogFrame(wx.Frame):
 class DataCatalogFrame(wx.Frame):
     """Frame for testing purposes only."""
     """Frame for testing purposes only."""
     def __init__(self, parent, giface=None):
     def __init__(self, parent, giface=None):
@@ -37,7 +38,7 @@ class DataCatalogFrame(wx.Frame):
         self._giface = giface
         self._giface = giface
         self.panel = wx.Panel(self)
         self.panel = wx.Panel(self)
 
 
-        self.toolbar = DataCatalogToolbar(parent = self)
+        self.toolbar = DataCatalogToolbar(parent=self)
         # workaround for http://trac.wxwidgets.org/ticket/13888
         # workaround for http://trac.wxwidgets.org/ticket/13888
         if sys.platform != 'darwin':
         if sys.platform != 'darwin':
             self.SetToolBar(self.toolbar)
             self.SetToolBar(self.toolbar)
@@ -46,7 +47,7 @@ class DataCatalogFrame(wx.Frame):
         self.tree = DataCatalogTree(parent=self.panel, giface=self._giface)
         self.tree = DataCatalogTree(parent=self.panel, giface=self._giface)
         self.tree.InitTreeItems()
         self.tree.InitTreeItems()
         self.tree.ExpandCurrentMapset()
         self.tree.ExpandCurrentMapset()
-        
+
         # buttons
         # buttons
         self.btnClose = wx.Button(parent=self.panel, id=wx.ID_CLOSE)
         self.btnClose = wx.Button(parent=self.panel, id=wx.ID_CLOSE)
         self.btnClose.SetToolTipString(_("Close GRASS GIS Data Catalog"))
         self.btnClose.SetToolTipString(_("Close GRASS GIS Data Catalog"))
@@ -90,3 +91,7 @@ class DataCatalogFrame(wx.Frame):
     def OnReloadCurrentMapset(self, event):
     def OnReloadCurrentMapset(self, event):
         """Reload current mapset tree only"""
         """Reload current mapset tree only"""
         self.tree.ReloadCurrentMapset()
         self.tree.ReloadCurrentMapset()
+
+    def SetRestriction(self, restrict):
+        """Allow editing other mapsets or restrict editing to current mapset"""
+        self.tree.SetRestriction(restrict)

+ 18 - 3
gui/wxpython/datacatalog/toolbars.py

@@ -15,15 +15,18 @@ This program is free software under the GNU General Public License
 """
 """
 
 
 import wx
 import wx
-from gui_core.toolbars import BaseToolbar, BaseIcons
+from gui_core.toolbars import BaseToolbar
 from icons.icon import MetaIcon
 from icons.icon import MetaIcon
 from core.utils import _
 from core.utils import _
 
 
 icons = {
 icons = {
     'reloadTree': MetaIcon(img='redraw', label=_("Reload GRASS locations")),
     'reloadTree': MetaIcon(img='redraw', label=_("Reload GRASS locations")),
-    'reloadMapset': MetaIcon(img='reload', label=_("Reload current GRASS mapset only"))
+    'reloadMapset': MetaIcon(img='reload', label=_("Reload current GRASS mapset only")),
+    'unlocked': MetaIcon(img='unlocked', label=_("Click to restrict editing to current mapset only")),
+    'locked': MetaIcon(img='locked', label=_("Click to allow editing other mapsets")),
     }
     }
 
 
+
 class DataCatalogToolbar(BaseToolbar):
 class DataCatalogToolbar(BaseToolbar):
     """Main data catalog toolbar
     """Main data catalog toolbar
     """
     """
@@ -44,5 +47,17 @@ class DataCatalogToolbar(BaseToolbar):
         return self._getToolbarData((("reloadTree", icons["reloadTree"],
         return self._getToolbarData((("reloadTree", icons["reloadTree"],
                                       self.parent.OnReloadTree),
                                       self.parent.OnReloadTree),
                                      ("reloadMapset", icons["reloadMapset"],
                                      ("reloadMapset", icons["reloadMapset"],
-                                      self.parent.OnReloadCurrentMapset)
+                                      self.parent.OnReloadCurrentMapset),
+                                     ("lock", icons['locked'],
+                                      self.OnSetRestriction, wx.ITEM_CHECK)
                                      ))
                                      ))
+
+    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)

+ 251 - 153
gui/wxpython/datacatalog/tree.py

@@ -32,6 +32,7 @@ from gui_core.treeview import TreeView
 from grass.pydispatch.signal import Signal
 from grass.pydispatch.signal import Signal
 
 
 import grass.script as gscript
 import grass.script as gscript
+from grass.script import gisenv
 from grass.exceptions import CalledModuleError
 from grass.exceptions import CalledModuleError
 
 
 
 
@@ -50,7 +51,7 @@ def getEnvironment(gisdbase, location, mapset):
     return tmp_gisrc_file, env
     return tmp_gisrc_file, env
 
 
 
 
-def getLocationTree(gisdbase, location, queue, mapsets=[]):
+def getLocationTree(gisdbase, location, queue, mapsets=None):
     """Creates dictionary with mapsets, elements, layers for given location.
     """Creates dictionary with mapsets, elements, layers for given location.
     Returns tuple with the dictionary and error (or None)"""
     Returns tuple with the dictionary and error (or None)"""
     tmp_gisrc_file, env = getEnvironment(gisdbase, location, 'PERMANENT')
     tmp_gisrc_file, env = getEnvironment(gisdbase, location, 'PERMANENT')
@@ -92,6 +93,64 @@ def getLocationTree(gisdbase, location, queue, mapsets=[]):
     gscript.try_remove(tmp_gisrc_file)
     gscript.try_remove(tmp_gisrc_file)
 
 
 
 
+def map_exists(name, element, env, mapset=None):
+    """Check is map is present in the mapset given in the environment
+
+    :param name: name of the map
+    :param element: data type ('raster', 'raster_3d', and 'vector')
+    :param env environment created by function getEnvironment
+    """
+    if not mapset:
+        mapset = gscript.run_command('g.mapset', flags='p', env=env).strip()
+    # change type to element used by find file
+    if element == 'raster':
+        element = 'cell'
+    elif element == 'raster_3d':
+        element = 'grid3'
+    # g.findfile returns non-zero when file was not found
+    # se we ignore return code and just focus on stdout
+    process = gscript.start_command('g.findfile', flags='n',
+                                    element=element, file=name, mapset=mapset,
+                                    stdout=gscript.PIPE, stderr=gscript.PIPE, env=env)
+    output, errors = process.communicate()
+    info = gscript.parse_key_val(output, sep='=')
+    # file is the key questioned in grass.script.core find_file()
+    # return code should be equivalent to checking the output
+    if info['file']:
+        return True
+    else:
+        return False
+
+
+class NameEntryDialog(TextEntryDialog):
+    def __init__(self, element, mapset, env, **kwargs):
+        TextEntryDialog.__init__(self, **kwargs)
+        self._element = element
+        self._mapset = mapset
+        self._env = env
+        id_OK = self.GetAffirmativeId()
+        self.Bind(wx.EVT_BUTTON, self.OnOK, self.FindWindowById(id_OK))
+
+    def OnOK(self, event):
+        new = self.GetValue()
+        if not new:
+            return
+        if map_exists(new, self._element, self._env, self._mapset):
+            dlg = wx.MessageDialog(self, message=_("Map of type {elem} <{name}> already exists in mapset <{mapset}>. "
+                                                   "Do you want to overwrite it?").format(elem=self._element,
+                                   name=new, mapset=self._mapset),
+                                   caption=_("Overwrite?"), style=wx.YES_NO)
+            if dlg.ShowModal() == wx.ID_YES:
+                dlg.Destroy()
+                self._env['GRASS_OVERWRITE'] = '1'
+                self.EndModal(wx.ID_OK)
+            else:
+                dlg.Destroy()
+                return
+        else:
+            self.EndModal(wx.ID_OK)
+
+
 class DataCatalogNode(DictNode):
 class DataCatalogNode(DictNode):
     """Node representing item in datacatalog."""
     """Node representing item in datacatalog."""
     def __init__(self, label, data=None):
     def __init__(self, label, data=None):
@@ -122,15 +181,16 @@ class LocationMapTree(TreeView):
         self.parent = parent
         self.parent = parent
         self.contextMenu.connect(self.OnRightClick)
         self.contextMenu.connect(self.OnRightClick)
         self.itemActivated.connect(self.OnDoubleClick)
         self.itemActivated.connect(self.OnDoubleClick)
-        
+
         self._initVariables()
         self._initVariables()
 
 
     def _initTreeItems(self, locations=None, mapsets=None):
     def _initTreeItems(self, locations=None, mapsets=None):
         """Add locations, mapsets and layers to the tree.
         """Add locations, mapsets and layers to the tree.
         Runs in multiple processes. Saves resulting data and error."""
         Runs in multiple processes. Saves resulting data and error."""
         # mapsets param currently unused
         # mapsets param currently unused
+        genv = gisenv()
         if not locations:
         if not locations:
-            locations = GetListOfLocations(self.gisdbase)
+            locations = GetListOfLocations(genv['GISDBASE'])
 
 
         loc_count = proc_count = 0
         loc_count = proc_count = 0
         queue_list = []
         queue_list = []
@@ -141,13 +201,13 @@ class LocationMapTree(TreeView):
             nprocs = cpu_count()
             nprocs = cpu_count()
         except NotImplementedError:
         except NotImplementedError:
                 nprocs = 4
                 nprocs = 4
-                
+
         results = dict()
         results = dict()
         errors = []
         errors = []
         location_nodes = []
         location_nodes = []
         nlocations = len(locations)
         nlocations = len(locations)
         grassdata_node = self._model.AppendNode(parent=self._model.root,
         grassdata_node = self._model.AppendNode(parent=self._model.root,
-                                                label=_('GRASS locations ({})').format(self.gisdbase),
+                                                label=_('GRASS locations in {}').format(genv['GISDBASE']),
                                                 data=dict(type='grassdata'))
                                                 data=dict(type='grassdata'))
         for location in locations:
         for location in locations:
             results[location] = dict()
             results[location] = dict()
@@ -160,7 +220,7 @@ class LocationMapTree(TreeView):
 
 
             q = Queue()
             q = Queue()
             p = Process(target=getLocationTree,
             p = Process(target=getLocationTree,
-                        args=(self.gisdbase, location, q))
+                        args=(genv['GISDBASE'], location, q))
             p.start()
             p.start()
 
 
             queue_list.append(q)
             queue_list.append(q)
@@ -212,6 +272,7 @@ class LocationMapTree(TreeView):
                 child = None
                 child = None
             return child
             return child
 
 
+        genv = gisenv()
         locationItem, mapsetItem = self.GetCurrentLocationMapsetNode()
         locationItem, mapsetItem = self.GetCurrentLocationMapsetNode()
         if not locationItem or not mapsetItem:
         if not locationItem or not mapsetItem:
             return
             return
@@ -224,11 +285,11 @@ class LocationMapTree(TreeView):
 
 
         q = Queue()
         q = Queue()
         p = Process(target=getLocationTree,
         p = Process(target=getLocationTree,
-                    args=(self.gisdbase, locationItem.data['name'], q, mapsetItem.data['name']))
+                    args=(genv['GISDBASE'], locationItem.data['name'], q, mapsetItem.data['name']))
         p.start()
         p.start()
         maps, error = q.get()
         maps, error = q.get()
         if error:
         if error:
-            raise CalledModuleError(e)
+            raise CalledModuleError(error)
 
 
         self._populateMapsetItem(mapsetItem, maps[mapsetItem.data['name']])
         self._populateMapsetItem(mapsetItem, maps[mapsetItem.data['name']])
         self.RefreshNode(mapsetItem)
         self.RefreshNode(mapsetItem)
@@ -251,6 +312,10 @@ class LocationMapTree(TreeView):
         """Create popup menu for mapsets"""
         """Create popup menu for mapsets"""
         raise NotImplementedError()
         raise NotImplementedError()
 
 
+    def _popupMenuElement(self):
+        """Create popup menu for elements"""
+        raise NotImplementedError()
+
     def _initVariables(self):
     def _initVariables(self):
         """Init variables."""
         """Init variables."""
         self.selected_layer = None
         self.selected_layer = None
@@ -258,11 +323,6 @@ class LocationMapTree(TreeView):
         self.selected_mapset = None
         self.selected_mapset = None
         self.selected_location = None
         self.selected_location = None
 
 
-        gisenv = gscript.gisenv()
-        self.gisdbase = gisenv['GISDBASE']
-        self.glocation = gisenv['LOCATION_NAME']
-        self.gmapset = gisenv['MAPSET']
-
     def GetControl(self):
     def GetControl(self):
         """Returns control itself."""
         """Returns control itself."""
         return self
         return self
@@ -279,7 +339,7 @@ class LocationMapTree(TreeView):
             self.selected_layer = item
             self.selected_layer = item
             type = 'element'
             type = 'element'
             item = item.parent
             item = item.parent
-            
+
         if type == 'element':
         if type == 'element':
             self.selected_type = item
             self.selected_type = item
             type = 'mapset'
             type = 'mapset'
@@ -289,20 +349,22 @@ class LocationMapTree(TreeView):
             self.selected_mapset = item
             self.selected_mapset = item
             type = 'location'
             type = 'location'
             item = item.parent
             item = item.parent
-            
+
         if type == 'location':
         if type == 'location':
             self.selected_location = item
             self.selected_location = item
-        
+
     def OnSelChanged(self, event):
     def OnSelChanged(self, event):
         self.selected_layer = None
         self.selected_layer = None
-                
+
     def OnRightClick(self, node):
     def OnRightClick(self, node):
         """Display popup menu."""
         """Display popup menu."""
         self.DefineItems(node)
         self.DefineItems(node)
         if self.selected_layer:
         if self.selected_layer:
-            self._popupMenuLayer(self.selected_mapset.label == self.gmapset)
+            self._popupMenuLayer()
         elif self.selected_mapset and not self.selected_type:
         elif self.selected_mapset and not self.selected_type:
             self._popupMenuMapset()
             self._popupMenuMapset()
+        elif self.selected_type:
+            self._popupMenuElement()
 
 
     def OnDoubleClick(self, node):
     def OnDoubleClick(self, node):
         """Expand/Collapse node."""
         """Expand/Collapse node."""
@@ -310,7 +372,7 @@ class LocationMapTree(TreeView):
             self.CollapseNode(node, recursive=False)
             self.CollapseNode(node, recursive=False)
         else:
         else:
             self.ExpandNode(node, recursive=False)
             self.ExpandNode(node, recursive=False)
-        
+
     def ExpandCurrentLocation(self):
     def ExpandCurrentLocation(self):
         """Expand current location"""
         """Expand current location"""
         location = gscript.gisenv()['LOCATION_NAME']
         location = gscript.gisenv()['LOCATION_NAME']
@@ -323,9 +385,9 @@ class LocationMapTree(TreeView):
 
 
     def GetCurrentLocationMapsetNode(self):
     def GetCurrentLocationMapsetNode(self):
         """Get current mapset node"""
         """Get current mapset node"""
-        gisenv = gscript.gisenv()
-        location = gisenv['LOCATION_NAME']
-        mapset = gisenv['MAPSET']
+        genv = gisenv()
+        location = genv['LOCATION_NAME']
+        mapset = genv['MAPSET']
         locationItem = self._model.SearchNodes(name=location, type='location')
         locationItem = self._model.SearchNodes(name=location, type='location')
         if not locationItem:
         if not locationItem:
             return None, None
             return None, None
@@ -335,7 +397,7 @@ class LocationMapTree(TreeView):
             return locationItem[0], None
             return locationItem[0], None
 
 
         return locationItem[0], mapsetItem[0]
         return locationItem[0], mapsetItem[0]
-            
+
     def ExpandCurrentMapset(self):
     def ExpandCurrentMapset(self):
         """Expand current mapset"""
         """Expand current mapset"""
         locationItem, mapsetItem = self.GetCurrentLocationMapsetNode()
         locationItem, mapsetItem = self.GetCurrentLocationMapsetNode()
@@ -343,11 +405,13 @@ class LocationMapTree(TreeView):
             self.Select(mapsetItem, select=True)
             self.Select(mapsetItem, select=True)
             self.ExpandNode(mapsetItem, recursive=True)
             self.ExpandNode(mapsetItem, recursive=True)
 
 
+
 class DataCatalogTree(LocationMapTree):
 class DataCatalogTree(LocationMapTree):
     def __init__(self, parent, giface=None):
     def __init__(self, parent, giface=None):
         """Data Catalog Tree constructor."""
         """Data Catalog Tree constructor."""
         super(DataCatalogTree, self).__init__(parent)
         super(DataCatalogTree, self).__init__(parent)
         self._giface = giface
         self._giface = giface
+        self._restricted = True
 
 
         self._initVariablesCatalog()
         self._initVariablesCatalog()
         self.beginDrag = Signal('DataCatalogTree.beginDrag')
         self.beginDrag = Signal('DataCatalogTree.beginDrag')
@@ -356,18 +420,18 @@ class DataCatalogTree(LocationMapTree):
         self.endEdit = Signal('DataCatalogTree.endEdit')
         self.endEdit = Signal('DataCatalogTree.endEdit')
 
 
         self.Bind(wx.EVT_TREE_BEGIN_DRAG, lambda evt:
         self.Bind(wx.EVT_TREE_BEGIN_DRAG, lambda evt:
-            self._emitSignal(evt.GetItem(), self.beginDrag, event=evt))
+                  self._emitSignal(evt.GetItem(), self.beginDrag, event=evt))
         self.Bind(wx.EVT_TREE_END_DRAG, lambda evt:
         self.Bind(wx.EVT_TREE_END_DRAG, lambda evt:
-            self._emitSignal(evt.GetItem(), self.endDrag, event=evt))
+                  self._emitSignal(evt.GetItem(), self.endDrag, event=evt))
         self.beginDrag.connect(self.OnBeginDrag)
         self.beginDrag.connect(self.OnBeginDrag)
         self.endDrag.connect(self.OnEndDrag)
         self.endDrag.connect(self.OnEndDrag)
 
 
         self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, lambda evt:
         self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, lambda evt:
-            self._emitSignal(evt.GetItem(), self.startEdit, event=evt))
+                  self._emitSignal(evt.GetItem(), self.startEdit, event=evt))
         self.Bind(wx.EVT_TREE_END_LABEL_EDIT, lambda evt:
         self.Bind(wx.EVT_TREE_END_LABEL_EDIT, lambda evt:
-            self._emitSignal(evt.GetItem(), self.endEdit, event=evt))
-        ###self.startEdit.connect(self.OnStartEditLabel)
-        ###self.endEdit.connect(self.OnEditLabel)
+                  self._emitSignal(evt.GetItem(), self.endEdit, event=evt))
+        self.startEdit.connect(self.OnStartEditLabel)
+        self.endEdit.connect(self.OnEditLabel)
 
 
     def _initVariablesCatalog(self):
     def _initVariablesCatalog(self):
         """Init variables."""
         """Init variables."""
@@ -376,17 +440,20 @@ class DataCatalogTree(LocationMapTree):
         self.copy_mapset = None
         self.copy_mapset = None
         self.copy_location = None
         self.copy_location = None
 
 
+    def SetRestriction(self, restrict):
+        self._restricted = restrict
+
     def _runCommand(self, prog, **kwargs):
     def _runCommand(self, prog, **kwargs):
         cmdString = ' '.join(gscript.make_command(prog, **kwargs))
         cmdString = ' '.join(gscript.make_command(prog, **kwargs))
         ret = RunCommand(prog, parent=self, **kwargs)
         ret = RunCommand(prog, parent=self, **kwargs)
 
 
         return ret, cmdString
         return ret, cmdString
-                
+
     def InitTreeItems(self):
     def InitTreeItems(self):
         """Add locations, mapsets and layers to the tree."""
         """Add locations, mapsets and layers to the tree."""
         self._initTreeItems()
         self._initTreeItems()
-        
-    def OnCopy(self, event):
+
+    def OnCopyMap(self, event):
         """Copy layer or mapset (just save it temporarily, copying is done by paste)"""
         """Copy layer or mapset (just save it temporarily, copying is done by paste)"""
         self.copy_layer = self.selected_layer
         self.copy_layer = self.selected_layer
         self.copy_type = self.selected_type
         self.copy_type = self.selected_type
@@ -394,15 +461,17 @@ class DataCatalogTree(LocationMapTree):
         self.copy_location = self.selected_location
         self.copy_location = self.selected_location
         label = _("Map <{layer}> marked for copying. "
         label = _("Map <{layer}> marked for copying. "
                   "You can paste it to the current mapset "
                   "You can paste it to the current mapset "
-                  "<{mapset}>.".format(layer=self.copy_layer.label, mapset=self.gmapset))
+                  "<{mapset}>.".format(layer=self.copy_layer.label, mapset=gisenv()['MAPSET']))
         self.showNotification.emit(message=label)
         self.showNotification.emit(message=label)
 
 
-    def OnRename(self, event):
-        """Rename levent with dialog"""
-        if self.selected_layer:
-            self.old_name = self.selected_layer.label
-            self.new_name = self._getUserEntry(_('New name'), _('Rename map'), self.old_name)
-            self.Rename()
+    def OnRenameMap(self, event):
+        """Rename layer with dialog"""
+        old_name = self.selected_layer.label
+        gisrc, env = getEnvironment(gisenv()['GISDBASE'], self.selected_location.label, mapset=self.selected_mapset.label)
+        new_name = self._getNewMapName(_('New name'), _('Rename map'),
+                                       old_name, env=env, mapset=self.selected_mapset.label, element=self.selected_type.label)
+        if new_name:
+            self.Rename(old_name, new_name)
 
 
     def OnStartEditLabel(self, node, event):
     def OnStartEditLabel(self, node, event):
         """Start label editing"""
         """Start label editing"""
@@ -416,51 +485,44 @@ class DataCatalogTree(LocationMapTree):
     def OnEditLabel(self, node, event):
     def OnEditLabel(self, node, event):
         """End label editing"""
         """End label editing"""
         if self.selected_layer and not event.IsEditCancelled():
         if self.selected_layer and not event.IsEditCancelled():
-            self.old_name = node.label
-            Debug.msg(1, "End label edit {name}".format(name=self.old_name))
-            self.new_name = event.GetLabel()
-            self.Rename()
+            old_name = node.label
+            Debug.msg(1, "End label edit {name}".format(name=old_name))
+            new_name = event.GetLabel()
+            self.Rename(old_name, new_name)
 
 
-    def Rename(self):
+    def Rename(self, old, new):
         """Rename layer"""
         """Rename layer"""
-        if self.selected_layer and self.new_name:
-            string = self.old_name + ',' + self.new_name
-            gisrc, env = getEnvironment(self.gisdbase, self.selected_location.label, self.selected_mapset.label)
-            renamed = 0
-            label = _("Renaming map <{name}>...").format(name=string)
-            self.showNotification.emit(message=label)
-            if self.selected_type.label == 'vector':
-                renamed, cmd = self._runCommand('g.rename', vector=string, env=env)
-            elif self.selected_type.label == 'raster':
-                renamed, cmd = self._runCommand('g.rename', raster=string, env=env)
-            else:
-                renamed, cmd = self._runCommand('g.rename', raster3d=string, env=env)
-            if renamed == 0:
-                self.selected_layer.label = self.new_name
-                self.selected_layer.data['name'] = self.new_name
-                self.RefreshNode(self.selected_layer)
-                self.showNotification.emit(message=_("{cmd} -- completed").format(cmd=cmd))
-                Debug.msg(1, "LAYER RENAMED TO: " + self.new_name)
-            gscript.try_remove(gisrc)
-
-    def OnPaste(self, event):
-        """Paste layer or mapset"""
+        string = old + ',' + new
+        gisrc, env = getEnvironment(gisenv()['GISDBASE'], self.selected_location.label, self.selected_mapset.label)
+        label = _("Renaming map <{name}>...").format(name=string)
+        self.showNotification.emit(message=label)
+        if self.selected_type.label == 'vector':
+            renamed, cmd = self._runCommand('g.rename', vector=string, env=env)
+        elif self.selected_type.label == 'raster':
+            renamed, cmd = self._runCommand('g.rename', raster=string, env=env)
+        else:
+            renamed, cmd = self._runCommand('g.rename', raster3d=string, env=env)
+        if renamed == 0:
+            self.selected_layer.label = new
+            self.selected_layer.data['name'] = new
+            self.RefreshNode(self.selected_layer)
+            self.showNotification.emit(message=_("{cmd} -- completed").format(cmd=cmd))
+            Debug.msg(1, "LAYER RENAMED TO: " + new)
+        gscript.try_remove(gisrc)
+
+    def OnPasteMap(self, event):
+        """Paste layer"""
         # copying between mapsets of one location
         # copying between mapsets of one location
         if not self.copy_layer:
         if not self.copy_layer:
             GMessage(_("No map selected for copying."), parent=self)
             GMessage(_("No map selected for copying."), parent=self)
             return
             return
-        if self.selected_location == self.copy_location and \
-           self.selected_mapset.data['name'] == gscript.gisenv()['MAPSET']:
-            if self.selected_type:
-                if self.copy_type.label != self.selected_type.label:  # copy raster to vector or vice versa
-                    GError(_("Failed to copy map: invalid map type "
-                             "({} vs. {}).".format(self.copy_type.label, self.selected_type.label)), parent=self)
-                    return
-            self.new_name = self._getUserEntry(_('New name'), _('Copy map'),
-                                               self.copy_layer.label + '_copy')
-            if not self.new_name:
+        if self.selected_location == self.copy_location:
+            gisrc, env = getEnvironment(gisenv()['GISDBASE'], self.selected_location.label, mapset=self.selected_mapset.label)
+            new_name = self._getNewMapName(_('New name'), _('Copy map'),
+                                           self.copy_layer.label, env=env, mapset=self.selected_mapset.label, element=self.copy_type.label)
+            if not new_name:
                 return
                 return
-            if self.copy_layer.label == self.new_name:
+            if map_exists(new_name, element=self.copy_type.label, env=env, mapset=self.selected_mapset.label):
                 GMessage(_("Failed to copy map: new map has the same name"), parent=self)
                 GMessage(_("Failed to copy map: new map has the same name"), parent=self)
                 return
                 return
 
 
@@ -470,21 +532,21 @@ class DataCatalogTree(LocationMapTree):
 
 
             overwrite = False
             overwrite = False
             if self.selected_type:
             if self.selected_type:
-                found = self._model.SearchNodes(parent=self.selected_type, type=self.copy_type.label, name=self.new_name)
+                found = self._model.SearchNodes(parent=self.selected_type, type=self.copy_type.label, name=new_name)
                 if found and found[0]:
                 if found and found[0]:
                     dlg = wx.MessageDialog(parent=self,
                     dlg = wx.MessageDialog(parent=self,
-                                           message = _("Map <{map}> already exists "
-                                                       "in the current mapset. "
-                                                       "Do you want to overwrite it?").format(map=self.new_name),
-                                           caption = _("Overwrite?"),
-                                           style = wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
+                                           message=_("Map <{map}> already exists "
+                                                     "in the current mapset. "
+                                                     "Do you want to overwrite it?").format(map=new_name),
+                                           caption=_("Overwrite?"),
+                                           style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
                     ret = dlg.ShowModal()
                     ret = dlg.ShowModal()
                     dlg.Destroy()
                     dlg.Destroy()
                     if ret == wx.ID_YES:
                     if ret == wx.ID_YES:
                         overwrite = True
                         overwrite = True
 
 
-            string = self.copy_layer.label + '@' + self.copy_mapset.label + ',' + self.new_name
-            gisrc, env = getEnvironment(self.gisdbase, self.selected_location.label, self.selected_mapset.label)
+            string = self.copy_layer.label + '@' + self.copy_mapset.label + ',' + new_name
+
             pasted = 0
             pasted = 0
             label = _("Copying <{name}>...").format(name=string)
             label = _("Copying <{name}>...").format(name=string)
             self.showNotification.emit(message=label)
             self.showNotification.emit(message=label)
@@ -498,60 +560,63 @@ class DataCatalogTree(LocationMapTree):
                 pasted, cmd = self._runCommand('g.copy', raster_3d=string, overwrite=overwrite, env=env)
                 pasted, cmd = self._runCommand('g.copy', raster_3d=string, overwrite=overwrite, env=env)
                 node = 'raster_3d'
                 node = 'raster_3d'
             if pasted == 0:
             if pasted == 0:
-                if not self.selected_type:
-                    # add type node if not exists
-                    self.selected_type = self._model.AppendNode(parent=self.selected_mapset, label=node,
-                                                                data=dict(type='element', name=node))
-                if not overwrite:
-                    self._model.AppendNode(parent=self.selected_type, label=self.new_name,
-                                           data=dict(type=node, name=self.new_name))
-                    self._model.SortChildren(self.selected_type)
-                    self.RefreshNode(self.selected_type, recursive=True)
-                Debug.msg(1, "COPIED TO: " + self.new_name)
-                self.showNotification.emit(message= _("{cmd} -- completed").format(cmd=cmd))
+                self.InsertLayer(name=new_name, mapset_node=self.selected_mapset, element_name=node)
+                Debug.msg(1, "COPIED TO: " + new_name)
+                self.showNotification.emit(message=_("g.copy completed").format(cmd=cmd))
             gscript.try_remove(gisrc)
             gscript.try_remove(gisrc)
         else:
         else:
-            if self.selected_location != self.copy_location:
-                GError(_("Failed to copy map: action is allowed only within the same location."),
-                       parent=self)
-            else:
-                GError(_("Failed to copy map: action is allowed only within the current mapset."),
-                       parent=self)
-        
+            GError(_("Failed to copy map: action is allowed only within the same location."),
+                   parent=self)
+
         # expand selected mapset
         # expand selected mapset
         self.ExpandNode(self.selected_mapset, recursive=True)
         self.ExpandNode(self.selected_mapset, recursive=True)
 
 
-    def OnDelete(self, event):
+    def InsertLayer(self, name, mapset_node, element_name):
+        """Insert layer into model and refresh tree"""
+        found_element = self._model.SearchNodes(parent=mapset_node, type='element', name=element_name)
+        found_element = found_element[0] if found_element else None
+        if not found_element:
+            # add type node if not exists
+            found_element = self._model.AppendNode(parent=mapset_node, label=element_name,
+                                                   data=dict(type='element', name=element_name))
+        found = self._model.SearchNodes(parent=found_element, name=name)
+        if len(found) == 0:
+            self._model.AppendNode(parent=found_element, label=name,
+                                   data=dict(type=element_name, name=name))
+            self._model.SortChildren(found_element)
+            self.RefreshNode(mapset_node, recursive=True)
+
+    def OnDeleteMap(self, event):
         """Delete layer or mapset"""
         """Delete layer or mapset"""
-        if self.selected_layer:
-            string = self.selected_layer.label
-            gisrc, env = getEnvironment(self.gisdbase, self.selected_location.label, self.selected_mapset.label)
-            removed = 0
-            # TODO: rewrite this that it will tell map type in the dialog
-            if self._confirmDialog(question=_('Do you really want to delete map <{m}>?').format(m=string),
-                                   title=_('Delete map')) == wx.ID_YES:
-                label = _("Deleting {name}...").format(name=string)
-                self.showNotification.emit(message=label)
-                if self.selected_type.label == 'vector':
-                    removed, cmd = self._runCommand('g.remove', flags='f', type='vector',
-                                         name=string, env=env)
-                elif self.selected_type.label == 'raster':
-                    removed, cmd = self._runCommand('g.remove', flags='f', type='raster',
-                                         name=string, env=env)
-                else:
-                    removed, cmd = self._runCommand('g.remove', flags='f', type='raster_3d',
-                                         name=string, env=env)
-                if removed == 0:
-                    self._model.RemoveNode(self.selected_layer)
-                    self.RefreshNode(self.selected_type, recursive=True)
-                    Debug.msg(1, "LAYER " + string + " DELETED")
-                    self.showNotification.emit(message= _("{cmd} -- completed").format(cmd=cmd))
-            gscript.try_remove(gisrc)
+        name = self.selected_layer.label
+        gisrc, env = getEnvironment(gisenv()['GISDBASE'], self.selected_location.label, self.selected_mapset.label)
+        if self._confirmDialog(question=_("Do you really want to delete map <{m}> of type <{etype}> from mapset "
+                               "<{mapset}> in location <{loc}>?").format(m=name, mapset=self.selected_mapset.label,
+                                                                         etype=self.selected_type.label,
+                                                                         loc=self.selected_location.label),
+                               title=_('Delete map')) == wx.ID_YES:
+            label = _("Deleting {name}...").format(name=name)
+            self.showNotification.emit(message=label)
+            if self.selected_type.label == 'vector':
+                removed, cmd = self._runCommand('g.remove', flags='f', type='vector',
+                                                name=name, env=env)
+            elif self.selected_type.label == 'raster':
+                removed, cmd = self._runCommand('g.remove', flags='f', type='raster',
+                                                name=name, env=env)
+            else:
+                removed, cmd = self._runCommand('g.remove', flags='f', type='raster_3d',
+                                                name=name, env=env)
+            if removed == 0:
+                self._model.RemoveNode(self.selected_layer)
+                self.RefreshNode(self.selected_type, recursive=True)
+                Debug.msg(1, "LAYER " + name + " DELETED")
+                self.showNotification.emit(message=_("g.remove completed").format(cmd=cmd))
+        gscript.try_remove(gisrc)
 
 
     def OnDisplayLayer(self, event):
     def OnDisplayLayer(self, event):
         """Display layer in current graphics view"""
         """Display layer in current graphics view"""
         layerName = []
         layerName = []
-        if self.selected_location.label == self.glocation and self.selected_mapset:
+        if self.selected_location.label == gisenv()['LOCATION_NAME'] and self.selected_mapset:
             string = self.selected_layer.label + '@' + self.selected_mapset.label
             string = self.selected_layer.label + '@' + self.selected_mapset.label
             layerName.append(string)
             layerName.append(string)
             label = _("Displaying {name}...").format(name=string)
             label = _("Displaying {name}...").format(name=string)
@@ -573,35 +638,39 @@ class DataCatalogTree(LocationMapTree):
 
 
     def OnBeginDrag(self, node, event):
     def OnBeginDrag(self, node, event):
         """Just copy necessary data"""
         """Just copy necessary data"""
-        if wx.GetMouseState().ControlDown():
-            #cursor = wx.StockCursor(wx.CURSOR_HAND)
-            #self.SetCursor(cursor)
+        self.DefineItems(node)
+        if self.selected_layer and \
+           not (self._restricted and gisenv()['LOCATION_NAME'] != self.selected_location.label):
             event.Allow()
             event.Allow()
-            self.DefineItems(node)
-            self.OnCopy(event)
+            self.OnCopyMap(event)
             Debug.msg(1, "DRAG")
             Debug.msg(1, "DRAG")
         else:
         else:
             event.Veto()
             event.Veto()
-            Debug.msg(1, "DRAGGING without ctrl key does nothing")
 
 
     def OnEndDrag(self, node, event):
     def OnEndDrag(self, node, event):
         """Copy layer into target"""
         """Copy layer into target"""
-        #cursor = wx.StockCursor(wx.CURSOR_ARROW)
-        #self.SetCursor(cursor)
+
+        if not wx.GetMouseState().ControlDown():
+            GMessage(_("Moving maps not implemented"), parent=self)
+            event.Veto()
+            return
         if node:
         if node:
             self.DefineItems(node)
             self.DefineItems(node)
+            if self._restricted and gisenv()['MAPSET'] != self.selected_mapset.label:
+                GMessage(_("Maps can be copied only to current mapset"), parent=self)
+                event.Veto()
+                return
             if self.selected_location == self.copy_location and self.selected_mapset:
             if self.selected_location == self.copy_location and self.selected_mapset:
                 event.Allow()
                 event.Allow()
-                self.OnPaste(event)
-                #cursor = wx.StockCursor(wx.CURSOR_DEFAULT)
-                #self.SetCursor(cursor) # TODO: change cursor while dragging and then back, this is not working
+                self.OnPasteMap(event)
                 Debug.msg(1, "DROP DONE")
                 Debug.msg(1, "DROP DONE")
             else:
             else:
                 event.Veto()
                 event.Veto()
 
 
-    def _getUserEntry(self, message, title, value):
+    def _getNewMapName(self, message, title, value, element, mapset, env):
         """Dialog for simple text entry"""
         """Dialog for simple text entry"""
-        dlg = TextEntryDialog(self, message, title)
+        dlg = NameEntryDialog(parent=self, message=message, caption=title,
+                              element=element, env=env, mapset=mapset)
         dlg.SetValue(value)
         dlg.SetValue(value)
         if dlg.ShowModal() == wx.ID_OK:
         if dlg.ShowModal() == wx.ID_OK:
             name = dlg.GetValue()
             name = dlg.GetValue()
@@ -618,28 +687,43 @@ class DataCatalogTree(LocationMapTree):
         dlg.Destroy()
         dlg.Destroy()
         return res
         return res
 
 
-    def _popupMenuLayer(self, current_mapset):
+    def _popupMenuLayer(self):
         """Create popup menu for layers"""
         """Create popup menu for layers"""
         menu = wx.Menu()
         menu = wx.Menu()
+        if self._restricted:
+            genv = gisenv()
+            currentMapset = currentLocation = False
+            if self.selected_location.label == genv['LOCATION_NAME']:
+                currentLocation = True
+                if self.selected_mapset.label == genv['MAPSET']:
+                    currentMapset = True
+        else:
+            currentMapset = currentLocation = True
 
 
         item = wx.MenuItem(menu, wx.NewId(), _("&Copy"))
         item = wx.MenuItem(menu, wx.NewId(), _("&Copy"))
         menu.AppendItem(item)
         menu.AppendItem(item)
-        self.Bind(wx.EVT_MENU, self.OnCopy, item)
+        self.Bind(wx.EVT_MENU, self.OnCopyMap, item)
+        item.Enable(currentLocation)
 
 
-        item = wx.MenuItem(menu, wx.NewId(), _("&Delete"))
+        item = wx.MenuItem(menu, wx.NewId(), _("&Paste"))
         menu.AppendItem(item)
         menu.AppendItem(item)
-        self.Bind(wx.EVT_MENU, self.OnDelete, item)
-        if not current_mapset:
+        self.Bind(wx.EVT_MENU, self.OnPasteMap, item)
+        if not(currentLocation and self.copy_layer and self.selected_location == self.copy_location):
             item.Enable(False)
             item.Enable(False)
 
 
+        item = wx.MenuItem(menu, wx.NewId(), _("&Delete"))
+        menu.AppendItem(item)
+        self.Bind(wx.EVT_MENU, self.OnDeleteMap, item)
+        item.Enable(currentMapset)
+
         item = wx.MenuItem(menu, wx.NewId(), _("&Rename"))
         item = wx.MenuItem(menu, wx.NewId(), _("&Rename"))
         menu.AppendItem(item)
         menu.AppendItem(item)
-        self.Bind(wx.EVT_MENU, self.OnRename, item)
-        if not current_mapset:
-            item.Enable(False)
+        self.Bind(wx.EVT_MENU, self.OnRenameMap, item)
+        item.Enable(currentMapset)
 
 
-        if not isinstance(self._giface, StandaloneGrassInterface):
-            item = wx.MenuItem(menu, wx.NewId(), _("&Display"))
+        if not isinstance(self._giface, StandaloneGrassInterface) and \
+           self.selected_location.label == genv['LOCATION_NAME']:
+            item = wx.MenuItem(menu, wx.NewId(), _("&Display layer"))
             menu.AppendItem(item)
             menu.AppendItem(item)
             self.Bind(wx.EVT_MENU, self.OnDisplayLayer, item)
             self.Bind(wx.EVT_MENU, self.OnDisplayLayer, item)
 
 
@@ -652,7 +736,21 @@ class DataCatalogTree(LocationMapTree):
 
 
         item = wx.MenuItem(menu, wx.NewId(), _("&Paste"))
         item = wx.MenuItem(menu, wx.NewId(), _("&Paste"))
         menu.AppendItem(item)
         menu.AppendItem(item)
-        self.Bind(wx.EVT_MENU, self.OnPaste, item)
+        self.Bind(wx.EVT_MENU, self.OnPasteMap, item)
+        if not (self.copy_layer and self.selected_location == self.copy_location):
+            item.Enable(False)
+
+        self.PopupMenu(menu)
+        menu.Destroy()
+
+    def _popupMenuElement(self):
+        """Create popup menu for elements"""
+        menu = wx.Menu()
+        item = wx.MenuItem(menu, wx.NewId(), _("&Paste"))
+        menu.AppendItem(item)
+        self.Bind(wx.EVT_MENU, self.OnPasteMap, item)
+        if not (self.copy_layer and self.selected_location == self.copy_location):
+            item.Enable(False)
 
 
         self.PopupMenu(menu)
         self.PopupMenu(menu)
         menu.Destroy()
         menu.Destroy()