diff --git a/QGCApplication.pro b/QGCApplication.pro index 2ceff3dc7153e11220da2a5351115477c9c34903..12fc55ae6bb1cce1a1531cb722860149cf7e5a6c 100644 --- a/QGCApplication.pro +++ b/QGCApplication.pro @@ -162,12 +162,10 @@ INCLUDEPATH += \ FORMS += \ src/QGCQmlWidgetHolder.ui \ - src/ui/Linechart.ui \ src/ui/LogReplayLinkConfigurationWidget.ui \ src/ui/MainWindow.ui \ src/ui/MAVLinkSettingsWidget.ui \ src/ui/QGCCommConfiguration.ui \ - src/ui/QGCDataPlot2D.ui \ src/ui/QGCLinkConfiguration.ui \ src/ui/QGCMapRCToParamDialog.ui \ src/ui/QGCMAVLinkLogPlayer.ui \ @@ -185,7 +183,9 @@ FORMS += \ !MobileBuild { FORMS += \ + src/ui/Linechart.ui \ src/ui/MultiVehicleDockWidget.ui \ + src/ui/QGCDataPlot2D.ui \ src/ui/QGCHilConfiguration.ui \ src/ui/QGCHilFlightGearConfiguration.ui \ src/ui/QGCHilJSBSimConfiguration.ui \ @@ -252,19 +252,11 @@ HEADERS += \ src/uas/UAS.h \ src/uas/UASInterface.h \ src/uas/UASMessageHandler.h \ - src/ui/linechart/ChartPlot.h \ - src/ui/linechart/IncrementalPlot.h \ - src/ui/linechart/LinechartPlot.h \ - src/ui/linechart/Linecharts.h \ - src/ui/linechart/LinechartWidget.h \ - src/ui/linechart/Scrollbar.h \ - src/ui/linechart/ScrollZoomer.h \ src/ui/LogReplayLinkConfigurationWidget.h \ src/ui/MainWindow.h \ src/ui/MAVLinkDecoder.h \ src/ui/MAVLinkSettingsWidget.h \ src/ui/QGCCommConfiguration.h \ - src/ui/QGCDataPlot2D.h \ src/ui/QGCLinkConfiguration.h \ src/ui/QGCMapRCToParamDialog.h \ src/ui/QGCMAVLinkLogPlayer.h \ @@ -292,7 +284,15 @@ HEADERS += \ src/comm/QGCXPlaneLink.h \ src/ui/CameraView.h \ src/ui/HILDockWidget.h \ + src/ui/linechart/ChartPlot.h \ + src/ui/linechart/IncrementalPlot.h \ + src/ui/linechart/LinechartPlot.h \ + src/ui/linechart/Linecharts.h \ + src/ui/linechart/LinechartWidget.h \ + src/ui/linechart/Scrollbar.h \ + src/ui/linechart/ScrollZoomer.h \ src/ui/MultiVehicleDockWidget.h \ + src/ui/QGCDataPlot2D.h \ src/ui/QGCHilConfiguration.h \ src/ui/QGCHilFlightGearConfiguration.h \ src/ui/QGCHilJSBSimConfiguration.h \ @@ -357,19 +357,11 @@ SOURCES += \ src/uas/FileManager.cc \ src/uas/UAS.cc \ src/uas/UASMessageHandler.cc \ - src/ui/linechart/ChartPlot.cc \ - src/ui/linechart/IncrementalPlot.cc \ - src/ui/linechart/LinechartPlot.cc \ - src/ui/linechart/Linecharts.cc \ - src/ui/linechart/LinechartWidget.cc \ - src/ui/linechart/Scrollbar.cc \ - src/ui/linechart/ScrollZoomer.cc \ src/ui/LogReplayLinkConfigurationWidget.cc \ src/ui/MainWindow.cc \ src/ui/MAVLinkDecoder.cc \ src/ui/MAVLinkSettingsWidget.cc \ src/ui/QGCCommConfiguration.cc \ - src/ui/QGCDataPlot2D.cc \ src/ui/QGCLinkConfiguration.cc \ src/ui/QGCMapRCToParamDialog.cpp \ src/ui/QGCMAVLinkLogPlayer.cc \ @@ -396,7 +388,15 @@ SOURCES += \ src/comm/QGCXPlaneLink.cc \ src/ui/CameraView.cc \ src/ui/HILDockWidget.cc \ + src/ui/linechart/ChartPlot.cc \ + src/ui/linechart/IncrementalPlot.cc \ + src/ui/linechart/LinechartPlot.cc \ + src/ui/linechart/Linecharts.cc \ + src/ui/linechart/LinechartWidget.cc \ + src/ui/linechart/Scrollbar.cc \ + src/ui/linechart/ScrollZoomer.cc \ src/ui/MultiVehicleDockWidget.cc \ + src/ui/QGCDataPlot2D.cc \ src/ui/QGCHilConfiguration.cc \ src/ui/QGCHilFlightGearConfiguration.cc \ src/ui/QGCHilJSBSimConfiguration.cc \ diff --git a/qgroundcontrol.desktop b/qgroundcontrol.desktop deleted file mode 100644 index 9f815f8e1edc32205ca0dc8429613e0b90d37bf6..0000000000000000000000000000000000000000 --- a/qgroundcontrol.desktop +++ /dev/null @@ -1,10 +0,0 @@ -[Desktop Entry] -Type=Application -Name=qgroundcontrol -GenericName=Ground Control Station -Comment=UAS ground control station -Icon=qgroundcontrol -Exec=qgroundcontrol -Terminal=false -Categories=Utility; -Keywords=computer; diff --git a/src/qgcunittest/MainWindowTest.cc b/src/qgcunittest/MainWindowTest.cc index c0c233e431229c2b11757420583ae04c08d9d17c..94ce67ce15509e3b70d688f51d82f9f23be57e62 100644 --- a/src/qgcunittest/MainWindowTest.cc +++ b/src/qgcunittest/MainWindowTest.cc @@ -84,8 +84,6 @@ void MainWindowTest::_connectWindowClose_test(MAV_AUTOPILOT autopilot) QTest::qWait(200); _mainToolBar->onFlyView(); QTest::qWait(200); - _mainToolBar->onAnalyzeView(); - QTest::qWait(200); // On MainWindow close we should get a message box telling the user to disconnect first. Cancel should do nothing. setExpectedMessageBox(QGCMessageBox::Cancel); diff --git a/src/ui/MainWindow.cc b/src/ui/MainWindow.cc index 0a7fd1ad73d4d6ccfd85bdc33282476a64d9ea04..04e8938ea2fe9f8d06722e8f9bb217f5481c2e88 100644 --- a/src/ui/MainWindow.cc +++ b/src/ui/MainWindow.cc @@ -46,8 +46,6 @@ This file is part of the QGROUNDCONTROL project #include "QGCMAVLinkLogPlayer.h" #include "SettingsDialog.h" #include "MAVLinkDecoder.h" -#include "QGCDataPlot2D.h" -#include "Linecharts.h" #include "FlightDisplayView.h" #include "SetupView.h" #include "QGCApplication.h" @@ -60,6 +58,8 @@ This file is part of the QGROUNDCONTROL project #include "UAS.h" #ifndef __mobile__ +#include "QGCDataPlot2D.h" +#include "Linecharts.h" #include "QGCUASFileViewMulti.h" #include "UASQuickView.h" #include "QGCTabbedInfoView.h" @@ -95,6 +95,7 @@ const char* MainWindow::_uasStatusDetailsDockWidgetName = "Status Details"; const char* MainWindow::_pfdDockWidgetName = "Primary Flight Display"; const char* MainWindow::_uasInfoViewDockWidgetName = "Info View"; const char* MainWindow::_hilDockWidgetName = "HIL Config"; +const char* MainWindow::_analyzeDockWidgetName = "Analyze"; const char* MainWindow::_visibleWidgetsKey = "VisibleWidgets"; #endif @@ -277,13 +278,11 @@ MainWindow::MainWindow(QSplashScreen* splashScreen) _ui.actionSetup->setShortcut(QApplication::translate("MainWindow", "Meta+1", 0)); _ui.actionPlan->setShortcut(QApplication::translate("MainWindow", "Meta+2", 0)); _ui.actionFlight->setShortcut(QApplication::translate("MainWindow", "Meta+3", 0)); - _ui.actionAnalyze->setShortcut(QApplication::translate("MainWindow", "Meta+4", 0)); _ui.actionFullscreen->setShortcut(QApplication::translate("MainWindow", "Meta+Return", 0)); #else _ui.actionSetup->setShortcut(QApplication::translate("MainWindow", "Ctrl+1", 0)); _ui.actionPlan->setShortcut(QApplication::translate("MainWindow", "Ctrl+2", 0)); _ui.actionFlight->setShortcut(QApplication::translate("MainWindow", "Ctrl+3", 0)); - _ui.actionAnalyze->setShortcut(QApplication::translate("MainWindow", "Ctrl+4", 0)); _ui.actionFullscreen->setShortcut(QApplication::translate("MainWindow", "Ctrl+Return", 0)); #endif @@ -367,6 +366,7 @@ void MainWindow::_buildCommonWidgets(void) _pfdDockWidgetName, _uasInfoViewDockWidgetName, _hilDockWidgetName, + _analyzeDockWidgetName, }; static const size_t cDockWidgetNames = sizeof(rgDockWidgetNames) / sizeof(rgDockWidgetNames[0]); @@ -419,6 +419,8 @@ void MainWindow::_createInnerDockWidget(const QString& widgetName) widget = new FlightDisplayWidget(widgetName, _mapName2Action[widgetName], this); } else if (widgetName == _hilDockWidgetName) { widget = new HILDockWidget(widgetName, _mapName2Action[widgetName], this); + } else if (widgetName == _analyzeDockWidgetName) { + widget = new Linecharts(widgetName, _mapName2Action[widgetName], mavlinkDecoder, this); } else if (widgetName == _uasInfoViewDockWidgetName) { QGCTabbedInfoView* pInfoView = new QGCTabbedInfoView(widgetName, _mapName2Action[widgetName], this); pInfoView->addSource(mavlinkDecoder); @@ -469,14 +471,6 @@ void MainWindow::_buildSetupView(void) } } -void MainWindow::_buildAnalyzeView(void) -{ - if (!_analyzeView) { - _analyzeView = new QGCDataPlot2D(this); - _analyzeView->setVisible(false); - } -} - void MainWindow::fullScreenActionItemCallback(bool) { _ui.actionNormal->setChecked(false); @@ -589,18 +583,10 @@ void MainWindow::connectCommonActions() { // Bind together the perspective actions QActionGroup* perspectives = new QActionGroup(_ui.menuPerspectives); - perspectives->addAction(_ui.actionAnalyze); - perspectives->addAction(_ui.actionFlight); perspectives->addAction(_ui.actionPlan); perspectives->addAction(_ui.actionSetup); perspectives->setExclusive(true); - // Mark the right one as selected - if (_currentView == VIEW_ANALYZE) - { - _ui.actionAnalyze->setChecked(true); - _ui.actionAnalyze->activate(QAction::Trigger); - } if (_currentView == VIEW_FLIGHT) { _ui.actionFlight->setChecked(true); @@ -625,7 +611,6 @@ void MainWindow::connectCommonActions() // Views actions connect(_ui.actionFlight, SIGNAL(triggered()), this, SLOT(loadFlightView())); - connect(_ui.actionAnalyze, SIGNAL(triggered()), this, SLOT(loadAnalyzeView())); connect(_ui.actionPlan, SIGNAL(triggered()), this, SLOT(loadPlanView())); // Help Actions @@ -695,18 +680,6 @@ void MainWindow::commsWidgetDestroyed(QObject *obj) void MainWindow::_vehicleAdded(Vehicle* vehicle) { connect(vehicle->uas(), SIGNAL(valueChanged(int,QString,QString,QVariant,quint64)), this, SIGNAL(valueChanged(int,QString,QString,QVariant,quint64))); - - if (!linechartWidget) - { - linechartWidget = new Linecharts(this); - linechartWidget->setVisible(false); - } - - linechartWidget->addSource(mavlinkDecoder); - if (_analyzeView != linechartWidget) - { - _analyzeView = linechartWidget; - } } /// Stores the state of the toolbar, status bar and widgets associated with the current view @@ -733,11 +706,6 @@ void MainWindow::_loadCurrentViewState(void) centerView = _setupView; break; - case VIEW_ANALYZE: - _buildAnalyzeView(); - centerView = _analyzeView; - break; - case VIEW_FLIGHT: _buildFlightView(); centerView = _flightView; @@ -779,17 +747,6 @@ void MainWindow::_loadCurrentViewState(void) emit repaintCanvas(); } -void MainWindow::loadAnalyzeView() -{ - if (_currentView != VIEW_ANALYZE) - { - _storeCurrentViewState(); - _currentView = VIEW_ANALYZE; - _ui.actionAnalyze->setChecked(true); - _loadCurrentViewState(); - } -} - void MainWindow::loadPlanView() { if (_currentView != VIEW_MISSIONEDITOR) diff --git a/src/ui/MainWindow.h b/src/ui/MainWindow.h index 0261b56b13a8611e8e28d65b9cf05a61119af136..9f818257596a2945450e47917bf332d845053d06 100644 --- a/src/ui/MainWindow.h +++ b/src/ui/MainWindow.h @@ -56,7 +56,6 @@ This file is part of the QGROUNDCONTROL project #endif // QGC_MOUSE_ENABLED_WIN -class QGCFirmwareUpdate; class QSplashScreen; class QGCStatusBar; class Linecharts; @@ -122,7 +121,6 @@ public slots: void loadSetupView(); void loadFlightView(); - void loadAnalyzeView(); void loadPlanView(); void manageLinks(); @@ -187,7 +185,7 @@ protected: typedef enum _VIEW_SECTIONS { - VIEW_ANALYZE, // Engineering/Analyze view mode. Used for analyzing data and modifying onboard parameters + VIEW_UNUSED5, // Unused (don't remove, or it will screw up saved settigns indices) VIEW_UNUSED3, // Unused (don't remove, or it will screw up saved settigns indices) VIEW_FLIGHT, // Flight/Fly/Operate view mode. Used for 1st-person observation of the vehicle. VIEW_UNUSED4, // Unused (don't remove, or it will screw up saved settigns indices) @@ -205,7 +203,6 @@ protected: void loadSettings(); void storeSettings(); - QSettings settings; // Center widgets @@ -263,7 +260,6 @@ private: QPointer _planView; QPointer _flightView; QPointer _setupView; - QPointer _analyzeView; QPointer _missionEditorView; #ifndef __mobile__ @@ -275,6 +271,7 @@ private: static const char* _pfdDockWidgetName; static const char* _uasInfoViewDockWidgetName; static const char* _hilDockWidgetName; + static const char* _analyzeDockWidgetName; QMap _mapName2DockWidget; QMap _mapName2Action; @@ -283,7 +280,6 @@ private: void _buildPlanView(void); void _buildFlightView(void); void _buildSetupView(void); - void _buildAnalyzeView(void); void _buildTerminalView(void); void _buildMissionEditorView(void); diff --git a/src/ui/MainWindow.ui b/src/ui/MainWindow.ui index 7ef494381eec26dab92eb91080afb8742fa27bcf..c4d0880d4763ff35119ca1d42def0b89cded88a6 100644 --- a/src/ui/MainWindow.ui +++ b/src/ui/MainWindow.ui @@ -80,7 +80,6 @@ - @@ -134,14 +133,6 @@ Plan - - - true - - - Analyze - - true @@ -237,9 +228,7 @@ - - - + actionExit diff --git a/src/ui/MultiVehicleDockWidget.cc b/src/ui/MultiVehicleDockWidget.cc index 3f5e82fbcc07454cd3f5dde3d29e69714f693a5b..4c5d812ba65a466492461068fdc564e79e106348 100644 --- a/src/ui/MultiVehicleDockWidget.cc +++ b/src/ui/MultiVehicleDockWidget.cc @@ -40,8 +40,11 @@ MultiVehicleDockWidget::MultiVehicleDockWidget(const QString& title, QAction* ac void MultiVehicleDockWidget::init(void) { + foreach (Vehicle* vehicle, MultiVehicleManager::instance()->vehicles()) { + _vehicleAdded(vehicle); + } + if (MultiVehicleManager::instance()->activeVehicle()) { - _vehicleAdded(MultiVehicleManager::instance()->activeVehicle()); _activeVehicleChanged(MultiVehicleManager::instance()->activeVehicle()); } } diff --git a/src/ui/linechart/Linecharts.cc b/src/ui/linechart/Linecharts.cc index 9b8dc33d8f646955c24dd7064193e5d0b11e42c6..f94fd88037daa5fded3de0be6cab4f7a5e22cf2b 100644 --- a/src/ui/linechart/Linecharts.cc +++ b/src/ui/linechart/Linecharts.cc @@ -5,99 +5,27 @@ #include "MainWindow.h" #include "UAS.h" -Linecharts::Linecharts(QWidget *parent) : - QStackedWidget(parent), - plots(), - active(true) +Linecharts::Linecharts(const QString& title, QAction* action, MAVLinkDecoder* decoder, QWidget *parent) + : MultiVehicleDockWidget(title, action, parent) + , _mavlinkDecoder(decoder) { - this->setVisible(false); - - // Add each MAV - foreach (Vehicle* vehicle, MultiVehicleManager::instance()->vehicles()) { - addVehicle(vehicle); - } - connect(MultiVehicleManager::instance(), &MultiVehicleManager::vehicleAdded, this, &Linecharts::addVehicle); -} + init(); -void Linecharts::showEvent(QShowEvent* event) -{ - // React only to internal (pre-display) - // events - Q_UNUSED(event) - QWidget* prevWidget = currentWidget(); - if (prevWidget) - { - LinechartWidget* chart = dynamic_cast(prevWidget); - if (chart) { - this->active = true; - chart->setActive(true); - } - } - QWidget::showEvent(event); - emit visibilityChanged(true); + this->setVisible(false); } -void Linecharts::hideEvent(QHideEvent* event) +QWidget* Linecharts::_newVehicleWidget(Vehicle* vehicle, QWidget* parent) { - // React only to internal (pre-display) - // events - Q_UNUSED(event) - QWidget* prevWidget = currentWidget(); - if (prevWidget) { - LinechartWidget* chart = dynamic_cast(prevWidget); - if (chart) { - this->active = false; - chart->setActive(false); - } - } - QWidget::hideEvent(event); - emit visibilityChanged(false); -} + LinechartWidget* widget = new LinechartWidget(vehicle->id(), parent); -void Linecharts::addVehicle(Vehicle* vehicle) -{ - UAS* uas = vehicle->uas(); - - // FIXME Add removeSystem() call + // Connect valueChanged signals + connect(vehicle->uas(), &UAS::valueChanged, widget, &LinechartWidget::appendData); - // Compatibility hack - int uasid = 0; /*uas->getUASID()*/ - if (!plots.contains(uasid)) - { - LinechartWidget* widget = new LinechartWidget(uasid, this); - addWidget(widget); - plots.insert(uasid, widget); - - // Connect valueChanged signals - connect(uas, SIGNAL(valueChanged(int,QString,QString,QVariant,quint64)), widget, SLOT(appendData(int,QString,QString,QVariant,quint64))); + // Connect decoder + connect(_mavlinkDecoder, &MAVLinkDecoder::valueChanged, widget, &LinechartWidget::appendData); - connect(widget, SIGNAL(logfileWritten(QString)), this, SIGNAL(logfileWritten(QString))); - // Set system active if this is the only system -// if (active) -// { -// if (plots.size() == 1) -// { - // FIXME XXX HACK - // Connect generic sources - for (int i = 0; i < genericSources.count(); ++i) - { - connect(genericSources[i], SIGNAL(valueChanged(int,QString,QString,QVariant,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,QVariant,quint64))); - } - // Select system - widget->setActive(true); - //widget->selectActiveSystem(0); - } -// } -// } -} + // Select system + widget->setActive(true); -void Linecharts::addSource(QObject* obj) -{ - genericSources.append(obj); - // FIXME XXX HACK - if (plots.size() > 0) - { - // Connect generic source - connect(obj, SIGNAL(valueChanged(int,QString,QString,QVariant,quint64)), plots.values().first(), SLOT(appendData(int,QString,QString,QVariant,quint64))); - } + return widget; } diff --git a/src/ui/linechart/Linecharts.h b/src/ui/linechart/Linecharts.h index dfa608994ebc75afbd8d62e977be40ce367c7082..198667118c8191832412ee710d5e0876ca6064d6 100644 --- a/src/ui/linechart/Linecharts.h +++ b/src/ui/linechart/Linecharts.h @@ -7,34 +7,26 @@ #include "LinechartWidget.h" #include "Vehicle.h" +#include "MultiVehicleDockWidget.h" +#include "MAVLinkDecoder.h" -class Linecharts : public QStackedWidget +class Linecharts : public MultiVehicleDockWidget { Q_OBJECT public: - explicit Linecharts(QWidget *parent = 0); + explicit Linecharts(const QString& title, QAction* action, MAVLinkDecoder* decoder, QWidget *parent = 0); signals: /** @brief This signal is emitted once a logfile has been finished writing */ void logfileWritten(QString fileName); void visibilityChanged(bool visible); -public slots: - /** @brief Add a new system to the list of plots */ - void addVehicle(Vehicle* vehicle); - /** @brief Add a new generic message source (not a system) */ - void addSource(QObject* obj); - protected: + // Override from MultiVehicleDockWidget + virtual QWidget* _newVehicleWidget(Vehicle* vehicle, QWidget* parent); - QMap plots; - QVector genericSources; - bool active; - /** @brief Start updating widget */ - void showEvent(QShowEvent* event); - /** @brief Stop updating widget */ - void hideEvent(QHideEvent* event); - +private: + MAVLinkDecoder* _mavlinkDecoder; }; #endif // LINECHARTS_H diff --git a/src/ui/toolbar/MainToolBar.cc b/src/ui/toolbar/MainToolBar.cc index b997d1ad7e222875e5f9e1cecc6ef64709b42a6d..52a640cce2a3faa6e5fd2f3b0244ec9eeac65b82 100644 --- a/src/ui/toolbar/MainToolBar.cc +++ b/src/ui/toolbar/MainToolBar.cc @@ -161,12 +161,6 @@ void MainToolBar::onFlyViewMenu() } } -void MainToolBar::onAnalyzeView() -{ - setCurrentView(MainWindow::VIEW_ANALYZE); - MainWindow::instance()->loadAnalyzeView(); -} - void MainToolBar::onDisconnect(QString conf) { if(conf.isEmpty()) { @@ -248,9 +242,6 @@ void MainToolBar::setCurrentView(int currentView) { ViewType_t view = ViewNone; switch((MainWindow::VIEW_SECTIONS)currentView) { - case MainWindow::VIEW_ANALYZE: - view = ViewAnalyze; - break; case MainWindow::VIEW_MISSIONEDITOR: view = ViewPlan; break; @@ -441,4 +432,4 @@ void MainToolBar::onToolBarMessageClosed(void) { _toolbarMessageVisible = false; _delayedShowToolBarMessage(); -} \ No newline at end of file +} diff --git a/src/ui/toolbar/MainToolBar.h b/src/ui/toolbar/MainToolBar.h index 44e0dbfe22f6fb5d5f01fe7ef85fc2a51a4e4a95..63e800c592ac51facf245b25d880758e3e47ba51 100644 --- a/src/ui/toolbar/MainToolBar.h +++ b/src/ui/toolbar/MainToolBar.h @@ -64,7 +64,6 @@ public: Q_INVOKABLE void onPlanView(); Q_INVOKABLE void onFlyView(); Q_INVOKABLE void onFlyViewMenu(); - Q_INVOKABLE void onAnalyzeView(); Q_INVOKABLE void onConnect(QString conf); Q_INVOKABLE void onDisconnect(QString conf); Q_INVOKABLE void onEnterMessageArea(int x, int y); diff --git a/src/ui/toolbar/MainToolBar.qml b/src/ui/toolbar/MainToolBar.qml index 2d55ed7452f010eda761658c94e0112b17f0159f..560d3501d8de09becdc432486f254bbea4af4ed2 100644 --- a/src/ui/toolbar/MainToolBar.qml +++ b/src/ui/toolbar/MainToolBar.qml @@ -626,7 +626,6 @@ Rectangle { setupButton.repaintChevron = true; planButton.repaintChevron = true; flyButton.repaintChevron = true; - analyzeButton.repaintChevron = true; } } @@ -670,19 +669,6 @@ Rectangle { } z: 800 } - - QGCToolBarButton { - id: analyzeButton - width: getProportionalDimmension(90) - height: cellHeight - exclusiveGroup: mainActionGroup - text: qsTr("Analyze") - checked: (mainToolBar.currentView === MainToolBar.ViewAnalyze) - onClicked: { - mainToolBar.onAnalyzeView(); - } - z: 700 - } } // Row //---------------------------------------------------------------------