Vous avez reçu un message "Your GitLab account has been locked ..." ? Pas d'inquiétude : lisez cet article https://docs.gricad-pages.univ-grenoble-alpes.fr/help/unlock/

ImpMainWindow.cpp 26.9 KB
Newer Older
1
/*****************************************************************************
2
3
4
 * $CAMITK_LICENCE_BEGIN$
 *
 * CamiTK - Computer Assisted Medical Intervention ToolKit
5
 * (c) 2001-2018 Univ. Grenoble Alpes, CNRS, TIMC-IMAG UMR 5525 (GMCAO)
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
 *
 * 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$
 ****************************************************************************/

// -- Application Imp stuff
#include "ImpMainWindow.h"

// -- Core stuff
#include <Application.h>
#include <ExtensionManager.h>
#include <MedicalImageViewer.h>
Jean-Loup HABERBUSCH's avatar
Jean-Loup HABERBUSCH committed
33
#include <ActionViewer.h>
34
35
36
#include <SettingsDialog.h>
#include <Component.h>
#include <Action.h>
37
38
#include <Core.h> // for getActionDirectories()
#include <Explorer.h>
39
#include <FrameExplorer.h>
40
#include <PropertyExplorer.h>
41
42
#include <Property.h>
#include <PropertyObject.h>
43
#include <Log.h>
44

45
using namespace camitk;
46
47
48
49
50
51
52
53
54
55
56

// -- QT stuff
#include <QAction>
#include <QFileDialog>
#include <QPixmap>
#include <QWhatsThis>
#include <QMenu>
#include <QToolBar>
#include <QMenuBar>
#include <QStatusBar>
#include <QDockWidget>
57
#include <QTranslator>
58
59

// ------------- constructor -----------------
60
ImpMainWindow::ImpMainWindow() : MainWindow("imp") {
61
62
63
    // set the specific actions state machine icon
    setWindowIcon(QPixmap(":/applicationIcon"));

Jean-Loup Haberbusch's avatar
Jean-Loup Haberbusch committed
64
65
    fileOpenDataDirectoryMenu = nullptr;

66
67
68
69
70
71
72
73
74
75
    // init all other GUI
    initActions();
    initMenuBar();
    initToolBar();

    // initialize architecture
    updateActionStates();

    // now add the different viewers
    setCentralViewer(MedicalImageViewer::getInstance());
76
    addDockViewer(Qt::LeftDockWidgetArea, Explorer::getInstance());
77
    addDockViewer(Qt::LeftDockWidgetArea, FrameExplorer::getInstance());
78
    addDockViewer(Qt::LeftDockWidgetArea, PropertyExplorer::getInstance());
79
    addDockViewer(Qt::RightDockWidgetArea, ActionViewer::getInstance());
80
81
82
83

    //Merge Explorer and FrameExplorer viewers in one layout
    QDockWidget* dockWidgetExplorer = dockWidgetMap.value(Explorer::getInstance(), NULL);
    QDockWidget* dockWidgetFrameExplorer = dockWidgetMap.value(FrameExplorer::getInstance(), NULL);
84
    if (dockWidgetExplorer && dockWidgetFrameExplorer) {
85
86
        tabifyDockWidget(dockWidgetExplorer, dockWidgetFrameExplorer);
        dockWidgetExplorer->raise();
87
88
    }

89
    showDockViewer(ActionViewer::getInstance(), false);
90
    ActionViewer::getInstance()->setSearchPanelVisible(true);
91
92
93
    showStatusBar(true);
}

94
// ------------- destructor -----------------
95
96
97
98
99
100
101
102
103
104
105
ImpMainWindow::~ImpMainWindow() {
}

// ------------- aboutToShow -----------------
void ImpMainWindow::aboutToShow() {
    MainWindow::aboutToShow(); // calls init settings

    // now that initSettings was called, populate the recent document menu
    updateRecentDocumentsMenu();

    // check autoload for files and load if needed
106
107
    if (Application::getPropertyObject()->getPropertyValue("Auto Load Last Opened Component").toBool() && Application::getRecentDocuments().size() > 0) {
        Application::open(Application::getRecentDocuments().last().absoluteFilePath());
108
109
110
111
112
113
114
115
116
    }
}

// ------------- refresh -----------------
void ImpMainWindow::refresh() {
    MainWindow::refresh();

    // update all the action states
    updateActionStates();
117

118
119
120
121
122
    // update menu
    updateRecentDocumentsMenu();
}

// ------------- addDockViewer -----------------
123
void ImpMainWindow::addDockViewer(Qt::DockWidgetArea dockingArea, Viewer* theViewer) {
124
125
126
127
128
129
    MainWindow::addDockViewer(dockingArea, theViewer);
    // update the menu
    updateViewMenu();
}

// ------------- setCentralViewer -----------------
130
void ImpMainWindow::setCentralViewer(Viewer* theViewer) {
131
132
133
134
135
136
137
    MainWindow::setCentralViewer(theViewer);
    // update the menu
    updateViewMenu();
}

// ------------- initActions -----------------
void ImpMainWindow::initActions() {
138
    //-- Check for action applications
139
    ActionExtension* applicationActionExtension = NULL;
140
    QListIterator<ActionExtension*> it(ExtensionManager::getActionExtensionsList());
141
142
    while (it.hasNext() && applicationActionExtension == NULL) {
        ActionExtension* current = it.next();
143
        if (current->getName() == "Application Level Actions") {
144
            applicationActionExtension = current;
145
        }
146
    }
147
    if (applicationActionExtension == NULL) {
148
        CAMITK_ERROR(tr("Application error: the \"Application Level Actions\" extension is required by this application but could not be found\nIn any of the following extension directories:\n - %1\nPlease check your CamiTK configuration and/or installation using \"camitk-config --config\"").arg(Core::getActionDirectories().join("\n - ")))
149
150
        exit(EXIT_FAILURE);
    }
151

152
153
    //--- actions of the File menu
    // get the CamiTK actions
154
    fileOpen = Application::getAction("Open")->getQAction();
155
156
157
158
159
160
161
    fileClose = Application::getAction("Close")->getQAction();
    fileCloseAll = Application::getAction("Close All")->getQAction();
    fileSave = Application::getAction("Save")->getQAction();
    fileSaveAs = Application::getAction("Save As")->getQAction();
    fileSaveAll = Application::getAction("Save All")->getQAction();
    fileQuit = Application::getAction("Quit")->getQAction();

162
163
164
    recentDocumentSeparator = new QAction(tr("Recent Documents"), this);
    recentDocumentSeparator->setSeparator(true);
    recentDocumentSeparator->setVisible(false);
165

166
167
168
169
    for (int i = 0; i < Application::getMaxRecentDocuments(); i++) {
        recentDocumentActions.append(new QAction(this));
        recentDocumentActions.last()->setVisible(false);
        connect(recentDocumentActions.last(), SIGNAL(triggered()), this, SLOT(openRecentDocuments()));
170
171
172
173
174
175
    }

    //--- actions of the Edit menu
    editClearSelection = Application::getAction("Clear Selection")->getQAction();

    // settings
176
177
178
179
180
    editApplicationSettings = new QAction(tr("&Preferences..."), this);
    editApplicationSettings->setShortcut(tr("Ctrl+P"));
    editApplicationSettings->setStatusTip(tr("Edit the preferences"));
    editApplicationSettings->setWhatsThis(tr("Preferences\n\nEdit the settings and preferences of imp"));
    connect(editApplicationSettings, SIGNAL(triggered()), this, SLOT(editSettings()));
181

182
    // save history as SCXML
183
    saveHistory = new QAction(tr("&Save History"), this);
184
185
186
    saveHistory->setStatusTip(tr("Save the history of actions processed as an SCXML file."));
    saveHistory->setWhatsThis(tr("Save the history of actions processed as an SCXML file."));
    connect(saveHistory, SIGNAL(triggered()), this, SLOT(saveHistoryAsSCXML()));
187
188

    //--- actions of the View menu
189
190
191
192
193
194
    viewMenuBar = new QAction(tr("Menu bar"), this);
    viewMenuBar->setCheckable(true);
    viewMenuBar->setChecked(true);
    viewMenuBar->setStatusTip(tr("Hide/show the menu bar (Ctrl-M to show again)."));
    viewMenuBar->setWhatsThis(tr("Hide/show the menu bar (Ctrl-M to show again)."));
    viewMenuBar->setShortcut(tr("Ctrl+M"));
195
196
    // global shortcut, NOTE: the action should also be added as an ImpMainWindow action, otherwise the shortcut will not work when
    // the menu bar is hidden! (see initMenuBar() method)
197
198
    viewMenuBar->setShortcutContext(Qt::ApplicationShortcut);
    connect(viewMenuBar, SIGNAL(triggered(bool)), this, SLOT(showMenuBar(bool)));
199
200
201
202
203
204
    // NOTE: viewMenuBar can be used to hide the menu bar, if the menu bar is not visible,
    // since Qt4, it does not receive any event (and thus there is no way to set the menu
    // visible again! Which is quite annoying).
    // To prevent this, the viewMenuBar action has to be added to the QMainWindow as well
    // This should be done everytime the shortcut context is set
    // to Qt::ApplicationShortcut using setShortcutContext(Qt::ApplicationShortcut);
205
    this->addAction(viewMenuBar);
206

207
208
209
210
211
212
    viewStatusBar = new QAction(tr("Status bar"), this);
    viewStatusBar->setCheckable(true);
    viewStatusBar->setChecked(true);
    viewStatusBar->setStatusTip(tr("Hide/show the status bar."));
    viewStatusBar->setWhatsThis(tr("Hide/show the status bar."));
    connect(viewStatusBar, SIGNAL(toggled(bool)), this, SLOT(showStatusBar(bool)));
213

214
215
    viewResetWindows = new QAction(tr("Reset Windows"), this);
    viewResetWindows->setStatusTip(tr("Reset all windows in the initial state"));
216
    connect(viewResetWindows, SIGNAL(triggered()), this, SLOT(resetWindows()));
217
218

    //--- actions of the Help menu
219
220
    helpAboutApp = Application::getAction("About...")->getQAction();
    helpShowConsole = Application::getAction("Toggle Log Console")->getQAction();
221
    changeLanguage = Application::getAction("Change Language")->getQAction();
222
223
224
225
226
227
228

}

//**************************************************************************

void ImpMainWindow::initMenuBar() {
    // -- file
229
230
    fileMenu = new QMenu(tr("&File"));
    fileMenu->addAction(fileOpen);
231

Jean-Loup Haberbusch's avatar
Jean-Loup Haberbusch committed
232
    openDataDirectoryMenuBuilder();
233

234
235
    fileMenu->addAction(fileClose);
    fileMenu->addAction(fileCloseAll);
236
    fileMenu->addSeparator();
237
238
239
    fileMenu->addAction(fileSave);
    fileMenu->addAction(fileSaveAs);
    fileMenu->addAction(fileSaveAll);
240
241
    fileMenu->addSeparator();
    fileMenu->addAction(saveHistory);
242
    fileMenu->addAction(recentDocumentSeparator);
243

244
245
    foreach (QAction* recentAction, recentDocumentActions) {
        fileMenu->addAction(recentAction);
246
247
248
249
    }

    fileMenu->addSeparator();
    fileMenu->addSeparator();
250
    fileMenu->addAction(fileQuit);
251

252
253

    // -- edit
254
255
    QMenu* editMenu = new QMenu(tr("&Edit"));
    editMenu->addAction(editClearSelection);
256
    editMenu->addSeparator();
257
    editMenu->addAction(editApplicationSettings);
258

259
260

    // -- View menu
261
    viewMenu = new QMenu(tr("&View"));
262
263

    // -- help
264
265
266
267
268
269
    QMenu* helpMenu = new QMenu(tr("&Help"));
    QAction* whatsThisAction = QWhatsThis::createAction(this);
    whatsThisAction->setStatusTip(tr("What's This and Viewer Keyboard Shortcuts."));
    whatsThisAction->setWhatsThis(tr("What's This and Viewer Keyboard Shortcuts."));
    helpMenu->addAction(whatsThisAction);
    this->addAction(whatsThisAction);
270
    helpMenu->addSeparator();
271
    helpMenu->addAction(helpShowConsole);
272
273
    helpMenu->addSeparator();
    helpMenu->addAction(changeLanguage);
274
    helpMenu->addSeparator();
275
    helpMenu->addAction(helpAboutApp);
276
277

    // -- action
278
    actionMenu = new QMenu(tr("&Actions"));
279
280

    // -- add everything in the menu bar
281
282
283
284
    menuBar()->addMenu(fileMenu);
    menuBar()->addMenu(editMenu);
    menuBar()->addMenu(viewMenu);
    menuBar()->addMenu(actionMenu);
285
    menuBar()->addSeparator();
286
    menuBar()->addMenu(helpMenu);
287
288
289
290
291

}

