def __init__(self, parent=None, f=QtCore.Qt.WindowFlags()): """ SpreadsheetWindow(parent: QWidget, f: WindowFlags) -> SpreadsheetWindow Layout menu, status bar and tab widget """ QtGui.QMainWindow.__init__(self, parent, f) self.createEventMap() self.setWindowTitle('UV-CDAT - Spreadsheet - Untitled') self.shownConfig = False #flag to control the window setup code is done only once self.stackedCentralWidget = QtGui.QStackedWidget(self) self.tabControllerStack = TabControllerStack(self.stackedCentralWidget) self.stackedCentralWidget.addWidget(self.tabControllerStack) self.fullScreenStackedWidget = QtGui.QStackedWidget( self.stackedCentralWidget) self.stackedCentralWidget.addWidget(self.fullScreenStackedWidget) self.setCentralWidget(self.stackedCentralWidget) self.setStatusBar(QtGui.QStatusBar(self)) self.modeActionGroup = QtGui.QActionGroup(self) self.visApp = QtCore.QCoreApplication.instance() self.visApp.installEventFilter(self) self.setupMenu() self.connect(self.tabControllerStack, QtCore.SIGNAL('needChangeTitle'), self.setWindowTitle) self.file_pool = module_utils.FilePool() self.echoMode = False self.echoCellEvents = [] if hasattr(self.visApp, 'builderWindow'): self.quitAction = QtGui.QAction('&Quit VisTrails', self) self.addAction(self.quitAction) self.quitAction.setShortcut('Ctrl+Q') self.connect(self.quitAction, QtCore.SIGNAL('triggered()'), self.quitActionTriggered)
class SpreadsheetWindow(QtGui.QMainWindow): """ SpreadsheetWindow is the top-level main window containing a stacked widget of QTabWidget and its stacked widget for slideshow mode """ def __init__(self, parent=None, f=QtCore.Qt.WindowFlags()): """ SpreadsheetWindow(parent: QWidget, f: WindowFlags) -> SpreadsheetWindow Layout menu, status bar and tab widget """ QtGui.QMainWindow.__init__(self, parent, f) self.createEventMap() self.setWindowTitle('UV-CDAT - Spreadsheet - Untitled') self.shownConfig = False #flag to control the window setup code is done only once self.stackedCentralWidget = QtGui.QStackedWidget(self) self.tabControllerStack = TabControllerStack(self.stackedCentralWidget) self.stackedCentralWidget.addWidget(self.tabControllerStack) self.fullScreenStackedWidget = QtGui.QStackedWidget( self.stackedCentralWidget) self.stackedCentralWidget.addWidget(self.fullScreenStackedWidget) self.setCentralWidget(self.stackedCentralWidget) self.setStatusBar(QtGui.QStatusBar(self)) self.modeActionGroup = QtGui.QActionGroup(self) self.visApp = QtCore.QCoreApplication.instance() self.visApp.installEventFilter(self) self.setupMenu() self.connect(self.tabControllerStack, QtCore.SIGNAL('needChangeTitle'), self.setWindowTitle) self.file_pool = module_utils.FilePool() self.echoMode = False self.echoCellEvents = [] if hasattr(self.visApp, 'builderWindow'): self.quitAction = QtGui.QAction('&Quit VisTrails', self) self.addAction(self.quitAction) self.quitAction.setShortcut('Ctrl+Q') self.connect(self.quitAction, QtCore.SIGNAL('triggered()'), self.quitActionTriggered) # if the spreadsheet has one row and 2 columns # this will cause the spreadsheet to have each cell # 550 x 450 size in the server #self.resize(1156, 599) def get_current_tab_controller(self): return self.tabControllerStack.currentWidget() def quitActionTriggered(self): if self.visApp and hasattr(self.visApp, 'builderWindow') and \ self.visApp.builderWindow.isVisible(): self.visApp.builderWindow.quit() def cleanup(self): if self.visApp!=None: self.visApp.removeEventFilter(self) self.file_pool.cleanup() self.tabControllerStack.cleanup() def destroy(self): self.tabControllerStack.cleanup() self.file_pool.cleanup() def setupMenu(self): """ setupMenu() -> None Add all available actions to the menu bar """ menu_bar = self.menuBar() self.mainMenu = QtGui.QMenu('&Spreadsheet', menu_bar) self.menuBar().addAction(self.mainMenu.menuAction()) # self.mainMenu.addAction(self.tabController.saveAction()) # self.mainMenu.addAction(self.tabController.saveAsAction()) # self.mainMenu.addAction(self.tabController.openAction()) # self.mainMenu.addSeparator() self.mainMenu.addAction(self.tabControllerStack.new_tab_action) #self.mainMenu.addAction(self.tabControllerStack.deleteSheetAction()) self.mainMenu.addSeparator() #self.menuBar().addAction(self.viewMenu.menuAction()) self.mainMenu.addAction(self.interactiveModeAction()) self.mainMenu.addAction(self.editingModeAction()) #self.viewMenu.addSeparator() #self.viewMenu.addAction(self.fitToWindowAction()) #self.viewMenu.addAction(self.fullScreenAction()) #self.windowMenu = QtGui.QMenu('&Window', self.menuBar()) #self.menuBar().addAction(self.windowMenu.menuAction()) #self.windowMenu.addAction(self.showBuilderWindowAction()) self.connect(self.modeActionGroup, QtCore.SIGNAL('triggered(QAction*)'), self.modeChanged) def fitToWindowAction(self): """ fitToWindowAction() -> QAction Return the fit to window action """ if not hasattr(self, 'fitAction'): self.fitAction = QtGui.QAction('Fit to window', self) self.fitAction.setStatusTip('Stretch spreadsheet cells ' 'to fit the window size') self.fitAction.setCheckable(True) checked = self.tabController.currentWidget().sheet.fitToWindow self.fitAction.setChecked(checked) self.connect(self.fitAction, QtCore.SIGNAL('toggled(bool)'), self.fitActionToggled) return self.fitAction def fitActionToggled(self, checked): """ fitActionToggled(checked: boolean) -> None Handle fitToWindow Action toggled """ self.tabController.currentWidget().sheet.setFitToWindow(checked) def fullScreenAction(self): """ fullScreenAction() -> QAction Return the fullscreen action """ if not hasattr(self, 'fullScreenActionVar'): self.fullScreenActionVar = QtGui.QAction('&Full Screen', self) self.fullScreenActionVar.setShortcut('Ctrl+F') self.fullScreenActionVar.setCheckable(True) self.fullScreenActionVar.setChecked(False) self.fullScreenActionVar.setStatusTip('Show sheets without any ' 'menubar or statusbar') self.connect(self.fullScreenActionVar, QtCore.SIGNAL('triggered(bool)'), self.fullScreenActivated) self.fullScreenAlternativeShortcuts = [QtGui.QShortcut('F11', self), QtGui.QShortcut('Alt+Return', self), QtGui.QShortcut('Alt+Enter', self)] for sc in self.fullScreenAlternativeShortcuts: self.connect(sc, QtCore.SIGNAL('activated()'), self.fullScreenActionVar.trigger) return self.fullScreenActionVar def fullScreenActivated(self, full=None): """ fullScreenActivated(full: bool) -> None if fullScreen has been requested has pressed, then go to fullscreen now """ if full==None: fs = self.isFullScreen() fs = not fs else: fs = full if fs: self.setWindowState(QtCore.Qt.WindowFullScreen) else: self.setWindowState(QtCore.Qt.WindowNoState) fs = self.isFullScreen() self.menuBar().setVisible(not fs) self.statusBar().setVisible(not fs) tabController = self.get_current_tab_controller() tabController.setupFullScreenWidget(fs,self.fullScreenStackedWidget) self.stackedCentralWidget.setCurrentIndex(int(fs)) def interactiveModeAction(self): """ interactiveModeAction() -> QAction Return the interactive mode action, this is the mode where users can interact with the content of the cells """ if not hasattr(self, 'interactiveModeActionVar'): self.interactiveModeActionVar = QtGui.QAction('&Interactive Mode', self.modeActionGroup) self.interactiveModeActionVar.setCheckable(True) self.interactiveModeActionVar.setChecked(True) self.interactiveModeActionVar.setShortcut('Ctrl+Shift+I') self.interactiveModeActionVar.setStatusTip('Use this mode to ' 'interact with ' 'the cell contents') return self.interactiveModeActionVar def editingModeAction(self): """ editingModeAction() -> QAction Return the editing mode action, this is the mode where users can interact with the content of the cells """ if not hasattr(self, 'editingModeActionVar'): self.editingModeActionVar = QtGui.QAction('&Editing Mode', self.modeActionGroup) self.editingModeActionVar.setCheckable(True) self.editingModeActionVar.setShortcut('Ctrl+Shift+E') self.editingModeActionVar.setStatusTip('Use this mode to ' 'layout cells and ' 'interact cells with ' 'the builder') return self.editingModeActionVar def showBuilderWindowAction(self): """ showBuilderWindowAction() -> QAction Return the show builder action, this is used to show the builder window when only the spreadsheet window is visible. """ if not hasattr(self, 'showBuilderWindowActionVar'): self.showBuilderWindowActionVar = \ QtGui.QAction('&Show Builder Window', self) self.showBuilderWindowActionVar.setShortcut('Ctrl+Shift+B') self.showBuilderWindowActionVar.setStatusTip('Show the ' 'Builder Window') if hasattr(self.visApp, 'builderWindow'): self.showBuilderWindowActionVar.setEnabled(True) else: self.showBuilderWindowActionVar.setEnabled(False) self.connect(self.showBuilderWindowActionVar, QtCore.SIGNAL('triggered()'), self.showBuilderWindowActionTriggered) return self.showBuilderWindowActionVar def modeChanged(self, action): """ modeChanged(action: QAction) -> None Handle the new mode (interactive or editing) based on the triggered action """ editing = self.editingModeAction().isChecked() tabController = self.get_current_tab_controller() tabController.setEditingMode(editing) def configShow(self, show=False): """ configShow() -> None Read VisTrails setting and show the spreadsheet window accordingly """ if hasattr(self.visApp, 'configuration'): if self.shownConfig: self.show() ### Multiheads desktop = QtGui.QApplication.desktop() if self.visApp.temp_configuration.multiHeads and desktop.numScreens()>1: builderScreen = desktop.screenNumber(self.visApp.builderWindow) r = desktop.availableGeometry(builderScreen) if self.visApp.builderWindow: self.visApp.builderWindow.ensurePolished() self.visApp.builderWindow.updateGeometry() frame = self.visApp.builderWindow.frameGeometry() rect = self.visApp.builderWindow.rect() frameDiff = QtCore.QPoint((frame.width()-rect.width())/2, (frame.height()-rect.height())/2) self.visApp.builderWindow.move( frame.topLeft()+r.center()-frame.center() ) for i in xrange(desktop.numScreens()): if i!=builderScreen: r = desktop.availableGeometry(i) self.adjustSize() self.move(r.center()-self.rect().center()-frameDiff) break if not self.visApp.temp_configuration.interactiveMode: self.shownConfig = True if show: self.show() return ### Maximize if self.visApp.temp_configuration.maximizeWindows: self.showMaximized() ### When the builder is hidden, the spreadsheet window does ### not have focus. We have to force it if self.visApp.temp_configuration.showSpreadsheetOnly: self.raise_() else: self.show() ### When the builder is hidden, the spreadsheet window does ### not have focus. We have to force it to have the focus if self.visApp.temp_configuration.showSpreadsheetOnly: self.raise_() else: self.show() self.shownConfig = True def showEvent(self, e): """ showEvent(e: QShowEvent) -> None Make sure we show ourself for show event """ self.show() # Without this Ubuntu Unity will not show the menu bar self.raise_() def closeEvent(self, e): """ closeEvent(e: QCloseEvent) -> None When close, just hide instead """ if hasattr(self.visApp, 'builderWindow'): if self.visApp.builderWindow.isVisible(): e.ignore() self.hide() else: #if the window is not visible, we need to quit the application QtCore.QCoreApplication.quit() else: QtGui.QMainWindow.closeEvent(self, e) def sizeHint(self): """ sizeHint() -> QSize Return a default size of the window """ return QtCore.QSize(1024, 768) def eventFilter(self,q,e): """ eventFilter(q: QObject, e: QEvent) -> depends on event type An application-wide eventfilter to capture mouse/keyboard events """ eType = e.type() tabController = self.get_current_tab_controller() if not tabController: return False # Handle Show/Hide cell resizer on MouseMove if eType==QtCore.QEvent.MouseMove: sheetWidget = tabController.tabWidgetUnderMouse() if sheetWidget: sheetWidget.showHelpers(True, QtGui.QCursor.pos()) # Slideshow mode if (eType==QtCore.QEvent.MouseButtonPress and self.isFullScreen() and e.buttons()&QtCore.Qt.RightButton): tabController.showPopupMenu() return True # Handle slideshow shortcuts if (eType==QtCore.QEvent.KeyPress and self.isFullScreen()): if (e.key() in [QtCore.Qt.Key_Space, QtCore.Qt.Key_PageDown,QtCore.Qt.Key_Right]): tabController.showNextTab() return True if (e.key() in [QtCore.Qt.Key_PageUp,QtCore.Qt.Key_Left]): tabController.showPrevTab() return True if (e.key()==QtCore.Qt.Key_Escape or (e.key()==QtCore.Qt.Key_F and e.modifiers()&QtCore.Qt.ControlModifier)): self.fullScreenAction().trigger() return True # Perform single-click event on the spread sheet if (not tabController.editingMode and eType==QtCore.QEvent.MouseButtonPress): if type(q)==QCellContainer: return q.containedWidget!=None p = q while (p and (not p.isModal()) and type(p)!=StandardWidgetSheet): try: p = p.parent() except TypeError: break try: if p and not p.isModal(): pos = p.viewport().mapFromGlobal(e.globalPos()) p.emit(QtCore.SIGNAL('cellActivated(int, int, bool)'), p.rowAt(pos.y()), p.columnAt(pos.x()), e.modifiers()==QtCore.Qt.ControlModifier) except AttributeError: return False return False #return QtGui.QMainWindow.eventFilter(self,q,e) def event(self, e): """ event(e: QEvent) -> depends on event type Handle all special events from spreadsheet controller """ if self.eventMap.has_key(e.type()): self.eventMap[e.type()](e) return False return QtGui.QMainWindow.event(self, e) def createEventMap(self): """ createEventMap() -> None Create the event map to call inside the event(). This must be called before anything else """ self.eventMap = { DisplayCellEventType : self.displayCellEvent, BatchDisplayCellEventType : self.batchDisplayCellEvent, RepaintCurrentSheetEventType: self.repaintCurrentSheetEvent } def displayCellEvent(self, e): """ displayCellEvent(e: DisplayCellEvent) -> None Display a cell when receive this event """ if self.echoMode: self.echoCellEvents.append(e) return None tabController = self.get_current_tab_controller() if tabController is None: self.addTabController("UV-CDAT") tabController = self.get_current_tab_controller() tabController.addPipeline(e.vistrail) cid = tabController.increasePipelineCellId(e.vistrail) pid = tabController.getCurrentPipelineId(e.vistrail) if tabController.isLoadingMode(): locations = tabController.getMonitoredLocations(( (e.vistrail), pid, cid)) for (sheet, row, col) in locations: sheet.tabWidget.setCurrentWidget(sheet) sheet.setCellPipelineInfo(row, col, (e.vistrail, pid, cid)) sheet.setCellByType(row, col, e.cellType, e.inputPorts) return None else: reference = e.sheetReference if reference==None: reference = StandardSheetReference() sheet = tabController.findSheet(reference) row = e.row col = e.col if row<0 or col<0: (row, col) = sheet.getFreeCell() sheet.tabWidget.setCurrentWidget(sheet) sheet.setCellPipelineInfo(row, col, (e.vistrail, pid, cid)) if e.rowSpan>=1 or e.colSpan>=1: sheet.setSpan(row, col, e.rowSpan, e.colSpan) if e.inputPorts!=None: sheet.setCellByType(row, col, e.cellType, e.inputPorts) else: sheet.setCellByWidget(row, col, e.cellType) QtCore.QCoreApplication.processEvents() cell = sheet.getCell(row, col) if self.editingModeAction().isChecked(): sheet.setCellEditingMode(row, col, True) #If a cell has to dump its contents to a file, it will be in the #extra_info dictionary if cell and e.vistrail.has_key('extra_info'): dump_as_pdf = False extra_info = e.vistrail['extra_info'] if extra_info.has_key('pathDumpCells'): dumppath = extra_info['pathDumpCells'] if extra_info.has_key('nameDumpCells'): name = extra_info['nameDumpCells'] base_fname = os.path.join(dumppath, name) else: locator = e.vistrail['locator'] if locator is not None: name = e.vistrail['locator'].short_name else: name = 'untitled' version = e.vistrail['version'] if version is None: version = 0L base_fname = os.path.join(dumppath,"%s_%s" % \ (name, e.vistrail['version'])) if configuration.dumpfileType == 'PNG': dump_as_pdf = False elif configuration.dumpfileType == 'PDF': dump_as_pdf = True #extra_info configuration overwrites global configuration if extra_info.has_key('pdf'): dump_as_pdf = extra_info['pdf'] file_extension = '.png' if dump_as_pdf == True: file_extension = '.pdf' # make a unique filename filename = base_fname + file_extension counter = 2 while os.path.exists(filename): filename = base_fname + "_%d%s" % (counter, file_extension) counter += 1 if not dump_as_pdf: cell.dumpToFile(filename) else: cell.saveToPDF(filename) #if the cell was already selected, then we need to update #the toolbar with this new cell if hasattr(sheet, 'sheet'): if sheet.sheet.activeCell == (row,col): sheet.sheet.setActiveCell(row,col) return cell def batchDisplayCellEvent(self, batchEvent): """ batchDisplayCellEvent(batchEvent: BatchDisplayCellEvent) -> None Handle event where a series of cells are arrived """ tabController = self.get_current_tab_controller() tabController.addPipeline(batchEvent.vistrail) for e in batchEvent.displayEvents: e.vistrail = batchEvent.vistrail self.displayCellEvent(e) def repaintCurrentSheetEvent(self, e): """ repaintCurrentSheetEvent(e: RepaintCurrentSheetEvent) -> None Repaint the current sheet """ tabController = self.get_current_tab_controller() currentTab = tabController.currentWidget() if currentTab: (rCount, cCount) = currentTab.getDimension() for r in xrange(rCount): for c in xrange(cCount): widget = currentTab.getCell(r, c) if widget: widget.repaint() def showBuilderWindowActionTriggered(self): """showBuilderWindowActionTriggered() -> None This will show the builder window """ self.visApp.builderWindow.show() def prepareReviewingMode(self, vCol): """ Trim down most of the spreadsheet window """ self.menuBar().hide() self.statusBar().hide() tabController = self.get_current_tab_controller() tabController.tabBar().hide() tabController.clearTabs() self.setWindowFlags(QtCore.Qt.Tool | QtCore.Qt.WindowStaysOnTopHint) self.setWindowTitle('Pipeline Review') self.resize(560*vCol, 512) self.show() def startReviewingMode(self): """ startReviewingMode() Reorganize the spreadsheet to contain only cells executed from locator:version """ tabController = self.get_current_tab_controller() currentTab = tabController.currentWidget() if currentTab: currentTab.toolBar.hide() buttonLayout = QtGui.QHBoxLayout() buttons = [QtGui.QPushButton('&Accept'), QtGui.QPushButton('&Discard')] buttonLayout.addStretch() buttonLayout.addWidget(buttons[0]) buttonLayout.addWidget(buttons[1]) buttonLayout.addStretch() currentTab.layout().addLayout(buttonLayout) self.connect(buttons[0], QtCore.SIGNAL('clicked()'), self.acceptReview) self.connect(buttons[1], QtCore.SIGNAL('clicked()'), self.discardReview) def discardReview(self): """ Just quit the program """ QtCore.QCoreApplication.quit() def acceptReview(self): """ Copy image of all cells to the clipboard and then exit """ tabController = self.get_current_tab_controller() currentTab = tabController.currentWidget() height = 0 width = 0 pixmaps = [] version = -1 if currentTab: (rCount, cCount) = currentTab.getDimension() for r in xrange(rCount): for c in xrange(cCount): widget = currentTab.getCell(r, c) if widget: version = currentTab.getCellPipelineInfo(r, c)[0]['version'] pix = widget.grabWindowPixmap() pixmaps.append(pix) width += pix.width() height = max(height, pix.height()) finalImage = QtGui.QImage(width, height, QtGui.QImage.Format_ARGB32) painter = QtGui.QPainter(finalImage) x = 0 for pix in pixmaps: painter.drawPixmap(x, 0, pix) x += pix.width() painter.end() filename = tempfile.gettempdir() + '/' + 'vtexport.png' finalImage.save(filename, 'PNG') sm = QtCore.QSharedMemory('VisTrailsPipelineImage') sm.create(32768) sm.attach() sm.lock() pfn = ctypes.c_char_p(filename) ctypes.memmove(int(sm.data()), pfn, len(filename)) pfn = ctypes.c_char_p(str(version)) ctypes.memmove(int(sm.data())+256, pfn, len(str(version))) sm.unlock() sm.detach() QtCore.QCoreApplication.quit() def setEchoMode(self, echo): """ setEchoMode(echo: bool) Instruct the spreadsheet to dispatch (echo) all cell widgets instead of managing them on the spreadsheet """ self.echoMode = echo def getEchoCellEvents(self): """ getEchoCellEvents() -> [DisplayCellEvent] Echo back the list of all cell events that have been captured earlier """ return self.echoCellEvents def clearEchoCellEvents(self): """ clearEchoCellEvents() Erase the list of echoed events """ self.echoCellEvents = [] def changeTabController(self, name): self.tabControllerStack.change_selected_view(name) def addTabController(self, name): self.tabControllerStack.add_view(name) def removeTabController(self, name): self.tabControllerStack.remove_view(name) def getTabController(self, name): return self.tabControllerStack.get_tab_controller_by_name(name)
class SpreadsheetWindow(QtGui.QMainWindow): """ SpreadsheetWindow is the top-level main window containing a stacked widget of QTabWidget and its stacked widget for slideshow mode """ def __init__(self, parent=None, f=QtCore.Qt.WindowFlags()): """ SpreadsheetWindow(parent: QWidget, f: WindowFlags) -> SpreadsheetWindow Layout menu, status bar and tab widget """ QtGui.QMainWindow.__init__(self, parent, f) self.createEventMap() self.setWindowTitle('UV-CDAT - Spreadsheet - Untitled') self.shownConfig = False #flag to control the window setup code is done only once self.stackedCentralWidget = QtGui.QStackedWidget(self) self.tabControllerStack = TabControllerStack(self.stackedCentralWidget) self.stackedCentralWidget.addWidget(self.tabControllerStack) self.fullScreenStackedWidget = QtGui.QStackedWidget( self.stackedCentralWidget) self.stackedCentralWidget.addWidget(self.fullScreenStackedWidget) self.setCentralWidget(self.stackedCentralWidget) self.setStatusBar(QtGui.QStatusBar(self)) self.modeActionGroup = QtGui.QActionGroup(self) self.visApp = QtCore.QCoreApplication.instance() self.visApp.installEventFilter(self) self.setupMenu() self.connect(self.tabControllerStack, QtCore.SIGNAL('needChangeTitle'), self.setWindowTitle) self.file_pool = module_utils.FilePool() self.echoMode = False self.echoCellEvents = [] if hasattr(self.visApp, 'builderWindow'): self.quitAction = QtGui.QAction('&Quit VisTrails', self) self.addAction(self.quitAction) self.quitAction.setShortcut('Ctrl+Q') self.connect(self.quitAction, QtCore.SIGNAL('triggered()'), self.quitActionTriggered) # if the spreadsheet has one row and 2 columns # this will cause the spreadsheet to have each cell # 550 x 450 size in the server #self.resize(1156, 599) def get_current_tab_controller(self): return self.tabControllerStack.currentWidget() def quitActionTriggered(self): if self.visApp and hasattr(self.visApp, 'builderWindow') and \ self.visApp.builderWindow.isVisible(): self.visApp.builderWindow.quit() def cleanup(self): if self.visApp != None: self.visApp.removeEventFilter(self) self.file_pool.cleanup() self.tabControllerStack.cleanup() def destroy(self): self.tabControllerStack.cleanup() self.file_pool.cleanup() def setupMenu(self): """ setupMenu() -> None Add all available actions to the menu bar """ menu_bar = self.menuBar() self.mainMenu = QtGui.QMenu('&Spreadsheet', menu_bar) self.menuBar().addAction(self.mainMenu.menuAction()) # self.mainMenu.addAction(self.tabController.saveAction()) # self.mainMenu.addAction(self.tabController.saveAsAction()) # self.mainMenu.addAction(self.tabController.openAction()) # self.mainMenu.addSeparator() self.mainMenu.addAction(self.tabControllerStack.new_tab_action) #self.mainMenu.addAction(self.tabControllerStack.deleteSheetAction()) self.mainMenu.addSeparator() #self.menuBar().addAction(self.viewMenu.menuAction()) self.mainMenu.addAction(self.interactiveModeAction()) self.mainMenu.addAction(self.editingModeAction()) #self.viewMenu.addSeparator() #self.viewMenu.addAction(self.fitToWindowAction()) #self.viewMenu.addAction(self.fullScreenAction()) #self.windowMenu = QtGui.QMenu('&Window', self.menuBar()) #self.menuBar().addAction(self.windowMenu.menuAction()) #self.windowMenu.addAction(self.showBuilderWindowAction()) self.connect(self.modeActionGroup, QtCore.SIGNAL('triggered(QAction*)'), self.modeChanged) def fitToWindowAction(self): """ fitToWindowAction() -> QAction Return the fit to window action """ if not hasattr(self, 'fitAction'): self.fitAction = QtGui.QAction('Fit to window', self) self.fitAction.setStatusTip('Stretch spreadsheet cells ' 'to fit the window size') self.fitAction.setCheckable(True) checked = self.tabController.currentWidget().sheet.fitToWindow self.fitAction.setChecked(checked) self.connect(self.fitAction, QtCore.SIGNAL('toggled(bool)'), self.fitActionToggled) return self.fitAction def fitActionToggled(self, checked): """ fitActionToggled(checked: boolean) -> None Handle fitToWindow Action toggled """ self.tabController.currentWidget().sheet.setFitToWindow(checked) def fullScreenAction(self): """ fullScreenAction() -> QAction Return the fullscreen action """ if not hasattr(self, 'fullScreenActionVar'): self.fullScreenActionVar = QtGui.QAction('&Full Screen', self) self.fullScreenActionVar.setShortcut('Ctrl+F') self.fullScreenActionVar.setCheckable(True) self.fullScreenActionVar.setChecked(False) self.fullScreenActionVar.setStatusTip('Show sheets without any ' 'menubar or statusbar') self.connect(self.fullScreenActionVar, QtCore.SIGNAL('triggered(bool)'), self.fullScreenActivated) self.fullScreenAlternativeShortcuts = [ QtGui.QShortcut('F11', self), QtGui.QShortcut('Alt+Return', self), QtGui.QShortcut('Alt+Enter', self) ] for sc in self.fullScreenAlternativeShortcuts: self.connect(sc, QtCore.SIGNAL('activated()'), self.fullScreenActionVar.trigger) return self.fullScreenActionVar def fullScreenActivated(self, full=None): """ fullScreenActivated(full: bool) -> None if fullScreen has been requested has pressed, then go to fullscreen now """ if full == None: fs = self.isFullScreen() fs = not fs else: fs = full if fs: self.setWindowState(QtCore.Qt.WindowFullScreen) else: self.setWindowState(QtCore.Qt.WindowNoState) fs = self.isFullScreen() self.menuBar().setVisible(not fs) self.statusBar().setVisible(not fs) tabController = self.get_current_tab_controller() tabController.setupFullScreenWidget(fs, self.fullScreenStackedWidget) self.stackedCentralWidget.setCurrentIndex(int(fs)) def interactiveModeAction(self): """ interactiveModeAction() -> QAction Return the interactive mode action, this is the mode where users can interact with the content of the cells """ if not hasattr(self, 'interactiveModeActionVar'): self.interactiveModeActionVar = QtGui.QAction( '&Interactive Mode', self.modeActionGroup) self.interactiveModeActionVar.setCheckable(True) self.interactiveModeActionVar.setChecked(True) self.interactiveModeActionVar.setShortcut('Ctrl+Shift+I') self.interactiveModeActionVar.setStatusTip('Use this mode to ' 'interact with ' 'the cell contents') return self.interactiveModeActionVar def editingModeAction(self): """ editingModeAction() -> QAction Return the editing mode action, this is the mode where users can interact with the content of the cells """ if not hasattr(self, 'editingModeActionVar'): self.editingModeActionVar = QtGui.QAction('&Editing Mode', self.modeActionGroup) self.editingModeActionVar.setCheckable(True) self.editingModeActionVar.setShortcut('Ctrl+Shift+E') self.editingModeActionVar.setStatusTip('Use this mode to ' 'layout cells and ' 'interact cells with ' 'the builder') return self.editingModeActionVar def showBuilderWindowAction(self): """ showBuilderWindowAction() -> QAction Return the show builder action, this is used to show the builder window when only the spreadsheet window is visible. """ if not hasattr(self, 'showBuilderWindowActionVar'): self.showBuilderWindowActionVar = \ QtGui.QAction('&Show Builder Window', self) self.showBuilderWindowActionVar.setShortcut('Ctrl+Shift+B') self.showBuilderWindowActionVar.setStatusTip('Show the ' 'Builder Window') if hasattr(self.visApp, 'builderWindow'): self.showBuilderWindowActionVar.setEnabled(True) else: self.showBuilderWindowActionVar.setEnabled(False) self.connect(self.showBuilderWindowActionVar, QtCore.SIGNAL('triggered()'), self.showBuilderWindowActionTriggered) return self.showBuilderWindowActionVar def modeChanged(self, action): """ modeChanged(action: QAction) -> None Handle the new mode (interactive or editing) based on the triggered action """ editing = self.editingModeAction().isChecked() tabController = self.get_current_tab_controller() tabController.setEditingMode(editing) def configShow(self, show=False): """ configShow() -> None Read VisTrails setting and show the spreadsheet window accordingly """ if hasattr(self.visApp, 'configuration'): if self.shownConfig: self.show() ### Multiheads desktop = QtGui.QApplication.desktop() if self.visApp.temp_configuration.multiHeads and desktop.numScreens( ) > 1: builderScreen = desktop.screenNumber(self.visApp.builderWindow) r = desktop.availableGeometry(builderScreen) if self.visApp.builderWindow: self.visApp.builderWindow.ensurePolished() self.visApp.builderWindow.updateGeometry() frame = self.visApp.builderWindow.frameGeometry() rect = self.visApp.builderWindow.rect() frameDiff = QtCore.QPoint( (frame.width() - rect.width()) / 2, (frame.height() - rect.height()) / 2) self.visApp.builderWindow.move(frame.topLeft() + r.center() - frame.center()) for i in xrange(desktop.numScreens()): if i != builderScreen: r = desktop.availableGeometry(i) self.adjustSize() self.move(r.center() - self.rect().center() - frameDiff) break if not self.visApp.temp_configuration.interactiveMode: self.shownConfig = True if show: self.show() return ### Maximize if self.visApp.temp_configuration.maximizeWindows: self.showMaximized() ### When the builder is hidden, the spreadsheet window does ### not have focus. We have to force it if self.visApp.temp_configuration.showSpreadsheetOnly: self.raise_() else: self.show() ### When the builder is hidden, the spreadsheet window does ### not have focus. We have to force it to have the focus if self.visApp.temp_configuration.showSpreadsheetOnly: self.raise_() else: self.show() self.shownConfig = True def showEvent(self, e): """ showEvent(e: QShowEvent) -> None Make sure we show ourself for show event """ self.show() # Without this Ubuntu Unity will not show the menu bar self.raise_() def closeEvent(self, e): """ closeEvent(e: QCloseEvent) -> None When close, just hide instead """ if hasattr(self.visApp, 'builderWindow'): if self.visApp.builderWindow.isVisible(): e.ignore() self.hide() else: #if the window is not visible, we need to quit the application QtCore.QCoreApplication.quit() else: QtGui.QMainWindow.closeEvent(self, e) def sizeHint(self): """ sizeHint() -> QSize Return a default size of the window """ return QtCore.QSize(1024, 768) def eventFilter(self, q, e): """ eventFilter(q: QObject, e: QEvent) -> depends on event type An application-wide eventfilter to capture mouse/keyboard events """ eType = e.type() tabController = self.get_current_tab_controller() if not tabController: return False # Handle Show/Hide cell resizer on MouseMove if eType == QtCore.QEvent.MouseMove: sheetWidget = tabController.tabWidgetUnderMouse() if sheetWidget: sheetWidget.showHelpers(True, QtGui.QCursor.pos()) # Slideshow mode if (eType == QtCore.QEvent.MouseButtonPress and self.isFullScreen() and e.buttons() & QtCore.Qt.RightButton): tabController.showPopupMenu() return True # Handle slideshow shortcuts if (eType == QtCore.QEvent.KeyPress and self.isFullScreen()): if (e.key() in [ QtCore.Qt.Key_Space, QtCore.Qt.Key_PageDown, QtCore.Qt.Key_Right ]): tabController.showNextTab() return True if (e.key() in [QtCore.Qt.Key_PageUp, QtCore.Qt.Key_Left]): tabController.showPrevTab() return True if (e.key() == QtCore.Qt.Key_Escape or (e.key() == QtCore.Qt.Key_F and e.modifiers() & QtCore.Qt.ControlModifier)): self.fullScreenAction().trigger() return True # Perform single-click event on the spread sheet if (not tabController.editingMode and eType == QtCore.QEvent.MouseButtonPress): if type(q) == QCellContainer: return q.containedWidget != None p = q while (p and (not p.isModal()) and type(p) != StandardWidgetSheet): try: p = p.parent() except TypeError: break try: if p and not p.isModal(): pos = p.viewport().mapFromGlobal(e.globalPos()) p.emit(QtCore.SIGNAL('cellActivated(int, int, bool)'), p.rowAt(pos.y()), p.columnAt(pos.x()), False) except AttributeError: return False return False #return QtGui.QMainWindow.eventFilter(self,q,e) def event(self, e): """ event(e: QEvent) -> depends on event type Handle all special events from spreadsheet controller """ if self.eventMap.has_key(e.type()): self.eventMap[e.type()](e) return False return QtGui.QMainWindow.event(self, e) def createEventMap(self): """ createEventMap() -> None Create the event map to call inside the event(). This must be called before anything else """ self.eventMap = { DisplayCellEventType: self.displayCellEvent, BatchDisplayCellEventType: self.batchDisplayCellEvent, RepaintCurrentSheetEventType: self.repaintCurrentSheetEvent } def displayCellEvent(self, e): """ displayCellEvent(e: DisplayCellEvent) -> None Display a cell when receive this event """ from spreadsheet_base import StandardSheetReference if self.echoMode: self.echoCellEvents.append(e) return None tabController = self.get_current_tab_controller() if tabController is None: self.addTabController("UV-CDAT") tabController = self.get_current_tab_controller() tabController.addPipeline(e.vistrail) cid = tabController.increasePipelineCellId(e.vistrail) pid = tabController.getCurrentPipelineId(e.vistrail) if tabController.isLoadingMode(): locations = tabController.getMonitoredLocations( ((e.vistrail), pid, cid)) for (sheet, row, col) in locations: sheet.tabWidget.setCurrentWidget(sheet) sheet.setCellPipelineInfo(row, col, (e.vistrail, pid, cid)) sheet.setCellByType(row, col, e.cellType, e.inputPorts) return None else: reference = e.sheetReference if reference == None: reference = StandardSheetReference() sheet = tabController.findSheet(reference) row = e.row col = e.col if row < 0 or col < 0: (row, col) = sheet.getFreeCell() sheet.tabWidget.setCurrentWidget(sheet) sheet.setCellPipelineInfo(row, col, (e.vistrail, pid, cid)) if e.rowSpan >= 1 or e.colSpan >= 1: sheet.setSpan(row, col, e.rowSpan, e.colSpan) if e.inputPorts != None: sheet.setCellByType(row, col, e.cellType, e.inputPorts) else: sheet.setCellByWidget(row, col, e.cellType) QtCore.QCoreApplication.processEvents() cell = sheet.getCell(row, col) if self.editingModeAction().isChecked(): sheet.setCellEditingMode(row, col, True) #If a cell has to dump its contents to a file, it will be in the #extra_info dictionary if cell and e.vistrail.has_key('extra_info'): dump_as_pdf = False extra_info = e.vistrail['extra_info'] if extra_info.has_key('pathDumpCells'): dumppath = extra_info['pathDumpCells'] if extra_info.has_key('nameDumpCells'): name = extra_info['nameDumpCells'] base_fname = os.path.join(dumppath, name) else: locator = e.vistrail['locator'] if locator is not None: name = e.vistrail['locator'].short_name else: name = 'untitled' version = e.vistrail['version'] if version is None: version = 0L base_fname = os.path.join(dumppath,"%s_%s" % \ (name, e.vistrail['version'])) if configuration.dumpfileType == 'PNG': dump_as_pdf = False elif configuration.dumpfileType == 'PDF': dump_as_pdf = True #extra_info configuration overwrites global configuration if extra_info.has_key('pdf'): dump_as_pdf = extra_info['pdf'] file_extension = '.png' if dump_as_pdf == True: file_extension = '.pdf' # make a unique filename filename = base_fname + file_extension counter = 2 while os.path.exists(filename): filename = base_fname + "_%d%s" % (counter, file_extension) counter += 1 if not dump_as_pdf: cell.dumpToFile(filename) else: cell.saveToPDF(filename) #if the cell was already selected, then we need to update #the toolbar with this new cell if hasattr(sheet, 'sheet'): if sheet.sheet.activeCell == (row, col): sheet.sheet.setActiveCell(row, col) return cell def batchDisplayCellEvent(self, batchEvent): """ batchDisplayCellEvent(batchEvent: BatchDisplayCellEvent) -> None Handle event where a series of cells are arrived """ tabController = self.get_current_tab_controller() tabController.addPipeline(batchEvent.vistrail) for e in batchEvent.displayEvents: e.vistrail = batchEvent.vistrail self.displayCellEvent(e) def repaintCurrentSheetEvent(self, e): """ repaintCurrentSheetEvent(e: RepaintCurrentSheetEvent) -> None Repaint the current sheet """ tabController = self.get_current_tab_controller() currentTab = tabController.currentWidget() if currentTab: (rCount, cCount) = currentTab.getDimension() for r in xrange(rCount): for c in xrange(cCount): widget = currentTab.getCell(r, c) if widget: widget.repaint() def showBuilderWindowActionTriggered(self): """showBuilderWindowActionTriggered() -> None This will show the builder window """ self.visApp.builderWindow.show() def prepareReviewingMode(self, vCol): """ Trim down most of the spreadsheet window """ self.menuBar().hide() self.statusBar().hide() tabController = self.get_current_tab_controller() tabController.tabBar().hide() tabController.clearTabs() self.setWindowFlags(QtCore.Qt.Tool | QtCore.Qt.WindowStaysOnTopHint) self.setWindowTitle('Pipeline Review') self.resize(560 * vCol, 512) self.show() def startReviewingMode(self): """ startReviewingMode() Reorganize the spreadsheet to contain only cells executed from locator:version """ tabController = self.get_current_tab_controller() currentTab = tabController.currentWidget() if currentTab: currentTab.toolBar.hide() buttonLayout = QtGui.QHBoxLayout() buttons = [ QtGui.QPushButton('&Accept'), QtGui.QPushButton('&Discard') ] buttonLayout.addStretch() buttonLayout.addWidget(buttons[0]) buttonLayout.addWidget(buttons[1]) buttonLayout.addStretch() currentTab.layout().addLayout(buttonLayout) self.connect(buttons[0], QtCore.SIGNAL('clicked()'), self.acceptReview) self.connect(buttons[1], QtCore.SIGNAL('clicked()'), self.discardReview) def discardReview(self): """ Just quit the program """ QtCore.QCoreApplication.quit() def acceptReview(self): """ Copy image of all cells to the clipboard and then exit """ tabController = self.get_current_tab_controller() currentTab = tabController.currentWidget() height = 0 width = 0 pixmaps = [] version = -1 if currentTab: (rCount, cCount) = currentTab.getDimension() for r in xrange(rCount): for c in xrange(cCount): widget = currentTab.getCell(r, c) if widget: version = currentTab.getCellPipelineInfo( r, c)[0]['version'] pix = widget.grabWindowPixmap() pixmaps.append(pix) width += pix.width() height = max(height, pix.height()) finalImage = QtGui.QImage(width, height, QtGui.QImage.Format_ARGB32) painter = QtGui.QPainter(finalImage) x = 0 for pix in pixmaps: painter.drawPixmap(x, 0, pix) x += pix.width() painter.end() filename = tempfile.gettempdir() + '/' + 'vtexport.png' finalImage.save(filename, 'PNG') sm = QtCore.QSharedMemory('VisTrailsPipelineImage') sm.create(32768) sm.attach() sm.lock() pfn = ctypes.c_char_p(filename) ctypes.memmove(int(sm.data()), pfn, len(filename)) pfn = ctypes.c_char_p(str(version)) ctypes.memmove(int(sm.data()) + 256, pfn, len(str(version))) sm.unlock() sm.detach() QtCore.QCoreApplication.quit() def setEchoMode(self, echo): """ setEchoMode(echo: bool) Instruct the spreadsheet to dispatch (echo) all cell widgets instead of managing them on the spreadsheet """ self.echoMode = echo def getEchoCellEvents(self): """ getEchoCellEvents() -> [DisplayCellEvent] Echo back the list of all cell events that have been captured earlier """ return self.echoCellEvents def clearEchoCellEvents(self): """ clearEchoCellEvents() Erase the list of echoed events """ self.echoCellEvents = [] def changeTabController(self, name): self.tabControllerStack.change_selected_view(name) def addTabController(self, name): self.tabControllerStack.add_view(name) def removeTabController(self, name): self.tabControllerStack.remove_view(name) def getTabController(self, name): return self.tabControllerStack.get_tab_controller_by_name(name)