""" CCP4WebBrowser.py: CCP4 GUI Project Copyright (C) 2001-2008 University of York, CCLRC Copyright (C) 2009-2010 University of York Copyright (C) 2011-2014 Science & Technology Facilities Council This library is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License version 3, modified in accordance with the provisions of the license to address the requirements of UK law. You should have received a copy of the modified GNU Lesser General Public License along with this library. If not, copies may be downloaded from http://www.ccp4.ac.uk/ccp4license.php This program 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 Lesser General Public License for more details. """ """ Liz Potterton Jan 2010 - Copied from MGWebBrowser with changes to make stand-alone and to enable Qt plugins and custom mime types Feb 2010 - Make menus/toolbars customisable, add CCP4ProjectManger as placeholder """ ##@package CCP4WebBrowser (QtWebKit) The web browser framework import os import sys import time import glob from PyQt4 import QtWebKit, QtGui, QtCore from qtgui import CCP4WebView from core import CCP4Modules from core.CCP4ErrorHandling import * def setupWebkit(): try: # nice.... not.... also our old friend the try-except-pass (check this is indent'ed ok ) if sys.platform == 'win32': homedir = os.environ.get('USERPROFILE') else: homedir = os.environ.get('HOME') except: pass if homedir and os.path.exists(homedir): webkit_db = os.path.join(homedir,'.qwebkit_idb') if os.path.exists(webkit_db): QtWebKit.QWebSettings.setIconDatabasePath(webkit_db) else: try: os.mkdir(webkit_db) QtWebKit.QWebSettings.setIconDatabasePath(webkit_db) except: # Favicons disabled pass def checkRunningJobs(): runningJobs = CCP4Modules.PROJECTSMANAGER().db().getRunningJobs() topRunningJobs = {} for job in runningJobs: if job[5] is None and len(job[1].split('.')) == 1: projectName=CCP4Modules.PROJECTSMANAGER().db().getProjectInfo(projectId=job[3],mode='projectname') if projectName in topRunningJobs: topRunningJobs[projectName].append(job) else: topRunningJobs[projectName] = [job] return topRunningJobs def exitBrowser(): if "-dbLocal" in sys.argv: topRunningJobs = checkRunningJobs() if len(topRunningJobs) > 0: message = "The following jobs are still running and you are in 'Local database mode'." if bool(CCP4Modules.PREFERENCES().DBLOCAL_QUIT_RUNNING): message += "

If you quit, results from these running jobs may be lost but the job will appear to still be running when you restart CCP4i2.

Do you really want to quit?

" else: message += "

Please wait for these jobs to finish before quitting. Or kill them if you really want to quit now.

" for proj,jobs in topRunningJobs.items(): message += "Project: "+proj+"
" for job in jobs: message += str(job[1]) + " " + job[2] + "
" message += "

