File: Application.h

package info (click to toggle)
camitk 6.0.0-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 389,496 kB
  • sloc: cpp: 103,476; sh: 2,448; python: 1,618; xml: 984; makefile: 128; perl: 84; sed: 20
file content (650 lines) | stat: -rw-r--r-- 26,390 bytes parent folder | download
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
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
/*****************************************************************************
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
 * (c) 2001-2025 Univ. Grenoble Alpes, CNRS, Grenoble INP - UGA, TIMC, 38000 Grenoble, France
 *
 * Visit http://camitk.imag.fr for more information
 *
 * This file is part of CamiTK.
 *
 * CamiTK is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * CamiTK is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with CamiTK.  If not, see <http://www.gnu.org/licenses/>.
 *
 * $CAMITK_LICENCE_END$
 ****************************************************************************/

#ifndef CAMITKAPPLICATION_H
#define CAMITKAPPLICATION_H

// -- Core stuff
#include "CamiTKAPI.h"
#include "InterfaceLogger.h"

// -- QT stuff
#include <QApplication>
#include <QSettings>
#include <QDir>
#include <QFileInfo>
#include <QStack>
#include <QList>
#include <QTranslator>

class vtkObject;
namespace camitk {
class MainWindow;
class ActionExtension;
class ViewerExtension;
class Action;
class Viewer;
class HistoryItem;
class ComponentExtension;
class Property;
class PropertyObject;
class SplashScreen;

/**
 * @ingroup group_sdk_libraries_core_application
 *
 * @brief
 * The generic/default application.
 *  Once this class is instantiated in the main, everything is setup.
 *  The constructor can take the command line arguments.
 *  It can also be asked not to load the extensions automatically,see Application().
 *
 *  If you do not have a specific MainWindow extension, then the default CamiTK MainWindow is used, see setMainWindow().
 *
 * This class manages all application-level instances, structures and all. This explains the number of _static_ methods
 * in this class.
 *
 * It manages:
 * - the registered/loaded action extensions and all the actions
 * - the registered/loaded component extensions and all the component instances
 * - the registered/loaded viewer extensions and all the viewer instances
 * - the refresh mechanism
 * - the current selection (selected components)
 * - the recently opened documents
 * - the application language/internationalization settings
 * - the opening/closing/saving of components
 * - the main window
 * - the history of applied actions (including saving it as a CamitK SCXML document)
 * - some application level settings
 *
 */
class CAMITK_API Application : public QApplication {
    Q_OBJECT

public:

    /**
     * Initializes the window system and constructs a CamiTK application object with argc command line arguments in argv.
     * The first parameter is the name of the application (used as a identifier in the settings, for example)
     *
     * The second and third parameters comes from the command line (see QApplication API documentation).
     * This constructor inits all the CamiTK context:
     *     - application wide settings
     *     - autoload (or not, depending on the last parameter) of the extension
     *
     * \note that you have to call init before doing anything!
     *
     * @param name the name of the application, it will be used to save specific configuration for example.
     * @param argc the number of command line arguments
     * @param argv the values of the command line arguments
     * @param autoloadExtension if true, all the plugins are loaded
     * @param registerFileExtension if true, the application will prompt the user at first run if
     *        she/he wants to register file formats handled by loaded components with this application
     *        for opening (only valid for windows).
     * @param useSplashScreen if true a splash screen is instantiated to show status message during launch
     *
     * \note registerFileExtension is only valid on Windows platform.
     */
    Application(QString name, int& argc, char** argv, bool autoloadExtension = true, bool registerFileExtension = false, bool useSplashScreen = false);

    /// destructor
    ~Application() override;

    /** @name Application specific
     */
    /// @{

    /// reimplemented from QApplication to catch all exception from external libs used in CEP (e.g. from ITK) and avoid crashes...
    bool notify(QObject*, QEvent*) override;

    /// get the application name
    static QString getName();

    /** Get the Core wide settings.
     *  This is the preferred methods for accessing and writing the settings for your specific needs,
     *  although you can use any kind of settings you like, using this allow you to store all
     *  settings in one place for all Core needs.
     *  This settings are stored in the user scope, using the INI format (i.e. no registers !),
     *  the organisation name is TIMC-IMAG and the application name is equal to Core::version().
     *  Check the QSettings API documentation to know exactly where is the settings file or
     *  call Application::getSettings().fileName()
     *
     *  The recommended method is to use one section for each Core area.
     *  Use the beginGroup("my area")/endGroup() to define specific settings area.
     *
     *  \note for each beginGroup you use, you HAVE TO use an endGroup(), otherwise the
     *  settings state integrity is not guaranteed!
     */
    static QSettings& getSettings();

