18 changes: 11 additions & 7 deletions src/Charts/TreeMapWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#include "Units.h" // for MILES_PER_KM
#include "HelpWhatsThis.h"
#include "GoldenCheetah.h"
#include "Perspective.h"

#include <QtGui>
#include <QString>
Expand All @@ -50,17 +51,17 @@ TreeMapWindow::TreeMapWindow(Context *context) :
// the plot
mainLayout = new QVBoxLayout;

ltmPlot = new TreeMapPlot(this, context);
ltmPlot->setVisible(true);
mainLayout->addWidget(ltmPlot);
treemapPlot = new TreeMapPlot(this, context);
treemapPlot->setVisible(true);
mainLayout->addWidget(treemapPlot);
mainLayout->setSpacing(0);
mainLayout->setContentsMargins(0,0,0,0);
setChartLayout(mainLayout);

setIsBlank(false);

HelpWhatsThis *helpLTMPlot = new HelpWhatsThis(ltmPlot);
ltmPlot->setWhatsThis(helpLTMPlot->getWhatsThisText(HelpWhatsThis::ChartTrends_CollectionTreeMap));
HelpWhatsThis *helpLTMPlot = new HelpWhatsThis(treemapPlot);
treemapPlot->setWhatsThis(helpLTMPlot->getWhatsThisText(HelpWhatsThis::ChartTrends_CollectionTreeMap));

// read metadata.xml
QString filename = QDir(gcroot).canonicalPath()+"/metadata.xml";
Expand Down Expand Up @@ -152,11 +153,13 @@ TreeMapWindow::TreeMapWindow(Context *context) :
connect(context, SIGNAL(rideDeleted(RideItem*)), this, SLOT(refresh(void)));
connect(context, SIGNAL(filterChanged()), this, SLOT(refresh(void)));
connect(context, SIGNAL(homeFilterChanged()), this, SLOT(refresh(void)));
connect(this, SIGNAL(perspectiveFilterChanged(QString)), this, SLOT(refresh()));
connect(this, SIGNAL(perspectiveChanged(Perspective*)), this, SLOT(refresh()));

connect(context, SIGNAL(configChanged(qint32)), this, SLOT(refresh()));

// user clicked on a cell in the plot
connect(ltmPlot, SIGNAL(clicked(QString,QString)), this, SLOT(cellClicked(QString,QString)));
connect(treemapPlot, SIGNAL(clicked(QString,QString)), this, SLOT(cellClicked(QString,QString)));

// date settings
connect(dateSetting, SIGNAL(useCustomRange(DateRange)), this, SLOT(useCustomRange(DateRange)));
Expand All @@ -180,7 +183,7 @@ TreeMapWindow::rideSelected()
void
TreeMapWindow::refreshPlot()
{
ltmPlot->setData(&settings);
treemapPlot->setData(&settings);
}

void
Expand Down Expand Up @@ -247,6 +250,7 @@ TreeMapWindow::refresh()
FilterSet fs;
fs.addFilter(context->isfiltered, context->filters);
fs.addFilter(context->ishomefiltered, context->homeFilters);
fs.addFilter(myPerspective->isFiltered(), myPerspective->filterlist(dr));
settings.specification.setFilterSet(fs);
settings.specification.setDateRange(dr);

Expand Down
2 changes: 1 addition & 1 deletion src/Charts/TreeMapWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ class TreeMapWindow : public GcChartWindow

// Widgets
QVBoxLayout *mainLayout;
TreeMapPlot *ltmPlot;
TreeMapPlot *treemapPlot;
QLabel *title;

QComboBox *field1,
Expand Down
2 changes: 2 additions & 0 deletions src/Charts/UserChart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,13 @@ UserChart::UserChart(Context *context, bool rangemode) : GcChartWindow(context),
connect(this, SIGNAL(dateRangeChanged(DateRange)), SLOT(setDateRange(DateRange)));
connect(context, SIGNAL(homeFilterChanged()), this, SLOT(refresh()));
connect(context, SIGNAL(filterChanged()), this, SLOT(refresh()));
connect(this, SIGNAL(perspectiveFilterChanged(QString)), this, SLOT(refresh()));
}

// need to refresh when chart settings change
connect(settingsTool, SIGNAL(chartConfigChanged()), this, SLOT(chartConfigChanged()));
connect(context, SIGNAL(configChanged(qint32)), this, SLOT(configChanged(qint32)));
connect(this, SIGNAL(perspectiveChanged(Perspective*)), this, SLOT(refresh()));

configChanged(0);
}
Expand Down
4 changes: 3 additions & 1 deletion src/Charts/UserChartData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
*/

#include "RideMetric.h"
#include "Perspective.h"
#include "UserChart.h"
#include "UserChartData.h"
#include "DataFilter.h"
#include "Athlete.h"
Expand Down Expand Up @@ -78,7 +80,7 @@ UserChartData::compute(RideItem *item, Specification spec, DateRange dr)
FilterSet fs;
fs.addFilter(context->isfiltered, context->filters);
fs.addFilter(context->ishomefiltered, context->homeFilters);
Specification spec;
fs.addFilter(rt->chart->myPerspective->isFiltered(), rt->chart->myPerspective->filterlist(dr));
spec.setFilterSet(fs);

