Skip to content

Commit 45d7d55

Browse files
committed
Implementation of custom element assignment from file
Signed-off-by: Adarsh Balasubramanian <[email protected]>
1 parent da6ebb9 commit 45d7d55

File tree

5 files changed

+346
-11
lines changed

5 files changed

+346
-11
lines changed

avogadro/qtplugins/customelements/CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,5 +3,5 @@ avogadro_plugin(CustomElements
33
ExtensionPlugin
44
customelements.h
55
CustomElements
6-
"customelements.cpp"
6+
"customelements.cpp;backgroundfileformat.cpp"
77
)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
/******************************************************************************
2+
3+
This source file is part of the Avogadro project.
4+
5+
Copyright 2013 Kitware, Inc.
6+
7+
This source code is released under the New BSD License, (the "License").
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
15+
******************************************************************************/
16+
17+
#include "backgroundfileformat.h"
18+
19+
#include <avogadro/io/fileformat.h>
20+
21+
namespace Avogadro {
22+
23+
BackgroundFileFormat::BackgroundFileFormat(Io::FileFormat* format,
24+
QObject* aparent)
25+
: QObject(aparent)
26+
, m_format(format)
27+
, m_molecule(nullptr)
28+
, m_success(false)
29+
{}
30+
31+
BackgroundFileFormat::~BackgroundFileFormat()
32+
{
33+
delete m_format;
34+
}
35+
36+
void BackgroundFileFormat::read()
37+
{
38+
m_success = false;
39+
m_error.clear();
40+
41+
if (!m_molecule)
42+
m_error = tr("No molecule set in BackgroundFileFormat!");
43+
44+
if (!m_format)
45+
m_error = tr("No Io::FileFormat set in BackgroundFileFormat!");
46+
47+
if (m_fileName.isEmpty())
48+
m_error = tr("No file name set in BackgroundFileFormat!");
49+
50+
if (m_error.isEmpty()) {
51+
m_success =
52+
m_format->readFile(m_fileName.toLocal8Bit().data(), *m_molecule);
53+
54+
if (!m_success)
55+
m_error = QString::fromStdString(m_format->error());
56+
}
57+
58+
emit finished();
59+
}
60+
61+
void BackgroundFileFormat::write()
62+
{
63+
m_success = false;
64+
m_error.clear();
65+
66+
if (!m_molecule)
67+
m_error = tr("No molecule set in BackgroundFileFormat!");
68+
69+
if (!m_format)
70+
m_error = tr("No Io::FileFormat set in BackgroundFileFormat!");
71+
72+
if (m_fileName.isEmpty())
73+
m_error = tr("No file name set in BackgroundFileFormat!");
74+
75+
if (m_error.isEmpty()) {
76+
m_success =
77+
m_format->writeFile(m_fileName.toLocal8Bit().data(), *m_molecule);
78+
79+
if (!m_success)
80+
m_error = QString::fromStdString(m_format->error());
81+
}
82+
83+
emit finished();
84+
}
85+
86+
} // namespace Avogadro
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/******************************************************************************
2+
3+
This source file is part of the Avogadro project.
4+
5+
Copyright 2013 Kitware, Inc.
6+
7+
This source code is released under the New BSD License, (the "License").
8+
9+
Unless required by applicable law or agreed to in writing, software
10+
distributed under the License is distributed on an "AS IS" BASIS,
11+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
See the License for the specific language governing permissions and
13+
limitations under the License.
14+
15+
******************************************************************************/
16+
17+
#ifndef AVOGADRO_BACKGROUNDFILEFORMAT_H
18+
#define AVOGADRO_BACKGROUNDFILEFORMAT_H
19+
20+
#include <QtCore/QObject>
21+
#include <QtCore/QString>
22+
23+
namespace Avogadro {
24+
25+
namespace Core {
26+
class Molecule;
27+
}
28+
29+
namespace Io {
30+
class FileFormat;
31+
}
32+
33+
/**
34+
* @brief The BackgroundFileFormat class provides a thin QObject wrapper around
35+
* an instance of Io::FileFormat.
36+
*/
37+
class BackgroundFileFormat : public QObject
38+
{
39+
Q_OBJECT
40+
public:
41+
/**
42+
* This class takes ownership of @a format and will delete it when destructed.
43+
*/
44+
explicit BackgroundFileFormat(Io::FileFormat* format, QObject* aparent = 0);
45+
~BackgroundFileFormat();
46+
47+
/**
48+
* The molecule instance to read/write.
49+
* @{
50+
*/
51+
void setMolecule(Core::Molecule* mol) { m_molecule = mol; }
52+
Core::Molecule* molecule() const { return m_molecule; }
53+
/**@}*/
54+
55+
/**
56+
* The name of the file to read/write.
57+
* @{
58+
*/
59+
void setFileName(const QString& filename) { m_fileName = filename; }
60+
QString fileName() const { return m_fileName; }
61+
/**@}*/
62+
63+
/**
64+
* The Io::FileFormat to use.
65+
*/
66+
Io::FileFormat* fileFormat() const { return m_format; }
67+
68+
/**
69+
* @return True if the operation was successful.
70+
*/
71+
bool success() const { return m_success; }
72+
73+
/**
74+
* @return An error string, set if success() is false.
75+
*/
76+
QString error() const { return m_error; }
77+
78+
signals:
79+
80+
/**
81+
* Emitted when a call to read or write is called.
82+
*/
83+
void finished();
84+
85+
public slots:
86+
87+
/**
88+
* Use the fileFormat() to read fileName() into molecule().
89+
*/
90+
void read();
91+
92+
/**
93+
* Use the fileFormat() to write fileName() from molecule().
94+
*/
95+
void write();
96+
97+
private:
98+
Io::FileFormat* m_format;
99+
Core::Molecule* m_molecule;
100+
QString m_fileName;
101+
QString m_error;
102+
bool m_success;
103+
};
104+
105+
} // namespace Avogadro
106+
107+
#endif // AVOGADRO_BACKGROUNDFILEFORMAT_H