    /** Overriden from QApplication:
     * Enters the main event loop and waits until exit() is called, then returns the value that was set to exit() (which is 0 if exit() is called via quit()).
     *
     * It is necessary to call this function to start event handling. The main event loop receives events from the window system and
     * dispatches these to the application widgets.
     *
     * Generally, no user interaction can take place before calling exec(). As a special case, modal widgets like QMessageBox can be used before calling exec(),
     * because modal widgets call exec() to start a local event loop.
     *
     * To make your application perform idle processing, i.e., executing a special function whenever there are no pending events, use a QTimer with 0 timeout.
     * More advanced idle processing schemes can be achieved using processEvents().
    */
    static int exec();

    /// @brief ask the user and if ok restart the application for the given reason
    static void restart(QString reason);

    /** Get the last used directory (e.g. the directory of the last opened document)
     */
    static const QDir getLastUsedDirectory();

    /// set (force) the last used directory
    static void setLastUsedDirectory(QDir);

    /** Add a document to the list of recent documents (e.g. when a document was opened)
     *  and update lastUsedDirectory
     */
    static void addRecentDocument(QString);

    /// Get the list of recent documents
    static const QList<QFileInfo> getRecentDocuments();

    /// get the maximal number of recent documents stored
    static const int getMaxRecentDocuments();

    ///@}

    /** @name Component instances management
     */
    ///@{

    /// load the filename and returns the corresponding top level Component (returns nullptr if an error occurs)
    /// @note this method opens the filename and created the associated TOP LEVEL component
    /// If you wish to open a subcomponent (not top level then), prefer directly calling its public constructor.
    /// @param fileName file that contains the component
    /// @param blockRefresh do not refresh the main window after closing the component
    static Component* open(const QString& fileName, bool blockRefresh = false);

    /** load a directory and returns the corresponding Component (returns nullptr if an error occurs)
     * @param dirName the name of the directory to open
     * @param pluginName the name of the plugin to use
     */
    static Component* openDirectory(const QString& dirName, const QString& pluginName);

    /** load a camitk file and its content into the application
     */
    static bool loadWorkspace(const QString& filepath);

    /** Close a Component: if it has been changed, ask the user for more information, then if everything is ok, delete it.
    *    @param component the Component to close.
    *    @param blockRefresh do not refresh the main window after closing the component
    *    @return true if the closing was made, false if the user cancelled the operation or a saving problem occurs
    */
    static bool close(Component* component, bool blockRefresh = false);

    /** save a component to its file (as given by component->getFileName()).
     *  \note the component's file name has to be set prior to call this method.
     *
     *  This method look for the proper loaded ComponentExtension, and call its save(Component*) method
     */
    static bool save(Component* component);

    /** save the current workspace to a .camitk file.
     *
     *  This method uses PersistenceManager to save the workspace
     */
    static bool saveWorkspace(const QString& filepath);

    /**
     * Get a unique name from the given name in the given componentList.
     * By default, it will check the given name against all current top level component names.
     *
     * For example getUniqueComponentName("Mesh", getTopLevelComponents()) may return "Mesh (3)"
     * if there is already a component name "Mesh" and "Mesh (2)"
     */
    static QString getUniqueComponentName(QString name, const ComponentList& components = getTopLevelComponents());

    /** get the current application wide list of instantiated top-level Components.
      * This is the public method (return a const, the top-level component list is private
      * and cannot be modified externally).
      */
    static const ComponentList& getTopLevelComponents();

    /** get the current application wide list of all Components.
      * This is the public method (return a const, the component list is private
      * and cannot be modified externally).
      */
    static const ComponentList& getAllComponents();

    /// does this Component still exist? (components can be deleted)
    static bool isAlive(Component*);

    /// does this Action still exist? (HotPlugAction can be unloaded)
    static bool isAlive(Action*);

    /// Return true if at least one of the opened components has been modified, false otherwise.
    static bool hasModified();

    ///@}

