""" qtgui/statusGui.py: CCP4MG Molecular Graphics Program Copyright (C) 2001-2008 University of York, CCLRC Copyright (C) 2009-2011 University of York Copyright (C) 2012 STFC 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. """ from PyQt4 import QtGui,QtCore from global_definitions import * import mgWidgets,guiUtils import os nameFilters = [ "Status file (*.pkl)", "Editable picture definition file (*.mgpic.py)"] #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- class guiRestore( QtGui.QDialog): #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- def addFilters(self,filters): self.filedialog.addFilters(filters) def addFilter(self,filter): self.filedialog.addFilter(filter) def filters(self): return self.filedialog.filters(filters) def setNameFilters(self,filters): self.filedialog.setNameFilters(filters) def __init__(self,parent=None): super(guiRestore,self).__init__(parent) import mgWidgets #self.setAttribute(QtCore.Qt.WA_MacMetalStyle) self.setObjectName('dialogRestore') self.setWindowTitle(self.tr("Restore status and/or view file(s)")) #self.setModal(True) layout = QtGui.QVBoxLayout() frame = QtGui.QFrame() frame.setFrameStyle(QtGui.QFrame.Box) frame_layout = QtGui.QVBoxLayout() #self.remove = QtGui.QCheckBox('Remove all currently loaded objects',self) #frame_layout.addWidget(self.remove) line_layout = QtGui.QHBoxLayout() line_layout.addWidget(QtGui.QLabel('Restore')) self.restore_status = QtGui.QCheckBox('display status',self) line_layout.addWidget(self.restore_status) self.restore_view = QtGui.QCheckBox('view',self) line_layout.addWidget(self.restore_view) line_layout.addStretch(5) self.preview_widget = QtGui.QLabel() self.preview_widget.setText('PREVIEW') self.preview_widget.setFixedHeight(100) line_layout.addWidget(self.preview_widget) frame_layout.addLayout(line_layout) frame.setLayout(frame_layout) layout.addWidget(frame) self.restore_status.setChecked(1) self.restore_view.setChecked(1) filedialog = mgWidgets.MGFileDialog(self) layout.addWidget(filedialog) self.filedialog = filedialog.getFileDialog() self.filedialog.setFileMode(self.filedialog.ExistingFiles) #self.filedialog.setDirectory(proj_dir) self.connect(self.filedialog,QtCore.SIGNAL("currentChanged(const QString)"),self.updatePreview) self.filedialog.setNameFilters(nameFilters) #self.setSidebar() self.setLayout(layout) self.connect(self.filedialog, QtCore.SIGNAL('filesSelected (const QStringList&)'), self.handleSelection) #------------------------------------------------------------------- def updatePreview(self,filename_=''): #------------------------------------------------------------------- filename = unicode(str(filename_.toUtf8()),'utf-8') if filename.endswith('.pkl') and os.path.exists(filename[:-4]): pixmap = QtGui.QPixmap(filename[:-4]).scaledToHeight(100) self.preview_widget.setText('') self.preview_widget.setPixmap(pixmap) else: self.preview_widget.setText('No preview available') #------------------------------------------------------------------- def getFileName(self): #------------------------------------------------------------------- if len(self.filedialog.selectedFiles()) > 0: if not os.path.isdir(self.filedialog.selectedFiles()[0]): return self.filedialog.selectedFiles()[0] return None #------------------------------------------------------------------- def handleSelection(self,selectedFiles,restore_status=-1): #------------------------------------------------------------------- if restore_status<0: restore_status = int(self.restore_status.isChecked()) for item in selectedFiles: self.status_file = str(item.toUtf8()) if restore_status and os.path.splitext(self.status_file)[1] == '.pkl': rv = HISTORY().get_status_data_files(filename=self.status_file) #print 'from HISTORY().get_status_data_files',rv if rv[0]<0: QtGui.QMessageBox.warning(self,'Error reading status file',rv[1]) elif not rv[0]: # No problems - just load the status file self.loadStatusFile(self.status_file) self.accept() self.close() #Is this necessary? Do we get here? else: self.hide() lostGui = lostFilesGui(self,self.status_file) rv = lostGui.exec_() if rv == QtGui.QDialog.Accepted: objList,fileDefn = lostGui.getFiles() status = HISTORY().edit_status_data_files(self.status_file,1,objList,fileDefn) self.loadStatusFile(status=status) retval = QtGui.QMessageBox.question(self, 'Save status file', 'Save the status with new data file names?\n', QtGui.QMessageBox.Save|QtGui.QMessageBox.Cancel) if retval == QtGui.QMessageBox.Cancel: return saveGui = guiSaveStatus(self) title = 'Save updated status from file: '+os.path.split(self.status_file)[1] saveGui.setWindowTitle(title) saveGui.fileDialog.selectFile(self.status_file) rv = saveGui.exec_() self.accept() self.close() #self.connect(self.lostFiles,QtCore.SIGNAL('apply'),self.applyFoundFiles) #self.connect(self.lostFiles,QtCore.SIGNAL('closed'),self.Close) else: rv = self.loadStatusFile(self.status_file) self.accept() self.close() #------------------------------------------------------------------- def loadStatusFile(self,file='',status={},restore_status=-1,restore_view=-1,remove=-1): #------------------------------------------------------------------- if restore_status<0: restore_status = int(self.restore_status.isChecked()) if restore_view<0: restore_view = int(self.restore_view.isChecked()) self.emit(QtCore.SIGNAL('filesSelected'),file,status,restore_status,restore_view,remove) #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- class guiSaveStatus(QtGui.QDialog): #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- def __init__(self,parent=None,saved_status=None): QtGui.QDialog.__init__(self,parent) self.saved_status = saved_status self.draw() #------------------------------------------------------------------- def draw(self): #------------------------------------------------------------------- self.setWindowTitle(self.tr('Save current status')) layout = QtGui.QGridLayout() file = mgWidgets.MGFileDialog(self) self.fileDialog = file.getFileDialog() self.fileDialog.setFileMode(QtGui.QFileDialog.AnyFile) self.fileDialog.setAcceptMode(QtGui.QFileDialog.AcceptSave) self.fileDialog.setConfirmOverwrite(False) filter_list = [] #formats = QtGui.QImageWriter.supportedImageFormats() # We use ccp4mg's image handling stuff for now. Maybe for ever? self.fileDialog.setNameFilters(nameFilters) self.connect(self.fileDialog, QtCore.SIGNAL('fileSelected(const QString&)'),self.saveFile) """ children = self.fileDialog.findChildren(QtGui.QPushButton,"") for child in children: if child.text() == self.tr("&Save"): self.connect(child, QtCore.SIGNAL('pressed()'),self.saveFile) """ layout.addWidget(file,1,0,1,2) self.setLayout(layout) #------------------------------------------------------------------- def saveFile(self): #------------------------------------------------------------------- file = self.fileDialog.selectedFiles() if not file: return file = str(file[0].toUtf8()) filt = str(self.fileDialog.selectedNameFilter().toUtf8()) filtsQt = self.fileDialog.nameFilters() filts = [] for f in filtsQt: _filt = str(f.toUtf8()) if "(*" in _filt: _filt = _filt[_filt.find("(*")+2:] if ")" in _filt: _filt = _filt[:_filt.rfind(")")] filts.append(_filt) hasSuffix = False for f in filts: if file.endswith(f): hasSuffix = True if not hasSuffix and "(*" in filt: filt = filt[filt.find("(*")+2:] if ")" in filt: filt = filt[:filt.rfind(")")] if not file.endswith(filt): file = file + filt self.emit(QtCore.SIGNAL('filesSelected'),file,self.saved_status) #print 'guiSaveStatus.saveFile accept' self.accept() #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- class lostFilesGui(QtGui.QDialog): #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- def __init__(self,parent=None,status_file = '',lost=[],defn={}): #------------------------------------------------------------------- QtGui.QDialog.__init__(self,parent) hints = [] if status_file: hints.append(os.path.split(status_file)[0]) if lost: objList = lost fileDef = defn else: nLost,objList,fileDef,nFound = HISTORY().get_status_data_files(status_file,hints) self.setWindowTitle('Find data files loading '+os.path.split(status_file)[1]+'status file') layout = QtGui.QGridLayout() layout.addWidget(QtGui.QLabel('Cannot find all data files as specified in status file'),0,0,1,5) layout.addWidget(QtGui.QLabel('Please give alternative files (or continue without missing files)'),1,0,1,5) layout.addWidget(QtGui.QLabel('Saved project/directory alias and filename'),2,0,1,2) layout.addWidget(QtGui.QLabel('File to be loaded'),2,2,1,3) self.widgets = [] row = 2 for objname in objList: if fileDef.has_key(objname): alias,filn,path = fileDef[objname] row = row + 1 self.widgets.append(lostFileWidget(alias,filn,path,layout,row)) self.widgets[-1].setObjectName(objname) self.connect(self.widgets[-1],QtCore.SIGNAL('happy'),self.handleHappyWidget) dialog = QtGui.QDialogButtonBox(self) button = dialog.addButton(QtGui.QDialogButtonBox.Apply) button.setAutoDefault(0) self.connect(button,QtCore.SIGNAL('clicked()'),self.Apply) button.setToolTip('Load the status file with selected data files') button = dialog.addButton(QtGui.QDialogButtonBox.Cancel) button.setAutoDefault(0) #self.connect(button,QtCore.SIGNAL('clicked()'),self.Close) self.connect(button,QtCore.SIGNAL('clicked()'),self,QtCore.SLOT('reject()')) button.setToolTip('Cancel loading status file') ''' button = dialog.addButton('Edit projects and aliases',QtGui.QDialogButtonBox.ActionRole) button.setToolTip('Add a new directory alias or change the existing ones') self.connect(button,QtCore.SIGNAL('clicked()'),self.editAliases) ''' layout.addWidget(dialog,row+1,0,1,5) self.grid = layout self.setLayout(layout) self.connect(CCP4DATABASE(),QtCore.SIGNAL('directoriesChanged'),self.handleChangedAlias) #------------------------------------------------------------------- def Apply(self): #------------------------------------------------------------------- lost = '' for ww in self.widgets: if not os.path.exists(str(ww.path.text())): lost = lost + str(ww.path.text()) +'\n' if lost: retval = QtGui.QMessageBox.question(self, 'Lost data files restoring status', 'The following data files can not be found..\n'+lost+ 'You can continue to load remaining data files', QtGui.QMessageBox.Apply|QtGui.QMessageBox.Cancel) if retval == QtGui.QMessageBox.Cancel: return self.accept() #self.emit(QtCore.SIGNAL('apply')) #------------------------------------------------------------------- def getFiles(self): #------------------------------------------------------------------- objList = [] fileDefn = {} for ww in self.widgets: name = str(ww.objectName()) objList.append(name) fileDefn[name] = ww.getFile() return [objList,fileDefn] #------------------------------------------------------------------- def Close(self): #------------------------------------------------------------------- #print 'lostFilesGui.Close' self.setResult(QtGui.QDialog.Rejected) #self.emit(QtCore.SIGNAL('closed')) self.close() #------------------------------------------------------------------- def handleChangedAlias(self,changed_alias=''): #------------------------------------------------------------------- #print 'handleChangedAlias' for w in self.widgets: w.handleChangedAlias(changed_alias) #------------------------------------------------------------------- def editAliases(self): #------------------------------------------------------------------- import ccp4iGui editAliasGui = ccp4iGui.ccp4iAliasGui(self) editAliasGui.loadAliases() rv = editAliasGui.exec_() #print 'editAliases rv',rv def handleHappyWidget(self,new_path): new_path = os.path.split(new_path)[0] for ww in self.widgets: ww.tryHint(new_path) #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- class lostFileWidget(QtGui.QWidget): #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- HAPPY = 3 NAME = 1 ALIAS = 0 PATH = 2 def __init__(self,alias,filn,path,layout,row): QtGui.QWidget.__init__(self) self.happy = QtGui.QLabel(self) self.happy.setPixmap(guiUtils.loadPixmap('question')) layout.addWidget(self.happy,row,lostFileWidget.HAPPY,1,1) self.filn = QtGui.QLabel(os.path.split(filn)[1],self) self.filn.setToolTip('Name of file') layout.addWidget(self.filn,row,lostFileWidget.NAME,1,1) if alias == 'FULLPATH': alias = ' ' self.alias = QtGui.QLabel(alias,self) self.alias.setToolTip('Project or directory alias') layout.addWidget(self.alias,row,lostFileWidget.ALIAS,1,1) self.path = QtGui.QLineEdit(self) self.path.setToolTip('Current full path name for file') self.path.setMinimumWidth(200) self.connect(self.path,QtCore.SIGNAL('editingFinished()'),self.setHappy) layout.addWidget(self.path,row,lostFileWidget.PATH,1,1) self.setFilename(path) self.browse = QtGui.QPushButton('Browser',self) self.browse.setToolTip('Use browser to find file') self.browse.setAutoDefault(0) self.connect(self.browse,QtCore.SIGNAL('clicked()'),self.openBrowser) layout.addWidget(self.browse,row,4,1,1) #------------------------------------------------------------------- def openBrowser(self): #------------------------------------------------------------------- filn = QtGui.QFileDialog.getOpenFileName(self,self.tr('Find file ')+str(self.filn.text()),"",""); if filn: self.setFilename(str(filn.toAscii())) return #------------------------------------------------------------------- def handleBrowser(self,filn): #------------------------------------------------------------------- #print 'handleBrowser',dirn if filn: self.setFilename(str(filn[0])) self.browser.close() #------------------------------------------------------------------- def setFilename(self,filn): #------------------------------------------------------------------- self.path.setText(filn) self.setHappy() #------------------------------------------------------------------- def setHappy(self): #------------------------------------------------------------------- if os.path.exists(str(self.path.text())): self.happy.setPixmap(guiUtils.loadPixmap('happy')) self.emit(QtCore.SIGNAL('happy'),str(self.path.text())) else: self.happy.setPixmap(guiUtils.loadPixmap('question')) #------------------------------------------------------------------- def getFile(self): #------------------------------------------------------------------- path = str(self.path.text()) # If we have sensible path then update alias and filn to match if os.path.exists(path): alias = CCP4DATABASE().aliasForDir(os.path.split(path)[0]) if not alias: import string alias = string.strip(str(self.alias.text())) filn = os.path.split(path)[1] else: # Still not good path - keep whatever we had alias = str(self.alias.text()) filn = str(self.filn.text()) if not alias: alias = 'FULLPATH' return [ alias, filn, path ] #------------------------------------------------------------------- def handleChangedAlias(self,changed_alias=''): #------------------------------------------------------------------- alias = str(self.alias.text()) path = CCP4DATABASE().get_project_dir(str(self.alias.text())) if path: path = os.path.join(path,str(self.filn.text())) #if os.path.exists(path): self.path.setText(path) self.setHappy() #------------------------------------------------------------------- def tryHint(self,new_path): #------------------------------------------------------------------- if os.path.exists(str(self.path.text())): return test_path = os.path.join(new_path,str(self.filn.text())) if os.path.exists(test_path): self.setFilename(test_path) #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- class recoverGUI(QtGui.QDialog): #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- def __init__(self,parent): #------------------------------------------------------------------- QtGui.QDialog.__init__(self,parent) self.setWindowTitle('Recover status') self.setObjectName('recover') layout = QtGui.QVBoxLayout() layout.addWidget(QtGui.QLabel('Recover program status from')) recover_files = HISTORY().getRecoverFiles() self.menu = QtGui.QComboBox(self) for item in recover_files: self.menu.addItem(item) layout.addWidget(self.menu) buttonBox = QtGui.QDialogButtonBox(self) buttonBox.setOrientation(QtCore.Qt.Horizontal) button = buttonBox.addButton('Recover',QtGui.QDialogButtonBox.ApplyRole) self.connect(button, QtCore.SIGNAL('clicked()'), self.recover) button = buttonBox.addButton('Cancel',QtGui.QDialogButtonBox.RejectRole) self.connect(button, QtCore.SIGNAL('clicked()'), self.close) layout.addWidget(buttonBox) self.setLayout(layout) #------------------------------------------------------------------- def recover(self): #------------------------------------------------------------------- self.close() status_label = str(self.menu.currentText()) DISPLAYTABLE().deleteAllDataObj() ret = HISTORY().recover(status_label) if ret: QtGui.QMessageBox.warning(self,'Error restoring status from '+status_label) else: DISPLAYTABLE().loadAllDataObj() import rebuild rebuild.UpdateDisplay()