20 changed files with 625 additions and 254 deletions
@ -0,0 +1,70 @@ |
|||||||
|
/**************************************************************************** |
||||||
|
* |
||||||
|
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org> |
||||||
|
* |
||||||
|
* QGroundControl is licensed according to the terms in the file |
||||||
|
* COPYING.md in the root of the source code directory. |
||||||
|
* |
||||||
|
****************************************************************************/ |
||||||
|
|
||||||
|
import QtQuick 2.5 |
||||||
|
import QtQuick.Controls 1.2 |
||||||
|
|
||||||
|
import QGroundControl 1.0 |
||||||
|
import QGroundControl.Palette 1.0 |
||||||
|
import QGroundControl.Controls 1.0 |
||||||
|
import QGroundControl.ScreenTools 1.0 |
||||||
|
|
||||||
|
/// Base view control for all Analyze pages |
||||||
|
QGCView { |
||||||
|
id: analyePage |
||||||
|
viewPanel: analyzePanel |
||||||
|
|
||||||
|
property alias pageComponent: pageLoader.sourceComponent |
||||||
|
property alias pageName: pageNameLabel.text |
||||||
|
property alias pageDescription: pageDescriptionLabel.text |
||||||
|
property real availableWidth: width - pageLoader.x |
||||||
|
property real availableHeight: height - pageLoader.y |
||||||
|
|
||||||
|
property real _margins: ScreenTools.defaultFontPixelHeight / 2 |
||||||
|
|
||||||
|
QGCPalette { id: qgcPal; colorGroupEnabled: analyzePanel.enabled } |
||||||
|
|
||||||
|
QGCViewPanel { |
||||||
|
id: analyzePanel |
||||||
|
anchors.fill: parent |
||||||
|
|
||||||
|
QGCFlickable { |
||||||
|
anchors.fill: parent |
||||||
|
contentWidth: pageLoader.x + pageLoader.item.width |
||||||
|
contentHeight: pageLoader.y + pageLoader.item.height |
||||||
|
clip: true |
||||||
|
|
||||||
|
Column { |
||||||
|
id: headingColumn |
||||||
|
width: analyzePanel.width |
||||||
|
spacing: _margins |
||||||
|
|
||||||
|
QGCLabel { |
||||||
|
id: pageNameLabel |
||||||
|
font.pointSize: ScreenTools.largeFontPointSize |
||||||
|
visible: !ScreenTools.isShortScreen |
||||||
|
} |
||||||
|
|
||||||
|
QGCLabel { |
||||||
|
id: pageDescriptionLabel |
||||||
|
anchors.left: parent.left |
||||||
|
anchors.right: parent.right |
||||||
|
wrapMode: Text.WordWrap |
||||||
|
visible: !ScreenTools.isShortScreen |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Loader { |
||||||
|
id: pageLoader |
||||||
|
anchors.topMargin: _margins |
||||||
|
anchors.top: headingColumn.bottom |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,126 @@ |
|||||||
|
/**************************************************************************** |
||||||
|
* |
||||||
|
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org> |
||||||
|
* |
||||||
|
* QGroundControl is licensed according to the terms in the file |
||||||
|
* COPYING.md in the root of the source code directory. |
||||||
|
* |
||||||
|
****************************************************************************/ |
||||||
|
|
||||||
|
|
||||||
|
/// @file |
||||||
|
/// @brief Setup View |
||||||
|
/// @author Don Gagne <don@thegagnes.com> |
||||||
|
|
||||||
|
import QtQuick 2.3 |
||||||
|
import QtQuick.Controls 1.2 |
||||||
|
|
||||||
|
import QGroundControl 1.0 |
||||||
|
import QGroundControl.Palette 1.0 |
||||||
|
import QGroundControl.Controls 1.0 |
||||||
|
import QGroundControl.ScreenTools 1.0 |
||||||
|
|
||||||
|
Rectangle { |
||||||
|
id: setupView |
||||||
|
color: qgcPal.window |
||||||
|
z: QGroundControl.zOrderTopMost |
||||||
|
|
||||||
|
QGCPalette { id: qgcPal; colorGroupEnabled: true } |
||||||
|
|
||||||
|
ExclusiveGroup { id: setupButtonGroup } |
||||||
|
|
||||||
|
readonly property real _defaultTextHeight: ScreenTools.defaultFontPixelHeight |
||||||
|
readonly property real _defaultTextWidth: ScreenTools.defaultFontPixelWidth |
||||||
|
readonly property real _horizontalMargin: _defaultTextWidth / 2 |
||||||
|
readonly property real _verticalMargin: _defaultTextHeight / 2 |
||||||
|
readonly property real _buttonWidth: _defaultTextWidth * 18 |
||||||
|
|
||||||
|
function showGeoTagPanel() { |
||||||
|
panelLoader.source = "GeoTagPage.qml" |
||||||
|
} |
||||||
|
|
||||||
|
Component.onCompleted: showGeoTagPanel() |
||||||
|
|
||||||
|
QGCFlickable { |
||||||
|
id: buttonScroll |
||||||
|
width: buttonColumn.width |
||||||
|
anchors.topMargin: _defaultTextHeight / 2 |
||||||
|
anchors.top: parent.top |
||||||
|
anchors.bottom: parent.bottom |
||||||
|
anchors.leftMargin: _horizontalMargin |
||||||
|
anchors.left: parent.left |
||||||
|
contentHeight: buttonColumn.height |
||||||
|
flickableDirection: Flickable.VerticalFlick |
||||||
|
clip: true |
||||||
|
|
||||||
|
Column { |
||||||
|
id: buttonColumn |
||||||
|
width: _maxButtonWidth |
||||||
|
spacing: _defaultTextHeight / 2 |
||||||
|
|
||||||
|
property real _maxButtonWidth: 0 |
||||||
|
|
||||||
|
Component.onCompleted: reflowWidths() |
||||||
|
|
||||||
|
// I don't know why this does not work |
||||||
|
Connections { |
||||||
|
target: QGroundControl |
||||||
|
onBaseFontPointSizeChanged: buttonColumn.reflowWidths() |
||||||
|
} |
||||||
|
|
||||||
|
function reflowWidths() { |
||||||
|
buttonColumn._maxButtonWidth = 0 |
||||||
|
for (var i = 0; i < children.length; i++) { |
||||||
|
buttonColumn._maxButtonWidth = Math.max(buttonColumn._maxButtonWidth, children[i].width) |
||||||
|
} |
||||||
|
for (var j = 0; j < children.length; j++) { |
||||||
|
children[j].width = buttonColumn._maxButtonWidth |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
QGCLabel { |
||||||
|
anchors.left: parent.left |
||||||
|
anchors.right: parent.right |
||||||
|
text: qsTr("Analyze") |
||||||
|
wrapMode: Text.WordWrap |
||||||
|
horizontalAlignment: Text.AlignHCenter |
||||||
|
visible: !ScreenTools.isShortScreen |
||||||
|
} |
||||||
|
|
||||||
|
SubMenuButton { |
||||||
|
id: summaryButton |
||||||
|
imageResource: "/qmlimages/GeoTagIcon.png" |
||||||
|
setupIndicator: false |
||||||
|
checked: true |
||||||
|
exclusiveGroup: setupButtonGroup |
||||||
|
text: "GeoTag Images" |
||||||
|
|
||||||
|
onClicked: showGeoTagPanel() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Rectangle { |
||||||
|
id: divider |
||||||
|
anchors.topMargin: _verticalMargin |
||||||
|
anchors.bottomMargin: _verticalMargin |
||||||
|
anchors.leftMargin: _horizontalMargin |
||||||
|
anchors.left: buttonScroll.right |
||||||
|
anchors.top: parent.top |
||||||
|
anchors.bottom: parent.bottom |
||||||
|
width: 1 |
||||||
|
color: qgcPal.windowShade |
||||||
|
} |
||||||
|
|
||||||
|
Loader { |
||||||
|
id: panelLoader |
||||||
|
anchors.topMargin: _verticalMargin |
||||||
|
anchors.bottomMargin: _verticalMargin |
||||||
|
anchors.leftMargin: _horizontalMargin |
||||||
|
anchors.rightMargin: _horizontalMargin |
||||||
|
anchors.left: divider.right |
||||||
|
anchors.right: parent.right |
||||||
|
anchors.top: parent.top |
||||||
|
anchors.bottom: parent.bottom |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,87 @@ |
|||||||
|
/****************************************************************************
|
||||||
|
* |
||||||
|
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
|
||||||
|
* |
||||||
|
* QGroundControl is licensed according to the terms in the file |
||||||
|
* COPYING.md in the root of the source code directory. |
||||||
|
* |
||||||
|
****************************************************************************/ |
||||||
|
|
||||||
|
#include "GeoTagController.h" |
||||||
|
#include "QGCFileDialog.h" |
||||||
|
|
||||||
|
GeoTagController::GeoTagController(void) |
||||||
|
: _progress(0) |
||||||
|
, _inProgress(false) |
||||||
|
{ |
||||||
|
connect(&_worker, &GeoTagWorker::progressChanged, this, &GeoTagController::_workerProgressChanged); |
||||||
|
connect(&_worker, &GeoTagWorker::error, this, &GeoTagController::_workerError); |
||||||
|
connect(&_worker, &GeoTagWorker::started, this, &GeoTagController::inProgressChanged); |
||||||
|
connect(&_worker, &GeoTagWorker::finished, this, &GeoTagController::inProgressChanged); |
||||||
|
} |
||||||
|
|
||||||
|
GeoTagController::~GeoTagController() |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
void GeoTagController::pickLogFile(void) |
||||||
|
{ |
||||||
|
QString filename = QGCFileDialog::getOpenFileName(NULL, "Select log file load", QString(), "PX4 log file (*.px4log);;All Files (*.*)"); |
||||||
|
if (!filename.isEmpty()) { |
||||||
|
_worker.setLogFile(filename); |
||||||
|
emit logFileChanged(filename); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void GeoTagController::pickImageDirectory(void) |
||||||
|
{ |
||||||
|
QString dir = QGCFileDialog::getExistingDirectory(NULL, "Select image directory"); |
||||||
|
if (!dir.isEmpty()) { |
||||||
|
_worker.setImageDirectory(dir); |
||||||
|
emit imageDirectoryChanged(dir); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void GeoTagController::startTagging(void) |
||||||
|
{ |
||||||
|
_errorMessage.clear(); |
||||||
|
emit errorMessageChanged(_errorMessage); |
||||||
|
_worker.start(); |
||||||
|
} |
||||||
|
|
||||||
|
void GeoTagController::_workerProgressChanged(double progress) |
||||||
|
{ |
||||||
|
_progress = progress; |
||||||
|
emit progressChanged(progress); |
||||||
|
} |
||||||
|
|
||||||
|
void GeoTagController::_workerError(QString errorMessage) |
||||||
|
{ |
||||||
|
_errorMessage = errorMessage; |
||||||
|
emit errorMessageChanged(errorMessage); |
||||||
|
} |
||||||
|
|
||||||
|
GeoTagWorker::GeoTagWorker(void) |
||||||
|
: _cancel(false) |
||||||
|
{ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
void GeoTagWorker::run(void) |
||||||
|
{ |
||||||
|
_cancel = false; |
||||||
|
emit progressChanged(0); |
||||||
|
|
||||||
|
for (int i=0; i<10;i++) { |
||||||
|
if (_cancel) { |
||||||
|
emit error(tr("Tagging cancelled")); |
||||||
|
return; |
||||||
|
} |
||||||
|
emit progressChanged(i*10); |
||||||
|
sleep(1); |
||||||
|
} |
||||||
|
|
||||||
|
emit progressChanged(100); |
||||||
|
emit taggingComplete(); |
||||||
|
} |
@ -0,0 +1,97 @@ |
|||||||
|
/****************************************************************************
|
||||||
|
* |
||||||
|
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
|
||||||
|
* |
||||||
|
* QGroundControl is licensed according to the terms in the file |
||||||
|
* COPYING.md in the root of the source code directory. |
||||||
|
* |
||||||
|
****************************************************************************/ |
||||||
|
|
||||||
|
#ifndef GeoTagController_H |
||||||
|
#define GeoTagController_H |
||||||
|
|
||||||
|
#include <QObject> |
||||||
|
#include <QString> |
||||||
|
#include <QThread> |
||||||
|
|
||||||
|
class GeoTagWorker : public QThread |
||||||
|
{ |
||||||
|
Q_OBJECT |
||||||
|
|
||||||
|
public: |
||||||
|
GeoTagWorker(void); |
||||||
|
|
||||||
|
QString logFile(void) const { return _logFile; } |
||||||
|
QString imageDirectory(void) const { return _imageDirectory; } |
||||||
|
|
||||||
|
void setLogFile(const QString& logFile) { _logFile = logFile; } |
||||||
|
void setImageDirectory(const QString& imageDirectory) { _imageDirectory = imageDirectory; } |
||||||
|
|
||||||
|
void cancellTagging(void) { _cancel = true; } |
||||||
|
|
||||||
|
protected: |
||||||
|
void run(void) final; |
||||||
|
|
||||||
|
signals: |
||||||
|
void error(QString errorMsg); |
||||||
|
void taggingComplete(void); |
||||||
|
void progressChanged(double progress); |
||||||
|
|
||||||
|
private: |
||||||
|
bool _cancel; |
||||||
|
QString _logFile; |
||||||
|
QString _imageDirectory; |
||||||
|
}; |
||||||
|
|
||||||
|
/// Controller for GeoTagPage.qml. Supports geotagging images based on logfile camera tags.
|
||||||
|
class GeoTagController : public QObject |
||||||
|
{ |
||||||
|
Q_OBJECT |
||||||
|
|
||||||
|
public: |
||||||
|
GeoTagController(void); |
||||||
|
~GeoTagController(); |
||||||
|
|
||||||
|
Q_PROPERTY(QString logFile READ logFile NOTIFY logFileChanged) |
||||||
|
Q_PROPERTY(QString imageDirectory READ imageDirectory NOTIFY imageDirectoryChanged) |
||||||
|
|
||||||
|
/// Set to an error message is geotagging fails
|
||||||
|
Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorMessageChanged) |
||||||
|
|
||||||
|
/// Progress indicator: 0-100
|
||||||
|
Q_PROPERTY(double progress READ progress NOTIFY progressChanged) |
||||||
|
|
||||||
|
/// true: Currently in the process of tagging
|
||||||
|
Q_PROPERTY(bool inProgress READ inProgress NOTIFY inProgressChanged) |
||||||
|
|
||||||
|
Q_INVOKABLE void pickLogFile(void); |
||||||
|
Q_INVOKABLE void pickImageDirectory(void); |
||||||
|
Q_INVOKABLE void startTagging(void); |
||||||
|
Q_INVOKABLE void cancelTagging(void) { _worker.cancellTagging(); } |
||||||
|
|
||||||
|
QString logFile (void) const { return _worker.logFile(); } |
||||||
|
QString imageDirectory (void) const { return _worker.imageDirectory(); } |
||||||
|
double progress (void) const { return _progress; } |
||||||
|
bool inProgress (void) const { return _worker.isRunning(); } |
||||||
|
QString errorMessage (void) const { return _errorMessage; } |
||||||
|
|
||||||
|
signals: |
||||||
|
void logFileChanged(QString logFile); |
||||||
|
void imageDirectoryChanged(QString imageDirectory); |
||||||
|
void progressChanged(double progress); |
||||||
|
void inProgressChanged(void); |
||||||
|
void errorMessageChanged(QString errorMessage); |
||||||
|
|
||||||
|
private slots: |
||||||
|
void _workerProgressChanged(double progress); |
||||||
|
void _workerError(QString errorMsg); |
||||||
|
|
||||||
|
private: |
||||||
|
QString _errorMessage; |
||||||
|
double _progress; |
||||||
|
bool _inProgress; |
||||||
|
|
||||||
|
GeoTagWorker _worker; |
||||||
|
}; |
||||||
|
|
||||||
|
#endif |
After Width: | Height: | Size: 502 B |
@ -0,0 +1,103 @@ |
|||||||
|
/**************************************************************************** |
||||||
|
* |
||||||
|
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org> |
||||||
|
* |
||||||
|
* QGroundControl is licensed according to the terms in the file |
||||||
|
* COPYING.md in the root of the source code directory. |
||||||
|
* |
||||||
|
****************************************************************************/ |
||||||
|
|
||||||
|
import QtQuick 2.5 |
||||||
|
import QtQuick.Controls 1.4 |
||||||
|
import QtQuick.Dialogs 1.2 |
||||||
|
|
||||||
|
import QGroundControl.Palette 1.0 |
||||||
|
import QGroundControl.Controls 1.0 |
||||||
|
import QGroundControl.ScreenTools 1.0 |
||||||
|
import QGroundControl.Controllers 1.0 |
||||||
|
|
||||||
|
AnalyzePage { |
||||||
|
id: geoTagPage |
||||||
|
pageComponent: pageComponent |
||||||
|
pageName: qsTr("GeoTag Images (WIP)") |
||||||
|
pageDescription: qsTr("GetTag Images is used to tag a set of images from a survey mission with gps coordinates. You must provide the binary log from the flight as well as the directory which contains the images to tag.") |
||||||
|
|
||||||
|
property real _margin: ScreenTools.defaultFontPixelWidth |
||||||
|
|
||||||
|
GeoTagController { |
||||||
|
id: controller |
||||||
|
} |
||||||
|
|
||||||
|
Component { |
||||||
|
id: pageComponent |
||||||
|
|
||||||
|
Column { |
||||||
|
id: mainColumn |
||||||
|
width: availableWidth |
||||||
|
spacing: _margin |
||||||
|
|
||||||
|
Row { |
||||||
|
spacing: _margin |
||||||
|
|
||||||
|
QGCLabel { |
||||||
|
text: "Log file:" |
||||||
|
} |
||||||
|
|
||||||
|
QGCLabel { |
||||||
|
text: controller.logFile |
||||||
|
} |
||||||
|
|
||||||
|
QGCButton { |
||||||
|
text: qsTr("Select log file") |
||||||
|
onClicked: controller.pickLogFile() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Row { |
||||||
|
spacing: _margin |
||||||
|
|
||||||
|
QGCLabel { |
||||||
|
text: "Image directory:" |
||||||
|
} |
||||||
|
|
||||||
|
QGCLabel { |
||||||
|
text: controller.imageDirectory |
||||||
|
} |
||||||
|
|
||||||
|
QGCButton { |
||||||
|
text: qsTr("Select image directory") |
||||||
|
onClicked: controller.pickImageDirectory() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
QGCLabel { text: "NYI - Simulated only" } |
||||||
|
|
||||||
|
QGCButton { |
||||||
|
text: controller.inProgress ? qsTr("Cancel Tagging") : qsTr("Start Tagging") |
||||||
|
|
||||||
|
onClicked: { |
||||||
|
if (controller.inProgress) { |
||||||
|
controller.cancelTagging() |
||||||
|
} else { |
||||||
|
if (controller.logFile == "" || controller.imageDirectory == "") { |
||||||
|
geoTagPage.showMessage(qsTr("Error"), qsTr("You must select a log file and image directory before you can start tagging."), StandardButton.Ok) |
||||||
|
return |
||||||
|
} |
||||||
|
controller.startTagging() |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
QGCLabel { |
||||||
|
text: controller.errorMessage |
||||||
|
} |
||||||
|
|
||||||
|
ProgressBar { |
||||||
|
anchors.left: parent.left |
||||||
|
anchors.right: parent.right |
||||||
|
maximumValue: 100 |
||||||
|
value: controller.progress |
||||||
|
} |
||||||
|
} // Column |
||||||
|
} // Component |
||||||
|
} // AnalyzePage |
@ -1,52 +0,0 @@ |
|||||||
/****************************************************************************
|
|
||||||
* |
|
||||||
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
|
|
||||||
* |
|
||||||
* QGroundControl is licensed according to the terms in the file |
|
||||||
* COPYING.md in the root of the source code directory. |
|
||||||
* |
|
||||||
****************************************************************************/ |
|
||||||
|
|
||||||
|
|
||||||
/// @file
|
|
||||||
/// @author Don Gagne <don@thegagnes.com>
|
|
||||||
|
|
||||||
#include "SetupViewTest.h" |
|
||||||
#include "MockLink.h" |
|
||||||
#include "MultiVehicleManager.h" |
|
||||||
#include "QGCApplication.h" |
|
||||||
|
|
||||||
void SetupViewTest::_clickThrough_test(void) |
|
||||||
{
|
|
||||||
_createMainWindow(); |
|
||||||
_connectMockLink(); |
|
||||||
|
|
||||||
AutoPilotPlugin* autopilot = qgcApp()->toolbox()->multiVehicleManager()->activeVehicle()->autopilotPlugin(); |
|
||||||
Q_ASSERT(autopilot); |
|
||||||
|
|
||||||
// Switch to the Setup view
|
|
||||||
qgcApp()->showSetupView(); |
|
||||||
QTest::qWait(1000); |
|
||||||
|
|
||||||
// Click through fixed buttons
|
|
||||||
qDebug() << "Showing firmware"; |
|
||||||
qgcApp()->_showSetupFirmware(); |
|
||||||
QTest::qWait(1000); |
|
||||||
qDebug() << "Showing parameters"; |
|
||||||
qgcApp()->_showSetupParameters(); |
|
||||||
QTest::qWait(1000); |
|
||||||
qDebug() << "Showing summary"; |
|
||||||
qgcApp()->_showSetupSummary(); |
|
||||||
QTest::qWait(1000); |
|
||||||
|
|
||||||
const QVariantList& components = autopilot->vehicleComponents(); |
|
||||||
foreach(QVariant varComponent, components) { |
|
||||||
VehicleComponent* component = qobject_cast<VehicleComponent*>(qvariant_cast<QObject *>(varComponent)); |
|
||||||
qDebug() << "Showing" << component->name(); |
|
||||||
qgcApp()->_showSetupVehicleComponent(component); |
|
||||||
QTest::qWait(1000); |
|
||||||
} |
|
||||||
|
|
||||||
_disconnectMockLink(); |
|
||||||
_closeMainWindow(); |
|
||||||
} |
|
@ -1,29 +0,0 @@ |
|||||||
/****************************************************************************
|
|
||||||
* |
|
||||||
* (c) 2009-2016 QGROUNDCONTROL PROJECT <http://www.qgroundcontrol.org>
|
|
||||||
* |
|
||||||
* QGroundControl is licensed according to the terms in the file |
|
||||||
* COPYING.md in the root of the source code directory. |
|
||||||
* |
|
||||||
****************************************************************************/ |
|
||||||
|
|
||||||
|
|
||||||
/// @file
|
|
||||||
/// @author Don Gagne <don@thegagnes.com>
|
|
||||||
|
|
||||||
#ifndef SetupViewTest_H |
|
||||||
#define SetupViewTest_H |
|
||||||
|
|
||||||
#include "UnitTest.h" |
|
||||||
#include "MainWindow.h" |
|
||||||
|
|
||||||
/// Click through test for Setup View buttons
|
|
||||||
class SetupViewTest : public UnitTest |
|
||||||
{ |
|
||||||
Q_OBJECT |
|
||||||
|
|
||||||
private slots: |
|
||||||
void _clickThrough_test(void); |
|
||||||
}; |
|
||||||
|
|
||||||
#endif |
|
Loading…
Reference in new issue