    ///
    /// @name Selection management
    ///
    ///@{
    /** get the currently selected Components.
      * This is the public method (return a const, the selected component list is private
      * and cannot be modified externally).
      */
    static const ComponentList& getSelectedComponents();

    /** clear all the selection, i.e call setSelected(false) for
      * all the previously selected components and clear the list.
      */
    static void clearSelectedComponents();
    ///@}

    /// @name Action instances management
    ///@{

    /// get a registered action given its name
    static Action* getAction(QString);

    /// get all the actions registered in the application (note: the returned ActionList is guaranteed to be sorted by action name and to contain no duplicates)
    static const ActionList getActions();

    /// get all the actions that can be applied on a given component (note: the returned ActionList is guaranteed to be sorted by action name and to contain no duplicates)
    static ActionList getActions(Component*);

    /// Get all the actions that can be applied on any components of the given list of components (note: the returned ActionList is guaranteed to be sorted by action name and to contain no duplicates)
    static ActionList getActions(ComponentList);

    /// get all the actions that of a given tag (note: the returned ActionList is guaranteed to be sorted by action name and to contain no duplicates)
    static ActionList getActions(ComponentList, QString);

    /** register all actions from the given ActionExtension
     *  @return the number of actions effectively registered (in case an action's name is already registered it won't be a second time)
     */
    static int registerAllActions(ActionExtension*);

    /** unregister all actions from the given ActionExtension
    *  @return the number of actions effectively unregistered
    */
    static int unregisterAllActions(ActionExtension*);

    /// set the currently triggered action
    /// This is used by Action::trigger(..) to refresh all the viewer (the viewers
    /// interested by the fact an action was triggered can then update what they need to)
    static void setTriggeredAction(Action* action);

    /// get the currently triggered action
    static Action* getTriggeredAction();
    ///@}

    /// @name Viewer management
    ///@{

    /// get the pointer to a registered viewer given its name
    static Viewer* getViewer(QString name);

    /// instantiate a new viewer of the given name and given class name (Viewer inheriting class).
    /// \note this method does not register the viewer automatically. Please call registerViewer(..) to add it
    /// to the list of registered viewers.
    static Viewer* getNewViewer(QString name, QString className);

    /// get all the viewers registered in the application (note: the returned ViewerList is guaranteed to be sorted by viewer name and to not contain any duplicate)
    static const ViewerList getViewers();

    /// get the viewers that can manage/display the given component (note: the returned ViewerList is guaranteed to be sorted by viewer name and to contain no duplicates)
    static const ViewerList getViewers(Component*);

    /// register a viewer in the viewer list (therefore allowing it to be refreshed by the main window automatically
    static bool registerViewer(Viewer*);

    /** register all viewers from the given ViewerExtension
    *  @return the number of viewers effectively registered (in case a viewer's name is already registered
    * by another viewer extension, it won't be registered a second time)
    */
    static int registerAllViewers(ViewerExtension*);

    /** unregister all viewers from the given ViewerExtension
    *  @return the number of viewer effectively unregistered
    */
    static int unregisterAllViewers(ViewerExtension*);
    ///@}

    /** @name Main Window management
     */
    ///@{

    /** set the main window.
     * You need to call this method in order to use a customized CamiTK MainWindow instead
     * of the default one. This method has to be called <b>after</b> init().
     *
     * It allows you to set the main window using your application extension instance.
     *
     * \note Application takes ownership of the MainWindow pointer and deletes it at the appropriate time.
     *
     * @param mw The instance of main window you want to use for your application (if nullptr a new instance of the MainWindow class is created)
     * @param redirect Start redirection to the application console
     */
    void setMainWindow(MainWindow* mw, bool redirect = true);

    /// get the main window
    /// \note if there is no MainWindow when this method is first called,
    /// then this method makes sure there is a MainWindow by and force the creation of
    /// a default MainWindow (direct instance of the MainWindow class)
    static MainWindow* getMainWindow();

    /// refresh the main window (this will call the refresh method of all viewers)
    static void refresh();

    /** Set a message to the status bar.
     *  By default there is no timeout (default), i.e. the given message remains displayed until this method is
     *  called again (or the status bar is cleared otherwise).
     * @param msg the message to display in the status bar.
     * @param timeout number of milli-seconds (timeout) before the status bar is cleared (default = 0, i.e. until next call)
     */
    static void showStatusBarMessage(QString msg, int timeout = 0);

    /** Resets the progress bar if it exists.
     *  See example of use for ProgressFunction for more detailed explanation.
     */
    static void resetProgressBar();

    /** set the progress bar value, value should be in [0..100].
     * Attempting to change the current value to one outside the minimum-maximum range has no effect on the current value.
     *
     * Consider using vtkProgressFunction()
     */
    static void setProgressBarValue(int);

    /** Observer function to be called by vtkFilters and to update progress bar
     * Example of use:
     * \code
     * Application::showStatusBarMessage("Applying my vtk filter");
     * Application::resetProgressBar();
     * vtkSmartPointer<vtkCallbackCommand> progressCallback = vtkSmartPointer<vtkCallbackCommand>::New();
     * progressCallback->SetCallback(&Application::vtkProgressFunction);
     * myVtkFilter->AddObserver(vtkCommand::ProgressEvent, progressCallback);
     * Application::resetProgressBar();
     * Application::showStatusBarMessage("");
     * \endcode
     */
    static void vtkProgressFunction(vtkObject* caller, long unsigned int, void*, void*);
    ///@}

    ///@name Actions pipeline history
    ///@{
    /** Add the history item to the application history.
     * The item is added to the history stack of actions used in a pipeline
     * @see removeLastHistoryItem() To pop back an action from the history use
     * @param item the item to add to the history
     */
    static void addHistoryItem(HistoryItem item);

    /** Remove the last pushed actions in the history of the current pipeline.
     * @see addHistoryItem() To push back the item use
     */
    static HistoryItem removeLastHistoryItem();

    /**
     * Save the history as an SCXML file, stored using @see addHistoryItem() method.
     * This file can be interpreted by the camitk actionstatemachine executable
     */
    static void saveHistoryAsSCXML();

    ///@}

    /// @name Application resources management
    ///@{
    /**
    * Returns for the current CamiTK application, the selected language (stored in its .ini configuration file)
    */
    static QString getSelectedLanguage();
    ///@}

    /// @name Property management
    ///@{
    /**
     * Get the property object of the application.
     * Note that every time a property is changed, the Application is notified, update its settings and take the
     * new property values into account.
     * @see eventFilter()
     */
    static PropertyObject* getPropertyObject();
    ///@}


    /// @name Friend class
    /// @{
    /// class Component is a friend class: only the class Component can access to the private members addComponent(..) and removeComponent(..)
    friend class Component;
    friend class PersistenceManager;
    /// @}

private slots:
    void quitting();

private:
    /// name of the CamiTK application (used to differentiate settings between CamiTK applications)
    static QString name;

    /// the main window of the CamiTK application
    static MainWindow* mainWindow;

    /// the splash screen (might not be instantiated)
    static SplashScreen* splashScreen;

    /// argc given from command line
    static int argc;

    /// argv given from command line
    static char** argv;

    static Action* currentAction;

    /// @name Recent document management
    ///@{
    /// list of all the remembered recent documents (last opened is last inserted!)
    static QList<QFileInfo> recentDocuments;

    /// last used directory
    static QDir lastUsedDirectory;

    /// max number of recent document (default 10)
    static int maxRecentDocuments;

    /// Provide internationalization support for text output.
    static QTranslator* translator;
    ///@}

    /// @name Components management
    ///@{
    /** get the current application wide list of instantiated top-level Components.
    * This is the private (intern) method.
    * The top-level component list is updated by the Component class top-level constructor.
    * This method follows the "construct on first use" idiom/design-pattern.
    * It therefore avoids the infamous "static initialization order fiasco",
    * see http://www.parashift.com/c++-faq/ctors.html
    */
    static ComponentList& getTopLevelComponentList();

    /** get the current application wide list of all Components.
      * This is the private (intern) method.
      * This holds all the components at any level (full component list), top-level or under.
      * This method follows the "construct on first use" idiom/design-pattern.
      * It therefore avoids the infamous "static initialization order fiasco",
      * see http://www.parashift.com/c++-faq/ctors.html
      */
    static ComponentList& getAllComponentList();

