Source code for PyMca5.PyMcaGui.physics.xrf.AttenuatorsTable
#/*##########################################################################
#
# The PyMca X-Ray Fluorescence Toolkit
#
# Copyright (c) 2004-2014 European Synchrotron Radiation Facility
#
# This file is part of the PyMca X-ray Fluorescence Toolkit developed at
# the ESRF by the Software group.
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
#
#############################################################################*/
__author__ = "V. Armando Sole - ESRF Data Analysis"
__contact__ = "sole@esrf.fr"
__license__ = "MIT"
__copyright__ = "European Synchrotron Radiation Facility, Grenoble, France"
import sys
from PyMca5.PyMcaGui import PyMcaQt as qt
QTVERSION = qt.qVersion()
qt.QLabel.AlignRight = qt.Qt.AlignRight
qt.QLabel.AlignCenter = qt.Qt.AlignCenter
qt.QLabel.AlignVCenter = qt.Qt.AlignVCenter
[docs]class Q3GridLayout(qt.QGridLayout):
[docs] def addMultiCellWidget(self, w, r0, r1, c0, c1, *var):
self.addWidget(w, r0, c0, 1 + r1 - r0, 1 + c1 - c0)
from PyMca5.PyMcaPhysics import Elements
from . import MaterialEditor
from . import MatrixEditor
import re
DEBUG = 0
[docs]class MyQLabel(qt.QLabel):
def __init__(self, parent=None, name=None, fl=0, bold=True,
color= qt.Qt.red):
qt.QLabel.__init__(self, parent)
palette = self.palette()
role = self.foregroundRole()
palette.setColor(role, color)
self.setPalette(palette)
self.font().setBold(bold)
[docs]class AttenuatorsTab(qt.QWidget):
def __init__(self, parent=None, name="Attenuators Tab",
attenuators=None, graph=None):
qt.QWidget.__init__(self, parent)
layout = qt.QVBoxLayout(self)
maxheight = qt.QDesktopWidget().height()
if maxheight < 800:
layout.setContentsMargins(0, 0, 0, 0)
layout.setSpacing(2)
self.table = AttenuatorsTableWidget(self, name, attenuators,
funnyfilters=True)
layout.addWidget(self.table)
self.mainTab = qt.QTabWidget(self)
layout.addWidget(self.mainTab)
rheight = self.table.horizontalHeader().sizeHint().height()
if maxheight < 801:
self.editor = MaterialEditor.MaterialEditor(height=5,
graph=graph)
self.table.setMinimumHeight(7 * rheight)
self.table.setMaximumHeight(13 * rheight)
else:
spacer = qt.VerticalSpacer(self)
layout.addWidget(spacer)
self.editor = MaterialEditor.MaterialEditor(graph=graph)
self.table.setMinimumHeight(13*rheight)
self.table.setMaximumHeight(13*rheight)
self.mainTab.addTab(self.editor, "Material Editor")
[docs]class MultilayerTab(qt.QWidget):
def __init__(self,parent=None, name="Multilayer Tab", matrixlayers=None):
if matrixlayers is None:
matrixlayers=["Layer0", "Layer1", "Layer2", "Layer3",
"Layer4", "Layer5", "Layer6", "Layer7",
"Layer8", "Layer9"]
qt.QWidget.__init__(self, parent)
layout = qt.QVBoxLayout(self)
self.matrixGeometry = MatrixEditor.MatrixEditor(self, "tabMatrix",
table=False, orientation="horizontal",
density=False, thickness=False,
size="image2")
layout.addWidget(self.matrixGeometry)
text = "This matrix definition will only be "
text += "considered if Matrix is selected and material is set to "
text += "MULTILAYER in the ATTENUATORS tab.\n "
self.matrixInfo = qt.QLabel(self)
layout.addWidget(self.matrixInfo)
self.matrixInfo.setText(text)
self.matrixTable = AttenuatorsTableWidget(self, name,
attenuators=matrixlayers,
matrixmode=True)
layout.addWidget(self.matrixTable)
[docs]class CompoundFittingTab(qt.QWidget):
def __init__(self, parent=None, name="Compound Tab",
layerlist=None):
qt.QWidget.__init__(self, parent)
if layerlist is None:
self.nlayers = 5
else:
self.nlayers = len(layerlist)
layout = qt.QVBoxLayout(self)
hbox = qt.QWidget(self)
hboxlayout = qt.QHBoxLayout(hbox)
#hboxlayout.addWidget(qt.HorizontalSpacer(hbox))
self._compoundFittingLabel = MyQLabel(hbox, color=qt.Qt.red)
self._compoundFittingLabel.setText("Compound Fitting Mode is OFF")
self._compoundFittingLabel.setAlignment(qt.QLabel.AlignCenter)
hboxlayout.addWidget(self._compoundFittingLabel)
#hboxlayout.addWidget(qt.HorizontalSpacer(hbox))
layout.addWidget(hbox)
grid = qt.QWidget(self)
glt = Q3GridLayout(grid)
glt.setContentsMargins(11, 11, 11, 11)
glt.setSpacing(2)
self._layerFlagWidgetList = []
options = ["FREE", "FIXED", "IGNORED"]
for i in range(self.nlayers):
r = int(i / 5)
c = 3 * (i % 5)
label = qt.QLabel(grid)
label.setText("Layer%d" % i)
cbox = qt.QComboBox(grid)
for item in options:
cbox.addItem(item)
if i == 0:
cbox.setCurrentIndex(0)
else:
cbox.setCurrentIndex(1)
glt.addWidget(label, r, c)
glt.addWidget(cbox, r, c + 1)
glt.addWidget(qt.QWidget(grid), r, c + 2)
layout.addWidget(grid)
self.mainTab = qt.QTabWidget(self)
layout.addWidget(self.mainTab)
self._editorList = []
for i in range(self.nlayers):
editor = CompoundFittingTab0(layerindex=i)
self.mainTab.addTab(editor, "layer Editor")
self._editorList.append(editor)
[docs]class CompoundFittingTab0(qt.QWidget):
def __init__(self, parent=None, name="Compound Tab",
layerindex=None, compoundlist=None):
if layerindex is None:
layerindex = 0
if compoundlist is None:
compoundlist = []
for i in range(10):
compoundlist.append("Compound%d%d" % (layerindex, i))
qt.QWidget.__init__(self, parent)
layout = qt.QVBoxLayout(self)
grid = qt.QWidget(self)
gl = Q3GridLayout(grid)
gl.setContentsMargins(11, 11, 11, 11)
gl.setSpacing(2)
# Layer name
nameLabel = qt.QLabel(grid)
nameLabel.setText("Name")
self.nameLine = qt.QLineEdit(grid)
self.nameLine.setText("Compound fitting layer %d" % layerindex)
gl.addWidget(nameLabel, 0, 0)
gl.addMultiCellWidget(self.nameLine, 0, 0, 1, 5)
Line = qt.QFrame(grid)
Line.setFrameShape(qt.QFrame.HLine)
Line.setFrameShadow(qt.QFrame.Sunken)
Line.setFrameShape(qt.QFrame.HLine)
gl.addMultiCellWidget(Line, 1, 1, 0, 5)
#labels
fixedLabel = qt.QLabel(grid)
fixedLabel_font = qt.QFont(fixedLabel.font())
fixedLabel_font.setItalic(1)
fixedLabel.setFont(fixedLabel_font)
fixedLabel.setText(str("Fixed"))
fixedLabel.setAlignment(qt.Qt.AlignVCenter)
valueLabel = qt.QLabel(grid)
valueLabel_font = qt.QFont(valueLabel.font())
valueLabel_font.setItalic(1)
valueLabel.setFont(valueLabel_font)
valueLabel.setText(str("Value"))
valueLabel.setAlignment(qt.QLabel.AlignCenter)
errorLabel = qt.QLabel(grid)
errorLabel_font = qt.QFont(errorLabel.font())
errorLabel_font.setItalic(1)
errorLabel.setFont(errorLabel_font)
errorLabel.setText(str("Error"))
errorLabel.setAlignment(qt.QLabel.AlignCenter)
gl.addWidget(fixedLabel, 2, 2)
gl.addWidget(valueLabel, 2, 3)
gl.addWidget(errorLabel, 2, 5)
#density
densityLabel = qt.QLabel(grid)
densityLabel.setText("Density")
self.densityCheck = qt.QCheckBox(grid)
self.densityCheck.setText(str(""))
self.densityValue = qt.QLineEdit(grid)
densitySepLabel = qt.QLabel(grid)
densitySepLabel_font = qt.QFont(densitySepLabel.font())
densitySepLabel_font.setBold(1)
densitySepLabel.setFont(densitySepLabel_font)
densitySepLabel.setText(str("+/-"))
self.densityError = qt.QLineEdit(grid)
gl.addWidget(densityLabel, 3, 0)
gl.addWidget(qt.HorizontalSpacer(grid), 3, 1)
gl.addWidget(self.densityCheck, 3, 2)
gl.addWidget(self.densityValue, 3, 3)
gl.addWidget(densitySepLabel, 3, 4)
gl.addWidget(self.densityError, 3, 5)
#thickness
thicknessLabel = qt.QLabel(grid)
thicknessLabel.setText("Thickness")
self.thicknessCheck = qt.QCheckBox(grid)
self.thicknessCheck.setText(str(""))
self.thicknessValue = qt.QLineEdit(grid)
thicknessSepLabel = qt.QLabel(grid)
thicknessSepLabel_font = qt.QFont(thicknessSepLabel.font())
thicknessSepLabel_font.setBold(1)
thicknessSepLabel.setFont(thicknessSepLabel_font)
thicknessSepLabel.setText(str("+/-"))
self.thicknessError = qt.QLineEdit(grid)
gl.addWidget(thicknessLabel, 4, 0)
gl.addWidget(self.thicknessCheck, 4, 2)
gl.addWidget(self.thicknessValue, 4, 3)
gl.addWidget(thicknessSepLabel, 4, 4)
gl.addWidget(self.thicknessError, 4, 5)
Line = qt.QFrame(grid)
Line.setFrameShape(qt.QFrame.HLine)
Line.setFrameShadow(qt.QFrame.Sunken)
Line.setFrameShape(qt.QFrame.HLine)
gl.addMultiCellWidget(Line, 5, 5, 0, 5)
layout.addWidget(grid)
"""
self.matrixGeometry = MatrixEditor.MatrixEditor(self,"tabMatrix",
table=False, orientation="horizontal",
density=False, thickness=False,
size="image2")
layout.addWidget(self.matrixGeometry)
text ="This matrix definition will only be "
text +="considered if Matrix is selected and material is set to "
text +="MULTILAYER in the ATTENUATORS tab.\n "
self.matrixInfo = qt.QLabel(self)
layout.addWidget(self.matrixInfo)
self.matrixInfo.setText(text)
"""
self.matrixTable = AttenuatorsTableWidget(self, name,
attenuators=compoundlist,
matrixmode=False,
compoundmode=True,
layerindex=layerindex)
layout.addWidget(self.matrixTable)
QTable = qt.QTableWidget
[docs]class AttenuatorsTableWidget(QTable):
sigValueChanged = qt.pyqtSignal(int, int)
def __init__(self, parent=None, name="Attenuators Table",
attenuators=None, matrixmode=None, compoundmode=None,
layerindex=0, funnyfilters=False):
attenuators0 = ["Atmosphere", "Air", "Window", "Contact", "DeadLayer",
"Filter5", "Filter6", "Filter7", "BeamFilter1",
"BeamFilter2", "Detector", "Matrix"]
QTable.__init__(self, parent)
self.setWindowTitle(name)
if attenuators is None:
attenuators = attenuators0
if matrixmode is None:
matrixmode = False
if matrixmode:
self.compoundMode = False
elif compoundmode is None:
self.compoundMode = False
else:
self.compoundMode = compoundmode
if funnyfilters is None:
funnyfilters = False
self.funnyFiltersMode = funnyfilters
if self.compoundMode:
self.funnyFiltersMode = False
labels = ["Compound", "Name", "Material", "Initial Amount"]
else:
if self.funnyFiltersMode:
labels = ["Attenuator", "Name", "Material",
"Density (g/cm3)", "Thickness (cm)", "Funny Factor"]
else:
labels = ["Attenuator", "Name", "Material",
"Density (g/cm3)", "Thickness (cm)"]
self.layerindex = layerindex
self.matrixMode = matrixmode
self.attenuators = attenuators
self.verticalHeader().hide()
if DEBUG:
print("margin to adjust")
print("focus style")
self.setFrameShape(qt.QTableWidget.NoFrame)
self.setSelectionMode(qt.QTableWidget.NoSelection)
self.setColumnCount(len(labels))
for i in range(len(labels)):
item = self.horizontalHeaderItem(i)
if item is None:
item = qt.QTableWidgetItem(labels[i],
qt.QTableWidgetItem.Type)
item.setText(labels[i])
self.setHorizontalHeaderItem(i,item)
if self.matrixMode:
self.__build(len(attenuators))
elif self.compoundMode:
self.__build(len(attenuators))
else:
self.__build(len(attenuators0))
#self.adjustColumn(0)
if self.matrixMode:
item = self.horizontalHeaderItem(0)
item.setText('Layer')
self.setHorizontalHeaderItem(0, item)
if self.compoundMode:
self.resizeColumnToContents(0)
self.resizeColumnToContents(1)
self.sigValueChanged[int,int].connect(self.mySlot)
def __build(self, nfilters=12):
n = 0
if (not self.matrixMode) and (not self.compoundMode):
n = 4
#self.setNumRows(nfilters+n)
self.setRowCount(12)
else:
self.setRowCount(nfilters)
rheight = self.horizontalHeader().sizeHint().height()
for idx in range(self.rowCount()):
self.setRowHeight(idx, rheight)
self.comboList = []
matlist = list(Elements.Material.keys())
matlist.sort()
if self.matrixMode or self.compoundMode:
if self.matrixMode:
roottext = "Layer"
else:
roottext = "Compound%d" % self.layerindex
a = []
#a.append('')
for key in matlist:
a.append(key)
for idx in range(self.rowCount()):
item= qt.QCheckBox(self)
self.setCellWidget(idx, 0, item)
text = roottext+"%d" % idx
item.setText(text)
item = self.item(idx, 1)
if item is None:
item = qt.QTableWidgetItem(text,
qt.QTableWidgetItem.Type)
self.setItem(idx, 1, item)
else:
item.setText(text)
item.setFlags(qt.Qt.ItemIsSelectable|
qt.Qt.ItemIsEnabled)
combo = MyQComboBox(self, options=a, row = idx, col = 2)
combo.setEditable(True)
self.setCellWidget(idx, 2, combo)
combo.sigMaterialComboBoxSignal.connect(self._comboSlot)
return
selfnumRows = self.rowCount()
for idx in range(selfnumRows - n):
text = "Filter% 2d" % idx
item = qt.QCheckBox(self)
self.setCellWidget(idx, 0, item)
item.setText(text)
if idx < len(self.attenuators):
text = self.attenuators[idx]
item = self.item(idx, 1)
if item is None:
item = qt.QTableWidgetItem(text,
qt.QTableWidgetItem.Type)
self.setItem(idx, 1, item)
else:
item.setText(text)
#a = qt.QStringList()
a = []
#a.append('')
for key in matlist:
a.append(key)
combo = MyQComboBox(self, options=a, row=idx, col = 2)
combo.setEditable(True)
self.setCellWidget(idx, 2, combo)
#self.setItem(idx,2,combo)
combo.sigMaterialComboBoxSignal.connect(self._comboSlot)
for i in range(2):
#BeamFilter(i)
item = qt.QCheckBox(self)
idx = self.rowCount() - (4 - i)
self.setCellWidget(idx, 0, item)
text = "BeamFilter%d" % i
item.setText(text)
item = self.item(idx,1)
if item is None:
item = qt.QTableWidgetItem(text,
qt.QTableWidgetItem.Type)
self.setItem(idx, 1, item)
else:
item.setText(text)
item.setFlags(qt.Qt.ItemIsSelectable|
qt.Qt.ItemIsEnabled)
text = "1.0"
item = self.item(idx, 5)
if item is None:
item = qt.QTableWidgetItem(text,
qt.QTableWidgetItem.Type)
self.setItem(idx, 5, item)
else:
item.setText(text)
item.setFlags(qt.Qt.ItemIsSelectable|
qt.Qt.ItemIsEnabled)
combo = MyQComboBox(self, options=a, row=idx, col=2)
combo.setEditable(True)
self.setCellWidget(idx, 2, combo)
combo.sigMaterialComboBoxSignal.connect(self._comboSlot)
#Detector
item = qt.QCheckBox(self)
idx = self.rowCount() - 2
self.setCellWidget(idx, 0, item)
text = "Detector"
item.setText(text)
item = self.item(idx,1)
if item is None:
item = qt.QTableWidgetItem(text,
qt.QTableWidgetItem.Type)
self.setItem(idx, 1, item)
else:
item.setText(text)
item.setFlags(qt.Qt.ItemIsSelectable | qt.Qt.ItemIsEnabled)
text = "1.0"
item = self.item(idx, 5)
if item is None:
item = qt.QTableWidgetItem(text,
qt.QTableWidgetItem.Type)
self.setItem(idx, 5, item)
else:
item.setText(text)
item.setFlags(qt.Qt.ItemIsSelectable | qt.Qt.ItemIsEnabled)
combo = MyQComboBox(self, options=a, row=idx, col=2)
combo.setEditable(True)
self.setCellWidget(idx, 2, combo)
#Matrix
item = qt.QCheckBox(self)
idx = self.rowCount() - 1
self.setCellWidget(idx, 0, item)
text = "Matrix"
item.setText(text)
item = self.item(idx, 1)
if item is None:
item = qt.QTableWidgetItem(text,
qt.QTableWidgetItem.Type)
self.setItem(idx, 1, item)
else:
item.setText(text)
item.setFlags(qt.Qt.ItemIsSelectable |qt.Qt.ItemIsEnabled)
text = "1.0"
item = self.item(idx, 5)
if item is None:
item = qt.QTableWidgetItem(text,
qt.QTableWidgetItem.Type)
self.setItem(idx, 5, item)
else:
item.setText(text)
item.setFlags(qt.Qt.ItemIsSelectable | qt.Qt.ItemIsEnabled)
combo.sigMaterialComboBoxSignal.connect(self._comboSlot)
#a = qt.QStringList()
a = []
#a.append('')
for key in matlist:
a.append(key)
#combo = qttable.QComboTableItem(self,a)
self.combo = MyQComboBox(self, options=a, row=idx, col=2)
self.setCellWidget(idx, 2, self.combo)
self.combo.sigMaterialComboBoxSignal.connect(self._comboSlot)
[docs] def mySlot(self,row,col):
if DEBUG:
print("Value changed row = %d cole = &d" % (row, col))
print("Text = %s" % self.text(row, col))
def _comboSlot(self, ddict):
if DEBUG:
print("_comboSlot", ddict)
row = ddict['row']
col = ddict['col']
text = ddict['text']
self.setCurrentCell(row, col)
self._checkDensityThickness(text, row)
self.sigValueChanged.emit(row, col)
[docs] def text(self, row, col):
if col == 2:
return self.cellWidget(row, col).currentText()
else:
if col not in [1, 3, 4, 5]:
print("row, col = %d, %d" % (row, col))
print("I should not be here")
else:
item = self.item(row, col)
return item.text()
[docs] def setText(self, row, col, text):
if col == 0:
self.cellWidget(row, 0).setText(text)
return
if col not in [1, 3, 4, 5]:
print("only compatible columns 1, 3 and 4")
raise ValueError("method for column > 2")
item = self.item(row, col)
if item is None:
item = qt.QTableWidgetItem(text,
qt.QTableWidgetItem.Type)
self.setItem(row, col, item)
else:
item.setText(text)
def _checkDensityThickness(self, text, row):
try:
currentDensity = float(str(self.text(row, 3)))
except:
currentDensity = 0.0
try:
currentThickness = float(str(self.text(row, 4)))
except:
currentThickness = 0.0
defaultDensity = -1.0
defaultThickness = -0.1
#check if default density is there
if Elements.isValidFormula(text):
#check if single element
if text in Elements.Element.keys():
defaultDensity = Elements.Element[text]['density']
else:
elts = [ w for w in re.split('[0-9]', text) if w != '']
nbs = [ int(w) for w in re.split('[a-zA-Z]', text) if w != '']
if len(elts) == 1 and len(nbs) == 1:
defaultDensity = Elements.Element[elts[0]]['density']
elif Elements.isValidMaterial(text):
key = Elements.getMaterialKey(text)
if key is not None:
if 'Density' in Elements.Material[key]:
defaultDensity = Elements.Material[key]['Density']
if 'Thickness' in Elements.Material[key]:
defaultThickness = Elements.Material[key]['Thickness']
if defaultDensity >= 0.0:
self.setText(row, 3, "%g" % defaultDensity)
elif currentDensity <= 0:
# should not be better to raise an exception if the
# entered density or thickness were negative?
self.setText(row, 3, "%g" % 1.0)
if defaultThickness >= 0.0:
self.setText(row, 4, "%g" % defaultThickness)
elif currentThickness <= 0.0:
# should not be better to raise an exception if the
# entered density or thickness were negative?
self.setText(row, 4, "%g" % 0.1)
[docs]class MyQComboBox(MaterialEditor.MaterialComboBox):
def _mySignal(self, qstring0):
qstring = qstring0
(result, index) = self.ownValidator.validate(qstring, 0)
if result != self.ownValidator.Valid:
qstring = self.ownValidator.fixup(qstring)
(result, index) = self.ownValidator.validate(qstring,0)
if result != self.ownValidator.Valid:
text = str(qstring)
if text.upper() != "MULTILAYER":
qt.QMessageBox.critical(self, "Invalid Material '%s'" % text,
"The material '%s' is not a valid Formula " \
"nor a valid Material.\n" \
"Please define the material %s or correct the formula\n" % \
(text, text))
self.setCurrentIndex(0)
for i in range(self.count()):
selftext = self.itemText(i)
if selftext == qstring0:
self.removeItem(i)
break
return
text = str(qstring)
self.setCurrentText(text)
ddict = {}
ddict['event'] = 'activated'
ddict['row'] = self.row
ddict['col'] = self.col
ddict['text'] = text
if qstring0 != qstring:
self.removeItem(self.count() - 1)
insert = True
for i in range(self.count()):
selftext = self.itemText(i)
if qstring == selftext:
insert = False
if insert:
self.insertItem(-1, qstring)
# signal defined in the superclass.
self.sigMaterialComboBoxSignal.emit(ddict)
[docs]def main(args):
app = qt.QApplication(args)
#tab = AttenuatorsTableWidget(None)
if len(args) < 2:
tab = AttenuatorsTab(None)
elif len(args) > 3:
tab = CompoundFittingTab(None)
else:
tab = MultilayerTab(None)
tab.show()
app.exec_()
if __name__=="__main__":
main(sys.argv)