| 1 | # -*- coding: utf-8 -*-
|
|---|
| 2 | """
|
|---|
| 3 | @package lmgr::frame
|
|---|
| 4 |
|
|---|
| 5 | @brief Layer Manager - main menu, layer management toolbar, notebook
|
|---|
| 6 | control for display management and access to command console.
|
|---|
| 7 |
|
|---|
| 8 | Classes:
|
|---|
| 9 | - frame::GMFrame
|
|---|
| 10 |
|
|---|
| 11 | (C) 2006-2015 by the GRASS Development Team
|
|---|
| 12 |
|
|---|
| 13 | This program is free software under the GNU General Public License
|
|---|
| 14 | (>=v2). Read the file COPYING that comes with GRASS for details.
|
|---|
| 15 |
|
|---|
| 16 | @author Michael Barton (Arizona State University)
|
|---|
| 17 | @author Jachym Cepicky (Mendel University of Agriculture)
|
|---|
| 18 | @author Martin Landa <landa.martin gmail.com>
|
|---|
| 19 | @author Vaclav Petras <wenzeslaus gmail.com> (menu customization)
|
|---|
| 20 | """
|
|---|
| 21 |
|
|---|
| 22 | import sys
|
|---|
| 23 | import os
|
|---|
| 24 | import tempfile
|
|---|
| 25 | import stat
|
|---|
| 26 | import platform
|
|---|
| 27 | import re
|
|---|
| 28 | try:
|
|---|
| 29 | import xml.etree.ElementTree as etree
|
|---|
| 30 | except ImportError:
|
|---|
| 31 | import elementtree.ElementTree as etree # Python <= 2.4
|
|---|
| 32 |
|
|---|
| 33 | from core import globalvar
|
|---|
| 34 | import wx
|
|---|
| 35 | import wx.aui
|
|---|
| 36 | try:
|
|---|
| 37 | import wx.lib.agw.flatnotebook as FN
|
|---|
| 38 | except ImportError:
|
|---|
| 39 | import wx.lib.flatnotebook as FN
|
|---|
| 40 |
|
|---|
| 41 | if os.path.join(globalvar.ETCDIR, "python") not in sys.path:
|
|---|
| 42 | sys.path.append(os.path.join(globalvar.ETCDIR, "python"))
|
|---|
| 43 |
|
|---|
| 44 | from grass.script import core as grass
|
|---|
| 45 | from grass.script.utils import decode
|
|---|
| 46 |
|
|---|
| 47 | from core.gcmd import RunCommand, GError, GMessage, EncodeString
|
|---|
| 48 | from core.settings import UserSettings, GetDisplayVectSettings
|
|---|
| 49 | from core.utils import SetAddOnPath, GetLayerNameFromCmd, command2ltype
|
|---|
| 50 | from gui_core.preferences import MapsetAccess, PreferencesDialog
|
|---|
| 51 | from lmgr.layertree import LayerTree, LMIcons
|
|---|
| 52 | from lmgr.menudata import LayerManagerMenuData, LayerManagerModuleTree
|
|---|
| 53 | from gui_core.widgets import GNotebook, FormNotebook
|
|---|
| 54 | from core.workspace import ProcessWorkspaceFile, ProcessGrcFile, WriteWorkspaceFile
|
|---|
| 55 | from core.gconsole import GConsole, EVT_IGNORED_CMD_RUN
|
|---|
| 56 | from core.giface import Notification
|
|---|
| 57 | from gui_core.goutput import GConsoleWindow, GC_PROMPT
|
|---|
| 58 | from gui_core.dialogs import LocationDialog, MapsetDialog, CreateNewVector, GroupDialog, MapLayersDialog, QuitDialog
|
|---|
| 59 | from gui_core.menu import SearchModuleWindow
|
|---|
| 60 | from gui_core.menu import Menu as GMenu
|
|---|
| 61 | from core.debug import Debug
|
|---|
| 62 | from lmgr.toolbars import LMWorkspaceToolbar, LMDataToolbar, LMToolsToolbar
|
|---|
| 63 | from lmgr.toolbars import LMMiscToolbar, LMVectorToolbar, LMNvizToolbar
|
|---|
| 64 | from lmgr.pyshell import PyShellWindow
|
|---|
| 65 | from lmgr.giface import LayerManagerGrassInterface
|
|---|
| 66 | from datacatalog.catalog import DataCatalog
|
|---|
| 67 | from gui_core.forms import GUI
|
|---|
| 68 | from gui_core.wrap import Menu, TextEntryDialog
|
|---|
| 69 |
|
|---|
| 70 |
|
|---|
| 71 | class GMFrame(wx.Frame):
|
|---|
| 72 | """Layer Manager frame with notebook widget for controlling GRASS
|
|---|
| 73 | GIS. Includes command console page for typing GRASS (and other)
|
|---|
| 74 | commands, tree widget page for managing map layers.
|
|---|
| 75 | """
|
|---|
| 76 |
|
|---|
| 77 | def __init__(
|
|---|
| 78 | self, parent, id=wx.ID_ANY, title=None, workspace=None,
|
|---|
| 79 | size=globalvar.GM_WINDOW_SIZE, style=wx.DEFAULT_FRAME_STYLE, **
|
|---|
| 80 | kwargs):
|
|---|
| 81 | self.parent = parent
|
|---|
| 82 | if title:
|
|---|
| 83 | self.baseTitle = title
|
|---|
| 84 | else:
|
|---|
| 85 | try:
|
|---|
| 86 | grassVersion = grass.version()['version']
|
|---|
| 87 | except KeyError:
|
|---|
| 88 | sys.stderr.write(_("Unable to get GRASS version\n"))
|
|---|
| 89 | grassVersion = "?"
|
|---|
| 90 | self.baseTitle = _("GRASS GIS %s Layer Manager") % grassVersion
|
|---|
| 91 |
|
|---|
| 92 | self.iconsize = (16, 16)
|
|---|
| 93 |
|
|---|
| 94 | self.displayIndex = 0 # index value for map displays and layer trees
|
|---|
| 95 | self.currentPage = None # currently selected page for layer tree notebook
|
|---|
| 96 | self.currentPageNum = None # currently selected page number for layer tree notebook
|
|---|
| 97 | self.workspaceFile = workspace # workspace file
|
|---|
| 98 | self.workspaceChanged = False # track changes in workspace
|
|---|
| 99 | # if we are currently loading workspace to ignore some events
|
|---|
| 100 | self.loadingWorkspace = False
|
|---|
| 101 | self.cwdPath = None # current working directory
|
|---|
| 102 |
|
|---|
| 103 | wx.Frame.__init__(self, parent=parent, id=id, size=size,
|
|---|
| 104 | style=style, **kwargs)
|
|---|
| 105 | self._setTitle()
|
|---|
| 106 | self.SetName("LayerManager")
|
|---|
| 107 |
|
|---|
| 108 | self.SetIcon(
|
|---|
| 109 | wx.Icon(
|
|---|
| 110 | os.path.join(
|
|---|
| 111 | globalvar.ICONDIR,
|
|---|
| 112 | 'grass.ico'),
|
|---|
| 113 | wx.BITMAP_TYPE_ICO))
|
|---|
| 114 |
|
|---|
| 115 | self._giface = LayerManagerGrassInterface(self)
|
|---|
| 116 |
|
|---|
| 117 | menu_errors = []
|
|---|
| 118 | def add_menu_error(message):
|
|---|
| 119 | menu_errors.append(message)
|
|---|
| 120 | def show_menu_errors(messages):
|
|---|
| 121 | if messages:
|
|---|
| 122 | self._gconsole.WriteError(
|
|---|
| 123 | _("There were some issues when loading menu"
|
|---|
| 124 | " or Modules tab:"))
|
|---|
| 125 | for message in messages:
|
|---|
| 126 | self._gconsole.WriteError(message)
|
|---|
| 127 |
|
|---|
| 128 | # the main menu bar
|
|---|
| 129 | self._menuTreeBuilder = LayerManagerMenuData(message_handler=add_menu_error)
|
|---|
| 130 | # the search tree and command console
|
|---|
| 131 | self._moduleTreeBuilder = LayerManagerModuleTree(message_handler=add_menu_error)
|
|---|
| 132 | self._auimgr = wx.aui.AuiManager(self)
|
|---|
| 133 |
|
|---|
| 134 | # list of open dialogs
|
|---|
| 135 | self.dialogs = dict()
|
|---|
| 136 | self.dialogs['preferences'] = None
|
|---|
| 137 | self.dialogs['nvizPreferences'] = None
|
|---|
| 138 | self.dialogs['atm'] = list()
|
|---|
| 139 |
|
|---|
| 140 | # create widgets
|
|---|
| 141 | self._createMenuBar()
|
|---|
| 142 | self.statusbar = self.CreateStatusBar(number=1)
|
|---|
| 143 | self.notebook = self._createNoteBook()
|
|---|
| 144 | self.toolbars = {'workspace': LMWorkspaceToolbar(parent=self),
|
|---|
| 145 | 'data': LMDataToolbar(parent=self),
|
|---|
| 146 | 'tools': LMToolsToolbar(parent=self),
|
|---|
| 147 | 'misc': LMMiscToolbar(parent=self),
|
|---|
| 148 | 'vector': LMVectorToolbar(parent=self),
|
|---|
| 149 | 'nviz': LMNvizToolbar(parent=self)}
|
|---|
| 150 | self._toolbarsData = {'workspace': ("toolbarWorkspace", # name
|
|---|
| 151 | _("Workspace Toolbar"), # caption
|
|---|
| 152 | 1), # row
|
|---|
| 153 | 'data': ("toolbarData",
|
|---|
| 154 | _("Data Toolbar"),
|
|---|
| 155 | 1),
|
|---|
| 156 | 'misc': ("toolbarMisc",
|
|---|
| 157 | _("Misc Toolbar"),
|
|---|
| 158 | 2),
|
|---|
| 159 | 'tools': ("toolbarTools",
|
|---|
| 160 | _("Tools Toolbar"),
|
|---|
| 161 | 2),
|
|---|
| 162 | 'vector': ("toolbarVector",
|
|---|
| 163 | _("Vector Toolbar"),
|
|---|
| 164 | 2),
|
|---|
| 165 | 'nviz': ("toolbarNviz",
|
|---|
| 166 | _("3D view Toolbar"),
|
|---|
| 167 | 2),
|
|---|
| 168 | }
|
|---|
| 169 | if sys.platform == 'win32':
|
|---|
| 170 | self._toolbarsList = ('workspace', 'data',
|
|---|
| 171 | 'vector', 'tools', 'misc', 'nviz')
|
|---|
| 172 | else:
|
|---|
| 173 | self._toolbarsList = ('data', 'workspace',
|
|---|
| 174 | 'nviz', 'misc', 'tools', 'vector')
|
|---|
| 175 | for toolbar in self._toolbarsList:
|
|---|
| 176 | name, caption, row = self._toolbarsData[toolbar]
|
|---|
| 177 | self._auimgr.AddPane(self.toolbars[toolbar],
|
|---|
| 178 | wx.aui.AuiPaneInfo().
|
|---|
| 179 | Name(name).Caption(caption).
|
|---|
| 180 | ToolbarPane().Top().Row(row).
|
|---|
| 181 | LeftDockable(False).RightDockable(False).
|
|---|
| 182 | BottomDockable(False).TopDockable(True).
|
|---|
| 183 | CloseButton(False).Layer(2).
|
|---|
| 184 | BestSize((self.toolbars[toolbar].GetBestSize())))
|
|---|
| 185 |
|
|---|
| 186 | self._auimgr.GetPane('toolbarNviz').Hide()
|
|---|
| 187 | # bindings
|
|---|
| 188 | self.Bind(wx.EVT_CLOSE, self.OnCloseWindowOrExit)
|
|---|
| 189 | self.Bind(wx.EVT_KEY_DOWN, self.OnKeyDown)
|
|---|
| 190 |
|
|---|
| 191 | self._giface.mapCreated.connect(self.OnMapCreated)
|
|---|
| 192 | self._giface.updateMap.connect(self._updateCurrentMap)
|
|---|
| 193 |
|
|---|
| 194 | # minimal frame size
|
|---|
| 195 | self.SetMinSize(globalvar.GM_WINDOW_MIN_SIZE)
|
|---|
| 196 |
|
|---|
| 197 | # AUI stuff
|
|---|
| 198 | self._auimgr.AddPane(self.notebook, wx.aui.AuiPaneInfo().
|
|---|
| 199 | Left().CentrePane().BestSize((-1, -1)).Dockable(False).
|
|---|
| 200 | CloseButton(False).DestroyOnClose(True).Row(1).Layer(0))
|
|---|
| 201 |
|
|---|
| 202 | self._auimgr.Update()
|
|---|
| 203 |
|
|---|
| 204 | wx.CallAfter(self.notebook.SetSelectionByName, 'layers')
|
|---|
| 205 |
|
|---|
| 206 | # use default window layout ?
|
|---|
| 207 | if UserSettings.Get(
|
|---|
| 208 | group='general', key='defWindowPos', subkey='enabled'):
|
|---|
| 209 | dim = UserSettings.Get(
|
|---|
| 210 | group='general',
|
|---|
| 211 | key='defWindowPos',
|
|---|
| 212 | subkey='dim')
|
|---|
| 213 | try:
|
|---|
| 214 | x, y = map(int, dim.split(',')[0:2])
|
|---|
| 215 | w, h = map(int, dim.split(',')[2:4])
|
|---|
| 216 | self.SetPosition((x, y))
|
|---|
| 217 | self.SetSize((w, h))
|
|---|
| 218 | except:
|
|---|
| 219 | pass
|
|---|
| 220 | else:
|
|---|
| 221 | # does center (of screen) make sense for lmgr?
|
|---|
| 222 | self.Centre()
|
|---|
| 223 |
|
|---|
| 224 | self.Layout()
|
|---|
| 225 | self.Show()
|
|---|
| 226 |
|
|---|
| 227 | # load workspace file if requested
|
|---|
| 228 | if self.workspaceFile:
|
|---|
| 229 | # load given workspace file
|
|---|
| 230 | if self.LoadWorkspaceFile(self.workspaceFile):
|
|---|
| 231 | self._setTitle()
|
|---|
| 232 | else:
|
|---|
| 233 | self.workspaceFile = None
|
|---|
| 234 | else:
|
|---|
| 235 | # start default initial display
|
|---|
| 236 | self.NewDisplay(show=False)
|
|---|
| 237 |
|
|---|
| 238 | # show map display widnow
|
|---|
| 239 | # -> OnSize() -> UpdateMap()
|
|---|
| 240 | for mapdisp in self.GetMapDisplay(onlyCurrent=False):
|
|---|
| 241 | mapdisp.Show()
|
|---|
| 242 |
|
|---|
| 243 | # redirect stderr to log area
|
|---|
| 244 | self._gconsole.Redirect()
|
|---|
| 245 |
|
|---|
| 246 | # fix goutput's pane size (required for Mac OSX)`
|
|---|
| 247 | self.goutput.SetSashPosition(int(self.GetSize()[1] * .8))
|
|---|
| 248 |
|
|---|
| 249 | self.workspaceChanged = False
|
|---|
| 250 |
|
|---|
| 251 | show_menu_errors(menu_errors)
|
|---|
| 252 |
|
|---|
| 253 | # start with layer manager on top
|
|---|
| 254 | if self.currentPage:
|
|---|
| 255 | self.GetMapDisplay().Raise()
|
|---|
| 256 | wx.CallAfter(self.Raise)
|
|---|
| 257 |
|
|---|
| 258 | def _setTitle(self):
|
|---|
| 259 | """Set frame title"""
|
|---|
| 260 | if self.workspaceFile:
|
|---|
| 261 | self.SetTitle(
|
|---|
| 262 | self.baseTitle +
|
|---|
| 263 | " - " +
|
|---|
| 264 | os.path.splitext(
|
|---|
| 265 | os.path.basename(
|
|---|
| 266 | self.workspaceFile))[0])
|
|---|
| 267 | else:
|
|---|
| 268 | self.SetTitle(self.baseTitle)
|
|---|
| 269 |
|
|---|
| 270 | def _createMenuBar(self):
|
|---|
| 271 | """Creates menu bar"""
|
|---|
| 272 | self.menubar = GMenu(
|
|---|
| 273 | parent=self,
|
|---|
| 274 | model=self._menuTreeBuilder.GetModel(
|
|---|
| 275 | separators=True))
|
|---|
| 276 | self.SetMenuBar(self.menubar)
|
|---|
| 277 | self.menucmd = self.menubar.GetCmd()
|
|---|
| 278 |
|
|---|
| 279 | def _createTabMenu(self):
|
|---|
| 280 | """Creates context menu for display tabs.
|
|---|
| 281 |
|
|---|
| 282 | Used to rename display.
|
|---|
| 283 | """
|
|---|
| 284 | menu = Menu()
|
|---|
| 285 | item = wx.MenuItem(menu, id=wx.ID_ANY, text=_("Rename Map Display"))
|
|---|
| 286 | menu.AppendItem(item)
|
|---|
| 287 | self.Bind(wx.EVT_MENU, self.OnRenameDisplay, item)
|
|---|
| 288 |
|
|---|
| 289 | return menu
|
|---|
| 290 |
|
|---|
| 291 | def _setCopyingOfSelectedText(self):
|
|---|
| 292 | copy = UserSettings.Get(
|
|---|
| 293 | group='manager',
|
|---|
| 294 | key='copySelectedTextToClipboard',
|
|---|
| 295 | subkey='enabled')
|
|---|
| 296 | self.goutput.SetCopyingOfSelectedText(copy)
|
|---|
| 297 |
|
|---|
| 298 | def IsPaneShown(self, name):
|
|---|
| 299 | """Check if pane (toolbar, ...) of given name is currently shown"""
|
|---|
| 300 | if self._auimgr.GetPane(name).IsOk():
|
|---|
| 301 | return self._auimgr.GetPane(name).IsShown()
|
|---|
| 302 | return False
|
|---|
| 303 |
|
|---|
| 304 | def _createNoteBook(self):
|
|---|
| 305 | """Creates notebook widgets"""
|
|---|
| 306 | if sys.platform == 'win32':
|
|---|
| 307 | self.notebook = GNotebook(
|
|---|
| 308 | parent=self, style=globalvar.FNPageDStyle)
|
|---|
| 309 | else:
|
|---|
| 310 | self.notebook = FormNotebook(parent=self, style=wx.NB_BOTTOM)
|
|---|
| 311 | # create displays notebook widget and add it to main notebook page
|
|---|
| 312 | cbStyle = globalvar.FNPageStyle
|
|---|
| 313 | if globalvar.hasAgw:
|
|---|
| 314 | self.notebookLayers = FN.FlatNotebook(
|
|---|
| 315 | self.notebook, id=wx.ID_ANY, agwStyle=cbStyle)
|
|---|
| 316 | else:
|
|---|
| 317 | self.notebookLayers = FN.FlatNotebook(
|
|---|
| 318 | self.notebook, id=wx.ID_ANY, style=cbStyle)
|
|---|
| 319 | self.notebookLayers.SetTabAreaColour(globalvar.FNPageColor)
|
|---|
| 320 | menu = self._createTabMenu()
|
|---|
| 321 | self.notebookLayers.SetRightClickMenu(menu)
|
|---|
| 322 | self.notebook.AddPage(
|
|---|
| 323 | page=self.notebookLayers,
|
|---|
| 324 | text=_("Layers"),
|
|---|
| 325 | name='layers')
|
|---|
| 326 |
|
|---|
| 327 | # create 'command output' text area
|
|---|
| 328 | self._gconsole = GConsole(
|
|---|
| 329 | guiparent=self, giface=self._giface,
|
|---|
| 330 | ignoredCmdPattern='^d\..*|^r[3]?\.mapcalc$|^i.group$|^r.import$|'
|
|---|
| 331 | '^r.external$|^r.external.out$|'
|
|---|
| 332 | '^v.import$|^v.external$|^v.external.out$|'
|
|---|
| 333 | '^cd$|^cd .*')
|
|---|
| 334 | self.goutput = GConsoleWindow(
|
|---|
| 335 | parent=self.notebook,
|
|---|
| 336 | gconsole=self._gconsole,
|
|---|
| 337 | menuModel=self._moduleTreeBuilder.GetModel(),
|
|---|
| 338 | gcstyle=GC_PROMPT)
|
|---|
| 339 | self.notebook.AddPage(
|
|---|
| 340 | page=self.goutput,
|
|---|
| 341 | text=_("Console"),
|
|---|
| 342 | name='output')
|
|---|
| 343 |
|
|---|
| 344 | self.goutput.showNotification.connect(
|
|---|
| 345 | lambda message: self.SetStatusText(message))
|
|---|
| 346 |
|
|---|
| 347 | self._gconsole.mapCreated.connect(self.OnMapCreated)
|
|---|
| 348 | self.goutput.contentChanged.connect(
|
|---|
| 349 | lambda notification: self._switchPage(notification))
|
|---|
| 350 |
|
|---|
| 351 | self._gconsole.Bind(EVT_IGNORED_CMD_RUN,
|
|---|
| 352 | lambda event: self.RunSpecialCmd(event.cmd))
|
|---|
| 353 |
|
|---|
| 354 | self._setCopyingOfSelectedText()
|
|---|
| 355 |
|
|---|
| 356 | # create 'search module' notebook page
|
|---|
| 357 | if not UserSettings.Get(
|
|---|
| 358 | group='manager', key='hideTabs', subkey='search'):
|
|---|
| 359 | self.search = SearchModuleWindow(
|
|---|
| 360 | parent=self.notebook, handlerObj=self,
|
|---|
| 361 | giface=self._giface,
|
|---|
| 362 | model=self._moduleTreeBuilder.GetModel())
|
|---|
| 363 | self.search.showNotification.connect(
|
|---|
| 364 | lambda message: self.SetStatusText(message))
|
|---|
| 365 | self.notebook.AddPage(
|
|---|
| 366 | page=self.search,
|
|---|
| 367 | text=_("Modules"),
|
|---|
| 368 | name='search')
|
|---|
| 369 | else:
|
|---|
| 370 | self.search = None
|
|---|
| 371 |
|
|---|
| 372 | # create 'data catalog' notebook page
|
|---|
| 373 | self.datacatalog = DataCatalog(
|
|---|
| 374 | parent=self.notebook, giface=self._giface)
|
|---|
| 375 | self.datacatalog.showNotification.connect(
|
|---|
| 376 | lambda message: self.SetStatusText(message))
|
|---|
| 377 | self.datacatalog.changeMapset.connect(lambda mapset: self.ChangeMapset(mapset))
|
|---|
| 378 | self.datacatalog.changeLocation.connect(lambda mapset, location: self.ChangeLocation(location, mapset))
|
|---|
| 379 | self.notebook.AddPage(
|
|---|
| 380 | page=self.datacatalog,
|
|---|
| 381 | text=_("Data"),
|
|---|
| 382 | name='catalog')
|
|---|
| 383 |
|
|---|
| 384 | # create 'python shell' notebook page
|
|---|
| 385 | if not UserSettings.Get(
|
|---|
| 386 | group='manager', key='hideTabs', subkey='pyshell'):
|
|---|
| 387 | self.pyshell = PyShellWindow(
|
|---|
| 388 | parent=self.notebook, giface=self._giface, simpleEditorHandler=self.OnSimpleEditor)
|
|---|
| 389 | self.notebook.AddPage(
|
|---|
| 390 | page=self.pyshell,
|
|---|
| 391 | text=_("Python"),
|
|---|
| 392 | name='pyshell')
|
|---|
| 393 | else:
|
|---|
| 394 | self.pyshell = None
|
|---|
| 395 |
|
|---|
| 396 | # bindings
|
|---|
| 397 | if sys.platform == 'win32':
|
|---|
| 398 | self.notebook.Bind(
|
|---|
| 399 | FN.EVT_FLATNOTEBOOK_PAGE_CHANGED,
|
|---|
| 400 | self.OnPageChanged)
|
|---|
| 401 | else:
|
|---|
| 402 | self.notebook.Bind(
|
|---|
| 403 | wx.EVT_NOTEBOOK_PAGE_CHANGED,
|
|---|
| 404 | self.OnPageChanged)
|
|---|
| 405 | self.notebookLayers.Bind(
|
|---|
| 406 | FN.EVT_FLATNOTEBOOK_PAGE_CHANGED,
|
|---|
| 407 | self.OnCBPageChanged)
|
|---|
| 408 | self.notebookLayers.Bind(
|
|---|
| 409 | FN.EVT_FLATNOTEBOOK_PAGE_CLOSING,
|
|---|
| 410 | self.OnCBPageClosed)
|
|---|
| 411 |
|
|---|
| 412 | return self.notebook
|
|---|
| 413 |
|
|---|
| 414 | def AddNvizTools(self, firstTime):
|
|---|
| 415 | """Add nviz notebook page
|
|---|
| 416 |
|
|---|
| 417 | :param firstTime: if a mapdisplay is starting 3D mode for the
|
|---|
| 418 | first time
|
|---|
| 419 | """
|
|---|
| 420 | Debug.msg(5, "GMFrame.AddNvizTools()")
|
|---|
| 421 | from nviz.main import haveNviz
|
|---|
| 422 | if not haveNviz:
|
|---|
| 423 | return
|
|---|
| 424 |
|
|---|
| 425 | from nviz.main import NvizToolWindow
|
|---|
| 426 |
|
|---|
| 427 | # show toolbar
|
|---|
| 428 | self._auimgr.GetPane('toolbarNviz').Show()
|
|---|
| 429 | # reorder other toolbars
|
|---|
| 430 | for pos, toolbar in enumerate(
|
|---|
| 431 | ('toolbarVector', 'toolbarTools', 'toolbarMisc', 'toolbarNviz')):
|
|---|
| 432 | self._auimgr.GetPane(toolbar).Row(2).Position(pos)
|
|---|
| 433 | self._auimgr.Update()
|
|---|
| 434 |
|
|---|
| 435 | # create nviz tools tab
|
|---|
| 436 | self.nviz = NvizToolWindow(
|
|---|
| 437 | parent=self.notebook,
|
|---|
| 438 | tree=self.GetLayerTree(),
|
|---|
| 439 | display=self.GetMapDisplay())
|
|---|
| 440 | idx = self.notebook.GetPageIndexByName('layers')
|
|---|
| 441 | self.notebook.InsertNBPage(
|
|---|
| 442 | index=idx + 1,
|
|---|
| 443 | page=self.nviz,
|
|---|
| 444 | text=_("3D view"),
|
|---|
| 445 | name='nviz')
|
|---|
| 446 | self.notebook.SetSelectionByName('nviz')
|
|---|
| 447 |
|
|---|
| 448 | # this is a bit strange here since a new window is created everytime
|
|---|
| 449 | if not firstTime:
|
|---|
| 450 | for page in ('view', 'light', 'fringe',
|
|---|
| 451 | 'constant', 'cplane', 'animation'):
|
|---|
| 452 | self.nviz.UpdatePage(page)
|
|---|
| 453 |
|
|---|
| 454 | def RemoveNvizTools(self):
|
|---|
| 455 | """Remove nviz notebook page"""
|
|---|
| 456 | # if more mapwindow3D were possible, check here if nb page should be
|
|---|
| 457 | # removed
|
|---|
| 458 | self.notebook.SetSelectionByName('layers')
|
|---|
| 459 | self.notebook.DeleteNBPage('nviz')
|
|---|
| 460 |
|
|---|
| 461 | # hide toolbar
|
|---|
| 462 | self._auimgr.GetPane('toolbarNviz').Hide()
|
|---|
| 463 | for pos, toolbar in enumerate(
|
|---|
| 464 | ('toolbarVector', 'toolbarTools', 'toolbarMisc')):
|
|---|
| 465 | self._auimgr.GetPane(toolbar).Row(2).Position(pos)
|
|---|
| 466 | self._auimgr.Update()
|
|---|
| 467 |
|
|---|
| 468 | def WorkspaceChanged(self):
|
|---|
| 469 | """Update window title"""
|
|---|
| 470 | if not self.workspaceChanged:
|
|---|
| 471 | self.workspaceChanged = True
|
|---|
| 472 |
|
|---|
| 473 | if self.workspaceFile:
|
|---|
| 474 | self._setTitle()
|
|---|
| 475 |
|
|---|
| 476 | def OnLocationWizard(self, event):
|
|---|
| 477 | """Launch location wizard"""
|
|---|
| 478 | from location_wizard.wizard import LocationWizard
|
|---|
| 479 | from location_wizard.dialogs import RegionDef
|
|---|
| 480 |
|
|---|
| 481 | gWizard = LocationWizard(parent=self,
|
|---|
| 482 | grassdatabase=grass.gisenv()['GISDBASE'])
|
|---|
| 483 | location = gWizard.location
|
|---|
| 484 |
|
|---|
| 485 | if location is not None:
|
|---|
| 486 | dlg = wx.MessageDialog(parent=self,
|
|---|
| 487 | message=_('Location <%s> created.\n\n'
|
|---|
| 488 | 'Do you want to switch to the '
|
|---|
| 489 | 'new location?') % location,
|
|---|
| 490 | caption=_("Switch to new location?"),
|
|---|
| 491 | style=wx.YES_NO | wx.NO_DEFAULT |
|
|---|
| 492 | wx.ICON_QUESTION | wx.CENTRE)
|
|---|
| 493 |
|
|---|
| 494 | ret = dlg.ShowModal()
|
|---|
| 495 | dlg.Destroy()
|
|---|
| 496 | if ret == wx.ID_YES:
|
|---|
| 497 | if RunCommand('g.mapset', parent=self,
|
|---|
| 498 | location=location,
|
|---|
| 499 | mapset='PERMANENT') != 0:
|
|---|
| 500 | return
|
|---|
| 501 |
|
|---|
| 502 | # close current workspace and create new one
|
|---|
| 503 | self.OnWorkspaceClose()
|
|---|
| 504 | self.OnWorkspaceNew()
|
|---|
| 505 | GMessage(parent=self,
|
|---|
| 506 | message=_("Current location is <%(loc)s>.\n"
|
|---|
| 507 | "Current mapset is <%(mapset)s>.") %
|
|---|
| 508 | {'loc': location, 'mapset': 'PERMANENT'})
|
|---|
| 509 |
|
|---|
| 510 | # code duplication with gis_set.py
|
|---|
| 511 | dlg = wx.MessageDialog(
|
|---|
| 512 | parent=self,
|
|---|
| 513 | message=_(
|
|---|
| 514 | "Do you want to set the default "
|
|---|
| 515 | "region extents and resolution now?"),
|
|---|
| 516 | caption=_("Location <%s> created") %
|
|---|
| 517 | location,
|
|---|
| 518 | style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
|
|---|
| 519 | dlg.CenterOnScreen()
|
|---|
| 520 | if dlg.ShowModal() == wx.ID_YES:
|
|---|
| 521 | dlg.Destroy()
|
|---|
| 522 | defineRegion = RegionDef(self, location=location)
|
|---|
| 523 | defineRegion.CenterOnScreen()
|
|---|
| 524 | defineRegion.ShowModal()
|
|---|
| 525 | defineRegion.Destroy()
|
|---|
| 526 | else:
|
|---|
| 527 | dlg.Destroy()
|
|---|
| 528 |
|
|---|
| 529 | def OnSettingsChanged(self):
|
|---|
| 530 | """Here can be functions which have to be called
|
|---|
| 531 | after receiving settingsChanged signal.
|
|---|
| 532 | Now only set copying of selected text to clipboard (in goutput).
|
|---|
| 533 | """
|
|---|
| 534 | # self._createMenuBar() # bug when menu is re-created on the fly
|
|---|
| 535 | self._setCopyingOfSelectedText()
|
|---|
| 536 |
|
|---|
| 537 | def OnGCPManager(self, event=None, cmd=None):
|
|---|
| 538 | """Launch georectifier module. See OnIClass documentation"""
|
|---|
| 539 | from gcp.manager import GCPWizard
|
|---|
| 540 | GCPWizard(self, self._giface)
|
|---|
| 541 |
|
|---|
| 542 | def OnGModeler(self, event=None, cmd=None):
|
|---|
| 543 | """Launch Graphical Modeler. See OnIClass documentation"""
|
|---|
| 544 | from gmodeler.frame import ModelFrame
|
|---|
| 545 | win = ModelFrame(parent=self, giface=self._giface)
|
|---|
| 546 | win.CentreOnScreen()
|
|---|
| 547 | win.Show()
|
|---|
| 548 |
|
|---|
| 549 | def OnPsMap(self, event=None, cmd=None):
|
|---|
| 550 | """Launch Cartographic Composer. See OnIClass documentation"""
|
|---|
| 551 | from psmap.frame import PsMapFrame
|
|---|
| 552 | win = PsMapFrame(parent=self)
|
|---|
| 553 | win.CentreOnScreen()
|
|---|
| 554 | win.Show()
|
|---|
| 555 |
|
|---|
| 556 | def OnMapSwipe(self, event=None, cmd=None):
|
|---|
| 557 | """Launch Map Swipe. See OnIClass documentation"""
|
|---|
| 558 | from mapswipe.frame import SwipeMapFrame
|
|---|
| 559 |
|
|---|
| 560 | win = SwipeMapFrame(parent=self, giface=self._giface)
|
|---|
| 561 |
|
|---|
| 562 | rasters = []
|
|---|
| 563 | tree = self.GetLayerTree()
|
|---|
| 564 | if tree:
|
|---|
| 565 | for layer in tree.GetSelections():
|
|---|
| 566 | if tree.GetLayerInfo(
|
|---|
| 567 | layer, key='maplayer').GetType() != 'raster':
|
|---|
| 568 | continue
|
|---|
| 569 | rasters.append(
|
|---|
| 570 | tree.GetLayerInfo(
|
|---|
| 571 | layer, key='maplayer').GetName())
|
|---|
| 572 |
|
|---|
| 573 | if len(rasters) >= 1:
|
|---|
| 574 | win.SetFirstRaster(rasters[0])
|
|---|
| 575 | if len(rasters) >= 2:
|
|---|
| 576 | win.SetSecondRaster(rasters[1])
|
|---|
| 577 | win.SetRasterNames()
|
|---|
| 578 |
|
|---|
| 579 | win.CentreOnScreen()
|
|---|
| 580 | win.Show()
|
|---|
| 581 |
|
|---|
| 582 | def OnRLiSetup(self, event=None, cmd=None):
|
|---|
| 583 | """Launch r.li setup. See OnIClass documentation"""
|
|---|
| 584 | from rlisetup.frame import RLiSetupFrame
|
|---|
| 585 | win = RLiSetupFrame(parent=self)
|
|---|
| 586 | win.CentreOnScreen()
|
|---|
| 587 | win.Show()
|
|---|
| 588 |
|
|---|
| 589 | def OnDone(self, event):
|
|---|
| 590 | """Command execution finished"""
|
|---|
| 591 | if hasattr(self, "model"):
|
|---|
| 592 | self.model.DeleteIntermediateData(log=self._gconsole)
|
|---|
| 593 | del self.model
|
|---|
| 594 | self.SetStatusText('')
|
|---|
| 595 |
|
|---|
| 596 | def OnRunModel(self, event):
|
|---|
| 597 | """Run model"""
|
|---|
| 598 | filename = ''
|
|---|
| 599 | dlg = wx.FileDialog(parent=self, message=_("Choose model to run"),
|
|---|
| 600 | defaultDir=os.getcwd(),
|
|---|
| 601 | wildcard=_("GRASS Model File (*.gxm)|*.gxm"))
|
|---|
| 602 | if dlg.ShowModal() == wx.ID_OK:
|
|---|
| 603 | filename = dlg.GetPath()
|
|---|
| 604 |
|
|---|
| 605 | if not filename:
|
|---|
| 606 | dlg.Destroy()
|
|---|
| 607 | return
|
|---|
| 608 |
|
|---|
| 609 | from gmodeler.model import Model
|
|---|
| 610 | self.model = Model()
|
|---|
| 611 | self.model.LoadModel(filename)
|
|---|
| 612 | self.model.Run(
|
|---|
| 613 | log=self.GetLogWindow(),
|
|---|
| 614 | onDone=self.OnDone,
|
|---|
| 615 | parent=self)
|
|---|
| 616 | dlg.Destroy()
|
|---|
| 617 |
|
|---|
| 618 | def OnMapsets(self, event):
|
|---|
| 619 | """Launch mapset access dialog
|
|---|
| 620 | """
|
|---|
| 621 | dlg = MapsetAccess(parent=self, id=wx.ID_ANY)
|
|---|
| 622 | dlg.CenterOnScreen()
|
|---|
| 623 |
|
|---|
| 624 | if dlg.ShowModal() == wx.ID_OK:
|
|---|
| 625 | ms = dlg.GetMapsets()
|
|---|
| 626 | RunCommand('g.mapsets',
|
|---|
| 627 | parent=self,
|
|---|
| 628 | mapset='%s' % ','.join(ms),
|
|---|
| 629 | operation='set')
|
|---|
| 630 |
|
|---|
| 631 | def OnCBPageChanged(self, event):
|
|---|
| 632 | """Page in notebook (display) changed"""
|
|---|
| 633 | self.currentPage = self.notebookLayers.GetCurrentPage()
|
|---|
| 634 | self.currentPageNum = self.notebookLayers.GetSelection()
|
|---|
| 635 | try:
|
|---|
| 636 | self.GetMapDisplay().SetFocus()
|
|---|
| 637 | self.GetMapDisplay().Raise()
|
|---|
| 638 | except:
|
|---|
| 639 | pass
|
|---|
| 640 |
|
|---|
| 641 | event.Skip()
|
|---|
| 642 |
|
|---|
| 643 | def OnPageChanged(self, event):
|
|---|
| 644 | """Page in notebook changed"""
|
|---|
| 645 | page = event.GetSelection()
|
|---|
| 646 | if page == self.notebook.GetPageIndexByName('output'):
|
|---|
| 647 | wx.CallAfter(self.goutput.ResetFocus)
|
|---|
| 648 | elif page == self.notebook.GetPageIndexByName('catalog'):
|
|---|
| 649 | wx.CallAfter(self.datacatalog.LoadItems)
|
|---|
| 650 | self.SetStatusText('', 0)
|
|---|
| 651 |
|
|---|
| 652 | event.Skip()
|
|---|
| 653 |
|
|---|
| 654 | def OnCBPageClosed(self, event):
|
|---|
| 655 | """Page of notebook closed
|
|---|
| 656 | Also close associated map display
|
|---|
| 657 | """
|
|---|
| 658 |
|
|---|
| 659 | # save changes in the workspace
|
|---|
| 660 | maptree = self.GetLayerTree()
|
|---|
| 661 | if self.workspaceChanged and UserSettings.Get(
|
|---|
| 662 | group='manager', key='askOnQuit', subkey='enabled'):
|
|---|
| 663 | if self.workspaceFile:
|
|---|
| 664 | message = _("Do you want to save changes in the workspace?")
|
|---|
| 665 | else:
|
|---|
| 666 | message = _("Do you want to store current settings "
|
|---|
| 667 | "to workspace file?")
|
|---|
| 668 |
|
|---|
| 669 | # ask user to save current settings
|
|---|
| 670 | if maptree.GetCount() > 0:
|
|---|
| 671 | name = self.notebookLayers.GetPageText(self.currentPageNum)
|
|---|
| 672 | dlg = wx.MessageDialog(self,
|
|---|
| 673 | message=message,
|
|---|
| 674 | caption=_("Close Map Display %s") % name,
|
|---|
| 675 | style=wx.YES_NO | wx.YES_DEFAULT |
|
|---|
| 676 | wx.CANCEL | wx.ICON_QUESTION | wx.CENTRE)
|
|---|
| 677 | ret = dlg.ShowModal()
|
|---|
| 678 | if ret == wx.ID_YES:
|
|---|
| 679 | if not self.workspaceFile:
|
|---|
| 680 | self.OnWorkspaceSaveAs()
|
|---|
| 681 | else:
|
|---|
| 682 | self.SaveToWorkspaceFile(self.workspaceFile)
|
|---|
| 683 | elif ret == wx.ID_CANCEL:
|
|---|
| 684 | event.Veto()
|
|---|
| 685 | dlg.Destroy()
|
|---|
| 686 | return
|
|---|
| 687 | dlg.Destroy()
|
|---|
| 688 |
|
|---|
| 689 | self.notebookLayers.GetPage(event.GetSelection()).maptree.Map.Clean()
|
|---|
| 690 | self.notebookLayers.GetPage(event.GetSelection()).maptree.Close(True)
|
|---|
| 691 |
|
|---|
| 692 | self.currentPage = None
|
|---|
| 693 |
|
|---|
| 694 | event.Skip()
|
|---|
| 695 |
|
|---|
| 696 | def _switchPageHandler(self, event, notification):
|
|---|
| 697 | self._switchPage(notification=notification)
|
|---|
| 698 | event.Skip()
|
|---|
| 699 |
|
|---|
| 700 | def _switchPage(self, notification):
|
|---|
| 701 | """Manages @c 'output' notebook page according to event notification."""
|
|---|
| 702 | if notification == Notification.HIGHLIGHT:
|
|---|
| 703 | self.notebook.HighlightPageByName('output')
|
|---|
| 704 | if notification == Notification.MAKE_VISIBLE:
|
|---|
| 705 | self.notebook.SetSelectionByName('output')
|
|---|
| 706 | if notification == Notification.RAISE_WINDOW:
|
|---|
| 707 | self.notebook.SetSelectionByName('output')
|
|---|
| 708 | self.SetFocus()
|
|---|
| 709 | self.Raise()
|
|---|
| 710 |
|
|---|
| 711 | def RunSpecialCmd(self, command):
|
|---|
| 712 | """Run command from command line, check for GUI wrappers"""
|
|---|
| 713 | if re.compile('^d\..*').search(command[0]):
|
|---|
| 714 | self.RunDisplayCmd(command)
|
|---|
| 715 | elif re.compile('r[3]?\.mapcalc').search(command[0]):
|
|---|
| 716 | self.OnMapCalculator(event=None, cmd=command)
|
|---|
| 717 | elif command[0] == 'i.group':
|
|---|
| 718 | self.OnEditImageryGroups(event=None, cmd=command)
|
|---|
| 719 | elif command[0] == 'r.import':
|
|---|
| 720 | self.OnImportGdalLayers(event=None, cmd=command)
|
|---|
| 721 | elif command[0] == 'r.external':
|
|---|
| 722 | self.OnLinkGdalLayers(event=None, cmd=command)
|
|---|
| 723 | elif command[0] == 'r.external.out':
|
|---|
| 724 | self.OnRasterOutputFormat(event=None)
|
|---|
| 725 | elif command[0] == 'v.import':
|
|---|
| 726 | self.OnImportOgrLayers(event=None, cmd=command)
|
|---|
| 727 | elif command[0] == 'v.external':
|
|---|
| 728 | self.OnLinkOgrLayers(event=None, cmd=command)
|
|---|
| 729 | elif command[0] == 'v.external.out':
|
|---|
| 730 | self.OnVectorOutputFormat(event=None)
|
|---|
| 731 | elif command[0] == 'cd':
|
|---|
| 732 | self.OnChangeCWD(event=None, cmd=command)
|
|---|
| 733 | else:
|
|---|
| 734 | raise ValueError('Layer Manager special command (%s)'
|
|---|
| 735 | ' not supported.' % ' '.join(command))
|
|---|
| 736 |
|
|---|
| 737 | def RunDisplayCmd(self, command):
|
|---|
| 738 | """Handles display commands.
|
|---|
| 739 |
|
|---|
| 740 | :param command: command in a list
|
|---|
| 741 | """
|
|---|
| 742 | if not self.currentPage:
|
|---|
| 743 | self.NewDisplay(show=True)
|
|---|
| 744 | # here should be the d.* commands which are not layers
|
|---|
| 745 | if command[0] == 'd.erase':
|
|---|
| 746 | # rest of d.erase is ignored
|
|---|
| 747 | self.GetLayerTree().DeleteAllLayers()
|
|---|
| 748 | return
|
|---|
| 749 | try:
|
|---|
| 750 | # display GRASS commands
|
|---|
| 751 | layertype = command2ltype[command[0]]
|
|---|
| 752 | except KeyError:
|
|---|
| 753 | GMessage(
|
|---|
| 754 | parent=self, message=_(
|
|---|
| 755 | "Command '%s' not yet implemented in the WxGUI. "
|
|---|
| 756 | "Try adding it as a command layer instead.") %
|
|---|
| 757 | command[0])
|
|---|
| 758 | return
|
|---|
| 759 |
|
|---|
| 760 | if layertype == 'barscale':
|
|---|
| 761 | if len(command) > 1:
|
|---|
| 762 | self.GetMapDisplay().AddBarscale(cmd=command)
|
|---|
| 763 | else:
|
|---|
| 764 | self.GetMapDisplay().AddBarscale()
|
|---|
| 765 | elif layertype == 'rastleg':
|
|---|
| 766 | if len(command) > 1:
|
|---|
| 767 | self.GetMapDisplay().AddLegendRast(cmd=command)
|
|---|
| 768 | else:
|
|---|
| 769 | self.GetMapDisplay().AddLegendRast()
|
|---|
| 770 | elif layertype == 'vectleg':
|
|---|
| 771 | if len(command) > 1:
|
|---|
| 772 | self.GetMapDisplay().AddLegendVect(cmd=command, showDialog=False)
|
|---|
| 773 | else:
|
|---|
| 774 | self.GetMapDisplay().AddLegendVect(showDialog=True)
|
|---|
| 775 | elif layertype == 'northarrow':
|
|---|
| 776 | if len(command) > 1:
|
|---|
| 777 | self.GetMapDisplay().AddArrow(cmd=command)
|
|---|
| 778 | else:
|
|---|
| 779 | self.GetMapDisplay().AddArrow()
|
|---|
| 780 | elif layertype == 'text':
|
|---|
| 781 | if len(command) > 1:
|
|---|
| 782 | self.GetMapDisplay().AddDtext(cmd=command)
|
|---|
| 783 | else:
|
|---|
| 784 | self.GetMapDisplay().AddDtext()
|
|---|
| 785 | elif layertype == 'redraw':
|
|---|
| 786 | self.GetMapDisplay().OnRender(None)
|
|---|
| 787 | elif layertype == 'export':
|
|---|
| 788 | GUI(parent=self, show=False).ParseCommand(
|
|---|
| 789 | command, completed=(self.GetMapDisplay().DOutFileOptData, '', ''))
|
|---|
| 790 | elif layertype == 'torast':
|
|---|
| 791 | if len(command) <= 1:
|
|---|
| 792 | task = GUI(
|
|---|
| 793 | parent=self, show=True).ParseCommand(
|
|---|
| 794 | command, completed=(
|
|---|
| 795 | self.GetMapDisplay().DToRastOptData, '', ''))
|
|---|
| 796 | else:
|
|---|
| 797 | task = GUI(
|
|---|
| 798 | parent=self, show=None).ParseCommand(
|
|---|
| 799 | command, completed=(
|
|---|
| 800 | self.GetMapDisplay().DToRastOptData, '', ''))
|
|---|
| 801 | self.GetMapDisplay().DToRast(command=task.get_cmd())
|
|---|
| 802 | else:
|
|---|
| 803 | # add layer into layer tree
|
|---|
| 804 | lname, found = GetLayerNameFromCmd(command, fullyQualified=True,
|
|---|
| 805 | layerType=layertype)
|
|---|
| 806 | self.GetLayerTree().AddLayer(ltype=layertype, lchecked=True if lname else None,
|
|---|
| 807 | lname=lname, lcmd=command)
|
|---|
| 808 |
|
|---|
| 809 | def GetLayerNotebook(self):
|
|---|
| 810 | """Get Layers Notebook"""
|
|---|
| 811 | return self.notebookLayers
|
|---|
| 812 |
|
|---|
| 813 | def GetLayerTree(self):
|
|---|
| 814 | """Get current layer tree
|
|---|
| 815 |
|
|---|
| 816 | :return: LayerTree instance
|
|---|
| 817 | :return: None no layer tree selected
|
|---|
| 818 | """
|
|---|
| 819 | if self.currentPage:
|
|---|
| 820 | return self.currentPage.maptree
|
|---|
| 821 | return None
|
|---|
| 822 |
|
|---|
| 823 | def GetMapDisplay(self, onlyCurrent=True):
|
|---|
| 824 | """Get current map display
|
|---|
| 825 |
|
|---|
| 826 | :param bool onlyCurrent: True to return only active mapdisplay
|
|---|
| 827 | False for list of all mapdisplays
|
|---|
| 828 |
|
|---|
| 829 | :return: MapFrame instance (or list)
|
|---|
| 830 | :return: None no mapdisplay selected
|
|---|
| 831 | """
|
|---|
| 832 | if onlyCurrent:
|
|---|
| 833 | if self.currentPage:
|
|---|
| 834 | return self.GetLayerTree().GetMapDisplay()
|
|---|
| 835 | else:
|
|---|
| 836 | return None
|
|---|
| 837 | else: # -> return list of all mapdisplays
|
|---|
| 838 | mlist = list()
|
|---|
| 839 | for idx in range(0, self.notebookLayers.GetPageCount()):
|
|---|
| 840 | mlist.append(self.notebookLayers.GetPage(
|
|---|
| 841 | idx).maptree.GetMapDisplay())
|
|---|
| 842 |
|
|---|
| 843 | return mlist
|
|---|
| 844 |
|
|---|
| 845 | def GetAllMapDisplays(self):
|
|---|
| 846 | """Get all (open) map displays"""
|
|---|
| 847 | return self.GetMapDisplay(onlyCurrent=False)
|
|---|
| 848 |
|
|---|
| 849 | def GetLogWindow(self):
|
|---|
| 850 | """Gets console for command output and messages"""
|
|---|
| 851 | return self._gconsole
|
|---|
| 852 |
|
|---|
| 853 | def GetToolbar(self, name):
|
|---|
| 854 | """Returns toolbar if exists else None"""
|
|---|
| 855 | if name in self.toolbars:
|
|---|
| 856 | return self.toolbars[name]
|
|---|
| 857 |
|
|---|
| 858 | return None
|
|---|
| 859 |
|
|---|
| 860 | def GetMenuCmd(self, event):
|
|---|
| 861 | """Get GRASS command from menu item
|
|---|
| 862 |
|
|---|
| 863 | :return: command as a list"""
|
|---|
| 864 | layer = None
|
|---|
| 865 | if event:
|
|---|
| 866 | cmd = self.menucmd[event.GetId()]
|
|---|
| 867 | else:
|
|---|
| 868 | cmd = ''
|
|---|
| 869 |
|
|---|
| 870 | try:
|
|---|
| 871 | cmdlist = cmd.split(' ')
|
|---|
| 872 | except: # already list?
|
|---|
| 873 | cmdlist = cmd
|
|---|
| 874 |
|
|---|
| 875 | # check list of dummy commands for GUI modules that do not have GRASS
|
|---|
| 876 | # bin modules or scripts.
|
|---|
| 877 | if cmd in ['vcolors', 'r.mapcalc', 'r3.mapcalc']:
|
|---|
| 878 | return cmdlist
|
|---|
| 879 |
|
|---|
| 880 | try:
|
|---|
| 881 | layer = self.GetLayerTree().layer_selected
|
|---|
| 882 | name = self.GetLayerTree().GetLayerInfo(layer, key='maplayer').name
|
|---|
| 883 | type = self.GetLayerTree().GetLayerInfo(layer, key='type')
|
|---|
| 884 | except:
|
|---|
| 885 | layer = None
|
|---|
| 886 |
|
|---|
| 887 | if layer and len(cmdlist) == 1: # only if no parameters given
|
|---|
| 888 | if (type == 'raster' and cmdlist[0][0] == 'r' and cmdlist[0][
|
|---|
| 889 | 1] != '3') or (type == 'vector' and cmdlist[0][0] == 'v'):
|
|---|
| 890 | input = GUI().GetCommandInputMapParamKey(cmdlist[0])
|
|---|
| 891 | if input:
|
|---|
| 892 | cmdlist.append("%s=%s" % (input, name))
|
|---|
| 893 |
|
|---|
| 894 | return cmdlist
|
|---|
| 895 |
|
|---|
| 896 | def RunMenuCmd(self, event=None, cmd=[]):
|
|---|
| 897 | """Run command selected from menu"""
|
|---|
| 898 | if event:
|
|---|
| 899 | cmd = self.GetMenuCmd(event)
|
|---|
| 900 | self._gconsole.RunCmd(cmd)
|
|---|
| 901 |
|
|---|
| 902 | def OnMenuCmd(self, event=None, cmd=[]):
|
|---|
| 903 | """Parse command selected from menu"""
|
|---|
| 904 | if event:
|
|---|
| 905 | cmd = self.GetMenuCmd(event)
|
|---|
| 906 | GUI(parent=self, giface=self._giface).ParseCommand(cmd)
|
|---|
| 907 |
|
|---|
| 908 | def OnVNet(self, event):
|
|---|
| 909 | """Vector network analysis tool"""
|
|---|
| 910 | if self.GetMapDisplay():
|
|---|
| 911 | self.GetMapDisplay().OnVNet(event)
|
|---|
| 912 | else:
|
|---|
| 913 | self.NewDisplay(show=True).OnVNet(event)
|
|---|
| 914 |
|
|---|
| 915 | def OnVDigit(self, event):
|
|---|
| 916 | """Start vector digitizer
|
|---|
| 917 | """
|
|---|
| 918 | if not self.currentPage:
|
|---|
| 919 | self.MsgNoLayerSelected()
|
|---|
| 920 | return
|
|---|
| 921 |
|
|---|
| 922 | tree = self.GetLayerTree()
|
|---|
| 923 | layer = tree.layer_selected
|
|---|
| 924 | # no map layer selected
|
|---|
| 925 | if not layer:
|
|---|
| 926 | self.MsgNoLayerSelected()
|
|---|
| 927 | return
|
|---|
| 928 |
|
|---|
| 929 | # available only for vector map layers
|
|---|
| 930 | try:
|
|---|
| 931 | mapLayer = tree.GetLayerInfo(layer, key='maplayer')
|
|---|
| 932 | except:
|
|---|
| 933 | mapLayer = None
|
|---|
| 934 |
|
|---|
| 935 | if not mapLayer or mapLayer.GetType() != 'vector':
|
|---|
| 936 | GMessage(parent=self,
|
|---|
| 937 | message=_("Selected map layer is not vector."))
|
|---|
| 938 | return
|
|---|
| 939 |
|
|---|
| 940 | if mapLayer.GetMapset() != grass.gisenv()['MAPSET']:
|
|---|
| 941 | GMessage(
|
|---|
| 942 | parent=self, message=_(
|
|---|
| 943 | "Editing is allowed only for vector maps from the "
|
|---|
| 944 | "current mapset."))
|
|---|
| 945 | return
|
|---|
| 946 |
|
|---|
| 947 | if not tree.GetLayerInfo(layer):
|
|---|
| 948 | return
|
|---|
| 949 | dcmd = tree.GetLayerInfo(layer, key='cmd')
|
|---|
| 950 | if not dcmd:
|
|---|
| 951 | return
|
|---|
| 952 |
|
|---|
| 953 | digitToolbar = self.GetMapDisplay().GetToolbar('vdigit')
|
|---|
| 954 | if digitToolbar:
|
|---|
| 955 | stopOnly = False
|
|---|
| 956 | if mapLayer is digitToolbar.GetLayer():
|
|---|
| 957 | stopOnly = True
|
|---|
| 958 | tree.OnStopEditing(None) # TODO: change to signal
|
|---|
| 959 | if stopOnly:
|
|---|
| 960 | return
|
|---|
| 961 |
|
|---|
| 962 | tree.OnStartEditing(None) # TODO: change to signal
|
|---|
| 963 |
|
|---|
| 964 | def OnRunScript(self, event):
|
|---|
| 965 | """Run user-defined script"""
|
|---|
| 966 | # open dialog and choose script file
|
|---|
| 967 | dlg = wx.FileDialog(
|
|---|
| 968 | parent=self,
|
|---|
| 969 | message=_("Choose script file to run"),
|
|---|
| 970 | defaultDir=os.getcwd(),
|
|---|
| 971 | wildcard=_("Python script (*.py)|*.py|Bash script (*.sh)|*.sh"))
|
|---|
| 972 |
|
|---|
| 973 | filename = None
|
|---|
| 974 | if dlg.ShowModal() == wx.ID_OK:
|
|---|
| 975 | filename = dlg.GetPath()
|
|---|
| 976 |
|
|---|
| 977 | if not filename:
|
|---|
| 978 | return False
|
|---|
| 979 | try:
|
|---|
| 980 | filename_encoded = EncodeString(filename)
|
|---|
| 981 | except UnicodeEncodeError:
|
|---|
| 982 | GError(
|
|---|
| 983 | parent=self, message=_(
|
|---|
| 984 | "Due to the limitations of your operating system, "
|
|---|
| 985 | "the script path cannot contain certain non-ascii characters. "
|
|---|
| 986 | "Please rename the script or move it to a different location."))
|
|---|
| 987 | return
|
|---|
| 988 |
|
|---|
| 989 | if not os.path.exists(filename):
|
|---|
| 990 | GError(parent=self,
|
|---|
| 991 | message=_("Script file '%s' doesn't exist. "
|
|---|
| 992 | "Operation canceled.") % filename)
|
|---|
| 993 | return
|
|---|
| 994 |
|
|---|
| 995 | # check permission
|
|---|
| 996 | if not os.access(filename, os.X_OK):
|
|---|
| 997 | dlg = wx.MessageDialog(
|
|---|
| 998 | self,
|
|---|
| 999 | message=_(
|
|---|
| 1000 | "Script <%s> is not executable. "
|
|---|
| 1001 | "Do you want to set the permissions "
|
|---|
| 1002 | "that allows you to run this script "
|
|---|
| 1003 | "(note that you must be the owner of the file)?" %
|
|---|
| 1004 | os.path.basename(filename)),
|
|---|
| 1005 | caption=_("Set permission?"),
|
|---|
| 1006 | style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
|
|---|
| 1007 | if dlg.ShowModal() != wx.ID_YES:
|
|---|
| 1008 | return
|
|---|
| 1009 | dlg.Destroy()
|
|---|
| 1010 | try:
|
|---|
| 1011 | mode = stat.S_IMODE(os.lstat(filename)[stat.ST_MODE])
|
|---|
| 1012 | os.chmod(filename, mode | stat.S_IXUSR)
|
|---|
| 1013 | except OSError:
|
|---|
| 1014 | GError(
|
|---|
| 1015 | _("Unable to set permission. Operation canceled."),
|
|---|
| 1016 | parent=self)
|
|---|
| 1017 | return
|
|---|
| 1018 |
|
|---|
| 1019 | # check GRASS_ADDON_PATH
|
|---|
| 1020 | addonPath = os.getenv('GRASS_ADDON_PATH', [])
|
|---|
| 1021 | if addonPath:
|
|---|
| 1022 | addonPath = addonPath.split(os.pathsep)
|
|---|
| 1023 | dirName = os.path.dirname(filename_encoded)
|
|---|
| 1024 | if dirName not in addonPath:
|
|---|
| 1025 | addonPath.append(dirName)
|
|---|
| 1026 | dlg = wx.MessageDialog(
|
|---|
| 1027 | self,
|
|---|
| 1028 | message=_(
|
|---|
| 1029 | "Directory '%s' is not defined in GRASS_ADDON_PATH. "
|
|---|
| 1030 | "Do you want add this directory to GRASS_ADDON_PATH?") %
|
|---|
| 1031 | dirName, caption=_("Update Addons path?"),
|
|---|
| 1032 | style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
|
|---|
| 1033 | if dlg.ShowModal() == wx.ID_YES:
|
|---|
| 1034 | SetAddOnPath(os.pathsep.join(addonPath), key='PATH')
|
|---|
| 1035 | dlg.Destroy()
|
|---|
| 1036 |
|
|---|
| 1037 | self._gconsole.WriteCmdLog(_("Launching script '%s'...") % filename)
|
|---|
| 1038 | self._gconsole.RunCmd([filename])
|
|---|
| 1039 |
|
|---|
| 1040 | def OnChangeLocation(self, event):
|
|---|
| 1041 | """Change current location"""
|
|---|
| 1042 | dlg = LocationDialog(parent=self)
|
|---|
| 1043 | if dlg.ShowModal() == wx.ID_OK:
|
|---|
| 1044 | location, mapset = dlg.GetValues()
|
|---|
| 1045 | dlg.Destroy()
|
|---|
| 1046 |
|
|---|
| 1047 | if not location or not mapset:
|
|---|
| 1048 | GError(
|
|---|
| 1049 | parent=self,
|
|---|
| 1050 | message=_(
|
|---|
| 1051 | "No location/mapset provided. Operation canceled."))
|
|---|
| 1052 | return # this should not happen
|
|---|
| 1053 | self.ChangeLocation(location, mapset)
|
|---|
| 1054 |
|
|---|
| 1055 | def ChangeLocation(self, location, mapset):
|
|---|
| 1056 | if RunCommand('g.mapset', parent=self,
|
|---|
| 1057 | location=location,
|
|---|
| 1058 | mapset=mapset) != 0:
|
|---|
| 1059 | return # error reported
|
|---|
| 1060 |
|
|---|
| 1061 | # close current workspace and create new one
|
|---|
| 1062 | self.OnWorkspaceClose()
|
|---|
| 1063 | self.OnWorkspaceNew()
|
|---|
| 1064 | GMessage(parent=self,
|
|---|
| 1065 | message=_("Current location is <%(loc)s>.\n"
|
|---|
| 1066 | "Current mapset is <%(mapset)s>.") %
|
|---|
| 1067 | {'loc': location, 'mapset': mapset})
|
|---|
| 1068 |
|
|---|
| 1069 | def OnCreateMapset(self, event):
|
|---|
| 1070 | """Create new mapset"""
|
|---|
| 1071 | dlg = wx.TextEntryDialog(parent=self,
|
|---|
| 1072 | message=_('Enter name for new mapset:'),
|
|---|
| 1073 | caption=_('Create new mapset'))
|
|---|
| 1074 |
|
|---|
| 1075 | if dlg.ShowModal() == wx.ID_OK:
|
|---|
| 1076 | mapset = dlg.GetValue()
|
|---|
| 1077 | if not mapset:
|
|---|
| 1078 | GError(parent=self,
|
|---|
| 1079 | message=_("No mapset provided. Operation canceled."))
|
|---|
| 1080 | return
|
|---|
| 1081 |
|
|---|
| 1082 | ret = RunCommand('g.mapset',
|
|---|
| 1083 | parent=self,
|
|---|
| 1084 | flags='c',
|
|---|
| 1085 | mapset=mapset)
|
|---|
| 1086 | # ensure that DB connection is defined
|
|---|
| 1087 | ret += RunCommand('db.connect',
|
|---|
| 1088 | parent=self,
|
|---|
| 1089 | flags='c')
|
|---|
| 1090 | if ret == 0:
|
|---|
| 1091 | GMessage(parent=self,
|
|---|
| 1092 | message=_("Current mapset is <%s>.") % mapset)
|
|---|
| 1093 |
|
|---|
| 1094 | def OnChangeMapset(self, event):
|
|---|
| 1095 | """Change current mapset"""
|
|---|
| 1096 | dlg = MapsetDialog(parent=self)
|
|---|
| 1097 |
|
|---|
| 1098 | if dlg.ShowModal() == wx.ID_OK:
|
|---|
| 1099 | mapset = dlg.GetMapset()
|
|---|
| 1100 | dlg.Destroy()
|
|---|
| 1101 |
|
|---|
| 1102 | if not mapset:
|
|---|
| 1103 | GError(parent=self,
|
|---|
| 1104 | message=_("No mapset provided. Operation canceled."))
|
|---|
| 1105 | return
|
|---|
| 1106 | self.ChangeMapset(mapset)
|
|---|
| 1107 |
|
|---|
| 1108 | def ChangeMapset(self, mapset):
|
|---|
| 1109 | """Change current mapset and update map display title"""
|
|---|
| 1110 | if RunCommand('g.mapset',
|
|---|
| 1111 | parent=self,
|
|---|
| 1112 | mapset=mapset) == 0:
|
|---|
| 1113 | GMessage(parent=self,
|
|---|
| 1114 | message=_("Current mapset is <%s>.") % mapset)
|
|---|
| 1115 |
|
|---|
| 1116 | # TODO: this does not use the actual names if they were
|
|---|
| 1117 | # renamed (it just uses the numbers)
|
|---|
| 1118 | dispId = 1
|
|---|
| 1119 | for display in self.GetMapDisplay(onlyCurrent=False):
|
|---|
| 1120 | display.SetTitleWithName(str(dispId)) # TODO: signal ?
|
|---|
| 1121 | dispId += 1
|
|---|
| 1122 |
|
|---|
| 1123 | def OnChangeCWD(self, event=None, cmd=None):
|
|---|
| 1124 | """Change current working directory
|
|---|
| 1125 |
|
|---|
| 1126 | :param event: to be able to serve as a handler of wx event
|
|---|
| 1127 | :param cmd: command as a list (must start with 'cd')
|
|---|
| 1128 | """
|
|---|
| 1129 | # local functions
|
|---|
| 1130 | def write_beginning(parameter=None, command=None):
|
|---|
| 1131 | if parameter:
|
|---|
| 1132 | self._giface.WriteCmdLog('cd "' + parameter + '"')
|
|---|
| 1133 | else:
|
|---|
| 1134 | # naive concat but will be enough most of the time
|
|---|
| 1135 | self._giface.WriteCmdLog(' '.join(command))
|
|---|
| 1136 |
|
|---|
| 1137 | def write_changed():
|
|---|
| 1138 | self._giface.WriteLog(_("Working directory changed to:\n\"%s\"")
|
|---|
| 1139 | % os.getcwd())
|
|---|
| 1140 |
|
|---|
| 1141 | def write_end():
|
|---|
| 1142 | self._giface.WriteCmdLog(' ')
|
|---|
| 1143 |
|
|---|
| 1144 | def write_help():
|
|---|
| 1145 | self._giface.WriteLog(_("Changes current working directory"
|
|---|
| 1146 | " for this GUI."))
|
|---|
| 1147 | self._giface.WriteLog(_("Usage: cd [directory]"))
|
|---|
| 1148 | self._giface.WriteLog(_("Without parameters it opens a dialog."))
|
|---|
| 1149 | # TODO: the following is longer then 80 chars
|
|---|
| 1150 | # but this should be solved by the function not caller
|
|---|
| 1151 | # also because of translations
|
|---|
| 1152 | self._giface.WriteLog(_("If ~ (tilde) is present as the first"
|
|---|
| 1153 | " directory on the path, it is replaced"
|
|---|
| 1154 | " by user's home directory."))
|
|---|
| 1155 |
|
|---|
| 1156 | # check correctness of cmd
|
|---|
| 1157 | if cmd and cmd[0] != 'cd':
|
|---|
| 1158 | # this is programmer's error
|
|---|
| 1159 | # can be relaxed in future
|
|---|
| 1160 | # but keep it strict unless needed otherwise
|
|---|
| 1161 | raise ValueError("OnChangeCWD cmd parameter must be list of"
|
|---|
| 1162 | " length 1 or 2 and 'cd' as a first item")
|
|---|
| 1163 | if cmd and len(cmd) > 2:
|
|---|
| 1164 | # this might be a user error
|
|---|
| 1165 | write_beginning(command=cmd)
|
|---|
| 1166 | self._giface.WriteError(_("More than one parameter provided."))
|
|---|
| 1167 | write_help()
|
|---|
| 1168 | write_end()
|
|---|
| 1169 | return
|
|---|
| 1170 | # use chdir or dialog
|
|---|
| 1171 | if cmd and len(cmd) == 2:
|
|---|
| 1172 | write_beginning(parameter=cmd[1])
|
|---|
| 1173 | if cmd[1] in ['-h', '--h', '--help', 'help']:
|
|---|
| 1174 | write_help()
|
|---|
| 1175 | write_end()
|
|---|
| 1176 | return
|
|---|
| 1177 | try:
|
|---|
| 1178 | path = os.path.expanduser(cmd[1])
|
|---|
| 1179 | os.chdir(path)
|
|---|
| 1180 | write_changed()
|
|---|
| 1181 | except OSError as error:
|
|---|
| 1182 | self._giface.WriteError(str(error))
|
|---|
| 1183 | write_end()
|
|---|
| 1184 | else:
|
|---|
| 1185 | dlg = wx.DirDialog(parent=self,
|
|---|
| 1186 | message=_("Choose a working directory"),
|
|---|
| 1187 | defaultPath=os.getcwd())
|
|---|
| 1188 |
|
|---|
| 1189 | if dlg.ShowModal() == wx.ID_OK:
|
|---|
| 1190 | self.cwdPath = dlg.GetPath() # is saved in the workspace
|
|---|
| 1191 | write_beginning(parameter=self.cwdPath)
|
|---|
| 1192 | os.chdir(self.cwdPath)
|
|---|
| 1193 | write_changed()
|
|---|
| 1194 | write_end()
|
|---|
| 1195 |
|
|---|
| 1196 | def GetCwdPath(self):
|
|---|
| 1197 | """Get current working directory or None"""
|
|---|
| 1198 | return self.cwdPath
|
|---|
| 1199 |
|
|---|
| 1200 | def OnNewVector(self, event):
|
|---|
| 1201 | """Create new vector map layer"""
|
|---|
| 1202 | dlg = CreateNewVector(self, giface=self._giface,
|
|---|
| 1203 | cmd=(('v.edit',
|
|---|
| 1204 | {'tool': 'create'},
|
|---|
| 1205 | 'map')))
|
|---|
| 1206 |
|
|---|
| 1207 | if not dlg:
|
|---|
| 1208 | return
|
|---|
| 1209 |
|
|---|
| 1210 | name = dlg.GetName(full=True)
|
|---|
| 1211 | if name and dlg.IsChecked('add'):
|
|---|
| 1212 | # add layer to map layer tree
|
|---|
| 1213 | self.GetLayerTree().AddLayer(ltype='vector',
|
|---|
| 1214 | lname=name, lchecked=True,
|
|---|
| 1215 | lcmd=['d.vect', 'map=%s' % name])
|
|---|
| 1216 | dlg.Destroy()
|
|---|
| 1217 |
|
|---|
| 1218 | def OnSystemInfo(self, event):
|
|---|
| 1219 | """Print system information"""
|
|---|
| 1220 | vInfo = grass.version()
|
|---|
| 1221 | if not vInfo:
|
|---|
| 1222 | sys.stderr.write(_("Unable to get GRASS version\n"))
|
|---|
| 1223 |
|
|---|
| 1224 | # check also OSGeo4W on MS Windows
|
|---|
| 1225 | if sys.platform == 'win32' and not os.path.exists(
|
|---|
| 1226 | os.path.join(os.getenv("GISBASE"), "WinGRASS-README.url")):
|
|---|
| 1227 | osgeo4w = ' (OSGeo4W)'
|
|---|
| 1228 | else:
|
|---|
| 1229 | osgeo4w = ''
|
|---|
| 1230 |
|
|---|
| 1231 | self._gconsole.WriteCmdLog(_("System Info"))
|
|---|
| 1232 | # platform decoding was added because of the Fedora 19 release
|
|---|
| 1233 | # which has the name "Schrödinger’s cat" (umlaut and special ' character)
|
|---|
| 1234 | # which appears in the platform.platform() string
|
|---|
| 1235 | platform_ = decode(platform.platform())
|
|---|
| 1236 | self._gconsole.WriteLog("%s: %s\n"
|
|---|
| 1237 | "%s: %s\n"
|
|---|
| 1238 | "%s: %s\n"
|
|---|
| 1239 | "%s: %s\n"
|
|---|
| 1240 | # "%s: %s (%s)\n"
|
|---|
| 1241 | "GDAL: %s\n"
|
|---|
| 1242 | "PROJ.4: %s\n"
|
|---|
| 1243 | "GEOS: %s\n"
|
|---|
| 1244 | "SQLite: %s\n"
|
|---|
| 1245 | "Python: %s\n"
|
|---|
| 1246 | "wxPython: %s\n"
|
|---|
| 1247 | "%s: %s%s\n" % (_("GRASS version"), vInfo.get('version', _('unknown version')),
|
|---|
| 1248 | _("GRASS SVN revision"), vInfo.get(
|
|---|
| 1249 | 'revision', '?'),
|
|---|
| 1250 | _("Build date"), vInfo.get(
|
|---|
| 1251 | 'build_date', '?'),
|
|---|
| 1252 | _("Build platform"), vInfo.get(
|
|---|
| 1253 | 'build_platform', '?'),
|
|---|
| 1254 | # _("GIS Library Revision"),
|
|---|
| 1255 | # vInfo.get('libgis_revision'],
|
|---|
| 1256 | # vInfo.get('libgis_date'].split('
|
|---|
| 1257 | # ', 1)[0],
|
|---|
| 1258 | vInfo.get(
|
|---|
| 1259 | 'gdal', '?'), vInfo.get(
|
|---|
| 1260 | 'proj4', '?'), vInfo.get(
|
|---|
| 1261 | 'geos', '?'), vInfo.get(
|
|---|
| 1262 | 'sqlite', '?'),
|
|---|
| 1263 | platform.python_version(),
|
|---|
| 1264 | wx.__version__,
|
|---|
| 1265 | _("Platform"), platform_, osgeo4w),
|
|---|
| 1266 | notification=Notification.MAKE_VISIBLE)
|
|---|
| 1267 | self._gconsole.WriteCmdLog(' ')
|
|---|
| 1268 |
|
|---|
| 1269 | def OnAboutGRASS(self, event):
|
|---|
| 1270 | """Display 'About GRASS' dialog"""
|
|---|
| 1271 | from gui_core.ghelp import AboutWindow
|
|---|
| 1272 | win = AboutWindow(self)
|
|---|
| 1273 | win.CentreOnScreen()
|
|---|
| 1274 | win.Show(True)
|
|---|
| 1275 |
|
|---|
| 1276 | def _popupMenu(self, data):
|
|---|
| 1277 | """Create popup menu
|
|---|
| 1278 | """
|
|---|
| 1279 | menu = Menu()
|
|---|
| 1280 |
|
|---|
| 1281 | for key, handler in data:
|
|---|
| 1282 | if key is None:
|
|---|
| 1283 | menu.AppendSeparator()
|
|---|
| 1284 | continue
|
|---|
| 1285 | item = wx.MenuItem(menu, wx.ID_ANY, LMIcons[key].GetLabel())
|
|---|
| 1286 | item.SetBitmap(LMIcons[key].GetBitmap(self.iconsize))
|
|---|
| 1287 | menu.AppendItem(item)
|
|---|
| 1288 | self.Bind(wx.EVT_MENU, handler, item)
|
|---|
| 1289 |
|
|---|
| 1290 | # create menu
|
|---|
| 1291 | self.PopupMenu(menu)
|
|---|
| 1292 | menu.Destroy()
|
|---|
| 1293 |
|
|---|
| 1294 | def OnImportMenu(self, event):
|
|---|
| 1295 | """Import maps menu (import, link)
|
|---|
| 1296 | """
|
|---|
| 1297 | self._popupMenu((('rastImport', self.OnImportGdalLayers),
|
|---|
| 1298 | ('vectImport', self.OnImportOgrLayers),
|
|---|
| 1299 | (None, None),
|
|---|
| 1300 | ('rastUnpack', self.OnUnpackRaster),
|
|---|
| 1301 | ('vectUnpack', self.OnUnpackVector),
|
|---|
| 1302 | (None, None),
|
|---|
| 1303 | ('rastLink', self.OnLinkGdalLayers),
|
|---|
| 1304 | ('vectLink', self.OnLinkOgrLayers),
|
|---|
| 1305 | ('rastOut', self.OnRasterOutputFormat),
|
|---|
| 1306 | ('vectOut', self.OnVectorOutputFormat)))
|
|---|
| 1307 |
|
|---|
| 1308 | def OnWorkspaceNew(self, event=None):
|
|---|
| 1309 | """Create new workspace file
|
|---|
| 1310 |
|
|---|
| 1311 | Erase current workspace settings first
|
|---|
| 1312 | """
|
|---|
| 1313 | Debug.msg(4, "GMFrame.OnWorkspaceNew():")
|
|---|
| 1314 |
|
|---|
| 1315 | # start new map display if no display is available
|
|---|
| 1316 | if not self.currentPage:
|
|---|
| 1317 | self.NewDisplay()
|
|---|
| 1318 |
|
|---|
| 1319 | maptrees = [self.notebookLayers.GetPage(i).maptree for i in range(self.notebookLayers.GetPageCount())]
|
|---|
| 1320 |
|
|---|
| 1321 | # ask user to save current settings
|
|---|
| 1322 | if self.workspaceFile and self.workspaceChanged:
|
|---|
| 1323 | self.OnWorkspaceSave()
|
|---|
| 1324 | elif self.workspaceFile is None and any(tree.GetCount() for tree in maptrees):
|
|---|
| 1325 | dlg = wx.MessageDialog(
|
|---|
| 1326 | self,
|
|---|
| 1327 | message=_(
|
|---|
| 1328 | "Current workspace is not empty. "
|
|---|
| 1329 | "Do you want to store current settings "
|
|---|
| 1330 | "to workspace file?"),
|
|---|
| 1331 | caption=_("Create new workspace?"),
|
|---|
| 1332 | style=wx.YES_NO | wx.YES_DEFAULT | wx.CANCEL | wx.ICON_QUESTION)
|
|---|
| 1333 | ret = dlg.ShowModal()
|
|---|
| 1334 | if ret == wx.ID_YES:
|
|---|
| 1335 | self.OnWorkspaceSaveAs()
|
|---|
| 1336 | elif ret == wx.ID_CANCEL:
|
|---|
| 1337 | dlg.Destroy()
|
|---|
| 1338 | return
|
|---|
| 1339 |
|
|---|
| 1340 | dlg.Destroy()
|
|---|
| 1341 |
|
|---|
| 1342 | # delete all layers in map displays
|
|---|
| 1343 | for maptree in maptrees:
|
|---|
| 1344 | maptree.DeleteAllLayers()
|
|---|
| 1345 |
|
|---|
| 1346 | # delete all decorations
|
|---|
| 1347 | for display in self.GetAllMapDisplays():
|
|---|
| 1348 | for overlayId in display.decorations.keys():
|
|---|
| 1349 | display.RemoveOverlay(overlayId)
|
|---|
| 1350 |
|
|---|
| 1351 | # no workspace file loaded
|
|---|
| 1352 | self.workspaceFile = None
|
|---|
| 1353 | self.workspaceChanged = False
|
|---|
| 1354 | self._setTitle()
|
|---|
| 1355 |
|
|---|
| 1356 | def OnWorkspaceOpen(self, event=None):
|
|---|
| 1357 | """Open file with workspace definition"""
|
|---|
| 1358 | dlg = wx.FileDialog(
|
|---|
| 1359 | parent=self,
|
|---|
| 1360 | message=_("Choose workspace file"),
|
|---|
| 1361 | defaultDir=os.getcwd(),
|
|---|
| 1362 | wildcard=_("GRASS Workspace File (*.gxw)|*.gxw"))
|
|---|
| 1363 |
|
|---|
| 1364 | filename = ''
|
|---|
| 1365 | if dlg.ShowModal() == wx.ID_OK:
|
|---|
| 1366 | filename = dlg.GetPath()
|
|---|
| 1367 |
|
|---|
| 1368 | if filename == '':
|
|---|
| 1369 | return
|
|---|
| 1370 |
|
|---|
| 1371 | Debug.msg(4, "GMFrame.OnWorkspaceOpen(): filename=%s" % filename)
|
|---|
| 1372 |
|
|---|
| 1373 | # delete current layer tree content
|
|---|
| 1374 | self.OnWorkspaceClose()
|
|---|
| 1375 | self.loadingWorkspace = True
|
|---|
| 1376 | self.LoadWorkspaceFile(filename)
|
|---|
| 1377 | self.loadingWorkspace = False
|
|---|
| 1378 |
|
|---|
| 1379 | self.workspaceFile = filename
|
|---|
| 1380 | self._setTitle()
|
|---|
| 1381 |
|
|---|
| 1382 | def _tryToSwitchMapsetFromWorkspaceFile(self, gxwXml):
|
|---|
| 1383 | returncode, errors = RunCommand('g.mapset',
|
|---|
| 1384 | dbase=gxwXml.database,
|
|---|
| 1385 | location=gxwXml.location,
|
|---|
| 1386 | mapset=gxwXml.mapset,
|
|---|
| 1387 | getErrorMsg=True,
|
|---|
| 1388 | )
|
|---|
| 1389 | if returncode != 0:
|
|---|
| 1390 | # TODO: use the function from grass.py
|
|---|
| 1391 | reason = _("Most likely the database, location or mapset"
|
|---|
| 1392 | " does not exist")
|
|---|
| 1393 | details = errors
|
|---|
| 1394 | message = _("Unable to change to location and mapset"
|
|---|
| 1395 | " specified in the workspace.\n"
|
|---|
| 1396 | "Reason: {reason}\nDetails: {details}\n\n"
|
|---|
| 1397 | "Do you want to proceed with opening"
|
|---|
| 1398 | " the workspace anyway?"
|
|---|
| 1399 | ).format(**locals())
|
|---|
| 1400 | dlg = wx.MessageDialog(
|
|---|
| 1401 | parent=self, message=message, caption=_(
|
|---|
| 1402 | "Proceed with opening of the workspace?"),
|
|---|
| 1403 | style=wx.YES_NO | wx.NO_DEFAULT | wx.ICON_QUESTION)
|
|---|
| 1404 | dlg.CenterOnParent()
|
|---|
| 1405 | if dlg.ShowModal() in [wx.ID_NO, wx.ID_CANCEL]:
|
|---|
| 1406 | return False
|
|---|
| 1407 | else:
|
|---|
| 1408 | # TODO: copy from ChangeLocation function
|
|---|
| 1409 | GMessage(
|
|---|
| 1410 | parent=self,
|
|---|
| 1411 | message=_("Current location is <%(loc)s>.\n"
|
|---|
| 1412 | "Current mapset is <%(mapset)s>.") %
|
|---|
| 1413 | {'loc': gxwXml.location,
|
|---|
| 1414 | 'mapset': gxwXml.mapset})
|
|---|
| 1415 | return True
|
|---|
| 1416 |
|
|---|
| 1417 | def LoadWorkspaceFile(self, filename):
|
|---|
| 1418 | """Load layer tree definition stored in GRASS Workspace XML file (gxw)
|
|---|
| 1419 |
|
|---|
| 1420 | .. todo::
|
|---|
| 1421 | Validate against DTD
|
|---|
| 1422 |
|
|---|
| 1423 | :return: True on success
|
|---|
| 1424 | :return: False on error
|
|---|
| 1425 | """
|
|---|
| 1426 | # parse workspace file
|
|---|
| 1427 | try:
|
|---|
| 1428 | gxwXml = ProcessWorkspaceFile(etree.parse(filename))
|
|---|
| 1429 | except Exception as e:
|
|---|
| 1430 | GError(
|
|---|
| 1431 | parent=self, message=_(
|
|---|
| 1432 | "Reading workspace file <%s> failed.\n"
|
|---|
| 1433 | "Invalid file, unable to parse XML document.") %
|
|---|
| 1434 | filename)
|
|---|
| 1435 | return False
|
|---|
| 1436 |
|
|---|
| 1437 | if gxwXml.database and gxwXml.location and gxwXml.mapset:
|
|---|
| 1438 | if not self._tryToSwitchMapsetFromWorkspaceFile(gxwXml):
|
|---|
| 1439 | return False
|
|---|
| 1440 |
|
|---|
| 1441 | # the really busy part starts here (mapset change is fast)
|
|---|
| 1442 | busy = wx.BusyInfo(_("Please wait, loading workspace..."),
|
|---|
| 1443 | parent=self)
|
|---|
| 1444 | wx.Yield()
|
|---|
| 1445 |
|
|---|
| 1446 | #
|
|---|
| 1447 | # load layer manager window properties
|
|---|
| 1448 | #
|
|---|
| 1449 | if UserSettings.Get(group='general', key='workspace', subkey=[
|
|---|
| 1450 | 'posManager', 'enabled']) is False:
|
|---|
| 1451 | if gxwXml.layerManager['pos']:
|
|---|
| 1452 | self.SetPosition(gxwXml.layerManager['pos'])
|
|---|
| 1453 | if gxwXml.layerManager['size']:
|
|---|
| 1454 | self.SetSize(gxwXml.layerManager['size'])
|
|---|
| 1455 | if gxwXml.layerManager['cwd']:
|
|---|
| 1456 | self.cwdPath = gxwXml.layerManager['cwd']
|
|---|
| 1457 | if os.path.isdir(self.cwdPath):
|
|---|
| 1458 | os.chdir(self.cwdPath)
|
|---|
| 1459 |
|
|---|
| 1460 | #
|
|---|
| 1461 | # start map displays first (list of layers can be empty)
|
|---|
| 1462 | #
|
|---|
| 1463 | displayId = 0
|
|---|
| 1464 | mapdisplay = list()
|
|---|
| 1465 | for display in gxwXml.displays:
|
|---|
| 1466 | mapdisp = self.NewDisplay(name=display['name'], show=False)
|
|---|
| 1467 | mapdisplay.append(mapdisp)
|
|---|
| 1468 | maptree = self.notebookLayers.GetPage(displayId).maptree
|
|---|
| 1469 |
|
|---|
| 1470 | # set windows properties
|
|---|
| 1471 | mapdisp.SetProperties(render=display['render'],
|
|---|
| 1472 | mode=display['mode'],
|
|---|
| 1473 | showCompExtent=display['showCompExtent'],
|
|---|
| 1474 | alignExtent=display['alignExtent'],
|
|---|
| 1475 | constrainRes=display['constrainRes'],
|
|---|
| 1476 | projection=display['projection']['enabled'])
|
|---|
| 1477 |
|
|---|
| 1478 | if display['projection']['enabled']:
|
|---|
| 1479 | if display['projection']['epsg']:
|
|---|
| 1480 | UserSettings.Set(
|
|---|
| 1481 | group='display',
|
|---|
| 1482 | key='projection',
|
|---|
| 1483 | subkey='epsg',
|
|---|
| 1484 | value=display['projection']['epsg'])
|
|---|
| 1485 | if display['projection']['proj']:
|
|---|
| 1486 | UserSettings.Set(
|
|---|
| 1487 | group='display',
|
|---|
| 1488 | key='projection',
|
|---|
| 1489 | subkey='proj4',
|
|---|
| 1490 | value=display['projection']['proj'])
|
|---|
| 1491 |
|
|---|
| 1492 | # set position and size of map display
|
|---|
| 1493 | if not UserSettings.Get(
|
|---|
| 1494 | group='general', key='workspace',
|
|---|
| 1495 | subkey=['posDisplay', 'enabled']):
|
|---|
| 1496 | if display['pos']:
|
|---|
| 1497 | mapdisp.SetPosition(display['pos'])
|
|---|
| 1498 | if display['size']:
|
|---|
| 1499 | mapdisp.SetSize(display['size'])
|
|---|
| 1500 |
|
|---|
| 1501 | # set extent if defined
|
|---|
| 1502 | if display['extent']:
|
|---|
| 1503 | w, s, e, n, b, t = display['extent']
|
|---|
| 1504 | region = maptree.Map.region = maptree.Map.GetRegion(
|
|---|
| 1505 | w=w, s=s, e=e, n=n)
|
|---|
| 1506 | mapdisp.GetWindow().ResetZoomHistory()
|
|---|
| 1507 | mapdisp.GetWindow().ZoomHistory(region['n'],
|
|---|
| 1508 | region['s'],
|
|---|
| 1509 | region['e'],
|
|---|
| 1510 | region['w'])
|
|---|
| 1511 | if 'showStatusbar' in display and not display['showStatusbar']:
|
|---|
| 1512 | mapdisp.statusbarManager.Show(False)
|
|---|
| 1513 | if 'showToolbars' in display and not display['showToolbars']:
|
|---|
| 1514 | for toolbar in mapdisp.GetToolbarNames():
|
|---|
| 1515 | mapdisp.RemoveToolbar(toolbar)
|
|---|
| 1516 |
|
|---|
| 1517 | displayId += 1
|
|---|
| 1518 | mapdisp.Show() # show mapdisplay
|
|---|
| 1519 | # set render property to False to speed up loading layers
|
|---|
| 1520 | mapdisp.mapWindowProperties.autoRender = False
|
|---|
| 1521 |
|
|---|
| 1522 | maptree = None
|
|---|
| 1523 | selectList = [] # list of selected layers
|
|---|
| 1524 | #
|
|---|
| 1525 | # load list of map layers
|
|---|
| 1526 | #
|
|---|
| 1527 | for layer in gxwXml.layers:
|
|---|
| 1528 | display = layer['display']
|
|---|
| 1529 | maptree = self.notebookLayers.GetPage(display).maptree
|
|---|
| 1530 | newItem = maptree.AddLayer(ltype=layer['type'],
|
|---|
| 1531 | lname=layer['name'],
|
|---|
| 1532 | lchecked=layer['checked'],
|
|---|
| 1533 | lopacity=layer['opacity'],
|
|---|
| 1534 | lcmd=layer['cmd'],
|
|---|
| 1535 | lgroup=layer['group'],
|
|---|
| 1536 | lnviz=layer['nviz'],
|
|---|
| 1537 | lvdigit=layer['vdigit'],
|
|---|
| 1538 | loadWorkspace=True)
|
|---|
| 1539 |
|
|---|
| 1540 | if 'selected' in layer:
|
|---|
| 1541 | selectList.append((maptree, newItem, layer['selected']))
|
|---|
| 1542 |
|
|---|
| 1543 | for maptree, layer, selected in selectList:
|
|---|
| 1544 | if selected:
|
|---|
| 1545 | if not layer.IsSelected():
|
|---|
| 1546 | maptree.SelectItem(layer, select=True)
|
|---|
| 1547 | else:
|
|---|
| 1548 | maptree.SelectItem(layer, select=False)
|
|---|
| 1549 |
|
|---|
| 1550 | del busy
|
|---|
| 1551 |
|
|---|
| 1552 | # set render property again when all layers are loaded
|
|---|
| 1553 | for i, display in enumerate(gxwXml.displays):
|
|---|
| 1554 | mapdisplay[i].mapWindowProperties.autoRender = display['render']
|
|---|
| 1555 |
|
|---|
| 1556 | for overlay in gxwXml.overlays:
|
|---|
| 1557 | # overlay["cmd"][0] name of command e.g. d.barscale, d.legend
|
|---|
| 1558 | # overlay["cmd"][1:] parameters and flags
|
|---|
| 1559 | if overlay['display'] == i:
|
|---|
| 1560 | if overlay['cmd'][0] == "d.legend.vect":
|
|---|
| 1561 | mapdisplay[i].AddLegendVect(overlay['cmd'])
|
|---|
| 1562 | if overlay['cmd'][0] == "d.legend":
|
|---|
| 1563 | mapdisplay[i].AddLegendRast(overlay['cmd'])
|
|---|
| 1564 | if overlay['cmd'][0] == "d.barscale":
|
|---|
| 1565 | mapdisplay[i].AddBarscale(overlay['cmd'])
|
|---|
| 1566 | if overlay['cmd'][0] == "d.northarrow":
|
|---|
| 1567 | mapdisplay[i].AddArrow(overlay['cmd'])
|
|---|
| 1568 | if overlay['cmd'][0] == "d.text":
|
|---|
| 1569 | mapdisplay[i].AddDtext(overlay['cmd'])
|
|---|
| 1570 |
|
|---|
| 1571 | # avoid double-rendering when loading workspace
|
|---|
| 1572 | # mdisp.MapWindow2D.UpdateMap()
|
|---|
| 1573 | # nviz
|
|---|
| 1574 | if gxwXml.displays[i]['viewMode'] == '3d':
|
|---|
| 1575 | mapdisplay[i].AddNviz()
|
|---|
| 1576 | self.nviz.UpdateState(view=gxwXml.nviz_state['view'],
|
|---|
| 1577 | iview=gxwXml.nviz_state['iview'],
|
|---|
| 1578 | light=gxwXml.nviz_state['light'])
|
|---|
| 1579 | mapdisplay[i].MapWindow3D.constants = gxwXml.nviz_state['constants']
|
|---|
| 1580 | for idx, constant in enumerate(mapdisplay[i].MapWindow3D.constants):
|
|---|
| 1581 | mapdisplay[i].MapWindow3D.AddConstant(constant, i + 1)
|
|---|
| 1582 | for page in ('view', 'light', 'fringe', 'constant', 'cplane'):
|
|---|
| 1583 | self.nviz.UpdatePage(page)
|
|---|
| 1584 | self.nviz.UpdateSettings()
|
|---|
| 1585 | mapdisplay[i].toolbars['map'].combo.SetSelection(1)
|
|---|
| 1586 |
|
|---|
| 1587 | return True
|
|---|
| 1588 |
|
|---|
| 1589 | def OnWorkspaceLoadGrcFile(self, event):
|
|---|
| 1590 | """Load map layers from GRC file (Tcl/Tk GUI) into map layer tree"""
|
|---|
| 1591 | dlg = wx.FileDialog(
|
|---|
| 1592 | parent=self,
|
|---|
| 1593 | message=_("Choose GRC file to load"),
|
|---|
| 1594 | defaultDir=os.getcwd(),
|
|---|
| 1595 | wildcard=_("Old GRASS Workspace File (*.grc)|*.grc"))
|
|---|
| 1596 |
|
|---|
| 1597 | filename = ''
|
|---|
| 1598 | if dlg.ShowModal() == wx.ID_OK:
|
|---|
| 1599 | filename = dlg.GetPath()
|
|---|
| 1600 |
|
|---|
| 1601 | if filename == '':
|
|---|
| 1602 | return
|
|---|
| 1603 |
|
|---|
| 1604 | Debug.msg(
|
|---|
| 1605 | 4,
|
|---|
| 1606 | "GMFrame.OnWorkspaceLoadGrcFile(): filename=%s" %
|
|---|
| 1607 | filename)
|
|---|
| 1608 |
|
|---|
| 1609 | # start new map display if no display is available
|
|---|
| 1610 | if not self.currentPage:
|
|---|
| 1611 | self.NewDisplay()
|
|---|
| 1612 |
|
|---|
| 1613 | busy = wx.BusyInfo(_("Please wait, loading workspace..."),
|
|---|
| 1614 | parent=self)
|
|---|
| 1615 | wx.Yield()
|
|---|
| 1616 |
|
|---|
| 1617 | maptree = None
|
|---|
| 1618 | for layer in ProcessGrcFile(filename).read(self):
|
|---|
| 1619 | maptree = self.notebookLayers.GetPage(layer['display']).maptree
|
|---|
| 1620 | newItem = maptree.AddLayer(ltype=layer['type'],
|
|---|
| 1621 | lname=layer['name'],
|
|---|
| 1622 | lchecked=layer['checked'],
|
|---|
| 1623 | lopacity=layer['opacity'],
|
|---|
| 1624 | lcmd=layer['cmd'],
|
|---|
| 1625 | lgroup=layer['group'])
|
|---|
| 1626 |
|
|---|
| 1627 | del busy
|
|---|
| 1628 |
|
|---|
| 1629 | if maptree:
|
|---|
| 1630 | # reverse list of map layers
|
|---|
| 1631 | maptree.Map.ReverseListOfLayers()
|
|---|
| 1632 |
|
|---|
| 1633 | def OnWorkspaceSaveAs(self, event=None):
|
|---|
| 1634 | """Save workspace definition to selected file"""
|
|---|
| 1635 | dlg = wx.FileDialog(
|
|---|
| 1636 | parent=self,
|
|---|
| 1637 | message=_("Choose file to save current workspace"),
|
|---|
| 1638 | defaultDir=os.getcwd(),
|
|---|
| 1639 | wildcard=_("GRASS Workspace File (*.gxw)|*.gxw"),
|
|---|
| 1640 | style=wx.FD_SAVE)
|
|---|
| 1641 |
|
|---|
| 1642 | filename = ''
|
|---|
| 1643 | if dlg.ShowModal() == wx.ID_OK:
|
|---|
| 1644 | filename = dlg.GetPath()
|
|---|
| 1645 |
|
|---|
| 1646 | if filename == '':
|
|---|
| 1647 | return False
|
|---|
| 1648 |
|
|---|
| 1649 | # check for extension
|
|---|
| 1650 | if filename[-4:] != ".gxw":
|
|---|
| 1651 | filename += ".gxw"
|
|---|
| 1652 |
|
|---|
| 1653 | if os.path.exists(filename):
|
|---|
| 1654 | dlg = wx.MessageDialog(
|
|---|
| 1655 | self,
|
|---|
| 1656 | message=_(
|
|---|
| 1657 | "Workspace file <%s> already exists. "
|
|---|
| 1658 | "Do you want to overwrite this file?") %
|
|---|
| 1659 | filename,
|
|---|
| 1660 | caption=_("Save workspace"),
|
|---|
| 1661 | style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
|
|---|
| 1662 | if dlg.ShowModal() != wx.ID_YES:
|
|---|
| 1663 | dlg.Destroy()
|
|---|
| 1664 | return False
|
|---|
| 1665 |
|
|---|
| 1666 | Debug.msg(4, "GMFrame.OnWorkspaceSaveAs(): filename=%s" % filename)
|
|---|
| 1667 |
|
|---|
| 1668 | self.SaveToWorkspaceFile(filename)
|
|---|
| 1669 | self.workspaceFile = filename
|
|---|
| 1670 | self._setTitle()
|
|---|
| 1671 |
|
|---|
| 1672 | def OnWorkspaceSave(self, event=None):
|
|---|
| 1673 | """Save file with workspace definition"""
|
|---|
| 1674 | if self.workspaceFile:
|
|---|
| 1675 | dlg = wx.MessageDialog(
|
|---|
| 1676 | self,
|
|---|
| 1677 | message=_(
|
|---|
| 1678 | "Workspace file <%s> already exists. "
|
|---|
| 1679 | "Do you want to overwrite this file?") %
|
|---|
| 1680 | self.workspaceFile,
|
|---|
| 1681 | caption=_("Save workspace"),
|
|---|
| 1682 | style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
|
|---|
| 1683 | if dlg.ShowModal() == wx.ID_NO:
|
|---|
| 1684 | dlg.Destroy()
|
|---|
| 1685 | else:
|
|---|
| 1686 | Debug.msg(
|
|---|
| 1687 | 4, "GMFrame.OnWorkspaceSave(): filename=%s" %
|
|---|
| 1688 | self.workspaceFile)
|
|---|
| 1689 | self.SaveToWorkspaceFile(self.workspaceFile)
|
|---|
| 1690 | self._setTitle()
|
|---|
| 1691 | self.workspaceChanged = False
|
|---|
| 1692 | else:
|
|---|
| 1693 | self.OnWorkspaceSaveAs()
|
|---|
| 1694 |
|
|---|
| 1695 | def SaveToWorkspaceFile(self, filename):
|
|---|
| 1696 | """Save layer tree layout to workspace file
|
|---|
| 1697 |
|
|---|
| 1698 | :return: True on success, False on error
|
|---|
| 1699 | """
|
|---|
| 1700 | tmpfile = tempfile.TemporaryFile(mode='w+b')
|
|---|
| 1701 | try:
|
|---|
| 1702 | WriteWorkspaceFile(lmgr=self, file=tmpfile)
|
|---|
| 1703 | except Exception as e:
|
|---|
| 1704 | GError(parent=self,
|
|---|
| 1705 | message=_("Writing current settings to workspace file "
|
|---|
| 1706 | "failed."))
|
|---|
| 1707 | return False
|
|---|
| 1708 |
|
|---|
| 1709 | try:
|
|---|
| 1710 | mfile = open(filename, "wb")
|
|---|
| 1711 | tmpfile.seek(0)
|
|---|
| 1712 | for line in tmpfile.readlines():
|
|---|
| 1713 | mfile.write(line)
|
|---|
| 1714 | except IOError:
|
|---|
| 1715 | GError(
|
|---|
| 1716 | parent=self,
|
|---|
| 1717 | message=_("Unable to open file <%s> for writing.") %
|
|---|
| 1718 | filename)
|
|---|
| 1719 | return False
|
|---|
| 1720 |
|
|---|
| 1721 | mfile.close()
|
|---|
| 1722 |
|
|---|
| 1723 | return True
|
|---|
| 1724 |
|
|---|
| 1725 | def OnWorkspaceClose(self, event=None):
|
|---|
| 1726 | """Close file with workspace definition
|
|---|
| 1727 |
|
|---|
| 1728 | If workspace has been modified ask user to save the changes.
|
|---|
| 1729 | """
|
|---|
| 1730 | Debug.msg(
|
|---|
| 1731 | 4, "GMFrame.OnWorkspaceClose(): file=%s" %
|
|---|
| 1732 | self.workspaceFile)
|
|---|
| 1733 |
|
|---|
| 1734 | self.OnDisplayCloseAll()
|
|---|
| 1735 | self.workspaceFile = None
|
|---|
| 1736 | self.workspaceChanged = False
|
|---|
| 1737 | self._setTitle()
|
|---|
| 1738 | self.displayIndex = 0
|
|---|
| 1739 | self.currentPage = None
|
|---|
| 1740 |
|
|---|
| 1741 | def OnDisplayClose(self, event=None):
|
|---|
| 1742 | """Close current map display window
|
|---|
| 1743 | """
|
|---|
| 1744 | if self.currentPage and self.GetMapDisplay():
|
|---|
| 1745 | self.GetMapDisplay().OnCloseWindow(event)
|
|---|
| 1746 |
|
|---|
| 1747 | def OnDisplayCloseAll(self, event=None):
|
|---|
| 1748 | """Close all open map display windows
|
|---|
| 1749 | """
|
|---|
| 1750 | for display in self.GetMapDisplay(onlyCurrent=False):
|
|---|
| 1751 | display.OnCloseWindow(event)
|
|---|
| 1752 |
|
|---|
| 1753 | def OnRenderAllMapDisplays(self, event=None):
|
|---|
| 1754 | for display in self.GetAllMapDisplays():
|
|---|
| 1755 | display.OnRender(None)
|
|---|
| 1756 |
|
|---|
| 1757 | def OnRenameDisplay(self, event):
|
|---|
| 1758 | """Change Map Display name"""
|
|---|
| 1759 | name = self.notebookLayers.GetPageText(self.currentPageNum)
|
|---|
| 1760 | dlg = TextEntryDialog(
|
|---|
| 1761 | self, message=_("Enter new name:"),
|
|---|
| 1762 | caption=_("Rename Map Display"),
|
|---|
| 1763 | value=name)
|
|---|
| 1764 | if dlg.ShowModal() == wx.ID_OK:
|
|---|
| 1765 | name = dlg.GetValue()
|
|---|
| 1766 | self.notebookLayers.SetPageText(
|
|---|
| 1767 | page=self.currentPageNum, text=name)
|
|---|
| 1768 | mapdisplay = self.GetMapDisplay()
|
|---|
| 1769 | # There is a slight inconsistency: When creating the display
|
|---|
| 1770 | # we use just the number, but when user renames it,
|
|---|
| 1771 | # we use the full name. Both cases make sense and each
|
|---|
| 1772 | # separately gives expected result, so we keep this
|
|---|
| 1773 | # behavior.
|
|---|
| 1774 | mapdisplay.SetTitleWithName(name)
|
|---|
| 1775 | dlg.Destroy()
|
|---|
| 1776 |
|
|---|
| 1777 | def OnRasterRules(self, event):
|
|---|
| 1778 | """Launches dialog for raster color rules"""
|
|---|
| 1779 | from modules.colorrules import RasterColorTable
|
|---|
| 1780 | ctable = RasterColorTable(self, layerTree=self.GetLayerTree())
|
|---|
| 1781 | ctable.Show()
|
|---|
| 1782 | ctable.CentreOnScreen()
|
|---|
| 1783 |
|
|---|
| 1784 | def OnVectorRules(self, event):
|
|---|
| 1785 | """Launches dialog for vector color rules"""
|
|---|
| 1786 | from modules.colorrules import VectorColorTable
|
|---|
| 1787 | ctable = VectorColorTable(self, layerTree=self.GetLayerTree(),
|
|---|
| 1788 | attributeType='color')
|
|---|
| 1789 | ctable.Show()
|
|---|
| 1790 | ctable.CentreOnScreen()
|
|---|
| 1791 |
|
|---|
| 1792 | def OnEditImageryGroups(self, event, cmd=None):
|
|---|
| 1793 | """Show dialog for creating and editing groups.
|
|---|
| 1794 | """
|
|---|
| 1795 | dlg = GroupDialog(self)
|
|---|
| 1796 | dlg.CentreOnScreen()
|
|---|
| 1797 | dlg.Show()
|
|---|
| 1798 |
|
|---|
| 1799 | def OnInstallExtension(self, event):
|
|---|
| 1800 | """Install extension from GRASS Addons SVN repository"""
|
|---|
| 1801 | from modules.extensions import InstallExtensionWindow
|
|---|
| 1802 | win = InstallExtensionWindow(
|
|---|
| 1803 | self, giface=self._giface, size=(650, 550))
|
|---|
| 1804 | win.CentreOnScreen()
|
|---|
| 1805 | win.Show()
|
|---|
| 1806 |
|
|---|
| 1807 | def OnManageExtension(self, event):
|
|---|
| 1808 | """Manage or uninstall extensions"""
|
|---|
| 1809 | from modules.extensions import ManageExtensionWindow
|
|---|
| 1810 | win = ManageExtensionWindow(self, size=(650, 300))
|
|---|
| 1811 | win.CentreOnScreen()
|
|---|
| 1812 | win.Show()
|
|---|
| 1813 |
|
|---|
| 1814 | def OnPreferences(self, event):
|
|---|
| 1815 | """General GUI preferences/settings
|
|---|
| 1816 | """
|
|---|
| 1817 | if not self.dialogs['preferences']:
|
|---|
| 1818 | dlg = PreferencesDialog(parent=self, giface=self._giface)
|
|---|
| 1819 | self.dialogs['preferences'] = dlg
|
|---|
| 1820 | self.dialogs['preferences'].CenterOnParent()
|
|---|
| 1821 |
|
|---|
| 1822 | dlg.settingsChanged.connect(self.OnSettingsChanged)
|
|---|
| 1823 | self.Bind(
|
|---|
| 1824 | wx.EVT_CLOSE,
|
|---|
| 1825 | lambda evt: self.dialogs.update(
|
|---|
| 1826 | preferences=None),
|
|---|
| 1827 | dlg)
|
|---|
| 1828 |
|
|---|
| 1829 | self.dialogs['preferences'].Show()
|
|---|
| 1830 |
|
|---|
| 1831 | def OnNvizPreferences(self, event):
|
|---|
| 1832 | """Show nviz preferences"""
|
|---|
| 1833 | if not self.dialogs['nvizPreferences']:
|
|---|
| 1834 | from nviz.preferences import NvizPreferencesDialog
|
|---|
| 1835 | dlg = NvizPreferencesDialog(parent=self, giface=self._giface)
|
|---|
| 1836 | self.dialogs['nvizPreferences'] = dlg
|
|---|
| 1837 | self.dialogs['nvizPreferences'].CenterOnScreen()
|
|---|
| 1838 | self.dialogs['nvizPreferences'].Show()
|
|---|
| 1839 |
|
|---|
| 1840 | def OnHelp(self, event):
|
|---|
| 1841 | """Show help
|
|---|
| 1842 | """
|
|---|
| 1843 | self._gconsole.RunCmd(['g.manual', '-i'])
|
|---|
| 1844 |
|
|---|
| 1845 | def OnIClass(self, event=None, cmd=None):
|
|---|
| 1846 | """Start wxIClass tool
|
|---|
| 1847 |
|
|---|
| 1848 | The parameters of all handlers which are associated with module
|
|---|
| 1849 | and contained in menu/toolboxes must be event and cmd.
|
|---|
| 1850 | When called from menu event is always None and cmd is the
|
|---|
| 1851 | associated command (list containing a module name and parameters).
|
|---|
| 1852 |
|
|---|
| 1853 | .. todo::
|
|---|
| 1854 | This documentation is actually documentation of some
|
|---|
| 1855 | component related to gui_core/menu.py file.
|
|---|
| 1856 | """
|
|---|
| 1857 | from iclass.frame import IClassMapFrame, haveIClass, errMsg
|
|---|
| 1858 | if not haveIClass:
|
|---|
| 1859 | GError(_('Unable to launch "Supervised Classification Tool".\n\n'
|
|---|
| 1860 | 'Reason: %s') % errMsg)
|
|---|
| 1861 | return
|
|---|
| 1862 |
|
|---|
| 1863 | win = IClassMapFrame(parent=self, giface=self._giface)
|
|---|
| 1864 | win.CentreOnScreen()
|
|---|
| 1865 |
|
|---|
| 1866 | win.Show()
|
|---|
| 1867 |
|
|---|
| 1868 | def OnAnimationTool(self, event=None, cmd=None):
|
|---|
| 1869 | """Launch Animation tool. See OnIClass documentation.
|
|---|
| 1870 | """
|
|---|
| 1871 | from animation.frame import AnimationFrame
|
|---|
| 1872 |
|
|---|
| 1873 | frame = AnimationFrame(parent=self, giface=self._giface)
|
|---|
| 1874 | frame.CentreOnScreen()
|
|---|
| 1875 | frame.Show()
|
|---|
| 1876 |
|
|---|
| 1877 | tree = self.GetLayerTree()
|
|---|
| 1878 | if tree:
|
|---|
| 1879 | rasters = []
|
|---|
| 1880 | for layer in tree.GetSelectedLayers(checkedOnly=False):
|
|---|
| 1881 | if tree.GetLayerInfo(layer, key='type') == 'raster':
|
|---|
| 1882 | rasters.append(
|
|---|
| 1883 | tree.GetLayerInfo(
|
|---|
| 1884 | layer, key='maplayer').GetName())
|
|---|
| 1885 | if len(rasters) >= 2:
|
|---|
| 1886 | from core.layerlist import LayerList
|
|---|
| 1887 | from animation.data import AnimLayer
|
|---|
| 1888 | layerList = LayerList()
|
|---|
| 1889 | layer = AnimLayer()
|
|---|
| 1890 | layer.mapType = 'raster'
|
|---|
| 1891 | layer.name = ','.join(rasters)
|
|---|
| 1892 | layer.cmd = ['d.rast', 'map=']
|
|---|
| 1893 | layerList.AddLayer(layer)
|
|---|
| 1894 | frame.SetAnimations([layerList, None, None, None])
|
|---|
| 1895 |
|
|---|
| 1896 | def OnTimelineTool(self, event=None, cmd=None):
|
|---|
| 1897 | """Launch Timeline Tool"""
|
|---|
| 1898 | try:
|
|---|
| 1899 | from timeline.frame import TimelineFrame
|
|---|
| 1900 | except ImportError:
|
|---|
| 1901 | GError(parent=self, message=_("Unable to start Timeline Tool."))
|
|---|
| 1902 | return
|
|---|
| 1903 | frame = TimelineFrame(None)
|
|---|
| 1904 | frame.Show()
|
|---|
| 1905 |
|
|---|
| 1906 | def OnTplotTool(self, event=None, cmd=None):
|
|---|
| 1907 | """Launch Temporal Plot Tool"""
|
|---|
| 1908 | try:
|
|---|
| 1909 | from tplot.frame import TplotFrame
|
|---|
| 1910 | except ImportError:
|
|---|
| 1911 | GError(parent=self, message=_(
|
|---|
| 1912 | "Unable to start Temporal Plot Tool."))
|
|---|
| 1913 | return
|
|---|
| 1914 | frame = TplotFrame(parent=self, giface=self._giface)
|
|---|
| 1915 | frame.Show()
|
|---|
| 1916 |
|
|---|
| 1917 | def OnHistogram(self, event):
|
|---|
| 1918 | """Init histogram display canvas and tools
|
|---|
| 1919 | """
|
|---|
| 1920 | from modules.histogram import HistogramFrame
|
|---|
| 1921 | win = HistogramFrame(self, giface=self._giface)
|
|---|
| 1922 |
|
|---|
| 1923 | win.CentreOnScreen()
|
|---|
| 1924 | win.Show()
|
|---|
| 1925 | win.Refresh()
|
|---|
| 1926 | win.Update()
|
|---|
| 1927 |
|
|---|
| 1928 | def OnMapCalculator(self, event, cmd=''):
|
|---|
| 1929 | """Init map calculator for interactive creation of mapcalc statements
|
|---|
| 1930 | """
|
|---|
| 1931 | from modules.mcalc_builder import MapCalcFrame
|
|---|
| 1932 | if event:
|
|---|
| 1933 | try:
|
|---|
| 1934 | cmd = self.GetMenuCmd(event)
|
|---|
| 1935 | except KeyError:
|
|---|
| 1936 | cmd = ['r.mapcalc']
|
|---|
| 1937 | win = MapCalcFrame(parent=self,
|
|---|
| 1938 | giface=self._giface,
|
|---|
| 1939 | cmd=cmd[0])
|
|---|
| 1940 | win.CentreOnScreen()
|
|---|
| 1941 | win.Show()
|
|---|
| 1942 |
|
|---|
| 1943 | def OnVectorCleaning(self, event, cmd=''):
|
|---|
| 1944 | """Init interactive vector cleaning
|
|---|
| 1945 | """
|
|---|
| 1946 | from modules.vclean import VectorCleaningFrame
|
|---|
| 1947 | win = VectorCleaningFrame(parent=self)
|
|---|
| 1948 | win.CentreOnScreen()
|
|---|
| 1949 | win.Show()
|
|---|
| 1950 |
|
|---|
| 1951 | def OnRasterOutputFormat(self, event):
|
|---|
| 1952 | """Set raster output format handler"""
|
|---|
| 1953 | self.OnMenuCmd(cmd=['r.external.out'])
|
|---|
| 1954 |
|
|---|
| 1955 | def OnVectorOutputFormat(self, event):
|
|---|
| 1956 | """Set vector output format handler"""
|
|---|
| 1957 | from modules.import_export import GdalOutputDialog
|
|---|
| 1958 | dlg = GdalOutputDialog(parent=self, ogr=True)
|
|---|
| 1959 | dlg.CentreOnScreen()
|
|---|
| 1960 | dlg.Show()
|
|---|
| 1961 |
|
|---|
| 1962 | def OnUnpackRaster(self, event):
|
|---|
| 1963 | """Unpack raster map handler"""
|
|---|
| 1964 | self.OnMenuCmd(cmd=['r.unpack'])
|
|---|
| 1965 |
|
|---|
| 1966 | def OnUnpackVector(self, event):
|
|---|
| 1967 | """Unpack vector map handler"""
|
|---|
| 1968 | self.OnMenuCmd(cmd=['v.unpack'])
|
|---|
| 1969 |
|
|---|
| 1970 | def OnImportDxfFile(self, event, cmd=None):
|
|---|
| 1971 | """Convert multiple DXF layers to GRASS vector map layers"""
|
|---|
| 1972 | from modules.import_export import DxfImportDialog
|
|---|
| 1973 | dlg = DxfImportDialog(parent=self, giface=self._giface)
|
|---|
| 1974 | dlg.CentreOnScreen()
|
|---|
| 1975 | dlg.Show()
|
|---|
| 1976 |
|
|---|
| 1977 | def OnImportGdalLayers(self, event, cmd=None):
|
|---|
| 1978 | """Convert multiple GDAL layers to GRASS raster map layers"""
|
|---|
| 1979 | from modules.import_export import GdalImportDialog
|
|---|
| 1980 | dlg = GdalImportDialog(parent=self, giface=self._giface)
|
|---|
| 1981 | dlg.CentreOnScreen()
|
|---|
| 1982 | dlg.Show()
|
|---|
| 1983 |
|
|---|
| 1984 | def OnLinkGdalLayers(self, event, cmd=None):
|
|---|
| 1985 | """Link multiple GDAL layers to GRASS raster map layers"""
|
|---|
| 1986 | from modules.import_export import GdalImportDialog
|
|---|
| 1987 | dlg = GdalImportDialog(parent=self, giface=self._giface, link=True)
|
|---|
| 1988 | dlg.CentreOnScreen()
|
|---|
| 1989 | dlg.Show()
|
|---|
| 1990 |
|
|---|
| 1991 | def OnImportOgrLayers(self, event, cmd=None):
|
|---|
| 1992 | """Convert multiple OGR layers to GRASS vector map layers"""
|
|---|
| 1993 | from modules.import_export import OgrImportDialog
|
|---|
| 1994 | dlg = OgrImportDialog(parent=self, giface=self._giface)
|
|---|
| 1995 | dlg.CentreOnScreen()
|
|---|
| 1996 | dlg.Show()
|
|---|
| 1997 |
|
|---|
| 1998 | def OnLinkOgrLayers(self, event, cmd=None):
|
|---|
| 1999 | """Links multiple OGR layers to GRASS vector map layers"""
|
|---|
| 2000 | from modules.import_export import OgrImportDialog
|
|---|
| 2001 | dlg = OgrImportDialog(parent=self, giface=self._giface, link=True)
|
|---|
| 2002 | dlg.CentreOnScreen()
|
|---|
| 2003 | dlg.Show()
|
|---|
| 2004 |
|
|---|
| 2005 | def OnAddWS(self, event, cmd=None):
|
|---|
| 2006 | """Add web services layer"""
|
|---|
| 2007 | from web_services.dialogs import AddWSDialog
|
|---|
| 2008 | dlg = AddWSDialog(parent=self, giface=self._giface)
|
|---|
| 2009 | dlg.CentreOnScreen()
|
|---|
| 2010 | x, y = dlg.GetPosition()
|
|---|
| 2011 | dlg.SetPosition((x, y - 200))
|
|---|
| 2012 | dlg.Show()
|
|---|
| 2013 |
|
|---|
| 2014 | def OnSimpleEditor(self, event):
|
|---|
| 2015 | # import on demand
|
|---|
| 2016 | from gui_core.pyedit import PyEditFrame
|
|---|
| 2017 |
|
|---|
| 2018 | # we don't keep track of them and we don't care about open files
|
|---|
| 2019 | # there when closing the main GUI
|
|---|
| 2020 | simpleEditor = PyEditFrame(parent=self, giface=self._giface)
|
|---|
| 2021 | simpleEditor.SetSize(self.GetSize())
|
|---|
| 2022 | simpleEditor.CenterOnScreen()
|
|---|
| 2023 | simpleEditor.Show()
|
|---|
| 2024 |
|
|---|
| 2025 | def OnShowAttributeTable(self, event, selection=None):
|
|---|
| 2026 | """Show attribute table of the given vector map layer
|
|---|
| 2027 | """
|
|---|
| 2028 | if not self.currentPage:
|
|---|
| 2029 | self.MsgNoLayerSelected()
|
|---|
| 2030 | return
|
|---|
| 2031 |
|
|---|
| 2032 | tree = self.GetLayerTree()
|
|---|
| 2033 | layer = tree.layer_selected
|
|---|
| 2034 | # no map layer selected
|
|---|
| 2035 | if not layer:
|
|---|
| 2036 | self.MsgNoLayerSelected()
|
|---|
| 2037 | return
|
|---|
| 2038 |
|
|---|
| 2039 | # available only for vector map layers
|
|---|
| 2040 | try:
|
|---|
| 2041 | maptype = tree.GetLayerInfo(layer, key='maplayer').type
|
|---|
| 2042 | except:
|
|---|
| 2043 | maptype = None
|
|---|
| 2044 |
|
|---|
| 2045 | if not maptype or maptype != 'vector':
|
|---|
| 2046 | GMessage(parent=self,
|
|---|
| 2047 | message=_("Selected map layer is not vector."))
|
|---|
| 2048 | return
|
|---|
| 2049 |
|
|---|
| 2050 | if not tree.GetLayerInfo(layer):
|
|---|
| 2051 | return
|
|---|
| 2052 | dcmd = tree.GetLayerInfo(layer, key='cmd')
|
|---|
| 2053 | if not dcmd:
|
|---|
| 2054 | return
|
|---|
| 2055 |
|
|---|
| 2056 | from dbmgr.manager import AttributeManager
|
|---|
| 2057 | dbmanager = AttributeManager(parent=self, id=wx.ID_ANY,
|
|---|
| 2058 | size=wx.Size(500, 300),
|
|---|
| 2059 | item=layer, log=self._gconsole,
|
|---|
| 2060 | selection=selection)
|
|---|
| 2061 | # register ATM dialog
|
|---|
| 2062 | self.dialogs['atm'].append(dbmanager)
|
|---|
| 2063 | # show ATM window
|
|---|
| 2064 | dbmanager.Show()
|
|---|
| 2065 |
|
|---|
| 2066 | def OnNewDisplay(self, event=None):
|
|---|
| 2067 | """Create new layer tree and map display instance"""
|
|---|
| 2068 | self.NewDisplay()
|
|---|
| 2069 |
|
|---|
| 2070 | def NewDisplay(self, name=None, show=True):
|
|---|
| 2071 | """Create new layer tree, which will
|
|---|
| 2072 | create an associated map display frame
|
|---|
| 2073 |
|
|---|
| 2074 | :param name: name of new map display
|
|---|
| 2075 | :param show: show map display window if True
|
|---|
| 2076 |
|
|---|
| 2077 | :return: reference to mapdisplay intance
|
|---|
| 2078 | """
|
|---|
| 2079 | Debug.msg(1, "GMFrame.NewDisplay(): idx=%d" % self.displayIndex)
|
|---|
| 2080 |
|
|---|
| 2081 | # make a new page in the bookcontrol for the layer tree (on page 0 of
|
|---|
| 2082 | # the notebook)
|
|---|
| 2083 | self.pg_panel = wx.Panel(
|
|---|
| 2084 | self.notebookLayers,
|
|---|
| 2085 | id=wx.ID_ANY,
|
|---|
| 2086 | style=wx.EXPAND)
|
|---|
| 2087 | if name:
|
|---|
| 2088 | dispName = name
|
|---|
| 2089 | else:
|
|---|
| 2090 | dispName = "Display " + str(self.displayIndex + 1)
|
|---|
| 2091 | self.notebookLayers.AddPage(self.pg_panel, text=dispName, select=True)
|
|---|
| 2092 | self.currentPage = self.notebookLayers.GetCurrentPage()
|
|---|
| 2093 |
|
|---|
| 2094 | # create layer tree (tree control for managing GIS layers) and put on
|
|---|
| 2095 | # new notebook page
|
|---|
| 2096 | self.currentPage.maptree = LayerTree(
|
|---|
| 2097 | self.currentPage, giface=self._giface, id=wx.ID_ANY,
|
|---|
| 2098 | pos=wx.DefaultPosition, size=wx.DefaultSize,
|
|---|
| 2099 | style=wx.TR_HAS_BUTTONS | wx.TR_LINES_AT_ROOT | wx.TR_HIDE_ROOT | wx.
|
|---|
| 2100 | TR_DEFAULT_STYLE | wx.NO_BORDER | wx.FULL_REPAINT_ON_RESIZE,
|
|---|
| 2101 | idx=self.displayIndex, lmgr=self, notebook=self.notebookLayers,
|
|---|
| 2102 | showMapDisplay=show)
|
|---|
| 2103 |
|
|---|
| 2104 | # layout for controls
|
|---|
| 2105 | cb_boxsizer = wx.BoxSizer(wx.VERTICAL)
|
|---|
| 2106 | cb_boxsizer.Add(
|
|---|
| 2107 | self.GetLayerTree(),
|
|---|
| 2108 | proportion=1,
|
|---|
| 2109 | flag=wx.EXPAND,
|
|---|
| 2110 | border=1)
|
|---|
| 2111 | self.currentPage.SetSizer(cb_boxsizer)
|
|---|
| 2112 | cb_boxsizer.Fit(self.GetLayerTree())
|
|---|
| 2113 | self.currentPage.Layout()
|
|---|
| 2114 | self.GetLayerTree().Layout()
|
|---|
| 2115 |
|
|---|
| 2116 | mapdisplay = self.currentPage.maptree.mapdisplay
|
|---|
| 2117 | mapdisplay.Bind(wx.EVT_ACTIVATE,
|
|---|
| 2118 | lambda event, page=self.currentPage:
|
|---|
| 2119 | self._onMapDisplayFocus(page))
|
|---|
| 2120 | mapdisplay.starting3dMode.connect(
|
|---|
| 2121 | lambda firstTime, mapDisplayPage=self.currentPage:
|
|---|
| 2122 | self._onMapDisplayStarting3dMode(mapDisplayPage))
|
|---|
| 2123 | mapdisplay.starting3dMode.connect(self.AddNvizTools)
|
|---|
| 2124 | mapdisplay.ending3dMode.connect(self.RemoveNvizTools)
|
|---|
| 2125 |
|
|---|
| 2126 | # use default window layout
|
|---|
| 2127 | if UserSettings.Get(
|
|---|
| 2128 | group='general', key='defWindowPos', subkey='enabled'):
|
|---|
| 2129 | dim = UserSettings.Get(
|
|---|
| 2130 | group='general',
|
|---|
| 2131 | key='defWindowPos',
|
|---|
| 2132 | subkey='dim')
|
|---|
| 2133 | idx = 4 + self.displayIndex * 4
|
|---|
| 2134 | try:
|
|---|
| 2135 | x, y = map(int, dim.split(',')[idx:idx + 2])
|
|---|
| 2136 | w, h = map(int, dim.split(',')[idx + 2:idx + 4])
|
|---|
| 2137 | self.GetMapDisplay().SetPosition((x, y))
|
|---|
| 2138 | self.GetMapDisplay().SetSize((w, h))
|
|---|
| 2139 | except:
|
|---|
| 2140 | pass
|
|---|
| 2141 |
|
|---|
| 2142 | # set default properties
|
|---|
| 2143 | mapdisplay.SetProperties(render=UserSettings.Get(
|
|---|
| 2144 | group='display', key='autoRendering', subkey='enabled'),
|
|---|
| 2145 | mode=UserSettings.Get(
|
|---|
| 2146 | group='display', key='statusbarMode', subkey='selection'),
|
|---|
| 2147 | alignExtent=UserSettings.Get(
|
|---|
| 2148 | group='display', key='alignExtent', subkey='enabled'),
|
|---|
| 2149 | constrainRes=UserSettings.Get(
|
|---|
| 2150 | group='display', key='compResolution', subkey='enabled'),
|
|---|
| 2151 | showCompExtent=UserSettings.Get(
|
|---|
| 2152 | group='display', key='showCompExtent', subkey='enabled'))
|
|---|
| 2153 |
|
|---|
| 2154 | self.displayIndex += 1
|
|---|
| 2155 |
|
|---|
| 2156 | return self.GetMapDisplay()
|
|---|
| 2157 |
|
|---|
| 2158 | def _onMapDisplayFocus(self, notebookLayerPage):
|
|---|
| 2159 | """Changes bookcontrol page to page associated with display."""
|
|---|
| 2160 | # moved from mapdisp/frame.py
|
|---|
| 2161 | # TODO: why it is called 3 times when getting focus?
|
|---|
| 2162 | # and one times when loosing focus?
|
|---|
| 2163 | if self.loadingWorkspace:
|
|---|
| 2164 | return
|
|---|
| 2165 | pgnum = self.notebookLayers.GetPageIndex(notebookLayerPage)
|
|---|
| 2166 | if pgnum > -1:
|
|---|
| 2167 | self.notebookLayers.SetSelection(pgnum)
|
|---|
| 2168 | self.currentPage = self.notebookLayers.GetCurrentPage()
|
|---|
| 2169 |
|
|---|
| 2170 | def _onMapDisplayStarting3dMode(self, mapDisplayPage):
|
|---|
| 2171 | """Disables 3D mode for all map displays except for @p mapDisplay"""
|
|---|
| 2172 | # TODO: it should be disabled also for newly created map windows
|
|---|
| 2173 | # moreover mapdisp.Disable3dMode() does not work properly
|
|---|
| 2174 | for page in range(0, self.GetLayerNotebook().GetPageCount()):
|
|---|
| 2175 | mapdisp = self.GetLayerNotebook().GetPage(page).maptree.GetMapDisplay()
|
|---|
| 2176 | if self.GetLayerNotebook().GetPage(page) != mapDisplayPage:
|
|---|
| 2177 | mapdisp.Disable3dMode()
|
|---|
| 2178 |
|
|---|
| 2179 | def OnAddMaps(self, event=None):
|
|---|
| 2180 | """Add selected map layers into layer tree"""
|
|---|
| 2181 | dialog = MapLayersDialog(parent=self, title=_(
|
|---|
| 2182 | "Add selected map layers into layer tree"))
|
|---|
| 2183 | dialog.applyAddingMapLayers.connect(self.AddMaps)
|
|---|
| 2184 | val = dialog.ShowModal()
|
|---|
| 2185 |
|
|---|
| 2186 | if val == wx.ID_OK:
|
|---|
| 2187 | self.AddMaps(dialog.GetMapLayers(), dialog.GetLayerType(cmd=True))
|
|---|
| 2188 | dialog.Destroy()
|
|---|
| 2189 |
|
|---|
| 2190 | def AddMaps(self, mapLayers, ltype, check=False):
|
|---|
| 2191 | """Add map layers to layer tree.
|
|---|
| 2192 |
|
|---|
| 2193 | :param list mapLayers: list of map names
|
|---|
| 2194 | :param str ltype: layer type ('raster', 'raster_3d', 'vector')
|
|---|
| 2195 | :param bool check: True if new layers should be checked in
|
|---|
| 2196 | layer tree False otherwise
|
|---|
| 2197 | """
|
|---|
| 2198 | # start new map display if no display is available
|
|---|
| 2199 | if not self.currentPage:
|
|---|
| 2200 | self.NewDisplay()
|
|---|
| 2201 |
|
|---|
| 2202 | maptree = self.GetLayerTree()
|
|---|
| 2203 |
|
|---|
| 2204 | for layerName in mapLayers:
|
|---|
| 2205 | if ltype == 'raster':
|
|---|
| 2206 | cmd = ['d.rast', 'map=%s' % layerName]
|
|---|
| 2207 | elif ltype == 'raster_3d':
|
|---|
| 2208 | cmd = ['d.rast3d', 'map=%s' % layerName]
|
|---|
| 2209 | elif ltype == 'vector':
|
|---|
| 2210 | cmd = [
|
|---|
| 2211 | 'd.vect', 'map=%s' %
|
|---|
| 2212 | layerName] + GetDisplayVectSettings()
|
|---|
| 2213 | else:
|
|---|
| 2214 | GError(parent=self,
|
|---|
| 2215 | message=_("Unsupported map layer type <%s>.") % ltype)
|
|---|
| 2216 | return
|
|---|
| 2217 |
|
|---|
| 2218 | newItem = maptree.AddLayer(ltype=ltype,
|
|---|
| 2219 | lname=layerName,
|
|---|
| 2220 | lchecked=check,
|
|---|
| 2221 | lopacity=1.0,
|
|---|
| 2222 | lcmd=cmd,
|
|---|
| 2223 | lgroup=None)
|
|---|
| 2224 |
|
|---|
| 2225 | def _updateCurrentMap(self, **kwargs):
|
|---|
| 2226 | """Updates map of the current map window."""
|
|---|
| 2227 | if 'delay' in kwargs:
|
|---|
| 2228 | self.GetMapDisplay().GetWindow().UpdateMap(delay=kwargs['delay'])
|
|---|
| 2229 | else:
|
|---|
| 2230 | self.GetMapDisplay().GetWindow().UpdateMap()
|
|---|
| 2231 |
|
|---|
| 2232 | def OnMapCreated(self, name, ltype, add=None):
|
|---|
| 2233 | """Decides wheter the map should be added to layer tree."""
|
|---|
| 2234 | if add is None:
|
|---|
| 2235 | # add new map into layer if globally enabled
|
|---|
| 2236 | if UserSettings.Get(group='cmd',
|
|---|
| 2237 | key='addNewLayer', subkey='enabled'):
|
|---|
| 2238 | self.AddOrUpdateMap(name, ltype)
|
|---|
| 2239 | elif add:
|
|---|
| 2240 | # add new map into layer tree
|
|---|
| 2241 | self.AddOrUpdateMap(name, ltype)
|
|---|
| 2242 | else:
|
|---|
| 2243 | # update the map
|
|---|
| 2244 | display = self.GetMapDisplay()
|
|---|
| 2245 | display.GetWindow().UpdateMap(render=True)
|
|---|
| 2246 |
|
|---|
| 2247 | def AddOrUpdateMap(self, mapName, ltype):
|
|---|
| 2248 | """Add map layer or update"""
|
|---|
| 2249 | # start new map display if no display is available
|
|---|
| 2250 | if ltype not in ['raster', 'raster_3d', 'vector']:
|
|---|
| 2251 | GError(parent=self,
|
|---|
| 2252 | message=_("Unsupported map layer type <%s>.") % ltype)
|
|---|
| 2253 | return
|
|---|
| 2254 |
|
|---|
| 2255 | if not self.currentPage:
|
|---|
| 2256 | self.AddMaps([mapName], ltype, check=True)
|
|---|
| 2257 | else:
|
|---|
| 2258 | display = self.GetMapDisplay()
|
|---|
| 2259 | mapLayers = map(lambda x: x.GetName(),
|
|---|
| 2260 | display.GetMap().GetListOfLayers(ltype=ltype))
|
|---|
| 2261 | if mapName in mapLayers:
|
|---|
| 2262 | display.GetWindow().UpdateMap(render=True)
|
|---|
| 2263 | else:
|
|---|
| 2264 | self.AddMaps([mapName], ltype, check=True)
|
|---|
| 2265 |
|
|---|
| 2266 | def OnAddRaster(self, event):
|
|---|
| 2267 | """Add raster map layer"""
|
|---|
| 2268 | # start new map display if no display is available
|
|---|
| 2269 | if not self.currentPage:
|
|---|
| 2270 | self.NewDisplay(show=True)
|
|---|
| 2271 |
|
|---|
| 2272 | self.notebook.SetSelectionByName('layers')
|
|---|
| 2273 | self.GetLayerTree().AddLayer('raster')
|
|---|
| 2274 |
|
|---|
| 2275 | def OnAddRasterMisc(self, event):
|
|---|
| 2276 | """Create misc raster popup-menu"""
|
|---|
| 2277 | # start new map display if no display is available
|
|---|
| 2278 | if not self.currentPage:
|
|---|
| 2279 | self.NewDisplay(show=True)
|
|---|
| 2280 |
|
|---|
| 2281 | self._popupMenu((('layerRaster_3d', self.OnAddRaster3D),
|
|---|
| 2282 | (None, None),
|
|---|
| 2283 | ('layerRgb', self.OnAddRasterRGB),
|
|---|
| 2284 | ('layerHis', self.OnAddRasterHIS),
|
|---|
| 2285 | (None, None),
|
|---|
| 2286 | ('layerShaded', self.OnAddRasterShaded),
|
|---|
| 2287 | (None, None),
|
|---|
| 2288 | ('layerRastarrow', self.OnAddRasterArrow),
|
|---|
| 2289 | ('layerRastnum', self.OnAddRasterNum)))
|
|---|
| 2290 |
|
|---|
| 2291 | # show map display
|
|---|
| 2292 | self.GetMapDisplay().Show()
|
|---|
| 2293 |
|
|---|
| 2294 | def OnAddVector(self, event):
|
|---|
| 2295 | """Add vector map to the current layer tree"""
|
|---|
| 2296 | # start new map display if no display is available
|
|---|
| 2297 | if not self.currentPage:
|
|---|
| 2298 | self.NewDisplay(show=True)
|
|---|
| 2299 |
|
|---|
| 2300 | self.notebook.SetSelectionByName('layers')
|
|---|
| 2301 | self.GetLayerTree().AddLayer('vector')
|
|---|
| 2302 |
|
|---|
| 2303 | def OnAddVectorMisc(self, event):
|
|---|
| 2304 | """Create misc vector popup-menu"""
|
|---|
| 2305 | # start new map display if no display is available
|
|---|
| 2306 | if not self.currentPage:
|
|---|
| 2307 | self.NewDisplay(show=True)
|
|---|
| 2308 |
|
|---|
| 2309 | self._popupMenu((('layerThememap', self.OnAddVectorTheme),
|
|---|
| 2310 | ('layerThemechart', self.OnAddVectorChart)))
|
|---|
| 2311 |
|
|---|
| 2312 | # show map display
|
|---|
| 2313 | self.GetMapDisplay().Show()
|
|---|
| 2314 |
|
|---|
| 2315 | def OnAddVectorTheme(self, event):
|
|---|
| 2316 | """Add thematic vector map to the current layer tree"""
|
|---|
| 2317 | self.notebook.SetSelectionByName('layers')
|
|---|
| 2318 | self.GetLayerTree().AddLayer('thememap')
|
|---|
| 2319 |
|
|---|
| 2320 | def OnAddVectorChart(self, event):
|
|---|
| 2321 | """Add chart vector map to the current layer tree"""
|
|---|
| 2322 | self.notebook.SetSelectionByName('layers')
|
|---|
| 2323 | self.GetLayerTree().AddLayer('themechart')
|
|---|
| 2324 |
|
|---|
| 2325 | def OnAddOverlay(self, event):
|
|---|
| 2326 | """Create decoration overlay menu"""
|
|---|
| 2327 | # start new map display if no display is available
|
|---|
| 2328 | if not self.currentPage:
|
|---|
| 2329 | self.NewDisplay(show=True)
|
|---|
| 2330 |
|
|---|
| 2331 | self._popupMenu((('layerGrid', self.OnAddGrid),
|
|---|
| 2332 | ('layerLabels', self.OnAddLabels),
|
|---|
| 2333 | ('layerGeodesic', self.OnAddGeodesic),
|
|---|
| 2334 | ('layerRhumb', self.OnAddRhumb),
|
|---|
| 2335 | (None, None),
|
|---|
| 2336 | ('layerCmd', self.OnAddCommand)))
|
|---|
| 2337 |
|
|---|
| 2338 | # show map display
|
|---|
| 2339 | self.GetMapDisplay().Show()
|
|---|
| 2340 |
|
|---|
| 2341 | def OnAddRaster3D(self, event):
|
|---|
| 2342 | """Add 3D raster map to the current layer tree"""
|
|---|
| 2343 | self.notebook.SetSelectionByName('layers')
|
|---|
| 2344 | self.GetLayerTree().AddLayer('raster_3d')
|
|---|
| 2345 |
|
|---|
| 2346 | def OnAddRasterRGB(self, event):
|
|---|
| 2347 | """Add RGB raster map to the current layer tree"""
|
|---|
| 2348 | self.notebook.SetSelectionByName('layers')
|
|---|
| 2349 | self.GetLayerTree().AddLayer('rgb')
|
|---|
| 2350 |
|
|---|
| 2351 | def OnAddRasterHIS(self, event):
|
|---|
| 2352 | """Add HIS raster map to the current layer tree"""
|
|---|
| 2353 | self.notebook.SetSelectionByName('layers')
|
|---|
| 2354 | self.GetLayerTree().AddLayer('his')
|
|---|
| 2355 |
|
|---|
| 2356 | def OnAddRasterShaded(self, event):
|
|---|
| 2357 | """Add shaded relief raster map to the current layer tree"""
|
|---|
| 2358 | self.notebook.SetSelectionByName('layers')
|
|---|
| 2359 | self.GetLayerTree().AddLayer('shaded')
|
|---|
| 2360 |
|
|---|
| 2361 | def OnAddRasterArrow(self, event):
|
|---|
| 2362 | """Add flow arrows raster map to the current layer tree"""
|
|---|
| 2363 | self.notebook.SetSelectionByName('layers')
|
|---|
| 2364 | # here it seems that it should be retrieved from the mapwindow
|
|---|
| 2365 | mapdisplay = self.GetMapDisplay()
|
|---|
| 2366 | resolution = mapdisplay.mapWindowProperties.resolution
|
|---|
| 2367 | if not resolution:
|
|---|
| 2368 | dlg = self.MsgDisplayResolution()
|
|---|
| 2369 | if dlg.ShowModal() == wx.ID_YES:
|
|---|
| 2370 | mapdisplay.mapWindowProperties.resolution = True
|
|---|
| 2371 | dlg.Destroy()
|
|---|
| 2372 |
|
|---|
| 2373 | self.GetLayerTree().AddLayer('rastarrow')
|
|---|
| 2374 |
|
|---|
| 2375 | def OnAddRasterNum(self, event):
|
|---|
| 2376 | """Add cell number raster map to the current layer tree"""
|
|---|
| 2377 | self.notebook.SetSelectionByName('layers')
|
|---|
| 2378 | mapdisplay = self.GetMapDisplay()
|
|---|
| 2379 | resolution = mapdisplay.mapWindowProperties.resolution
|
|---|
| 2380 | if not resolution:
|
|---|
| 2381 | limitText = _("Note that cell values can only be displayed for "
|
|---|
| 2382 | "regions of less than 10,000 cells.")
|
|---|
| 2383 | dlg = self.MsgDisplayResolution(limitText)
|
|---|
| 2384 | if dlg.ShowModal() == wx.ID_YES:
|
|---|
| 2385 | mapdisplay.mapWindowProperties.resolution = True
|
|---|
| 2386 | dlg.Destroy()
|
|---|
| 2387 |
|
|---|
| 2388 | # region = tree.GetMap().GetCurrentRegion()
|
|---|
| 2389 | # if region['cells'] > 10000:
|
|---|
| 2390 | # GMessage(message = "Cell values can only be displayed for regions of < 10,000 cells.", parent = self)
|
|---|
| 2391 | self.GetLayerTree().AddLayer('rastnum')
|
|---|
| 2392 |
|
|---|
| 2393 | def OnAddCommand(self, event):
|
|---|
| 2394 | """Add command line map layer to the current layer tree"""
|
|---|
| 2395 | # start new map display if no display is available
|
|---|
| 2396 | if not self.currentPage:
|
|---|
| 2397 | self.NewDisplay(show=True)
|
|---|
| 2398 |
|
|---|
| 2399 | self.notebook.SetSelectionByName('layers')
|
|---|
| 2400 | self.GetLayerTree().AddLayer('command')
|
|---|
| 2401 |
|
|---|
| 2402 | # show map display
|
|---|
| 2403 | self.GetMapDisplay().Show()
|
|---|
| 2404 |
|
|---|
| 2405 | def OnAddGroup(self, event):
|
|---|
| 2406 | """Add layer group"""
|
|---|
| 2407 | # start new map display if no display is available
|
|---|
| 2408 | if not self.currentPage:
|
|---|
| 2409 | self.NewDisplay(show=True)
|
|---|
| 2410 |
|
|---|
| 2411 | self.notebook.SetSelectionByName('layers')
|
|---|
| 2412 | self.GetLayerTree().AddLayer('group')
|
|---|
| 2413 |
|
|---|
| 2414 | # show map display
|
|---|
| 2415 | self.GetMapDisplay().Show()
|
|---|
| 2416 |
|
|---|
| 2417 | def OnAddGrid(self, event):
|
|---|
| 2418 | """Add grid map layer to the current layer tree"""
|
|---|
| 2419 | self.notebook.SetSelectionByName('layers')
|
|---|
| 2420 | self.GetLayerTree().AddLayer('grid')
|
|---|
| 2421 |
|
|---|
| 2422 | def OnAddGeodesic(self, event):
|
|---|
| 2423 | """Add geodesic line map layer to the current layer tree"""
|
|---|
| 2424 | self.notebook.SetSelectionByName('layers')
|
|---|
| 2425 | self.GetLayerTree().AddLayer('geodesic')
|
|---|
| 2426 |
|
|---|
| 2427 | def OnAddRhumb(self, event):
|
|---|
| 2428 | """Add rhumb map layer to the current layer tree"""
|
|---|
| 2429 | self.notebook.SetSelectionByName('layers')
|
|---|
| 2430 | self.GetLayerTree().AddLayer('rhumb')
|
|---|
| 2431 |
|
|---|
| 2432 | def OnAddLabels(self, event):
|
|---|
| 2433 | """Add vector labels map layer to the current layer tree"""
|
|---|
| 2434 | # start new map display if no display is available
|
|---|
| 2435 | if not self.currentPage:
|
|---|
| 2436 | self.NewDisplay(show=True)
|
|---|
| 2437 |
|
|---|
| 2438 | self.notebook.SetSelectionByName('layers')
|
|---|
| 2439 | self.GetLayerTree().AddLayer('labels')
|
|---|
| 2440 |
|
|---|
| 2441 | # show map display
|
|---|
| 2442 | self.GetMapDisplay().Show()
|
|---|
| 2443 |
|
|---|
| 2444 | def OnShowRegionExtent(self, event):
|
|---|
| 2445 | """Add vector labels map layer to the current layer tree"""
|
|---|
| 2446 | # start new map display if no display is available
|
|---|
| 2447 | if not self.currentPage:
|
|---|
| 2448 | self.NewDisplay(show=True)
|
|---|
| 2449 | # get current map display
|
|---|
| 2450 | mapdisp = self.GetMapDisplay()
|
|---|
| 2451 | # change the property
|
|---|
| 2452 | mapdisp.mapWindowProperties.showRegion = True
|
|---|
| 2453 | # show map display (user said show so make sure it is visible)
|
|---|
| 2454 | mapdisp.Show()
|
|---|
| 2455 | # redraw map if auto-rendering is enabled
|
|---|
| 2456 | # seems little too low level for this place
|
|---|
| 2457 | # no redraw when Render is unchecked
|
|---|
| 2458 | if mapdisp.IsAutoRendered():
|
|---|
| 2459 | mapdisp.GetMapWindow().UpdateMap(render=False)
|
|---|
| 2460 |
|
|---|
| 2461 | def OnDeleteLayer(self, event):
|
|---|
| 2462 | """Remove selected map layer from the current layer Tree
|
|---|
| 2463 | """
|
|---|
| 2464 | if not self.currentPage or not self.GetLayerTree().layer_selected:
|
|---|
| 2465 | self.MsgNoLayerSelected()
|
|---|
| 2466 | return
|
|---|
| 2467 |
|
|---|
| 2468 | if UserSettings.Get(
|
|---|
| 2469 | group='manager', key='askOnRemoveLayer', subkey='enabled'):
|
|---|
| 2470 | layerName = ''
|
|---|
| 2471 | for item in self.GetLayerTree().GetSelections():
|
|---|
| 2472 | name = self.GetLayerTree().GetItemText(item)
|
|---|
| 2473 | idx = name.find('(' + _('opacity:'))
|
|---|
| 2474 | if idx > -1:
|
|---|
| 2475 | layerName += '<' + name[:idx].strip(' ') + '>,\n'
|
|---|
| 2476 | else:
|
|---|
| 2477 | layerName += '<' + name + '>,\n'
|
|---|
| 2478 | layerName = layerName.rstrip(',\n')
|
|---|
| 2479 |
|
|---|
| 2480 | if len(layerName) > 2: # <>
|
|---|
| 2481 | message = _("Do you want to remove map layer(s)\n%s\n"
|
|---|
| 2482 | "from layer tree?") % layerName
|
|---|
| 2483 | else:
|
|---|
| 2484 | message = _("Do you want to remove selected map layer(s) "
|
|---|
| 2485 | "from layer tree?")
|
|---|
| 2486 |
|
|---|
| 2487 | dlg = wx.MessageDialog(
|
|---|
| 2488 | parent=self,
|
|---|
| 2489 | message=message,
|
|---|
| 2490 | caption=_("Remove map layer"),
|
|---|
| 2491 | style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION)
|
|---|
| 2492 |
|
|---|
| 2493 | if dlg.ShowModal() != wx.ID_YES:
|
|---|
| 2494 | dlg.Destroy()
|
|---|
| 2495 | return
|
|---|
| 2496 |
|
|---|
| 2497 | dlg.Destroy()
|
|---|
| 2498 |
|
|---|
| 2499 | for layer in self.GetLayerTree().GetSelections():
|
|---|
| 2500 | if self.GetLayerTree().GetLayerInfo(layer, key='type') == 'group':
|
|---|
| 2501 | self.GetLayerTree().DeleteChildren(layer)
|
|---|
| 2502 | self.GetLayerTree().Delete(layer)
|
|---|
| 2503 |
|
|---|
| 2504 | def OnKeyDown(self, event):
|
|---|
| 2505 | """Key pressed"""
|
|---|
| 2506 | kc = event.GetKeyCode()
|
|---|
| 2507 |
|
|---|
| 2508 | if event.ControlDown():
|
|---|
| 2509 | if kc == wx.WXK_TAB:
|
|---|
| 2510 | # switch layer list / command output
|
|---|
| 2511 | if self.notebook.GetSelection() == self.notebook.GetPageIndexByName('layers'):
|
|---|
| 2512 | self.notebook.SetSelectionByName('output')
|
|---|
| 2513 | else:
|
|---|
| 2514 | self.notebook.SetSelectionByName('layers')
|
|---|
| 2515 |
|
|---|
| 2516 | try:
|
|---|
| 2517 | ckc = chr(kc)
|
|---|
| 2518 | except ValueError:
|
|---|
| 2519 | event.Skip()
|
|---|
| 2520 | return
|
|---|
| 2521 |
|
|---|
| 2522 | if event.CtrlDown():
|
|---|
| 2523 | if kc == 'R':
|
|---|
| 2524 | self.OnAddRaster(None)
|
|---|
| 2525 | elif kc == 'V':
|
|---|
| 2526 | self.OnAddVector(None)
|
|---|
| 2527 |
|
|---|
| 2528 | event.Skip()
|
|---|
| 2529 |
|
|---|
| 2530 | def OnCloseWindow(self, event):
|
|---|
| 2531 | """Cleanup when wxGUI is quitted"""
|
|---|
| 2532 | self._closeWindow(event)
|
|---|
| 2533 |
|
|---|
| 2534 | def OnCloseWindowOrExit(self, event):
|
|---|
| 2535 | """Cleanup when wxGUI is quitted
|
|---|
| 2536 |
|
|---|
| 2537 | Ask user also to quit GRASS including terminal
|
|---|
| 2538 | """
|
|---|
| 2539 | dlg = QuitDialog(self)
|
|---|
| 2540 | ret = dlg.ShowModal()
|
|---|
| 2541 | dlg.Destroy()
|
|---|
| 2542 | if ret != wx.ID_CANCEL:
|
|---|
| 2543 | self._closeWindow(event)
|
|---|
| 2544 | if ret == wx.ID_YES:
|
|---|
| 2545 | self._quitGRASS()
|
|---|
| 2546 |
|
|---|
| 2547 | def _closeWindow(self, event):
|
|---|
| 2548 | """Close wxGUI"""
|
|---|
| 2549 | # save command protocol if actived
|
|---|
| 2550 | if self.goutput.btnCmdProtocol.GetValue():
|
|---|
| 2551 | self.goutput.CmdProtocolSave()
|
|---|
| 2552 |
|
|---|
| 2553 | if not self.currentPage:
|
|---|
| 2554 | self._auimgr.UnInit()
|
|---|
| 2555 | self.Destroy()
|
|---|
| 2556 | return
|
|---|
| 2557 |
|
|---|
| 2558 | if UserSettings.Get(group='manager', key='askOnQuit',
|
|---|
| 2559 | subkey='enabled') and self.workspaceChanged:
|
|---|
| 2560 | maptree = self.GetLayerTree()
|
|---|
| 2561 |
|
|---|
| 2562 | if self.workspaceFile:
|
|---|
| 2563 | message = _("Do you want to save changes in the workspace?")
|
|---|
| 2564 | else:
|
|---|
| 2565 | message = _("Do you want to store current settings "
|
|---|
| 2566 | "to workspace file?")
|
|---|
| 2567 |
|
|---|
| 2568 | # ask user to save current settings
|
|---|
| 2569 | if maptree.GetCount() > 0:
|
|---|
| 2570 | dlg = wx.MessageDialog(self,
|
|---|
| 2571 | message=message,
|
|---|
| 2572 | caption=_("Quit GRASS GUI"),
|
|---|
| 2573 | style=wx.YES_NO | wx.YES_DEFAULT |
|
|---|
| 2574 | wx.CANCEL | wx.ICON_QUESTION | wx.CENTRE)
|
|---|
| 2575 | ret = dlg.ShowModal()
|
|---|
| 2576 | dlg.Destroy()
|
|---|
| 2577 | if ret == wx.ID_YES:
|
|---|
| 2578 | if not self.workspaceFile:
|
|---|
| 2579 | self.OnWorkspaceSaveAs()
|
|---|
| 2580 | else:
|
|---|
| 2581 | self.SaveToWorkspaceFile(self.workspaceFile)
|
|---|
| 2582 | elif ret == wx.ID_CANCEL:
|
|---|
| 2583 | # when called from menu, it gets CommandEvent and not
|
|---|
| 2584 | # CloseEvent
|
|---|
| 2585 | if hasattr(event, 'Veto'):
|
|---|
| 2586 | event.Veto()
|
|---|
| 2587 | return
|
|---|
| 2588 |
|
|---|
| 2589 | # don't ask any more...
|
|---|
| 2590 | UserSettings.Set(group='manager', key='askOnQuit', subkey='enabled',
|
|---|
| 2591 | value=False)
|
|---|
| 2592 |
|
|---|
| 2593 | self.OnDisplayCloseAll()
|
|---|
| 2594 |
|
|---|
| 2595 | self.notebookLayers.DeleteAllPages()
|
|---|
| 2596 | self._auimgr.UnInit()
|
|---|
| 2597 | self.Destroy()
|
|---|
| 2598 |
|
|---|
| 2599 | def _quitGRASS(self):
|
|---|
| 2600 | """Quit GRASS terminal"""
|
|---|
| 2601 | try:
|
|---|
| 2602 | shellPid = int(grass.gisenv()['PID'])
|
|---|
| 2603 | except:
|
|---|
| 2604 | grass.warning(_("Unable to exit GRASS shell: unknown PID"))
|
|---|
| 2605 | return
|
|---|
| 2606 |
|
|---|
| 2607 | Debug.msg(1, "Exiting shell with pid={0}".format(shellPid))
|
|---|
| 2608 | import signal
|
|---|
| 2609 | os.kill(shellPid, signal.SIGTERM)
|
|---|
| 2610 |
|
|---|
| 2611 | def MsgNoLayerSelected(self):
|
|---|
| 2612 | """Show dialog message 'No layer selected'"""
|
|---|
| 2613 | wx.MessageBox(parent=self,
|
|---|
| 2614 | message=_("No map layer selected. Operation canceled."),
|
|---|
| 2615 | caption=_("Message"),
|
|---|
| 2616 | style=wx.OK | wx.ICON_INFORMATION | wx.CENTRE)
|
|---|
| 2617 |
|
|---|
| 2618 | def MsgDisplayResolution(self, limitText=None):
|
|---|
| 2619 | """Returns dialog for d.rast.num, d.rast.arrow
|
|---|
| 2620 | when display resolution is not constrained
|
|---|
| 2621 |
|
|---|
| 2622 | :param limitText: adds a note about cell limit
|
|---|
| 2623 | """
|
|---|
| 2624 | message = _("Display resolution is currently not constrained to "
|
|---|
| 2625 | "computational settings. "
|
|---|
| 2626 | "It's suggested to constrain map to region geometry. "
|
|---|
| 2627 | "Do you want to constrain "
|
|---|
| 2628 | "the resolution?")
|
|---|
| 2629 | if limitText:
|
|---|
| 2630 | message += "\n\n%s" % _(limitText)
|
|---|
| 2631 | dlg = wx.MessageDialog(
|
|---|
| 2632 | parent=self, message=message,
|
|---|
| 2633 | caption=_("Constrain map to region geometry?"),
|
|---|
| 2634 | style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION | wx.CENTRE)
|
|---|
| 2635 | return dlg
|
|---|