1 | # global |
---|
2 | import logging |
---|
3 | from periodictable import formula as Formula |
---|
4 | |
---|
5 | from PyQt4 import QtGui, QtCore |
---|
6 | |
---|
7 | # Local UI |
---|
8 | from UI.DensityPanel import Ui_DensityPanel |
---|
9 | |
---|
10 | def enum(*sequential, **named): |
---|
11 | enums = dict(zip(sequential, range(len(sequential))), **named) |
---|
12 | return type('Enum', (), enums) |
---|
13 | |
---|
14 | MODEL = enum( |
---|
15 | 'MOLECULAR_FORMULA', |
---|
16 | 'MOLAR_MASS', |
---|
17 | 'MOLAR_VOLUME', |
---|
18 | 'MASS_DENSITY', |
---|
19 | ) |
---|
20 | |
---|
21 | MODES = enum( |
---|
22 | 'VOLUME_TO_DENSITY', |
---|
23 | 'DENSITY_TO_VOLUME', |
---|
24 | ) |
---|
25 | |
---|
26 | def toMolarMass(formula): |
---|
27 | AVOGADRO = 6.02214129e23 |
---|
28 | |
---|
29 | try: |
---|
30 | f = Formula(str(formula)) |
---|
31 | return "%g" % (f.molecular_mass * AVOGADRO) |
---|
32 | except: |
---|
33 | return "" |
---|
34 | |
---|
35 | |
---|
36 | class FormulaValidator(QtGui.QValidator): |
---|
37 | def __init__(self, parent=None): |
---|
38 | super(FormulaValidator, self).__init__(parent) |
---|
39 | |
---|
40 | def validate(self, input, pos): |
---|
41 | try: |
---|
42 | Formula(str(input)) |
---|
43 | self._setStyleSheet("") |
---|
44 | return QtGui.QValidator.Acceptable, pos |
---|
45 | |
---|
46 | except Exception as e: |
---|
47 | self._setStyleSheet("background-color:pink;") |
---|
48 | return QtGui.QValidator.Intermediate, pos |
---|
49 | |
---|
50 | def _setStyleSheet(self, value): |
---|
51 | try: |
---|
52 | if self.parent(): |
---|
53 | self.parent().setStyleSheet(value) |
---|
54 | except: |
---|
55 | pass |
---|
56 | |
---|
57 | |
---|
58 | class DensityPanel(QtGui.QDialog): |
---|
59 | |
---|
60 | def __init__(self, parent=None): |
---|
61 | super(DensityPanel, self).__init__(parent) |
---|
62 | |
---|
63 | self.mode = None |
---|
64 | |
---|
65 | self.setupUi() |
---|
66 | self.setupModel() |
---|
67 | self.setupMapper() |
---|
68 | |
---|
69 | def setupUi(self): |
---|
70 | self.ui = Ui_DensityPanel() |
---|
71 | self.ui.setupUi(self) |
---|
72 | |
---|
73 | # set validators |
---|
74 | self.ui.editMolecularFormula.setValidator(FormulaValidator(self.ui.editMolecularFormula)) |
---|
75 | |
---|
76 | rx = QtCore.QRegExp("[+\-]?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][+\-]?\d+)?") |
---|
77 | self.ui.editMolarVolume.setValidator(QtGui.QRegExpValidator(rx, self.ui.editMolarVolume)) |
---|
78 | self.ui.editMassDensity.setValidator(QtGui.QRegExpValidator(rx, self.ui.editMassDensity)) |
---|
79 | |
---|
80 | # signals |
---|
81 | QtCore.QObject.connect( |
---|
82 | self.ui.editMolarVolume, |
---|
83 | QtCore.SIGNAL("textEdited(QString)"), |
---|
84 | lambda text: self.setMode(MODES.VOLUME_TO_DENSITY)) |
---|
85 | QtCore.QObject.connect( |
---|
86 | self.ui.editMassDensity, |
---|
87 | QtCore.SIGNAL("textEdited(QString)"), |
---|
88 | lambda text: self.setMode(MODES.DENSITY_TO_VOLUME)) |
---|
89 | QtCore.QObject.connect( |
---|
90 | self.ui.buttonBox.button(QtGui.QDialogButtonBox.Reset), |
---|
91 | QtCore.SIGNAL("clicked(bool)"), |
---|
92 | lambda checked: self.modelReset()) |
---|
93 | |
---|
94 | def setupModel(self): |
---|
95 | self.model = QtGui.QStandardItemModel(self) |
---|
96 | self.model.setItem(MODEL.MOLECULAR_FORMULA, QtGui.QStandardItem()) |
---|
97 | self.model.setItem(MODEL.MOLAR_MASS , QtGui.QStandardItem()) |
---|
98 | self.model.setItem(MODEL.MOLAR_VOLUME , QtGui.QStandardItem()) |
---|
99 | self.model.setItem(MODEL.MASS_DENSITY , QtGui.QStandardItem()) |
---|
100 | |
---|
101 | QtCore.QObject.connect( |
---|
102 | self.model, |
---|
103 | QtCore.SIGNAL("dataChanged(QModelIndex,QModelIndex)"), |
---|
104 | self.dataChanged) |
---|
105 | |
---|
106 | self.modelReset() |
---|
107 | |
---|
108 | def setupMapper(self): |
---|
109 | self.mapper = QtGui.QDataWidgetMapper(self) |
---|
110 | self.mapper.setModel(self.model) |
---|
111 | self.mapper.setOrientation(QtCore.Qt.Vertical) |
---|
112 | |
---|
113 | self.mapper.addMapping(self.ui.editMolecularFormula, MODEL.MOLECULAR_FORMULA) |
---|
114 | self.mapper.addMapping(self.ui.editMolarMass , MODEL.MOLAR_MASS) |
---|
115 | self.mapper.addMapping(self.ui.editMolarVolume , MODEL.MOLAR_VOLUME) |
---|
116 | self.mapper.addMapping(self.ui.editMassDensity , MODEL.MASS_DENSITY) |
---|
117 | |
---|
118 | self.mapper.toFirst() |
---|
119 | |
---|
120 | def dataChanged(self, top, bottom): |
---|
121 | for index in xrange(top.row(), bottom.row() + 1): |
---|
122 | if index == MODEL.MOLECULAR_FORMULA: |
---|
123 | molarMass = toMolarMass(self.model.item(MODEL.MOLECULAR_FORMULA).text()) |
---|
124 | self.model.item(MODEL.MOLAR_MASS).setText(molarMass) |
---|
125 | |
---|
126 | if self.mode == MODES.VOLUME_TO_DENSITY: |
---|
127 | self._updateDensity() |
---|
128 | elif self.mode == MODES.DENSITY_TO_VOLUME: |
---|
129 | self._updateVolume() |
---|
130 | |
---|
131 | elif index == MODEL.MOLAR_VOLUME and self.mode == MODES.VOLUME_TO_DENSITY: |
---|
132 | self._updateDensity() |
---|
133 | |
---|
134 | elif index == MODEL.MASS_DENSITY and self.mode == MODES.DENSITY_TO_VOLUME: |
---|
135 | self._updateVolume() |
---|
136 | |
---|
137 | def setMode(self, mode): |
---|
138 | self.mode = mode |
---|
139 | |
---|
140 | def _updateDensity(self): |
---|
141 | try: |
---|
142 | molarMass = float(toMolarMass(self.model.item(MODEL.MOLECULAR_FORMULA).text())) |
---|
143 | molarVolume = float(self.model.item(MODEL.MOLAR_VOLUME).text()) |
---|
144 | |
---|
145 | molarDensity = molarMass / molarVolume |
---|
146 | self.model.item(MODEL.MASS_DENSITY).setText(str(molarDensity)) |
---|
147 | |
---|
148 | except: |
---|
149 | self.model.item(MODEL.MASS_DENSITY).setText("") |
---|
150 | |
---|
151 | def _updateVolume(self): |
---|
152 | try: |
---|
153 | molarMass = float(toMolarMass(self.model.item(MODEL.MOLECULAR_FORMULA).text())) |
---|
154 | molarDensity = float(self.model.item(MODEL.MASS_DENSITY).text()) |
---|
155 | |
---|
156 | molarVolume = molarMass / molarDensity |
---|
157 | self.model.item(MODEL.MOLAR_VOLUME).setText(str(molarVolume)) |
---|
158 | |
---|
159 | except: |
---|
160 | self.model.item(MODEL.MOLAR_VOLUME).setText("") |
---|
161 | |
---|
162 | def modelReset(self): |
---|
163 | #self.model.beginResetModel() |
---|
164 | try: |
---|
165 | self.setMode(None) |
---|
166 | self.model.item(MODEL.MOLECULAR_FORMULA).setText("H2O") |
---|
167 | self.model.item(MODEL.MOLAR_VOLUME ).setText("") |
---|
168 | self.model.item(MODEL.MASS_DENSITY ).setText("") |
---|
169 | finally: |
---|
170 | pass |
---|
171 | #self.model.endResetModel() |
---|