Changeset 52c5d4 for src


Ignore:
Timestamp:
Aug 5, 2015, 5:32:09 PM (9 years ago)
Author:
Frederik Heber <heber@…>
Branches:
Action_Thermostats, Add_AtomRandomPerturbation, Add_FitFragmentPartialChargesAction, Add_RotateAroundBondAction, Add_SelectAtomByNameAction, Added_ParseSaveFragmentResults, AddingActions_SaveParseParticleParameters, Adding_Graph_to_ChangeBondActions, Adding_MD_integration_tests, Adding_ParticleName_to_Atom, Adding_StructOpt_integration_tests, AtomFragments, Automaking_mpqc_open, AutomationFragmentation_failures, Candidate_v1.5.4, Candidate_v1.6.0, Candidate_v1.6.1, ChangeBugEmailaddress, ChangingTestPorts, ChemicalSpaceEvaluator, CombiningParticlePotentialParsing, Combining_Subpackages, Debian_Package_split, Debian_package_split_molecuildergui_only, Disabling_MemDebug, Docu_Python_wait, EmpiricalPotential_contain_HomologyGraph, EmpiricalPotential_contain_HomologyGraph_documentation, Enable_parallel_make_install, Enhance_userguide, Enhanced_StructuralOptimization, Enhanced_StructuralOptimization_continued, Example_ManyWaysToTranslateAtom, Exclude_Hydrogens_annealWithBondGraph, FitPartialCharges_GlobalError, Fix_BoundInBox_CenterInBox_MoleculeActions, Fix_ChargeSampling_PBC, Fix_ChronosMutex, Fix_FitPartialCharges, Fix_FitPotential_needs_atomicnumbers, Fix_ForceAnnealing, Fix_IndependentFragmentGrids, Fix_ParseParticles, Fix_ParseParticles_split_forward_backward_Actions, Fix_PopActions, Fix_QtFragmentList_sorted_selection, Fix_Restrictedkeyset_FragmentMolecule, Fix_StatusMsg, Fix_StepWorldTime_single_argument, Fix_Verbose_Codepatterns, Fix_fitting_potentials, Fixes, ForceAnnealing_goodresults, ForceAnnealing_oldresults, ForceAnnealing_tocheck, ForceAnnealing_with_BondGraph, ForceAnnealing_with_BondGraph_continued, ForceAnnealing_with_BondGraph_continued_betteresults, ForceAnnealing_with_BondGraph_contraction-expansion, FragmentAction_writes_AtomFragments, FragmentMolecule_checks_bonddegrees, GeometryObjects, Gui_Fixes, Gui_displays_atomic_force_velocity, ImplicitCharges, IndependentFragmentGrids, IndependentFragmentGrids_IndividualZeroInstances, IndependentFragmentGrids_IntegrationTest, IndependentFragmentGrids_Sole_NN_Calculation, JobMarket_RobustOnKillsSegFaults, JobMarket_StableWorkerPool, JobMarket_unresolvable_hostname_fix, MoreRobust_FragmentAutomation, ODR_violation_mpqc_open, PartialCharges_OrthogonalSummation, PdbParser_setsAtomName, PythonUI_with_named_parameters, QtGui_reactivate_TimeChanged_changes, Recreated_GuiChecks, Rewrite_FitPartialCharges, RotateToPrincipalAxisSystem_UndoRedo, SaturateAtoms_findBestMatching, SaturateAtoms_singleDegree, StoppableMakroAction, Subpackage_CodePatterns, Subpackage_JobMarket, Subpackage_LinearAlgebra, Subpackage_levmar, Subpackage_mpqc_open, Subpackage_vmg, Switchable_LogView, ThirdParty_MPQC_rebuilt_buildsystem, TrajectoryDependenant_MaxOrder, TremoloParser_IncreasedPrecision, TremoloParser_MultipleTimesteps, TremoloParser_setsAtomName, Ubuntu_1604_changes, stable
Children:
3d5b5b
Parents:
fcdf05
git-author:
Frederik Heber <heber@…> (07/15/15 13:56:58)
git-committer:
Frederik Heber <heber@…> (08/05/15 17:32:09)
Message:

