From ed2bdc5d3a397335a7cc98d4bb8e4b6a5ce5170a Mon Sep 17 00:00:00 2001 From: Mark Liversedge Date: Sat, 27 Jul 2013 21:41:03 +0100 Subject: [PATCH] MainWindow Refactor Part 4 of 5 Split the views in MainWindow into separate classes; * Tab is a collection of the 4 main views * TabView is a base class for all of the 4 view types * {Analysis,Train,Diary,Home}View are all derived from TabView and deal with specifics of those views (e.g. Diary/Home worry about date ranges). We should be ready to move to tabbed athletes soon. There are a few nits left for this part of the refactor that will need to be resolved in some fixups over the next few days; * tile mode segment selector has wrong segment selected when the view is in tile mode. * Minimum height/width of MainWindow is large for some reason * the Train view controls (play, ffwd etc) have nowhere to go at present -- need to fix that !!! * When you resize the mainwindow width the sidebars expand and should remain a fixed width * not sure if it will build on Windows or Mac! --- src/Context.h | 6 +- src/DiarySidebar.cpp | 1 + src/ErgDBDownloadDialog.cpp | 2 +- src/GcScopeBar.cpp | 5 +- src/GcScopeBar.h | 2 +- src/GcSideBarItem.cpp | 1 + src/HomeWindow.cpp | 9 +- src/MainWindow.cpp | 506 +++++------------------------------- src/MainWindow.h | 72 +---- src/RideNavigator.cpp | 1 + src/RideNavigator.h | 2 +- src/SearchBox.cpp | 9 +- src/Tab.cpp | 148 +++++++++++ src/Tab.h | 87 +++++++ src/TabView.cpp | 61 ++++- src/TabView.h | 12 +- src/Views.cpp | 185 +++++++++++++ src/Views.h | 89 +++++++ src/src.pro | 6 + 19 files changed, 665 insertions(+), 539 deletions(-) create mode 100644 src/Tab.cpp create mode 100644 src/Tab.h create mode 100644 src/Views.cpp create mode 100644 src/Views.h diff --git a/src/Context.h b/src/Context.h index 47be13caf..f51f86d2d 100644 --- a/src/Context.h +++ b/src/Context.h @@ -44,16 +44,14 @@ class Context : public QObject RideItem *rideItem() const { return ride; } const RideFile *currentRide(); const RideItem *currentRideItem() { return ride; } - - // last date range selected in diary/home view - DateRange currentDateRange() { return _dr; } + DateRange currentDateRange() { return dr_; } // current selections MainWindow *mainWindow; Tab *tab; Athlete *athlete; RideItem *ride; // the currently selected ride - DateRange _dr; // the currently selected date range + DateRange dr_; ErgFile *workout; // the currently selected workout file long now; // point in time during train session SpecialFields specialFields; diff --git a/src/DiarySidebar.cpp b/src/DiarySidebar.cpp index c1b459d79..a6faafca8 100644 --- a/src/DiarySidebar.cpp +++ b/src/DiarySidebar.cpp @@ -806,6 +806,7 @@ GcMultiCalendar::GcMultiCalendar(Context *context) : QScrollArea(context->mainWi { setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setContentsMargins(0,0,0,0); + _ride = NULL; setFrameStyle(QFrame::NoFrame); diff --git a/src/ErgDBDownloadDialog.cpp b/src/ErgDBDownloadDialog.cpp index b9342290b..1d3b08558 100644 --- a/src/ErgDBDownloadDialog.cpp +++ b/src/ErgDBDownloadDialog.cpp @@ -132,7 +132,7 @@ ErgDBDownloadDialog::okClicked() status->setText(QString("%1 workouts downloaded, %2 failed or skipped.").arg(downloads).arg(fails)); ok->setText("Finish"); - context->mainWindow->trainsidebar()->configChanged(); + context->notifyConfigChanged(); } else if (ok->text() == "Abort") { aborted = true; diff --git a/src/GcScopeBar.cpp b/src/GcScopeBar.cpp index dd057d3ff..fdd877620 100644 --- a/src/GcScopeBar.cpp +++ b/src/GcScopeBar.cpp @@ -18,10 +18,11 @@ #include "GcScopeBar.h" #include "DiaryWindow.h" +#include "DiarySidebar.h" #include "Context.h" #include "QtMacButton.h" -GcScopeBar::GcScopeBar(Context *context, QWidget *traintool) : QWidget(context->mainWindow), context(context) +GcScopeBar::GcScopeBar(Context *context) : QWidget(context->mainWindow), context(context) { setFixedHeight(23); @@ -94,7 +95,7 @@ GcScopeBar::GcScopeBar(Context *context, QWidget *traintool) : QWidget(context-> connect(train, SIGNAL(clicked(bool)), this, SLOT(clickedTrain())); layout->addStretch(); - layout->addWidget(traintool); + //layout->addWidget(traintool); //XXX!!! eek layout->addStretch(); // we now need to adjust the buttons according to their text size diff --git a/src/GcScopeBar.h b/src/GcScopeBar.h index 339e4d808..c68ce4ed1 100644 --- a/src/GcScopeBar.h +++ b/src/GcScopeBar.h @@ -59,7 +59,7 @@ class GcScopeBar : public QWidget public: - GcScopeBar(Context *context, QWidget *traintool); + GcScopeBar(Context *context); ~GcScopeBar(); public slots: diff --git a/src/GcSideBarItem.cpp b/src/GcSideBarItem.cpp index b00b028f5..42b23d97b 100644 --- a/src/GcSideBarItem.cpp +++ b/src/GcSideBarItem.cpp @@ -18,6 +18,7 @@ #include "GcSideBarItem.h" #include "DiaryWindow.h" +#include "DiarySidebar.h" QIcon iconFromPNG(QString filename, bool emboss) { diff --git a/src/HomeWindow.cpp b/src/HomeWindow.cpp index a4639302f..f3aa32539 100644 --- a/src/HomeWindow.cpp +++ b/src/HomeWindow.cpp @@ -16,9 +16,9 @@ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ -#include "MainWindow.h" #include "Athlete.h" #include "Context.h" +#include "Tab.h" #include "HomeWindow.h" #include "LTMTool.h" #include "LTMSettings.h" @@ -476,8 +476,8 @@ HomeWindow::dropEvent(QDropEvent *event) void HomeWindow::showControls() { - context->mainWindow->chartsettings()->adjustSize(); - context->mainWindow->chartsettings()->show(); + context->tab->chartsettings()->adjustSize(); + context->tab->chartsettings()->show(); } void @@ -652,8 +652,7 @@ HomeWindow::resetLayout() for(int i = 0; i < charts.count(); i++) { RideItem *notconst = (RideItem*)context->currentRideItem(); charts[i]->setProperty("ride", QVariant::fromValue(notconst)); - DateRange dr = context->currentDateRange(); - charts[i]->setProperty("dateRange", QVariant::fromValue(dr)); + charts[i]->setProperty("dateRange", property("dateRange")); if (currentStyle != 0) charts[i]->show(); } diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp index ea1750a68..ec71d1cc0 100644 --- a/src/MainWindow.cpp +++ b/src/MainWindow.cpp @@ -21,7 +21,6 @@ #include "Context.h" #include "Athlete.h" #include "AboutDialog.h" -#include "BlankState.h" #include "ChooseCyclistDialog.h" #include "Colors.h" #include "ConfigDialog.h" @@ -47,10 +46,9 @@ #include "ErgDBDownloadDialog.h" #include "DeviceConfiguration.h" #include "AddDeviceWizard.h" -#include "TrainSidebar.h" +#include "Tab.h" #include "GcToolBar.h" -#include "GcSideBarItem.h" #ifdef GC_HAVE_SOAP #include "TPUploadDialog.h" #include "TPDownloadDialog.h" @@ -60,10 +58,7 @@ #endif #include "HelpWindow.h" #include "HomeWindow.h" -#include "DiarySidebar.h" #include "GcScopeBar.h" -#include "LTMSidebar.h" -#include "AnalysisSidebar.h" #ifdef Q_OS_MAC #ifdef GC_HAVE_LION @@ -83,8 +78,6 @@ #include "SearchFilterBox.h" #endif -#include "ChartSettings.h" - #include #include #include @@ -304,6 +297,8 @@ MainWindow::MainWindow(const QDir &home) searchBox->setStyle(toolStyle); searchBox->setFixedWidth(300); head->addWidget(searchBox); + connect(searchBox, SIGNAL(searchResults(QStringList)), this, SLOT(setFilter(QStringList))); + connect(searchBox, SIGNAL(searchClear()), this, SLOT(clearFilter())); #endif #endif @@ -403,6 +398,8 @@ MainWindow::MainWindow(const QDir &home) searchBox->setStyle(toolStyle); searchBox->setFixedWidth(250); head->addWidget(searchBox); + connect(searchBox, SIGNAL(searchResults(QStringList)), this, SLOT(setFilter(QStringList))); + connect(searchBox, SIGNAL(searchClear()), this, SLOT(clearFilter())); #endif Spacer *spacer = new Spacer(this); spacer->setFixedWidth(5); @@ -410,39 +407,16 @@ MainWindow::MainWindow(const QDir &home) #endif /*---------------------------------------------------------------------- - * Sidebar + * ScopeBar *--------------------------------------------------------------------*/ - - // sidebar items - diarySidebar = new DiarySidebar(context); - ltmSidebar = new LTMSidebar(context); - analysisSidebar = new AnalysisSidebar(context); - trainSidebar = new TrainSidebar(context); - trainSidebar->hide(); - trainSidebar->getToolbarButtons()->hide(); // no show yet - - - // we need to connect the search box on Linux/Windows -#ifdef GC_HAVE_LUCENE - - // link to the sidebars - connect(searchBox, SIGNAL(searchResults(QStringList)), this, SLOT(setFilter(QStringList))); - connect(searchBox, SIGNAL(searchClear()), this, SLOT(clearFilter())); -#endif - - /*---------------------------------------------------------------------- - * Scope Bar - *--------------------------------------------------------------------*/ - - scopebar = new GcScopeBar(context, trainSidebar->getToolbarButtons()); + scopebar = new GcScopeBar(context); connect(scopebar, SIGNAL(selectDiary()), this, SLOT(selectDiary())); connect(scopebar, SIGNAL(selectHome()), this, SLOT(selectHome())); connect(scopebar, SIGNAL(selectAnal()), this, SLOT(selectAnalysis())); connect(scopebar, SIGNAL(selectTrain()), this, SLOT(selectTrain())); - // add chart button with a menu + // Add chart is on the scope bar chartMenu = new QMenu(this); - QCleanlooksStyle *styler = new QCleanlooksStyle(); QPushButton *newchart = new QPushButton("+", this); scopebar->addWidget(newchart); @@ -459,159 +433,27 @@ MainWindow::MainWindow(const QDir &home) connect(chartMenu, SIGNAL(triggered(QAction*)), this, SLOT(addChart(QAction*))); /*---------------------------------------------------------------------- - * The 4 views + * Central Widget *--------------------------------------------------------------------*/ - splitter = new QSplitter; + tab = new Tab(context); - toolBox = new QStackedWidget(this); - toolBox->setAcceptDrops(true); - toolBox->setFrameStyle(QFrame::NoFrame); - toolBox->setContentsMargins(0,0,0,0); - toolBox->layout()->setSpacing(0); - splitter->addWidget(toolBox); + /*---------------------------------------------------------------------- + * Central Widget + *--------------------------------------------------------------------*/ - // CONTAINERS FOR TOOLBOX - masterControls = new QStackedWidget(this); - masterControls->setFrameStyle(QFrame::Plain | QFrame::NoFrame); - masterControls->setCurrentIndex(0); // default to Analysis - masterControls->setContentsMargins(0,0,0,0); - analysisControls = new QStackedWidget(this); - analysisControls->setFrameStyle(QFrame::Plain | QFrame::NoFrame); - analysisControls->setCurrentIndex(0); // default to Analysis - analysisControls->setContentsMargins(0,0,0,0); - masterControls->addWidget(analysisControls); - trainControls = new QStackedWidget(this); - trainControls->setFrameStyle(QFrame::Plain | QFrame::NoFrame); - trainControls->setCurrentIndex(0); // default to Analysis - trainControls->setContentsMargins(0,0,0,0); - masterControls->addWidget(trainControls); - diaryControls = new QStackedWidget(this); - diaryControls->setFrameStyle(QFrame::Plain | QFrame::NoFrame); - diaryControls->setCurrentIndex(0); // default to Analysis - diaryControls->setContentsMargins(0,0,0,0); - masterControls->addWidget(diaryControls); - homeControls = new QStackedWidget(this); - homeControls->setFrameStyle(QFrame::Plain | QFrame::NoFrame); - homeControls->setContentsMargins(0,0,0,0); - masterControls->addWidget(homeControls); - - // HOME WINDOW & CONTROLS - homeWindow = new HomeWindow(context, "home", "Home"); - homeControls->addWidget(homeWindow->controls()); - homeControls->setCurrentIndex(0); - - // DIARY WINDOW & CONTROLS - diaryWindow = new HomeWindow(context, "diary", "Diary"); - diaryControls->addWidget(diaryWindow->controls()); - - // TRAIN WINDOW & CONTROLS - trainWindow = new HomeWindow(context, "train", "Training"); - trainWindow->controls()->hide(); - trainControls->addWidget(trainWindow->controls()); - - // ANALYSIS WINDOW & CONTRAOLS - analWindow = new HomeWindow(context, "analysis", "Analysis"); - analysisControls->addWidget(analWindow->controls()); - - currentWindow = NULL; - - // NO RIDE WINDOW - Replace analysis, home and train window when no ride - - // did we say we din't want to see this? - showBlankTrain = !(appsettings->cvalue(context->athlete->cyclist, GC_BLANK_TRAIN, false).toBool()); - showBlankHome = !(appsettings->cvalue(context->athlete->cyclist, GC_BLANK_HOME, false).toBool()); - showBlankAnal = !(appsettings->cvalue(context->athlete->cyclist, GC_BLANK_ANALYSIS, false).toBool()); - showBlankDiary = !(appsettings->cvalue(context->athlete->cyclist, GC_BLANK_DIARY, false).toBool()); - - // setup the blank pages - blankStateAnalysisPage = new BlankStateAnalysisPage(context); - blankStateHomePage = new BlankStateHomePage(context); - blankStateDiaryPage = new BlankStateDiaryPage(context); - blankStateTrainPage = new BlankStateTrainPage(context); - - connect(blankStateDiaryPage, SIGNAL(closeClicked()), this, SLOT(closeBlankDiary())); - connect(blankStateHomePage, SIGNAL(closeClicked()), this, SLOT(closeBlankHome())); - connect(blankStateAnalysisPage, SIGNAL(closeClicked()), this, SLOT(closeBlankAnal())); - connect(blankStateTrainPage, SIGNAL(closeClicked()), this, SLOT(closeBlankTrain())); - - - // POPULATE TOOLBOX - - // do controllers after home windows -- they need their first signals caught - connect(diarySidebar, SIGNAL(dateRangeChanged(DateRange)), this, SLOT(dateRangeChangedDiary(DateRange))); - connect(ltmSidebar, SIGNAL(dateRangeChanged(DateRange)), this, SLOT(dateRangeChangedLTM(DateRange))); - ltmSidebar->dateRangeTreeWidgetSelectionChanged(); // force an update to get first date range shown - - toolBox->addWidget(analysisSidebar); - toolBox->addWidget(diarySidebar); - toolBox->addWidget(trainSidebar->controls()); - toolBox->addWidget(ltmSidebar); - - // Chart Settings now in their own dialog box - chartSettings = new ChartSettings(this, masterControls); - chartSettings->setMaximumWidth(450); - chartSettings->setMaximumHeight(600); - - //toolBox->addItem(masterControls, QIcon(":images/settings.png"), "Chart Settings"); - chartSettings->hide(); - - views = new QStackedWidget(this); - views->setFrameStyle(QFrame::Plain | QFrame::NoFrame); - views->setMinimumWidth(500); - - // add all the layouts - views->addWidget(analWindow); - views->addWidget(trainWindow); - views->addWidget(diaryWindow); - views->addWidget(homeWindow); - - // add Blank State pages - views->addWidget(blankStateAnalysisPage); - views->addWidget(blankStateHomePage); - views->addWidget(blankStateDiaryPage); - views->addWidget(blankStateTrainPage); - - //views->setCurrentIndex(0); - views->setContentsMargins(0,0,0,0); - - QWidget *sviews = new QWidget(this); - sviews->setContentsMargins(0,0,0,0); - QVBoxLayout *sviewLayout = new QVBoxLayout(sviews); - sviewLayout->setContentsMargins(0,0,0,0); - sviewLayout->setSpacing(0); - sviewLayout->addWidget(scopebar); - sviewLayout->addWidget(views); - splitter->addWidget(sviews); - - splitter->setStretchFactor(0,0); - splitter->setStretchFactor(1,1); - splitter->setCollapsible(0, true); - splitter->setCollapsible(1, false); - splitter->setHandleWidth(1); - splitter->setStyleSheet(" QSplitter::handle { background-color: rgb(120,120,120); color: darkGray; }"); - splitter->setFrameStyle(QFrame::NoFrame); - splitter->setContentsMargins(0, 0, 0, 0); // attempting to follow some UI guides - - QVariant splitterSizes = appsettings->cvalue(context->athlete->cyclist, GC_SETTINGS_SPLITTER_SIZES); - if (splitterSizes.toByteArray().size() > 1 ) { - splitter->restoreState(splitterSizes.toByteArray()); - splitter->setOpaqueResize(true); // redraw when released, snappier UI - } - - // CENTRAL LAYOUT QWidget *central = new QWidget(this); + setContentsMargins(0,0,0,0); central->setContentsMargins(0,0,0,0); - - QVBoxLayout *centralLayout = new QVBoxLayout(central); - centralLayout->setSpacing(0); - centralLayout->setContentsMargins(0,0,0,0); + QVBoxLayout *mainLayout = new QVBoxLayout(central); + mainLayout->setSpacing(0); + mainLayout->setContentsMargins(0,0,0,0); #ifndef Q_OS_MAC // nonmac toolbar on main view -- its not // unified with the title bar. - centralLayout->addWidget(head); + mainLayout->addWidget(head); #endif - centralLayout->addWidget(splitter); - + mainLayout->addWidget(scopebar); + mainLayout->addWidget(tab); setCentralWidget(central); /*---------------------------------------------------------------------- @@ -682,7 +524,7 @@ MainWindow::MainWindow(const QDir &home) optionsMenu->addAction(tr("Refresh Calendar"), this, SLOT(refreshCalendar()), tr ("")); #endif optionsMenu->addSeparator(); - optionsMenu->addAction(tr("Find intervals..."), analysisSidebar, SLOT(addIntervals()), tr ("")); + optionsMenu->addAction(tr("Find intervals..."), this, SLOT(addIntervals()), tr ("")); // Add all the data processors to the tools menu const DataProcessorFactory &factory = DataProcessorFactory::instance(); @@ -756,28 +598,17 @@ MainWindow::MainWindow(const QDir &home) if (context->athlete->allRides->childCount() != 0) context->athlete->treeWidget->setCurrentItem(context->athlete->allRides->child(context->athlete->allRides->childCount()-1)); - // now we're up and runnning lets connect the signals - connect(splitter,SIGNAL(splitterMoved(int,int)), this, SLOT(splitterMoved(int,int))); - - // We really do need a mechanism for showing if a ride needs saving... + //XXX!!! We really do need a mechanism for showing if a ride needs saving... //connect(this, SIGNAL(rideDirty()), this, SLOT(enableSaveButton())); //connect(this, SIGNAL(rideClean()), this, SLOT(enableSaveButton())); // cpx aggregate cache check connect(context,SIGNAL(rideSelected(RideItem*)), this, SLOT(rideSelected(RideItem*))); - // when metricDB updates check if BlankState needs to be closed - connect(context->athlete->metricDB, SIGNAL(dataChanged()), this, SLOT(checkBlankState())); - // when config changes see if Train View BlankState needs to be closed - connect(context, SIGNAL(configChanged()), this, SLOT(checkBlankState())); - // when trainDB updates check if BlankState needs to be closed - connect(trainDB, SIGNAL(dataChanged()), this, SLOT(checkBlankState())); - // Kick off context->athlete->rideTreeWidgetSelectionChanged(); selectAnalysis(); - setStyle(); } /*---------------------------------------------------------------------- @@ -787,45 +618,13 @@ MainWindow::MainWindow(const QDir &home) void MainWindow::toggleSidebar() { - showSidebar(!toolBox->isVisible()); -#ifdef Q_OS_MAC - sidebar->setSelected(toolBox->isVisible()); -#endif + tab->toggleSidebar(); } void MainWindow::showSidebar(bool want) { - if (want) { - - toolBox->show(); - - // Restore sizes - QVariant splitterSizes = appsettings->cvalue(context->athlete->cyclist, GC_SETTINGS_SPLITTER_SIZES); - if (splitterSizes.toByteArray().size() > 1 ) { - splitter->restoreState(splitterSizes.toByteArray()); - splitter->setOpaqueResize(true); // redraw when released, snappier UI - } - - // if it was collapsed we need set to at least 200 - // unless the mainwindow isn't big enough - if (toolBox->width()<10) { - int size = width() - 200; - if (size>200) size = 200; - - QList sizes; - sizes.append(size); - sizes.append(width()-size); - splitter->setSizes(sizes); - } - - } else { - - toolBox->hide(); - } - showhideSidebar->setChecked(toolBox->isVisible()); - setStyle(); - + tab->setSidebarEnabled(want); } void @@ -839,14 +638,18 @@ void MainWindow::setChartMenu() { unsigned int mask=0; + // called when chart menu about to be shown // setup to only show charts that are relevant // to this view - if (currentWindow == analWindow) mask = VIEW_ANALYSIS; - if (currentWindow == trainWindow) mask = VIEW_TRAIN; - if (currentWindow == diaryWindow) mask = VIEW_DIARY; - if (currentWindow == homeWindow) mask = VIEW_HOME; - + switch(tab->currentView()) { + case 0 : mask = VIEW_HOME; break; + default: + case 1 : mask = VIEW_ANALYSIS; break; + case 2 : mask = VIEW_DIARY; break; + case 3 : mask = VIEW_TRAIN; break; + } + chartMenu->clear(); if (!mask) return; @@ -863,10 +666,13 @@ MainWindow::setSubChartMenu() // called when chart menu about to be shown // setup to only show charts that are relevant // to this view - if (currentWindow == analWindow) mask = VIEW_ANALYSIS; - if (currentWindow == trainWindow) mask = VIEW_TRAIN; - if (currentWindow == diaryWindow) mask = VIEW_DIARY; - if (currentWindow == homeWindow) mask = VIEW_HOME; + switch(tab->currentView()) { + case 0 : mask = VIEW_HOME; break; + default: + case 1 : mask = VIEW_ANALYSIS; break; + case 2 : mask = VIEW_DIARY; break; + case 3 : mask = VIEW_TRAIN; break; + } subChartMenu->clear(); if (!mask) return; @@ -908,7 +714,7 @@ MainWindow::addChart(QAction*action) } } if (id != GcWindowTypes::None) - currentWindow->appendChart(id); // called from MainWindow to inset chart + tab->addChart(id); // called from MainWindow to inset chart } void @@ -935,29 +741,15 @@ MainWindow::selectWindow(QAction *act) void MainWindow::setStyleFromSegment(int segment) { - if (!currentWindow) return; - currentWindow->setStyle(segment ? 2 : 0); + tab->setTiled(segment); styleAction->setChecked(!segment); } void MainWindow::toggleStyle() { - if (!currentWindow) return; - - switch (currentWindow->currentStyle) { - - default: - case 0 : - currentWindow->setStyle(2); - styleAction->setChecked(false); - break; - - case 2 : - currentWindow->setStyle(0); - styleAction->setChecked(true); - break; - } + tab->toggleTile(); + styleAction->setChecked(tab->isTiled()); setStyle(); } @@ -970,27 +762,6 @@ MainWindow::toggleFullScreen() } #endif -void -MainWindow::dateRangeChangedDiary(DateRange dr) -{ - // we got signalled date range changed, tell the current view - // when we have multiple sidebars that change date we need to connect - // them up individually.... i.e. LTM.... - diaryWindow->setProperty("dateRange", QVariant::fromValue(dr)); - context->_dr = dr; -} - -void -MainWindow::dateRangeChangedLTM(DateRange dr) -{ - // we got signalled date range changed, tell the current view - // when we have multiple sidebars that change date we need to connect - // them up individually.... i.e. LTM.... - homeWindow->setProperty("dateRange", QVariant::fromValue(dr)); - context->_dr = dr; -} - - void MainWindow::resizeEvent(QResizeEvent*) { @@ -1001,16 +772,6 @@ MainWindow::resizeEvent(QResizeEvent*) #endif } -void -MainWindow::splitterMoved(int pos, int /*index*/) -{ - // show / hide sidebar as dragged.. - if ((pos == 0 && toolBox->isVisible()) || (pos>10 && !toolBox->isVisible())) toggleSidebar(); - - analysisSidebar->setWidth(pos); - appsettings->setCValue(context->athlete->cyclist, GC_SETTINGS_SPLITTER_SIZES, splitter->saveState()); -} - void MainWindow::showOptions() { @@ -1030,16 +791,6 @@ MainWindow::closeEvent(QCloseEvent* event) if (saveRideExitDialog() == false) event->ignore(); else { - // stop any active realtime conneection - trainSidebar->Stop(); - analysisSidebar->close(); // save settings - - // save the state of all the pages - analWindow->saveState(); - homeWindow->saveState(); - trainWindow->saveState(); - diaryWindow->saveState(); - #ifdef GC_HAVE_LUCENE // save the named searches context->athlete->namedSearches->write(); @@ -1048,11 +799,8 @@ MainWindow::closeEvent(QCloseEvent* event) // clear the clipboard if neccessary QApplication::clipboard()->setText(""); - // blank state settings - appsettings->setCValue(context->athlete->cyclist, GC_BLANK_ANALYSIS, blankStateAnalysisPage->dontShow->isChecked()); - appsettings->setCValue(context->athlete->cyclist, GC_BLANK_DIARY, blankStateDiaryPage->dontShow->isChecked()); - appsettings->setCValue(context->athlete->cyclist, GC_BLANK_HOME, blankStateHomePage->dontShow->isChecked()); - appsettings->setCValue(context->athlete->cyclist, GC_BLANK_TRAIN, blankStateTrainPage->dontShow->isChecked()); + // close the tab + tab->close(); // close athlete context->athlete->close(); @@ -1066,16 +814,7 @@ MainWindow::closeEvent(QCloseEvent* event) MainWindow::~MainWindow() { - delete analysisSidebar; - delete ltmSidebar; - delete diarySidebar; - delete trainSidebar; - - delete analWindow; - delete homeWindow; - delete trainWindow; - delete diaryWindow; - + delete tab; delete context->athlete; } @@ -1122,7 +861,7 @@ void MainWindow::showWorkoutWizard() void MainWindow::resetWindowLayout() { - currentWindow->resetLayout(); + tab->resetLayout(); } void MainWindow::manualProcess(QString name) @@ -1152,160 +891,38 @@ MainWindow::helpView() QDesktopServices::openUrl(QUrl("http://www.goldencheetah.org/wiki.html")); } -void -MainWindow::checkBlankState() -{ - // Home? - if (views->currentWidget() == blankStateHomePage) { - // should it be closed? - if (context->athlete->allRides->childCount() > 0) closeBlankHome(); - } - // Diary? - if (views->currentWidget() == blankStateDiaryPage) { - // should it be closed? - if (context->athlete->allRides->childCount() > 0) closeBlankDiary(); - } - // Analysis?? - if (views->currentWidget() == blankStateAnalysisPage) { - // should it be closed? - if (context->athlete->allRides->childCount() > 0) closeBlankAnal(); - } - // Train?? - if (views->currentWidget() == blankStateTrainPage) { - // should it be closed? - if (appsettings->value(this, GC_DEV_COUNT).toInt() > 0 && trainDB->getCount() > 2) closeBlankTrain(); - } -} - -void -MainWindow::closeBlankTrain() -{ - showBlankTrain = false; - selectTrain(); -} - -void -MainWindow::closeBlankAnal() -{ - showBlankAnal = false; - selectAnalysis(); -} - -void -MainWindow::closeBlankDiary() -{ - showBlankDiary = false; - selectDiary(); -} - -void -MainWindow::closeBlankHome() -{ - showBlankHome = false; - selectHome(); -} - void MainWindow::selectAnalysis() { - // No ride - no analysis view - if (context->athlete->allRides->childCount() == 0 && showBlankAnal == true) { - masterControls->setVisible(false); - toolBox->hide(); - views->setCurrentWidget(blankStateAnalysisPage); - } else { - masterControls->setVisible(true); - masterControls->setCurrentIndex(0); - views->setCurrentIndex(0); - analWindow->selected(); // tell it! - trainSidebar->getToolbarButtons()->hide(); -#ifdef GC_HAVE_ICAL - scopebar->selected(2); -#else - scopebar->selected(1); -#endif - toolBox->setCurrentIndex(0); - } - currentWindow = analWindow; + tab->selectView(1); setStyle(); } void MainWindow::selectTrain() { - // no devices configured -or- only the manual mode workouts defined - // we need to get setup properly... - if ((appsettings->value(this, GC_DEV_COUNT) == 0 || trainDB->getCount() <= 2) && showBlankTrain == true) { - masterControls->setVisible(false); - toolBox->hide(); - views->setCurrentWidget(blankStateTrainPage); - } else { - masterControls->setVisible(true); - //this->showSidebar(true); - masterControls->setCurrentIndex(1); - views->setCurrentIndex(1); - trainWindow->selected(); // tell it! - trainSidebar->getToolbarButtons()->show(); -#ifdef GC_HAVE_ICAL - scopebar->selected(3); -#else - scopebar->selected(2); -#endif - toolBox->setCurrentIndex(2); - } - currentWindow = trainWindow; + tab->selectView(3); setStyle(); } void MainWindow::selectDiary() { - if (context->athlete->allRides->childCount() == 0 && showBlankDiary == true) { - masterControls->setVisible(false); - toolBox->hide(); - views->setCurrentWidget(blankStateDiaryPage); - } else { - masterControls->setVisible(true); - //this->showSidebar(true); - masterControls->setCurrentIndex(2); - views->setCurrentIndex(2); - diaryWindow->selected(); // tell it! - trainSidebar->getToolbarButtons()->hide(); - scopebar->selected(1); - toolBox->setCurrentIndex(1); - diarySidebar->refresh(); // get that signal with the date range... - } - currentWindow = diaryWindow; + tab->selectView(2); setStyle(); } void MainWindow::selectHome() { - // No ride - no analysis view - if (context->athlete->allRides->childCount() == 0 && showBlankHome == true) { - masterControls->setVisible(false); - toolBox->hide(); - views->setCurrentWidget(blankStateHomePage); - } else { - masterControls->setVisible(true); - //toolBox->show(); - //this->showSidebar(true); - masterControls->setCurrentIndex(3); - views->setCurrentIndex(3); - homeWindow->selected(); // tell it! - trainSidebar->getToolbarButtons()->hide(); - scopebar->selected(0); - toolBox->setCurrentIndex(3); - } - currentWindow = homeWindow; + tab->selectView(0); setStyle(); } void MainWindow::setStyle() { - int select = currentWindow->currentStyle == 0 ? 0 : 1; + int select = tab->isTiled() ? 1 : 0; #ifdef Q_OS_MAC styleSelector->setSelected(select, true); @@ -1339,7 +956,7 @@ MainWindow::dropEvent(QDropEvent *event) QList urls = event->mimeData()->urls(); if (urls.isEmpty()) return; - if (currentWindow != trainWindow) { + if (tab->currentView() != 3) { // we're not on train view // We have something to process then RideImportWizard *dialog = new RideImportWizard (&urls, context->athlete->home, context); dialog->process(); // do it! @@ -1777,7 +1394,7 @@ MainWindow::actionClicked(int index) switch(index) { default: - case 0: analysisSidebar->addIntervals(); + case 0: tab->addIntervals(); break; case 1 : splitRide(); @@ -1789,6 +1406,12 @@ MainWindow::actionClicked(int index) } } +void +MainWindow::addIntervals() +{ + tab->addIntervals(); +} + void MainWindow::rideSelected(RideItem*) { @@ -1796,12 +1419,7 @@ MainWindow::rideSelected(RideItem*) // update the ride property on all widgets // to let them know they need to replot new // selected ride - diarySidebar->setRide(context->ride); - analysisSidebar->setRide(context->ride); - analWindow->setProperty("ride", QVariant::fromValue(dynamic_cast(context->ride))); - homeWindow->setProperty("ride", QVariant::fromValue(dynamic_cast(context->ride))); - diaryWindow->setProperty("ride", QVariant::fromValue(dynamic_cast(context->ride))); - trainWindow->setProperty("ride", QVariant::fromValue(dynamic_cast(context->ride))); + tab->setRide(context->ride); if (!context->ride) return; diff --git a/src/MainWindow.h b/src/MainWindow.h index e422fcc3a..4dc30120d 100644 --- a/src/MainWindow.h +++ b/src/MainWindow.h @@ -31,23 +31,13 @@ #include #endif -class HomeWindow; -class GcToolBar; -class DiarySidebar; -class LTMSidebar; -class AnalysisSidebar; class LionFullScreen; class QTFullScreen; -class TrainSidebar; -class ChartSettings; class QtMacSegmentedButton; class QtMacButton; +class GcToolBar; class GcScopeBar; class Library; -class BlankStateAnalysisPage; -class BlankStateHomePage; -class BlankStateDiaryPage; -class BlankStateTrainPage; class QtSegmentControl; class SaveSingleDialogWidget; @@ -69,11 +59,11 @@ class MainWindow : public QMainWindow ~MainWindow(); // temp to zap db - will move to tab // // temporary access to chart settings - ChartSettings *chartsettings() { return chartSettings; } // by HomeWindow + //ChartSettings *chartsettings() { return chartSettings; } // by HomeWindow // temporary access to the sidebars - AnalysisSidebar *analysissidebar() {return analysisSidebar; } // by SearchBox - TrainSidebar *trainsidebar() {return trainSidebar; } // by ErgDBDownloadDialog + //AnalysisSidebar *analysissidebar() {return analysisSidebar; } // by SearchBox + //TrainSidebar *trainsidebar() {return trainSidebar; } // by ErgDBDownloadDialog // temporary access to the context Context *contextmain() { return context; } // by ChooseCyclistDialog @@ -94,7 +84,6 @@ class MainWindow : public QMainWindow #ifndef Q_OS_MAC void toggleFullScreen(); #endif - void splitterMoved(int, int); void aboutDialog(); void helpView(); void logBug(); @@ -106,11 +95,6 @@ class MainWindow : public QMainWindow void clearFilter(); - void checkBlankState(); - void closeBlankTrain(); - void closeBlankAnal(); - void closeBlankDiary(); - void closeBlankHome(); void selectHome(); void selectDiary(); void selectAnalysis(); @@ -123,6 +107,7 @@ class MainWindow : public QMainWindow void selectWindow(QAction*); void showOptions(); + void toggleSidebar(); void showSidebar(bool want); void showToolbar(bool want); @@ -144,15 +129,11 @@ class MainWindow : public QMainWindow void importWorkout(); // Diary View - void dateRangeChangedDiary(DateRange); void refreshCalendar(); #ifdef GC_HAVE_ICAL void uploadCalendar(); // upload ride to calendar #endif - // LTM View - void dateRangeChangedLTM(DateRange); - // Measures View void downloadMeasures(); void downloadMeasuresFromZeo(); @@ -162,6 +143,7 @@ class MainWindow : public QMainWindow void openCyclist(); // Activity Collection + void addIntervals(); // pass thru to tab void rideSelected(RideItem*ride); bool saveRideSingleDialog(RideItem *); void saveSilent(RideItem *); @@ -188,38 +170,8 @@ class MainWindow : public QMainWindow private: Context *context; - - // Top-level views - HomeWindow *homeWindow; - HomeWindow *diaryWindow; - HomeWindow *trainWindow; - HomeWindow *analWindow; - HomeWindow *currentWindow; // tracks the curerntly showing window - - BlankStateAnalysisPage *blankStateAnalysisPage; - BlankStateHomePage *blankStateHomePage; - BlankStateDiaryPage *blankStateDiaryPage; - BlankStateTrainPage *blankStateTrainPage; - - bool showBlankAnal; - bool showBlankTrain; - bool showBlankHome; - bool showBlankDiary; - - ChartSettings *chartSettings; - - // splitter for sidebar and main view - QSplitter *splitter; - - // sidebar and views - QStackedWidget *toolBox; // contains all left sidebars - QStackedWidget *views; // contains all the views - - // sidebars - AnalysisSidebar *analysisSidebar; - TrainSidebar *trainSidebar; // train view - LTMSidebar *ltmSidebar; // home view - DiarySidebar *diarySidebar; // diary + GcScopeBar *scopebar; + Tab *tab; #if (defined Q_OS_MAC) && (defined GC_HAVE_LION) LionFullScreen *fullScreen; @@ -243,7 +195,6 @@ class MainWindow : public QMainWindow QIcon importIcon, composeIcon, intervalIcon, splitIcon, deleteIcon, sidebarIcon, tabbedIcon, tiledIcon; #endif - GcScopeBar *scopebar; // chart menus QMenu *chartMenu; @@ -259,13 +210,6 @@ class MainWindow : public QMainWindow QAction *rideWithGPSAction; QAction *ttbAction; - // each view has its own controls - QStackedWidget *masterControls, - *analysisControls, - *trainControls, - *diaryControls, - *homeControls; - // Miscellany QSignalMapper *toolMapper; }; diff --git a/src/RideNavigator.cpp b/src/RideNavigator.cpp index aed124875..901a663b2 100644 --- a/src/RideNavigator.cpp +++ b/src/RideNavigator.cpp @@ -18,6 +18,7 @@ #include "Athlete.h" #include "Context.h" +#include "RideItem.h" #include "RideNavigator.h" #include "RideNavigatorProxy.h" #include "SearchFilterBox.h" diff --git a/src/RideNavigator.h b/src/RideNavigator.h index 376272f6a..edf5c1f87 100644 --- a/src/RideNavigator.h +++ b/src/RideNavigator.h @@ -25,7 +25,6 @@ #include "RideMetadata.h" #include "DBAccess.h" #include "Context.h" -#include "DiarySidebar.h" #include "Settings.h" #include "Colors.h" @@ -37,6 +36,7 @@ class GroupByModel; class SearchFilter; class SearchFilterBox; class DiaryWindow; +class DiarySidebar; class BUGFIXQSortFilterProxyModel; class DataFilter; class GcMiniCalendar; diff --git a/src/SearchBox.cpp b/src/SearchBox.cpp index 0a99ae7f0..34bba28c4 100644 --- a/src/SearchBox.cpp +++ b/src/SearchBox.cpp @@ -211,7 +211,14 @@ void SearchBox::runMenu(QAction *x) editor->show(); } else if (x->text() == tr("Column Chooser")) { - ColumnChooser *selector = new ColumnChooser(context->mainWindow->analysissidebar()->rideNavigator->logicalHeadings); + + QStringList logicalHeadings; + foreach(FieldDefinition field, context->athlete->rideMetadata()->getFields()) { + if (!context->specialFields.isMetric(field.name) && (field.type < 5 || field.type == 7)) { + logicalHeadings << context->specialFields.displayName(field.name); + } + } + ColumnChooser *selector = new ColumnChooser(logicalHeadings); selector->show(); } else { NamedSearch get = context->athlete->namedSearches->get(x->text()); diff --git a/src/Tab.cpp b/src/Tab.cpp new file mode 100644 index 000000000..ac654f484 --- /dev/null +++ b/src/Tab.cpp @@ -0,0 +1,148 @@ +/* + * Copyright (c) 2013 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 + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include "Tab.h" +#include "Views.h" +#include "MainWindow.h" + +Tab::Tab(Context *context) : QWidget(context->mainWindow), context(context) +{ + context->tab = this; + + setContentsMargins(0,0,0,0); + QVBoxLayout *main = new QVBoxLayout(this); + main->setSpacing(0); + main->setContentsMargins(0,0,0,0); + + views = new QStackedWidget(this); + views->setContentsMargins(0,0,0,0); + main->addWidget(views); + + // all the stack views for the controls + masterControls = new QStackedWidget(this); + masterControls->setFrameStyle(QFrame::Plain | QFrame::NoFrame); + masterControls->setCurrentIndex(0); + masterControls->setContentsMargins(0,0,0,0); + + // Home + homeControls = new QStackedWidget(this); + homeControls->setFrameStyle(QFrame::Plain | QFrame::NoFrame); + homeControls->setContentsMargins(0,0,0,0); + masterControls->addWidget(homeControls); + homeView = new HomeView(context, homeControls); + views->addWidget(homeView); + + // Analysis + analysisControls = new QStackedWidget(this); + analysisControls->setFrameStyle(QFrame::Plain | QFrame::NoFrame); + analysisControls->setCurrentIndex(0); + analysisControls->setContentsMargins(0,0,0,0); + masterControls->addWidget(analysisControls); + analysisView = new AnalysisView(context, analysisControls); + views->addWidget(analysisView); + + // Diary + diaryControls = new QStackedWidget(this); + diaryControls->setFrameStyle(QFrame::Plain | QFrame::NoFrame); + diaryControls->setCurrentIndex(0); + diaryControls->setContentsMargins(0,0,0,0); + masterControls->addWidget(diaryControls); + diaryView = new DiaryView(context, diaryControls); + views->addWidget(diaryView); + + // Train + trainControls = new QStackedWidget(this); + trainControls->setFrameStyle(QFrame::Plain | QFrame::NoFrame); + trainControls->setCurrentIndex(0); + trainControls->setContentsMargins(0,0,0,0); + masterControls->addWidget(trainControls); + trainView = new TrainView(context, trainControls); + views->addWidget(trainView); + + // the dialog box for the chart settings + chartSettings = new ChartSettings(this, masterControls); + chartSettings->setMaximumWidth(450); + chartSettings->setMaximumHeight(600); + chartSettings->hide(); +} + +Tab::~Tab() +{ + delete analysisView; + delete homeView; + delete trainView; + delete diaryView; + delete views; +} + +void +Tab::close() +{ + analysisView->saveState(); + homeView->saveState(); + trainView->saveState(); + diaryView->saveState(); + + analysisView->close(); + homeView->close(); + trainView->close(); + diaryView->close(); +} + +/****************************************************************************** + * MainWindow integration with Tab / TabView (mostly pass through) + *****************************************************************************/ + +void Tab::setSidebarEnabled(bool x) { view(currentView())->setSidebarEnabled(x); } +bool Tab::isSidebarEnabled() { return view(currentView())->sidebarEnabled(); } +void Tab::toggleSidebar() { view(currentView())->setSidebarEnabled(!view(currentView())->sidebarEnabled()); } +void Tab::setTiled(bool x) { view(currentView())->setTiled(x); } +bool Tab::isTiled() { return view(currentView())->isTiled(); } +void Tab::toggleTile() { view(currentView())->setTiled(!view(currentView())->isTiled()); } +void Tab::resetLayout() { view(currentView())->resetLayout(); } +void Tab::addChart(GcWinID i) { view(currentView())->addChart(i); } +void Tab::addIntervals() { analysisView->addIntervals(); } + +void Tab::setRide(RideItem*ride) +{ + analysisView->setRide(ride); + homeView->setRide(ride); + trainView->setRide(ride); + diaryView->setRide(ride); +} + +TabView * +Tab::view(int index) +{ + switch(index) { + case 0 : return homeView; + default: + case 1 : return analysisView; + case 2 : return diaryView; + case 3 : return trainView; + } +} + +void +Tab::selectView(int index) +{ + views->setCurrentIndex(index); + view(index)->setSelected(true); + masterControls->setCurrentIndex(index); +} diff --git a/src/Tab.h b/src/Tab.h new file mode 100644 index 000000000..529be103e --- /dev/null +++ b/src/Tab.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 2013 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 + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _GC_Tab_h +#define _GC_Tab_h 1 + +#include "TabView.h" +#include "Views.h" + +class Tab: public QWidget +{ + Q_OBJECT + + public: + + Tab(Context *context); + ~Tab(); + void close(); + + ChartSettings *chartsettings() { return chartSettings; } // by HomeWindow + int currentView() { return views->currentIndex(); } + TabView *view(int index); + + signals: + + public slots: + + // set Ride + void setRide(RideItem*); + + // tile mode + void setTiled(bool); + bool isTiled(); + void toggleTile(); + + // sidebar + void toggleSidebar(); + void setSidebarEnabled(bool); + bool isSidebarEnabled(); + + // layout + void resetLayout(); + void addChart(GcWinID); + + // switch views + void selectView(int); + + // specific to analysis view + void addIntervals(); + + private: + + Context *context; + + // Each of the views + QStackedWidget *views; + AnalysisView *analysisView; + HomeView *homeView; + TrainView *trainView; + DiaryView *diaryView; + + // Chart Settings Dialog + ChartSettings *chartSettings; + QStackedWidget *masterControls, + *analysisControls, + *trainControls, + *diaryControls, + *homeControls; + +}; + +#endif // _GC_TabView_h diff --git a/src/TabView.cpp b/src/TabView.cpp index 345d4ae98..9df6c2e28 100644 --- a/src/TabView.cpp +++ b/src/TabView.cpp @@ -27,7 +27,7 @@ #include "MainWindow.h" // temp - will become Tab when its ready TabView::TabView(Context *context, int type) : - QWidget(context->mainWindow), type(type), + QWidget(context->mainWindow), context(context), type(type), _sidebar(true), _tiled(false), _selected(false), stack(NULL), splitter(NULL), sidebar_(NULL), page_(NULL), blank_(NULL) { @@ -38,14 +38,13 @@ TabView::TabView(Context *context, int type) : layout->setSpacing(0); stack = new QStackedWidget(this); + stack->setContentsMargins(0,0,0,0); layout->addWidget(stack); // the splitter splitter = new QSplitter(this); splitter->setStretchFactor(0,0); splitter->setStretchFactor(1,1); - splitter->setCollapsible(0, true); - splitter->setCollapsible(1, false); splitter->setHandleWidth(1); splitter->setStyleSheet(" QSplitter::handle { background-color: rgb(120,120,120); color: darkGray; }"); splitter->setFrameStyle(QFrame::NoFrame); @@ -53,11 +52,7 @@ TabView::TabView(Context *context, int type) : splitter->setOpaqueResize(true); // redraw when released, snappier UI stack->insertWidget(0, splitter); // splitter always at index 0 - QString setting = QString("%1/%2").arg(GC_SETTINGS_SPLITTER_SIZES).arg(type); - QVariant splitterSizes = appsettings->cvalue(context->athlete->cyclist, setting); - if (splitterSizes.toByteArray().size() > 1 ) { - splitter->restoreState(splitterSizes.toByteArray()); - } + connect(splitter,SIGNAL(splitterMoved(int,int)), this, SLOT(splitterMoved(int,int))); } TabView::~TabView() @@ -65,6 +60,12 @@ TabView::~TabView() if (page_) page_->saveState(); } +void +TabView::setRide(RideItem*ride) +{ + page()->setProperty("ride", QVariant::fromValue(dynamic_cast(ride))); +} + void TabView::splitterMoved(int pos,int) { @@ -91,7 +92,17 @@ void TabView::setPage(HomeWindow *page) { page_ = page; + + // now reset the splitter splitter->insertWidget(-1, page); + splitter->setCollapsible(0, true); + splitter->setCollapsible(1, false); + QString setting = QString("%1/%2").arg(GC_SETTINGS_SPLITTER_SIZES).arg(type); + QVariant splitterSizes = appsettings->cvalue(context->athlete->cyclist, setting); + if (splitterSizes.toByteArray().size() > 1 ) { + splitter->restoreState(splitterSizes.toByteArray()); + } + } void @@ -105,14 +116,37 @@ TabView::setBlank(BlankStatePage *blank) void TabView::sidebarChanged() { - if (sidebarEnabled()) sidebar_->show(); - else sidebar_->hide(); + if (sidebarEnabled()) { + + sidebar_->show(); + + // Restore sizes + QString setting = QString("%1/%2").arg(GC_SETTINGS_SPLITTER_SIZES).arg(type); + QVariant splitterSizes = appsettings->cvalue(context->athlete->cyclist, setting); + if (splitterSizes.toByteArray().size() > 1 ) { + splitter->restoreState(splitterSizes.toByteArray()); + splitter->setOpaqueResize(true); // redraw when released, snappier UI + } + + // if it was collapsed we need set to at least 200 + // unless the mainwindow isn't big enough + if (sidebar_->width()<10) { + int size = width() - 200; + if (size>200) size = 200; + + QList sizes; + sizes.append(size); + sizes.append(width()-size); + splitter->setSizes(sizes); + } + + } else sidebar_->hide(); } void TabView::tileModeChanged() { - if (page_) page_->setStyle(isTiled() ? 0 : 2); + if (page_) page_->setStyle(isTiled() ? 2 : 0); } void @@ -120,6 +154,11 @@ TabView::selectionChanged() { // we got selected.. if (isSelected()) { + + emit onSelected(); // give view a change to prepare + page()->selected(); // select the view + + // or do we need to show blankness? if (isBlank() && blank_ && page_) stack->setCurrentIndex(1); if (!isBlank() && blank_ && page_) stack->setCurrentIndex(0); } diff --git a/src/TabView.h b/src/TabView.h index f21560809..9fa1c1a75 100644 --- a/src/TabView.h +++ b/src/TabView.h @@ -43,6 +43,7 @@ class TabView : public QWidget TabView(Context *context, int type); virtual ~TabView(); + virtual void close() {}; // add the widgets to the view void setSidebar(QWidget *sidebar); @@ -64,34 +65,35 @@ class TabView : public QWidget void setSelected(bool x) { _selected=x; selectionChanged(); } bool isSelected() const { return _selected; } + void saveState() { if (page_) page_->saveState(); } + signals: void sidebarClosed(); // the user dragged the sidebar closed. + void onSelected(); public slots: // interface used by the Tab class - must be implemented by a TabView virtual bool isBlank() = 0; + virtual void setRide(RideItem*); // can be overriden by the derived class but we provide a working version virtual void sidebarChanged(); virtual void tileModeChanged(); virtual void selectionChanged(); virtual void resetLayout(); - //virtual void setChartMenu(); // need to be in Tab - //virtual void setSubChartMenu(); // need to be in Tab and scopebar by the looks of it + virtual void addChart(GcWinID id); // Let the base class handle the splitter movement and // hiding the sidebar by dragging it closed. void splitterMoved(int, int); - //void dateRangeChanged(DateRange); - //void rideSelected(RideItem*ride); //void mediaSelected(QString filename); //void ergSelected(ErgFile *erg); - private: + protected: Context *context; int type; // used by windowregistry; e.g VIEW_TRAIN VIEW_ANALYSIS VIEW_DIARY VIEW_HOME diff --git a/src/Views.cpp b/src/Views.cpp new file mode 100644 index 000000000..b09583077 --- /dev/null +++ b/src/Views.cpp @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2013 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 + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "Views.h" +#include "AnalysisSidebar.h" +#include "DiarySidebar.h" +#include "TrainSidebar.h" +#include "LTMSidebar.h" +#include "BlankState.h" + +// BLANK STATE NEEDS FIXING +// blank state settings +//appsettings->setCValue(context->athlete->cyclist, GC_BLANK_ANALYSIS, blankStateAnalysisPage->dontShow->isChecked()); +//appsettings->setCValue(context->athlete->cyclist, GC_BLANK_DIARY, blankStateDiaryPage->dontShow->isChecked()); +//appsettings->setCValue(context->athlete->cyclist, GC_BLANK_HOME, blankStateHomePage->dontShow->isChecked()); +//appsettings->setCValue(context->athlete->cyclist, GC_BLANK_TRAIN, blankStateTrainPage->dontShow->isChecked()); +// // when metricDB updates check if BlankState needs to be closed +// connect(context->athlete->metricDB, SIGNAL(dataChanged()), this, SLOT(checkBlankState())); +// // when config changes see if Train View BlankState needs to be closed +// connect(context, SIGNAL(configChanged()), this, SLOT(checkBlankState())); +// // when trainDB updates check if BlankState needs to be closed +// connect(trainDB, SIGNAL(dataChanged()), this, SLOT(checkBlankState())); + + +AnalysisView::AnalysisView(Context *context, QStackedWidget *controls) : TabView(context, VIEW_ANALYSIS) +{ + AnalysisSidebar *s = new AnalysisSidebar(context); + HomeWindow *a = new HomeWindow(context, "analysis", "Analysis"); + controls->addWidget(a->controls()); + controls->setCurrentIndex(0); + BlankStateAnalysisPage *b = new BlankStateAnalysisPage(context); + + setSidebar(s); + setPage(a); + setBlank(b); +} + +AnalysisView::~AnalysisView() +{ +} + +void +AnalysisView::setRide(RideItem *ride) +{ + static_cast(sidebar())->setRide(ride); // save settings + page()->setProperty("ride", QVariant::fromValue(dynamic_cast(ride))); +} + +void +AnalysisView::addIntervals() +{ + static_cast(sidebar())->addIntervals(); // save settings +} + +void AnalysisView::close() +{ + static_cast(sidebar())->close(); // save settings +} + +bool +AnalysisView::isBlank() +{ + return false; +} + +DiaryView::DiaryView(Context *context, QStackedWidget *controls) : TabView(context, VIEW_DIARY) +{ + DiarySidebar *s = new DiarySidebar(context); + HomeWindow *d = new HomeWindow(context, "diary", "Diary"); + controls->addWidget(d->controls()); + controls->setCurrentIndex(0); + BlankStateDiaryPage *b = new BlankStateDiaryPage(context); + + setSidebar(s); + setPage(d); + setBlank(b); + + connect(s, SIGNAL(dateRangeChanged(DateRange)), this, SLOT(dateRangeChanged(DateRange))); +} + +DiaryView::~DiaryView() +{ +} + +void +DiaryView::setRide(RideItem*ride) +{ + static_cast(sidebar())->setRide(ride); + page()->setProperty("ride", QVariant::fromValue(dynamic_cast(ride))); +} + +void +DiaryView::dateRangeChanged(DateRange dr) +{ + context->dr_ = dr; + page()->setProperty("dateRange", QVariant::fromValue(dr)); +} + +bool +DiaryView::isBlank() +{ + return false; +} + +HomeView::HomeView(Context *context, QStackedWidget *controls) : TabView(context, VIEW_HOME) +{ + LTMSidebar *s = new LTMSidebar(context); + HomeWindow *h = new HomeWindow(context, "home", "Home"); + controls->addWidget(h->controls()); + controls->setCurrentIndex(0); + BlankStateHomePage *b = new BlankStateHomePage(context); + + setSidebar(s); + setPage(h); + setBlank(b); + + connect(s, SIGNAL(dateRangeChanged(DateRange)), this, SLOT(dateRangeChanged(DateRange))); + connect(this, SIGNAL(onSelected()), this, SLOT(justSelected())); +} + +HomeView::~HomeView() +{ +} + +void +HomeView::dateRangeChanged(DateRange dr) +{ + context->dr_ = dr; + page()->setProperty("dateRange", QVariant::fromValue(dr)); +} +bool +HomeView::isBlank() +{ + return false; +} + +void +HomeView::justSelected() +{ + // force date range refresh + static_cast(sidebar())->dateRangeTreeWidgetSelectionChanged(); +} + +TrainView::TrainView(Context *context, QStackedWidget *controls) : TabView(context, VIEW_TRAIN) +{ + TrainSidebar *s = new TrainSidebar(context); + s->hide(); + s->getToolbarButtons()->hide(); // no show yet + + HomeWindow *t = new HomeWindow(context, "train", "train"); + controls->addWidget(t->controls()); + controls->setCurrentIndex(0); + BlankStateTrainPage *b = new BlankStateTrainPage(context); + + setSidebar(s->controls()); + setPage(t); + setBlank(b); + +} + +TrainView::~TrainView() +{ + static_cast(sidebar())->Stop(); +} + +bool +TrainView::isBlank() +{ + return false; +} diff --git a/src/Views.h b/src/Views.h new file mode 100644 index 000000000..d3622457f --- /dev/null +++ b/src/Views.h @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2013 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 + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _GC_Views_h +#define _GC_Views_h 1 + +#include "TabView.h" + +class AnalysisView : public TabView +{ + Q_OBJECT + + public: + + AnalysisView(Context *context, QStackedWidget *controls); + ~AnalysisView(); + void close(); + void setRide(RideItem*ride); + void addIntervals(); + + public slots: + + bool isBlank(); + +}; +class DiaryView : public TabView +{ + Q_OBJECT + + public: + + DiaryView(Context *context, QStackedWidget *controls); + ~DiaryView(); + void setRide(RideItem*ride); + + public slots: + + bool isBlank(); + void dateRangeChanged(DateRange); + +}; +class TrainView : public TabView +{ + Q_OBJECT + + public: + + TrainView(Context *context, QStackedWidget *controls); + ~TrainView(); + + public slots: + + bool isBlank(); + +}; +class HomeView : public TabView +{ + Q_OBJECT + + public: + + HomeView(Context *context, QStackedWidget *controls); + ~HomeView(); + + + public slots: + + bool isBlank(); + void justSelected(); + void dateRangeChanged(DateRange); + +}; + +#endif // _GC_Views_h diff --git a/src/src.pro b/src/src.pro index 35994796e..9c1e364a1 100644 --- a/src/src.pro +++ b/src/src.pro @@ -377,6 +377,8 @@ HEADERS += \ SummaryMetrics.h \ SummaryWindow.h \ SyncRideFile.h \ + Tab.h \ + TabView.h \ TcxParser.h \ TcxRideFile.h \ TxtRideFile.h \ @@ -389,6 +391,7 @@ HEADERS += \ TreeMapPlot.h \ TtbDialog.h \ Units.h \ + Views.h \ WithingsDownload.h \ WkoRideFile.h \ WorkoutPlotWindow.h \ @@ -565,6 +568,8 @@ SOURCES += \ SummaryMetrics.cpp \ SummaryWindow.cpp \ SyncRideFile.cpp \ + Tab.cpp \ + TabView.cpp \ TacxCafRideFile.cpp \ TcxParser.cpp \ TcxRideFile.cpp \ @@ -579,6 +584,7 @@ SOURCES += \ TreeMapPlot.cpp \ TtbDialog.cpp \ TRIMPPoints.cpp \ + Views.cpp \ WattsPerKilogram.cpp \ WithingsDownload.cpp \ WkoRideFile.cpp \