//--------------------------initToolBar-------------------------------
void ImpMainWindow::initToolBar() {
292
    mainToolbar = addToolBar("Main Toolbar");
293
    // ensure object name is set for saving the state
294
    mainToolbar->setObjectName("ImpMainWindow Main Toolbar");
295
296
297
    mainToolbar->addAction(fileOpen);
    mainToolbar->addAction(fileSave);
    mainToolbar->addAction(QWhatsThis::createAction(this));
298
299
300
301
302
}

// ------------------------ updateActionStates ----------------------------
void ImpMainWindow::updateActionStates() {
    unsigned int nrOfSelectedItems = Application::getSelectedComponents().size();
303
    bool selectedIsTopLevel = (nrOfSelectedItems > 0 && Application::getSelectedComponents().last()->isTopLevel());
304
305
306
    unsigned int nrOfComponents = Application::getTopLevelComponents().size();

    //-- update file menu
307
308
309
310
311
    fileCloseAll->setEnabled(nrOfComponents > 0);
    fileSaveAll->setEnabled(nrOfComponents > 0);
    fileSave->setEnabled(selectedIsTopLevel && Application::getSelectedComponents().first()->getTopLevelComponent()->getModified());    // save available only if needed
    fileSaveAs->setEnabled(nrOfSelectedItems > 0);     // no need to be top level to be saved as in a compatible format
    fileClose->setEnabled(selectedIsTopLevel);
312

313
    //-- update edit menu
314
    editClearSelection->setEnabled(nrOfSelectedItems > 0);
315
316
317

    //-- update the action menu
    actionMenu->clear();
318
    actionMenu->setEnabled(false);
319

320
    if (nrOfSelectedItems > 0) {
321
        // use the selection to populate the menu
322
        Component* comp = Application::getSelectedComponents().last();
323
324

        if (comp) {
325
            QMenu* compActionsMenu = comp->getActionMenu();
326
327
328

            if (compActionsMenu) {
                actionMenu->addActions(compActionsMenu->actions());
329
                actionMenu->setEnabled(true);
330
331
            }
        }
332
333
    }
    else {
334
335
        // add all generic actions
        ActionList allActions = Application::getActions(NULL);
336
        foreach (Action* action, allActions) {
337
            actionMenu->addAction(action->getQAction());
338
            actionMenu->setEnabled(true);
339
340
341
342
        }
    }

    // update the application window title
343
    if (nrOfSelectedItems > 0) {
344
        setWindowSubtitle(Application::getSelectedComponents().last()->getFileName() + ((Application::getSelectedComponents().last()->getTopLevelComponent()->getModified()) ? "*" : ""));
345
346
    }
    else {
347
        setWindowSubtitle("");
348
    }
349
350
351
}

