Commit 0e9b3907 authored by Sebastian Gottfried's avatar Sebastian Gottfried
Browse files

Fix Crash On Exit

The QML engine deletes all parentless QObject it sees on shutdown. So
we can't expose the main window directly to it. Move all QML interface
code in to a dedicated class which is instantiated as a child object
of the main window.
parent b51ab857
......@@ -81,6 +81,7 @@ set(ktouch_SRCS
trainingconfigwidget.cpp
colorsconfigwidget.cpp
customlessoneditordialog.cpp
ktouchcontext.cpp
)
# compile UI files
......
/*
* Copyright 2016 Sebastian Gottfried <sebastian.gottfried@posteo.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ktouchcontext.h"
#include <QMenu>
#include <QPointer>
#include <QDialogButtonBox>
#include <QMenu>
#include <QQuickWidget>
#include "application.h"
#include "colorsconfigwidget.h"
#include "editor/resourceeditor.h"
#include "customlessoneditordialog.h"
#include "preferences.h"
#include "trainingconfigwidget.h"
#include <KActionCollection>
#include <KStandardAction>
#include <KHelpMenu>
#include <KToggleFullScreenAction>
#include <KShortcutsDialog>
#include <KConfigDialog>
#include <KCMultiDialog>
#include <KLocalizedString>
#ifdef KTOUCH_BUILD_WITH_X11
#include "x11_helper.h"
#else
#include "keyboardlayoutmenu.h"
#endif
const QString keyboardKCMName = "kcm_keyboard";
KTouchContext::KTouchContext(KMainWindow* mainWindow, QQuickWidget* view, QObject *parent) :
QObject(parent),
m_actionCollection(new KActionCollection(this)),
m_menu(new QMenu(mainWindow)),
m_mainWindow(mainWindow),
m_view(view)
{
#ifdef KTOUCH_BUILD_WITH_X11
m_XEventNotifier = new XEventNotifier();
m_XEventNotifier->start();
connect(m_XEventNotifier, SIGNAL(layoutChanged()), SIGNAL(keyboardLayoutNameChanged()));
#else
m_keyboardLayoutMenu = new KeyboardLayoutMenu(this);
m_keyboardLayoutMenu->setDataIndex(Application::dataIndex());
connect(m_keyboardLayoutMenu, SIGNAL(keyboardLayoutNameChanged()), SIGNAL(keyboardLayoutNameChanged()));
#endif
init();
}
KTouchContext::~KTouchContext()
{
#ifdef KTOUCH_BUILD_WITH_X11
m_XEventNotifier->stop();
delete m_XEventNotifier;
#endif
}
QString KTouchContext::keyboardLayoutName() const
{
#ifdef KTOUCH_BUILD_WITH_X11
return X11Helper::getCurrentLayout().toString();
#else
return m_keyboardLayoutMenu->keyboardLayoutName();
#endif
}
DataIndex* KTouchContext::dataIndex()
{
return Application::dataIndex();
}
void KTouchContext::showMenu(int xPos, int yPos)
{
m_menu->popup(m_view->mapToGlobal(QPoint(xPos, yPos)));
}
void KTouchContext::showResourceEditor()
{
QSharedPointer<ResourceEditor>& resourceEditorRef = Application::resourceEditorRef();
if (resourceEditorRef.isNull())
{
resourceEditorRef = QSharedPointer<ResourceEditor>(new ResourceEditor());
}
ResourceEditor* resourceEditor = resourceEditorRef.data();
resourceEditor->show();
resourceEditor->activateWindow();
}
bool KTouchContext::showCustomLessonDialog(Lesson* lesson, KeyboardLayout* keyboardLayout)
{
CustomLessonEditorDialog* dialog = new CustomLessonEditorDialog(m_mainWindow);
dialog->setLesson(lesson);
dialog->setKeyboardLayout(keyboardLayout);
bool result = dialog->exec() == QDialog::Accepted;
delete dialog;
return result;
}
void KTouchContext::showConfigDialog()
{
if (KConfigDialog::showDialog("preferences"))
{
return;
}
KConfigDialog* dialog = new KConfigDialog(m_mainWindow, "preferences", Preferences::self());
dialog->setFaceType(KPageDialog::List);
dialog->setModal(true);
dialog->addPage(new TrainingConfigWidget(), i18n("Training"), "chronometer", i18n("Training Settings"));
dialog->addPage(new ColorsConfigWidget(), i18n("Colors"), "preferences-desktop-color", i18n("Color Settings"));
dialog->show();
}
void KTouchContext::configureShortcuts()
{
KShortcutsDialog::configure(m_actionCollection, KShortcutsEditor::LetterShortcutsDisallowed, m_mainWindow);
}
void KTouchContext::configureKeyboard()
{
QPointer<KCMultiDialog> kcm = new KCMultiDialog(m_mainWindow);
kcm->setWindowTitle(i18n("Configure Keyboard"));
kcm->addModule(keyboardKCMName);
kcm->exec();
delete kcm;
}
void KTouchContext::setFullscreen(bool fullScreen)
{
KToggleFullScreenAction::setFullScreen(m_mainWindow, fullScreen);
}
void KTouchContext::init()
{
m_actionCollection->addAssociatedWidget(m_mainWindow);
m_menu->addAction(KStandardAction::fullScreen(this, SLOT(setFullscreen(bool)), m_mainWindow, m_actionCollection));
m_menu->addSeparator();
QAction* editorAction = new QAction(i18n("Course and Keyboard Layout Editor..."), this);
connect(editorAction, &QAction::triggered, this, &KTouchContext::showResourceEditor);
m_actionCollection->addAction("editor", editorAction);
m_menu->addAction(editorAction);
m_menu->addSeparator();
m_menu->addAction(KStandardAction::preferences(this, SLOT(showConfigDialog()), m_actionCollection));
m_menu->addAction(KStandardAction::keyBindings(this, SLOT(configureShortcuts()), m_actionCollection));
#ifdef KTOUCH_BUILD_WITH_X11
if (testKCMAvailibility(keyboardKCMName))
{
QAction* configureKeyboardAction = new QAction(i18n("Configure Keyboard..."), this);
m_menu->addAction(configureKeyboardAction);
connect(configureKeyboardAction, &QAction::triggered, this, &KTouchContext::configureKeyboard);
}
#else
m_menu->addMenu(m_keyboardLayoutMenu);
#endif
m_menu->addSeparator();
KHelpMenu* helpMenu = new KHelpMenu(m_mainWindow);
m_menu->addMenu(helpMenu->menu());
}
bool KTouchContext::testKCMAvailibility(const QString& name)
{
KService::Ptr service = KService::serviceByStorageId(name + ".desktop");
if (!service)
{
return false;
}
return service->hasServiceType("KCModule") && !service->noDisplay();
}
/*
* Copyright 2016 Sebastian Gottfried <sebastian.gottfried@posteo.de>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KTOUCHCONTEXT_H
#define KTOUCHCONTEXT_H
#include <QObject>
class QMenu;
class QQuickWidget;
class KActionCollection;
class KMainWindow;
class DataIndex;
class KeyboardLayout;
class KeyboardLayoutMenu;
class Lesson;
class XEventNotifier;
class KTouchContext : public QObject
{
Q_OBJECT
Q_PROPERTY(QString keyboardLayoutName READ keyboardLayoutName NOTIFY keyboardLayoutNameChanged)
Q_PROPERTY(DataIndex* globalDataIndex READ dataIndex CONSTANT)
public:
explicit KTouchContext(KMainWindow* mainWindow, QQuickWidget* view, QObject* parent = 0);
~KTouchContext();
QString keyboardLayoutName() const;
DataIndex* dataIndex();
Q_INVOKABLE void showMenu(int xPos, int yPos);
public slots:
void showResourceEditor();
bool showCustomLessonDialog(Lesson* lesson, KeyboardLayout* keyboardLayout);
private slots:
void showConfigDialog();
void configureShortcuts();
void configureKeyboard();
void setFullscreen(bool fullscreen);
signals:
void keyboardLayoutNameChanged();
private:
void init();
bool testKCMAvailibility(const QString& name);
KActionCollection* m_actionCollection;
QMenu* m_menu;
KMainWindow* m_mainWindow;
QQuickWidget* m_view;
#ifdef KTOUCH_BUILD_WITH_X11
XEventNotifier* m_XEventNotifier;
#else
KeyboardLayoutMenu* m_keyboardLayoutMenu;
#endif
};
#endif // KTOUCHCONTEXT_H
......@@ -18,195 +18,37 @@
#include "mainwindow.h"
#include <QQuickWidget>
#include <QMenu>
#include <QPointer>
#include <QVariant>
#include <QDialogButtonBox>
#include <QStandardPaths>
#include <QMenu>
#include <QQmlContext>
#include <KActionCollection>
#include <KStandardAction>
#include <KHelpMenu>
#include <KToggleFullScreenAction>
#include <KShortcutsDialog>
#include <KConfigDialog>
#include <KCMultiDialog>
#include <KLocalizedString>
#include "editor/resourceeditor.h"
#include "application.h"
#include "preferences.h"
#include "trainingconfigwidget.h"
#include "colorsconfigwidget.h"
#include "customlessoneditordialog.h"
#ifdef KTOUCH_BUILD_WITH_X11
#include "x11_helper.h"
#else
#include "keyboardlayoutmenu.h"
#endif
const QString keyboardKCMName = "kcm_keyboard";
#include "ktouchcontext.h"
MainWindow::MainWindow(QWidget* parent):
KMainWindow(parent),
m_view(new QQuickWidget(this)),
m_actionCollection(new KActionCollection(this)),
m_menu(new QMenu(this))
m_context(new KTouchContext(this, m_view, this))
{
#ifdef KTOUCH_BUILD_WITH_X11
m_XEventNotifier = new XEventNotifier();
m_XEventNotifier->start();
connect(m_XEventNotifier, SIGNAL(layoutChanged()), SIGNAL(keyboardLayoutNameChanged()));
#else
m_keyboardLayoutMenu = new KeyboardLayoutMenu(this);
m_keyboardLayoutMenu->setDataIndex(Application::dataIndex());
connect(m_keyboardLayoutMenu, SIGNAL(keyboardLayoutNameChanged()), SIGNAL(keyboardLayoutNameChanged()));
#endif
init();
}
MainWindow::~MainWindow()
{
#ifdef KTOUCH_BUILD_WITH_X11
m_XEventNotifier->stop();
delete m_XEventNotifier;
#endif
}
QString MainWindow::keyboardLayoutName() const
{
#ifdef KTOUCH_BUILD_WITH_X11
return X11Helper::getCurrentLayout().toString();
#else
return m_keyboardLayoutMenu->keyboardLayoutName();
#endif
}
DataIndex *MainWindow::dataIndex()
{
return Application::dataIndex();
}
void MainWindow::showMenu(int xPos, int yPos)
{
m_menu->popup(m_view->mapToGlobal(QPoint(xPos, yPos)));
}
void MainWindow::showResourceEditor()
{
QSharedPointer<ResourceEditor>& resourceEditorRef = Application::resourceEditorRef();
if (resourceEditorRef.isNull())
{
resourceEditorRef = QSharedPointer<ResourceEditor>(new ResourceEditor());
}
ResourceEditor* resourceEditor = resourceEditorRef.data();
resourceEditor->show();
resourceEditor->activateWindow();
}
bool MainWindow::showCustomLessonDialog(Lesson* lesson, KeyboardLayout* keyboardLayout)
{
CustomLessonEditorDialog* dialog = new CustomLessonEditorDialog(this);
dialog->setLesson(lesson);
dialog->setKeyboardLayout(keyboardLayout);
bool result = dialog->exec() == QDialog::Accepted;
delete dialog;
return result;
}
void MainWindow::showConfigDialog()
{
if (KConfigDialog::showDialog("preferences"))
{
return;
}
KConfigDialog* dialog = new KConfigDialog(this, "preferences", Preferences::self());
dialog->setFaceType(KPageDialog::List);
dialog->setModal(true);
dialog->addPage(new TrainingConfigWidget(), i18n("Training"), "chronometer", i18n("Training Settings"));
dialog->addPage(new ColorsConfigWidget(), i18n("Colors"), "preferences-desktop-color", i18n("Color Settings"));
dialog->show();
}
void MainWindow::configureShortcuts()
{
KShortcutsDialog::configure(m_actionCollection, KShortcutsEditor::LetterShortcutsDisallowed, this);
}
void MainWindow::configureKeyboard()
{
QPointer<KCMultiDialog> kcm = new KCMultiDialog(this);
kcm->setWindowTitle(i18n("Configure Keyboard"));
kcm->addModule(keyboardKCMName);
kcm->exec();
delete kcm;
}
void MainWindow::setFullscreen(bool fullScreen)
{
KToggleFullScreenAction::setFullScreen(this, fullScreen);
}
void MainWindow::init()
{
m_actionCollection->addAssociatedWidget(this);
m_menu->addAction(KStandardAction::fullScreen(this, SLOT(setFullscreen(bool)), this, m_actionCollection));
m_menu->addSeparator();
QAction* editorAction = new QAction(i18n("Course and Keyboard Layout Editor..."), this);
connect(editorAction, &QAction::triggered, this, &MainWindow::showResourceEditor);
m_actionCollection->addAction("editor", editorAction);
m_menu->addAction(editorAction);
m_menu->addSeparator();
m_menu->addAction(KStandardAction::preferences(this, SLOT(showConfigDialog()), m_actionCollection));
m_menu->addAction(KStandardAction::keyBindings(this, SLOT(configureShortcuts()), m_actionCollection));
#ifdef KTOUCH_BUILD_WITH_X11
if (testKCMAvailibility(keyboardKCMName))
{
QAction* configureKeyboardAction = new QAction(i18n("Configure Keyboard..."), this);
m_menu->addAction(configureKeyboardAction);
connect(configureKeyboardAction, &QAction::triggered, this, &MainWindow::configureKeyboard);
}
#else
m_menu->addMenu(m_keyboardLayoutMenu);
#endif
m_menu->addSeparator();
KHelpMenu* helpMenu = new KHelpMenu(this);
m_menu->addMenu(helpMenu->menu());
setCentralWidget(m_view);
Application::setupDeclarativeBindings(m_view->engine());
m_view->setMinimumSize(1000, 700);
m_view->rootContext()->setContextProperty(QStringLiteral("ktouch"), this);
m_view->rootContext()->setContextProperty(QStringLiteral("ktouch"), m_context);
m_view->setResizeMode(QQuickWidget::SizeRootObjectToView);
m_view->setSource(QUrl::fromLocalFile(QStandardPaths::locate(QStandardPaths::DataLocation, "qml/main.qml")));
}
bool MainWindow::testKCMAvailibility(const QString& name)
{
KService::Ptr service = KService::serviceByStorageId(name + ".desktop");
if (!service)
{
return false;
}
return service->hasServiceType("KCModule") && !service->noDisplay();
}
......@@ -23,12 +23,8 @@
#include <QWeakPointer>
class QQuickWidget;
class QMenu;
class KActionCollection;
class DataIndex;
class ResourceEditor;
class KeyboardLayout;
class Lesson;
class KTouchContext;
#ifdef KTOUCH_BUILD_WITH_X11
class XEventNotifier;
......@@ -39,35 +35,13 @@ class KeyboardLayoutMenu;
class MainWindow : public KMainWindow
{
Q_OBJECT
Q_PROPERTY(QString keyboardLayoutName READ keyboardLayoutName NOTIFY keyboardLayoutNameChanged)
Q_PROPERTY(DataIndex* globalDataIndex READ dataIndex CONSTANT)
public:
explicit MainWindow(QWidget* parent = 0);
~MainWindow();
QString keyboardLayoutName() const;
DataIndex* dataIndex();
Q_INVOKABLE void showMenu(int xPos, int yPos);
public slots:
void showResourceEditor();
bool showCustomLessonDialog(Lesson* lesson, KeyboardLayout* keyboardLayout);
signals:
void keyboardLayoutNameChanged();
private slots:
void showConfigDialog();
void configureShortcuts();
void configureKeyboard();
void setFullscreen(bool fullscreen);
private:
void init();
bool testKCMAvailibility(const QString& name);
QQuickWidget* m_view;
KActionCollection* m_actionCollection;
QMenu* m_menu;
#ifdef KTOUCH_BUILD_WITH_X11
XEventNotifier* m_XEventNotifier;
#else
KeyboardLayoutMenu* m_keyboardLayoutMenu;
#endif
KTouchContext* m_context;
};
#endif // MAINWINDOW_H
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment