1
0
mirror of https://github.com/tumic0/GPXSee.git synced 2024-10-07 07:13:21 +02:00
GPXSee/src/gui.cpp

449 lines
12 KiB
C++
Raw Normal View History

2015-10-05 01:43:48 +02:00
#include <QApplication>
#include <QVBoxLayout>
#include <QMenuBar>
#include <QStatusBar>
#include <QMessageBox>
#include <QFileDialog>
#include <QPrinter>
#include <QPainter>
#include <QKeyEvent>
#include "config.h"
#include "icons.h"
#include "keys.h"
#include "gpx.h"
2015-10-12 01:12:12 +02:00
#include "elevationgraph.h"
#include "speedgraph.h"
2015-10-05 01:43:48 +02:00
#include "track.h"
#include "infoitem.h"
2015-10-20 22:18:41 +02:00
#include "filebrowser.h"
#include "gui.h"
2015-10-05 01:43:48 +02:00
#include <QDebug>
2015-10-14 02:54:36 +02:00
static QString timeSpan(qreal time)
{
unsigned h, m, s;
h = time / 3600;
m = (time - (h * 3600)) / 60;
s = time - (h * 3600) - (m * 60);
return QString("%1:%2:%3").arg(h).arg(m, 2, 10, QChar('0'))
.arg(s,2, 10, QChar('0'));
}
2015-10-20 22:18:41 +02:00
2015-10-05 01:43:48 +02:00
GUI::GUI()
{
createActions();
createMenus();
createToolBars();
createTrackView();
createTrackGraphs();
createStatusBar();
connect(_elevationGraph, SIGNAL(sliderPositionChanged(qreal)), _track,
SLOT(movePositionMarker(qreal)));
connect(_speedGraph, SIGNAL(sliderPositionChanged(qreal)), _track,
SLOT(movePositionMarker(qreal)));
2015-10-20 22:18:41 +02:00
_browser = new FileBrowser(this);
_browser->setFilter(QStringList("*.gpx"));
2015-10-05 01:43:48 +02:00
QVBoxLayout *layout = new QVBoxLayout;
layout->addWidget(_track);
layout->addWidget(_trackGraphs);
QWidget *widget = new QWidget;
widget->setLayout(layout);
setCentralWidget(widget);
setWindowTitle(APP_NAME);
setUnifiedTitleAndToolBarOnMac(true);
2015-10-14 02:54:36 +02:00
_distance = 0;
_time = 0;
2015-10-05 01:43:48 +02:00
resize(600, 800);
}
void GUI::createActions()
{
// Action Groups
_fileActionGroup = new QActionGroup(this);
_fileActionGroup->setExclusive(false);
_fileActionGroup->setEnabled(false);
// General actions
_exitAction = new QAction(QIcon(QPixmap(QUIT_ICON)), tr("Quit"), this);
_exitAction->setShortcut(QKeySequence::Quit);
2015-10-05 01:43:48 +02:00
connect(_exitAction, SIGNAL(triggered()), this, SLOT(close()));
2015-10-21 01:09:17 +02:00
// Help & About
_keysAction = new QAction(tr("Keyboard controls"), this);
connect(_keysAction, SIGNAL(triggered()), this, SLOT(keys()));
2015-10-05 01:43:48 +02:00
_aboutAction = new QAction(QIcon(QPixmap(APP_ICON)),
tr("About GPXSee"), this);
connect(_aboutAction, SIGNAL(triggered()), this, SLOT(about()));
_aboutQtAction = new QAction(QIcon(QPixmap(QT_ICON)), tr("About Qt"), this);
2015-10-05 01:43:48 +02:00
connect(_aboutQtAction, SIGNAL(triggered()), qApp, SLOT(aboutQt()));
// File related actions
_openFileAction = new QAction(QIcon(QPixmap(OPEN_FILE_ICON)),
tr("Open"), this);
_openFileAction->setShortcut(QKeySequence::Open);
2015-10-05 01:43:48 +02:00
connect(_openFileAction, SIGNAL(triggered()), this, SLOT(openFile()));
_saveFileAction = new QAction(QIcon(QPixmap(SAVE_FILE_ICON)),
tr("Save"), this);
_saveFileAction->setShortcut(QKeySequence::Save);
2015-10-05 01:43:48 +02:00
_saveFileAction->setActionGroup(_fileActionGroup);
connect(_saveFileAction, SIGNAL(triggered()), this, SLOT(saveFile()));
_saveAsAction = new QAction(QIcon(QPixmap(SAVE_AS_ICON)),
tr("Save as"), this);
_saveAsAction->setShortcut(QKeySequence::SaveAs);
2015-10-05 01:43:48 +02:00
_saveAsAction->setActionGroup(_fileActionGroup);
connect(_saveAsAction, SIGNAL(triggered()), this, SLOT(saveAs()));
_closeFileAction = new QAction(QIcon(QPixmap(CLOSE_FILE_ICON)),
tr("Close"), this);
_closeFileAction->setShortcut(QKeySequence::Close);
2015-10-05 01:43:48 +02:00
_closeFileAction->setActionGroup(_fileActionGroup);
connect(_closeFileAction, SIGNAL(triggered()), this, SLOT(closeFile()));
2015-10-20 22:18:41 +02:00
_reloadFileAction = new QAction(QIcon(QPixmap(RELOAD_FILE_ICON)),
tr("Reload"), this);
_reloadFileAction->setShortcut(QKeySequence::Refresh);
_reloadFileAction->setActionGroup(_fileActionGroup);
connect(_reloadFileAction, SIGNAL(triggered()), this, SLOT(reloadFile()));
2015-10-05 01:43:48 +02:00
// POI actions
_openPOIAction = new QAction(QIcon(QPixmap(OPEN_FILE_ICON)),
tr("Load file"), this);
connect(_openPOIAction, SIGNAL(triggered()), this, SLOT(openPOIFile()));
_showPOIAction = new QAction(QIcon(QPixmap(SHOW_POI_ICON)),
tr("Show"), this);
_showPOIAction->setCheckable(true);
connect(_showPOIAction, SIGNAL(triggered()), this, SLOT(showPOI()));
}
void GUI::createMenus()
{
_fileMenu = menuBar()->addMenu(tr("File"));
_fileMenu->addAction(_openFileAction);
_fileMenu->addSeparator();
2015-10-05 01:43:48 +02:00
_fileMenu->addAction(_saveFileAction);
_fileMenu->addAction(_saveAsAction);
_fileMenu->addSeparator();
2015-10-20 22:18:41 +02:00
_fileMenu->addAction(_reloadFileAction);
_fileMenu->addSeparator();
2015-10-05 01:43:48 +02:00
_fileMenu->addAction(_closeFileAction);
2015-10-06 23:54:43 +02:00
#ifndef __APPLE__
_fileMenu->addSeparator();
2015-10-05 01:43:48 +02:00
_fileMenu->addAction(_exitAction);
2015-10-06 23:54:43 +02:00
#endif // __APPLE__
2015-10-05 01:43:48 +02:00
_poiMenu = menuBar()->addMenu(tr("POI"));
_poiMenu->addAction(_openPOIAction);
_poiMenu->addAction(_showPOIAction);
2015-10-21 01:09:17 +02:00
_helpMenu = menuBar()->addMenu(tr("Help"));
_helpMenu->addAction(_keysAction);
_helpMenu->addSeparator();
_helpMenu->addAction(_aboutAction);
_helpMenu->addAction(_aboutQtAction);
2015-10-05 01:43:48 +02:00
}
void GUI::createToolBars()
{
_fileToolBar = addToolBar(tr("File"));
_fileToolBar->addAction(_openFileAction);
_fileToolBar->addAction(_saveFileAction);
2015-10-20 22:18:41 +02:00
_fileToolBar->addAction(_reloadFileAction);
2015-10-05 01:43:48 +02:00
_fileToolBar->addAction(_closeFileAction);
#ifdef __APPLE__
_fileToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
#endif // __APPLE__
2015-10-05 01:43:48 +02:00
_poiToolBar = addToolBar(tr("POI"));
_poiToolBar->addAction(_showPOIAction);
#ifdef __APPLE__
_poiToolBar->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
#endif // __APPLE__
2015-10-05 01:43:48 +02:00
}
void GUI::createTrackView()
{
_track = new Track(this);
}
void GUI::createTrackGraphs()
{
2015-10-12 01:12:12 +02:00
_elevationGraph = new ElevationGraph;
_speedGraph = new SpeedGraph;
2015-10-05 01:43:48 +02:00
_trackGraphs = new QTabWidget;
_trackGraphs->addTab(_elevationGraph, tr("Elevation"));
_trackGraphs->addTab(_speedGraph, tr("Speed"));
connect(_trackGraphs, SIGNAL(currentChanged(int)), this,
SLOT(graphChanged(int)));
_trackGraphs->setFixedHeight(200);
_trackGraphs->setSizePolicy(
QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed));
}
void GUI::createStatusBar()
{
2015-10-14 02:54:36 +02:00
_fileNameLabel = new QLabel();
_distanceLabel = new QLabel();
_timeLabel = new QLabel();
_distanceLabel->setAlignment(Qt::AlignHCenter);
_timeLabel->setAlignment(Qt::AlignHCenter);
statusBar()->addPermanentWidget(_fileNameLabel, 8);
statusBar()->addPermanentWidget(_distanceLabel, 1);
statusBar()->addPermanentWidget(_timeLabel, 1);
2015-10-05 01:43:48 +02:00
statusBar()->setSizeGripEnabled(false);
}
void GUI::about()
{
QMessageBox msgBox(this);
msgBox.setWindowTitle(tr("About GPXSee"));
msgBox.setText(QString("<h3>") + QString(APP_NAME" "APP_VERSION)
+ QString("</h3><p>") + tr("GPX viewer and analyzer") + QString("<p/>"));
msgBox.setInformativeText(QString("<table width=\"300\"><tr><td>")
+ tr("GPXSee is distributed under the terms of the GNU General Public "
"License version 3. For more info about GPXSee visit the project "
"homepage at ") + QString("<a href=\""APP_HOMEPAGE"\">"APP_HOMEPAGE
"</a>.</td></tr></table>"));
QIcon icon = msgBox.windowIcon();
QSize size = icon.actualSize(QSize(64, 64));
msgBox.setIconPixmap(icon.pixmap(size));
msgBox.exec();
2015-10-05 01:43:48 +02:00
}
2015-10-21 01:09:17 +02:00
void GUI::keys()
{
QMessageBox msgBox(this);
msgBox.setWindowTitle(tr("Keyboard controls"));
msgBox.setText(QString("<h3>") + tr("Keyboard controls") + QString("</h3>"));
msgBox.setInformativeText(
QString("<div><table width=\"300\"><tr><td>") + tr("Next file")
2015-10-21 01:09:17 +02:00
+ QString("</td><td><i>SPACE</i></td></tr><tr><td>") + tr("Previous file")
+ QString("</td><td><i>BACKSPACE</i></td></tr><tr><td>")
+ tr("Append modifier") + QString("</td><td><i>SHIFT</i></td></tr>"
"</table></div>"));
2015-10-21 01:09:17 +02:00
msgBox.exec();
}
2015-10-05 01:43:48 +02:00
void GUI::openFile()
{
QStringList files = QFileDialog::getOpenFileNames(this, tr("Open file"));
QStringList list = files;
2015-10-07 01:30:03 +02:00
for (QStringList::Iterator it = list.begin(); it != list.end(); it++)
2015-10-20 22:18:41 +02:00
openFile(*it);
2015-10-05 01:43:48 +02:00
}
bool GUI::openFile(const QString &fileName)
{
2015-10-20 22:18:41 +02:00
if (fileName.isEmpty() || _files.contains(fileName))
return false;
if (loadFile(fileName)) {
_files.append(fileName);
_browser->setCurrent(fileName);
updateStatusBarInfo();
_fileActionGroup->setEnabled(true);
return true;
} else
return false;
}
2015-10-05 01:43:48 +02:00
2015-10-20 22:18:41 +02:00
bool GUI::loadFile(const QString &fileName)
{
GPX gpx;
2015-10-17 12:08:30 +02:00
2015-10-20 22:18:41 +02:00
if (gpx.loadFile(fileName)) {
_elevationGraph->loadGPX(gpx);
_speedGraph->loadGPX(gpx);
_track->loadGPX(gpx);
if (_showPOIAction->isChecked())
_track->loadPOI(_poi);
2015-10-17 12:08:30 +02:00
2015-10-20 22:18:41 +02:00
_distance += gpx.distance();
_time += gpx.time();
2015-10-05 01:43:48 +02:00
2015-10-20 22:18:41 +02:00
return true;
} else {
QMessageBox::critical(this, tr("Error"), fileName + QString("\n\n")
+ tr("Error loading GPX file:\n%1").arg(gpx.errorString()));
return false;
2015-10-05 01:43:48 +02:00
}
}
void GUI::openPOIFile()
{
QString fileName = QFileDialog::getOpenFileName(this, tr("Open POI file"));
if (!fileName.isEmpty()) {
if (!_poi.loadFile(fileName)) {
QMessageBox::critical(this, tr("Error"),
tr("Error loading POI file:\n%1").arg(_poi.errorString()));
} else {
_showPOIAction->setChecked(true);
_track->loadPOI(_poi);
}
}
}
void GUI::saveAs()
{
QString fileName = QFileDialog::getSaveFileName(this, "Export to PDF",
QString(), "*.pdf");
if (!fileName.isEmpty()) {
saveFile(fileName);
_saveFileName = fileName;
}
}
void GUI::saveFile()
{
if (_saveFileName.isEmpty())
emit saveAs();
else
saveFile(_saveFileName);
}
void GUI::saveFile(const QString &fileName)
{
QPrinter printer(QPrinter::HighResolution);
printer.setPageSize(QPrinter::A4);
printer.setOrientation(_track->orientation());
printer.setOutputFormat(QPrinter::PdfFormat);
printer.setOutputFileName(fileName);
QPainter p(&printer);
_track->plot(&p, QRectF(0, 300, printer.width(), (0.80 * printer.height())
- 400));
2015-10-05 01:43:48 +02:00
_elevationGraph->plot(&p, QRectF(0, 0.80 * printer.height(),
printer.width(), printer.height() * 0.20));
QGraphicsScene scene;
InfoItem info;
2015-10-19 09:54:29 +02:00
info.insert(tr("Distance"), QString::number(_distance / 1000, 'f', 1)
+ THIN_SPACE + tr("km"));
info.insert(tr("Time"), timeSpan(_time));
info.insert(tr("Ascent"), QString::number(_elevationGraph->ascent(), 'f', 0)
+ THIN_SPACE + tr("m"));
info.insert(tr("Descent"), QString::number(_elevationGraph->descent(), 'f',
0) + THIN_SPACE + tr("m"));
info.insert(tr("Maximum"), QString::number(_elevationGraph->max(), 'f', 0)
+ THIN_SPACE + tr("m"));
info.insert(tr("Minimum"), QString::number(_elevationGraph->min(), 'f', 0)
+ THIN_SPACE + tr("m"));
scene.addItem(&info);
scene.render(&p, QRectF(0, 0, printer.width(), 200));
2015-10-05 01:43:48 +02:00
p.end();
}
2015-10-20 22:18:41 +02:00
void GUI::reloadFile()
{
_distance = 0;
_time = 0;
_elevationGraph->clear();
_speedGraph->clear();
_track->clear();
for (int i = 0; i < _files.size(); i++) {
if (!loadFile(_files.at(i))) {
_files.removeAt(i);
i--;
}
}
updateStatusBarInfo();
if (_files.isEmpty())
_fileActionGroup->setEnabled(false);
else
_browser->setCurrent(_files.last());
}
2015-10-05 01:43:48 +02:00
void GUI::closeFile()
{
2015-10-14 02:54:36 +02:00
_distance = 0;
_time = 0;
2015-10-12 01:12:12 +02:00
2015-10-05 01:43:48 +02:00
_elevationGraph->clear();
_speedGraph->clear();
_track->clear();
2015-10-20 22:18:41 +02:00
_files.clear();
2015-10-05 01:43:48 +02:00
_fileActionGroup->setEnabled(false);
2015-10-20 22:18:41 +02:00
updateStatusBarInfo();
2015-10-05 01:43:48 +02:00
}
void GUI::showPOI()
{
if (_showPOIAction->isChecked())
_track->loadPOI(_poi);
else
_track->clearPOI();
}
2015-10-20 22:18:41 +02:00
void GUI::updateStatusBarInfo()
2015-10-17 12:08:30 +02:00
{
2015-10-20 22:18:41 +02:00
int files = _files.size();
if (files == 0) {
_fileNameLabel->clear();
_distanceLabel->clear();
_timeLabel->clear();
return;
} else if (files == 1)
_fileNameLabel->setText(_files.at(0));
2015-10-17 12:08:30 +02:00
else
2015-10-20 22:18:41 +02:00
_fileNameLabel->setText(tr("%1 tracks").arg(_files.size()));
2015-10-17 12:08:30 +02:00
_distanceLabel->setText(QString::number(_distance / 1000, 'f', 1)
+ " " + tr("km"));
_timeLabel->setText(timeSpan(_time));
}
2015-10-05 01:43:48 +02:00
void GUI::graphChanged(int index)
{
if (_trackGraphs->widget(index) == _elevationGraph)
_elevationGraph->setSliderPosition(_speedGraph->sliderPosition());
else if (_trackGraphs->widget(index) == _speedGraph)
_speedGraph->setSliderPosition(_elevationGraph->sliderPosition());
}
void GUI::keyPressEvent(QKeyEvent *event)
{
2015-10-20 22:18:41 +02:00
QString file;
2015-10-05 01:43:48 +02:00
2015-10-20 22:18:41 +02:00
if (event->key() == PREV_KEY)
file = _browser->prev();
if (event->key() == NEXT_KEY)
file = _browser->next();
2015-10-05 01:43:48 +02:00
2015-10-20 22:18:41 +02:00
if (!file.isNull()) {
if (!(event->modifiers() & MODIFIER))
closeFile();
openFile(file);
}
2015-10-05 01:43:48 +02:00
}