Skip to content

Commit

Permalink
Kick off network requests for molecule names
Browse files Browse the repository at this point in the history
Signed-off-by: Geoff Hutchison <[email protected]>
  • Loading branch information
ghutchis committed Oct 28, 2024
1 parent 6730c3c commit 60e14da
Show file tree
Hide file tree
Showing 2 changed files with 128 additions and 6 deletions.
120 changes: 115 additions & 5 deletions avogadro/qtplugins/molecularproperties/molecularmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,20 @@

#include <avogadro/core/elements.h>
#include <avogadro/core/residue.h>
#include <avogadro/io/fileformatmanager.h>
#include <avogadro/qtgui/molecule.h>

#include <QtCore/QDebug>
#include <QtCore/QRegularExpression>
#include <QtGui/QColor>
#include <QtCore/QTimer>

#include <QtCore/QJsonArray>
#include <QtCore/QJsonDocument>
#include <QtCore/QJsonObject>
#include <QtCore/QJsonValue>

#include <QtNetwork/QNetworkAccessManager>
#include <QtNetwork/QNetworkReply>

#include <limits>

Expand All @@ -23,11 +32,110 @@ using QtGui::Molecule;
MolecularModel::MolecularModel(QObject* parent)
: QAbstractTableModel(parent), m_molecule(nullptr)
{
m_network = new QNetworkAccessManager(this);
connect(m_network, SIGNAL(finished(QNetworkReply*)), this,
SLOT(updateNameReady(QNetworkReply*)));
}

void MolecularModel::setMolecule(QtGui::Molecule* molecule)
{
m_molecule = molecule;
// check if it has a pre-defined name
if (molecule) {
if (m_molecule->data("name").toString().empty())
m_autoName = true;
else
m_autoName = false;
m_name = QString::fromStdString(molecule->data("name").toString());
}
}

QString MolecularModel::name() const
{
// if we have a defined name
// or we're not ready to update
// then return the current name
if (!m_autoName || m_nameRequestPending)
return m_name;

if (!m_molecule || m_molecule->atomCount() == 0)
return m_name; // empty

// okay, kick off the update
m_name = tr("(pending)", "asking server for molecule name");
m_nameRequestPending = true;

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");
m_network->get(QNetworkRequest(QUrl(requestURL)));

// don't update again until we're ready - 5 seconds
QTimer::singleShot(5000, this, SLOT(canUpdateName()));

return m_name;
}

void MolecularModel::canUpdateName()
{
m_nameRequestPending = false;
}

void MolecularModel::updateNameReady(QNetworkReply* reply)
{
// Read in all the data
if (!reply->isReadable()) {
reply->deleteLater();
m_name = tr("unknown molecule");
return;
}

// check if the data came through
QByteArray data = reply->readAll();
if (data.contains("Error report") || data.contains("<h1>")) {
reply->deleteLater();
m_name = 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_name = 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_name = 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();
}

int MolecularModel::rowCount(const QModelIndex& parent) const
Expand Down Expand Up @@ -59,7 +167,7 @@ int MolecularModel::columnCount(const QModelIndex& parent) const
return 1; // values
}

QString formatFormula(Molecule* m)
QString formatFormula(Molecule* molecule)
{
QString formula = QString::fromStdString(molecule->formula());
QRegularExpression digitParser("(\\d+)");
Expand All @@ -76,9 +184,11 @@ QString formatFormula(Molecule* m)
}

// add total charge as a superscript
int charge = m->totalCharge();
if (charge != 0)
int charge = molecule->totalCharge();
if (charge < 0)
formula += QString("<sup>%1</sup>").arg(charge);
else if (charge > 0)
formula += QString("<sup>+%1</sup>").arg(charge);

return formula;
}
Expand Down Expand Up @@ -107,7 +217,7 @@ QVariant MolecularModel::data(const QModelIndex& index, int role) const
return QVariant();

if (row == Name) {
return QString::fromStdString(m_molecule->data("name").toString());
return this->name();
} else if (row == Mass) {
return m_molecule->mass();
} else if (row == Formula) {
Expand Down
14 changes: 13 additions & 1 deletion avogadro/qtplugins/molecularproperties/molecularmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@
#include <QtCore/QObject>
#include <QtCore/QString>

class QNetworkAccessManager;
class QNetworkReply;

#include <avogadro/qtgui/rwmolecule.h>

namespace Avogadro {
Expand All @@ -35,6 +38,8 @@ class MolecularModel : public QAbstractTableModel

public slots:
void updateTable(unsigned int flags);
void updateNameReady(QNetworkReply* reply); // reply from network
void canUpdateName(); // don't do it too often

public:
explicit MolecularModel(QObject* parent = 0);
Expand All @@ -50,8 +55,15 @@ public slots:

void setMolecule(QtGui::Molecule* molecule);

QString name() const;

private:
QtGui::Molecule* m_molecule;
QtGui::Molecule* m_molecule = nullptr;
mutable QString m_name;
mutable bool m_autoName = true;
mutable bool m_nameRequestPending = false;

QNetworkAccessManager* m_network = nullptr;
};

} // end namespace Avogadro
Expand Down

1 comment on commit 60e14da

@github-actions
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ERROR: clang-format-diff detected formatting issues. See the artifact for a patch or run clang-format on your branch.

Please sign in to comment.