Newer
Older
lm
committed
#include "QGCToolWidget.h"
#include "ui_QGCToolWidget.h"
#include <QMenu>
#include <QList>
#include <QInputDialog>
#include <QDockWidget>
#include <QContextMenuEvent>
Bryant Mairs
committed
#include <QStandardPaths>
lm
committed
#include "QGCParamSlider.h"
Michael Carpenter
committed
#include "QGCComboBox.h"
Michael Carpenter
committed
#include "QGCTextLabel.h"
lm
committed
#include "UASManager.h"
John Tapsell
committed
QGCToolWidget::QGCToolWidget(const QString& objectName, const QString& title, QWidget *parent, QSettings* settings) :
QWidget(parent),
mav(NULL),
mainMenuAction(NULL),
widgetTitle(title),
lm
committed
{
Michael Carpenter
committed
isFromMetaData = false;
ui->setupUi(this);
if (settings) loadSettings(*settings);
lm
committed
createActions();
lm
committed
toolLayout->setAlignment(Qt::AlignTop);
lm
committed
toolLayout->setSpacing(8);
lm
committed
this->setTitle(widgetTitle);
lm
committed
QList<UASInterface*> systems = UASManager::instance()->getUASList();
foreach (UASInterface* uas, systems)
{
lm
committed
UAS* newMav = dynamic_cast<UAS*>(uas);
lm
committed
addUAS(uas);
}
}
connect(UASManager::instance(), SIGNAL(UASCreated(UASInterface*)), this, SLOT(addUAS(UASInterface*)));
John Tapsell
committed
if(!objectName.isEmpty()) {
instances()->insert(objectName, this);
setObjectName(objectName);
} //Otherwise we must call loadSettings() immediately to set the object name
lm
committed
}
QGCToolWidget::~QGCToolWidget()
{
if (mainMenuAction) mainMenuAction->deleteLater();
John Tapsell
committed
if (QGCToolWidget::instances()) QGCToolWidget::instances()->remove(objectName());
lm
committed
delete ui;
}
void QGCToolWidget::setParent(QWidget *parent)
{
QWidget::setParent(parent);
setTitle(getTitle()); //Update titles
/**
* @param parent Object later holding these widgets, usually the main window
* @return List of all widgets
*/
QList<QGCToolWidget*> QGCToolWidget::createWidgetsFromSettings(QWidget* parent, QString settingsFile)
// Load widgets from application settings
QSettings* settings;
// Or load them from a settings file
if (!settingsFile.isEmpty())
{
settings = new QSettings(settingsFile, QSettings::IniFormat);
//qDebug() << "LOADING SETTINGS FROM" << settingsFile;
}
else
{
settings = new QSettings();
//qDebug() << "LOADING SETTINGS FROM DEFAULT" << settings->fileName();
Michael Carpenter
committed
settings->beginGroup("Custom_Tool_Widgets");
int size = settings->beginReadArray("QGC_TOOL_WIDGET_NAMES");
for (int i = 0; i < size; i++)
{
QString name = settings->value("TITLE", "").toString();
Michael Carpenter
committed
QString objname = settings->value("OBJECT_NAME", "").toString();
John Tapsell
committed
if (!instances()->contains(objname) && !objname.isEmpty())
John Tapsell
committed
QGCToolWidget* tool = new QGCToolWidget(objname, name, parent, settings);
else if (name.length() == 0)
{
// Silently catch empty widget name - sanity check
// to survive broken settings (e.g. from user manipulation)
}
//qDebug() << "WIDGET" << name << "DID ALREADY EXIST, REJECTING";
//qDebug() << "NEW WIDGETS: " << newWidgets.size();
for (int i = 0; i < newWidgets.size(); i++)
{
Michael Carpenter
committed
settings->endGroup();
settings->sync();
Michael Carpenter
committed
void QGCToolWidget::showLabel(QString name,int num)
{
for (int i=0;i<toolItemList.size();i++)
{
if (toolItemList[i]->objectName() == name)
{
QGCTextLabel *label = qobject_cast<QGCTextLabel*>(toolItemList[i]);
if (label)
{
label->enableText(num);
}
}
}
}
/**
* @param singleinstance If this is set to true, the widget settings will only be loaded if not another widget with the same title exists
*/
bool QGCToolWidget::loadSettings(const QString& settings, bool singleinstance)
QSettings set(settings, QSettings::IniFormat);
QStringList groups = set.childGroups();
if (groups.length() > 0)
{
John Tapsell
committed
QString objectName = groups.first();
setObjectName(objectName);
if (singleinstance && QGCToolWidget::instances()->contains(objectName)) return false;
instances()->insert(objectName, this);
// Do not use setTitle() here,
// interferes with loading settings
John Tapsell
committed
widgetTitle = objectName;
//qDebug() << "WIDGET TITLE LOADED: " << widgetName;
loadSettings(set);
return true;
}
else
{
return false;
}
Michael Carpenter
committed
void QGCToolWidget::setSettings(QVariantMap& settings)
{
Michael Carpenter
committed
isFromMetaData = true;
Michael Carpenter
committed
settingsMap = settings;
QString widgetName = getTitle();
int size = settingsMap["count"].toInt();
for (int j = 0; j < size; j++)
{
QString type = settings.value(widgetName + "\\" + QString::number(j) + "\\" + "TYPE", "UNKNOWN").toString();
if (type == "SLIDER")
{
QString checkparam = settingsMap.value(widgetName + "\\" + QString::number(j) + "\\" + "QGC_PARAM_SLIDER_PARAMID").toString();
paramList.append(checkparam);
}
else if (type == "COMBO")
{
QString checkparam = settingsMap.value(widgetName + "\\" + QString::number(j) + "\\" + "QGC_PARAM_COMBOBOX_PARAMID").toString();
paramList.append(checkparam);
}
}
}
QList<QString> QGCToolWidget::getParamList()
{
return paramList;
}
void QGCToolWidget::setParameterValue(int uas, int component, QString parameterName, const QVariant value)
{
Don Gagne
committed
Q_UNUSED(uas);
Q_UNUSED(component);
Q_UNUSED(value);
Michael Carpenter
committed
QString widgetName = getTitle();
int size = settingsMap["count"].toInt();
Michael Carpenter
committed
if (paramToItemMap.contains(parameterName))
{
//If we already have an item for this parameter, updates are handled internally.
Michael Carpenter
committed
return;
}
Michael Carpenter
committed
for (int j = 0; j < size; j++)
{
QString type = settingsMap.value(widgetName + "\\" + QString::number(j) + "\\" + "TYPE", "UNKNOWN").toString();
QGCToolWidgetItem* item = NULL;
if (type == "COMMANDBUTTON")
{
//This shouldn't happen, but I'm not sure... so lets test for it.
continue;
Michael Carpenter
committed
}
else if (type == "SLIDER")
{
QString checkparam = settingsMap.value(widgetName + "\\" + QString::number(j) + "\\" + "QGC_PARAM_SLIDER_PARAMID").toString();
if (checkparam == parameterName)
{
item = new QGCParamSlider(this);
Michael Carpenter
committed
paramToItemMap[parameterName] = item;
Michael Carpenter
committed
addToolWidget(item);
item->readSettings(widgetName + "\\" + QString::number(j) + "\\",settingsMap);
return;
}
}
else if (type == "COMBO")
{
QString checkparam = settingsMap.value(widgetName + "\\" + QString::number(j) + "\\" + "QGC_PARAM_COMBOBOX_PARAMID").toString();
if (checkparam == parameterName)
{
item = new QGCComboBox(this);
addToolWidget(item);
item->readSettings(widgetName + "\\" + QString::number(j) + "\\",settingsMap);
Michael Carpenter
committed
paramToItemMap[parameterName] = item;
Michael Carpenter
committed
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
return;
}
}
}
}
void QGCToolWidget::loadSettings(QVariantMap& settings)
{
QString widgetName = getTitle();
//settings.beginGroup(widgetName);
qDebug() << "LOADING FOR" << widgetName;
//int size = settings.beginReadArray("QGC_TOOL_WIDGET_ITEMS");
int size = settings["count"].toInt();
qDebug() << "CHILDREN SIZE:" << size;
for (int j = 0; j < size; j++)
{
QApplication::processEvents();
//settings.setArrayIndex(j);
QString type = settings.value(widgetName + "\\" + QString::number(j) + "\\" + "TYPE", "UNKNOWN").toString();
if (type != "UNKNOWN")
{
QGCToolWidgetItem* item = NULL;
if (type == "COMMANDBUTTON")
{
item = new QGCCommandButton(this);
//qDebug() << "CREATED COMMANDBUTTON";
}
Michael Carpenter
committed
else if (type == "TEXT")
{
item = new QGCTextLabel(this);
item->setActiveUAS(mav);
}
Michael Carpenter
committed
else if (type == "SLIDER")
{
item = new QGCParamSlider(this);
//qDebug() << "CREATED PARAM SLIDER";
}
else if (type == "COMBO")
{
item = new QGCComboBox(this);
//qDebug() << "CREATED COMBOBOX";
Michael Carpenter
committed
}
else if (type == "XYPLOT")
{
item = new QGCXYPlot(this);
//qDebug() << "CREATED XYPlot";
}
Michael Carpenter
committed
if (item)
{
// Configure and add to layout
addToolWidget(item);
item->readSettings(widgetName + "\\" + QString::number(j) + "\\",settings);
//qDebug() << "Created tool widget";
}
}
else
{
qDebug() << "UNKNOWN TOOL WIDGET TYPE" << type;
}
}
//settings.endArray();
//settings.endGroup();
}
void QGCToolWidget::loadSettings(QSettings& settings)
{
QString widgetName = getTitle();
settings.beginGroup(widgetName);
int size = settings.beginReadArray("QGC_TOOL_WIDGET_ITEMS");
for (int j = 0; j < size; j++)
{
settings.setArrayIndex(j);
QString type = settings.value("TYPE", "UNKNOWN").toString();
if (type == "COMMANDBUTTON")
{
Michael Carpenter
committed
QGCCommandButton *button = new QGCCommandButton(this);
connect(button,SIGNAL(showLabel(QString,int)),this,SLOT(showLabel(QString,int)));
item = button;
item->setActiveUAS(mav);
}
else if (type == "SLIDER")
{
Michael Carpenter
committed
item->setActiveUAS(mav);
Michael Carpenter
committed
else if (type == "COMBO")
{
item = new QGCComboBox(this);
Michael Carpenter
committed
item->setActiveUAS(mav);
Michael Carpenter
committed
qDebug() << "CREATED PARAM COMBOBOX";
}
Michael Carpenter
committed
else if (type == "TEXT")
{
item = new QGCTextLabel(this);
item->setObjectName(settings.value("QGC_TEXT_ID").toString());
item->setActiveUAS(mav);
}
else if (type == "XYPLOT")
{
item = new QGCXYPlot(this);
item->setActiveUAS(mav);
}
// Configure and add to layout
addToolWidget(item);
item->readSettings(settings);
}
}
settings.endArray();
settings.endGroup();
}
John Tapsell
committed
void QGCToolWidget::storeWidgetsToSettings(QSettings &settings) //static
John Tapsell
committed
settings.beginGroup("Custom_Tool_Widgets");
int preArraySize = settings.beginReadArray("QGC_TOOL_WIDGET_NAMES");
settings.endArray();
John Tapsell
committed
settings.beginWriteArray("QGC_TOOL_WIDGET_NAMES");
Michael Carpenter
committed
int num = 0;
for (int i = 0; i < qMax(preArraySize, instances()->size()); ++i)
if (i < instances()->size())
{
// Updating value
Michael Carpenter
committed
if (!instances()->values().at(i)->fromMetaData())
{
John Tapsell
committed
settings.setArrayIndex(num++);
settings.setValue("TITLE", instances()->values().at(i)->getTitle());
settings.setValue("OBJECT_NAME", instances()->values().at(i)->objectName());
John Tapsell
committed
qDebug() << "WRITING TITLE" << instances()->values().at(i)->getTitle() << "object:" << instances()->values().at(i)->objectName();
Michael Carpenter
committed
}
}
else
{
// Deleting old value
John Tapsell
committed
settings.remove("TITLE");
John Tapsell
committed
settings.endArray();
for (int i = 0; i < instances()->size(); ++i)
{
John Tapsell
committed
instances()->values().at(i)->storeSettings(settings);
John Tapsell
committed
settings.endGroup();
settings.sync();
}
void QGCToolWidget::storeSettings(QSettings& settings)
{
John Tapsell
committed
/* This function should be called from storeWidgetsToSettings() which sets up the group etc */
Q_ASSERT(settings.group() == "Custom_Tool_Widgets");
Michael Carpenter
committed
if (isFromMetaData)
{
//Refuse to store if this is loaded from metadata or dynamically generated.
return;
}
//qDebug() << "WRITING WIDGET" << widgetTitle << "TO SETTINGS";
settings.beginWriteArray("QGC_TOOL_WIDGET_ITEMS");
int k = 0; // QGCToolItem counter
John Tapsell
committed
foreach(QGCToolWidgetItem *item, toolItemList) {
// Only count actual tool widget item children
settings.setArrayIndex(k++);
// Store the ToolWidgetItem
item->writeSettings(settings);
//qDebug() << "WROTE" << k << "SUB-WIDGETS TO SETTINGS";
settings.endArray();
settings.endGroup();
lm
committed
void QGCToolWidget::addUAS(UASInterface* uas)
{
UAS* newMav = dynamic_cast<UAS*>(uas);
lm
committed
// FIXME Convert to list
if (mav == NULL) mav = newMav;
}
}
void QGCToolWidget::contextMenuEvent (QContextMenuEvent* event)
{
QMenu menu(this);
menu.addAction(addParamAction);
menu.addAction(addLabelAction);
menu.addSeparator();
lm
committed
menu.addAction(setTitleAction);
lm
committed
menu.exec(event->globalPos());
}
void QGCToolWidget::hideEvent(QHideEvent* event)
{
// Store settings
QWidget::hideEvent(event);
}
/**
* The widgets current view and the applied dock widget area.
* Both values are only stored internally and allow an external
* widget to configure it accordingly
*/
void QGCToolWidget::setViewVisibilityAndDockWidgetArea(int view, bool visible, Qt::DockWidgetArea area)
{
viewVisible.insert(view, visible);
dockWidgetArea.insert(view, area);
}
lm
committed
void QGCToolWidget::createActions()
{
addParamAction = new QAction(tr("New &Parameter Slider"), this);
addParamAction->setStatusTip(tr("Add a parameter setting slider widget to the tool"));
connect(addParamAction, SIGNAL(triggered()), this, SLOT(addParam()));
addCommandAction = new QAction(tr("New MAV &Command Button"), this);
addCommandAction->setStatusTip(tr("Add a new action button to the tool"));
connect(addCommandAction, SIGNAL(triggered()), this, SLOT(addCommand()));
lm
committed
addLabelAction = new QAction(tr("New &Text Label"), this);
addLabelAction->setStatusTip(tr("Add a new label to the tool"));
connect(addLabelAction, SIGNAL(triggered()), this, SLOT(addLabel()));
addPlotAction = new QAction(tr("New &XY Plot"), this);
addPlotAction->setStatusTip(tr("Add a XY Plot to the tool"));
connect(addPlotAction, SIGNAL(triggered()), this, SLOT(addPlot()));
lm
committed
setTitleAction = new QAction(tr("Set Widget Title"), this);
setTitleAction->setStatusTip(tr("Set the title caption of this tool widget"));
connect(setTitleAction, SIGNAL(triggered()), this, SLOT(setTitle()));
deleteAction = new QAction(tr("Delete this widget"), this);
deleteAction->setStatusTip(tr("Delete this widget permanently"));
connect(deleteAction, SIGNAL(triggered()), this, SLOT(deleteWidget()));
exportAction = new QAction(tr("Export this widget"), this);
exportAction->setStatusTip(tr("Export this widget to be reused by others"));
connect(exportAction, SIGNAL(triggered()), this, SLOT(exportWidget()));
importAction = new QAction(tr("Import widget"), this);
importAction->setStatusTip(tr("Import this widget from a file (current content will be removed)"));
connect(importAction, SIGNAL(triggered()), this, SLOT(importWidget()));
}
QMap<QString, QGCToolWidget*>* QGCToolWidget::instances()
{
static QMap<QString, QGCToolWidget*>* instances;
if (!instances) instances = new QMap<QString, QGCToolWidget*>();
return instances;
}
Michael Carpenter
committed
void QGCToolWidget::addParam(int uas,int component,QString paramname,QVariant value)
{
Michael Carpenter
committed
isFromMetaData = true;
Michael Carpenter
committed
QGCParamSlider* slider = new QGCParamSlider(this);
Michael Carpenter
committed
slider->setActiveUAS(mav);
slider->setParameterValue(uas,component,0,-1,paramname,value);
}
lm
committed
void QGCToolWidget::addParam()
{
lm
committed
}
addToolWidgetAndEdit(new QGCCommandButton(this));
void QGCToolWidget::addLabel()
{
addToolWidgetAndEdit(new QGCTextLabel(this));
}
void QGCToolWidget::addPlot()
{
addToolWidgetAndEdit(new QGCXYPlot(this));
}
void QGCToolWidget::addToolWidgetAndEdit(QGCToolWidgetItem* widget)
{
addToolWidget(widget);
widget->startEditMode();
void QGCToolWidget::addToolWidget(QGCToolWidgetItem* widget)
{
ui->hintLabel = NULL;
John Tapsell
committed
connect(widget, SIGNAL(editingFinished()), this, SLOT(storeWidgetsToSettings()));
connect(widget, SIGNAL(destroyed()), this, SLOT(widgetRemoved()));
Michael Carpenter
committed
toolItemList.append(widget);
void QGCToolWidget::widgetRemoved()
{
//Must static cast and not dynamic cast since the object is in the destructor
//and we only want to use it as a pointer value
QGCToolWidgetItem *widget = static_cast<QGCToolWidgetItem *>(QObject::sender());
toolItemList.removeAll(widget);
storeWidgetsToSettings();
}
void QGCToolWidget::exportWidget()
{
Bryant Mairs
committed
QString fileName = QFileDialog::getSaveFileName(this, tr("Specify File Name"), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), tr("QGroundControl Widget (*%1);;").arg(widgetFileExtension));
if (!fileName.endsWith(widgetFileExtension))
{
fileName = fileName.append(widgetFileExtension);
}
John Tapsell
committed
QSettings settings(fileName, QSettings::IniFormat);
storeSettings(settings);
Bryant Mairs
committed
QString fileName = QFileDialog::getOpenFileName(this, tr("Specify File Name"), QStandardPaths::writableLocation(QStandardPaths::DesktopLocation), tr("QGroundControl Widget (*%1);;").arg(widgetFileExtension));
QString QGCToolWidget::getTitle() const
return widgetTitle;
lm
committed
void QGCToolWidget::setTitle()
{
QDockWidget* parent = dynamic_cast<QDockWidget*>(this->parentWidget());
QString text = QInputDialog::getText(this, tr("Enter Widget Title"),
lm
committed
tr("Widget title:"), QLineEdit::Normal,
parent->windowTitle(), &ok);
if (ok && !text.isEmpty())
{
setTitle(text);
lm
committed
}
}
void QGCToolWidget::setTitle(const QString& title)
// Sets title and calls setWindowTitle on QWidget
widgetTitle = title;
QWidget::setWindowTitle(title);
QDockWidget* dock = dynamic_cast<QDockWidget*>(this->parentWidget());
John Tapsell
committed
if (dock)
dock->setWindowTitle(widgetTitle);
emit titleChanged(title);
if (mainMenuAction) mainMenuAction->setText(title);
John Tapsell
committed
John Tapsell
committed
//Do not save the settings here, because this function might be
//called while loading, and thus saving here could end up clobbering
//all of the other widgets
void QGCToolWidget::setMainMenuAction(QAction* action)
{
this->mainMenuAction = action;
}
void QGCToolWidget::deleteWidget()
{
// Remove from settings
// Hide
this->hide();
John Tapsell
committed
instances()->remove(objectName());
QSettings settings;
settings.beginGroup("QGC_MAINWINDOW");
settings.remove(QString("TOOL_PARENT_") + objectName());