Commit 4d40f298 authored by Don Gagne's avatar Don Gagne

New MainWindow central and dock widget architecture

- Central widget no longer stacked. Views are added/removed to layout
to switch view
- Dock Widgets are globals with single instance of each type
- Both central views and dock widgets are just-in-time created saving
lots of memory
parent 78507bfe
......@@ -451,7 +451,6 @@ HEADERS += \
src/ui/QGCHilFlightGearConfiguration.h \
src/ui/QGCHilJSBSimConfiguration.h \
src/ui/QGCHilXPlaneConfiguration.h \
src/ui/submainwindow.h \
src/ui/uas/UASQuickView.h \
src/ui/uas/UASQuickViewItem.h \
src/ui/linechart/ChartPlot.h \
......@@ -480,7 +479,6 @@ HEADERS += \
src/ui/px4_configuration/PX4Bootloader.h \
src/ui/px4_configuration/PX4FirmwareUpgradeThread.h \
src/ui/px4_configuration/PX4FirmwareUpgrade.h \
src/ui/menuactionhelper.h \
src/uas/UASManagerInterface.h \
src/uas/QGCUASParamManagerInterface.h \
src/uas/QGCUASFileManager.h \
......@@ -495,6 +493,7 @@ HEADERS += \
src/QGCQuickWidget.h \
src/QGCPalette.h \
src/QGCQmlWidgetHolder.h \
src/QGCDockWidget.h \
SOURCES += \
src/main.cc \
......@@ -595,7 +594,6 @@ SOURCES += \
src/ui/QGCHilFlightGearConfiguration.cc \
src/ui/QGCHilJSBSimConfiguration.cc \
src/ui/QGCHilXPlaneConfiguration.cc \
src/ui/submainwindow.cpp \
src/ui/uas/UASQuickViewItem.cc \
src/ui/uas/UASQuickView.cc \
src/ui/linechart/ChartPlot.cc \
......@@ -624,7 +622,6 @@ SOURCES += \
src/ui/px4_configuration/PX4Bootloader.cc \
src/ui/px4_configuration/PX4FirmwareUpgradeThread.cc \
src/ui/px4_configuration/PX4FirmwareUpgrade.cc \
src/ui/menuactionhelper.cpp \
src/uas/QGCUASFileManager.cc \
src/ui/QGCUASFileView.cc \
src/CmdLineOptParser.cc \
......@@ -636,6 +633,7 @@ SOURCES += \
src/QGCQuickWidget.cc \
src/QGCPalette.cc \
src/QGCQmlWidgetHolder.cpp \
src/QGCDockWidget.cc \
#
# Unit Test specific configuration goes here
......
......@@ -12,7 +12,7 @@
// If you need to make an incompatible changes to stored settings, bump this version number
// up by 1. This will caused store settings to be cleared on next boot.
#define QGC_SETTINGS_VERSION 2
#define QGC_SETTINGS_VERSION 3
#define QGC_APPLICATION_NAME "QGroundControl"
#define QGC_ORG_NAME "QGroundControl.org"
......
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL 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 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
#include "QGCDockWidget.h"
#include <QCloseEvent>
QGCDockWidget::QGCDockWidget(const QString& title, QWidget *parent, Qt::WindowFlags flags) :
QDockWidget(title, parent, flags)
{
}
// Instead of destroying the widget just hide it
void QGCDockWidget::closeEvent(QCloseEvent* event)
{
event->ignore();
setVisible(false);
}
/*=====================================================================
QGroundControl Open Source Ground Control Station
(c) 2009 - 2014 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
This file is part of the QGROUNDCONTROL project
QGROUNDCONTROL 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 3 of the License, or
(at your option) any later version.
QGROUNDCONTROL 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 QGROUNDCONTROL. If not, see <http://www.gnu.org/licenses/>.
======================================================================*/
#ifndef QGCDockWidget_h
#define QGCDockWidget_h
#include <QDockWidget>
/// @file
/// @brief Subclass of QDockWidget so we can intercept the closeEvent.
///
/// @author Don Gagne <don@thegagnes.com>
class QGCDockWidget : public QDockWidget {
Q_OBJECT
public:
QGCDockWidget(const QString& title, QWidget *parent = 0, Qt::WindowFlags flags = 0);
void closeEvent(QCloseEvent* event);
};
#endif
This diff is collapsed.
This diff is collapsed.
......@@ -62,7 +62,6 @@
<addaction name="separator"/>
<addaction name="actionMuteAudioOutput"/>
<addaction name="actionSettings"/>
<addaction name="actionAdvanced_Mode"/>
<addaction name="separator"/>
<addaction name="actionExit"/>
</widget>
......
#include "menuactionhelper.h"
MenuActionHelper::MenuActionHelper(QObject *parent) : QObject(parent),
m_isAdvancedMode(false),
m_dockWidgetTitleBarsEnabled(true),
m_addedCustomSeperator(false)
{
}
QAction *MenuActionHelper::createToolAction(const QString &title, const QString &name)
{
QAction *action = m_menuToDockNameMap.key(name); //For sanity, check that the action is not NULL
if(action) {
qWarning() << "createToolAction was called for action" << name << "which already exists in the menu";
return action;
}
action = new QAction(title, NULL);
action->setCheckable(true);
connect(action,SIGNAL(triggered(bool)),this,SLOT(showTool(bool)));
m_menuToDockNameMap[action] = name;
m_menu->addAction(action);
return action;
}
void MenuActionHelper::removeDockWidget()
{
// Do not dynamic cast or de-reference QObject, since object is either in destructor or may have already
// been destroyed.
QObject *dockWidget = QObject::sender();
Q_ASSERT(dockWidget);
//qDebug() << "Dockwidget:" << dockWidget->objectName() << "of type" << dockWidget->metaObject()->className();
QAction *action = m_menuToDockNameMap.key(dockWidget->objectName());
if(action) {
m_menuToDockNameMap.remove(action);
action->deleteLater();
}
QMap<MainWindow::VIEW_SECTIONS,QMap<QString,QDockWidget*> >::iterator it;
for (it = m_centralWidgetToDockWidgetsMap.begin(); it != m_centralWidgetToDockWidgetsMap.end(); ++it) {
QMap<QString,QDockWidget*>::iterator it2 = it.value().begin();
while( it2 != it.value().end()) {
if(it2.value() == dockWidget)
it2 = it.value().erase(it2);
else
++it2;
}
}
//Don't delete the dockWidget because this could have been called from the dockWidget destructor
m_dockWidgets.removeAll(static_cast<QDockWidget*>(dockWidget));
}
QAction *MenuActionHelper::createToolActionForCustomDockWidget(const QString &title, const QString& name, QDockWidget* dockWidget, MainWindow::VIEW_SECTIONS view) {
bool found = false;
QAction *action = NULL;
foreach(QAction *act, m_menuToDockNameMap.keys()) {
if(act->text() == title) {
found = true;
action = act;
}
}
if(!found)
action = createToolAction(title, name);
else
m_menuToDockNameMap[action] = name;
m_centralWidgetToDockWidgetsMap[view][name] = dockWidget;
connect(dockWidget, SIGNAL(destroyed()), SLOT(removeDockWidget()),Qt::UniqueConnection); //Use UniqueConnection since we might have already created this connection in createDockWidget
connect(dockWidget, SIGNAL(visibilityChanged(bool)), action, SLOT(setChecked(bool)));
action->setChecked(dockWidget->isVisible());
return action;
}
QDockWidget* MenuActionHelper::createDockWidget(const QString& title,const QString& name)
{
QDockWidget *dockWidget = new QDockWidget(title);
m_dockWidgets.append(dockWidget);
setDockWidgetTitleBar(dockWidget);
dockWidget->setObjectName(name);
connect(dockWidget, SIGNAL(destroyed()), SLOT(removeDockWidget()));
return dockWidget;
}
bool MenuActionHelper::containsDockWidget(MainWindow::VIEW_SECTIONS view, const QString &name) const {
return m_centralWidgetToDockWidgetsMap.contains(view) && m_centralWidgetToDockWidgetsMap[view].contains(name);
}
QDockWidget *MenuActionHelper::getDockWidget(MainWindow::VIEW_SECTIONS view, const QString &name) const {
if(!m_centralWidgetToDockWidgetsMap.contains(view))
return NULL;
return m_centralWidgetToDockWidgetsMap[view].value(name);
}
void MenuActionHelper::showTool(bool show) {
//Called when a menu item is clicked on, regardless of view.
QAction* act = qobject_cast<QAction *>(sender());
Q_ASSERT(act);
if (m_menuToDockNameMap.contains(act)) {
QString name = m_menuToDockNameMap[act];
emit needToShowDockWidget(name, show);
}
}
void MenuActionHelper::setDockWidgetTitleBarsEnabled(bool enabled)
{
m_dockWidgetTitleBarsEnabled = enabled;
for (int i = 0; i < m_dockWidgets.size(); i++)
setDockWidgetTitleBar(m_dockWidgets[i]);
}
void MenuActionHelper::setAdvancedMode(bool advancedMode)
{
m_isAdvancedMode = advancedMode;
for (int i = 0; i < m_dockWidgets.size(); i++)
setDockWidgetTitleBar(m_dockWidgets[i]);
}
void MenuActionHelper::setDockWidgetTitleBar(QDockWidget* widget)
{
Q_ASSERT(widget);
QWidget* oldTitleBar = widget->titleBarWidget();
// In advanced mode, we use the default titlebar provided by Qt.
if (m_isAdvancedMode)
{
widget->setTitleBarWidget(0);
}
// Otherwise, if just a textlabel should be shown, make that the titlebar.
else if (m_dockWidgetTitleBarsEnabled)
{
QLabel* label = new QLabel(widget);
label->setText(widget->windowTitle());
label->installEventFilter(this); //Ignore mouse clicks
widget->installEventFilter(this); //Update label if window title changes. See eventFilter below
widget->setTitleBarWidget(label);
}
// And if nothing should be shown, use an empty widget.
else
{
QWidget* newTitleBar = new QWidget(widget);
widget->setTitleBarWidget(newTitleBar);
}
// Be sure to clean up the old titlebar. When using QDockWidget::setTitleBarWidget(),
// it doesn't delete the old titlebar object.
delete oldTitleBar;
}
bool MenuActionHelper::eventFilter(QObject *object,QEvent *event)
{
if (event->type() == QEvent::WindowTitleChange)
{
QDockWidget *dock = qobject_cast<QDockWidget *>(object);
if(dock) {
// Update the dock title bar label
QLabel *label = dynamic_cast<QLabel *>(dock->titleBarWidget());
if(label)
label->setText(dock->windowTitle());
// Now update the action label
QString oldObjectName = dock->objectName();
QAction *action = m_menuToDockNameMap.key(oldObjectName);
if(action)
action->setText(dock->windowTitle());
//Now modify the object name - it is a strange naming scheme..
}
} else if (event->type() == QEvent::MouseButtonPress || event->type() == QEvent::MouseButtonRelease)
{
if(qobject_cast<QLabel *>(object))
return true;
}
return QObject::eventFilter(object,event);
}
#ifndef MENUACTIONHELPER_H
#define MENUACTIONHELPER_H
#include "MainWindow.h"
#include <QDockWidget>
class MenuActionHelper : public QObject
{
Q_OBJECT
public:
MenuActionHelper(QObject *parent = NULL);
~MenuActionHelper() {}
/** @brief Get title bar mode setting */
bool dockWidgetTitleBarsEnabled() const { return m_dockWidgetTitleBarsEnabled; }
void setDockWidgetTitleBarsEnabled(bool enabled);
bool isAdvancedMode() const { return m_isAdvancedMode; }
void setAdvancedMode(bool advancedMode);
QAction *createToolAction(const QString &title, const QString &name = QString());
QAction *createToolActionForCustomDockWidget(const QString& title, const QString& name, QDockWidget* dockWidget, MainWindow::VIEW_SECTIONS view);
QDockWidget *createDockWidget(const QString& title, const QString& name);
bool containsDockWidget(MainWindow::VIEW_SECTIONS view, const QString &name) const;
QDockWidget *getDockWidget(MainWindow::VIEW_SECTIONS view, const QString &name) const;
/** QMenu to add QActions to */
void setMenu(QMenu *menu) { m_menu = menu; }
protected:
virtual bool eventFilter(QObject *object,QEvent *event);
private slots:
void removeDockWidget();
/** @brief Shows a Docked Widget based on the action sender */
void showTool(bool show);
signals:
void needToShowDockWidget(const QString& name, bool show);
private:
QMap<QAction*,QString > m_menuToDockNameMap;
QList<QDockWidget*> m_dockWidgets;
QMap<MainWindow::VIEW_SECTIONS,QMap<QString,QDockWidget*> > m_centralWidgetToDockWidgetsMap;
bool m_isAdvancedMode; ///< If enabled dock widgets can be moved and floated.
bool m_dockWidgetTitleBarsEnabled; ///< If enabled, dock widget titlebars are displayed when NOT in advanced mode.
QMenu *m_menu; ///< \see setMenu()
bool m_addedCustomSeperator; ///< Whether we have added a seperator between the actions and the custom actions
void setDockWidgetTitleBar(QDockWidget* widget);
};
#endif // MENUACTIONHELPER_H
#include "submainwindow.h"
SubMainWindow::SubMainWindow(QWidget *parent) : QMainWindow(parent)
{
}
#ifndef SUBMAINWINDOW_H
#define SUBMAINWINDOW_H
#include <QMainWindow>
class SubMainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit SubMainWindow(QWidget *parent = 0);
signals:
public slots:
};
#endif // SUBMAINWINDOW_H
Markdown is supported
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