123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421 |
- """!
- @package mapdisp.main
- @brief Start Map Display as standalone application
- Classes:
- - mapdisp::MapApp
- Usage:
- python mapdisp/main.py monitor-identifier /path/to/map/file /path/to/command/file /path/to/env/file
- (C) 2006-2011 by the GRASS Development Team
- This program is free software under the GNU General Public License
- (>=v2). Read the file COPYING that comes with GRASS for details.
- @author Michael Barton
- @author Jachym Cepicky
- @author Martin Landa <landa.martin gmail.com>
- @author Vaclav Petras <wenzeslaus gmail.com> (MapFrameBase)
- @author Anna Kratochvilova <kratochanna gmail.com> (MapFrameBase)
- """
- import os
- import sys
- if __name__ == "__main__":
- sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'wxpython'))
- from core import globalvar
- import wx
- from core import utils
- from core.giface import StandaloneGrassInterface
- from core.gcmd import RunCommand
- from core.render import Map, MapLayer
- from mapdisp.frame import MapFrame
- from grass.script import core as grass
- from core.debug import Debug
- from core.settings import UserSettings
- # for standalone app
- monFile = { 'cmd' : None,
- 'map' : None,
- 'env' : None,
- }
- monName = None
- monSize = list(globalvar.MAP_WINDOW_SIZE)
- class DMonMap(Map):
- def __init__(self, gisrc = None, cmdfile = None, mapfile = None, envfile = None, monitor = None):
- """!Map composition (stack of map layers and overlays)
- @param cmdline full path to the cmd file (defined by d.mon)
- @param mapfile full path to the map file (defined by d.mon)
- @param envfile full path to the env file (defined by d.mon)
- @param monitor name of monitor (defined by d.mon)
- """
- Map.__init__(self)
- # environment settings
- self.env = dict()
- self.cmdfile = cmdfile
- self.envfile = envfile
- self.monitor = monitor
- if mapfile:
- self.mapfileCmd = mapfile
- self.maskfileCmd = os.path.splitext(mapfile)[0] + '.pgm'
- # generated file for g.pnmcomp output for rendering the map
- self.mapfile = grass.tempfile(create = False) + '.ppm'
- self._writeEnvFile(self.env) # self.env is expected to be defined in parent class
- self._writeEnvFile({"GRASS_PNG_READ" : "TRUE"})
- def GetLayersFromCmdFile(self):
- """!Get list of map layers from cmdfile
- """
- if not self.cmdfile:
- return
-
- nlayers = 0
- try:
- fd = open(self.cmdfile, 'r')
- existingLayers = self.GetListOfLayers()
- for line in fd.readlines():
- cmd = utils.split(line.strip())
- ltype = None
- try:
- ltype = utils.command2ltype[cmd[0]]
- except KeyError:
- grass.warning(_("Unsupported command %s.") % cmd[0])
- continue
- name = utils.GetLayerNameFromCmd(cmd, fullyQualified = True,
- layerType = ltype)[0]
- # creating temporary layer object to compare commands
- # neccessary to get the same format
- # supposing that there are no side effects
- tmpMapLayer = MapLayer(ltype = ltype, name = name,
- cmd = cmd, Map = None,
- active = False, hidden = True,
- opacity = 0)
- exists = False
- for layer in existingLayers:
- if layer.GetCmd(string=True) == tmpMapLayer.GetCmd(string=True):
- exists = True
- break
- if exists:
- continue
- self.AddLayer(ltype = ltype, command = cmd, active = False, name = name)
- nlayers += 1
- except IOError, e:
- grass.warning(_("Unable to read cmdfile '%(cmd)s'. Details: %(det)s") % \
- { 'cmd' : self.cmdfile, 'det' : e })
- return
-
- fd.close()
- Debug.msg(1, "Map.GetLayersFromCmdFile(): cmdfile=%s" % self.cmdfile)
- Debug.msg(1, " nlayers=%d" % nlayers)
-
- def _parseCmdFile(self):
- """!Parse cmd file for standalone application
- """
- nlayers = 0
- try:
- fd = open(self.cmdfile, 'r')
- grass.try_remove(self.mapfile)
- cmdLines = fd.readlines()
- RunCommand('g.gisenv',
- set = 'MONITOR_%s_CMDFILE=' % self.monitor)
- for cmd in cmdLines:
- cmdStr = utils.split(cmd.strip())
- cmd = utils.CmdToTuple(cmdStr)
- RunCommand(cmd[0], **cmd[1])
- nlayers += 1
-
- RunCommand('g.gisenv',
- set = 'MONITOR_%s_CMDFILE=%s' % (self.monitor, self.cmdfile))
- except IOError, e:
- grass.warning(_("Unable to read cmdfile '%(cmd)s'. Details: %(det)s") % \
- { 'cmd' : self.cmdfile, 'det' : e })
- return
-
- fd.close()
- Debug.msg(1, "Map.__parseCmdFile(): cmdfile=%s" % self.cmdfile)
- Debug.msg(1, " nlayers=%d" % nlayers)
-
- return nlayers
- def _renderCmdFile(self, force, windres):
- if not force:
- return ([self.mapfileCmd],
- [self.maskfileCmd],
- ['1.0'])
-
- region = os.environ["GRASS_REGION"] = self.SetRegion(windres)
- self._writeEnvFile({'GRASS_REGION' : region})
- currMon = grass.gisenv()['MONITOR']
- if currMon != self.monitor:
- RunCommand('g.gisenv',
- set = 'MONITOR=%s' % self.monitor)
-
- grass.try_remove(self.mapfileCmd) # GRASS_PNG_READ is TRUE
-
- nlayers = self._parseCmdFile()
- if self.overlays:
- RunCommand('g.gisenv',
- unset = 'MONITOR') # GRASS_RENDER_IMMEDIATE doesn't like monitors
- driver = UserSettings.Get(group = 'display', key = 'driver', subkey = 'type')
- if driver == 'png':
- os.environ["GRASS_RENDER_IMMEDIATE"] = "png"
- else:
- os.environ["GRASS_RENDER_IMMEDIATE"] = "cairo"
- self._renderLayers(overlaysOnly = True)
- del os.environ["GRASS_RENDER_IMMEDIATE"]
- RunCommand('g.gisenv',
- set = 'MONITOR=%s' % currMon)
-
- if currMon != self.monitor:
- RunCommand('g.gisenv',
- set = 'MONITOR=%s' % currMon)
-
- if nlayers > 0:
- return ([self.mapfileCmd],
- [self.maskfileCmd],
- ['1.0'])
- else:
- return ([], [], [])
-
- def _writeEnvFile(self, data):
- """!Write display-related variable to the file (used for
- standalone app)
- """
- if not self.envfile:
- return
-
- try:
- fd = open(self.envfile, "r")
- for line in fd.readlines():
- key, value = line.split('=')
- if key not in data.keys():
- data[key] = value
- fd.close()
-
- fd = open(self.envfile, "w")
- for k, v in data.iteritems():
- fd.write('%s=%s\n' % (k.strip(), str(v).strip()))
- except IOError, e:
- grass.warning(_("Unable to open file '%(file)s' for writting. Details: %(det)s") % \
- { 'cmd' : self.envfile, 'det' : e })
- return
-
- fd.close()
-
- def ChangeMapSize(self, (width, height)):
- """!Change size of rendered map.
-
- @param width,height map size
- """
- Map.ChangeMapSize(self, (width, height))
-
- self._writeEnvFile({'GRASS_WIDTH' : self.width,
- 'GRASS_HEIGHT' : self.height})
-
- def GetMapsMasksAndOpacities(self, force, windres):
- """!
- Used by Render function.
-
- @return maps, masks, opacities
- """
- return self._renderCmdFile(force, windres)
- class Layer(object):
- def __init__(self, maplayer):
- self._maplayer = maplayer
- def __getattr__(self, name):
- if name == 'cmd':
- return utils.CmdTupleToList(self._maplayer.GetCmd())
- elif hasattr(self._maplayer, name):
- return getattr(self._maplayer, name)
- elif name == 'maplayer':
- return self._maplayer
- elif name == 'type':
- return self._maplayer.GetType()
- #elif name == 'ctrl':
- elif name == 'label':
- return self._maplayer.GetName()
- #elif name == 'maplayer' : None,
- #elif name == 'propwin':
- class LayerList(object):
- def __init__(self, map):
- self._map = map
- # def __iter__(self):
- # for in :
- # yield
- def GetSelectedLayers(self, checkedOnly=True):
- # hidden and selected vs checked and selected
- items = self._map.GetListOfLayers()
- layers = []
- for item in items:
- layer = Layer(item)
- layers.append(layer)
- return layers
- class DMonGrassInterface(StandaloneGrassInterface):
- def __init__(self, mapframe):
- StandaloneGrassInterface.__init__(self)
- self._mapframe = mapframe
- def GetLayerList(self):
- return LayerList(self._mapframe.GetMap())
- class DMonFrame(MapFrame):
- def OnZoomToMap(self, event):
- layers = self.MapWindow.GetMap().GetListOfLayers()
- self.MapWindow.ZoomToMap(layers = layers)
-
- class MapApp(wx.App):
- def OnInit(self):
- if not globalvar.CheckWxVersion([2, 9]):
- wx.InitAllImageHandlers()
- if __name__ == "__main__":
- self.cmdTimeStamp = os.path.getmtime(monFile['cmd'])
- self.Map = DMonMap(cmdfile = monFile['cmd'], mapfile = monFile['map'],
- envfile = monFile['env'], monitor = monName)
- else:
- self.Map = None
- # actual use of StandaloneGrassInterface not yet tested
- # needed for adding functionality in future
- giface = DMonGrassInterface(None)
- self.mapFrm = DMonFrame(parent = None, id = wx.ID_ANY, Map = self.Map,
- giface = giface, size = monSize)
- # FIXME: hack to solve dependency
- giface._mapframe = self.mapFrm
- # self.SetTopWindow(Map)
- self.mapFrm.GetMapWindow().SetAlwaysRenderEnabled(True)
- self.mapFrm.Show()
-
- if __name__ == "__main__":
- self.timer = wx.PyTimer(self.watcher)
- #check each 0.5s
- global mtime
- mtime = 500
- self.timer.Start(mtime)
-
- return True
-
- def OnExit(self):
- if __name__ == "__main__":
- # stop the timer
- # self.timer.Stop()
- # terminate thread
- for f in monFile.itervalues():
- grass.try_remove(f)
-
- def watcher(self):
- """!Redraw, if new layer appears (check's timestamp of
- cmdfile)
- """
- try:
- # GISBASE and other sytem enviromental variables can not be used
- # since the process inherited them from GRASS
- # raises exception when vaiable does not exists
- grass.gisenv()['GISDBASE']
- except KeyError:
- self.timer.Stop()
- return
-
- # todo: events
- try:
- currentCmdFileTime = os.path.getmtime(monFile['cmd'])
- if currentCmdFileTime > self.cmdTimeStamp:
- self.timer.Stop()
- self.cmdTimeStamp = currentCmdFileTime
- self.mapFrm.OnDraw(None)
- self.mapFrm.GetMap().GetLayersFromCmdFile()
- self.timer.Start(mtime)
- except OSError, e:
- grass.warning("%s" % e)
- self.timer.Stop()
- def GetMapFrame(self):
- """!Get Map Frame instance"""
- return self.mapFrm
- if __name__ == "__main__":
- # set command variable
- if len(sys.argv) < 5:
- print __doc__
- sys.exit(1)
-
- monName = sys.argv[1]
- monFile = { 'map' : sys.argv[2],
- 'cmd' : sys.argv[3],
- 'env' : sys.argv[4],
- }
- if len(sys.argv) >= 6:
- try:
- monSize[0] = int(sys.argv[5])
- except ValueError:
- pass
-
- if len(sys.argv) == 7:
- try:
- monSize[1] = int(sys.argv[6])
- except ValueError:
- pass
- import gettext
- gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
-
- grass.verbose(_("Starting map display <%s>...") % (monName))
- RunCommand('g.gisenv',
- set = 'MONITOR_%s_PID=%d' % (monName, os.getpid()))
-
- gmMap = MapApp(0)
- # set title
- gmMap.mapFrm.SetTitle(_("GRASS GIS Map Display: " +
- monName +
- " - Location: " + grass.gisenv()["LOCATION_NAME"]))
-
- gmMap.MainLoop()
-
- grass.verbose(_("Stopping map display <%s>...") % (monName))
- # clean up GRASS env variables
- env = grass.gisenv()
- env_name = 'MONITOR_%s' % monName
- for key in env.keys():
- if key.find(env_name) == 0:
- RunCommand('g.gisenv',
- unset = '%s' % key)
- if key == 'MONITOR' and env[key] == monName:
- RunCommand('g.gisenv',
- unset = '%s' % key)
-
- sys.exit(0)
|