/*
 * Project: MoleCuilder
 * Description: creates and alters molecular systems
 * Copyright (C)  2010-2012 University of Bonn. 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 .
 */
/*
 * GLWorldView.cpp
 *
 *  Created on: Aug 1, 2010
 *      Author: heber
 */
// include config.h
#ifdef HAVE_CONFIG_H
#include 
#endif
#include "GLWorldView.hpp"
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include "GLWorldScene.hpp"
#include "CodePatterns/MemDebug.hpp"
#include "Atom/AtomObserver.hpp"
#include "Atom/atom_observable.hpp"
#include "Box.hpp"
#include "CodePatterns/Log.hpp"
#include "CodePatterns/Observer/Notification.hpp"
#include "CodePatterns/Observer/ObserverLog.hpp"
#include "molecule.hpp"
#include "Shapes/ShapeRegistry.hpp"
#include "World.hpp"
GLWorldView::GLWorldView(QWidget *parent)
  : QGLView(parent), Observer("GLWorldView"), worldscene(NULL), changesPresent(false), needsRedraw(false)
{
  worldscene = new GLWorldScene(this);
  setOption(QGLView::ObjectPicking, true);
  setOption(QGLView::CameraNavigation, false);
  setCameraControlMode(Rotate);
  defaultEyeSeparation = 4.0;
  createDomainBox();
  createDreiBein();
  //changeMaterials(false);
  connect(worldscene, SIGNAL(changeOccured()), this, SLOT(changeSignalled()));
  connect(worldscene, SIGNAL(changed()), this, SIGNAL(changed()));
  connect(worldscene, SIGNAL(hoverChanged(const atom *)), this, SLOT(sceneHoverSignalled(const atom *)));
  connect(this, SIGNAL(atomInserted(const atom *)), worldscene, SLOT(atomInserted(const atom *)));
  connect(this, SIGNAL(atomRemoved(const atom *)), worldscene, SLOT(atomRemoved(const atom *)));
  connect(this, SIGNAL(worldSelectionChanged()), worldscene, SLOT(worldSelectionChanged()));
  connect(this, SIGNAL(moleculeRemoved(const molecule *)), worldscene, SLOT(moleculeRemoved(const molecule *)));
  //connect(this, SIGNAL(moleculeInserted(const molecule *)), worldscene, SLOT(moleculeInserted(const molecule *)));
  //connect(this, SIGNAL(changed()), this, SLOT(updateGL()));
  connect(this, SIGNAL(changed()), this, SLOT(sceneChangeSignalled()));
  // sign on to changes in the world
  World::getInstance().signOn(this);
  World::getInstance().signOn(this, World::AtomInserted);
  World::getInstance().signOn(this, World::AtomRemoved);
  World::getInstance().signOn(this, World::MoleculeInserted);
  World::getInstance().signOn(this, World::MoleculeRemoved);
  World::getInstance().signOn(this, World::SelectionChanged);
  AtomObserver::getInstance().signOn(this, AtomObservable::PositionChanged);
  ShapeRegistry::getInstance().signOn(this);
  ShapeRegistry::getInstance().signOn(this, ShapeRegistry::ShapeInserted);
  ShapeRegistry::getInstance().signOn(this, ShapeRegistry::ShapeRemoved);
  ShapeRegistry::getInstance().signOn(this, ShapeRegistry::SelectionChanged);
  redrawTimer = new QTimer(this);
}
GLWorldView::~GLWorldView()
{
  World::getInstance().signOff(this);
  World::getInstance().signOff(this, World::AtomInserted);
  World::getInstance().signOff(this, World::AtomRemoved);
  World::getInstance().signOff(this, World::MoleculeInserted);
  World::getInstance().signOff(this, World::MoleculeRemoved);
  World::getInstance().signOff(this, World::SelectionChanged);
  AtomObserver::getInstance().signOff(this, AtomObservable::PositionChanged);
  ShapeRegistry::getInstance().signOff(this);
  ShapeRegistry::getInstance().signOff(this, ShapeRegistry::ShapeInserted);
  ShapeRegistry::getInstance().signOff(this, ShapeRegistry::ShapeRemoved);
  ShapeRegistry::getInstance().signOff(this, ShapeRegistry::SelectionChanged);
  delete worldscene;
  delete(domainBoxMaterial);
  for (int i=0;i<3;i++)
    delete(dreiBeinMaterial[i]);
}
/**
 * Add some widget specific actions to the toolbar:
 * - camera rotation/translation mode
 * - camera fit to domain
 */
