Index: src/UIElements/Views/Qt4/Qt3D/GLMoleculeObject_atom.cpp
===================================================================
--- src/UIElements/Views/Qt4/Qt3D/GLMoleculeObject_atom.cpp	(revision f01769bf04baacedde88443ce16ab2f2dd809f30)
+++ src/UIElements/Views/Qt4/Qt3D/GLMoleculeObject_atom.cpp	(revision 20f9b5ca3d0b9027b2885d6239e5b48b8dea45a5)
@@ -44,8 +44,12 @@
 #include "CodePatterns/Observer/Notification.hpp"
 
+#include <algorithm>
+#include <boost/assign.hpp>
+
 #include "Atom/atom.hpp"
 #include "Bond/bond.hpp"
 #include "Descriptors/AtomIdDescriptor.hpp"
 #include "Element/element.hpp"
+#include "Element/periodentafel.hpp"
 #include "LinearAlgebra/Vector.hpp"
 #include "GLMoleculeObject_bond.hpp"
@@ -53,65 +57,129 @@
 #include "WorldTime.hpp"
 
+using namespace boost::assign;
+
+static const Observable::channels_t getAtomBondsChannels()
+{
+  Observable::channels_t channels;
+  channels += AtomObservable::BondsAdded, AtomObservable::BondsRemoved;
+  return channels;
+}
+
+// static entities
+const Observable::channels_t
+GLMoleculeObject_atom::AtomIndexChannels(1, AtomObservable::IndexChanged);
+const Observable::channels_t
+GLMoleculeObject_atom::AtomPositionChannels(1, AtomObservable::PositionChanged);
+const Observable::channels_t
+GLMoleculeObject_atom::AtomElementChannels(1, AtomObservable::ElementChanged);
+const Observable::channels_t
+GLMoleculeObject_atom::AtomBondsChannels(getAtomBondsChannels());
+const Observable::channels_t
+GLMoleculeObject_atom::AtomSelectionStatusChannels(World::SelectionChanged);
+
 GLMoleculeObject_atom::GLMoleculeObject_atom(QGLSceneNode *mesh[], QObject *parent, const atomId_t _id) :
   GLMoleculeObject(mesh, parent),
   Observer(std::string("GLMoleculeObject_atom")+toString(_id)),
