From 6730c3c091bffbbfcc5be8a5a4b03ac691ca597e Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Mon, 28 Oct 2024 15:36:29 -0400 Subject: [PATCH] Update to use rich text delegate and charged formula Signed-off-by: Geoff Hutchison --- .../molecularproperties/molecularmodel.cpp | 12 +- .../molecularproperties.cpp | 6 + .../molecularpropertiesdialog.cpp | 251 ------------------ .../molecularpropertiesdialog.h | 75 ------ .../molecularpropertiesdialog.ui | 144 ---------- 5 files changed, 15 insertions(+), 473 deletions(-) delete mode 100644 avogadro/qtplugins/molecularproperties/molecularpropertiesdialog.cpp delete mode 100644 avogadro/qtplugins/molecularproperties/molecularpropertiesdialog.h delete mode 100644 avogadro/qtplugins/molecularproperties/molecularpropertiesdialog.ui diff --git a/avogadro/qtplugins/molecularproperties/molecularmodel.cpp b/avogadro/qtplugins/molecularproperties/molecularmodel.cpp index 5ce8dc0ec4..b854a33f6b 100644 --- a/avogadro/qtplugins/molecularproperties/molecularmodel.cpp +++ b/avogadro/qtplugins/molecularproperties/molecularmodel.cpp @@ -59,9 +59,9 @@ int MolecularModel::columnCount(const QModelIndex& parent) const return 1; // values } -QString formatFormula(std::string f) +QString formatFormula(Molecule* m) { - QString formula = QString::fromStdString(f); + QString formula = QString::fromStdString(molecule->formula()); QRegularExpression digitParser("(\\d+)"); QRegularExpressionMatchIterator i = digitParser.globalMatch(formula); @@ -74,6 +74,12 @@ QString formatFormula(std::string f) QString("%1").arg(digits)); offset += 11; // length of ... } + + // add total charge as a superscript + int charge = m->totalCharge(); + if (charge != 0) + formula += QString("%1").arg(charge); + return formula; } @@ -105,7 +111,7 @@ QVariant MolecularModel::data(const QModelIndex& index, int role) const } else if (row == Mass) { return m_molecule->mass(); } else if (row == Formula) { - return formatFormula(m_molecule->formula()); + return formatFormula(m_molecule); } else if (row == Atoms) { return QVariant::fromValue(m_molecule->atomCount()); } else if (row == Bonds) { diff --git a/avogadro/qtplugins/molecularproperties/molecularproperties.cpp b/avogadro/qtplugins/molecularproperties/molecularproperties.cpp index 44773b063e..313a334692 100644 --- a/avogadro/qtplugins/molecularproperties/molecularproperties.cpp +++ b/avogadro/qtplugins/molecularproperties/molecularproperties.cpp @@ -6,6 +6,8 @@ #include "molecularproperties.h" #include "molecularview.h" +#include + #include #include #include @@ -13,6 +15,8 @@ #include #include +using Avogadro::QtGui::RichTextDelegate; + namespace Avogadro::QtPlugins { MolecularProperties::MolecularProperties(QObject* parent_) @@ -69,6 +73,8 @@ void MolecularProperties::showDialog() view->setSourceModel(model); view->setModel(model); + view->setItemDelegateForColumn(0, new RichTextDelegate(view)); + view->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); view->resizeColumnsToContents(); diff --git a/avogadro/qtplugins/molecularproperties/molecularpropertiesdialog.cpp b/avogadro/qtplugins/molecularproperties/molecularpropertiesdialog.cpp deleted file mode 100644 index 930020018b..0000000000 --- a/avogadro/qtplugins/molecularproperties/molecularpropertiesdialog.cpp +++ /dev/null @@ -1,251 +0,0 @@ -/****************************************************************************** - This source file is part of the Avogadro project. - This source code is released under the 3-Clause BSD License, (see "LICENSE"). -******************************************************************************/ - -#include "molecularpropertiesdialog.h" -#include "ui_molecularpropertiesdialog.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using Avogadro::QtGui::Molecule; - -namespace Avogadro::QtPlugins { - -MolecularPropertiesDialog::MolecularPropertiesDialog(QtGui::Molecule* mol, - QWidget* parent_) - : QDialog(parent_), m_molecule(nullptr), - m_ui(new Ui::MolecularPropertiesDialog) -{ - m_ui->setupUi(this); - m_ui->buttonBox->button(QDialogButtonBox::Apply)->setText(tr("&Copy")); - - connect(m_ui->buttonBox, SIGNAL(clicked(QAbstractButton*)), this, - SLOT(buttonClicked(QAbstractButton*))); - - m_network = new QNetworkAccessManager(this); - connect(m_network, SIGNAL(finished(QNetworkReply*)), this, - SLOT(replyFinished(QNetworkReply*))); - - setMolecule(mol); -} - -MolecularPropertiesDialog::~MolecularPropertiesDialog() -{ - delete m_ui; -} - -void MolecularPropertiesDialog::setMolecule(QtGui::Molecule* mol) -{ - if (mol == m_molecule) - return; - - if (m_molecule) - m_molecule->disconnect(this); - - m_molecule = mol; - - if (!m_molecule) - return; - - connect(m_molecule, SIGNAL(changed(unsigned int)), SLOT(updateLabels())); - connect(m_molecule, SIGNAL(destroyed()), SLOT(moleculeDestroyed())); - updateLabels(); -} - -void MolecularPropertiesDialog::updateLabels() -{ - if (m_molecule) { - updateMassLabel(); - updateFormulaLabel(); - updateName(); - m_ui->atomCountLabel->setText(QString::number(m_molecule->atomCount())); - m_ui->bondCountLabel->setText(QString::number(m_molecule->bondCount())); - } else { - m_ui->molMassLabel->clear(); - m_ui->formulaLabel->clear(); - m_ui->atomCountLabel->clear(); - m_ui->bondCountLabel->clear(); - } -} - -void MolecularPropertiesDialog::updateName() -{ - QString name = tr("(pending)", "asking server for molecule name"); - - if (!m_molecule || m_molecule->atomCount() == 0) { - m_ui->moleculeNameLabel->clear(); - return; - } - - m_ui->moleculeNameLabel->setText(name); // while we wait - - // InChI is intentionally designed to avoid issues with URL encoding - std::string smiles; - Io::FileFormatManager::instance().writeString(*m_molecule, smiles, "smi"); - QString smilesString = QString::fromStdString(smiles); - smilesString.remove(QRegularExpression("\\s+.*")); - QString requestURL = - QString("https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/smiles/" + - QUrl::toPercentEncoding(smilesString) + "/json"); - - // qDebug() << "Requesting" << requestURL; - - m_network->get(QNetworkRequest(QUrl(requestURL))); -} - -void MolecularPropertiesDialog::replyFinished(QNetworkReply* reply) -{ - // Read in all the data - if (!reply->isReadable()) { - reply->deleteLater(); - m_ui->moleculeNameLabel->setText(tr("unknown molecule")); - return; - } - - // check if the data came through - QByteArray data = reply->readAll(); - if (data.contains("Error report") || data.contains("