void GLWorldView::addToolBarActions(QToolBar *toolbar)
{
  // camera control mode
  toolbar->addSeparator();
  QAction *transAction = new QAction(QIcon::fromTheme("forward"), tr("camera translation mode"), this);
  connect(transAction, SIGNAL(triggered()), this, SLOT(setCameraControlModeTranslation()));
  toolbar->addAction(transAction);
  QAction *rotAction = new QAction(QIcon::fromTheme("object-rotate-left"), tr("camera rotation mode"), this);
  connect(rotAction, SIGNAL(triggered()), this, SLOT(setCameraControlModeRotation()));
  toolbar->addAction(rotAction);
  QAction *fitAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("camera fit to domain"), this);
  connect(fitAction, SIGNAL(triggered()), this, SLOT(fitCameraToDomain()));
  toolbar->addAction(fitAction);
  // stereo mode
  QToolButton *stereoButton = new QToolButton(toolbar);
  QMenu *stereoMenu = new QMenu();
  QAction *stereoDisableAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("disable"), this);
  connect(stereoDisableAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeDisable()));
  stereoMenu->addAction(stereoDisableAction);
  QAction *stereoHardwareAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("hardware"), this);
  connect(stereoHardwareAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeHardware()));
  stereoMenu->addAction(stereoHardwareAction);
  QAction *stereoLeftRightAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("left right"), this);
  connect(stereoLeftRightAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeLeftRight()));
  stereoMenu->addAction(stereoLeftRightAction);
  QAction *stereoRightLeftAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("right left"), this);
  connect(stereoRightLeftAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeRightLeft()));
  stereoMenu->addAction(stereoRightLeftAction);
  QAction *stereoTopBottomAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("top bottom"), this);
  connect(stereoTopBottomAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeTopBottom()));
  stereoMenu->addAction(stereoTopBottomAction);
  QAction *stereoBottomTopAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("bottom top"), this);
  connect(stereoBottomTopAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeBottomTop()));
  stereoMenu->addAction(stereoBottomTopAction);
  QAction *stereoAnaglyphAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("anaglyph"), this);
  connect(stereoAnaglyphAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeAnaglyph()));
  stereoMenu->addAction(stereoAnaglyphAction);
  stereoButton->setMenu(stereoMenu);
  stereoButton->setIcon(QIcon(QPixmap(":/icon_view_stereo.png")));
  stereoButton->setPopupMode(QToolButton::InstantPopup);
  toolbar->addWidget(stereoButton);
  // selection mode
  toolbar->addSeparator();
  QAction *selAtomAction = new QAction(QIcon(QPixmap(":/icon_select_atom.png")), tr("select atom by clicking"), this);
  connect(selAtomAction, SIGNAL(triggered()), worldscene, SLOT(setSelectionModeAtom()));
  toolbar->addAction(selAtomAction);
  QAction *selMolAction = new QAction(QIcon(QPixmap(":/icon_select_molecule.png")), tr("select molecule by clicking"), this);
  connect(selMolAction, SIGNAL(triggered()), worldscene, SLOT(setSelectionModeMolecule()));
  toolbar->addAction(selMolAction);
}
void GLWorldView::createDomainBox()
{
  QSettings settings;
  settings.beginGroup("WorldView");
  QColor colorFrame = settings.value("domainBoxColorFrame", QColor(150,160,200,255)).value();
  QColor colorAmbient = settings.value("domainBoxColorAmbient", QColor(50,60,100,255)).value();
  QColor colorDiffuse = settings.value("domainBoxColorDiffuse", QColor(150,160,200,180)).value();
  settings.setValue("domainBoxColorFrame", colorFrame);
  settings.setValue("domainBoxColorAmbient", colorAmbient);
  settings.setValue("domainBoxColorDiffuse", colorDiffuse);
  settings.endGroup();
  domainBoxMaterial = new QGLMaterial;
  domainBoxMaterial->setAmbientColor(QColor(0,0,0,255));
  domainBoxMaterial->setDiffuseColor(QColor(0,0,0,255));
  domainBoxMaterial->setEmittedLight(colorFrame);
  QGLMaterial *material = new QGLMaterial;
  material->setAmbientColor(colorAmbient);
  material->setDiffuseColor(colorDiffuse);
  QGLBuilder builder;
  builder << QGL::Faceted;
  builder << QGLCube(-1.0); // "inverted" => inside faces are used as front.
  meshDomainBox = builder.finalizedSceneNode();
  QMatrix4x4 mat;
  mat.translate(0.5f, 0.5f, 0.5f);
  meshDomainBox->setLocalTransform(mat);
  meshDomainBox->setMaterial(material);
}
void GLWorldView::createDreiBein()
{
  QSettings settings;
  settings.beginGroup("WorldView");
  QColor colorX = settings.value("dreiBeinColorX", QColor(255,50,50,255)).value();
  QColor colorY = settings.value("dreiBeinColorY", QColor(50,255,50,255)).value();
  QColor colorZ = settings.value("dreiBeinColorZ", QColor(50,50,255,255)).value();
  settings.setValue("dreiBeinColorX", colorX);
  settings.setValue("dreiBeinColorY", colorY);
  settings.setValue("dreiBeinColorZ", colorZ);
  settings.setValue("dreiBeinEnabled", true);
  settings.endGroup();
  // Create 3 color for the 3 axes.
  dreiBeinMaterial[0] = new QGLMaterial;
  dreiBeinMaterial[0]->setColor(colorX);
  dreiBeinMaterial[1] = new QGLMaterial;
  dreiBeinMaterial[1]->setColor(colorY);
  dreiBeinMaterial[2] = new QGLMaterial;
  dreiBeinMaterial[2]->setColor(colorZ);
  // Create the basic meshes (cylinder and cone).
  QGLBuilder builderCyl;
  builderCyl << QGLCylinder(.15,.15,1.6,16);
  QGLSceneNode *cyl = builderCyl.finalizedSceneNode();
  QGLBuilder builderCone;
  builderCone << QGLCylinder(0,.4,0.4,16);
  QGLSceneNode *cone = builderCone.finalizedSceneNode();
  {
    QMatrix4x4 mat;
    mat.translate(0.0f, 0.0f, 1.0f);
    cone->setLocalTransform(mat);
  }
  // Create a scene node from the 3 axes.
  meshDreiBein = new QGLSceneNode(this);
  // X-direction
  QGLSceneNode *node = new QGLSceneNode(meshDreiBein);
  node->setMaterial(dreiBeinMaterial[0]);
  node->addNode(cyl);
  node->setPosition(QVector3D(.8f, 0.f, 0.f));
  node->addNode(cone);
  {
    QMatrix4x4 mat;
    mat.rotate(90, 0.0f, 1.0f, 0.0f);
    node->setLocalTransform(mat);
  }
  // Y-direction
  node = new QGLSceneNode(meshDreiBein);
  node->setMaterial(dreiBeinMaterial[1]);
  node->addNode(cyl);
  node->addNode(cone);
  {
    QMatrix4x4 mat;
    mat.rotate(-90, 1.0f, 0.0f, 0.0f);
    node->setLocalTransform(mat);
  }
  node->setPosition(QVector3D(0.f, .8f, 0.f));
  // Z-direction
  node = new QGLSceneNode(meshDreiBein);
  node->setMaterial(dreiBeinMaterial[2]);
  node->addNode(cyl);
  node->addNode(cone);
  node->setPosition(QVector3D(0.f, 0.f, .8f));
}
/**
 * Update operation which can be invoked by the observable (which should be the
 * change tracker here).
 */
void GLWorldView::update(Observable *publisher)
{
  emit changed();
}
/**
 * The observable can tell when it dies.
 */
void GLWorldView::subjectKilled(Observable *publisher) {}
/** Listen to specific changes to the world.
 *
 * @param publisher ref to observable.
 * @param notification type of notification
 */
void GLWorldView::recieveNotification(Observable *publisher, Notification_ptr notification)
{
  if (static_cast(publisher) == World::getPointer()) {
    switch (notification->getChannelNo()) {
      case World::AtomInserted:
      {
        const atom *_atom = World::getInstance().lastChanged();
  #ifdef LOG_OBSERVER
        observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast(this)) << " received notification that atom "+toString(_atom->getId())+" has been inserted.";
  #endif
        emit atomInserted(_atom);
        break;
      }
      case World::AtomRemoved:
      {
        const atom *_atom = World::getInstance().lastChanged();
  #ifdef LOG_OBSERVER
        observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast(this)) << " received notification that atom "+toString(_atom->getId())+" has been removed.";
  #endif
        emit atomRemoved(_atom);
        break;
      }
      case World::SelectionChanged:
      {
  #ifdef LOG_OBSERVER
        observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast(this)) << " received notification that selection has changed.";
  #endif
        emit worldSelectionChanged();
        break;
      }
      case World::MoleculeInserted:
      {
        const molecule *_molecule = World::getInstance().lastChanged();
  #ifdef LOG_OBSERVER
        observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast(this)) << " received notification that molecule "+toString(_molecule->getId())+" has been removed.";
  #endif
        emit moleculeInserted(_molecule);
        break;
      }
      case World::MoleculeRemoved:
      {
        const molecule *_molecule = World::getInstance().lastChanged();
  #ifdef LOG_OBSERVER
        observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast(this)) << " received notification that molecule "+toString(_molecule->getId())+" has been removed.";
  #endif
        emit moleculeRemoved(_molecule);
        break;
      }
      default:
        ASSERT(0, "GLWorldView::recieveNotification() - we cannot get here.");
        break;
    }
  } else if (dynamic_cast(publisher) != NULL) {
    switch (notification->getChannelNo()) {
      case AtomObservable::PositionChanged:
      {
        const atom *_atom = dynamic_cast(publisher);
    #ifdef LOG_OBSERVER
        observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast(this)) << " received notification that atom "+toString(_atom->getId())+" has changed its position.";
    #endif
        emit changed();
        break;
      }
      default:
        ASSERT(0, "GLWorldView::recieveNotification() - we cannot get here.");
        break;
    }
  } else if (static_cast(publisher) == ShapeRegistry::getPointer()) {
    switch (notification->getChannelNo()) {
      case ShapeRegistry::ShapeInserted:
      {
        worldscene->addShape(*ShapeRegistry::getInstance().lastChanged());
        break;
      }
      case ShapeRegistry::ShapeRemoved:
      {
        worldscene->removeShape(*ShapeRegistry::getInstance().lastChanged());
        break;
      }
      case ShapeRegistry::SelectionChanged:
      {
        worldscene->updateSelectedShapes();
        break;
      }
      default:
        ASSERT(0, "GLWorldView::recieveNotification() - we cannot get here.");
        break;
    }
  } else
    ASSERT(0, "GLWorldView::recieveNotification() - received notification from unknown source.");
}
void GLWorldView::checkChanges()
{
  updateGL();
  needsRedraw = false;
}
void GLWorldView::sceneChangeSignalled()
{
  if (!needsRedraw){
    redrawTimer->singleShot(0, this, SLOT(checkChanges()));
    needsRedraw = true;
    redrawTimer->start();
  }
}
void GLWorldView::initializeGL(QGLPainter *painter)
{
  worldscene->initialize(this, painter);
  changesPresent = false;
}
void GLWorldView::paintGL(QGLPainter *painter)
{
  if (changesPresent) {
    initializeGL(painter);
    changesPresent = false;
  }
  QVector3D cameraDir = camera()->center() - camera()->eye();
  cameraDir.normalize();
  QVector4D cameraPlane(cameraDir, QVector3D::dotProduct(cameraDir, camera()->eye()));
  worldscene->draw(painter, cameraPlane);
  drawDreiBein(painter);
  // Domain box has to be last because of its transparency.
  drawDomainBox(painter);
}
void GLWorldView::keyPressEvent(QKeyEvent *e)
{
  if (e->key() == Qt::Key_Tab) {
    // The Tab key turns the ShowPicking option on and off,
    // which helps show what the pick buffer looks like.
    setOption(QGLView::ShowPicking, ((options() & QGLView::ShowPicking) == 0));
    updateGL();
  }
  QGLView::keyPressEvent(e);
}
void GLWorldView::changeSignalled()
{
  changesPresent = true;
}
/**
 * Set the current camera control mode.
 */
