Source code for gsdview.layermanager

# -*- 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.


'''Components for layers management.'''


import logging
import itertools

from qt import QtCore, QtGui


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


SelectCurrentRows = (QtGui.QItemSelectionModel.SelectCurrent |
                                                QtGui.QItemSelectionModel.Rows)


[docs]class BaseLayerManager(QtCore.QObject): def __init__(self, parent=None, **kargs): super(BaseLayerManager, self).__init__(parent, **kargs) self.actions = self._setupActions() def _setupActions(self): style = QtGui.QApplication.style() actions = QtGui.QActionGroup(self) icon = QtGui.QIcon(':/trolltech/styles/commonstyle/images/up-128.png') QtGui.QAction(icon, self.tr('Move to top'), actions, objectName='moveToTopAction', statusTip=self.tr('Move to top'), shortcut=self.tr('Ctrl+PgUp')) icon = style.standardIcon(QtGui.QStyle.SP_ArrowUp) QtGui.QAction(icon, self.tr('Move up'), actions, objectName='moveUpAction', statusTip=self.tr('Move up'), shortcut=self.tr('Ctrl+Up')) icon = style.standardIcon(QtGui.QStyle.SP_ArrowDown) QtGui.QAction(icon, self.tr('Move down'), actions, objectName='moveDownAction', statusTip=self.tr('Move down'), shortcut=self.tr('Ctrl+Down')) icon = QtGui.QIcon( ':/trolltech/styles/commonstyle/images/down-128.png') QtGui.QAction(icon, self.tr('Move to bottom'), actions, objectName='moveToBottomAction', statusTip=self.tr('Move to bottom'), shortcut=self.tr('Ctrl+PgDown')) #~ #'standardbutton-closetab-16.png' icon = QtGui.QIcon(':/trolltech/styles/commonstyle/images/' 'standardbutton-cancel-128.png') QtGui.QAction(icon, self.tr('Remove'), actions, objectName='removeLayerAction', statusTip=self.tr('Remove'), shortcut=self.tr('Del')) icon = QtGui.QIcon( ':/trolltech/styles/commonstyle/images/standardbutton-yes-128.png') QtGui.QAction(icon, self.tr('Show'), actions, objectName='showLayerAction', statusTip=self.tr('Show the layer')) icon = QtGui.QIcon( ':/trolltech/styles/commonstyle/images/standardbutton-no-128.png') QtGui.QAction(icon, self.tr('Hide'), actions, objectName='hideLayerAction', statusTip=self.tr('Hide the layer')) return actions
[docs] def action(self, name): return self.actions.findChild(QtGui.QAction, name)
[docs] def isLayer(self, item): # @TODO: complete return True
@staticmethod def _selectionmap(selection): sortedselection = sorted(selection, key=QtGui.QItemSelectionRange.parent) selectionmap = {} # collections.OrderedDict() for key, group in itertools.groupby(sortedselection, QtGui.QItemSelectionRange.parent): ranges = [] for item in sorted(group, key=QtGui.QItemSelectionRange.top): if len(ranges) == 0: ranges.append(item) continue lastitem = ranges[-1] assert lastitem.parent() == item.parent() if lastitem.bottom() + 1 >= item.top(): model = lastitem.model() topleft = model.index(min(lastitem.top(), item.top()), #min(lastitem.left(), item.left()), 0, lastitem.parent()) bottomright = model.index( max(lastitem.bottom(), item.bottom()), #max(lastitem.right(), item.right()), model.columnCount() - 1, lastitem.parent()) ranges[-1] = QtGui.QItemSelectionRange(topleft, bottomright) else: ranges.append(item) selectionmap[key] = ranges return selectionmap @staticmethod def _parentitem(selectionrange): index = selectionrange.parent() if index.isValid(): item = selectionrange.model().itemFromIndex(index) else: item = selectionrange.model().invisibleRootItem() return item @staticmethod
[docs] def updateStackOrder(rootitem, offset=0): nrows = rootitem.rowCount() for row in range(nrows): qitem = rootitem.child(row).data() if qitem: qitem.setZValue(nrows + offset - row - 1) else: logging.warning('no graphics item associated to layer ' 'n. %d' % row) # @TODO: beginMoveRows, endMoveRows
def _takeRowsRange(self, selectionrange): parent = self._parentitem(selectionrange) rows = [] for row in range(selectionrange.bottom(), selectionrange.top() - 1, -1): # @TODO: check if not self.isLayer(parent.child(row)): #continue break items = parent.takeRow(row) rows.insert(0, items) return rows # @TODO: beginMoveRows, endMoveRows def _moveSelectionRange(self, selectionrange, dst): if selectionrange.top() == dst: return selectionrange model = selectionrange.model() parentindex = selectionrange.parent() parentitem = self._parentitem(selectionrange) nrows_selected = selectionrange.bottom() - selectionrange.top() + 1 ncols = model.columnCount() if nrows_selected == parentitem.rowCount(): return selectionrange if dst > parentitem.rowCount() - nrows_selected or dst < 0: return selectionrange selectedrows = self._takeRowsRange(selectionrange) for index, items in enumerate(selectedrows): parentitem.insertRow(dst + index, items) topleft = model.index(dst, 0, parentindex) bottomright = model.index(dst + nrows_selected - 1, ncols - 1, parentindex) return QtGui.QItemSelectionRange(topleft, bottomright)
[docs] def moveSelectionToTop(self, selectionmodel): #assert selectionmodel.model() is self.model selection = selectionmodel.selection() selectionmap = self._selectionmap(selection) newselection = QtGui.QItemSelection() for parent, ranges in selectionmap.iteritems(): dst = 0 for selectionrange in ranges: newrange = self._moveSelectionRange(selectionrange, dst) newselection.append(newrange) dst = newrange.bottom() + 1 selectionmodel.select(newselection, SelectCurrentRows)
[docs] def moveSelectionUp(self, selectionmodel): #assert selectionmodel.model() is self.model selection = selectionmodel.selection() selectionmap = self._selectionmap(selection) newselection = QtGui.QItemSelection() for parent, ranges in selectionmap.iteritems(): for selectionrange in ranges: dst = selectionrange.top() - 1 newrange = self._moveSelectionRange(selectionrange, dst) newselection.append(newrange) selectionmodel.select(newselection, SelectCurrentRows)
[docs] def moveSelectionDown(self, selectionmodel): #assert selectionmodel.model() is self.model selection = selectionmodel.selection() selectionmap = self._selectionmap(selection) newselection = QtGui.QItemSelection() for parent, ranges in selectionmap.iteritems(): ranges.reverse() for selectionrange in ranges: dst = selectionrange.top() + 1 newrange = self._moveSelectionRange(selectionrange, dst) newselection.append(newrange) selectionmodel.select(newselection, SelectCurrentRows)
[docs] def moveSelectionToBottom(self, selectionmodel): #assert selectionmodel.model() is self.model selection = selectionmodel.selection() selectionmap = self._selectionmap(selection) newselection = QtGui.QItemSelection() nrows = selectionmodel.model().rowCount() for parent, ranges in selectionmap.iteritems(): ranges.reverse() dst = nrows for selectionrange in ranges: dst -= selectionrange.height() newrange = self._moveSelectionRange(selectionrange, dst) newselection.append(newrange) selectionmodel.select(newselection, SelectCurrentRows)
[docs] def removeSelectedLayers(self, selectionmodel): selection = selectionmodel.selection() selectionmap = self._selectionmap(selection) for parentindex, ranges in selectionmap.iteritems(): ranges.reverse() parentitem = self._parentitem(ranges[0]) for selectionrange in ranges: for row in range(selectionrange.top(), selectionrange.bottom() + 1): item = parentitem.child(row) if not self.isLayer(item): break graphicsitem = item.data() assert isinstance(graphicsitem, QtGui.QGraphicsItem) scene = graphicsitem.scene() scene.removeItem(graphicsitem) else: parentitem.removeRows(selectionrange.top(), selectionrange.height()) # @TODO: check #self.updateStackOrder(parent)
def _updateActions(self, selectionmodel): model = selectionmodel.model() enabled = selectionmodel.hasSelection() for action in self.actions.actions(): if action.objectName() == 'selectAllAction': selectedrows = selectionmodel.selectedRows() nselected = len(selectedrows) nlayers = model.rowCount() allselected = bool(nselected == nlayers) action.setEnabled(nlayers and not allselected) elif action.objectName() in ('showLayerAction', 'hideLayerAction'): selectedrows = selectionmodel.selectedRows() nselected = len(selectedrows) if nselected == 0: action.setEnabled(False) else: items = [model.itemFromIndex(index) for index in selectedrows] activerows = [item.row() for item in items if item.checkState() == QtCore.Qt.Checked] if action.objectName() == 'showLayerAction': action.setEnabled(len(activerows) != nselected) elif action.objectName() == 'hideLayerAction': action.setEnabled(len(activerows) != 0) else: action.setEnabled(enabled) @QtCore.Slot(QtCore.QModelIndex) #@QtCore.Slot(QtGui.QStandardItem) @QtCore.Slot('QStandardItem*') # @TODO: fix
[docs] def updateVisibility(self, index): if isinstance(index, QtCore.QModelIndex): if index.column() != 0: return item = index.model().itemFromIndex(index) elif isinstance(index, QtGui.QStandardItem): item = index index = item.index() if index.column() != 0: return else: raise TypeError('unexpected type for index parameter: "%s"' % type(index)) checked = bool(item.checkState() == QtCore.Qt.Checked) qlayer = item.data() # index.data(QtCore.Qt.UserRole + 1) qlayer.setVisible(checked)
[docs] def checkSelectedItems(self, selectionmodel, checked=True): model = selectionmodel.model() #assert model is self.model if checked: newstate = QtCore.Qt.Checked else: newstate = QtCore.Qt.Unchecked update = False for index in selectionmodel.selectedRows(): item = model.itemFromIndex(index) if item.checkState() != newstate: item.setCheckState(newstate) self.updateVisibility(index) update = True if update: self._updateActions(selectionmodel)
[docs] def toggleSelectedItems(self, selectionmodel): model = selectionmodel.model() #assert model is self.model update = False for index in selectionmodel.selectedRows(): item = model.itemFromIndex(index) state = item.checkState() if state == QtCore.Qt.Checked: item.setCheckState(QtCore.Qt.Unchecked) update = True elif state == QtCore.Qt.Unchecked: item.setCheckState(QtCore.Qt.Checked) update = True else: logging.debug('unexpected check state: "%s"' % state) continue self.updateVisibility(index) if update: self._updateActions(selectionmodel)
[docs]class LayerManager(BaseLayerManager): def __init__(self, view, parent=None, **kargs): self.view = view super(LayerManager, self).__init__(parent, **kargs) view.addActions(self.actions.actions()) view.installEventFilter(self) # spacebar # connect signals model = self.view.model() model.layoutChanged.connect(self.updateStackOrder) model.rowsInserted.connect(self.updateStackOrder) model.rowsInserted.connect(self._updateActions) model.rowsRemoved.connect(self.updateStackOrder) model.rowsRemoved.connect(self._updateActions) model.itemChanged.connect(self.updateVisibility) view.clicked.connect(self.updateVisibility) view.activated.connect(self.toggleSelectedItems) view.selectionModel().selectionChanged.connect(self._updateActions) self._updateActions() @property
[docs] def model(self): return self.view.model()
@property
[docs] def selectionmodel(self): return self.view.selectionModel()
def _setupActions(self): actions = super(LayerManager, self)._setupActions() icon = QtGui.QIcon( ':/trolltech/styles/commonstyle/images/viewdetailed-128.png') QtGui.QAction(icon, self.tr('Select all'), actions, objectName='selectAllAction', statusTip=self.tr('Select all'), shortcut=self.tr('Ctrl-A'), triggered=self.view.selectAll) # connect actions action = actions.findChild(QtGui.QAction, 'moveToTopAction') action.triggered.connect(self.moveSelectionToTop) action = actions.findChild(QtGui.QAction, 'moveUpAction') action.triggered.connect(self.moveSelectionUp) action = actions.findChild(QtGui.QAction, 'moveDownAction') action.triggered.connect(self.moveSelectionDown) action = actions.findChild(QtGui.QAction, 'moveToBottomAction') action.triggered.connect(self.moveSelectionToBottom) action = actions.findChild(QtGui.QAction, 'removeLayerAction') action.triggered.connect(self.removeSelectedLayers) action = actions.findChild(QtGui.QAction, 'showLayerAction') action.triggered.connect(self.checkSelectedItems) action = actions.findChild(QtGui.QAction, 'hideLayerAction') action.triggered.connect(self.uncheckSelectedItems) return actions
[docs] def eventFilter(self, obj, event): if (event.type() == QtCore.QEvent.KeyPress and event.key() == QtCore.Qt.Key_Space): self.toggleSelectedItems() return True else: return super(LayerManager, self).eventFilter(obj, event)
@QtCore.Slot()
[docs] def moveSelectionToTop(self, selectionmodel=None): if selectionmodel is None: selectionmodel = self.selectionmodel super(LayerManager, self).moveSelectionToTop(selectionmodel)
@QtCore.Slot()
[docs] def moveSelectionUp(self, selectionmodel=None): if selectionmodel is None: selectionmodel = self.selectionmodel super(LayerManager, self).moveSelectionUp(selectionmodel)
@QtCore.Slot()
[docs] def moveSelectionDown(self, selectionmodel=None): if selectionmodel is None: selectionmodel = self.selectionmodel super(LayerManager, self).moveSelectionDown(selectionmodel)
@QtCore.Slot()
[docs] def moveSelectionToBottom(self, selectionmodel=None): if selectionmodel is None: selectionmodel = self.selectionmodel super(LayerManager, self).moveSelectionToBottom(selectionmodel)
@QtCore.Slot()
[docs] def removeSelectedLayers(self, selectionmodel=None): if selectionmodel is None: selectionmodel = self.selectionmodel super(LayerManager, self).removeSelectedLayers(selectionmodel)
@QtCore.Slot()
[docs] def checkSelectedItems(self, selectionmodel=None, checked=True): if selectionmodel is None: selectionmodel = self.selectionmodel super(LayerManager, self).checkSelectedItems(selectionmodel, checked)
@QtCore.Slot()
[docs] def uncheckSelectedItems(self, selectionmodel=None): self.checkSelectedItems(selectionmodel, False)
@QtCore.Slot()
[docs] def toggleSelectedItems(self, selectionmodel=None): if selectionmodel is None: selectionmodel = self.selectionmodel super(LayerManager, self).toggleSelectedItems(selectionmodel)
@QtCore.Slot() def _updateActions(self, selectionmodel=None): if selectionmodel is None: selectionmodel = self.selectionmodel super(LayerManager, self)._updateActions(selectionmodel) @QtCore.Slot()
[docs] def updateStackOrder(self, rootitem=None): if rootitem is None: rootitem = self.model.invisibleRootItem() super(LayerManager, self).updateStackOrder(rootitem)

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