    /** get the currently selected Components.
      * This is the private (intern) method.
      * the current selection (selected Components can at any level).
      * This method follows the "construct on first use" idiom/design-pattern.
      * It therefore avoids the infamous "static initialization order fiasco",
      * see http://www.parashift.com/c++-faq/ctors.html
      */
    static ComponentList& getSelectedComponentList();

    /** insert/remove one specific Component to the selection (at the end).
     *  The selected component list is a QList, because the selection order is important (QList
     *  is order, QSet is not).
     *  But it does not make any sense to have two times the same Component instance
     *  so if isSelected is true we have to "manually" check that it is not already in the list
     *
     * \note do not call this method from anywhere BUT the Component setSelected method;
     * Component is a friend class.
     *
     * @param component the component to insert/remove from the selection
     * @param isSelected if true then insert if not already in the selection, otherwise remove
     */
    static void setSelected(Component* component, bool isSelected);

    /** register a new component either in the full component list, or in the full list
      * and in the top-level list.
      *
      * \note do not call this method from anywhere BUT the Component class destructor;
      * Component is a friend class.
      */
    static void addComponent(Component*);

    /** unregister a Component.
      * This method remove top-level component and other level component
      *
      * \note do not call this method from anywhere BUT the Component class destructor
      * Component is a friend class.
      */
    static void removeComponent(Component*);

    ///@}

    ///@name Application settings
    ///@{

    /// global settings for CamiTK application
    static QSettings settings;

    /// Apply all the property values to update the model (e.g., use the logLevel to modify the actual log level of the application logger)
    static void applyPropertyValues();

    /// Apply main window specific settings once it is set or instantiated (e.g. stylesheet)
    static void applyMainWindowPropertyValues();

    ///@}

    ///@name Actions pipeline history
    ///@{
    /** get the history of actions stored.
     *
     * This methods returns the singleton stack of actions stored in a pipeline as
     * their are applied during the execution of the application.
     *
     * This is the private (intern) method.
     * This history is updated (push(), pop()) by addHistoryItem() and removeHistoryItem()
     * This method follows the "construct on first use" idiom/design-pattern.
     * It therefore avoids the infamous "static initialization order fiasco",
     * see http://www.parashift.com/c++-faq/ctors.html
     */
    static QStack<HistoryItem>& getHistory();

    /// @}

    /// @name Actions management
    ///@{
    /** As actions are mainly sort/compared/process by name, an internal QMap
     * associates all the contains all the registered actions with their name (key)
     * This is the private (intern) method.
     *
     * The action extension map is updated by loadExtension, unloadExtension and autoloadExtensions.
     *
     * This method follows the "construct on first use" idiom/design-pattern.
     * It therefore avoids the infamous "static initialization order fiasco",
     * see http://www.parashift.com/c++-faq/ctors.html
     */
    static QMap<QString, Action*>& getActionMap();

    /// sort an ActionSet by action's name
    static ActionList sort(ActionSet);
    ///@}

    /// @name viewer management
    ///@{
    /** As viewers are mainly sort/compared/process by name, an internal QMap
     * associates all the registered viewers with their name (key).
     * This is the private (intern) method.
     *
     * This is the private (intern) method.
     *
     * The viewer extension map is updated by loadExtension, unloadExtension and autoloadExtensions.
     *
     * This method follows the "construct on first use" idiom/design-pattern.
     * It therefore avoids the infamous "static initialization order fiasco",
     * see http://www.parashift.com/c++-faq/ctors.html
     */
    static QMap<QString, Viewer*>& getViewerMap();

    /// return the viewer extension that manages the given viewer
    static ViewerExtension* getViewerExtension(Viewer* viewer);

    /// sort an ViewerSet by viewer's name
    static ViewerList sort(ViewerSet);
    ///@}

    /// @name Property management
    ///@{
    /**
     * Create all the application properties and add them to the qApp
     */
    static void createProperties();

    /**
     * A simple QObject that holds the CamiTK level properties of the application.
     *
     * @note
     * Use the accessor getPropertyObject() to access this object
     *
     * @see
     * PropertyObject
     */
    static PropertyObject* propertyObject;
    ///@}

    /// Init the application resources by loading the language associated .qml file
    static void initResources();

protected:
    /**
     * Event filter of this class instance to watch its properties instances.
     * Each time a property has dynamically changed, this method is called.
     */
    bool eventFilter(QObject* object, QEvent* event) override;
};



}

#endif // CAMITKAPPLICATION_H