" mb = QtGui.QMessageBox(QtGui.QMessageBox.Question,"Jobs still running",message) if bool(CCP4Modules.PREFERENCES().DBLOCAL_QUIT_RUNNING): mb.addButton("Really quit",QtGui.QMessageBox.AcceptRole) mb.addButton("Cancel",QtGui.QMessageBox.RejectRole) rv = mb.exec_() if rv == 1: return else: mb.addButton("Cancel",QtGui.QMessageBox.RejectRole) rv = mb.exec_() return purgeStatusFiles(0) from qtgui import CCP4ProjectViewer #print '*CCP4WebBrowser exitBrowser' CMainWindow.queryClose=False rv = saveStatus() purgeStatusFiles(2) for win in CCP4ProjectViewer.CProjectViewer.Instances: win.Exit() CCP4Modules.PREFERENCES().save() #print 'purgeStatusFiles done' CCP4Modules.QTAPPLICATION().setActiveWindow(CCP4Modules.WEBBROWSER()) CCP4Modules.QTAPPLICATION().closeAllWindows() def saveStatus(): from core import CCP4Utils from qtgui import CCP4I1Projects from core import CCP4File if CMainWindow.STATUS_SAVED: return '' from lxml import etree from qtgui import CCP4ProjectViewer body = etree.Element('body') root = etree.Element('windows') body.append(root) #print 'saveStatus',CBrowserWindow.Instances,CCP4ProjectViewer.CProjectViewer.Instances #import traceback #traceback.print_stack(limit=5) for win in CCP4I1Projects.CI1ProjectViewer.Instances: win.Exit() for win in CBrowserWindow.Instances: winEle = etree.Element('browser') try: size = (win.size().width(),win.size().height()) sizeEle = etree.Element('windowSize') sizeEle.text = str(size[0]) + ',' + str(size[1]) winEle.append(sizeEle) except: pass #print 'CMainWindow.saveStatus browser',win.tab().count() for ii in range(win.tab().count()): tabEle = etree.Element('tab') winEle.append(tabEle) fileEle = etree.Element('filename') try: url = win.tab().widget(ii).url() except: pass else: #filename = os.path.normpath(str(win.tab().widget(ii).fileName)) #print 'CMainWindow.saveStatus',url.isLocalFile() if url.isLocalFile(): filename = url.toLocalFile().__str__().strip('file:') if not os.path.exists(filename) and os.path.splitext(filename)[1] == '.htm': filename = filename + 'l' if os.path.relpath(filename, CCP4Utils.getCCP4I2Dir()).startswith('docs'): fileEle.text = '$CCP4I2/' + os.path.relpath(filename, CCP4Utils.getCCP4I2Dir()) else: fileEle.text = filename else: fileEle.text = url.toString().__str__() #print 'CMainWindow.saveStatus browser tab file',win.tab().widget(ii).fileName tabEle.append(fileEle) title = win.tab().widget(ii).title() if title is not None: titleEle = etree.Element('title') titleEle.text = title tabEle.append(titleEle) root.append(winEle) for win in CCP4ProjectViewer.CProjectViewer.Instances: size = None try: projectName = CCP4Modules.PROJECTSMANAGER().db().getProjectInfo(projectId=win.getProject(), mode='projectname') jobNumber = win.getOpenJobNumber() size = (win.size().width(),win.size().height()) except: pass else: winEle = etree.Element('projectViewer') projectEle = etree.Element('project') #print 'CMainWindow.saveStatus projectName',projectName projectEle.text = projectName winEle.append(projectEle) if jobNumber is not None: jobEle = etree.Element('openJobNumber') jobEle.text = str(jobNumber) winEle.append(jobEle) if size is not None: sizeEle = etree.Element('windowSize') sizeEle.text = str(size[0])+','+str(size[1]) winEle.append(sizeEle) # Issues with handing ByteArray - skip this for now #ele = etree.SubElement(projectEle,'headerState') #ele.text = win.projectWidget().getHeaderState() root.append(winEle) #print 'CCP4WebBrowser.saveStatus',etree.tostring(body,pretty_print=True) statusFile = os.path.join(CCP4Utils.getDotDirectory(), 'status', 'status_' + str(int(time.time())) + '.ccp4i2_status.xml') f= CCP4File.CI2XmlDataFile(statusFile) f.header.function='STATUS' f.header.setCurrent() f.saveFile(bodyEtree=body) CMainWindow.STATUS_SAVED = True print 'CCP4i2 status saved to', statusFile return statusFile def restoreStatus(): from core import CCP4Utils from qtgui import CCP4ProjectViewer from qtcore import CCP4CustomMimeTypes from lxml import etree # For now just try to restore projects statusEtree = retrieveStatus() if statusEtree is None: return nBrowserWindows = 0 for winEle in statusEtree.iterchildren(): #print 'CCP4WebBrowser.restoreStatus', winEle.tag if str(winEle.tag) == 'projectViewer': for projectEle in winEle.iter('project'): projectName=projectEle.text try: projectId = CCP4Modules.PROJECTSMANAGER().db().getProjectId(projectName=projectName) except: projectId = None print 'Unable to open project - ' + projectEle.text + '- not found in database' # 'restoreStatus ',projectEle.text,projectId if projectId is not None: # Do we know the open job? #print 'Opening project:',projectEle.text jobId= None jobEle = winEle.find('openJobNumber') if jobEle is not None: try: jobId = CCP4Modules.PROJECTSMANAGER().db().getJobId(jobNumber=str(jobEle.text), projectName=projectName) except CException as e: #print e.report() jobId = None try: print 'Opening Job:', jobEle.text, jobId proj = CCP4ProjectViewer.CProjectViewer(projectId=projectId, jobId=jobId) try: sizeStr = winEle.find('windowSize').text.split(',') size = (int(sizeStr[0]), int(sizeStr[1])) except: size = CCP4ProjectViewer.DEFAULT_WINDOW_SIZE proj.resize(size[0], size[1]) # Issues with handing ByteArray - skip this for now #headerEle = winEle.find('headerState') #if headerEle is not None: # proj.projectWidget().setHeaderState(str(headerEle.text())) proj.menuBar().show() proj.show() proj.raise_() except: print "Failed to open project", projectId, jobId elif str(winEle.tag) == 'browser': if nBrowserWindows == 0: browser = CCP4Modules.WEBBROWSER() else: browser = CBrowserWindow() browser.show() browser.raise_() nBrowserWindows = nBrowserWindows + 1 for tab in winEle.iterchildren(): if tab.tag == 'windowSize': try: sizeStr = tab.text.split(',') browser.resize(int(sizeStr[0]), int(sizeStr[1])) except: pass elif tab.tag == 'tab': fileName = None title = None for ele in tab.iterchildren(): if ele.tag == 'filename': fileName = str(ele.text) #print 'restoreStatus fileName',fileName if fileName.startswith('$CCP4I2'): fileName = os.path.join(CCP4Utils.getCCP4I2Dir(), fileName[8:]) elif ele.tag == 'title': title = str(ele.text) if fileName is not None: #print 'Opening file:',fileName if fileName.startswith('http'): url = QtCore.QUrl(fileName) browser.loadPage(url) else: browser.openFile(fileName, title=title, internal=True) def applyCommandLine(args): # If there is a file/project on the com line. from core import CCP4Utils from qtgui import CCP4ProjectViewer #print 'CCP4Browser.applyCommandLine',args iArg = 0 while iArg < len(args): filepath = None if args[iArg][0:2] == '-t': top_path = CCP4Utils.getCCP4I2Dir() filepath = os.path.join(top_path, 'test', 'data', 'test_plugin.html') else: projectName = args[iArg] try: projectId = CCP4Modules.PROJECTSMANAGER().db().getProjectId(projectName=projectName) except: projectId = None #print 'CCP4WebBrowser.applyCommandLine projectId', projectId if projectId is None: filepath = os.path.abspath(args[iArg]) #print 'CCP4Browser.applyCommandLine filepath', filepath if os.path.exists(filepath): #print 'Opening file:', filepath CCP4Modules.WEBBROWSER().openFile(filepath, internal=True) else: print args[iArg],'not recognised as project name or file' else: #print 'Opening project:',projectName proj = CCP4ProjectViewer.CProjectViewer(projectId=projectId) proj.resize(CCP4ProjectViewer.DEFAULT_WINDOW_SIZE[0], CCP4ProjectViewer.DEFAULT_WINDOW_SIZE[1]) proj.show() proj.raise_() iArg = iArg + 1 if len(CBrowserWindow.Instances) + len(CCP4ProjectViewer.CProjectViewer.Instances) <= 0: #print 'Opening default browser window' browser = CBrowserWindow() browser.show() def retrieveStatus(): from core import CCP4File from core import CCP4Utils statusFileList = glob.glob(os.path.join(CCP4Utils.getDotDirectory(), 'status', 'status_*.ccp4i2_status.xml')) if len(statusFileList) == 0: return None else: statusFileList.sort() print 'Retrieving status file:' + statusFileList[-1] f = CCP4File.CI2XmlDataFile(statusFileList[-1]) body = f.getBodyEtree() root = body.find('windows') return root def purgeStatusFiles(leave=1): from core import CCP4Utils #print 'purgeStatusFiles leave',leave statusFileList = glob.glob(os.path.join(CCP4Utils.getDotDirectory(), 'status', 'status_*.ccp4i2_status.xml')) #print 'purgeStatusFiles',statusFileList if leave == 0: for sFile in statusFileList: os.remove(sFile) elif len(statusFileList) > leave: for sFile in statusFileList[0:-leave]: os.remove(sFile) #------------------------------------------------------------------- def OPENFILE(fileName=None, cformat=None, title=None, toFront=False): #------------------------------------------------------------------- mimeTypeHandler = CCP4Modules.MIMETYPESHANDLER() if os.path.isdir(fileName): cformat = 'dir' if mimeTypeHandler is None: # No handler so just throw it at web browser and hope if cformat is None: cformat = 'text/html' else: if cformat is None: cformat = mimeTypeHandler.formatFromFileExt(fileName) if not mimeTypeHandler.isSupportedFormat(format): cformat = 'text/html' #print 'CCP4WebBrowser.OPENFILE format',fileName,format if mimeTypeHandler.useDesktopServices(format): abs_fileName = os.path.abspath(fileName) #print 'calling QDesktopServices',abs_fileName url = QtCore.QUrl.fromLocalFile(abs_fileName) rv = QtGui.QDesktopServices.openUrl(url) if not rv: QtGui.QMessageBox.warning(None, 'CCP4i2 display ' + fileName, 'Attempting to display file ' + os.path.split(abs_fileName)[-1] + '\nusing desktop services failed') return None widgetClassList = mimeTypeHandler.getViewers(format) if len(widgetClassList) > 0: widgetClass = widgetClassList[0] if isinstance(widgetClass,str): # This is a keyword for the launcher CCP4Modules.LAUNCHER().openInViewer(viewer=widgetClass, fileName=fileName) return None CCP4Modules.WEBBROWSER().openFile(fileName=fileName, format=format, title=title, toFront=toFront) class CTabWidget(QtGui.QTabWidget): def __init__(self, parent=None, name=None, mini=False): QtGui.QTabWidget.__init__(self, parent) self.setObjectName(name) self.connect(self, QtCore.SIGNAL('currentChanged(int)'), self.handleCurrentChanged) self.currentOpen = -1 #try: # self.setTabsCloseable(True) #except: if mini: self.setCornerWidget(QtGui.QPushButton(self.tr("Expand window"))) else: self.setCornerWidget(QtGui.QPushButton(self.tr("Close tab"))) def deleteTabWidget(self, idx=None, widget=None): if idx is None: for ii in range(self.count()): if self.widget(ii) == widget: idx = ii break if idx is None: return self.widget(idx).handleTabbedClosed() self.widget(idx).close() self.widget(idx).deleteLater() # We are keeping track of currentOpen to be sure to # call handleTabbedClosed() when necessary if self.currentOpen > idx: self.currentOpen = self.currentOpen - 1 elif self.currentOpen == idx: self.currentOpen = -1 self.removeTab(idx) def handleCurrentChanged(self,indx): #print 'CTabWidget.handleCurrentChanged', indx if self.currentOpen >= 0: self.widget(self.currentOpen).handleTabbedClosed() #print 'CTabWidget.handleCurrentChanged',self.currentOpen,self.widget(self.currentOpen) self.currentOpen = indx self.parent().parent().editSplitter.addressEdit.setText(self.widget(indx).title()) self.widget(indx).handleTabbedOpen() self.parent().parent().updateActionEnabled() def closeTabWidget(self,obj): for ii in range(len(self.widget)): if self.widget[ii] == obj: self.deleteTabWidget(ii) class CEditSplitter(QtGui.QSplitter): def __init__(self,parent): QtGui.QSplitter.__init__(self,parent) self.addressEdit = QtGui.QLineEdit() self.searchEdit = QtGui.QLineEdit() searchStyle = """QLineEdit {border: 1px solid gray;border-radius: 6;border-style: inset;padding: 0 3px;}""" self.searchEdit.setStyleSheet(searchStyle) self.addWidget(self.addressEdit) self.addWidget(self.searchEdit) self.setStretchFactor(0, 2) class CMenuBar(QtGui.QMenuBar): def __init__(self, parent): from core.CCP4Bazaar import bzrlib_exists QtGui.QMenuBar. __init__(self, parent) self.menuDefinitions = {} for menuName, menuTitle in [['File', '&File'], ['Edit', '&Edit'], ['Utilities', '&Utilities'], ['Projects', '&Projects'],['Help', 'Help']]: self.addMenu(menuName, menuTitle) self.menuDefinitions['File'] = ['open_browser', 'open', 'sep','close_window', 'quit'] #self.menuDefinitions['Edit'] = ['find','preferences','ccp4i2_config'] #It is a bit cheeky inserting help_about here, but we know that OS X will intercept this and stick in Application Menu. #And the 'Edit' menu does not seem to be redrawn (at present!). I guess a special '_dummy' menu as MG does it would allow #'Edit' to be dynamic in future. if sys.platform == "darwin": self.menuDefinitions['Edit'] = ['find', 'preferences','help_about'] else: self.menuDefinitions['Edit'] = ['find', 'preferences'] self.menuDefinitions['History'] = [] self.menuDefinitions['Utilities'] = ['listProcesses', 'manageImportFiles', ['Program log', 'programPrintLog','programHTTPLog'],'clearStatusFiles', 'editScript', 'sendReport',['System administrator tools','update_core', 'serverSetup','import_task'], ['Developer tools','redo_report','view_report_source','remake_cached_lookups','view_test_report', 'export_task','list_tasks','grab_task','compress_demo_data','auto_task_docs']] self.menuDefinitions['Customisation'] = ['manageWorkflows', 'patchComFile', 'customTask', 'importJob'] self.menuDefinitions['Projects'] = ['manager_projects', 'new_project',['View old CCP4i projects', 'open_i1projects_default', 'open_i1projects_select']] if sys.platform == "darwin": self.menuDefinitions['Help'] = ['help_quickstart', 'help_quickexpert', 'help_youtube', 'task_docs', 'welcome_ccp4i2', 'help_ccp4i2', 'help_ccp4_home', 'help_updates', 'help_license'] else: self.menuDefinitions['Help'] = ['help_about', 'help_quickstart', 'help_quickexpert', 'help_youtube', 'task_docs', 'welcome_ccp4i2', 'help_ccp4i2', 'help_ccp4_home', 'help_updates', 'help_license'] if bzrlib_exists: self.menuDefinitions['Utilities'][6].insert(1, 'update_gui') # Beware need to define the 'quit' in File menu at startup for the slot to exitBrowser() to work # This is likely a mac-specific thing since the quit gets move to application menu from qtgui import CCP4GuiUtils CCP4GuiUtils.populateMenu(self.parent(), self.menuWidget('Edit'), self.menuDefinition('Edit'), default_icon='') CCP4GuiUtils.populateMenu(self.parent(), self.menuWidget('File'), self.menuDefinition('File'), default_icon='') def menuWidget(self,menuName): return self.findChild(QtGui.QMenu, menuName) def updateMenu(self, menuName): from qtgui import CCP4GuiUtils import functools menuWidget = self.menuWidget(menuName) if menuWidget is None: pass elif menuName == 'Projects': recentProjects = CCP4Modules.PROJECTSMANAGER().db().getRecentProjects(order='access', limit=11) menuDefn = ['manage_projects', 'new_project', 'export_project', 'import_project', ['View old CCP4i projects', 'open_i1projects_default', 'open_i1projects_select'], 'sep'] for projectId, projectName, accessTime in recentProjects[:10]: if not self.parent().actionDefinitions.has_key('open_project_' + str(projectId)): self.parent().setActionDefinition('open_project_' + str(projectId), dict(text = projectName, tip = "Open this project", slot = functools.partial(self.parent().openProject, projectId, projectName), enabled = 1, checkable = 1, checked = functools.partial( self.isProjectOpen, projectId))) menuDefn.append('open_project_' + str(projectId)) menuDefn.append('more_projects') # Enable more_projects if >10 projects in db self.parent().actionDefinitions['more_projects']['enabled'] = len(recentProjects) > 10 menuWidget.clear() CCP4GuiUtils.populateMenu(self.parent(), menuWidget, menuDefn, default_icon='') #self._redrawProjectMenu = False elif menuName == 'Edit': pass elif menuName == 'Utilities': menuWidget.clear() menuDefn = [['Copy demo data to project']] if self.parent().isProjectViewer(): testDatasets = CCP4Modules.DEMODATAMANAGER().getTestDatasets() for dataset,label in testDatasets: self.parent().setActionDefinition('download_test_' + dataset, dict(text=label, tip="Copy this data to project directory", slot = functools.partial(CCP4Modules.DEMODATAMANAGER().copyDemoDataToProject, self, self.parent().taskFrame.openJob.projectId, dataset), enabled = self.parent().isProjectViewer)) menuDefn[0].append('download_test_' + dataset) menuDefn[0].append('sep') menuDefn[0].append('demo_data_info') menuDefn[0].append('download_demo_data') menuDefn.extend( self.menuDefinitions['Utilities'] ) CCP4GuiUtils.populateMenu(self.parent(), menuWidget, menuDefn, default_icon='') else: menuWidget.clear() CCP4GuiUtils.populateMenu(self.parent(), menuWidget, self.menuDefinition(menuName), default_icon='') def isProjectOpen(self, projectId): from qtgui import CCP4ProjectViewer for proj in CCP4ProjectViewer.CProjectViewer.Instances: if hasattr(proj,'openJob') and proj.openJob.projectId == projectId: return True return False def addMenu(self, menuName=None, menuTitle=None, updateFunction=None): import functools if menuName is None or menuTitle is None: print 'ERROR in CMenuBar.addMenu; no menu name or no menu title given' return None widget = self.menuWidget(menuName) if widget is None: widget = QtGui.QMenuBar.addMenu(self, menuTitle) widget.setObjectName(menuName) if updateFunction is None: self.connect(widget, QtCore.SIGNAL("aboutToShow()"), functools.partial(self.updateMenu, menuName)) else: self.connect(widget, QtCore.SIGNAL("aboutToShow()"), functools.partial(updateFunction, menuName)) return widget def removeMenu(self, menuName=''): # Save current menus, clear and add all menus again currentMenuList = [] found = False currentMenuWidgets = self.findChildren(QtGui.QMenu) for w in currentMenuWidgets: name = str(w.objectName()) if name == menuName: found = True else: currentMenuList.append([str(w.objectName()), str(w.title())]) if found: self.clear() for menuName, menuTitle in currentMenuList: self.addMenu(menuName, menuTitle) def setMenuTitle(self, menuName='', menuTitle=''): widget = self.menuWidget(menuName) if widget is not None: widget.setTitle(menuTitle) def menuDefinition(self, menuName=''): return self.menuDefinitions.get(menuName,[]) def setMenuDefinition(self, menuName='', definition=[]): self.menuDefinitions[menuName] = definition def appendToMenu(self, menuName='', menuItem=''): # menuItem should be the name of an action or 'sep' (separator) if not self.menuDefinitions.has_key(menuName): print 'ERROR in CMenuBar.appendToMenu: ' + menuName + ' menu does not exist' self.menuDefinitions[menuName].append(menuItem) class CToolBar(QtGui.QToolBar): #FIXME "toPyObject()" should probably be "value()" in PyQt5. #FIXME And all the use of str should go in PyQt5. toolBarPreferencesMapping = { "task_menu" : "SHOW_TASK_MENU_TOOLBUTTON", "job_search" : "SHOW_JOB_SEARCH_TOOLBUTTON", "export_project" : "SHOW_EXPORT_PROJECT_TOOLBUTTON", "run" : "SHOW_RUN_TOOLBUTTON", "run_remote" : "SHOW_RUN_REMOTE_TOOLBUTTON", "clone" : "SHOW_CLONE_TOOLBUTTON", "task_help" : "SHOW_TASK_HELP_TOOLBUTTON", "references" : "SHOW_REFERENCES_TOOLBUTTON", "export_mtz" : "SHOW_EXPORT_MTZ_TOOLBUTTON", "view_coot" : "SHOW_VIEW_COOT_TOOLBUTTON", "view_ccp4mg" : "SHOW_VIEW_CCP4MG_TOOLBUTTON" } def __init__(self,parent,name='',title=''): QtGui.QToolBar.__init__(self, title, parent) self.setObjectName(name) if hasattr(CCP4Modules.PREFERENCES(), "TOOLBARBUTTONSSTYLE"): self.setToolButtonStyle(int(CCP4Modules.PREFERENCES().TOOLBARBUTTONSSTYLE)) self.setIconSize(QtCore.QSize(24, 24)) self.definition = [] def append(self,toolName=''): if not self.definition.count(toolName): self.definition.append(toolName) self.redraw() def extend(self,toolNameList=[]): for toolName in toolNameList: if not self.definition.count(toolName): self.definition.append(toolName) self.redraw() def remove(self,toolName=''): if self.definition.count(toolName): self.definition.remove(toolName) self.redraw() def redraw(self): self.clear() from qtgui import CCP4GuiUtils CCP4GuiUtils.populateToolBar(parent=self.parent(), toolBarWidget=self, definition=self.definition) children = self.findChildren(QtGui.QToolButton) for child in children: if child.defaultAction() is not None: theName = str(child.defaultAction().objectName()) if theName in self.toolBarPreferencesMapping: if CCP4Modules.PREFERENCES().get(self.toolBarPreferencesMapping[theName]) == False: child.defaultAction().setVisible(False) def editPreferences(self): import CCP4ProjectViewer prefWidget = QtGui.QDialog() prefWidget.setWindowTitle("Edit visible tool buttons") children = self.findChildren(QtGui.QToolButton) listWidget = QtGui.QListWidget() layout = QtGui.QVBoxLayout() prefWidget.setLayout(layout) layout.addWidget(listWidget) for child in children: if child.defaultAction() is not None: item = QtGui.QListWidgetItem() item.setText(child.defaultAction().text()) item.setIcon(child.defaultAction().icon()) listWidget.addItem(item) item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable) item.setCheckState(QtCore.Qt.Unchecked) if child.defaultAction().isVisible(): item.setCheckState(QtCore.Qt.Checked) item.setData(QtCore.Qt.UserRole,child) def setItemVisibilities(item): checkState, tb = item.checkState(), item.data(QtCore.Qt.UserRole).toPyObject() theName = tb.defaultAction().objectName() for window in CCP4ProjectViewer.CProjectViewer.Instances: acts = window.findChildren(QtGui.QAction,theName) for act in acts: #Should be length 0 or 1 if checkState: act.setVisible(True) else: act.setVisible(False) mapping = self.toolBarPreferencesMapping[str(theName)] if checkState: val = True else: val = False #FIXME - Aargh. There must be a nicer way. if mapping == "SHOW_TASK_MENU_TOOLBUTTON": CCP4Modules.PREFERENCES().SHOW_TASK_MENU_TOOLBUTTON.set(val) elif mapping == "SHOW_JOB_SEARCH_TOOLBUTTON": CCP4Modules.PREFERENCES().SHOW_JOB_SEARCH_TOOLBUTTON.set(val) elif mapping == "SHOW_EXPORT_PROJECT_TOOLBUTTON": CCP4Modules.PREFERENCES().SHOW_EXPORT_PROJECT_TOOLBUTTON.set(val) elif mapping == "SHOW_RUN_TOOLBUTTON": CCP4Modules.PREFERENCES().SHOW_RUN_TOOLBUTTON.set(val) elif mapping == "SHOW_RUN_REMOTE_TOOLBUTTON": CCP4Modules.PREFERENCES().SHOW_RUN_REMOTE_TOOLBUTTON.set(val) elif mapping == "SHOW_CLONE_TOOLBUTTON": CCP4Modules.PREFERENCES().SHOW_CLONE_TOOLBUTTON.set(val) elif mapping == "SHOW_TASK_HELP_TOOLBUTTON": CCP4Modules.PREFERENCES().SHOW_TASK_HELP_TOOLBUTTON.set(val) elif mapping == "SHOW_REFERENCES_TOOLBUTTON": CCP4Modules.PREFERENCES().SHOW_REFERENCES_TOOLBUTTON.set(val) elif mapping == "SHOW_EXPORT_MTZ_TOOLBUTTON": CCP4Modules.PREFERENCES().SHOW_EXPORT_MTZ_TOOLBUTTON.set(val) elif mapping == "SHOW_VIEW_COOT_TOOLBUTTON": CCP4Modules.PREFERENCES().SHOW_VIEW_COOT_TOOLBUTTON.set(val) elif mapping == "SHOW_VIEW_CCP4MG_TOOLBUTTON": CCP4Modules.PREFERENCES().SHOW_VIEW_CCP4MG_TOOLBUTTON.set(val) listWidget.itemChanged.connect(setItemVisibilities) prefWidget.exec_() def contextMenuEvent(self,e): if self.parent().objectName() != 'projectViewer': return menu = QtGui.QMenu(self) custAct = QtGui.QAction("Customize",self) custAct.triggered.connect(self.editPreferences) menu.addAction(custAct); menu.exec_(e.globalPos()); def isAlive(qobj): import sip try: sip.unwrapinstance(qobj) except RuntimeError: return False return True def mainWindowIcon(): if CMainWindow._MAINWINDOWICON is None: from core import CCP4Utils fileName = os.path.join(CCP4Utils.getCCP4I2Dir(), 'qticons', 'ccp4.png') CMainWindow._MAINWINDOWICON = QtGui.QIcon(QtGui.QPixmap(fileName)) return CMainWindow._MAINWINDOWICON class CMainWindow(QtGui.QMainWindow): projectManagerDialog = None queryClose = False STATUS_SAVED = False _MAINWINDOWICON = None ERROR_CODES = {201 : {'description' : 'Error opening zip file for write'}, 202 : {'description' : 'Error saving directory to zip file'}, 203 : {'description' : 'Error closing zip file from read'}, 204 : {'description' : 'Error opening zip file to read'}, 205 : {'description' : 'Error extracting zip file from directory'}, 206 : {'description' : 'Compressed task file does not contain appropriately named task'}, 207 : {'description' : 'Can not import task as it requires overwriting exisiting task'}, 208 : {'description' : 'Error deleting existing task directory'}, # KJS : Changed below to 209 ..... 209 : {'description' : 'Selected inappropriate directory to save as compressed task file'}} def backupDB(self): CCP4Modules.PROJECTSMANAGER().backupDB() def backupDBXML(self): CCP4Modules.PROJECTSMANAGER().backupDBXML() def __init__(self, parent=None): from qtcore import CCP4UpdateManager QtGui.QMainWindow.__init__(self,parent) self.setAttribute(QtCore.Qt.WA_DeleteOnClose) self.setWindowIcon(mainWindowIcon()) # Remove access to bzr as Andrey claims it causes access to repository that is acting badly possibly due to loading try: from core import CCP4Update self.version = CCP4Update.get_ccp4_str() + ' ' except: self.version = 'DEVELOPMENT CCP4i2' self.preferenceWindow=None self.configWindow=None self.fileDialog = None self.findFrame= None self.um = CCP4UpdateManager.um self.initialiseActionDefinitions() self.setMenuBar(CMenuBar(self)) def closeEvent(self, event): from qtgui import CCP4ProjectViewer from qtgui import CCP4I1Projects if CBrowserWindow.Dummy is None: nOpen = 0 else: nOpen = len(CBrowserWindow.Dummy.findChildren(QtGui.QDialog)) #print 'closeEvent Dummy.findChildren',nOpen nOpen = nOpen + len(CBrowserWindow.Instances) + len(CCP4ProjectViewer.CProjectViewer.Instances) + len(CCP4I1Projects.CI1ProjectViewer.Instances) #print 'closeEvent Instances',nOpen #print 'closingDown',CCP4Modules.QTAPPLICATION().closingDown() if nOpen > 1: self.close() event.accept() else: if CMainWindow.queryClose: rv = QtGui.QMessageBox.question(self,'Close CCP4Browser','Close CCP4 Browser?', QtGui.QMessageBox.Close|QtGui.QMessageBox.Cancel, QtGui.QMessageBox.Cancel) else: rv = QtGui.QMessageBox.Close if rv == QtGui.QMessageBox.Close: self.Exit() saveStatus() purgeStatusFiles(2) event.accept() else: event.ignore() def Exit(self): pass def windowTitle(self): return str(QtGui.QMainWindow.windowTitle(self)) def initialiseActionDefinitions(self): import functools self.actionDefinitions = {} self.actionDefinitions['quit'] = dict(text='Quit CCP4i2', tip='Close all CCP4i2 windows', slot=exitBrowser) self.actionDefinitions['help_about'] = dict(text="About", tip="CCP4i2 background", slot=self.showAbout) self.actionDefinitions['welcome_ccp4i2'] = dict(text="Welcome - options to get started", tip="Options to set up CCP4i2 Project", slot=functools.partial(self.showHelp, 'ccp4i2'), shortcut=self.tr('cmd+P'), icon='ccp4') self.actionDefinitions['help_quickstart'] = dict(text="Quickstart - 10 minute intro", tip="Quick introduction to using i2", slot = functools.partial(self.showHelp, 'quickstart'), shortcut = self.tr('cmd+Q'), icon='ccp4') self.actionDefinitions['help_quickexpert'] = dict(text = "Quick expert - more quick hints", tip = "Part 2 of quick introduction to i2", slot = functools.partial(self.showHelp, 'quickexpert'), icon='ccp4') self.actionDefinitions['help_youtube'] = dict(text = "View YouTube video", tip = "Quick introduction iin youtube (6mins)", slot = functools.partial(self.showHelp, 'youtube'), icon = 'ccp4') self.actionDefinitions['help_ccp4i2'] = dict(text = "CCP4i2 Help", tip = "Documentation and 'where to start'", slot = functools.partial(self.showHelp, 'tutorial'), shortcut = self.tr('cmd+H'), icon='ccp4') self.actionDefinitions['task_docs'] = dict(text = "Task documentation", tip = "Documentation for the individual tasks", slot = functools.partial(self.showHelp, 'task_docs'), icon = 'ccp4') self.actionDefinitions['help_ccp4_home'] = dict(text = "CCP4 Home Page", tip = "For further information on CCP4", slot = functools.partial(self.showHelp, 'ccp4_home'), icon = 'ccp4') self.actionDefinitions['help_updates'] = dict(text = "CCP4 Updates", tip = "", slot = functools.partial(self.showHelp, 'updates')) self.actionDefinitions['help_license'] = dict(text = "CCP4 Licence", tip = "", slot = functools.partial(self.showHelp, 'license'),) self.actionDefinitions['open'] = dict(text = "Open file", tip = "Open html, text, image or log file", slot = self.openFileDialog, icon = 'fileopen', shortcut = QtGui.QKeySequence.Open, enabled = self.isNotProjectViewer) self.actionDefinitions['close_window'] = dict(text = "Close window", tip = "Close this CCP4i2 window", slot = self.close, shortcut = QtGui.QKeySequence.Close) self.actionDefinitions['save'] = dict(text = "Save", tip = "Save to file", slot = self.handleSave, enabled = self.widgetIsSaveable) self.actionDefinitions['print'] = dict(text = "Print", tip = "Print file", slot = self.handlePrint, enabled = self.widgetIsPrintable) #FIXME - What does this do? self.actionDefinitions['run'] = dict(text = "Run", tip = "Run script", slot = self.handleRun, enabled = self.widgetIsRunable) self.actionDefinitions['find'] = dict(text = "Find", tip = "Find in file", slot = self.openFind, icon = 'search', checkable = 1, checked = self.isFindFrameOpen, enabled = self.widgetIsSearchable, shortcut = QtGui.QKeySequence.Find) self.actionDefinitions['preferences'] = dict(text = "Preferences", slot = self.openPreferences, checkable = 1, checked = self.isPreferencesOpen,) self.actionDefinitions['ccp4i2_config'] = dict(text = "Configure CCP4i2", slot = self.openConfig, checkable = 1, checked = self.isConfigOpen,) self.actionDefinitions['close_tab'] = dict(text = "Close tab", tip = "Close the currently displayed file", slot = self.deleteTab, enabled = 1) self.actionDefinitions['open_browser'] = dict(text = "Open browser window", tip = "Open a new web browser window", slot = self.openBrowserWindow, enabled = 1) self.actionDefinitions['open_i1projects_default'] = dict(text = "View default CCP4i projects", tip = "Import and display projects from previous CCP4 interface", slot = self.openI1Projects, enabled = 1) self.actionDefinitions['open_i1projects_select'] = dict(text = "View selected CCP4i projects", tip = "Import and display projects from previous CCP4 interface", slot = functools.partial(self.openI1Projects, 'select'), enabled = 1) self.actionDefinitions['back'] = dict(text = "Back", tip = "Go back one page", slot = self.historyBack, enabled = 1) self.actionDefinitions['forward'] = dict(text = "Forward",tip = "Go forward one page", slot = self.historyForward, enabled = 1) self.actionDefinitions['reload'] = dict(text = "Reload",tip = "Reload current page", slot = self.reloadPage, shortcut = "Ctrl+R", enabled = 1) self.actionDefinitions['listProcesses'] = dict(text = "Running jobs and processes", tip = "Check jobs are still running", slot = self.listProcesses) self.actionDefinitions['manageImportFiles'] = dict(text = "Manage imported files", tip = "Record provenance or remove imported files", slot = self.openManageImportFiles, enabled = self.isProjectViewer) self.actionDefinitions['manageWorkflows'] = dict(text = "Workflows", tip = "Create & manage user defined work flows", slot = self.openWorkflow) self.actionDefinitions['patchComFile'] = dict(text = "Task parameters and patches", tip = "Save/restore task parameters or customise a program command file", slot = self.openPatchComFile) self.actionDefinitions['customTask'] = dict(text = "Custom tasks", tip = "Define a task", slot = self.openCustomTasks) self.actionDefinitions['importJob'] = dict(text = "Import job", tip = "Report job run outside CCP4i2", slot = self.openImportJobs) self.actionDefinitions['programPrintLog'] = dict(text = "Program print log", tip = "Show printed diagnostic for this run of the program", slot = functools.partial(self.openApplication,'programPrintLog'), enabled = 1) self.actionDefinitions['programHTTPLog'] = dict(text = "HTTP server log", tip = "Show log from internal HTTP server", slot = functools.partial(self.openApplication,'programHTTPLog'), enabled = 1) self.actionDefinitions['editScript'] = dict(text = "Edit/run script", tip = "Edit/run Python script within CCP4i2", slot = functools.partial(self.openApplication,'editScript'), enabled = 1) self.actionDefinitions['sendReport'] = dict(text = "Send error report", tip = "Send error report to CCP4", slot = self.openSendReport,enabled = self.isProjectViewer) self.actionDefinitions['update_core'] = dict(text = "Manage CCP4 updates", tip = "Examine, apply or remove CCP4 updates", slot = self.um.manage, enabled = self.um.is_unlocked) self.actionDefinitions['update_gui'] = dict(text = "Update CCP4I2", tip = "Fast track update for CCP4 interface", slot = self.openUpdate, enabled = CCP4Modules.PREFERENCES().guiUpdateEnabled) self.actionDefinitions['import_task'] = dict(text = "Import task code", tip = "Load new task from compressed file", slot = self.openImportTask, enabled = 1) self.actionDefinitions['export_task'] = dict(text = "Export task", tip = "Save task to compressed file", slot = self.openExportTask, enabled = 1) self.actionDefinitions['list_tasks'] = dict(text = "List tasks", tip = "List tasks currently available in CCP4i2", slot = self.listTasks, enabled = 1) self.actionDefinitions['grab_task'] = dict(text = "Grab task widget/report", tip = "Make screenshot of current task widget or report", slot = self.grabWidget, enabled = self.isProjectViewer) self.setActionDefinition('compress_demo_data', dict(text = "Compress demo data", tip = "Create zip file to place on demo data download site", slot = self.makeDemoData, enabled = 1)) self.setActionDefinition('general_project', dict(text = "Create a General project", tip = "Create a project for odds and ends", slot = self.makeGeneralProject, enabled = 1)) self.setActionDefinition('new_project', dict(text = "New project", tip = "Create new CCP4 project", slot = functools.partial(self.handleProjectMenu,'new_project'), enabled = 1)) self.setActionDefinition('more_projects', dict(text = "More projects..",tip = "Show all projects", slot = functools.partial(self.handleProjectMenu,'more_projects'), enabled = 1)) self.setActionDefinition('manage_projects',dict(text = "Manage/open projects", tip = "Review, manage and open CCP4 projects", slot = functools.partial(self.handleProjectMenu, 'manage_projects'), enabled = 1)) self.setActionDefinition('export_project',dict(text = "Export project", tip = "Save project to a compressed file", slot = self.handleProjectMenuExport, enabled = self.isProjectViewer, icon = 'export_arrow_new')) self.setActionDefinition('import_project',dict(text = "Import project", tip = "Load project from a compressed file", slot = functools.partial(self.handleProjectMenu, 'import_project'), enabled = 1, icon = 'import_arrow_new')) self.setActionDefinition('serverSetup',dict(text="Configure servers for 'remote' run jobs", tip = "Specify host and mechanism to run remote jobs", slot = self.openServerSetup, checked = self.isServerSetupOpen)) self.setActionDefinition('redo_report',dict(text="Remake report", tip="Remake the task report", slot=functools.partial(self.handleDeveloperTools, 'redo_report'), enabled=self.reportAvailable)) self.setActionDefinition('view_report_source', dict(text = "View report source", tip = "Display the report in a text viewer", slot = functools.partial(self.handleDeveloperTools, 'view_report_source'), enabled = self.reportAvailable)) self.setActionDefinition('remake_cached_lookups', dict(text = "Remake cached lookups", tip = "Remake lookups, e.g. when a new module or datatype is added", slot = functools.partial(self.handleDeveloperTools, 'remake_cached_lookups'), enabled = self.isProjectViewer)) self.setActionDefinition('view_test_report', dict(text = "Show project test report", tip = "Display the report from re-running the project", slot = functools.partial(self.handleDeveloperTools, 'view_test_report'), enabled = self.testReportAvailable)) self.setActionDefinition('make_test_suite', dict(text="Convert project to test suite", tip="Add unittest template files", slot=functools.partial(self.handleDeveloperTools, 'make_test_suite'), enabled=self.isProjectViewer)) self.setActionDefinition('demo_data_info', dict(text="More info", tip="Description of downloadable demo data", slot=functools.partial(self.showDemoDataInfo))) self.setActionDefinition('download_demo_data', dict(text="Download data", tip="Download data from internet", slot=functools.partial(self.downloadDemoData))) self.setActionDefinition('auto_task_docs', dict(text="Recreate task docs index", tip="Auto generate docs/tasks/index.html", slot=functools.partial(self.handleDeveloperTools, 'auto_task_docs'))) self.setActionDefinition('clearStatusFiles', dict(text = "Clear shutdown/restart status", tip="Remove possibly corrupt status files", slot = functools.partial(purgeStatusFiles,0))) def updateActionEnabled(self): for actionName in ['print', 'run', 'find', 'save']: ifEnabled = self.actionDefinitions[actionName]['enabled']() action = self.findChild(QtGui.QAction,actionName) #print 'updateActionEnabled',actionName,ifEnabled,action if action is not None: action.setEnabled(ifEnabled) def actionDefinition(self, actionName=''): return self.actionDefinitions.get(actionName,{}) def setActionDefinition(self,actionName='',actionDefinition={}): self.actionDefinitions[actionName] = actionDefinition def getActionDef(self,name): return self.actionDefinitions.get(name,dict(text=name)) def openBrowserWindow(self): b = CBrowserWindow() # KJS : Broken ? #print 'openBrowserWindow',b,len(CBrowserWindow.Instances) b.show() #print 'openBrowserWindow raise_' b.raise_() def openI1Projects(self, mode='default'): if mode == 'default': self.openI1Projects1() else: from qtgui import CCP4FileBrowser self.I1FileBrowser = CCP4FileBrowser.CFileDialog(self, title='Open old CCP4 project(s) from directories.def or database.def', filters= ['Old CCP4 directory.def or database.def (*.def)'], defaultSuffix='.def', fileMode=QtGui.QFileDialog.ExistingFile) self.I1FileBrowser.widget.fileDialog.setFilter(QtCore.QDir.AllEntries | QtCore.QDir.Hidden | QtCore.QDir.NoDotAndDotDot) self.connect(self.I1FileBrowser,QtCore.SIGNAL('selectFile'),self.openI1Projects1) self.I1FileBrowser.show() def openI1Projects1(self, fileName=None): from qtgui import CCP4I1Projects from core import CCP4Utils if fileName is None: if sys.platform == "win32": fileName = os.path.normpath(os.path.join(CCP4Utils.getHOME(), 'CCP4', 'windows', 'directories.def')) else: fileName = os.path.normpath(os.path.join(CCP4Utils.getHOME(), '.CCP4', 'unix', 'directories.def')) for pV in CCP4I1Projects.CI1ProjectViewer.Instances: if pV.model().sourceFile == fileName: pV.show() pV.raise_() return pV = CCP4I1Projects.CI1ProjectViewer(fileName=fileName) CCP4I1Projects.CI1ProjectViewer.Instances[-1].show() CCP4I1Projects.CI1ProjectViewer.Instances[-1].raise_() def toolBar(self,name): return self.findChild(QtGui.QToolBar,name) def openProject(self,projectId,projectName=None): #print 'CMainWindow.openProject',projectId,projectName from qtgui import CCP4ProjectViewer for window in CCP4ProjectViewer.CProjectViewer.Instances: #print 'currently open',window,window.taskFrame.openJob.projectId,type(window.taskFrame.openJob.projectId) try: if window.taskFrame.openJob.projectId == projectId: window.show() window.raise_() return except Exception as e: #print 'CMainWindow.openProject error',str(e) pass projectDir = CCP4Modules.PROJECTSMANAGER().db().getProjectInfo(projectId=projectId,mode='projectdirectory') if not os.path.exists(projectDir): QtGui.QMessageBox.warning(self,'','Error in opening project '+str(projectName)+'\nProject directory does not exist:\n'+str(projectDir)) return if not os.path.exists(os.path.join(projectDir,'CCP4_JOBS')): QtGui.QMessageBox.warning(self,'','Error in opening project '+str(projectName)+'\nProject directory does not exist:\n'+os.path.join(projectDir,'CCP4_JOBS')) return p = CCP4ProjectViewer.CProjectViewer(projectId=projectId) p.resize(CCP4ProjectViewer.DEFAULT_WINDOW_SIZE[0],CCP4ProjectViewer.DEFAULT_WINDOW_SIZE[1]) p.show() def openWorkflow(self): from core import CCP4WorkflowManagerGui CCP4WorkflowManagerGui.openWorkflowManagerGui() def openPatchComFile(self): from core import CCP4ComFilePatchManagerGui CCP4ComFilePatchManagerGui.openGui() def openCustomTasks(self): from qtgui import CCP4CustomTaskManagerGui CCP4CustomTaskManagerGui.openGui() def openImportJobs(self): from qtgui import CCP4ImportedJobManagerGui CCP4ImportedJobManagerGui.openGui() def handleProjectMenu(self, mode=''): from qtgui import CCP4ProjectManagerGui #print 'handleprojectMenu',mode if mode == 'new_project': if CCP4ProjectManagerGui.CNewProjectGui.insts is None: CCP4ProjectManagerGui.CNewProjectGui.insts = CCP4ProjectManagerGui.CNewProjectGui() CCP4ProjectManagerGui.CNewProjectGui.insts.clear() CCP4ProjectManagerGui.CNewProjectGui.insts.show() # KJS : PyDev indicating no clear/show. Investigate this. elif mode == 'manage_projects': if CMainWindow.projectManagerDialog is None: CMainWindow.projectManagerDialog = CCP4ProjectManagerGui.CProjectManagerDialog() CMainWindow.projectManagerDialog.setMode('all') CMainWindow.projectManagerDialog.show() CMainWindow.projectManagerDialog.raise_() elif mode == 'more_projects': if CMainWindow.projectManagerDialog is None: CMainWindow.projectManagerDialog = CCP4ProjectManagerGui.CProjectManagerDialog() CMainWindow.projectManagerDialog.setMode('open') CMainWindow.projectManagerDialog.show() CMainWindow.projectManagerDialog.raise_() elif mode == 'import_project': if CMainWindow.projectManagerDialog is None: CMainWindow.projectManagerDialog = CCP4ProjectManagerGui.CProjectManagerDialog() CMainWindow.projectManagerDialog.hide() CMainWindow.projectManagerDialog.handleImportProject() elif mode == 'general_project': self.makeGeneralProject() def makeGeneralProject(self): from core import CCP4Utils name = 'General' status = CCP4Modules.PROJECTSMANAGER().projectStatus(name) if status == 0: QtGui.QMessageBox.information(self,'General project exists','General project already exists - use Project menu to open it') return elif status != 1: # Its in the database but broken in some way.. QtGui.QMessageBox.warning(self,'General project exists','General project exists but may be corrupted - use Manage Projects tool from the Projects menu') return else: directory = os.path.join(CCP4Utils.getHOME(),'CCP4_General_Project') print 'Making General Project in directory:',directory try: projectId = CCP4Modules.PROJECTSMANAGER().createProject(projectName=name,projectPath=directory) except CException as e: e.warningMessage() return except: QtGui.QMessageBox.warning(self, 'Error creating project', 'Unknown error creating project') return else: QtGui.QMessageBox.information(self, 'General project created', 'General project created in directory\n' + directory) self.openProject(projectName='General') def openPreferences(self): if self.preferenceWindow is None: from qtgui import CCP4PreferencesGui self.preferenceWindow = CCP4PreferencesGui.CPreferencesWindow(self) #print 'CMainWindow.openPreferences',self.preferenceWindow self.preferenceWindow.show() self.preferenceWindow.raise_() def isPreferencesOpen(self): if self.preferenceWindow is not None and self.preferenceWindow.isVisible(): return True else: return False def openServerSetup(self): if getattr(self,'serverSetupWindow',None) is None: from qtgui import CCP4JobControlGui self.serverSetupWindow = CCP4JobControlGui.CServerSetupWindow(self) #print 'CMainWindow.openPreferences',self.preferenceWindow self.serverSetupWindow.show() self.serverSetupWindow.raise_() def isServerSetupOpen(self): if getattr(self,'serverSetupWindow',None) is not None and self.serverSetupWindow.isVisible(): return True else: return False def openConfig(self): if self.configWindow is None: from core import CCP4ConfigGui self.configWindow = CCP4ConfigGui.CConfigWindow(self) #print 'CMainWindow.openConfig',self.configWindow self.configWindow.show() self.configWindow.raise_() def isConfigOpen(self): if self.configWindow is not None and self.configWindow.isVisible(): return True else: return False def openFileDialog(self): from qtgui import CCP4FileBrowser filter_list = [] mimeTypeHandler = CCP4Modules.MIMETYPESHANDLER() if self.fileDialog is None: filter_list.append('All files (*.*)') self.fileDialog = CCP4FileBrowser.CFileDialog(self, title='Open file', filters=filter_list, addAll=False) self.connect(self.fileDialog, QtCore.SIGNAL('selectFile'), self.handleOpenFileSelection) self.fileDialog.show() def handleOpenFileSelection(self, fileName=''): #print 'CCP4BrowserWindow.handleOpenFileSelection',fileName if isinstance(self, CBrowserWindow): self.openFile(fileName, internal=True) else: OPENFILE(fileName) def handleDeveloperTools(self,mode): #print 'handleDeveloperTools',mode if mode == 'redo_report': self.redoReport() elif mode == 'view_report_source': try: openJob = self.taskFrame.openJob except: return fileName = CCP4Modules.PROJECTSMANAGER().makeFileName(jobId=openJob.jobId,mode='REPORT') if os.path.exists(fileName): CCP4Modules.WEBBROWSER().openFile(fileName=fileName,format='text/plain') elif mode == 'remake_cached_lookups': try: from core.CCP4Modules import TASKMANAGER, PIXMAPMANAGER from core.CCP4DataManager import DATAMANAGER print "Off to remake CTaskManager cache..." TASKMANAGER().buildLookupFromScratch() print "...Completed" print "Off to remake CDataManager cache..." DATAMANAGER().buildClassLookupFromScratch() print "...Completed" print "Off to remake CPixmapManager cache..." PIXMAPMANAGER().buildCacheFromScratch() print "...Completed" except: print "Failed to remake caches" elif mode == 'view_test_report': testReportList = glob.glob(os.path.join(CCP4Modules.PROJECTSMANAGER().db().getProjectInfo(projectId=self.openJob.projectId,mode='projectdirectory'),'CCP4_test*.log')) if len(testReportList) > 0: CCP4Modules.WEBBROWSER().openFile(fileName=testReportList[0]) return elif mode == 'make_test_suite': from core import CCP4ProjectBasedTesting testBuilder = CCP4ProjectBasedTesting.BuildTestSuite(projectId=self.getProject()) rv = testBuilder.run() if rv.maxSeverity() > SEVERITY_WARNING: rv.warningMessage(parent=self,windowTitle=self.windowTitle(),message='Error converting project to test suite') else: builder = CCP4ProjectBasedTesting.BuildTestSuite(projectId=self.getProject()) try: err = builder.run() except: err.warningMessage() else: projDir = CCP4Modules.PROJECTSMANAGER().db().getProjectDirectory(projectId=self.getProject()) self.testSuiteDialog = QtGui.QDialog(self) self.testSuiteDialog.setWindowTitle('Creating a test suite') self.testSuiteDialog.setLayout(QtGui.QVBoxLayout()) label = QtGui.QLabel("""A directory for test definitions has been created at\n""" + str(projDir)+'/CCP4_TEST_SYSTEM\n' + """You should edit in your tests and then 'Export' this project from 'Manage Projects'\n""" + """You can then run the test with 'testi2sys exported_file_path'""", self) self.testSuiteDialog.layout().addWidget(label) self.testSuiteDialog.show() self.testSuiteDialog.raise_() elif mode == 'auto_task_docs': from core import CCP4TaskManager rv = CCP4TaskManager.CMakeDocsIndex().run() if rv.maxSeverity() > SEVERITY_WARNING: rv.warningMessage(parent=self,windowTitle=self.windowTitle(),message='Error recreating task documentation index page') def listTasks(self): import tempfile from core import CCP4TaskManager from core import CCP4Utils text = CCP4TaskManager.LISTTASKS(ifPrint=False) fileName = tempfile.mktemp(suffix='.txt') CCP4Utils.saveFile(fileName,text) widget = CCP4Modules.WEBBROWSER().openFile(fileName) widget.setFont(style='fixed_width') def openExportTask(self): from core import CCP4Utils import zipfile dirPath = QtGui.QFileDialog.getExistingDirectory(self,'Select pipeline directory to save as task compressed file',os.path.join(CCP4Utils.getCCP4I2Dir(),'pipelines')).__str__() if not os.path.isdir(dirPath): return if not os.path.relpath(dirPath,CCP4Utils.getCCP4I2Dir()).startswith('pipelines'): err = CException(self.__class__,209,dirPath) err.warningMessage(parent=self,windowTitle='Error creating compressed task file',message='Selected directory is not a pipeline in the currently running cccp4i2') return zipPath = dirPath + '.ccp4i2task.zip' if os.path.exists(zipPath): query = QtGui.QMessageBox.question(self,'Overwrite task compressed file?','Overwrite existing'+zipPath+'?',QtGui.QMessageBox.Cancel|QtGui.QMessageBox.Yes) if query == QtGui.QMessageBox.Cancel: return else: os.remove(zipPath) try: zip = zipfile.ZipFile(zipPath, mode='w') except: err = CException(self.__class__, 201, zipPath) err.warningMessage(parent=self,windowTitle='Error creating compressed task file',message='Creating'+str(zipPath)) return try: CCP4Utils.zipDirectory(zip,dirPath,rootRelPath=CCP4Utils.getCCP4I2Dir()) except: err = CException(self.__class__, 202, 'Saving', dirPath, 'to', zipPath) err.warningMessage(parent=self,windowTitle='Error creating compressed task file',message='Saving'+str(dirPath)) return try: zip.close() except: return CErrorReport(self.__class__,203,zipPath) err.warningMessage(parent=self,windowTitle='Error creating compressed task file',message='Closing'+str(zipPath)) return # KJS : Ok, wtf is this ? <^ info = QtGui.QMessageBox.information(self,'Saved compressed task file','Task saved to'+str(zipPath)) def openImportTask(self): import shutil import zipfile from core import CCP4Utils filePath = QtGui.QFileDialog.getOpenFileName(self,'Select compressed file containing task','',"Compressed task (*.ccp4i2task.zip)").__str__() if not os.path.isfile(filePath): return try: zip = zipfile.ZipFile(filePath,mode='r') except: err = CException(self.__class__,204,filePath) err.warningMessage(parent=self,windowTitle='Error reading compressed task file',message='Reading '+str(filePath)) return targetPath = CCP4Utils.getCCP4I2Dir() err= CException() for zinfo in zip.infolist(): if not zinfo.filename.startswith('pipelines'): err.append(self.__class__,206,str(zinfo.filename)) else: if os.path.exists(os.path.join(targetPath,zinfo.filename)): overwrite = QtGui.QMessageBox.question(self,'Overwrite existing task?','Overwrite existing '+str(zinfo.filename)+'?',QtGui.QMessageBox.Cancel|QtGui.QMessageBox.Yes) if overwrite == QtGui.QMessageBox.Cancel: err.append(self.__class__,207,zinfo.filename) break else: try: shutil.rmtree(os.path.join(targetPath,zinfo.filename)) except: err.append(self.__class__,208,os.path.join(targetPath,zinfo.filename)) break try: zip.extract(zinfo,targetPath) except: err.append(self.__class__,205,filePath) zip.close() if len(err) > 0: err.warningMessage(parent=self,windowTitle='Error reading compressed task file',message='Extracting from '+str(filePath)+' to '+str(targetPath)) return info = QtGui.QMessageBox.information(self,'New task installed','New '+ zinfo.filename+ ' task installed - Please restart CCP4i2') def showAbout(self): if not hasattr(self,'aboutDialog'): from core import CCP4Utils self.aboutDialog = QtGui.QDialog(self) self.aboutDialog.setLayout(QtGui.QVBoxLayout()) self.aboutDialog.layout().setContentsMargins(1,1,1,1) #self.aboutDialog.layout().setSpacing(1) self.aboutDialog.setWindowTitle('About CCP4i2') topWidget = QtGui.QWidget() topWidget.setLayout(QtGui.QHBoxLayout()) topWidget.setStyleSheet("QWidget { background-color:white; }") label = QtGui.QLabel(self) fileName = os.path.normpath(os.path.join(CCP4Utils.getCCP4I2Dir(),'qticons','ccp4.png')) label.setPixmap(QtGui.QPixmap(fileName)) topWidget.layout().addWidget(label) topRightWidget = QtGui.QWidget() topRightWidget.setLayout(QtGui.QVBoxLayout()) label = QtGui.QLabel('CCP4i2',self) label.setStyleSheet("QLabel { font-size: 24px; font-weight: bold; }") topRightWidget.layout().addWidget(label) topWidget.layout().addWidget(topRightWidget) self.aboutDialog.layout().addWidget(topWidget) version = CCP4Utils.getProgramVersion('ccp4i2') date = CCP4Utils.getProgramVersion('ccp4i2',mode='date') label = QtGui.QLabel('Version '+version+' built on '+date+"\n"+'User interface to CCP4 Program Suite version '+ CCP4Utils.getProgramVersion('ccp4'),self) label.setStyleSheet("QLabel { font-size: 14px; font-style: italic; font-weight: bold; }") topRightWidget.layout().addWidget(label) label = QtGui.QLabel(self) label.setText('Copyright (C) 2001-2008 University of York, CCLRC\n' + 'Copyright (C) 2009-2010 University of York\n' + 'Copyright (C) 2011-2015 Science & Technology Facilities Council') bottomWidget = QtGui.QWidget() bottomWidget.setLayout(QtGui.QHBoxLayout()) bottomWidget.layout().addWidget(label) self.aboutDialog.layout().addWidget(bottomWidget) self.aboutDialog.show() self.aboutDialog.raise_() def showDemoDataInfo(self): from core import CCP4Utils CCP4Modules.WEBBROWSER().loadWebPage(CCP4Modules.DEMODATAMANAGER().getOverviewPage()) def downloadDemoData(self): CCP4Modules.DEMODATAMANAGER().downloadDemoData(self) def getProject(self): return None def isProjectViewer(self): return (self.getProject() is not None) def isNotProjectViewer(self): return True def reportAvailable(self): return False def testReportAvailable(self): return False def grabWidget(self): # Dummy method reimplemented in CProjectViewer pass def makeDemoData(self): CCP4Modules.DEMODATAMANAGER().makeDemoData(parentWidget=self) def listProcesses(self): CCP4Modules.JOBCONTROLLER().listLocalProcesses() from qtgui import CCP4JobControlGui if getattr(self,'listProcessesWindow',None) is None: self.listProcessesWindow = CCP4JobControlGui.CListProcesses(self) self.listProcessesWindow.load() self.listProcessesWindow.show() self.listProcessesWindow.raise_() class CBrowserWindow(CMainWindow): ERROR_CODES = {100 : {'description' : 'Invalid file name'}} Instances = set() Dummy = None def __init__(self, parent=None, welcome=True): self.stack = None CMainWindow.__init__(self,parent) self.setWindowTitle(self.version) CBrowserWindow.Instances.add(self) self.stack = QtGui.QStackedWidget(self) #print 'CBrowserWindow.__init__ parent',self,parent,CBrowserWindow.Instances self.setCentralWidget(self.stack) self.connect(self,QtCore.SIGNAL("destroyed(QObject*)"),CBrowserWindow.updateInstances) self.factory = None QtWebKit.QWebSettings.globalSettings().setAttribute(QtWebKit.QWebSettings.PluginsEnabled, True) # Create menu and tool bar and add the 'general' actions self.mainToolBar = CToolBar(self,'main','Main toolbar') self.fileToolBar = CToolBar(self,'file','File') self.addToolBar(self.mainToolBar) self.addToolBarBreak() self.addToolBar(self.fileToolBar) if self.mainToolBar is not None: self.mainToolBar.extend(['help_ccp4i2','open','back','forward','reload','find']) self.mini = False self.setTab('nocontext') self.editSplitter = CEditSplitter(self) self.connect(self.editSplitter.addressEdit,QtCore.SIGNAL("returnPressed()"),self.addressEdited) self.connect(self.editSplitter.searchEdit,QtCore.SIGNAL("returnPressed()"),self.searchEdited) self.toolBar('file').addWidget(self.editSplitter) self.setHistoryActionAvailability() self.connect(self.tab(),QtCore.SIGNAL("currentChanged(int)"),self.setTabTitles) sb = self.statusBar() self.searchEngineString = "http://www.google.com/search?q=" self.drawFindTool() self.defaultSizePolicy = [self.sizePolicy().horizontalPolicy(),self.sizePolicy().verticalPolicy()] if welcome: self.loadWebPage(helpFileName='welcome.html',newTab=True) self.resize(800,800) @staticmethod def updateInstances(qobj): CBrowserWindow.Instances = set([window for window in CBrowserWindow.Instances if isAlive(window)]) #print 'webbrowser.updateInstances',CBrowserWindow.Instances def close(self): #Close any widgets in tabs - mostly out of concern for watched files for indx in range(self.tab().count()): self.tab().widget(indx).close() CMainWindow.close(self) def setMini(self,mode=True): self.mini = mode tabs = self.findChildren(CTabWidget) if self.mini: self.mainToolBar.hide() self.fileToolBar.hide() self.resize(500,300) self.layout().setContentsMargins(0,0,0,0) self.layout().setSpacing(0) for tab in tabs: tab.cornerWidget().setText('Expand window') else: self.mainToolBar.show() self.fileToolBar.show() self.resize(800,800) for tab in tabs: tab.cornerWidget().setText('Close tab') def positionOver(self,widget): geom = widget.geometry() globalPos = widget.mapToGlobal(QtCore.QPoint(geom.x(),geom.y())) self.move(globalPos) def downloadTestData(self,**kw): pass def drawFindTool(self): self.findFrame = CFindFrame(self) self.findDock = QtGui.QDockWidget('Find',self) self.findDock.setWidget(self.findFrame) self.findDock.setAllowedAreas(QtCore.Qt.TopDockWidgetArea|QtCore.Qt.BottomDockWidgetArea) self.findDock.setTitleBarWidget(None) self.addDockWidget(QtCore.Qt.BottomDockWidgetArea,self.findDock,QtCore.Qt.Horizontal) self.findDock.close() self.connect(self.findFrame,QtCore.SIGNAL('findNext'),self.handleFindNext) self.connect(self.findFrame,QtCore.SIGNAL('findPrevious'),self.handleFindPrevious) self.connect(self.findFrame,QtCore.SIGNAL('highlightAll'),self.handleFindHighlightAll) def StatusBarMessage(self,message=None): sb = self.statusBar() sb.showMessage(message) def NewWindowRequested(self,view=None): if view: self.tab().addTab(view,view.title()) view.connect(view,QtCore.SIGNAL("CustomMimeTypeRequested"),self.CustomMimeTypeRequested) self.connect(view,QtCore.SIGNAL("NewWindowRequested"),self.NewWindowRequested) self.connect(view,QtCore.SIGNAL("StatusBarMessage"),self.StatusBarMessage) self.connect(view,QtCore.SIGNAL("titleChanged(const QString &)"),self.setTabTitles) self.connect(view,QtCore.SIGNAL("IconReady"),self.IconReady) def setTabTitles(self,title=None): #print 'setTabTitles',title for i in range(self.tab().count()): widget = self.tab().widget(i) if hasattr(widget,"title") and callable(widget.title): self.tab().setTabText(i,widget.title()) self.setWindowTitle(self.version+self.tab().tabText(self.tab().currentIndex())) widget = self.tab().widget(self.tab().currentIndex()) if hasattr(widget,"url") and callable(widget.url): if hasattr(widget.url(),"toString") and callable(widget.url().toString): self.editSplitter.addressEdit.setText(widget.url().toString()) self.setHistoryActionAvailability() def tab(self): # Returns the CTabWidget for the current context (ie project) if self.stack is None: return None return self.stack.currentWidget() def contextTab(self,context): for indx in range(self.stack.count()): if str(self.stack.widget(indx).objectName()) == context: return self.stack.widget(indx) return None def setTab(self,context): tab = self.stack.currentWidget() if tab is not None and str(tab.objectName()) == context: return for indx in range(self.stack.count()): if str(self.stack.widget(indx).objectName()) == context: self.stack.setCurrentIndex(indx) return tab = CTabWidget(self,name=context,mini=self.mini) self.connect(tab.cornerWidget(),QtCore.SIGNAL("clicked(bool)"),self.handleTabCornerWidget) indx = self.stack.addWidget(tab) self.stack.setCurrentIndex(indx) #print 'setTab new',indx,tab,context #------------------------------------------------------------------- def newTab(self, widget=None, title=None, context='nocontext', toolTip=None, icon=None, copen=True): #------------------------------------------------------------------- if title is None: title = widget.title() #print 'CWebBrowser.newTab title',widget,title if icon is not None: idx = self.tab().addTab(widget,icon,title) else: idx = self.tab().addTab(widget,QtCore.QString(title)) if toolTip is not None: self.tab().setTabToolTip(idx,toolTip) #if colour: self.tab().setTabTextColor(QtGui.QColor(colour)) if copen: self.setTabIndex(idx) self.editSplitter.addressEdit.setText(title) self.tab().repaint() return idx def handleTabCornerWidget(self,clickBool = None): if self.mini: self.setMini(False) else: self.deleteTab() #------------------------------------------------------------------- def deleteTab(self, ok=False): #------------------------------------------------------------------- if self.tab().count() > 1: indx = self.tab().currentIndex() self.tab().deleteTabWidget(indx) self.setHistoryActionAvailability() def tabWidgets(self): widgets = [] for idx in range(0,self.tab().count()): widgets.append(self.tab().widget(idx)) return widgets #------------------------------------------------------------------- def setTabIndex(self, index=-1, fileName=''): #------------------------------------------------------------------- if fileName and index < 0: index = self.fileOpenInTab(fileName) if index >= 0 and index <= self.tab().count(): self.tab().setCurrentIndex(index) self.setWindowTitle(self.version+self.tab().widget(index).objectName()) #------------------------------------------------------------------- def fileOpenInTab(self, fileName): #------------------------------------------------------------------- for idx in range(0,self.tab().count()): if str(self.tab().tabText(idx)) == fileName: return idx fileName = os.path.abspath(str(fileName)) for idx in range(0,self.tab().count()): if self.tab().widget(idx).fileName == fileName: return idx return -1 def CustomMimeTypeRequested(self, url=None): #print 'CWebBrowser.CustomMimeTypeRequested',url.path(),url.scheme() if url is not None and url.scheme() == 'file': path = str(url.path()) if os.path.exists(path): self.openFile(path, internal=True) elif os.path.splitext(path)[1] == '.i2com': com = os.path.split(os.path.splitext(path)[0])[1] #print 'CustomMimeTypeRequested i2com',com action = self.findChild(QtGui.QAction,com) if action is not None: action.trigger() elif self.actionDefinitions.has_key(com) and self.actionDefinitions[com].has_key('slot'): #print 'CustomMimeTypeRequested try',self.actionDefinitions[com]['slot'] try: self.actionDefinitions[com]['slot']() except: pass #------------------------------------------------------------------- def openApplication(self, application=None): #------------------------------------------------------------------- from qtgui import CCP4TextViewer from qtgui import CCP4ErrorReportViewer widget = None application = str(application) idx = self.fileOpenInTab(application) #print 'openApplication',application,idx if idx >= 0: self.tab().setCurrentIndex(idx) #self.tab().widget(idx).open(self.tab().widget(idx).filename) return self.tab().widget(idx) if application == 'programPrintLog': widget = CCP4ErrorReportViewer.CPrintLogViewer(self) #print 'CWebBrowser.openApplication',widget widget.openThread(thread='main_thread') title = 'Program print log' elif application == 'programHTTPLog': widget = CCP4ErrorReportViewer.CPrintLogViewer(self) #print 'CWebBrowser.openApplication',widget widget.openThread(thread='HTTPServer') title = 'Program print log' elif application == 'editScript': widget = CCP4TextViewer.CScriptViewer(self) widget.open() title= 'Edit script' if widget is not None: widget.setObjectName(title) self.newTab(widget,title) widget.show() return widget #------------------------------------------------------------------- def openFile(self, fileName=None, format=None, title=None, toFront=False, internal=False): #------------------------------------------------------------------- from core import CCP4Config # Is the file already displayed - force a redraw if fileName is None or fileName=='None': return None fileName = str(fileName) idx = self.fileOpenInTab(fileName) if idx >= 0: if self.tab().widget(idx).isFileModified(): self.tab().widget(idx).reload() self.tab().setCurrentIndex(idx) if toFront: self.raise_() return self.tab().widget(idx) mimeTypeHandler = CCP4Modules.MIMETYPESHANDLER() #print "CCP4WebBrowser.open fileName",fileName,format,mimeTypeHandler,title if not os.path.exists(fileName): QtGui.QMessageBox.warning(self,self.windowTitle(),'File does not exist \n'+fileName) return None if os.path.isdir(fileName): format = 'dir' # If format not recognised try if file extension is recognised if mimeTypeHandler is None and format is None: # No handler so just throw it at web browser and hope format = 'text/html' else: if format is not None and not mimeTypeHandler.isSupportedFormat(format): format = None if format is None: format = mimeTypeHandler.formatFromFileExt(fileName) if format is None: format = 'text/html' #print 'CCP4WebBrowser.openFile format',format # If its a plugin format launch the plugin if ['text/html'].count(format): widget = self.loadWebPage(fileName,newTab=True) elif mimeTypeHandler.useDesktopServices(format): abs_fileName = os.path.abspath(fileName) #print 'calling QDesktopServices',abs_fileName url = QtCore.QUrl.fromLocalFile(abs_fileName) rv = QtGui.QDesktopServices.openUrl(url) if not rv: QtGui.QMessageBox.warning(None,self.windowTitle(),'Attempting to display file '+os.path.split(abs_fileName)[-1]+'\nusing desktop services failed') #.. and close this window if nothing else is displayed if not internal and self.stack.count() == 1: self.close() return None else: widgetClassList = mimeTypeHandler.getViewers(format) widgetClass = widgetClassList[0] if len(widgetClassList) == 0: QtGui.QMessageBox.warning(None,self.windowTitle(),'Sorry no way to display file type: '+format) return None else: #widgetClass = widgetClassList[0] # PhilE hack to display non-MTZ files as text root, ext = os.path.splitext(str(fileName)) if ext != '.mtz': widgetClass = mimeTypeHandler.getViewers("text/plain")[0] if isinstance(widgetClass,str): # This is a keyword for the launcher CCP4Modules.LAUNCHER().openInViewer(viewer=widgetClass,fileName=fileName) return None if CCP4Config.DEVELOPER(): widget = widgetClass(self) else: try: widget = widgetClass(self) except: QtGui.QMessageBox.warning(None,self.windowTitle(),'Error opening display for file type: '+format) return None #print 'CWebBrowser.openFile',widget if CCP4Config.DEVELOPER(): rv = widget.open(fileName=fileName) else: try: rv = widget.open(fileName=fileName) except CException as e: widget.close() e.warningMessage(windowTitle=self.windowTitle()) except: widget.close() QtGui.QMessageBox.warning(None,self.windowTitle(),'Attempting to display file '+os.path.split(fileName)[-1]+'\n as '+format+' failed.\n') return None if title is None: title = widget.title() self.newTab(widget,title) widget.show() #print 'openFile size',widget.height(),widget.width() if toFront: self.raise_() return widget def reloadFile(self,fileName): # Beware this is used as slot by CCP4ProjectManagerGui so arguments are fixed #print 'WEBBROWSER.reloadFile',fileName if fileName is None or fileName=='None': return None fileName = str(fileName) idx = self.fileOpenInTab(fileName) if idx >= 0: if self.tab().widget(idx).isFileModified(): self.tab().widget(idx).reload() self.tab().setCurrentIndex(idx) #if toFront: self.raise_() return self.tab().widget(idx) else: return None def showHelp(self,mode='ccp4i2'): #print 'showHelp',mode from core import CCP4Utils if mode == 'ccp4i2': self.loadWebPage(helpFileName='welcome.html', newTab=True) elif mode == 'quickstart': self.loadWebPage(helpFileName='quickstart/index.html', newTab=True) elif mode == 'quickexpert': self.loadWebPage(helpFileName='quickexpert/index.html', newTab=True) elif mode == 'youtube': rv = QtGui.QDesktopServices.openUrl(QtCore.QUrl('https://www.youtube.com/watch?v=fB7BRVzBURg')) elif mode == 'task_docs': self.loadWebPage(helpFileName=os.path.join(CCP4Utils.getCCP4I2Dir(), 'docs', 'tasks', 'index.html'), newTab=True) elif mode == 'tutorial': self.loadWebPage(helpFileName='tutorial.html', newTab=True) elif mode == 'ccp4_home': url = QtCore.QUrl("http://www.ccp4.ac.uk") self.loadPage(url, newTab=True) elif mode == 'updates': url = QtCore.QUrl("http://www.ccp4.ac.uk/updates") self.loadPage(url, newTab=True) elif mode == 'license': self.loadWebPage(helpFileName='general/license.html', newTab=True) def loadWebPage(self, fileName=None, helpFileName=None, target=None, newTab=0): from core import CCP4Utils #print 'loadWebPage',fileName,helpFileName,target if fileName is not None: if target is None and fileName.count('#'): fileName, target = fileName.split('#', 1) elif helpFileName is not None: if target is None and helpFileName.count('#'): helpFileName, target = helpFileName.split('#', 1) if os.path.splitext(helpFileName)[1] == '': helpFileName = helpFileName + '.html' if os.path.exists(helpFileName): fileName = helpFileName else: docDir = os.path.join(CCP4Utils.getCCP4I2Dir(), 'docs') fileName = os.path.join(docDir, helpFileName) idx = 0 subDirList = ['general', 'developers', 'tasks'] while not os.path.exists(fileName) and idx < len(subDirList): fileName = os.path.join(docDir, subDirList[idx], helpFileName) idx += 1 if idx > len(subDirList): return None if target is not None: if target[0] != '#': target = '#' + target else: target = '' if os.path.exists(fileName): url = QtCore.QUrl.fromLocalFile(os.path.abspath(fileName)) if len(target) > 1: url.setFragment(target[1:]) #url = QtCore.QUrl(fileName+target) elif not fileName[0:4] == 'http': url = QtCore.QUrl("http://" + fileName) else: #url = QtCore.QUrl(file) url = file return self.loadPage(url, newTab=newTab) def loadPage(self, url, newTab=0): #print 'CWebBrowser.loadPage', url.scheme(), url.path().toAscii() target = '' if url.scheme() == 'file': if str(url.path().toAscii()).find('#') > 0: urlpath, target = str(url.path().toAscii()).split('#', 1) url = QtCore.QUrl.fromLocalFile(urlpath) #print 'loadPage file',target if not url.isValid(): err = CException(self.__class__, 100, url.path().toAscii()) err.warningMessage() return #print "CWebBrowser.loadPage trying", url.path(), target if self.tab().count() > 0: widget = self.tab().currentWidget() else: widget= None #print 'CWebBrowser.loadPage', url.isValid(), widget, newTab if not newTab and isinstance(widget, CCP4WebView.CWebView): try: widget.setTarget(target) widget.load(url) #print 'CWebBrowser.loadPage widget.loaded' except: exc_type, exc_value, exc_tb = sys.exc_info()[:3] print exc_type print exc_value import traceback traceback.print_tb(exc_tb) return None return widget else: view = CCP4WebView.CWebView() view.connect(view, QtCore.SIGNAL("CustomMimeTypeRequested"), self.CustomMimeTypeRequested) self.connect(view, QtCore.SIGNAL("NewWindowRequested"), self.NewWindowRequested) self.connect(view, QtCore.SIGNAL("StatusBarMessage"), self.StatusBarMessage) self.connect(view, QtCore.SIGNAL("titleChanged(const QString &)"), self.setTabTitles) self.connect(view, QtCore.SIGNAL("IconReady"), self.IconReady) view.load(url) view.setTarget(target) #self.connect(view, QtCore.SIGNAL("linkClicked(const QUrl &)"), self.handleLinkClick) ''' # This is now done in CWebView if self.factory is None: #Create Qt web plugin factory try: from qtgui import CCP4WebPluginFactory self.factory = CCP4WebPluginFactory.CWebPluginFactory(view) except: print 'CCP4WebBrowser Error creating web plugin factory' if self.factory is not None: view.page().setPluginFactory(self.factory) ''' self.newTab(view, str(view.title())) return view def loadViaHTTP(self, fileName=None, target=None): from core import CCP4Utils relPath = os.path.relpath(fileName, os.path.join(CCP4Utils.getCCP4I2Dir(), 'docs')) #print 'loadViaHTTP',relPath url = QtCore.QUrl('http://127.0.0.1:43434/' + relPath + '#' + target) #print 'loadViaHTTP fragment',url.fragment() self.loadPage(url, True) def handleLinkClick(self, url): #print 'CCP4BrowserWindow.handleLinkClick',url pass def IconReady(self, args=None): icon,view = args for i in range(self.tab().count()): widget = self.tab().widget(i) if widget is view: self.tab().setTabIcon(i,icon) def searchEdited(self): text = self.editSplitter.searchEdit.text().replace(QtCore.QRegExp("\\s+"), QtCore.QString("+")) #print 'QWebBrowser.searchEdited', text self.loadPage(QtCore.QUrl(self.searchEngineString + str(text))) def addressEdited(self): text = str(self.editSplitter.addressEdit.text()) if os.path.exists(text.split('#')[0]): self.openFile(fileName=text, internal=True) else: self.loadPage(QtCore.QUrl(self.editSplitter.addressEdit.text())) def setHistoryActionAvailability(self): widget = self.tab().currentWidget() forwardAction = self.findChild(QtGui.QAction, 'forward') backAction = self.findChild(QtGui.QAction, 'back') if hasattr(widget,"history") and callable(widget.history): history = widget.history() #print 'setHistoryActionAvailability', backAction, history.canGoBack() if forwardAction: if history.canGoForward(): forwardAction.setEnabled(True) else: forwardAction.setEnabled(False) if backAction: if history.canGoBack(): backAction.setEnabled(True) else: backAction.setEnabled(False) else: # No notion of history so set actions disabled if forwardAction: forwardAction.setEnabled(False) if backAction: backAction.setEnabled(False) def historyForward(self): widget = self.tab().currentWidget() if widget and hasattr(widget, "history") and callable(widget.history): history = widget.history() if history.canGoForward(): history.goToItem(history.forwardItem()) self.setHistoryActionAvailability() def historyBack(self): widget = self.tab().currentWidget() if widget and hasattr(widget, "history") and callable(widget.history): history = widget.history() if history.canGoBack(): history.goToItem(history.backItem()) self.setHistoryActionAvailability() def reloadPage(self): widget = self.tab().currentWidget() if widget is None: return if hasattr(widget, "history") and callable(widget.history): #print 'QWebBrowser.reloadPage' widget.history().goToItem(widget.history().currentItem()) #------------------------------------------------------------------- def currentWidget(self): #------------------------------------------------------------------- if self.tab() is None: return None idx = self.tab().currentIndex() if idx < 0: return None return self.tab().widget(idx) #------------------------------------------------------------------- def widgetIsRunable(self): #------------------------------------------------------------------- w = self.currentWidget() if w is not None: return w.isRunable() else: return False #------------------------------------------------------------------- def widgetIsSaveable(self): #------------------------------------------------------------------- w = self.currentWidget() if w is not None: return w.isSaveable() else: return False #------------------------------------------------------------------- def widgetIsPrintable(self): #------------------------------------------------------------------- w = self.currentWidget() if w is not None: return w.isPrintable() else: return False #------------------------------------------------------------------- def widgetIsSearchable(self): #------------------------------------------------------------------- w = self.currentWidget() if w is not None: return w.isSearchable() else: return False #------------------------------------------------------------------- def widgetIsScaleable(self): #------------------------------------------------------------------- w = self.currentWidget() if w is not None: return w.isScaleable() else: return None #------------------------------------------------------------------- def isCurrentWidget(self, mode='text'): #------------------------------------------------------------------- widget = self.currentWidget() if widget is None: return 0 if mode=='text': from qtgui import CCP4TextViewer if isinstance(widget, CCP4TextViewer.CTextViewer): return 1 else: return 0 if mode=='image': from qtgui import CCP4ImageViewer if isinstance(widget, CCP4ImageViewer.CImageViewer): return 1 else: return 0 else: return 0 #------------------------------------------------------------------- def handlePrint(self): #------------------------------------------------------------------- idx = self.tab().currentIndex() if idx < 0: return printer = QtGui.QPrinter() pd = QtGui.QPrintDialog(printer) pdret = pd.exec_() if pdret == QtGui.QDialog.Accepted: painter = QtGui.QPainter() painter.begin(printer) self.tab().widget(idx).Print(painter) painter.end() #------------------------------------------------------------------- def handleSave(self): #------------------------------------------------------------------- from qtgui import CCP4FileBrowser widget = self.currentWidget() if widget is None: return defaultSuffix = '' filter_list = [] ext_list = widget.getFileExt() if ext_list: defaultSuffix = ext_list[0] ext_text = '' for ext in widget.getFileExt(): ext_text = ext_text + '*.' + ext + ' ' if ext_text: filter_list.append(widget.getLabel() + ' (' + ext_text + ')') self.saveWidget = CCP4FileBrowser.CFileDialog(self, title='Save ' + widget.objectName(), filters=filter_list, defaultSuffix=defaultSuffix, fileMode=QtGui.QFileDialog.AnyFile) self.connect(self.saveWidget, QtCore.SIGNAL('selectFile'), self.currentWidget().Save) self.saveWidget.show() def handleRun(self): widget = self.currentWidget() if widget is None: return widget.run() #------------------------------------------------------------------- def openFind(self): #------------------------------------------------------------------- if self.findDock.isVisible(): self.findDock.setVisible(0) else: self.findDock.setVisible(1) #------------------------------------------------------------------- def isFindFrameOpen(self): #------------------------------------------------------------------- if self.findFrame is not None and self.findFrame.isVisible(): return 1 return 0 #------------------------------------------------------------------- def handleFind(self, direction=1): #------------------------------------------------------------------- widget=self.currentWidget() if widget is None or not widget.isSearchable(): return text = self.findFrame.text() #print 'CCP4WebBrowser.handleFind',text,direction rv = widget.findText(subString=text, direction=direction, caseSensitive=self.findFrame.caseSensitive(), wrapAroundDocument=self.findFrame.wrapAroundDocument() ) #------------------------------------------------------------------- def handleFindNext(self): #------------------------------------------------------------------- self.handleFind(1) #------------------------------------------------------------------- def handleFindPrevious(self): #------------------------------------------------------------------- self.handleFind(-1) #------------------------------------------------------------------- def handleFindHighlightAll(self): #------------------------------------------------------------------- widget=self.currentWidget() if widget is None or not widget.isSearchable(): return text = self.findFrame.text() rv = widget.findText(subString=text, highlightAll=1) def setFixedWidth(self, width=0): if width <= 0: self.setMaximumWidth(16777215) self.setMinimumWidth(0) else: self.setMaximumWidth(width + 10) self.setMinimumWidth(width + 10) def moveEvent(self, event): delta = event.pos()-event.oldPos() #print 'CWebBrowser.moveEvent', event.pos().x(), event.pos().y(), event.oldPos().x(), event.oldPos().y(), '*', delta.x(), delta.y() self.emit(QtCore.SIGNAL('windowMoved'), delta) event.ignore() def openSendReport(self): from qtgui import CCP4ErrorReportViewer widget = CCP4ErrorReportViewer.CSendJobError(self, projectId=self.getProject()) widget.show() def openUpdate(self): from qtgui import CCP4UpdateDialog widget = CCP4UpdateDialog.CUpdateDialog(self) widget.show() def handleProjectMenuExport(self): pass def openManageImportFiles(self): pass class CFindFrame(QtGui.QFrame): def __init__(self, parent): QtGui.QFrame.__init__(self, parent) import functools find_layout = QtGui.QHBoxLayout() margin = 2 find_layout.setContentsMargins(margin, margin, margin, margin) find_layout.setSpacing(margin) #widget = QtGui.QPushButton('Close', self) #find_layout.addWidget(widget) #self.connect(widget,QtCore.SIGNAL('clicked(bool)'), self.closeFind) find_layout.addWidget(QtGui.QLabel('Find:')) self.findTextWidget = QtGui.QLineEdit(self) find_layout.addWidget(self.findTextWidget) self.connect(self.findTextWidget,QtCore.SIGNAL('returnPressed()'), functools.partial(self.handleClicked, 'findNext')) self.next = QtGui.QPushButton('Next', self) find_layout.addWidget(self.next) self.connect(self.next,QtCore.SIGNAL('clicked(bool)'), functools.partial(self.handleClicked, 'findNext')) self.previous= QtGui.QPushButton('Previous', self) find_layout.addWidget(self.previous) self.connect(self.previous, QtCore.SIGNAL('clicked(bool)'), functools.partial(self.handleClicked, 'findPrevious')) ''' self.all= QtGui.QPushButton('Highlight all',self) find_layout.addWidget(self.all) self.connect(self.all,QtCore.SIGNAL('clicked(bool)'),functools.partial(self.emit,QtCore.SIGNAL('highlightAll'))) ''' self.findCase = QtGui.QCheckBox('Match case', self) find_layout.addWidget(self.findCase) find_layout.addStretch(5) self.wrap = QtGui.QCheckBox('Wrap', self) find_layout.addWidget(self.wrap) self.wrap.setChecked(1) find_layout.addStretch(5) self.setLayout(find_layout) def handleClicked(self, mode, clickBool=False): #print 'CFindFrame.handleClicked',mode,clickBool self.emit(QtCore.SIGNAL(mode)) def text(self): return str(self.findTextWidget.text()) def caseSensitive(self): return self.findCase.isChecked() def wrapAroundDocument(self): return self.wrap.isChecked()