RideNavigator as a Window

You can now place a ride navigator on the chart layouts, this allows
the user to configure many more columns and use the navigator to
browse and order the activity history in a log/journal format.

The default diary layout now has two tabs; one for the calendar and
another for the activity history.

There appears to be a few minor bugs related to column/chart resizing
that have been present for a while, but are more obvious now the navigator
is a chart in its own right. These will be resolved later.
This commit is contained in:
Mark Liversedge
2011-10-21 18:43:24 +01:00
parent cd58af530e
commit 0d1ad15bf7
7 changed files with 241 additions and 151 deletions

View File

@@ -40,6 +40,7 @@
#include "HrPwWindow.h"
#include "RaceWindow.h" // XXX not done
#include "RideEditor.h"
#include "RideNavigator.h"
#include "RideSummaryWindow.h"
#include "ScatterWindow.h"
#include "SummaryWindow.h"
@@ -53,32 +54,33 @@
GcWindowRegistry GcWindows[] = {
// name GcWinID
{ "Aerolab Chung Analysis",GcWindowTypes::Aerolab },
{ "Performance Graph",GcWindowTypes::AllPlot },
{ "Critical Mean Maximals",GcWindowTypes::CriticalPower },
{ "Activity Calendar",GcWindowTypes::Diary },
{ "Google Route Map",GcWindowTypes::GoogleMap },
{ "Bing Route Map",GcWindowTypes::BingMap },
{ "Distribution Histogram",GcWindowTypes::Histogram },
{ "Long Term Metrics",GcWindowTypes::LTM },
{ "3d Analysis",GcWindowTypes::Model },
{ "Performance Manager",GcWindowTypes::PerformanceManager },
{ "Pedal Force vs Velocity",GcWindowTypes::PfPv },
{ "Heartrate vs Power",GcWindowTypes::HrPw },
{ "Editor",GcWindowTypes::RideEditor },
{ "Calendar",GcWindowTypes::Diary },
{ "Navigator", GcWindowTypes::ActivityNavigator },
{ "Summary",GcWindowTypes::RideSummary },
{ "Details",GcWindowTypes::MetadataWindow },
{ "Editor",GcWindowTypes::RideEditor },
{ "Summary & Details",GcWindowTypes::Summary },
{ "2d Analysis",GcWindowTypes::Scatter },
{ "Collection TreeMap",GcWindowTypes::TreeMap },
{ "Performance",GcWindowTypes::AllPlot },
{ "Pedal Force vs Velocity",GcWindowTypes::PfPv },
{ "Critical Mean Maximals",GcWindowTypes::CriticalPower },
{ "Histogram",GcWindowTypes::Histogram },
{ "Google Map",GcWindowTypes::GoogleMap },
{ "Bing Map",GcWindowTypes::BingMap },
{ "2d Plot",GcWindowTypes::Scatter },
{ "3d Plot",GcWindowTypes::Model },
{ "Heartrate vs Power",GcWindowTypes::HrPw },
{ "Weekly Summary",GcWindowTypes::WeeklySummary },
{ "Video Player",GcWindowTypes::VideoPlayer },
{ "Long Term Metrics",GcWindowTypes::LTM },
{ "Performance Manager",GcWindowTypes::PerformanceManager },
{ "Collection TreeMap",GcWindowTypes::TreeMap },
{ "Aerolab Chung Analysis",GcWindowTypes::Aerolab },
{ "Realtime Controls", GcWindowTypes::RealtimeControls },
{ "Realtime Dial",GcWindowTypes::DialWindow },
{ "Realtime Plot",GcWindowTypes::RealtimePlot },
{ "Workout Plot",GcWindowTypes::WorkoutPlot },
{ "Train Map Window", GcWindowTypes::MapWindow },
{ "Train StreetView Window", GcWindowTypes::StreetViewWindow },
{ "Video Player",GcWindowTypes::VideoPlayer },
{ "", GcWindowTypes::None }};
// instantiate a new window
@@ -126,6 +128,7 @@ GcWindowRegistry::newGcWindow(GcWinID id, MainWindow *main) //XXX mainWindow wil
case GcWindowTypes::BingMap: returning = new BingMap(main); break;
case GcWindowTypes::MapWindow: returning = new MapWindow(main); break;
case GcWindowTypes::StreetViewWindow: returning = new StreetViewWindow(main); break;
case GcWindowTypes::ActivityNavigator: returning = new RideNavigator(main); break;
default: return NULL; break;
}
if (returning) returning->setProperty("type", QVariant::fromValue<GcWinID>(id));

