/
ISISReflectometryInterface.html
412 lines (369 loc) · 51.8 KB
/
ISISReflectometryInterface.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
<!DOCTYPE html>
<html lang="en" data-content_root="./">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /><meta name="viewport" content="width=device-width, initial-scale=1" />
<title>ISIS Reflectometry Interface</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=fa44fd50" />
<link rel="stylesheet" type="text/css" href="_static/bootstrap-sphinx.css?v=fadd4351" />
<link rel="stylesheet" type="text/css" href="_static/custom.css?v=77160d70" />
<script src="_static/documentation_options.js?v=30d551ce"></script>
<script src="_static/doctools.js?v=9a2dae69"></script>
<script src="_static/sphinx_highlight.js?v=dc90522c"></script>
<link rel="index" title="Index" href="genindex.html" />
<link rel="search" title="Search" href="search.html" />
<link rel="next" title="Workbench Index" href="Workbench/index.html" />
<link rel="prev" title="Mantid Icon Table" href="MantidUsedIconsTable.html" />
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-59110517-1', 'auto');
ga('send', 'pageview');
</script>
</head><body>
<div id="navbar" class="navbar navbar-default ">
<div class="container">
<div class="navbar-header">
<!-- .btn-navbar is used as the toggle for collapsed navbar content -->
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".nav-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="http://www.mantidproject.org">
</a>
<span class="navbar-text navbar-version pull-left"><b>master</b></span>
</div>
<div class="collapse navbar-collapse nav-collapse">
<ul class="nav navbar-nav">
<li class="divider-vertical"></li>
<li><a href="index.html">Home</a></li>
<li><a href="https://download.mantidproject.org">Download</a></li>
<li><a href="https://docs.mantidproject.org">User Documentation</a></li>
<li><a href="http://www.mantidproject.org/contact">Contact Us</a></li>
</ul>
<form class="navbar-form navbar-right" action="search.html" method="get">
<div class="form-group">
<input type="text" name="q" class="form-control" placeholder="Search" />
</div>
<input type="hidden" name="check_keywords" value="yes" />
<input type="hidden" name="area" value="default" />
</form>
</div>
</div>
<p>
<div class="related" role="navigation" aria-label="related navigation">
<h3>Navigation</h3>
<ul>
<li class="nav-item nav-item-0"><a href="index.html">Documentation</a> »</li>
<li class="nav-item nav-item-this"><a href="">ISIS Reflectometry Interface</a></li>
</ul>
</div> </p>
</div>
<div class="container">
<div class="row">
<div class="body col-md-12 content" role="main">
<section id="isis-reflectometry-interface">
<span id="isisreflectometryinterface"></span><h1>ISIS Reflectometry Interface<a class="headerlink" href="#isis-reflectometry-interface" title="Link to this heading">¶</a></h1>
<p>This document gives a brief overview of the <a class="reference external" href="https://docs.mantidproject.org/nightly/interfaces/ISIS%20Reflectometry.html">ISIS Reflectometry Interface</a> design and things that you should be aware of when working on this interface. If you need to work on this interface, please make sure you are familiar with the <a class="reference internal" href="#development-guidelines">Development guidelines</a> below as a minimum.</p>
<section id="overview">
<h2>Overview<a class="headerlink" href="#overview" title="Link to this heading">¶</a></h2>
<p>The <a class="reference external" href="https://docs.mantidproject.org/nightly/interfaces/ISIS%20Reflectometry.html">ISIS Reflectometry Interface</a> provides a way for users to easily run a reduction on a <em>batch</em> of runs. A batch of runs is entered into a table, which is actually a tree structure with two levels - this allows sets of runs to be grouped so that their outputs are post-processed (stitched) together. Various default settings can be specified on the tabs. A tab is also provided to make exporting the results for a set of workspaces easy.</p>
<p>The reduction for each row is done via <a class="reference external" href="https://docs.mantidproject.org/nightly/algorithms/ReflectometryISISLoadAndProcess-v1.html#algm-reflectometryisisloadandprocess" title="(in MantidProject v6.9)"><span>ReflectometryISISLoadAndProcess v1</span></a> (which includes any pre-processing). Post-processing for a group is done via <a class="reference external" href="https://docs.mantidproject.org/nightly/algorithms/Stitch1DMany-v1.html#algm-stitch1dmany" title="(in MantidProject v6.9)"><span>Stitch1DMany v1</span></a>.</p>
<p>The GUI provides a lot of other functionality as well. Because it is quite complex, it is important to keep to the established guidelines, in particular sticking to the MVP design pattern, to avoid the code becoming difficult to work with.</p>
</section>
<section id="structure">
<h2>Structure<a class="headerlink" href="#structure" title="Link to this heading">¶</a></h2>
<section id="gui">
<h3><code class="code docutils literal notranslate"><span class="pre">GUI</span></code><a class="headerlink" href="#gui" title="Link to this heading">¶</a></h3>
<p>This directory contains all of the GUI code for the interface. Each separate component e.g. the Experiment tab, has its own subdirectory. Each of these components has its own view and presenter. There is also a <code class="code docutils literal notranslate"><span class="pre">Common</span></code> subdirectory for GUI components/interfaces common to more than one widget (e.g. the <code class="code docutils literal notranslate"><span class="pre">IReflMessageHandler</span></code> interface).</p>
<p>Briefly the structure is as follows:</p>
<ul class="simple">
<li><p>The top level is the <code class="code docutils literal notranslate"><span class="pre">MainWindow</span></code>.</p></li>
<li><p>This can have one or more vertical <code class="code docutils literal notranslate"><span class="pre">Batch</span></code> tabs.</p></li>
<li><p>Each <code class="code docutils literal notranslate"><span class="pre">Batch</span></code> has several horizontal tabs:</p>
<ul>
<li><p>The <code class="code docutils literal notranslate"><span class="pre">Runs</span></code> tab is where the user specifies which runs to process. The actual runs list is specified in the embedded <code class="code docutils literal notranslate"><span class="pre">RunsTable</span></code> component, which comprises of the generic <a class="reference external" href="BatchWidget/API/JobTreeView.html">JobTreeView</a> table along with a reflectometry-specific toolbar. The <code class="code docutils literal notranslate"><span class="pre">Runs</span></code> tab also contains various other operations to do with finding and processing runs, such as searching and autoprocessing by investigation ID and a live data monitor. Note that a <em>table</em> here actually refers to a two-level tree, due to the way sets of runs can be grouped together for post-processing.</p></li>
<li><p>The <code class="code docutils literal notranslate"><span class="pre">Experiment</span></code> tab allows the user to enter default settings related to a particular experiment.</p></li>
<li><p>The <code class="code docutils literal notranslate"><span class="pre">Instrument</span></code> tab allows the user to enter default settings related to the current instrument.</p></li>
<li><p>The <code class="code docutils literal notranslate"><span class="pre">Save</span></code> tab allows easy saving of a batch of outputs in ASCII format. It essentially just works on the ADS so this might not be necessary longer term if similar batch-saving functionality could be provided from the workspaces list.</p></li>
</ul>
</li>
</ul>
<figure class="align-center" style="width: 70%">
<img alt="_images/ISISReflectometryInterface_structure.png" src="_images/ISISReflectometryInterface_structure.png" />
</figure>
</section>
<section id="reduction">
<h3><code class="code docutils literal notranslate"><span class="pre">Reduction</span></code><a class="headerlink" href="#reduction" title="Link to this heading">¶</a></h3>
<p>This directory contains models which centre around the <em>reduction configuration</em>. This is a representation of all of the runs and settings that have been entered in a particular Batch tab in the GUI. The top level <code class="code docutils literal notranslate"><span class="pre">Batch</span></code> model therefore provides everything needed to perform a reduction for a particular set of runs.</p>
<p>Additionally, these models also contain state information, e.g. the <code class="code docutils literal notranslate"><span class="pre">Row</span></code> and <code class="code docutils literal notranslate"><span class="pre">Group</span></code> contain information about whether processing has been performed and what the output workspaces are.</p>
</section>
<section id="common">
<h3><code class="code docutils literal notranslate"><span class="pre">Common</span></code><a class="headerlink" href="#common" title="Link to this heading">¶</a></h3>
<p>This directory contains non-GUI-specific utility files useful in more than one component of the reflectometry interface but that are still specific to this interface, e.g. <code class="code docutils literal notranslate"><span class="pre">Parse.h</span></code> contains parsing utility functions that are specific for parsing reflectometry input strings such as lists of run numbers. More generic utilities should be put elsewhere, e.g. generic string handling functions might go in <code class="code docutils literal notranslate"><span class="pre">Framework/Kernel</span></code>.</p>
</section>
<section id="testhelpers">
<h3><code class="code docutils literal notranslate"><span class="pre">TestHelpers</span></code><a class="headerlink" href="#testhelpers" title="Link to this heading">¶</a></h3>
<p>This directory contains components specific for unit testing. The actual tests are in <code class="code docutils literal notranslate"><span class="pre">../test/ISISReflectometry/</span></code>.</p>
</section>
</section>
<section id="reduction-back-end">
<h2>Reduction back-end<a class="headerlink" href="#reduction-back-end" title="Link to this heading">¶</a></h2>
<p>The back-end is primarily a set of algorithms, with the entry points from the GUI being <a class="reference external" href="https://docs.mantidproject.org/nightly/algorithms/ReflectometryISISLoadAndProcess-v1.html#algm-reflectometryisisloadandprocess" title="(in MantidProject v6.9)"><span>ReflectometryISISLoadAndProcess v1</span></a> (for reducing a row) and <a class="reference external" href="https://docs.mantidproject.org/nightly/algorithms/Stitch1DMany-v1.html#algm-stitch1dmany" title="(in MantidProject v6.9)"><span>Stitch1DMany v1</span></a> (for post-processing a group). Any additional processing should be added to these algorithms, or a new wrapper algorithm could be added if appropriate (this might be necessary in future if post-processing will involve more than just stitching).</p>
<p>The <code class="code docutils literal notranslate"><span class="pre">BatchPresenter</span></code> is the main coordinator for executing a reduction. It uses the <code class="code docutils literal notranslate"><span class="pre">BatchJobManager</span></code>, which converts the reduction configuration to a format appropriate for the algorithms. The conversion functions are in files called <code class="code docutils literal notranslate"><span class="pre">RowProcessingAlgorithm</span></code> and <code class="code docutils literal notranslate"><span class="pre">GroupProcessingAlgorithm</span></code>, and any algorithm-specific code should be kept to these files.</p>
<p>Unfortunately the whole batch cannot be farmed off to a single algorithm because we need to update the GUI after each row completes, and we must be able to interrupt processing so that we can cancel a large batch operation. We also need to know whether rows completed successfully before we can set up the group post-processing algorithms. Some queue management is therefore done by the <code class="code docutils literal notranslate"><span class="pre">BatchPresenter</span></code>, with the help of the <code class="code docutils literal notranslate"><span class="pre">BatchAlgorithmRunner</span></code>.</p>
</section>
<section id="development-guidelines">
<h2>Development guidelines<a class="headerlink" href="#development-guidelines" title="Link to this heading">¶</a></h2>
<p>The following design principles should be adhered to when developing the GUI. If the current design does not seem appropriate for additional feature requests, do consult with a senior developer to work out the best way forward rather than proceeding in a non-optimal way.</p>
<section id="adhere-to-mvp">
<h3>Adhere to MVP<a class="headerlink" href="#adhere-to-mvp" title="Link to this heading">¶</a></h3>
<p>To ensure the GUI can be easily tested we follow the MVP design pattern. There is general guidance on this <a class="reference internal" href="MVPDesign.html#mvpdesign"><span class="std std-ref">here</span></a>.</p>
<p>The view cannot easily be tested, so the aim of MVP is to keep the view as simple as possible so that testing it is not necessary. Typically any user action on the view results in a notification to the presenter and is handled from there (even if that is just an update back to the view). Even simple things like which buttons are enabled on startup are controlled via the presenter rather than setting defaults in the view itself.</p>
<p>It can be tempting to add one line to toggle or update something in the view without wiring up the presenter. But these quick fixes can quickly introduce bugs as they accumulate. The first question to ask yourself before making any change is: how will I unit test it? In fact, we recommend you follow <a class="reference external" href="https://en.wikipedia.org/wiki/Test-driven_development">test driven development</a> and write the unit tests first.</p>
<p>Note that the views should not have a direct pointer to their presenters, so the notification is done via a subscriber interface (see <a class="reference internal" href="#subscriber-pattern">Subscriber pattern</a> for an example). The only exception is the <code class="code docutils literal notranslate"><span class="pre">QtMainWindowView</span></code> (see <a class="reference internal" href="#dependency-inversion">Dependency inversion</a>), but notifications should still be done via the subscriber interface. This helps to avoid accidentally introducing logic into the view about what should happen on an event and instead just notify that an event happened. It could also be easily extended to support multiple notifyees of different types, such as different subscribed presenters.</p>
</section>
<section id="dependency-inversion">
<h3>Dependency inversion<a class="headerlink" href="#dependency-inversion" title="Link to this heading">¶</a></h3>
<p>Dependency inversion has been introduced in an effort to simplify some aspects of the design and to make the code more modular. Objects that a class depends on are “injected”, rather than being created directly within the class that requires them. This makes testing easier, because the real objects can easily be replaced with mocks. Most injection is currently performed using constructors and takes place at the ‘entry-point’ for the Reflectometry GUI, in <code class="code docutils literal notranslate"><span class="pre">QtMainWindowView</span></code>. See the <a class="reference internal" href="#dependency-injection">Dependency injection</a> example below.</p>
<p>It is not normal in MVP for a view to have ownership of its presenter. However since the whole of mantid does not use Dependency Injection, and due to the way interfaces get instantiated this is currently necessary for <code class="code docutils literal notranslate"><span class="pre">QtMainWindowView</span></code>. This pointer should only be used for ownership and all other usage should be avoided, so ensure you use the <code class="code docutils literal notranslate"><span class="pre">MainWindowSubscriber</span></code> interface to send notifications to the presenter - i.e. use <code class="code docutils literal notranslate"><span class="pre">m_notifyee</span></code> instead of <code class="code docutils literal notranslate"><span class="pre">m_presenter</span></code>.</p>
</section>
<section id="coordinate-via-presenters">
<h3>Coordinate via presenters<a class="headerlink" href="#coordinate-via-presenters" title="Link to this heading">¶</a></h3>
<p>Although the components are largely self-contained, there are occasions where communication between them is required. For example, when processing is running, we do not want the user to be able to edit any settings, because this would change the model that the reduction is running on. We therefore disable all inputs that would affect the reduction when processing is running, and re-enable them when it stops.</p>
<p>Although enabling/disabling inputs in this example affects the views, coordination between components is done via the presenters. This is to ensure that all of these interactions can be unit tested. Each presenter owns its child presenters, and also has a pointer to its parent presenter (which is set by its parent calling <code class="code docutils literal notranslate"><span class="pre">acceptMainPresenter</span></code> on the child and passing a pointer to itself).</p>
<p>In the example mentioned, processing is initiated from e.g. the button on the <code class="code docutils literal notranslate"><span class="pre">RunsView</span></code>. This sends a notification to the <code class="code docutils literal notranslate"><span class="pre">RunsPresenter</span></code> via the subscriber interface. However, the <code class="code docutils literal notranslate"><span class="pre">RunsPresenter</span></code> cannot initiate processing because information is needed from the other tabs, and the other tabs need to be updated after it starts. Processing therefore needs to be coordinated at the Batch level. The <code class="code docutils literal notranslate"><span class="pre">RunsPresenter</span></code> therefore simply notifies its parent <code class="code docutils literal notranslate"><span class="pre">BatchPresenter</span></code> that the user requested to start processing. The <code class="code docutils literal notranslate"><span class="pre">BatchPresenter</span></code> then does the work to initiate processing. Once it has started (assuming it started successfully) it then notifies all of its child presenters (including the <code class="code docutils literal notranslate"><span class="pre">RunsPresenter</span></code>) that processing is in progress.</p>
<p>Communication between different Batch components is also occasionally required. For example, for usability reasons, only one autoprocessing operation is allowed to be running at any one time. This means that when autoprocessing is running, we need to disable the <code class="code docutils literal notranslate"><span class="pre">AutoProcess</span></code> button on all of the other Batch tabs as well. This must be coordinated via the MainWindow component, which is the only component that has access to all of the Batch tabs. The user initiates autoprocessing using the <code class="code docutils literal notranslate"><span class="pre">AutoProcess</span></code> button on the <code class="code docutils literal notranslate"><span class="pre">BatchView</span></code>, which notifies the <code class="code docutils literal notranslate"><span class="pre">BatchPresenter</span></code> via the subscriber interface. Since the <code class="code docutils literal notranslate"><span class="pre">BatchPresenter</span></code> knows everything it needs to start autoprocessing for that batch, it does the work to initiate autoprocessing itself. It then simply notifies its parent <code class="code docutils literal notranslate"><span class="pre">MainWindowPresneter</span></code> that autoprocessing is in progress (again, assuming that it started successfully). The <code class="code docutils literal notranslate"><span class="pre">MainWindowPresenter</span></code> then notifies all of its child presenters that autoprocessing is in progress so that they can enable/disable any buttons/widgets as required.</p>
</section>
<section id="avoid-use-of-qt-types-outside-of-qt-classes">
<h3>Avoid use of Qt types outside of Qt classes<a class="headerlink" href="#avoid-use-of-qt-types-outside-of-qt-classes" title="Link to this heading">¶</a></h3>
<p>Qt-specific types such as <code class="code docutils literal notranslate"><span class="pre">QString</span></code>, <code class="code docutils literal notranslate"><span class="pre">QColor</span></code> and subclasses of <code class="code docutils literal notranslate"><span class="pre">QWidget</span></code> should be kept out of the presenters and models. This avoids confusion over which types should be used and a potentially messy situation where we are always having to convert back and forth between Qt types and <code class="code docutils literal notranslate"><span class="pre">std</span></code> types. It also avoids an over-reliance on Qt, so that the view could be swapped out in future to one using a different framework, with little or no changes to the presenters and models.</p>
<p>To help make it clear where Qt is used, all classes that use Qt (namely the views, along with a few supporting classes which wrap or subclass <code class="code docutils literal notranslate"><span class="pre">QObject</span></code>) are named with a <code class="code docutils literal notranslate"><span class="pre">Qt</span></code> prefix in their file and class names. Conversion from types like <code class="code docutils literal notranslate"><span class="pre">QString</span></code> to <code class="code docutils literal notranslate"><span class="pre">std::string</span></code> is performed within the views, and no Qt types are present in their interfaces.</p>
</section>
<section id="keep-the-reduction-configuration-up-to-date">
<h3>Keep the reduction configuration up to date<a class="headerlink" href="#keep-the-reduction-configuration-up-to-date" title="Link to this heading">¶</a></h3>
<p>Any change on the GUI’s views results in a notification to the relevant presenter, which typically then updates a relevant model in the <code class="code docutils literal notranslate"><span class="pre">Reduction</span></code> directory. The model should always be an up-to-date representation of the view.</p>
<p>Model state (i.e. processed state for rows/groups and output workspace names) should also be kept up to date. For example, if a row’s output workspace has been deleted, then its state is reset. If settings have changed that would affect the reduction output, then the state is also reset.</p>
</section>
<section id="perform-all-processing-in-algorithms">
<h3>Perform all processing in algorithms<a class="headerlink" href="#perform-all-processing-in-algorithms" title="Link to this heading">¶</a></h3>
<p>When adding new functionality, where possible this should be done by extending the algorithms rather than by adding logic to the GUI. The aim is that there is a single algorithm that will be run for each entry in the table (albeit a different algorithm for Rows and Groups).</p>
<p>Consider adding new wrapper algorithms if appropriate. <a class="reference external" href="https://docs.mantidproject.org/nightly/algorithms/ReflectometryISISLoadAndProcess-v1.html#algm-reflectometryisisloadandprocess" title="(in MantidProject v6.9)"><span>ReflectometryISISLoadAndProcess v1</span></a> is an algorithm that has been added specifically for this purpose and can usually be extended or modified quite easily because it is designed for use with this GUI. The post-processing algorithm, <a class="reference external" href="https://docs.mantidproject.org/nightly/algorithms/Stitch1DMany-v1.html#algm-stitch1dmany" title="(in MantidProject v6.9)"><span>Stitch1DMany v1</span></a>, is more generic so it is likely in future that we would want to add a wrapper for this algorithm rather than changing it directly.</p>
</section>
</section>
<section id="design-pattern-examples">
<h2>Design pattern examples<a class="headerlink" href="#design-pattern-examples" title="Link to this heading">¶</a></h2>
<section id="subscriber-pattern">
<h3>Subscriber pattern<a class="headerlink" href="#subscriber-pattern" title="Link to this heading">¶</a></h3>
<p>Let’s take the <code class="code docutils literal notranslate"><span class="pre">Event</span></code> component as an example.</p>
<ul>
<li><p>The view is constructed first and is passed to the presenter. The presenter then immediately subscribes to the view.</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">EventPresenter</span><span class="o">::</span><span class="n">EventPresenter</span><span class="p">(</span><span class="n">IEventView</span><span class="w"> </span><span class="o">*</span><span class="n">view</span><span class="p">)</span>
<span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="n">m_view</span><span class="p">(</span><span class="n">view</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">m_view</span><span class="o">-></span><span class="n">subscribe</span><span class="p">(</span><span class="k">this</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
</li>
<li><p>This sets the notifyee in the view, using a subscriber interface.</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">QtEventView::subscribe</span><span class="p">(</span><span class="n">EventViewSubscriber</span><span class="w"> </span><span class="o">*</span><span class="n">notifyee</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">m_notifyee</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">notifyee</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
</li>
<li><p>The subscriber interface defines the set of notifications that the view needs to send.</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">MANTIDQT_ISISREFLECTOMETRY_DLL</span><span class="w"> </span><span class="n">EventViewSubscriber</span><span class="w"> </span><span class="p">{</span>
<span class="k">public</span><span class="o">:</span>
<span class="w"> </span><span class="k">virtual</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="n">notifySliceTypeChanged</span><span class="p">(</span><span class="n">SliceType</span><span class="w"> </span><span class="n">newSliceType</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="k">virtual</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">notifyUniformSliceCountChanged</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">sliceCount</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="p">...</span>
<span class="p">};</span>
</pre></div>
</div>
<p>Note that <code class="code docutils literal notranslate"><span class="pre">MANTIDQT_ISISREFLECTOMETRY_DLL</span></code> is used to expose classes/functions so they can be used in different modules. In this case, it is needed in order for this class to be used in the tests, because the tests are not part of the ISISReflectometry library. If you get linker errors, this is one thing to check.</p>
</li>
<li><p>The presenter implements the subscriber interface.</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">MANTIDQT_ISISREFLECTOMETRY_DLL</span><span class="w"> </span><span class="n">EventPresenter</span>
<span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="n">IEventPresenter</span><span class="p">,</span>
<span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="n">EventViewSubscriber</span>
</pre></div>
</div>
</li>
<li><p>It overrides the notification functions to perform the relevant actions.</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">EventPresenter::notifyUniformSliceCountChanged</span><span class="p">(</span><span class="kt">int</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">setUniformSlicingByNumberOfSlicesFromView</span><span class="p">();</span>
<span class="w"> </span><span class="n">m_mainPresenter</span><span class="o">-></span><span class="n">notifySettingsChanged</span><span class="p">();</span>
<span class="p">}</span>
</pre></div>
</div>
</li>
<li><p>When a user interacts with the view, all the view needs to do is send the appropriate notification. By using an interface, the view does not know anything about the concrete type that it is notifying. This helps to avoid accidentally introducing logic into the view about what should happen on an event and instead just notify that an event happened. It could also be easily extended to support multiple notifyees of different types, such as different subscribed presenters.</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">QtEventView::onUniformEvenChanged</span><span class="p">(</span><span class="kt">int</span><span class="w"> </span><span class="n">numberOfSlices</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">m_notifyee</span><span class="o">-></span><span class="n">notifyUniformSliceCountChanged</span><span class="p">(</span><span class="n">numberOfSlices</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
</li>
</ul>
</section>
<section id="dependency-injection">
<h3>Dependency injection<a class="headerlink" href="#dependency-injection" title="Link to this heading">¶</a></h3>
<p>A simple example of <a class="reference internal" href="#dependency-inversion">Dependency inversion</a> is in the use of an <code class="code docutils literal notranslate"><span class="pre">IReflMessageHandler</span></code> interface to provide a service to display messages to the user. These messages must be displayed by a Qt view. Rather than each view having to implement this, we use one object (in this case the <code class="code docutils literal notranslate"><span class="pre">QtMainWindowView</span></code>) to implement this functionality and inject it as an <code class="code docutils literal notranslate"><span class="pre">IReflMessageHandler</span></code> to all of the presenters that need it.</p>
<ul>
<li><p>The <code class="code docutils literal notranslate"><span class="pre">IReflMessageHandler</span></code> interface defines the functions for displaying messages:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">IReflMessageHandler</span><span class="w"> </span><span class="p">{</span>
<span class="k">public</span><span class="o">:</span>
<span class="w"> </span><span class="k">virtual</span><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="n">giveUserCritical</span><span class="p">(</span><span class="k">const</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="w"> </span><span class="o">&</span><span class="n">prompt</span><span class="p">,</span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="w"> </span><span class="o">&</span><span class="n">title</span><span class="p">)</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="p">...</span>
<span class="p">};</span>
</pre></div>
</div>
</li>
<li><p>The <code class="code docutils literal notranslate"><span class="pre">QtMainWindowView</span></code> implements these:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">QtMainWindowView::giveUserCritical</span><span class="p">(</span><span class="k">const</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="w"> </span><span class="o">&</span><span class="n">prompt</span><span class="p">,</span>
<span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="n">std</span><span class="o">::</span><span class="n">string</span><span class="w"> </span><span class="o">&</span><span class="n">title</span><span class="p">)</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">QMessageBox</span><span class="o">::</span><span class="n">critical</span><span class="p">(</span><span class="k">this</span><span class="p">,</span><span class="w"> </span><span class="n">QString</span><span class="o">::</span><span class="n">fromStdString</span><span class="p">(</span><span class="n">title</span><span class="p">),</span>
<span class="w"> </span><span class="n">QString</span><span class="o">::</span><span class="n">fromStdString</span><span class="p">(</span><span class="n">prompt</span><span class="p">),</span><span class="w"> </span><span class="n">QMessageBox</span><span class="o">::</span><span class="n">Ok</span><span class="p">,</span>
<span class="w"> </span><span class="n">QMessageBox</span><span class="o">::</span><span class="n">Ok</span><span class="p">);</span>
<span class="p">}</span>
</pre></div>
</div>
</li>
<li><p>The <code class="code docutils literal notranslate"><span class="pre">QtMainWindowView</span></code> creates a concrete instance of the interface (actually just a pointer to itself) and passes it in the construction of anything that needs it, e.g. the <code class="code docutils literal notranslate"><span class="pre">RunsPresenter</span></code> (in this case using a factory to perform the construction - more about the <a class="reference internal" href="#factory-pattern">Factory pattern</a> below):</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">auto</span><span class="w"> </span><span class="n">messageHandler</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">this</span><span class="p">;</span>
<span class="k">auto</span><span class="w"> </span><span class="n">makeRunsPresenter</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">RunsPresenterFactory</span><span class="p">(...,</span><span class="w"> </span><span class="n">messageHandler</span><span class="p">);</span>
</pre></div>
</div>
</li>
<li><p>The <code class="code docutils literal notranslate"><span class="pre">RunsPresenter</span></code> then has a simple service it can use to display messages without needing to know anything about the <code class="code docutils literal notranslate"><span class="pre">QtMainWindowView</span></code>:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">m_messageHandler</span><span class="o">-></span><span class="n">giveUserCritical</span><span class="p">(</span><span class="s">"Catalog login failed"</span><span class="p">,</span><span class="w"> </span><span class="s">"Error"</span><span class="p">);</span>
</pre></div>
</div>
</li>
<li><p>Our unit tests can then ensure that a notification is sent to Qt in a known critical situation, e.g. in <code class="code docutils literal notranslate"><span class="pre">RunsPresenterTest</span></code>:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">testSearchCatalogLoginFails</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="p">...</span>
<span class="w"> </span><span class="n">EXPECT_CALL</span><span class="p">(</span><span class="n">m_messageHandler</span><span class="p">,</span>
<span class="w"> </span><span class="n">giveUserCritical</span><span class="p">(</span><span class="s">"Catalog login failed"</span><span class="p">,</span><span class="w"> </span><span class="s">"Error"</span><span class="p">))</span>
<span class="w"> </span><span class="p">.</span><span class="n">Times</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
<span class="w"> </span><span class="p">...</span>
<span class="p">}</span>
</pre></div>
</div>
</li>
</ul>
</section>
<section id="factory-pattern">
<h3>Factory pattern<a class="headerlink" href="#factory-pattern" title="Link to this heading">¶</a></h3>
<p>The <code class="code docutils literal notranslate"><span class="pre">MainWindowPresenter</span></code> constructs the child Batch presenters on demand. This prevents us injecting them in its constructor. In order to follow <a class="reference internal" href="#dependency-inversion">Dependency inversion</a>, we therefore need to use factories to create the child presenters. Let’s use the <code class="code docutils literal notranslate"><span class="pre">MainWindow</span></code> -> <code class="code docutils literal notranslate"><span class="pre">Batch</span></code> -> <code class="code docutils literal notranslate"><span class="pre">Event</span></code> components as an example.</p>
<ul class="simple">
<li><p>As mentioned, the <code class="code docutils literal notranslate"><span class="pre">QtMainWindowView</span></code> is our entry point. This creates (and owns) the <code class="code docutils literal notranslate"><span class="pre">MainWindowPresenter</span></code>. It:</p>
<ul>
<li><p>creates an <code class="code docutils literal notranslate"><span class="pre">EventPresenterFactory</span></code>;</p></li>
<li><p>passes this to the <code class="code docutils literal notranslate"><span class="pre">BatchPresenterFactory</span></code> constructor so it can create the child <code class="code docutils literal notranslate"><span class="pre">EventPresenter</span></code> when needed;</p></li>
<li><p>passes this to the <code class="code docutils literal notranslate"><span class="pre">MainWindowPresenter</span></code> constructor, which accepts a <code class="code docutils literal notranslate"><span class="pre">BatchPresenterFactory</span></code>, ready for making a Batch when needed.</p></li>
</ul>
</li>
<li><p>When required, we then create a Batch:</p>
<ul>
<li><p>The <code class="code docutils literal notranslate"><span class="pre">QtMainWindowView</span></code> notifies the presenter that a new batch was requested.</p></li>
<li><p>The presenter instructs the view to create a child <code class="code docutils literal notranslate"><span class="pre">QtBatchView</span></code> (which will also construct its child <code class="code docutils literal notranslate"><span class="pre">QtEventView</span></code>).</p></li>
<li><p>The <code class="code docutils literal notranslate"><span class="pre">QtBatchView</span></code> is passed to the <code class="code docutils literal notranslate"><span class="pre">BatchPresenterFactory</span></code> to create the <code class="code docutils literal notranslate"><span class="pre">BatchPresenter</span></code>:</p>
<ul>
<li><p>the <code class="code docutils literal notranslate"><span class="pre">BatchPresenterFactory</span></code> extracts the <code class="code docutils literal notranslate"><span class="pre">QtEventView</span></code> from the <code class="code docutils literal notranslate"><span class="pre">QtBatchView</span></code>;</p></li>
<li><p>this is passed to the <code class="code docutils literal notranslate"><span class="pre">EventPresenterFactory</span></code> to create the child <code class="code docutils literal notranslate"><span class="pre">EventPresenter</span></code>; it receives an <code class="code docutils literal notranslate"><span class="pre">IEventPresenter</span></code> back;</p></li>
<li><p>the batch factory injects the <code class="code docutils literal notranslate"><span class="pre">IEventPresenter</span></code> into the <code class="code docutils literal notranslate"><span class="pre">BatchPresenter</span></code> constructor;</p></li>
<li><p>it returns the result as an <code class="code docutils literal notranslate"><span class="pre">IBatchPresenter</span></code>.</p></li>
</ul>
</li>
<li><p>The <code class="code docutils literal notranslate"><span class="pre">IBatchPresenter</span></code> is then added to the <code class="code docutils literal notranslate"><span class="pre">MainWindowPresenter</span></code>’s list of child presenters.</p></li>
</ul>
</li>
</ul>
<p>The <code class="code docutils literal notranslate"><span class="pre">MainWindowPresenter</span></code> therefore creates, and owns, the <code class="code docutils literal notranslate"><span class="pre">BatchPresenter</span></code>, but does not need to know its concrete type. In turn, the <code class="code docutils literal notranslate"><span class="pre">BatchPresenterFactory</span></code> creates the child <code class="code docutils literal notranslate"><span class="pre">EventPresenter</span></code> and injects this into the <code class="code docutils literal notranslate"><span class="pre">BatchPresenter</span></code>, also without knowing the child’s concrete type. As mentioned in the <a class="reference internal" href="#dependency-inversion">Dependency inversion</a> section, this helps testability by allowing us to replace the real dependencies with mock objects.</p>
</section>
</section>
<section id="testing">
<h2>Testing<a class="headerlink" href="#testing" title="Link to this heading">¶</a></h2>
<p>Let’s look at the presenter-view interactions in the <code class="code docutils literal notranslate"><span class="pre">Event</span></code> component as an example.</p>
<ul>
<li><p>The <code class="code docutils literal notranslate"><span class="pre">EventPresenterTest</span></code> class sets up a mock view to use for testing:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="n">NiceMock</span><span class="o"><</span><span class="n">MockEventView</span><span class="o">></span><span class="w"> </span><span class="n">m_view</span><span class="p">;</span>
<span class="n">EventPresenter</span><span class="w"> </span><span class="nf">makePresenter</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">auto</span><span class="w"> </span><span class="n">presenter</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">EventPresenter</span><span class="p">(</span><span class="o">&</span><span class="n">m_view</span><span class="p">);</span>
<span class="w"> </span><span class="p">...</span>
<span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">presenter</span><span class="p">;</span>
<span class="p">}</span>
</pre></div>
</div>
</li>
<li><p>The mock view mocks any methods we’re interested in testing, e.g. it mocks the subscribe method so that we can check that the presenter subscribes to the view:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="k">class</span><span class="w"> </span><span class="nc">MockEventView</span><span class="w"> </span><span class="o">:</span><span class="w"> </span><span class="k">public</span><span class="w"> </span><span class="n">IEventView</span><span class="w"> </span><span class="p">{</span>
<span class="k">public</span><span class="o">:</span>
<span class="w"> </span><span class="n">MOCK_METHOD1</span><span class="p">(</span><span class="n">subscribe</span><span class="p">,</span><span class="w"> </span><span class="kt">void</span><span class="p">(</span><span class="n">EventViewSubscriber</span><span class="w"> </span><span class="o">*</span><span class="p">));</span>
</pre></div>
</div>
</li>
<li><p>The presenter then uses <code class="code docutils literal notranslate"><span class="pre">EXPECT_CALL</span></code> to check that the method was called. Note that for <code class="code docutils literal notranslate"><span class="pre">subscribe</span></code> it is difficult to check that the correct presenter pointer is passed because of the two-way dependency in the construction, so we just check that it is called with any argument; for other methods we typically want to check the exact arguments.</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">testPresenterSubscribesToView</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">EXPECT_CALL</span><span class="p">(</span><span class="n">m_view</span><span class="p">,</span><span class="w"> </span><span class="n">subscribe</span><span class="p">(</span><span class="n">_</span><span class="p">)).</span><span class="n">Times</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
<span class="w"> </span><span class="k">auto</span><span class="w"> </span><span class="n">presenter</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">makePresenter</span><span class="p">();</span>
<span class="w"> </span><span class="n">verifyAndClear</span><span class="p">();</span>
<span class="p">}</span>
</pre></div>
</div>
</li>
<li><p>We know that the only notifications we can get from the view are the set of methods in the subscriber interface. Our presenter tests should test each of these. We may also have functions in the presenter that are initiated from different callers than the view, e.g. the parent presenter, so we must test these too. Generally, we want to test all functions in the public interface to the presenter class - and exercise all possible code paths that can result.</p></li>
<li><p>Note that it’s likely we need multiple tests for each notification, for example <code class="code docutils literal notranslate"><span class="pre">notifyUniformSliceCountChanged</span></code> has a test to check that the model is updated as well as one to check that the main presenter is notified:</p>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">testChangingSliceCountUpdatesModel</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="p">...</span>
<span class="w"> </span><span class="n">presenter</span><span class="p">.</span><span class="n">notifyUniformSliceCountChanged</span><span class="p">(</span><span class="n">expectedSliceCount</span><span class="p">);</span>
<span class="w"> </span><span class="k">auto</span><span class="w"> </span><span class="k">const</span><span class="w"> </span><span class="o">&</span><span class="n">sliceValues</span><span class="w"> </span><span class="o">=</span>
<span class="w"> </span><span class="n">boost</span><span class="o">::</span><span class="n">get</span><span class="o"><</span><span class="n">UniformSlicingByNumberOfSlices</span><span class="o">></span><span class="p">(</span><span class="n">presenter</span><span class="p">.</span><span class="n">slicing</span><span class="p">());</span>
<span class="w"> </span><span class="n">TS_ASSERT</span><span class="p">(</span><span class="n">sliceValues</span><span class="w"> </span><span class="o">==</span>
<span class="w"> </span><span class="n">UniformSlicingByNumberOfSlices</span><span class="p">(</span><span class="n">expectedSliceCount</span><span class="p">));</span>
<span class="w"> </span><span class="n">verifyAndClear</span><span class="p">();</span>
<span class="p">}</span>
</pre></div>
</div>
<div class="highlight-c++ notranslate"><div class="highlight"><pre><span></span><span class="kt">void</span><span class="w"> </span><span class="nf">testChangingSliceCountNotifiesMainPresenter</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="k">auto</span><span class="w"> </span><span class="n">presenter</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">makePresenter</span><span class="p">();</span>
<span class="w"> </span><span class="n">EXPECT_CALL</span><span class="p">(</span><span class="n">m_mainPresenter</span><span class="p">,</span><span class="w"> </span><span class="n">notifySettingsChanged</span><span class="p">()).</span><span class="n">Times</span><span class="p">(</span><span class="n">AtLeast</span><span class="p">(</span><span class="mi">1</span><span class="p">));</span>
<span class="w"> </span><span class="n">presenter</span><span class="p">.</span><span class="n">notifyUniformSliceCountChanged</span><span class="p">(</span><span class="mi">1</span><span class="p">);</span>
<span class="w"> </span><span class="n">verifyAndClear</span><span class="p">();</span>
<span class="p">}</span>
</pre></div>
</div>
</li>
<li><p>Testing outcomes separately like this speeds up future development because it makes it easier to see where and why failures happen. It also makes it easier to maintain the tests as the code develops - e.g. if a functional change deliberately changes the expected action on the main presenter then we only need to update that test. The test that checks the model should not be affected (and if it is, we know we’ve broken something!).</p></li>
<li><p>Note that although the <code class="code docutils literal notranslate"><span class="pre">EventPresenter</span></code> tests currently check the model directly, the model could (and should) be mocked out and tested separately if it was more complex.</p></li>
</ul>
</section>
</section>
</div>
</div>
</div>
<footer class="footer">
<div class="container">
<ul class="nav navbar-nav" style=" float: right;">
<li>
<a href="MantidUsedIconsTable.html" title="Previous Chapter: Mantid Icon Table"><span class="glyphicon glyphicon-chevron-left visible-sm"></span><span class="hidden-sm hidden-tablet">« Mantid Icon Table</span>
</a>
</li>
<li>
<a href="Workbench/index.html" title="Next Chapter: Workbench Index"><span class="glyphicon glyphicon-chevron-right visible-sm"></span><span class="hidden-sm hidden-tablet">Workbench Index »</span>
</a>
</li>
<li><a href="#">Back to top</a></li>
</ul>
<p>
</p>
</div>
</footer>
</body>
</html>