File indexing completed on 2022-11-29 18:12:01

0001 /*
0002     SPDX-FileCopyrightText: 2003-2005, 2006 Carsten Niehaus <cniehaus@kde.org>
0003     SPDX-FileCopyrightText: 2005 Inge Wallin <inge@lysator.liu.se>
0004     SPDX-FileCopyrightText: 2009 Kashyap. R. Puranik <kashthealien@gmail.com>
0005 
0006     SPDX-License-Identifier: GPL-2.0-or-later
0007 */
0008 
0009 #include "molcalcwidget.h"
0010 
0011 // libscience
0012 #include <element.h>
0013 
0014 #include "kalziumdataobject.h"
0015 #include "kalziumutils.h"
0016 #include "prefs.h"
0017 #include "search.h"
0018 
0019 #include "kalzium_debug.h"
0020 #include <QFile>
0021 #include <QKeyEvent>
0022 #include <QLineEdit>
0023 #include <QPushButton>
0024 #include <QStandardPaths>
0025 #include <QTimer>
0026 
0027 #include <KLocalizedString>
0028 
0029 MolcalcWidget::MolcalcWidget(QWidget *parent)
0030     : QWidget(parent)
0031 {
0032     m_parser = new MoleculeParser(KalziumDataObject::instance()->ElementList);
0033 
0034     m_timer = new QTimer(this);
0035     m_timer->setSingleShot(true);
0036 
0037     ui.setupUi(this);
0038 
0039     connect(ui.calcButton, &QAbstractButton::clicked, this, &MolcalcWidget::slotCalculate);
0040     connect(ui.formulaEdit, &QLineEdit::returnPressed, this, &MolcalcWidget::slotCalculate);
0041     connect(m_timer, &QTimer::timeout, this, &MolcalcWidget::slotCalculate);
0042 
0043     ui.formulaEdit->setClearButtonEnabled(true);
0044 
0045     clear();
0046     if (!Prefs::addAlias()) {
0047         hideExtra();
0048         ui.details->show();
0049     }
0050     if (!Prefs::alias()) {
0051         ui.details->hide();
0052     }
0053 
0054     if (Prefs::addAlias()) {
0055         connect(ui.alias, &QAbstractButton::clicked, this, &MolcalcWidget::addAlias);
0056         QString shortForm, fullForm; // short form (symbol) and full form (expansion)
0057         QList<QString> shortList, fullList; // Used to store the short and full forms
0058         int i = 0; // loop counter
0059 
0060         // Search in User defined aliases.
0061         QString fileName = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("libkdeedu/data/symbols2.csv"));
0062         QFile file(fileName);
0063 
0064         // Check file validity
0065         if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
0066             qCDebug(KALZIUM_LOG) << fileName << " opened";
0067             QTextStream in(&file);
0068             // Get all shortForms and fullForms in the file.
0069             // eg the short form and full form extracted from ("Me","CH3")
0070             // are (Me) and (CH3) respectively
0071             while (!in.atEnd()) {
0072                 QString line = in.readLine();
0073                 shortForm = line.section(',', 0, 0);
0074                 shortForm.remove(QChar('\"'));
0075                 fullForm = line.section(',', 1, 1);
0076                 fullForm.remove(QChar('\"'));
0077                 shortList << shortForm;
0078                 fullList << fullForm;
0079             }
0080 
0081             int length = shortList.length();
0082             ui.user_defined->setRowCount(length);
0083             // Put all the aliases on to the table in the user interface
0084             for (i = 0; i < length; ++i) {
0085                 shortForm = shortList.takeFirst();
0086                 fullForm = fullList.takeFirst();
0087                 ui.user_defined->setItem((int)i, 0, new QTableWidgetItem(i18n("%1", shortForm + " : " + fullForm)));
0088             }
0089         } else {
0090             qCDebug(KALZIUM_LOG) << fileName << " could not be opened!";
0091         }
0092 
0093         // Find the system defined aliases
0094         // Open the file
0095         fileName = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("libkdeedu/data/symbols.csv"));
0096         QFile file2(fileName);
0097         shortList.clear();
0098         fullList.clear();
0099 
0100         // Check file validity
0101         if (!(!file2.open(QIODevice::ReadOnly | QIODevice::Text))) {
0102             qCDebug(KALZIUM_LOG) << fileName << " opened";
0103             QTextStream in(&file2);
0104 
0105             // Get all shortForms and fullForms in the file.
0106             while (!in.atEnd()) {
0107                 QString line = in.readLine();
0108                 shortForm = line.section(',', 0, 0);
0109                 shortForm.remove(QChar('\"'));
0110                 fullForm = line.section(',', 1, 1);
0111                 fullForm.remove(QChar('\"'));
0112                 shortList << shortForm;
0113                 fullList << fullForm;
0114             }
0115             int length = shortList.length();
0116             ui.pre_defined->setRowCount(length);
0117 
0118             // Put all the aliases on to the table in the user interface
0119             for (i = 0; i < length; ++i) {
0120                 shortForm = shortList.takeFirst();
0121                 fullForm = fullList.takeFirst();
0122                 ui.pre_defined->setItem((int)i, 0, new QTableWidgetItem(i18n("%1", shortForm + " : " + fullForm)));
0123             }
0124         } else {
0125             qCDebug(KALZIUM_LOG) << fileName << " could not be opened!";
0126         }
0127     }
0128 }
0129 
0130 MolcalcWidget::~MolcalcWidget()
0131 {
0132     delete m_parser;
0133 }
0134 
0135 void MolcalcWidget::clear()
0136 {
0137     // Clear the data.
0138     m_mass = 0;
0139     m_elementMap.clear();
0140 
0141     // stop the selection in the periodic table
0142     KalziumDataObject::instance()->search()->resetSearch();
0143 
0144     // Clear the widgets.
0145     ui.resultLabel->clear();
0146     ui.resultMass->clear();
0147     ui.resultValue->hide();
0148 
0149     ui.resultComposition->setText(i18n("Enter a formula in the\nwidget above and\nclick on 'Calc'.\nE.g. #Et#OH"));
0150 
0151     ui.resultMass->setToolTip(QString());
0152     ui.resultComposition->setToolTip(QString());
0153     ui.resultLabel->setToolTip(QString());
0154 }
0155 
0156 void MolcalcWidget::updateUI()
0157 {
0158     qCDebug(KALZIUM_LOG) << "MolcalcWidget::updateUI()";
0159 
0160     if (m_validInput) {
0161         qCDebug(KALZIUM_LOG) << "m_validInput == true";
0162 
0163         // The complexString stores the whole molecule like this:
0164         // 1 Seaborgium. Cumulative Mass: 263.119 u (39.2564 %)
0165         QString complexString;
0166         if (Prefs::alias()) {
0167             double mass;
0168             QString str;
0169             int i = 0; // counter
0170             int rows = m_elementMap.elements().count(); // number of columns
0171             ui.table->setRowCount(rows);
0172 
0173             foreach (ElementCount *count, m_elementMap.map()) {
0174                 // Update the resultLabel
0175                 mass = count->element()->dataAsVariant(ChemicalDataObject::mass).toDouble();
0176 
0177                 ui.table->setItem(i, 0, new QTableWidgetItem(i18n("%1", count->element()->dataAsString(ChemicalDataObject::name))));
0178                 ui.table->setItem(i, 1, new QTableWidgetItem(i18n("%1", count->count())));
0179                 ui.table->setItem(i, 2, new QTableWidgetItem(i18n("%1", count->element()->dataAsString(ChemicalDataObject::mass))));
0180                 ui.table->setItem(i, 3, new QTableWidgetItem(i18n("%1", mass * count->count())));
0181                 ui.table->setItem(i, 4, new QTableWidgetItem(i18n("%1", mass * count->count() / m_mass * 100)));
0182 
0183                 ++i;
0184             }
0185             // The alias list
0186             i = 0;
0187             rows = m_aliasList.count();
0188             ui.alias_list->setRowCount(rows);
0189             foreach (const QString &alias, m_aliasList) {
0190                 ui.alias_list->setItem(i++, 0, new QTableWidgetItem(alias));
0191             }
0192         }
0193 
0194         // The composition
0195         ui.resultComposition->setText(compositionString(m_elementMap));
0196 
0197         // The mass
0198         ui.resultMass->setText(i18n("Molecular mass: "));
0199 
0200         ui.resultValue->setText(QString::number(m_mass) + " u");
0201         ui.resultValue->show();
0202         ui.resultMass->setToolTip(complexString);
0203         ui.resultComposition->setToolTip(complexString);
0204 
0205 #if 0
0206         // FIXME
0207         //select the elements in the table
0208         QList<Element*> list = m_elementMap.elements();
0209         KalziumDataObject::instance()->findElements(list);
0210 #endif
0211     } else { // the input was invalid, so tell this the user
0212         qCDebug(KALZIUM_LOG) << "m_validInput == false";
0213         ui.resultComposition->setText(i18n("Invalid input"));
0214         ui.resultLabel->setText(QString());
0215         ui.resultMass->setText(QString());
0216 
0217         ui.resultMass->setToolTip(i18n("Invalid input"));
0218         ui.resultComposition->setToolTip(i18n("Invalid input"));
0219         ui.resultLabel->setToolTip(i18n("Invalid input"));
0220     }
0221 }
0222 
0223 QString MolcalcWidget::compositionString(ElementCountMap &_map)
0224 {
0225     QString str;
0226 
0227     foreach (ElementCount *count, _map.map()) {
0228         str += i18n("%1<sub>%2</sub> ", count->element()->dataAsString(ChemicalDataObject::symbol), count->count());
0229     }
0230 
0231     return str;
0232 }
0233 
0234 // ----------------------------------------------------------------
0235 //                            slots
0236 
0237 void MolcalcWidget::slotCalculate()
0238 {
0239     qCDebug(KALZIUM_LOG) << "MolcalcWidget::slotCalcButtonClicked()";
0240     QString molecule = ui.formulaEdit->text();
0241 
0242     // Parse the molecule, and at the same time calculate the total
0243     // mass, and the composition of it.
0244     if (!molecule.isEmpty()) {
0245         m_validInput = m_parser->weight(molecule, &m_mass, &m_elementMap);
0246         m_aliasList = m_parser->aliasList();
0247     }
0248     qCDebug(KALZIUM_LOG) << "done calculating.";
0249 
0250     updateUI();
0251 }
0252 
0253 void MolcalcWidget::keyPressEvent(QKeyEvent * /* e */)
0254 {
0255     m_timer->start(500);
0256 }
0257 
0258 void MolcalcWidget::addAlias()
0259 {
0260     const QString shortForm = ui.shortForm->text();
0261     const QString fullForm = ui.fullForm->text();
0262 
0263     // Validate the alias
0264     double x;
0265     ElementCountMap y;
0266 
0267     ui.aliasMessage->setText(QLatin1String(""));
0268     if (shortForm.length() < 2) {
0269         ui.aliasMessage->setText(i18n("Symbol should consist of two or more letters."));
0270         return;
0271     }
0272 
0273     if (m_parser->weight(shortForm, &x, &y)) {
0274         ui.aliasMessage->setText(i18n("Symbol already being used"));
0275         return;
0276     }
0277 
0278     if (fullForm.isEmpty() || !m_parser->weight(fullForm, &x, &y)) {
0279         ui.aliasMessage->setText(i18n("Expansion is invalid, please specify a valid expansion"));
0280         return;
0281     }
0282 
0283     // Open the file to write
0284     QString fileName = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("libkdeedu/data/symbols2.csv"));
0285     QFile file(fileName);
0286 
0287     if (!(!file.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text))) {
0288         QTextStream out(&file);
0289         out << "\"" + shortForm + "\",\"" + fullForm + "\"\n";
0290         qCDebug(KALZIUM_LOG) << fileName << "is the file.";
0291         qCDebug(KALZIUM_LOG) << "\"" + shortForm + "\",\"" + fullForm + "\"\n";
0292         ui.aliasMessage->setText(i18n("done!"));
0293         return;
0294     } else {
0295         ui.aliasMessage->setText((i18n("Unable to find the user defined alias file.")) + fileName);
0296         return;
0297     }
0298 }
0299 
0300 void MolcalcWidget::hideExtra()
0301 {
0302     ui.details->hide();
0303     ui.tabWidget->removeTab(1);
0304 }