""" qtgui/mgWidgets.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. """ import sys import os from PyQt4 import QtGui,QtCore import sip import guiUtils import global_definitions import ColourBrowser import MGSimpleDialog import copy from mgSliders import * import mgapp #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- class mgLineEdit(QtGui.QLineEdit): #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- # This class is just a kludge to intercept the return key press which # in many dialog boxes activates default button def __init__(self,parent=None): QtGui.QLineEdit.__init__(self,parent) def keyPressEvent(self,event=None): #print 'mgLineEdit.keyPressEvent',event,event.key() if event.key() == QtCore.Qt.Key_Return: #print 'mgLineEdit emmit apply' self.emit(QtCore.SIGNAL('apply')) else: QtGui.QLineEdit.keyPressEvent(self,event) #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- class mgCidValidator(QtGui.QValidator): #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- def __init__(self,parent=None,mode='atom'): QtGui.QValidator.__init__(self,parent) self.mode = mode self.useMMDB = 1 self.selHnd = -1 self.MolData_name = '' ''' def __del__(self): print 'mgCidValidator.__del__' if self.useMMDB: dobj.molHnd.DeleteSelection(self.selHnd) QtGui.QValidator.__del__(self) ''' def deleteSelHnd(self): if not self.MolData_name or self.selHnd<0: return dobj = data(self.MolData_name) if dobj: dobj.molHnd.DeleteSelection(self.selHnd) self.MolData_name = '' self.selHnd = -1 def createSelHnd(self): self.MolData_name = self.parent.MolData_name dobj = self.parent().getDataobj() self.selHnd = dobj.molHnd.NewSelection() #---------------------------------------------------------------------- def validate(self,text='',pos=0): #---------------------------------------------------------------------- import string import pygl_coord selindexp = pygl_coord.intp() #print 'mgCidValidator.validate',text,self.parent().getDataobj() text = string.strip(str(text)) if not text: return (QtGui.QValidator.Intermediate,pos) dobj = self.parent().getDataobj() if not dobj: return (QtGui.QValidator.Intermediate,pos) if self.useMMDB: import mmdb2 as mmdb self.selHnd = dobj.molHnd.NewSelection() if self.selHnd<0: self.createSelHnd() if self.mode == 'atom': selAtoms = mmdb.newPPCAtom() dobj.molHnd.Select(self.selHnd,mmdb.STYPE_ATOM,text,mmdb.SKEY_NEW) #nHits = dobj.molHnd.GetSelIndex(self.selHnd,selAtoms) selAtoms = mmut.GetAtomSelIndex(dobj.molHnd,self.selHnd,selindexp) nHits = selindexp.value() elif self.mode == 'residue': selRes = mmdb.newPPCResidue() dobj.molHnd.Select(self.selHnd,mmdb.STYPE_RESIDUE,text,mmdb.SKEY_NEW) #nHits = dobj.molHnd.GetSelIndex(self.selHnd,selRes) selRes = mmut.GetResidueSelIndex(dobj.molHnd,self.selHnd,selindexp) nHits = selindexp.value() dobj.molHnd.DeleteSelection(self.selHnd) if nHits == 1: return (QtGui.QValidator.Acceptable,pos) else: return (QtGui.QValidator.Intermediate,pos) else: splitText = string.split(text,'/') return (QtGui.QValidator.Acceptable,pos) #---------------------------------------------------------------------- def fixup(self,text=''): #---------------------------------------------------------------------- print 'mgCidValidator.fixup',text #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- class mgSelectionCombo(QtGui.QFrame): #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- pendingColour = QtCore.Qt.lightGray regularColour = '' def __init__(self,parent=None,abstractModel=None,modelGroups=['ligands','metal','peptide','nucleic','nucleotide','water','solute','nglycosylation','oglycosylation'],multi=0,selectionWidgets=[],highlightPending=0): super(mgSelectionCombo,self).__init__(parent) if not mgSelectionCombo.regularColour: mgSelectionCombo.regularColour = self.palette().color(QtGui.QPalette.Normal,QtGui.QPalette.Button) self.treeView = None self.dataViewWindow = None self.seleDialog = None self.seleWidget = None self.highlightPending = highlightPending self.lastLineText = '' self.selParams = {} self.seleWidgetMode = '' self.modelGroups = modelGroups self.setFrameStyle(QtGui.QFrame.Panel|QtGui.QFrame.Plain) margin = 0 layout = QtGui.QHBoxLayout() layout.setContentsMargins(margin,margin,margin,margin) layout.setSpacing(0) if multi: self.dataobjCombo = mgDataObjCombo(object_type='MolData',parent=self) layout.addWidget(self.dataobjCombo) else: self.dataobjCombo = None self.lineEdit = mgLineEdit(self) #self.lineEdit = mgLineEdit(self) ht = self.lineEdit.height() self.lineEdit.setMinimumWidth(200) wid = 200 + 2*ht if selectionWidgets: wid = wid + ht self.setMinimumWidth(wid) layout.addWidget(self.lineEdit,5) import guiUtils icon = QtGui.QIcon(guiUtils.loadPixmap('seleTree','disptab')) self.iconButton = QtGui.QToolButton(self) self.iconButton.setPopupMode(QtGui.QToolButton.InstantPopup) self.iconButton.setIcon(icon) self.iconButton.setMaximumSize(QtCore.QSize(ht-2,ht-2)) self.iconButton.setToolTip('Open selection browser') layout.addWidget(self.iconButton) icon = QtGui.QIcon(guiUtils.loadPixmap('gtk-clear','disptab')) self.clearButton = QtGui.QToolButton(self) self.clearButton.setIcon(icon) self.clearButton.setMaximumSize(QtCore.QSize(ht-2,ht-2)) self.clearButton.setToolTip('Clear selection') layout.addWidget(self.clearButton) if selectionWidgets: icon = QtGui.QIcon(guiUtils.loadPixmap('lasso')) self.seleButton = QtGui.QToolButton(self) self.seleButton.setIcon(icon) self.seleButton.setMaximumSize(QtCore.QSize(ht-2,ht-2)) self.seleButton.setToolTip('Open selection widgets') #print 'mgSelectionCombo selectionWidgets',selectionWidgets menu = QtGui.QMenu(self) guiUtils.populateMenu(self,menu,selectionWidgets,default_icon='') self.seleButton.setMenu(menu) self.seleButton.setPopupMode(QtGui.QToolButton.InstantPopup) layout.addWidget(self.seleButton) self.setLayout(layout) if not mgSelectionCombo.regularColour: mgSelectionCombo.regularColour = self.lineEdit.palette().color( QtGui.QPalette.Base) self.abstractModel = None self.setAbstractModel(abstractModel=abstractModel) if multi: self.connect(self.dataobjCombo,QtCore.SIGNAL('currentIndexChanged(int)'), self.setAbstractModel) self.connect (self.clearButton,QtCore.SIGNAL("released()"),self.clear) self.connect(self.iconButton,QtCore.SIGNAL("released()"),self.toggleDataView) self.connect(self.iconButton,QtCore.SIGNAL("pressed()"),self.returnPressed) self.connect(self.lineEdit,QtCore.SIGNAL("apply"),self.returnPressed) if self.highlightPending: self.connect(self.lineEdit,QtCore.SIGNAL("textEdited(const QString)"),self.updateTextHighlight) #---------------------------------------------------------------------- def toggleDataView(self): #---------------------------------------------------------------------- #print "in toggleDataView" geom = self.lineEdit.geometry().bottomLeft() pos = self.mapToGlobal( self.lineEdit.geometry().bottomLeft() ) #print "mgSelectionCombo.toggleDataView",geom.x(),geom.y(),pos.x(),pos.y() xx = pos.x() yy = pos.y() wid = self.lineEdit.width() #print pos,xx,yy,wid if not self.dataViewWindow: self.dataViewWindow = QtGui.QDialog(self,QtCore.Qt.Popup) #self.dataViewWindow = QtGui.QDialog(self) layout = QtGui.QGridLayout() layout.setContentsMargins(0,0,0,0) import mgTreeView self.treeView = mgTreeView.mgTreeView(self,self.abstractModel) self.treeView.setExpandsOnDoubleClick(0) self.treeView.loadGroups(self.modelGroups) layout.addWidget(self.treeView,0,0,1,1) self.dataViewWindow.setLayout(layout) #self.connect(self.treeView,QtCore.SIGNAL('doubleClicked(QModelIndex)'),self.handleDoubleClick) self.dataViewWindow.show() self.dataViewWindow.setGeometry(xx,yy,wid,300) self.updateTreeView() self.connect(self.treeView,QtCore.SIGNAL('changed'),self.updateLineEdit) elif self.dataViewWindow.isHidden(): self.dataViewWindow.show() self.dataViewWindow.setGeometry(xx,yy,wid,300) #self.updateTreeView() else: self.dataViewWindow.hide() #---------------------------------------------------------------------- def returnPressed(self): #---------------------------------------------------------------------- #print "returnPressed" self.updateTreeView() self.lastLineText = self.text() self.updateTextHighlight() self.emit(QtCore.SIGNAL("changed")) #---------------------------------------------------------------------- def updateTextHighlight(self,text=''): #---------------------------------------------------------------------- if not self.highlightPending: return palette = self.lineEdit.palette() #print 'updateTextHighlight',self.lastLineText,'*',self.text(),'*' if self.text() != self.lastLineText: self.lastLineText = self.text() palette.setColor( QtGui.QPalette.Base, mgSelectionCombo.pendingColour ) #print 'updateTextHighlight pending' else: palette.setColor( QtGui.QPalette.Base, mgSelectionCombo.regularColour ) self.lastLineText = self.text() #print 'updateTextHighlight regular' self.lineEdit.setPalette(palette) #---------------------------------------------------------------------- def updateLineEdit(self): #---------------------------------------------------------------------- selected = self.treeView.selectedIndexes() #print "mgSelectionCombo.updateLineEdit selected",selected ret = self.abstractModel.interpretTreeSelection(selected,returnCommand=1) if not ret[0]: self.setText(ret[1]) self.emit(QtCore.SIGNAL("changed")) #---------------------------------------------------------------------- def text(self): #---------------------------------------------------------------------- return str(self.lineEdit.text()) #---------------------------------------------------------------------- def setText(self,text): #---------------------------------------------------------------------- self.lineEdit.setText(text) self.lastLineText = text self.updateTextHighlight() #---------------------------------------------------------------------- def getParams(self): #---------------------------------------------------------------------- if self.seleWidget: self.selParams.update(self.seleWidget.getParams()) return self.selParams #---------------------------------------------------------------------- def setParams(self,params={},**kw): #---------------------------------------------------------------------- params.update(kw) self.selParams.update(params) if self.seleWidget: self.seleWidget.setParams(self.selParams) if self.selParams.has_key('selection'): self.setText(self.selParams['selection']) #---------------------------------------------------------------------- def updateTreeView(self): #---------------------------------------------------------------------- if self.treeView: sele_text = str(self.lineEdit.text()) #Test if this is a named selection (eg all/peptide) rv = self.treeView.setGroupSelection(sele_text) if not rv: return # Make sure command will actually parse molobj = self.getCurrentDataObj() rv = molobj.parse_selection(command=sele_text) #print "mgSelectionCombo.updateTreeView rv",rv # Update tree view if not rv[0]: #self.disconnect(self.treeView,QtCore.SIGNAL('changed'),self.updateLineEdit) self.treeView.blockSignals(True) self.treeView.clearSelection() self.treeView.loadMMDBSelection(rv[1]) molobj.molHnd.DeleteSelection(rv[1]) #self.connect(self.treeView,QtCore.SIGNAL('changed'),self.updateLineEdit) self.treeView.blockSignals(False) #---------------------------------------------------------------------- def clear(self): #---------------------------------------------------------------------- #print "mgSelectionCombo.clear",self.treeView if self.treeView: #self.disconnect(self.treeView,QtCore.SIGNAL('changed'),self.updateLineEdit) self.treeView.blockSignals(True) self.treeView.clearSelection() #print "mgSelectionCombo from treeView.clearSelection" self.setText('') if self.treeView: #self.connect(self.treeView,QtCore.SIGNAL('changed'),self.updateLineEdit) self.treeView.blockSignals(False) self.emit(QtCore.SIGNAL("changed")) #------------------------------------------------------------------------ def setAbstractModel(self,index=-1,abstractModel=''): #------------------------------------------------------------------------ ''' Set the abstract model - beware used as slot and receives index from comboBox ''' if abstractModel: if abstractModel == self.abstractModel: return self.abstractModel = abstractModel elif self.dataobjCombo: dobj = self.dataobjCombo.getCurrentDataObj() if dobj and hasattr(dobj,'treeModel'): if dobj.treeModel == self.abstractModel: return self.abstractModel = dobj.treeModel else: return self.dataViewWindow = None self.setText('') #---------------------------------------------------------------------- def handleDoubleClick(self): #---------------------------------------------------------------------- #print "emit doubleClick" self.emit(QtCore.SIGNAL("doubleClicked()")) self.dataViewWindow.hide() #---------------------------------------------------------------------- def getCurrentDataObj(self): #---------------------------------------------------------------------- if self.dataobjCombo: return self.dataobjCombo.getCurrentDataObj() else: return self.abstractModel.MolDataObj #---------------------------------------------------------------------- def setCurrentDataObj(self,MolData=''): #---------------------------------------------------------------------- if self.dataobjCombo: self.dataobjCombo.setCurrentDataObj(MolData) #---------------------------------------------------------------------- def getActionDef(self,name): #---------------------------------------------------------------------- if name == 'neighb': return dict ( text = 'Neighbourhood..', icon = '', tip = 'Select atoms/residues around central atom(s)', signal = 'triggered()', slot = guiUtils.partial(self.openSelectionWidget,name) ) if name == 'buried': return dict ( text = 'Buried area..', icon = '', tip = 'Select atoms/residues buried by another set of atoms', signal = 'triggered()', slot = guiUtils.partial(self.openSelectionWidget,name) ) if name == 'secStr': return dict ( text = 'Secondary structure..', icon = '', tip = 'Select secondary structure elements', signal = 'triggered()', slot = guiUtils.partial(self.openSelectionWidget,name) ) if name == 'resType': return dict ( text = 'Residue types..', icon = '', tip = 'Select residue types', signal = 'triggered()', slot = guiUtils.partial(self.openSelectionWidget,name) ) if name == 'chains': return dict ( text = 'Chains..', icon = '', tip = 'Select whole chains', signal = 'triggered()', slot = guiUtils.partial(self.openSelectionWidget,name) ) if name == 'property': return dict ( text = 'Property..', icon = '', tip = 'Select by the value of atom property', signal = 'triggered()', slot = guiUtils.partial(self.openSelectionWidget,name) ) if name == 'namedSelection': return dict ( text = 'Save/restore selection..', icon = '', tip = 'Save or restore a selection', signal = 'triggered()', slot = guiUtils.partial(self.openSelectionWidget,name) ) return {} #---------------------------------------------------------------------- def openSelectionWidget(self,name): #---------------------------------------------------------------------- import selectionBrowser if self.seleWidget: if self.seleWidgetMode == name: self.seleDialog.show() self.seleDialog.raise_() return else: self.selParams.update(self.seleWidget.getParams()) self.seleWidget.close() #self.seleWidget.deleteLater() self.seleWidget=None self.seleWidgetMode = '' if self.seleDialog: #self.seleDialog.deleteLater() self.seleDialog.close() self.seleDialog = QtGui.QDialog(self) layout = QtGui.QVBoxLayout() layout.setContentsMargins(0,0,0,0) layout.setSpacing(0) if name == 'neighb': self.seleDialog.setWindowTitle('Select neighbourhood for '+self.getCurrentDataObj().name_label) self.seleWidget = selectionBrowser.neighbGui(self.seleDialog,self.getCurrentDataObj().name_label ) self.seleWidget.setParams() self.connect(self.seleWidget,QtCore.SIGNAL('accepted()'),guiUtils.partial(self.updateFromTabWidget,'neighb')) if name == 'buried': self.seleDialog.setWindowTitle('Select buried area for '+self.getCurrentDataObj().name_label) self.seleWidget = selectionBrowser.buriedGui(self.seleDialog,self.getCurrentDataObj().name_label ) self.seleWidget.setParams() self.connect(self.seleWidget,QtCore.SIGNAL('accepted()'),guiUtils.partial(self.updateFromTabWidget,'buried')) elif name == 'namedSelection': self.seleDialog.setWindowTitle('Save/restore selection for '+self.getCurrentDataObj().name_label) self.seleWidget = selectionBrowser.namedSelectionGui(self.seleDialog,self.getCurrentDataObj().name_label,delete=0 ) self.connect(self.seleWidget,QtCore.SIGNAL('save'),self.saveNamedSelection) self.connect(self.seleWidget,QtCore.SIGNAL('restore'),self.restoreNamedSelection) elif name == 'secStr': self.seleDialog.setWindowTitle('Select secondary structure for '+self.getCurrentDataObj().name_label) self.seleWidget = selectionBrowser.secStrGui(self.seleDialog,self.getCurrentDataObj().name_label ) self.seleWidget.setGeometry(0,0,selectionBrowser.tabWidth,selectionBrowser.tabHeight) self.seleDialog.setFixedHeight(selectionBrowser.tabHeight+20) self.seleDialog.setFixedWidth(selectionBrowser.tabWidth+20) self.connect(self.seleWidget,QtCore.SIGNAL('accepted()'),guiUtils.partial(self.updateFromTabWidget,'secStr')) elif name == 'property': self.seleDialog.setWindowTitle('Select by property for '+self.getCurrentDataObj().name_label) self.seleWidget = selectionBrowser.propertyGui(self.seleDialog,self.getCurrentDataObj().name_label ) self.connect(self.seleWidget,QtCore.SIGNAL('accepted()'),guiUtils.partial(self.updateFromTabWidget,'property')) elif name == 'resType': self.seleDialog.setWindowTitle('Select by residue type for '+self.getCurrentDataObj().name_label) self.seleWidget = selectionBrowser.resTypeGui(self.seleDialog,self.getCurrentDataObj().name_label ) self.seleWidget.setGeometry(0,0,selectionBrowser.tabWidth,selectionBrowser.tabHeight) self.seleDialog.setFixedHeight(selectionBrowser.tabHeight+20) self.seleDialog.setFixedWidth(selectionBrowser.tabWidth+20) self.connect(self.seleWidget,QtCore.SIGNAL('accepted()'),guiUtils.partial(self.updateFromTabWidget,'resType')) elif name == 'chains': self.seleDialog.setWindowTitle('Select chains for '+self.getCurrentDataObj().name_label) self.seleWidget = selectionBrowser.chainsGui(self.seleDialog,self.getCurrentDataObj().name_label ) self.seleWidget.setGeometry(0,0,selectionBrowser.tabWidth,selectionBrowser.tabHeight) self.seleDialog.setFixedHeight(selectionBrowser.tabHeight+20) self.seleDialog.setFixedWidth(selectionBrowser.tabWidth+20) self.connect(self.seleWidget,QtCore.SIGNAL('accepted()'),guiUtils.partial(self.updateFromTabWidget,'chains')) #print "openSelectionWidget name",name if name != 'namedSelection' and self.seleWidget: self.seleWidget.setParams(self.selParams) layout.addWidget(self.seleWidget) self.seleDialog.setLayout(layout) self.seleWidget.show() self.seleDialog.show() self.seleWidgetMode = name #--------------------------------------------------------------------------- def restoreNamedSelection(self): #--------------------------------------------------------------------------- set,name = self.seleWidget.getSelection() if name: import model_selection SelHandle = model_selection.SelHandle(self.getCurrentDataObj().name) SelHandle.restoreSelection(name) #print "restoreNamedSelection command",SelHandle.getCommand() self.setText(SelHandle.getCommand()) del SelHandle self.updateTreeView() self.emit(QtCore.SIGNAL("changed")) #--------------------------------------------------------------------------- def saveNamedSelection(self): #--------------------------------------------------------------------------- pars = self.seleWidget.getSaveParams() name = pars.get('name','') if name: save_mode = pars.get('save_mode','this') import model_selection SelHandle = model_selection.SelHandle(self.getCurrentDataObj().name) #print "saveNamedSelection command",self.text() SelHandle.setCommand(self.text()) SelHandle.saveSelection (name=name,save_mode=save_mode,overwrite=1) del SelHandle DISPLAYTABLE().getDataObj(self.getCurrentDataObj().name).handleSavedSelection(save_mode) #self.seleWidget.populateList() #---------------------------------------------------------------------- def updateFromTabWidget(self,mode=''): #---------------------------------------------------------------------- # Update browser based on input to one of the tab widgets # First get the widget to return its selection in the # form of a SelHandle widgetSelHandle = self.seleWidget.getSelHandle() if not widgetSelHandle: return #print "updateFromTabWidget command",widgetSelHandle.getCommand() self.setText(widgetSelHandle.getCommand()) del widgetSelHandle self.updateTreeView() self.emit(QtCore.SIGNAL("changed")) if self.seleDialog: self.seleDialog.close() return 0 #---------------------------------------------------------------------- def close(self): #---------------------------------------------------------------------- if self.seleDialog: self.seleDialog.close() #self.seleDilog.deleteLater() self.seleDialog = None QtGui.QFrame.close(self) #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- #class mgDataObjCombo(QtGui.QComboBox,dataobj.Dependency): class mgDataObjCombo(QtGui.QComboBox): #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- def __init__(self,object_type='',default='',null='',parent=None): # default should be a name_label for the model super(mgDataObjCombo,self).__init__(parent) # Maintain list of data objects that are excluded self.exclude_list = [] self.null = null #dataobj.Dependency.__init__(self) self.object_type = object_type self.setEditable(0) self.populateMenu(default=default) #import model #if object_type == 'MolData': # self.add_dependency(model.MolData,['create'],[self.populateMenu]) self.connect(global_definitions.DISPLAYTABLE(),QtCore.SIGNAL('addDataObj'),self.resetMenu) self.connect(global_definitions.DISPLAYTABLE(),QtCore.SIGNAL('deleteDataObj'),self.resetMenu) self.connect(global_definitions.DISPLAYTABLE(),QtCore.SIGNAL('loadAllDataObj'),self.resetMenu) self.connect(global_definitions.DISPLAYTABLE(),QtCore.SIGNAL('update'),self.resetMenu) self.connect(global_definitions.DISPLAYTABLE(),QtCore.SIGNAL('update_labels'),self.resetMenu) #---------------------------------------------------------------------- def disconnectGlobalSignals(self): #---------------------------------------------------------------------- self.disconnect(global_definitions.DISPLAYTABLE(),QtCore.SIGNAL('addDataObj'),self.resetMenu) self.disconnect(global_definitions.DISPLAYTABLE(),QtCore.SIGNAL('deleteDataObj'),self.resetMenu) self.disconnect(global_definitions.DISPLAYTABLE(),QtCore.SIGNAL('loadAllDataObj'),self.resetMenu) self.disconnect(global_definitions.DISPLAYTABLE(),QtCore.SIGNAL('update'),self.resetMenu) self.disconnect(global_definitions.DISPLAYTABLE(),QtCore.SIGNAL('update_labels'),self.resetMenu) #---------------------------------------------------------------------- def resetMenu(self): #---------------------------------------------------------------------- #print 'mgDataObjCombo.resetMenu' self.blockSignals(1) current = self.getCurrentDataObj() if current: default = current.name else: default = '' self.emit(QtCore.SIGNAL('currentDataObjDeleted()')) self.populateMenu(default = default) self.blockSignals(0) #---------------------------------------------------------------------- def populateMenu(self,default='',attributes=[],**keywords): #---------------------------------------------------------------------- #print "mgDataObjCombo populateMenu",default self.clear() if self.null: self.addItem(self.null,QtCore.QVariant(self.null)) obj_list = global_definitions.get_dataobj(object_type = self.object_type) #print "mgDataObjCombo.populateMenu obj_list",obj_list if obj_list: for obj in obj_list: if not self.exclude_list.count(obj.name): self.addItem(obj.name_label,QtCore.QVariant(obj.name)) elif self.null: # make sure ther is a 'blank' option in case user deletes all objects self.addItem(self.null,QtCore.QVariant(self.null)) # Set up dependencies #self.add_dependency(obj,['delete','rename'],[self.populateMenu]) default_index = 0 if default: default_obj = global_definitions.get_dataobj(name=default) if default_obj and len(default_obj)>0 and obj_list.count(default_obj[0]): default_index = obj_list.index(default_obj[0]) if self.null: default_index = default_index + 1 self.setCurrentIndex(default_index) elif len(obj_list) == 1 and self.null: default_index = 1 self.setCurrentIndex(default_index) #print "currentIndex",self.currentIndex() ## **********delete the dependencies!!! #---------------------------------------------------------------------- def setCurrentDataObj(self,name): #---------------------------------------------------------------------- for n in range(0,self.count()): if str(self.itemData(n).toString())==name: self.setCurrentIndex(n) break #---------------------------------------------------------------------- def getCurrentDataObj(self): #---------------------------------------------------------------------- if self.currentIndex()<0: return None else: # * beware the text is the DataObj.name_label which is not necessarilly # unique - check the userData for the DataObj.name name = str(self.itemData(self.currentIndex()).toString()) obj_list = global_definitions.get_dataobj(name = name) #print 'getCurrentDataObj',name,obj_list if obj_list: return obj_list[0] else: return None def setExcludeDataObjList(self,excluded=[]): self.exclude_list = excluded self.resetMenu() def getExcludeDataObjList(self): return self.exclude_list #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- class MGOpenFileDialog(QtGui.QDialog): #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- def __init__(self,parent=None,title='Open file',filters=[],defaultSuffix='',defaultFileName=''): QtGui.QDialog.__init__(self,parent) self.setWindowTitle(self.tr(title)) layout = QtGui.QGridLayout() filed = MGFileDialog(self) self.fileDialog = filed.getFileDialog() self.fileDialog.setNameFilters(filters) selectedFilter = str(self.fileDialog.selectedNameFilter().toAscii()) needDefaultSuffix = False if selectedFilter.find('(')>-1 and selectedFilter.find(')')>selectedFilter.find('('): splitFilters = selectedFilter[selectedFilter.find('(')+1:selectedFilter.find(')')].strip().split(' ') if (len(splitFilters) == 1 and splitFilters[0]=='*.*') or (len(splitFilters) > 0 and splitFilters[0]=='*.*') or len(splitFilters) > 1: needDefaultSuffix = True if defaultSuffix and ((len(self.fileDialog.filters())==1 and str((self.fileDialog.filters()[0]).toAscii()).find(self.tr('All Files'))>-1)) or (len(self.fileDialog.filters()))==0: self.fileDialog.setDefaultSuffix(defaultSuffix) if defaultFileName: self.fileDialog.selectFile(defaultFileName) self.connect(self.fileDialog, QtCore.SIGNAL('rejected()'),self.close) children = self.fileDialog.findChildren(QtGui.QPushButton,"") for child in children: if child.text() == self.tr("&Open"): self.connect(child, QtCore.SIGNAL('pressed()'),self.openFile) layout.addWidget(filed) self.setLayout(layout) def openFile(self): files = self.fileDialog.selectedFiles() if files: self.emit(QtCore.SIGNAL('open'),str(files[0].toUtf8())) self.close() def getFilename(self): files = self.fileDialog.selectedFiles() if files: return str(files[0].toUtf8()) else: return '' #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- class MGSaveFileDialog(QtGui.QDialog): #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- def exec_(self): QtGui.QDialog.exec_(self) def __init__(self,parent=None,title='Save to file',filters=[],defaultSuffix='',defaultFileName=''): QtGui.QDialog.__init__(self,parent) self.setWindowTitle(self.tr(title)) layout = QtGui.QGridLayout() filed = MGFileDialog(self) self.fileDialog = filed.getFileDialog() self.fileDialog.setFileMode(QtGui.QFileDialog.AnyFile) self.fileDialog.setAcceptMode(QtGui.QFileDialog.AcceptSave) self.fileDialog.setConfirmOverwrite(False) self.fileDialog.setNameFilters(filters) selectedFilter = str(self.fileDialog.selectedNameFilter().toAscii()) needDefaultSuffix = False if selectedFilter.find('(')>-1 and selectedFilter.find(')')>selectedFilter.find('('): splitFilters = selectedFilter[selectedFilter.find('(')+1:selectedFilter.find(')')].strip().split(' ') if (len(splitFilters) == 1 and splitFilters[0]=='*.*') or (len(splitFilters) > 0 and splitFilters[0]=='*.*') or len(splitFilters) > 1: needDefaultSuffix = True if defaultSuffix and (((len(self.fileDialog.filters())==1 and str((self.fileDialog.filters()[0]).toAscii()).find(self.tr('All Files'))>-1)) or (len(self.fileDialog.filters()))==0 or needDefaultSuffix): self.fileDialog.setDefaultSuffix(defaultSuffix) if defaultFileName: self.fileDialog.selectFile(defaultFileName) self.connect(self.fileDialog, QtCore.SIGNAL('rejected()'),self.close) children = self.fileDialog.findChildren(QtGui.QPushButton,"") for child in children: if child.text() == self.tr("&Save"): self.connect(child, QtCore.SIGNAL('pressed()'),self.save) layout.addWidget(filed) self.setLayout(layout) self.connect(self.fileDialog, QtCore.SIGNAL('filesSelected(const QStringList&)'),self.saveSelected) self.defaultSuffix = defaultSuffix def setDefaultFileName(self,defaultFileName): self.fileDialog.selectFile(defaultFileName) def saveSelected(self,files=None): if files: self.emit(QtCore.SIGNAL('save'),str(files[0].toUtf8())) self.close() def save(self): files = self.fileDialog.selectedFiles() theFile = str(files[0].toUtf8()) if files: if files[0].count('.') == 0: selectedFilter = str(self.fileDialog.selectedNameFilter().toAscii()) if selectedFilter.find('(')>-1 and selectedFilter.find(')')>selectedFilter.find('('): splitFilters = selectedFilter[selectedFilter.find('(')+1:selectedFilter.find(')')].strip().split(' ') if (len(splitFilters) == 1 and splitFilters[0]=='*.*') or (len(splitFilters) > 0 and splitFilters[0]=='*.*') or len(splitFilters) > 1: useSuffix = self.defaultSuffix useSuffix = useSuffix[useSuffix.find('.'):] theFile = theFile + useSuffix elif len(splitFilters) == 1: useSuffix = splitFilters[0] useSuffix = useSuffix[useSuffix.find('.'):] theFile = theFile + useSuffix self.emit(QtCore.SIGNAL('save'),theFile) self.close() def getFilename(self): files = self.fileDialog.selectedFiles() if files: return str(files[0].toUtf8()) else: return '' #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- class MGFileDialog(QtGui.QWidget): #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- last_directory = '' def event(self,event=None): if event.type()==QtCore.QEvent.WhatsThisClicked: import global_definitions global_definitions. HELPBROWSER().loadMgHelp(file=str(event.href())) return QtGui.QWidget.event(self,event) def __init__(self,parent=None,editAlias=0): QtGui.QWidget.__init__(self,parent) self.setWhatsThis(self.tr("A file dialog for opening data files supported by ccp4mg with a wizard to select drawing styles of molecular structure more help")) layout = QtGui.QVBoxLayout() ccp4_dirs,ccp4_aliases = global_definitions.CCP4DATABASE().getProjectsList() if len(ccp4_dirs)>0 or len(ccp4_aliases)>0: layout0 = QtGui.QHBoxLayout() self.ccp4i_combo = QtGui.QComboBox() self.load_ccp4i_combo() ccp4i_label1 = QtGui.QLabel() ccp4i_label1.setText("Look in ccp4 project or aliased directory:") if editAlias: ccp4i_button = QtGui.QPushButton('Edit aliases',self) ccp4i_label2 = QtGui.QLabel(" or ...") layout0.addWidget(ccp4i_label1) layout0.addWidget(self.ccp4i_combo) if editAlias: layout0.addWidget(ccp4i_button) layout0.addWidget(ccp4i_label2) layout0.addStretch() layout.addLayout(layout0) self.connect(self.ccp4i_combo,QtCore.SIGNAL("activated(const QString&)"),self.ccp4iDirectoryChanged) if editAlias: self.connect(ccp4i_button,QtCore.SIGNAL("clicked()"),self.editAlias) self.connect(global_definitions.CCP4DATABASE(),QtCore.SIGNAL('directoriesChanged'),self.load_ccp4i_combo) self.filedialog = MGFileDialog0(parent) self.filedialog.setObjectName('fileDialog') layout.addWidget( self.filedialog) if len(ccp4_dirs)>0: self.connect( self.filedialog, QtCore.SIGNAL('directoryEntered(QString)'),self.update_ccp4i_combo) self.setLayout(layout) # Set keyboard focus to text input widget self.filedialog.findChildren(QtGui.QLineEdit)[0].setFocus(QtCore.Qt.ActiveWindowFocusReason) if MGFileDialog.last_directory: #print "setting last_directory",MGFileDialog.last_directory self.filedialog.setDirectory(MGFileDialog.last_directory) if len(ccp4_dirs)>0 or len(ccp4_aliases)>0: self.update_ccp4i_combo(self.filedialog.directory().path()) def load_ccp4i_combo(self): self.ccp4i_combo.clear() self.ccp4i_combo.addItem(' -Projects- ') ccp4_dirs,ccp4_aliases = global_definitions.CCP4DATABASE().getProjectsList() print ccp4_dirs,ccp4_aliases for project in ccp4_dirs: #self.ccp4i_combo.addItem(project) self.ccp4i_combo.addItem(unicode(project,'utf-8')) self.ccp4i_combo.addItem(' -Aliases- ') for project in ccp4_aliases: self.ccp4i_combo.addItem(project) def ccp4iDirectoryChanged(self,alias): path = global_definitions.CCP4DATABASE().get_project_dir(str(alias.toUtf8())) if path: self.filedialog.setDirectory(unicode(path,'utf-8')) MGFileDialog.last_directory = path def getFileDialog(self): return self.filedialog def setSidebar(self): url_list = self.filedialog.sidebarUrls () #print "in setSidebar",url_list for item in url_list: #print "side bar",item.path(),item.port(),'*',item.host() pass #self.filedialog.setSidebarUrls(side) #for path in ['/work/stuart']: # url = QtCore.QUrl("file://"+path) # url_list.append(url) self.filedialog.setSidebarUrls(url_list ) def update_ccp4i_combo(self,directory): MGFileDialog.last_directory = directory proj = global_definitions.CCP4DATABASE().aliasForDir(str(directory.toUtf8())) if proj: indx = self.ccp4i_combo.findText(unicode(proj,'utf-8')) if indx>=0: self.ccp4i_combo.setCurrentIndex(indx) return self.ccp4i_combo.setCurrentIndex(0) def editAlias(self): import ccp4iGui ccp4iGui.ccp4iAliasGui(self) def setLabelText(self,mode,text): self.filedialog.setLabelText(mode,text) def selectFile(self,file): #print 'MGFileDialog.selectFile',file self.filedialog.selectFile(file) class IconProvider(QtGui.QFileIconProvider): def __init__(self): QtGui.QFileIconProvider.__init__(self) self._filters = {} self._icon_cache = {} def setIconForFilter(self,icon,filter): self._filters[icon] = filter def setIconsForFilters(self,filters): self._filters = filters def icon(self,info): if info and hasattr(info,'filePath'): for k in self._filters: for f in self._filters[k]: if repr(info.filePath()).endswith(f): if not self._icon_cache.has_key(k): self._icon_cache[k] = QtGui.QIcon(k) return self._icon_cache[k] return QtGui.QFileIconProvider.icon(self,info) class ProxyModel(QtGui.QSortFilterProxyModel): def __init__(self,parent=None): QtGui.QSortFilterProxyModel.__init__(self,parent) def filterAcceptsRow(self, sourceRow, sourceParent): if sourceParent.row() == -1 or sourceParent.column(): return True index0 = self.sourceModel().index(sourceRow, 0, sourceParent); if self.sourceModel().isDir(index0): return True for f in self.sourceModel().nameFilters(): if str(self.sourceModel().fileName(index0).toUpper()).endswith(str(f).lstrip('*').upper()): return True return False #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- class MGFileDialog0(QtGui.QFileDialog): #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- # Reimplement to stop widget closing immediately a file is selected def addFilters(self,filters_in): filters = self.filters() for filter in filters_in: filters.append(filter) self.setNameFilters(filters) def addFilter(self,filter): filters = self.filters() filters.append(filter) self.setNameFilters(filters) def setNameFilters(self,filters,all=1): import types self.suffix_lookup = {} all_filters = "All files (" new_filters = [] for filt in filters: #print "setNameFilters filt",filt if isinstance(filt,types.ListType): self.suffix_lookup[filt[0]] = filt[1] filter = str(filt[0]) else: filter = str(filt) if len(filter)>11 and filter[:11] == 'All files (' and (filter).rfind(')') > 0: pass else: new_filters.append(filter) left_par = filter.rfind('(') right_par = filter.rfind(')') if left_par > -1 and right_par > 0 and right_par > left_par: if (filter[left_par+1:right_par]).find('*')>-1: all_filters = all_filters + " " + filter[left_par+1:right_par] else: all_filters = all_filters + " " + filter else: all_filters = all_filters + " " + filter all_filters = all_filters + " )" total_filters = new_filters # Put all_filters at end of list when saving file and # at beginning when reading file if all: if self.acceptMode() == QtGui.QFileDialog.AcceptSave: total_filters.append(all_filters) else: total_filters.insert(0,all_filters) QtGui.QFileDialog.setNameFilters(self,total_filters) if self.suffix_lookup: self.setSuffix(filters[0][0]) self.connect(self,QtCore.SIGNAL('filterSelected(QString)'),self.setSuffix) def checkMounts(self,**args): try: import subprocess import signal signal.siginterrupt(signal.SIGCHLD,False) except: pass mounts = [] try: syscmd = "/sbin/mount" p = subprocess.Popen([syscmd],stdout=subprocess.PIPE) output = p.communicate()[0].split('\n') except: return for o in output: if o and o.find('/dev/disk')==0: t = o[o.find(' ')+1:] t2 = t[t.find(' ')+1:] mounts.append(t2[:t2.find('(')-1]) if mounts != self._old_mounts: #print "CHANGE!!", mounts urls = self.sidebarUrls() newUrls = [] _urls = [] for url in urls: if url.host() == "" and url.port() == -1: path = str(url.toLocalFile().toAscii()) if path == '': path = '/' if path.find('/Volumes') == 0: if path in mounts: newUrls.append(url) _urls.append(path) else: newUrls.append(url) _urls.append(path) for m in mounts: if m != '/': if not m in _urls: newUrls.append(QtCore.QUrl.fromLocalFile(m)) _urls.append(path) self.setSidebarUrls(newUrls) self._old_mounts = mounts def checkMountsNew(self,**args): fd = self sb = fd.sidebarUrls() for url in sb[:]: path = str(url.toLocalFile().toAscii()) if path.find('/Volumes') == 0: if not os.path.exists(path): sb.remove(url) # Clear everything fd.setSidebarUrls([]) for loc in [QtGui.QDesktopServices.HomeLocation,QtGui.QDesktopServices.DesktopLocation,QtGui.QDesktopServices.DocumentsLocation]: path = QtGui.QDesktopServices.storageLocation(loc) url = QtCore.QUrl.fromLocalFile(path) if not url in sb: sb.append(url) # The following will hopefully be replaced by QStorageInfo in Qt5. if sys.platform == "darwin": for v in os.listdir('/Volumes'): url = QtCore.QUrl.fromLocalFile(os.path.join("/Volumes/",v)) if not url in sb: sb.append(url) """ # This would probably be good on windows roots = QtCore.QDir.drives() for r in roots: print r.filePath() """ # Add "My Computer" computer = QtCore.QUrl.fromLocalFile('') if not computer in sb: sb.insert(0,computer) fd.setSidebarUrls(sb) def __init__(self,parent=None): QtGui.QFileDialog.__init__(self,parent) self.setSizeGripEnabled(0) """ if sys.platform == "darwin": # We will need to implement the low level stuff for other oses. self.fstimer = QtCore.QTimer(); self.connect(self.fstimer, QtCore.SIGNAL("timeout()"), self.checkMounts); self.fstimer.start(2000); self._old_mounts = [] self.checkMounts() """ self.checkMountsNew() #self.show() """ pm = ProxyModel() self.setProxyModel(pm) iconProvider = IconProvider() iconProvider.setIconsForFilters({ os.path.join(os.environ["CCP4MG"],'qticons','dispobj','MolData.png'):['.pdb','.pdb.gz','.ent','.ent.gz','.brk','.brk.gz'], os.path.join(os.environ["CCP4MG"],'qticons','dispobj','MapData.png'):['.map','mtz'], os.path.join(os.environ["CCP4MG"],'qticons','dispobj','VectorsData.svg'):['.vector'] }) self.setIconProvider(iconProvider) """ def close(self): pass def done(self,mode): pass def reject(self): #print "MGFileDialog reject",self.parent(),self.window() if self.window(): self.window().close() else: self.close() def setSuffix(self,filter): filter = str(filter) #print "setSuffix",filter if self.suffix_lookup.has_key(filter): self.setDefaultSuffix(self.suffix_lookup[filter]) def selectFile(self,file): #print 'MGFileDialog0.selectFile',file #QFileDialog.selectFile does not work for selecting non-existing files # as you would want in Save mode - so try this kludge if self.fileMode() == QtGui.QFileDialog.ExistingFile: widget = self.findChild(QtGui.QLineEdit,'fileNameEdit') #print 'MGFileDialog0.selectFile widget',widget if widget: widget.setText(file) else: QtGui.QFileDialog.selectFile(self,file) #----------------------------------------------------------------------- #----------------------------------------------------------------------- #----------------------------------------------------------------------- class mgGroupSelector(QtGui.QWidget): #----------------------------------------------------------------------- #----------------------------------------------------------------------- #----------------------------------------------------------------------- def __init__(self,parent=None,groups=[],items=[],reMatch=0,closeButton=0, height=200,width=400): super(mgGroupSelector,self).__init__(parent) self.groupOrder = [] self.groupSelection = {} self.itemOrder = [] self.itemText = {} self.reMatch = reMatch self.closeButton = closeButton self.widgetHeight = height self.widgetWidth = width self.addItems(items) self.addGroups(groups) self.draw() #----------------------------------------------------------------------- def addItems(self,items=[]): #----------------------------------------------------------------------- import types for it in items: if len(it) >= 2 and isinstance(it[0],types.StringType) and isinstance(it[1],types.StringType): self.itemOrder.append(it[0]) self.itemText[it[0]] = it[1] #print "addItems",self.itemOrder #----------------------------------------------------------------------- def addGroups(self,groups=[]): #----------------------------------------------------------------------- import types for gp in groups: if len(gp) >= 2 and isinstance(gp[0],types.StringType) and isinstance(gp[1],types.ListType): self.groupOrder.append(gp[0]) self.groupSelection[gp[0]] = gp[1] elif len(gp) == 1: self.groupOrder.append(gp[0]) #----------------------------------------------------------------------- def select(self,group='',state=1): #----------------------------------------------------------------------- #print "select group",group,self.itemOrder if group: if group == 'all': for item in self.itemOrder: but = self.itemList.findChild(QtGui.QCheckBox,item) if but: but.setChecked(1) elif group == 'clear': for item in self.itemOrder: but = self.itemList.findChild(QtGui.QCheckBox,item) if but: but.setChecked(0) elif self.groupSelection.has_key(group): if self.reMatch: for item in self.groupSelection[group]: #print "searching for",item but_list = self.itemList.findChildren(QtGui.QCheckBox,item) #print "but_list",but_list for but in but_list: but.setChecked(state) else: for item in self.groupSelection[group]: but = self.itemList.findChild(QtGui.QCheckBox,item) if but: but.setChecked(state) #----------------------------------------------------------------------- def draw(self): #----------------------------------------------------------------------- # Scrolled list of items with checkboxes on left side self.listArea = QtGui.QScrollArea(self) margin = 0 layout0 = QtGui.QHBoxLayout() self.listArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) #self.listArea.setFixedHeight(self.widgetHeight) #self.listArea.setMinimumWidth(self.widgetWidth-220) self.itemList = QtGui.QWidget() layout = QtGui.QVBoxLayout() layout.setContentsMargins(margin,margin,margin,margin) layout.setSpacing(margin) for item in self.itemOrder: cb = QtGui.QCheckBox(self.itemText[item].strip(),self) cb.setObjectName(item) layout.addWidget(cb) self.itemList.setLayout(layout) self.listArea.setWidget(self.itemList) layout0.addWidget(self.listArea) if self.groupOrder: self.custom_box = QtGui.QWidget() layout = QtGui.QVBoxLayout() layout.setContentsMargins(margin,margin,margin,margin) layout.setSpacing(margin) layout.addStretch(5) for gp in self.groupOrder: w = QtGui.QPushButton(gp,self) w.setObjectName(gp) layout.addWidget(w) self.connect(w,QtCore.SIGNAL('released()'),guiUtils.partial(self.select,gp)) self.custom_box.setLayout(layout) layout0.addWidget(self.custom_box) rbox = QtGui.QWidget() layout = QtGui.QVBoxLayout() layout.setContentsMargins(margin,margin,margin,margin) layout.setSpacing(margin) clear = QtGui.QPushButton('Clear',self) clear.setContentsMargins(margin,margin,margin,margin) layout.addWidget(clear) self.connect(clear,QtCore.SIGNAL('released()'),guiUtils.partial(self.select,'clear')) all = QtGui.QPushButton('Select all',self) all.setContentsMargins(margin,margin,margin,margin) layout.addWidget(all) self.connect(all,QtCore.SIGNAL('released()'),guiUtils.partial(self.select,'all')) layout.addStretch(5) apply = QtGui.QPushButton('Apply',self) layout.addWidget(apply) self.connect(apply,QtCore.SIGNAL('released()'),self.apply) if self.closeButton: close = QtGui.QPushButton('Close',self) layout.addWidget(close) self.connect(apply,QtCore.SIGNAL('released()'),self.close) rbox.setLayout(layout) layout0.addSpacing(5) layout0.addWidget(rbox) self.setLayout(layout0) #----------------------------------------------------------------------- def apply(self): #----------------------------------------------------------------------- self.emit(QtCore.SIGNAL("accepted()")) #----------------------------------------------------------------------- def getSelection(self): #----------------------------------------------------------------------- sele_list = [] for item in self.itemOrder: but = self.itemList.findChild(QtGui.QCheckBox,item) if but and but.isChecked(): sele_list.append(item) return sele_list #----------------------------------------------------------------------- def setSelection(self,selectedList=[]): #----------------------------------------------------------------------- # Input a list of selected items # Also set items not in that list to unchecked for item in self.itemOrder: but = self.itemList.findChild(QtGui.QCheckBox,item) if but: but.setChecked(selectedList.count(item)) #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- class extendingFrame(QtGui.QWidget): #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- LINE_HEIGHT = 32 #------------------------------------------------------------------- def __init__(self,parent=None,widget='',nLines=1,ifApply=1, ifEditable=1,ifClose=0,ifClear=0,ifSave=0,height=200,width=400): #------------------------------------------------------------------- QtGui.QWidget.__init__(self,parent) margin = 0 self.widgetClass = widget self.lineHeight = extendingFrame.LINE_HEIGHT self.ifClear = ifClear self.ifEditable = ifEditable self.ifAddLine = ifEditable self.ifSave = ifSave self.widgetHeight = height if width: self.widgetWidth = width else: tmp_widget = self.widgetClass(self.parent()) tmp_widget.setAttribute(QtCore.Qt.WA_DeleteOnClose) tmp_widget.show() self.widgetWidth = tmp_widget.width() + extendingFrame.LINE_HEIGHT + 5 #print 'extendingFrame widgetWidth',self.widgetWidth tmp_widget.close() # Buttons buttonLayout = QtGui.QHBoxLayout() buttonLayout.addStretch() if ifApply: apply_button = QtGui.QPushButton('Apply') apply_button.setObjectName('applyButton') apply_button.setFocusPolicy(QtCore.Qt.ClickFocus) apply_button.setAutoDefault(0) buttonLayout.addWidget(apply_button) self.connect(apply_button,QtCore.SIGNAL('released()'),guiUtils.partial(self.emit,QtCore.SIGNAL('accepted()'))) if ifSave: save_button = QtGui.QPushButton('Save') save_button.setObjectName('saveButton') save_button.setAutoDefault(0) buttonLayout.addWidget(save_button) self.connect(save_button,QtCore.SIGNAL('released()'),guiUtils.partial(self.emit,QtCore.SIGNAL('save'))) if self.ifClear: clear_button = QtGui.QPushButton('Clear') clear_button.setObjectName('clearButton') clear_button.setAutoDefault(0) clear_button.setFocusPolicy(QtCore.Qt.ClickFocus) buttonLayout.addWidget(clear_button) if self.ifAddLine: add_button = QtGui.QPushButton('Add line') add_button.setObjectName('addButton') add_button.setAutoDefault(0) add_button.setFocusPolicy(QtCore.Qt.ClickFocus) buttonLayout.addWidget(add_button) if ifClose: close_button = QtGui.QPushButton('Close') close_button.setObjectName('closeButton') close_button.setAutoDefault(0) buttonLayout.addWidget(close_button) self.connect(close_button,QtCore.SIGNAL('released()'),guiUtils.partial(self.emit,QtCore.SIGNAL('close()'))) # Body in which sub-widgets will be drawn self.scroll_frame = QtGui.QFrame(self) #if self.widgetHeight>0: self.scroll_frame.setFixedHeight(self.widgetHeight-40) scroll_layout = QtGui.QGridLayout() scroll_layout.setSpacing(0) scroll_layout.setContentsMargins(0,0,0,0) scroll = QtGui.QScrollArea(self) scroll.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) #scroll.setFixedWidth(self.widgetWidth+scroll.verticalScrollBar().height()) #if self.widgetHeight>0: scroll.setFixedHeight(self.widgetHeight-40-2*margin) scroll_layout.addWidget(scroll,0,0,1,1) self.scroll_frame.setLayout(scroll_layout) self.body = QtGui.QWidget(self) self.body.setFixedWidth(self.widgetWidth-10) body_layout = QtGui.QVBoxLayout() body_layout.setSpacing(0) body_layout.setContentsMargins(0,0,0,0) self.body.setLayout(body_layout) scroll.setWidget(self.body) v_layout = QtGui.QVBoxLayout() v_layout.setSpacing(margin) v_layout.setContentsMargins(margin,margin,margin,margin) v_layout.addWidget(self.scroll_frame) v_layout.addLayout(buttonLayout) self.setLayout(v_layout) if self.ifAddLine: self.connect(add_button,QtCore.SIGNAL('clicked()'),self.addLine) if self.ifClear: self.connect(clear_button,QtCore.SIGNAL('released()'),self.clear) self.setNofLines(nLines) #------------------------------------------------------------------- def clear(self): #------------------------------------------------------------------- self.setNofLines(0) self.emit(QtCore.SIGNAL('cleared')) #------------------------------------------------------------------- def setNofLines(self,nLines): #------------------------------------------------------------------- # Add or delete lines to get to NLines curNLines = self.body.layout().count() #print 'exFrame.setNofLines',curNLines,nLines if nLines == curNLines: return elif nLines > curNLines: for ii in range(curNLines,nLines): self.addLine() elif nLines < curNLines and nLines>=0: for ii in range(curNLines,nLines,-1): #print 'exFrame.setNofLines deleteLine',ii-1 self.deleteLine(line=ii-1) #------------------------------------------------------------------- def getNofLines(self): #------------------------------------------------------------------- return self.body.layout().count() #------------------------------------------------------------------- def getLine(self,index): #------------------------------------------------------------------- item = self.body.layout().itemAt(index) if not item: return None else: return item.widget().child #------------------------------------------------------------------- def setWidget(self,widget): #------------------------------------------------------------------- self.widgetClass = widget #------------------------------------------------------------------- def addLine(self,index=-1): #------------------------------------------------------------------- widget = self.widgetClass(self.parent()) line = extendingFrameLine(parent=self,child=widget,ifEditable=self.ifEditable) line.show() self.body.layout().insertWidget(index,line) self.setBodyHeight() if index<0: index = self.body.layout().count()-1 self.emit(QtCore.SIGNAL('lineAdded(int)'),index) #------------------------------------------------------------------- def setBodyHeight(self): #------------------------------------------------------------------- nLines = self.body.layout().count() #print "setBodyHeight",nLines if self.lineHeight<0: widget = self.widgetClass() self.lineHeight = self.widgetClass().height()+6 #print "lineHeight", self.lineHeight self.body.setMinimumHeight( self.lineHeight * nLines) self.body.setMaximumHeight( self.lineHeight * nLines) self.body.updateGeometry() #------------------------------------------------------------------- def deleteLine(self,widget=None,line=-1): #------------------------------------------------------------------- #print "deleteLine",line,widget if line>=0: item = self.body.layout().itemAt(line) #print 'exFrame deleteLine item',item,item.widget() if item: # Beware have seen crashes with the two following # lines in reversed order (close after removeWidget) item.widget().close() self.body.layout().removeWidget(item.widget()) self.setBodyHeight() self.emit(QtCore.SIGNAL('lineDeleted')) elif widget: ii = self.body.layout().indexOf(widget) if ii>=0: widget.close() self.body.layout().removeWidget(widget) self.setBodyHeight() self.emit(QtCore.SIGNAL('lineDeleted')) #------------------------------------------------------------------- def insertLine(self,args): #------------------------------------------------------------------- widget = args[0] mode = args[1] #print "insertLine",widget,mode ii = self.body.layout().indexOf(widget) if ii>=0: if mode == 'below': ii = ii +1 self.addLine(index=ii) #------------------------------------------------------------------- def getParams(self,params={},index=-1): #------------------------------------------------------------------- keyList = params.keys() if index<0: first = 0 last = self.body.layout().count() else: first = index last = index + 1 for line in range(first,last): item = self.body.layout().itemAt(line) if item: lineWidget = item.widget().child try: pars = lineWidget.getParams() for key in keyList: params[key].append(pars.get(key,'')) except: for key in keyList: widget = lineWidget.findChild(QtGui.QWidget,key) value = '' if widget: if isinstance(widget,QtGui.QComboBox): value = str(widget.itemData(widget.currentIndex()).toString()) if not value: value = str(widget.currentText()) elif isinstance(widget,QtGui.QLabel): value = str(widget.text()) elif isinstance(widget,QtGui.QLineEdit): value = str(widget.text()) elif isinstance(widget,QtGui.QAbstractButton): value = int(widget.isChecked()) elif isinstance(widget,mgSelectionCombo): value = str(widget.text()) elif isinstance(widget,mgColourCombo): value = str(widget.get_colour()) elif isinstance(widget,mgAtomPicker): value = str(widget.selection()) elif isinstance(widget,QtGui.QDoubleSpinBox): value = float(widget.value()) elif isinstance(widget,QtGui.QSpinBox): value = int(widget.value()) params[key].append(value) #print "exframe.getParams",params return params #---------------------------------------------------------------- def setParams(self,params,index=0): #---------------------------------------------------------------- # Beware - do not assume that all items in params are # in our widget # index in the first line in the extending frame that the params # should be assigned to keyList = params.keys() #print "exframe.setParams",params,keyList # This will be tricky without an instance of the line # so create one if one does not exist if self.body.layout().count() == 0: self.addLine() lineWidget = self.body.layout().itemAt(0).widget() # Need find at least one item in keyList that is definitely in the line widget = None ii = -1 while not widget and ii=0: widget.setCurrentIndex(ic) elif isinstance(widget,QtGui.QLineEdit): widget.setText(str(params[key][jj])) elif isinstance(widget,QtGui.QLabel): widget.setText(str(params[key][jj])) elif isinstance(widget,QtGui.QAbstractButton): widget.setChecked(params[key][jj]) elif isinstance(widget,mgSelectionCombo): widget.setText(params[key][jj]) elif isinstance(widget,mgColourCombo): widget.set_colour(params[key][jj]) elif isinstance(widget,mgAtomPicker): widget.setSelection(atomName=params[key][jj]) elif isinstance(widget,QtGui.QDoubleSpinBox): widget.setValue(float(params[key][jj])) elif isinstance(widget,QtGui.QSpinBox): widget.setValue(int(params[key][jj])) else: # If cant find widget in this line then wont find # one in any subsequent lines break return nL #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- class extendingFrameLine(QtGui.QWidget): #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- iconPixmap = None def __init__(self,parent=None,child=None,ifEditable=1): QtGui.QWidget.__init__(self,parent) self.child = child layout = QtGui.QHBoxLayout() margin = 0 layout.setSpacing(margin) layout.setContentsMargins(margin,margin,margin,margin) if child: layout.addWidget(child) #ht = child.height() if not extendingFrameLine.iconPixmap: extendingFrameLine.iconPixmap = guiUtils.loadPixmap(name='extendingFrameLine',group='actions') if ifEditable: icon = QtGui.QIcon(extendingFrameLine.iconPixmap) iconButton = QtGui.QToolButton(self) iconButton.setPopupMode(QtGui.QToolButton.InstantPopup) iconButton.setIcon(icon) iconButton.setMaximumSize(QtCore.QSize(extendingFrame.LINE_HEIGHT-4,extendingFrame.LINE_HEIGHT-4)) iconButton.setToolTip('Add or delete a row') iconMenu = QtGui.QMenu(self) deleteAction = QtGui.QAction('Delete',parent) self.connect(deleteAction,QtCore.SIGNAL('triggered()'),guiUtils.partial(parent.deleteLine,self)) iconMenu.addAction(deleteAction) aboveAction = QtGui.QAction('Insert above',parent) self.connect(aboveAction,QtCore.SIGNAL('triggered()'),guiUtils.partial(parent.insertLine,[self,'above'])) iconMenu.addAction(aboveAction) belowAction = QtGui.QAction('Insert below',parent) self.connect(belowAction,QtCore.SIGNAL('triggered()'),guiUtils.partial(parent.insertLine,[self,'below'])) iconMenu.addAction(belowAction) resetAction = QtGui.QAction('Reset',parent) self.connect(resetAction,QtCore.SIGNAL('triggered()'),self.child.setDefault) iconMenu.addAction(resetAction) iconButton.setMenu(iconMenu) layout.addWidget(iconButton) self.setLayout(layout) class frameLine(QtGui.QWidget): def __init__(self,parent=None): QtGui.QWidget.__init__(self,parent) #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- class mgColourCombo( QtGui.QComboBox ): #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- def __init__(self,parent=None,colour='black',browser=0): #---------------------------------------------------------------------- QtGui.QComboBox.__init__(self,parent) self.ifBrowser= browser self.loadColours() self.old_colour = colour self.set_colour(colour) self.connect(ColourBrowserManager(),QtCore.SIGNAL('coloursChanged'),self.loadColours) if self.ifBrowser: self.connect(self,QtCore.SIGNAL('currentIndexChanged(const QString)'),self.handleIndexChanged) #print 'mgColourCombo.init',self,self.old_colour #---------------------------------------------------------------------- def loadColours(self): #---------------------------------------------------------------------- #print 'mgColourCombo.loadColours' current_colour = self.currentText() self.blockSignals(1) self.clear() for col in global_definitions.MGCOLOUR().colourlist(): colour = global_definitions.MGCOLOUR().RGB255(col) qcol = QtGui.QColor(colour[0],colour[1],colour[2]) pixmap = QtGui.QPixmap(20,10) pixmap.fill(qcol) icon = QtGui.QIcon(pixmap) self.addItem(icon,col) idx = self.findText(current_colour) if idx>=0: self.setCurrentIndex(idx) if self.ifBrowser: self.addItem('Colour browser') self.blockSignals(0) #---------------------------------------------------------------------- def handleIndexChanged(self,label): #---------------------------------------------------------------------- #print 'mgColourCombo.handleIndexChanged',label,self.old_colour if label == 'Colour browser': idx = global_definitions.MGCOLOUR().index(self.old_colour) if idx>=0: self.setCurrentIndex( idx ) if not hasattr(self,'browser'): self.browser = mgColourBrowser(self) self.connect(self.browser,QtCore.SIGNAL('ColourSelected'),self.handleBrowser) else: self.browser.show() #---------------------------------------------------------------------- def handleBrowser(self,col): #---------------------------------------------------------------------- #print 'mgColourCombo.handleBrowser',col self.loadColours() self.set_colour(col) #---------------------------------------------------------------------- def set_colour(self,col): #---------------------------------------------------------------------- #print 'colourCombo.set_colour',col; sys.stdout.flush() #self.blockSignals(1) if col == 'Colour browser': idx = self.findText(self.old_colour) if idx>=0: self.setCurrentIndex( idx ) else: idx = self.findText(col) if idx>=0: self.setCurrentIndex( idx ) self.old_colour = col #self.blockSignals(0) #print 'colourCombo.set_colour',col,idx; sys.stdout.flush() #---------------------------------------------------------------------- def get_colour(self): #---------------------------------------------------------------------- return str(self.currentText()) #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- class mgAtomPicker(QtGui.QFrame): #---------------------------------------------------------------------- #---------------------------------------------------------------------- #---------------------------------------------------------------------- def textChanged0(self): txt = str(self.textBox.text()) #print 'mgAtomPicker.textChanged0',txt return self.textChanged(txt) def textChanged(self,text=''): self.blockComboSignals(1) text = (str(text)).strip() model,chain,residue,residue2,atom = self.getDataobj().splitAtomID(text,res_range=1) #print 'mgAtomPicker.textChanged',self.mode,model,chain,residue,residue2,atom if self.showModelCombo: match = self.modelCombo.findText(QtCore.QString(model),QtCore.Qt.MatchExactly) #print 'modelCombo match',model,match if match>=0: self.modelCombo.setCurrentIndex(match) if not chain and self.blankOption: self.chainCombo.setCurrentIndex(0) else: match = self.chainCombo.findText(chain,QtCore.Qt.MatchExactly) #print 'mgAtomPicker.textChanged chainCombo match',chain,'*',match if match>=0: self.chainCombo.setCurrentIndex(match) self.chainChanged(match,updateText=0) if not residue and self.blankOption: self.residueCombo.setCurrentIndex(0) else: match = self.residueCombo.findText(residue,QtCore.Qt.MatchExactly) if match<0: match = self.residueCombo.findText(residue+'(',QtCore.Qt.MatchStartsWith) #print 'residueCombo match',residue,match if match>=0: self.residueCombo.setCurrentIndex(match) self.residueChanged(match,updateText=0) if self.mode == 'atom': if not atom and self.blankOption: self.atomCombo.setCurrentIndex(0) else: match = self.atomCombo.findText(atom,QtCore.Qt.MatchExactly) #print 'atomCombo match',atom,match if match>=0: self.atomCombo.setCurrentIndex(match) else: pass #print "atom:--"+atom+"-- not found" elif self.mode == 'range': if residue2: match = self.rangeCombo.findText(residue2,QtCore.Qt.MatchExactly) if match<0: match = self.rangeCombo.findText(residue2+'(',QtCore.Qt.MatchStartsWith) #print 'residueCombo match',residue,match if match>=0: self.rangeCombo.setCurrentIndex(match) else: self.rangeCombo.setCurrentIndex(0) self.blockComboSignals(0) dobj = self.getDataobj() if not self.signalBlocked and (dobj.name,model,chain,residue,residue2,atom) != self.lastEmitSelection: self.emit(QtCore.SIGNAL("AtomChanged"),(dobj.name,model,chain,residue,residue2,atom)) self.lastEmitSelection = (dobj.name,model,chain,residue,residue2,atom) def atomChanged(self,iatom,updateText=1): if iatom < 0: return if self.showDataCombo and self.dataCombo.count()==0: return if self.showModelCombo and self.modelCombo.count()==0: return if self.chainCombo.count()==0: return if self.residueCombo.count()==0: return dobj = self.getDataobj() imodel = self.getModelNumber() ichain = self.chainCombo.currentIndex() iresidue = self.residueCombo.currentIndex() changed = False if self.showDataCombo and dobj.name != self.dataName: self.dataName = dobj.name changed = True if imodel != self.imodel: self.imodel = imodel changed = True if ichain != self.ichain: self.ichain = ichain changed = True if iresidue != self.iresidue: self.iresidue = iresidue changed = True if iatom != self.iatom: self.iatom = iatom changed = True if changed: #print dataName+"/"+str(imodel)+"/"+str(ichain)+"/"+str(iresidue)+"/"+str(iatom) if updateText:self.updateTextBox() def rangeChanged(self,ires,updateText=1): #print 'rangeChanged',ires if updateText: self.updateTextBox() def updateTextBox(self): dobj = self.getDataobj() imodel = self.getModelNumber() ichain = self.chainCombo.currentIndex()-self.blankOption iresidue = self.residueCombo.currentIndex()-self.blankOption iresidue2 = -1 #print 'updateTextBox',self.signalBlocked,imodel,ichain,iresidue iatom = -1 text = '' if self.showModelCombo and imodel>0: text = '/'+str(imodel) if ichain>=0: chainID = dobj.molHnd.GetModel(imodel).GetChain(ichain).GetChainID() if text: text = text + "/"+str(chainID)+ "/" elif len(chainID)>0: text = str(chainID)+ "/" else: text = '// /' pRes = dobj.molHnd.GetModel(imodel).GetChain(ichain).GetResidue(iresidue) if pRes: text = text +str(pRes.GetSeqNum()) if self.mode == 'atom': iatom = self.atomCombo.currentIndex()-self.blankOption if iatom>=0: theAtom = pRes.GetAtom(iatom) atomID = theAtom.GetAtomName() text = text +'/' + (atomID).strip() altLoc = theAtom.GetAltLoc().strip() if altLoc: text = text + ':' + altLoc elif self.mode == 'range': irange = self.rangeCombo.currentIndex()-self.blankOption if irange>=0: resNo2 = dobj.molHnd.GetModel(imodel).GetChain(ichain).GetResidue(irange).GetSeqNum() if irange>iresidue: text = text +'-'+str(resNo2) elif iresidue>irange: text = "/"+str(imodel)+"/"+str(chainID)+"/"+str(resNo2)+'-'+str(pRes.GetSeqNum()) iresidue2 = resNo2 self.textBox.blockSignals(1) self.textBox.setText(text) self.textBox.blockSignals(0) if not self.signalBlocked: if self.lastEmitSelection != (dobj.name,imodel,ichain,iresidue,iresidue2,iatom): self.emit(QtCore.SIGNAL("AtomChanged"),(dobj.name,imodel,ichain,iresidue,iresidue2,iatom)) self.lastEmitSelection = (dobj.name,imodel,ichain,iresidue,iresidue2,iatom) def reset(self): if self.showDataCombo: self.dataCombo.setCurrentIndex(0) if self.showModelCombo: self.modelCombo.setCurrentIndex(0) self.chainCombo.setCurrentIndex(0) self.residueCombo.setCurrentIndex(0) self.rangeCombo.setCurrentIndex(0) def blockSignals(self,mode): self.signalBlocked = mode def blockComboSignals(self,mode): if self.showDataCombo: self.dataCombo.blockSignals(mode) if self.showModelCombo: self.modelCombo.blockSignals(mode) self.chainCombo.blockSignals(mode) self.residueCombo.blockSignals(mode) if self.rangeCombo: self.rangeCombo.blockSignals(mode) self.atomCombo.blockSignals(mode) def setSelection(self,modelName='',atomName='',MolData=None,pAtom=None): #print 'mgAtomPicker setSelection atomName',atomName if MolData: dobj = MolData modelName = dobj.name elif modelName: dobj = global_definitions.data(modelName) else: dobj = self.getDataobj() if not dobj: return if pAtom: atomName = pAtom.GetAtomID() #print 'mgAtomPicker setSelection',dobj,atomName if dobj and self.showDataCombo and self.dataCombo.findText(modelName,QtCore.Qt.MatchExactly)>-1: self.dataCombo.setCurrentIndex(self.dataCombo.findText(modelName,QtCore.Qt.MatchExactly)) self.textBox.blockSignals(1) self.textBox.setText(atomName) self.textBox.blockSignals(0) self.textChanged(atomName) ''' full_id = dobj.splitAtomID(atomName,res_range=1) print 'mgAtomPicker setSelection atomName',atomName,full_id if self.showModelCombo: if full_id[0]: iModel = self.modelCombo.findText(full_id[0]) if iModel>= 0: self.modelCombo.setCurrentIndex(iModel) iChain = self.chainCombo.findText(full_id[1]) if iChain>=0: self.chainCombo.setCurrentIndex(iChain) iRes = self.residueCombo.findText(full_id[2]) if iRes<0: iRes = self.residueCombo.findText(full_id[2]+'(',QtCore.Qt.MatchStartsWith) if iRes>=0: self.residueCombo.setCurrentIndex(iRes) if self.mode == 'atom': iAtom = self.atomCombo.findText(full_id[4]) if iAtom>=0: self.atomCombo.setCurrentIndex(iAtom) iRes2 = self.rangeCombo.findText(full_id[3]) if iRes2<0: iRes2 = self.rangeCombo.findText(full_id[3]+'(',QtCore.Qt.MatchStartsWith) print 'mgAtomPicker.setSelection iRes2',iRes,iRes2 if iRes2>=0: self.rangeCombo.setCurrentIndex(iRes2) ''' return 0 def selection(self): return str(self.textBox.text()) def modelAtomPtr(self): dobj = self.getDataobj() if not dobj: return (None,None) atm_ptr = dobj.interpretAtomID(dobj,str(self.textBox.text()),force_one_atom=1) #print "modelAtomPtr",self.dataName,str(self.textBox.text()),atm_ptr return dobj,atm_ptr def modelNameAtomName(self): # Use modelAtomPtr to check that atom id is interpretable ret = self.modelAtomPtr() #print "modelNameAtomName ret",ret if ret: return ret[0].name,str(self.textBox.text()) else: return () def residueChanged(self,ires,updateText=1): if ires < 0: return if self.showDataCombo and self.dataCombo.count()==0: return if self.showModelCombo and self.modelCombo.count()==0: return if self.chainCombo.count()==0: return dobj = self.getDataobj() imodel = self.getModelNumber() ichain = self.chainCombo.currentIndex()-self.blankOption ires = ires - self.blankOption if self.mode == 'atom': self.atomCombo.clear() if self.blankOption: self.atomCombo.addItem('') if ires>=0 and ichain>=0 and imodel>=0: natoms = dobj.molHnd.GetModel(imodel).GetChain(ichain).GetResidue(ires).GetNumberOfAtoms() if natoms == 0: return pres = dobj.molHnd.GetModel(imodel).GetChain(ichain).GetResidue(ires) init_atom = 0 for j in range(natoms): pat = pres.GetAtom(j) atomID = pat.GetAtomName().strip() if atomID == 'CA': init_atom = j if pat.GetAltLoc(): atomID =atomID+':'+ pat.GetAltLoc() self.atomCombo.addItem(atomID) if self.atomCombo.currentIndex !=init_atom: self.atomCombo.setCurrentIndex(init_atom) self.atomChanged(init_atom,updateText) else: if updateText: self.updateTextBox() def chainChanged(self,ichain,updateText=1): if ichain < 0: return if self.showDataCombo and self.dataCombo.count()==0: return if self.showModelCombo and self.modelCombo.count()==0: return ichain = ichain - self.blankOption self.residueCombo.clear() self.rangeCombo.clear() if self.blankOption: self.residueCombo.addItem('') self.rangeCombo.addItem('') dobj = self.getDataobj() imodel = self.getModelNumber() if ichain>=0 and imodel>=0: nres = dobj.molHnd.GetModel(imodel).GetChain(ichain).GetNumberOfResidues() if nres == 0: if self.mode == 'atom': self.atomCombo.clear() return pch = dobj.molHnd.GetModel(imodel).GetChain(ichain) for j in range(nres): pres = pch.GetResidue(j) resID = pres.GetResName() resNo = pres.GetSeqNum() resIns = pres.GetInsCode() if resIns: name = str(resNo)+"."+resIns+"("+resID+")" else: name = str(resNo)+"("+resID+")" self.residueCombo.addItem(name) #if self.mode == 'range': self.rangeCombo.addItem(name) self.rangeCombo.addItem(name) self.residueChanged(0,updateText) if self.residueCombo.currentIndex !=0: self.residueCombo.setCurrentIndex(0) #if self.mode == 'range': if self.rangeCombo.currentIndex !=0: self.rangeCombo.setCurrentIndex(0) def modelChanged(self,imodel,updateText=1): if imodel < 0: return if self.showDataCombo and self.dataCombo.count()==0: return imodel = (imodel - self.blankOption) + 1 self.chainCombo.clear() if self.blankOption: self.chainCombo.addItem(' ') self.residueCombo.clear() if self.mode == 'atom': self.atomCombo.clear() if self.mode == 'range': self.rangeCombo.clear() if imodel>0: dobj = self.getDataobj() nchains = dobj.molHnd.GetModel(imodel).GetNumberOfChains() if nchains == 0: return for j in range(nchains): chainID = dobj.molHnd.GetModel(imodel).GetChain(j).GetChainID() self.chainCombo.addItem(chainID) self.chainChanged(0,updateText) if self.chainCombo.currentIndex !=0: self.chainCombo.setCurrentIndex(0) def dataObjChanged(self,i,updateText=1): dobj = self.getDataobj() if not dobj: return if self.showModelCombo: self.modelCombo.clear() nmodels = dobj.molHnd.GetNumberOfModels() if nmodels == 0: self.chainCombo.clear() self.residueCombo.clear() if self.mode == 'range': self.rangeCombo.clear() if self.mode == 'atom': self.atomCombo.clear() return if self.blankOption: self.modelCombo.addItem('') for j in range(nmodels): self.modelCombo.addItem(str(j+1)) self.modelChanged(0,updateText) if self.modelCombo.currentIndex !=0: self.modelCombo.setCurrentIndex(0) else: # Set the chainCombo self.modelChanged(self.blankOption,updateText) def __init__(self,parent=None,MolData_name='',mode = 'atom',blank=0): QtGui.QFrame.__init__(self) self.setFrameStyle(QtGui.QFrame.Box | QtGui.QFrame.Plain) self.showModelCombo = 1 self.mode = mode if MolData_name: self.showDataCombo = 0 dobj = global_definitions.data(MolData_name) if dobj and dobj.molHnd.GetNumberOfModels() == 1: self.showModelCombo = 0 else: self.showDataCombo = 1 self.blankOption = blank self.dataName = MolData_name self.imodel = 0 self.ichain = 0 self.iresidue = 0 self.iatom = 0 self.signalBlocked = 0 self.lastEmitSelection = [self.dataName,0,0,0,0,0] vblayout = QtGui.QHBoxLayout() vblayout.setContentsMargins(0,0,0,0) vblayout.setSpacing(0) if self.showDataCombo: self.dataCombo = mgDataObjCombo(object_type='MolData',parent=self) vblayout.addWidget(self.dataCombo) if self.showModelCombo: self.modelCombo = QtGui.QComboBox() self.modelCombo.setMaxVisibleItems(10) self.modelCombo.setMinimumContentsLength(1) vblayout.addWidget(self.modelCombo) self.chainCombo = QtGui.QComboBox() self.chainCombo.setMaxVisibleItems(10) self.chainCombo.setMinimumContentsLength(1) vblayout.addWidget(self.chainCombo) self.residueCombo = QtGui.QComboBox() self.residueCombo.setMaxVisibleItems(10) self.residueCombo.setMinimumContentsLength(8) vblayout.addWidget(self.residueCombo) self.atomCombo = QtGui.QComboBox() self.atomCombo.setMinimumContentsLength(4) if self.mode == 'atom':vblayout.addWidget(self.atomCombo) self.to_label = QtGui.QLabel('to',self) self.rangeCombo = QtGui.QComboBox() self.rangeCombo.setMinimumContentsLength(8) if self.mode == 'range': vblayout.addWidget(self.to_label) vblayout.addWidget(self.rangeCombo) else: self.to_label.hide() self.rangeCombo.hide() #self.textBox = QtGui.QLineEdit() self.textBox = mgLineEdit() someText = "/99/Z/999.2/HG51" dummy = QtGui.QTextEdit() fn = dummy.currentFont() fm = QtGui.QFontMetrics(fn) textWidth = fm.width(someText) vblayout.addWidget(self.textBox) vblayout.addStretch(5) self.textBox.setMinimumWidth(textWidth) #self.textBox.setValidator(mgCidValidator(self,'atom')) self.dataObjChanged(0) if self.showDataCombo and self.dataCombo.count()>0: self.dataCombo.setCurrentIndex(0) if self.showDataCombo: self.connect(self.dataCombo,QtCore.SIGNAL("currentIndexChanged(int)"),self.dataObjChanged) if self.showModelCombo: self.connect(self.modelCombo,QtCore.SIGNAL("currentIndexChanged(int)"),self.modelChanged) self.setToolTip() self.connect(self.chainCombo,QtCore.SIGNAL("currentIndexChanged(int)"),self.chainChanged) self.connect(self.residueCombo,QtCore.SIGNAL("currentIndexChanged(int)"),self.residueChanged) self.connect(self.atomCombo,QtCore.SIGNAL("currentIndexChanged(int)"),self.atomChanged) self.connect(self.rangeCombo,QtCore.SIGNAL("currentIndexChanged(int)"),self.rangeChanged) #self.connect(self.textBox,QtCore.SIGNAL("textEdited(const QString&)"),self.textChanged) self.connect(self.textBox,QtCore.SIGNAL("editingFinished()"),self.textChanged0) self.connect(self.textBox,QtCore.SIGNAL("apply"),self.textChanged0) #self.connect(self.textBox,QtCore.SIGNAL("mouseRelease()"),self.pasteFromAtomPick) self.setLayout(vblayout) def getDataobj(self): if self.showDataCombo: name = str(self.dataCombo.itemText(self.dataCombo.currentIndex())) else: name = self.dataName return global_definitions.data(name) def getModelNumber(self): if self.showModelCombo: return (self.modelCombo.currentIndex()-self.blankOption)+1 else: return 1 def setToolTip(self,text=''): if text: text = text + ' ' if self.showDataCombo: self.dataCombo.setToolTip(text+'Model object - equivalent to PDB file') if self.showModelCombo: self.modelCombo.setToolTip(text + "'NMR' or symmetry model number") self.chainCombo.setToolTip(text+"Chain ID") self.residueCombo.setToolTip(text+"Residue sequence number and type") if self.mode == 'atom': self.atomCombo.setToolTip(text+"Atom name") if self.mode == 'range': self.rangeCombo.setToolTip(text+"end of residue range") self.textBox.setToolTip(text+"Full atom id") def pasteFromAtomPick(self): # This is NOT used - instead uses the standard QT paster buffer # But this would have advatage that user does not have to delete # any existing text in the text input #print 'mgAtomPicker.pasteFromAtomPick' pickevent = MAINWINDOW().getLastPickEvent() if not pickevent: return atoms = pickevent.getPickedAtoms() if len(atoms) == 1: #print 'pasteFromAtomPick',atoms,atoms[0].GetAtomID() self.textChanged(atoms[0].GetAtomID()) def setMode(self,mode): if mode == self.mode: return self.blockSignals(1) if self.mode == 'atom': self.atomCombo.clear() self.layout().removeWidget(self.atomCombo) self.atomCombo.hide() elif self.mode == 'range': self.layout().removeWidget(self.to_label) self.layout().removeWidget(self.rangeCombo) self.rangeCombo.clear() self.rangeCombo.hide() self.to_label.hide() idx = self.layout().indexOf(self.textBox) if mode == 'atom': self.atomCombo.show() self.layout().insertWidget(idx,self.atomCombo) self.residueChanged(self.residueCombo.currentIndex()) elif mode == 'range': self.to_label.show() self.rangeCombo.show() self.layout().insertWidget(idx,self.to_label) self.layout().insertWidget(idx+1,self.rangeCombo) self.chainChanged(self.chainCombo.currentIndex()) self.mode = mode self.updateTextBox() self.blockSignals(0) #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- class CartesianPickerDialog(MGSimpleDialog.MultiDialog): #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- """ Pick a point in 3D Cartesian space. """ def Apply2(self,pos): self.emit(QtCore.SIGNAL("PositionChanged"),pos) def Apply(self): xyz = ['x','y'] if self.dim >=3:xyz.append('z') pos = [] #for item in xyz: pos.append(self.cartesian.widgets[item].value()) for item in xyz: p = self.cartesian.widgets[item].text() if not p: p = 0.0 pos.append(float(p)) self.emit(QtCore.SIGNAL("PositionChanged"),pos) def ApplyAndClose(self): self.Apply() self.Close() def __init__(self,parent=None,x=0.0,y=0.0,z=0.0,dim=3): MGSimpleDialog.MultiDialog.__init__(self,parent) self.setWindowTitle(self.tr("Cartesian point picker")) self.dim = dim mylayout = QtGui.QVBoxLayout() self.cartesian = CartesianPicker(self,x=x,y=y,z=z,dim=dim) if QtCore.PYQT_VERSION >= 0x040500 and sip.SIP_VERSION >= 0x040800: self.cartesian.PositionChanged.connect(self.Apply2) else: self.connect(self.cartesian,QtCore.SIGNAL("PositionChanged"),self.Apply2) mylayout.addWidget(self.cartesian) dialog_buttons = QtGui.QDialogButtonBox() # 'Enter' or 'return' key anywhere in the dialog box seems to fire # the ok button and exit the dialog box. Remove ok button for now #ok_button = dialog_buttons.addButton(QtGui.QDialogButtonBox.Ok) apply_button = dialog_buttons.addButton(QtGui.QDialogButtonBox.Apply) cancel_button = dialog_buttons.addButton(QtGui.QDialogButtonBox.Cancel) self.connect(cancel_button,QtCore.SIGNAL('clicked()'),self.Close) #self.connect(ok_button,QtCore.SIGNAL('clicked()'),self.ApplyAndClose) self.connect(apply_button,QtCore.SIGNAL('clicked()'),self.Apply) mylayout.addWidget(dialog_buttons) self.setLayout(mylayout) self.setSizeGripEnabled(0) self.CreateMenuEntry() def setParams(self,params={},**kw): params.update(kw) self.cartesian.setParams(params) #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- class CartesianPicker(QtGui.QWidget): #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- if QtCore.PYQT_VERSION >= 0x040500 and sip.SIP_VERSION >= 0x040800: PositionChanged = QtCore.pyqtSignal(list) def __init__(self,parent=None,dim=3,params={},**kw): QtGui.QWidget.__init__(self,parent) hlayout = QtGui.QHBoxLayout() self.widgets = {} items = ['x','y'] if dim>=3: items.append('z') self.validator = QtGui.QDoubleValidator(-1000.0,1000.0,2,self) for item in items: label = QtGui.QLabel(item+':') self.widgets[item] = QtGui.QLineEdit(self) self.widgets[item].setValidator(self.validator) #self.widgets[item] = mgDeltaSlider(QtCore.Qt.Vertical,self) #self.widgets[item].setRange(-100.0,100.0) #self.widgets[item].setSingleStep(0.5) #self.widgets[item].setMaximumHeight(30) self.widgets[item].setObjectName('CartesianPicker-'+item) self.connect(self.widgets[item],QtCore.SIGNAL("valueChanged(double)"),self.Apply) hlayout.addWidget(label) hlayout.addWidget(self.widgets[item]) self.setLayout(hlayout) params.update(kw) self.setParams(params) def setParams(self,params={},**kw): params.update(kw) for key,value in params.items(): if self.widgets.has_key(key): self.widgets[key].setText(str(value)) #self.widgets[key].setValue(value) def Apply(self): pos = [] #for item in ['x','y']: pos.append(self.widgets[item].value()) #if self.widgets.has_key('z'):pos.append(self.widgets['z'].value()) xyz = ['x','y'] if self.widgets.has_key('z'): xyz.append('z') for item in items: p = self.widgets[item].text() if not p: p = 0.0 pos.append(float(p)) if QtCore.PYQT_VERSION >= 0x040500 and sip.SIP_VERSION >= 0x040800: self.PositionChanged.emit(pos) else: self.emit(QtCore.SIGNAL("PositionChanged"),pos) #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- class animationIntervalWidget(mgSlider): #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- def __init__(self,parent): mgSlider.__init__(self,QtCore.Qt.Horizontal,parent) # Enable range of 0 - 1000 ms self.setRange(1,1000,integer=1) self.setValue(global_definitions.MAINWINDOW().animationInterval()) self.connect(self,QtCore.SIGNAL("valueChanged(int)"),self.apply) #------------------------------------------------------------------- def apply(self): #------------------------------------------------------------------- #print "animationIntervalGUI.apply",self.value() global_definitions.MAINWINDOW().setAnimationInterval(int(self.value())) # ?? Test for other instances of this widget and update them def ColourBrowserManager(): if not ColBrowserManager.insts: ColBrowserManager() return ColBrowserManager.insts class ColBrowserManager(QtCore.QObject): insts = None def __init__(self): QtCore.QObject.__init__(self) ColBrowserManager.insts = self def coloursChanged(self): self.emit(QtCore.SIGNAL('coloursChanged')) #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- class mgColourBrowser(ColourBrowser.ColourBrowser): #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- def __init__(self,parent=None,selected_colour=''): #------------------------------------------------------------------- COL = global_definitions.MGCOLOUR() if selected_colour == 'complement': selected_colour = 'white' ColourBrowser.ColourBrowser.__init__(self,parent,standard_colours=COL.get_standard_colours(),custom_colours=COL.get_custom_colours(),new_name_number=COL.new_name_number,selected_colour=selected_colour) self.show() self.connect(self,QtCore.SIGNAL("clearCustomColours"),self.handleClearCustomColours) self.connect(self,QtCore.SIGNAL("deleteColour"),self.handleDeleteColour) self.connect(self,QtCore.SIGNAL("newColour"),self.handleNewColour) self.connect(self,QtCore.SIGNAL("colourNameEdit(PyQt_PyObject)"),self.handleRenameColour) self.connect(ColourBrowserManager(),QtCore.SIGNAL('coloursChanged'),self.updateCustomColours) def updateCustomColours(self): ColourBrowser.ColourBrowser.updateCustomColours(self,global_definitions.MGCOLOUR().get_custom_colours()) #------------------------------------------------------------------- def handleNewColour(self,colour=[]): #------------------------------------------------------------------- rgb = [] for ii in range(1,4): rgb.append(float(colour[ii])/float(256.0)) #print "handleNewColour rgb",rgb global_definitions.MGCOLOUR().new(colour[0],rgb) ColourBrowserManager().coloursChanged() #------------------------------------------------------------------- def handleRenameColour(self,args): #------------------------------------------------------------------- #print 'mgColourBrowser.handleRenameColour',args if not len(args)==2: return global_definitions.MGCOLOUR().rename(args[0],args[1]) ColourBrowserManager().coloursChanged() #------------------------------------------------------------------- def handleDeleteColour(self,colour): #------------------------------------------------------------------- global_definitions.MGCOLOUR().delete(colour) ColourBrowserManager().coloursChanged() #------------------------------------------------------------------- def handleClearCustomColours(self): #------------------------------------------------------------------- global_definitions.MGCOLOUR().clear_custom_colours() ColourBrowserManager().coloursChanged() class GridWidget(QtGui.QWidget): def __init__(self,parent=None,rows=0,cols=0): QtGui.QWidget.__init__(self,parent) layout = QtGui.QGridLayout() self.setLayout(layout) self.validator = QtGui.QDoubleValidator(self) for i in range(rows): for j in range(cols): le = QtGui.QLineEdit(self) le.setValidator(self.validator) layout.addWidget(le,i,j) #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- class TransformMatrixDialog(MGSimpleDialog.MultiDialog): #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- def __init__(self,parent=None,title="Transformation matrix"): MGSimpleDialog.MultiDialog.__init__(self,parent) self.setWindowTitle(title) layout = QtGui.QVBoxLayout() widget = QtGui.QLabel('Rotation matrix:',self) layout.addWidget(widget) self.rotmat=GridWidget(self,3,3) self.rotmat.setMaximumSize(QtCore.QSize(400,100)) layout.addWidget(self.rotmat) line_layout = QtGui.QHBoxLayout() widget = QtGui.QLabel('Not doing what you expected? Try',self) line_layout.addWidget(widget) widget = QtGui.QPushButton('Flip matrix',self) line_layout.addWidget(widget) self.connect(widget,QtCore.SIGNAL('clicked()'),self.flipMatrix) layout.addLayout(line_layout) widget = QtGui.QLabel('Translation vector:',self) layout.addWidget(widget) self.transvect = GridWidget(self,1,3) layout.addWidget(self.transvect) absLayout = QtGui.QHBoxLayout() absLabel = QtGui.QLabel(self.tr('Apply transformation to ')) absLayout.addWidget(absLabel) self.absCombo = QtGui.QComboBox() self.absCombo.addItem(self.tr('absolute coordinates')) self.absCombo.addItem(self.tr('current view')) absLayout.addWidget(self.absCombo) absLayout.addStretch() layout.addLayout(absLayout) dialog_buttons = QtGui.QDialogButtonBox() apply_button = dialog_buttons.addButton(QtGui.QDialogButtonBox.Apply) undo_button = dialog_buttons.addButton('Undo transformation',QtGui.QDialogButtonBox.ResetRole) cancel_button = dialog_buttons.addButton(QtGui.QDialogButtonBox.Cancel) self.connect(cancel_button,QtCore.SIGNAL('clicked()'),self.Close) #self.connect(ok_button,QtCore.SIGNAL('clicked()'),self.ApplyAndClose) self.connect(apply_button,QtCore.SIGNAL('clicked()'),self.Apply) self.connect(undo_button,QtCore.SIGNAL('clicked()'),self.Undo) layout.addWidget(dialog_buttons) self.setLayout(layout) self.setSizeGripEnabled(0) self.CreateMenuEntry() #------------------------------------------------------------------- def setParams(self,params={},**kw): #------------------------------------------------------------------- params.update(kw) #print 'TransformMatrixDialog.setParams',params import types import re,string if params.has_key('rotation'): if (isinstance(params['rotation'],types.ListType) or isinstance(params['rotation'],types.TupleType) ) and len(params['rotation'])==9: self.setGrid(self.rotmat,params['rotation']) elif isinstance(params['rotation'],types.StringType): rotmat = string.split(re.sub(',',' ',params['rotation'])) self.setGrid(self.rotmat,rotmat) if params.has_key('translation'): if (isinstance(params['translation'],types.ListType) or isinstance(params['translation'],types.TupleType) ) and len(params['translation'])==3: self.setGrid(self.transvect,params['translation']) elif isinstance(params['translation'],types.StringType): rotmat = string.split(re.sub(',',' ',params['translation'])) self.setGrid(self.transvect,rotmat) #------------------------------------------------------------------- def getParams(self): #------------------------------------------------------------------- import re,string pars = {} text = self.absCombo.currentText() if self.tr(text) == self.tr('absolute coordinates'): pars['transmode'] = 'absolute' else: pars['transmode'] = 'relative' #text = str(self.transvect.text()) if False: pars['translation'] = [0.0,0.0,0.0] else: numlist = self.extractGrid(self.transvect) if len(numlist)==3: pars['translation'] = numlist #text = str(self.rotmat.toPlainText()) if False: pars['rotation'] = [1.0,0.0,0.0, 0.0,1.0,0.0, 0.0,0.0,1.0] else: tmtrx = self.extractGrid(self.rotmat) print tmtrx if len(tmtrx)==9: det = ( tmtrx[0] * ( tmtrx[4]* tmtrx[8] - tmtrx[5]* tmtrx[7] ) ) + \ ( tmtrx[1] * ( tmtrx[5]* tmtrx[6] - tmtrx[3]* tmtrx[8] ) ) + \ ( tmtrx[2] * ( tmtrx[3]* tmtrx[7] - tmtrx[4]* tmtrx[6] ) ) print "det",det import math det = math.fabs(det) if det > 0.99 and det < 1.01: pars['rotation'] = tmtrx return pars def setGrid(self,grid,vals): ij = 0 for i in range(grid.layout().rowCount()): for j in range(grid.layout().columnCount()): try: grid.layout().itemAtPosition(i,j).widget().setText(str(vals[ij])) except: print ij,"out of range ? in", grid.layout().rowCount(),"x",grid.layout().columnCount() ij += 1 def extractGrid(self,grid): vals = [] for i in range(grid.layout().rowCount()): for j in range(grid.layout().columnCount()): vals.append(float(grid.layout().itemAtPosition(i,j).widget().text())) return vals #------------------------------------------------------------------- def extractVector(self,text): #------------------------------------------------------------------- import re,string strlist = string.split(re.sub(',',' ',text)) numlist = [] for item in strlist: try: numlist.append(float(item)) except: pass return numlist #------------------------------------------------------------------- def Apply(self): #------------------------------------------------------------------- pars = self.getParams() errmess = '' if not pars.has_key('rotation'): errmess = errmess + 'Rotation is not correct\n' if not pars.has_key('translation'): errmess = errmess + 'Translation is not correct\n' if errmess: QtGui.QMessageBox.warning(None,self.windowTitle(),'Can not apply transformation\n'+errmess) else: self.emit(QtCore.SIGNAL('transformationChanged')) #------------------------------------------------------------------- def Undo(self): #------------------------------------------------------------------- self.setParams(rotation = ( 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 ), translation = ( 0.0, 0.0, 0.0 ) ) self.emit(QtCore.SIGNAL('transformationUndone')) #------------------------------------------------------------------- def flipMatrix(self): #------------------------------------------------------------------- params = self.getParams() if not params.has_key('rotation'): QtGui.QMessageBox.warning(None,'Can not flip matrix\n'+'Rotation is not correct') return mx = params['rotation'] self.setParams(rotation = ( mx[0] , mx[3], mx[6], mx[1], mx[4], mx[7], mx[2], mx[5], mx[8] ) ) #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- class saveMultiDataObj(QtGui.QDialog): #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- def __init__(self,parent,title='Save all data files',tag='',version='',message=''): QtGui.QDialog.__init__(self,parent) self.setWindowTitle(title) layout = QtGui.QVBoxLayout() if message: line_layout = QtGui.QHBoxLayout() line_layout.addWidget(QtGui.QLabel(message)) line_layout.addStretch(5) layout.addLayout(line_layout) line_layout = QtGui.QHBoxLayout() line_layout.addWidget(QtGui.QLabel('Save files with tag',self)) self.tag = QtGui.QLineEdit(self) line_layout.addWidget(self.tag) line_layout.addWidget(QtGui.QLabel('and version number')) self.tag.setText(tag) self.version = QtGui.QSpinBox(self) self.version.setRange(0,100) self.version.setSingleStep(1) self.version.setValue(version) line_layout.addWidget(self.version) line_layout.addStretch(5) layout.addLayout(line_layout) self.mode = QtGui.QButtonGroup(self) line_layout = QtGui.QHBoxLayout() self.append_tag = QtGui.QRadioButton('Save to filename with tag appended',self) self.mode.addButton(self.append_tag,0) line_layout.addWidget(self.append_tag) line_layout.addStretch(5) layout.addLayout(line_layout) line_layout = QtGui.QHBoxLayout() self.backup = QtGui.QRadioButton('Save to same filename and backup to file with tag',self) self.mode.addButton(self.backup,0) line_layout.addWidget(self.backup) line_layout.addStretch(5) layout.addLayout(line_layout) dialog_buttons = QtGui.QDialogButtonBox() apply_button = dialog_buttons.addButton('Save',QtGui.QDialogButtonBox.ApplyRole) cancel_button = dialog_buttons.addButton('Close',QtGui.QDialogButtonBox.RejectRole) self.connect(apply_button,QtCore.SIGNAL('clicked()'),guiUtils.partial(self.emit,QtCore.SIGNAL('save'))) self.connect(apply_button,QtCore.SIGNAL('clicked()'),self.Apply) self.connect(cancel_button,QtCore.SIGNAL('clicked()'),self.close) layout.addWidget(dialog_buttons) self.setLayout(layout) self.show() def getMode(self): return ['append','backup'][int(self.mode.checkedId())] def getTag(self): return str(self.tag.text()) + str(self.version.value()) #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- class RoundToMultipleSpin(QtGui.QSpinBox): #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- def __init__(self,parent=None): QtGui.QSpinBox.__init__(self,parent) self.setMultiple(1) def setMultiple(self,value): self.multiple = value self.setSingleStep(value) def fixValue(self): v = self.value() vnew = (v+(self.multiple-1))/self.multiple * self.multiple self.setValue(vnew) def fixup(self,input): v = int(input.toAscii()) vnew = (v+(self.multiple-1))/self.multiple * self.multiple input.replace(0,len(input),str(vnew)) def validate(self,input,pos): try: v = int(input.toAscii()) if v/self.multiple *self.multiple == v: return (QtGui.QValidator.Acceptable,pos) except: return (QtGui.QValidator.Invalid,pos) return (QtGui.QValidator.Intermediate,pos) #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- class RestrictedSpinBox(QtGui.QSpinBox): #------------------------------------------------------------------- #------------------------------------------------------------------- #------------------------------------------------------------------- def __init__(self,parent=None): QtGui.QSpinBox.__init__(self,parent) self.restriction = [] def setRestriction(self,value): self.restriction = value def fixup(self,input): v = int(input.toAscii()) if len(self.restriction)>0: if self.restriction.count(v)==0: input.replace(0,len(str(self.restriction[0])),str(self.restriction[0])) def validate(self,input,pos): try: v = int(input.toAscii()) if len(self.restriction)>0: if self.restriction.count(v)>0: return (QtGui.QValidator.Acceptable,pos) else: return (QtGui.QValidator.Acceptable,pos) except: return (QtGui.QValidator.Invalid,pos) return (QtGui.QValidator.Intermediate,pos) class DoubleColourSlider(QtGui.QWidget): def __init__(self,parent=None): QtGui.QWidget. __init__(self,parent) colourLayout = QtGui.QGridLayout() #colourLayout.setContentsMargins(0,0,0,0) unAlignedLabel = QtGui.QLabel(self.tr("Unaligned colour"),self) self.nonAlignedCombo = mgColourCombo(self,'white',browser=1) interpLabel = QtGui.QLabel(self.tr("Blend from "),self) interpLabel2 = QtGui.QLabel(self.tr(" to "),self) self.interpCombo = QtGui.QComboBox(self) self.interpCombo.addItems(["Between RGB values","Colour wheel clockwise","Colour wheel anti-clockwise"]) self.slider = UpperLowerSlider(QtCore.Qt.Horizontal,self) self.slider.setRange(0,1,minDecimals=4) self.lowColourCombo = mgColourCombo(self,'yellow',browser=1) self.highColourCombo = mgColourCombo(self,'red',browser=1) editMax = QtGui.QPushButton("Change max. value") colourLayout.addWidget(interpLabel,0,0) colourLayout.addWidget(self.lowColourCombo,0,1) colourLayout.addWidget(interpLabel2,0,2) colourLayout.addWidget(self.highColourCombo,0,3) colourLayout.addWidget(self.interpCombo,1,1,1,3) colourLayout.addWidget(self.slider,2,0,1,4) colourLayout.addWidget(unAlignedLabel,3,0) colourLayout.addWidget(self.nonAlignedCombo,3,1) colourLayout.addWidget(editMax,3,3) self.setLayout(colourLayout) self.connect(self.lowColourCombo,QtCore.SIGNAL('currentIndexChanged(const QString&)'),self.valuesChanged) self.connect(self.highColourCombo,QtCore.SIGNAL('currentIndexChanged(const QString&)'),self.valuesChanged) self.connect(self.nonAlignedCombo,QtCore.SIGNAL('currentIndexChanged(const QString&)'),self.valuesChanged) self.connect(self.interpCombo,QtCore.SIGNAL('currentIndexChanged(const QString&)'),self.valuesChanged) self.connect(self.slider,QtCore.SIGNAL("rangeChanged"),self.valuesChanged) self.connect(self, QtCore.SIGNAL('finished(int)'), self.hide) self.connect(editMax, QtCore.SIGNAL('clicked(bool)'), self.editMaximumValue) def editMaximumValue(self): w = QtGui.QDialog() layout = QtGui.QVBoxLayout() lineEdit = QtGui.QLineEdit() validator = QtGui.QDoubleValidator(lineEdit) lineEdit.setText(str(self.slider.maximum())) lineEdit.setValidator(validator) layout.addWidget(lineEdit) w.setLayout(layout) w.setWindowTitle("Set maximum slider value") def setEditMax(): minVal = self.slider.minimum() maxVal = float(lineEdit.text()) decimals = self.slider.decimals() lower = self.slider.lowerSpin.value() upper = self.slider.upperSpin.value() self.slider.setRange(minVal,maxVal,decimals) self.slider.lowerSpin.setValue(lower) self.slider.upperSpin.setValue(upper) self.connect(lineEdit,QtCore.SIGNAL("textEdited(const QString&)"),setEditMax) w.exec_() def getValues(self): import atom_util mode = 1 dirn = atom_util.COLOUR_WHEEL_CLOCK if str(self.interpCombo.currentText().toUtf8()) == "Colour wheel clockwise": mode = 2 if str(self.interpCombo.currentText().toUtf8()) == "Colour wheel anti-clockwise": mode = 2 dirn = atom_util.COLOUR_WHEEL_ANTICLOCK colourInfo = {'lowerColour':str(self.lowColourCombo.currentText().toUtf8()),'upperColour':str(self.highColourCombo.currentText().toUtf8()),'lower':self.slider.getValues()[0],'upper':self.slider.getValues()[1],"mode":mode,"direction":dirn,'noneColour':str(self.nonAlignedCombo.currentText().toUtf8())} return colourInfo def getValuesAsColourInfo(self): import atom_util mode = 1 dirn = atom_util.COLOUR_WHEEL_CLOCK if str(self.interpCombo.currentText().toUtf8()) == "Colour wheel clockwise": mode = 2 if str(self.interpCombo.currentText().toUtf8()) == "Colour wheel anti-clockwise": mode = 2 dirn = atom_util.COLOUR_WHEEL_ANTICLOCK colourInfo = mgapp.DoubleColourSliderInfo(str(self.lowColourCombo.currentText().toUtf8()),str(self.highColourCombo.currentText().toUtf8()),self.slider.getValues()[0],self.slider.getValues()[1],mode,dirn,str(self.nonAlignedCombo.currentText().toUtf8())) return colourInfo def valuesChanged(self,val=None): import atom_util if QtCore.QString('Colour browser') == val: return mode = 1 dirn = atom_util.COLOUR_WHEEL_CLOCK if str(self.interpCombo.currentText().toUtf8()) == "Colour wheel clockwise": mode = 2 if str(self.interpCombo.currentText().toUtf8()) == "Colour wheel anti-clockwise": mode = 2 dirn = atom_util.COLOUR_WHEEL_ANTICLOCK colourInfo = mgapp.DoubleColourSliderInfo(str(self.lowColourCombo.currentText().toUtf8()),str(self.highColourCombo.currentText().toUtf8()),self.slider.getValues()[0],self.slider.getValues()[1],mode,dirn,str(self.nonAlignedCombo.currentText().toUtf8())) self.emit(QtCore.SIGNAL("valuesChanged"),colourInfo)