// ------------- showToolbar -----------------
352
353
void ImpMainWindow::showToolbar(bool b) {
    mainToolbar->setVisible(b);
354
355
356
}

// ------------- showMenuBar -----------------
357
void ImpMainWindow::showMenuBar(bool b) {
358
    if (!b) {
359
360
361
362
363
364
365
366
367
368
369
370
        // warn the user first
        CAMITK_WARNING(tr("Hide menu: the menu is going to be hidden. There is only one way to make it reappear: you need to press CTRL+M again."))
        viewMenuBar->blockSignals(true);
        viewMenuBar->setChecked(true);
        viewMenuBar->blockSignals(false);
    }
    else {
        menuBar()->setVisible(b);
        viewMenuBar->blockSignals(true);
        viewMenuBar->setChecked(b);
        viewMenuBar->blockSignals(false);
        showStatusBar(b);
371
372
373
374
375
376
377
378
379
380
    }
}

// ------------- showStatusBar -----------------
void ImpMainWindow::showStatusBar(bool b) {
    MainWindow::showStatusBar(b);
}

// ------------------------ resetWindows ----------------------------
void ImpMainWindow::resetWindows() {
381
    for (QMap<Viewer*, QDockWidget*>::iterator it = dockWidgetMap.begin(); it != dockWidgetMap.end(); it++) {
382
        if (it.value()->widget() == Explorer::getInstance()->getWidget(NULL)) {
383
384
385
            removeDockWidget(it.value());
            addDockWidget(Qt::LeftDockWidgetArea, it.value());
            it.value()->show();
386
        }
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
        else
            if (it.value()->widget() == FrameExplorer::getInstance()->getWidget(NULL)) {
                removeDockWidget(it.value());
                addDockWidget(Qt::LeftDockWidgetArea, it.value());
                it.value()->show();
            }
            else
                if (it.value()->widget() == PropertyExplorer::getInstance()->getWidget()) {
                    removeDockWidget(it.value());
                    addDockWidget(Qt::LeftDockWidgetArea, it.value());
                    it.value()->show();
                }
                else
                    if (it.value()->widget() == ActionViewer::getInstance()->getWidget()) {
                        removeDockWidget(it.value());
                        addDockWidget(Qt::RightDockWidgetArea, it.value());
                        it.value()->show();
                    }
405
    }
406
407
408
    //Merge Explorer and FrameExplorer viewers in one layout
    QDockWidget* dockWidgetExplorer = dockWidgetMap.value(Explorer::getInstance(), NULL);
    QDockWidget* dockWidgetFrameExplorer = dockWidgetMap.value(FrameExplorer::getInstance(), NULL);
409
    if (dockWidgetExplorer && dockWidgetFrameExplorer) {
410
411
        tabifyDockWidget(dockWidgetExplorer, dockWidgetFrameExplorer);
        dockWidgetExplorer->raise();
412
    }
413
414
415
416
417
418

    showStatusBar(true);
    showMenuBar(true);
    showToolbar(true);

    // reset geometry to default
419
420
    resize(1024, 768);
    move(0, 0);
421
422
423
}

// ------------- openDataDirectory -----------------
Jean-Loup Haberbusch's avatar
Jean-Loup Haberbusch committed
424
void ImpMainWindow::openDataDirectory(QString plugin) {
425
    QString pluginName = plugin;
426

427
    statusBar()->showMessage(tr(QString("Opening " + pluginName + " directory...").toStdString().c_str()));
428
429

    // Open more than one file
430
    QString dir = QFileDialog::getExistingDirectory(this, tr(QString("Choose a " + pluginName + " directory ").toStdString().c_str()), Application::getLastUsedDirectory().absolutePath());
431

432
    if (!dir.isEmpty()) {
433
        // set waiting cursor
434
        QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
435

436
        // instantiate a Component to represent the data contained in the directory
437
        Component* comp = Application::openDirectory(dir, pluginName);
438

439
440
        if (!comp) {
            statusBar()->showMessage(tr("Error loading directory:") + dir);
441
442
        }
        else {
443
            // TODO add to recent document and manage directories as recent documents
444
            statusBar()->showMessage(tr(QString("Directory " + dir + " successfully loaded").toStdString().c_str()));
445
446
447
448
449
450
451
452
453
454
455
456
457

            // refresh all
            refresh();
        }

        // restore the normal cursor
        QApplication::restoreOverrideCursor();
        getProgressBar()->setValue(0.0);
    }
}

