| [2ad1ec] | 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 | * | 
|---|
| [52c5d4] | 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. For all of these cases we have to | 
|---|
|  | 62 | * accommodate. This is especially problematic with the instantiation and | 
|---|
|  | 63 | * destruction of objects. | 
|---|
|  | 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 deal with 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. | 
|---|
|  | 76 | * | 
|---|
|  | 77 | * \subsection qt-gui-general-observedvalue Observed Value | 
|---|
|  | 78 | * | 
|---|
|  | 79 | * These representants are called \a ObservedValue in CodePatterns and they | 
|---|
|  | 80 | * are used everywhere in the Qt Gui. | 
|---|
|  | 81 | * | 
|---|
|  | 82 | * They contain an internal information, e.g. a boolean, a Vector or even | 
|---|
|  | 83 | * a complex structure such as a Tesselation. They require an updater | 
|---|
|  | 84 | * function to obtain the derived information from the original source. And | 
|---|
|  | 85 | * they signOn to the source in order to be notified either generally on | 
|---|
|  | 86 | * updates or for specific channels only. | 
|---|
|  | 87 | * | 
|---|
|  | 88 | * The ObservedValue will automatically and immediately update its internal | 
|---|
|  | 89 | * representation of the derived information by calling the updater function | 
|---|
|  | 90 | * as soon as it has been informed about the update. Hence, the internal | 
|---|
|  | 91 | * information is always up-to-date and lives beyond the scope of the | 
|---|
|  | 92 | * source of the information until its own destruction. As updates are | 
|---|
|  | 93 | * processed immediately, this pattern only makes sense for "small" pieces | 
|---|
|  | 94 | * of information, i.e. when the updater function is very light-weight and | 
|---|
|  | 95 | * does not do much in terms of using computing resources. | 
|---|
|  | 96 | * | 
|---|
|  | 97 | * Note that there is another concept that is opposite to the observed value, | 
|---|
|  | 98 | * namely the Cacheable. This pattern will update itself only when requested, | 
|---|
|  | 99 | * referred to as "lazy evaluation". Hence, this pattern is used for "large" | 
|---|
|  | 100 | * pieces of information that require more computing resources within the | 
|---|
|  | 101 | * updater. Also, the Cacheable's information can only be obtained as long | 
|---|
|  | 102 | * as the source of information is still alive. | 
|---|
|  | 103 | * | 
|---|
|  | 104 | * Both concepts can be used in threaded environments as mutexed are used to | 
|---|
|  | 105 | * protect read and write accesses. | 
|---|
|  | 106 | * | 
|---|
|  | 107 | * \subsection qt-gui-general-signalslot Observer/Observable and Signal/Slot | 
|---|
|  | 108 | * | 
|---|
|  | 109 | * In the following we refer to Observer/Observable as "O/O" and to Signal/Slot | 
|---|
|  | 110 | * as "S/S". | 
|---|
|  | 111 | * | 
|---|
|  | 112 | * One thing we need to do is to translate between update() or | 
|---|
|  | 113 | * recieveNotification() calls from an Observable and subsequent signal/slot | 
|---|
|  | 114 | * calls. The general idea is to use these ObservedValues as translation | 
|---|
|  | 115 | * points for small pieces of information and Cacheables for larger pieces. | 
|---|
|  | 116 | * | 
|---|
|  | 117 | * However, we need more of these translation points: | 
|---|
|  | 118 | * -# GLWorldView checks for | 
|---|
|  | 119 | *   -# World's MoleculeInserted | 
|---|
|  | 120 | *   -# World's SelectionChanged | 
|---|
|  | 121 | *   -# WorldTime's TimeChanged | 
|---|
|  | 122 | *   -# each molecule's AtomInserted and AtomRemoved | 
|---|
|  | 123 | *   -# AtomObservable's AtomChanged. | 
|---|
|  | 124 | *   -# ShapeRegistry's ShapedAdded, ShapeRemoved, and SelectionChanged | 
|---|
|  | 125 | * -# GLMoleculeObject_molecule checks for | 
|---|
|  | 126 | *   -# molecule's AtomInserted, AtomRemoved, AtomMoved, IndexChanged | 
|---|
|  | 127 | *   -# World's SelectionChanged | 
|---|
|  | 128 | * | 
|---|
| [2ad1ec] | 129 | * \section qt-gui-qt3d Qt3D and the way to get atoms and bonds displayed | 
|---|
|  | 130 | * | 
|---|
| [52c5d4] | 131 | * By far the most difficult component of the Qt GUI is the 3D view. So, | 
|---|
|  | 132 | * let us explain it in detail. | 
|---|
|  | 133 | * | 
|---|
|  | 134 | * The general widget making up the view is called \a GLWorldView. It contains | 
|---|
|  | 135 | * the GLWorldScene (i.e. all atoms, bonds, molecules, and shapes). Also | 
|---|
|  | 136 | * the "dreibein" and the domain. It processes key presses and mouse events | 
|---|
|  | 137 | * to manipulate the view. And it also serves as the translator O/O to S/S | 
|---|
|  | 138 | * system. | 
|---|
|  | 139 | * | 
|---|
|  | 140 | * The GLWorldScene contains the actual nodes of the molecular system, i.e. | 
|---|
|  | 141 | * the atoms, bonds, molecules, and shapes. All of these are derived from | 
|---|
|  | 142 | * GLMoleculeObject and have their parent to the instance of the GLWorldScene | 
|---|
|  | 143 | * which goes through its list of children and to call draw() on them. | 
|---|
|  | 144 | * | 
|---|
|  | 145 | * The bottom-most structure is GLMoleculeObject_atom displaying a sphere | 
|---|
|  | 146 | * of an element-specific color at the atom's position. The atom relies | 
|---|
|  | 147 | * on its representants to be contain all required information but it | 
|---|
|  | 148 | * is also signOn() to the atom itself whose O/O are translated to S/S | 
|---|
|  | 149 | * for processing whenever desired. | 
|---|
|  | 150 | * | 
|---|
|  | 151 | * Next comes the GLMoleculeObject_bond which displays a cylinder between | 
|---|
|  | 152 | * two atoms. Actual, a true bond consists of two of these objects. If the | 
|---|
|  | 153 | * bond is between heterogeneous atoms each half will be displayed in the | 
|---|
|  | 154 | * color of the closer atom. These bond objects are not associated with | 
|---|
|  | 155 | * the atoms directly as the are linked to two atoms at the same time. They | 
|---|
|  | 156 | * rely on ObservedValues for position and element of either atom and for | 
|---|
|  | 157 | * the degree of the bond itself. | 
|---|
|  | 158 | * | 
|---|
|  | 159 | * Parallel to these are GLMoleculeObject_shape which display the surface | 
|---|
|  | 160 | * of a selected shape. A shape in general does not change after instantation, | 
|---|
|  | 161 | * hence the shape lives with the information it gets on instantiation till | 
|---|
|  | 162 | * it dies. | 
|---|
|  | 163 | * | 
|---|
|  | 164 | * Finally, the GLMoleculeObject_molecule owns both atoms and bonds. This | 
|---|
|  | 165 | * allows for switching the view between the classical ball-and-stick model | 
|---|
|  | 166 | * and the tesselated surface of the molecule. The latter uses a lot less | 
|---|
|  | 167 | * triangles and thus is faster. Also, it is especially suited for large | 
|---|
|  | 168 | * molecules. The molecule also needs ObservedValues for its bounding box | 
|---|
|  | 169 | * (used to show when it's selected), the index, the selection status, | 
|---|
|  | 170 | * and the list of atom ids. As Cacheable we use the tesselation structure. | 
|---|
|  | 171 | * | 
|---|
|  | 172 | * \section qt-gui-cases Sample cases | 
|---|
|  | 173 | * | 
|---|
|  | 174 | * Let us discuss some cases and how the different instances interact. | 
|---|
|  | 175 | * | 
|---|
|  | 176 | * \section qt-gui-cases-start Start | 
|---|
|  | 177 | * | 
|---|
|  | 178 | * When molecuilder is started, several singletons such as the World and | 
|---|
|  | 179 | * others are instantiated. No atoms are yet present, no bonds, no molecules. | 
|---|
|  | 180 | * Hence, nothing to display yet. | 
|---|
|  | 181 | * | 
|---|
|  | 182 | * Before launching any Action the ActionQueue is forced to wait till the | 
|---|
|  | 183 | * GUI is finished instantiating. This is to ensure that GLWorldView and | 
|---|
|  | 184 | * others are in place to receive signals from the O/O system. | 
|---|
|  | 185 | * | 
|---|
|  | 186 | * When a molecule is loaded, the instantiation of a GLMoleculeObject_molecule | 
|---|
|  | 187 | * does not happen immediately. Hence, GLWorldView listens to the World's | 
|---|
|  | 188 | * MoleculeInserted. On receiving it, it also signOn()s to the molecule | 
|---|
|  | 189 | * to get its subjectKilled(). It translates then these and also all | 
|---|
|  | 190 | * AtomInserted and AtomRemoved to the S/S system as moleculeInserted, | 
|---|
|  | 191 | * moleculeRemoved and atomInserted/atomRemoved respectively, which are | 
|---|
|  | 192 | * processed by the GLWorldScene. | 
|---|
|  | 193 | * | 
|---|
|  | 194 | * The GLWorldScene records any atomInserted/atomRemoved until the molecule | 
|---|
|  | 195 | * has been instantiated. On instantiation all recorded events are played. | 
|---|
|  | 196 | * This is to ensure that there is no overlap in instantiation and signOn() | 
|---|
|  | 197 | * to the molecule. If we would simply get all atoms which are present | 
|---|
|  | 198 | * on processing the molecule's instantiation we might stumble over a signal | 
|---|
|  | 199 | * of a molecule of a just added atom. This occurs frequently as both | 
|---|
|  | 200 | * are very much correlated. | 
|---|
|  | 201 | * | 
|---|
|  | 202 | * GLWorldView keep track of all ObservedMolecules. And GLWorldScene keeps | 
|---|
|  | 203 | * track of all shapes and molecules in the scene. Each | 
|---|
|  | 204 | * GLMoleculeObject_molecule in turn keeps track of all atoms and bonds in | 
|---|
|  | 205 | * its part of the scene. | 
|---|
| [2ad1ec] | 206 | * | 
|---|
| [eee1b7] | 207 | * \section QtElementList | 
|---|
|  | 208 | * | 
|---|
| [52c5d4] | 209 | * Lists for each element how often it occurs in the world. Selecting an entry | 
|---|
| [eee1b7] | 210 | * calls SelectionAtomByElementAction to select all atoms of that particular | 
|---|
|  | 211 | * element. | 
|---|
|  | 212 | * | 
|---|
| [52c5d4] | 213 | * Initially, it fills itself by looking at all elements in the World's | 
|---|
|  | 214 | * periodentafel. It also listens to AtomObserver's ElementChanged to know | 
|---|
|  | 215 | * when to update a certain element in its list. By using an internal list | 
|---|
|  | 216 | * for each atom's element, it can update each element's occurrence. | 
|---|
| [eee1b7] | 217 | * | 
|---|
|  | 218 | * \section QtMoleculeList | 
|---|
|  | 219 | * | 
|---|
|  | 220 | * Lists all the molecules currently in the world grouped by their formula. | 
|---|
|  | 221 | * Selecting an entry calls the SelectionMoleculeByIdAction. | 
|---|
|  | 222 | * | 
|---|
| [52c5d4] | 223 | * The QtMoleculeList is also a rather complex beast. It is a tree of | 
|---|
|  | 224 | * rows and each row consists of a number of elements. There are two | 
|---|
|  | 225 | * levels, the group level where the common formula for all molecules | 
|---|
|  | 226 | * is given, and the molecule level where are molecules of this specific | 
|---|
|  | 227 | * formula are summarized. | 
|---|
|  | 228 | * | 
|---|
|  | 229 | * The group items are QStandardItems. Sadly, they are not derived from | 
|---|
|  | 230 | * QObject and hence do not use the S/S system. The group items are | 
|---|
|  | 231 | * directly controlled by the QtMoleculeList. | 
|---|
|  | 232 | * | 
|---|
|  | 233 | * However, the molecule items are different. They are derived from | 
|---|
|  | 234 | * QtMoleculeList and use an ObservedValue internally to contain an always | 
|---|
|  | 235 | * valid copy of the required information. They inform the QtMoleculeList on | 
|---|
|  | 236 | * updates via a callback (as QStandardItem, from which they are also derived, | 
|---|
|  | 237 | * does not use the S/S system). The callback takes care of then also updating | 
|---|
|  | 238 | * the group items and possibly moving the molecule items around, e.g. if | 
|---|
|  | 239 | * their formula has changed they suddenly belong to another group. | 
|---|
|  | 240 | * | 
|---|
|  | 241 | * All items are instantiated by the QtMoleculeItemFactory. | 
|---|
|  | 242 | * | 
|---|
|  | 243 | * QtMoleculeList uses an internal QTimer to only update itself at regular | 
|---|
|  | 244 | * intervals. Hence, updates are processed rather lazily. We keep lists | 
|---|
|  | 245 | * of changes, separated for group and molecule items. And these are processed | 
|---|
|  | 246 | * one after the other at the intervals dictated by the QTimer in | 
|---|
|  | 247 | * updateItemStates(). | 
|---|
| [eee1b7] | 248 | * | 
|---|
|  | 249 | * \section QtShapeController | 
|---|
|  | 250 | * | 
|---|
|  | 251 | * This is the interface for the ShapeRegistry. It lists all the shapes in the | 
|---|
|  | 252 | * registry and lets the user select them. It also features buttons to call | 
|---|
|  | 253 | * actions creating and manipulating the selected shapes. | 
|---|
|  | 254 | * | 
|---|
|  | 255 | * As an Observer it handles the following messages from ShapeRegistry: | 
|---|
|  | 256 | *  - ShapeRegistry::ShapeInserted | 
|---|
|  | 257 | *  - ShapeRegistry::ShapeRemoved | 
|---|
|  | 258 | *  - ShapeRegistry::SelectionChanged | 
|---|
|  | 259 | * | 
|---|
|  | 260 | * \section QtInfoBox | 
|---|
|  | 261 | * | 
|---|
| [8c9049] | 262 | * Shows information about the atom and molecule the cursor is currently hovering | 
|---|
|  | 263 | * over inside the GLWorldView. | 
|---|
| [eee1b7] | 264 | * | 
|---|
| [8c9049] | 265 | * GLWorldView emits hoverChanged signals (via QT's signal slot mechanism) which | 
|---|
|  | 266 | * the QtInfoBox receives. QtInfoBox then creates its info pages for the atom | 
|---|
|  | 267 | * being transmitted as the signal's parameter. | 
|---|
| [eee1b7] | 268 | * | 
|---|
| [8c9049] | 269 | * The info pages are Observers for the atom/molecule. When recieving subjectKilled | 
|---|
|  | 270 | * they automatically clear the info box. | 
|---|
|  | 271 | * | 
|---|
| [52c5d4] | 272 | * \date 2015-07-15 | 
|---|
| [2ad1ec] | 273 | */ | 
|---|