| 1 | /*
 | 
|---|
| 2 |  * Project: MoleCuilder
 | 
|---|
| 3 |  * Description: creates and alters molecular systems
 | 
|---|
| 4 |  * Copyright (C)  2010 University of Bonn. All rights reserved.
 | 
|---|
| 5 |  * Please see the LICENSE file or "Copyright notice" in builder.cpp for details.
 | 
|---|
| 6 |  */
 | 
|---|
| 7 | 
 | 
|---|
| 8 | /**
 | 
|---|
| 9 |  * \file qt-gui.dox
 | 
|---|
| 10 |  *
 | 
|---|
| 11 |  * Created on: Jan 5, 2012
 | 
|---|
| 12 |  *    Author: heber
 | 
|---|
| 13 |  */
 | 
|---|
| 14 | 
 | 
|---|
| 15 | /**
 | 
|---|
| 16 |  * \page qt-gui Qt GUI
 | 
|---|
| 17 |  *
 | 
|---|
| 18 |  * The Qt GUI is the most advanced interface and thus the most complex.
 | 
|---|
| 19 |  *
 | 
|---|
| 20 |  * In the following we want to explain some of the details that are involved.
 | 
|---|
| 21 |  *
 | 
|---|
| 22 |  * \section qt-gui-general General Concepts
 | 
|---|
| 23 |  *
 | 
|---|
| 24 |  * Let us first discuss about the general concepts.
 | 
|---|
| 25 |  *
 | 
|---|
| 26 |  * MoleCuilder is about atoms, bonds and the molecules made up by them. But
 | 
|---|
| 27 |  * there is more: There are fragments, potentials, shapes, and so on.
 | 
|---|
| 28 |  *
 | 
|---|
| 29 |  * In the Qt GUI all of these are displayed in certain areas of the screen
 | 
|---|
| 30 |  * and also in a certain manner:
 | 
|---|
| 31 |  * -# the 3D view represents a three-dimensional representation of all atoms,
 | 
|---|
| 32 |  *    and their bonds or possibly the molecules they form alone. Also the
 | 
|---|
| 33 |  *    bounding box is shown and all selected shapes. Atoms or molecules can
 | 
|---|
| 34 |  *    be selected by clicking. The view can be manipulated through rotation
 | 
|---|
| 35 |  *    and translation.
 | 
|---|
| 36 |  * -# an element list shows all available elements of the period table.
 | 
|---|
| 37 |  * -# a molecule list shows all present molecules sorted by their formula.
 | 
|---|
| 38 |  * -# a fragment list shows all fragments with their energies and contributions
 | 
|---|
| 39 |  * -# a potential list shows all currently instantiated potentials and
 | 
|---|
| 40 |  *    gives a 2D plot.
 | 
|---|
| 41 |  * -# a shape list displays all currently available shapes, allows to select
 | 
|---|
| 42 |  *    them and buttons allow to combine them via boolean operation.
 | 
|---|
| 43 |  * -# an info box informs about the current atom/molecule the mouse pointer
 | 
|---|
| 44 |  *    is hovering over.
 | 
|---|
| 45 |  *
 | 
|---|
| 46 |  * So, there are many objects that need to be filled with information and
 | 
|---|
| 47 |  * they need to access the World and other singletons in order to obtain
 | 
|---|
| 48 |  * this information.
 | 
|---|
| 49 |  *
 | 
|---|
| 50 |  * One major obstacle, or rather THE major obstacle, is that Qt is threaded,
 | 
|---|
| 51 |  * i.e. the Actions are processed in one thread and the Gui does its event
 | 
|---|
| 52 |  * processing in another one. Qt's Signal/Slot system is handled via this
 | 
|---|
| 53 |  * event system, i.e. a signal launched by one thread may be handled by
 | 
|---|
| 54 |  * the slot function in another thread. The Observer/Observable system
 | 
|---|
| 55 |  * of the CodePatterns which we used internally/outside Qt's scope does
 | 
|---|
| 56 |  * not do this.
 | 
|---|
| 57 |  *
 | 
|---|
| 58 |  * Also, signals may get delayed. This can happen either deliberately, e.g.
 | 
|---|
| 59 |  * there is a QTimer that only updates an object in regular intervals, or
 | 
|---|
| 60 |  * because of asynchronous threads. Elsewhen, the slot callback for a
 | 
|---|
| 61 |  * certain signal is called directly. All of these cases we have to
 | 
|---|
| 62 |  * accommodate. This is especially problematic with the instantiation and
 | 
|---|
| 63 |  * destruction of objects that represent atoms and molecules in the World.
 | 
|---|
| 64 |  *
 | 
|---|
| 65 |  * A clarifying example: Imagine an atom is constructed, the AtomObserver
 | 
|---|
| 66 |  * notifies about it, but the information is not processed immediately.
 | 
|---|
| 67 |  * Shortly after, the atom is destroyed again before its representation is
 | 
|---|
| 68 |  * instantiated in the GUI. Afterwards the GUI attempts to instantiate it
 | 
|---|
| 69 |  * but can not longer access the atom for its position and element.
 | 
|---|
| 70 |  *
 | 
|---|
| 71 |  * The only possible way out is to duplicate information. This is the usual
 | 
|---|
| 72 |  * way how to proceed in environments with multiple threads. I.e. all the
 | 
|---|
| 73 |  * information that the GUI representants of information inside the World
 | 
|---|
| 74 |  * needs to be doubled such that when the original information is destroyed
 | 
|---|
| 75 |  * the representant can still be accessed as long as needed. Here, we use
 | 
|---|
| 76 |  * the ObservedValue construct of CodePatterns.
 | 
|---|
| 77 |  *
 | 
|---|
| 78 |  * \subsection qt-gui-general-observedvalue Observed Value
 | 
|---|
| 79 |  *
 | 
|---|
| 80 |  * These representants are called \a ObservedValue in CodePatterns and they
 | 
|---|
| 81 |  * are used everywhere in the Qt Gui.
 | 
|---|
| 82 |  *
 | 
|---|
| 83 |  * They contain an internal information, e.g. a boolean, a Vector or even
 | 
|---|
| 84 |  * a complex structure such as a Tesselation. They require an updater
 | 
|---|
| 85 |  * function to obtain the derived information from the original source. And
 | 
|---|
| 86 |  * they signOn to the source in order to be notified either generally on
 | 
|---|
| 87 |  * updates or for specific channels only.
 | 
|---|
| 88 |  *
 | 
|---|
| 89 |  * The ObservedValue will automatically and immediately update its internal
 | 
|---|
| 90 |  * representation of the derived information by calling the updater function
 | 
|---|
| 91 |  * as soon as it has been informed about the update. Hence, the internal
 | 
|---|
| 92 |  * information is always up-to-date and lives beyond the scope of the
 | 
|---|
| 93 |  * source of the information until its own destruction. As updates are
 | 
|---|
| 94 |  * processed immediately, this pattern only makes sense for "small" pieces
 | 
|---|
| 95 |  * of information, i.e. when the updater function is very light-weight and
 | 
|---|
| 96 |  * does not do much in terms of using computing resources.
 | 
|---|
| 97 |  *
 | 
|---|
| 98 |  * Note that there is another concept that is opposite to the observed value,
 | 
|---|
| 99 |  * namely the Cacheable. This pattern will update itself only when requested,
 | 
|---|
| 100 |  * referred to as "lazy evaluation". Hence, this pattern is used for "large"
 | 
|---|
| 101 |  * pieces of information that require more computing resources within the
 | 
|---|
| 102 |  * updater. Also, the Cacheable's information can only be obtained as long
 | 
|---|
| 103 |  * as the source of information is still alive. However, so far Cacheable's
 | 
|---|
| 104 |  * content is marked invalid when an update signal has been received and
 | 
|---|
| 105 |  * update itself only on request, which is no longer possible when the object
 | 
|---|
| 106 |  * to represent is gone.
 | 
|---|
| 107 |  *
 | 
|---|
| 108 |  * Both concepts can be used in threaded environments as mutexes are used to
 | 
|---|
| 109 |  * protect read and write accesses.
 | 
|---|
| 110 |  *
 | 
|---|
| 111 |  * \subsection qt-gui-general-observedinstance The observed instance board
 | 
|---|
| 112 |  *
 | 
|---|
| 113 |  * The setup is then as follows: We have two distinct realms, the World (with
 | 
|---|
| 114 |  * atoms and molecules) on the one side and the QtGUI (with visual
 | 
|---|
| 115 |  * representations of atoms and molecules) on the other side.
 | 
|---|
| 116 |  *
 | 
|---|
| 117 |  * There is an interface between this world such that the destruction of an
 | 
|---|
| 118 |  * atom does not directly invalidate its visual representation. This interface
 | 
|---|
| 119 |  * between the two realms is contained in the class QtObservedInstanceBoard,
 | 
|---|
| 120 |  * which is a singleton and is similar to the World instance in the World realm
 | 
|---|
| 121 |  * for the QtGui realm.
 | 
|---|
| 122 |  *
 | 
|---|
| 123 |  * All properties, e.g. the position of an element, relevant to the QtGUI are
 | 
|---|
| 124 |  * duplicated as ObservedValues. Properties associated to the same instance in
 | 
|---|
| 125 |  * the World, e.g. the same atom, are combined into a QtObservedAtom instance,
 | 
|---|
| 126 |  * and similarly QtObservedMolecule for molecule. All of these observed
 | 
|---|
| 127 |  * instances are placed into ObservedValuesContainer which are contained in
 | 
|---|
| 128 |  * the interface QtObservedInstanceBoard.
 | 
|---|
| 129 |  *
 | 
|---|
| 130 |  * The sequence of events is then as follows (here exemplified with an atom):
 | 
|---|
| 131 |  * -# an atom is created (World::createAtom()), the World notifies about it
 | 
|---|
| 132 |  *    via its World::AtomInserted channel.
 | 
|---|
| 133 |  * -# QtObservedInstanceBoard is signOn()ed to this channel and instantiates
 | 
|---|
| 134 |  *    a new QtObservedAtom which is placed into its respective
 | 
|---|
| 135 |  *    ObservedValuesContainer.
 | 
|---|
| 136 |  * -# on instantiation of QtObservedAtom a vector of specific ObservedValues is
 | 
|---|
| 137 |  *    created, one for each property (position, element, bond count, ...).
 | 
|---|
| 138 |  *    Each signOn()s to the respective atom's channel. Also the QtObservedAtom
 | 
|---|
| 139 |  *    signOn()s to each of these channels as it converts these notifications
 | 
|---|
| 140 |  *    into Qt signals (and the updated value can be accessed via getters from
 | 
|---|
| 141 |  *    the QtObservedAtom instance). The QtObservedInstanceBoard is notified
 | 
|---|
| 142 |  *    of this with the instance being marked as connected.
 | 
|---|
| 143 |  * -# when the atom is destroyed (World::destroyAtom()), being an Observable
 | 
|---|
| 144 |  *    it will call subjectKilled() on all its channels. The
 | 
|---|
| 145 |  *    ObservedValue_wCallback announces this subjectKilled() via the callback
 | 
|---|
| 146 |  *    function which notifies QtObservedAtom. Once all subjectKilled(), for
 | 
|---|
| 147 |  *    each observed value and for QtObservedAtom itself, have been received,
 | 
|---|
| 148 |  *    the QtObservedInstanceBoard is notified by the instance now being
 | 
|---|
| 149 |  *    marked as disconnected and ready for erase.
 | 
|---|
| 150 |  * -# then the QtObservedInstanceBoard removes the instance from its
 | 
|---|
| 151 |  *    ObservedValuesContainer.
 | 
|---|
| 152 |  *
 | 
|---|
| 153 |  * Note however that the instance is a shared_ptr and will continue to exist
 | 
|---|
| 154 |  * and therefore its getters will still deliver the last piece of information
 | 
|---|
| 155 |  * before the atom was destroyed until all shared_ptrs are released. Hence,
 | 
|---|
| 156 |  * the QtGui may safely continue using the pointer.
 | 
|---|
| 157 |  *
 | 
|---|
| 158 |  * As new observed instances may come in immediately having the same id and
 | 
|---|
| 159 |  * as it is difficult to keep track who got its observed instance already
 | 
|---|
| 160 |  * and who not, a soft fail is required. I.e. of the QtObservedInstanceBoard
 | 
|---|
| 161 |  * returns an empty shared_ptr this means that the object -- despite any
 | 
|---|
| 162 |  * received (and probably delayed) signal -- has been destroyed and should
 | 
|---|
| 163 |  * not be displayed, updated by, ... whatsoever.
 | 
|---|
| 164 |  *
 | 
|---|
| 165 |  * \subsection qt-gui-general-signalslot Details on the slot connections
 | 
|---|
| 166 |  *
 | 
|---|
| 167 |  * Qt's event system does not guarantee that events are always processed in
 | 
|---|
| 168 |  * the order they are emitted. This is because connections can be defined
 | 
|---|
| 169 |  * as direct or queued (or both with auto). Direct connections will always
 | 
|---|
| 170 |  * be executed as direct function calls, i.e. immediately. Queued connections
 | 
|---|
| 171 |  * however are inserted into Qt's event queue and may even get processed by
 | 
|---|
| 172 |  * a different thread.
 | 
|---|
| 173 |  *
 | 
|---|
| 174 |  * We have to take care of this.
 | 
|---|
| 175 |  *
 | 
|---|
| 176 |  * Basically what we do in QtObservedInstanceBoard and the observed instances
 | 
|---|
| 177 |  * of type QtObservedAtom and QtObservedMolecule is that we translate between
 | 
|---|
| 178 |  * the Observer/Observable (O/O) system of CodePatterns with its callback
 | 
|---|
| 179 |  * functions and the event system of Qt with its Signal/Slot (S/S).
 | 
|---|
| 180 |  *
 | 
|---|
| 181 |  * That is in the recieveNotification() functions many "emit()"s can be found.
 | 
|---|
| 182 |  *
 | 
|---|
| 183 |  * Furthermore, signals are used in a specific way to ensure synchronicity.
 | 
|---|
| 184 |  * This is only a problem with the visual representation as we there find a
 | 
|---|
| 185 |  * a nested problem: First molecules, then atoms belonging to a certain
 | 
|---|
| 186 |  * molecule. This enforces a certain sequence of events and thus of signals.
 | 
|---|
| 187 |  *
 | 
|---|
| 188 |  * \subsubsection qt-gui-general-signalslot-glworldscene Details on GLWorldScene
 | 
|---|
| 189 |  *
 | 
|---|
| 190 |  * The central place for all events is the GLWorldScene instance. There
 | 
|---|
| 191 |  * signals from QtObservedInstanceBoard for insertion and removal of both atoms
 | 
|---|
| 192 |  * and molecules are caught. Insertion of molecules is dealt with directly,
 | 
|---|
| 193 |  * we sign on to the inserted&removed channels for its atoms, then we emit
 | 
|---|
| 194 |  * a queued signal to actually instantiate the GLMoleculeObject_molecule.
 | 
|---|
| 195 |  *
 | 
|---|
| 196 |  * Until its instantiation we store incoming signals in the
 | 
|---|
| 197 |  * GLWorldScene::MoleculeMissedStateMap, protected by a mutex to enforce atomic
 | 
|---|
| 198 |  * access. After it has been instantiated (and all stored signals have been
 | 
|---|
| 199 |  * processed), they are relayed onto the specific instance. However, we do not
 | 
|---|
| 200 |  * do this via emits but by directly using Qt's invokeMethod() which allows
 | 
|---|
| 201 |  * to trigger queued events. This way it is done in a likewise manner whether
 | 
|---|
| 202 |  * it has been a stored or live signal that was received.
 | 
|---|
| 203 |  *
 | 
|---|
| 204 |  * \subsubsection qt-gui-general-signalslot-other Details on other signals
 | 
|---|
| 205 |  *
 | 
|---|
| 206 |  * All other signals that only change the property of a visual representation,
 | 
|---|
| 207 |  * e.g. the element of an atom, is directly processed by, in this case, the
 | 
|---|
| 208 |  * GLMoleculeObject_atom connected to QtObservedAtom.
 | 
|---|
| 209 | . *
 | 
|---|
| 210 |  * \section qt-gui-qt3d Qt3D and the way to get atoms and bonds displayed
 | 
|---|
| 211 |  *
 | 
|---|
| 212 |  * By far the most difficult component of the Qt GUI is the 3D view. So,
 | 
|---|
| 213 |  * let us explain it in detail.
 | 
|---|
| 214 |  *
 | 
|---|
| 215 |  * The general widget making up the view is called \a GLWorldView. It contains
 | 
|---|
| 216 |  * the GLWorldScene (i.e. all atoms, bonds, molecules, and shapes). Also
 | 
|---|
| 217 |  * the "dreibein" and the domain. It processes key presses and mouse events
 | 
|---|
| 218 |  * to manipulate the view. And it also serves as the translator O/O to S/S
 | 
|---|
| 219 |  * system.
 | 
|---|
| 220 |  *
 | 
|---|
| 221 |  * The GLWorldScene contains the actual nodes of the molecular system, i.e.
 | 
|---|
| 222 |  * the atoms, bonds, molecules, and shapes. All of these are derived from
 | 
|---|
| 223 |  * GLMoleculeObject and have their parent to the instance of the GLWorldScene
 | 
|---|
| 224 |  * which goes through its list of children and to call draw() on them.
 | 
|---|
| 225 |  *
 | 
|---|
| 226 |  * The bottom-most structure is GLMoleculeObject_atom displaying a sphere
 | 
|---|
| 227 |  * of an element-specific color at the atom's position. The atom relies
 | 
|---|
| 228 |  * on its representants to be contain all required information but it
 | 
|---|
| 229 |  * is also signOn() to the QtObservedAtom itself whose O/O are translated to
 | 
|---|
| 230 |  * S/S for processing whenever desired.
 | 
|---|
| 231 |  *
 | 
|---|
| 232 |  * Next comes the GLMoleculeObject_bond which displays a cylinder between
 | 
|---|
| 233 |  * two atoms. Actual, a true bond consists of two of these objects. If the
 | 
|---|
| 234 |  * bond is between heterogeneous atoms each half will be displayed in the
 | 
|---|
| 235 |  * color of the closer atom. These bond objects are not associated with
 | 
|---|
| 236 |  * the atoms directly as the are linked to two atoms at the same time. They
 | 
|---|
| 237 |  * rely on ObservedValues for position and element of either atom and for
 | 
|---|
| 238 |  * the degree of the bond itself.
 | 
|---|
| 239 |  *
 | 
|---|
| 240 |  * Parallel to these are GLMoleculeObject_shape which display the surface
 | 
|---|
| 241 |  * of a selected shape. A shape in general does not change after instantiation,
 | 
|---|
| 242 |  * hence the shape lives with the information it gets on instantiation till
 | 
|---|
| 243 |  * it dies.
 | 
|---|
| 244 |  *
 | 
|---|
| 245 |  * Finally, the GLMoleculeObject_molecule owns both atoms and bonds. This
 | 
|---|
| 246 |  * allows for switching the view between the classical ball-and-stick model
 | 
|---|
| 247 |  * and the tesselated surface of the molecule. The latter uses a lot less
 | 
|---|
| 248 |  * triangles and thus is faster. Also, it is especially suited for large
 | 
|---|
| 249 |  * molecules. The molecule also needs ObservedValues for its bounding box
 | 
|---|
| 250 |  * (used to show when it's selected), the index, the selection status,
 | 
|---|
| 251 |  * and the list of atom ids.
 | 
|---|
| 252 |  *
 | 
|---|
| 253 |  * \section qt-gui-cases Sample cases
 | 
|---|
| 254 |  *
 | 
|---|
| 255 |  * Let us discuss some cases and how the different instances interact.
 | 
|---|
| 256 |  *
 | 
|---|
| 257 |  * \section qt-gui-cases-start Start
 | 
|---|
| 258 |  *
 | 
|---|
| 259 |  * When molecuilder is started, several singletons such as the World and
 | 
|---|
| 260 |  * others are instantiated. No atoms are yet present, no bonds, no molecules.
 | 
|---|
| 261 |  * Hence, nothing to display yet.
 | 
|---|
| 262 |  *
 | 
|---|
| 263 |  * Before launching any Action the ActionQueue is forced to wait till the
 | 
|---|
| 264 |  * GUI is finished instantiating. This is to ensure that GLWorldView and
 | 
|---|
| 265 |  * others are in place to receive signals from the O/O system.
 | 
|---|
| 266 |  *
 | 
|---|
| 267 |  * When a molecule is loaded, the instantiation of a GLMoleculeObject_molecule
 | 
|---|
| 268 |  * does not happen immediately. Hence, GLWorldView listens to the World's
 | 
|---|
| 269 |  * MoleculeInserted. On receiving it, it also signOn()s to the molecule
 | 
|---|
| 270 |  * to get its subjectKilled(). It translates then these and also all
 | 
|---|
| 271 |  * AtomInserted and AtomRemoved to the S/S system as moleculeInserted,
 | 
|---|
| 272 |  * moleculeRemoved and atomInserted/atomRemoved respectively, which are
 | 
|---|
| 273 |  * processed by the GLWorldScene.
 | 
|---|
| 274 |  *
 | 
|---|
| 275 |  * The GLWorldScene records any atomInserted/atomRemoved until the molecule
 | 
|---|
| 276 |  * has been instantiated. On instantiation all recorded events are played.
 | 
|---|
| 277 |  * This is to ensure that there is no overlap in instantiation and signOn()
 | 
|---|
| 278 |  * to the molecule. If we would simply get all atoms which are present
 | 
|---|
| 279 |  * on processing the molecule's instantiation we might stumble over a signal
 | 
|---|
| 280 |  * of a molecule of a just added atom. This occurs frequently as both
 | 
|---|
| 281 |  * are very much correlated.
 | 
|---|
| 282 |  *
 | 
|---|
| 283 |  * GLWorldView keep track of all ObservedMolecules. And GLWorldScene keeps
 | 
|---|
| 284 |  * track of all shapes and molecules in the scene. Each
 | 
|---|
| 285 |  * GLMoleculeObject_molecule in turn keeps track of all atoms and bonds in
 | 
|---|
| 286 |  * its part of the scene.
 | 
|---|
| 287 |  *
 | 
|---|
| 288 |  * \section QtElementList
 | 
|---|
| 289 |  *
 | 
|---|
| 290 |  * Lists for each element how often it occurs in the world. Selecting an entry
 | 
|---|
| 291 |  * calls SelectionAtomByElementAction to select all atoms of that particular
 | 
|---|
| 292 |  * element.
 | 
|---|
| 293 |  *
 | 
|---|
| 294 |  * Initially, it fills itself by looking at all elements in the World's
 | 
|---|
| 295 |  * periodentafel. It also listens to AtomObserver's ElementChanged to know
 | 
|---|
| 296 |  * when to update a certain element in its list. By using an internal list
 | 
|---|
| 297 |  * for each atom's element, it can update each element's occurrence.
 | 
|---|
| 298 |  *
 | 
|---|
| 299 |  * \section QtMoleculeList
 | 
|---|
| 300 |  *
 | 
|---|
| 301 |  * Lists all the molecules currently in the world grouped by their formula.
 | 
|---|
| 302 |  * Selecting an entry calls the SelectionMoleculeByIdAction.
 | 
|---|
| 303 |  *
 | 
|---|
| 304 |  * The QtMoleculeList is also a rather complex beast. It is a tree of
 | 
|---|
| 305 |  * rows and each row consists of a number of elements. There are two
 | 
|---|
| 306 |  * levels, the group level where the common formula for all molecules
 | 
|---|
| 307 |  * is given, and the molecule level where are molecules of this specific
 | 
|---|
| 308 |  * formula are summarized.
 | 
|---|
| 309 |  *
 | 
|---|
| 310 |  * The group items are QStandardItems. Sadly, they are not derived from
 | 
|---|
| 311 |  * QObject and hence do not use the S/S system. The group items are
 | 
|---|
| 312 |  * directly controlled by the QtMoleculeList.
 | 
|---|
| 313 |  *
 | 
|---|
| 314 |  * However, the molecule items are different. They are derived from
 | 
|---|
| 315 |  * QtMoleculeList and use an ObservedValue internally to contain an always
 | 
|---|
| 316 |  * valid copy of the required information. They inform the QtMoleculeList on
 | 
|---|
| 317 |  * updates via a callback (as QStandardItem, from which they are also derived,
 | 
|---|
| 318 |  * does not use the S/S system). The callback takes care of then also updating
 | 
|---|
| 319 |  * the group items and possibly moving the molecule items around, e.g. if
 | 
|---|
| 320 |  * their formula has changed they suddenly belong to another group.
 | 
|---|
| 321 |  *
 | 
|---|
| 322 |  * All items are instantiated by the QtMoleculeItemFactory.
 | 
|---|
| 323 |  *
 | 
|---|
| 324 |  * QtMoleculeList uses an internal QTimer to only update itself at regular
 | 
|---|
| 325 |  * intervals. Hence, updates are processed rather lazily. We keep lists
 | 
|---|
| 326 |  * of changes, separated for group and molecule items. And these are processed
 | 
|---|
| 327 |  * one after the other at the intervals dictated by the QTimer in
 | 
|---|
| 328 |  * updateItemStates().
 | 
|---|
| 329 |  *
 | 
|---|
| 330 |  * \section QtShapeController
 | 
|---|
| 331 |  *
 | 
|---|
| 332 |  * This is the interface for the ShapeRegistry. It lists all the shapes in the
 | 
|---|
| 333 |  * registry and lets the user select them. It also features buttons to call
 | 
|---|
| 334 |  * actions creating and manipulating the selected shapes.
 | 
|---|
| 335 |  *
 | 
|---|
| 336 |  * As an Observer it handles the following messages from ShapeRegistry:
 | 
|---|
| 337 |  *  - ShapeRegistry::ShapeInserted
 | 
|---|
| 338 |  *  - ShapeRegistry::ShapeRemoved
 | 
|---|
| 339 |  *  - ShapeRegistry::SelectionChanged
 | 
|---|
| 340 |  *
 | 
|---|
| 341 |  * \section QtInfoBox
 | 
|---|
| 342 |  *
 | 
|---|
| 343 |  * Shows information about the atom and molecule the cursor is currently hovering
 | 
|---|
| 344 |  * over inside the GLWorldView.
 | 
|---|
| 345 |  *
 | 
|---|
| 346 |  * GLWorldView emits hoverChanged signals (via QT's signal slot mechanism) which
 | 
|---|
| 347 |  * the QtInfoBox receives. QtInfoBox then creates its info pages for the atom
 | 
|---|
| 348 |  * being transmitted as the signal's parameter.
 | 
|---|
| 349 |  *
 | 
|---|
| 350 |  * The info pages are Observers for the atom/molecule. When recieving subjectKilled
 | 
|---|
| 351 |  * they automatically clear the info box.
 | 
|---|
| 352 |  *
 | 
|---|
| 353 |  * \date 2016-01-08
 | 
|---|
| 354 |  */
 | 
|---|