// ------------- updateViewMenu -----------------
void ImpMainWindow::updateViewMenu() {
458
459
460
461
    // From Qt documentation:
    // "Removes all the menu's actions. Actions owned by the menu and not shown in any other widget are deleted"
    // I.e., the central viewer toggle action are own by viewMenu (they are created and used here), they will
    // therefore be no memory leak
462
463
464
    viewMenu->clear();

    // insert viewers menu
465
    foreach (Viewer* v, viewers) {
466
        QMenu* viewerMenu = v->getMenu();
467

468
469
        if (viewerMenu) {
            viewMenu->addMenu(viewerMenu);
470
        }
471
472
    }

473
474
475
    // change the central viewer if there is more than one viewer in the central area
    if (qobject_cast<QStackedWidget*>(centralWidget())->count() > 1) {
        viewMenu->addSeparator()->setText(tr("Toggle Central Viewers"));
Emmanuel Promayon's avatar
Emmanuel Promayon committed
476

Emmanuel Promayon's avatar
Emmanuel Promayon committed
477
        // add a toggle action for each widget stacked inside the central widget
478
479
        for (int i = 0; i < qobject_cast<QStackedWidget*>(centralWidget())->count(); i++) {
            QWidget* cWidget = qobject_cast<QStackedWidget*>(centralWidget())->widget(i);
Emmanuel Promayon's avatar
Emmanuel Promayon committed
480
481
482
            // Get the viewer associated with the widget in the central area
            // As there is no map from widget to viewer, we need to find the viewer that
            // has the given corresponding widget.
483
484
485
486
487
488
489
490
            // Beware that getWidget(..) requires a parent and as the widget was setup inside centralWidget()
            // it was reparented to centralWidget() → use getWidget(centralWidget()) and not getWidget(this)
            // in order not to modify the central widget parenting
            auto it = std::find_if(viewers.begin(), viewers.end(), [&](Viewer * v) {
                return v->getWidget(centralWidget()) == cWidget;
            });
            Viewer* cViewer = (*it);
            // viewerAction is own by viewMenu, viewMenu->clear() will delete it
Emmanuel Promayon's avatar
Emmanuel Promayon committed
491
            QAction* viewerAction = viewMenu->addAction(cViewer->objectName());
492
493
494
495
496
497
            viewerAction->setCheckable(true);
            viewerAction->setChecked(cViewer == centralViewer);
            QString tipString = "Hide/show the " + cViewer->objectName() + " central viewer";
            viewerAction->setStatusTip(tr(tipString.toStdString().c_str()));
            viewerAction->setWhatsThis(tr(tipString.toStdString().c_str()));
            // add the toggle action slot using C++11 lambda so that everything is contained inside viewMenu
Emmanuel Promayon's avatar
Emmanuel Promayon committed
498
499
            connect(viewerAction, &QAction::toggled, [ = ](bool) {
                setCentralViewer(cViewer);
500
501
            });
        }
502
503
    }

504
    // insert viewers on/off actions
505
    viewMenu->addSeparator()->setText(tr("Toggle Viewers"));
506
507
    viewMenu->addAction(viewResetWindows);

508
509
    for (QMap<Viewer*, QDockWidget*>::iterator it = dockWidgetMap.begin(); it != dockWidgetMap.end(); it++) {
        viewMenu->addAction(it.value()->toggleViewAction());
510
    }
511
512

    // insert generic on/off actions
513
514
515
516
    viewMenu->addSeparator()->setText(tr("Other Toggle"));
    viewMenu->addAction(viewMenuBar);
    viewMenu->addAction(viewStatusBar);
    viewMenu->addAction(mainToolbar->toggleViewAction());
517
518
519
520
}

