Skip to content
Snippets Groups Projects
Commit 0cda31e2 authored by Dilawar Singh's avatar Dilawar Singh
Browse files

Squashed 'moose-gui/' content from commit a3d3a06

git-subtree-dir: moose-gui
git-subtree-split: a3d3a067901ee0f1f183f50f667a98bebf3e447f
parents
No related branches found
No related tags found
No related merge requests found
from PyQt4 import Qt, QtCore, QtGui
from PyQt4.QtGui import *
import os
APPLICATION_BACKGROUND_PATH = os.path.join( os.path.dirname(os.path.realpath(__file__))
, "icons/moose_icon_large.png"
)
class MdiArea(QMdiArea):
def __init__(self):
super(MdiArea, self).__init__()
self.backgroundImage = QImage(APPLICATION_BACKGROUND_PATH)
self.background = None
def resizeEvent(self,event):
# http://qt-project.org/faq/answer/when_setting_a_background_pixmap_for_a_widget_it_is_tiled_if_the_pixmap_is_
self.background = QImage(event.size(), QImage.Format_ARGB32_Premultiplied)
painter = QPainter(self.background)
painter.fillRect(self.background.rect(), QColor(243, 239, 238, 255))
scaled = self.backgroundImage.scaled(event.size() , QtCore.Qt.KeepAspectRatio)
scaledRect = scaled.rect()
scaledRect.moveCenter(self.background.rect().center())
painter.drawImage(scaledRect, scaled)
self.setBackground(QBrush(self.background))
super(MdiArea, self).resizeEvent(event)
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function
"""
"""
__author__ = "Aviral Goel"
__credits__ = ["Upi Lab"]
__license__ = "GPL3"
__version__ = "1.0.0"
__maintainer__ = "Aviral Goel"
__email__ = "goel.aviral@gmail.com"
__status__ = "Development"
import sys
import os
import PyQt4
from PyQt4 import QtGui, Qt
from PyQt4.QtGui import QWidget
from PyQt4.QtGui import QSizeGrip
from PyQt4.QtGui import QDockWidget
from PyQt4.QtGui import QLayout
from PyQt4.QtGui import QVBoxLayout
from PyQt4.QtGui import QGridLayout
from PyQt4.QtGui import QScrollArea
from PyQt4.QtGui import QToolBar
from PyQt4.QtGui import QSizeGrip
from PyQt4.QtGui import QSplitter
import moose
import default
import sidebar
# from default import PlotWidget
ELECTRICAL = 0
CHEMICAL = 1
class PlotWidgetContainer(QWidget):
def __init__(self, modelRoot, *args, **kwargs):
super(PlotWidgetContainer, self).__init__(*args)
self.modelRoot = modelRoot
if len(moose.wildcardFind(modelRoot + "/##[ISA=ChemCompt]")) == 0:
self.modelType = ELECTRICAL
else:
self.modelType = CHEMICAL
self.model = moose.element(self.modelRoot)
if self.modelRoot != "/":
if moose.exists(modelRoot + "/data"):
self.data = moose.element(self.modelRoot + "/data")
else:
self.data = moose.Neutral(self.modelRoot + "/data")
else:
self.data = moose.element("/data")
self._layout = QVBoxLayout()
self.graphs = QSplitter()
self.graphs.setOrientation(PyQt4.QtCore.Qt.Vertical)
self.graphsArea = QScrollArea()
# self.graphsLayout = QGridLayout()
# self.menubar = self.createMenuBar()
self.rowIndex = 0
# self.setSizePolicy( QtGui.QSizePolicy.Expanding
# , QtGui.QSizePolicy.Expanding
# )
self.graphs.setSizePolicy( QtGui.QSizePolicy.Expanding
, QtGui.QSizePolicy.Expanding
)
self.setAcceptDrops(True)
# self._layout.setSizeConstraint( QLayout.SetNoConstraint )
# self.graphs.setLayout(self.graphsLayout)
self.graphsArea.setWidget(self.graphs)
self.graphsArea.setWidgetResizable(True)
self.graphWidgets = []
# self._layout.addWidget(self.menubar)
self._layout.addWidget(self.graphsArea)
self.setLayout(self._layout)
for graph in self.data.children:
self.addPlotWidget(graph = graph)
if len(self.data.children) == 0:
self.addPlotWidget()
def deleteWidget(self, graphWidget):
# print("Deleted => ", graphWidget)
self.graphWidgets.remove(graphWidget)
graphWidget.setParent(None)
graphWidget.close()
def createMenuBar(self):
bar = sidebar.sidebar()
bar.addAction(sidebar.add_graph_action(bar, lambda event: self.addPlotWidget() ))
# bar.addAction(sidebar.delete_graph_action(bar, lambda event: self.addPlotWidget() ))
# bar.addAction(sidebar.list_action(bar, self.showPlotView))
return bar
def addPlotWidget(self, row = None, col = 0, graph = None):
if graph == None:
graph = moose.Neutral(self.data.path + "/graph_" + str(self.rowIndex))
widget = default.PlotWidget(self.model, graph, self.rowIndex, self)
if self.modelType == ELECTRICAL:
for axes in widget.canvas.axes.values():
# axes.autoscale(False, axis='x', tight=True)
axes.set_ylim(bottom = -0.07, top= 0.03)
if row == None:
row = self.rowIndex
self.graphs.addWidget(widget)
self.rowIndex += 1
self.graphWidgets.append(widget)
widget.widgetClosedSignal.connect(self.deleteWidget)
widget.addGraph.connect(lambda event : self.addPlotWidget())
# widget.resize(1, 1);
return widget
def showPlotView(self):
pass
def setModelRoot(self, *args):
pass
def getMenus(self, *args):
return []
def setDataRoot(self, *args):
pass
def updatePlots(self):
for graphWidget in self.graphWidgets:
graphWidget.updatePlots()
def rescalePlots(self):
for graphWidget in self.graphWidgets:
graphWidget.rescalePlots()
def extendXAxes(self, xlim):
for graphWidget in self.graphWidgets:
graphWidget.extendXAxes(xlim)
def plotAllData(self):
for graphWidget in self.graphWidgets:
graphWidget.plotAllData()
#print(graphWidget)
# def plotAll(self):
# self.apply(lambda obj: obj.plotAll())
# def plotAllData(self):
# selt.plotWidgetContainer.plotAllData()
# def genColorMap(self,tableObject):
# pass
# def onclick(self,event1):
# pass
# def addTimeSeries(self, table, *args, **kwargs):
# pass
# def addRasterPlot(self, eventtable, yoffset=0, *args, **kwargs):
# pass
# def extendXAxes(self, xlim):
# pass
# def saveCsv(self, line,directory):
# pass
# def saveAllCsv(self):
# pass
README 0 → 100644
File: README
Author: Subhasis Ray
Created: 2012-11-29
Requirements:
Required:
PyQt4 (4.8 or higher)
numpy
matplotlib
Optional:
python-qscintilla (prettier Python shell with autocomplete)
This directory contains scripts for the MOOSE GUI.
mgui.py : main driver for the gui. This provides a main window and
basic menubar and toolbar.
plugins/ : All plugins should be added to this directory.
Each plugin should be derived from MoosePlugin in plugins/default.py.
Each plugin provides three views: EditorView, PlotView and RunView.
EditorView: the view for editing models
PlotView: this is for advanced users to select fine details of
plotting.
RunView: this view is for displaying dynamic updates when the
simulation is executed.
# moose-gui
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function
"""Sidebar for plugins. The sidebar comprises of actions.
Currently mode, connect and settings are defined.
"""
__author__ = "Aviral Goel"
__credits__ = ["Upi Lab"]
__license__ = "GPL3"
__version__ = "1.0.0"
__maintainer__ = "Aviral Goel"
__email__ = "goel.aviral@gmail.com"
__status__ = "Development"
import sys
import os
import SettingsDialog
from PyQt4 import QtGui, Qt
from PyQt4.QtGui import QWidget
from PyQt4.QtGui import QScrollArea
from PyQt4.QtGui import QGridLayout
from PyQt4.QtGui import QSplitter
class RunWidget(QSplitter):
def __init__(self, modelRoot, *args, **kwargs):
super(RunWidget, self).__init__(None)
self.modelRoot = modelRoot
layout = QGridLayout()
self.setLayout(layout)
self.plotWidgetContainer = None
def setChildWidget(self, widget, wrap, row, col, rowspan = 1, colspan = 1):
if wrap:
scrollArea = QScrollArea()
scrollArea.setWidget(widget)
scrollArea.setWidgetResizable(True);
self.layout().addWidget(scrollArea, row, col, rowspan, colspan)
else:
self.addWidget(widget)
# self.layout().addWidget(widget, row, col, rowspan, colspan)
def setPlotWidgetContainer(self, widget):
self.plotWidgetContainer = widget
def setModelRoot(self, *args):
pass
def getMenus(self, *args):
return []
def setDataRoot(self, *args):
pass
def updatePlots(self):
self.plotWidgetContainer.updatePlots()
def rescalePlots(self):
self.plotWidgetContainer.rescalePlots()
def extendXAxes(self, xlim):
self.plotWidgetContainer.extendXAxes(xlim)
def plotAllData(self):
self.plotWidgetContainer.plotAllData()
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from __future__ import print_function
"""Dialog for settings. Currently only plot settings are supported
"""
__author__ = "Aviral Goel"
__credits__ = ["Upi Lab"]
__license__ = "GPL3"
__version__ = "1.0.0"
__maintainer__ = "Aviral Goel"
__email__ = "goel.aviral@gmail.com"
__status__ = "Development"
import sys
import os
from PyQt4 import QtGui, Qt
from PyQt4.QtGui import QWidget
from PyQt4.QtGui import QLabel
from PyQt4.QtGui import QComboBox
from PyQt4.QtGui import QGridLayout
from PyQt4.QtGui import QTabWidget
class SettingsWidget(QTabWidget):
def __init__( self
, plotFieldMap
, parent = None
):
super(SettingsWidget, self).__init__(parent)
self.plotFieldMap = plotFieldMap
self.addTab(self.plotSettingsPage(),"Plot Settings");
self.addTab(self.plotSettingsPage(),"Other Settings");
def plotSettingsPage(self):
page = QWidget()
layout = QGridLayout()
page.setLayout(layout)
index = 0
for key, values in self.plotFieldMap.iteritems() :
label = QLabel(key, page)
combo = QComboBox(page)
for value in values:
combo.addItem(value)
layout.addWidget(label,index,0, Qt.Qt.AlignRight)
layout.addWidget(combo,index,1, Qt.Qt.AlignLeft)
index += 1
return page
# combo.move(50, 50)
# self.lbl.move(50, 150)
# combo.activated[str].connect(self.onActivated)
# self.setGeometry(300, 300, 300, 200)
# self.setWindowTitle('QtGui.QComboBox')
# self.show()
def main():
app = QtGui.QApplication(sys.argv)
window = QtGui.QMainWindow()
dialog = SettingsWidget({
'LeakyIaF':['Vm'],
'Compartment':['Vm','Im'],
'HHChannel':['Ik','Gk'],
'ZombiePool':['n','conc'],
'ZombieBufPool':['n','conc'],
'HHChannel2D':['Ik','Gk'],
'CaConc':['Ca']
}
)
dialog.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
all = [ "plugins" ]
<html>
<hr/>
<b align="center">MOOSE is the Multiscale Object-Oriented Simulation Environment (MOOSE)
<p> Version 3.0.2pre "Ghevar"
</b>
<hr/>
<p>Copyright (C) 2003-2016 Upinder S. Bhalla and NCBS.</p>
<p>MOOSE is released under the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.</p>
<p>MOOSE is the Multiscale Object-Oriented Simulation Environment. It is designed
to simulate neural systems ranging from subcellular components and biochemical
reactions to complex models of single neurons, circuits, and large networks.
MOOSE can operate at many levels of detail, from stochastic chemical
computations, to multicompartment single-neuron models, to spiking neuron
network models.
MOOSE is multiscale: It can do all these calculations together. For example it
handles interactions seamlessly between electrical and chemical signaling.
MOOSE is object-oriented. Biological concepts are mapped into classes, and a
model is built by creating instances of these classes and connecting them by
messages. MOOSE also has classes whose job is to take over difficult
computations in a certain domain, and do them fast. There are such solver
classes for stochastic and deterministic chemistry, for diffusion, and for
multicompartment neuronal models. MOOSE is a simulation environment, not just a
numerical engine: It provides data representations and solvers (of course!), but
also a scripting interface with Python, graphical displays with Matplotlib,
PyQt, and OpenGL, and support for many model formats. These include SBML,
NeuroML, GENESIS kkit and cell.p formats, HDF5 and NSDF for data writing.</p>
<p align="center">Home Page: <a href="http://moose.ncbs.res.in">
http://moose.ncbs.res.in</a></p>
</html>
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
# biomodelsclient.py ---
#
# Filename: biomodelsclient.py
# Description:
# Author: Subhasis Ray
# Maintainer:
# Created: Tue Mar 2 07:57:39 2010 (+0530)
# Version:
# Last-Updated: Wed Dec 11 15:47:32 2010 (+0530)
# By:
# Update #:
# URL:
# Keywords:
# Compatibility:
#
#
# Commentary:
#
# This is a client for Biomodels database SOAP service.
# It imitates the SOAP client written in JAVA
# availabele at biomodels website.
# Change log:
#
#
#
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3, or
# (at your option) any later version.
#
# 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
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street, Fifth
# Floor, Boston, MA 02110-1301, USA.
#
#
# Code:
from suds.client import Client
from suds.transport.http import HttpTransport as SudsHttpTransport
import os
import config
import pickle
import moose
BIOMODELS_WSDL_URI = 'http://www.ebi.ac.uk/biomodels-main/services/BioModelsWebServices?wsdl'
proxyOpts = dict()
for k,v in {'http':'http_proxy','https':'https_proxy'}.items():
if os.environ.has_key(v):
httpProxy = os.environ[v].replace('http://', '')
proxyOpts[k] = httpProxy[0:httpProxy.rfind('/',0,len(httpProxy))]
elif os.environ.has_key(v.upper()):
HttpProxy = os.environ[v.upper()].replace('http://', '')
proxyOpts[k] = HttpProxy[0:HttpProxy.rfind('/',0,len(HttpProxy))]
'''
class HttpTransport(SudsHttpTransport):
"""HttpTransport which properly obeys the ``*_proxy`` environment variables."""
def u2handlers(self):
return []
'''
class BioModelsClient(Client):
def __init__(self, WSDL_URI=BIOMODELS_WSDL_URI):
"""Initialize the client with the available queries listed in
the WSDL file. All the queries can be executed using the following syntax:
client.service.queryToBeExecuted()
"""
try:
Client.__init__(self, WSDL_URI,proxy=proxyOpts)
#Client.__init__(self, WSDL_URI,transport=HttpTransport())
except Exception, e:
print e
from PyQt4.Qt import Qt
from PyQt4 import QtCore, QtGui
class BioModelsClientWidget(QtGui.QDialog):
"""This is a widget with a Biomodels Client. It provides simple
access to the biomodel queries and gives the user a view of the
results"""
COMBO_ITEM_QUERY_MAP = [('All Curated Model Ids', 'getAllCuratedModelsId'),
('All Model Ids', 'getAllModelsId'),
('All Non-curated Model Ids', 'getAllNonCuratedModelsId'),
('Model Name By Id', 'getModelNameById'),
('Model Ids by ChEBI', 'getModelsIdByChEBI'),
('Model Ids by ChEBI Id', 'getModelsIdByChEBIId'),
('Model Ids by Gene Ontology Term', 'getModelsIdByGO'),
('Model Ids by Gene Ontology Id', 'getModelsIdByGOId'),
('Model Ids by Name', 'getModelsIdByName'),
('Model Ids by Author/Modeler', 'getModelsIdByPerson'),
('Model Ids by Publication', 'getModelsIdByPublication'),
('Model Ids by Taxonomy', 'getModelsIdByTaxonomy'),]
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setWindowTitle('Connect to BioModels')
self.client = BioModelsClient()
self.queryPanel = QtGui.QWidget(self)
self.queryModelLabel = QtGui.QLabel('Get ', self.queryPanel)
self.queryModelCombo = QtGui.QComboBox(self.queryPanel)
self.queryLineEdit = QtGui.QLineEdit(self.queryPanel)
self.goButton = QtGui.QPushButton('Go', self.queryPanel)
self.filePath = ''
layout = QtGui.QHBoxLayout(self.queryPanel)
layout.addWidget(self.queryModelLabel)
layout.addWidget(self.queryModelCombo)
layout.addWidget(self.queryLineEdit)
layout.addWidget(self.goButton)
self.queryPanel.setLayout(layout)
for entry in BioModelsClientWidget.COMBO_ITEM_QUERY_MAP:
self.queryModelCombo.addItem(self.tr(entry[0]), QtCore.QVariant(entry[1]))
self.resultsPanel = QtGui.QTableWidget(self)
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.queryPanel)
layout.addWidget(self.resultsPanel)
self.queryPanel1 = QtGui.QWidget(self)
self.importButton = QtGui.QPushButton('Import',self.queryPanel1)
self.importButton.setEnabled(False)
self.closeButton = QtGui.QPushButton('Close',self.queryPanel1)
hbox = QtGui.QHBoxLayout(self.queryPanel1)
hbox.addStretch(1)
hbox.addWidget(self.importButton)
hbox.addWidget(self.closeButton)
layout.addWidget(self.queryPanel1)
self.setLayout(layout)
self.setupActions()
self.client.set_options(proxy=proxyOpts)
# TODO:
# proxy = [ can be set using set_option(proxy={'http':'proxyhost:port', ...}) function
def setupActions(self):
self.connect(self.queryLineEdit, QtCore.SIGNAL('returnPressed()'), self.runQuery)
self.connect(self.goButton, QtCore.SIGNAL('clicked()'), self.runQuery)
self.connect(self.closeButton, QtCore.SIGNAL('clicked()'),self.close)
self.connect(self.importButton,QtCore.SIGNAL('clicked()'),self.downloadModel)
self.connect(self.resultsPanel, QtCore.SIGNAL('cellClicked(int,int)'),self.enableimportButton)
def closeWidget(self):
self.close()
def downloadModel(self):
"""Download the selected model"""
""" If user select multi row, only data from currentRow is downloaded and loaded into moose """
selectedRow = self.resultsPanel.currentRow()
modelId = self.resultsPanel.item(selectedRow, 0).text()
modelSBML = unicode(self.client.service.getModelSBMLById(modelId)).encode("utf-8")
self.filePath = os.path.join(config.settings[config.KEY_LOCAL_DEMOS_DIR], str(modelId)+'.xml')
f = open(str(self.filePath), 'w')
f.write(modelSBML)
self.close()
type_sbml = 'SBML'
filters = {'SBML(*.xml)': type_sbml}
filepath,filter_ = QtGui.QFileDialog.getSaveFileNameAndFilter(None,'Save File',modelId,';;'.join(filters))
if filepath:
if str(filepath).rfind('.') != -1:
filepath = filepath[:str(filepath).rfind('.')]
if str(filter_).rfind('.') != -1:
extension = filter_[str(filter_).rfind('.'):len(filter_)-1]
self.filePath = str(filepath+extension)
if filters[str(filter_)] == 'SBML':
f = open(str(self.filePath), 'w')
f.write(modelSBML)
f.close()
def getTargetPath(self):
return str(self.filePath)
def runQuery(self):
print 'Running query .....'
#self.resultsPanel.cellClicked.connect(self.enableDownload)
progressDialog = QtGui.QProgressDialog()
progressDialog.setLabelText('Retrieving data from BioModels Database')
progressDialog.setModal(True)
progressDialog.setVisible(True)
progressDialog.setWindowTitle("BioModels Database")
index = self.queryModelCombo.currentIndex()
query = self.queryModelCombo.itemData(index).toString()
argument = self.queryLineEdit.text().trimmed()
function = eval('self.client.service.' + str(query))
if index > 2:
result = function(str(argument))
else:
result = function()
self.resultsPanel.clear()
row = 0
column = 0
self.resultsPanel.setColumnCount(2)
self.resultsPanel.setHorizontalHeaderItem(column, QtGui.QTableWidgetItem('Id'))
self.resultsPanel.setHorizontalHeaderItem(column + 1, QtGui.QTableWidgetItem('Name'))
self.resultsPanel.setRowCount(0)
display = True
totalRows = 0
if type(result) is type(''):
self.resultsPanel.insertRow(row)
item = QtGui.QTableWidgetItem(argument)
item.setFlags(item.flags() & ~Qt.ItemIsEditable)
self.resultsPanel.setItem(row, column, item)
item = QtGui.QTableWidgetItem(result)
item.setFlags(item.flags() & ~Qt.ItemIsEditable)
self.resultsPanel.setItem(row, column + 1, item)
elif type(result) is type([]):
totalRows = len(result)
updatepickleFile = False
filename = str(query)
filePath = os.path.join(config.settings[config.KEY_BIOMODEL_DIR], filename+'.pkl')
#print filePath
pickleResult = {}
if os.path.isfile(filePath):
pickleFile = open(filePath,'rb')
pickleResult = pickle.load(pickleFile)
#If there is update from BioModels,then pickle file is updated.
r = 0
if progressDialog:
progressDialog.setMaximum(totalRows)
for item in result:
if item not in pickleResult:
if progressDialog:
progressDialog.setValue(r)
if progressDialog.wasCanceled():
return 0
name = unicode(self.client.service.getModelNameById(item)).encode("utf-8")
r = r+1
pickleResult.update({item:name})
updatepickleFile = True
if updatepickleFile:
output = open(os.path.join(config.settings[config.KEY_BIOMODEL_DIR], filename+'.pkl'),'wb')
pickle.dump(pickleResult,output)
output.close()
if not argument.isEmpty():
try:
name = pickleResult[str(argument)]
pickleResult = {}
pickleResult[argument] = name;
except KeyError, e:
print 'A KeyError - "%s"' % str(e) ,' not found in ',filename
QtGui.QMessageBox.critical(None, "BioModels Database"," The Id "+ str(e) +" not found in "+ filename,QtGui.QMessageBox.Ok | QtGui.QMessageBox.Default,QtGui.QMessageBox.NoButton)
display = False
if display:
for value,name in pickleResult.items():
self.resultsPanel.insertRow(row)
item = QtGui.QTableWidgetItem(self.tr(value))
item.setFlags(item.flags() & ~Qt.ItemIsEditable)
#item.setData(Qt.DisplayRole, QtCore.QVariant(value))
self.resultsPanel.setItem(row, column, item)
#name = self.client.service.getModelNameById(value)
item = QtGui.QTableWidgetItem(name)
item.setFlags(item.flags() & ~Qt.ItemIsEditable)
self.resultsPanel.setItem(row, column + 1, item)
row = row + 1
if progressDialog:
progressDialog.close()
#self.importButton.setEnabled(True)
print 'Finished running query'
def enableimportButton(self):
self.importButton.setEnabled(True)
if __name__ == '__main__':
client = BioModelsClient()
#print dir(client)
#print client.helloBioModels()
app = QtGui.QApplication([])
clientWidget = BioModelsClientWidget()
#clientWidget.exec_()
app.exec_()
#
# biomodelsclient.py ends here
# checkcombobox.py ---
#
# Filename: checkcombobox.py
# Description:
# Author:
# Maintainer:
# Created: Wed Jun 5 15:06:21 2013 (+0530)
# Version:
# Last-Updated: Wed Jun 5 18:42:50 2013 (+0530)
# By: subha
# Update #: 188
# URL:
# Keywords:
# Compatibility:
#
#
# Commentary:
#
# ComboBox with checkable items. Inspired by the same in libqxt.
#
#
# Change log:
#
#
#
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation; either version 3, or
# (at your option) any later version.
#
# 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
# General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; see the file COPYING. If not, write to
# the Free Software Foundation, Inc., 51 Franklin Street, Fifth
# Floor, Boston, MA 02110-1301, USA.
#
#
# Code:
import sys
from PyQt4 import QtCore, QtGui
from PyQt4.Qt import Qt
from collections import defaultdict
class CheckComboBoxModel(QtGui.QStandardItemModel):
"""This is inspired by Qxt library."""
checkStateChange = QtCore.pyqtSignal(name='checkStateChanged')
def __init__(self, *args):
QtGui.QStandardItemModel.__init__(self, *args)
self.checked_dict = defaultdict(int)
def flags(self, index):
return Qt.ItemIsUserCheckable | Qt.ItemIsSelectable | Qt.ItemIsEnabled
def data(self, index, role):
if index.isValid() and role == Qt.CheckStateRole:
return QtCore.QVariant(self.checked_dict[index])
else:
return QtGui.QStandardItemModel.data(self, index, role)
def setData(self, index, value, role=Qt.EditRole):
if not index.isValid():
return False
ok = QtGui.QStandardItemModel.setData(self, index, value, role)
if ok and role == Qt.CheckStateRole:
self.checked_dict[index] = value.toInt()[0]
self.dataChanged.emit(index, index)
self.checkStateChange.emit()
return ok
class ComboEventFilter(QtCore.QObject):
"""Event filter for CheckComboBox - inspired by Qxt library"""
def __init__(self, parent):
QtCore.QObject.__init__(self, parent)
def eventFilter(self, obj, event):
etype = event.type()
if etype == event.KeyPress or etype == event.KeyRelease:
if obj == self and \
(event.key() == Qt.Key_UP or
event.key() == Qt.Key_Down):
self.parent().showPopup()
return True
elif event.key() == Qt.Key_Enter or \
event.key() == Qt.Key_Return or \
event.key() == Qt.Key_Escape:
QtGui.QComboBox.hidePopup(self.parent())
if event.key() != Qt.Key_Escape:
return True
elif etype == event.MouseButtonPress:
self.parent()._containerMousePress = (obj == self.parent().view().window())
elif etype == event.MouseButtonRelease:
self.parent()._containerMousePress = False
return False
class CheckComboBox(QtGui.QComboBox):
"""Specialization of QComboBox to allow checkable items. This is
inspired by the same class in Qxt"""
def __init__(self, *args):
QtGui.QComboBox.__init__(self, *args)
self._containerMousePress = False
self.setModel(CheckComboBoxModel())
self.activated.connect(self.toggleCheckState)
self.ef = ComboEventFilter(self)
self.view().installEventFilter(self.ef)
self.view().window().installEventFilter(self.ef)
self.view().viewport().installEventFilter(self.ef)
self.installEventFilter(self.ef)
def hidePopup(self):
"""This is to disable hiding of the popup when an item is clicked."""
if self._containerMousePress:
QtGui.QComboBox.hidePopup(self)
def itemCheckState(self, index):
return self.itemData(index, Qt.CheckStateRole).toInt()[0]
def setItemCheckState(self, index, state):
self.setItemData(index, QtCore.QVariant(state), QtCore.Qt.CheckStateRole)
def checkedItems(self):
index = self.model().index(0,0)
checked = self.model().match(index, Qt.CheckStateRole, Qt.Checked, -1, Qt.MatchExactly)
return [index.data().toString() for index in checked]
def setCheckedItems(self, textItemList):
for text in textItemList:
index = self.findText(text)
if index.isValid():
self.setItemCheckState(index, Qt.Checked)
else:
self.setItemCheckState(index, Qt.Unchecked)
def toggleCheckState(self, index):
value = self.itemData(index, Qt.CheckStateRole)
if value.isValid():
state = value.toInt()[0]
if state == Qt.Checked:
self.setItemData(index, Qt.Unchecked, Qt.CheckStateRole)
else:
self.setItemData(index, Qt.Checked, Qt.CheckStateRole)
def main():
"""Test main: load a model and display the tree for it"""
app = QtGui.QApplication([])
mainwin = QtGui.QMainWindow()
mainwin.setWindowTitle('CheckComboBox test')
box = CheckComboBox()
for ii in range(5):
box.addItem('myitem_%d' % (ii))
mainwin.setCentralWidget(box)
mainwin.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
#
# checkcombobox.py ends here
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment