mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2025-01-21 06:52:11 +01:00
OP-642 Added <category> element which is a string in uavo object type definition to be used in uavo browser to categorise uavo:s visually into subtrees. Category value is assigned in generated code and accessible via getter method. OP-644 Fixed option for uavo browser to enable disable hilights for objects which values wasn't really changed to indicate stream activity in uavo object tree.
This commit is contained in:
parent
7425547b33
commit
3c754af484
@ -45,5 +45,6 @@ void UAVObjectBrowser::loadConfiguration(IUAVGadgetConfiguration* config)
|
|||||||
m_widget->setRecentlyUpdatedColor(m->recentlyUpdatedColor());
|
m_widget->setRecentlyUpdatedColor(m->recentlyUpdatedColor());
|
||||||
m_widget->setManuallyChangedColor(m->manuallyChangedColor());
|
m_widget->setManuallyChangedColor(m->manuallyChangedColor());
|
||||||
m_widget->setRecentlyUpdatedTimeout(m->recentlyUpdatedTimeout());
|
m_widget->setRecentlyUpdatedTimeout(m->recentlyUpdatedTimeout());
|
||||||
|
m_widget->setOnlyHilightChangedValues(m->onlyHighlightChangedValues());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,17 +31,20 @@ UAVObjectBrowserConfiguration::UAVObjectBrowserConfiguration(QString classId, QS
|
|||||||
IUAVGadgetConfiguration(classId, parent),
|
IUAVGadgetConfiguration(classId, parent),
|
||||||
m_recentlyUpdatedColor(QColor(255, 230, 230)),
|
m_recentlyUpdatedColor(QColor(255, 230, 230)),
|
||||||
m_manuallyChangedColor(QColor(230, 230, 255)),
|
m_manuallyChangedColor(QColor(230, 230, 255)),
|
||||||
m_recentlyUpdatedTimeout(500)
|
m_recentlyUpdatedTimeout(500),
|
||||||
|
m_onlyHilightChangedValues(false)
|
||||||
{
|
{
|
||||||
//if a saved configuration exists load it
|
//if a saved configuration exists load it
|
||||||
if(qSettings != 0) {
|
if(qSettings != 0) {
|
||||||
QColor recent = qSettings->value("recentlyUpdatedColor").value<QColor>();
|
QColor recent = qSettings->value("recentlyUpdatedColor").value<QColor>();
|
||||||
QColor manual = qSettings->value("manuallyChangedColor").value<QColor>();
|
QColor manual = qSettings->value("manuallyChangedColor").value<QColor>();
|
||||||
int timeout = qSettings->value("recentlyUpdatedTimeout").toInt();
|
int timeout = qSettings->value("recentlyUpdatedTimeout").toInt();
|
||||||
|
bool hilight = qSettings->value("onlyHilightChangedValues").toBool();
|
||||||
|
|
||||||
m_recentlyUpdatedColor = recent;
|
m_recentlyUpdatedColor = recent;
|
||||||
m_manuallyChangedColor = manual;
|
m_manuallyChangedColor = manual;
|
||||||
m_recentlyUpdatedTimeout = timeout;
|
m_recentlyUpdatedTimeout = timeout;
|
||||||
|
m_onlyHilightChangedValues = hilight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,6 +54,7 @@ IUAVGadgetConfiguration *UAVObjectBrowserConfiguration::clone()
|
|||||||
m->m_recentlyUpdatedColor = m_recentlyUpdatedColor;
|
m->m_recentlyUpdatedColor = m_recentlyUpdatedColor;
|
||||||
m->m_manuallyChangedColor = m_manuallyChangedColor;
|
m->m_manuallyChangedColor = m_manuallyChangedColor;
|
||||||
m->m_recentlyUpdatedTimeout = m_recentlyUpdatedTimeout;
|
m->m_recentlyUpdatedTimeout = m_recentlyUpdatedTimeout;
|
||||||
|
m->m_onlyHilightChangedValues = m_onlyHilightChangedValues;
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -62,4 +66,5 @@ void UAVObjectBrowserConfiguration::saveConfig(QSettings* qSettings) const {
|
|||||||
qSettings->setValue("recentlyUpdatedColor", m_recentlyUpdatedColor);
|
qSettings->setValue("recentlyUpdatedColor", m_recentlyUpdatedColor);
|
||||||
qSettings->setValue("manuallyChangedColor", m_manuallyChangedColor);
|
qSettings->setValue("manuallyChangedColor", m_manuallyChangedColor);
|
||||||
qSettings->setValue("recentlyUpdatedTimeout", m_recentlyUpdatedTimeout);
|
qSettings->setValue("recentlyUpdatedTimeout", m_recentlyUpdatedTimeout);
|
||||||
|
qSettings->setValue("onlyHilightChangedValues", m_onlyHilightChangedValues);
|
||||||
}
|
}
|
||||||
|
@ -39,6 +39,7 @@ Q_OBJECT
|
|||||||
Q_PROPERTY(QColor m_recentlyUpdatedColor READ recentlyUpdatedColor WRITE setRecentlyUpdatedColor)
|
Q_PROPERTY(QColor m_recentlyUpdatedColor READ recentlyUpdatedColor WRITE setRecentlyUpdatedColor)
|
||||||
Q_PROPERTY(QColor m_manuallyChangedColor READ manuallyChangedColor WRITE setManuallyChangedColor)
|
Q_PROPERTY(QColor m_manuallyChangedColor READ manuallyChangedColor WRITE setManuallyChangedColor)
|
||||||
Q_PROPERTY(int m_recentlyUpdatedTimeout READ recentlyUpdatedTimeout WRITE setRecentlyUpdatedTimeout)
|
Q_PROPERTY(int m_recentlyUpdatedTimeout READ recentlyUpdatedTimeout WRITE setRecentlyUpdatedTimeout)
|
||||||
|
Q_PROPERTY(bool m_onlyHilightChangedValues READ onlyHighlightChangedValues WRITE setOnlyHighlightChangedValues)
|
||||||
public:
|
public:
|
||||||
explicit UAVObjectBrowserConfiguration(QString classId, QSettings* qSettings = 0, QObject *parent = 0);
|
explicit UAVObjectBrowserConfiguration(QString classId, QSettings* qSettings = 0, QObject *parent = 0);
|
||||||
|
|
||||||
@ -48,6 +49,7 @@ public:
|
|||||||
QColor recentlyUpdatedColor() const { return m_recentlyUpdatedColor; }
|
QColor recentlyUpdatedColor() const { return m_recentlyUpdatedColor; }
|
||||||
QColor manuallyChangedColor() const { return m_manuallyChangedColor; }
|
QColor manuallyChangedColor() const { return m_manuallyChangedColor; }
|
||||||
int recentlyUpdatedTimeout() const { return m_recentlyUpdatedTimeout; }
|
int recentlyUpdatedTimeout() const { return m_recentlyUpdatedTimeout; }
|
||||||
|
bool onlyHighlightChangedValues() const {return m_onlyHilightChangedValues;}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
@ -55,11 +57,13 @@ public slots:
|
|||||||
void setRecentlyUpdatedColor(QColor color) { m_recentlyUpdatedColor = color; }
|
void setRecentlyUpdatedColor(QColor color) { m_recentlyUpdatedColor = color; }
|
||||||
void setManuallyChangedColor(QColor color) { m_manuallyChangedColor = color; }
|
void setManuallyChangedColor(QColor color) { m_manuallyChangedColor = color; }
|
||||||
void setRecentlyUpdatedTimeout(int timeout) { m_recentlyUpdatedTimeout = timeout; }
|
void setRecentlyUpdatedTimeout(int timeout) { m_recentlyUpdatedTimeout = timeout; }
|
||||||
|
void setOnlyHighlightChangedValues(bool hilight) { m_onlyHilightChangedValues = hilight; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QColor m_recentlyUpdatedColor;
|
QColor m_recentlyUpdatedColor;
|
||||||
QColor m_manuallyChangedColor;
|
QColor m_manuallyChangedColor;
|
||||||
int m_recentlyUpdatedTimeout;
|
int m_recentlyUpdatedTimeout;
|
||||||
|
bool m_onlyHilightChangedValues;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // UAVOBJECTBROWSERCONFIGURATION_H
|
#endif // UAVOBJECTBROWSERCONFIGURATION_H
|
||||||
|
@ -52,6 +52,7 @@ QWidget *UAVObjectBrowserOptionsPage::createPage(QWidget *parent)
|
|||||||
m_page->recentlyUpdatedButton->setColor(m_config->recentlyUpdatedColor());
|
m_page->recentlyUpdatedButton->setColor(m_config->recentlyUpdatedColor());
|
||||||
m_page->manuallyChangedButton->setColor(m_config->manuallyChangedColor());
|
m_page->manuallyChangedButton->setColor(m_config->manuallyChangedColor());
|
||||||
m_page->recentlyUpdatedTimeoutSpinBox->setValue(m_config->recentlyUpdatedTimeout());
|
m_page->recentlyUpdatedTimeoutSpinBox->setValue(m_config->recentlyUpdatedTimeout());
|
||||||
|
m_page->hilightBox->setChecked(m_config->onlyHighlightChangedValues());
|
||||||
|
|
||||||
return w;
|
return w;
|
||||||
|
|
||||||
@ -62,6 +63,7 @@ void UAVObjectBrowserOptionsPage::apply()
|
|||||||
m_config->setRecentlyUpdatedColor(m_page->recentlyUpdatedButton->color());
|
m_config->setRecentlyUpdatedColor(m_page->recentlyUpdatedButton->color());
|
||||||
m_config->setManuallyChangedColor(m_page->manuallyChangedButton->color());
|
m_config->setManuallyChangedColor(m_page->manuallyChangedButton->color());
|
||||||
m_config->setRecentlyUpdatedTimeout(m_page->recentlyUpdatedTimeoutSpinBox->value());
|
m_config->setRecentlyUpdatedTimeout(m_page->recentlyUpdatedTimeoutSpinBox->value());
|
||||||
|
m_config->setOnlyHighlightChangedValues(m_page->hilightBox->isChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
void UAVObjectBrowserOptionsPage::finish()
|
void UAVObjectBrowserOptionsPage::finish()
|
||||||
|
@ -48,7 +48,7 @@
|
|||||||
</property>
|
</property>
|
||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item row="4" column="3">
|
<item row="5" column="3">
|
||||||
<spacer name="verticalSpacer">
|
<spacer name="verticalSpacer">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
@ -115,6 +115,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QCheckBox" name="hilightBox">
|
||||||
|
<property name="text">
|
||||||
|
<string>Only hilight nodes when value actually changes</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<customwidgets>
|
<customwidgets>
|
||||||
|
@ -48,6 +48,8 @@ public:
|
|||||||
void setRecentlyUpdatedColor(QColor color) { m_model->setRecentlyUpdatedColor(color); }
|
void setRecentlyUpdatedColor(QColor color) { m_model->setRecentlyUpdatedColor(color); }
|
||||||
void setManuallyChangedColor(QColor color) { m_model->setManuallyChangedColor(color); }
|
void setManuallyChangedColor(QColor color) { m_model->setManuallyChangedColor(color); }
|
||||||
void setRecentlyUpdatedTimeout(int timeout) { m_model->setRecentlyUpdatedTimeout(timeout); }
|
void setRecentlyUpdatedTimeout(int timeout) { m_model->setRecentlyUpdatedTimeout(timeout); }
|
||||||
|
void setOnlyHilightChangedValues(bool hilight) { m_model->setOnlyHilightChangedValues(hilight); }
|
||||||
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void showMetaData(bool show);
|
void showMetaData(bool show);
|
||||||
|
@ -363,11 +363,16 @@ void UAVObjectTreeModel::highlightUpdatedObject(UAVObject *obj)
|
|||||||
Q_ASSERT(obj);
|
Q_ASSERT(obj);
|
||||||
ObjectTreeItem *item = findObjectTreeItem(obj);
|
ObjectTreeItem *item = findObjectTreeItem(obj);
|
||||||
Q_ASSERT(item);
|
Q_ASSERT(item);
|
||||||
|
if(!m_onlyHilightChangedValues){
|
||||||
|
item->setHighlight(true);
|
||||||
|
}
|
||||||
item->update();
|
item->update();
|
||||||
|
if(!m_onlyHilightChangedValues){
|
||||||
QModelIndex itemIndex = index(item);
|
QModelIndex itemIndex = index(item);
|
||||||
Q_ASSERT(itemIndex != QModelIndex());
|
Q_ASSERT(itemIndex != QModelIndex());
|
||||||
emit dataChanged(itemIndex, itemIndex);
|
emit dataChanged(itemIndex, itemIndex);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ObjectTreeItem *UAVObjectTreeModel::findObjectTreeItem(UAVObject *object)
|
ObjectTreeItem *UAVObjectTreeModel::findObjectTreeItem(UAVObject *object)
|
||||||
{
|
{
|
||||||
|
@ -68,6 +68,7 @@ public:
|
|||||||
m_recentlyUpdatedTimeout = timeout;
|
m_recentlyUpdatedTimeout = timeout;
|
||||||
TreeItem::setHighlightTime(timeout);
|
TreeItem::setHighlightTime(timeout);
|
||||||
}
|
}
|
||||||
|
void setOnlyHilightChangedValues(bool hilight) {m_onlyHilightChangedValues = hilight; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
@ -97,6 +98,7 @@ private:
|
|||||||
int m_recentlyUpdatedTimeout;
|
int m_recentlyUpdatedTimeout;
|
||||||
QColor m_recentlyUpdatedColor;
|
QColor m_recentlyUpdatedColor;
|
||||||
QColor m_manuallyChangedColor;
|
QColor m_manuallyChangedColor;
|
||||||
|
bool m_onlyHilightChangedValues;
|
||||||
|
|
||||||
// Highlight manager to handle highlighting of tree items.
|
// Highlight manager to handle highlighting of tree items.
|
||||||
HighLightManager *m_highlightManager;
|
HighLightManager *m_highlightManager;
|
||||||
|
@ -145,6 +145,22 @@ void UAVObject::setDescription(const QString& description)
|
|||||||
this->description = description;
|
this->description = description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the category of the object
|
||||||
|
*/
|
||||||
|
QString UAVObject::getCategory()
|
||||||
|
{
|
||||||
|
return category;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the category of the object
|
||||||
|
*/
|
||||||
|
void UAVObject::setCategory(const QString& category)
|
||||||
|
{
|
||||||
|
this->category = category;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the total number of bytes of the object's data
|
* Get the total number of bytes of the object's data
|
||||||
|
@ -103,6 +103,7 @@ public:
|
|||||||
quint32 getInstID();
|
quint32 getInstID();
|
||||||
bool isSingleInstance();
|
bool isSingleInstance();
|
||||||
QString getName();
|
QString getName();
|
||||||
|
QString getCategory();
|
||||||
QString getDescription();
|
QString getDescription();
|
||||||
quint32 getNumBytes();
|
quint32 getNumBytes();
|
||||||
qint32 pack(quint8* dataOut);
|
qint32 pack(quint8* dataOut);
|
||||||
@ -163,6 +164,7 @@ protected:
|
|||||||
bool isSingleInst;
|
bool isSingleInst;
|
||||||
QString name;
|
QString name;
|
||||||
QString description;
|
QString description;
|
||||||
|
QString category;
|
||||||
quint32 numBytes;
|
quint32 numBytes;
|
||||||
QMutex* mutex;
|
QMutex* mutex;
|
||||||
quint8* data;
|
quint8* data;
|
||||||
@ -170,6 +172,7 @@ protected:
|
|||||||
|
|
||||||
void initializeFields(QList<UAVObjectField*>& fields, quint8* data, quint32 numBytes);
|
void initializeFields(QList<UAVObjectField*>& fields, quint8* data, quint32 numBytes);
|
||||||
void setDescription(const QString& description);
|
void setDescription(const QString& description);
|
||||||
|
void setCategory(const QString& category);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // UAVOBJECT_H
|
#endif // UAVOBJECT_H
|
||||||
|
@ -35,6 +35,7 @@
|
|||||||
|
|
||||||
const QString $(NAME)::NAME = QString("$(NAME)");
|
const QString $(NAME)::NAME = QString("$(NAME)");
|
||||||
const QString $(NAME)::DESCRIPTION = QString("$(DESCRIPTION)");
|
const QString $(NAME)::DESCRIPTION = QString("$(DESCRIPTION)");
|
||||||
|
const QString $(NAME)::CATEGORY = QString("$(CATEGORY)");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@ -51,6 +52,9 @@ $(FIELDSINIT)
|
|||||||
// Set the object description
|
// Set the object description
|
||||||
setDescription(DESCRIPTION);
|
setDescription(DESCRIPTION);
|
||||||
|
|
||||||
|
// Set the Category of this object type
|
||||||
|
setCategory(CATEGORY);
|
||||||
|
|
||||||
connect(this, SIGNAL(objectUpdated(UAVObject*)),
|
connect(this, SIGNAL(objectUpdated(UAVObject*)),
|
||||||
SLOT(emitNotifications()));
|
SLOT(emitNotifications()));
|
||||||
}
|
}
|
||||||
|
@ -54,6 +54,7 @@ $(DATAFIELDINFO)
|
|||||||
static const quint32 OBJID = $(OBJIDHEX);
|
static const quint32 OBJID = $(OBJIDHEX);
|
||||||
static const QString NAME;
|
static const QString NAME;
|
||||||
static const QString DESCRIPTION;
|
static const QString DESCRIPTION;
|
||||||
|
static const QString CATEGORY;
|
||||||
static const bool ISSINGLEINST = $(ISSINGLEINST);
|
static const bool ISSINGLEINST = $(ISSINGLEINST);
|
||||||
static const bool ISSETTINGS = $(ISSETTINGS);
|
static const bool ISSETTINGS = $(ISSETTINGS);
|
||||||
static const quint32 NUMBYTES = sizeof(DataFields);
|
static const quint32 NUMBYTES = sizeof(DataFields);
|
||||||
|
@ -55,6 +55,8 @@ void replaceCommonTags(QString& out, ObjectInfo* info)
|
|||||||
out.replace(QString("$(NAMELC)"), info->namelc);
|
out.replace(QString("$(NAMELC)"), info->namelc);
|
||||||
// Replace $(DESCRIPTION) tag
|
// Replace $(DESCRIPTION) tag
|
||||||
out.replace(QString("$(DESCRIPTION)"), info->description);
|
out.replace(QString("$(DESCRIPTION)"), info->description);
|
||||||
|
// Replace $(CATEGORY) tag
|
||||||
|
out.replace(QString("$(CATEGORY)"), info->category);
|
||||||
// Replace $(NAMEUC) tag
|
// Replace $(NAMEUC) tag
|
||||||
out.replace(QString("$(NAMEUC)"), info->name.toUpper());
|
out.replace(QString("$(NAMEUC)"), info->name.toUpper());
|
||||||
// Replace $(OBJID) tag
|
// Replace $(OBJID) tag
|
||||||
|
@ -198,6 +198,12 @@ QString UAVObjectParser::parseXML(QString& xml, QString& filename)
|
|||||||
|
|
||||||
descriptionFound = true;
|
descriptionFound = true;
|
||||||
}
|
}
|
||||||
|
else if ( childNode.nodeName().compare(QString("category")) == 0 ) {
|
||||||
|
QString status = processObjectCategory(childNode, &info->category);
|
||||||
|
|
||||||
|
if (!status.isNull())
|
||||||
|
return status;
|
||||||
|
}
|
||||||
else if (!childNode.isComment()) {
|
else if (!childNode.isComment()) {
|
||||||
return QString("Unknown object element");
|
return QString("Unknown object element");
|
||||||
}
|
}
|
||||||
@ -540,3 +546,12 @@ QString UAVObjectParser::processObjectDescription(QDomNode& childNode, QString *
|
|||||||
description->append(childNode.firstChild().nodeValue());
|
description->append(childNode.firstChild().nodeValue());
|
||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the category field from the XML file
|
||||||
|
*/
|
||||||
|
QString UAVObjectParser::processObjectCategory(QDomNode& childNode, QString * category)
|
||||||
|
{
|
||||||
|
category->append(childNode.firstChild().nodeValue());
|
||||||
|
return QString();
|
||||||
|
}
|
||||||
|
@ -96,6 +96,7 @@ typedef struct {
|
|||||||
int loggingUpdatePeriod; /** Update period used by the logging module (only if logging mode is PERIODIC) */
|
int loggingUpdatePeriod; /** Update period used by the logging module (only if logging mode is PERIODIC) */
|
||||||
QList<FieldInfo*> fields; /** The data fields for the object **/
|
QList<FieldInfo*> fields; /** The data fields for the object **/
|
||||||
QString description; /** Description used for Doxygen **/
|
QString description; /** Description used for Doxygen **/
|
||||||
|
QString category; /** Description used for Doxygen **/
|
||||||
} ObjectInfo;
|
} ObjectInfo;
|
||||||
|
|
||||||
class UAVObjectParser
|
class UAVObjectParser
|
||||||
@ -127,6 +128,7 @@ private:
|
|||||||
QString processObjectFields(QDomNode& childNode, ObjectInfo* info);
|
QString processObjectFields(QDomNode& childNode, ObjectInfo* info);
|
||||||
QString processObjectAccess(QDomNode& childNode, ObjectInfo* info);
|
QString processObjectAccess(QDomNode& childNode, ObjectInfo* info);
|
||||||
QString processObjectDescription(QDomNode& childNode, QString * description);
|
QString processObjectDescription(QDomNode& childNode, QString * description);
|
||||||
|
QString processObjectCategory(QDomNode& childNode, QString * category);
|
||||||
QString processObjectMetadata(QDomNode& childNode, UpdateMode* mode, int* period, bool* acked);
|
QString processObjectMetadata(QDomNode& childNode, UpdateMode* mode, int* period, bool* acked);
|
||||||
void calculateID(ObjectInfo* info);
|
void calculateID(ObjectInfo* info);
|
||||||
quint32 updateHash(quint32 value, quint32 hash);
|
quint32 updateHash(quint32 value, quint32 hash);
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
<xml>
|
<xml>
|
||||||
<object name="Gyros" singleinstance="true" settings="false">
|
<object name="Gyros" singleinstance="true" settings="false">
|
||||||
|
<category>Sensors</category>
|
||||||
<description>The gyro data.</description>
|
<description>The gyro data.</description>
|
||||||
<field name="x" units="deg/s" type="float" elements="1"/>
|
<field name="x" units="deg/s" type="float" elements="1"/>
|
||||||
<field name="y" units="deg/s" type="float" elements="1"/>
|
<field name="y" units="deg/s" type="float" elements="1"/>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user