31 #include "gui/formmain.h"
33 #include "definitions/definitions.h"
34 #include "gui/formupdate.h"
35 #include "gui/formabout.h"
36 #include "gui/formsettings.h"
37 #include "gui/systemtrayicon.h"
38 #include "gui/formhelp.h"
39 #include "gui/formsimulator.h"
40 #include "gui/formnewproject.h"
41 #include "gui/custommessagebox.h"
42 #include "gui/formuploadbundle.h"
43 #include "miscellaneous/iconfactory.h"
44 #include "core/templatesimulator.h"
45 #include "core/templatefactory.h"
46 #include "core/templateentrypoint.h"
47 #include "core/templateeditor.h"
48 #include "core/templategenerator.h"
49 #include "templates/quiz/quizentrypoint.h"
51 #include <QStackedWidget>
52 #include <QMessageBox>
53 #include <QFileDialog>
54 #include <QInputDialog>
55 #include <QHBoxLayout>
56 #include <QVBoxLayout>
57 #include <QDesktopWidget>
58 #include <QLayoutItem>
59 #include <QProgressBar>
60 #include <QScrollArea>
64 : QMainWindow(parent),
65 m_statusProgress(new QProgressBar(this)),
66 m_statusLabel(new QLabel(this)),
67 m_centralArea(new QScrollArea(this)),
68 m_centralLayout(new QVBoxLayout(m_centralArea)),
69 m_firstTimeShow(true),
71 m_simulatorWindow(NULL) {
74 m_normalTitle = APP_LONG_NAME;
75 m_unsavedTitle = m_normalTitle +
" *";
77 m_statusProgress->setFixedHeight(m_ui->m_statusBar->sizeHint().height());
80 m_ui->m_statusBar->addWidget(m_statusProgress);
81 m_ui->m_statusBar->addWidget(m_statusLabel, 1);
82 m_statusLabel->setVisible(
false);
83 m_statusProgress->setVisible(
false);
85 setWindowTitle(m_normalTitle);
88 setWindowFlags(windowFlags() & ~Qt::WindowMaximizeButtonHint);
90 m_centralArea->setFrameStyle(QFrame::NoFrame);
92 setCentralWidget(m_centralArea);
93 setupSimulatorWindow();
94 setupActionShortcuts();
98 loadSizeAndPosition();
102 #if defined(DISABLE_STORE)
103 m_ui->m_actionUploadApplicationToStore->setVisible(
false);
105 if (!qApp->settings()->value(APP_CFG_GEN,
"enable_store",
true).toBool()) {
106 m_ui->m_actionUploadApplicationToStore->setVisible(
false);
110 #if defined(DISABLE_APK_GENERATION)
111 m_ui->m_actionGenerateMobileApplication->setVisible(
false);
113 if (!qApp->settings()->value(APP_CFG_GEN,
"enable_apk_generation",
true).toBool()) {
114 m_ui->m_actionGenerateMobileApplication->setVisible(
false);
120 m_ui->m_actionViewSimulatorWindow->setChecked(m_simulatorWindow->
isVisibleOnStartup());
121 m_ui->m_actionStickSimulatorWindow->setChecked(m_simulatorWindow->
isSticked());
124 FormMain::~FormMain() {
127 qDebug(
"Destroying FormMain instance.");
131 QList<QAction*> actions;
133 actions.append(m_ui->m_actionCheckForUpdates);
134 actions.append(m_ui->m_actionGenerateMobileApplication);
135 actions.append(m_ui->m_actionUploadApplicationToStore);
136 actions.append(m_ui->m_actionLoadProject);
137 actions.append(m_ui->m_actionNewProject);
138 actions.append(m_ui->m_actionSaveProject);
139 actions.append(m_ui->m_actionSaveProjectAs);
140 actions.append(m_ui->m_actionSimulatorRun);
141 actions.append(m_ui->m_actionSimulatorStop);
142 actions.append(m_ui->m_actionSimulatorGoBack);
143 actions.append(m_ui->m_actionViewSimulatorWindow);
144 actions.append(m_ui->m_actionStickSimulatorWindow);
145 actions.append(m_ui->m_actionQuit);
146 actions.append( m_ui->m_actionSettings);
147 actions.append(m_ui->m_actionHelp);
152 void FormMain::setupSimulatorWindow() {
156 void FormMain::createConnections() {
158 connect(qApp, SIGNAL(aboutToQuit()),
this, SLOT(onAboutToQuit()));
159 connect(m_ui->m_actionQuit, SIGNAL(triggered()),
this, SLOT(close()));
160 connect(m_ui->m_actionCheckForUpdates, SIGNAL(triggered()),
this, SLOT(showUpdates()));
161 connect(m_ui->m_actionAboutToolkit, SIGNAL(triggered()),
this, SLOT(showAbout()));
162 connect(m_ui->m_actionSettings, SIGNAL(triggered()),
this, SLOT(showSettings()));
163 connect(m_ui->m_actionHelp, SIGNAL(triggered()),
this, SLOT(showHelp()));
166 connect(m_ui->m_actionViewSimulatorWindow, SIGNAL(toggled(
bool)),
this, SLOT(switchSimulatorWindow(
bool)));
167 connect(m_ui->m_actionStickSimulatorWindow, SIGNAL(toggled(
bool)), m_simulatorWindow, SLOT(setIsSticked(
bool)));
170 connect(m_simulatorWindow, SIGNAL(closed()),
this, SLOT(onSimulatorWindowClosed()));
171 connect(m_simulatorWindow, SIGNAL(stopEnableChanged(
bool)), m_ui->m_actionSimulatorStop, SLOT(setEnabled(
bool)));
172 connect(m_ui->m_actionSimulatorStop, SIGNAL(triggered()), m_simulatorWindow->m_ui->m_btnStopSimulation, SLOT(click()));
173 connect(m_ui->m_actionSimulatorRun, SIGNAL(triggered()),
this, SLOT(startSimulation()));
174 connect(m_ui->m_actionSimulatorGoBack, SIGNAL(triggered()),
this, SLOT(takeSimulationOneStepBack()));
178 connect(m_ui->m_actionSaveProject, SIGNAL(triggered()),
this ,SLOT(openSaveProjectDialog()));
179 connect(m_ui->m_actionSaveProjectAs, SIGNAL(triggered()),
this, SLOT(openSaveProjectAsDialog()));
180 connect(m_ui->m_actionLoadProject, SIGNAL(triggered()),
this ,SLOT(openLoadProjectDialog()));
181 connect(m_ui->m_actionOpenOutputDirectory, SIGNAL(triggered()),
this, SLOT(openOutputDirectory()));
184 connect(qApp->templateManager(), SIGNAL(newTemplateCoreCreated(
TemplateCore*)),
this, SLOT(setTemplateCore(
TemplateCore*)));
185 connect(qApp, SIGNAL(externalApplicationsRechecked()),
this, SLOT(onExternalApplicationsChanged()));
188 connect(qApp->templateManager()->generator(), SIGNAL(generationStarted()),
this, SLOT(onGenerationStarted()));
191 connect(qApp->templateManager()->generator(), SIGNAL(generationProgress(
int,QString)),
this, SLOT(onGenerationProgress(
int,QString)));
194 void FormMain::setupActionShortcuts() {
195 m_ui->m_actionGenerateMobileApplication->setShortcut(QKeySequence(
"Ctrl+G", QKeySequence::PortableText));
196 m_ui->m_actionLoadProject->setShortcut(QKeySequence(
"Ctrl+L", QKeySequence::PortableText));
197 m_ui->m_actionNewProject->setShortcut(QKeySequence(
"Ctrl+N", QKeySequence::PortableText));
198 m_ui->m_actionSaveProject->setShortcut(QKeySequence(
"Ctrl+S", QKeySequence::PortableText));
199 m_ui->m_actionSaveProjectAs->setShortcut(QKeySequence(
"Ctrl+Shift+S", QKeySequence::PortableText));
200 m_ui->m_actionQuit->setShortcut(QKeySequence(
"Ctrl+Q", QKeySequence::PortableText));
201 m_ui->m_actionSettings->setShortcut(QKeySequence(
"Ctrl+T", QKeySequence::PortableText));
202 m_ui->m_actionHelp->setShortcut(QKeySequence(
"F1", QKeySequence::PortableText));
203 m_ui->m_actionOpenOutputDirectory->setShortcut(QKeySequence(
"Ctrl+D", QKeySequence::PortableText));
206 void FormMain::setupIcons() {
209 m_ui->m_actionSettings->setIcon(factory->
fromTheme(
"application-settings"));
210 m_ui->m_actionQuit->setIcon(factory->
fromTheme(
"application-exit"));
211 m_ui->m_actionAboutToolkit->setIcon(factory->
fromTheme(
"application-about"));
212 m_ui->m_actionCheckForUpdates->setIcon(factory->
fromTheme(
"check-for-updates"));
213 m_ui->m_actionHelp->setIcon(factory->
fromTheme(
"dialog-question"));
214 m_ui->m_actionNewProject->setIcon(factory->
fromTheme(
"project-new"));
215 m_ui->m_actionSaveProject->setIcon(factory->
fromTheme(
"project-save"));
216 m_ui->m_actionSaveProjectAs->setIcon(factory->
fromTheme(
"project-save-as"));
217 m_ui->m_actionLoadProject->setIcon(factory->
fromTheme(
"project-load"));
218 m_ui->m_actionUploadApplicationToStore->setIcon(factory->
fromTheme(
"project-upload"));
219 m_ui->m_actionGenerateMobileApplication->setIcon(factory->
fromTheme(
"project-generate"));
220 m_ui->m_menuSimulatorWindow->setIcon(factory->
fromTheme(
"view-simulator"));
221 m_ui->m_actionStickSimulatorWindow->setIcon(factory->
fromTheme(
"simulation-stick"));
222 m_ui->m_actionViewSimulatorWindow->setIcon(factory->
fromTheme(
"view-simulator"));
223 m_ui->m_actionSimulatorRun->setIcon(factory->
fromTheme(
"simulation-run"));
224 m_ui->m_actionSimulatorStop->setIcon(factory->
fromTheme(
"simulation-stop"));
225 m_ui->m_actionSimulatorGoBack->setIcon(factory->
fromTheme(
"simulation-back"));
226 m_ui->m_actionOpenOutputDirectory->setIcon(factory->
fromTheme(
"view-output"));
229 void FormMain::setupToolbar() {
230 m_ui->m_toolBar->setWindowTitle(tr(
"Main toolbar"));
232 m_ui->m_toolBar->addAction(m_ui->m_actionNewProject);
233 m_ui->m_toolBar->addAction(m_ui->m_actionLoadProject);
234 m_ui->m_toolBar->addAction(m_ui->m_actionSaveProject);
235 m_ui->m_toolBar->addAction(m_ui->m_actionSaveProjectAs);
236 m_ui->m_toolBar->addSeparator();
237 m_ui->m_toolBar->addAction(m_ui->m_actionSimulatorRun);
238 m_ui->m_toolBar->addAction(m_ui->m_actionSimulatorStop);
239 m_ui->m_toolBar->addAction(m_ui->m_actionSimulatorGoBack);
240 m_ui->m_toolBar->addAction(m_ui->m_actionGenerateMobileApplication);
241 m_ui->m_toolBar->addAction(m_ui->m_actionUploadApplicationToStore);
242 m_ui->m_toolBar->addAction(m_ui->m_actionHelp);
245 void FormMain::setupTrayMenu() {
247 #if defined(Q_OS_WIN)
248 m_trayMenu =
new TrayIconMenu(APP_NAME,
this);
250 m_trayMenu =
new QMenu(APP_NAME,
this);
254 m_trayMenu->addAction(m_ui->m_actionCheckForUpdates);
255 m_trayMenu->addSeparator();
256 m_trayMenu->addAction(m_ui->m_actionQuit);
258 qDebug(
"Creating tray icon menu.");
262 void FormMain::loadSizeAndPosition() {
263 QRect screen = qApp->desktop()->screenGeometry();
264 QRect windows = rect();
265 Settings *settings = qApp->settings();
267 windows.setWidth(windows.width() + m_simulatorWindow->width());
270 resize(settings->
value(APP_CFG_GUI,
"window_size", size()).toSize());
271 move(settings->
value(APP_CFG_GUI,
"window_position", screen.center() - windows.center()).toPoint());
277 void FormMain::saveSizeAndPosition() {
278 Settings *settings = qApp->settings();
280 settings->
setValue(APP_CFG_GUI,
"window_position", pos());
281 settings->
setValue(APP_CFG_GUI,
"window_size", size());
287 void FormMain::quit()
292 void FormMain::startSimulation() {
294 QTimer::singleShot(0, m_simulatorWindow, SLOT(startSimulation()));
297 void FormMain::takeSimulationOneStepBack() {
299 QTimer::singleShot(0, m_simulatorWindow, SLOT(goBack()));
302 void FormMain::onCanGenerateChanged(
bool can_generate,
const QString &informative_text) {
305 if (!qApp->externalApplicationChecked()) {
306 qApp->recheckExternalApplications(
false);
309 if (!qApp->externalApplicationsReady()) {
310 m_ui->m_actionGenerateMobileApplication->setEnabled(
false);
311 m_ui->m_actionGenerateMobileApplication->setToolTip(qApp->externalApplicationsStatus());
315 m_ui->m_actionGenerateMobileApplication->setEnabled(
true);
316 m_ui->m_actionGenerateMobileApplication->setToolTip(tr(
"Generate mobile application"));
319 m_ui->m_actionUploadApplicationToStore->setEnabled(
true);
320 m_ui->m_actionUploadApplicationToStore->setToolTip(tr(
"Upload mobile application to store"));
321 m_ui->m_actionSimulatorRun->setEnabled(
true);
322 m_ui->m_actionSimulatorRun->setToolTip(tr(
"Start new simulation"));
326 m_ui->m_actionUploadApplicationToStore->setEnabled(
false);
327 m_ui->m_actionUploadApplicationToStore->setToolTip(informative_text);
328 m_ui->m_actionGenerateMobileApplication->setEnabled(can_generate);
329 m_ui->m_actionGenerateMobileApplication->setToolTip(qApp->externalApplicationsStatus());
330 m_ui->m_actionSimulatorRun->setEnabled(can_generate);
331 m_ui->m_actionSimulatorRun->setToolTip(informative_text);
335 void FormMain::onExternalApplicationsChanged() {
336 if (qApp->templateManager()->activeCore() != NULL) {
337 TemplateEditor *active_editor = qApp->templateManager()->activeCore()->editor();
345 onCanGenerateChanged(
false, QString());
349 void FormMain::onEditorChanged() {
350 setWindowTitle(m_unsavedTitle);
358 m_ui->m_actionSaveProjectAs->setEnabled(
true);
359 m_ui->m_actionSaveProject->setEnabled(
true);
363 m_ui->m_actionSaveProjectAs->setEnabled(
true);
364 m_ui->m_actionSaveProject->setEnabled(
true);
368 void FormMain::onGenerationProgress(
int percentage_completed,
const QString &message) {
369 qApp->processEvents();
371 m_statusLabel->setText(message);
372 m_statusLabel->setVisible(
true);
373 m_statusProgress->setValue(percentage_completed);
374 m_statusProgress->setVisible(
true);
377 void FormMain::onGenerationStarted() {
378 qApp->processEvents();
380 m_ui->m_actionGenerateMobileApplication->setEnabled(
false);
384 qApp->processEvents();
386 m_generatedApplicationPath = output_file;
388 if (qApp->templateManager()->activeCore() != NULL) {
389 m_ui->m_actionGenerateMobileApplication->setEnabled(qApp->templateManager()->activeCore()->editor()->canGenerateApplications());
392 m_ui->m_actionGenerateMobileApplication->setEnabled(
false);
395 m_statusLabel->clear();
396 m_statusLabel->setVisible(
false);
397 m_statusProgress->setValue(0);
398 m_statusProgress->setVisible(
false);
401 switch (result_code) {
402 case TemplateCore::Success: {
406 msg_box.setWindowTitle(tr(
"Mobile application generated"));
407 #if defined(Q_OS_WIN32)
408 msg_box.setText(tr(
"Mobile application was successfully generated."));
410 QPushButton *btn_open_folder = msg_box.addButton(tr(
"Open output folder"),
411 QMessageBox::DestructiveRole);
412 connect(btn_open_folder, SIGNAL(clicked()),
this, SLOT(openOutputDirectory()));
414 msg_box.setText(tr(
"Mobile application was successfully generated and is placed in "
415 "output directory \"%1\"").arg(QDir::toNativeSeparators(qApp->templateManager()->outputDirectory())));
417 msg_box.setIcon(QMessageBox::Information);
418 msg_box.setStandardButtons(QMessageBox::Ok);
421 #if defined(Q_OS_OS2)
422 QDialogButtonBox *button_box = msg_box.findChild<QDialogButtonBox*>();
429 case TemplateCore::Aborted:
435 tr(
"Application was NOT generated successfully."));
440 void FormMain::openOutputDirectory() {
441 #if defined(Q_OS_WIN32)
443 QProcess::startDetached(
"explorer", QStringList() << QDir::toNativeSeparators(qApp->templateManager()->outputDirectory()));
447 tr(
"Output directory cannot be opened, output directory is \"%1\".").arg(QDir::toNativeSeparators(qApp->templateManager()->outputDirectory())));
452 setWindowTitle(m_normalTitle);
460 while (m_centralLayout->count() > 0) {
461 QLayoutItem *item = m_centralLayout->itemAt(0);
463 item->widget()->deleteLater();
464 m_centralLayout->removeItem(item);
470 m_centralLayout->layout()->addWidget(editor);
471 editor->setParent(m_centralArea);
473 connect(editor, SIGNAL(changed()),
this, SLOT(onEditorChanged()));
474 connect(editor, SIGNAL(canGenerateChanged(
bool,QString)),
this, SLOT(onCanGenerateChanged(
bool,QString)));
475 connect(simulator, SIGNAL(canGoBackChanged(
bool)), m_ui->m_actionSimulatorGoBack, SLOT(setEnabled(
bool)));
484 void FormMain::onAboutToQuit() {
486 saveSizeAndPosition();
489 void FormMain::onSimulatorWindowClosed() {
490 m_ui->m_actionViewSimulatorWindow->setChecked(
false);
493 void FormMain::switchSimulatorWindow(
bool show) {
495 m_simulatorWindow->
show();
498 m_simulatorWindow->close();
502 void FormMain::showSimulator() {
503 if (!m_ui->m_actionViewSimulatorWindow->isChecked()) {
504 m_ui->m_actionViewSimulatorWindow->setChecked(
true);
508 void FormMain::showSettings() {
509 QPointer<FormSettings> form_pointer =
new FormSettings(
this);
510 form_pointer.data()->exec();
511 delete form_pointer.data();
514 void FormMain::showAbout() {
515 QPointer<FormAbout> form_about =
new FormAbout(
this);
516 form_about.data()->exec();
517 delete form_about.data();
520 void FormMain::showUpdates() {
521 QPointer<FormUpdate> form_update =
new FormUpdate(
this);
522 form_update.data()->exec();
523 delete form_update.data();
526 void FormMain::showHelp(
bool enable_do_not_show_again_option) {
527 QPointer<FormHelp> form_help =
new FormHelp(enable_do_not_show_again_option,
this);
528 form_help.data()->exec();
529 delete form_help.data();
532 void FormMain::showUpdatesAfterBubbleClick() {
538 if (force_hide || isVisible()) {
541 m_simulatorWindow->hide();
552 m_simulatorWindow->
show();
560 if (m_firstTimeShow) {
561 m_firstTimeShow =
false;
563 if (qApp->settings()->value(APP_CFG_GUI,
"show_help_startup",
true).toBool()) {
571 setWindowState(windowState() & ~Qt::WindowMinimized);
579 Application::alert(
this);
582 void FormMain::openSaveProjectDialog() {
583 if (qApp->templateManager()->activeCore()->assignedFile().isEmpty()) {
586 openSaveProjectAsDialog();
589 if (qApp->templateManager()->saveCurrentProject()) {
591 m_ui->m_actionSaveProject->setEnabled(
false);
592 setWindowTitle(m_normalTitle);
600 void FormMain::openSaveProjectAsDialog() {
601 QString selected_file = QFileDialog::getSaveFileName(
this,
602 tr(
"Select destination file for the project"),
603 qApp->templateManager()->activeCore()->assignedFile(),
604 tr(
"BuildmLearn Toolkit projects (*.buildmlearn)"),
607 if (!selected_file.isEmpty()) {
608 if (qApp->templateManager()->saveCurrentProjectAs(selected_file)) {
610 m_ui->m_actionSaveProject->setEnabled(
false);
611 setWindowTitle(m_normalTitle);
619 void FormMain::openLoadProjectDialog() {
624 QString selected_file = QFileDialog::getOpenFileName(
this,
625 tr(
"Select destination file for the project"),
627 tr(
"BuildmLearn Toolkit projects (*.buildmlearn)"),
630 if (selected_file.isEmpty()) {
634 if (qApp->templateManager()->loadProject(selected_file)) {
635 m_ui->m_actionSaveProjectAs->setEnabled(
true);
636 m_ui->m_actionSaveProject->setEnabled(
false);
645 QPointer<FormNewProject> form_new_project =
new FormNewProject(qApp->templateManager(),
this);
648 delete form_new_project.data();
650 if (entry_point != NULL) {
653 qApp->templateManager()->startNewProject(entry_point);
658 if (qApp->templateManager()->activeCore() != NULL) {
659 qApp->templateManager()->generator()->generateMobileApplication(qApp->templateManager()->activeCore());
662 QMessageBox::warning(
this,
663 tr(
"Cannot generate application"),
664 tr(
"No project is opened, thus, cannot generate application."));
670 form_pointer.data()->exec();
672 if (form_pointer.data()->uploadStatus() == StoreFactory::Success) {
675 tr(
"Application uploaded"),
676 tr(
"Your application was successfully submitted. It would be reviewed and published to the BuildmLearn Store. You would receive email notification regarding this."));
679 delete form_pointer.data();
683 if (qApp->templateManager()->activeCore() != NULL) {
684 if (qApp->templateManager()->activeCore()->editor()->isDirty()) {
686 QMessageBox::Warning,
688 tr(
"There is unsaved project. You might want to save your current project, unless you do not mind losing your unsaved work."),
689 tr(
"Do you want to save your unsaved project before proceeding?"), QString(),
690 QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel,
694 case QMessageBox::Yes:
695 openSaveProjectDialog();
698 case QMessageBox::No:
701 case QMessageBox::Cancel:
712 if (!qApp->isClosing()) {
720 qApp->trayIcon()->hide();
void generateMobileApplication()
Generates mobile APK application from currently active project.
void switchVisibility(bool force_hide=false)
Switches visibility of main window.
void moved()
Emitted when window is moved.
virtual QString generationStatusDescription()
Access to description of current state.
virtual TemplateEditor * editor() const
Access to editor widget of the template.
virtual TemplateSimulator * simulator() const
Access to simulator widget of the template.
static void iconify(QDialogButtonBox *button_box)
Performs icon replacements for given button box.
void resizeEvent(QResizeEvent *e)
Executed when window is resized.
void moveEvent(QMoveEvent *e)
Executed when window is moved.
void uploadMobileApplicationToStore()
Displays dialog for uploading applications to store.
Represents the editor of the template.
void openNewProjectDialog()
Opens "New project" dialog.
void resized()
Emitted when window is resized.
virtual bool canGenerateApplications()
Specifies if template can generate applications or not.
void setValue(const QString §ion, const QString &key, const QVariant &value)
Sets new value into settings.
virtual void launch()
Called after this template is fully loaded in toolkit.
void show()
Displays window.
Icon theme manipulator and provider.
void display()
Displays the window.
Application-wide settings mechanism.
bool saveUnsavedProject()
Performs necessary steps to save active project if there is unsaved work.
static bool isSystemTrayAvailable()
Indicates whether tray icon is supported.
static QMessageBox::StandardButton show(QWidget *parent, QMessageBox::Icon icon, const QString &title, const QString &text, const QString &informative_text=QString(), const QString &detailed_text=QString(), QMessageBox::StandardButtons buttons=QMessageBox::Ok, QMessageBox::StandardButton default_button=QMessageBox::Ok)
Displays custom message box.
The entry point for a template.
QString assignedFile() const
Access to assigned XML "bundle" file.
FormMain(QWidget *parent=0)
Constructor.
QVariant value(const QString §ion, const QString &key, const QVariant &default_value=QVariant())
Getter/setter for settings values.
void closeEvent(QCloseEvent *e)
Executed when main application window is closed.
QList< QAction * > allActions()
Access to all actions provided by this window.
The core class container for single template.
GenerationResult
Possible results of generation of bundle data.
QIcon fromTheme(const QString &name)
Returns icon from active theme.
static IconFactory * instance()
Singleton getter.
Base widget which represents simulator of the template.