Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation of custom element assignment from file #281

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 138 additions & 7 deletions avogadro/qtplugins/customelements/customelements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,39 @@

#include "customelements.h"

#include <avogadro/qtgui/backgroundfileformat.h>
#include <avogadro/qtgui/customelementdialog.h>
#include <avogadro/qtgui/fileformatdialog.h>
#include <avogadro/qtgui/molecule.h>

#include <QtCore/QSettings>
#include <QtCore/QThread>
#include <QtWidgets/QAction>
#include <QtWidgets/QMessageBox>
#include <QtWidgets/QProgressDialog>

using Avogadro::QtGui::BackgroundFileFormat;
using Avogadro::QtGui::Molecule;

namespace Avogadro {
namespace QtPlugins {

CustomElements::CustomElements(QObject* parent_)
: Avogadro::QtGui::ExtensionPlugin(parent_), m_molecule(nullptr),
m_reassignAction(new QAction(tr("Reassign &Custom Elements..."), this))
m_reassignUsingTool(nullptr), m_reassignFromFile(nullptr),
m_fileReadThread(nullptr), m_threadedReader(nullptr),
m_fileReadMolecule(nullptr), m_progressDialog(nullptr)
{
connect(m_reassignAction, SIGNAL(triggered()), SLOT(reassign()));
m_reassignUsingTool = new QAction(tr("Reassign &Custom Elements..."), this);
m_reassignFromFile =
new QAction(tr("&Import Coordinate/Topology File..."), this);
connect(m_reassignUsingTool, SIGNAL(triggered()), SLOT(reassign()));
connect(m_reassignFromFile, SIGNAL(triggered()), SLOT(importMapFile()));

updateReassignAction();
}

CustomElements::~CustomElements()
{
}
CustomElements::~CustomElements() {}

QString CustomElements::description() const
{
Expand All @@ -46,7 +57,7 @@ QString CustomElements::description() const

QList<QAction*> CustomElements::actions() const
{
return QList<QAction*>() << m_reassignAction;
return QList<QAction*>() << m_reassignUsingTool << m_reassignFromFile;
}

QStringList CustomElements::menuPath(QAction*) const
Expand Down Expand Up @@ -86,9 +97,129 @@ void CustomElements::reassign()
}
}

bool CustomElements::openFile(const QString& fileName, Io::FileFormat* reader)
{
if (fileName.isEmpty() || reader == nullptr) {
delete reader;
return false;
}

QString ident = QString::fromStdString(reader->identifier());

// Prepare the background thread to read in the selected file.
if (!m_fileReadThread)
m_fileReadThread = new QThread(qobject_cast<QWidget*>(parent()));
if (m_threadedReader)
m_threadedReader->deleteLater();
m_threadedReader = new BackgroundFileFormat(reader);
if (m_fileReadMolecule)
m_fileReadMolecule->deleteLater();
m_fileReadMolecule = new Molecule(qobject_cast<QWidget*>(parent()));
m_fileReadMolecule->setData("fileName", fileName.toLocal8Bit().data());
m_threadedReader->moveToThread(m_fileReadThread);
m_threadedReader->setMolecule(m_fileReadMolecule);
m_threadedReader->setFileName(fileName);

// Setup a progress dialog in case file loading is slow
m_progressDialog = new QProgressDialog(qobject_cast<QWidget*>(parent()));
m_progressDialog->setRange(0, 0);
m_progressDialog->setValue(0);
m_progressDialog->setMinimumDuration(750);
m_progressDialog->setWindowTitle(tr("Reading File"));
m_progressDialog->setLabelText(
tr("Opening file '%1'\nwith '%2'").arg(fileName).arg(ident));
m_progressDialog->setCancelButton(nullptr);
connect(m_progressDialog, SIGNAL(canceled()), m_fileReadThread, SLOT(quit()));
connect(m_fileReadThread, SIGNAL(started()), m_threadedReader, SLOT(read()));
connect(m_threadedReader, SIGNAL(finished()), m_fileReadThread, SLOT(quit()));
connect(m_threadedReader, SIGNAL(finished()),
SLOT(backgroundReaderFinished()));

// Start the file operation
m_fileReadThread->start();
m_progressDialog->show();

return true;
}

void CustomElements::backgroundReaderFinished()
{
QString fileName = m_threadedReader->fileName();
if (m_progressDialog->wasCanceled()) {
delete m_fileReadMolecule;
} else if (m_threadedReader->success()) {
if (!fileName.isEmpty()) {
m_fileReadMolecule->setData("fileName", fileName.toLocal8Bit().data());
} else {
m_fileReadMolecule->setData("fileName", Core::Variant());
}
setMapFromMolecule(m_fileReadMolecule);
} else {
QMessageBox::critical(qobject_cast<QWidget*>(parent()), tr("File error"),
tr("Error while reading file '%1':\n%2")
.arg(fileName)
.arg(m_threadedReader->error()));
delete m_fileReadMolecule;
}
m_fileReadThread->deleteLater();
m_fileReadThread = nullptr;
m_threadedReader->deleteLater();
m_threadedReader = nullptr;
m_fileReadMolecule = nullptr;
m_progressDialog->hide();
m_progressDialog->deleteLater();
m_progressDialog = nullptr;
}

void CustomElements::setMapFromMolecule(QtGui::Molecule* mol)
{
if (mol->atomCount() != m_molecule->atomCount()) {
QMessageBox::critical(
qobject_cast<QWidget*>(parent()), tr("Error"),
tr("Atom count mismatch.\nExpected %1 atoms, found %2.")
.arg(m_molecule->atomCount())
.arg(mol->atomCount()));
} else {
size_t n = m_molecule->atomCount(), i;
for (i = 0; i < n; ++i) {
m_molecule->atom(i).setAtomicNumber(mol->atom(i).atomicNumber());
}
n = m_molecule->bondCount();
for (i = 0; i < n; ++i) {
m_molecule->addBond(mol->bond(i).atom1(), mol->bond(i).atom2(),
mol->bond(i).order());
}
m_molecule->emitChanged(Molecule::Atoms | Molecule::Modified);
}
}

void CustomElements::importMapFile()
{
QSettings settings;
QString dir = settings.value("MainWindow/lastOpenDir").toString();

QtGui::FileFormatDialog::FormatFilePair reply =
QtGui::FileFormatDialog::fileToRead(qobject_cast<QWidget*>(parent()),
tr("Open Molecule"), dir);

if (reply.first == NULL) // user cancel
return;

dir = QFileInfo(reply.second).absoluteDir().absolutePath();
settings.setValue("MainWindow/lastOpenDir", dir);

if (!openFile(reply.second, reply.first->newInstance())) {
QMessageBox::information(
qobject_cast<QWidget*>(parent()), tr("Cannot open file"),
tr("Can't open supplied file %1").arg(reply.second));
}
}

void CustomElements::updateReassignAction()
{
m_reassignAction->setEnabled(m_molecule && m_molecule->hasCustomElements());
m_reassignUsingTool->setEnabled(m_molecule &&
m_molecule->hasCustomElements());
m_reassignFromFile->setEnabled(m_molecule && m_molecule->atomCount());
}

} // namespace QtPlugins
Expand Down
19 changes: 18 additions & 1 deletion avogadro/qtplugins/customelements/customelements.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,15 @@

#include <avogadro/qtgui/extensionplugin.h>

class QProgressDialog;
class QThread;

namespace Avogadro {

namespace QtGui {
class BackgroundFileFormat;
}

namespace QtPlugins {

/**
Expand All @@ -43,12 +51,21 @@ public slots:
private slots:
void moleculeChanged(unsigned int changes);
void reassign();
void importMapFile();
void backgroundReaderFinished();

private:
QtGui::Molecule* m_molecule;
QAction* m_reassignAction;
QAction* m_reassignUsingTool;
QAction* m_reassignFromFile;
QThread* m_fileReadThread;
QtGui::BackgroundFileFormat* m_threadedReader;
QtGui::Molecule* m_fileReadMolecule;
QProgressDialog* m_progressDialog;

void updateReassignAction();
bool openFile(const QString& fileName, Io::FileFormat* reader);
void setMapFromMolecule(QtGui::Molecule* mol);
};

} // namespace QtPlugins
Expand Down