mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-13 16:18:42 +00:00
File Export (part 2 of 2)
Added a function for Batch Export of current activity history. The user can select files to export, the target directory and format to use. This completes the updates to improve export functionality. Fixes #476.
This commit is contained in:
250
src/BatchExportDialog.cpp
Normal file
250
src/BatchExportDialog.cpp
Normal file
@@ -0,0 +1,250 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 Mark Liversedge (liversedge@gmail.com)
|
||||
*
|
||||
* 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, write to the Free Software Foundation, Inc., 51
|
||||
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "BatchExportDialog.h"
|
||||
|
||||
BatchExportDialog::BatchExportDialog(MainWindow *main) : QDialog(main), main(main)
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
|
||||
setWindowTitle(tr("Activity Batch Export"));
|
||||
|
||||
// make the dialog a resonable size
|
||||
setMinimumWidth(550);
|
||||
setMinimumHeight(400);
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout;
|
||||
setLayout(layout);
|
||||
|
||||
files = new QTreeWidget;
|
||||
files->headerItem()->setText(0, tr(""));
|
||||
files->headerItem()->setText(1, tr("Filename"));
|
||||
files->headerItem()->setText(2, tr("Date"));
|
||||
files->headerItem()->setText(3, tr("Time"));
|
||||
files->headerItem()->setText(4, tr("Action"));
|
||||
|
||||
files->setColumnCount(5);
|
||||
files->setColumnWidth(0, 30); // selector
|
||||
files->setColumnWidth(1, 190); // filename
|
||||
files->setColumnWidth(2, 95); // date
|
||||
files->setColumnWidth(3, 90); // time
|
||||
files->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
files->setEditTriggers(QAbstractItemView::SelectedClicked); // allow edit
|
||||
files->setUniformRowHeights(true);
|
||||
files->setIndentation(0);
|
||||
|
||||
// populate with each ride in the ridelist
|
||||
const QTreeWidgetItem *allRides = main->allRideItems();
|
||||
|
||||
for (int i=0; i<allRides->childCount(); i++) {
|
||||
|
||||
RideItem *rideItem = static_cast<RideItem*>(allRides->child(i));
|
||||
|
||||
QTreeWidgetItem *add = new QTreeWidgetItem(files->invisibleRootItem());
|
||||
add->setFlags(add->flags() | Qt::ItemIsEditable);
|
||||
|
||||
// selector
|
||||
QCheckBox *checkBox = new QCheckBox("", this);
|
||||
checkBox->setChecked(true);
|
||||
files->setItemWidget(add, 0, checkBox);
|
||||
|
||||
// we will wipe the original file
|
||||
add->setText(1, rideItem->fileName);
|
||||
add->setText(2, rideItem->dateTime.toString(tr("dd MMM yyyy")));
|
||||
add->setText(3, rideItem->dateTime.toString(tr("hh:mm:ss ap")));
|
||||
|
||||
// interval action
|
||||
add->setText(4, "Export");
|
||||
}
|
||||
|
||||
// format and directory
|
||||
QGridLayout *grid = new QGridLayout;
|
||||
formatLabel = new QLabel("Export as", this);
|
||||
format = new QComboBox(this);
|
||||
|
||||
const RideFileFactory &rff = RideFileFactory::instance();
|
||||
foreach(QString suffix, rff.writeSuffixes()) format->addItem(rff.description(suffix));
|
||||
|
||||
selectDir = new QPushButton("Browse", this);
|
||||
dirLabel = new QLabel ("Export to", this);
|
||||
dirName = new QLabel(QDir::home().absolutePath(), this);
|
||||
all = new QCheckBox("check/uncheck all", this);
|
||||
all->setChecked(true);
|
||||
|
||||
grid->addWidget(formatLabel, 0,0, Qt::AlignLeft);
|
||||
grid->addWidget(format, 0,1, Qt::AlignLeft);
|
||||
grid->addWidget(dirLabel, 1,0, Qt::AlignLeft);
|
||||
grid->addWidget(dirName, 1,1, Qt::AlignLeft);
|
||||
grid->addWidget(selectDir, 1,2, Qt::AlignLeft);
|
||||
grid->addWidget(all, 2,0, Qt::AlignLeft);
|
||||
grid->setColumnStretch(0, 1);
|
||||
grid->setColumnStretch(1, 10);
|
||||
|
||||
// buttons
|
||||
QHBoxLayout *buttons = new QHBoxLayout;
|
||||
status = new QLabel("", this);
|
||||
status->hide();
|
||||
overwrite = new QCheckBox("Overwrite existing files", this);
|
||||
cancel = new QPushButton("Cancel", this);
|
||||
ok = new QPushButton("Export", this);
|
||||
buttons->addWidget(overwrite);
|
||||
buttons->addWidget(status);
|
||||
buttons->addStretch();
|
||||
buttons->addWidget(cancel);
|
||||
buttons->addWidget(ok);
|
||||
|
||||
layout->addLayout(grid);
|
||||
layout->addWidget(files);
|
||||
layout->addLayout(buttons);
|
||||
|
||||
exports = fails = 0;
|
||||
|
||||
// connect signals and slots up..
|
||||
connect(selectDir, SIGNAL(clicked()), this, SLOT(selectClicked()));
|
||||
connect(ok, SIGNAL(clicked()), this, SLOT(okClicked()));
|
||||
connect(all, SIGNAL(stateChanged(int)), this, SLOT(allClicked()));
|
||||
connect(cancel, SIGNAL(clicked()), this, SLOT(cancelClicked()));
|
||||
}
|
||||
|
||||
void
|
||||
BatchExportDialog::selectClicked()
|
||||
{
|
||||
QString dir = QFileDialog::getExistingDirectory(this, tr("Select Target Directory"),
|
||||
dirName->text(),
|
||||
QFileDialog::ShowDirsOnly
|
||||
| QFileDialog::DontResolveSymlinks);
|
||||
if (dir!="") dirName->setText(dir);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
BatchExportDialog::allClicked()
|
||||
{
|
||||
// set/uncheck all rides according to the "all"
|
||||
bool checked = all->isChecked();
|
||||
|
||||
for(int i=0; i<files->invisibleRootItem()->childCount(); i++) {
|
||||
QTreeWidgetItem *current = files->invisibleRootItem()->child(i);
|
||||
static_cast<QCheckBox*>(files->itemWidget(current,0))->setChecked(checked);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BatchExportDialog::okClicked()
|
||||
{
|
||||
if (ok->text() == "Export") {
|
||||
aborted = false;
|
||||
|
||||
overwrite->hide();
|
||||
status->setText("Exporting...");
|
||||
status->show();
|
||||
cancel->hide();
|
||||
ok->setText("Abort");
|
||||
exportFiles();
|
||||
status->setText(QString("%1 activities exported, %2 failed or skipped.").arg(exports).arg(fails));
|
||||
ok->setText("Finish");
|
||||
|
||||
} else if (ok->text() == "Abort") {
|
||||
aborted = true;
|
||||
} else if (ok->text() == "Finish") {
|
||||
accept(); // our work is done!
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
BatchExportDialog::cancelClicked()
|
||||
{
|
||||
reject();
|
||||
}
|
||||
|
||||
void
|
||||
BatchExportDialog::exportFiles()
|
||||
{
|
||||
// what format to export as?
|
||||
QString type = RideFileFactory::instance().writeSuffixes().at(format->currentIndex());
|
||||
|
||||
// loop through the table and export all selected
|
||||
for(int i=0; i<files->invisibleRootItem()->childCount(); i++) {
|
||||
|
||||
// give user a chance to abort..
|
||||
QApplication::processEvents();
|
||||
|
||||
// did they?
|
||||
if (aborted == true) return; // user aborted!
|
||||
|
||||
QTreeWidgetItem *current = files->invisibleRootItem()->child(i);
|
||||
|
||||
// is it selected
|
||||
if (static_cast<QCheckBox*>(files->itemWidget(current,0))->isChecked()) {
|
||||
|
||||
files->setCurrentItem(current); QApplication::processEvents();
|
||||
|
||||
QString filename = dirName->text() + "/" + QFileInfo(current->text(1)).baseName() + "." + type;
|
||||
|
||||
if (QFile(filename).exists()) {
|
||||
if (overwrite->isChecked() == false) {
|
||||
// skip existing files
|
||||
current->setText(4, "Exists - not exported"); QApplication::processEvents();
|
||||
fails++;
|
||||
continue;
|
||||
|
||||
} else {
|
||||
|
||||
// remove existing
|
||||
QFile(filename).remove();
|
||||
current->setText(4, "Removing..."); QApplication::processEvents();
|
||||
}
|
||||
|
||||
}
|
||||
// this one then
|
||||
current->setText(4, "Reading..."); QApplication::processEvents();
|
||||
|
||||
// open it..
|
||||
QStringList errors;
|
||||
QList<RideFile*> rides;
|
||||
QFile thisfile(QString(main->home.absolutePath()+"/"+current->text(1)));
|
||||
RideFile *ride = RideFileFactory::instance().openRideFile(main, thisfile, errors, &rides);
|
||||
|
||||
// open success?
|
||||
if (ride) {
|
||||
|
||||
|
||||
current->setText(4, "Writing..."); QApplication::processEvents();
|
||||
QFile out(filename);
|
||||
bool success = RideFileFactory::instance().writeRideFile(main, ride, out, type);
|
||||
|
||||
if (success) {
|
||||
exports++;
|
||||
current->setText(4, "Exported"); QApplication::processEvents();
|
||||
} else {
|
||||
fails++;
|
||||
current->setText(4, "Write failed"); QApplication::processEvents();
|
||||
}
|
||||
|
||||
delete ride; // free memory!
|
||||
|
||||
// open failed
|
||||
} else {
|
||||
|
||||
current->setText(4, "Read error"); QApplication::processEvents();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
80
src/BatchExportDialog.h
Normal file
80
src/BatchExportDialog.h
Normal file
@@ -0,0 +1,80 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2011 Mark Liversedge (liversedge@gmail.com)
|
||||
*
|
||||
* 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, write to the Free Software Foundation, Inc., 51
|
||||
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _BatchExportDialog_h
|
||||
#define _BatchExportDialog_h
|
||||
#include "GoldenCheetah.h"
|
||||
#include "MainWindow.h"
|
||||
#include "Settings.h"
|
||||
#include "Units.h"
|
||||
|
||||
#include "RideItem.h"
|
||||
#include "RideFile.h"
|
||||
|
||||
#include <QtGui>
|
||||
#include <QTableWidget>
|
||||
#include <QProgressBar>
|
||||
#include <QList>
|
||||
#include <QLabel>
|
||||
#include <QListIterator>
|
||||
#include <QDebug>
|
||||
|
||||
// Dialog class to show filenames, import progress and to capture user input
|
||||
// of ride date and time
|
||||
|
||||
class BatchExportDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
G_OBJECT
|
||||
|
||||
|
||||
public:
|
||||
BatchExportDialog(MainWindow *main);
|
||||
|
||||
QTreeWidget *files; // choose files to export
|
||||
|
||||
signals:
|
||||
|
||||
private slots:
|
||||
void cancelClicked();
|
||||
void okClicked();
|
||||
void selectClicked();
|
||||
void exportFiles();
|
||||
void allClicked();
|
||||
|
||||
private:
|
||||
MainWindow *main;
|
||||
bool aborted;
|
||||
|
||||
QCheckBox *all;
|
||||
|
||||
QComboBox *format;
|
||||
QLabel *formatLabel;
|
||||
|
||||
QPushButton *selectDir;
|
||||
QLabel *dirLabel, *dirName;
|
||||
|
||||
QCheckBox *overwrite;
|
||||
QPushButton *cancel, *ok;
|
||||
|
||||
int exports, fails;
|
||||
QLabel *status;
|
||||
};
|
||||
#endif // _BatchExportDialog_h
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
static int gcFileReaderRegistered =
|
||||
RideFileFactory::instance().registerReader(
|
||||
"gc", "GoldenCheetah XML Format", new GcFileReader());
|
||||
"gc", "GoldenCheetah XML", new GcFileReader());
|
||||
|
||||
RideFile *
|
||||
GcFileReader::openRideFile(QFile &file, QStringList &errors, QList<RideFile*>*) const
|
||||
|
||||
@@ -226,7 +226,7 @@ string: STRING { JsonString = unprotect(JsonRideFiletex
|
||||
|
||||
static int jsonFileReaderRegistered =
|
||||
RideFileFactory::instance().registerReader(
|
||||
"json", "GoldenCheetah Json Format", new JsonFileReader());
|
||||
"json", "GoldenCheetah Json", new JsonFileReader());
|
||||
|
||||
RideFile *
|
||||
JsonFileReader::openRideFile(QFile &file, QStringList &errors, QList<RideFile*>*) const
|
||||
|
||||
@@ -62,7 +62,7 @@ using kmldom::StyleMapPtr;
|
||||
|
||||
static int kmlFileReaderRegistered =
|
||||
RideFileFactory::instance().registerReader(
|
||||
"kml", "Google Earth KML Format", new KmlFileReader());
|
||||
"kml", "Google Earth KML", new KmlFileReader());
|
||||
//
|
||||
// Utility functions
|
||||
//
|
||||
|
||||
@@ -52,6 +52,7 @@
|
||||
#include "ToolsDialog.h"
|
||||
#include "MetricAggregator.h"
|
||||
#include "SplitActivityWizard.h"
|
||||
#include "BatchExportDialog.h"
|
||||
#include "TwitterDialog.h"
|
||||
#include "WithingsDownload.h"
|
||||
#include "CalendarDownload.h"
|
||||
@@ -440,8 +441,8 @@ MainWindow::MainWindow(const QDir &home) :
|
||||
rideMenu->addAction(tr("&Import from file..."), this, SLOT (importFile()), tr ("Ctrl+I"));
|
||||
rideMenu->addAction(tr("&Manual activity entry..."), this, SLOT(manualRide()), tr("Ctrl+M"));
|
||||
rideMenu->addSeparator ();
|
||||
rideMenu->addAction(tr("&Export ..."), this, SLOT(exportRide()), tr("Ctrl+E"));
|
||||
rideMenu->addAction(tr("&Batch export ..."), this, SLOT(exportBatch()), tr("Ctrl+B"));
|
||||
rideMenu->addAction(tr("&Export..."), this, SLOT(exportRide()), tr("Ctrl+E"));
|
||||
rideMenu->addAction(tr("&Batch export..."), this, SLOT(exportBatch()), tr("Ctrl+B"));
|
||||
rideMenu->addAction(tr("Export Metrics as CSV..."), this, SLOT(exportMetrics()), tr(""));
|
||||
#ifdef GC_HAVE_SOAP
|
||||
rideMenu->addSeparator ();
|
||||
@@ -1090,7 +1091,8 @@ MainWindow::currentRide()
|
||||
void
|
||||
MainWindow::exportBatch()
|
||||
{
|
||||
// XXX todo
|
||||
BatchExportDialog *d = new BatchExportDialog(this);
|
||||
d->exec();
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
static int tcxFileReaderRegistered =
|
||||
RideFileFactory::instance().registerReader(
|
||||
"tcx", "Garmin Training Centre", new TcxFileReader());
|
||||
"tcx", "Garmin Training Centre TCX", new TcxFileReader());
|
||||
|
||||
RideFile *TcxFileReader::openRideFile(QFile &file, QStringList &errors, QList<RideFile*>*list) const
|
||||
{
|
||||
|
||||
@@ -163,6 +163,7 @@ HEADERS += \
|
||||
ANTMessages.h \
|
||||
ANTlocalController.h \
|
||||
ANTplusController.h \
|
||||
BatchExportDialog.h \
|
||||
BestIntervalDialog.h \
|
||||
BinRideFile.h \
|
||||
BingMap.h \
|
||||
@@ -325,6 +326,7 @@ SOURCES += \
|
||||
ANTlocalController.cpp \
|
||||
ANTplusController.cpp \
|
||||
BasicRideMetrics.cpp \
|
||||
BatchExportDialog.cpp \
|
||||
BestIntervalDialog.cpp \
|
||||
BikeScore.cpp \
|
||||
BinRideFile.cpp \
|
||||
|
||||
Reference in New Issue
Block a user