-  atomicid(_id),
-  uptodatePosition(false),
-  uptodateElement(false)
-{
-  // sign on as observer (obtain non-const instance before)
-  const atom * const _atom = const_cast<const World &>(World::getInstance()).
-      getAtom(AtomById(atomicid));
-  if (_atom != NULL) {
-    _atom->signOn(this, AtomObservable::IndexChanged);
-    _atom->signOn(this, AtomObservable::PositionChanged);
-    _atom->signOn(this, AtomObservable::ElementChanged);
-    _atom->signOn(this, AtomObservable::BondsAdded);
-  } else {
-    ELOG(2, "Atom with id "+toString(atomicid)+" is already gone.");
-  }
-  World::getInstance().signOn(this, World::SelectionChanged);
-
-  // set the object's id
-  resetProperties();
-
-  LOG(2, "INFO: Created sphere for atom " << atomicid << ".");
+  atomref(getAtom(_id)),
+  AtomIndex(
+      atomref,
+      boost::bind(&GLMoleculeObject_atom::updateIndex, this),
+      "AtomIndex_"+toString(_id),
+      _id,
+      AtomIndexChannels),
+  AtomPosition(
+      atomref,
+      boost::bind(&GLMoleculeObject_atom::updatePosition, this),
+      "AtomPosition_"+toString(_id),
+      updatePosition(),
+      AtomPositionChannels),
+  AtomElement(
+      atomref,
+      boost::bind(&GLMoleculeObject_atom::updateElement, this),
+      "AtomElement"+toString(_id),
+      updateElement(),
+      AtomElementChannels),
+  AtomBonds(
+      atomref,
+      boost::bind(&GLMoleculeObject_atom::updateBonds, this),
+      "AtomBonds_"+toString(_id),
+      updateBonds(),
+      AtomBondsChannels),
+  AtomSelectionStatus(
+      World::getPointer(),
+      boost::bind(&GLMoleculeObject_atom::updateSelectionStatus, this),
+      "AtomSelectionStatus_"+toString(_id),
+      updateSelectionStatus(),
+      AtomSelectionStatusChannels),
+  owner(NULL)
+{
+  setObjectId(_id);
+  resetPosition();
+  resetElement();
+
+  // sign On
+  activateObserver();
+
+  // atomref is only used for caching the ref, it must be used elswhere
+  const_cast<atom *&>(atomref) = NULL;
 
   connect( this, SIGNAL(clicked()), this, SLOT(wasClicked()));
+  connect( this, SIGNAL(idChanged()), this, SLOT(resetIndex()), Qt::QueuedConnection);
+  connect( this, SIGNAL(elementChanged()), this, SLOT(resetElement()), Qt::QueuedConnection);
+  connect( this, SIGNAL(positionChanged()), this, SLOT(resetPosition()), Qt::QueuedConnection);
+  connect( this, SIGNAL(bondsChanged()), this, SLOT(resetPosition()), Qt::QueuedConnection);
+  connect( this, SIGNAL(selectionstatusChanged()), this, SLOT(resetSelectionStatus()), Qt::QueuedConnection);
+}
+
+void GLMoleculeObject_atom::activateObserver()
+{
+  if (atomref != NULL) {
+    owner = static_cast<const Observable *>(atomref);
+    owner->signOn(this, AtomObservable::IndexChanged);
+    owner->signOn(this, AtomObservable::PositionChanged);
+    owner->signOn(this, AtomObservable::ElementChanged);
+    owner->signOn(this, AtomObservable::BondsAdded);
+    owner->signOn(this, AtomObservable::BondsRemoved);
+    World::getInstance().signOn(this, World::SelectionChanged);
+  }
+}
+
+
+void GLMoleculeObject_atom::deactivateObserver()
+{
+  // sign Off
+  if (owner != NULL) {
+    owner->signOff(this, AtomObservable::IndexChanged);
+    owner->signOff(this, AtomObservable::PositionChanged);
+    owner->signOff(this, AtomObservable::ElementChanged);
+    owner->signOff(this, AtomObservable::BondsAdded);
+    owner->signOff(this, AtomObservable::BondsRemoved);
+    World::getInstance().signOff(this, World::SelectionChanged);
+    owner = NULL;
+  }
 }
 
 GLMoleculeObject_atom::~GLMoleculeObject_atom()
 {
-  const atom * const _atom = const_cast<const World &>(World::getInstance()).
-      getAtom(AtomById(atomicid));
-  if (_atom != NULL){
-    _atom->signOff(this, AtomObservable::IndexChanged);
-    _atom->signOff(this, AtomObservable::PositionChanged);
-    _atom->signOff(this, AtomObservable::ElementChanged);
-    _atom->signOff(this, AtomObservable::BondsAdded);
-  }
-  World::getInstance().signOff(this, World::SelectionChanged);
-}
-
-void GLMoleculeObject_atom::update(Observable *publisher)
-{
-#ifdef LOG_OBSERVER
-  observerLog().addMessage() << "++ Update of Observer " << observerLog().getName(static_cast<Observer *>(this)) << " from atom "+toString(atomicid)+".";
-#endif
-  resetProperties();
+  deactivateObserver();
+}
+
+void GLMoleculeObject_atom::resetIndex()
+{
+  const atomId_t newId = AtomIndex.get();
+  const size_t oldId = objectId();
+  ASSERT( newId != oldId,
+      "GLMoleculeObject_atom::updateIndex() - index "+toString(newId)+" did not change.");
+  LOG(4, "INFO: GLMoleculeObject_atom::resetIndex() - new index is "+toString(newId)+".");
+  setObjectId(newId);
+
+  emit indexChanged(this, oldId, newId);
 }
 
 void GLMoleculeObject_atom::resetPosition()
 {
-  const atom * const _atom = const_cast<const World &>(World::getInstance()).
-      getAtom(AtomById(atomicid));
-  if (_atom != NULL) {
-    const Vector Position = _atom->getPosition();
-    LOG(4, "INFO: GLMoleculeObject_atom::resetIndex() - new position is "+toString(Position)+".");
-    setPosition(QVector3D(Position[0], Position[1], Position[2]));
-  } else {
-    ELOG(2, "Atom with id "+toString(atomicid)+" is already gone.");
-  }
-  uptodatePosition = true;
+  const Vector Position = AtomPosition.get();
+  LOG(4, "INFO: GLMoleculeObject_atom::resetIndex() - new position is "+toString(Position)+".");
+  setPosition(QVector3D(Position[0], Position[1], Position[2]));
 }
 
@@ -119,12 +187,6 @@
 {
   size_t elementno = 0;
-  const atom * const _atom = const_cast<const World &>(World::getInstance()).
-      getAtom(AtomById(atomicid));
-  const element *_type = NULL;
-  if (_atom != NULL) {
-    _type = _atom->getType();
-  } else {
-    ELOG(2, "Atom with id "+toString(atomicid)+" is already gone.");
-  }
+  const element * const _type = World::getInstance().
+      getPeriode()->FindElement(AtomElement.get());
   if (_type != NULL) {
     elementno = _type->getAtomicNumber();
@@ -148,115 +210,166 @@
   }
   setScale( radius / 4. );
-
-  uptodateElement = true;
-}
-
-void GLMoleculeObject_atom::resetIndex()
-{
-  int oldId = objectId();
-  LOG(4, "INFO: GLMoleculeObject_atom::resetIndex() - new index is "+toString(atomicid)+".");
-  setObjectId(atomicid);
-
-  emit indexChanged(this, oldId, atomicid);
-}
-
-void GLMoleculeObject_atom::resetProperties()
-{
-  // set position
-  resetPosition();
-
-  // set element
-  resetElement();
-
-  // set the object's id
-  resetIndex();
-
-  // selected?
-  setSelected(World::getInstance().isAtomSelected(atomicid));
+}
+
+void GLMoleculeObject_atom::resetBonds()
+{
+  ListOfBonds_t ListOfBonds_new = AtomBonds.get();
+  std::sort(ListOfBonds_new.begin(), ListOfBonds_new.end());
+  ListOfBonds_t BondsToAdd;
+  std::set_difference(
+      ListOfBonds_new.begin(), ListOfBonds_new.end(),
+      ListOfBonds.begin(), ListOfBonds.end(),
+      std::back_inserter(BondsToAdd));
+  ListOfBonds_t BondsToRemove;
+  std::set_difference(
+      ListOfBonds.begin(), ListOfBonds.end(),
+      ListOfBonds_new.begin(), ListOfBonds_new.end(),
+      std::back_inserter(BondsToRemove));
+  for (ListOfBonds_t::const_iterator iter = BondsToAdd.begin();
+      iter != BondsToAdd.end();
+      ++iter) {
+    const GLMoleculeObject_bond::SideOfBond side = (iter->first == AtomIndex.get()) ?
+        GLMoleculeObject_bond::left : GLMoleculeObject_bond::right;
+    emit BondsAdded(iter->first, iter->second, side);
+  }
+  for (ListOfBonds_t::const_iterator iter = BondsToRemove.begin();
+      iter != BondsToRemove.end();
+      ++iter) {
+    emit BondsRemoved(iter->first, iter->second);
+  }
+  ListOfBonds = ListOfBonds_new;
+}
+
+void GLMoleculeObject_atom::resetSelectionStatus()
+{
+  setSelected(AtomSelectionStatus.get());
 }
 
 void GLMoleculeObject_atom::draw(QGLPainter *painter, const QVector4D &cameraPlane)
 {
-  // hook to update prior to painting
-  if (!uptodatePosition)
-    resetPosition();
-  if (!uptodateElement)
-    resetElement();
-
   // call old hook to do the actual paining
   GLMoleculeObject::draw(painter, cameraPlane);
 }
 
+void GLMoleculeObject_atom::wasClicked()
+{
+  LOG(4, "INFO: GLMoleculeObject_atom: atom " << AtomIndex.get() << " has been clicked");
+  emit clicked(AtomIndex.get());
+}
+
+const atom * const GLMoleculeObject_atom::getAtomConst(const atomId_t _id)
+{
+  const atom * const _atom = const_cast<const World &>(World::getInstance()).
+      getAtom(AtomById(_id));
+  return _atom;
+}
+
+atom * const GLMoleculeObject_atom::getAtom(const atomId_t _id)
+{
+  atom * const _atom = World::getInstance().getAtom(AtomById(_id));
+  return _atom;
+}
+
+atomId_t GLMoleculeObject_atom::updateIndex() const
+{
+  const atom * const _atom = World::getInstance().lastChanged<atom>();
+  if (_atom != NULL) {
+    return _atom->getId();
+  }
+  return (atomId_t)-1;
+}
+
+Vector GLMoleculeObject_atom::updatePosition() const
+{
+  const atom * const _atom = getAtom(AtomIndex.get());
+  if (_atom != NULL) {
+    return _atom->getPosition();
+  } else {
+    return zeroVec;
+  }
+}
+
+atomicNumber_t GLMoleculeObject_atom::updateElement() const
+{
+  const atom * const _atom = getAtom(AtomIndex.get());
+  if (_atom != NULL) {
+    return _atom->getElementNo();
+  } else {
+    return (atomicNumber_t)-1;
+  }
+}
+
+GLMoleculeObject_atom::ListOfBonds_t GLMoleculeObject_atom::updateBonds() const
+{
+  ListOfBonds_t ListOfBonds;
+  const atom * const _atom = getAtom(AtomIndex.get());
+  if (_atom != NULL) {
+    // make sure position 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()) );
+  } else {
+    ELOG(2, "Atom with id "+toString(AtomIndex.get())+" is already gone.");
+  }
+  return ListOfBonds;
+}
+
+bool GLMoleculeObject_atom::updateSelectionStatus() const
+{
+  const atom * const _atom = getAtom(AtomIndex.get());
+  if (_atom != NULL) {
+    return const_cast<const World &>(World::getInstance()).isSelected(_atom);
+  }
+  return false;
+}
+
+void GLMoleculeObject_atom::update(Observable *publisher)
+{
+  ASSERT(0, "GLMoleculeObject_atom::update() - we are not signed on for global updates.");
+}
+
 void GLMoleculeObject_atom::subjectKilled(Observable *publisher)
 {
-  // remove id such that we don't sign off accidentally from a different atom
-  const_cast<atomId_t &>(atomicid) = -1;
+  deactivateObserver();
 }
 
 void GLMoleculeObject_atom::recieveNotification(Observable *publisher, Notification_ptr notification)
 {
-  const atom * const _atom = const_cast<const World &>(World::getInstance()).
-      getAtom(AtomById(atomicid));
-  if (publisher == dynamic_cast<const Observable*>(_atom)){
-    // notofication from atom
-#ifdef LOG_OBSERVER
-    observerLog().addMessage() << "++ Update of Observer "<< observerLog().getName(static_cast<Observer *>(this))
-          << " received notification from atom " << _atom->getId() << " for channel "
-          << notification->getChannelNo() << ".";
-#endif
+  // ObservedValues have been updated before, hence convert updates to Qt's signals
+  atom * const _atom = dynamic_cast<atom *>(publisher);
+  if (_atom != NULL) {
     switch (notification->getChannelNo()) {
+      case AtomObservable::IndexChanged:
+        emit idChanged();
+        break;
+      case AtomObservable::PositionChanged:
+        emit positionChanged();
+        break;
       case AtomObservable::ElementChanged:
-        uptodateElement = false;
-        break;
-      case AtomObservable::IndexChanged:
-        resetIndex();
-        break;
-      case AtomObservable::PositionChanged:
-        uptodatePosition = false;
+        emit elementChanged();
         break;
       case AtomObservable::BondsAdded:
-      {
-        const atom * const _atom = const_cast<const World &>(World::getInstance()).
-            getAtom(AtomById(atomicid));
-        if (_atom != NULL) {
-          // make sure position is up-to-date
-          if (!uptodatePosition)
-            resetPosition();
-          ASSERT(!_atom->getListOfBonds().empty(),
-              "GLMoleculeObject_atom::recieveNotification() - received BondsAdded but ListOfBonds is empty.");
-          const bond::ptr _bond = *(_atom->getListOfBonds().rbegin());
-          const GLMoleculeObject_bond::SideOfBond side = (_bond->leftatom == _atom) ?
-              GLMoleculeObject_bond::left : GLMoleculeObject_bond::right;
-          emit BondsInserted(_bond, side);
-        } else {
-          ELOG(2, "Atom with id "+toString(atomicid)+" is already gone.");
-        }
-        break;
-      }
+      case AtomObservable::BondsRemoved:
+        emit bondsChanged();
+        break;
       default:
-        //setProperties();
+        ASSERT(0, "GLMoleculeObject_atom::recieveNotification() - we are not signed on to channel "
+            +toString(notification->getChannelNo())+" of the atom.");
         break;
     }
-  }else if (static_cast<World *>(publisher) == World::getPointer()) {
-    // notification from world
-#ifdef LOG_OBSERVER
-    observerLog().addMessage() << "++ Update of Observer "<< observerLog().getName(static_cast<Observer *>(this))
-          << " received notification from world for channel "
-          << notification->getChannelNo() << ".";
-#endif
+  } else if (publisher == static_cast<World *>(World::getPointer())) {
     switch (notification->getChannelNo()) {
       case World::SelectionChanged:
-        if (_atom != NULL)
-          setSelected(World::getInstance().isSelected(_atom));
+        emit selectionstatusChanged();
         break;
       default:
+        ASSERT(0, "GLMoleculeObject_atom::recieveNotification() - we are not signed on to channel "
+            +toString(notification->getChannelNo())+" of the World.");
         break;
     }
   }
 }
-
-void GLMoleculeObject_atom::wasClicked()
-{
-  LOG(4, "INFO: GLMoleculeObject_atom: atom " << atomicid << " has been clicked");
-  emit clicked(atomicid);
-}
