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
|