/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2016 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 . */ /* * QtObservedBond.cpp * * Created on: Mar 03, 2016 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include "QtObservedBond.hpp" #include #include "UIElements/Qt4/InstanceBoard/QtObservedInstanceBoard.hpp" #include "CodePatterns/MemDebug.hpp" #include #include "Atom/atom.hpp" #include "Bond/bond.hpp" #include "World.hpp" #include "UIElements/Qt4/InstanceBoard/ObservedValue_wCallback.hpp" using namespace boost::assign; template Observable * const getObservable(const T * _ptr) { return static_cast( const_cast(_ptr)); } static QtObservedBond::ObservableCount_t initAllsignedOnChannels(const bond::ptr _bond) { const QtObservedBond::ObservableCount_t returnlist = boost::assign::list_of< QtObservedBond::ObservableCount_t::value_type > ( getObservable(_bond.get()), 1); return returnlist; } // static entities const Observable::channels_t QtObservedBond::BondDegreeChannels(1, BondObservable::DegreeChanged); QtObservedBond::QtObservedBond( const bondId_t _id, const bond::ptr _bond, const QtObservedAtom::ptr &_leftatom, const QtObservedAtom::ptr &_rightatom, QtObservedInstanceBoard &_board, QWidget * _parent) : QWidget(_parent), Observer("QtObservedBond"), AllsignedOnChannels(initAllsignedOnChannels(_bond)), bondowner(NULL), oldbondId(_id), leftatom(_leftatom), rightatom(_rightatom), index(static_cast(const_cast(this))), board(_board), BoardIsGone(false), ObservedValues(QtObservedBond::MAX_ObservedTypes) { qRegisterMetaType("bondId_t"); typedef boost::function map_accessor_t; const map_accessor_t accessor = boost::bind( &ObservableCount_t::at, boost::ref(subjectKilledCount), _1); const boost::function bondSubjectKilled( boost::bind(&QtObservedBond::countValuesSubjectKilled, boost::ref(*this), boost::bind(&QtObservedBond::getIndex, boost::cref(*this)), boost::bind(accessor, getObservable(_bond.get())))); initObservedValues( ObservedValues, _id, _bond, bondSubjectKilled); // activating Observer is done by ObservedValueContainer when it's inserted } QtObservedBond::~QtObservedBond() { boost::any_cast *>(ObservedValues[BondDegree])->noteCallBackIsGone(); deactivateObserver(); destroyObservedValues(ObservedValues); } #ifdef HAVE_INLINE inline #endif int QtObservedBond::updateDegree(const bond &_bond) { return _bond.getDegree(); } void QtObservedBond::update(Observable *publisher) { ASSERT(0, "QtObservedBond::update() - we are not signed on for global updates."); } void QtObservedBond::subjectKilled(Observable *publisher) { ++(signedOffChannels[publisher]); checkForRemoval(getIndex()); } void QtObservedBond::countValuesSubjectKilled( ObservedValue_Index_t _id, unsigned int &_counter) { ASSERT( _id == getIndex(), "QtObservedBond::countValuesSubjectKilled() - bond "+toString(getIndex()) +" received countValuesSubjectKilled for bond id "+toString(_id)+"."); ++_counter; checkForRemoval(_id); } void QtObservedBond::checkForRemoval(ObservedValue_Index_t _id) { if (bondowner != NULL) { // only bond needs to be destroyed to signal removal const ObservableCount_t::const_iterator subjectkillediter = subjectKilledCount.find(const_cast(bondowner)); const ObservableCount_t::const_iterator allsignediter = AllsignedOnChannels.find(const_cast(bondowner)); const ObservableCount_t::const_iterator signedoffiter = signedOffChannels.find(const_cast(bondowner)); ASSERT( (subjectkillediter != subjectKilledCount.end()) && (allsignediter != AllsignedOnChannels.end()) && (signedoffiter != signedOffChannels.end()), "QtObservedBond::checkForRemoval() - something is wrong here."); if ((signedoffiter->second == allsignediter->second) && (subjectkillediter->second == allsignediter->second)) { // remove owner: no more signOff needed bondowner = NULL; emit bondRemoved(); if (!BoardIsGone) { board.markObservedBondAsDisconnected(_id); board.markObservedBondForErase(_id); } } } } void QtObservedBond::recieveNotification(Observable *publisher, Notification_ptr notification) { // ObservedValues have been updated before, hence convert updates to Qt's signals if (publisher == bondowner) { switch (notification->getChannelNo()) { case BondObservable::DegreeChanged: emit degreeChanged(); break; default: ASSERT(0, "QtObservedBond::recieveNotification() - we are not signed on to channel " +toString(notification->getChannelNo())+" of the bond " +toString(getBondIndex())+"."); break; } } else ASSERT(0, "QtObservedBond::recieveNotification() - received signal from unknown source."); } static QtObservedBond::ObservableCount_t::mapped_type getObservableCountValue( const QtObservedBond::ObservableCount_t &_map, const Observable *_obs) { Observable * const obs_const = const_cast(_obs); QtObservedBond::ObservableCount_t::const_iterator iter = _map.find(obs_const); ASSERT( iter != _map.end(), "getObservableCount_tValue"); return iter->second; } static void assignObservableCountValue( QtObservedBond::ObservableCount_t &_map, const Observable *_obs, const QtObservedBond::ObservableCount_t::mapped_type &_value) { Observable * const obs_const = const_cast(_obs); QtObservedBond::ObservableCount_t::iterator iter = _map.find(obs_const); ASSERT( iter != _map.end(), "getObservableCount_tValue"); iter->second = _value; } void QtObservedBond::activateObserver() { signedOffChannels.clear(); subjectKilledCount.clear(); atom * leftatomref = getAtom(getLeftAtomIndex()); atom * rightatomref = getAtom(getRightAtomIndex()); bond::ptr bondref = leftatomref->getBond(rightatomref); if (bondref != NULL) { // bond { bondowner = static_cast(bondref.get()); bondowner->signOn(this, BondObservable::DegreeChanged); subjectKilledCount.insert( std::make_pair(const_cast(bondowner), 0)); signedOffChannels.insert( std::make_pair(const_cast(bondowner), 0)); } // and mark as connected if (!BoardIsGone) board.markObservedBondAsConnected(getIndex()); } else { subjectKilledCount.insert( std::make_pair(const_cast(bondowner), 1)); assignObservableCountValue(signedOffChannels, bondowner, getObservableCountValue(AllsignedOnChannels, bondowner)); } // pass thru to signals from both atoms connect( leftatom.get(), SIGNAL(indexChanged(const atomId_t, const atomId_t)), this, SIGNAL(leftAtomIndexChanged(atomId_t, atomId_t))); connect( leftatom.get(), SIGNAL(elementChanged()), this, SIGNAL(leftAtomElementChanged())); connect( leftatom.get(), SIGNAL(positionChanged()), this, SIGNAL(leftAtomPositionChanged())); connect( leftatom.get(), SIGNAL(moleculeChanged()), this, SIGNAL(leftmoleculeChanged())); connect( rightatom.get(), SIGNAL(indexChanged(const atomId_t, const atomId_t)), this, SIGNAL(rightAtomIndexChanged(atomId_t, atomId_t))); connect( rightatom.get(), SIGNAL(elementChanged()), this, SIGNAL(rightAtomElementChanged())); connect( rightatom.get(), SIGNAL(positionChanged()), this, SIGNAL(rightAtomPositionChanged())); connect( rightatom.get(), SIGNAL(moleculeChanged()), this, SIGNAL(rightmoleculeChanged())); } void QtObservedBond::deactivateObserver() { if (bondowner != NULL) { const ObservableCount_t::iterator subjectkilledbonditer = subjectKilledCount.find(const_cast(bondowner)); ASSERT( (subjectkilledbonditer != subjectKilledCount.end()), "QtObservedBond::deactivateObserver() - no entry in subjectKilledCount for bond" +toString(bondowner)+"," +" has activateObserver() been called?"); if (subjectkilledbonditer->second == 0) bondowner->signOff(this, BondObservable::DegreeChanged); subjectkilledbonditer->second = 1; bondowner = NULL; signedOffChannels.clear(); signedOffChannels.insert(AllsignedOnChannels.begin(), AllsignedOnChannels.end()); if (!BoardIsGone) board.markObservedBondAsDisconnected(getIndex()); } } const atom * const QtObservedBond::getAtomConst(const atomId_t _id) { const atom * const _atom = const_cast(World::getInstance()). getAtom(AtomById(_id)); return _atom; } atom * const QtObservedBond::getAtom(const atomId_t _id) { atom * const _atom = World::getInstance().getAtom(AtomById(_id)); return _atom; } void QtObservedBond::initObservedValues( ObservedValues_t &_ObservedValues, const bondId_t _id, const bond::ptr _bondref, const boost::function &_bondsubjectKilled) { // fill ObservedValues: index first const boost::function BondIndexGetter = boost::bind(&QtObservedBond::getIndex, boost::cref(*this)); // fill ObservedValues: then all the other that need index const boost::function BondDegreeUpdater( boost::bind(&QtObservedBond::updateDegree, boost::cref(*_bondref))); _ObservedValues[BondDegree] = new ObservedValue_wCallback( _bondref.get(), BondDegreeUpdater, "BondDegree_bond"+toString(_id), BondDegreeUpdater(), BondDegreeChannels, _bondsubjectKilled); } void QtObservedBond::destroyObservedValues( std::vector &_ObservedValues) { delete boost::any_cast *>(_ObservedValues[BondDegree]); _ObservedValues.clear(); } ObservedValue_Index_t QtObservedBond::getIndex() const { ASSERT( index != NULL, "QtObservedBond::getIndex() - index is NULL"); return index; } const QtObservedBond::bondId_t QtObservedBond::getBondIndex() const { return QtObservedBond::bondId_t(getLeftAtomIndex(), getRightAtomIndex()); } const int& QtObservedBond::getBondDegree() const { return boost::any_cast *>(ObservedValues[BondDegree])->get(); } const atomId_t& QtObservedBond::getLeftAtomIndex() const { return leftatom->getAtomIndex(); } const atomicNumber_t& QtObservedBond::getLeftAtomElement() const { return leftatom->getAtomElement(); } const Vector& QtObservedBond::getLeftAtomPosition() const { return leftatom->getAtomPosition(); } const moleculeId_t QtObservedBond::getLeftMoleculeIndex() const { if (leftatom->getMoleculeRef() != NULL) return leftatom->getMoleculeRef()->getMolIndex(); else return (moleculeId_t)-1; } const atomId_t& QtObservedBond::getRightAtomIndex() const { return rightatom->getAtomIndex(); } const atomicNumber_t& QtObservedBond::getRightAtomElement() const { return rightatom->getAtomElement(); } const Vector& QtObservedBond::getRightAtomPosition() const { return rightatom->getAtomPosition(); } const moleculeId_t QtObservedBond::getRightMoleculeIndex() const { if (rightatom->getMoleculeRef() != NULL) return rightatom->getMoleculeRef()->getMolIndex(); else return (moleculeId_t)-1; }