From a6eabb73d7c5c76abc61ee2cb7bac5f7b605aa87 Mon Sep 17 00:00:00 2001 From: Joern Date: Sun, 25 Oct 2015 13:04:19 +0100 Subject: [PATCH] Autoimport Stealth/Background Mode ... new Feature to Autoimport without Dialog (with same timeframe option like the Dialog version) ... in case "Dates/Time" is missing - the Dialog Window appears and waits for input - if entered and "Save" presses no further input action is required ... malformed activity files are silently ignored ... to avoid inconsistencies closing of the Athlete for which Background Import is running is blocked until the Import is finalized (Info on import complete is sent to UI) .. UI is not blocked by Autoimport - but a bit less reactive as long as the import is executed --- src/Athlete.cpp | 15 +++--- src/Athlete.h | 4 +- src/MainWindow.cpp | 44 ++++++++++++++--- src/RideAutoImportConfig.cpp | 4 ++ src/RideAutoImportConfig.h | 3 +- src/RideImportWizard.cpp | 93 +++++++++++++++++++++++++++++++----- src/RideImportWizard.h | 9 +++- 7 files changed, 143 insertions(+), 29 deletions(-) diff --git a/src/Athlete.cpp b/src/Athlete.cpp index c7d2c272a..eb9f3c502 100644 --- a/src/Athlete.cpp +++ b/src/Athlete.cpp @@ -121,8 +121,9 @@ Athlete::Athlete(Context *context, const QDir &homeDir) } } - // read athlete's autoimport configuration + // read athlete's autoimport configuration and initialize the autoimport process autoImportConfig = new RideAutoImportConfig(home->config()); + autoImport = NULL; // read athlete's charts.xml and translate etc loadCharts(); @@ -230,6 +231,9 @@ Athlete::~Athlete() delete zones_; delete hrzones_; for (int i=0; i<2; i++) delete pacezones_[i]; + delete autoImportConfig; + delete autoImport; + } void Athlete::selectRideFile(QString fileName) @@ -343,16 +347,15 @@ Athlete::configChanged(qint32 state) void Athlete::importFilesWhenOpeningAthlete() { + autoImport = NULL; // just do it if something is configured if (autoImportConfig->hasRules()) { - RideImportWizard *import = new RideImportWizard(autoImportConfig, context); + autoImport = new RideImportWizard(autoImportConfig, context); // only process the popup if we have any files available at all - if ( import->getNumberOfFiles() > 0) { - import->process(); - } else { - delete import; + if ( autoImport->getNumberOfFiles() > 0) { + autoImport->process(); } } } diff --git a/src/Athlete.h b/src/Athlete.h index 6590386a4..1c53bd70d 100644 --- a/src/Athlete.h +++ b/src/Athlete.h @@ -51,6 +51,7 @@ class PMCData; class LTMSettings; class Routes; class AthleteDirectoryStructure; +class RideImportWizard; class RideAutoImportConfig; class RideCache; class IntervalCache; @@ -118,7 +119,8 @@ class Athlete : public QObject CalDAV *davCalendar; #endif - // Athlete's autoimport configuration + // Athlete's autoimport handling + RideImportWizard *autoImport; RideAutoImportConfig *autoImportConfig; // ride metadata definitions diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index e597593dd..01f63ca19 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -1015,20 +1015,32 @@ MainWindow::closeEvent(QCloseEvent* event) { QList closing = tabList; bool needtosave = false; + bool importrunning = false; // close all the tabs .. if any refuse we need to ignore // the close event foreach(Tab *tab, closing) { - // do we need to save? - if (tab->context->mainWindow->saveRideExitDialog(tab->context) == true) - removeTab(tab); - else - needtosave = true; + // check for if RideImport is is process and let it finalize / or be stopped by the user + if (tab->context->athlete->autoImport) { + if (tab->context->athlete->autoImport->importInProcess() ) { + importrunning = true; + QMessageBox::information(this, tr("Activity Import"), tr("Closing of athlete window not possible while background activity import is in progress...")); + } + } + + // only check for unsaved if autoimport is not running any more + if (!importrunning) { + // do we need to save? + if (tab->context->mainWindow->saveRideExitDialog(tab->context) == true) + removeTab(tab); + else + needtosave = true; + } } - // were any left hanging around? - if (needtosave) event->ignore(); + // were any left hanging around? or autoimport in action on any windows, then don't close any + if (needtosave || importrunning) event->ignore(); else { // finish off the job and leave @@ -1631,7 +1643,17 @@ MainWindow::openTab(QString name) void MainWindow::closeTabClicked(int index) { + Tab *tab = tabList[index]; + + // check for autoimport and let it finalize + if (tab->context->athlete->autoImport) { + if (tab->context->athlete->autoImport->importInProcess() ) { + QMessageBox::information(this, tr("Activity Import"), tr("Closing of athlete window not possible while background activity import is in progress...")); + return; + } + } + if (saveRideExitDialog(tab->context) == false) return; // lets wipe it @@ -1641,6 +1663,14 @@ MainWindow::closeTabClicked(int index) bool MainWindow::closeTab() { + // check for autoimport and let it finalize + if (currentTab->context->athlete->autoImport) { + if (currentTab->context->athlete->autoImport->importInProcess() ) { + QMessageBox::information(this, tr("Activity Import"), tr("Closing of athlete window not possible while background activity import is in progress...")); + return false; + } + } + // wipe it down ... if (saveRideExitDialog(currentTab->context) == false) return false; diff --git a/src/RideAutoImportConfig.cpp b/src/RideAutoImportConfig.cpp index 487bb6772..b88aa6a20 100644 --- a/src/RideAutoImportConfig.cpp +++ b/src/RideAutoImportConfig.cpp @@ -35,6 +35,10 @@ RideAutoImportRule::RideAutoImportRule() { _ruleDescriptions.append(tr("Autoimport with dialog - past 90 days")); _ruleDescriptions.append(tr("Autoimport with dialog - past 180 days")); _ruleDescriptions.append(tr("Autoimport with dialog - past 360 days")); + _ruleDescriptions.append(tr("Autoimport in background")); + _ruleDescriptions.append(tr("Autoimport in background - past 90 days")); + _ruleDescriptions.append(tr("Autoimport in background - past 180 days")); + _ruleDescriptions.append(tr("Autoimport in background - past 360 days")); } diff --git a/src/RideAutoImportConfig.h b/src/RideAutoImportConfig.h index 2053abaca..a67573460 100644 --- a/src/RideAutoImportConfig.h +++ b/src/RideAutoImportConfig.h @@ -30,7 +30,8 @@ class RideAutoImportRule { public: static QList rules; - enum ImportRule { noImport=0, importAll=1, importLast90days=2, importLast180days=3, importLast360days=4 }; + enum ImportRule { noImport=0, importAll=1, importLast90days=2, importLast180days=3, importLast360days=4, + importBackgroundAll=5, importBackground90=6, importBackground180=7, importBackground360=8 }; RideAutoImportRule(); diff --git a/src/RideImportWizard.cpp b/src/RideImportWizard.cpp index f843b01dc..e4e573007 100644 --- a/src/RideImportWizard.cpp +++ b/src/RideImportWizard.cpp @@ -41,29 +41,42 @@ // drag and drop passes urls ... convert to a list of files and call main constructor RideImportWizard::RideImportWizard(QList *urls, Context *context, QWidget *parent) : QDialog(parent), context(context) { + _importInProcess = true; setAttribute(Qt::WA_DeleteOnClose); setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint); QList filenames; for (int i=0; icount(); i++) filenames.append(QFileInfo(urls->value(i).toLocalFile()).absoluteFilePath()); autoImportMode = false; + autoImportStealth = false; init(filenames, context); filenames.clear(); + _importInProcess = false; + } RideImportWizard::RideImportWizard(QList files, Context *context, QWidget *parent) : QDialog(parent), context(context) { + _importInProcess = true; + setAttribute(Qt::WA_DeleteOnClose); autoImportMode = false; + autoImportStealth = false; init(files, context); + _importInProcess = false; + } RideImportWizard::RideImportWizard(RideAutoImportConfig *dirs, Context *context, QWidget *parent) : QDialog(parent), context(context), importConfig(dirs) { + _importInProcess = true; autoImportMode = true; + autoImportStealth = true; + + if (autoImportStealth) hide(); QList files; - // get the directories + // get the directories & rules QList rules = importConfig->getConfig(); // prepare the widget to show the status of the directory @@ -142,16 +155,30 @@ RideImportWizard::RideImportWizard(RideAutoImportConfig *dirs, Context *context, QDate selectAfter = QDate::currentDate(); switch(rule.getImportRule()) { case RideAutoImportRule::importLast90days: + case RideAutoImportRule::importBackground90: selectAfter = selectAfter.addDays(Q_INT64_C(-90)); break; case RideAutoImportRule::importLast180days: + case RideAutoImportRule::importBackground180: selectAfter = selectAfter.addDays(Q_INT64_C(-180)); break; case RideAutoImportRule::importLast360days: + case RideAutoImportRule::importBackground360: selectAfter = selectAfter.addDays(Q_INT64_C(-360)); break; } + // if any of the rules says "with Dialog" then we keep the dialog - if not it's stealth + switch (rule.getImportRule()) { + + case RideAutoImportRule::importAll: + case RideAutoImportRule::importLast90days: + case RideAutoImportRule::importLast180days: + case RideAutoImportRule::importLast360days: + autoImportStealth = false; + break; + } + // now get the files with their full names QFileInfoList fileInfos = importDir->entryInfoList(allFormats, QDir::Files, QDir::NoSort); if (!fileInfos.isEmpty()) { @@ -160,12 +187,16 @@ RideImportWizard::RideImportWizard(RideAutoImportConfig *dirs, Context *context, // append following the import rules switch (rule.getImportRule()) { case RideAutoImportRule::importAll: + case RideAutoImportRule::importBackgroundAll: files.append(f.absoluteFilePath()); j++; break; case RideAutoImportRule::importLast90days: case RideAutoImportRule::importLast180days: case RideAutoImportRule::importLast360days: + case RideAutoImportRule::importBackground90: + case RideAutoImportRule::importBackground180: + case RideAutoImportRule::importBackground360: if (f.created().date() >= selectAfter || f.lastModified().date() >= selectAfter) { files.append(f.absoluteFilePath()); j++; @@ -190,6 +221,9 @@ RideImportWizard::RideImportWizard(RideAutoImportConfig *dirs, Context *context, init(files, context); + _importInProcess = false; + + } @@ -379,9 +413,14 @@ int RideImportWizard::process() { + // import process is starting + _importInProcess = true; + // Make visible and put in front prior to running down the list & processing... - if (!isActiveWindow()) activateWindow(); - this->show(); + if (!autoImportStealth) { + if (!isActiveWindow()) activateWindow(); + this->show(); + } // set progress bar limits - for each file we // will make 5 passes over the files @@ -427,7 +466,7 @@ RideImportWizard::process() } - if (aborted) { done(0); } + if (aborted) { done(0); return 0; } repaint(); QApplication::processEvents(); @@ -447,7 +486,7 @@ RideImportWizard::process() tableWidget->setCurrentCell(i,5); QApplication::processEvents(); - if (aborted) { done(0); } + if (aborted) { done(0); return 0; } this->repaint(); QApplication::processEvents(); @@ -611,7 +650,7 @@ RideImportWizard::process() } progressBar->setValue(progressBar->value()+1); QApplication::processEvents(); - if (aborted) { done(0); } + if (aborted) { done(0); return 0; } this->repaint(); next:; @@ -637,8 +676,13 @@ RideImportWizard::process() progressBar->repaint(); } // get it on top to save / correct missing dates - if (!isActiveWindow()) activateWindow(); - + if (autoImportStealth && needdates > 0) { + // leave the stealth mode + this->show(); + activateWindow(); + } else { + if (!isActiveWindow()) activateWindow(); + } // Wait for user to press save abortButton->setText(tr("Save")); aborted = false; @@ -656,8 +700,8 @@ RideImportWizard::process() // without user intervention abortButton->setDisabled(false); + if (autoImportStealth) abortClicked(); // simulate "Save" by User - // abortClicked(); } else { // de-activate Save button until the dates and times are sorted @@ -856,6 +900,10 @@ RideImportWizard::abortClicked() if (label == tr("Finish")) { // phew. our work is done. -- lets force an update stats... hide(); + if (autoImportStealth) { + // inform the user that the work is done + QMessageBox::information(NULL, tr("Auto Import"), tr("Automatic import from defined directories is completed.")); + } done(0); return; } @@ -914,7 +962,7 @@ RideImportWizard::abortClicked() tableWidget->item(i,5)->setText(tr("Saving...")); tableWidget->setCurrentCell(i,5); QApplication::processEvents(); - if (aborted) { done(0); } + if (aborted) { done(0); return; } this->repaint(); @@ -1021,7 +1069,7 @@ RideImportWizard::abortClicked() delete ride; QApplication::processEvents(); - if (aborted) { done(0); } + if (aborted) { done(0); return; } progressBar->setValue(progressBar->value()+1); this->repaint(); } @@ -1040,8 +1088,12 @@ RideImportWizard::abortClicked() progressBar->setValue(progressBar->maximum()); phaseLabel->setText(donemessage); abortButton->setText(tr("Finish")); - if (!isActiveWindow()) activateWindow(); aborted = false; + if (autoImportStealth) { + abortClicked(); // simulate pressing the "Finish" button - even if the window got visible + } else { + if (!isActiveWindow()) activateWindow(); + } } @@ -1068,6 +1120,23 @@ RideImportWizard::moveFile(const QString &source, const QString &target) { } + +void +RideImportWizard::closeEvent(QCloseEvent* event) +{ + if (_importInProcess) + event->ignore(); + else + event->accept(); +} + +void +RideImportWizard::done(int rc) +{ + _importInProcess = false; + QDialog::done(rc); +} + // clean up files RideImportWizard::~RideImportWizard() { diff --git a/src/RideImportWizard.h b/src/RideImportWizard.h index a2ac1e013..ae69cdb82 100644 --- a/src/RideImportWizard.h +++ b/src/RideImportWizard.h @@ -48,10 +48,13 @@ public: RideImportWizard(RideAutoImportConfig *dirs, Context *context, QWidget *parent = 0); ~RideImportWizard(); + void closeEvent(QCloseEvent*); + void done(int); + int getNumberOfFiles(); // get the number of files selected for processing int process(); - -signals: + bool importInProcess() { return _importInProcess; } + bool isAutoImport() { return autoImportMode;} private slots: void abortClicked(); @@ -72,6 +75,8 @@ private: QDir tmpActivities; // activitiy .JSON is stored here until rideCache() update was successfull bool aborted; bool autoImportMode; + bool autoImportStealth; + bool _importInProcess; QLabel *phaseLabel; QTableWidget *tableWidget; QTableWidget *directoryWidget;