")) { - reply->deleteLater(); - m_ui->moleculeNameLabel->setText(tr("unknown molecule")); - return; - } - - // parse the JSON - // https://pubchem.ncbi.nlm.nih.gov/rest/pug/compound/smiles/…/json - - // PC_Compounds[0].props - // iterate // get "urn" / "name" == "Markup" and "Preferred" - // .. get "value" / "sval" - - QJsonDocument doc = QJsonDocument::fromJson(data); - QJsonObject obj = doc.object(); - QJsonArray array = obj["PC_Compounds"].toArray(); - if (array.isEmpty()) { - reply->deleteLater(); - m_ui->moleculeNameLabel->setText(tr("unknown molecule")); - return; - } - obj = array.first().toObject(); - array = obj["props"].toArray(); // props is an array of objects - for (const QJsonValue& value : array) { - obj = value.toObject(); - QJsonObject urn = obj["urn"].toObject(); - - if (urn["name"].toString() == "Markup") { - // HTML version for dialog - QJsonObject nameValue = obj["value"].toObject(); - m_ui->moleculeNameLabel->setText(nameValue["sval"].toString()); - } else if (urn["name"].toString() == "Preferred") { - // save this text version for files and copy/paste - QJsonObject nameValue = obj["value"].toObject(); - m_molecule->setData("name", nameValue["sval"].toString().toStdString()); - m_name = nameValue["sval"].toString(); - } - } - - reply->deleteLater(); -} - -void MolecularPropertiesDialog::updateMassLabel() -{ - double mass = 0.0; - for (size_t i = 0; i < m_molecule->atomCount(); ++i) - mass += Core::Elements::mass(m_molecule->atom(i).atomicNumber()); - m_ui->molMassLabel->setText(QString::number(mass, 'f', 3)); -} - -void MolecularPropertiesDialog::updateFormulaLabel() -{ - QString formula = QString::fromStdString(m_molecule->formula()); - QRegularExpression digitParser("(\\d+)"); - - QRegularExpressionMatchIterator i = digitParser.globalMatch(formula); - unsigned int offset = 0; - while (i.hasNext()) { - const QRegularExpressionMatch match = i.next(); - QString digits = match.captured(1); - - formula.replace(match.capturedStart(1) + offset, digits.size(), - QString("%1").arg(digits)); - offset += 11; // length of ... - } - - m_ui->formulaLabel->setText(formula); -} - -void MolecularPropertiesDialog::moleculeDestroyed() -{ - m_molecule = nullptr; - updateLabels(); -} - -void MolecularPropertiesDialog::keyPressEvent(QKeyEvent* event) -{ - if (event->key() == Qt::Key_Escape) - close(); - - if (event->matches(QKeySequence::Copy)) { - copy(); - event->accept(); - } -} - -void MolecularPropertiesDialog::buttonClicked(QAbstractButton* button) -{ - if (button->text() == tr("&Copy")) - copy(); -} - -void MolecularPropertiesDialog::copy() -{ - // format the text for copy: - // name, mass, formula, atom count, bond count - QString p("

"); - QString endP("

