def __init__(self, rows=0, cols=0, parent=None): """ StandardWidgetSheet(rows: int, cols: int, parent: QWidget) -> StandardWidgetSheet Construct a sheet with rows x cols cells """ QtGui.QTableWidget.__init__(self, 0, 0, parent) self.setSelectionMode(QtGui.QAbstractItemView.NoSelection) self.fitToWindow = False self.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) self.setHorizontalHeader(StandardWidgetHeaderView(QtCore.Qt.Horizontal, self)) self.horizontalHeader().setSelectionModel(self.selectionModel()) self.connect(self.horizontalHeader(), QtCore.SIGNAL("sectionCountChanged(int, int)"), self.updateColumnLabels) self.connect(self.horizontalHeader(), QtCore.SIGNAL("sectionMoved(int,int,int)"), self.columnMoved) self.connect(self.horizontalHeader(), QtCore.SIGNAL("sectionPressed(int)"), self.forceColumnMultiSelect) self.setVerticalHeader(StandardWidgetHeaderView(QtCore.Qt.Vertical, self)) self.verticalHeader().setSelectionModel(self.selectionModel()) self.connect(self.verticalHeader(), QtCore.SIGNAL("sectionCountChanged(int, int)"), self.updateRowLabels) self.connect(self.verticalHeader(), QtCore.SIGNAL("sectionMoved(int,int,int)"), self.rowMoved) self.connect(self.verticalHeader(), QtCore.SIGNAL("sectionPressed(int)"), self.forceRowMultiSelect) # A hack to force the select all button in single click mode cornerButton = self.findChild(QtGui.QAbstractButton) if cornerButton: self.connect(cornerButton, QtCore.SIGNAL("clicked()"), self.forceSheetSelect) self.delegate = StandardWidgetItemDelegate(self) self.setItemDelegate(self.delegate) self.helpers = CellHelpers(parent, CellResizer(self)) self.setRowCount(rows) self.setColumnCount(cols) self.setFitToWindow(True) self.connect(self, QtCore.SIGNAL("cellActivated(int, int, bool)"), self.selectCell) self.activeCell = (-1, -1)
def __init__(self, tabWidget, row=1, col=1): """ StandardSingleCellSheetTab(row: int, col: int) -> StandardSingleCellSheetTab Initialize with the vertical layout containing only a single widget """ QtGui.QWidget.__init__(self, None) StandardWidgetSheetTabInterface.__init__(self) self.type = "StandardSingleCellSheetTab" self.tabWidget = tabWidget self.vLayout = QtGui.QVBoxLayout() self.vLayout.setSpacing(0) self.vLayout.setMargin(0) self.setLayout(self.vLayout) self.cell = QtGui.QWidget() self.layout().addWidget(self.cell) self.helpers = CellHelpers(self) self.toolBars = {} self.blankCellToolBar = None self.pipelineInfo = {}
class StandardWidgetSheet(QtGui.QTableWidget): """ StandardWidgetSheet is a standard sheet that can contain any type of cell widget. Each of them will be put into a separate cell. In the case of vtkRenderWindow, where creating each sheet separately can end up with a large number of GL contexts, a special type of VTK sheet need to be derived from this one """ def __init__(self, rows=0, cols=0, parent=None): """ StandardWidgetSheet(rows: int, cols: int, parent: QWidget) -> StandardWidgetSheet Construct a sheet with rows x cols cells """ QtGui.QTableWidget.__init__(self, 0, 0, parent) self.setSelectionMode(QtGui.QAbstractItemView.NoSelection) self.fitToWindow = False self.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) self.setHorizontalHeader(StandardWidgetHeaderView(QtCore.Qt.Horizontal, self)) self.horizontalHeader().setSelectionModel(self.selectionModel()) self.connect(self.horizontalHeader(), QtCore.SIGNAL('sectionCountChanged(int, int)'), self.updateColumnLabels) self.connect(self.horizontalHeader(), QtCore.SIGNAL('sectionMoved(int,int,int)'), self.columnMoved) self.connect(self.horizontalHeader(), QtCore.SIGNAL('sectionPressed(int)'), self.forceColumnMultiSelect) self.setVerticalHeader(StandardWidgetHeaderView(QtCore.Qt.Vertical, self)) self.verticalHeader().setSelectionModel(self.selectionModel()) self.connect(self.verticalHeader(), QtCore.SIGNAL('sectionCountChanged(int, int)'), self.updateRowLabels) self.connect(self.verticalHeader(), QtCore.SIGNAL('sectionMoved(int,int,int)'), self.rowMoved) self.connect(self.verticalHeader(), QtCore.SIGNAL('sectionPressed(int)'), self.forceRowMultiSelect) # A hack to force the select all button in single click mode cornerButton = self.findChild(QtGui.QAbstractButton) if cornerButton: self.connect(cornerButton, QtCore.SIGNAL('clicked()'), self.forceSheetSelect) self.delegate = StandardWidgetItemDelegate(self) self.setItemDelegate(self.delegate) self.helpers = CellHelpers(parent, CellResizer(self)) self.setRowCount(rows) self.setColumnCount(cols) self.setFitToWindow(True) self.connect(self, QtCore.SIGNAL('cellActivated(int, int, bool)'), self.selectCell) self.activeCell = (-1,-1) def forceColumnMultiSelect(self, logicalIndex): """ forceColumnMultiSelect(logicalIndex: int) -> None Make sure we always toggle the headerview in the right way NOTE: the MultiSelection type of SelectionMode does not work correctly for overlapping columns and rows selection """ if (self.selectionModel().isColumnSelected(logicalIndex, QtCore.QModelIndex())): self.selectionModel().select(self.model().index(0, logicalIndex), QtGui.QItemSelectionModel.Deselect | QtGui.QItemSelectionModel.Columns) else: self.selectionModel().select(self.model().index(0, logicalIndex), QtGui.QItemSelectionModel.Select | QtGui.QItemSelectionModel.Columns) def forceRowMultiSelect(self, logicalIndex): """ forceRowMultiSelect(logicalIndex: int) -> None Make sure we always toggle the headerview in the right way NOTE: the MultiSelection type of SelectionMode does not work correctly for overlapping columns and rows selection """ if (self.selectionModel().isRowSelected(logicalIndex, QtCore.QModelIndex())): self.selectionModel().select(self.model().index(logicalIndex, 0), QtGui.QItemSelectionModel.Deselect | QtGui.QItemSelectionModel.Rows) else: self.selectionModel().select(self.model().index(logicalIndex, 0), QtGui.QItemSelectionModel.Select | QtGui.QItemSelectionModel.Rows) def forceSheetSelect(self): """ forceSheetSelect() -> None Make sure we can toggle the whole sheet selection """ totalCells = self.rowCount()*self.columnCount() if (len(self.selectionModel().selectedIndexes())<totalCells): self.selectionModel().select( QtGui.QItemSelection(self.model().index(0,0), self.model().index(self.rowCount()-1, self.columnCount()-1)), QtGui.QItemSelectionModel.Select) else: self.selectionModel().clearSelection() def updateHeaderStatus(self): """ updateHeaderStatus() -> None Update the visibility of the row and column header """ return self.horizontalHeader().setVisible(self.columnCount() > 1 or self.rowCount() > 1) self.verticalHeader().setVisible(self.columnCount() > 1 or self.rowCount() > 1) def updateRowLabels(self, oldCount, newCount): """ updateRowLabels(oldCount: int, newCount: int) -> None Update vertical labels when the number of row changed """ vLabels = QtCore.QStringList() vIdx = self.verticalHeader().visualIndex for i in xrange(newCount): vLabels << str(vIdx(i)+1) self.setVerticalHeaderLabels(vLabels) self.updateHeaderStatus() def rowMoved(self, row, old, new): """ rowMove(row: int, old: int, new: int) -> None Renumber the vertical header labels when rows moved """ self.updateRowLabels(self.rowCount(), self.rowCount()) def updateColumnLabels(self, oldCount, newCount): """ updateColumnLabels(oldCount: int, newCount: int) -> None Update horizontal labels when the number of column changed """ hLabels = QtCore.QStringList() vIdx = self.horizontalHeader().visualIndex for i in xrange(newCount): hLabels << chr(vIdx(i)+ord('A')) self.setHorizontalHeaderLabels(hLabels) self.updateHeaderStatus() def columnMoved(self, row, old, new): """ columnMoved(row: int, old: int, new: int) -> None Renumber the horizontal header labels when columns moved """ self.updateColumnLabels(self.columnCount(), self.columnCount()) def setFitToWindow(self, fit=True): """ setFitToWindow(fit: boolean) -> None Force to fit all cells into the visible area. Set fit=False for the scroll mode where hidden cell can be view by scrolling the scrollbars. """ if fit!=self.fitToWindow: self.fitToWindow = fit self.horizontalHeader().setFitToViewport(fit) self.verticalHeader().setFitToViewport(fit) if not fit: width = self.columnWidth(self.columnCount()-1) height = self.rowHeight(self.rowCount()-1) self.horizontalHeader().setStretchLastSection(fit) self.verticalHeader().setStretchLastSection(fit) if not fit: self.setColumnWidth(self.columnCount()-1, width) self.setRowHeight(self.rowCount()-1, height) self.stretchCells() def showEvent(self, event): """ showEvent(event: QShowEvent) -> None Make sure to stretch the sheet on the first appearance """ self.stretchCells() def stretchCells(self): """ stretchCells() -> None Stretch all the cells with equally spaces to fit in the viewport """ if self.fitToWindow: self.horizontalHeader().setFitToViewport(False) self.horizontalHeader().resizeSections(QtGui.QHeaderView.Stretch) self.horizontalHeader().setFitToViewport(True) self.verticalHeader().setFitToViewport(False) self.verticalHeader().resizeSections(QtGui.QHeaderView.Stretch) self.verticalHeader().setFitToViewport(True) def resizeEvent(self, e): """ resizeEvent(e: QResizeEvent) -> None ResizeEvent will make sure all columns/rows stretched right when the table get resized """ QtGui.QTableWidget.resizeEvent(self, e) self.stretchCells() def showHelpers(self, show, row, col): """ showHelpers(show: boolean, row: int, col: int) -> None Show/hide the helpers (resizer, toolbar) on the current cell depending on the value of show """ if self.helpers.isInteracting(): return if show: if row>=0 and col>=0: self.helpers.snapTo(row, col) self.helpers.adjustPosition() self.helpers.show() else: self.helpers.hide() else: self.helpers.hide() def getRealLocation(self, vRow, vCol, visual=False): """ getRealLocation(vRow: int, vCol: int, visual: bool) -> (int, int) Return the actual location even if there is spanning at (vRow, vCol) """ # Qt doesn't provide a mechanism to map from a cell to its # span region, so we have to scan the whole spreadsheet N^2 # for now, but our spreadsheet is usuallly small enough. if visual: (row, col) = (vRow, vCol) else: row = self.verticalHeader().logicalIndex(vRow) col = self.horizontalHeader().logicalIndex(vCol) cellSet = set() for r in xrange(self.rowCount()): for c in xrange(self.columnCount()): cellSet.add((r, c)) for r in xrange(self.rowCount()): for c in xrange(self.columnCount()): if (r, c) not in cellSet: continue rect = self.visualRect(self.model().index(r, c)) rSpan = self.rowSpan(r, c) cSpan = self.columnSpan(r, c) for rs in xrange(rSpan): for cs in xrange(cSpan): if (row==r+rs) and (col==c+cs): return (r, c) if (r+rs, c+cs) in cellSet: cellSet.remove((r+rs, c+cs)) return (-1, -1) def getCell(self, row, col): """ getCell(row: int, col: int) -> QWidget Get cell at a specific row and column """ return self.cellWidget(*self.getRealLocation(row, col)) def getCellRect(self, row, col): """ getCellRect(row: int, col: int) -> QRect Return the rectangle surrounding the cell at location (row, col) in parent coordinates """ idx = self.model().index(*self.getRealLocation(row, col)) return self.visualRect(idx) def getCellGlobalRect(self, row, col): """ getCellGlobalRect(row: int, col: int) -> QRect Return the rectangle surrounding the cell at location (row, col) in global coordinates """ rect = self.getCellRect(row, col) rect.moveTo(self.viewport().mapToGlobal(rect.topLeft())) return rect def setCellByWidget(self, row, col, cellWidget): """ setCellByWidget(row: int, col: int, cellWidget: QWidget) -> None Replace the current location (row, col) with a cell widget """ if cellWidget: # Relax the size constraint of the widget cellWidget.setMinimumSize(QtCore.QSize(0, 0)) cellWidget.setMaximumSize(QtCore.QSize(16777215, 16777215)) cellWidget.setParent(self) (row, col) = self.getRealLocation(row, col) index = self.model().index(row, col) self.setCellWidget(row, col, cellWidget) if cellWidget: self.delegate.updateEditorGeometry(cellWidget, None, index) def selectCell(self, row, col, toggling): """ selectCell(row: int, col: int, toggling: bool) -> None Select a cell based on its current selection """ (row, col) = self.getRealLocation(row, col, visual=True) if toggling: self.selectionModel().setCurrentIndex(self.model().index(row, col), QtGui.QItemSelectionModel.Toggle) if (self.selectionModel().isSelected(self.model().index(row, col))): self.setActiveCell(row, col) else: self.setActiveCell(-1, -1) else: if len(self.selectionModel().selectedIndexes())<=1: self.selectionModel().setCurrentIndex( self.model().index(row, col), QtGui.QItemSelectionModel.ClearAndSelect) self.setActiveCell(row, col) self.viewport().repaint() def setActiveCell(self, row, col): """ setActiveCell(row: int, col: int) -> None Set the location of an active cell also bring up the corresponding toolbar """ self.activeCell = (row, col) toolBar = self.parent().getCellToolBar(row, col) if toolBar: toolBar.snapTo(row, col) self.parent().toolBar.setCellToolBar(toolBar) def adjustWidgetGeometry(self, row, col): """ setActiveCell(row: int, col: int) -> None Adjust the widget at cell (row, col) to fit inside the cell """ cellWidget = self.getCell(row, col) if cellWidget: index = self.model().index(*self.getRealLocation(row, col)) self.delegate.updateEditorGeometry(cellWidget, None, index)
class StandardSingleCellSheetTab(QtGui.QWidget, StandardWidgetSheetTabInterface): """ StandardSingleCellSheetTab is a container of StandardWidgetSheet with only a single cell. This will be added directly to a QTabWidget on the spreadsheet as a sheet for displaying """ def __init__(self, tabWidget, row=1, col=1): """ StandardSingleCellSheetTab(row: int, col: int) -> StandardSingleCellSheetTab Initialize with the vertical layout containing only a single widget """ QtGui.QWidget.__init__(self, None) StandardWidgetSheetTabInterface.__init__(self) self.type = "StandardSingleCellSheetTab" self.tabWidget = tabWidget self.vLayout = QtGui.QVBoxLayout() self.vLayout.setSpacing(0) self.vLayout.setMargin(0) self.setLayout(self.vLayout) self.cell = QtGui.QWidget() self.layout().addWidget(self.cell) self.helpers = CellHelpers(self) self.toolBars = {} self.blankCellToolBar = None self.pipelineInfo = {} ### Belows are API Wrappers to connect to self.sheet def getDimension(self): """ getDimension() -> tuple Get the sheet dimensions """ return (1, 1) def getCell(self, row, col): """ getCell(row: int, col: int) -> QWidget Get cell at a specific row and column. """ return self.cell def getCellToolBar(self, row, col): """ getCellToolBar(row: int, col: int) -> QWidget Return the toolbar widget at cell location (row, col) """ cell = self.getCell(row, col) if cell and hasattr(cell, "toolBarType"): if not self.toolBars.has_key(cell.toolBarType): self.toolBars[cell.toolBarType] = cell.toolBarType(self) return self.toolBars[cell.toolBarType] else: return self.blankCellToolBar return self.sheet.getCellToolBar(row, col) def getCellRect(self, row, col): """ getCellRect(row: int, col: int) -> QRect Return the rectangle surrounding the cell at location (row, col) in parent coordinates """ return self.contentsRect() def getCellGlobalRect(self, row, col): """ getCellGlobalRect(row: int, col: int) -> QRect Return the rectangle surrounding the cell at location (row, col) in global coordinates """ rect = self.getCellRect(row, col) rect.moveTo(self.mapToGlobal(rect.topLeft())) return rect def setCellByType(self, row, col, cellType, inputPorts): """ setCellByType(row: int, col: int, cellType: a type inherits from QWidget, inpurPorts: tuple) -> None Replace the current location (row, col) with a cell of cellType. If the current type of that cell is the same as cellType, only the contents is updated with inputPorts. """ oldCell = self.getCell(row, col) if type(oldCell) != cellType: oldCell.hide() self.layout().removeWidget(oldCell) if cellType: self.cell = cellType(self) # self.cell.setGeometry(self.getCellRect(row, col)) self.layout().addWidget(self.cell) self.cell.show() self.cell.updateContents(inputPorts) if hasattr(oldCell, "deleteLater"): oldCell.deleteLater() del oldCell else: oldCell.updateContents(inputPorts) def showHelpers(self, show, globalPos): """ showHelpers(show: boolean, globalPos: QPoint) -> None Show the helpers (toolbar, resizer) when show==True """ if show: self.helpers.snapTo(0, 0) self.helpers.adjustPosition() self.helpers.show() else: self.helpers.hide() def getSelectedLocations(self): """ getSelectedLocations() -> tuple Return the selected locations (row, col) of the current sheet """ return [(0, 0)]
class StandardWidgetSheet(QtGui.QTableWidget): """ StandardWidgetSheet is a standard sheet that can contain any type of cell widget. Each of them will be put into a separate cell. In the case of vtkRenderWindow, where creating each sheet separately can end up with a large number of GL contexts, a special type of VTK sheet need to be derived from this one """ def __init__(self, rows=0, cols=0, parent=None): """ StandardWidgetSheet(rows: int, cols: int, parent: QWidget) -> StandardWidgetSheet Construct a sheet with rows x cols cells """ QtGui.QTableWidget.__init__(self, 0, 0, parent) self.setSelectionMode(QtGui.QAbstractItemView.NoSelection) self.fitToWindow = False self.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) self.setHorizontalHeader( StandardWidgetHeaderView(QtCore.Qt.Horizontal, self)) self.horizontalHeader().setSelectionModel(self.selectionModel()) self.connect(self.horizontalHeader(), QtCore.SIGNAL('sectionCountChanged(int, int)'), self.updateColumnLabels) self.connect(self.horizontalHeader(), QtCore.SIGNAL('sectionMoved(int,int,int)'), self.columnMoved) self.connect(self.horizontalHeader(), QtCore.SIGNAL('sectionPressed(int)'), self.forceColumnMultiSelect) self.setVerticalHeader( StandardWidgetHeaderView(QtCore.Qt.Vertical, self)) self.verticalHeader().setSelectionModel(self.selectionModel()) self.connect(self.verticalHeader(), QtCore.SIGNAL('sectionCountChanged(int, int)'), self.updateRowLabels) self.connect(self.verticalHeader(), QtCore.SIGNAL('sectionMoved(int,int,int)'), self.rowMoved) self.connect(self.verticalHeader(), QtCore.SIGNAL('sectionPressed(int)'), self.forceRowMultiSelect) # A hack to force the select all button in single click mode cornerButton = self.findChild(QtGui.QAbstractButton) if cornerButton: self.connect(cornerButton, QtCore.SIGNAL('clicked()'), self.forceSheetSelect) self.delegate = StandardWidgetItemDelegate(self) self.setItemDelegate(self.delegate) self.helpers = CellHelpers(parent, CellResizer(self)) self.setRowCount(rows) self.setColumnCount(cols) self.setFitToWindow(True) self.connect(self, QtCore.SIGNAL('cellActivated(int, int, bool)'), self.selectCell) self.activeCell = (-1, -1) def forceColumnMultiSelect(self, logicalIndex): """ forceColumnMultiSelect(logicalIndex: int) -> None Make sure we always toggle the headerview in the right way NOTE: the MultiSelection type of SelectionMode does not work correctly for overlapping columns and rows selection """ if (self.selectionModel().isColumnSelected(logicalIndex, QtCore.QModelIndex())): self.selectionModel().select( self.model().index(0, logicalIndex), QtGui.QItemSelectionModel.Deselect | QtGui.QItemSelectionModel.Columns) else: self.selectionModel().select( self.model().index(0, logicalIndex), QtGui.QItemSelectionModel.Select | QtGui.QItemSelectionModel.Columns) def forceRowMultiSelect(self, logicalIndex): """ forceRowMultiSelect(logicalIndex: int) -> None Make sure we always toggle the headerview in the right way NOTE: the MultiSelection type of SelectionMode does not work correctly for overlapping columns and rows selection """ if (self.selectionModel().isRowSelected(logicalIndex, QtCore.QModelIndex())): self.selectionModel().select( self.model().index(logicalIndex, 0), QtGui.QItemSelectionModel.Deselect | QtGui.QItemSelectionModel.Rows) else: self.selectionModel().select( self.model().index(logicalIndex, 0), QtGui.QItemSelectionModel.Select | QtGui.QItemSelectionModel.Rows) def forceSheetSelect(self): """ forceSheetSelect() -> None Make sure we can toggle the whole sheet selection """ totalCells = self.rowCount() * self.columnCount() if (len(self.selectionModel().selectedIndexes()) < totalCells): self.selectionModel().select( QtGui.QItemSelection( self.model().index(0, 0), self.model().index(self.rowCount() - 1, self.columnCount() - 1)), QtGui.QItemSelectionModel.Select) else: self.selectionModel().clearSelection() def updateHeaderStatus(self): """ updateHeaderStatus() -> None Update the visibility of the row and column header """ return self.horizontalHeader().setVisible(self.columnCount() > 1 or self.rowCount() > 1) self.verticalHeader().setVisible(self.columnCount() > 1 or self.rowCount() > 1) def updateRowLabels(self, oldCount, newCount): """ updateRowLabels(oldCount: int, newCount: int) -> None Update vertical labels when the number of row changed """ vLabels = [] vIdx = self.verticalHeader().visualIndex for i in xrange(newCount): vLabels.append(str(vIdx(i) + 1)) self.setVerticalHeaderLabels(vLabels) self.updateHeaderStatus() def rowMoved(self, row, old, new): """ rowMove(row: int, old: int, new: int) -> None Renumber the vertical header labels when rows moved """ self.updateRowLabels(self.rowCount(), self.rowCount()) def updateColumnLabels(self, oldCount, newCount): """ updateColumnLabels(oldCount: int, newCount: int) -> None Update horizontal labels when the number of column changed """ hLabels = [] vIdx = self.horizontalHeader().visualIndex for i in xrange(newCount): hLabels.append(chr(vIdx(i) + ord('A'))) self.setHorizontalHeaderLabels(hLabels) self.updateHeaderStatus() def columnMoved(self, row, old, new): """ columnMoved(row: int, old: int, new: int) -> None Renumber the horizontal header labels when columns moved """ self.updateColumnLabels(self.columnCount(), self.columnCount()) def setFitToWindow(self, fit=True): """ setFitToWindow(fit: boolean) -> None Force to fit all cells into the visible area. Set fit=False for the scroll mode where hidden cell can be viewed by scrolling the scrollbars. """ if fit != self.fitToWindow: self.fitToWindow = fit self.horizontalHeader().fitToWindow = fit self.horizontalHeader()._target_size = None self.verticalHeader().fitToWindow = fit self.verticalHeader()._target_size = None if not fit: width = self.columnWidth(self.columnCount() - 1) height = self.rowHeight(self.rowCount() - 1) self.setColumnWidth(self.columnCount() - 1, width) self.setRowHeight(self.rowCount() - 1, height) self.stretchCells() policy = (QtCore.Qt.ScrollBarAlwaysOff if fit else QtCore.Qt.ScrollBarAlwaysOn) self.setHorizontalScrollBarPolicy(policy) self.setVerticalScrollBarPolicy(policy) def showEvent(self, event): """ showEvent(event: QShowEvent) -> None Make sure to stretch the sheet on the first appearance """ self.stretchCells() def stretchCells(self): """ stretchCells() -> None Stretch all the cells with equally spaces to fit in the viewport """ if self.fitToWindow: self.horizontalHeader().resizeSections(QtGui.QHeaderView.Stretch) self.verticalHeader().resizeSections(QtGui.QHeaderView.Stretch) def showHelpers(self, show, row, col): """ showHelpers(show: boolean, row: int, col: int) -> None Show/hide the helpers (resizer, toolbar) on the current cell depending on the value of show """ if self.helpers.isInteracting(): return if show: if row >= 0 and col >= 0: self.helpers.snapTo(row, col) self.helpers.adjustPosition() self.helpers.show() else: self.helpers.hide() else: self.helpers.hide() def resizeEvent(self, e): if not self.fitToWindow: return thickness = StandardWidgetHeaderView.THICKNESS self.horizontalHeader()._target_size = self.size().width() - thickness self.horizontalHeader().resize_right_rows(0) self.verticalHeader()._target_size = self.size().height() - thickness self.verticalHeader().resize_right_rows(0) def getRealLocation(self, vRow, vCol, visual=False): """ getRealLocation(vRow: int, vCol: int, visual: bool) -> (int, int) Return the actual location even if there is spanning at (vRow, vCol) """ # Qt doesn't provide a mechanism to map from a cell to its # span region, so we have to scan the whole spreadsheet N^2 # for now, but our spreadsheet is usuallly small enough. if visual: (row, col) = (vRow, vCol) else: row = self.verticalHeader().logicalIndex(vRow) col = self.horizontalHeader().logicalIndex(vCol) cellSet = set() for r in xrange(self.rowCount()): for c in xrange(self.columnCount()): cellSet.add((r, c)) for r in xrange(self.rowCount()): for c in xrange(self.columnCount()): if (r, c) not in cellSet: continue rect = self.visualRect(self.model().index(r, c)) rSpan = self.rowSpan(r, c) cSpan = self.columnSpan(r, c) for rs in xrange(rSpan): for cs in xrange(cSpan): if (row == r + rs) and (col == c + cs): return (r, c) if (r + rs, c + cs) in cellSet: cellSet.remove((r + rs, c + cs)) return (-1, -1) def getCell(self, row, col): """ getCell(row: int, col: int) -> QWidget Get cell at a specific row and column """ return self.cellWidget(*self.getRealLocation(row, col)) def getCellRect(self, row, col): """ getCellRect(row: int, col: int) -> QRect Return the rectangle surrounding the cell at location (row, col) in parent coordinates """ idx = self.model().index(*self.getRealLocation(row, col)) return self.visualRect(idx) def getCellGlobalRect(self, row, col): """ getCellGlobalRect(row: int, col: int) -> QRect Return the rectangle surrounding the cell at location (row, col) in global coordinates """ rect = self.getCellRect(row, col) rect.moveTo(self.viewport().mapToGlobal(rect.topLeft())) return rect def setCellByWidget(self, row, col, cellWidget): """ setCellByWidget(row: int, col: int, cellWidget: QWidget) -> None Replace the current location (row, col) with a cell widget """ if cellWidget: # Relax the size constraint of the widget cellWidget.setMinimumSize(QtCore.QSize(0, 0)) cellWidget.setMaximumSize(QtCore.QSize(16777215, 16777215)) cellWidget.setParent(self) (row, col) = self.getRealLocation(row, col) index = self.model().index(row, col) self.setCellWidget(row, col, cellWidget) if cellWidget: self.delegate.updateEditorGeometry(cellWidget, None, index) def selectCell(self, row, col, toggling): """ selectCell(row: int, col: int, toggling: bool) -> None Select a cell based on its current selection """ (row, col) = self.getRealLocation(row, col, visual=True) if toggling: self.selectionModel().setCurrentIndex( self.model().index(row, col), QtGui.QItemSelectionModel.Toggle) if (self.selectionModel().isSelected(self.model().index(row, col))): self.setActiveCell(row, col) else: self.setActiveCell(-1, -1) else: if len(self.selectionModel().selectedIndexes()) <= 1: self.selectionModel().setCurrentIndex( self.model().index(row, col), QtGui.QItemSelectionModel.ClearAndSelect) self.setActiveCell(row, col) self.viewport().repaint() def setActiveCell(self, row, col): """ setActiveCell(row: int, col: int) -> None Set the location of an active cell also bring up the corresponding toolbar """ self.activeCell = (row, col) toolBar = self.parent().getCellToolBar(row, col) if toolBar: toolBar.snapTo(row, col) self.parent().toolBar.setCellToolBar(toolBar) def adjustWidgetGeometry(self, row, col): """ setActiveCell(row: int, col: int) -> None Adjust the widget at cell (row, col) to fit inside the cell """ cellWidget = self.getCell(row, col) if cellWidget: index = self.model().index(*self.getRealLocation(row, col)) self.delegate.updateEditorGeometry(cellWidget, None, index)
class StandardSingleCellSheetTab(QtGui.QWidget, StandardWidgetSheetTabInterface): """ StandardSingleCellSheetTab is a container of StandardWidgetSheet with only a single cell. This will be added directly to a QTabWidget on the spreadsheet as a sheet for displaying """ def __init__(self, tabWidget, row=1, col=1): """ StandardSingleCellSheetTab(row: int, col: int) -> StandardSingleCellSheetTab Initialize with the vertical layout containing only a single widget """ QtGui.QWidget.__init__(self, None) StandardWidgetSheetTabInterface.__init__(self) self.type = 'StandardSingleCellSheetTab' self.tabWidget = tabWidget self.vLayout = QtGui.QVBoxLayout() self.vLayout.setSpacing(0) self.vLayout.setMargin(0) self.setLayout(self.vLayout) self.cell = QtGui.QWidget() self.layout().addWidget(self.cell) self.helpers = CellHelpers(self) self.toolBars = {} self.blankCellToolBar = None self.pipelineInfo = {} ### Belows are API Wrappers to connect to self.sheet def getDimension(self): """ getDimension() -> tuple Get the sheet dimensions """ return (1, 1) def getCell(self, row, col): """ getCell(row: int, col: int) -> QWidget Get cell at a specific row and column. """ return self.cell def getCellToolBar(self, row, col): """ getCellToolBar(row: int, col: int) -> QWidget Return the toolbar widget at cell location (row, col) """ cell = self.getCell(row, col) if cell and hasattr(cell, 'toolBarType'): if not self.toolBars.has_key(cell.toolBarType): self.toolBars[cell.toolBarType] = cell.toolBarType(self) return self.toolBars[cell.toolBarType] else: return self.blankCellToolBar def getCellRect(self, row, col): """ getCellRect(row: int, col: int) -> QRect Return the rectangle surrounding the cell at location (row, col) in parent coordinates """ return self.contentsRect() def getCellGlobalRect(self, row, col): """ getCellGlobalRect(row: int, col: int) -> QRect Return the rectangle surrounding the cell at location (row, col) in global coordinates """ rect = self.getCellRect(row, col) rect.moveTo(self.mapToGlobal(rect.topLeft())) return rect def setCellByType(self, row, col, cellType, inputPorts): """ setCellByType(row: int, col: int, cellType: a type inherits from QWidget, inpurPorts: tuple) -> None Replace the current location (row, col) with a cell of cellType. If the current type of that cell is the same as cellType, only the contents is updated with inputPorts. """ oldCell = self.getCell(row, col) if type(oldCell) != cellType: oldCell.hide() self.layout().removeWidget(oldCell) if cellType: self.cell = cellType(self) # self.cell.setGeometry(self.getCellRect(row, col)) self.layout().addWidget(self.cell) self.cell.show() self.cell.updateContents(inputPorts) if hasattr(oldCell, 'deleteLater'): oldCell.deleteLater() del oldCell else: oldCell.updateContents(inputPorts) def showHelpers(self, show, globalPos): """ showHelpers(show: boolean, globalPos: QPoint) -> None Show the helpers (toolbar, resizer) when show==True """ if show: self.helpers.snapTo(0, 0) self.helpers.adjustPosition() self.helpers.show() else: self.helpers.hide() def getSelectedLocations(self): """ getSelectedLocations() -> tuple Return the selected locations (row, col) of the current sheet """ return [(0, 0)]