mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-14 00:28:42 +00:00
MainWindow Refactor Part 5 of 5 - TABBED ATHLETES
The final part (and one of the reasons) for the mainwindow refactoring -- we now support tabbed athletes rather than having a new mainwindow for each athlete opened. Context is saved/restored and there are new functions for opening and closing tabs and windows of tabs. The tabbar itself is fugly -- the next few days will spend some time looking at making it prettier on Linux/Win and more native on Mac (see MMTabBar).
This commit is contained in:
@@ -23,8 +23,7 @@
|
||||
#include "Athlete.h"
|
||||
#include <QtGui>
|
||||
|
||||
ChooseCyclistDialog::ChooseCyclistDialog(const QDir &home, bool allowNew) :
|
||||
home(home)
|
||||
ChooseCyclistDialog::ChooseCyclistDialog(const QDir &home, bool allowNew) : home(home)
|
||||
{
|
||||
setWindowTitle(tr("Choose an Athlete"));
|
||||
|
||||
@@ -38,9 +37,14 @@ ChooseCyclistDialog::ChooseCyclistDialog(const QDir &home, bool allowNew) :
|
||||
QListWidgetItem *newone = new QListWidgetItem(name, listWidget);
|
||||
|
||||
// only allow selection of cyclists which are not already open
|
||||
foreach (MainWindow *x, mainwindows)
|
||||
if (x->contextmain()->athlete->cyclist == name)
|
||||
newone->setFlags(newone->flags() & ~Qt::ItemIsEnabled);
|
||||
foreach (MainWindow *x, mainwindows) {
|
||||
QMapIterator<QString, Tab*> t(x->tabs);
|
||||
while (t.hasNext()) {
|
||||
t.next();
|
||||
if (t.key() == name)
|
||||
newone->setFlags(newone->flags() & ~Qt::ItemIsEnabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (allowNew)
|
||||
|
||||
@@ -40,6 +40,13 @@ class Context : public QObject
|
||||
public:
|
||||
Context(MainWindow *mainWindow);
|
||||
|
||||
// mainwindow state
|
||||
int viewIndex;
|
||||
bool showSidebar, showLowbar, showToolbar, showTabbar;
|
||||
int style;
|
||||
QString searchText;
|
||||
bool scopehighlighted;
|
||||
|
||||
// ride item
|
||||
RideItem *rideItem() const { return ride; }
|
||||
const RideFile *currentRide();
|
||||
|
||||
@@ -95,12 +95,11 @@ void
|
||||
DBAccess::initDatabase(QDir home)
|
||||
{
|
||||
|
||||
|
||||
if(db && db->database(sessionid).isOpen()) return;
|
||||
|
||||
QString cyclist = QFileInfo(home.path()).baseName();
|
||||
sessionid = QString("%1").arg(context->athlete->cyclist);
|
||||
|
||||
if(db && db->database(sessionid).isOpen()) return;
|
||||
|
||||
// use different name for v3 metricDB to avoid constant rebuilding
|
||||
// when switching between v2 stable and v3 development builds
|
||||
db = new QSqlDatabase(QSqlDatabase::addDatabase("QSQLITE", sessionid));
|
||||
|
||||
@@ -242,9 +242,27 @@ GcScopeBar::clickedTrain()
|
||||
emit selectTrain();
|
||||
}
|
||||
|
||||
void
|
||||
GcScopeBar::selected(int index)
|
||||
int
|
||||
GcScopeBar::selected()
|
||||
{
|
||||
if (home->isChecked()) return 0;
|
||||
#ifdef GC_HAVE_ICAL
|
||||
if (diary->isChecked()) return 1;
|
||||
if (anal->isChecked()) return 2;
|
||||
if (train->isChecked()) return 3;
|
||||
#else
|
||||
if (anal->isChecked()) return 1;
|
||||
if (train->isChecked()) return 2;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
GcScopeBar::setSelected(int index)
|
||||
{
|
||||
// we're already there
|
||||
if (index == selected()) return;
|
||||
|
||||
// mainwindow wants to tell us to switch to a selection
|
||||
home->setChecked(false);
|
||||
#ifdef GC_HAVE_ICAL
|
||||
|
||||
@@ -36,8 +36,10 @@ class GcScopeButton : public QWidget
|
||||
GcScopeButton(QWidget *parent);
|
||||
void setText(QString _text) { text = _text; }
|
||||
void setChecked(bool _checked) { checked = _checked; repaint(); }
|
||||
bool isChecked() { return checked; }
|
||||
void setWidth(int x) { setFixedWidth(x); }
|
||||
void setHighlighted(bool x) { highlighted = x; }
|
||||
bool ishighlighted() const { return highlighted; }
|
||||
|
||||
signals:
|
||||
void clicked(bool);
|
||||
@@ -72,10 +74,13 @@ public slots:
|
||||
void clickedDiary();
|
||||
|
||||
// mainwindow tells us when it switched without user clicking.
|
||||
void selected(int index);
|
||||
int selected();
|
||||
void setSelected(int index);
|
||||
void setHighlighted();
|
||||
void setContext(Context *c) { context = c; }
|
||||
|
||||
void addWidget(QWidget*);
|
||||
|
||||
void setHighlighted();
|
||||
|
||||
signals:
|
||||
void selectHome();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,5 +1,6 @@
|
||||
/*
|
||||
* Copyright (c) 2006 Sean C. Rhea (srhea@srhea.net)
|
||||
* Copyright (c) 2012 Mark Liversedge (liversedge@gmail.com)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License as published by the Free
|
||||
@@ -40,6 +41,8 @@ class GcScopeBar;
|
||||
class Library;
|
||||
class QtSegmentControl;
|
||||
class SaveSingleDialogWidget;
|
||||
class ChooseCyclistDialog;
|
||||
class SearchFilterBox;
|
||||
|
||||
class MainWindow;
|
||||
class Athlete;
|
||||
@@ -48,6 +51,7 @@ class Tab;
|
||||
|
||||
extern QList<MainWindow *> mainwindows; // keep track of all the MainWindows we have open
|
||||
extern QDesktopWidget *desktop; // how many screens / res etc
|
||||
extern QString gcroot; // root directory for gc
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
@@ -59,12 +63,15 @@ class MainWindow : public QMainWindow
|
||||
MainWindow(const QDir &home);
|
||||
~MainWindow(); // temp to zap db - will move to tab //
|
||||
|
||||
// temporary access to the context
|
||||
Context *contextmain() { return context; } // by ChooseCyclistDialog
|
||||
void byebye() { close(); } // go bye bye for a restart
|
||||
|
||||
protected:
|
||||
|
||||
// used by ChooseCyclistDialog to see which athletes
|
||||
// have already been opened
|
||||
friend class ::ChooseCyclistDialog;
|
||||
QMap<QString,Tab*> tabs;
|
||||
|
||||
virtual void resizeEvent(QResizeEvent*);
|
||||
virtual void moveEvent(QMoveEvent*);
|
||||
virtual void closeEvent(QCloseEvent*);
|
||||
@@ -80,14 +87,29 @@ class MainWindow : public QMainWindow
|
||||
void aboutDialog();
|
||||
void helpView();
|
||||
void logBug();
|
||||
void closeAll();
|
||||
void actionClicked(int);
|
||||
|
||||
// open and closing windows and tabs
|
||||
void closeAll(); // close all windows and tabs
|
||||
|
||||
void setOpenWindowMenu(); // set the Open Window menu
|
||||
void newCyclistWindow(); // create a new Cyclist
|
||||
void openWindow(QString name);
|
||||
void closeWindow();
|
||||
|
||||
void setOpenTabMenu(); // set the Open Tab menu
|
||||
void newCyclistTab(); // create a new Cyclist
|
||||
void openTab(QString name);
|
||||
bool closeTab(); // close current, might not if the user
|
||||
// changes mind if there are unsaved changes.
|
||||
void removeTab(Tab*); // remove without question
|
||||
|
||||
void switchTab(int index); // for switching between one tab and another
|
||||
|
||||
// Search / Filter
|
||||
void setFilter(QStringList);
|
||||
void clearFilter();
|
||||
|
||||
|
||||
void selectHome();
|
||||
void selectDiary();
|
||||
void selectAnalysis();
|
||||
@@ -96,14 +118,13 @@ class MainWindow : public QMainWindow
|
||||
void setChartMenu();
|
||||
void setSubChartMenu();
|
||||
void addChart(QAction*);
|
||||
void setWindowMenu();
|
||||
void selectWindow(QAction*);
|
||||
|
||||
void showOptions();
|
||||
|
||||
void toggleSidebar();
|
||||
void showSidebar(bool want);
|
||||
void showToolbar(bool want);
|
||||
void showTabbar(bool want);
|
||||
void resetWindowLayout();
|
||||
void toggleStyle();
|
||||
void setToolButtons(); // set toolbar buttons to match tabview
|
||||
@@ -133,13 +154,8 @@ class MainWindow : public QMainWindow
|
||||
void downloadMeasures();
|
||||
void downloadMeasuresFromZeo();
|
||||
|
||||
// Athlete Collection
|
||||
void newCyclist();
|
||||
void openCyclist();
|
||||
|
||||
// Activity Collection
|
||||
void addIntervals(); // pass thru to tab
|
||||
void rideSelected(RideItem*ride);
|
||||
bool saveRideSingleDialog(RideItem *);
|
||||
void saveSilent(RideItem *);
|
||||
void downloadRide();
|
||||
@@ -165,16 +181,24 @@ class MainWindow : public QMainWindow
|
||||
void revertRide();
|
||||
bool saveRideExitDialog(); // save dirty rides on exit dialog
|
||||
|
||||
// save and restore state to context
|
||||
void saveState(Context *);
|
||||
void restoreState(Context *);
|
||||
|
||||
private:
|
||||
|
||||
Context *context;
|
||||
GcScopeBar *scopebar;
|
||||
Tab *tab;
|
||||
Tab *currentTab;
|
||||
QList<Tab*> tabList;
|
||||
|
||||
#ifndef Q_OS_MAC
|
||||
QTFullScreen *fullScreen;
|
||||
#endif
|
||||
|
||||
#ifdef GC_HAVE_LUCENE
|
||||
SearchFilterBox *searchBox;
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MAC
|
||||
// Mac Native Support
|
||||
QtMacButton *import, *compose, *sidebar, *lowbar;
|
||||
@@ -190,19 +214,25 @@ class MainWindow : public QMainWindow
|
||||
QIcon importIcon, composeIcon, intervalIcon, splitIcon,
|
||||
deleteIcon, sidebarIcon, lowbarIcon, tabbedIcon, tiledIcon;
|
||||
#endif
|
||||
// tab bar
|
||||
QTabBar *tabbar;
|
||||
QStackedWidget *tabStack;
|
||||
|
||||
// window and tab menu
|
||||
QMenu *openWindowMenu, *openTabMenu;
|
||||
QSignalMapper *windowMapper, *tabMapper;
|
||||
|
||||
// chart menus
|
||||
QMenu *chartMenu;
|
||||
QMenu *subChartMenu;
|
||||
|
||||
// Application menu
|
||||
QMenu *windowMenu;
|
||||
|
||||
// Application actions
|
||||
// only keeping those used outside of mainwindow constructor
|
||||
// Toolbar state checkables in View menu / context
|
||||
QAction *styleAction;
|
||||
QAction *showhideSidebar;
|
||||
QAction *showhideLowbar;
|
||||
QAction *showhideToolbar;
|
||||
QAction *showhideTabbar;
|
||||
|
||||
QAction *tweetAction;
|
||||
QAction *shareAction;
|
||||
QAction *ttbAction;
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
#include "MainWindow.h"
|
||||
#include "Tab.h"
|
||||
#include "Athlete.h"
|
||||
#include "GcRideFile.h"
|
||||
#include "JsonRideFile.h"
|
||||
@@ -93,8 +94,8 @@ MainWindow::saveRideExitDialog()
|
||||
// have we been told to not warn on exit?
|
||||
if (warnExit() == false) return true; // just close regardless!
|
||||
|
||||
for (int i=0; i<context->athlete->allRides->childCount(); i++) {
|
||||
RideItem *curr = (RideItem *)context->athlete->allRides->child(i);
|
||||
for (int i=0; i<currentTab->context->athlete->allRides->childCount(); i++) {
|
||||
RideItem *curr = (RideItem *)currentTab->context->athlete->allRides->child(i);
|
||||
if (curr->isDirty() == true) dirtyList.append(curr);
|
||||
}
|
||||
|
||||
@@ -175,7 +176,7 @@ MainWindow::saveSilent(RideItem *rideItem)
|
||||
|
||||
// save in GC format
|
||||
JsonFileReader reader;
|
||||
reader.writeRideFile(context, rideItem->ride(), savedFile);
|
||||
reader.writeRideFile(currentTab->context, rideItem->ride(), savedFile);
|
||||
|
||||
// rename the file and update the rideItem list to reflect the change
|
||||
if (convert) {
|
||||
|
||||
@@ -44,6 +44,7 @@ public:
|
||||
void setText(QString);
|
||||
SearchBoxMode getMode() { return mode; }
|
||||
bool isFiltered() const { return filtered; }
|
||||
void setContext(Context *c) { context = c; }
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *);
|
||||
|
||||
@@ -37,6 +37,11 @@ public:
|
||||
void setFilter(QString); // filter:text or search:text
|
||||
bool isFiltered() const { return searchbox->isFiltered(); }
|
||||
|
||||
QString text() const { return searchbox->text(); }
|
||||
void setText(QString t) { searchbox->setText(t); }
|
||||
|
||||
void setContext(Context *c) { context = c; searchbox->setContext(c); }
|
||||
|
||||
private slots:
|
||||
|
||||
signals:
|
||||
|
||||
50
src/Tab.cpp
50
src/Tab.cpp
@@ -19,6 +19,8 @@
|
||||
|
||||
#include "Tab.h"
|
||||
#include "Views.h"
|
||||
#include "Athlete.h"
|
||||
#include "IntervalItem.h"
|
||||
#include "MainWindow.h"
|
||||
|
||||
Tab::Tab(Context *context) : QWidget(context->mainWindow), context(context)
|
||||
@@ -80,6 +82,16 @@ Tab::Tab(Context *context) : QWidget(context->mainWindow), context(context)
|
||||
chartSettings->setMaximumWidth(450);
|
||||
chartSettings->setMaximumHeight(600);
|
||||
chartSettings->hide();
|
||||
|
||||
// cpx aggregate cache check
|
||||
connect(context,SIGNAL(rideSelected(RideItem*)), this, SLOT(rideSelected(RideItem*)));
|
||||
|
||||
// selects the latest ride in the list:
|
||||
if (context->athlete->allRides->childCount() != 0)
|
||||
context->athlete->treeWidget->setCurrentItem(context->athlete->allRides->child(context->athlete->allRides->childCount()-1));
|
||||
|
||||
// Kick off - select a ride and switch to Analysis View
|
||||
context->athlete->rideTreeWidgetSelectionChanged();
|
||||
}
|
||||
|
||||
Tab::~Tab()
|
||||
@@ -158,3 +170,41 @@ Tab::selectView(int index)
|
||||
view(index)->setSelected(true);
|
||||
masterControls->setCurrentIndex(index);
|
||||
}
|
||||
|
||||
void
|
||||
Tab::rideSelected(RideItem*)
|
||||
{
|
||||
// update the ride property on all widgets
|
||||
// to let them know they need to replot new
|
||||
// selected ride
|
||||
setRide(context->ride);
|
||||
|
||||
if (!context->ride) return;
|
||||
|
||||
// refresh interval list for bottom left
|
||||
// first lets wipe away the existing intervals
|
||||
QList<QTreeWidgetItem *> intervals = context->athlete->allIntervals->takeChildren();
|
||||
for (int i=0; i<intervals.count(); i++) delete intervals.at(i);
|
||||
|
||||
// now add the intervals for the current ride
|
||||
if (context->ride) { // only if we have a ride pointer
|
||||
RideFile *selected = context->ride->ride();
|
||||
if (selected) {
|
||||
// get all the intervals in the currently selected RideFile
|
||||
QList<RideFileInterval> intervals = selected->intervals();
|
||||
for (int i=0; i < intervals.count(); i++) {
|
||||
// add as a child to context->athlete->allIntervals
|
||||
IntervalItem *add = new IntervalItem(selected,
|
||||
intervals.at(i).name,
|
||||
intervals.at(i).start,
|
||||
intervals.at(i).stop,
|
||||
selected->timeToDistance(intervals.at(i).start),
|
||||
selected->timeToDistance(intervals.at(i).stop),
|
||||
context->athlete->allIntervals->childCount()+1);
|
||||
add->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled);
|
||||
context->athlete->allIntervals->addChild(add);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "Views.h"
|
||||
|
||||
class RideNavigator;
|
||||
class MainWindow;
|
||||
|
||||
class Tab: public QWidget
|
||||
{
|
||||
@@ -40,10 +41,17 @@ class Tab: public QWidget
|
||||
|
||||
RideNavigator *rideNavigator(); // to get logical headings
|
||||
|
||||
protected:
|
||||
|
||||
friend class ::MainWindow;
|
||||
Context *context;
|
||||
|
||||
signals:
|
||||
|
||||
public slots:
|
||||
|
||||
void rideSelected(RideItem*);
|
||||
|
||||
// set Ride
|
||||
void setRide(RideItem*);
|
||||
|
||||
@@ -74,7 +82,6 @@ class Tab: public QWidget
|
||||
|
||||
private:
|
||||
|
||||
Context *context;
|
||||
|
||||
// Each of the views
|
||||
QStackedWidget *views;
|
||||
|
||||
@@ -59,6 +59,9 @@ void nostderr(QString dir)
|
||||
QApplication *application;
|
||||
bool restarting = false;
|
||||
|
||||
// root directory shared by all
|
||||
QString gcroot;
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
@@ -213,6 +216,9 @@ main(int argc, char *argv[])
|
||||
}
|
||||
}
|
||||
|
||||
// set global root directory
|
||||
gcroot = home.absolutePath();
|
||||
|
||||
// now redirect stderr
|
||||
#ifndef WIN32
|
||||
if (!debug) nostderr(home.absolutePath());
|
||||
|
||||
Reference in New Issue
Block a user