"); - - QString html = p + tr("Molecule Name:") + - QString(" %1").arg(m_ui->moleculeNameLabel->text()) + endP; - html += p + tr("Molecular Mass (g/mol):") + - QString(" %1\n").arg(m_ui->molMassLabel->text()) + endP; - html += p + tr("Chemical Formula:") + - QString(" %1\n").arg(m_ui->formulaLabel->text()) + endP; - html += p + tr("Number of Atoms:") + - QString(" %1\n").arg(m_molecule->atomCount()) + endP; - html += p + tr("Number of Bonds:") + - QString(" %1\n").arg(m_molecule->bondCount()) + endP; - - QString text = tr("Molecule Name:") + - QString(" %1\n").arg( - QString::fromStdString(m_molecule->data("name").toString())); - text += tr("Molecular Mass (g/mol):") + - QString(" %1\n").arg(m_ui->molMassLabel->text()); - text += tr("Chemical Formula:") + - QString(" %1\n").arg(QString::fromStdString(m_molecule->formula())); - text += - tr("Number of Atoms:") + QString(" %1\n").arg(m_molecule->atomCount()); - text += - tr("Number of Bonds:") + QString(" %1\n").arg(m_molecule->bondCount()); - - // include both HTML and plain text - QMimeData* mimeData = new QMimeData(); - mimeData->setText(text); - mimeData->setHtml(html); - QApplication::clipboard()->setMimeData(mimeData); -} - -} // namespace Avogadro::QtPlugins diff --git a/avogadro/qtplugins/molecularproperties/molecularpropertiesdialog.h b/avogadro/qtplugins/molecularproperties/molecularpropertiesdialog.h deleted file mode 100644 index a3259018af..0000000000 --- a/avogadro/qtplugins/molecularproperties/molecularpropertiesdialog.h +++ /dev/null @@ -1,75 +0,0 @@ -/****************************************************************************** - This source file is part of the Avogadro project. - This source code is released under the 3-Clause BSD License, (see "LICENSE"). -******************************************************************************/ - -#ifndef AVOGADRO_QTGUI_MOLECULARPROPERTIESDIALOG_H -#define AVOGADRO_QTGUI_MOLECULARPROPERTIESDIALOG_H - -#include - -// Forward declarations -class QAbstractButton; -class QKeyEvent; -class QNetworkAccessManager; -class QNetworkReply; - -namespace Avogadro { - -namespace QtGui { -class Molecule; -} - -namespace QtPlugins { - -namespace Ui { -class MolecularPropertiesDialog; -} - -/** - * @class MolecularPropertiesDialog molecularpropertiesdialog.h - * - * @brief The MolecularPropertiesDialog class provides a dialog which displays - * basic molecular properties. - * @author Allison Vacanti - * - */ -class MolecularPropertiesDialog : public QDialog -{ - Q_OBJECT - -public: - explicit MolecularPropertiesDialog(QtGui::Molecule* mol, - QWidget* parent_ = nullptr); - ~MolecularPropertiesDialog() override; - - QtGui::Molecule* molecule() { return m_molecule; } - -protected: - void keyPressEvent(QKeyEvent *event) override; - -public slots: - void setMolecule(QtGui::Molecule* mol); - void buttonClicked(QAbstractButton *button); - -private slots: - void updateName(); - void updateLabels(); - void updateMassLabel(); - void updateFormulaLabel(); - void moleculeDestroyed(); - void replyFinished(QNetworkReply*); - void copy(); - -private: - QtGui::Molecule* m_molecule; - Ui::MolecularPropertiesDialog* m_ui; - - QString m_name; - QNetworkAccessManager *m_network; - bool m_nameRequestPending; -}; - -} // namespace QtPlugins -} // namespace Avogadro -#endif // AVOGADRO_QTGUI_MOLECULARPROPERTIESDIALOG_H diff --git a/avogadro/qtplugins/molecularproperties/molecularpropertiesdialog.ui b/avogadro/qtplugins/molecularproperties/molecularpropertiesdialog.ui deleted file mode 100644 index 676cd8364a..0000000000 --- a/avogadro/qtplugins/molecularproperties/molecularpropertiesdialog.ui +++ /dev/null @@ -1,144 +0,0 @@ - - - Avogadro::QtPlugins::MolecularPropertiesDialog - - - - 0 - 0 - 405 - 183 - - - - Molecular Properties - - - - - - QFormLayout::ExpandingFieldsGrow - - - Qt::AlignHCenter|Qt::AlignTop - - - - - TODO - - - - - - - Molecular Mass (g/mol): - - - - - - - TODO - - - - - - - Chemical Formula: - - - - - - - TODO - - - - - - - Number of Atoms: - - - - - - - TODO - - - - - - - Number of Bonds: - - - - - - - TODO - - - - - - - Molecule Name: - - - - - - - - - Qt::Horizontal - - - QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok - - - - - - - - - buttonBox - accepted() - Avogadro::QtPlugins::MolecularPropertiesDialog - accept() - - - 248 - 254 - - - 157 - 274 - - - - - buttonBox - rejected() - Avogadro::QtPlugins::MolecularPropertiesDialog - reject() - - - 316 - 260 - - - 286 - 274 - - - - -