// ------------------------------ slotEditSettings -------------------------------
void ImpMainWindow::editSettings() {
521
    statusBar()->showMessage(tr("Edit application preferences..."));
522
523
524
525
    // ask the ImpMainWindowDoc to show the settings

    // create the dialog
    SettingsDialog settingsDialog;
526

527
528
    // show the properties of the CamiTK application
    settingsDialog.editSettings(dynamic_cast<Application*>(qApp)->getPropertyObject());
529

530
    // edit all viewers that have properties
531
    foreach (Viewer* v, viewers) {
532
        QObject* viewerProp = v->getPropertyObject();
533

534
535
        if (viewerProp) {
            settingsDialog.editSettings(viewerProp);
536
        }
537
538
539
    }

    // execute the dialog
540
    if (settingsDialog.exec() == QDialog::Accepted) {
541
542
543
        // update recent docs
        updateRecentDocumentsMenu();
    }
544
545

    // check if there are anything to change in the data directory menu (for data directory manager)
Jean-Loup Haberbusch's avatar
Jean-Loup Haberbusch committed
546
    ImpMainWindow::openDataDirectoryMenuBuilder();
547
548
549
}

// ------------- setApplicationConsole -----------------
550
void ImpMainWindow::redirectToConsole(bool visible) {
551
    MainWindow::redirectToConsole(visible);
552
    helpShowConsole->setEnabled(visible);
553
554
555
556
557
}


// ------------------------------ slotRecentDocuments -------------------------------
void ImpMainWindow::openRecentDocuments() {
558
    QAction* action = qobject_cast<QAction*> (sender());
559

560
    if (action) {
561
        // check if this recent document still exists!
562
        if (QFileInfo(action->data().toString()).exists()) {
563
564
565
            Action* openFileAction = Application::getAction("Open File");
            openFileAction->setProperty("File Name", action->data().toString()); // avoid opening a dialog, as the file path is already know
            openFileAction->applyAndRegister();
566
        }
567
        else {
568
            CAMITK_WARNING(tr("Open Recent Documents: document \"%1\" does not exist anymore.").arg(action->data().toString()))
569
        }
570
    }
571

572
573
574
575
}

// ------------------------------ updateRecentDocumentsMenu -------------------------------
void ImpMainWindow::updateRecentDocumentsMenu() {
576
    const QList<QFileInfo>& recentDocuments = Application::getRecentDocuments();
577
    recentDocumentSeparator->setVisible(recentDocuments.size() > 0);
578
579
580

    int id = 0;

581
582
583
584
585
586
587
    for (int i = recentDocuments.size() - 1; i >= 0 && id < Application::getMaxRecentDocuments(); i--, id++) {
        QString text = tr("&%1 %2").arg(id + 1).arg(recentDocuments[i].fileName());
        recentDocumentActions[id]->setText(text);
        recentDocumentActions[id]->setData(recentDocuments[i].absoluteFilePath());
        recentDocumentActions[id]->setStatusTip(recentDocuments[i].absoluteFilePath());
        recentDocumentActions[id]->setWhatsThis(recentDocuments[i].absoluteFilePath());
        recentDocumentActions[id]->setVisible(true);
588
589
    }

590
591
    for (; id < recentDocumentActions.size(); id++) {
        recentDocumentActions[id]->setVisible(false);
592
593
594
    }
}

595
// ------------------------------ saveHistoryAsSCXML -------------------------------
596
void ImpMainWindow::saveHistoryAsSCXML() {
597
598
599
    Application::saveHistoryAsSXML();
}

