mirror of
https://github.com/danieldemus/openhab-core.git
synced 2025-01-10 13:21:53 +01:00
[sitemap] Buttongrid as container for new Button elements (#4223)
Related to #4173 Signed-off-by: Laurent Garnier <lg.hc@free.fr>
This commit is contained in:
parent
73f4722b91
commit
3b9a97101b
@ -79,6 +79,7 @@ import org.openhab.core.library.CoreItemFactory;
|
||||
import org.openhab.core.library.types.HSBType;
|
||||
import org.openhab.core.model.sitemap.SitemapProvider;
|
||||
import org.openhab.core.model.sitemap.sitemap.Button;
|
||||
import org.openhab.core.model.sitemap.sitemap.ButtonDefinition;
|
||||
import org.openhab.core.model.sitemap.sitemap.Buttongrid;
|
||||
import org.openhab.core.model.sitemap.sitemap.Chart;
|
||||
import org.openhab.core.model.sitemap.sitemap.ColorArray;
|
||||
@ -101,6 +102,7 @@ import org.openhab.core.model.sitemap.sitemap.Webview;
|
||||
import org.openhab.core.model.sitemap.sitemap.Widget;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.ui.items.ItemUIRegistry;
|
||||
import org.openhab.core.ui.items.ItemUIRegistry.WidgetLabelSource;
|
||||
import org.osgi.service.component.annotations.Activate;
|
||||
import org.osgi.service.component.annotations.Component;
|
||||
import org.osgi.service.component.annotations.Deactivate;
|
||||
@ -142,6 +144,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
* @author Laurent Garnier - Support added for multiple AND conditions in labelcolor/valuecolor/visibility
|
||||
* @author Laurent Garnier - New widget icon parameter based on conditional rules
|
||||
* @author Laurent Garnier - Added releaseCmd field for mappings used for switch element
|
||||
* @author Laurent Garnier - Added support for Buttongrid as container for Button elements
|
||||
*/
|
||||
@Component(service = { RESTResource.class, EventSubscriber.class })
|
||||
@JaxrsResource
|
||||
@ -616,7 +619,7 @@ public class SitemapResource
|
||||
bean.visibility = itemUIRegistry.getVisiblity(widget);
|
||||
if (widget instanceof LinkableWidget linkableWidget) {
|
||||
EList<Widget> children = itemUIRegistry.getChildren(linkableWidget);
|
||||
if (widget instanceof Frame) {
|
||||
if (widget instanceof Frame || widget instanceof Buttongrid) {
|
||||
for (Widget child : children) {
|
||||
String wID = itemUIRegistry.getWidgetId(child);
|
||||
WidgetDTO subWidget = createWidgetBean(sitemapName, child, drillDown, uri, wID, locale,
|
||||
@ -700,7 +703,7 @@ public class SitemapResource
|
||||
bean.step = setpointWidget.getStep();
|
||||
}
|
||||
if (widget instanceof Buttongrid buttonGridWidget) {
|
||||
for (Button button : buttonGridWidget.getButtons()) {
|
||||
for (ButtonDefinition button : buttonGridWidget.getButtons()) {
|
||||
MappingDTO mappingBean = new MappingDTO();
|
||||
mappingBean.row = button.getRow();
|
||||
mappingBean.column = button.getColumn();
|
||||
@ -710,6 +713,23 @@ public class SitemapResource
|
||||
bean.mappings.add(mappingBean);
|
||||
}
|
||||
}
|
||||
if (widget instanceof Button buttonWidget) {
|
||||
// Get the icon from the widget only
|
||||
if (widget.getIcon() == null && widget.getStaticIcon() == null && widget.getIconRules().isEmpty()) {
|
||||
bean.icon = null;
|
||||
bean.staticIcon = null;
|
||||
}
|
||||
// Get the label from the widget only and fail back to the command if not set
|
||||
bean.label = widget.getLabel() != null ? widget.getLabel() : buttonWidget.getCmd();
|
||||
bean.labelSource = WidgetLabelSource.SITEMAP_WIDGET.toString();
|
||||
bean.pattern = null;
|
||||
bean.unit = null;
|
||||
bean.row = buttonWidget.getRow();
|
||||
bean.column = buttonWidget.getColumn();
|
||||
bean.command = buttonWidget.getCmd();
|
||||
bean.releaseCommand = buttonWidget.getReleaseCmd();
|
||||
bean.stateless = buttonWidget.isStateless();
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
@ -740,6 +760,10 @@ public class SitemapResource
|
||||
if (isLeaf(frame.getChildren())) {
|
||||
return false;
|
||||
}
|
||||
} else if (w instanceof Buttongrid grid) {
|
||||
if (isLeaf(grid.getChildren())) {
|
||||
return false;
|
||||
}
|
||||
} else if (w instanceof LinkableWidget linkableWidget) {
|
||||
if (!itemUIRegistry.getChildren(linkableWidget).isEmpty()) {
|
||||
return false;
|
||||
@ -828,6 +852,8 @@ public class SitemapResource
|
||||
// Consider all items inside the frame
|
||||
if (widget instanceof Frame frame) {
|
||||
items.addAll(getAllItems(frame.getChildren()));
|
||||
} else if (widget instanceof Buttongrid grid) {
|
||||
items.addAll(getAllItems(grid.getChildren()));
|
||||
}
|
||||
// Consider items involved in any icon condition
|
||||
items.addAll(getItemsInIconCond(widget.getIconRules()));
|
||||
|
@ -28,6 +28,7 @@ import org.openhab.core.io.rest.core.item.EnrichedItemDTO;
|
||||
* @author Laurent Garnier - New field columns
|
||||
* @author Danny Baumann - New field labelSource
|
||||
* @author Laurent Garnier - Remove field columns
|
||||
* @author Laurent Garnier - New fields row, column, command, releaseCommand and stateless for Button element
|
||||
*/
|
||||
public class WidgetDTO {
|
||||
|
||||
@ -70,12 +71,17 @@ public class WidgetDTO {
|
||||
public String yAxisDecimalPattern;
|
||||
public Boolean legend;
|
||||
public Boolean forceAsItem;
|
||||
public Integer row;
|
||||
public Integer column;
|
||||
public String command;
|
||||
public String releaseCommand;
|
||||
public Boolean stateless;
|
||||
public String state;
|
||||
|
||||
public EnrichedItemDTO item;
|
||||
public PageDTO linkedPage;
|
||||
|
||||
// only for frames, other linkable widgets link to a page
|
||||
// only for frames and button grids, other linkable widgets link to a page
|
||||
public final List<WidgetDTO> widgets = new ArrayList<>();
|
||||
|
||||
public WidgetDTO() {
|
||||
|
@ -35,6 +35,8 @@ import org.openhab.core.items.events.GroupStateUpdatedEvent;
|
||||
import org.openhab.core.items.events.ItemEvent;
|
||||
import org.openhab.core.items.events.ItemStateChangedEvent;
|
||||
import org.openhab.core.library.CoreItemFactory;
|
||||
import org.openhab.core.model.sitemap.sitemap.Button;
|
||||
import org.openhab.core.model.sitemap.sitemap.Buttongrid;
|
||||
import org.openhab.core.model.sitemap.sitemap.Chart;
|
||||
import org.openhab.core.model.sitemap.sitemap.ColorArray;
|
||||
import org.openhab.core.model.sitemap.sitemap.Condition;
|
||||
@ -44,6 +46,7 @@ import org.openhab.core.model.sitemap.sitemap.VisibilityRule;
|
||||
import org.openhab.core.model.sitemap.sitemap.Widget;
|
||||
import org.openhab.core.types.State;
|
||||
import org.openhab.core.ui.items.ItemUIRegistry;
|
||||
import org.openhab.core.ui.items.ItemUIRegistry.WidgetLabelSource;
|
||||
|
||||
/**
|
||||
* This is a class that listens on item state change events and creates sitemap events for the registered widgets.
|
||||
@ -52,6 +55,7 @@ import org.openhab.core.ui.items.ItemUIRegistry;
|
||||
* @author Laurent Garnier - Added support for icon color
|
||||
* @author Laurent Garnier - Support added for multiple AND conditions in labelcolor/valuecolor/visibility
|
||||
* @author Laurent Garnier - New widget icon parameter based on conditional rules
|
||||
* @author Laurent Garnier - Buttongrid as container for Button elements
|
||||
*/
|
||||
public class WidgetsChangeListener implements EventSubscriber {
|
||||
|
||||
@ -124,6 +128,8 @@ public class WidgetsChangeListener implements EventSubscriber {
|
||||
addItemWithName(items, widget.getItem());
|
||||
if (widget instanceof Frame frame) {
|
||||
items.addAll(getAllItems(frame.getChildren()));
|
||||
} else if (widget instanceof Buttongrid grid) {
|
||||
items.addAll(getAllItems(grid.getChildren()));
|
||||
}
|
||||
// now scan icon rules
|
||||
for (IconRule rule : widget.getIconRules()) {
|
||||
@ -193,6 +199,8 @@ public class WidgetsChangeListener implements EventSubscriber {
|
||||
for (Widget w : widgets) {
|
||||
if (w instanceof Frame frame) {
|
||||
events.addAll(constructSitemapEvents(item, state, itemUIRegistry.getChildren(frame)));
|
||||
} else if (w instanceof Buttongrid grid) {
|
||||
events.addAll(constructSitemapEvents(item, state, itemUIRegistry.getChildren(grid)));
|
||||
}
|
||||
|
||||
boolean itemBelongsToWidget = w.getItem() != null && w.getItem().equals(item.getName());
|
||||
@ -218,6 +226,16 @@ public class WidgetsChangeListener implements EventSubscriber {
|
||||
event.widgetId = itemUIRegistry.getWidgetId(widget);
|
||||
event.icon = itemUIRegistry.getCategory(widget);
|
||||
event.reloadIcon = widget.getStaticIcon() == null;
|
||||
if (widget instanceof Button buttonWidget) {
|
||||
// Get the icon from the widget only
|
||||
if (widget.getIcon() == null && widget.getStaticIcon() == null && widget.getIconRules().isEmpty()) {
|
||||
event.icon = null;
|
||||
event.reloadIcon = false;
|
||||
}
|
||||
// Get the label from the widget only and fail back to the command if not set
|
||||
event.label = widget.getLabel() != null ? widget.getLabel() : buttonWidget.getCmd();
|
||||
event.labelSource = WidgetLabelSource.SITEMAP_WIDGET.toString();
|
||||
}
|
||||
event.visibility = itemUIRegistry.getVisiblity(widget);
|
||||
event.descriptionChanged = false;
|
||||
// event.item contains the (potentially changed) data of the item belonging to
|
||||
@ -311,6 +329,8 @@ public class WidgetsChangeListener implements EventSubscriber {
|
||||
for (Widget w : widgets) {
|
||||
if (w instanceof Frame frame) {
|
||||
events.addAll(constructSitemapEventsForUpdatedDescr(item, itemUIRegistry.getChildren(frame)));
|
||||
} else if (w instanceof Buttongrid grid) {
|
||||
events.addAll(constructSitemapEventsForUpdatedDescr(item, itemUIRegistry.getChildren(grid)));
|
||||
}
|
||||
|
||||
boolean itemBelongsToWidget = w.getItem() != null && w.getItem().equals(item.getName());
|
||||
|
@ -39,8 +39,9 @@ public class RESTConstants {
|
||||
* Version 5: transparent charts (#2502)
|
||||
* Version 6: extended chart period parameter format (#3863)
|
||||
* Version 7: extended chart period parameter format to cover past and future
|
||||
* Version 8: Buttongrid as container for new Button elements
|
||||
*/
|
||||
public static final String API_VERSION = "7";
|
||||
public static final String API_VERSION = "8";
|
||||
|
||||
public static final CacheControl CACHE_CONTROL = new CacheControl();
|
||||
static {
|
||||
|
@ -15,10 +15,10 @@ Widget:
|
||||
(LinkableWidget | NonLinkableWidget);
|
||||
|
||||
NonLinkableWidget:
|
||||
Switch | Selection | Slider | Setpoint | Video | Chart | Webview | Colorpicker | Mapview | Input | Buttongrid | Default;
|
||||
Switch | Selection | Slider | Setpoint | Video | Chart | Webview | Colorpicker | Mapview | Input | Button | Default;
|
||||
|
||||
LinkableWidget:
|
||||
(Text | Group | Image | Frame)
|
||||
(Text | Group | Image | Frame | Buttongrid)
|
||||
('{'
|
||||
(children+=Widget)+
|
||||
'}')?;
|
||||
@ -179,11 +179,23 @@ Input:
|
||||
('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)*) ']')?);
|
||||
|
||||
Buttongrid:
|
||||
'Buttongrid' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? &
|
||||
'Buttongrid' (('item=' item=ItemRef)? & ('label=' label=(ID | STRING))? &
|
||||
(('icon=' icon=Icon) |
|
||||
('icon=[' (IconRules+=IconRule (',' IconRules+=IconRule)*) ']') |
|
||||
('staticIcon=' staticIcon=Icon))? &
|
||||
('buttons=[' buttons+=Button (',' buttons+=Button)* ']') &
|
||||
('buttons=[' buttons+=ButtonDefinition (',' buttons+=ButtonDefinition)* ']')? &
|
||||
('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)*) ']')? &
|
||||
('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)*) ']')? &
|
||||
('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)*) ']')? &
|
||||
('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)*) ']')?);
|
||||
|
||||
Button:
|
||||
'Button' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? &
|
||||
(('icon=' icon=Icon) |
|
||||
('icon=[' (IconRules+=IconRule (',' IconRules+=IconRule)*) ']') |
|
||||
('staticIcon=' staticIcon=Icon))? &
|
||||
('row=' row=INT) & ('column=' column=INT) & (stateless?='stateless')? &
|
||||
('click=' cmd=Command) & ('release=' releaseCmd=Command)? &
|
||||
('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)*) ']')? &
|
||||
('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)*) ']')? &
|
||||
('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)*) ']')? &
|
||||
@ -200,7 +212,7 @@ Default:
|
||||
('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)*) ']')? &
|
||||
('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)*) ']')?);
|
||||
|
||||
Button:
|
||||
ButtonDefinition:
|
||||
row=INT ':' column=INT ':' cmd=Command '=' label=(ID | STRING) ('=' icon=Icon)?;
|
||||
|
||||
Mapping:
|
||||
|
@ -15,6 +15,9 @@
|
||||
*/
|
||||
package org.openhab.core.model.sitemap.validation
|
||||
|
||||
import org.openhab.core.model.sitemap.sitemap.Button
|
||||
import org.openhab.core.model.sitemap.sitemap.ButtonDefinition
|
||||
import org.openhab.core.model.sitemap.sitemap.Buttongrid
|
||||
import org.openhab.core.model.sitemap.sitemap.Frame
|
||||
import org.openhab.core.model.sitemap.sitemap.LinkableWidget
|
||||
import org.openhab.core.model.sitemap.sitemap.Setpoint
|
||||
@ -24,7 +27,6 @@ import org.openhab.core.model.sitemap.sitemap.Widget
|
||||
import org.eclipse.xtext.validation.Check
|
||||
import java.math.BigDecimal
|
||||
import org.openhab.core.model.sitemap.sitemap.Input
|
||||
import org.eclipse.xtext.nodemodel.INode
|
||||
import org.eclipse.xtext.nodemodel.util.NodeModelUtils
|
||||
|
||||
//import org.eclipse.xtext.validation.Check
|
||||
@ -45,6 +47,11 @@ class SitemapValidator extends AbstractSitemapValidator {
|
||||
SitemapPackage.Literals.FRAME.getEStructuralFeature(SitemapPackage.FRAME__CHILDREN));
|
||||
return;
|
||||
}
|
||||
if (w instanceof Button) {
|
||||
error("Frames should not contain Button, Button is allowed only in Buttongrid",
|
||||
SitemapPackage.Literals.FRAME.getEStructuralFeature(SitemapPackage.FRAME__CHILDREN));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,6 +61,11 @@ class SitemapValidator extends AbstractSitemapValidator {
|
||||
var containsOtherWidgets = false
|
||||
|
||||
for (Widget w : sitemap.children) {
|
||||
if (w instanceof Button) {
|
||||
error("Sitemap should not contain Button, Button is allowed only in Buttongrid",
|
||||
SitemapPackage.Literals.SITEMAP.getEStructuralFeature(SitemapPackage.SITEMAP__NAME));
|
||||
return;
|
||||
}
|
||||
if (w instanceof Frame) {
|
||||
containsFrames = true
|
||||
} else {
|
||||
@ -70,13 +82,21 @@ class SitemapValidator extends AbstractSitemapValidator {
|
||||
@Check
|
||||
def void checkFramesInWidgetList(LinkableWidget widget) {
|
||||
if (widget instanceof Frame) {
|
||||
|
||||
// we have a dedicated check for frames in place
|
||||
return;
|
||||
}
|
||||
if (widget instanceof Buttongrid) {
|
||||
// we have a dedicated check for Buttongrid in place
|
||||
return;
|
||||
}
|
||||
var containsFrames = false
|
||||
var containsOtherWidgets = false
|
||||
for (Widget w : widget.children) {
|
||||
if (w instanceof Button) {
|
||||
error("Linkable widget should not contain Button, Button is allowed only in Buttongrid",
|
||||
SitemapPackage.Literals.FRAME.getEStructuralFeature(SitemapPackage.LINKABLE_WIDGET__CHILDREN));
|
||||
return;
|
||||
}
|
||||
if (w instanceof Frame) {
|
||||
containsFrames = true
|
||||
} else {
|
||||
@ -90,6 +110,25 @@ class SitemapValidator extends AbstractSitemapValidator {
|
||||
}
|
||||
}
|
||||
|
||||
@Check
|
||||
def void checkWidgetsInButtongrid(Buttongrid grid) {
|
||||
var nb = 0
|
||||
for (ButtonDefinition b : grid.getButtons) {
|
||||
nb = nb + 1
|
||||
}
|
||||
if (nb > 0 && grid.item === null) {
|
||||
error("To use the \"buttons\" parameter in a Buttongrid, the \"item\" parameter is required",
|
||||
SitemapPackage.Literals.BUTTONGRID.getEStructuralFeature(SitemapPackage.BUTTONGRID__CHILDREN));
|
||||
}
|
||||
for (Widget w : grid.children) {
|
||||
if (!(w instanceof Button)) {
|
||||
error("Buttongrid must contain only Button",
|
||||
SitemapPackage.Literals.BUTTONGRID.getEStructuralFeature(SitemapPackage.BUTTONGRID__CHILDREN));
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Check
|
||||
def void checkSetpoints(Setpoint sp) {
|
||||
if (BigDecimal.ZERO == sp.step) {
|
||||
@ -107,7 +146,7 @@ class SitemapValidator extends AbstractSitemapValidator {
|
||||
SitemapPackage.Literals.SETPOINT.getEStructuralFeature(SitemapPackage.SETPOINT__MIN_VALUE));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Check
|
||||
def void checkInputHintParameter(Input i) {
|
||||
if (i.inputHint !== null && !ALLOWED_HINTS.contains(i.inputHint)) {
|
||||
|
@ -32,7 +32,7 @@ import org.openhab.core.config.core.ConfigUtil;
|
||||
import org.openhab.core.model.core.EventType;
|
||||
import org.openhab.core.model.core.ModelRepositoryChangeListener;
|
||||
import org.openhab.core.model.sitemap.SitemapProvider;
|
||||
import org.openhab.core.model.sitemap.sitemap.Button;
|
||||
import org.openhab.core.model.sitemap.sitemap.ButtonDefinition;
|
||||
import org.openhab.core.model.sitemap.sitemap.ColorArray;
|
||||
import org.openhab.core.model.sitemap.sitemap.IconRule;
|
||||
import org.openhab.core.model.sitemap.sitemap.LinkableWidget;
|
||||
@ -42,7 +42,7 @@ import org.openhab.core.model.sitemap.sitemap.SitemapFactory;
|
||||
import org.openhab.core.model.sitemap.sitemap.SitemapPackage;
|
||||
import org.openhab.core.model.sitemap.sitemap.VisibilityRule;
|
||||
import org.openhab.core.model.sitemap.sitemap.Widget;
|
||||
import org.openhab.core.model.sitemap.sitemap.impl.ButtonImpl;
|
||||
import org.openhab.core.model.sitemap.sitemap.impl.ButtonDefinitionImpl;
|
||||
import org.openhab.core.model.sitemap.sitemap.impl.ButtongridImpl;
|
||||
import org.openhab.core.model.sitemap.sitemap.impl.ChartImpl;
|
||||
import org.openhab.core.model.sitemap.sitemap.impl.ColorArrayImpl;
|
||||
@ -392,7 +392,7 @@ public class UIComponentSitemapProvider implements SitemapProvider, RegistryChan
|
||||
}
|
||||
}
|
||||
|
||||
private void addWidgetButtons(EList<Button> buttons, UIComponent component) {
|
||||
private void addWidgetButtons(EList<ButtonDefinition> buttons, UIComponent component) {
|
||||
if (component.getConfig() != null && component.getConfig().containsKey("buttons")) {
|
||||
Object sourceButtons = component.getConfig().get("buttons");
|
||||
if (sourceButtons instanceof Collection<?> sourceButtonsCollection) {
|
||||
@ -405,7 +405,8 @@ public class UIComponentSitemapProvider implements SitemapProvider, RegistryChan
|
||||
String cmd = stripQuotes(splitted2[0].trim());
|
||||
String label = stripQuotes(splitted2[1].trim());
|
||||
String icon = splitted2.length < 3 ? null : stripQuotes(splitted2[2].trim());
|
||||
ButtonImpl button = (ButtonImpl) SitemapFactory.eINSTANCE.createButton();
|
||||
ButtonDefinitionImpl button = (ButtonDefinitionImpl) SitemapFactory.eINSTANCE
|
||||
.createButtonDefinition();
|
||||
button.setRow(row);
|
||||
button.setColumn(column);
|
||||
button.setCmd(cmd);
|
||||
|
Loading…
Reference in New Issue
Block a user