// loop through rides for daterange
Expand Down
3 changes: 1 addition & 2 deletions src/Cloud/CloudDBChart.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1066,12 +1066,11 @@ CloudDBChartListDialog::applyAllFilters() {
// setup to only show charts that are relevant to the current view
unsigned int mask=0;
switch(g_chartView) {
case 0 : mask = VIEW_HOME; break;
case 0 : mask = VIEW_TRENDS; break;
default:
case 1 : mask = VIEW_ANALYSIS; break;
case 2 : mask = VIEW_DIARY; break;
case 3 : mask = VIEW_TRAIN; break;
case 4 : mask = VIEW_INTERVAL; break;
}

QStringList searchList;
Expand Down
31 changes: 18 additions & 13 deletions src/Core/DataFilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2788,22 +2788,10 @@ Result DataFilter::evaluate(RideItem *item, RideFilePoint *p)
return res;
}

Result DataFilter::evaluate(DateRange dr, QString filter)
Result DataFilter::evaluate(Specification spec, DateRange dr)
{
// if there is no current ride item then there is no data
// so it really is ok to baulk at no current ride item here
// we must always have a ride since context is used
if (context->currentRideItem() == NULL || !treeRoot || DataFiltererrors.count()) return Result(0);

// reset stack
rt.stack = 0;

Result res(0);

Specification spec;
spec.setDateRange(dr);
if (filter != "") spec.addMatches(SearchFilterBox::matches(context, filter));

// if we are a set of functions..
if (rt.functions.count()) {

Expand All @@ -2820,6 +2808,23 @@ Result DataFilter::evaluate(DateRange dr, QString filter)
return res;
}

Result DataFilter::evaluate(DateRange dr, QString filter)
{
// if there is no current ride item then there is no data
// so it really is ok to baulk at no current ride item here
// we must always have a ride since context is used
if (context->currentRideItem() == NULL || !treeRoot || DataFiltererrors.count()) return Result(0);

// reset stack
rt.stack = 0;

Specification spec;
spec.setDateRange(dr);
if (filter != "") spec.addMatches(SearchFilterBox::matches(context, filter));

return evaluate(spec, dr);
}

QStringList DataFilter::check(QString query)
{
// since we may use it afterwards
Expand Down
1 change: 1 addition & 0 deletions src/Core/DataFilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ class DataFilter : public QObject
// RideItem always available and supplies th context
Result evaluate(RideItem *rideItem, RideFilePoint *p);
Result evaluate(DateRange dr, QString filter="");
Result evaluate(Specification spec, DateRange dr);
QStringList getErrors() { return errors; };
void colorSyntax(QTextDocument *content, int pos);

Expand Down
2 changes: 1 addition & 1 deletion src/Gui/AthleteView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ static const int gl_progress_width = ROWHEIGHT/2;
static const int gl_button_height = ROWHEIGHT*1.5;
static const int gl_button_width = ROWHEIGHT*5;

AthleteView::AthleteView(Context *context) : ChartSpace(context, OverviewScope::ATHLETES)
AthleteView::AthleteView(Context *context) : ChartSpace(context, OverviewScope::ATHLETES, NULL)
{
HelpWhatsThis *help = new HelpWhatsThis(this);
this->setWhatsThis(help->getWhatsThisText(HelpWhatsThis::ScopeBar_Athletes));
Expand Down
4 changes: 2 additions & 2 deletions src/Gui/ChartSpace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ double gl_major;
static QIcon grayConfig, whiteConfig, accentConfig;
ChartSpaceItemRegistry *ChartSpaceItemRegistry::_instance;

ChartSpace::ChartSpace(Context *context, int scope) :
state(NONE), context(context), scope(scope), group(NULL), fixedZoom(0), _viewY(0),
ChartSpace::ChartSpace(Context *context, int scope, GcWindow *window) :
state(NONE), context(context), scope(scope), window(window), group(NULL), fixedZoom(0), _viewY(0),
yresizecursor(false), xresizecursor(false), block(false), scrolling(false),
setscrollbar(false), lasty(-1)
{
Expand Down
5 changes: 4 additions & 1 deletion src/Gui/ChartSpace.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ class ChartSpace : public QWidget

public:

ChartSpace(Context *context, int scope);
ChartSpace(Context *context, int scope, GcWindow *window);

// current state for event processing
enum { NONE, DRAG, XRESIZE, YRESIZE } state;
Expand All @@ -174,6 +174,9 @@ class ChartSpace : public QWidget
QGraphicsView *device() { return view; }
const QList<ChartSpaceItem*> allItems() { return items; }

// window we are rendered in
GcWindow *window;


signals:
void itemConfigRequested(ChartSpaceItem*);
Expand Down
38 changes: 16 additions & 22 deletions src/Gui/GcWindowRegistry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,12 +65,6 @@
// Not until v4.0
//#include "RouteWindow.h"

#define VIEW_TRAIN 0x01
#define VIEW_ANALYSIS 0x02
#define VIEW_DIARY 0x04
#define VIEW_HOME 0x08
#define VIEW_INTERVAL 0x16

// GcWindows initialization is done in initialize method to enable translations
GcWindowRegistry* GcWindows;

Expand All @@ -79,45 +73,45 @@ GcWindowRegistry::initialize()
{
static GcWindowRegistry GcWindowsInit[34] = {
// name GcWinID
{ VIEW_HOME|VIEW_DIARY, tr("Overview "),GcWindowTypes::OverviewTrends },
{ VIEW_HOME|VIEW_DIARY, tr("User Chart"),GcWindowTypes::UserTrends },
{ VIEW_HOME|VIEW_DIARY, tr("Trends"),GcWindowTypes::LTM },
{ VIEW_HOME|VIEW_DIARY, tr("TreeMap"),GcWindowTypes::TreeMap },
//{ VIEW_HOME, tr("Weekly Summary"),GcWindowTypes::WeeklySummary },// DEPRECATED
{ VIEW_HOME|VIEW_DIARY, tr("Power Duration "),GcWindowTypes::CriticalPowerSummary },
//{ VIEW_HOME, tr("Training Plan"),GcWindowTypes::SeasonPlan },
//{ VIEW_HOME|VIEW_DIARY, tr("Performance Manager"),GcWindowTypes::PerformanceManager },
{ VIEW_TRENDS|VIEW_DIARY, tr("Overview "),GcWindowTypes::OverviewTrends },
{ VIEW_TRENDS|VIEW_DIARY, tr("User Chart"),GcWindowTypes::UserTrends },
{ VIEW_TRENDS|VIEW_DIARY, tr("Trends"),GcWindowTypes::LTM },
{ VIEW_TRENDS|VIEW_DIARY, tr("TreeMap"),GcWindowTypes::TreeMap },
//{ VIEW_TRENDS, tr("Weekly Summary"),GcWindowTypes::WeeklySummary },// DEPRECATED
{ VIEW_TRENDS|VIEW_DIARY, tr("Power Duration "),GcWindowTypes::CriticalPowerSummary },
//{ VIEW_TRENDS, tr("Training Plan"),GcWindowTypes::SeasonPlan },
//{ VIEW_TRENDS|VIEW_DIARY, tr("Performance Manager"),GcWindowTypes::PerformanceManager },
{ VIEW_ANALYSIS, tr("User Chart "),GcWindowTypes::UserAnalysis },
{ VIEW_ANALYSIS, tr("Overview"),GcWindowTypes::Overview },
{ VIEW_ANALYSIS|VIEW_INTERVAL, tr("Summary"),GcWindowTypes::RideSummary },
{ VIEW_ANALYSIS, tr("Summary"),GcWindowTypes::RideSummary },
{ VIEW_ANALYSIS, tr("Data"),GcWindowTypes::MetadataWindow },
//{ VIEW_ANALYSIS, tr("Summary and Details"),GcWindowTypes::Summary },
//{ VIEW_ANALYSIS, tr("Editor"),GcWindowTypes::RideEditor },
{ VIEW_ANALYSIS|VIEW_INTERVAL, tr("Performance"),GcWindowTypes::AllPlot },
{ VIEW_ANALYSIS, tr("Performance"),GcWindowTypes::AllPlot },
{ VIEW_ANALYSIS, tr("Power Duration"),GcWindowTypes::CriticalPower },
{ VIEW_ANALYSIS, tr("Histogram"),GcWindowTypes::Histogram },
{ VIEW_HOME|VIEW_DIARY, tr("Distribution"),GcWindowTypes::Distribution },
{ VIEW_TRENDS|VIEW_DIARY, tr("Distribution"),GcWindowTypes::Distribution },
{ VIEW_ANALYSIS, tr("Pedal Force vs Velocity"),GcWindowTypes::PfPv },
{ VIEW_ANALYSIS, tr("Heartrate vs Power"),GcWindowTypes::HrPw },
{ VIEW_ANALYSIS|VIEW_INTERVAL, tr("Map"),GcWindowTypes::RideMapWindow },
{ VIEW_ANALYSIS, tr("Map"),GcWindowTypes::RideMapWindow },
{ VIEW_ANALYSIS, tr("R Chart"),GcWindowTypes::RConsole },
{ VIEW_HOME, tr("R Chart "),GcWindowTypes::RConsoleSeason },
{ VIEW_TRENDS, tr("R Chart "),GcWindowTypes::RConsoleSeason },
{ VIEW_ANALYSIS, tr("Python Chart"),GcWindowTypes::Python },
{ VIEW_HOME, tr("Python Chart "),GcWindowTypes::PythonSeason },
{ VIEW_TRENDS, tr("Python Chart "),GcWindowTypes::PythonSeason },
//{ VIEW_ANALYSIS, tr("Bing Map"),GcWindowTypes::BingMap },
{ VIEW_ANALYSIS, tr("Scatter"),GcWindowTypes::Scatter },
{ VIEW_ANALYSIS, tr("Aerolab"),GcWindowTypes::Aerolab },
{ VIEW_DIARY, tr("Calendar"),GcWindowTypes::Diary },
{ VIEW_DIARY, tr("Navigator"), GcWindowTypes::ActivityNavigator },
{ VIEW_DIARY|VIEW_HOME, tr("Summary "), GcWindowTypes::DateRangeSummary },
{ VIEW_DIARY|VIEW_TRENDS, tr("Summary "), GcWindowTypes::DateRangeSummary },
{ VIEW_TRAIN, tr("Telemetry"),GcWindowTypes::DialWindow },
{ VIEW_TRAIN, tr("Workout"),GcWindowTypes::WorkoutPlot },
{ VIEW_TRAIN, tr("Realtime"),GcWindowTypes::RealtimePlot },
{ VIEW_TRAIN, tr("Pedal Stroke"),GcWindowTypes::SpinScanPlot },
{ VIEW_TRAIN, tr("Video Player"),GcWindowTypes::VideoPlayer },
{ VIEW_TRAIN, tr("Workout Editor"),GcWindowTypes::WorkoutWindow },
{ VIEW_TRAIN, tr("Live Map"),GcWindowTypes::LiveMapWebPageWindow },
{ VIEW_ANALYSIS|VIEW_HOME|VIEW_TRAIN, tr("Web page"),GcWindowTypes::WebPageWindow },
{ VIEW_ANALYSIS|VIEW_TRENDS|VIEW_TRAIN, tr("Web page"),GcWindowTypes::WebPageWindow },
{ 0, "", GcWindowTypes::None }};
// initialize the global registry
GcWindows = GcWindowsInit;
Expand Down
3 changes: 1 addition & 2 deletions src/Gui/GcWindowRegistry.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ Q_DECLARE_METATYPE(GcWinID)
#define VIEW_TRAIN 0x01
#define VIEW_ANALYSIS 0x02
#define VIEW_DIARY 0x04
#define VIEW_HOME 0x08
#define VIEW_INTERVAL 0x16
#define VIEW_TRENDS 0x08

class GcChartWindow;
class GcWindowRegistry {
Expand Down
14 changes: 6 additions & 8 deletions src/Gui/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -655,7 +655,7 @@ MainWindow::MainWindow(const QDir &home)

viewMenu->addSeparator();
viewMenu->addAction(tr("Activities"), this, SLOT(selectAnalysis()));
viewMenu->addAction(tr("Trends"), this, SLOT(selectHome()));
viewMenu->addAction(tr("Trends"), this, SLOT(selectTrends()));
viewMenu->addAction(tr("Train"), this, SLOT(selectTrain()));
viewMenu->addSeparator();
viewMenu->addAction(tr("Import Perspective..."), this, SLOT(importPerspective()));
Expand Down Expand Up @@ -874,12 +874,11 @@ MainWindow::setChartMenu()
// setup to only show charts that are relevant
// to this view
switch(currentTab->currentView()) {
case 0 : mask = VIEW_HOME; break;
case 0 : mask = VIEW_TRENDS; break;
default:
case 1 : mask = VIEW_ANALYSIS; break;
case 2 : mask = VIEW_DIARY; break;
case 3 : mask = VIEW_TRAIN; break;
case 4 : mask = VIEW_INTERVAL; break;
}

chartMenu->clear();
Expand All @@ -905,12 +904,11 @@ MainWindow::setChartMenu(QMenu *menu)
// setup to only show charts that are relevant
// to this view
switch(currentTab->currentView()) {
case 0 : mask = VIEW_HOME; break;
case 0 : mask = VIEW_TRENDS; break;
default:
case 1 : mask = VIEW_ANALYSIS; break;
case 2 : mask = VIEW_DIARY; break;
case 3 : mask = VIEW_TRAIN; break;
case 4 : mask = VIEW_INTERVAL; break;
}

menu->clear();
Expand Down Expand Up @@ -1319,7 +1317,7 @@ MainWindow::sidebarSelected(int id)
case 0: selectAthlete(); break;
case 1: // plan not written yet
break;
case 2: selectHome(); break;
case 2: selectTrends(); break;
case 3: selectAnalysis(); break;
case 4: // reflect not written yet
break;
Expand Down Expand Up @@ -1369,7 +1367,7 @@ MainWindow::selectDiary()
}

void
MainWindow::selectHome()
MainWindow::selectTrends()
{
currentTab->homeView->setPerspectives(perspectiveSelector);
viewStack->setCurrentIndex(1);
Expand Down Expand Up @@ -1626,7 +1624,7 @@ MainWindow::dropEvent(QDropEvent *event)
QMessageBox::information(this, tr("Chart Import"), QString(tr("Imported %1 metric charts")).arg(imported.count()));

// switch to trend view if we aren't on it
selectHome();
selectTrends();

// now select what was added
currentTab->context->notifyPresetSelected(currentTab->context->athlete->presets.count()-1);
Expand Down
2 changes: 1 addition & 1 deletion src/Gui/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ class MainWindow : public QMainWindow
void clearFilter();

void selectAthlete();
void selectHome();
void selectTrends();
void selectDiary();
void selectAnalysis();
void selectTrain();
Expand Down
4 changes: 2 additions & 2 deletions src/Gui/NavigationModel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ NavigationModel::NavigationModel(Tab *tab) : tab(tab), block(false), viewinit(fa
{
connect(tab, SIGNAL(viewChanged(int)), this, SLOT(viewChanged(int)));
connect(tab, SIGNAL(rideItemSelected(RideItem*)), this, SLOT(rideChanged(RideItem*)));
connect(static_cast<HomeView*>(tab->view(0))->sidebar, SIGNAL(dateRangeChanged(DateRange)), this, SLOT(dateChanged(DateRange)));
connect(static_cast<TrendsView*>(tab->view(0))->sidebar, SIGNAL(dateRangeChanged(DateRange)), this, SLOT(dateChanged(DateRange)));
connect(tab->context->mainWindow, SIGNAL(backClicked()), this, SLOT(back()));
connect(tab->context->mainWindow, SIGNAL(forwardClicked()), this, SLOT(forward()));

Expand Down Expand Up @@ -185,7 +185,7 @@ NavigationModel::action(bool redo, NavigationEvent event)
case NavigationEvent::DATERANGE:
{
dr = redo ? event.after.value<DateRange>() : event.before.value<DateRange>();
static_cast<HomeView*>(tab->view(0))->sidebar->selectDateRange(dr);
static_cast<TrendsView*>(tab->view(0))->sidebar->selectDateRange(dr);
}
break;
}
Expand Down
54 changes: 43 additions & 11 deletions src/Gui/Perspective.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ static const int tileSpacing = 10;

Perspective::Perspective(Context *context, QString title, int type) :
GcWindow(context), context(context), active(false), clicked(NULL), dropPending(false),
type(type), title_(title), chartCursor(-2), df(NULL), expression_("")
type_(type), title_(title), chartCursor(-2), df(NULL), expression_("")
{
// setup control area
QWidget *cw = new QWidget(this);
Expand All @@ -77,10 +77,10 @@ Perspective::Perspective(Context *context, QString title, int type) :
cl->addWidget(controlStack);
setControls(cw);

switch(this->type) {
switch(this->type_) {
case VIEW_ANALYSIS: view="analysis"; break;
case VIEW_DIARY: view="diary"; break;
case VIEW_HOME: view="home"; break;
case VIEW_TRENDS: view="home"; break;
case VIEW_TRAIN: view="train"; break;
}
setProperty("isManager", true);
Expand Down Expand Up @@ -175,7 +175,7 @@ Perspective::Perspective(Context *context, QString title, int type) :
connect(titleEdit, SIGNAL(textChanged(const QString&)), SLOT(titleChanged()));

// trends view we should select a library chart when a chart is selected.
if (type == VIEW_HOME) connect(context, SIGNAL(presetSelected(int)), this, SLOT(presetSelected(int)));
if (type == VIEW_TRENDS) connect(context, SIGNAL(presetSelected(int)), this, SLOT(presetSelected(int)));

// Allow realtime controllers to scroll train view with steering movements
if (type == VIEW_TRAIN) connect(context, SIGNAL(steerScroll(int)), this, SLOT(steerScroll(int)));
Expand Down Expand Up @@ -662,6 +662,7 @@ Perspective::addChart(GcChartWindow* newone)
newone->setProperty("ride", QVariant::fromValue<RideItem*>(notconst));
newone->setProperty("dateRange", property("dateRange"));
newone->setProperty("style", currentStyle);
newone->setProperty("perspective", QVariant::fromValue<Perspective*>(this));

// add to tabs
switch (currentStyle) {
Expand Down Expand Up @@ -1212,6 +1213,12 @@ GcWindowDialog::GcWindowDialog(GcWinID type, Context *context, GcChartWindow **h
title->setText(GcWindowRegistry::title(type));

win = GcWindowRegistry::newGcWindow(type, context);

// before we do anything, we need to set the perspective, in case
// the chart uses it to decide something - apologies for the convoluted
// method to determine the perspective, but its rare to use this outside
// the context of a chart or a view
win->setProperty("perspective", QVariant::fromValue<Perspective*>(context->mainWindow->athleteTab()->view(context->mainWindow->athleteTab()->currentView())->page()));
chartLayout->addWidget(win);
//win->setFrameStyle(QFrame::Box);

Expand Down Expand Up @@ -1447,7 +1454,7 @@ Perspective *Perspective::fromFile(Context *context, QString filename, int type)

// return the first one with the right type (if there are multiple)
for(int i=0; i<handler.perspectives.count(); i++)
if (returning == NULL && handler.perspectives[i]->type == type)
if (returning == NULL && handler.perspectives[i]->type_ == type)
returning = handler.perspectives[i];

// delete any further perspectives
Expand Down Expand Up @@ -1483,7 +1490,7 @@ void
Perspective::toXml(QTextStream &out)
{
out<<"<layout name=\""<< title_ <<"\" style=\"" << currentStyle
<<"\" type=\"" << type<<"\" expression=\"" << Utils::xmlprotect(expression_) << "\">\n";
<<"\" type=\"" << type_<<"\" expression=\"" << Utils::xmlprotect(expression_) << "\">\n";

// iterate over charts
foreach (GcChartWindow *chart, charts) {
Expand Down Expand Up @@ -1548,12 +1555,17 @@ Perspective::setExpression(QString expr)
if (expression_ != "")
df = new DataFilter(this, context, expression_);

// notify charts that the filter changed
// but only for trends views where it matters
if (type_ == VIEW_TRENDS)
foreach(GcWindow *chart, charts)
chart->notifyPerspectiveFilterChanged(expression_);
}

bool
Perspective::relevant(RideItem *item)
{
if (type != VIEW_ANALYSIS) return true;
if (type_ != VIEW_ANALYSIS) return true;
else if (df == NULL) return false;
else if (df == NULL || item == NULL) return false;

Expand All @@ -1563,6 +1575,25 @@ Perspective::relevant(RideItem *item)

}

QStringList
Perspective::filterlist(DateRange dr)
{
QStringList returning;

Specification spec;
spec.setDateRange(dr);

foreach(RideItem *item, context->athlete->rideCache->rides()) {
if (!spec.pass(item)) continue;

// if no filter, or the filter passes add to count
if (!isFiltered() || df->evaluate(item, NULL).number() != 0)
returning << item->fileName;
}

return returning;
}

/*--------------------------------------------------------------------------------
* Import Chart Dialog - select/deselect charts before importing them
* -----------------------------------------------------------------------------*/
Expand Down Expand Up @@ -1694,7 +1725,7 @@ ImportChartDialog::importClicked()
}

int x=0;
if (view == tr("Trends")) { x=0; context->mainWindow->selectHome(); }
if (view == tr("Trends")) { x=0; context->mainWindow->selectTrends(); }
if (view == tr("Activities")) { x=1; context->mainWindow->selectAnalysis(); }
if (view == tr("Diary")) { x=2; context->mainWindow->selectDiary(); }
if (view == tr("Train")) { x=3; context->mainWindow->selectTrain(); }
Expand Down Expand Up @@ -1729,12 +1760,13 @@ AddPerspectiveDialog::AddPerspectiveDialog(Context *context, QString &name, QStr
form->addRow(new QLabel(tr("Perspective Name")), nameEdit);
layout->addLayout(form);

if (type == VIEW_ANALYSIS) {
if (type == VIEW_ANALYSIS || type == VIEW_TRENDS) {
filterEdit = new SearchBox(context, this);
filterEdit->setFixedMode(true);
filterEdit->setMode(SearchBox::Filter);
filterEdit->setText(expression);
form->addRow(new QLabel(tr("Switch expression")), filterEdit);
if (type == VIEW_ANALYSIS) form->addRow(new QLabel(tr("Switch expression")), filterEdit);
if (type == VIEW_TRENDS) form->addRow(new QLabel(tr("Activities filter")), filterEdit);
}

QHBoxLayout *buttons = new QHBoxLayout();
Expand All @@ -1754,7 +1786,7 @@ void
AddPerspectiveDialog::addClicked()
{
name = nameEdit->text();
if (type == VIEW_ANALYSIS) expression = filterEdit->text();
if (type == VIEW_ANALYSIS || type == VIEW_TRENDS) expression = filterEdit->text();
accept();
}

Expand Down
11 changes: 10 additions & 1 deletion src/Gui/Perspective.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,15 @@ class PerspectiveDialog;
class QTextStream;
class DataFilter;
class SearchBox;
class TrendsView;

class Perspective : public GcWindow
{
Q_OBJECT
G_OBJECT

friend ::TabView;
friend ::TrendsView;
friend ::ViewParser;
friend ::PerspectiveDialog;

Expand All @@ -64,6 +66,10 @@ class Perspective : public GcWindow
// am I relevant? (for switching when ride selected)
bool relevant(RideItem*);

// the items I'd choose (for filtering on trends view)
bool isFiltered() const override { return (type_ == VIEW_TRENDS && df != NULL); }
QStringList filterlist(DateRange dr);

// get/set the expression (will compile df)
QString expression() const;
void setExpression(QString);
Expand All @@ -73,6 +79,7 @@ class Perspective : public GcWindow
bool toFile(QString filename);
void toXml(QTextStream &out);

int type() const { return type_; }
QString title() const { return title_; }

void resetLayout();
Expand Down Expand Up @@ -142,7 +149,7 @@ class Perspective : public GcWindow
bool dropPending;

// what are we?
int type;
int type_;
QString view;

// top bar
Expand Down Expand Up @@ -176,6 +183,8 @@ class Perspective : public GcWindow
static void translateChartTitles(QList<GcChartWindow*> charts);
};

Q_DECLARE_METATYPE(Perspective*);

// setup the chart
class GcWindowDialog : public QDialog
{
Expand Down
11 changes: 8 additions & 3 deletions src/Gui/PerspectiveDialog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ PerspectiveDialog::exportPerspectiveClicked()

QString typedesc;
switch (tabView->type) {
case VIEW_HOME: typedesc="Trends"; break;
case VIEW_TRENDS: typedesc="Trends"; break;
case VIEW_ANALYSIS: typedesc="Analysis"; break;
case VIEW_DIARY: typedesc="Diary"; break;
case VIEW_TRAIN: typedesc="Train"; break;
Expand Down Expand Up @@ -429,8 +429,13 @@ PerspectiveTableWidget::dropEvent(QDropEvent *event)
// move, but only if source and dest are not the same
if (perspective != hoverp) {
chart = perspective->takeChart(chart);
if (chart) hoverp->addChart(chart);
emit chartMoved(chart);
if (chart) {
hoverp->addChart(chart);
emit chartMoved(chart);

// let the chart know it has moved perspectives.
chart->notifyPerspectiveChanged(hoverp);
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/Gui/Tab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ Tab::Tab(Context *context) : QWidget(context->mainWindow), context(context), nos
homeControls = new QStackedWidget(this);
homeControls->setFrameStyle(QFrame::Plain | QFrame::NoFrame);
homeControls->setContentsMargins(0,0,0,0);
homeView = new HomeView(context, homeControls);
homeView = new TrendsView(context, homeControls);

// Diary
diaryControls = new QStackedWidget(this);
Expand Down
2 changes: 1 addition & 1 deletion src/Gui/Tab.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ class Tab: public QWidget
// Each of the views
QStackedWidget *views;
AnalysisView *analysisView;
HomeView *homeView;
TrendsView *homeView;
TrainView *trainView;
DiaryView *diaryView;

Expand Down
6 changes: 3 additions & 3 deletions src/Gui/TabView.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ TabView::TabView(Context *context, int type) :
stack->insertWidget(0, splitter); // splitter always at index 0

QString heading = tr("Compare Activities and Intervals");
if (type == VIEW_HOME) heading = tr("Compare Date Ranges");
if (type == VIEW_TRENDS) heading = tr("Compare Date Ranges");
else if (type == VIEW_TRAIN) heading = tr("Intensity Adjustments and Workout Control");

mainSplitter = new ViewSplitter(Qt::Vertical, heading, this);
Expand Down Expand Up @@ -276,7 +276,7 @@ TabView::saveState()
case VIEW_ANALYSIS: view = "analysis"; break;
case VIEW_TRAIN: view = "train"; break;
case VIEW_DIARY: view = "diary"; break;
case VIEW_HOME: view = "home"; break;
case VIEW_TRENDS: view = "home"; break;
}

QString filename = context->athlete->home->config().canonicalPath() + "/" + view + "-perspectives.xml";
Expand Down Expand Up @@ -314,7 +314,7 @@ TabView::restoreState(bool useDefault)
case VIEW_ANALYSIS: view = "analysis"; break;
case VIEW_TRAIN: view = "train"; break;
case VIEW_DIARY: view = "diary"; break;
case VIEW_HOME: view = "home"; break;
case VIEW_TRENDS: view = "home"; break;
}

// restore window state
Expand Down
2 changes: 1 addition & 1 deletion src/Gui/TabView.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ class TabView : public QWidget
protected:

Context *context;
int type; // used by windowregistry; e.g VIEW_TRAIN VIEW_ANALYSIS VIEW_DIARY VIEW_HOME
int type; // used by windowregistry; e.g VIEW_TRAIN VIEW_ANALYSIS VIEW_DIARY VIEW_TRENDS
// we don't care what values are pass through to the GcWindowRegistry to decide
// what charts are relevant for this view.

Expand Down
58 changes: 52 additions & 6 deletions src/Gui/Views.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
#include "TrainDB.h"
#include "ComparePane.h"
#include "TrainBottom.h"
#include "Specification.h"

#include <QDesktopWidget>
extern QDesktopWidget *desktop;
Expand Down Expand Up @@ -176,7 +177,7 @@ DiaryView::isBlank()
else return true;
}

HomeView::HomeView(Context *context, QStackedWidget *controls) : TabView(context, VIEW_HOME)
TrendsView::TrendsView(Context *context, QStackedWidget *controls) : TabView(context, VIEW_TRENDS)
{
sidebar = new LTMSidebar(context);
BlankStateHomePage *b = new BlankStateHomePage(context);
Expand All @@ -200,36 +201,81 @@ HomeView::HomeView(Context *context, QStackedWidget *controls) : TabView(context
connect(bottomSplitter(), SIGNAL(compareClear()), bottom(), SLOT(clear()));
}

HomeView::~HomeView()
TrendsView::~TrendsView()
{
appsettings->setValue(GC_SETTINGS_MAIN_SIDEBAR "trend", _sidebar);
delete sidebar;
//delete hw; tabview deletes after save state
}

void
HomeView::compareChanged(bool state)
TrendsView::compareChanged(bool state)
{
// we turned compare on / off
context->notifyCompareDateRanges(state);
}

int
TrendsView::countActivities(Perspective *perspective, DateRange dr)
{
// get the filterset for the current daterange
// using the data filter expression
int returning=0;
bool filtered= perspective->df != NULL;

Specification spec;
FilterSet fs;
fs.addFilter(context->isfiltered, context->filters);
fs.addFilter(context->ishomefiltered, context->homeFilters);
spec.setDateRange(dr);
spec.setFilterSet(fs);

foreach(RideItem *item, context->athlete->rideCache->rides()) {
if (!spec.pass(item)) continue;

// if no filter, or the filter passes add to count
if (!filtered || perspective->df->evaluate(item, NULL).number() != 0)
returning++;
}
return returning;

}

void
HomeView::dateRangeChanged(DateRange dr)
TrendsView::dateRangeChanged(DateRange dr)
{
#if 0 // commented out auto switching perspectives on trends because it was annoying...
// if there are no activities for the current perspective
// lets switch to one that has the most
if (countActivities(page(), dr) == 0) {

int max=0;
int index=perspectives_.indexOf(page());
int switchto=index;
for (int i=0; i<perspectives_.count(); i++) {
int count = countActivities(perspectives_[i], dr);
if (count > max) { max=count; switchto=i; }
}

// if we found a better one
if (index != switchto) context->mainWindow->switchPerspective(switchto);
}
#endif

// Once the right perspective is set, we can go ahead and update everyone
emit dateChanged(dr);
context->notifyDateRangeChanged(dr);
if (loaded) page()->setProperty("dateRange", QVariant::fromValue<DateRange>(dr));
}
bool
HomeView::isBlank()
TrendsView::isBlank()
{
if (context->athlete->rideCache->rides().count() > 0) return false;
else return true;
}

void
HomeView::justSelected()
TrendsView::justSelected()
{
if (isSelected()) {
// force date range refresh
Expand Down
8 changes: 5 additions & 3 deletions src/Gui/Views.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,18 +100,20 @@ private slots:
};

class LTMSidebar;
class HomeView : public TabView
class TrendsView : public TabView
{
Q_OBJECT

public:

HomeView(Context *context, QStackedWidget *controls);
~HomeView();
TrendsView(Context *context, QStackedWidget *controls);
~TrendsView();

LTMSidebar *sidebar;
Perspective *hw;

int countActivities(Perspective *, DateRange dr);

signals:
void dateChanged(DateRange);

Expand Down
2 changes: 2 additions & 0 deletions src/Python/PythonEmbed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@ bool PythonEmbed::pythonInstalled(QString &pybin, QString &pypath, QString PYTHO
PythonEmbed::PythonEmbed(const bool verbose, const bool interactive) : verbose(verbose), interactive(interactive)
{
loaded = false;
chart = NULL;
perspective = NULL;
threadid=-1;
name = QString("GoldenCheetah");

Expand Down
1 change: 1 addition & 0 deletions src/Python/PythonEmbed.h
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ class PythonEmbed {

// context for caller - can be called in a thread
QMap<long, ScriptContext> contexts;
Perspective *perspective;
PythonChart *chart;
QWidget *canvas;

Expand Down
10 changes: 8 additions & 2 deletions src/Python/SIP/Bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "HrZones.h"
#include "PaceZones.h"
#include "DataProcessor.h"
#include "Perspective.h"

#include "Bindings.h"

Expand Down Expand Up @@ -583,6 +584,7 @@ Bindings::activities(QString filter) const
FilterSet fs;
fs.addFilter(context->isfiltered, context->filters);
fs.addFilter(context->ishomefiltered, context->homeFilters);
fs.addFilter(python->perspective->isFiltered(), python->perspective->filterlist(DateRange(QDate(1,1,1970),QDate(31,12,3000))));

// did call contain any filters?
if (filter != "") {
Expand Down Expand Up @@ -1187,6 +1189,7 @@ Bindings::seasonMetrics(bool all, DateRange range, QString filter) const
FilterSet fs;
fs.addFilter(context->isfiltered, context->filters);
fs.addFilter(context->ishomefiltered, context->homeFilters);
fs.addFilter(python->perspective->isFiltered(), python->perspective->filterlist(DateRange(QDate(1,1,1970),QDate(31,12,3000))));

// did call contain a filter?
if (filter != "") {
Expand Down Expand Up @@ -1380,6 +1383,7 @@ Bindings::seasonIntervals(DateRange range, QString type) const
FilterSet fs;
fs.addFilter(context->isfiltered, context->filters);
fs.addFilter(context->ishomefiltered, context->homeFilters);
fs.addFilter(python->perspective->isFiltered(), python->perspective->filterlist(DateRange(QDate(1,1,1970),QDate(31,12,3000))));
specification.setFilterSet(fs);

// we need to count intervals that are in range...
Expand Down Expand Up @@ -1817,6 +1821,7 @@ Bindings::metrics(QString metric, bool all, QString filter) const
FilterSet fs;
fs.addFilter(context->isfiltered, context->filters);
fs.addFilter(context->ishomefiltered, context->homeFilters);
fs.addFilter(python->perspective->isFiltered(), python->perspective->filterlist(DateRange(QDate(1,1,1970),QDate(31,12,3000))));

// did call contain a filter?
if (filter != "") {
Expand Down Expand Up @@ -1983,8 +1988,8 @@ Bindings::seasonMeanmax(bool all, DateRange range, QString filter) const
if (all) range = DateRange(QDate(1900,01,01), QDate(2100,01,01));

// did call contain any filters?
QStringList filelist;
bool filt=false;
QStringList filelist=python->perspective->filterlist(DateRange(QDate(1,1,1970),QDate(31,12,3000)));
bool filt=python->perspective->isFiltered();

// if not empty write a filter
if (filter != "") {
Expand Down Expand Up @@ -2402,6 +2407,7 @@ Bindings::seasonPeaks(bool all, DateRange range, QString filter, QList<RideFile:
FilterSet fs;
fs.addFilter(context->isfiltered, context->filters);
fs.addFilter(context->ishomefiltered, context->homeFilters);
fs.addFilter(python->perspective->isFiltered(), python->perspective->filterlist(DateRange(QDate(1,1,1970),QDate(31,12,3000))));
specification.setFilterSet(fs);

// did call contain any filters?
Expand Down
11 changes: 11 additions & 0 deletions src/R/RTool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include "HrZones.h"
#include "PaceZones.h"
#include "GenericChart.h"
#include "Perspective.h"

// Structure used to register routines has changed in v3.4 of R
//
Expand Down Expand Up @@ -68,6 +69,7 @@ RTool::RTool()
failed = false;
starting = true;
canvas = NULL;
perspective = NULL;
chart = NULL;
context = NULL;

Expand Down Expand Up @@ -1227,6 +1229,7 @@ RTool::dfForDateRange(bool all, DateRange range, SEXP filter)
FilterSet fs;
fs.addFilter(rtool->context->isfiltered, rtool->context->filters);
fs.addFilter(rtool->context->ishomefiltered, rtool->context->homeFilters);
fs.addFilter(rtool->perspective->isFiltered(), rtool->perspective->filterlist(range));
specification.setFilterSet(fs);

// did call contain any filters?
Expand Down Expand Up @@ -1451,6 +1454,7 @@ RTool::dfForDateRangeIntervals(DateRange range, QStringList types)
FilterSet fs;
fs.addFilter(rtool->context->isfiltered, rtool->context->filters);
fs.addFilter(rtool->context->ishomefiltered, rtool->context->homeFilters);
fs.addFilter(rtool->perspective->isFiltered(), rtool->perspective->filterlist(range));
specification.setFilterSet(fs);

// we need to count intervals that are in range...
Expand Down Expand Up @@ -2629,6 +2633,12 @@ RTool::dfForDateRangeMeanmax(bool all, DateRange range, SEXP filter)
}
UNPROTECT(1);

// apply perspective filter if trends view and filtered
if (rtool->perspective && rtool->perspective->type() == VIEW_TRENDS && rtool->perspective->isFiltered()) {
filt = true;
filelist << rtool->perspective->filterlist(DateRange(range));
}

// RideFileCache for a date range with our filters (if any)
RideFileCache cache(rtool->context, range.from, range.to, filt, filelist, true, NULL);

Expand Down Expand Up @@ -2921,6 +2931,7 @@ RTool::dfForDateRangePeaks(bool all, DateRange range, SEXP filter, QList<RideFil
FilterSet fs;
fs.addFilter(rtool->context->isfiltered, rtool->context->filters);
fs.addFilter(rtool->context->ishomefiltered, rtool->context->homeFilters);
fs.addFilter(rtool->perspective->isFiltered(), rtool->perspective->filterlist(range));
specification.setFilterSet(fs);

// did call contain any filters?
Expand Down
1 change: 1 addition & 0 deletions src/R/RTool.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ class RTool {
// the canvas to plot on, it may be null
// if no canvas is active
RCanvas *canvas;
Perspective *perspective;
RChart *chart;

Context *context;
Expand Down