600
// ------------------------- openDataDirectoryMenuBuilder ---------------------------
Jean-Loup Haberbusch's avatar
Jean-Loup Haberbusch committed
601
void ImpMainWindow::openDataDirectoryMenuBuilder() {
602
    QStringList dirExt = ExtensionManager::getDataDirectoryExtNames();
603
604

    if (dirExt.size() > 1) {
Emmanuel Promayon's avatar
Emmanuel Promayon committed
605
        if (fileOpenDataDirectoryMenu == nullptr) {
606
            fileOpenDataDirectoryMenu = new QMenu("Open Data Directory");
Jean-Loup Haberbusch's avatar
Jean-Loup Haberbusch committed
607
            fileMenu->addMenu(fileOpenDataDirectoryMenu);
Emmanuel Promayon's avatar
Emmanuel Promayon committed
608
609
610
        }
        else {
            disconnect(fileOpenDataDirectoryMenu, 0, 0, 0);
611
612
            fileOpenDataDirectoryMenu->clear();
        }
613
        fileOpenDataDirectoryMenu->setIcon(QPixmap(":/fileOpen"));
Emmanuel Promayon's avatar
Emmanuel Promayon committed
614
        for (QString dirExtName : dirExt) {
615
616
617
            QAction* openDirectory = new QAction(dirExtName, this);
            openDirectory->setStatusTip(tr(QString("Opens data directory for " + dirExtName).toStdString().c_str()));
            openDirectory->setWhatsThis(tr(QString("Opens data directory for " + dirExtName).toStdString().c_str()));
Emmanuel Promayon's avatar
Emmanuel Promayon committed
618
619
620
            connect(openDirectory, &QAction::triggered, this, [ = ]() {
                this->openDataDirectory(dirExtName);
            });
621
622

            fileOpenDataDirectoryMenu->addAction(openDirectory);
623

624
        }
Emmanuel Promayon's avatar
Emmanuel Promayon committed
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
    }
    else
        if (dirExt.size() == 1) {
            // if it exists, remove the default directory extension menu (that has only one submenu)
            // from the file "open" action list
            bool updateAction = false;
            QList<QAction*> menuActions = fileMenu->actions();
            int indexAction = 0;
            while (indexAction < menuActions.size() && !updateAction) {
                if (menuActions.at(indexAction)->text().contains(" Directory")) {
                    menuActions.at(indexAction)->destroyed();
                    updateAction = true;
                }
                indexAction++;
            }

            // create the single open directory action
            QString dirExtName = dirExt.at(0);
            QAction* openDirectoryAction = new QAction("Open " + dirExtName + " Directory", this);
            if (!updateAction) {
                // there was no specific menu, just add the single "open directory" action in the file menu
                fileMenu->addAction(openDirectoryAction);
647
648
            }

Emmanuel Promayon's avatar
Emmanuel Promayon committed
649
650
            openDirectoryAction->setStatusTip(tr(QString("Opens data directory for " + dirExtName).toStdString().c_str()));
            openDirectoryAction->setWhatsThis(tr(QString("Opens data directory for " + dirExtName).toStdString().c_str()));
651

Emmanuel Promayon's avatar
Emmanuel Promayon committed
652
653
654
            connect(openDirectoryAction, &QAction::triggered, this, [ = ]() {
                this->openDataDirectory(dirExtName);
            });
655

Emmanuel Promayon's avatar
Emmanuel Promayon committed
656
657
658
659
660
661
662
663
            openDirectoryAction->setIcon(QPixmap(":/fileOpen"));
        }
        else {
            fileOpenDataDirectoryMenu = new QMenu("No plugins loaded to Open Data Directory");
            fileOpenDataDirectoryMenu->setIcon(QPixmap(":/fileOpen"));
            fileOpenDataDirectoryMenu->setEnabled(false);
            fileMenu->addMenu(fileOpenDataDirectoryMenu);
        }
664
}