Make Analysis view configurable

You can now configure the Analysis view to drag and drop
charts on the page and lay them out etc. A default setup
displays basic data such as ride summary, histograms and
ride plot.

MainWindow still needs a bit of a tidy-up as the basic
code has been edited and re-edited by a cast of thousands
and its a bit of a mess as a result.
This commit is contained in:
Mark Liversedge
2011-05-15 14:34:34 +01:00
parent 5bd102bf70
commit c4ce45fef9
12 changed files with 236 additions and 335 deletions

View File

@@ -357,7 +357,8 @@ AllPlotWindow::AllPlotWindow(MainWindow *mainWindow) :
void
AllPlotWindow::configChanged()
{
fullPlot->setCanvasBackground(GColor(CPLOTTHUMBNAIL));
//We now use the window background color
//fullPlot->setCanvasBackground(GColor(CPLOTTHUMBNAIL));
// we're going to replot, but only if we're active
// and all the other guff
@@ -414,7 +415,8 @@ AllPlotWindow::redrawFullPlot()
// hide the usual plot decorations etc
fullPlot->showPower(1);
fullPlot->setCanvasBackground(GColor(CPLOTTHUMBNAIL));
//We now use the window background color
//fullPlot->setCanvasBackground(GColor(CPLOTTHUMBNAIL));
fullPlot->setCanvasLineWidth(0);
fullPlot->grid->enableY(false);
fullPlot->enableAxis(QwtPlot::yLeft, false);

View File

@@ -462,6 +462,12 @@ HomeWindow::removeChart(int num)
return true;
}
void
HomeWindow::showEvent(QShowEvent *)
{
resizeEvent(NULL);
}
void
HomeWindow::resizeEvent(QResizeEvent * /* e */)
{

View File

@@ -56,6 +56,7 @@ class HomeWindow : public GcWindow
virtual void dragEnterEvent(QDragEnterEvent *);
virtual void dropEvent(QDropEvent *);
void resizeEvent(QResizeEvent *);
void showEvent(QShowEvent *);
bool eventFilter(QObject *object, QEvent *e);
// My widget signals and events

View File

@@ -34,6 +34,10 @@
#include <math.h>
class QwtPlotPanner;
class QwtPlotPicker;
class QwtPlotZoomer;
#include <qwt_plot_picker.h>
#include <qwt_text_engine.h>

View File

@@ -126,7 +126,7 @@ MainWindow::parseRideFileName(const QString &name, QString *notesFileName, QDate
MainWindow::MainWindow(const QDir &home) :
home(home), session(0), isclean(false),
zones_(new Zones), hrzones_(new HrZones), calendar(NULL),
zones_(new Zones), hrzones_(new HrZones),
ride(NULL)
{
setAttribute(Qt::WA_DeleteOnClose);
@@ -273,12 +273,6 @@ MainWindow::MainWindow(const QDir &home) :
calendarDownload = new CalendarDownload(this);
// Analysis toolbox contents
calendar = new RideCalendar(this);
calendar->setHome(home);
calendar->setFixedHeight(250);
calendar->hide();
chartTool = new GcWindowTool(this);
treeWidget = new QTreeWidget;
@@ -334,18 +328,12 @@ MainWindow::MainWindow(const QDir &home) :
last = new RideItem(RIDE_TYPE, home.path(),
name, dt, zones(), hrZones(), notesFileName, this);
allRides->addChild(last);
calendar->update();
}
}
splitter = new QSplitter;
splitter->setContentsMargins(0, 0, 0, 0); // attempting to follow some UI guides
tabWidget = new QTabWidget;
tabWidget->setUsesScrollButtons(true);
tabWidget->setTabPosition(QTabWidget::North);
tabWidget->setContentsMargins(0,0,0,0);
// setup the stacks for all the view controls
// a stacked widget for each toolbar option
masterControls = new QStackedWidget(this);
@@ -388,9 +376,14 @@ MainWindow::MainWindow(const QDir &home) :
trainWindow = new HomeWindow(this, "train", "Training");
trainControls->addWidget(new TrainTool(this, this->home));
// analysis
analWindow = new HomeWindow(this, "analysis", "Analysis");
analysisControls->addWidget(analWindow->controls());
// ToolBox has one thing at the mo... will change soon
toolBox = new QToolBox(this);
toolBox->setStyleSheet(" QToolBox::tab:selected { font: bold; }");
toolBox->setFixedWidth(300);
//toolBox->addItem(calendar, "Calendar"); //XXX some folks will complain, I HATE IT with a PASSION!
#ifdef Q_OS_MAC // on a mac the controls go into a dock drawer widget
@@ -417,11 +410,6 @@ MainWindow::MainWindow(const QDir &home) :
splitter->setSizes(sizes);
}
/////////////////////////// Summary /////////////////////////
summaryWindow = new SummaryWindow(this);
tabs.append(TabInfo(summaryWindow, tr("Summary")));
/////////////////////////// Diary ///////////////////////////
#ifdef GC_HAVE_ICAL
diaryWindow = new DiaryWindow(this);
@@ -429,89 +417,12 @@ MainWindow::MainWindow(const QDir &home) :
diaryControls->addWidget(diaryWindow->controls());
#endif
/////////////////////////// Ride Plot Tab ///////////////////////////
allPlotWindow = new AllPlotWindow(this);
tabs.append(TabInfo(allPlotWindow, tr("Ride Plot")));
////////////////////// Critical Power Plot Tab //////////////////////
criticalPowerWindow = new CriticalPowerWindow(home, this);
tabs.append(TabInfo(criticalPowerWindow, tr("Critical Durations")));
//////////////////////// Power Histogram Tab ////////////////////////
histogramWindow = new HistogramWindow(this);
tabs.append(TabInfo(histogramWindow, tr("Histograms")));
//////////////////////// Pedal Force/zones_Velocity Plot ////////////////////////
pfPvWindow = new PfPvWindow(this);
tabs.append(TabInfo(pfPvWindow, tr("PF/PV")));
//////////////////////// HrPw Plot ////////////////////////
hrPwWindow = new HrPwWindow(this);
tabs.append(TabInfo(hrPwWindow, tr("HrPw")));
//////////////////////// Scatter Plot ////////////////////////
scatterWindow = new ScatterWindow(this, home);
tabs.append(TabInfo(scatterWindow, tr("2D")));
//////////////////////// 3d Model Window ////////////////////////////
#ifdef GC_HAVE_QWTPLOT3D
modelWindow = new ModelWindow(this, home);
tabs.append(TabInfo(modelWindow, tr("3D")));
#endif
//////////////////////// Weekly Summary ////////////////////////
// add daily distance / duration graph:
weeklySummaryWindow = new WeeklySummaryWindow(useMetricUnits, this);
tabs.append(TabInfo(weeklySummaryWindow, tr("Weekly Summary")));
//////////////////////// LTM ////////////////////////
// long term metrics window
ltmWindow = new LTMWindow(this, useMetricUnits, home);
ltmWindow->setChart(0); // XXX mimic old style, before properties managed by layout manager
ltmWindow->setDateRange("All Dates"); // XXX this is going soon anyway
tabs.append(TabInfo(ltmWindow, tr("Metrics")));
//////////////////////// Treemap ////////////////////////
// treemap window
treemapWindow = new TreeMapWindow(this, useMetricUnits, home);
tabs.append(TabInfo(treemapWindow, tr("Treemap")));
//////////////////////// Performance Manager ////////////////////////
performanceManagerWindow = new PerformanceManagerWindow(this);
tabs.append(TabInfo(performanceManagerWindow, tr("PM")));
///////////////////////////// Aerolab //////////////////////////////////
aerolabWindow = new AerolabWindow(this);
tabs.append(TabInfo(aerolabWindow, tr("Aerolab")));
///////////////////////////// GoogleMaps //////////////////////////////////
googleMap = new GoogleMapControl(this);
tabs.append(TabInfo(googleMap, tr("Map")));
///////////////////////////// Editor //////////////////////////////////
rideEdit = new RideEditor(this);
tabs.append(TabInfo(rideEdit, tr("Editor")));
/////////////////////////// Views //////////////////////////////////////
// Setup the two views
views = new QStackedWidget(this);
views->setFrameStyle(QFrame::Plain | QFrame::NoFrame);
views->addWidget(tabWidget); // Analysis stuff
views->addWidget(analWindow); // Analysis stuff
views->addWidget(trainWindow); // Train Stuff
#ifdef GC_HAVE_ICAL
views->addWidget(diaryWindow);
@@ -526,10 +437,10 @@ MainWindow::MainWindow(const QDir &home) :
// on a mac it has only one widget since the
// toolBox is in a drawer, on other platforms
// it has the views and the toolBox
splitter->addWidget(views);
#ifndef Q_OS_MAC
splitter->addWidget(toolBox);
#endif
splitter->addWidget(views);
setCentralWidget(splitter);
/////////////////////////////// Menus ///////////////////////////////
@@ -644,6 +555,7 @@ MainWindow::MainWindow(const QDir &home) :
}
}
#if 0
QMenu *viewMenu = menuBar()->addMenu(tr("&View"));
#ifndef Q_OS_MAC
@@ -677,6 +589,7 @@ MainWindow::MainWindow(const QDir &home) :
viewMenu->addAction(tab.action);
}
tabViewTriggered(true);
#endif
QMenu *helpMenu = menuBar()->addMenu(tr("&Help"));
helpMenu->addAction(tr("&About GoldenCheetah"), this, SLOT(aboutDialog()));
@@ -697,16 +610,10 @@ MainWindow::MainWindow(const QDir &home) :
setUnifiedTitleAndToolBarOnMac(true);
// now we're up and runnning lets connect the signals
connect(calendar, SIGNAL(clicked(const QDate &)),
this, SLOT(dateChanged(const QDate &)));
connect(treeWidget,SIGNAL(customContextMenuRequested(const QPoint &)),
this, SLOT(showTreeContextMenuPopup(const QPoint &)));
connect(treeWidget, SIGNAL(itemSelectionChanged()),
this, SLOT(rideTreeWidgetSelectionChanged()));
connect(splitter, SIGNAL(splitterMoved(int,int)),
this, SLOT(splitterMoved()));
connect(tabWidget, SIGNAL(currentChanged(int)),
this, SLOT(tabChanged(int)));
connect(intervalWidget,SIGNAL(customContextMenuRequested(const QPoint &)),
this, SLOT(showContextMenuPopup(const QPoint &)));
connect(intervalWidget,SIGNAL(itemSelectionChanged()),
@@ -716,6 +623,9 @@ MainWindow::MainWindow(const QDir &home) :
// Kick off
rideTreeWidgetSelectionChanged();
// default to analysis
analWindow->selected();
}
void
@@ -724,35 +634,6 @@ MainWindow::showDock()
dock->toggleViewAction()->activate(QAction::Trigger);
}
void
MainWindow::tabViewTriggered(bool)
{
#ifndef Q_OS_MAC
// lets show/hide
if (sideView->isChecked()) toolBox->show();
else toolBox->hide();
#endif
disconnect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));
QWidget *currentWidget = tabWidget->currentWidget();
int currentIndex = tabWidget->currentIndex();
tabWidget->clear();
QStringList tabsToHide;
foreach (const TabInfo &tab, tabs) {
if (!tab.action || tab.action->isChecked())
tabWidget->addTab(tab.contents, tab.name);
else
tabsToHide << tab.name;
}
if (tabWidget->indexOf(currentWidget) >= 0)
tabWidget->setCurrentWidget(currentWidget);
else if (currentIndex < tabWidget->count())
tabWidget->setCurrentIndex(currentIndex);
tabChanged(tabWidget->currentIndex());
connect(tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabChanged(int)));
appsettings->setValue(GC_TABS_TO_HIDE, tabsToHide.join(","));
}
void
MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
@@ -780,7 +661,7 @@ MainWindow::dropEvent(QDropEvent *event)
}
void
MainWindow::addRide(QString name, bool bSelect /*=true*/)
MainWindow::addRide(QString name, bool /* bSelect =true*/)
{
QString notesFileName;
QDateTime dt;
@@ -814,13 +695,6 @@ MainWindow::addRide(QString name, bool bSelect /*=true*/)
}
rideAdded(last); // here so emitted BEFORE rideSelected is emitted!
allRides->insertChild(index, last);
calendar->update();
criticalPowerWindow->newRideAdded();
if (bSelect)
{
tabWidget->setCurrentWidget(summaryWindow);
treeWidget->setCurrentItem(last);
}
}
void
@@ -886,7 +760,6 @@ MainWindow::removeCurrentRide()
treeWidget->setCurrentItem(itemToSelect);
rideTreeWidgetSelectionChanged();
calendar->update();
}
void
@@ -1190,21 +1063,15 @@ MainWindow::rideTreeWidgetSelectionChanged()
// update the ride property on all widgets
// to let them know they need to replot new
// selected ride
foreach (TabInfo tab, tabs) {
tab.contents->setProperty("ride", QVariant::fromValue<RideItem*>(dynamic_cast<RideItem*>(ride)));
}
_rideMetadata->setProperty("ride", QVariant::fromValue<RideItem*>(dynamic_cast<RideItem*>(ride)));
analWindow->setProperty("ride", QVariant::fromValue<RideItem*>(dynamic_cast<RideItem*>(ride)));
homeWindow->setProperty("ride", QVariant::fromValue<RideItem*>(dynamic_cast<RideItem*>(ride)));
#ifdef GC_HAVE_ICAL
diaryWindow->setProperty("ride", QVariant::fromValue<RideItem*>(dynamic_cast<RideItem*>(ride)));
#endif
trainWindow->setProperty("ride", QVariant::fromValue<RideItem*>(dynamic_cast<RideItem*>(ride)));
if (!ride)
return;
calendar->setSelectedDate(ride->dateTime.date());
if (!ride) return;
// refresh interval list for bottom left
// first lets wipe away the existing intervals
@@ -1230,25 +1097,8 @@ MainWindow::rideTreeWidgetSelectionChanged()
}
}
}
// turn off tabs that don't make sense for manual file entry
int histIndex = tabWidget->indexOf(histogramWindow);
int pfpvIndex = tabWidget->indexOf(pfPvWindow);
int plotIndex = tabWidget->indexOf(allPlotWindow);
int modelIndex = tabWidget->indexOf(modelWindow);
int mapIndex = tabWidget->indexOf(googleMap);
int editorIndex = tabWidget->indexOf(rideEdit);
bool enabled = (ride->ride() && ride->ride()->deviceType() != QString("Manual CSV") &&
!ride->ride()->dataPoints().isEmpty());
if (histIndex >= 0) tabWidget->setTabEnabled(histIndex, enabled);
if (pfpvIndex >= 0) tabWidget->setTabEnabled(pfpvIndex, enabled);
if (plotIndex >= 0) tabWidget->setTabEnabled(plotIndex, enabled);
if (modelIndex >= 0) tabWidget->setTabEnabled(modelIndex, enabled);
if (mapIndex >= 0) tabWidget->setTabEnabled(mapIndex, enabled);
if (editorIndex >= 0) tabWidget->setTabEnabled(editorIndex, enabled);
}
void
MainWindow::showTreeContextMenuPopup(const QPoint &pos)
{
@@ -1315,15 +1165,19 @@ MainWindow::showContextMenuPopup(const QPoint &pos)
connect(actFrontInt, SIGNAL(triggered(void)), this, SLOT(frontInterval(void)));
connect(actBackInt, SIGNAL(triggered(void)), this, SLOT(backInterval(void)));
#if 0
if (tabWidget->currentWidget() == allPlotWindow)
menu.addAction(actZoomInt);
#endif
menu.addAction(actRenameInt);
menu.addAction(actDeleteInt);
#if 0
if ((tabWidget->currentWidget() == pfPvWindow || tabWidget->currentWidget() == scatterWindow)
&& activeInterval->isSelected()) {
menu.addAction(actFrontInt);
menu.addAction(actBackInt);
}
#endif
menu.exec(intervalWidget->mapToGlobal( pos ));
}
}
@@ -1381,7 +1235,7 @@ MainWindow::intervalEdited(QTreeWidgetItem *, int) {
void
MainWindow::zoomInterval() {
// zoom into this interval on allPlot
allPlotWindow->zoomInterval(activeInterval);
//allPlotWindow->zoomInterval(activeInterval);
}
void
@@ -1495,6 +1349,7 @@ MainWindow::closeEvent(QCloseEvent* event)
else {
// save the state of all the pages
analWindow->saveState();
homeWindow->saveState();
trainWindow->saveState();
@@ -1503,23 +1358,6 @@ MainWindow::closeEvent(QCloseEvent* event)
}
}
void
MainWindow::leftLayoutMoved()
{
appsettings->setValue(GC_SETTINGS_CALENDAR_SIZES, leftLayout->saveState());
}
void
MainWindow::splitterMoved()
{
appsettings->setValue(GC_SETTINGS_SPLITTER_SIZES, splitter->saveState());
}
void
MainWindow::summarySplitterMoved()
{
appsettings->setValue(GC_SETTINGS_SUMMARYSPLITTER_SIZES, metaSplitter->saveState());
}
// set the rider value of CP to the value derived from the CP model extraction
void
MainWindow::setCriticalPower(int cp)
@@ -1557,25 +1395,6 @@ MainWindow::setCriticalPower(int cp)
zonesChanged();
}
void
MainWindow::tabChanged(int id)
{
// id is the tab number and not the offset
// into the full list, so lets find the tab
// we just changed to and set the controls
// to the one selected
if (ride == NULL) return;
GcWindow *selected = static_cast<GcWindow*>(tabWidget->widget(id));
for(int i=0; i< tabs.count(); i++) {
if (tabs[i].contents == selected) {
analysisControls->setCurrentIndex(i);
tabs[i].contents->setProperty("ride", QVariant::fromValue<RideItem*>(dynamic_cast<RideItem*>(ride)));
break;
}
}
}
void
MainWindow::aboutDialog()
{
@@ -1747,8 +1566,6 @@ MainWindow::notifyConfigChanged()
void
MainWindow::notifyRideSelected()
{
//rideSelected();
if (calendar) calendar->configUpdate(); //XXX << nasty hack fix to refresh calendar when ride start changes
}
void
@@ -1862,6 +1679,7 @@ MainWindow::selectAnalysis()
{
masterControls->setCurrentIndex(0);
views->setCurrentIndex(0);
analWindow->selected(); // tell it!
}
void

View File

@@ -32,77 +32,99 @@
#include "SpecialFields.h"
#include <boost/shared_ptr.hpp>
class AerolabWindow;
class GoogleMapControl;
class AllPlotWindow;
class CriticalPowerWindow;
class HistogramWindow;
class PfPvWindow;
class HrPwWindow;
class QwtPlotPanner;
class QwtPlotPicker;
class QwtPlotZoomer;
class LTMWindow;
class MetricAggregator;
class ModelWindow;
class ScatterWindow;
class RealtimeWindow;
class RideFile;
class RideMetadata;
class WeeklySummaryWindow;
class Zones;
class HrZones;
class RideCalendar;
class PerformanceManagerWindow;
class SummaryWindow;
class ViewSelection;
class TrainWindow;
class RideEditor;
class RideNavigator;
class RideFile;
class ErgFile;
class RideMetadata;
class WithingsDownload;
class CalendarDownload;
class DiaryWindow;
class TreeMapWindow;
class GcWindowTool;
class HomeWindow;
class ICalendar;
class CalDAV;
class HomeWindow;
class GcWindowTool;
class Seasons;
class IntervalSummaryWindow;
class ErgFile;
class MainWindow : public QMainWindow
{
Q_OBJECT
G_OBJECT
public:
MainWindow(const QDir &home);
void addRide(QString name, bool bSelect=true);
void removeCurrentRide();
const RideFile *currentRide();
const RideItem *currentRideItem() { return ride; }
const QTreeWidgetItem *allRideItems() { return allRides; }
const QTreeWidgetItem *allIntervalItems() { return allIntervals; }
QTreeWidget *intervalTreeWidget() { return intervalWidget; }
QTreeWidget *rideTreeWidget() { return treeWidget; }
QTreeWidgetItem *mutableIntervalItems() { return allIntervals; }
void getBSFactors(double &timeBS, double &distanceBS,
double &timeDP, double &distanceDP);
QDir home;
void setCriticalPower(int cp);
MainWindow(const QDir &home);
// *********************************************
// ATHLETE INFO
// *********************************************
// general data
QString cyclist; // the cyclist name
bool useMetricUnits; // metric/imperial prefs
QDir home;
const Zones *zones() const { return zones_; }
const HrZones *hrZones() const { return hrzones_; }
void setCriticalPower(int cp);
QSqlDatabase db;
MetricAggregator *metricDB;
Seasons *seasons;
void updateRideFileIntervals();
// athlete's ride library
void addRide(QString name, bool bSelect=true);
void removeCurrentRide();
void getBSFactors(double &timeBS, double &distanceBS,
double &timeDP, double &distanceDP);
// athlete's calendar
CalendarDownload *calendarDownload;
#ifdef GC_HAVE_ICAL
ICalendar *rideCalendar;
CalDAV *davCalendar;
#endif
// *********************************************
// ATHLETE RIDE LIBRARY
// *********************************************
// save a ride to disk
void saveSilent(RideItem *);
bool saveRideSingleDialog(RideItem *);
// currently selected ride item, files, metadata
void selectRideFile(QString);
QTreeWidget *rideTreeWidget() { return treeWidget; }
const QTreeWidgetItem *allRideItems() { return allRides; }
RideItem *rideItem() const { return ride; }
const RideFile *currentRide();
const RideItem *currentRideItem() { return ride; }
void updateRideFileIntervals();
RideMetadata *rideMetadata() { return _rideMetadata; }
// let the other widgets know when ride status changes
// ride intervals
const QTreeWidgetItem *allIntervalItems() { return allIntervals; }
QTreeWidget *intervalTreeWidget() { return intervalWidget; }
QTreeWidgetItem *mutableIntervalItems() { return allIntervals; }
// *********************************************
// MAINWINDOW STATE DATA
// *********************************************
// state data
SpecialFields specialFields;
int session;
bool isclean;
// *********************************************
// APPLICATION EVENTS
// *********************************************
// MainWindow signals are used to notify
// widgets of important events, these methods
// can be called to raise signals
void notifyConfigChanged(); // used by ConfigDialog to notify MainWindow
// when config has changed - and to get a
// signal emitted to notify its children
@@ -110,30 +132,13 @@ class MainWindow : public QMainWindow
// rideItem date/time changes
void notifyRideClean() { rideClean(); }
void notifyRideDirty() { rideDirty(); }
void selectView(int);
void selectRideFile(QString);
// realtime signals
void notifyTelemetryUpdate(RealtimeData rtData) { telemetryUpdate(rtData); }
void notifyErgFileSelected(ErgFile *x) { ergFileSelected(x); }
void notifySetNow(long now) { setNow(now); }
// db connections to cyclistdir/metricDB - one per active MainWindow
QSqlDatabase db;
MetricAggregator *metricDB;
SpecialFields specialFields;
Seasons *seasons;
int session;
bool isclean;
QString cyclist; // the cyclist name
bool useMetricUnits; // whether metric units are used (or imperial)
CalendarDownload *calendarDownload;
#ifdef GC_HAVE_ICAL
ICalendar *rideCalendar;
CalDAV *davCalendar;
#endif
protected:
@@ -148,7 +153,6 @@ class MainWindow : public QMainWindow
signals:
//void rideSelected();
void intervalSelected();
void intervalsChanged();
void zonesChanged();
@@ -163,12 +167,8 @@ class MainWindow : public QMainWindow
void setNow(long);
private slots:
void tabViewTriggered(bool);
void rideTreeWidgetSelectionChanged();
void intervalTreeWidgetSelectionChanged();
void leftLayoutMoved();
void splitterMoved();
void summarySplitterMoved();
void newCyclist();
void openCyclist();
void downloadRide();
@@ -195,7 +195,6 @@ class MainWindow : public QMainWindow
void findPowerPeaks();
void splitRide();
void deleteRide();
void tabChanged(int index);
void aboutDialog();
void saveRide(); // save current ride menu item
void revertRide();
@@ -203,9 +202,9 @@ class MainWindow : public QMainWindow
void showOptions();
void showTools();
void showWorkoutWizard();
void importRideToDB();
void importRideToDB();
void scanForMissing();
void dateChanged(const QDate &);
void dateChanged(const QDate &);
void showTreeContextMenuPopup(const QPoint &);
void showContextMenuPopup(const QPoint &);
void deleteInterval();
@@ -243,21 +242,13 @@ class MainWindow : public QMainWindow
static QString notesFileName(QString rideFileName);
private:
RideItem *ride; // the currently selected ride
QToolBox *toolBox;
QToolBar *toolbar;
QDockWidget *dock;
QDockWidget *dock;
QAction *homeAct, *diaryAct, *analysisAct, *measuresAct, *trainAct, *athleteAct, *helpAct, *configAct;
bool parseRideFileName(const QString &name, QString *notesFileName, QDateTime *dt);
struct TabInfo {
GcWindow *contents;
QString name;
QAction *action;
TabInfo(GcWindow *contents, QString name) :
contents(contents), name(name), action(NULL) {}
};
QList<TabInfo> tabs;
boost::shared_ptr<QSettings> settings;
IntervalItem *activeInterval; // currently active for context menu popup
RideItem *activeRide; // currently active for context menu popup
@@ -274,57 +265,32 @@ class MainWindow : public QMainWindow
QAction *sideView;
QAction *toolView;
// Analysis
RideCalendar *calendar;
// Top-level views
HomeWindow *homeWindow;
DiaryWindow *diaryWindow;
HomeWindow *trainWindow;
HomeWindow *analWindow;
// sidebar
QTreeWidgetItem *allRides;
QTreeWidgetItem *allIntervals;
IntervalSummaryWindow *intervalSummaryWindow;
QSplitter *leftLayout;
RideMetadata *_rideMetadata;
GcWindowTool *chartTool;
QSplitter *summarySplitter;
QSplitter *splitter;
QSplitter *metaSplitter;
QTreeWidget *treeWidget;
QSplitter *intervalSplitter;
QTreeWidget *intervalWidget;
IntervalSummaryWindow *intervalSummaryWindow;
QTabWidget *tabWidget;
SummaryWindow *summaryWindow;
DiaryWindow *diaryWindow;
HomeWindow *homeWindow;
HomeWindow *trainWindow;
AllPlotWindow *allPlotWindow;
HistogramWindow *histogramWindow;
WeeklySummaryWindow *weeklySummaryWindow;
LTMWindow *ltmWindow;
CriticalPowerWindow *criticalPowerWindow;
ModelWindow *modelWindow;
ScatterWindow *scatterWindow;
AerolabWindow *aerolabWindow;
GoogleMapControl *googleMap;
TreeMapWindow *treemapWindow;
RideEditor *rideEdit;
RideNavigator *rideNavigator;
QTreeWidgetItem *allRides;
QTreeWidgetItem *allIntervals;
QSplitter *leftLayout;
RideMetadata *_rideMetadata;
QSplitter *summarySplitter;
//QwtPlotCurve *weeklyBSCurve;
//QwtPlotCurve *weeklyRICurve;
PerformanceManagerWindow *performanceManagerWindow;
// pedal force/pedal velocity scatter plot widgets
PfPvWindow *pfPvWindow;
HrPwWindow *hrPwWindow;
RideItem *ride; // the currently selected ride
QuarqdClient *client;
QSignalMapper *toolMapper;
WithingsDownload *withingsDownload;
GcWindowTool *chartTool;
// Miscellany
QuarqdClient *client;
QSignalMapper *toolMapper;
WithingsDownload *withingsDownload;
bool parseRideFileName(const QString &name, QString *notesFileName, QDateTime *dt);
};
#endif // _GC_MainWindow_h

View File

@@ -37,6 +37,7 @@ class MainWindow;
class RideItem;
class RideFilePoint;
class RideFileCache;
class HistogramWindow;
class PowerHistBackground;
class PowerHistZoneLabel;
class HrHistBackground;

View File

@@ -146,7 +146,6 @@ class TrainTool : public QWidget
const QDir home;
MainWindow *main;
ViewSelection *viewSelection;
QTreeWidget *workoutTree;
QTreeWidget *deviceTree;

View File

@@ -28,6 +28,8 @@
#include "MainWindow.h"
class TreeMapWindow;
// for sorting
class TreeMap;
bool TreeMapLessThan(const TreeMap *, const TreeMap *);

View File

@@ -39,6 +39,8 @@
#include <qwt_plot_picker.h>
#include <qwt_text_engine.h>
class TreeMapPlot;
class TreeMapWindow : public GcWindow
{
Q_OBJECT

View File

@@ -36,6 +36,7 @@
<file>xml/metadata.xml</file>
<file>xml/measures.xml</file>
<file>xml/train-layout.xml</file>
<file>xml/analysis-layout.xml</file>
<file>html/ltm-summary.html</file>
<file>images/toolbar/close-icon.png</file>
<file>images/toolbar/save.png</file>

View File

@@ -0,0 +1,99 @@
<layout name="analysis">
<chart id="14" name="Ride Summary Window" title="Summary" >
<property name="instanceName" type="QString" value="Ride Summary Window" />
<property name="title" type="QString" value="Summary" />
<property name="widthFactor" type="double" value="1.7042" />
<property name="heightFactor" type="double" value="1.65821" />
<property name="resizable" type="bool" value="1" />
</chart>
<chart id="5" name="Google Map" title="Map" >
<property name="instanceName" type="QString" value="Google Map" />
<property name="title" type="QString" value="Map" />
<property name="widthFactor" type="double" value="2.45521" />
<property name="heightFactor" type="double" value="1.66194" />
<property name="resizable" type="bool" value="1" />
</chart>
<chart id="6" name="Histogram Window" title="Power Distribution" >
<property name="instanceName" type="QString" value="Histogram Window" />
<property name="title" type="QString" value="Power Distribution" />
<property name="widthFactor" type="double" value="4" />
<property name="heightFactor" type="double" value="2.51311" />
<property name="resizable" type="bool" value="1" />
<property name="series" type="int" value="0" />
<property name="percent" type="int" value="0" />
<property name="bin" type="double" value="4" />
<property name="logY" type="bool" value="0" />
<property name="zeroes" type="bool" value="0" />
<property name="shade" type="bool" value="0" />
<property name="zoned" type="bool" value="0" />
<property name="scope" type="bool" value="0" />
</chart>
<chart id="6" name="Histogram Window" title="Cadence Distribution" >
<property name="instanceName" type="QString" value="Histogram Window" />
<property name="title" type="QString" value="Cadence Distribution" />
<property name="widthFactor" type="double" value="4" />
<property name="heightFactor" type="double" value="2.51349" />
<property name="resizable" type="bool" value="1" />
<property name="series" type="int" value="3" />
<property name="percent" type="int" value="0" />
<property name="bin" type="double" value="1" />
<property name="logY" type="bool" value="0" />
<property name="zeroes" type="bool" value="0" />
<property name="shade" type="bool" value="0" />
<property name="zoned" type="bool" value="0" />
<property name="scope" type="bool" value="0" />
</chart>
<chart id="6" name="Histogram Window" title="Heartrate Distribution" >
<property name="instanceName" type="QString" value="Histogram Window" />
<property name="title" type="QString" value="Heartrate Distribution" />
<property name="widthFactor" type="double" value="4" />
<property name="heightFactor" type="double" value="2.51349" />
<property name="resizable" type="bool" value="1" />
<property name="series" type="int" value="1" />
<property name="percent" type="int" value="0" />
<property name="bin" type="double" value="1" />
<property name="logY" type="bool" value="0" />
<property name="zeroes" type="bool" value="0" />
<property name="shade" type="bool" value="0" />
<property name="zoned" type="bool" value="0" />
<property name="scope" type="bool" value="0" />
</chart>
<chart id="6" name="Histogram Window" title="Speed Distribution" >
<property name="instanceName" type="QString" value="Histogram Window" />
<property name="title" type="QString" value="Speed Distribution" />
<property name="widthFactor" type="double" value="4" />
<property name="heightFactor" type="double" value="2.51349" />
<property name="resizable" type="bool" value="1" />
<property name="series" type="int" value="2" />
<property name="percent" type="int" value="0" />
<property name="bin" type="double" value="20" />
<property name="logY" type="bool" value="0" />
<property name="zeroes" type="bool" value="0" />
<property name="shade" type="bool" value="0" />
<property name="zoned" type="bool" value="0" />
<property name="scope" type="bool" value="0" />
</chart>
<chart id="23" name="Metadata Window" title="Information" >
<property name="instanceName" type="QString" value="Metadata Window" />
<property name="title" type="QString" value="Information" />
<property name="widthFactor" type="double" value="1.00103" />
<property name="heightFactor" type="double" value="2.16898" />
<property name="resizable" type="bool" value="1" />
</chart>
<chart id="2" name="Ride Plot Window" title="Ride Plot" >
<property name="instanceName" type="QString" value="Ride Plot Window" />
<property name="title" type="QString" value="Ride Plot" />
<property name="widthFactor" type="double" value="1" />
<property name="heightFactor" type="double" value="1" />
<property name="resizable" type="bool" value="1" />
<property name="stacked" type="bool" value="0" />
<property name="showGrid" type="int" value="2" />
<property name="showHr" type="int" value="2" />
<property name="showSpeed" type="int" value="2" />
<property name="showCad" type="int" value="2" />
<property name="showAlt" type="int" value="2" />
<property name="showPower" type="int" value="1" />
<property name="byDistance" type="int" value="0" />
<property name="smoothing" type="int" value="1" />
</chart>
</layout>