/*
* 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 .
*/
/*
* QtObservedMolecule.cpp
*
* Created on: Oct 28, 2015
* Author: heber
*/
// include config.h
#ifdef HAVE_CONFIG_H
#include
#endif
#include "QtObservedMolecule.hpp"
#include "UIElements/Qt4/InstanceBoard/QtObservedInstanceBoard.hpp"
#include "CodePatterns/MemDebug.hpp"
#include "CodePatterns/Assert.hpp"
#include "CodePatterns/Log.hpp"
#include
#include
#include "UIElements/Qt4/InstanceBoard/ObservedValue_wCallback.hpp"
#include "Atom/atom.hpp"
#include "Descriptors/MoleculeIdDescriptor.hpp"
#include "World.hpp"
using namespace boost::assign;
static const Observable::channels_t getAllObservedChannels()
{
Observable::channels_t channels;
channels +=
molecule::AtomInserted,
molecule::AtomMoved,
molecule::AtomRemoved,
molecule::FormulaChanged,
molecule::IndexChanged,
molecule::MoleculeNameChanged,
molecule::BoundingBoxChanged,
molecule::SelectionChanged;
return channels;
}
static const Observable::channels_t getAllAtomCountChannels()
{
Observable::channels_t channels;
channels +=
molecule::AtomInserted,
molecule::AtomRemoved;
return channels;
}
static const Observable::channels_t getAllCenterChannels()
{
Observable::channels_t channels;
channels +=
molecule::AtomInserted,
molecule::AtomMoved,
molecule::AtomRemoved;
return channels;
}
// static instances
const Observable::channels_t QtObservedMolecule::AtomCountChannels(getAllAtomCountChannels());
const Observable::channels_t QtObservedMolecule::BondCountChannels(getAllAtomCountChannels());
const Observable::channels_t QtObservedMolecule::BoundingBoxChannels(1, molecule::BoundingBoxChanged);
const Observable::channels_t QtObservedMolecule::FormulaStringChannels(1, molecule::FormulaChanged);
const Observable::channels_t QtObservedMolecule::CenterChannels(getAllCenterChannels());
const Observable::channels_t QtObservedMolecule::IndexChannels(1, molecule::IndexChanged);
const Observable::channels_t QtObservedMolecule::NameChannels(1, molecule::MoleculeNameChanged);
const Observable::channels_t QtObservedMolecule::NonHydrogenCountChannels(1, molecule::FormulaChanged);
const Observable::channels_t QtObservedMolecule::SelectedChannels(1, molecule::SelectionChanged);
QtObservedMolecule::QtObservedMolecule(
const moleculeId_t _id,
const molecule * const _mol,
QtObservedInstanceBoard &_board,
QWidget * _parent) :
QWidget(_parent),
Observer("QtObservedMolecule"),
subjectKilledCount(0),
AllsignedOnChannels(getAllObservedChannels().size()),
signedOffChannels(0),
owner(NULL),
oldId(_id),
board(_board),
BoardIsGone(false),
ObservedValues(QtObservedMolecule::MAX_ObservedTypes)
{
boost::function moleculeSubjectKilled(
boost::bind(&QtObservedMolecule::countValuesSubjectKilled,
boost::ref(*this),
boost::bind(&QtObservedMolecule::getIndex, boost::ref(*this))));
initObservedValues(ObservedValues, _id, _mol, moleculeSubjectKilled);
// activating Observer is done by ObservedValueContainer when it's prepared
}
QtObservedMolecule::~QtObservedMolecule()
{
boost::any_cast *>(ObservedValues[MolIndex])->noteCallBackIsGone();
boost::any_cast *>(ObservedValues[AtomCount])->noteCallBackIsGone();
boost::any_cast *>(ObservedValues[BondCount])->noteCallBackIsGone();
boost::any_cast *>(ObservedValues[BoundingBox])->noteCallBackIsGone();
boost::any_cast *>(ObservedValues[FormulaString])->noteCallBackIsGone();
boost::any_cast *>(ObservedValues[MolCenter])->noteCallBackIsGone();
boost::any_cast *>(ObservedValues[MolName])->noteCallBackIsGone();
boost::any_cast *>(ObservedValues[NonHydrogenCount])->noteCallBackIsGone();
boost::any_cast *>(ObservedValues[MolSelected])->noteCallBackIsGone();
deactivateObserver();
destroyObservedValues(ObservedValues);
}
void QtObservedMolecule::deactivateObserver()
{
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.markObservedMoleculeAsDisconnected(getIndex());
}
}
void QtObservedMolecule::activateObserver()
{
// sign on as observer (obtain non-const instance before)
const molecule * const _molecule = getMolecule(getMolIndex());
if (_molecule != NULL) {
Observable::channels_t channels = getAllObservedChannels();
owner = static_cast(_molecule);
for (Observable::channels_t::const_iterator iter = channels.begin();
iter != channels.end(); ++iter)
owner->signOn(this, *iter);
if (!BoardIsGone)
board.markObservedMoleculeAsConnected(getIndex());
} else
signedOffChannels = AllsignedOnChannels;
}
void QtObservedMolecule::update(Observable *publisher)
{
ASSERT(0,
"QtObservedMolecule::update() - general update from unexpected source.");
}
void QtObservedMolecule::subjectKilled(Observable *publisher)
{
++signedOffChannels;
checkForRemoval(getIndex());
}
void QtObservedMolecule::countValuesSubjectKilled(ObservedValue_Index_t _id)
{
ASSERT( _id == getIndex(),
"QtObservedAtom::countValuesSubjectKilled() - molecule "+toString(getIndex())
+" received countValuesSubjectKilled for molecule id "+toString(_id)+".");
++subjectKilledCount;
checkForRemoval(_id);
}
void QtObservedMolecule::checkForRemoval(ObservedValue_Index_t _id)
{
if ((signedOffChannels == AllsignedOnChannels) && (subjectKilledCount == MAX_ObservedTypes)) {
// remove owner: no more signOff needed
owner = NULL;
emit moleculeRemoved();
if (!BoardIsGone) {
board.markObservedMoleculeAsDisconnected(_id);
board.markObservedMoleculeForErase(_id);
}
}
}
void QtObservedMolecule::recieveNotification(Observable *publisher, Notification_ptr notification)
{
const molecule * const _molecule = getMolecule(getMolIndex());
// when molecule is NULL we will soon get destroyed anyway
if (_molecule == NULL)
return;
if (publisher == dynamic_cast(_molecule)){
// notification from atom
#ifdef LOG_OBSERVER
observerLog().addMessage() << "++ Update of Observer "<< observerLog().getName(static_cast(this))
<< " received notification from molecule " << getMolIndex() << " for channel "
<< notification->getChannelNo() << ".";
#endif
switch (notification->getChannelNo()) {
case molecule::AtomInserted:
{
const atomId_t _id = _molecule->lastChangedAtomId();
QtObservedAtom::ptr _atom = board.getObservedAtom(_id);
emit atomcountChanged();
emit atomInserted(_atom, this);
emit bondcountChanged();
emit boundingboxChanged();
emit centerChanged();
emit tesselationhullChanged();
break;
}
case molecule::AtomMoved:
{
emit boundingboxChanged();
emit centerChanged();
emit tesselationhullChanged();
break;
}
case molecule::AtomRemoved:
{
const atomId_t _id = _molecule->lastChangedAtomId();
QtObservedAtom::ptr _atom = board.getObservedAtom(_id);
emit atomcountChanged();
emit atomRemoved(_atom->getIndex(), this);
emit bondcountChanged();
emit boundingboxChanged();
emit centerChanged();
emit tesselationhullChanged();
break;
}
case molecule::BoundingBoxChanged:
{
#ifdef LOG_OBSERVER
observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast(this)) << " received notification that bounding box has changed.";
#endif
emit tesselationhullChanged();
emit boundingboxChanged();
break;
}
case molecule::FormulaChanged:
{
emit formulaChanged();
emit nononhydrogenChanged();
break;
}
case molecule::IndexChanged:
{
#ifdef LOG_OBSERVER
const atomId_t _id = _molecule->lastChangedAtomId();
observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast(this)) << " received notification that atom "+toString(_id)+"'s index has changed.";
#endif
const moleculeId_t newId = getMolIndex();
emit indexChanged(oldId, newId);
oldId = newId;
break;
}
case molecule::MoleculeNameChanged:
{
#ifdef LOG_OBSERVER
observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast(this)) << " received notification that name has changed.";
#endif
emit nameChanged();
break;
}
case molecule::SelectionChanged:
{
#ifdef LOG_OBSERVER
observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast(this)) << " received notification that selected has changed.";
#endif
emit selectedChanged();
break;
}
default:
break;
}
}
}
const molecule * const QtObservedMolecule::getMolecule(const moleculeId_t _id)
{
const molecule * const mol = const_cast(World::getInstance()).
getMolecule(MoleculeById(_id));
return mol;
}
static molecule::BoundingBoxInfo initBoundingBox()
{
molecule::BoundingBoxInfo info;
info.position = zeroVec;
info.radius = 0.;
return info;
}
void QtObservedMolecule::initObservedValues(
ObservedValues_t &_ObservedValues,
const moleculeId_t _molid,
const molecule * const _molref,
const boost::function &_subjectKilled)
{
ASSERT( _ObservedValues.size() == MAX_ObservedTypes,
"QtObservedMolecule::initObservedValues() - given ObservedValues has not correct size.");
// fill ObservedValues: index first
const boost::function MolIndexGetter =
boost::bind(&QtObservedMolecule::getIndex,
boost::cref(*this));
// fill ObservedValues: then all the other that need index
const boost::function MolIndexUpdater(
boost::bind(&QtObservedMolecule::updateIndex, boost::cref(*_molref)));
const boost::function AtomCountUpdater(
boost::bind(&QtObservedMolecule::updateAtomCount, boost::cref(*_molref)));
const boost::function BondCountUpdater(
boost::bind(&QtObservedMolecule::updateBondCount, boost::cref(*_molref)));
const boost::function MolCenterUpdater(
boost::bind(&QtObservedMolecule::updateCenter, boost::cref(*_molref)));
const boost::function MolFormulaUpdater(
boost::bind(&QtObservedMolecule::updateFormulaString, boost::cref(*_molref)));
const boost::function MolNameUpdater(
boost::bind(&QtObservedMolecule::updateName, boost::cref(*_molref)));
const boost::function NonHydrogenCountUpdater(
boost::bind(&QtObservedMolecule::updateNonHydrogenCount, boost::cref(*_molref)));
const boost::function BoundingBoxUpdater(
boost::bind(&QtObservedMolecule::updateBoundingBox, boost::cref(*_molref)));
const boost::function SelectedUpdater(
boost::bind(&QtObservedMolecule::updateSelected, boost::cref(*_molref)));
_ObservedValues[MolIndex] = new ObservedValue_wCallback(
_molref,
MolIndexUpdater,
"MoleculeIndex_"+toString(_molid),
_molid,
IndexChannels,
_subjectKilled,
MolIndexGetter);
_ObservedValues[AtomCount] = new ObservedValue_wCallback(
_molref,
AtomCountUpdater,
"MoleculeAtomCount_"+toString(_molid),
AtomCountUpdater(),
AtomCountChannels,
_subjectKilled,
MolIndexGetter);
_ObservedValues[BondCount] = new ObservedValue_wCallback(
_molref,
BondCountUpdater,
"MoleculeBondCount_"+toString(_molid),
BondCountUpdater(),
BondCountChannels,
_subjectKilled,
MolIndexGetter);
_ObservedValues[BoundingBox] = new ObservedValue_wCallback(
_molref,
BoundingBoxUpdater,
"MoleculeBoundingBox_"+toString(_molid),
initBoundingBox(),
BoundingBoxChannels,
_subjectKilled,
MolIndexGetter);
_ObservedValues[FormulaString] = new ObservedValue_wCallback(
_molref,
MolFormulaUpdater,
"MoleculeFormula_"+toString(_molid),
MolFormulaUpdater(),
FormulaStringChannels,
_subjectKilled,
MolIndexGetter);
_ObservedValues[MolCenter] = new ObservedValue_wCallback(
_molref,
MolCenterUpdater,
"MoleculeCenter_"+toString(_molid),
MolCenterUpdater(),
CenterChannels,
_subjectKilled,
MolIndexGetter);
_ObservedValues[MolName] = new ObservedValue_wCallback(
_molref,
MolNameUpdater,
"MoleculeName_"+toString(_molid),
MolNameUpdater(),
NameChannels,
_subjectKilled,
MolIndexGetter);
_ObservedValues[NonHydrogenCount] = new ObservedValue_wCallback(
_molref,
NonHydrogenCountUpdater,
"MoleculeNonHydrogenCount_"+toString(_molid),
NonHydrogenCountUpdater(),
NonHydrogenCountChannels,
_subjectKilled,
MolIndexGetter);
_ObservedValues[MolSelected] = new ObservedValue_wCallback(
_molref,
SelectedUpdater,
"MoleculeSelected_"+toString(_molid),
SelectedUpdater(),
SelectedChannels,
_subjectKilled,
MolIndexGetter);
}
void QtObservedMolecule::destroyObservedValues(
std::vector &_ObservedValues)
{
delete boost::any_cast *>(_ObservedValues[MolIndex]);
delete boost::any_cast *>(_ObservedValues[AtomCount]);
delete boost::any_cast *>(_ObservedValues[BondCount]);
delete boost::any_cast *>(_ObservedValues[BoundingBox]);
delete boost::any_cast *>(_ObservedValues[FormulaString]);
delete boost::any_cast *>(_ObservedValues[MolCenter]);
delete boost::any_cast *>(_ObservedValues[MolName]);
delete boost::any_cast *>(_ObservedValues[NonHydrogenCount]);
delete boost::any_cast *>(_ObservedValues[MolSelected]);
_ObservedValues.clear();
}
#ifdef HAVE_INLINE
inline
#endif
int QtObservedMolecule::updateAtomCount(const molecule &mol)
{
return mol.getAtomCount();
}
#ifdef HAVE_INLINE
inline
#endif
int QtObservedMolecule::updateBondCount(const molecule &mol)
{
return mol.getBondCount();
}
#ifdef HAVE_INLINE
inline
#endif
molecule::BoundingBoxInfo QtObservedMolecule::updateBoundingBox(const molecule &mol)
{
return mol.getBoundingBox();
}
#ifdef HAVE_INLINE
inline
#endif
std::string QtObservedMolecule::updateFormulaString(const molecule &mol)
{
return mol.getFormula().toString();
}
#ifdef HAVE_INLINE
inline
#endif
Vector QtObservedMolecule::updateCenter(const molecule &mol)
{
return mol.DetermineCenterOfAll();
}
#ifdef HAVE_INLINE
inline
#endif
moleculeId_t QtObservedMolecule::updateIndex(const molecule &mol)
{
return mol.getId();
}
#ifdef HAVE_INLINE
inline
#endif
std::string QtObservedMolecule::updateName(const molecule &mol)
{
return mol.getName();
}
#ifdef HAVE_INLINE
inline
#endif
int QtObservedMolecule::updateNonHydrogenCount(const molecule &mol)
{
return mol.getNoNonHydrogen();
}
#ifdef HAVE_INLINE
inline
#endif
bool QtObservedMolecule::updateSelected(const molecule &mol)
{
return mol.getSelected();
}
ObservedValue_Index_t QtObservedMolecule::getIndex() const
{
ASSERT( owner != NULL,
"QtObservedMolecule::getIndex() - index is NULL");
return owner;
}
const int& QtObservedMolecule::getAtomCount() const
{
return boost::any_cast *>(ObservedValues[AtomCount])->get();
}
const int& QtObservedMolecule::getBondCount() const
{
return boost::any_cast *>(ObservedValues[BondCount])->get();
}
const std::string& QtObservedMolecule::getMolFormula() const
{
return boost::any_cast *>(ObservedValues[FormulaString])->get();
}
const Vector& QtObservedMolecule::getMolCenter() const
{
return boost::any_cast *>(ObservedValues[MolCenter])->get();
}
const moleculeId_t& QtObservedMolecule::getMolIndex() const
{
return boost::any_cast *>(ObservedValues[MolIndex])->get();
}
const std::string& QtObservedMolecule::getMolName() const
{
return boost::any_cast *>(ObservedValues[MolName])->get();
}
const int& QtObservedMolecule::getNonHydrogenCount() const
{
return boost::any_cast *>(ObservedValues[NonHydrogenCount])->get();
}
const molecule::BoundingBoxInfo& QtObservedMolecule::getBoundingBox() const
{
return boost::any_cast *>(ObservedValues[BoundingBox])->get();
}
const bool& QtObservedMolecule::getMolSelected() const
{
return boost::any_cast *>(ObservedValues[MolSelected])->get();
}