main.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354
  1. """!
  2. @package mapdisp.main
  3. @brief Start Map Display as standalone application
  4. Classes:
  5. - mapdisp::DMonMap
  6. - mapdisp::Layer
  7. - mapdisp::LayerList
  8. - mapdisp::DMonGrassInterface
  9. - mapdisp::DMonFrame
  10. - mapdisp::MapApp
  11. Usage:
  12. python mapdisp/main.py monitor-identifier /path/to/map/file /path/to/command/file /path/to/env/file
  13. (C) 2006-2013 by the GRASS Development Team
  14. This program is free software under the GNU General Public License
  15. (>=v2). Read the file COPYING that comes with GRASS for details.
  16. @author Michael Barton
  17. @author Jachym Cepicky
  18. @author Martin Landa <landa.martin gmail.com>
  19. @author Vaclav Petras <wenzeslaus gmail.com> (MapFrameBase)
  20. @author Anna Kratochvilova <kratochanna gmail.com> (MapFrameBase)
  21. """
  22. import os
  23. import sys
  24. if __name__ == "__main__":
  25. sys.path.append(os.path.join(os.getenv('GISBASE'), 'etc', 'gui', 'wxpython'))
  26. from core import globalvar
  27. import wx
  28. from core import utils
  29. from core.giface import StandaloneGrassInterface
  30. from core.gcmd import RunCommand
  31. from core.render import Map, MapLayer
  32. from mapdisp.frame import MapFrame
  33. from grass.script import core as grass
  34. from core.debug import Debug
  35. from core.settings import UserSettings
  36. # for standalone app
  37. monFile = { 'cmd' : None,
  38. 'map' : None,
  39. 'env' : None,
  40. }
  41. monName = None
  42. monSize = list(globalvar.MAP_WINDOW_SIZE)
  43. class DMonMap(Map):
  44. def __init__(self, giface, cmdfile=None, mapfile=None):
  45. """!Map composition (stack of map layers and overlays)
  46. @param cmdline full path to the cmd file (defined by d.mon)
  47. @param mapfile full path to the map file (defined by d.mon)
  48. """
  49. Map.__init__(self)
  50. self._giface = giface
  51. # environment settings
  52. self.env = dict()
  53. self.cmdfile = cmdfile
  54. if mapfile:
  55. self.mapfileCmd = mapfile
  56. self.maskfileCmd = os.path.splitext(mapfile)[0] + '.pgm'
  57. # generated file for g.pnmcomp output for rendering the map
  58. self.mapfile = monFile['map'] + '.ppm'
  59. def GetLayersFromCmdFile(self):
  60. """!Get list of map layers from cmdfile
  61. """
  62. if not self.cmdfile:
  63. return
  64. nlayers = 0
  65. try:
  66. fd = open(self.cmdfile, 'r')
  67. existingLayers = self.GetListOfLayers()
  68. for line in fd.readlines():
  69. cmd = utils.split(line.strip())
  70. ltype = None
  71. try:
  72. ltype = utils.command2ltype[cmd[0]]
  73. except KeyError:
  74. grass.warning(_("Unsupported command %s.") % cmd[0])
  75. continue
  76. name = utils.GetLayerNameFromCmd(cmd, fullyQualified = True,
  77. layerType = ltype)[0]
  78. # creating temporary layer object to compare commands
  79. # neccessary to get the same format
  80. # supposing that there are no side effects
  81. tmpMapLayer = MapLayer(ltype = ltype, name = name,
  82. cmd = cmd, Map = None,
  83. active = False, hidden = True,
  84. opacity = 0)
  85. exists = False
  86. for layer in existingLayers:
  87. if layer.GetCmd(string=True) == tmpMapLayer.GetCmd(string=True):
  88. exists = True
  89. break
  90. if exists:
  91. continue
  92. Map.AddLayer(self, ltype = ltype, command = cmd, active = True, name = name)
  93. nlayers += 1
  94. except IOError, e:
  95. grass.warning(_("Unable to read cmdfile '%(cmd)s'. Details: %(det)s") % \
  96. { 'cmd' : self.cmdfile, 'det' : e })
  97. return
  98. fd.close()
  99. if nlayers:
  100. self._giface.updateMap.emit()
  101. Debug.msg(1, "Map.GetLayersFromCmdFile(): cmdfile=%s" % self.cmdfile)
  102. Debug.msg(1, " nlayers=%d" % nlayers)
  103. def Render(self, *args, **kwargs):
  104. """!Render layer to image.
  105. For input params and returned data see overridden method in Map class.
  106. """
  107. currMon = grass.gisenv()['MONITOR']
  108. RunCommand('g.gisenv',
  109. unset = 'MONITOR') # GRASS_RENDER_IMMEDIATE doesn't like monitors
  110. ret = Map.Render(self, *args, **kwargs)
  111. RunCommand('g.gisenv',
  112. set = 'MONITOR=%s' % currMon)
  113. return ret
  114. def AddLayer(self, *args, **kwargs):
  115. """!Adds generic map layer to list of layers.
  116. For input params and returned data see overridden method in Map class.
  117. """
  118. currMon = grass.gisenv()['MONITOR']
  119. RunCommand('g.gisenv',
  120. unset = 'MONITOR') # GRASS_RENDER_IMMEDIATE doesn't like monitors
  121. driver = UserSettings.Get(group = 'display', key = 'driver', subkey = 'type')
  122. if driver == 'png':
  123. os.environ["GRASS_RENDER_IMMEDIATE"] = "png"
  124. else:
  125. os.environ["GRASS_RENDER_IMMEDIATE"] = "cairo"
  126. layer = Map.AddLayer(self, *args, **kwargs)
  127. del os.environ["GRASS_RENDER_IMMEDIATE"]
  128. RunCommand('g.gisenv',
  129. set = 'MONITOR=%s' % currMon)
  130. return layer
  131. class Layer(object):
  132. def __init__(self, maplayer):
  133. self._maplayer = maplayer
  134. def __getattr__(self, name):
  135. if name == 'cmd':
  136. return utils.CmdTupleToList(self._maplayer.GetCmd())
  137. elif hasattr(self._maplayer, name):
  138. return getattr(self._maplayer, name)
  139. elif name == 'maplayer':
  140. return self._maplayer
  141. elif name == 'type':
  142. return self._maplayer.GetType()
  143. #elif name == 'ctrl':
  144. elif name == 'label':
  145. return self._maplayer.GetName()
  146. #elif name == 'maplayer' : None,
  147. #elif name == 'propwin':
  148. class LayerList(object):
  149. def __init__(self, map):
  150. self._map = map
  151. # def __iter__(self):
  152. # for in :
  153. # yield
  154. def GetSelectedLayers(self, checkedOnly=True):
  155. # hidden and selected vs checked and selected
  156. items = self._map.GetListOfLayers()
  157. layers = []
  158. for item in items:
  159. layer = Layer(item)
  160. layers.append(layer)
  161. return layers
  162. class DMonGrassInterface(StandaloneGrassInterface):
  163. """!@implements GrassInterface"""
  164. def __init__(self, mapframe):
  165. StandaloneGrassInterface.__init__(self)
  166. self._mapframe = mapframe
  167. def GetLayerList(self):
  168. return LayerList(self._mapframe.GetMap())
  169. class DMonFrame(MapFrame):
  170. def OnZoomToMap(self, event):
  171. layers = self.MapWindow.GetMap().GetListOfLayers()
  172. self.MapWindow.ZoomToMap(layers = layers)
  173. class MapApp(wx.App):
  174. def OnInit(self):
  175. if not globalvar.CheckWxVersion([2, 9]):
  176. wx.InitAllImageHandlers()
  177. # actual use of StandaloneGrassInterface not yet tested
  178. # needed for adding functionality in future
  179. giface = DMonGrassInterface(None)
  180. if __name__ == "__main__":
  181. self.cmdTimeStamp = os.path.getmtime(monFile['cmd'])
  182. self.Map = DMonMap(giface=giface, cmdfile=monFile['cmd'],
  183. mapfile = monFile['map'])
  184. else:
  185. self.Map = None
  186. self.mapFrm = DMonFrame(parent = None, id = wx.ID_ANY, Map = self.Map,
  187. giface = giface, size = monSize)
  188. # FIXME: hack to solve dependency
  189. giface._mapframe = self.mapFrm
  190. # self.SetTopWindow(Map)
  191. self.mapFrm.GetMapWindow().SetAlwaysRenderEnabled(True)
  192. self.mapFrm.Show()
  193. if __name__ == "__main__":
  194. self.timer = wx.PyTimer(self.watcher)
  195. #check each 0.5s
  196. global mtime
  197. mtime = 500
  198. self.timer.Start(mtime)
  199. return True
  200. def OnExit(self):
  201. if __name__ == "__main__":
  202. # stop the timer
  203. # self.timer.Stop()
  204. # terminate thread
  205. for f in monFile.itervalues():
  206. grass.try_remove(f)
  207. def watcher(self):
  208. """!Redraw, if new layer appears (check's timestamp of
  209. cmdfile)
  210. """
  211. try:
  212. # GISBASE and other sytem enviromental variables can not be used
  213. # since the process inherited them from GRASS
  214. # raises exception when vaiable does not exists
  215. grass.gisenv()['GISDBASE']
  216. except KeyError:
  217. self.timer.Stop()
  218. return
  219. # todo: events
  220. try:
  221. currentCmdFileTime = os.path.getmtime(monFile['cmd'])
  222. if currentCmdFileTime > self.cmdTimeStamp:
  223. self.timer.Stop()
  224. self.cmdTimeStamp = currentCmdFileTime
  225. self.mapFrm.GetMap().GetLayersFromCmdFile()
  226. self.timer.Start(mtime)
  227. except OSError, e:
  228. grass.warning("%s" % e)
  229. self.timer.Stop()
  230. def GetMapFrame(self):
  231. """!Get Map Frame instance"""
  232. return self.mapFrm
  233. if __name__ == "__main__":
  234. # set command variable
  235. if len(sys.argv) < 5:
  236. print __doc__
  237. sys.exit(1)
  238. monName = sys.argv[1]
  239. monFile = { 'map' : sys.argv[2],
  240. 'cmd' : sys.argv[3],
  241. 'env' : sys.argv[4],
  242. }
  243. if len(sys.argv) >= 6:
  244. try:
  245. monSize[0] = int(sys.argv[5])
  246. except ValueError:
  247. pass
  248. if len(sys.argv) == 7:
  249. try:
  250. monSize[1] = int(sys.argv[6])
  251. except ValueError:
  252. pass
  253. import gettext
  254. gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)
  255. grass.verbose(_("Starting map display <%s>...") % (monName))
  256. RunCommand('g.gisenv',
  257. set = 'MONITOR_%s_PID=%d' % (monName, os.getpid()))
  258. gmMap = MapApp(0)
  259. # set title
  260. gmMap.mapFrm.SetTitle(_("GRASS GIS Map Display: " +
  261. monName +
  262. " - Location: " + grass.gisenv()["LOCATION_NAME"]))
  263. gmMap.MainLoop()
  264. grass.verbose(_("Stopping map display <%s>...") % (monName))
  265. # clean up GRASS env variables
  266. env = grass.gisenv()
  267. env_name = 'MONITOR_%s' % monName
  268. for key in env.keys():
  269. if key.find(env_name) == 0:
  270. RunCommand('g.gisenv',
  271. unset = '%s' % key)
  272. if key == 'MONITOR' and env[key] == monName:
  273. RunCommand('g.gisenv',
  274. unset = '%s' % key)
  275. sys.exit(0)