""" qtgui/guiUtils.py: CCP4 Gui Project Copyright (C) 2001-2008 University of York, CCLRC Copyright (C) 2009 University of York 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. """ ##@package CCP4GuiUtils (QtGui) Assorted Gui utilities import os,types,copy,functools from PyQt4 import QtGui,QtCore,QtSvg import CCP4Widgets LOADED_PIXMAPS = {} ICON_EXTENSIONS= ['.svg','.png'] class mgMenu(QtGui.QMenu): def __init__(self,parent=None): QtGui.QMenu.__init__(self,parent) def mouseReleaseEvent(self,event): action = self.actionAt(QtCore.QPoint(event.x(),event.y())) if action: action.emit(QtCore.SIGNAL('mouseRelease')) #if event.key()!=QtCore.Qt.Key_Return: QtGui.QMenu.mouseReleaseEvent(self,event) def checkState(inp): if inp: return QtCore.Qt.Checked else: return QtCore.Qt.Unchecked def fromCheckState(inp): if inp == QtCore.Qt.Unchecked: return 0 else: return 1 #---------------------------------------------------------------------- def fromMenu(text,menu_list,alias_list): #---------------------------------------------------------------------- # return the short alias for a given long menu text if menu_list.count(text): return alias_list[menu_list.index(text)] else: return text #---------------------------------------------------------------------- def createAction(name='',parent=None,definition={},icon_path='',default_icon=''): #---------------------------------------------------------------------- if definition: adef = definition else: adef = parent.getActionDef(name) #print "createAction",name,adef # Is it a 'build-in' action if adef.has_key('action'): #print "createAction build-in",name,adef['action'] return adef['action'] text = '' if adef.has_key('text'): if callable(adef['text']): text = adef['text']() else: text = adef['text'] # Is it grouped with other actions if adef.has_key('group'): group=parent.findChild(QtGui.QActionGroup,adef['group']) if not group: group = QtGui.QActionGroup(parent) group.setObjectName(adef['group']) a = group.addAction(text) else: a = QtGui.QAction(text,parent) a.setObjectName(name) if adef.has_key('shortcut') and adef['shortcut']: if isinstance(adef['shortcut'],types.IntType): a.setShortcut(adef['shortcut']) else: a.setShortcut(QtGui.QKeySequence(adef['shortcut'])) icon = createIcon(name,adef,icon_path=icon_path,default_icon=default_icon) if icon: a.setIcon(icon) tip = adef.get('toolTip','') if tip: a.setToolTip(tip) if adef.has_key('checkable') and adef['checkable']: a.setCheckable(1) if adef.has_key('checked') and callable(adef["checked"]): res = adef["checked"]() if type(res)==types.IntType or type(res)==types.BooleanType: a.setChecked(res) if adef.has_key('enabled'): if callable(adef["enabled"]): res = adef["enabled"]() else: res = adef["enabled"] if type(res)==types.IntType or type(res)==types.BooleanType: a.setEnabled(res) if adef.get('deleteLater',0): a.deleteLater() # Sort out a signal if adef.has_key('signal'): signal = adef['signal'] else: signal = 'triggered()' if adef.get('slot',''): if isinstance(adef['slot'],types.ListType) and len(adef['slot'])>1: parent.connect(a,QtCore.SIGNAL(signal),functools.partial(adef['slot'][0],adef['slot'][1])) else: parent.connect(a,QtCore.SIGNAL(signal),adef['slot']) return a #---------------------------------------------------------------------- def createIcon(name=None,adef={},icon_path='',default_icon='unknown'): #---------------------------------------------------------------------- #print 'guiUtils.createIcon',name if adef.has_key('icon') and adef['icon']: icon_name = str(adef['icon']) elif name is not None: icon_name = str(name) else: icon_name = 'unknown' if not icon_path: for item in ['CCP4I2_TOP']: if os.environ.has_key(item): icon_path = os.path.join(os.path.abspath(os.environ[item]),'qticons') #print 'guiUtils.createIcon',icon_path,icon_name for ext in ICON_EXTENSIONS: filename = os.path.join(icon_path,icon_name+ext) if os.path.exists(filename): #print 'guiUtils.createIcon',filename if ext == '.svg': pix = loadSvg(filename) else: pix = QtGui.QPixmap(filename) ico = QtGui.QIcon(pix) return ico if default_icon: for item in ['CCP4I2_TOP']: if os.environ.has_key(item): file = os.path.join(os.path.abspath(os.environ[item]),'qticons',default_icon+'.png') return QtGui.QIcon(file) else: return None def loadSvgWithSize(fileName,width,height): svg = QtSvg.QSvgRenderer() svg.load(fileName) pixmap = QtGui.QImage(width,height,QtGui.QImage.Format_ARGB32) pixmap.fill(QtGui.QColor(0, 0, 0, 0)) painter = QtGui.QPainter(pixmap) painter.setRenderHints(QtGui.QPainter.Antialiasing); svg.render(painter) painter.end() #pixmap = pixmap.scaledToHeight(height,QtCore.Qt.SmoothTransformation) return QtGui.QPixmap.fromImage(pixmap) def loadSvg(fileName): ICONSIZE = 24 svg = QtSvg.QSvgRenderer() svg.load(fileName) pixmap = QtGui.QPixmap(ICONSIZE,ICONSIZE) pixmap.fill(QtGui.QColor(0,0,0,0)) painter = QtGui.QPainter(pixmap) svg.render(painter) painter.end() return pixmap #---------------------------------------------------------------------- def addMenuEntry(name='',definition={},parent=None,icon_path=''): #---------------------------------------------------------------------- action = createAction(name,parent,definition,icon_path) parent.addAction(action) if definition.has_key('slot') and definition.has_key('signal'): if type(definition['slot']) == tuple: # Hmm, I need to know how to have arbitrary number of arguments. parent.connect(action,QtCore.SIGNAL(definition['signal']),functools.partial(definition['slot'][0],definition['slot'][1])) else: parent.connect(action,QtCore.SIGNAL(definition['signal']),definition['slot']) return action #---------------------------------------------------------------------- def clearMenu(menu=None): #---------------------------------------------------------------------- submenus = menu.findChildren(QtGui.QMenu) menu.clear() for sm in submenus: sm.clear() #---------------------------------------------------------------------- def populateMenu(parent=None,menuWidget=None,definition=[], getActionDef=None,default_icon='',info={}): #---------------------------------------------------------------------- #print "populateMenu",definition #menuWidget.connect(menuWidget, QtCore.SIGNAL("hovered(QAction *)"),handleMenuHover) if not definition: menuWidget.addAction(createAction('dummy',parent,{ 'text' : ' -- '} ,default_icon=default_icon)) elif not isinstance(definition,types.ListType): parent.connect(menuWidget,QtCore.SIGNAL("aboutToShow()"),functools.partial(definition,menuWidget)) else: for item in definition: a = None if item == 'sep': #print 'Not adding a menu separator',definition menuWidget.addSeparator() elif isinstance(item,types.ListType) and len(item)>0: sub_menu=menuWidget.addMenu(item[0]) if len(item) == 1: # This is a sub without actions defined sub_menu.setEnabled(0) elif isinstance(item[1],types.StringType): populateMenu(parent=parent,menuWidget=sub_menu,definition = item[1:],getActionDef=getActionDef,default_icon=default_icon,info=info) elif isinstance(item[1],types.MethodType): parent.connect(sub_menu,QtCore.SIGNAL("aboutToShow()"),functools.partial(item[1],(sub_menu,item[0]))) else: if getActionDef: adef = getActionDef(item) else: adef = parent.getActionDef(item) #print 'populateMenu adef ',item,adef if adef: a = adef.get('action',None) if a is None: a = createAction(item,parent,adef,default_icon=default_icon) adef['action'] = a else: # The action exists but lets update the checked status if adef.has_key('text') and callable(adef["text"]): a.setText(adef['text']()) if adef.has_key('checked') and callable(adef["checked"]): res = adef["checked"]() #print "populateMenu checked",item,res if type(res)==types.IntType or type(res)==types.BooleanType: a.setChecked(res) if adef.has_key('enabled'): #print 'reload adef enabled',item,adef["enabled"] if callable(adef["enabled"]): res = adef["enabled"]() else: res = adef["enabled"] #print 'reload adef enabled',item,res if type(res)==types.IntType or type(res)==types.BooleanType: a.setEnabled(res) if a: menuWidget.addAction(a) def handleMenuHover(action): tip = action.toolTip() if not tip: return QtGui.QToolTip.showText(QtGui.QCursor.pos(),tip) #---------------------------------------------------------------------- def populateToolBar(parent=None,toolBarWidget=None,definition=[], getActionDef=None,default_icon='',info={}): #---------------------------------------------------------------------- #print 'populateToolBar',definition if not definition: toolBarWidget.addAction(createAction('dummy',parent,{ 'text' : ' -- '} ,default_icon=default_icon)) elif not isinstance(definition,types.ListType): parent.connect(toolbarWidget,QtCore.SIGNAL("aboutToShow()"),partial(definition,toolBarWidget)) else: for item in definition: a = None if item == 'sep': # ?????????????????????????? pass elif isinstance(item,types.ListType) and len(item)>0: # ????????????? handling splitter pass else: if getActionDef: adef = apply(getActionDef,[item],info) else: adef = apply(parent.getActionDef,[item],info) if adef: #print "createAction adef",adef a = parent.findChild(QtGui.QAction,item) #print "populateMenu find action",item,a if not a: a = createAction(item,parent,adef,default_icon=default_icon) else: # The action exists but lets update the checked status if adef.has_key('text') and callable(adef["text"]): a.setText(adef['text']()) if adef.has_key('checked') and callable(adef["checked"]): res = adef["checked"]() #print "populateMenu checked",item,res if type(res)==types.IntType or type(res)==types.BooleanType: a.setChecked(res) if adef.has_key('enabled'): #print 'reload adef enabled',item,adef["enabled"] if callable(adef["enabled"]): res = adef["enabled"]() else: res = adef["enabled"] #print 'reload adef enabled',item,res if type(res)==types.IntType or type(res)==types.BooleanType: a.setEnabled(res) if a: toolBarWidget.addAction(a) #------------------------------------------------------------------- def loadPixmap(name='',group='actions',icon_path='',width=32,height=0): #------------------------------------------------------------------- if not height: height = width size_key = str(width)+'_'+str(height) if not (LOADED_PIXMAPS.has_key(name) and LOADED_PIXMAPS[name].has_key(size_key)): if not icon_path: icon_path = os.path.join(os.path.abspath(os.environ['CCP4I2_TOP']),'qticons') file = '' for ext in ICON_EXTENSIONS: f = os.path.join(icon_path,group,name+ext) if os.path.exists(f): file = f break if not file: file = os.path.join(os.environ['CCP4I2_TOP'],'qticons','unknown.png') if not os.path.exists(file): return None if not LOADED_PIXMAPS.has_key(name): LOADED_PIXMAPS[name] = {} LOADED_PIXMAPS[name][size_key] = QtGui.QPixmap(file).scaled(width,height) return LOADED_PIXMAPS[name][size_key] #------------------------------------------------------------------- def loadResource(self,url='',mode=QtGui.QTextDocument.StyleSheetResource): #------------------------------------------------------------------- qu = QtCore.QUrl(url) self.style = self.textBrowser.loadResource(mode, qu) #------------------------------------------------------------------- def setWidgetValue(widget,value): #------------------------------------------------------------------- #print 'setWidgetValue',widget,value if isinstance(widget,QtGui.QComboBox): ic = widget.findText(QtCore.QString(value)) if ic < 0: ic = widget.findData(QtCore.QVariant(value)) if ic>=0: widget.setCurrentIndex(ic) elif isinstance(widget,QtGui.QLineEdit): widget.setText(str(value)) elif isinstance(widget,QtGui.QLabel): widget.setText(str(value)) elif isinstance(widget,QtGui.QAbstractButton): widget.setChecked(value) elif isinstance(widget,QtGui.QDoubleSpinBox): widget.setValue(float(value)) elif isinstance(widget,QtGui.QSpinBox): widget.setValue(int(value)) elif isinstance(widget,CCP4Widgets.CDataFileView): widget.setDataFile(value) ''' elif isinstance(widget,mgSelectionCombo): widget.setText(value) elif isinstance(widget,mgColourCombo): widget.set_colour(value) elif isinstance(widget,mgAtomPicker): widget.setSelection(atomName=value) ''' #------------------------------------------------------------------- def getWidgetValue(widget=None,default='',baseType='text'): #------------------------------------------------------------------- value = default if isinstance(widget,QtGui.QComboBox): #value = str(widget.itemData(widget.currentIndex()).toString()) variant = widget.itemData(widget.currentIndex()) if variant: if baseType == 'int': value = variant.toInt() elif baseType == 'real': value = variant.toFloat() else: value = str(variant.toString()) #print 'getWidgetValue menu variant',variant,value 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,QtGui.QDoubleSpinBox): value = float(widget.value()) elif isinstance(widget,QtGui.QSpinBox): value = int(widget.value()) elif isinstance(widget,CCP4Widgets.CDataFileView): value = widget.getDataFile() ''' 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()) ''' return value def getWidgetSignal(widget=None,default='clicked()'): signal = default if isinstance(widget,QtGui.QComboBox): signal = 'currentIndexChanged(int)' elif isinstance(widget,QtGui.QLabel): signal = 'linkActivated(const QString)' elif isinstance(widget,QtGui.QLineEdit): signal = 'editingFinished()' elif isinstance(widget,QtGui.QAbstractButton): signal = 'clicked(bool)' elif isinstance(widget,QtGui.QDoubleSpinBox): signal = 'valueChanged(double)' elif isinstance(widget,QtGui.QSpinBox): signal = 'valueChanged(int)' return signal