mainwindow.cpp
421 lines
| 13.5 KiB
| text/x-c
|
CppLexer
Michal Klocek
|
r1126 | /**************************************************************************** | ||
Titta Heikkala
|
r2749 | ** | ||
** Copyright (C) 2014 Digia Plc | ||||
** All rights reserved. | ||||
** For any questions to Digia, please use contact form at http://qt.io | ||||
** | ||||
** This file is part of the Qt Charts module. | ||||
** | ||||
** Licensees holding valid commercial license for Qt may use this file in | ||||
** accordance with the Qt License Agreement provided with the Software | ||||
** or, alternatively, in accordance with the terms contained in a written | ||||
** agreement between you and Digia. | ||||
** | ||||
** If you have questions regarding the use of this file, please use | ||||
** contact form at http://qt.io | ||||
** | ||||
****************************************************************************/ | ||||
Michal Klocek
|
r1126 | |||
#include "mainwindow.h" | ||||
#include "objectinspectorwidget.h" | ||||
#include "penwidget.h" | ||||
#include "brushwidget.h" | ||||
#include "engine.h" | ||||
Titta Heikkala
|
r2714 | #include <QtCore/QSettings> | ||
#include <QtCharts/QChartView> | ||||
#include <QtWidgets/QDockWidget> | ||||
#include <QtWidgets/QMenuBar> | ||||
#include <QtWidgets/QTableWidget> | ||||
#include <QtWidgets/QSplitter> | ||||
#include <QtCore/QMetaEnum> | ||||
#include <QtGui/QStandardItemModel> | ||||
#include <QtWidgets/QHeaderView> | ||||
#include <QtCore/QDebug> | ||||
#include <QtWidgets/QMessageBox> | ||||
Michal Klocek
|
r1126 | |||
static const QString FILENAME_SETTING("filename"); | ||||
static const QString GEOMETRY_SETTING("geometry"); | ||||
MainWindow::MainWindow() : | ||||
m_engine(new Engine(this)), | ||||
m_view(new QChartView(m_engine->chart())), | ||||
m_scene(m_view->scene()), | ||||
m_table(new QTableView()), | ||||
m_addSeriesMenu(0), | ||||
m_seriesMenu(0), | ||||
m_chartMenu(0), | ||||
m_themeMenu(0), | ||||
m_animationMenu(0), | ||||
m_zoomMenu(0), | ||||
m_removeAllAction(0), | ||||
m_legendAction(0), | ||||
m_antialiasingAction(0) | ||||
{ | ||||
createMenus(); | ||||
createDockWidgets(); | ||||
createTable(); | ||||
createLayout(); | ||||
QSettings settings; | ||||
restoreGeometry(settings.value(GEOMETRY_SETTING).toByteArray()); | ||||
m_filename = settings.value(FILENAME_SETTING).toString(); | ||||
if (m_filename.isEmpty()) | ||||
m_filename = "untitled"; | ||||
setWindowTitle(m_filename); | ||||
updateUI(); | ||||
} | ||||
MainWindow::~MainWindow() | ||||
{ | ||||
delete m_engine; | ||||
} | ||||
void MainWindow::createMenus() | ||||
{ | ||||
QMenu *file = menuBar()->addMenu(tr("File")); | ||||
QMenu *edit = menuBar()->addMenu(tr("Edit")); | ||||
m_seriesMenu = menuBar()->addMenu(tr("Series")); | ||||
m_chartMenu = menuBar()->addMenu(tr("Chart")); | ||||
m_addSeriesMenu = new QMenu(tr("Add series")); | ||||
m_themeMenu = new QMenu(tr("Apply theme")); | ||||
m_animationMenu = new QMenu(tr("Animations")); | ||||
m_zoomMenu = new QMenu(tr("Zoom")); | ||||
file->addAction(tr("New"), this, SLOT(handleNewAction())); | ||||
file->addAction(tr("Load"), this, SLOT(handleLoadAction())); | ||||
file->addAction(tr("Save"), this, SLOT(handleSaveAction())); | ||||
file->addAction(tr("Save As"), this, SLOT(handleSaveAsAction())); | ||||
//seriesMenu | ||||
m_seriesMenu->addMenu(m_addSeriesMenu); | ||||
m_removeAllAction = new QAction(tr("Remove all series"), this); | ||||
QObject::connect(m_removeAllAction, SIGNAL(triggered()), this, SLOT(handleRemoveAllSeriesAction())); | ||||
m_seriesMenu->addAction(m_removeAllAction); | ||||
m_seriesMenu->addSeparator(); | ||||
//seriesMenu /addSeriesMenu | ||||
{ | ||||
int index = QAbstractSeries::staticMetaObject.indexOfEnumerator("SeriesType"); | ||||
QMetaEnum metaEnum = QAbstractSeries::staticMetaObject.enumerator(index); | ||||
int count = metaEnum.keyCount(); | ||||
for (int i = 0; i < count; ++i) { | ||||
QAction* action = new QAction(metaEnum.key(i), this); | ||||
action->setData(metaEnum.value(i)); | ||||
m_addSeriesMenu->addAction(action); | ||||
QObject::connect(action, SIGNAL(triggered()), this, SLOT(handleAddSeriesMenu())); | ||||
} | ||||
} | ||||
//chartMenu / themeMenu | ||||
{ | ||||
m_chartMenu->addMenu(m_themeMenu); | ||||
int index = QChart::staticMetaObject.indexOfEnumerator("ChartTheme"); | ||||
QMetaEnum metaEnum = QChart::staticMetaObject.enumerator(index); | ||||
int count = metaEnum.keyCount(); | ||||
for (int i = 0; i < count; ++i) { | ||||
QAction* action = new QAction(metaEnum.key(i), this); | ||||
action->setData(metaEnum.value(i)); | ||||
action->setCheckable(true); | ||||
m_themeMenu->addAction(action); | ||||
QObject::connect(action, SIGNAL(triggered()), this, SLOT(handleThemeMenu())); | ||||
} | ||||
} | ||||
//chartMenu / animationMenu | ||||
{ | ||||
m_chartMenu->addMenu(m_animationMenu); | ||||
int index = QChart::staticMetaObject.indexOfEnumerator("AnimationOption"); | ||||
QMetaEnum metaEnum = QChart::staticMetaObject.enumerator(index); | ||||
int count = metaEnum.keyCount(); | ||||
for (int i = 0; i < count; ++i) { | ||||
QAction* action = new QAction(metaEnum.key(i), this); | ||||
action->setData(metaEnum.value(i)); | ||||
action->setCheckable(true); | ||||
m_animationMenu->addAction(action); | ||||
QObject::connect(action, SIGNAL(triggered()), this, SLOT(handleAnimationMenu())); | ||||
} | ||||
} | ||||
//chartMenu / zoomMenu | ||||
{ | ||||
m_chartMenu->addMenu(m_zoomMenu); | ||||
int index = QChartView::staticMetaObject.indexOfEnumerator("RubberBand"); | ||||
QMetaEnum metaEnum = QChartView::staticMetaObject.enumerator(index); | ||||
int count = metaEnum.keyCount(); | ||||
for (int i = 0; i < count; ++i) { | ||||
QAction* action = new QAction(metaEnum.key(i), this); | ||||
action->setData(metaEnum.value(i)); | ||||
action->setCheckable(true); | ||||
m_zoomMenu->addAction(action); | ||||
QObject::connect(action, SIGNAL(triggered()), this, SLOT(handleZoomMenu())); | ||||
} | ||||
} | ||||
//chartMenu / legend | ||||
m_legendAction = new QAction(tr("Legend"), this); | ||||
m_legendAction->setCheckable(true); | ||||
m_chartMenu->addAction(m_legendAction); | ||||
QObject::connect(m_legendAction, SIGNAL(triggered()), this, SLOT(handleLegendAction())); | ||||
//chartMenu / Anti-aliasing | ||||
m_antialiasingAction = new QAction(tr("Anti-aliasing"), this); | ||||
m_antialiasingAction->setCheckable(true); | ||||
m_chartMenu->addAction(m_antialiasingAction); | ||||
QObject::connect(m_antialiasingAction, SIGNAL(triggered()), this, SLOT(handleAntialiasingAction())); | ||||
} | ||||
void MainWindow::createDockWidgets() | ||||
{ | ||||
m_brushWidget = new BrushWidget(); | ||||
QDockWidget *brushDockWidget = new QDockWidget(tr("Brush"), this); | ||||
brushDockWidget->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); | ||||
brushDockWidget->setWidget(m_brushWidget); | ||||
addDockWidget(Qt::RightDockWidgetArea, brushDockWidget); | ||||
m_penWidget = new PenWidget(); | ||||
QDockWidget *penDockWidget = new QDockWidget(tr("Pen"), this); | ||||
penDockWidget->setFeatures(QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); | ||||
penDockWidget->setWidget(m_penWidget); | ||||
addDockWidget(Qt::RightDockWidgetArea, penDockWidget); | ||||
m_inspectorWidget = new InspectorWidget(); | ||||
QDockWidget *inspectorDockWidget = new QDockWidget(tr("Object Inspector"), this); | ||||
inspectorDockWidget->setFeatures( | ||||
QDockWidget::DockWidgetMovable | QDockWidget::DockWidgetFloatable); | ||||
inspectorDockWidget->setWidget(m_inspectorWidget); | ||||
addDockWidget(Qt::RightDockWidgetArea, inspectorDockWidget); | ||||
setDockOptions(QMainWindow::AnimatedDocks); | ||||
} | ||||
void MainWindow::createLayout() | ||||
{ | ||||
Titta Heikkala
|
r2712 | m_table->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); | ||
Michal Klocek
|
r1126 | |||
int rowHeight = m_table->rowHeight(0); | ||||
int tableHeight = (m_engine->modelCount() * rowHeight) + m_table->horizontalHeader()->height() + 2 * m_table->frameWidth(); | ||||
m_table->setMinimumHeight(tableHeight); | ||||
m_table->setMaximumHeight(tableHeight); | ||||
QSplitter *splitter = new QSplitter(this); | ||||
splitter->setOrientation(Qt::Vertical); | ||||
splitter->addWidget(m_table); | ||||
splitter->addWidget(m_view); | ||||
setCentralWidget(splitter); | ||||
m_view->hide(); | ||||
} | ||||
void MainWindow::createTable() | ||||
{ | ||||
m_table->setModel(m_engine->model()); | ||||
m_table->setSelectionModel(m_engine->selectionModel()); | ||||
Jani Honkonen
|
r2110 | QObject::connect(m_table->selectionModel(),SIGNAL(selectionChanged(QItemSelection,QItemSelection)), this,SLOT(updateUI())); | ||
Michal Klocek
|
r1126 | } | ||
void MainWindow::updateUI() | ||||
{ | ||||
QItemSelectionModel* selection = m_table->selectionModel(); | ||||
const QModelIndexList& list = selection->selectedIndexes(); | ||||
QMap<int, QModelIndex> columns; | ||||
Jani Honkonen
|
r2100 | foreach (const QModelIndex& index, list) { | ||
Michal Klocek
|
r1126 | columns.insertMulti(index.column(), index); | ||
} | ||||
QList<int> keys = columns.uniqueKeys(); | ||||
bool seriesEnabled = false; | ||||
Jani Honkonen
|
r2100 | foreach (QAction* action, m_addSeriesMenu->actions()) { | ||
Michal Klocek
|
r1126 | switch (action->data().toInt()) { | ||
case QAbstractSeries::SeriesTypeLine: | ||||
case QAbstractSeries::SeriesTypeSpline: | ||||
case QAbstractSeries::SeriesTypeScatter: | ||||
action->setEnabled(list.count() > 0 && keys.count() >= 2); | ||||
seriesEnabled |= action->isEnabled(); | ||||
break; | ||||
case QAbstractSeries::SeriesTypeBar: | ||||
case QAbstractSeries::SeriesTypePercentBar: | ||||
case QAbstractSeries::SeriesTypeStackedBar: | ||||
action->setEnabled(list.count() > 0 && keys.count() >= 2); | ||||
seriesEnabled |= action->isEnabled(); | ||||
break; | ||||
case QAbstractSeries::SeriesTypePie: | ||||
action->setEnabled(list.count() > 0 && keys.count() == 2); | ||||
seriesEnabled |= action->isEnabled(); | ||||
break; | ||||
case QAbstractSeries::SeriesTypeArea: | ||||
action->setEnabled(list.count() > 0 && keys.count() == 3); | ||||
seriesEnabled |= action->isEnabled(); | ||||
break; | ||||
} | ||||
} | ||||
m_chartMenu->setEnabled(m_engine->chart()->series().count() > 0); | ||||
m_seriesMenu->setEnabled(seriesEnabled || m_engine->chart()->series().count() > 0); | ||||
m_removeAllAction->setEnabled(m_engine->chart()->series().count() > 0); | ||||
int theme = m_engine->chart()->theme(); | ||||
Jani Honkonen
|
r2100 | foreach (QAction* action, m_themeMenu->actions()) { | ||
Michal Klocek
|
r1126 | action->setChecked(action->data().toInt() == theme); | ||
} | ||||
int animation = m_engine->chart()->animationOptions(); | ||||
Jani Honkonen
|
r2100 | foreach (QAction* action, m_animationMenu->actions()) { | ||
Michal Klocek
|
r1126 | action->setChecked(action->data().toInt() == animation); | ||
} | ||||
int zoom = m_view->rubberBand(); | ||||
Jani Honkonen
|
r2100 | foreach (QAction* action, m_zoomMenu->actions()) { | ||
Michal Klocek
|
r1126 | action->setChecked(action->data().toInt() == zoom); | ||
} | ||||
m_legendAction->setChecked(m_engine->chart()->legend()->isVisible()); | ||||
m_antialiasingAction->setChecked(m_view->renderHints().testFlag(QPainter::Antialiasing)); | ||||
Jani Honkonen
|
r2100 | foreach (QAction *action, m_seriesMenu->actions()) { | ||
Michal Klocek
|
r1126 | //TODO: visibility handling | ||
//if (m_series.value(action->text())) | ||||
// ; | ||||
//action->setChecked(false); | ||||
} | ||||
} | ||||
void MainWindow::closeEvent(QCloseEvent *event) | ||||
{ | ||||
QSettings settings; | ||||
settings.setValue(GEOMETRY_SETTING, saveGeometry()); | ||||
settings.setValue(FILENAME_SETTING, m_filename); | ||||
QMainWindow::closeEvent(event); | ||||
} | ||||
//handlers | ||||
void MainWindow::handleNewAction() | ||||
{ | ||||
m_engine->chart()->removeAllSeries(); | ||||
m_view->hide(); | ||||
m_engine->clearModels(); | ||||
createTable(); | ||||
m_filename = "untitled"; | ||||
setWindowTitle(m_filename); | ||||
updateUI(); | ||||
} | ||||
void MainWindow::handleAddSeriesMenu() | ||||
{ | ||||
m_view->show(); | ||||
QAction* action = qobject_cast<QAction*>(sender()); | ||||
QList<QAbstractSeries*> series = m_engine->addSeries(QAbstractSeries::SeriesType(action->data().toInt())); | ||||
Jani Honkonen
|
r2100 | foreach (QAbstractSeries* s , series) | ||
Michal Klocek
|
r1126 | { | ||
QAction *newAction = new QAction(s->name(),this); | ||||
//newAction->setCheckable(true); | ||||
m_series.insert(s->name(),s); | ||||
m_seriesMenu->addAction(newAction); | ||||
} | ||||
updateUI(); | ||||
} | ||||
void MainWindow::handleRemoveAllSeriesAction() | ||||
{ | ||||
Jani Honkonen
|
r2100 | foreach (QAction* action, m_seriesMenu->actions()){ | ||
Michal Klocek
|
r1126 | if(m_series.contains(action->text())){ | ||
m_seriesMenu->removeAction(action); | ||||
m_engine->removeSeries(m_series.value(action->text())); | ||||
delete action; | ||||
} | ||||
} | ||||
m_series.clear(); | ||||
m_view->hide(); | ||||
updateUI(); | ||||
} | ||||
void MainWindow::handleThemeMenu() | ||||
{ | ||||
QAction* action = qobject_cast<QAction*>(sender()); | ||||
m_engine->chart()->setTheme(QChart::ChartTheme(action->data().toInt())); | ||||
updateUI(); | ||||
} | ||||
void MainWindow::handleAnimationMenu() | ||||
{ | ||||
QAction* action = qobject_cast<QAction*>(sender()); | ||||
m_engine->chart()->setAnimationOptions(QChart::AnimationOption(action->data().toInt())); | ||||
updateUI(); | ||||
} | ||||
void MainWindow::handleZoomMenu() | ||||
{ | ||||
QAction* action = qobject_cast<QAction*>(sender()); | ||||
m_view->setRubberBand(QChartView::RubberBand(action->data().toInt())); | ||||
updateUI(); | ||||
} | ||||
void MainWindow::handleAntialiasingAction() | ||||
{ | ||||
QAction* action = qobject_cast<QAction*>(sender()); | ||||
if (action->isChecked()) { | ||||
m_view->setRenderHint(QPainter::Antialiasing, true); | ||||
} | ||||
else { | ||||
m_view->setRenderHint(QPainter::Antialiasing, false); | ||||
} | ||||
} | ||||
void MainWindow::handleLegendAction() | ||||
{ | ||||
QAction* action = qobject_cast<QAction*>(sender()); | ||||
if (action->isChecked()) { | ||||
m_engine->chart()->legend()->setVisible(true); | ||||
} | ||||
else { | ||||
m_engine->chart()->legend()->setVisible(false); | ||||
} | ||||
} | ||||
void MainWindow::handleSaveAction() | ||||
{ | ||||
if(!m_engine->save(m_filename)) { | ||||
QScopedPointer<QMessageBox> messageBox(new QMessageBox(this)); | ||||
messageBox->setIcon(QMessageBox::Warning); | ||||
messageBox->setWindowModality(Qt::WindowModal); | ||||
messageBox->setWindowTitle(QString(tr("Error"))); | ||||
messageBox->setText(tr("Could not write to ") + m_filename); | ||||
messageBox->exec(); | ||||
} | ||||
} | ||||
void MainWindow::handleLoadAction() | ||||
{ | ||||
if(!m_engine->load(m_filename)) { | ||||
QScopedPointer<QMessageBox> messageBox(new QMessageBox(this)); | ||||
messageBox->setIcon(QMessageBox::Warning); | ||||
messageBox->setWindowModality(Qt::WindowModal); | ||||
messageBox->setWindowTitle(QString(tr("Error"))); | ||||
messageBox->setText(tr("Could not open ") + m_filename); | ||||
messageBox->exec(); | ||||
}else createTable(); | ||||
} | ||||