/* * 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: 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); _ObservedValues[AtomCount] = new ObservedValue_wCallback( _molref, AtomCountUpdater, "MoleculeAtomCount_"+toString(_molid), AtomCountUpdater(), AtomCountChannels, _subjectKilled); _ObservedValues[BondCount] = new ObservedValue_wCallback( _molref, BondCountUpdater, "MoleculeBondCount_"+toString(_molid), BondCountUpdater(), BondCountChannels, _subjectKilled); _ObservedValues[BoundingBox] = new ObservedValue_wCallback( _molref, BoundingBoxUpdater, "MoleculeBoundingBox_"+toString(_molid), initBoundingBox(), BoundingBoxChannels, _subjectKilled); _ObservedValues[FormulaString] = new ObservedValue_wCallback( _molref, MolFormulaUpdater, "MoleculeFormula_"+toString(_molid), MolFormulaUpdater(), FormulaStringChannels, _subjectKilled); _ObservedValues[MolCenter] = new ObservedValue_wCallback( _molref, MolCenterUpdater, "MoleculeCenter_"+toString(_molid), MolCenterUpdater(), CenterChannels, _subjectKilled); _ObservedValues[MolName] = new ObservedValue_wCallback( _molref, MolNameUpdater, "MoleculeName_"+toString(_molid), MolNameUpdater(), NameChannels, _subjectKilled); _ObservedValues[NonHydrogenCount] = new ObservedValue_wCallback( _molref, NonHydrogenCountUpdater, "MoleculeNonHydrogenCount_"+toString(_molid), NonHydrogenCountUpdater(), NonHydrogenCountChannels, _subjectKilled); _ObservedValues[MolSelected] = new ObservedValue_wCallback( _molref, SelectedUpdater, "MoleculeSelected_"+toString(_molid), SelectedUpdater(), SelectedChannels, _subjectKilled); } 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(); }