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 3 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
2 changes: 1 addition & 1 deletion avogadro/qtplugins/customelements/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@ avogadro_plugin(CustomElements
ExtensionPlugin
customelements.h
CustomElements
"customelements.cpp"
"customelements.cpp;backgroundfileformat.cpp"
)
86 changes: 86 additions & 0 deletions avogadro/qtplugins/customelements/backgroundfileformat.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/******************************************************************************

This source file is part of the Avogadro project.

Copyright 2013 Kitware, Inc.

This source code is released under the New BSD License, (the "License").

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

******************************************************************************/

#include "backgroundfileformat.h"

#include <avogadro/io/fileformat.h>

namespace Avogadro {

BackgroundFileFormat::BackgroundFileFormat(Io::FileFormat* format,
QObject* aparent)
: QObject(aparent)
, m_format(format)
, m_molecule(nullptr)
, m_success(false)
{}

BackgroundFileFormat::~BackgroundFileFormat()
{
delete m_format;
}

void BackgroundFileFormat::read()
{
m_success = false;
m_error.clear();

if (!m_molecule)
m_error = tr("No molecule set in BackgroundFileFormat!");

if (!m_format)
m_error = tr("No Io::FileFormat set in BackgroundFileFormat!");

if (m_fileName.isEmpty())
m_error = tr("No file name set in BackgroundFileFormat!");

if (m_error.isEmpty()) {
m_success =
m_format->readFile(m_fileName.toLocal8Bit().data(), *m_molecule);

if (!m_success)
m_error = QString::fromStdString(m_format->error());
}

emit finished();
}

void BackgroundFileFormat::write()
{
m_success = false;
m_error.clear();

if (!m_molecule)
m_error = tr("No molecule set in BackgroundFileFormat!");

if (!m_format)
m_error = tr("No Io::FileFormat set in BackgroundFileFormat!");

if (m_fileName.isEmpty())
m_error = tr("No file name set in BackgroundFileFormat!");

if (m_error.isEmpty()) {
m_success =
m_format->writeFile(m_fileName.toLocal8Bit().data(), *m_molecule);

if (!m_success)
m_error = QString::fromStdString(m_format->error());
}

emit finished();
}

} // namespace Avogadro
107 changes: 107 additions & 0 deletions avogadro/qtplugins/customelements/backgroundfileformat.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/******************************************************************************

This source file is part of the Avogadro project.

Copyright 2013 Kitware, Inc.

This source code is released under the New BSD License, (the "License").

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

******************************************************************************/

#ifndef AVOGADRO_BACKGROUNDFILEFORMAT_H
#define AVOGADRO_BACKGROUNDFILEFORMAT_H

#include <QtCore/QObject>
#include <QtCore/QString>

namespace Avogadro {

namespace Core {
class Molecule;
}

namespace Io {
class FileFormat;
}

/**
* @brief The BackgroundFileFormat class provides a thin QObject wrapper around
* an instance of Io::FileFormat.
*/
class BackgroundFileFormat : public QObject
{
Q_OBJECT
public:
/**
* This class takes ownership of @a format and will delete it when destructed.
*/
explicit BackgroundFileFormat(Io::FileFormat* format, QObject* aparent = 0);
~BackgroundFileFormat();

/**
* The molecule instance to read/write.
* @{
*/
void setMolecule(Core::Molecule* mol) { m_molecule = mol; }
Core::Molecule* molecule() const { return m_molecule; }
/**@}*/

/**
* The name of the file to read/write.
* @{
*/
void setFileName(const QString& filename) { m_fileName = filename; }
QString fileName() const { return m_fileName; }
/**@}*/

/**
* The Io::FileFormat to use.
*/
Io::FileFormat* fileFormat() const { return m_format; }

/**
* @return True if the operation was successful.
*/
bool success() const { return m_success; }

/**
* @return An error string, set if success() is false.
*/
QString error() const { return m_error; }

signals:

/**
* Emitted when a call to read or write is called.
*/
void finished();

public slots:

/**
* Use the fileFormat() to read fileName() into molecule().
*/
void read();

/**
* Use the fileFormat() to write fileName() from molecule().
*/
void write();

private:
Io::FileFormat* m_format;
Core::Molecule* m_molecule;
QString m_fileName;
QString m_error;
bool m_success;
};

} // namespace Avogadro

#endif // AVOGADRO_BACKGROUNDFILEFORMAT_H
144 changes: 137 additions & 7 deletions avogadro/qtplugins/customelements/customelements.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,17 @@
******************************************************************************/

#include "customelements.h"
#include "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::Molecule;

Expand All @@ -28,16 +34,20 @@ 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 +56,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 +96,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
Loading