Source code for gsdview.gdalbackend.core

# -*- coding: utf-8 -*-

### Copyright (C) 2008-2012 Antonio Valentino <a_valentino@users.sf.net>

### This file is part of GSDView.

### GSDView is free software; you can redistribute it and/or modify
### it under the terms of the GNU General Public License as published by
### the Free Software Foundation; either version 2 of the License, or
### (at your option) any later version.

### GSDView is distributed in the hope that it will be useful,
### but WITHOUT ANY WARRANTY; without even the implied warranty of
### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
### GNU General Public License for more details.

### You should have received a copy of the GNU General Public License
### along with GSDView; if not, write to the Free Software
### Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA.


'''Core GDAL backend functions and classes.'''


import os

from osgeo import gdal

from qt import QtCore, QtGui

from .. import qt4support

from . import widgets
from . import helpers
from . import modelitems
from . import gdalsupport
from . import gdalexectools


__author__ = 'Antonio Valentino <a_valentino@users.sf.net>'
__date__ = '$Date$'
__revision__ = '$Revision$'

__all__ = ['GDALBackend']


[docs]class GDALBackend(QtCore.QObject): # @TODO: # # - fix selection mess # # * trying to re-oped an already open file should select the # corresponding dataset item (no active sub-window change is expected) # # - sub-windows title and window menu _use_exceptions = None # @TODO: fix names @staticmethod
[docs] def UseExceptions(): gdal.UseExceptions() gdal.SetConfigOption('PYHTON_USE_EXCEPTIONS', 'TRUE')
@staticmethod
[docs] def DontUseExceptions(): gdal.DontUseExceptions() gdal.SetConfigOption('PYHTON_USE_EXCEPTIONS', 'FALSE')
@staticmethod
[docs] def getUseExceptions(): return gdal.GetConfigOption('PYHTON_USE_EXCEPTIONS', 'FALSE') == 'TRUE'
def __init__(self, app, **kwargs): QtCore.QObject.__init__(self, app, **kwargs) self._app = app self._helpers = {} self._actionsmap = self._setupActions() self._app.treeview.activated.connect(self.onItemActivated) self._tools = self._setupExternalTools() self._helpers = self._setupHelpers(self._tools) def _setupExternalTools(self): tools = {} app = self._app handler = gdalexectools.GdalOutputHandler(app.logger, app.statusBar(), app.progressbar) # gdaladdo tool = gdalexectools.GdalAddOverviewDescriptor(stdout_handler=handler) tools['addo'] = tool # gdalinfo for statistics computation tool = gdalexectools.GdalInfoDescriptor(stdout_handler=handler) tool.stats = True tool.nomd = True tool.nogcp = True tool.noct = True tools['stats'] = tool # gdalinfo for histogram computation tool = gdalexectools.GdalInfoDescriptor(stdout_handler=handler) tool.hist = True tool.nomd = True tool.nogcp = True tool.noct = True tools['hist'] = tool return tools def _setupHelpers(self, tools): hmap = {} app = self._app hmap['addo'] = helpers.AddoHelper(app, tools['addo']) hmap['stats'] = helpers.StatsHelper(app, tools['stats']) hmap['statsdialog'] = helpers.StatsDialogHelper(app, tools['stats']) hmap['histdialog'] = helpers.HistDialogHelper(app, tools['hist']) hmap['ovrdialog'] = helpers.AddoDialogHelper(app, tools['addo']) return hmap
[docs] def findItemFromFilename(self, filename): '''Serch for and return the (dataset) item corresponding to filename. If no item is found retirn None. ''' # @NOTE: linear complexity # @NOTE: only scan toplevel items # @TODO: use an internal regidtry (set or dict) in oder to perfotm # O(1) search over all nesting levels filename = os.path.abspath(filename) filename = os.path.normpath(filename) root = self._app.datamodel.invisibleRootItem() for index in range(root.rowCount()): try: item = root.child(index) if item.filename == filename: return item except AttributeError: pass return None
@qt4support.overrideCursor
[docs] def openFile(self, filename): item = self.findItemFromFilename(filename) if item: self._app.treeview.setCurrentIndex(item.index()) # @TODO: remove selection code sm = self._app.treeview.selectionModel() sm.select(item.index(), QtGui.QItemSelectionModel.Select) # @TODO: maybe it is better to use an exception here return None return modelitems.datasetitem(filename)
[docs] def itemActions(self, item): try: method = getattr(self, '_get%sActions' % item.__class__.__name__) except AttributeError: actions = self._actionsmap.get(item.__class__.__name__) else: actions = method(item) return actions
[docs] def itemContextMenu(self, item): actions = self.itemActions(item) if actions: return qt4support.actionGroupToMenu(actions, self.tr('Context menu'), self._app.treeview)
@QtCore.Slot(QtCore.QModelIndex)
[docs] def onItemActivated(self, index): defaultActionsMap = { modelitems.BandItem: 'actionOpenImageView', modelitems.DatasetItem: 'actionOpenRGBImageView', modelitems.SubDatasetItem: 'actionOpenSubDatasetItem', } item = self._app.datamodel.itemFromIndex(index) actions = self._actionsmap[type(item).__name__] name = defaultActionsMap.get(type(item)) if name: action = actions.findChild(QtGui.QAction, name) if action: action.trigger() return for itemtype in defaultActionsMap: if isinstance(item, itemtype): action = actions.findChild(QtGui.QAction, defaultActionsMap[itemtype]) if action: action.trigger() break ### Actions setup #########################################################
def _setupMajorObjectItemActions(self, actionsgroup=None): if actionsgroup is None: actionsgroup = QtGui.QActionGroup(self) # open metadata view icon = qt4support.geticon('metadata.svg', __name__) QtGui.QAction(icon, self.tr('Open &Metadata View'), actionsgroup, objectName='actionOpenItemMetadataView', shortcut=self.tr('Ctrl+M'), toolTip=self.tr('Show metadata in a new window'), statusTip=self.tr('Show metadata in a new window'), triggered=self.openItemMatadataView, enabled=False) # @TODO: remove # show properties # @TODO: standard info icon from gdsview package icon = qt4support.geticon('info.svg', 'gsdview') QtGui.QAction(icon, self.tr('&Show Properties'), actionsgroup, objectName='actionShowItemProperties', shortcut=self.tr('Ctrl+S'), toolTip=self.tr('Show the property dialog for the ' 'cutent item'), statusTip=self.tr('Show the property dialog for the ' 'cutent item'), triggered=self.showItemProperties) return actionsgroup def _setupBandItemActions(self, actionsgroup=None): if actionsgroup is None: actionsgroup = QtGui.QActionGroup(self) # open image view icon = qt4support.geticon('open.svg', __name__) QtGui.QAction(icon, self.tr('&Open Image View'), actionsgroup, objectName='actionOpenImageView', shortcut=self.tr('Ctrl+O'), toolTip=self.tr('Open an image view'), statusTip=self.tr('Open a new image view'), triggered=self.openImageView) # @TODO: add a new action for newImageView # @TODO: Masked bands, Compute statistics, Compute histogram # @TODO: dataset --> Build overviews self._setupMajorObjectItemActions(actionsgroup) return actionsgroup def _setupOverviewItemActions(self, actionsgroup=None): # @TODO: remove open # @TODO: remove overviews build #~ actionsgroup = self._setupBandItemActions() #~ action = actionsgroup.findChild(QtGui.QAction, 'actionBuidOverviews') #~ actionsgroup.removeAction(action) #~ return actionsgroup return self._setupBandItemActions(actionsgroup) # @TODO #def _setupVirtualBandItemActions(self): # pass def _setupDatasetItemActions(self, actionsgroup=None): if actionsgroup is None: actionsgroup = QtGui.QActionGroup(self) # open RGB # @TODO: find an icon for RGB icon = qt4support.geticon('rasterband.svg', __name__) QtGui.QAction(icon, self.tr('Open as RGB'), actionsgroup, objectName='actionOpenRGBImageView', #shortcut=self.tr('Ctrl+B'), toolTip=self.tr('Display the dataset as an RGB image'), statusTip=self.tr('Open as RGB'), triggered=self.openRGBImageView) # build overviews icon = qt4support.geticon('overview.svg', __name__) QtGui.QAction(icon, self.tr('&Build overviews'), actionsgroup, objectName='actionBuidOverviews', shortcut=self.tr('Ctrl+B'), toolTip=self.tr('Build overviews for all raster bands'), statusTip=self.tr( 'Build overviews for all raster bands'), triggered=self.buildOverviews) # @TODO: add band, add virtual band, open GCPs view # close icon = qt4support.geticon('close.svg', 'gsdview') QtGui.QAction(icon, self.tr('Close'), actionsgroup, objectName='actionCloseItem', shortcut=self.tr('Ctrl+W'), toolTip=self.tr('Close the current item'), statusTip=self.tr('Close the current item'), triggered=self.closeCurrentItem) self._setupMajorObjectItemActions(actionsgroup) return actionsgroup def _setupSubDatasetItemActions(self, actionsgroup=None): if actionsgroup is None: actionsgroup = QtGui.QActionGroup(self) # open icon = qt4support.geticon('open.svg', __name__) QtGui.QAction(icon, self.tr('Open Sub Dataset'), actionsgroup, objectName='actionOpenSubDatasetItem', shortcut=self.tr('Ctrl+O'), toolTip=self.tr('Open Sub Dataset'), statusTip=self.tr('Open Sub Dataset'), triggered=self.openSubDataset) self._setupDatasetItemActions(actionsgroup) return actionsgroup def _setupActions(self, actionsmap=None): if actionsmap is None: actionsmap = {} actionsmap['MajorObjectItem'] = self._setupMajorObjectItemActions() actionsmap['BandItem'] = self._setupBandItemActions() actionsmap['OverviewItem'] = self._setupOverviewItemActions() #actionsmap['VirtualBandItem'] = self._setupVirtualBandItemActions() actionsmap['DatasetItem'] = self._setupDatasetItemActions() actionsmap['CachedDatasetItem'] = actionsmap['DatasetItem'] actionsmap['SubDatasetItem'] = self._setupSubDatasetItemActions() return actionsmap ### Actions enabling ###################################################### def _getBandItemActions(self, item=None, actionsgroup=None): if actionsgroup is None: actionsgroup = self._actionsmap['BandItem'] action = actionsgroup.findChild(QtGui.QAction, 'actionOpenImageView') action.setEnabled(True) if item is not None: assert isinstance(item, modelitems.BandItem) # @TODO: find a better solution allowcomplex = True if gdal.DataTypeIsComplex(item.DataType) and not allowcomplex: action.setEnabled(False) else: # @TODO: remove this to allow multiple views on the same item for subwin in self._app.mdiarea.subWindowList(): #if subwin.item == item: # action.setEnabled(False) # break # @COMPATIBILITY: pyside 1.0.1 try: if subwin.item == item: action.setEnabled(False) break except NotImplementedError: if id(subwin.item) == id(item): action.setEnabled(False) break return actionsgroup def _getDatasetItemActions(self, item=None, actionsgroup=None): if actionsgroup is None: actionsgroup = self._actionsmap['DatasetItem'] # RGB action = actionsgroup.findChild(QtGui.QAction, 'actionOpenRGBImageView') if gdalsupport.isRGB(item): # @TODO: remove this to allow multiple views on the same item for subwin in self._app.mdiarea.subWindowList(): #if subwin.item == item: # action.setEnabled(False) # break # @COMPATIBILITY: pyside 1.0.1 try: if subwin.item == item: action.setEnabled(False) break except NotImplementedError: if id(subwin.item) == id(item): action.setEnabled(False) break else: action.setEnabled(True) else: action.setEnabled(False) return actionsgroup # @NOTE: this is needed for correct context menu setup # @TODO: maybe it is possible to find a better way to handle the problem _getCachedDatasetItemActions = _getDatasetItemActions def _getSubDatasetItemActions(self, item=None, actionsgroup=None): if actionsgroup is None: actionsgroup = self._actionsmap['SubDatasetItem'] actionsgroup = self._getDatasetItemActions(item, actionsgroup) openaction = actionsgroup.findChild(QtGui.QAction, 'actionOpenSubDatasetItem') closeaction = actionsgroup.findChild(QtGui.QAction, 'actionCloseItem') propertyaction = actionsgroup.findChild(QtGui.QAction, 'actionShowItemProperties') ovraction = actionsgroup.findChild(QtGui.QAction, 'actionBuidOverviews') if item is not None: assert isinstance(item, modelitems.SubDatasetItem) if item.isopen(): openaction.setEnabled(False) closeaction.setEnabled(True) propertyaction.setEnabled(True) ovraction.setEnabled(True) else: openaction.setEnabled(True) closeaction.setEnabled(False) propertyaction.setEnabled(False) ovraction.setEnabled(False) return actionsgroup ### Major object ########################################################## @QtCore.Slot()
[docs] def openItemMatadataView(self): # @TODO: implementation self._app.logger.info('method not yet implemented')
def _infoDialogFactory(self, item): for itemtype in item.__class__.__mro__: name = itemtype.__name__ assert name.endswith('Item') name = name[:-4] + 'InfoDialog' dialogclass = getattr(widgets, name, None) if dialogclass: dialog = dialogclass(item, self._app) break else: dialog = None # @TODO: rewrite if dialog and isinstance(dialog, widgets.BandInfoDialog): if isinstance(item, modelitems.OverviewItem): # disable some function on overview items dialog.overviewWidget.setReadOnly(True) dialog.approxStatsCheckBox.hide() dialog.computeStatsButton.hide() dialog.customHistogramCheckBox.hide() dialog.computeHistogramButton.hide() # helpers setup for helpername in ('statsdialog', 'histdialog', 'ovrdialog'): helper = self._helpers[helpername] helper.dialog = dialog dialog.statsComputationRequest.connect( self._helpers['statsdialog'].start) dialog.histogramComputationRequest.connect( self._helpers['histdialog'].start) dialog.overviewComputationRequest.connect( self._helpers['ovrdialog'].start) dialog.finished.connect(self._resethelpers) return dialog @QtCore.Slot() def _resethelpers(self): self._helpers['statsdialog'].reset() self._helpers['histdialog'].reset() self._helpers['ovrdialog'].reset() @QtCore.Slot()
[docs] def showItemProperties(self): item = self._app.currentItem() dialog = self._infoDialogFactory(item) if dialog: dialog.exec_() else: self._app.logger.debug('unable to show info dialog for "%s" ' 'item class' % (item.__class__.__name__)) ### Driver ################################################################ ### Dataset ###############################################################
@QtCore.Slot() @QtCore.Slot(QtGui.QStandardItem)
[docs] def openRGBImageView(self, item=None): if item is None: item = self._app.currentItem() assert isinstance(item, modelitems.DatasetItem), ('item = %s' % str(item)) if not item.scene: msg = "This dataset can't be opened in RGB mode." self._app.logger.info(msg) #title = self.tr('WARNING') #msg = self.tr(msg) #QtGui.QMessageBox.warning(self._app, title, msg) return # only open a new view if there is no other on the item selected if len(item.scene.views()) == 0: self.newImageView(item)
@QtCore.Slot()
[docs] def buildOverviews(self, item=None): if item is None: item = self._app.currentItem() assert isinstance(item, modelitems.DatasetItem), ('item = %s' % str(item)) dialog = widgets.OverviewDialog(item, self._app) helper = self._helpers['ovrdialog'] helper.dialog = dialog dialog.overviewComputationRequest.connect(helper.start) dialog.exec_() # @TODO: add band, add virtual band, open GCPs view
@QtCore.Slot()
[docs] def closeCurrentItem(self): item = self._app.currentItem() self._app.treeview.collapse(item.index()) item.close() ### Sub-dataset ###########################################################
@QtCore.Slot()
[docs] def openSubDataset(self): item = self._app.currentItem() assert isinstance(item, modelitems.SubDatasetItem) if item.isopen(): if gdalsupport.isRGB(item): self.openRGBImageView(item) return try: # Only works for CachedDatasetItems cachedir = os.path.dirname(item.parent().vrtfilename) except AttributeError: id_ = gdalsupport.uniqueDatasetID(item.parent()) cachedir = os.path.join(modelitems.SubDatasetItem.CACHEDIR, id_) # sub-dataset index (starting from 1) index = item.row() - item.parent().RasterCount + 1 cachedir = os.path.join(cachedir, 'subdataset%02d' % index) item.open(cachedir) #self._app.treeview.expand(item.index()) #for row in range(item.rowCount()): # child = item.child(row) # self._app.treeview.expand(child.index()) ### Raster Band ###########################################################
@QtCore.Slot() @QtCore.Slot(QtGui.QStandardItem) # @TODO: check @qt4support.overrideCursor
[docs] def openImageView(self, item=None): if item is None: item = self._app.currentItem() assert isinstance(item, modelitems.BandItem), 'item = %s' % str(item) # NOTE: a reguest of opening an overview is converted into a request # for opening the corresponding raster band while isinstance(item, modelitems.OverviewItem): item = item.parent() if not item.scene: if not item.GetDescription(): msg = 'band "%s" is not visualizable' % (item.row() + 1) else: msg = 'band "%s" is not visualizable' % item.GetDescription() self._app.logger.warning(msg) return # only open a new view if there is no other on the item selected if len(item.scene.views()) == 0: stats = gdalsupport.GetCachedStatistics(item) if None in stats: self._helpers['stats'].start(item) else: self.newImageView(item)
[docs] def newImageView(self, item=None): if item is None: item = self._app.currentItem() #assert isinstance(item, modelitems.BandItem) assert isinstance(item, (modelitems.BandItem, modelitems.DatasetItem)) # @TODO: check if any graphics view is open on the selected item winlist = self._app.mdiarea.subWindowList() if len(winlist): maximized = winlist[0].windowState() & QtCore.Qt.WindowMaximized else: maximized = True subwin = GraphicsViewSubWindow(item) self._app.mdiarea.addSubWindow(subwin) grephicsview = subwin.widget() self._app.monitor.register(grephicsview) self._app.mousemanager.register(grephicsview) subwin.destroyed.connect(self._app.subWindowClosed) if maximized: subwin.showMaximized() else: subwin.show() # @TODO: check helper = self._helpers['addo'] helper.start(item) # @TODO: Open, Masked bands # @TODO: dataset --> Build overviews ### Overview ############################################################## ### Virtualband ###########################################################
[docs] def loadGDALSettings(self, settings): logger = self._app.logger settings.beginGroup('gdal') try: cachesize = settings.value('GDAL_CACHEMAX') if cachesize is not None: cachesize = int(cachesize) gdal.SetCacheMax(cachesize) logger.debug('GDAL cache size det to %d' % cachesize) value = settings.value('GDAL_DATA') if value: value = os.path.expanduser(os.path.expandvars(value)) gdal.SetConfigOption('GDAL_DATA', value) logger.debug('GDAL_DATA directory set to "%s"' % value) for optname in ('GDAL_SKIP', 'GDAL_DRIVER_PATH', 'OGR_DRIVER_PATH'): value = settings.value(optname) if value is not None: value = os.path.expanduser(os.path.expandvars(value)) # @NOTE: type of arg 2 of SetConfigOption must be str, # not an unicode gdal.SetConfigOption(optname, str(value)) logger.debug('%s set to "%s"' % (optname, value)) gdal.AllRegister() logger.debug('run "gdal.AllRegister()"') # update the about dialog tabWidget = self._app.aboutdialog.tabWidget for index in range(tabWidget.count()): if tabWidget.tabText(index) == 'GDAL': gdalinfowidget = tabWidget.widget(index) gdalinfowidget.setGdalDriversTab() break else: logger.debug('GDAL page ot found in the about dialog') return finally: settings.endGroup()
[docs] def loadSettings(self, settings): self.loadGDALSettings(settings) settings.beginGroup('gdalbackend') try: # show overviews in the treeview value = settings.value('visible_overview_items') # @COMPATIBILITY: presumably a bug in PyQt4 (4.7.2) if isinstance(value, basestring): value = True if value in ('true', 'True') else False modelitems.VISIBLE_OVERVIEW_ITEMS = value # @TODO: reload all items finally: settings.endGroup()
[docs] def saveSettings(self, settings): # @NOTE: GDAL preferences are only modified via preferences dialog settings.beginGroup('gdalbackend') try: # show overviews in the treeview settings.setValue('visible_overview_items', modelitems.VISIBLE_OVERVIEW_ITEMS) finally: settings.endGroup() ### MISC ######################################################################
from ..mdi import ItemSubWindow # @TODO: move elsewhere class GraphicsViewSubWindow(ItemSubWindow): def __init__(self, item, parent=None, flags=QtCore.Qt.WindowFlags(0), **kwargs): super(GraphicsViewSubWindow, self).__init__(item, parent, flags, **kwargs) title = str(item.GetDescription()).strip() self.setWindowTitle(title) scene = item.scene graphicsview = QtGui.QGraphicsView(scene) graphicsview.setMouseTracking(True) self.setWidget(graphicsview)

Get GSDView at SourceForge.net. Fast, secure and Free Open Source software downloads