void GLWorldView::setCameraControlMode(GLWorldView::CameraControlModeType mode)
{
  cameraControlMode = mode;
}
void GLWorldView::setCameraControlModeRotation()
{
  setCameraControlMode(Rotate);
}
void GLWorldView::setCameraControlModeTranslation()
{
  setCameraControlMode(Translate);
}
/**
 * Returns the current camera control mode.
 * This needs to be invertable (rotation - translation), if the shift key is pressed.
 */
GLWorldView::CameraControlModeType GLWorldView::getCameraControlMode(bool inverted)
{
  if (inverted){
    if (cameraControlMode == Rotate)
      return Translate;
    if (cameraControlMode == Translate)
      return Rotate;
    return Rotate;
  }else
    return cameraControlMode;
}
/**
 * Set the camera so it can oversee the whole domain.
 */
void GLWorldView::fitCameraToDomain()
{
  // Move the camera focus point to the center of the domain box.
  Vector v = World::getInstance().getDomain().translateIn(Vector(0.5, 0.5, 0.5));
  camera()->setCenter(QVector3D(v[0], v[1], v[2]));
  // Guess some eye distance.
  double dist = v.Norm() * 3;
  camera()->setEye(QVector3D(v[0], v[1], v[2] + dist));
  camera()->setUpVector(QVector3D(0, 1, 0));
}
void GLWorldView::setCameraStereoModeDisable()
{
  setStereoType(QGLView::Hardware);
  camera()->setEyeSeparation(0.0);
  updateGL();
}
void GLWorldView::setCameraStereoModeHardware()
{
  setStereoType(QGLView::Hardware);
  camera()->setEyeSeparation(defaultEyeSeparation);
  updateGL();
}
void GLWorldView::setCameraStereoModeLeftRight()
{
  setStereoType(QGLView::LeftRight);
  camera()->setEyeSeparation(defaultEyeSeparation);
  updateGL();
}
void GLWorldView::setCameraStereoModeRightLeft()
{
  setStereoType(QGLView::RightLeft);
  camera()->setEyeSeparation(defaultEyeSeparation);
  updateGL();
}
void GLWorldView::setCameraStereoModeTopBottom()
{
  setStereoType(QGLView::TopBottom);
  camera()->setEyeSeparation(defaultEyeSeparation);
  updateGL();
}
void GLWorldView::setCameraStereoModeBottomTop()
{
  setStereoType(QGLView::BottomTop);
  camera()->setEyeSeparation(defaultEyeSeparation);
  updateGL();
}
void GLWorldView::setCameraStereoModeAnaglyph()
{
  setStereoType(QGLView::RedCyanAnaglyph);
  camera()->setEyeSeparation(defaultEyeSeparation);
  updateGL();
}
void GLWorldView::mousePressEvent(QMouseEvent *event)
{
  QGLView::mousePressEvent(event);
  // Reset the saved mouse position.
  lastMousePos = event->posF();
}
/**
 * Handle a mouse move event.
 * This is used to control the camera (rotation and translation) when the left button is being pressed.
 */
void GLWorldView::mouseMoveEvent(QMouseEvent *event)
{
  if (event->buttons() & Qt::LeftButton){
    // Find the mouse distance since the last event.
    QPointF d = event->posF() - lastMousePos;
    lastMousePos = event->posF();
    // Rotate or translate?   (inverted by shift key)
    CameraControlModeType mode = getCameraControlMode(event->modifiers() & Qt::ShiftModifier);
    if (mode == Rotate){
      // Rotate the camera.
      d *= 0.3;
      camera()->tiltPanRollCenter(- d.y(), - d.x(), 0);
    }else if (mode == Translate){
      // Translate the camera.
      d *= 0.02;
      camera()->translateCenter(- d.x(), d.y(), 0);
      camera()->translateEye(- d.x(), d.y(), 0);
    }
  }else{
    // Without this Qt would not test for hover events (i.e. mouse over an atom).
    QGLView::mouseMoveEvent(event);
  }
}
/**
 * When the mouse wheel is used, zoom in or out.
 */
void GLWorldView::wheelEvent(QWheelEvent *event)
{
  // Find the distance between the eye and focus point.
  QVector3D d = camera()->eye() - camera()->center();
  // Scale the distance.
  if (event->delta() < 0)
    d *= 1.2;
  else if (event->delta() > 0)
    d /= 1.2;
  // Set new eye position.
  camera()->setEye(camera()->center() + d);
}
/**
 * Draw a transparent cube representing the domain.
 */
