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
|
// ************************************************************************************************
//
// BornAgain: simulate and fit reflection and scattering
//
//! @file GUI/View/Main/ActionManager.cpp
//! @brief Implements class ActionManager.
//!
//! @homepage http://www.bornagainproject.org
//! @license GNU General Public License v3 or higher (see COPYING)
//! @copyright Forschungszentrum Jülich GmbH 2021
//! @authors Scientific Computing Group at MLZ (see CITATION, AUTHORS)
//
// ************************************************************************************************
#include "GUI/View/Main/ActionManager.h"
#include "Base/Util/Assert.h"
#include "Base/Util/SysUtil.h"
#include "GUI/Model/Descriptor/ComboProperty.h"
#include "GUI/Model/Project/ProjectDocument.h"
#include "GUI/Model/Util/Path.h"
#include "GUI/View/Base/mainwindow_constants.h"
#include "GUI/View/Main/AboutDialog.h"
#include "GUI/View/Main/CentralWidget.h"
#include "GUI/View/Main/ProjectManager.h"
#include "GUI/View/Numeric/ComboUtil.h"
#include "GUI/View/View/InstrumentView.h"
#include "GUI/View/View/JobView.h"
#include "GUI/View/View/SampleView.h"
#include "GUI/View/Widget/AppConfig.h"
#include <QBoxLayout>
#include <QButtonGroup>
#include <QCheckBox>
#include <QDesktopServices>
#include <QDir>
#include <QLabel>
#include <QRadioButton>
#include <QSettings>
#include <QUrl>
#include <QWidgetAction>
ActionManager::ActionManager(QMainWindow* parent, ProjectManager* pm)
: QObject(parent)
, m_main_window(parent)
, m_project_manager(pm)
{
createActions();
createMenus();
// createGlobalShortcuts();
updateActionEnabling();
}
void ActionManager::updateActionEnabling()
{
const bool documentExists = (bool)gDoc;
m_save_action->setEnabled(documentExists);
m_save_as_action->setEnabled(documentExists);
}
void ActionManager::createActions()
{
ASSERT(m_project_manager);
// new project action
m_new_action = new QAction("&New project", m_main_window);
m_new_action->setShortcuts(QKeySequence::New);
m_new_action->setStatusTip("Create a new project");
connect(m_new_action, &QAction::triggered, m_project_manager, &ProjectManager::newProject);
// open project action
m_open_action = new QAction("&Open project", m_main_window);
m_open_action->setShortcuts(QKeySequence::Open);
m_open_action->setStatusTip("Open an existing project");
connect(m_open_action, &QAction::triggered, [this] { m_project_manager->openProject(); });
// save project action
m_save_action = new QAction("&Save project", m_main_window);
m_save_action->setShortcuts(QKeySequence::Save);
m_save_action->setStatusTip("Save project");
m_save_action->setShortcutContext(Qt::ApplicationShortcut);
connect(m_save_action, &QAction::triggered, [this] { m_project_manager->saveProject(); });
// save-as project action
m_save_as_action = new QAction("Save project &as...", m_main_window);
m_save_as_action->setShortcuts(QKeySequence::SaveAs);
m_save_as_action->setStatusTip("Save project under different name");
connect(m_save_as_action, &QAction::triggered, m_project_manager,
&ProjectManager::saveProjectAs);
// exit application action
m_exit_action = new QAction("&Quit", this);
m_exit_action->setShortcuts(QKeySequence::Quit);
m_exit_action->setStatusTip("Exit the application");
connect(m_exit_action, &QAction::triggered, m_main_window, &QMainWindow::close);
// visit web doc action
m_webdoc_action = new QAction("&Visit web docs", this);
m_webdoc_action->setStatusTip("Open BornAgain documentation in default browser");
connect(m_webdoc_action, &QAction::triggered,
[] { QDesktopServices::openUrl(QUrl("https://www.bornagainproject.org/latest")); });
// about application action
m_about_action = new QAction("&About BornAgain", this);
m_about_action->setStatusTip("About the application");
connect(m_about_action, &QAction::triggered, this, &ActionManager::onAboutApplication);
}
void ActionManager::createMenus()
{
m_menu_bar = new QMenuBar(nullptr); // No parent (System menu bar on Mac OS X)
#ifndef Q_OS_MAC
m_main_window->setMenuBar(m_menu_bar);
#endif
// File Menu
m_file_menu = m_menu_bar->addMenu("&File");
m_file_menu->addAction(m_new_action);
m_file_menu->addAction(m_open_action);
connect(m_file_menu, &QMenu::aboutToShow, this, &ActionManager::onAboutToShowFileMenu);
m_recent_projects_menu = m_file_menu->addMenu("&Recent Projects");
m_file_menu->addSeparator();
m_file_menu->addAction(m_save_action);
m_file_menu->addAction(m_save_as_action);
m_file_menu->addSeparator();
m_file_menu->addAction(m_exit_action);
// Settings Menu
m_settings_menu = new QMenu("&Settings", m_main_window);
m_menu_bar->addMenu(m_settings_menu);
m_settings_menu->setToolTipsVisible(true);
{
auto* action = new QWidgetAction(m_settings_menu);
action->setText("&Enable autosave");
auto* box = new QCheckBox("&Enable autosave", m_settings_menu);
action->setDefaultWidget(box);
action->setToolTip("Project will be saved periodically in project's autosave directory.\n"
"When opening project, recover option will be suggested, if possible.");
action->setCheckable(true);
box->setChecked(gApp->autosave_enabled);
connect(box, &QCheckBox::toggled, [=] { gApp->autosave_enabled = box->isChecked(); });
m_settings_menu->addAction(action);
}
{
auto* action = new QWidgetAction(m_settings_menu);
action->setToolTip("Color gradient for 2d plots");
auto* w = new QWidget;
auto* l = new QHBoxLayout(w);
l->addWidget(new QLabel("2D plot color scheme"));
QComboBox* box =
GUI::Util::createComboBox([] { return *gApp->color_gradient_combo; },
[](const QString& s) {
gApp->color_gradient_combo->setCurrentValue(s);
emit gApp->gradientChanged();
},
false);
l->addWidget(box);
action->setDefaultWidget(w);
m_settings_menu->addAction(action);
}
// View menu
m_view_menu = new QMenu("&View", m_main_window);
onAboutToShowViewMenu(); // MacOS feature: action should exist already, otherwise menuBar will
// not add menu
connect(m_view_menu, &QMenu::aboutToShow, this, &ActionManager::onAboutToShowViewMenu);
m_menu_bar->addMenu(m_view_menu);
// Help Menu
m_help_menu = m_menu_bar->addMenu("&Help");
m_help_menu->addAction(m_webdoc_action);
m_help_menu->addAction(m_about_action);
onCurrentViewChanged();
}
void ActionManager::onAboutToShowFileMenu()
{
m_recent_projects_menu->clear();
bool hasRecentProjects = false;
int orderNr = 1;
for (const QString& file : m_project_manager->recentProjects()) {
hasRecentProjects = true;
QString actionText = GUI::Path::withTildeHomePath(QDir::toNativeSeparators(file));
if (orderNr < 10)
actionText = QString("&%1 ").arg(orderNr) + actionText;
QAction* action = m_recent_projects_menu->addAction(actionText);
action->setData(QVariant::fromValue(file));
connect(action, &QAction::triggered,
[this, file] { m_project_manager->openProject(file); });
orderNr++;
}
m_recent_projects_menu->setEnabled(hasRecentProjects);
if (hasRecentProjects) {
m_recent_projects_menu->addSeparator();
QAction* action = m_recent_projects_menu->addAction("&Clear Menu");
connect(action, &QAction::triggered, m_project_manager,
&ProjectManager::clearRecentProjects);
}
}
void ActionManager::onAboutToShowViewMenu()
{
m_view_menu->clear();
if (auto* cw = dynamic_cast<CentralWidget*>(m_main_window->centralWidget())) {
QWidget* view = cw->currentView();
if (auto* jobView = dynamic_cast<JobView*>(view); jobView != nullptr)
jobView->fillViewMenu(m_view_menu);
}
}
void ActionManager::onAboutApplication()
{
AboutDialog dialog(m_main_window);
dialog.exec();
}
void ActionManager::onCurrentViewChanged()
{
// not every view support view menu entries -> hide it, if empty
onAboutToShowViewMenu();
m_view_menu->menuAction()->setVisible(!m_view_menu->actions().isEmpty());
gDoc->setModified();
}
|