/**********************************************************************
DrawCommand - Set of command classes for drawing.
Copyright (C) 2007 Donald Ephraim Curtis
Copyright (C) 2008,2009 Tim Vandermeersch
Copyright (C) 2008 Geoffrey Hutchison
This file is part of the Avogadro molecular editor project.
For more information, see
Avogadro is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
Avogadro is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
02110-1301, USA.
**********************************************************************/
#include "drawcommand.h"
#include
#include
#include
#include
#include
// use this for creating drawcommand unit tests
// #define DEBUG_COMMANDS 1
using namespace OpenBabel;
namespace Avogadro {
/////////////////////////////////////////////////////////////////////////////
// Adjust Hydrogens PreCommand
/////////////////////////////////////////////////////////////////////////////
class AdjustHydrogensPreCommandPrivate {
public:
AdjustHydrogensPreCommandPrivate() : molecule(0) {};
Molecule *molecule;
QList atomIds;
QHash > hydrogenIds;
QHash > bondIds;
};
AdjustHydrogensPreCommand::AdjustHydrogensPreCommand(Molecule *molecule, const QList &atomIds)
: d(new AdjustHydrogensPreCommandPrivate)
{
#ifdef DEBUG_COMMANDS
qDebug() << "AdjustHydrogensPreCommand()";
#endif
d->molecule = molecule;
d->atomIds = atomIds;
constructor();
}
AdjustHydrogensPreCommand::AdjustHydrogensPreCommand(Molecule *molecule, unsigned long atomId)
: d(new AdjustHydrogensPreCommandPrivate)
{
#ifdef DEBUG_COMMANDS
qDebug() << "AdjustHydrogensPreCommand()";
#endif
d->molecule = molecule;
d->atomIds.append(atomId);
constructor();
}
void AdjustHydrogensPreCommand::constructor()
{
foreach (unsigned long id, d->atomIds) {
Atom *atom = d->molecule->atomById(id);
if (atom) {
if (atom->isHydrogen())
continue;
foreach (unsigned long nbrId, atom->neighbors()) {
Atom *nbr = d->molecule->atomById(nbrId);
if (nbr)
if (nbr->isHydrogen()) {
d->hydrogenIds[id].append(nbrId);
d->bondIds[id].append(d->molecule->bond(id, nbrId)->id());
}
}
}
}
}
AdjustHydrogensPreCommand::~AdjustHydrogensPreCommand()
{
delete d;
}
void AdjustHydrogensPreCommand::undo()
{
#ifdef DEBUG_COMMANDS
qDebug() << "AdjustHydrogensPreCommand::undo()";
#endif
foreach (unsigned long id, d->atomIds) {
Atom *atom = d->molecule->atomById(id);
if (atom) {
if (atom->isHydrogen())
continue;
d->molecule->addHydrogens(atom, d->hydrogenIds.value(atom->id()), d->bondIds.value(atom->id()));
}
}
}
void AdjustHydrogensPreCommand::redo()
{
#ifdef DEBUG_COMMANDS
qDebug() << "AdjustHydrogensPreCommand::redo()";
#endif
foreach (unsigned long id, d->atomIds) {
Atom *atom = d->molecule->atomById(id);
if (atom) {
if (atom->isHydrogen())
continue;
d->molecule->removeHydrogens(atom);
}
}
}
/////////////////////////////////////////////////////////////////////////////
// Adjust Hydrogens PostCommand
/////////////////////////////////////////////////////////////////////////////
class AdjustHydrogensPostCommandPrivate {
public:
AdjustHydrogensPostCommandPrivate() : molecule(0) {};
Molecule *molecule;
QList atomIds;
QHash > hydrogenIds;
QHash > bondIds;
};
AdjustHydrogensPostCommand::AdjustHydrogensPostCommand(Molecule *molecule, const QList &atomIds)
: d(new AdjustHydrogensPostCommandPrivate)
{
#ifdef DEBUG_COMMANDS
qDebug() << "AdjustHydrogensPostCommand()";
#endif
d->molecule = molecule;
d->atomIds = atomIds;
}
AdjustHydrogensPostCommand::AdjustHydrogensPostCommand(Molecule *molecule, unsigned long atomId)
: d(new AdjustHydrogensPostCommandPrivate)
{
#ifdef DEBUG_COMMANDS
qDebug() << "AdjustHydrogensPostCommand()";
#endif
d->molecule = molecule;
d->atomIds.append(atomId);
}
AdjustHydrogensPostCommand::~AdjustHydrogensPostCommand()
{
delete d;
}
void AdjustHydrogensPostCommand::undo()
{
#ifdef DEBUG_COMMANDS
qDebug() << "AdjustHydrogensPostCommand::undo()";
#endif
foreach (unsigned long id, d->atomIds) {
Atom *atom = d->molecule->atomById(id);
if (atom) {
if (atom->isHydrogen())
continue;
d->molecule->removeHydrogens(atom);
}
}
}
void AdjustHydrogensPostCommand::redo()
{
#ifdef DEBUG_COMMANDS
qDebug() << "AdjustHydrogensPostCommand::redo()";
#endif
if (d->hydrogenIds.isEmpty()) {
foreach (unsigned long id, d->atomIds) {
Atom *atom = d->molecule->atomById(id);
if (atom) {
if (atom->isHydrogen())
continue;
d->molecule->addHydrogens(atom); // new ids...
// save the new ids for reuse
foreach (unsigned long nbrId, atom->neighbors()) {
Atom *nbr = d->molecule->atomById(nbrId);
if (nbr)
if (nbr->isHydrogen()) {
Bond *bond = d->molecule->bond(id, nbrId);
if (!bond) {
#ifdef DEBUG_COMMANDS
qDebug() << "Error, AdjustHydrogensPostCommand::redo...";
#endif
continue;
}
d->hydrogenIds[id].append(nbrId);
d->bondIds[id].append(bond->id());
}
}
}
}
} else {
// reuse ids from before
foreach (unsigned long id, d->atomIds) {
Atom *atom = d->molecule->atomById(id);
if (atom) {
if (atom->isHydrogen())
continue;
d->molecule->addHydrogens(atom, d->hydrogenIds.value(atom->id()), d->bondIds.value(atom->id()));
}
}
}
}
/////////////////////////////////////////////////////////////////////////////
// Add Atom
/////////////////////////////////////////////////////////////////////////////
class AddAtomDrawCommandPrivate {
public:
AddAtomDrawCommandPrivate() : molecule(0), atom(0), id(-1), prevId(false), postCommand(0) {};
Molecule *molecule;
Atom *atom;
Eigen::Vector3d pos;
unsigned int element;
unsigned long id;
bool prevId;
AdjustHydrogens::Options adjustHydrogens;
QUndoCommand *postCommand;
};
AddAtomDrawCommand::AddAtomDrawCommand(Molecule *molecule, const Eigen::Vector3d& pos, unsigned int element,
AdjustHydrogens::Options adjustHydrogens) : d(new AddAtomDrawCommandPrivate)
{
#ifdef DEBUG_COMMANDS
qDebug() << "AddAtomDrawCommand_ctor1(element=" << element << ", adj=" << adjustHydrogens << ")";
qDebug() << "adj =" << adjustHydrogens;
#endif
setText(QObject::tr("Add Atom"));
d->molecule = molecule;
d->pos = pos;
d->element = element;
d->adjustHydrogens = adjustHydrogens;
}
AddAtomDrawCommand::AddAtomDrawCommand(Molecule *molecule, Atom *atom, AdjustHydrogens::Options adjustHydrogens)
: d(new AddAtomDrawCommandPrivate)
{
#ifdef DEBUG_COMMANDS
qDebug() << "AddAtomDrawCommand_ctor2(element=" << atom->atomicNumber() << ", adj=" << adjustHydrogens << ")";
qDebug() << "adj =" << adjustHydrogens;
#endif
setText(QObject::tr("Add Atom"));
d->molecule = molecule;
d->pos = *atom->pos();
d->element = atom->atomicNumber();
d->atom = atom;
d->id = atom->id();
d->adjustHydrogens = adjustHydrogens;
}
AddAtomDrawCommand::~AddAtomDrawCommand()
{
if (d->postCommand) {
delete d->postCommand;
d->postCommand = 0;
}
delete d;
}
void AddAtomDrawCommand::undo()
{
#ifdef DEBUG_COMMANDS
qDebug() << "AddAtomDrawCommand::undo()";
#endif
Atom *atom = d->molecule->atomById(d->id);
if (atom) {
// Remove the previously add hydrogens if needed
if (d->adjustHydrogens & AdjustHydrogens::RemoveOnUndo)
d->postCommand->undo();
d->molecule->removeAtom(atom);
}
}
void AddAtomDrawCommand::redo()
{
#ifdef DEBUG_COMMANDS
qDebug() << "AddAtomDrawCommand::redo()";
#endif
if (d->atom) { // initial creation
if (d->adjustHydrogens != AdjustHydrogens::Never) {
d->postCommand = new AdjustHydrogensPostCommand(d->molecule, d->id);
if (d->adjustHydrogens & AdjustHydrogens::AddOnRedo)
d->postCommand->redo();
}
d->atom = 0;
return;
}
Atom *atom = 0;
if (d->id != static_cast(-1)) {
atom = d->molecule->addAtom(d->id);
} else {
atom = d->molecule->addAtom();
d->id = atom->id();
}
atom->setPos(d->pos);
atom->setAtomicNumber(d->element);
if (d->adjustHydrogens != AdjustHydrogens::Never) {
if (!d->postCommand)
d->postCommand = new AdjustHydrogensPostCommand(d->molecule, d->id);
if (d->adjustHydrogens & AdjustHydrogens::AddOnRedo)
d->postCommand->redo();
}
atom->update();
}
/////////////////////////////////////////////////////////////////////////////
// Delete Atom
/////////////////////////////////////////////////////////////////////////////
class DeleteAtomDrawCommandPrivate {
public:
DeleteAtomDrawCommandPrivate() : id(-1), preCommand(0), postCommand(0) {};
Molecule *molecule;
unsigned long id;
QList bonds;
QList bondOrders;
QList neighbors;
Eigen::Vector3d pos;
unsigned int element;
int adjustHydrogens;
QUndoCommand *preCommand;
QUndoCommand *postCommand;
};
DeleteAtomDrawCommand::DeleteAtomDrawCommand(Molecule *molecule, int index, int adjustHydrogens)
: d(new DeleteAtomDrawCommandPrivate)
{
setText(QObject::tr("Delete Atom"));
d->molecule = molecule;
Atom *atom = molecule->atom(index);
d->id = atom->id();
#ifdef DEBUG_COMMANDS
qDebug() << "DeleteAtomDrawCommand(id=" << d->id << ", adj=" << adjustHydrogens << ")";
#endif
d->element = atom->atomicNumber();
d->pos = *(atom->pos());
d->adjustHydrogens = adjustHydrogens;
}
DeleteAtomDrawCommand::~DeleteAtomDrawCommand()
{
if (d->preCommand) {
delete d->preCommand;
d->preCommand = 0;
}
if (d->postCommand) {
delete d->postCommand;
d->postCommand = 0;
}
delete d;
}
void DeleteAtomDrawCommand::undo()
{
#ifdef DEBUG_COMMANDS
qDebug() << "DeleteAtomDrawCommand::undo()";
#endif
if (d->adjustHydrogens)
d->postCommand->undo();
Atom *atom = d->molecule->addAtom(d->id);
atom->setAtomicNumber(d->element);
atom->setPos(d->pos);
// Add the bonds again...
foreach (unsigned long id, d->bonds) {
int index = d->bonds.indexOf(id);
Bond *bond = d->molecule->addBond(id);
bond->setAtoms(d->id, d->neighbors.at(index), d->bondOrders.at(index));
}
if (d->adjustHydrogens)
d->preCommand->undo();
d->molecule->update();
}
void DeleteAtomDrawCommand::redo()
{
#ifdef DEBUG_COMMANDS
qDebug() << "DeleteAtomDrawCommand::redo()";
#endif
Atom *atom = d->molecule->atomById(d->id);
d->bonds.clear();
d->bondOrders.clear();
d->neighbors.clear();
foreach (unsigned long id, atom->neighbors()) {
Atom *nbr = d->molecule->atomById(id);
if (nbr->isHydrogen()) continue;
Bond *bond = d->molecule->bond(id, atom->id());
d->neighbors.append(id);
d->bonds.append(bond->id());
d->bondOrders.append(bond->order());
}
if (atom) {
QList neighbors;
if (d->adjustHydrogens) {
if (!d->preCommand) {
QList ids;
foreach (unsigned long id, atom->neighbors()) {
if (!d->molecule->atomById(id)->isHydrogen())
neighbors.append(id);
ids.append(id);
}
ids.append(atom->id());
// Delete all hydrogens on the to be deleted atom and its heavy atom neighbors
// The hydrogen ids are saved along with thier bond ids
d->preCommand = new AdjustHydrogensPreCommand(d->molecule, ids);
}
d->preCommand->redo();
}
// Delete the atom, also deletes the bonds
d->molecule->removeAtom(atom);
if (d->adjustHydrogens) {
if (!d->postCommand)
// Add hydrogens to the heavy atom neighbors of the delted atom
// Uses new ids the first time, reuses these on successive calls
d->postCommand = new AdjustHydrogensPostCommand(d->molecule, neighbors);
d->postCommand->redo();
}
d->molecule->update();
}
}
/////////////////////////////////////////////////////////////////////////////
// Add Bond
/////////////////////////////////////////////////////////////////////////////
class AddBondDrawCommandPrivate {
public:
AddBondDrawCommandPrivate() : molecule(0), bond(0), id(-1), beginAtomId(-1), endAtomId(-1),
prevId(false), preCommandBegin(0), postCommandBegin(0), preCommandEnd(0),
postCommandEnd(0) {}
Molecule *molecule;
Bond *bond;
unsigned long id;
unsigned int beginAtomId;
unsigned int endAtomId;
bool prevId;
Eigen::Vector3d pos;
unsigned int order;
AdjustHydrogens::Options adjustHydrogensBegin;
AdjustHydrogens::Options adjustHydrogensEnd;
QUndoCommand *preCommandBegin;
QUndoCommand *postCommandBegin;
QUndoCommand *preCommandEnd;
QUndoCommand *postCommandEnd;
};
AddBondDrawCommand::AddBondDrawCommand(Molecule *molecule, Atom *beginAtom, Atom *endAtom,
unsigned int order, AdjustHydrogens::Options adjustHydrogensOnBeginAtom,
AdjustHydrogens::Options adjustHydrogensOnEndAtom) : d(new AddBondDrawCommandPrivate)
{
#ifdef DEBUG_COMMANDS
qDebug() << "AddBondDrawCommand(begin=" << beginAtom->id() << ", end=" << endAtom->id()
<< ", adjBegin=" << adjustHydrogensOnBeginAtom
<< ", adjEnd=" << adjustHydrogensOnEndAtom << ")";
#endif
setText(QObject::tr("Add Bond"));
d->molecule = molecule;
d->beginAtomId = beginAtom->id();
d->endAtomId = endAtom->id();
d->order = order;
d->adjustHydrogensBegin = adjustHydrogensOnBeginAtom;
d->adjustHydrogensEnd = adjustHydrogensOnEndAtom;
}
AddBondDrawCommand::AddBondDrawCommand(Molecule *molecule, Bond *bond,
AdjustHydrogens::Options adjustHydrogensOnBeginAtom,
AdjustHydrogens::Options adjustHydrogensOnEndAtom) : d(new AddBondDrawCommandPrivate)
{
#ifdef DEBUG_COMMANDS
qDebug() << "AddBondDrawCommand(begin=" << bond->beginAtomId() << ", end=" << bond->endAtomId()
<< ", adjBegin=" << adjustHydrogensOnBeginAtom
<< ", adjEnd=" << adjustHydrogensOnEndAtom << ")";
#endif
setText(QObject::tr("Add Bond"));
d->molecule = molecule;
d->beginAtomId = bond->beginAtomId();
d->endAtomId = bond->endAtomId();
d->order = bond->order();
d->bond = bond;
d->prevId = true;
d->id = bond->id();
d->adjustHydrogensBegin = adjustHydrogensOnBeginAtom;
d->adjustHydrogensEnd = adjustHydrogensOnEndAtom;
}
AddBondDrawCommand::~AddBondDrawCommand()
{
if (d->preCommandBegin) {
delete d->preCommandBegin;
d->preCommandBegin = 0;
}
if (d->postCommandBegin) {
delete d->postCommandBegin;
d->postCommandBegin = 0;
}
if (d->preCommandEnd) {
delete d->preCommandEnd;
d->preCommandEnd = 0;
}
if (d->postCommandEnd) {
delete d->postCommandEnd;
d->postCommandEnd = 0;
}
delete d;
}
void AddBondDrawCommand::undo()
{
#ifdef DEBUG_COMMANDS
qDebug() << "AddBondDrawCommand::undo()";
#endif
Bond *bond = d->molecule->bondById(d->id);
if (bond) {
// remove the hydrogens added after the bond was created
if (d->adjustHydrogensBegin & AdjustHydrogens::RemoveOnUndo)
d->postCommandBegin->undo();
if (d->adjustHydrogensEnd & AdjustHydrogens::RemoveOnUndo)
d->postCommandEnd->undo();
// remove the bond
d->molecule->removeBond(bond);
// restore the hydrogens to the way they were before the bond was added
if (d->adjustHydrogensBegin & AdjustHydrogens::AddOnUndo)
d->preCommandBegin->undo();
if (d->adjustHydrogensEnd & AdjustHydrogens::AddOnUndo)
d->preCommandEnd->undo();
d->molecule->update();
}
}
void AddBondDrawCommand::redo()
{
#ifdef DEBUG_COMMANDS
qDebug() << "AddBondDrawCommand::redo()";
#endif
if (d->bond) { // already created the bond
// adjust hydrogens on begin atom if needed
if (d->adjustHydrogensBegin != AdjustHydrogens::Never) {
QList ids;
ids.append(d->bond->beginAtomId());
d->preCommandBegin = new AdjustHydrogensPreCommand(d->molecule, d->bond->beginAtomId());
// remove hydrogens from begin and/or end atom
if (d->adjustHydrogensBegin & AdjustHydrogens::RemoveOnRedo)
d->preCommandBegin->redo();
d->postCommandBegin = new AdjustHydrogensPostCommand(d->molecule, d->bond->beginAtomId());
// add hydrogens again
if (d->adjustHydrogensBegin & AdjustHydrogens::AddOnRedo)
d->postCommandBegin->redo();
}
// adjust hydrogens on end atom if needed
if (d->adjustHydrogensEnd != AdjustHydrogens::Never) {
d->preCommandEnd = new AdjustHydrogensPreCommand(d->molecule, d->bond->endAtomId());
// remove hydrogens from begin and/or end atom
if (d->adjustHydrogensEnd & AdjustHydrogens::RemoveOnRedo)
d->preCommandEnd->redo();
d->postCommandEnd = new AdjustHydrogensPostCommand(d->molecule, d->bond->endAtomId());
// add hydrogens again
if (d->adjustHydrogensEnd & AdjustHydrogens::AddOnRedo)
d->postCommandEnd->redo();
}
d->bond = 0;
return;
}
// adjust hydrogens on begin atom if needed
if (d->adjustHydrogensBegin != AdjustHydrogens::Never) {
if (!d->preCommandBegin)
d->preCommandBegin = new AdjustHydrogensPreCommand(d->molecule, d->beginAtomId);
// remove hydrogens from begin and/or end atom
if (d->adjustHydrogensBegin & AdjustHydrogens::RemoveOnRedo)
d->preCommandBegin->redo();
}
// adjust hydrogens on end atom if needed
if (d->adjustHydrogensEnd != AdjustHydrogens::Never) {
if (!d->preCommandEnd)
d->preCommandEnd = new AdjustHydrogensPreCommand(d->molecule, d->endAtomId);
// remove hydrogens from begin and/or end atom
if (d->adjustHydrogensEnd & AdjustHydrogens::RemoveOnRedo)
d->preCommandEnd->redo();
}
Atom *beginAtom = d->molecule->atomById(d->beginAtomId);
Atom *endAtom = d->molecule->atomById(d->endAtomId);
if (!beginAtom || !endAtom)
return;
Bond *bond;
if (d->id != static_cast(-1)) {
bond = d->molecule->addBond(d->id);
} else {
bond = d->molecule->addBond();
d->id = bond->id();
}
bond->setOrder(d->order);
bond->setBegin(beginAtom);
bond->setEnd(endAtom);
// adjust hydrogens on begin atom if needed
if (d->adjustHydrogensBegin != AdjustHydrogens::Never) {
if (!d->postCommandBegin)
d->postCommandBegin = new AdjustHydrogensPostCommand(d->molecule, d->beginAtomId);
// remove hydrogens from begin and/or end atom
if (d->adjustHydrogensBegin & AdjustHydrogens::AddOnRedo)
d->postCommandBegin->redo();
}
// adjust hydrogens on end atom if needed
if (d->adjustHydrogensEnd != AdjustHydrogens::Never) {
if (!d->postCommandEnd)
d->postCommandEnd = new AdjustHydrogensPostCommand(d->molecule, d->endAtomId);
// remove hydrogens from begin and/or end atom
if (d->adjustHydrogensEnd & AdjustHydrogens::AddOnRedo)
d->postCommandEnd->redo();
}
d->molecule->update();
}
/////////////////////////////////////////////////////////////////////////////
// Delete Bond
/////////////////////////////////////////////////////////////////////////////
class DeleteBondDrawCommandPrivate {
public:
DeleteBondDrawCommandPrivate() : id(-1) {};
Molecule *molecule;
Molecule moleculeCopy;
unsigned long id;
int adjustHydrogens;
};
DeleteBondDrawCommand::DeleteBondDrawCommand(Molecule *molecule, int index, int adjustHydrogens) : d(new DeleteBondDrawCommandPrivate)
{
setText(QObject::tr("Delete Bond"));
d->molecule = molecule;
d->moleculeCopy = (*(molecule));
d->id = molecule->bond(index)->id();
d->adjustHydrogens = adjustHydrogens;
}
DeleteBondDrawCommand::~DeleteBondDrawCommand()
{
delete d;
}
void DeleteBondDrawCommand::undo()
{
#ifdef DEBUG_COMMANDS
qDebug() << "DeleteBondDrawCommand::undo()";
#endif
*d->molecule = d->moleculeCopy;
d->molecule->update();
}
void DeleteBondDrawCommand::redo()
{
#ifdef DEBUG_COMMANDS
qDebug() << "DeleteBondDrawCommand::redo()";
#endif
Bond *bond = d->molecule->bondById(d->id);
if(bond)
{
d->molecule->removeBond(bond);
if (d->adjustHydrogens) {
Atom *a1, *a2;
a1 = d->molecule->atomById(bond->beginAtomId());
a2 = d->molecule->atomById(bond->endAtomId());
d->molecule->removeHydrogens(a1);
d->molecule->removeHydrogens(a2);
d->molecule->addHydrogens(a1);
d->molecule->addHydrogens(a2);
}
d->molecule->update();
}
}
/////////////////////////////////////////////////////////////////////////////
// Change Element
/////////////////////////////////////////////////////////////////////////////
class ChangeElementDrawCommandPrivate {
public:
ChangeElementDrawCommandPrivate() : molecule(0), id(-1), preCommand(0), postCommand(0) {};
Molecule *molecule;
unsigned int newElement, oldElement;
unsigned long id;
int adjustHydrogens;
QUndoCommand *preCommand;
QUndoCommand *postCommand;
};
ChangeElementDrawCommand::ChangeElementDrawCommand(Molecule *molecule, Atom *atom, unsigned int oldElement,
int adjustHydrogens) : d(new ChangeElementDrawCommandPrivate)
{
#ifdef DEBUG_COMMANDS
qDebug() << "ChangeElementDrawCommand(id=" << atom->id() << ", old=" << oldElement << ", adj=" << adjustHydrogens << ")";
#endif
setText(QObject::tr("Change Element"));
d->molecule = molecule;
d->newElement = atom->atomicNumber();
d->oldElement = oldElement;
d->id = atom->id();
d->adjustHydrogens = adjustHydrogens;
}
ChangeElementDrawCommand::~ChangeElementDrawCommand()
{
if (d->preCommand) {
delete d->preCommand;
d->preCommand = 0;
}
if (d->postCommand) {
delete d->postCommand;
d->postCommand = 0;
}
delete d;
}
void ChangeElementDrawCommand::undo()
{
#ifdef DEBUG_COMMANDS
qDebug() << "ChangeElementDrawCommand::undo()";
#endif
Atom *atom = d->molecule->atomById(d->id);
if (atom) {
// Remove Hydrogens if needed
if (d->adjustHydrogens)
d->postCommand->undo();
// Make sure we call BeginModify / EndModify (e.g., PR#1720879)
atom->setAtomicNumber(d->oldElement);
// Remove Hydrogens if needed
if (d->adjustHydrogens)
d->preCommand->undo();
d->molecule->update();
}
}
void ChangeElementDrawCommand::redo()
{
#ifdef DEBUG_COMMANDS
qDebug() << "ChangeElementDrawCommand::redo()";
#endif
Atom *atom = d->molecule->atomById(d->id);
if (atom) {
// Remove Hydrogens if needed
if (d->adjustHydrogens) {
if (!d->preCommand) {
QList ids;
ids.append(d->id);
d->preCommand = new AdjustHydrogensPreCommand(d->molecule, ids);
}
d->preCommand->redo();
}
// Make sure we call BeginModify / EndModify (e.g., PR#1720879)
atom->setAtomicNumber(d->newElement);
// Add hydrogens again if needed
if (d->adjustHydrogens) {
if (!d->postCommand) {
QList ids;
ids.append(d->id);
d->postCommand = new AdjustHydrogensPostCommand(d->molecule, ids);
}
d->postCommand->redo();
}
d->molecule->update();
}
}
/////////////////////////////////////////////////////////////////////////////
// Change Bond Order
/////////////////////////////////////////////////////////////////////////////
class ChangeBondOrderDrawCommandPrivate {
public:
ChangeBondOrderDrawCommandPrivate() : molecule(0), id(-1), preCommand(0), postCommand(0) {};
Molecule *molecule;
unsigned long id;
unsigned int addBondOrder, oldBondOrder;
int adjustHydrogens;
QUndoCommand *preCommand;
QUndoCommand *postCommand;
};
ChangeBondOrderDrawCommand::ChangeBondOrderDrawCommand(Molecule *molecule, Bond *bond,
unsigned int oldBondOrder, int adjustHydrogens) : d(new ChangeBondOrderDrawCommandPrivate)
{
#ifdef DEBUG_COMMANDS
qDebug() << "ChangeBondOrderDrawCommand(id=" << bond->id() << ", old=" << oldBondOrder
<< ", adj=" << adjustHydrogens << ")";
#endif
setText(QObject::tr("Change Bond Order"));
d->molecule = molecule;
d->id = bond->id();
d->addBondOrder = bond->order();
d->oldBondOrder = oldBondOrder;
d->adjustHydrogens = adjustHydrogens;
}
ChangeBondOrderDrawCommand::~ChangeBondOrderDrawCommand()
{
if (d->preCommand) {
delete d->preCommand;
d->preCommand = 0;
}
if (d->postCommand) {
delete d->postCommand;
d->postCommand = 0;
}
delete d;
}
void ChangeBondOrderDrawCommand::undo()
{
#ifdef DEBUG_COMMANDS
qDebug() << "ChangeBondOrderDrawCommand::undo()";
#endif
Bond *bond = d->molecule->bondById(d->id);
if (bond) {
// Remove Hydrogens if needed
if (d->adjustHydrogens)
d->postCommand->undo();
// Make sure we call BeginModify / EndModify (e.g., PR#1720879)
bond->setOrder(d->oldBondOrder);
// Add Hydrogens if needed
if (d->adjustHydrogens)
d->preCommand->undo();
d->molecule->update();
}
}
void ChangeBondOrderDrawCommand::redo()
{
#ifdef DEBUG_COMMANDS
qDebug() << "ChangeBondOrderDrawCommand::redo()";
#endif
Bond *bond = d->molecule->bondById(d->id);
if (bond) {
// Remove Hydrogens if needed
if (d->adjustHydrogens) {
if (!d->preCommand) {
QList ids;
ids.append(bond->beginAtomId());
ids.append(bond->endAtomId());
d->preCommand = new AdjustHydrogensPreCommand(d->molecule, ids);
}
d->preCommand->redo();
}
// Make sure we call BeginModify / EndModify (e.g., PR#1720879)
bond->setOrder(d->addBondOrder);
// Add Hydrogens if needed
if (d->adjustHydrogens) {
if (!d->postCommand) {
QList ids;
ids.append(bond->beginAtomId());
ids.append(bond->endAtomId());
d->postCommand = new AdjustHydrogensPostCommand(d->molecule, ids);
}
d->postCommand->redo();
}
d->molecule->update();
}
}
/////////////////////////////////////////////////////////////////////////////
// Insert Fragment
/////////////////////////////////////////////////////////////////////////////
class InsertFragmentCommandPrivate {
public:
InsertFragmentCommandPrivate() : molecule(0), generatedMolecule(0) {};
Molecule *molecule;
Molecule moleculeCopy, generatedMolecule;
};
InsertFragmentCommand::InsertFragmentCommand(Molecule *molecule, Molecule &generatedMolecule)
: d(new InsertFragmentCommandPrivate)
{
setText(QObject::tr("Insert Fragment"));
d->molecule = molecule;
d->moleculeCopy = *molecule;
d->generatedMolecule = generatedMolecule;
}
InsertFragmentCommand::~InsertFragmentCommand()
{
delete d;
}
void InsertFragmentCommand::undo()
{
*(d->molecule) = d->moleculeCopy;
d->molecule->update();
}
void InsertFragmentCommand::redo()
{
*(d->molecule) += d->generatedMolecule;
d->molecule->update();
}
} // end namespace Avogadro