catalog.py 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. """
  2. @package datacatalog::catalog
  3. @brief Data catalog
  4. Classes:
  5. - datacatalog::DataCatalog
  6. (C) 2014-2018 by Tereza Fiedlerova, and the GRASS Development Team
  7. This program is free software under the GNU General Public
  8. License (>=v2). Read the file COPYING that comes with GRASS
  9. for details.
  10. @author Tereza Fiedlerova
  11. @author Linda Kladivova l.kladivova@seznam.cz
  12. """
  13. import wx
  14. import os
  15. from core.debug import Debug
  16. from datacatalog.tree import DataCatalogTree
  17. from datacatalog.toolbars import DataCatalogToolbar
  18. from gui_core.infobar import InfoBar
  19. from datacatalog.infomanager import DataCatalogInfoManager
  20. from gui_core.wrap import Menu
  21. from gui_core.forms import GUI
  22. from grass.script import gisenv
  23. from grass.pydispatch.signal import Signal
  24. from grass.grassdb.manage import split_mapset_path
  25. from grass.grassdb.checks import (
  26. get_reason_id_mapset_not_usable,
  27. is_fallback_session,
  28. is_first_time_user,
  29. )
  30. class DataCatalog(wx.Panel):
  31. """Data catalog panel"""
  32. def __init__(
  33. self,
  34. parent,
  35. giface=None,
  36. id=wx.ID_ANY,
  37. title=_("Data catalog"),
  38. name="catalog",
  39. **kwargs,
  40. ):
  41. """Panel constructor """
  42. self.showNotification = Signal("DataCatalog.showNotification")
  43. self.parent = parent
  44. self.baseTitle = title
  45. self.giface = giface
  46. wx.Panel.__init__(self, parent=parent, id=id, **kwargs)
  47. self.SetName("DataCatalog")
  48. Debug.msg(1, "DataCatalog.__init__()")
  49. # toolbar
  50. self.toolbar = DataCatalogToolbar(parent=self)
  51. # tree with layers
  52. self.tree = DataCatalogTree(self, giface=giface)
  53. self.tree.showNotification.connect(self.showNotification)
  54. # infobar for data catalog
  55. delay = 2000
  56. self.infoBar = InfoBar(self)
  57. self.giface.currentMapsetChanged.connect(self.dismissInfobar)
  58. # infobar manager for data catalog
  59. self.infoManager = DataCatalogInfoManager(
  60. infobar=self.infoBar, giface=self.giface
  61. )
  62. self.tree.showImportDataInfo.connect(self.showImportDataInfo)
  63. # some layout
  64. self._layout()
  65. # show infobar for first-time user if applicable
  66. if is_first_time_user():
  67. # show data structure infobar for first-time user
  68. wx.CallLater(delay, self.showDataStructureInfo)
  69. # show infobar if last used mapset is not usable
  70. if is_fallback_session():
  71. # get reason why last used mapset is not usable
  72. last_mapset_path = gisenv()["LAST_MAPSET_PATH"]
  73. self.reason_id = get_reason_id_mapset_not_usable(last_mapset_path)
  74. if self.reason_id in ("non-existent", "invalid", "different-owner"):
  75. # show non-standard situation info
  76. wx.CallLater(delay, self.showFallbackSessionInfo)
  77. elif self.reason_id == "locked":
  78. # show info allowing to switch to locked mapset
  79. wx.CallLater(delay, self.showLockedMapsetInfo)
  80. def _layout(self):
  81. """Do layout"""
  82. sizer = wx.BoxSizer(wx.VERTICAL)
  83. sizer.Add(self.toolbar, proportion=0, flag=wx.EXPAND)
  84. sizer.Add(self.infoBar, proportion=0, flag=wx.EXPAND)
  85. sizer.Add(self.tree.GetControl(), proportion=1, flag=wx.EXPAND)
  86. self.SetAutoLayout(True)
  87. self.SetSizer(sizer)
  88. self.Fit()
  89. self.Layout()
  90. def showDataStructureInfo(self):
  91. self.infoManager.ShowDataStructureInfo(self.OnCreateLocation)
  92. def showLockedMapsetInfo(self):
  93. self.infoManager.ShowLockedMapsetInfo(self.OnSwitchToLastUsedMapset)
  94. def showFallbackSessionInfo(self):
  95. self.infoManager.ShowFallbackSessionInfo(self.reason_id)
  96. def showImportDataInfo(self):
  97. self.infoManager.ShowImportDataInfo(
  98. self.OnImportOgrLayers, self.OnImportGdalLayers
  99. )
  100. def LoadItems(self):
  101. self.tree.ReloadTreeItems()
  102. def dismissInfobar(self):
  103. if self.infoBar.IsShown():
  104. self.infoBar.Dismiss()
  105. def OnReloadTree(self, event):
  106. """Reload whole tree"""
  107. self.LoadItems()
  108. def OnReloadCurrentMapset(self, event):
  109. """Reload current mapset tree only"""
  110. self.tree.ReloadCurrentMapset()
  111. def OnAddGrassDB(self, event):
  112. """Add grass database"""
  113. dlg = wx.DirDialog(
  114. self, _("Choose GRASS data directory:"), os.getcwd(), wx.DD_DEFAULT_STYLE
  115. )
  116. if dlg.ShowModal() == wx.ID_OK:
  117. grassdatabase = dlg.GetPath()
  118. grassdb_node = self.tree.InsertGrassDb(name=grassdatabase)
  119. # Offer to create a new location
  120. if grassdb_node and not os.listdir(grassdatabase):
  121. message = _("Do you want to create a location?")
  122. dlg2 = wx.MessageDialog(
  123. self,
  124. message=message,
  125. caption=_("Create location?"),
  126. style=wx.YES_NO | wx.YES_DEFAULT | wx.ICON_QUESTION,
  127. )
  128. if dlg2.ShowModal() == wx.ID_YES:
  129. self.tree.CreateLocation(grassdb_node)
  130. dlg2.Destroy()
  131. dlg.Destroy()
  132. def OnCreateMapset(self, event):
  133. """Create new mapset in current location"""
  134. db_node, loc_node, mapset_node = self.tree.GetCurrentDbLocationMapsetNode()
  135. self.tree.CreateMapset(db_node, loc_node)
  136. def OnCreateLocation(self, event):
  137. """Create new location"""
  138. db_node, loc_node, mapset_node = self.tree.GetCurrentDbLocationMapsetNode()
  139. self.tree.CreateLocation(db_node)
  140. def OnDownloadLocation(self, event):
  141. """Download location to current grass database"""
  142. db_node, loc_node, mapset_node = self.tree.GetCurrentDbLocationMapsetNode()
  143. self.tree.DownloadLocation(db_node)
  144. def OnSwitchToLastUsedMapset(self, event):
  145. """Switch to last used mapset"""
  146. last_mapset_path = gisenv()["LAST_MAPSET_PATH"]
  147. grassdb, location, mapset = split_mapset_path(last_mapset_path)
  148. self.tree.SwitchMapset(grassdb, location, mapset)
  149. def OnImportGdalLayers(self, event):
  150. """Convert multiple GDAL layers to GRASS raster map layers"""
  151. from modules.import_export import GdalImportDialog
  152. dlg = GdalImportDialog(parent=self, giface=self.giface)
  153. dlg.CentreOnScreen()
  154. dlg.Show()
  155. def OnImportOgrLayers(self, event):
  156. """Convert multiple OGR layers to GRASS vector map layers"""
  157. from modules.import_export import OgrImportDialog
  158. dlg = OgrImportDialog(parent=self, giface=self.giface)
  159. dlg.CentreOnScreen()
  160. dlg.Show()
  161. def OnLinkGdalLayers(self, event):
  162. """Link multiple GDAL layers to GRASS raster map layers"""
  163. from modules.import_export import GdalImportDialog
  164. dlg = GdalImportDialog(parent=self, giface=self.giface, link=True)
  165. dlg.CentreOnScreen()
  166. dlg.Show()
  167. def OnLinkOgrLayers(self, event):
  168. """Links multiple OGR layers to GRASS vector map layers"""
  169. from modules.import_export import OgrImportDialog
  170. dlg = OgrImportDialog(parent=self, giface=self.giface, link=True)
  171. dlg.CentreOnScreen()
  172. dlg.Show()
  173. def OnRasterOutputFormat(self, event):
  174. """Set raster output format handler"""
  175. from modules.import_export import GdalOutputDialog
  176. dlg = GdalOutputDialog(parent=self, ogr=False)
  177. dlg.CentreOnScreen()
  178. dlg.Show()
  179. def OnVectorOutputFormat(self, event):
  180. """Set vector output format handler"""
  181. from modules.import_export import GdalOutputDialog
  182. dlg = GdalOutputDialog(parent=self, ogr=True)
  183. dlg.CentreOnScreen()
  184. dlg.Show()
  185. def GuiParseCommand(self, cmd):
  186. """Generic handler"""
  187. GUI(parent=self, giface=self.giface).ParseCommand(cmd=[cmd])
  188. def OnMoreOptions(self, event):
  189. self.giface.Help(entry="topic_import")
  190. def SetRestriction(self, restrict):
  191. """Allow editing other mapsets or restrict editing to current mapset"""
  192. self.tree.SetRestriction(restrict)
  193. def Filter(self, text, element=None):
  194. self.tree.Filter(text=text, element=element)
  195. def OnImportMenu(self, event):
  196. """Create popup menu for other import options"""
  197. # create submenu
  198. subMenu = Menu()
  199. subitem = wx.MenuItem(
  200. subMenu, wx.ID_ANY, _("Link external raster data [r.external]")
  201. )
  202. subMenu.AppendItem(subitem)
  203. self.Bind(wx.EVT_MENU, self.OnLinkGdalLayers, subitem)
  204. subitem = wx.MenuItem(
  205. subMenu, wx.ID_ANY, _("Link external vector data [v.external]")
  206. )
  207. subMenu.AppendItem(subitem)
  208. self.Bind(wx.EVT_MENU, self.OnLinkOgrLayers, subitem)
  209. subMenu.AppendSeparator()
  210. subitem = wx.MenuItem(
  211. subMenu, wx.ID_ANY, _("Set raster output format [r.external.out]")
  212. )
  213. subMenu.AppendItem(subitem)
  214. self.Bind(wx.EVT_MENU, self.OnRasterOutputFormat, subitem)
  215. subitem = wx.MenuItem(
  216. subMenu, wx.ID_ANY, _("Set vector output format [v.external.out]")
  217. )
  218. subMenu.AppendItem(subitem)
  219. self.Bind(wx.EVT_MENU, self.OnVectorOutputFormat, subitem)
  220. # create menu
  221. menu = Menu()
  222. item = wx.MenuItem(menu, wx.ID_ANY, _("Unpack GRASS raster map [r.unpack]"))
  223. menu.AppendItem(item)
  224. self.Bind(wx.EVT_MENU, lambda evt: self.GuiParseCommand("r.unpack"), item)
  225. item = wx.MenuItem(menu, wx.ID_ANY, _("Unpack GRASS vector map [v.unpack]"))
  226. menu.AppendItem(item)
  227. self.Bind(wx.EVT_MENU, lambda evt: self.GuiParseCommand("v.unpack"), item)
  228. menu.AppendSeparator()
  229. item = wx.MenuItem(
  230. menu, wx.ID_ANY, _("Create raster map from x,y,z data [r.in.xyz]")
  231. )
  232. menu.AppendItem(item)
  233. self.Bind(wx.EVT_MENU, lambda evt: self.GuiParseCommand("r.in.xyz"), item)
  234. item = wx.MenuItem(
  235. menu, wx.ID_ANY, _("Create vector map from x,y,z data [v.in.ascii]")
  236. )
  237. menu.AppendItem(item)
  238. self.Bind(wx.EVT_MENU, lambda evt: self.GuiParseCommand("v.in.ascii"), item)
  239. menu.AppendSeparator()
  240. menu.AppendMenu(wx.ID_ANY, _("Link external data"), subMenu)
  241. menu.AppendSeparator()
  242. item = wx.MenuItem(menu, wx.ID_ANY, _("More options..."))
  243. menu.AppendItem(item)
  244. self.Bind(wx.EVT_MENU, self.OnMoreOptions, item)
  245. self.PopupMenu(menu)
  246. menu.Destroy()