void GLWorldView::drawDomainBox(QGLPainter *painter) const
{
  // Apply the domain matrix.
  RealSpaceMatrix m = World::getInstance().getDomain().getM();
  painter->modelViewMatrix().push();
  painter->modelViewMatrix() *= QMatrix4x4(m.at(0,0), m.at(0,1), m.at(0,2), 0.0,
                                           m.at(1,0), m.at(1,1), m.at(1,2), 0.0,
                                           m.at(2,0), m.at(2,1), m.at(2,2), 0.0,
                                           0.0,       0.0,       0.0,       1.0);
  // Draw the transparent cube.
  painter->setStandardEffect(QGL::LitMaterial);
  glCullFace(GL_BACK);
  glEnable(GL_CULL_FACE);
  glEnable(GL_BLEND);
  glDepthMask(0);
  //glDisable(GL_DEPTH_TEST);
  meshDomainBox->draw(painter);
  //glEnable(GL_DEPTH_TEST);
  glDepthMask(1);
  glDisable(GL_BLEND);
  glDisable(GL_CULL_FACE);
  // Draw the outlines.
  painter->setFaceMaterial(QGL::AllFaces, domainBoxMaterial);
  //glEnable(GL_LINE_SMOOTH);
  QVector3DArray array;
  array.append(0, 0, 0); array.append(1, 0, 0);
  array.append(1, 0, 0); array.append(1, 1, 0);
  array.append(1, 1, 0); array.append(0, 1, 0);
  array.append(0, 1, 0); array.append(0, 0, 0);
  array.append(0, 0, 1); array.append(1, 0, 1);
  array.append(1, 0, 1); array.append(1, 1, 1);
  array.append(1, 1, 1); array.append(0, 1, 1);
  array.append(0, 1, 1); array.append(0, 0, 1);
  array.append(0, 0, 0); array.append(0, 0, 1);
  array.append(1, 0, 0); array.append(1, 0, 1);
  array.append(0, 1, 0); array.append(0, 1, 1);
  array.append(1, 1, 0); array.append(1, 1, 1);
  painter->clearAttributes();
  painter->setVertexAttribute(QGL::Position, array);
  painter->draw(QGL::Lines, 24);
  painter->modelViewMatrix().pop();
}
void GLWorldView::drawDreiBein(QGLPainter *painter)
{
  painter->modelViewMatrix().push();
  painter->modelViewMatrix().translate(camera()->center());
  painter->setStandardEffect(QGL::LitMaterial);
  painter->setFaceMaterial(QGL::FrontFaces, NULL);
  meshDreiBein->draw(painter);
  painter->modelViewMatrix().pop();
}
void GLWorldView::sceneHoverSignalled(const atom *_atom)
{
  emit hoverChanged(_atom);
}
//#include 
//#include 
//#include 
//
//#include "ui_dialoglight.h"
//
//#include "CodePatterns/MemDebug.hpp"
//
//#include 
//#include 
//
//#include "LinearAlgebra/Line.hpp"
//#include "Atom/atom.hpp"
//#include "Bond/bond.hpp"
//#include "Element/element.hpp"
//#include "molecule.hpp"
//#include "Element/periodentafel.hpp"
//#include "World.hpp"
//
//#if defined(Q_CC_MSVC)
//#pragma warning(disable:4305) // init: truncation from const double to float
//#endif
//
//
//GLMoleculeView::GLMoleculeView(QWidget *parent) :
//  QGLWidget(parent), Observer("GLMoleculeView"), X(Vector(1,0,0)), Y(Vector(0,1,0)), Z(Vector(0,0,1))
//{
//    xRot = yRot = zRot = 0.0;    // default object rotation
//    scale = 5.;      // default object scale
//    object = 0;
//    LightPosition[0] = 0.0f;
//    LightPosition[1] = 2.0f;
//    LightPosition[2] = 2.0f;
//    LightPosition[3] = 0.0f;
//    LightDiffuse[0] = 0.5f;
//    LightDiffuse[1] = 0.5f;
//    LightDiffuse[2] = 0.5f;
//    LightDiffuse[3] = 0.0f;
//    LightAmbient[0] = 0.0f;
//    LightAmbient[1] = 0.0f;
//    LightAmbient[2] = 0.0f;
//    LightAmbient[3] = 0.0f;
//
//    SelectionColor[0] = 0;
//    SelectionColor[1] = 128;
//    SelectionColor[2] = 128;
//
//    MultiViewEnabled = true;
//
//    isSignaller = false;
//
//    World::getInstance().signOn(this);
//}
//
///** Destructor of GLMoleculeView.
// * Free's the CallList.
// */
//GLMoleculeView::~GLMoleculeView()
//{
//    makeCurrent();
//    glDeleteLists( object, 1 );
//
//    World::getInstance().signOff(this);
//}
//
///** Paints the conents of the OpenGL window.
// * Clears the GL buffers, enables lighting and depth.
// * Window is either quartered (if GLMoleculeView::MultiViewEnabled) and xy, xz, yz planar views
// * are added. Uses the CallList, constructed during InitializeGL().
// */
//void GLMoleculeView::paintGL()
//{
//  Vector spot;
//
//  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//  glShadeModel(GL_SMOOTH);            // Enable Smooth Shading
//  glEnable(GL_LIGHTING);              // Enable Light One
//  glEnable(GL_DEPTH_TEST);            // Enables Depth Testing
//  glDepthFunc(GL_LEQUAL);              // The Type Of Depth Testing To Do
//  glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);      // Really Nice Perspective Calculations
//
//  // 3d viewport
//  if (MultiViewEnabled)
//    glViewport( 0, 0, (GLint)width/2, (GLint)height/2 );
//  else
//    glViewport( 0, 0, (GLint)width, (GLint)height );
//  glMatrixMode( GL_PROJECTION );
//  glLoadIdentity();
//  glFrustum( -1.0, 1.0, -1.0, 1.0, 1.0, 50.0 );
//  glMatrixMode( GL_MODELVIEW );
//  glLoadIdentity();
//
//  // calculate point of view and direction
//  glTranslated(position[0],position[1],position[2]);
//  glTranslated(0.0, 0.0, -scale);
//  glRotated(xRot, 1.0, 0.0, 0.0);
//  glRotated(yRot, 0.0, 1.0, 0.0);
//  glRotated(zRot, 0.0, 0.0, 1.0);
//
//  // render scene
//  glCallList(object);
//
//  // enable light
//  glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);       // Setup The Ambient Light
//  glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);       // Setup The Diffuse Light
//  glLightfv(GL_LIGHT1, GL_POSITION,LightPosition);      // Position The Light
//  glEnable(GL_LIGHT1);              // Enable Light One
//
//  if (MultiViewEnabled) {
//    // xy view port
//    glViewport( (GLint)width/2, 0, (GLint)width/2, (GLint)height/2 );
//    glMatrixMode( GL_PROJECTION );
//    glLoadIdentity();
//    glScalef(1./scale, 1./scale,1./scale);
//    glOrtho(0, width/2, 0, height/2, 0,0);
//    glMatrixMode( GL_MODELVIEW );
//    glLoadIdentity();
//
//    // calculate point of view and direction
//    view = position;
//    spot = Vector(0.,0.,scale);
//    top = Vector(0.,1.,0.);
//    gluLookAt(
//        spot[0], spot[1], spot[2],
//        view[0], view[1], view[2],
//        top[0], top[1], top[2]);
//
//    // enable light
//    glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);       // Setup The Ambient Light
//    glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);       // Setup The Diffuse Light
//    glLightfv(GL_LIGHT1, GL_POSITION,LightPosition);      // Position The Light
//    glEnable(GL_LIGHT1);              // Enable Light One
//
//    // render scene
//    glCallList(object);
//
//    // xz viewport
//    glViewport( 0, (GLint)height/2, (GLint)width/2, (GLint)height/2 );
//    glMatrixMode( GL_PROJECTION );
//    glLoadIdentity();
//    glScalef(1./scale, 1./scale,1./scale);
//    glOrtho(0, width/2, 0, height/2, 0,0);
//    glMatrixMode( GL_MODELVIEW );
//    glLoadIdentity();
//
//    // calculate point of view and direction
//    view = position;
//    spot = Vector(0.,scale,0.);
//    top = Vector(1.,0.,0.);
//    gluLookAt(
//        spot[0], spot[1], spot[2],
//        view[0], view[1], view[2],
//        top[0], top[1], top[2]);
//
//    // enable light
//    glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);       // Setup The Ambient Light
//    glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);       // Setup The Diffuse Light
//    glLightfv(GL_LIGHT1, GL_POSITION,LightPosition);      // Position The Light
//    glEnable(GL_LIGHT1);              // Enable Light One
//
//    // render scene
//    glCallList(object);
//
//    //yz viewport
//    glViewport( (GLint)width/2, (GLint)height/2, (GLint)width/2, (GLint)height/2 );
//    glMatrixMode( GL_PROJECTION );
//    glLoadIdentity();
//    glScalef(1./scale, 1./scale,1./scale);
//    glOrtho(0, width/2, 0, height/2, 0,0);
//    glMatrixMode( GL_MODELVIEW );
//    glLoadIdentity();
//
//    // calculate point of view and direction
//    view= position;
//    spot = Vector(scale,0.,0.);
//    top = Vector(0.,1.,0.);
//    gluLookAt(
//        spot[0], spot[1], spot[2],
//        view[0], view[1], view[2],
//        top[0], top[1], top[2]);
//
//    // enable light
//    glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient);       // Setup The Ambient Light
//    glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse);       // Setup The Diffuse Light
//    glLightfv(GL_LIGHT1, GL_POSITION,LightPosition);      // Position The Light
//    glEnable(GL_LIGHT1);              // Enable Light One
//
//    // render scene
//    glCallList(object);
//  }
//  //CoordinatesBar->setText( QString ("X: %1, Y: %2, Z: %3").arg(position[0]).arg(position[1]).arg(position[2]) );
//}
//
////void polarView{GLdouble distance, GLdouble twist,
////   GLdouble elevation, GLdouble azimuth)
////{
////      glTranslated(0.0, 0.0, -distance);
////      glRotated(-twist, 0.0, 0.0, 1.0);
////      glRotated(-elevation, 1.0, 0.0, 0.0);
////      glRotated(azimuth, 0.0, 0.0, 1.0);
////}
//
///** Make a sphere.
// * \param x position
// * \param radius radius
// * \param color[3] color rgb values
// */
//void GLMoleculeView::makeSphere(const Vector &x, double radius, const unsigned char color[3])
//{
//  float blueMaterial[] = { 255./(float)color[0], 255./(float)color[1], 255./(float)color[2], 1 };  // need to recast from [0,255] with integers into [0,1] with floats
//  GLUquadricObj* q = gluNewQuadric ();
//  gluQuadricOrientation(q, GLU_OUTSIDE);
//
//  std::cout << "Setting sphere at " << x << " with color r"
//      << (int)color[0] << ",g" << (int)color[1] << ",b" << (int)color[2] << "." << endl;
//
//  glPushMatrix();
//  glTranslatef( x[0], x[1], x[2]);
////  glRotatef( xRot, 1.0, 0.0, 0.0);
////  glRotatef( yRot, 0.0, 1.0, 0.0);
////  glRotatef( zRot, 0.0, 0.0, 1.0);
//  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blueMaterial);
//  gluSphere (q, (GLdouble)radius, 10, 10);
//  glPopMatrix();
//}
//
///** Make a cylinder.
// * \param x origin
// * \param y direction
// * \param radius thickness
// * \param height length
// * \color[3] color rgb values
// */
//void GLMoleculeView::makeCylinder(const Vector &x, const Vector &y, double radius, double height, const unsigned char color[3])
//{
//  float blueMaterial[] = { 255./(float)color[0], 255./(float)color[1], 255./(float)color[2], 1 };
//  GLUquadricObj* q = gluNewQuadric ();
//  gluQuadricOrientation(q, GLU_OUTSIDE);
//  Vector a,b;
//  Vector OtherAxis;
//  double alpha;
//  a = x - y;
//  // construct rotation axis
//  b = a;
//  b.VectorProduct(Z);
//  Line axis(zeroVec, b);
//  // calculate rotation angle
//  alpha = a.Angle(Z);
//  // construct other axis to check right-hand rule
//  OtherAxis = b;
//  OtherAxis.VectorProduct(Z);
//  // assure right-hand rule for the rotation
//  if (a.ScalarProduct(OtherAxis) < MYEPSILON)
//    alpha = M_PI-alpha;
//  // check
//  Vector a_rotated = axis.rotateVector(a, alpha);
//  std::cout << "Setting cylinder from "// << x << " to " << y
//      << a << " to " << a_rotated << " around " << b << " by " << alpha/M_PI*180. << ", respectively, "
//      << " with color r"
//      << (int)color[0] << ",g" << (int)color[1] << ",b" << (int)color[2] << "." << endl;
//
//  glPushMatrix();
//  glTranslatef( x[0], x[1], x[2]);
//  glRotatef( alpha/M_PI*180., b[0], b[1], b[2]);
//  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blueMaterial);
//  gluCylinder (q, (GLdouble)radius, (GLdouble)radius, (GLdouble)height, 10, 10);
//  glPopMatrix();
//}
//
///** Defines the display CallList.
// * Goes through all molecules and their atoms and adds spheres for atoms and cylinders
// * for bonds. Heeds GLMoleculeView::SelectedAtom and GLMoleculeView::SelectedMolecule.
// */
//void GLMoleculeView::initializeGL()
//{
//  double x[3] = {-1, 0, -10};
//  unsigned char white[3] = {255,255,255};
//  Vector Position, OtherPosition;
//  QSize window = size();
//  width = window.width();
//  height = window.height();
//  std::cout << "Setting width to " << width << " and height to " << height << std::endl;
//  GLfloat shininess[] = { 0.0 };
//  GLfloat specular[] = { 0, 0, 0, 1 };
//  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);     // Let OpenGL clear to black
//  object = glGenLists(1);
//  glNewList( object, GL_COMPILE );
//  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
//  glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
//
//  const std::vector &molecules = World::getInstance().getAllMolecules();
//
//  if (molecules.size() > 0) {
//    for (std::vector::const_iterator Runner = molecules.begin();
//        Runner != molecules.end();
//        Runner++) {
//      for (molecule::const_iterator atomiter = (*Runner)->begin();
//          atomiter != (*Runner)->end();
//          ++atomiter) {
//        // create atom
//        const element *ptr = (*atomiter)->getType();
//        boost::shared_ptr MolCenter((*Runner)->DetermineCenterOfGravity());
//        Position = (*atomiter)->getPosition() - *MolCenter;
//        const unsigned char* color = NULL;
//        if ((World::getInstance().isSelected(*atomiter)) || (World::getInstance().isSelected((*Runner))))
//          color = SelectionColor;
//        else
//          color = ptr->getColor();
//        makeSphere(Position, ptr->getVanDerWaalsRadius()*0.25, color);
//
//        // create bonds
//        const BondList &bonds = (*atomiter)->getListOfBonds();
//        for (BondList::const_iterator bonditer = bonds.begin();
//            bonditer != bonds.end();
//            ++bonditer) {
//          if ((*bonditer)->leftatom->getId() == (*atomiter)->getId()) {
//            Position = (*bonditer)->leftatom->getPosition() - *MolCenter;
//            OtherPosition = (*bonditer)->rightatom->getPosition() - *MolCenter;
//            const double distance = sqrt(Position.DistanceSquared(OtherPosition))/2.;
//            const unsigned char *color1 = (*bonditer)->leftatom->getType()->getColor();
//            const unsigned char *color2 = (*bonditer)->rightatom->getType()->getColor();
//            makeCylinder(Position, OtherPosition, 0.1, distance, color1);
//            makeCylinder(OtherPosition, Position, 0.1, distance, color2);
//          }
//        }
//      }
//    }
//  } else {
//    makeSphere( x,1, white);
//  }
//  glEndList();
//}
//
//
///* ================================== SLOTS ============================== */
//
///** Initializes some public variables.
// * \param *ptr pointer to QLabel statusbar
// */
//void GLMoleculeView::init(QLabel *ptr)
//{
//  StatusBar = ptr;
//}
//
///** Initializes the viewport statusbar.
// * \param *ptr pointer to QLabel for showing view pointcoordinates.
// */
//void GLMoleculeView::initCoordinates(QLabel *ptr)
//{
//  CoordinatesBar = ptr;
//}
//
///** Slot to be called when to initialize GLMoleculeView::MolData.
// */
//void GLMoleculeView::createView( )
//{
//  initializeGL();
//  updateGL();
//}
//
///** Slot of window is resized.
// * Copies new width and height to GLMoleculeView::width and GLMoleculeView::height and calls updateGL().
// * \param w new width of window
// * \param h new height of window
// */
//void GLMoleculeView::resizeGL( int w, int h )
//{
//  width = w;
//  height = h;
//  updateGL();
//}
//
///** Sets x rotation angle.
// * sets GLMoleculeView::xRot and calls updateGL().
// * \param degrees new rotation angle in degrees
// */
//void GLMoleculeView::setXRotation( int degrees )
//{
//  xRot = (GLfloat)(degrees % 360);
//  updateGL();
//}
//
//
///** Sets y rotation angle.
// * sets GLMoleculeView::yRot and calls updateGL().
// * \param degrees new rotation angle in degrees
// */
//void GLMoleculeView::setYRotation( int degrees )
//{
//  yRot = (GLfloat)(degrees % 360);
//  updateGL();
//}
//
//
///** Sets z rotation angle.
// * sets GLMoleculeView::zRot and calls updateGL().
// * \param degrees new rotation angle in degrees
// */
//void GLMoleculeView::setZRotation( int degrees )
//{
//  zRot = (GLfloat)(degrees % 360);
//  updateGL();
//}
//
///** Sets the scale of the scene.
// * sets GLMoleculeView::scale and calls updateGL().
// * \param distance distance divided by 100 is the new scale
// */
//void GLMoleculeView::setScale( int distance )
//{
//  scale = (GLfloat)(distance / 100.);
//  updateGL();
//}
//
///** Update the ambient light.
// * \param light[4] light strength per axis and position (w)
// */
//void GLMoleculeView::setLightAmbient( int *light )
//{
//  for(int i=0;i<4;i++)
//    LightAmbient[i] = light[i];
//  updateGL();
//}
//
///** Update the diffuse light.
// * \param light[4] light strength per axis and position (w)
// */
//void GLMoleculeView::setLightDiffuse( int *light )
//{
//  for(int i=0;i<4;i++)
//    LightDiffuse[i] = light[i];
//  updateGL();
//}
//
///** Update the position of light.
// * \param light[4] light strength per axis and position (w)
// */
//void GLMoleculeView::setLightPosition( int *light )
//{
//  for(int i=0;i<4;i++)
//    LightPosition[i] = light[i];
//  updateGL();
//}
//
///** Toggles the boolean GLMoleculeView::MultiViewEnabled.
// * Flips the boolean and calls updateGL().
// */
//void GLMoleculeView::toggleMultiViewEnabled ( )
//{
//  MultiViewEnabled = !MultiViewEnabled;
//  cout << "Setting MultiView to " << MultiViewEnabled << "." << endl;
//  updateGL();
//}
//
///** Launch a dialog to configure the lights.
// */
//void GLMoleculeView::createDialogLight()
//{
////  Ui_DialogLight *Lights = new Ui_DialogLight();
////  if (Lights == NULL)
////    return;
////  // Set up the dynamic dialog here
////  QLineEdit *Field = NULL;
////  Field = Lights->findChild("LightPositionX");
////  if (Field) Field->setText( QString("%1").arg(LightPosition[0]) );
////  Field = Lights->findChild("LightPositionY");
////  if (Field) Field->setText( QString("%1").arg(LightPosition[1]) );
////  Field = Lights->findChild("LightPositionZ");
////  if (Field) Field->setText( QString("%1").arg(LightPosition[2]) );
////  Field = Lights->findChild("LightPositionW");
////  if (Field) Field->setText( QString("%1").arg(LightPosition[3]) );
////
////  Field = Lights->findChild("LightDiffuseX");
////  if (Field) Field->setText( QString("%1").arg(LightDiffuse[0]) );
////  Field = Lights->findChild("LightDiffuseY");
////  if (Field) Field->setText( QString("%1").arg(LightDiffuse[1]) );
////  Field = Lights->findChild("LightDiffuseZ");
////  if (Field) Field->setText( QString("%1").arg(LightDiffuse[2]) );
////  Field = Lights->findChild("LightDiffuseW");
////  if (Field) Field->setText( QString("%1").arg(LightDiffuse[3]) );
////
////  Field = Lights->findChild("LightAmbientX");
////  if (Field) Field->setText( QString("%1").arg(LightAmbient[0]) );
////  Field = Lights->findChild("LightAmbientY");
////  if (Field) Field->setText( QString("%1").arg(LightAmbient[1]) );
////  Field = Lights->findChild("LightAmbientZ");
////  if (Field) Field->setText( QString("%1").arg(LightAmbient[2]) );
////  Field = Lights->findChild("LightAmbientW");
////  if (Field) Field->setText( QString("%1").arg(LightAmbient[3]) );
////
////  if ( Lights->exec() ) {
////    //cout << "User accepted.\n";
////    // The user accepted, act accordingly
////    Field = Lights->findChild("LightPositionX");
////    if (Field) LightPosition[0] = Field->text().toDouble();
////    Field = Lights->findChild("LightPositionY");
////    if (Field) LightPosition[1] = Field->text().toDouble();
////    Field = Lights->findChild("LightPositionZ");
////    if (Field) LightPosition[2] = Field->text().toDouble();
////    Field = Lights->findChild("LightPositionW");
////    if (Field) LightPosition[3] = Field->text().toDouble();
////
////    Field = Lights->findChild("LightDiffuseX");
////    if (Field) LightDiffuse[0] = Field->text().toDouble();
////    Field = Lights->findChild("LightDiffuseY");
////    if (Field) LightDiffuse[1] = Field->text().toDouble();
////    Field = Lights->findChild("LightDiffuseZ");
////    if (Field) LightDiffuse[2] = Field->text().toDouble();
////    Field = Lights->findChild("LightDiffuseW");
////    if (Field) LightDiffuse[3] = Field->text().toDouble();
////
////    Field = Lights->findChild("LightAmbientX");
////    if (Field) LightAmbient[0] = Field->text().toDouble();
////    Field = Lights->findChild("LightAmbientY");
////    if (Field) LightAmbient[1] = Field->text().toDouble();
////    Field = Lights->findChild("LightAmbientZ");
////    if (Field) LightAmbient[2] = Field->text().toDouble();
////    Field = Lights->findChild("LightAmbientW");
////    if (Field) LightAmbient[3] = Field->text().toDouble();
////    updateGL();
////  } else {
////    //cout << "User reclined.\n";
////  }
////  delete(Lights);
//}
//
///** Slot for event of pressed mouse button.
// * Switch discerns between buttons and stores position of event in GLMoleculeView::LeftButtonPos,
// * GLMoleculeView::MiddleButtonPos or GLMoleculeView::RightButtonPos.
// * \param *event structure containing information of the event
// */
//void GLMoleculeView::mousePressEvent(QMouseEvent *event)
//{
//  std::cout << "MousePressEvent." << endl;
//  QPoint *pos = NULL;
//  switch (event->button()) {  // get the right array
//    case Qt::LeftButton:
//      pos = &LeftButtonPos;
//      std::cout << "Left Button" << endl;
//      break;
//    case Qt::MidButton:
//      pos = &MiddleButtonPos;
//      std::cout << "Middle Button" << endl;
//      break;
//    case Qt::RightButton:
//      pos = &RightButtonPos;
//      std::cout << "Right Button" << endl;
//      break;
//    default:
//      break;
//  }
//  if (pos) {    // store the position
//    pos->setX(event->pos().x());
//    pos->setY(event->pos().y());
//    std::cout << "Stored src position is (" << pos->x() << "," << pos->y() << ")." << endl;
//  } else {
//    std::cout << "pos is NULL." << endl;
//  }
//}
//
///** Slot for event of pressed mouse button.
// * Switch discerns between buttons:
// * -# Left Button: Rotates the view of the GLMoleculeView, relative to GLMoleculeView::LeftButtonPos.
// * -# Middle Button: nothing
// * -# Right Button: Shifts the selected molecule or atom, relative to GLMoleculeView::RightButtonPos.
// * \param *event structure containing information of the event
// */
//void GLMoleculeView::mouseReleaseEvent(QMouseEvent *event)
//{
//  std::cout << "MouseReleaseEvent." << endl;
//  QPoint *srcpos = NULL;
//  QPoint destpos = event->pos();
//  int Width = (MultiViewEnabled) ? width/2 : width;
//  int Height = (MultiViewEnabled) ? height/2 : height;
//  std::cout << "Received dest position is (" << destpos.x() << "," << destpos.y() << ")." << endl;
//  switch (event->button()) {  // get the right array
//    case Qt::LeftButton:  // LeftButton rotates the view
//      srcpos = &LeftButtonPos;
//      std::cout << "Left Button" << endl;
//      if (srcpos) {    // subtract the position and act
//        std::cout << "Stored src position is (" << srcpos->x() << "," << srcpos->y() << ")." << endl;
//        destpos -= *srcpos;
//        std::cout << "Resulting diff position is (" << destpos.x() << "," << destpos.y() << ")." << endl;
//        std::cout << "Width and Height are " << Width << "," << Height << "." << endl;
//
//        int pos = (int)floor((double)srcpos->x()/(double)Width) + ((int)floor((double)srcpos->y()/(double)Height))*2;
//        if ((MultiViewEnabled) && (pos != 2)) { // means four regions, and we are in a shifting one
//          // switch between three regions
//          // decide into which of the four screens the initial click has been made
//          std::cout << "Position is " << pos << "." << endl;
//          switch(pos) {
//            case 0:  // lower left = xz
//              position[0] += -destpos.y()/100.;
//              position[2] += destpos.x()/100.;
//              break;
//            case 1: // lower right = yz
//              position[1] += -destpos.y()/100.;
//              position[2] += -destpos.x()/100.;
//              break;
//            case 2:  // upper left = projected
//              std::cout << "This is impossible: Shifting in the projected region, we should rotate!." << endl;
//              break;
//            case 3:  // upper right = xy
//              position[0] += destpos.x()/100.;
//              position[1] += -destpos.y()/100.;
//              break;
//            default:
//              std::cout << "click was not in any of the four regions." << endl;
//              break;
//          }
//          updateGL();
//        } else { // we are in rotation region
//          QWidget *Parent = parentWidget();
//          QSlider *sliderX = Parent->findChild("sliderX");
//          QSlider *sliderY = Parent->findChild("sliderY");
//          std::cout << sliderX << " and " << sliderY << endl;
//          if (sliderX) {
//            int xrange = sliderX->maximum() - sliderX->minimum();
//            double xValue = ((destpos.x() + Width) % Width);
//            xValue *= (double)xrange/(double)Width;
//            xValue += sliderX->value();
//            int xvalue = (int) xValue % xrange;
//            std::cout << "Setting x to " << xvalue << " within range " << xrange << "." << endl;
//            setXRotation(xvalue);
//            sliderX->setValue(xvalue);
//          } else {
//            std::cout << "sliderX is NULL." << endl;
//          }
//          if (sliderY) {
//            int yrange = sliderY->maximum() - sliderY->minimum();
//            double yValue = ((destpos.y() + Height) % Height);
//            yValue *= (double)yrange/(double)Height;
//            yValue += sliderY->value();
//            int yvalue = (int) yValue % yrange;
//            std::cout << "Setting y to " << yvalue << " within range " << yrange << "." << endl;
//            setYRotation(yvalue);
//            sliderY->setValue(yvalue);
//          } else {
//            std::cout << "sliderY is NULL." << endl;
//          }
//        }
//      } else {
//        std::cout << "srcpos is NULL." << endl;
//      }
//      break;
//
//    case Qt::MidButton: // MiddleButton has no function so far
//      srcpos = &MiddleButtonPos;
//      std::cout << "Middle Button" << endl;
//      if (srcpos) {    // subtract the position and act
//        QWidget *Parent = parentWidget();
//        QSlider *sliderZ = Parent->findChild("sliderZ");
//        QSlider *sliderScale = Parent->findChild("sliderScale");
//        std::cout << sliderZ << " and " << sliderScale << endl;
//        std::cout << "Stored src position is (" << srcpos->x() << "," << srcpos->y() << ")." << endl;
//        destpos -= *srcpos;
//        std::cout << "Resulting diff position is (" << destpos.x() << "," << destpos.y() << ")." << endl;
//        std::cout << "Width and Height are " << Width << "," << Height << "." << endl;
//        if (sliderZ) {
//          int xrange = sliderZ->maximum() - sliderZ->minimum();
//          double xValue = ((destpos.x() + Width) % Width);
//          xValue *= (double)xrange/(double)Width;
//          xValue += sliderZ->value();
//          int xvalue = (int) xValue % xrange;
//          std::cout << "Setting x to " << xvalue << " within range " << xrange << "." << endl;
//          setZRotation(xvalue);
//          sliderZ->setValue(xvalue);
//        } else {
//          std::cout << "sliderZ is NULL." << endl;
//        }
//        if (sliderScale) {
//          int yrange = sliderScale->maximum() - sliderScale->minimum();
//          double yValue = ((destpos.y() + Height) % Height);
//          yValue *= (double)yrange/(double)Height;
//          yValue += sliderScale->value();
//          int yvalue = (int) yValue % yrange;
//          std::cout << "Setting y to " << yvalue << " within range " << yrange << "." << endl;
//          setScale(yvalue);
//          sliderScale->setValue(yvalue);
//        } else {
//          std::cout << "sliderScale is NULL." << endl;
//        }
//      } else {
//        std::cout << "srcpos is NULL." << endl;
//      }
//      break;
//      break;
//
//    case Qt::RightButton:  // RightButton moves eitstdher the selected molecule or atom
//      srcpos = &RightButtonPos;
//      std::cout << "Right Button" << endl;
//      if (srcpos) {    // subtract the position and act
//        std::cout << "Stored src position is (" << srcpos->x() << "," << srcpos->y() << ")." << endl;
//        destpos -= *srcpos;
//        std::cout << "Resulting diff position is (" << destpos.x() << "," << destpos.y() << ")." << endl;
//        std::cout << "Width and Height are " << Width << "," << Height << "." << endl;
//        if (MultiViewEnabled) {
//          // which vector to change
//          Vector SelectedPosition;
//          const std::vector &SelectedAtoms = World::getInstance().getSelectedAtoms();
//          const std::vector &SelectedMolecules = World::getInstance().getSelectedMolecules();
//          if (SelectedMolecules.size()) {
//            if (SelectedAtoms.size())
//              SelectedPosition = (*SelectedAtoms.begin())->getPosition();
//            else
//              SelectedPosition = (*(*SelectedMolecules.begin())->begin())->getPosition();
//          }
//          // decide into which of the four screens the initial click has been made
//          int pos = (int)floor((double)srcpos->x()/(double)Width) + ((int)floor((double)srcpos->y()/(double)Height))*2;
//          if (!SelectedPosition.IsZero()) {
//            std::cout << "Position is " << pos << "." << endl;
//            switch(pos) {
//              case 0:  // lower left = xz
//                SelectedPosition[0] += -destpos.y()/100.;
//                SelectedPosition[2] += destpos.x()/100.;
//                break;
//              case 1: // lower right = yz
//                SelectedPosition[1] += -destpos.y()/100.;
//                SelectedPosition[2] += -destpos.x()/100.;
//                break;
//              case 2:  // upper left = projected
//                SelectedPosition[0] += destpos.x()/100.;
//                SelectedPosition[1] += destpos.y()/100.;
//                SelectedPosition[2] += destpos.y()/100.;
//                break;
//              case 3:  // upper right = xy
//                SelectedPosition[0] += destpos.x()/100.;
//                SelectedPosition[1] += -destpos.y()/100.;
//                break;
//              default:
//                std::cout << "click was not in any of the four regions." << endl;
//                break;
//            }
//          } else {
//            std::cout << "Nothing selected." << endl;
//          }
//          // update Tables
//          if (SelectedMolecules.size()) {
//            isSignaller = true;
//            if (SelectedAtoms.size())
//              emit notifyAtomChanged( (*SelectedMolecules.begin()), (*SelectedAtoms.begin()), AtomPosition);
//            else
//              emit notifyMoleculeChanged( (*SelectedMolecules.begin()), MoleculePosition );
//          }
//          // update graphic
//          initializeGL();
//          updateGL();
//        } else {
//          cout << "MultiView is not enabled." << endl;
//        }
//      } else {
//        cout << "srcpos is NULL." << endl;
//      }
//  break;
//
//    default:
//      break;
//  }
//}
//
///* ======================================== SLOTS ================================ */
//
///** Hear announcement of selected molecule.
// * \param *mol pointer to selected molecule
// */
//void GLMoleculeView::hearMoleculeSelected(molecule *mol)
//{
//  if (isSignaller) { // if we emitted the signal, return
//    isSignaller = false;
//    return;
//  }
//  initializeGL();
//  updateGL();
//};
//
///** Hear announcement of selected atom.
// * \param *mol pointer to molecule containing atom
// * \param *Walker pointer to selected atom
// */
//void GLMoleculeView::hearAtomSelected(molecule *mol, atom *Walker)
//{
//  if (isSignaller) { // if we emitted the signal, return
//    isSignaller = false;
//    return;
//  }
//  initializeGL();
//  updateGL();
//};
//
///** Hear announcement of changed molecule.
// * \param *mol pointer to changed molecule
// * \param type of change
// */
//void GLMoleculeView::hearMoleculeChanged(molecule *mol, enum ChangesinMolecule type)
//{
//  if (isSignaller) { // if we emitted the signal, return
//    isSignaller = false;
//    return;
//  }
//  initializeGL();
//  updateGL();
//};
//
///** Hear announcement of changed atom.
// * \param *mol pointer to molecule containing atom
// * \param *Walker pointer to changed atom
// * \param type type of change
// */
//void GLMoleculeView::hearAtomChanged(molecule *mol, atom *Walker, enum ChangesinAtom type)
//{
//  if (isSignaller) { // if we emitted the signal, return
//    isSignaller = false;
//    return;
//  }
//  initializeGL();
//  updateGL();
//};
//
///** Hear announcement of changed element.
// * \param *Runner pointer to changed element
// * \param type of change
// */
//void GLMoleculeView::hearElementChanged(element *Runner, enum ChangesinElement type)
//{
//  if (isSignaller) { // if we emitted the signal, return
//    isSignaller = false;
//    return;
//  }
//  switch(type) {
//    default:
//    case ElementName:
//    case ElementSymbol:
//    case ElementMass:
//    case ElementValence:
//    case ElementZ:
//      break;
//    case ElementCovalent:
//    case ElementVanderWaals:
//      initializeGL();
//      updateGL();
//      break;
//  }
//};
//
///** Hear announcement of added molecule.
// * \param *mol pointer to added molecule
// */
//void GLMoleculeView::hearMoleculeAdded(molecule *mol)
//{
//  if (isSignaller) { // if we emitted the signal, return
//    isSignaller = false;
//    return;
//  }
//  initializeGL();
//  updateGL();
//};
//
///** Hear announcement of added atom.
// * \param *mol pointer to molecule containing atom
// * \param *Walker pointer to added atom
// */
//void GLMoleculeView::hearAtomAdded(molecule *mol, atom *Walker)
//{
//  if (isSignaller) { // if we emitted the signal, return
//    isSignaller = false;
//    return;
//  }
//  initializeGL();
//  updateGL();
//};
//
///** Hear announcement of removed molecule.
// * \param *mol pointer to removed molecule
// */
//void GLMoleculeView::hearMoleculeRemoved(molecule *mol)
//{
//  if (isSignaller) { // if we emitted the signal, return
//    isSignaller = false;
//    return;
//  }
//  initializeGL();
//  updateGL();
//};
//
///** Hear announcement of removed atom.
// * \param *mol pointer to molecule containing atom
// * \param *Walker pointer to removed atom
// */
//void GLMoleculeView::hearAtomRemoved(molecule *mol, atom *Walker)
//{
//  if (isSignaller) { // if we emitted the signal, return
//    isSignaller = false;
//    return;
//  }
//  initializeGL();
//  updateGL();
//};
//
//void GLMoleculeView::update(Observable *publisher)
//{
//  initializeGL();
//  updateGL();
//}
//
///**
// * This method is called when a special named change
// * of the Observable occured
// */
//void GLMoleculeView::recieveNotification(Observable *publisher, Notification_ptr notification)
//{
//  initializeGL();
//  updateGL();
//}
//
///**
// * This method is called when the observed object is destroyed.
// */
//void GLMoleculeView::subjectKilled(Observable *publisher)
//{
//
//}
//
//
//// new stuff
//
///** Returns the ref to the Material for element No \a from the map.
// *
// * \note We create a new one if the element is missing.
// *
// * @param no element no
// * @return ref to QGLMaterial
// */
//QGLMaterial* GLMoleculeView::getMaterial(size_t no)
//{
//  if (ElementNoMaterialMap.find(no) != ElementNoMaterialMap.end()){
//    // get present one
//
//  } else {
//    ASSERT( (no >= 0) && (no < MAX_ELEMENTS),
//        "GLMoleculeView::getMaterial() - Element no "+toString(no)+" is invalid.");
//    // create new one
//    LOG(1, "Creating new material for element "+toString(no)+".");
//    QGLMaterial *newmaterial = new QGLMaterial(this);
//    periodentafel *periode = World::getInstance().getPeriode();
//    element *desiredelement = periode->FindElement(no);
//    ASSERT(desiredelement != NULL,
//        "GLMoleculeView::getMaterial() - desired element "+toString(no)+" not present in periodentafel.");
//    const unsigned char* color = desiredelement->getColor();
//    newmaterial->setAmbientColor( QColor(color[0], color[1], color[2]) );
//    newmaterial->setSpecularColor( QColor(60, 60, 60) );
//    newmaterial->setShininess( QColor(128) );
//    ElementNoMaterialMap.insert( no, newmaterial);
//  }
//}
//
//QGLSceneNode* GLMoleculeView::getAtom(size_t no)
//{
//  // first some sensibility checks
//  ASSERT(World::getInstance().getAtom(AtomById(no)) != NULL,
//      "GLMoleculeView::getAtom() - desired atom "
//      +toString(no)+" not present in the World.");
//  ASSERT(AtomsinSceneMap.find(no) != AtomsinSceneMap.end(),
//      "GLMoleculeView::getAtom() - desired atom "
//      +toString(no)+" not present in the AtomsinSceneMap.");
//
//  return AtomsinSceneMap[no];
//}
//
//QGLSceneNode* GLMoleculeView::getBond(size_t leftno, size_t rightno)
//{
//  // first some sensibility checks
//  ASSERT(World::getInstance().getAtom(AtomById(leftno)) != NULL,
//      "GLMoleculeView::getAtom() - desired atom "
//      +toString(leftno)+" of bond not present in the World.");
//  ASSERT(World::getInstance().getAtom(AtomById(rightno)) != NULL,
//      "GLMoleculeView::getAtom() - desired atom "
//      +toString(rightno)+" of bond not present in the World.");
//  ASSERT(AtomsinSceneMap.find(leftno) != AtomsinSceneMap.end(),
//      "GLMoleculeView::getAtom() - desired atom "
//      +toString(leftno)+" of bond not present in the AtomsinSceneMap.");
//  ASSERT(AtomsinSceneMap.find(rightno) != AtomsinSceneMap.end(),
//      "GLMoleculeView::getAtom() - desired atom "
//      +toString(rightno)+" of bond not present in the AtomsinSceneMap.");
//  ASSERT(leftno == rightno,
//      "GLMoleculeView::getAtom() - bond must not be between the same atom: "
//      +toString(leftno)+" == "+toString(rightno)+".");
//
//  // then return with smaller index first
//  if (leftno > rightno)
//    return AtomsinSceneMap[ make_pair(rightno, leftno) ];
//  else
//    return AtomsinSceneMap[ make_pair(leftno, rightno) ];
//}
//