source: src/documentation/constructs/qt-gui.dox@ 59f1bc

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
Last change on this file since 59f1bc was 59f1bc, checked in by Frederik Heber <heber@…>, 9 years ago

All ..Inserted/..Removed signals now go through GLWorldScene.

  • this should enforce synchronicity of the signals. If we mix direct and queued connections, then this cannot be ensured.
  • the idea is that GLWorldScene gets all Inserted/Removed signals for atoms and molecules from the QtObservedInstanceBoard. It connects to each QtObservedMolecule and thus can call the GLMoleculeObject_molecule's atomInserted, atomRemoved functions in sequence.
  • removed RemovalMolecules, no longer needed.
  • we now enforce with mutexes that instantation of molecule and MissedStateMap do not interfere, i.e. it is always perfectly clear whether to push a signal into the Map or whether to call the function of the present GLMolObj_mol.
  • FIX: MoleculesInScene_mutex has not been used properly, now is.
  • DOCU: Updated construct qt-gu documentation with the new concept.
  • Property mode set to 100644
File size: 17.8 KB
Line 
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 */
Note: See TracBrowser for help on using the repository browser.