avogadro/qtplugins/customelements/customelements.cpp

+136-9
Original file line numberDiff line numberDiff line change
@@ -15,29 +15,42 @@
1515
******************************************************************************/
1616

1717
#include "customelements.h"
18+
#include "backgroundfileformat.h"
1819

1920
#include <avogadro/qtgui/customelementdialog.h>
21+
#include <avogadro/qtgui/fileformatdialog.h>
2022
#include <avogadro/qtgui/molecule.h>
2123

24+
#include <QtCore/QSettings>
25+
#include <QtCore/QThread>
2226
#include <QtWidgets/QAction>
27+
#include <QtWidgets/QMessageBox>
28+
#include <QtWidgets/QProgressDialog>
2329

2430
using Avogadro::QtGui::Molecule;
2531

2632
namespace Avogadro {
2733
namespace QtPlugins {
2834

2935
CustomElements::CustomElements(QObject* parent_)
30-
: Avogadro::QtGui::ExtensionPlugin(parent_), m_molecule(nullptr),
31-
m_reassignAction(new QAction(tr("Reassign &Custom Elements..."), this))
36+
: Avogadro::QtGui::ExtensionPlugin(parent_)
37+
, m_molecule(nullptr)
38+
, m_reassignUsingTool(nullptr)
39+
, m_reassignFromFile(nullptr)
40+
, m_fileReadThread(nullptr)
41+
, m_threadedReader(nullptr)
42+
, m_fileReadMolecule(nullptr)
43+
, m_progressDialog(nullptr)
3244
{
33-
connect(m_reassignAction, SIGNAL(triggered()), SLOT(reassign()));
45+
m_reassignUsingTool = new QAction(tr("Using &Mapping tool..."), this);
46+
m_reassignFromFile = new QAction(tr("From &File..."), this);
47+
connect(m_reassignUsingTool, SIGNAL(triggered()), SLOT(reassign()));
48+
connect(m_reassignFromFile, SIGNAL(triggered()), SLOT(importMapFile()));
3449

3550
updateReassignAction();
3651
}
3752

38-
CustomElements::~CustomElements()
39-
{
40-
}
53+
CustomElements::~CustomElements() {}
4154

4255
QString CustomElements::description() const
4356
{
@@ -46,12 +59,12 @@ QString CustomElements::description() const
4659

4760
QList<QAction*> CustomElements::actions() const
4861
{
49-
return QList<QAction*>() << m_reassignAction;
62+
return QList<QAction*>() << m_reassignUsingTool << m_reassignFromFile;
5063
}
5164

5265
QStringList CustomElements::menuPath(QAction*) const
5366
{
54-
return QStringList() << tr("&Build");
67+
return QStringList() << tr("&Build") << tr("Assign &Custom Elements...");
5568
}
5669

5770
void CustomElements::setMolecule(QtGui::Molecule* mol)
@@ -86,9 +99,123 @@ void CustomElements::reassign()
8699
}
87100
}
88101

102+
bool CustomElements::openFile(const QString& fileName, Io::FileFormat* reader)
103+
{
104+
if (fileName.isEmpty() || reader == nullptr) {
105+
delete reader;
106+
return false;
107+
}
108+
109+
QString ident = QString::fromStdString(reader->identifier());
110+
111+
// Prepare the background thread to read in the selected file.
112+
if (!m_fileReadThread)
113+
m_fileReadThread = new QThread(qobject_cast<QWidget*>(parent()));
114+
if (m_threadedReader)
115+
m_threadedReader->deleteLater();
116+
m_threadedReader = new BackgroundFileFormat(reader);
117+
if (m_fileReadMolecule)
118+
m_fileReadMolecule->deleteLater();
119+
m_fileReadMolecule = new Molecule(qobject_cast<QWidget*>(parent()));
120+
m_fileReadMolecule->setData("fileName", fileName.toLocal8Bit().data());
121+
m_threadedReader->moveToThread(m_fileReadThread);
122+
m_threadedReader->setMolecule(m_fileReadMolecule);
123+
m_threadedReader->setFileName(fileName);
124+
125+
// Setup a progress dialog in case file loading is slow
126+
m_progressDialog = new QProgressDialog(qobject_cast<QWidget*>(parent()));
127+
m_progressDialog->setRange(0, 0);
128+
m_progressDialog->setValue(0);
129+
m_progressDialog->setMinimumDuration(750);
130+
m_progressDialog->setWindowTitle(tr("Reading File"));
131+
m_progressDialog->setLabelText(
132+
tr("Opening file '%1'\nwith '%2'").arg(fileName).arg(ident));
133+
/// @todo Add API to abort file ops
134+
m_progressDialog->setCancelButton(nullptr);
135+
connect(m_fileReadThread, SIGNAL(started()), m_threadedReader, SLOT(read()));
136+
connect(m_threadedReader, SIGNAL(finished()), m_fileReadThread, SLOT(quit()));
137+
connect(m_threadedReader, SIGNAL(finished()),
138+
SLOT(backgroundReaderFinished()));
139+
140+
// Start the file operation
141+
m_fileReadThread->start();
142+
m_progressDialog->show();
143+
144+
return true;
145+
}
146+
147+
void CustomElements::backgroundReaderFinished()
148+
{
149+
QString fileName = m_threadedReader->fileName();
150+
if (m_progressDialog->wasCanceled()) {
151+
delete m_fileReadMolecule;
152+
} else if (m_threadedReader->success()) {
153+
if (!fileName.isEmpty()) {
154+
m_fileReadMolecule->setData("fileName", fileName.toLocal8Bit().data());
155+
} else {
156+
m_fileReadMolecule->setData("fileName", Core::Variant());
157+
}
158+
setMapFromMolecule(m_fileReadMolecule);
159+
} else {
160+
QMessageBox::critical(qobject_cast<QWidget*>(parent()), tr("File error"),
161+
tr("Error while reading file '%1':\n%2")
162+
.arg(fileName)
163+
.arg(m_threadedReader->error()));
164+
delete m_fileReadMolecule;
165+
}
166+
m_fileReadThread->deleteLater();
167+
m_fileReadThread = nullptr;
168+
m_threadedReader->deleteLater();
169+
m_threadedReader = nullptr;
170+
m_fileReadMolecule = nullptr;
171+
m_progressDialog->hide();
172+
m_progressDialog->deleteLater();
173+
m_progressDialog = nullptr;
174+
}
175+
176+
void CustomElements::setMapFromMolecule(QtGui::Molecule* mol)
177+
{
178+
if (mol->atomCount() != m_molecule->atomCount()) {
179+
QMessageBox::critical(
180+
qobject_cast<QWidget*>(parent()), tr("Error"),
181+
tr("Atom count mismatch.\nExpected %1 atoms, found %2.")
182+
.arg(m_molecule->atomCount())
183+
.arg(mol->atomCount()));
184+
} else {
185+
size_t n = m_molecule->atomCount();
186+
for (size_t i = 0; i < n; ++i) {
187+
m_molecule->atom(i).setAtomicNumber(mol->atom(i).atomicNumber());
188+
}
189+
m_molecule->emitChanged(Molecule::Atoms | Molecule::Modified);
190+
}
191+
}
192+
193+
void CustomElements::importMapFile()
194+
{
195+
QSettings settings;
196+
QString dir = settings.value("MainWindow/lastOpenDir").toString();
197+
198+
QtGui::FileFormatDialog::FormatFilePair reply =
199+
QtGui::FileFormatDialog::fileToRead(qobject_cast<QWidget*>(parent()),
200+
tr("Open Molecule"), dir);
201+
202+
if (reply.first == NULL) // user cancel
203+
return;
204+
205+
dir = QFileInfo(reply.second).absoluteDir().absolutePath();
206+
settings.setValue("MainWindow/lastOpenDir", dir);
207+
208+
if (!openFile(reply.second, reply.first->newInstance())) {
209+
QMessageBox::information(
210+
qobject_cast<QWidget*>(parent()), tr("Cannot open file"),
211+
tr("Can't open supplied file %1").arg(reply.second));
212+
}
213+
}
214+
89215
void CustomElements::updateReassignAction()
90216
{
91-
m_reassignAction->setEnabled(m_molecule && m_molecule->hasCustomElements());
217+
m_reassignUsingTool->setEnabled(m_molecule);
218+
m_reassignFromFile->setEnabled(m_molecule);
92219
}
93220

94221
} // namespace QtPlugins

0 commit comments

Comments
 (0)