View File

@@ -55,6 +55,7 @@ enum gcwinid {
StreetViewWindow = 27,
BingMap = 28,
RealtimeControls = 29,
ActivityNavigator = 30,
};
};
typedef enum GcWindowTypes::gcwinid GcWinID;

View File

@@ -254,6 +254,14 @@ MainWindow::MainWindow(const QDir &home) :
// UI Ride List (configurable)
listView = new RideNavigator(this);
// retrieve settings (properties are saved when we close the window)
if (appsettings->cvalue(cyclist, GC_NAVHEADINGS, "").toString() != "") {
listView->setSortByIndex(appsettings->cvalue(cyclist, GC_SORTBY).toInt());
listView->setSortByOrder(appsettings->cvalue(cyclist, GC_SORTBYORDER).toInt());
listView->setGroupBy(appsettings->cvalue(cyclist, GC_NAVGROUPBY).toInt());
listView->setColumns(appsettings->cvalue(cyclist, GC_NAVHEADINGS).toString());
listView->setWidths(appsettings->cvalue(cyclist, GC_NAVHEADINGWIDTHS).toString());
}
// INTERVALS
intervalSummaryWindow = new IntervalSummaryWindow(this);
@@ -697,7 +705,7 @@ MainWindow::showTreeContextMenuPopup(const QPoint &pos)
connect(actTweetRide, SIGNAL(triggered(void)), this, SLOT(tweetRide()));
menu.addAction(actTweetRide);
#endif
menu.exec(listView->mapToGlobal( pos ));
menu.exec(pos);
}
}
@@ -761,6 +769,13 @@ MainWindow::closeEvent(QCloseEvent* event)
if (saveRideExitDialog() == false) event->ignore();
else {
// save ride list config
appsettings->setCValue(cyclist, GC_SORTBY, listView->sortByIndex());
appsettings->setCValue(cyclist, GC_SORTBYORDER, listView->sortByOrder());
appsettings->setCValue(cyclist, GC_NAVGROUPBY, listView->groupBy());
appsettings->setCValue(cyclist, GC_NAVHEADINGS, listView->columns());
appsettings->setCValue(cyclist, GC_NAVHEADINGWIDTHS, listView->widths());
// save the state of all the pages
analWindow->saveState();
homeWindow->saveState();

View File

@@ -175,6 +175,9 @@ class MainWindow : public QMainWindow
void ergFileSelected(ErgFile *);
void setNow(long);
public slots:
void showTreeContextMenuPopup(const QPoint &);
private slots:
void rideTreeWidgetSelectionChanged();
void intervalTreeWidgetSelectionChanged();
@@ -211,7 +214,6 @@ class MainWindow : public QMainWindow
void showWorkoutWizard();
void resetWindowLayout();
void dateChanged(const QDate &);
void showTreeContextMenuPopup(const QPoint &);
void showContextMenuPopup(const QPoint &);
void deleteInterval();
void renameInterval();

View File

@@ -24,19 +24,26 @@
#define tr(s) QObject::tr(s)
static const QString defaultconfig = QString("Duration|Distance|TSS|IF|Date");
// default column layouts etc
static const QString defaultColumns = QString("Duration|Distance|TSS|IF|Date");
static const QString defaultWidths = QString("50|50|50|50|50");
static const int defaultSortBy = 2;
RideNavigator::RideNavigator(MainWindow *parent) : main(parent), active(false), groupBy(-1)
RideNavigator::RideNavigator(MainWindow *parent) : main(parent), active(false), _groupBy(-1)
{
// get column headings
QList<QString> defaultColumns = appsettings->cvalue(main->cyclist, GC_NAVHEADINGS, defaultconfig)
.toString().split("|", QString::SkipEmptyParts);
_columns = defaultColumns;
_widths = defaultWidths;
_sortByIndex = defaultSortBy;
_sortByOrder = 0;
currentColumn = -1;
_groupBy = -1;
if (defaultColumns.count() < 2) defaultColumns = defaultconfig.split("|", QString::SkipEmptyParts);
init = false;
QVBoxLayout *mainLayout = new QVBoxLayout(this);
mainLayout = new QVBoxLayout(this);
mainLayout->setSpacing(0);
mainLayout->setContentsMargins(0,0,0,0);
mainLayout->setContentsMargins(3,3,3,3);
sqlModel = new QSqlTableModel(this, main->metricDB->db()->connection());
sqlModel->setTable("metrics");
@@ -53,6 +60,7 @@ RideNavigator::RideNavigator(MainWindow *parent) : main(parent), active(false),
sortModel->setDynamicSortFilter(true);
//sortModel->setSort(2, Qt::AscendingOrder); // date backwards
// get setup
tableView = new QTreeView;
delegate = new NavigatorCellDelegate(this);
tableView->setItemDelegate(delegate);
@@ -67,7 +75,7 @@ RideNavigator::RideNavigator(MainWindow *parent) : main(parent), active(false),
tableView->header()->setCascadingSectionResizes(true); // easier to resize this way
tableView->setContextMenuPolicy(Qt::CustomContextMenu);
tableView->header()->setStretchLastSection(false);
tableView->header()->setMinimumSectionSize(20);
tableView->header()->setMinimumSectionSize(0);
//tableView->setUniformRowHeights(true);
QFont smaller;
smaller.setPointSize(smaller.pointSize()-2);
@@ -84,76 +92,9 @@ RideNavigator::RideNavigator(MainWindow *parent) : main(parent), active(false),
"color: #535353;"
"font-weight: bold; }");
#endif
// good to go
tableView->show();
// this maps friendly names to metric names
QMap <QString, QString> nameMap;
// add the standard columns to the map
nameMap.insert("filename", "File");
nameMap.insert("timestamp", "Last updated");
nameMap.insert("ride_date", "Date");
nameMap.insert("fingerprint", "Config Checksum");
// add metrics to the map
const RideMetricFactory &factory = RideMetricFactory::instance();
for (int i=0; i<factory.metricCount(); i++) {
QString converted = QTextEdit(factory.rideMetric(factory.metricName(i))->name()).toPlainText();
// from sql column name to friendly metric name
nameMap.insert(QString("X%1").arg(factory.metricName(i)), converted);
// from friendly metric name to metric pointer
columnMetrics.insert(converted, factory.rideMetric(factory.metricName(i)));
}
// add metadata fields...
SpecialFields sp; // all the special fields are in here...
foreach(FieldDefinition field, main->rideMetadata()->getFields()) {
if (!sp.isMetric(field.name) && field.type < 5) {
nameMap.insert(QString("Z%1").arg(sp.makeTechName(field.name)), field.name);
}
}
// rename and hide columns in the view to be more user friendly
// and maintain a list of all the column headings so we can
// reference the section for a given column and unhide later
// if the user specifically wants to see it
for (int i=0; i<tableView->header()->count(); i++) {
QString friendly, techname = sortModel->headerData(i, Qt::Horizontal).toString();
if ((friendly = nameMap.value(techname, "unknown")) != "unknown") {
sortModel->setHeaderData(i, Qt::Horizontal, friendly);
logicalHeadings << friendly;
} else
logicalHeadings << techname;
if (i && !defaultColumns.contains(friendly)) {
tableView->setColumnHidden(i, true);
}
}
// now re-order the columns according to the
// prevailing preferences. They are listed in
// the order we want them, column zero is the
// group by column, so we leave that alone
for(int i=1; i<defaultColumns.count(); i++) {
tableView->header()->moveSection(tableView->header()->visualIndex(logicalHeadings.indexOf(defaultColumns[i])), i);
}
// initialise to whatever groupBy we want to start with
tableView->sortByColumn(appsettings->cvalue(main->cyclist, GC_SORTBY, "2").toInt(),
static_cast<Qt::SortOrder>(appsettings->value(this, GC_SORTBYORDER, static_cast<int>(Qt::AscendingOrder)).toInt()));
//tableView->setColumnHidden(0, true);
tableView->setColumnWidth(0,0);
// set the column widths
int columnnumber=0;
foreach(QString size, appsettings->cvalue(main->cyclist, GC_NAVHEADINGWIDTHS, "50|50|50|50|50").toString().split("|", QString::SkipEmptyParts))
tableView->setColumnWidth(columnnumber++,size.toInt());
groupBy = -1;
currentColumn = appsettings->cvalue(main->cyclist, GC_NAVGROUPBY, "-1").toInt();
setGroupBy();
resetView();
// refresh when database is updated
connect(main->metricDB, SIGNAL(dataChanged()), this, SLOT(refresh()));
@@ -163,22 +104,22 @@ RideNavigator::RideNavigator(MainWindow *parent) : main(parent), active(false),
// refresh when rides added/removed
connect(main, SIGNAL(rideAdded(RideItem*)), this, SLOT(refresh()));
connect(main, SIGNAL(rideDeleted(RideItem*)), this, SLOT(refresh()));
connect(main->rideTreeWidget(), SIGNAL(itemSelectionChanged()), this, SLOT(rideTreeSelectionChanged()));
// selection of a ride by double clicking it, we need to update the ride list
connect(tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(selectRide(QModelIndex)));
connect(tableView->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(cursorRide()));
// user selected a ride on the ride list, we should reflect that too..
connect(main->rideTreeWidget(), SIGNAL(itemSelectionChanged()), this, SLOT(rideTreeSelectionChanged()));
// user moved columns
connect(tableView->header(), SIGNAL(sectionMoved(int,int,int)), this, SLOT(columnsChanged()));
connect(tableView->header(), SIGNAL(sectionResized(int,int,int)), this, SLOT(columnsChanged()));
// user sorted by column
connect(tableView->header(), SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)), this, SLOT(selectRow()));
// context menu is provided by mainWindow
connect(tableView,SIGNAL(customContextMenuRequested(const QPoint &)), main, SLOT(showTreeContextMenuPopup(const QPoint &)));
connect(tableView,SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(showTreeContextMenuPopup(const QPoint &)));
connect(tableView->header(), SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(setSortBy(int,Qt::SortOrder)));
// we accept drag and drop operations
setAcceptDrops(true);
}
RideNavigator::~RideNavigator()
@@ -206,12 +147,106 @@ RideNavigator::resizeEvent(QResizeEvent*)
}
void
RideNavigator::setWidth(int x)
RideNavigator::resetView()
{
active = true;
QList<QString> cols = _columns.split("|", QString::SkipEmptyParts);
nameMap.clear();
columnMetrics.clear();
// add the standard columns to the map
nameMap.insert("filename", "File");
nameMap.insert("timestamp", "Last updated");
nameMap.insert("ride_date", "Date");
nameMap.insert("fingerprint", "Config Checksum");
// add metrics to the map
const RideMetricFactory &factory = RideMetricFactory::instance();
for (int i=0; i<factory.metricCount(); i++) {
QString converted = QTextEdit(factory.rideMetric(factory.metricName(i))->name()).toPlainText();
// from sql column name to friendly metric name
nameMap.insert(QString("X%1").arg(factory.metricName(i)), converted);
// from friendly metric name to metric pointer
columnMetrics.insert(converted, factory.rideMetric(factory.metricName(i)));
}
// add metadata fields...
SpecialFields sp; // all the special fields are in here...
foreach(FieldDefinition field, main->rideMetadata()->getFields()) {
if (!sp.isMetric(field.name) && field.type < 5) {
nameMap.insert(QString("Z%1").arg(sp.makeTechName(field.name)), field.name);
}
}
logicalHeadings.clear();
tableView->reset();
// setup the logical heading list
for (int i=0; i<tableView->header()->count(); i++) {
QString friendly, techname = sortModel->headerData(i, Qt::Horizontal).toString();
if ((friendly = nameMap.value(techname, "unknown")) != "unknown") {
sortModel->setHeaderData(i, Qt::Horizontal, friendly);
logicalHeadings << friendly;
} else
logicalHeadings << techname;
}
// hide and show selected columns
for (int i=0; i<tableView->header()->count(); i++) {
QString techname = sortModel->headerData(i, Qt::Horizontal).toString();
QString friendly = nameMap.value(techname, techname);
if (i && !cols.contains(friendly)) {
tableView->setColumnHidden(i, true);
tableView->setColumnWidth(i, 0);
} else if (i) {
tableView->setColumnHidden(i, false);
}
}
// now re-order the columns according to the
// prevailing preferences. They are listed in
// the order we want them, column zero is the
// group by column, so we leave that alone
for(int i=1; i<cols.count(); i++) {
tableView->header()->moveSection(tableView->header()->visualIndex(logicalHeadings.indexOf(cols[i])), i);
}
// initialise to whatever groupBy we want to start with
tableView->sortByColumn(sortByIndex(), static_cast<Qt::SortOrder>(sortByOrder()));;
//tableView->setColumnHidden(0, true);
tableView->setColumnWidth(0,0);
// set the column widths
int columnnumber=0;
foreach(QString size, _widths.split("|", QString::SkipEmptyParts)) {
int index = tableView->header()->logicalIndex(columnnumber);
tableView->setColumnHidden(index, false);
tableView->setColumnWidth(index, columnnumber ? size.toInt() : 0);
columnnumber++;
}
setGroupByColumn();
active = false;
resizeEvent(NULL);
}
void
RideNavigator::setWidth(int x)
{
if (init == false) return;
active = true;
if (tableView->verticalScrollBar()->isVisible())
x -= tableView->verticalScrollBar()->width();
x -= tableView->verticalScrollBar()->width()
+ 6 ; // !! account for content margins of 3,3,3,3
// ** NOTE **
// When iterating over the section headings we
@@ -274,7 +309,6 @@ RideNavigator::setWidth(int x)
}
//tableView->setColumnWidth(last, newwidth + (x-setwidth)); // account for rounding errors
if (setwidth < x)
delegate->setWidth(pwidth=setwidth);
else
@@ -282,34 +316,15 @@ RideNavigator::setWidth(int x)
active = false;
}
#if 0
// make sure the columns are all neat and tidy when the ride navigator is shown
bool
RideNavigator::event(QEvent *e)
{
if (e->type() == QEvent::WindowActivate) {
active=false;
setWidth(geometry().width()); // calculate width...
}
if (e->type() == QEvent::ToolTip || e->type() == QEvent::ToolTipChange) {
QModelIndex index = tableView->indexAt(dynamic_cast<QHelpEvent*>(e)->pos());
if (index.isValid()) {
QString hoverFileName = tableView->model()->data(index, Qt::UserRole+1).toString();
e->accept();
// XXX todo custom tooltip balloon here.
// remember to make it hide when mouse moves again.
// or another tooltip event occurs
// qDebug()<<"ride navigator tooltip"<<hoverFileName;
main->setBubble(hoverFileName, dynamic_cast<QHelpEvent*>(e)->globalPos());
}
} else if (e->object() == this) {
qDebug()<<"hide bubble on event"<<e->type();
main->setBubble("");
}
return QWidget::event(e);
// make sure the columns are all neat and tidy when the ride navigator is shown
void
RideNavigator::showEvent(QShowEvent *)
{
resetView();
init = true;
setWidth(geometry().width());
}
#endif
void
RideNavigator::columnsChanged()
@@ -331,17 +346,18 @@ RideNavigator::columnsChanged()
foreach(QString name, visualHeadings)
headings += name + "|";
appsettings->setCValue(main->cyclist, GC_NAVHEADINGS, headings);
_columns = headings;
// get column widths
QString widths;
for (int i=0; i<tableView->header()->count(); i++)
if (tableView->header()->isSectionHidden(i) != true)
widths += QString("%1|").arg(tableView->columnWidth(i));
// clean up
active = false;
setWidth(geometry().width()); // calculate width...
appsettings->setCValue(main->cyclist, GC_NAVHEADINGWIDTHS, widths);
_widths = widths;
}
bool
@@ -415,6 +431,12 @@ RideNavigator::eventFilter(QObject *object, QEvent *e)
case QEvent::WindowActivate:
{
active=true;
// set the column widths
int columnnumber=0;
foreach(QString size, _widths.split("|", QString::SkipEmptyParts)) {
tableView->setColumnWidth(columnnumber, size.toInt());
}
active=false;
setWidth(geometry().width()); // calculate width...
}
@@ -481,10 +503,10 @@ RideNavigator::borderMenu(const QPoint &pos)
menu.addAction(insCol);
connect(insCol, SIGNAL(triggered()), this, SLOT(showColumnChooser()));
QAction *toggleGroupBy = new QAction(groupBy >= 0 ? tr("Do Not Show in Groups") : tr("Show In Groups"), tableView);
QAction *toggleGroupBy = new QAction(_groupBy >= 0 ? tr("Do Not Show in Groups") : tr("Show In Groups"), tableView);
toggleGroupBy->setEnabled(true);
menu.addAction(toggleGroupBy);
connect(toggleGroupBy, SIGNAL(triggered()), this, SLOT(setGroupBy()));
connect(toggleGroupBy, SIGNAL(triggered()), this, SLOT(setGroupByColumn()));
// set current column...
currentColumn = column;
@@ -492,13 +514,13 @@ RideNavigator::borderMenu(const QPoint &pos)
}
void
RideNavigator::setGroupBy()
RideNavigator::setGroupByColumn()
{
// toggle
groupBy = groupBy >= 0 ? -1 : currentColumn;
setGroupBy(_groupBy >= 0 ? -1 : currentColumn);
// set proxy model
groupByModel->setGroupBy(groupBy);
groupByModel->setGroupBy(_groupBy);
// lets expand column 0 for the groupBy heading
for (int i=0; i < groupByModel->groupCount(); i++) {
@@ -508,9 +530,6 @@ RideNavigator::setGroupBy()
// now show em
tableView->expandAll();
// save away
appsettings->setCValue(main->cyclist, GC_NAVGROUPBY, groupBy);
// reselect current ride - since selectionmodel
// is changed by setGroupBy()
rideTreeSelectionChanged();
@@ -519,8 +538,8 @@ RideNavigator::setGroupBy()
void
RideNavigator::setSortBy(int index, Qt::SortOrder order)
{
appsettings->setCValue(main->cyclist, GC_SORTBY, index);
appsettings->setCValue(main->cyclist, GC_SORTBYORDER, order);
_sortByIndex = index;
_sortByOrder = static_cast<int>(order);
}
//
@@ -1009,3 +1028,9 @@ ColumnChooser::buttonClicked(QString name)
drag->setMimeData(mimeData);
drag->exec(Qt::MoveAction);
}
void
RideNavigator::showTreeContextMenuPopup(const QPoint &pos)
{
main->showTreeContextMenuPopup(mapToGlobal(pos));
}

View File

@@ -43,11 +43,16 @@ class BUGFIXQSortFilterProxyModel;
// a QSQLTableModel which reads from the "metrics" table
// via the DBAccess database connection
//
class RideNavigator : public QWidget
class RideNavigator : public GcWindow
{
Q_OBJECT
G_OBJECT
Q_PROPERTY(int sortByIndex READ sortByIndex WRITE setSortByIndex USER true)
Q_PROPERTY(int sortByOrder READ sortByOrder WRITE setSortByOrder USER true)
Q_PROPERTY(int groupBy READ groupBy WRITE setGroupBy USER true)
Q_PROPERTY(QString columns READ columns WRITE setColumns USER true)
Q_PROPERTY(QString widths READ widths WRITE setWidths USER true)
friend class ::NavigatorCellDelegate;
friend class ::GroupByModel;
@@ -66,19 +71,17 @@ class RideNavigator : public QWidget
public slots:
void refresh();
#if 0
bool event(QEvent *event);
#endif
void showEvent(QShowEvent *event);
void resizeEvent(QResizeEvent*);
void showTreeContextMenuPopup(const QPoint &);
// working with columns
void columnsChanged();
void removeColumn();
void showColumnChooser();
// user selected a group by column
void setGroupBy();
// user double clicked or pressed enter on ride
void selectRide(const QModelIndex &index);
@@ -95,6 +98,24 @@ class RideNavigator : public QWidget
// how wide am I?
void setWidth(int x);
void setSortBy(int index, Qt::SortOrder);
void setGroupByColumn();
int sortByIndex() const { return _sortByIndex; }
void setSortByIndex(int x) { _sortByIndex = x; }
int sortByOrder() const { return _sortByOrder; }
void setSortByOrder(int x) { _sortByOrder = x; }
int groupBy() const { return _groupBy; }
void setGroupBy(int x) { _groupBy = x; }
QString columns() const { return _columns; }
void setColumns(QString x) { _columns = x; }
QString widths() const { return _widths; }
void setWidths (QString x) { _widths = x; resetView(); } // only reset once widths are set
void resetView(); // when columns/width changes
protected:
QSqlTableModel *sqlModel; // the sql table
@@ -105,15 +126,25 @@ class RideNavigator : public QWidget
QList<QString> logicalHeadings;
QList<QString> visualHeadings;
// this maps friendly names to metric names
QMap <QString, QString> nameMap;
QMap<QString, const RideMetric *> columnMetrics;
private:
MainWindow *main;
bool active;
int groupBy;
bool init;
int currentColumn;
int pwidth;
NavigatorCellDelegate *delegate;
QVBoxLayout *mainLayout;
// properties
int _sortByIndex;
int _sortByOrder;
int _groupBy;
QString _columns;
QString _widths;
};
//

View File

@@ -1,11 +1,24 @@
<layout name="diary" style="2">
<layout name="diary" style="0">
<chart id="30" name="" title="Activity Log" >
<property name="instanceName" type="QString" value="" />
<property name="title" type="QString" value="Activity Log" />
<property name="subtitle" type="QString" value="" />
<property name="widthFactor" type="double" value="1.92308" />
<property name="heightFactor" type="double" value="1" />
<property name="resizable" type="bool" value="0" />
<property name="sortByIndex" type="int" value="4" />
<property name="sortByOrder" type="int" value="1" />
<property name="groupBy" type="int" value="91" />
<property name="columns" type="QString" value="*|Date|Sport|Duration|Distance|NP|TSS|VI|Data|" />
<property name="widths" type="QString" value="0|67|67|60|37|31|28|60|85|" />
</chart>
<chart id="4" name="Diary Window" title="Calendar" >
<property name="instanceName" type="QString" value="Diary Window" />
<property name="title" type="QString" value="Calendar" />
<property name="subtitle" type="QString" value="" />
<property name="widthFactor" type="double" value="1.00033" />
<property name="heightFactor" type="double" value="1.0004" />
<property name="resizable" type="bool" value="1" />
<property name="widthFactor" type="double" value="2" />
<property name="heightFactor" type="double" value="1" />
<property name="resizable" type="bool" value="0" />
<property name="view" type="int" value="0" />
</chart>
</layout>