/*
* Project: MoleCuilder
* Description: creates and alters molecular systems
* Copyright (C) 2015 Frederik Heber. All rights reserved.
*
*
* This file is part of MoleCuilder.
*
* MoleCuilder 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.
*
* MoleCuilder 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 MoleCuilder. If not, see .
*/
/*
* QtObservedAtom.cpp
*
* Created on: Oct 28, 2015
* Author: heber
*/
// include config.h
#ifdef HAVE_CONFIG_H
#include
#endif
#include "QtObservedAtom.hpp"
#include "UIElements/Qt4/InstanceBoard/QtObservedInstanceBoard.hpp"
#include "CodePatterns/MemDebug.hpp"
#include
#include "Atom/atom.hpp"
#include "Bond/bond.hpp"
#include "Descriptors/AtomIdDescriptor.hpp"
#include "Element/element.hpp"
#include "World.hpp"
#include "UIElements/Qt4/InstanceBoard/ObservedValue_wCallback.hpp"
using namespace boost::assign;
static const Observable::channels_t getAtomBondsChannels()
{
Observable::channels_t channels;
channels += AtomObservable::BondsAdded, AtomObservable::BondsRemoved;
return channels;
}
static const Observable::channels_t getAllObservedChannels()
{
Observable::channels_t channels;
channels +=
AtomObservable::IndexChanged,
AtomObservable::BondsAdded,
AtomObservable::BondsRemoved,
AtomObservable::MoleculeChanged,
AtomObservable::NameChanged,
AtomObservable::ElementChanged,
AtomObservable::PositionChanged,
AtomObservable::SelectionChanged;
return channels;
}
// static entities
const Observable::channels_t
QtObservedAtom::AtomIndexChannels(1, AtomObservable::IndexChanged);
const Observable::channels_t
QtObservedAtom::AtomBondsChannels(getAtomBondsChannels());
const Observable::channels_t
QtObservedAtom::AtomElementChannels(1, AtomObservable::ElementChanged);
const Observable::channels_t
QtObservedAtom::MoleculeChangedChannels(1, AtomObservable::MoleculeChanged);
const Observable::channels_t
QtObservedAtom::AtomNameChannels(1, AtomObservable::NameChanged);
const Observable::channels_t
QtObservedAtom::AtomPositionChannels(1, AtomObservable::PositionChanged);
const Observable::channels_t
QtObservedAtom::AtomSelectedChannels(1, AtomObservable::SelectionChanged);
QtObservedAtom::QtObservedAtom(
const atomId_t _id,
const atom * const _atom,
QtObservedInstanceBoard &_board,
QWidget * _parent) :
QWidget(_parent),
Observer("QtObservedAtom"),
subjectKilledCount(0),
AllsignedOnChannels(getAllObservedChannels().size()),
signedOffChannels(0),
owner(NULL),
oldId(_id),
index(static_cast(const_cast(this))),
board(_board),
BoardIsGone(false),
ObservedValues(QtObservedAtom::MAX_ObservedTypes)
{
boost::function atomSubjectKilled(
boost::bind(&QtObservedAtom::countValuesSubjectKilled,
boost::ref(*this),
boost::bind(&QtObservedAtom::getIndex, boost::ref(*this))));
initObservedValues( ObservedValues, _id, _atom, atomSubjectKilled);
// activating Observer is done by ObservedValueContainer when it's inserted
}
QtObservedAtom::~QtObservedAtom()
{
boost::any_cast *>(ObservedValues[AtomIndex])->noteCallBackIsGone();
boost::any_cast *>(ObservedValues[AtomBonds])->noteCallBackIsGone();
boost::any_cast *>(ObservedValues[AtomElement])->noteCallBackIsGone();
boost::any_cast *>(ObservedValues[MoleculeRef])->noteCallBackIsGone();
boost::any_cast *>(ObservedValues[AtomName])->noteCallBackIsGone();
boost::any_cast *>(ObservedValues[AtomPosition])->noteCallBackIsGone();
boost::any_cast *>(ObservedValues[AtomSelected])->noteCallBackIsGone();
deactivateObserver();
destroyObservedValues(ObservedValues);
}
const atom * const QtObservedAtom::getAtomConst(const atomId_t _id)
{
const atom * const _atom = const_cast(World::getInstance()).
getAtom(AtomById(_id));
return _atom;
}
atom * const QtObservedAtom::getAtom(const atomId_t _id)
{
atom * const _atom = World::getInstance().getAtom(AtomById(_id));
return _atom;
}
#ifdef HAVE_INLINE
inline
#endif
atomId_t QtObservedAtom::updateIndex(const atom &_atomref)
{
return _atomref.getId();
}
QtObservedAtom::ListOfBonds_t QtObservedAtom::updateBonds(
const atom &_atom)
{
ListOfBonds_t ListOfBonds;
// make sure bonds is up-to-date
const BondList ListBonds = _atom.getListOfBonds();
for (BondList::const_iterator iter = ListBonds.begin();
iter != ListBonds.end();
++iter)
ListOfBonds.insert( ListOfBonds.end(), std::make_pair(
(*iter)->leftatom->getId(),
(*iter)->rightatom->getId()) );
return ListOfBonds;
}
#ifdef HAVE_INLINE
inline
#endif
atomicNumber_t QtObservedAtom::updateElement(
const atom &_atom)
{
return _atom.getElementNo();
}
#ifdef HAVE_INLINE
inline
#endif
QtObservedMolecule* QtObservedAtom::updateMoleculeRef(
const atom &_atom)
{
if (_atom.getMolecule() != NULL) {
const moleculeId_t molid = _atom.getMolecule()->getId();
const QtObservedMolecule::ptr mol = board.getObservedMolecule(molid);
ASSERT(mol,
"QtObservedAtom::updateMoleculeRef() - could not update the ref, "
+toString(molid)+" unknown to Instance board?");
return mol.get();
} else {
return (QtObservedMolecule*)NULL;
}
}
#ifdef HAVE_INLINE
inline
#endif
std::string QtObservedAtom::updateName(
const atom &_atom)
{
return _atom.getName();
}
#ifdef HAVE_INLINE
inline
#endif
Vector QtObservedAtom::updatePosition(
const atom &_atom)
{
return _atom.getPosition();
}
#ifdef HAVE_INLINE
inline
#endif
bool QtObservedAtom::updateSelected(
const atom &_atom)
{
return _atom.getSelected();
}
void QtObservedAtom::update(Observable *publisher)
{
ASSERT(0, "QtObservedAtom::update() - we are not signed on for global updates.");
}
void QtObservedAtom::subjectKilled(Observable *publisher)
{
++signedOffChannels;
checkForRemoval(getIndex());
}
void QtObservedAtom::countValuesSubjectKilled(ObservedValue_Index_t _id)
{
ASSERT( _id == getIndex(),
"QtObservedAtom::countValuesSubjectKilled() - atom "+toString(getIndex())
+" received countValuesSubjectKilled for atom id "+toString(_id)+".");
++subjectKilledCount;
checkForRemoval(_id);
}
#ifdef HAVE_INLINE
inline
#endif
void QtObservedAtom::checkForRemoval(ObservedValue_Index_t _id)
{
if ((signedOffChannels == AllsignedOnChannels) && (subjectKilledCount == MAX_ObservedTypes)) {
// remove owner: no more signOff needed
owner = NULL;
emit atomRemoved();
if (!BoardIsGone) {
board.markObservedAtomAsDisconnected(_id);
board.markObservedAtomForErase(_id);
}
}
}
void QtObservedAtom::recieveNotification(Observable *publisher, Notification_ptr notification)
{
// ObservedValues have been updated before, hence convert updates to Qt's signals
switch (notification->getChannelNo()) {
case AtomObservable::IndexChanged:
{
const atomId_t newId = getAtomIndex();
emit indexChanged(oldId, newId);
oldId = newId;
break;
}
case AtomObservable::BondsAdded:
case AtomObservable::BondsRemoved:
emit bondsChanged();
break;
case AtomObservable::ElementChanged:
emit elementChanged();
break;
case AtomObservable::MoleculeChanged:
emit moleculeChanged();
break;
case AtomObservable::NameChanged:
emit nameChanged();
break;
case AtomObservable::PositionChanged:
emit positionChanged();
break;
case AtomObservable::SelectionChanged:
emit selectedChanged();
break;
default:
ASSERT(0, "QtObservedAtom::recieveNotification() - we are not signed on to channel "
+toString(notification->getChannelNo())+" of the atom.");
break;
}
}
void QtObservedAtom::activateObserver()
{
atom * atomref = getAtom(getAtomIndex());
if (atomref != NULL) {
Observable::channels_t channels = getAllObservedChannels();
owner = static_cast(atomref);
for (Observable::channels_t::const_iterator iter = channels.begin();
iter != channels.end(); ++iter)
owner->signOn(this, *iter);
if (!BoardIsGone)
board.markObservedAtomAsConnected(getIndex());
} else
signedOffChannels = AllsignedOnChannels;
}
void QtObservedAtom::deactivateObserver()
{
// sign Off
if (owner != NULL) {
Observable::channels_t channels = getAllObservedChannels();
for (Observable::channels_t::const_iterator iter = channels.begin();
iter != channels.end(); ++iter)
owner->signOff(this, *iter);
owner = NULL;
signedOffChannels = AllsignedOnChannels;
if (!BoardIsGone)
board.markObservedAtomAsDisconnected(getIndex());
}
}
void QtObservedAtom::initObservedValues(
ObservedValues_t &_ObservedValues,
const atomId_t _id,
const atom * const _atomref,
const boost::function &_subjectKilled)
{
ASSERT( _ObservedValues.size() == MAX_ObservedTypes,
"QtObservedAtom::initObservedValues() - given ObservedValues has not correct size.");
// fill ObservedValues: then all the other that need index
const boost::function AtomIndexUpdater(
boost::bind(&QtObservedAtom::updateIndex, boost::cref(*_atomref)));
const boost::function AtomBondsUpdater(
boost::bind(&QtObservedAtom::updateBonds, boost::cref(*_atomref)));
const boost::function AtomElementUpdater(
boost::bind(&QtObservedAtom::updateElement, boost::cref(*_atomref)));
const boost::function AtomNameUpdater(
boost::bind(&QtObservedAtom::updateName, boost::cref(*_atomref)));
const boost::function AtomPositionUpdater(
boost::bind(&QtObservedAtom::updatePosition, boost::cref(*_atomref)));
const boost::function AtomSelectedUpdater(
boost::bind(&QtObservedAtom::updateSelected, boost::cref(*_atomref)));
const boost::function MoleculeRefUpdater(
boost::bind(&QtObservedAtom::updateMoleculeRef, this, boost::cref(*_atomref)));
_ObservedValues[AtomIndex] = new ObservedValue_wCallback(
_atomref,
AtomIndexUpdater,
"AtomIndex_"+toString(_id),
_id,
AtomIndexChannels,
_subjectKilled);
_ObservedValues[AtomBonds] = new ObservedValue_wCallback(
_atomref,
AtomBondsUpdater,
"AtomBonds_"+toString(_id),
AtomBondsUpdater(),
AtomBondsChannels,
_subjectKilled);
_ObservedValues[AtomElement] = new ObservedValue_wCallback(
_atomref,
AtomElementUpdater,
"AtomElement"+toString(_id),
AtomElementUpdater(),
AtomElementChannels,
_subjectKilled);
_ObservedValues[AtomName] = new ObservedValue_wCallback(
_atomref,
AtomNameUpdater,
"AtomName"+toString(_id),
AtomNameUpdater(),
AtomNameChannels,
_subjectKilled);
_ObservedValues[AtomPosition] = new ObservedValue_wCallback(
_atomref,
AtomPositionUpdater,
"AtomPosition_"+toString(_id),
AtomPositionUpdater(),
AtomPositionChannels,
_subjectKilled);
_ObservedValues[AtomSelected] = new ObservedValue_wCallback(
_atomref,
AtomSelectedUpdater,
"AtomSelected_"+toString(_id),
AtomSelectedUpdater(),
AtomSelectedChannels,
_subjectKilled);
_ObservedValues[MoleculeRef] = new ObservedValue_wCallback(
_atomref,
MoleculeRefUpdater,
"AtomMoleculeIndex"+toString(_id),
MoleculeRefUpdater(),
MoleculeChangedChannels,
_subjectKilled);
}
void QtObservedAtom::destroyObservedValues(
std::vector &_ObservedValues)
{
delete boost::any_cast *>(_ObservedValues[AtomIndex]);
delete boost::any_cast *>(_ObservedValues[AtomBonds]);
delete boost::any_cast *>(_ObservedValues[AtomElement]);
delete boost::any_cast *>(_ObservedValues[AtomName]);
delete boost::any_cast *>(_ObservedValues[AtomPosition]);
delete boost::any_cast *>(_ObservedValues[AtomSelected]);
delete boost::any_cast *>(_ObservedValues[MoleculeRef]);
_ObservedValues.clear();
}
ObservedValue_Index_t QtObservedAtom::getIndex() const
{
ASSERT( index != NULL,
"QtObservedAtom::getIndex() - index is NULL");
return index;
}
const atomId_t& QtObservedAtom::getAtomIndex() const
{
return boost::any_cast *>(ObservedValues[AtomIndex])->get();
}
const QtObservedAtom::ListOfBonds_t& QtObservedAtom::getAtomBonds() const
{
return boost::any_cast *>(ObservedValues[AtomBonds])->get();
}
const atomicNumber_t& QtObservedAtom::getAtomElement() const
{
return boost::any_cast *>(ObservedValues[AtomElement])->get();
}
const std::string& QtObservedAtom::getAtomName() const
{
return boost::any_cast *>(ObservedValues[AtomName])->get();
}
const Vector& QtObservedAtom::getAtomPosition() const
{
return boost::any_cast *>(ObservedValues[AtomPosition])->get();
}
const bool QtObservedAtom::getAtomSelected() const
{
return boost::any_cast *>(ObservedValues[AtomSelected])->get();
}
const QtObservedMolecule* const QtObservedAtom::getMoleculeRef() const
{
return boost::any_cast *>(ObservedValues[MoleculeRef])->get();
}