Move intervals to AnalysisSidebar

Further MainWindow updates, this time moving the code
for working with intervals to the AnalysisSidebar and the
associate menus.

Ultimately, the functions for working with Activities and
their Intervals will move from MainWindow and Sidebars to
the ActivityCollection classes.

This is a step as we strip out MainWindow to just GUI
aspects.
This commit is contained in:
Mark Liversedge
2013-07-18 08:00:35 +01:00
parent 6ebba3c874
commit d2901c3119
6 changed files with 490 additions and 470 deletions

View File

@@ -21,8 +21,6 @@
#include "Context.h"
#include "Athlete.h"
#include "AboutDialog.h"
#include "AddIntervalDialog.h"
#include "BestIntervalDialog.h"
#include "BlankState.h"
#include "ChooseCyclistDialog.h"
#include "Colors.h"
@@ -718,7 +716,7 @@ MainWindow::MainWindow(const QDir &home) :
optionsMenu->addAction(tr("Refresh Calendar"), this, SLOT(refreshCalendar()), tr (""));
#endif
optionsMenu->addSeparator();
optionsMenu->addAction(tr("Find intervals..."), this, SLOT(addIntervals()), tr (""));
optionsMenu->addAction(tr("Find intervals..."), analysisSidebar, SLOT(addIntervals()), tr (""));
// Add all the data processors to the tools menu
const DataProcessorFactory &factory = DataProcessorFactory::instance();
@@ -801,7 +799,6 @@ MainWindow::MainWindow(const QDir &home) :
// cpx aggregate cache check
connect(context,SIGNAL(rideSelected(RideItem*)), this, SLOT(rideSelected(RideItem*)));
connect(context->athlete->intervalWidget,SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(showContextMenuPopup(const QPoint &)));
// when metricDB updates check if BlankState needs to be closed
connect(context->athlete->metricDB, SIGNAL(dataChanged()), this, SLOT(checkBlankState()));
@@ -1027,177 +1024,6 @@ MainWindow::dateRangeChangedLTM(DateRange dr)
context->_dr = dr;
}
void
MainWindow::analysisPopup()
{
// set the point for the menu and call below
//XXX showTreeContextMenuPopup(analSidebar->mapToGlobal(QPoint(analItem->pos().x()+analItem->width()-20, analItem->pos().y())));
}
void
MainWindow::showTreeContextMenuPopup(const QPoint &pos)
{
if (context->athlete->treeWidget->selectedItems().size() == 0) return; //none selected!
RideItem *rideItem = (RideItem *)context->athlete->treeWidget->selectedItems().first();
if (rideItem != NULL && rideItem->text(0) != tr("All Activities")) {
QMenu menu(context->athlete->treeWidget);
QAction *actSaveRide = new QAction(tr("Save Changes"), context->athlete->treeWidget);
connect(actSaveRide, SIGNAL(triggered(void)), this, SLOT(saveRide()));
QAction *revertRide = new QAction(tr("Revert to Saved version"), context->athlete->treeWidget);
connect(revertRide, SIGNAL(triggered(void)), this, SLOT(revertRide()));
QAction *actDeleteRide = new QAction(tr("Delete Activity"), context->athlete->treeWidget);
connect(actDeleteRide, SIGNAL(triggered(void)), this, SLOT(deleteRide()));
QAction *actSplitRide = new QAction(tr("Split Activity"), context->athlete->treeWidget);
connect(actSplitRide, SIGNAL(triggered(void)), this, SLOT(splitRide()));
QAction *actMergeRide = new QAction(tr("Merge Activities"), context->athlete->treeWidget);
connect(actMergeRide, SIGNAL(triggered(void)), this, SLOT(mergeRide()));
if (rideItem->isDirty() == true) {
menu.addAction(actSaveRide);
menu.addAction(revertRide);
}
menu.addAction(actDeleteRide);
menu.addAction(actSplitRide);
#ifdef GC_HAVE_ICAL
QAction *actUploadCalendar = new QAction(tr("Upload Activity to Calendar"), context->athlete->treeWidget);
connect(actUploadCalendar, SIGNAL(triggered(void)), this, SLOT(uploadCalendar()));
menu.addAction(actUploadCalendar);
#endif
menu.addSeparator();
// ride navigator stuff
//XXX QAction *colChooser = new QAction(tr("Show Column Chooser"), context->athlete->treeWidget);
//XXX connect(colChooser, SIGNAL(triggered(void)), listView, SLOT(showColumnChooser()));
//XXX menu.addAction(colChooser);
#if 0 //XXX
if (listView->groupBy() >= 0) {
// already grouped lets ungroup
QAction *nogroups = new QAction(tr("Do Not Show In Groups"), context->athlete->treeWidget);
connect(nogroups, SIGNAL(triggered(void)), listView, SLOT(noGroups()));
menu.addAction(nogroups);
} else {
QMenu *groupByMenu = new QMenu(tr("Group By"), context->athlete->treeWidget);
groupByMenu->setEnabled(true);
menu.addMenu(groupByMenu);
// add menu options for each column
if (groupByMapper) delete groupByMapper;
groupByMapper = new QSignalMapper(this);
connect(groupByMapper, SIGNAL(mapped(const QString &)), listView, SLOT(setGroupByColumnName(QString)));
foreach(QString heading, listView->columnNames()) {
if (heading == "*") continue; // special hidden column
QAction *groupByAct = new QAction(heading, context->athlete->treeWidget);
connect(groupByAct, SIGNAL(triggered()), groupByMapper, SLOT(map()));
groupByMenu->addAction(groupByAct);
// map action to column heading
groupByMapper->setMapping(groupByAct, heading);
}
}
#endif
menu.exec(pos);
}
}
void
MainWindow::intervalPopup()
{
//XXX
#if 0
// always show the 'find best' 'find peaks' options
QMenu menu(intervalItem);
RideItem *rideItem = (RideItem *)context->athlete->treeWidget->selectedItems().first();
if (rideItem != NULL && rideItem->ride() && rideItem->ride()->dataPoints().count()) {
QAction *actFindPeak = new QAction(tr("Find Peak Intervals"), intervalItem);
QAction *actFindBest = new QAction(tr("Find Best Intervals"), intervalItem);
connect(actFindPeak, SIGNAL(triggered(void)), this, SLOT(findPowerPeaks(void)));
connect(actFindBest, SIGNAL(triggered(void)), this, SLOT(addIntervals(void)));
menu.addAction(actFindPeak);
menu.addAction(actFindBest);
// sort but only if 2 or more intervals
if (context->athlete->allIntervals->childCount() > 1) {
QAction *actSort = new QAction(tr("Sort Intervals"), intervalItem);
connect(actSort, SIGNAL(triggered(void)), this, SLOT(sortIntervals(void)));
menu.addAction(actSort);
}
if (context->athlete->intervalWidget->selectedItems().count()) menu.addSeparator();
}
if (context->athlete->intervalWidget->selectedItems().count() == 1) {
// we can zoom, rename etc if only 1 interval is selected
QAction *actZoomInt = new QAction(tr("Zoom to interval"), context->athlete->intervalWidget);
QAction *actEditInt = new QAction(tr("Edit interval"), context->athlete->intervalWidget);
QAction *actDeleteInt = new QAction(tr("Delete interval"), context->athlete->intervalWidget);
connect(actZoomInt, SIGNAL(triggered(void)), this, SLOT(zoomIntervalSelected(void)));
connect(actEditInt, SIGNAL(triggered(void)), this, SLOT(editIntervalSelected(void)));
connect(actDeleteInt, SIGNAL(triggered(void)), this, SLOT(deleteIntervalSelected(void)));
menu.addAction(actZoomInt);
menu.addAction(actEditInt);
menu.addAction(actDeleteInt);
}
if (context->athlete->intervalWidget->selectedItems().count() > 1) {
QAction *actRenameInt = new QAction(tr("Rename selected intervals"), context->athlete->intervalWidget);
connect(actRenameInt, SIGNAL(triggered(void)), this, SLOT(renameIntervalsSelected(void)));
QAction *actDeleteInt = new QAction(tr("Delete selected intervals"), context->athlete->intervalWidget);
connect(actDeleteInt, SIGNAL(triggered(void)), this, SLOT(deleteIntervalSelected(void)));
menu.addAction(actRenameInt);
menu.addAction(actDeleteInt);
}
//XXX menu.exec(analSidebar->mapToGlobal((QPoint(intervalItem->pos().x()+intervalItem->width()-20, intervalItem->pos().y()))));
#endif
}
void
MainWindow::showContextMenuPopup(const QPoint &pos)
{
QTreeWidgetItem *trItem = context->athlete->intervalWidget->itemAt( pos );
if (trItem != NULL && trItem->text(0) != tr("Intervals")) {
QMenu menu(context->athlete->intervalWidget);
activeInterval = (IntervalItem *)trItem;
QAction *actEditInt = new QAction(tr("Edit interval"), context->athlete->intervalWidget);
QAction *actDeleteInt = new QAction(tr("Delete interval"), context->athlete->intervalWidget);
QAction *actZoomInt = new QAction(tr("Zoom to interval"), context->athlete->intervalWidget);
QAction *actFrontInt = new QAction(tr("Bring to Front"), context->athlete->intervalWidget);
QAction *actBackInt = new QAction(tr("Send to back"), context->athlete->intervalWidget);
connect(actEditInt, SIGNAL(triggered(void)), this, SLOT(editInterval(void)));
connect(actDeleteInt, SIGNAL(triggered(void)), this, SLOT(deleteInterval(void)));
connect(actZoomInt, SIGNAL(triggered(void)), this, SLOT(zoomInterval(void)));
connect(actFrontInt, SIGNAL(triggered(void)), this, SLOT(frontInterval(void)));
connect(actBackInt, SIGNAL(triggered(void)), this, SLOT(backInterval(void)));
menu.addAction(actZoomInt);
menu.addAction(actEditInt);
menu.addAction(actDeleteInt);
menu.exec(context->athlete->intervalWidget->mapToGlobal( pos ));
}
}
void
MainWindow::resizeEvent(QResizeEvent*)
@@ -1908,274 +1734,6 @@ MainWindow::downloadTP()
}
#endif
/*----------------------------------------------------------------------
* Intervals
*--------------------------------------------------------------------*/
void
MainWindow::addIntervals()
{
if (context->ride && context->ride->ride() && context->ride->ride()->dataPoints().count()) {
AddIntervalDialog *p = new AddIntervalDialog(context);
p->setWindowModality(Qt::ApplicationModal); // don't allow select other ride or it all goes wrong!
p->exec();
} else {
if (!context->ride || !context->ride->ride())
QMessageBox::critical(this, tr("Find Best Intervals"), tr("No activity selected"));
else
QMessageBox::critical(this, tr("Find Best Intervals"), tr("Current activity contains no data"));
}
}
void
MainWindow::addIntervalForPowerPeaksForSecs(RideFile *ride, int windowSizeSecs, QString name)
{
QList<BestIntervalDialog::BestInterval> results;
BestIntervalDialog::findBests(ride, windowSizeSecs, 1, results);
if (results.isEmpty()) return;
const BestIntervalDialog::BestInterval &i = results.first();
QTreeWidgetItem *peak =
new IntervalItem(ride, name+tr(" (%1 watts)").arg((int) round(i.avg)),
i.start, i.stop,
ride->timeToDistance(i.start),
ride->timeToDistance(i.stop),
context->athlete->allIntervals->childCount()+1);
peak->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled);
context->athlete->allIntervals->addChild(peak);
}
void
MainWindow::findPowerPeaks()
{
if (!context->ride) return;
QTreeWidgetItem *which = context->athlete->treeWidget->selectedItems().first();
if (which->type() != RIDE_TYPE) {
return;
}
if (context->ride && context->ride->ride() && context->ride->ride()->dataPoints().count()) {
addIntervalForPowerPeaksForSecs(context->ride->ride(), 5, "Peak 5s");
addIntervalForPowerPeaksForSecs(context->ride->ride(), 10, "Peak 10s");
addIntervalForPowerPeaksForSecs(context->ride->ride(), 20, "Peak 20s");
addIntervalForPowerPeaksForSecs(context->ride->ride(), 30, "Peak 30s");
addIntervalForPowerPeaksForSecs(context->ride->ride(), 60, "Peak 1min");
addIntervalForPowerPeaksForSecs(context->ride->ride(), 120, "Peak 2min");
addIntervalForPowerPeaksForSecs(context->ride->ride(), 300, "Peak 5min");
addIntervalForPowerPeaksForSecs(context->ride->ride(), 600, "Peak 10min");
addIntervalForPowerPeaksForSecs(context->ride->ride(), 1200, "Peak 20min");
addIntervalForPowerPeaksForSecs(context->ride->ride(), 1800, "Peak 30min");
addIntervalForPowerPeaksForSecs(context->ride->ride(), 3600, "Peak 60min");
// now update the RideFileIntervals
context->athlete->updateRideFileIntervals();
} else {
if (!context->ride || !context->ride->ride())
QMessageBox::critical(this, tr("Find Power Peaks"), tr("No activity selected"));
else
QMessageBox::critical(this, tr("Find Power Peaks"), tr("Current activity contains no data"));
}
}
bool
lessItem(const IntervalItem *s1, const IntervalItem *s2) {
return s1->start < s2->start;
}
void
MainWindow::sortIntervals()
{
// sort them chronologically
QList<IntervalItem*> intervals;
// set string to first interval selected
for (int i=0; i<context->athlete->allIntervals->childCount();i++)
intervals.append((IntervalItem*)(context->athlete->allIntervals->child(i)));
// now sort them into start time order
qStableSort(intervals.begin(), intervals.end(), lessItem);
// empty context->athlete->allIntervals
context->athlete->allIntervals->takeChildren();
// and put em back in chronological sequence
foreach(IntervalItem* item, intervals) {
context->athlete->allIntervals->addChild(item);
}
// now update the ridefile
context->athlete->updateRideFileIntervals(); // will emit intervalChanged() signal
}
// rename multiple intervals
void
MainWindow::renameIntervalsSelected()
{
QString string;
// set string to first interval selected
for (int i=0; i<context->athlete->allIntervals->childCount();i++) {
if (context->athlete->allIntervals->child(i)->isSelected()) {
string = context->athlete->allIntervals->child(i)->text(0);
break;
}
}
// type in a name and we will renumber all the intervals
// in the same fashion -- esp if the last characters are
RenameIntervalDialog dialog(string, this);
dialog.setFixedWidth(320);
if (dialog.exec()) {
int number = 1;
// does it end in a number?
// if so we use that to renumber from
QRegExp ends("^(.*[^0-9])([0-9]+)$");
if (ends.exactMatch(string)) {
string = ends.cap(1);
number = ends.cap(2).toInt();
} else if (!string.endsWith(" ")) string += " ";
// now go and renumber from 'number' with prefix 'string'
for (int i=0; i<context->athlete->allIntervals->childCount();i++) {
if (context->athlete->allIntervals->child(i)->isSelected())
context->athlete->allIntervals->child(i)->setText(0, QString("%1%2").arg(string).arg(number++));
}
context->athlete->updateRideFileIntervals(); // will emit intervalChanged() signal
}
}
void
MainWindow::deleteIntervalSelected()
{
// delete the intervals that are selected (from the menu)
// the normal delete intervals does that already
deleteInterval();
}
void
MainWindow::deleteInterval()
{
// now delete highlighted!
for (int i=0; i<context->athlete->allIntervals->childCount();) {
if (context->athlete->allIntervals->child(i)->isSelected()) delete context->athlete->allIntervals->takeChild(i);
else i++;
}
context->athlete->updateRideFileIntervals(); // will emit intervalChanged() signal
}
void
MainWindow::renameIntervalSelected()
{
// go edit the name
for (int i=0; i<context->athlete->allIntervals->childCount();) {
if (context->athlete->allIntervals->child(i)->isSelected()) {
context->athlete->allIntervals->child(i)->setFlags(context->athlete->allIntervals->child(i)->flags() | Qt::ItemIsEditable);
context->athlete->intervalWidget->editItem(context->athlete->allIntervals->child(i), 0);
break;
} else i++;
}
context->athlete->updateRideFileIntervals(); // will emit intervalChanged() signal
}
void
MainWindow::renameInterval() {
// go edit the name
activeInterval->setFlags(activeInterval->flags() | Qt::ItemIsEditable);
context->athlete->intervalWidget->editItem(activeInterval, 0);
}
void
MainWindow::editIntervalSelected()
{
// go edit the interval
for (int i=0; i<context->athlete->allIntervals->childCount();) {
if (context->athlete->allIntervals->child(i)->isSelected()) {
activeInterval = (IntervalItem*)context->athlete->allIntervals->child(i);
editInterval();
break;
} else i++;
}
}
void
MainWindow::editInterval()
{
IntervalItem temp = *activeInterval;
EditIntervalDialog dialog(this, temp);
if (dialog.exec()) {
*activeInterval = temp;
context->athlete->updateRideFileIntervals(); // will emit intervalChanged() signal
context->athlete->intervalWidget->update();
}
}
void
MainWindow::zoomIntervalSelected()
{
// zoom the one interval that is selected via popup menu
for (int i=0; i<context->athlete->allIntervals->childCount();) {
if (context->athlete->allIntervals->child(i)->isSelected()) {
context->notifyIntervalZoom((IntervalItem*)(context->athlete->allIntervals->child(i)));
break;
} else i++;
}
}
void
MainWindow::zoomInterval() {
// zoom into this interval on allPlot
context->notifyIntervalZoom(activeInterval);
}
void
MainWindow::frontInterval()
{
int oindex = activeInterval->displaySequence;
for (int i=0; i<context->athlete->allIntervals->childCount(); i++) {
IntervalItem *it = (IntervalItem *)context->athlete->allIntervals->child(i);
int ds = it->displaySequence;
if (ds > oindex)
it->setDisplaySequence(ds-1);
}
activeInterval->setDisplaySequence(context->athlete->allIntervals->childCount());
// signal!
context->notifyIntervalsChanged();
}
void
MainWindow::backInterval()
{
int oindex = activeInterval->displaySequence;
for (int i=0; i<context->athlete->allIntervals->childCount(); i++) {
IntervalItem *it = (IntervalItem *)context->athlete->allIntervals->child(i);
int ds = it->displaySequence;
if (ds < oindex)
it->setDisplaySequence(ds+1);
}
activeInterval->setDisplaySequence(1);
// signal!
context->notifyIntervalsChanged();
}
/*----------------------------------------------------------------------
* Utility
@@ -2322,7 +1880,7 @@ MainWindow::actionClicked(int index)
switch(index) {
default:
case 0: addIntervals();
case 0: analysisSidebar->addIntervals();
break;
case 1 : splitRide();