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:
Mark Liversedge
2013-12-26 01:03:32 +00:00
parent c11c90f621
commit daf63f2dac
13 changed files with 621 additions and 224 deletions

View File

@@ -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)

View File

@@ -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();

View File

@@ -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));

View File

@@ -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

View File

@@ -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

View File

@@ -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;

View File

@@ -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) {

View File

@@ -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 *);

View File

@@ -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:

View File

@@ -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);
}
}
}
}

View File

@@ -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;

View File

@@ -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());