DOCU: Updated documentation on Qt Gui construct.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/documentation/constructs/qt-gui.dox

    rfcdf05 r52c5d4  
    2020 * In the following we want to explain some of the details that are involved.
    2121 *
     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 *
    22129 * \section qt-gui-qt3d Qt3D and the way to get atoms and bonds displayed
    23130 *
    24  * Atoms and Bonds have to displayed, the widget for this is GLWorldView. To
    25  * this class belongs GLWorldScene that contains lots of GLMoleculeObject's or
    26  * nodes in the speak of Qt3D. We have four derived class for these kind of
    27  * objects:
    28  * -# GLMoleculeObject_atom: for each atom,
    29  * -# GLMoleculeObject_bond: for each "side" of the bond (each represents half of
    30  *     the bond that join in the middle between the two atoms),
    31  * -# GLMoleculeObject_molecule: for each molecule (shows a box is selected),
    32  * -# GLMoleculeObject_shape: shows the shapes in the ShapeRegistry.
    33  *
    34  * We can only add new nodes to the Qt3D scene at the level of GLWorldScene,
    35  * hence all insertion go through this instance to add new nodes. Destruction
    36  * may occur anywhere as the new nodes are parentized to the scene.
    37  *
    38  * \subsection qt-gui-qt3d-atoms How atom object are constructed/destroyed.
    39  *
    40  * Atoms are rendered as spheres, see createAtom(). GLWorldView gets notified
    41  * by the World about new and removed atoms via the Channel's World::AtomInserted
    42  * and World::AtomRemoved. It translates these into Qt signals with the correct
    43  * affected atom, by looking at
    44  * \code
    45  *   const atom *_atom = World::getInstance().lastChanged<atom>();
    46  * \endcode
    47  * These signals call slots of GLWorldScene that has a map of all contained
    48  * GLMoleculeObject, one for either of the two kinds:
    49  * -# GLWorldScene::atomInserted(): create a new node and connect its signals
    50  *  with us, add to map
    51  * -# GLWorldScene::atomRemoved(): disconnect, remove from map, destroy
    52  *
    53  * We do not need to destroy the node itself as it is connected via the Observer
    54  * mechanism to the associated atom
    55  *
    56  * \subsection qt-gui-qt3d-bonds How bond object are constructed/destroyed.
    57  *
    58  * Bonds are displayed as cylinders that elongate from one atom to the midpoint
    59  * of the bond (i.e. the spot in between the two atoms). That is we have always
    60  * two cylinders per bond. That's why we need to distinguish
    61  * GLMoleculeObject_bond::SideOfBond to get the right node.
    62  *
    63  * Bonds are not as easy as atoms: The World does not know about bonds being
    64  * created or destroyed, only the atoms themselves know about them.
    65  *
    66  * That's way the atom node object GLMoleculeObject_atom is an Observer of is
    67  * associated atom and listens to the Channel AtomObservable::BondsAdded. It then
    68  * translates this into a Qt signal that calls a slot GLWorldScene:BondInserted.
    69  *
    70  *
    71  * Bonds themselves are also Observables, as are atoms. Hence,
    72  * GLMoleculeObject_bond connect via the Observer mechanism to their associated
    73  * bond and are thus notified when they are destroyed.
    74  *
    75  * Additionally, we use GLWorldScene to do some bookkeeping about all bond nodes.
    76  * This is not strictly required but might in general be useful. Hence, signals
    77  * notify GLWorldScene also about GLWorldScene::bondRemoved that are emitted by
    78  * the node itself.
     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.
    79206 *
    80207 * \section QtElementList
    81208 *
    82  * Lists for each element how often it occures in the world. Selecting an entry
     209 * Lists for each element how often it occurs in the world. Selecting an entry
    83210 * calls SelectionAtomByElementAction to select all atoms of that particular
    84211 * element.
    85212 *
    86  * It observes the World and performs a complete refill on any message. To reduce
    87  * performance issues it marks the list as dirty and refills it the next time the
    88  * GUI is idle. This way many successive changes to the world only lead to a
    89  * single refill.
     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.
    90217 *
    91218 * \section QtMoleculeList
     
    94221 * Selecting an entry calls the SelectionMoleculeByIdAction.
    95222 *
    96  * It observes the World the same way QtElementList does.
     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().
    97248 *
    98249 * \section QtShapeController
     
    119270 * they automatically clear the info box.
    120271 *
    121  * \date 2013-02-22
     272 * \date 2015-07-15
    122273 */
Note: See TracChangeset for help on using the changeset viewer.