[Sitemap] Add support for multiple AND conditions (#3819)

Concerns labelcolor, valuecolor and visibility

Also fix wrong positions of ")" in Sitemap.xtext

Closes #3058

Signed-off-by: Laurent Garnier <lg.hc@free.fr>
pull/3820/head^2
lolodomo 2023-10-08 09:48:58 +02:00 committed by GitHub
parent eff85c6470
commit e5518b9322
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 471 additions and 271 deletions

View File

@ -23,6 +23,7 @@ import java.util.function.Predicate;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.EList;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.common.ThreadPoolManager; import org.openhab.core.common.ThreadPoolManager;
import org.openhab.core.events.Event; import org.openhab.core.events.Event;
import org.openhab.core.events.EventSubscriber; import org.openhab.core.events.EventSubscriber;
@ -36,6 +37,7 @@ import org.openhab.core.items.events.ItemStateChangedEvent;
import org.openhab.core.library.CoreItemFactory; import org.openhab.core.library.CoreItemFactory;
import org.openhab.core.model.sitemap.sitemap.Chart; import org.openhab.core.model.sitemap.sitemap.Chart;
import org.openhab.core.model.sitemap.sitemap.ColorArray; import org.openhab.core.model.sitemap.sitemap.ColorArray;
import org.openhab.core.model.sitemap.sitemap.Condition;
import org.openhab.core.model.sitemap.sitemap.Frame; import org.openhab.core.model.sitemap.sitemap.Frame;
import org.openhab.core.model.sitemap.sitemap.VisibilityRule; import org.openhab.core.model.sitemap.sitemap.VisibilityRule;
import org.openhab.core.model.sitemap.sitemap.Widget; import org.openhab.core.model.sitemap.sitemap.Widget;
@ -47,6 +49,7 @@ import org.openhab.core.ui.items.ItemUIRegistry;
* *
* @author Kai Kreuzer - Initial contribution * @author Kai Kreuzer - Initial contribution
* @author Laurent Garnier - Added support for icon color * @author Laurent Garnier - Added support for icon color
* @author Laurent Garnier - Support added for multiple AND conditions in labelcolor/valuecolor/visibility
*/ */
public class PageChangeListener implements EventSubscriber { public class PageChangeListener implements EventSubscriber {
@ -121,25 +124,33 @@ public class PageChangeListener implements EventSubscriber {
} }
// now scan visibility rules // now scan visibility rules
for (VisibilityRule rule : widget.getVisibility()) { for (VisibilityRule rule : widget.getVisibility()) {
addItemWithName(items, rule.getItem()); addItemsFromConditions(items, rule.getConditions());
} }
// now scan label color rules // now scan label color rules
for (ColorArray rule : widget.getLabelColor()) { for (ColorArray rule : widget.getLabelColor()) {
addItemWithName(items, rule.getItem()); addItemsFromConditions(items, rule.getConditions());
} }
// now scan value color rules // now scan value color rules
for (ColorArray rule : widget.getValueColor()) { for (ColorArray rule : widget.getValueColor()) {
addItemWithName(items, rule.getItem()); addItemsFromConditions(items, rule.getConditions());
} }
// now scan value icon rules // now scan icon color rules
for (ColorArray rule : widget.getIconColor()) { for (ColorArray rule : widget.getIconColor()) {
addItemWithName(items, rule.getItem()); addItemsFromConditions(items, rule.getConditions());
} }
} }
} }
return items; return items;
} }
private void addItemsFromConditions(Set<Item> items, @Nullable EList<Condition> conditions) {
if (conditions != null) {
for (Condition condition : conditions) {
addItemWithName(items, condition.getItem());
}
}
}
private void addItemWithName(Set<Item> items, String itemName) { private void addItemWithName(Set<Item> items, String itemName) {
if (itemName != null) { if (itemName != null) {
try { try {
@ -238,10 +249,14 @@ public class PageChangeListener implements EventSubscriber {
} }
private boolean definesVisibilityOrColor(Widget w, String name) { private boolean definesVisibilityOrColor(Widget w, String name) {
return w.getVisibility().stream().anyMatch(r -> name.equals(r.getItem())) return w.getVisibility().stream().anyMatch(r -> conditionsDependsOnItem(r.getConditions(), name))
|| w.getLabelColor().stream().anyMatch(r -> name.equals(r.getItem())) || w.getLabelColor().stream().anyMatch(r -> conditionsDependsOnItem(r.getConditions(), name))
|| w.getValueColor().stream().anyMatch(r -> name.equals(r.getItem())) || w.getValueColor().stream().anyMatch(r -> conditionsDependsOnItem(r.getConditions(), name))
|| w.getIconColor().stream().anyMatch(r -> name.equals(r.getItem())); || w.getIconColor().stream().anyMatch(r -> conditionsDependsOnItem(r.getConditions(), name));
}
private boolean conditionsDependsOnItem(@Nullable EList<Condition> conditions, String name) {
return conditions != null && conditions.stream().anyMatch(c -> name.equals(c.getItem()));
} }
public void sitemapContentChanged(EList<Widget> widgets) { public void sitemapContentChanged(EList<Widget> widgets) {

View File

@ -80,6 +80,7 @@ import org.openhab.core.model.sitemap.sitemap.Button;
import org.openhab.core.model.sitemap.sitemap.Buttongrid; import org.openhab.core.model.sitemap.sitemap.Buttongrid;
import org.openhab.core.model.sitemap.sitemap.Chart; import org.openhab.core.model.sitemap.sitemap.Chart;
import org.openhab.core.model.sitemap.sitemap.ColorArray; import org.openhab.core.model.sitemap.sitemap.ColorArray;
import org.openhab.core.model.sitemap.sitemap.Condition;
import org.openhab.core.model.sitemap.sitemap.Frame; import org.openhab.core.model.sitemap.sitemap.Frame;
import org.openhab.core.model.sitemap.sitemap.Image; import org.openhab.core.model.sitemap.sitemap.Image;
import org.openhab.core.model.sitemap.sitemap.Input; import org.openhab.core.model.sitemap.sitemap.Input;
@ -135,6 +136,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
* @author Mark Herwege - Added pattern and unit fields * @author Mark Herwege - Added pattern and unit fields
* @author Laurent Garnier - Added support for new sitemap element Buttongrid * @author Laurent Garnier - Added support for new sitemap element Buttongrid
* @author Laurent Garnier - Added icon field for mappings used for switch element * @author Laurent Garnier - Added icon field for mappings used for switch element
* @author Laurent Garnier - Support added for multiple AND conditions in labelcolor/valuecolor/visibility
*/ */
@Component(service = { RESTResource.class, EventSubscriber.class }) @Component(service = { RESTResource.class, EventSubscriber.class })
@JaxrsResource @JaxrsResource
@ -769,25 +771,23 @@ public class SitemapResource
private Set<GenericItem> getItemsInVisibilityCond(EList<VisibilityRule> ruleList) { private Set<GenericItem> getItemsInVisibilityCond(EList<VisibilityRule> ruleList) {
Set<GenericItem> items = new HashSet<>(); Set<GenericItem> items = new HashSet<>();
for (VisibilityRule rule : ruleList) { for (VisibilityRule rule : ruleList) {
String itemName = rule.getItem(); getItemsInConditions(rule.getConditions(), items);
if (itemName != null) {
try {
Item item = itemUIRegistry.getItem(itemName);
if (item instanceof GenericItem genericItem) {
items.add(genericItem);
}
} catch (ItemNotFoundException e) {
// ignore
}
}
} }
return items; return items;
} }
private Set<GenericItem> getItemsInColorCond(EList<ColorArray> colorList) { private Set<GenericItem> getItemsInColorCond(EList<ColorArray> colorList) {
Set<GenericItem> items = new HashSet<>(); Set<GenericItem> items = new HashSet<>();
for (ColorArray color : colorList) { for (ColorArray rule : colorList) {
String itemName = color.getItem(); getItemsInConditions(rule.getConditions(), items);
}
return items;
}
private void getItemsInConditions(@Nullable EList<Condition> conditions, Set<GenericItem> items) {
if (conditions != null) {
for (Condition condition : conditions) {
String itemName = condition.getItem();
if (itemName != null) { if (itemName != null) {
try { try {
Item item = itemUIRegistry.getItem(itemName); Item item = itemUIRegistry.getItem(itemName);
@ -799,7 +799,7 @@ public class SitemapResource
} }
} }
} }
return items; }
} }
@Override @Override

View File

@ -49,6 +49,7 @@ import org.openhab.core.library.types.OnOffType;
import org.openhab.core.library.types.PercentType; import org.openhab.core.library.types.PercentType;
import org.openhab.core.model.sitemap.SitemapProvider; import org.openhab.core.model.sitemap.SitemapProvider;
import org.openhab.core.model.sitemap.sitemap.ColorArray; import org.openhab.core.model.sitemap.sitemap.ColorArray;
import org.openhab.core.model.sitemap.sitemap.Condition;
import org.openhab.core.model.sitemap.sitemap.Sitemap; import org.openhab.core.model.sitemap.sitemap.Sitemap;
import org.openhab.core.model.sitemap.sitemap.VisibilityRule; import org.openhab.core.model.sitemap.sitemap.VisibilityRule;
import org.openhab.core.model.sitemap.sitemap.Widget; import org.openhab.core.model.sitemap.sitemap.Widget;
@ -251,6 +252,30 @@ public class SitemapResourceTest extends JavaTest {
// return // return
} }
@Test
public void whenLongPollingShouldObserveItemsFromIconColorConditions() {
ItemEvent itemEvent = mock(ItemEvent.class);
when(itemEvent.getItemName()).thenReturn(iconColorItem.getName());
new Thread(() -> {
try {
Thread.sleep(STATE_UPDATE_WAIT_TIME); // wait for the #getPageData call and listeners to attach to the
// item
sitemapResource.receive(itemEvent);
} catch (InterruptedException e) {
}
}).start();
// non-null is sufficient here.
when(headersMock.getRequestHeader(HTTP_HEADER_X_ATMOSPHERE_TRANSPORT)).thenReturn(List.of());
Response response = sitemapResource.getPageData(headersMock, null, SITEMAP_MODEL_NAME, SITEMAP_NAME, null,
false);
PageDTO pageDTO = (PageDTO) response.getEntity();
assertThat(pageDTO.timeout, is(false)); // assert that the item state change did trigger the blocking method to
// return
}
@Test @Test
public void whenGetPageDataShouldReturnPageBean() throws ItemNotFoundException { public void whenGetPageDataShouldReturnPageBean() throws ItemNotFoundException {
item.setState(new PercentType(50)); item.setState(new PercentType(50));
@ -333,28 +358,44 @@ public class SitemapResourceTest extends JavaTest {
// add visibility rules to the mock widget: // add visibility rules to the mock widget:
VisibilityRule visibilityRule = mock(VisibilityRule.class); VisibilityRule visibilityRule = mock(VisibilityRule.class);
when(visibilityRule.getItem()).thenReturn(VISIBILITY_RULE_ITEM_NAME); Condition conditon = mock(Condition.class);
BasicEList<VisibilityRule> visibilityRules = new BasicEList<>(1); when(conditon.getItem()).thenReturn(VISIBILITY_RULE_ITEM_NAME);
EList<Condition> conditions = new BasicEList<>();
conditions.add(conditon);
when(visibilityRule.getConditions()).thenReturn(conditions);
EList<VisibilityRule> visibilityRules = new BasicEList<>(1);
visibilityRules.add(visibilityRule); visibilityRules.add(visibilityRule);
when(w1.getVisibility()).thenReturn(visibilityRules); when(w1.getVisibility()).thenReturn(visibilityRules);
// add label color conditions to the item: // add label color conditions to the item:
ColorArray labelColor = mock(ColorArray.class); ColorArray labelColor = mock(ColorArray.class);
when(labelColor.getItem()).thenReturn(LABEL_COLOR_ITEM_NAME); Condition conditon1 = mock(Condition.class);
when(conditon1.getItem()).thenReturn(LABEL_COLOR_ITEM_NAME);
EList<Condition> conditions1 = new BasicEList<>();
conditions1.add(conditon1);
when(labelColor.getConditions()).thenReturn(conditions1);
EList<ColorArray> labelColors = new BasicEList<>(); EList<ColorArray> labelColors = new BasicEList<>();
labelColors.add(labelColor); labelColors.add(labelColor);
when(w1.getLabelColor()).thenReturn(labelColors); when(w1.getLabelColor()).thenReturn(labelColors);
// add value color conditions to the item: // add value color conditions to the item:
ColorArray valueColor = mock(ColorArray.class); ColorArray valueColor = mock(ColorArray.class);
when(valueColor.getItem()).thenReturn(VALUE_COLOR_ITEM_NAME); Condition conditon2 = mock(Condition.class);
when(conditon2.getItem()).thenReturn(VALUE_COLOR_ITEM_NAME);
EList<Condition> conditions2 = new BasicEList<>();
conditions2.add(conditon2);
when(valueColor.getConditions()).thenReturn(conditions2);
EList<ColorArray> valueColors = new BasicEList<>(); EList<ColorArray> valueColors = new BasicEList<>();
valueColors.add(valueColor); valueColors.add(valueColor);
when(w1.getValueColor()).thenReturn(valueColors); when(w1.getValueColor()).thenReturn(valueColors);
// add icon color conditions to the item: // add icon color conditions to the item:
ColorArray iconColor = mock(ColorArray.class); ColorArray iconColor = mock(ColorArray.class);
when(iconColor.getItem()).thenReturn(ICON_COLOR_ITEM_NAME); Condition conditon3 = mock(Condition.class);
when(conditon3.getItem()).thenReturn(ICON_COLOR_ITEM_NAME);
EList<Condition> conditions3 = new BasicEList<>();
conditions3.add(conditon3);
when(iconColor.getConditions()).thenReturn(conditions3);
EList<ColorArray> iconColors = new BasicEList<>(); EList<ColorArray> iconColors = new BasicEList<>();
iconColors.add(iconColor); iconColors.add(iconColor);
when(w1.getIconColor()).thenReturn(iconColors); when(w1.getIconColor()).thenReturn(iconColors);
@ -376,7 +417,7 @@ public class SitemapResourceTest extends JavaTest {
when(w2.getValueColor()).thenReturn(valueColors); when(w2.getValueColor()).thenReturn(valueColors);
when(w2.getIconColor()).thenReturn(iconColors); when(w2.getIconColor()).thenReturn(iconColors);
BasicEList<Widget> widgets = new BasicEList<>(2); EList<Widget> widgets = new BasicEList<>(2);
widgets.add(w1); widgets.add(w1);
widgets.add(w2); widgets.add(w2);
return widgets; return widgets;

View File

@ -26,147 +26,147 @@ LinkableWidget:
Frame: Frame:
{Frame} 'Frame' (('item=' item=ItemRef)? & ('label=' label=(ID | STRING))? & {Frame} 'Frame' (('item=' item=ItemRef)? & ('label=' label=(ID | STRING))? &
(('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? & (('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? &
('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)* ']'))? & ('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)*) ']')? &
('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)* ']'))? & ('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)*) ']')? &
('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)* ']'))? & ('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)*) ']')? &
('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)* ']'))?); ('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)*) ']')?);
Text: Text:
{Text} 'Text' (('item=' item=ItemRef)? & ('label=' label=(ID | STRING))? & {Text} 'Text' (('item=' item=ItemRef)? & ('label=' label=(ID | STRING))? &
(('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? & (('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? &
('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)* ']'))? & ('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)*) ']')? &
('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)* ']'))? & ('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)*) ']')? &
('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)* ']'))? & ('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)*) ']')? &
('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)* ']'))?); ('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)*) ']')?);
Group: Group:
'Group' (('item=' item=GroupItemRef) & ('label=' label=(ID | STRING))? & 'Group' (('item=' item=GroupItemRef) & ('label=' label=(ID | STRING))? &
(('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? & (('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? &
('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)* ']'))? & ('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)*) ']')? &
('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)* ']'))? & ('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)*) ']')? &
('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)* ']'))? & ('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)*) ']')? &
('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)* ']'))?); ('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)*) ']')?);
Image: Image:
'Image' (('item=' item=ItemRef)? & ('label=' label=(ID | STRING))? & 'Image' (('item=' item=ItemRef)? & ('label=' label=(ID | STRING))? &
(('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? & (('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? &
('url=' url=STRING)? & ('refresh=' refresh=INT)? & ('url=' url=STRING)? & ('refresh=' refresh=INT)? &
('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)* ']'))? & ('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)*) ']')? &
('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)* ']'))? & ('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)*) ']')? &
('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)* ']'))? & ('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)*) ']')? &
('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)* ']'))?); ('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)*) ']')?);
Video: Video:
'Video' (('item=' item=ItemRef)? & ('label=' label=(ID | STRING))? & 'Video' (('item=' item=ItemRef)? & ('label=' label=(ID | STRING))? &
(('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? & (('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? &
('url=' url=STRING) & ('encoding=' encoding=STRING)? & ('url=' url=STRING) & ('encoding=' encoding=STRING)? &
('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)* ']'))? & ('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)*) ']')? &
('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)* ']'))? & ('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)*) ']')? &
('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)* ']'))? & ('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)*) ']')? &
('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)* ']'))?); ('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)*) ']')?);
Chart: Chart:
'Chart' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? & 'Chart' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? &
(('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? & (('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? &
('service=' service=STRING)? & ('refresh=' refresh=INT)? & ('period=' period=ID) & ('service=' service=STRING)? & ('refresh=' refresh=INT)? & ('period=' period=ID) &
('legend=' legend=BOOLEAN_OBJECT)? & ('forceasitem=' forceAsItem=BOOLEAN_OBJECT)? & ('legend=' legend=BOOLEAN_OBJECT)? & ('forceasitem=' forceAsItem=BOOLEAN_OBJECT)? &
('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)* ']'))? & ('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)*) ']')? &
('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)* ']'))? & ('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)*) ']')? &
('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)* ']'))? & ('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)*) ']')? &
('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)* ']'))? & ('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)*) ']')? &
('yAxisDecimalPattern=' yAxisDecimalPattern=(STRING))?); ('yAxisDecimalPattern=' yAxisDecimalPattern=(STRING))?);
Webview: Webview:
'Webview' (('item=' item=ItemRef)? & ('label=' label=(ID | STRING))? & 'Webview' (('item=' item=ItemRef)? & ('label=' label=(ID | STRING))? &
(('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? & (('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? &
('height=' height=INT)? & ('url=' url=STRING) & ('height=' height=INT)? & ('url=' url=STRING) &
('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)* ']'))? & ('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)*) ']')? &
('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)* ']'))? & ('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)*) ']')? &
('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)* ']'))? & ('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)*) ']')? &
('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)* ']'))?); ('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)*) ']')?);
Switch: Switch:
'Switch' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? & 'Switch' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? &
(('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? & (('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? &
('mappings=[' mappings+=Mapping (',' mappings+=Mapping)* ']')? & ('mappings=[' mappings+=Mapping (',' mappings+=Mapping)* ']')? &
('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)* ']'))? & ('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)*) ']')? &
('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)* ']'))? & ('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)*) ']')? &
('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)* ']'))? & ('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)*) ']')? &
('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)* ']'))?); ('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)*) ']')?);
Mapview: Mapview:
'Mapview' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? & 'Mapview' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? &
(('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? & (('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? &
('height=' height=INT)? & ('height=' height=INT)? &
('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)* ']'))? & ('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)*) ']')? &
('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)* ']'))? & ('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)*) ']')? &
('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)* ']'))? & ('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)*) ']')? &
('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)* ']'))?); ('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)*) ']')?);
Slider: Slider:
'Slider' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? & 'Slider' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? &
(('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? & (('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? &
('sendFrequency=' frequency=INT)? & (switchEnabled?='switchSupport')? & ('sendFrequency=' frequency=INT)? & (switchEnabled?='switchSupport')? &
('minValue=' minValue=Number)? & ('maxValue=' maxValue=Number)? & ('step=' step=Number)? & ('minValue=' minValue=Number)? & ('maxValue=' maxValue=Number)? & ('step=' step=Number)? &
('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)* ']'))? & ('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)*) ']')? &
('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)* ']'))? & ('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)*) ']')? &
('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)* ']'))? & ('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)*) ']')? &
('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)* ']'))?); ('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)*) ']')?);
Selection: Selection:
'Selection' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? & 'Selection' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? &
(('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? & (('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? &
('mappings=[' mappings+=Mapping (',' mappings+=Mapping)* ']')? & ('mappings=[' mappings+=Mapping (',' mappings+=Mapping)* ']')? &
('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)* ']'))? & ('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)*) ']')? &
('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)* ']'))? & ('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)*) ']')? &
('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)* ']'))? & ('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)*) ']')? &
('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)* ']'))?); ('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)*) ']')?);
Setpoint: Setpoint:
'Setpoint' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? & 'Setpoint' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? &
(('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? & (('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? &
('minValue=' minValue=Number)? & ('maxValue=' maxValue=Number)? & ('step=' step=Number)? & ('minValue=' minValue=Number)? & ('maxValue=' maxValue=Number)? & ('step=' step=Number)? &
('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)* ']'))? & ('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)*) ']')? &
('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)* ']'))? & ('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)*) ']')? &
('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)* ']'))? & ('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)*) ']')? &
('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)* ']'))?); ('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)*) ']')?);
Colorpicker: Colorpicker:
'Colorpicker' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? & 'Colorpicker' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? &
(('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? & (('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? &
('sendFrequency=' frequency=INT)? & ('sendFrequency=' frequency=INT)? &
('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)* ']'))? & ('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)*) ']')? &
('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)* ']'))? & ('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)*) ']')? &
('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)* ']'))? & ('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)*) ']')? &
('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)* ']'))?); ('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)*) ']')?);
Input: Input:
'Input' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? & 'Input' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? &
(('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? & (('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? &
('inputHint=' inputHint=STRING)? & ('inputHint=' inputHint=STRING)? &
('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)* ']'))? & ('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)*) ']')? &
('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)* ']'))? & ('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)*) ']')? &
('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)* ']'))? & ('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)*) ']')? &
('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)* ']'))?); ('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)*) ']')?);
Buttongrid: Buttongrid:
'Buttongrid' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? & 'Buttongrid' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? &
(('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? & (('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? &
('columns=' columns=INT) & ('columns=' columns=INT) &
('buttons=[' buttons+=Button (',' buttons+=Button)* ']') & ('buttons=[' buttons+=Button (',' buttons+=Button)* ']') &
('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)* ']'))? & ('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)*) ']')? &
('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)* ']'))? & ('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)*) ']')? &
('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)* ']'))? & ('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)*) ']')? &
('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)* ']'))?); ('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)*) ']')?);
Default: Default:
'Default' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? & 'Default' (('item=' item=ItemRef) & ('label=' label=(ID | STRING))? &
(('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? & (('icon=' icon=Icon) | ('staticIcon=' staticIcon=Icon))? &
('height=' height=INT)? & ('height=' height=INT)? &
('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)* ']'))? & ('labelcolor=[' (LabelColor+=ColorArray (',' LabelColor+=ColorArray)*) ']')? &
('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)* ']'))? & ('valuecolor=[' (ValueColor+=ColorArray (',' ValueColor+=ColorArray)*) ']')? &
('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)* ']'))? & ('iconcolor=[' (IconColor+=ColorArray (',' IconColor+=ColorArray)*) ']')? &
('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)* ']'))?); ('visibility=[' (Visibility+=VisibilityRule (',' Visibility+=VisibilityRule)*) ']')?);
Button: Button:
position=INT ':' cmd=Command '=' label=(ID | STRING) ('=' icon=Icon)?; position=INT ':' cmd=Command '=' label=(ID | STRING) ('=' icon=Icon)?;
@ -175,7 +175,7 @@ Mapping:
cmd=Command '=' label=(ID | STRING) ('=' icon=Icon)?; cmd=Command '=' label=(ID | STRING) ('=' icon=Icon)?;
VisibilityRule: VisibilityRule:
(item=ID) (condition=('==' | '>' | '<' | '>=' | '<=' | '!=')) (sign=('-' | '+'))? (state=XState); conditions+=Condition ('AND' conditions+=Condition)*;
ItemRef: ItemRef:
ID; ID;
@ -191,8 +191,10 @@ IconName:
(ID '-')* ID; (ID '-')* ID;
ColorArray: ColorArray:
((item=ID)? (condition=('==' | '>' | '<' | '>=' | '<=' | '!='))? (sign=('-' | '+'))? (state=XState) '=')? ((conditions+=Condition ('AND' conditions+=Condition)*) '=')? (arg=STRING);
(arg=STRING);
Condition:
(item=ID)? (condition=('==' | '>' | '<' | '>=' | '<=' | '!='))? (sign=('-' | '+'))? (state=XState);
Command returns ecore::EString: Command returns ecore::EString:
Number | ID | STRING; Number | ID | STRING;

View File

@ -44,6 +44,7 @@ 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.ChartImpl;
import org.openhab.core.model.sitemap.sitemap.impl.ColorArrayImpl; import org.openhab.core.model.sitemap.sitemap.impl.ColorArrayImpl;
import org.openhab.core.model.sitemap.sitemap.impl.ColorpickerImpl; import org.openhab.core.model.sitemap.sitemap.impl.ColorpickerImpl;
import org.openhab.core.model.sitemap.sitemap.impl.ConditionImpl;
import org.openhab.core.model.sitemap.sitemap.impl.DefaultImpl; import org.openhab.core.model.sitemap.sitemap.impl.DefaultImpl;
import org.openhab.core.model.sitemap.sitemap.impl.FrameImpl; import org.openhab.core.model.sitemap.sitemap.impl.FrameImpl;
import org.openhab.core.model.sitemap.sitemap.impl.GroupImpl; import org.openhab.core.model.sitemap.sitemap.impl.GroupImpl;
@ -378,10 +379,12 @@ public class UIComponentSitemapProvider implements SitemapProvider, RegistryChan
if (matcher.matches()) { if (matcher.matches()) {
VisibilityRuleImpl visibilityRule = (VisibilityRuleImpl) SitemapFactory.eINSTANCE VisibilityRuleImpl visibilityRule = (VisibilityRuleImpl) SitemapFactory.eINSTANCE
.createVisibilityRule(); .createVisibilityRule();
visibilityRule.setItem(matcher.group("item")); ConditionImpl condition = (ConditionImpl) SitemapFactory.eINSTANCE.createCondition();
visibilityRule.setCondition(matcher.group("condition")); condition.setItem(matcher.group("item"));
visibilityRule.setSign(matcher.group("sign")); condition.setCondition(matcher.group("condition"));
visibilityRule.setState(matcher.group("state")); condition.setSign(matcher.group("sign"));
condition.setState(matcher.group("state"));
visibilityRule.eSet(SitemapPackage.VISIBILITY_RULE__CONDITIONS, condition);
visibility.add(visibilityRule); visibility.add(visibilityRule);
} else { } else {
logger.warn("Syntax error in visibility rule '{}' for widget {}", sourceVisibility, logger.warn("Syntax error in visibility rule '{}' for widget {}", sourceVisibility,
@ -411,11 +414,12 @@ public class UIComponentSitemapProvider implements SitemapProvider, RegistryChan
Matcher matcher = COLOR_PATTERN.matcher(sourceColor.toString()); Matcher matcher = COLOR_PATTERN.matcher(sourceColor.toString());
if (matcher.matches()) { if (matcher.matches()) {
ColorArrayImpl colorArray = (ColorArrayImpl) SitemapFactory.eINSTANCE.createColorArray(); ColorArrayImpl colorArray = (ColorArrayImpl) SitemapFactory.eINSTANCE.createColorArray();
colorArray.setItem(matcher.group("item")); ConditionImpl condition = (ConditionImpl) SitemapFactory.eINSTANCE.createCondition();
colorArray.setCondition(matcher.group("condition")); condition.setItem(matcher.group("item"));
colorArray.setSign(matcher.group("sign")); condition.setCondition(matcher.group("condition"));
colorArray.setState(matcher.group("state")); condition.setSign(matcher.group("sign"));
colorArray.setArg(matcher.group("arg")); condition.setState(matcher.group("state"));
colorArray.eSet(SitemapPackage.COLOR_ARRAY__CONDITIONS, condition);
color.add(colorArray); color.add(colorArray);
} else { } else {
logger.warn("Syntax error in {} rule '{}' for widget {}", key, sourceColor, logger.warn("Syntax error in {} rule '{}' for widget {}", key, sourceColor,

View File

@ -109,6 +109,7 @@ import org.slf4j.LoggerFactory;
* @author Erdoan Hadzhiyusein - Adapted the class to work with the new DateTimeType * @author Erdoan Hadzhiyusein - Adapted the class to work with the new DateTimeType
* @author Laurent Garnier - new method getIconColor * @author Laurent Garnier - new method getIconColor
* @author Mark Herwege - new method getFormatPattern(widget), clean pattern * @author Mark Herwege - new method getFormatPattern(widget), clean pattern
* @author Laurent Garnier - Support added for multiple AND conditions in labelcolor/valuecolor/visibility
*/ */
@NonNullByDefault @NonNullByDefault
@Component(immediate = true, configurationPid = "org.openhab.sitemap", // @Component(immediate = true, configurationPid = "org.openhab.sitemap", //
@ -1149,152 +1150,120 @@ public class ItemUIRegistryImpl implements ItemUIRegistry {
return matched; return matched;
} }
private @Nullable String processColorDefinition(@Nullable State state, @Nullable List<ColorArray> colorList) { private @Nullable String processColorDefinition(Widget w, @Nullable List<ColorArray> colorList, String colorType) {
// Sanity check // Sanity check
if (colorList == null) { if (colorList == null || colorList.isEmpty()) {
return null;
}
if (colorList.isEmpty()) {
return null; return null;
} }
logger.debug("Checking {} color for widget '{}'.", colorType, w.getLabel());
String colorString = null; String colorString = null;
// Check for the "arg". If it doesn't exist, assume there's just an
// static colour
if (colorList.size() == 1 && colorList.get(0).getState() == null) {
colorString = colorList.get(0).getArg();
} else {
// Loop through all elements looking for the definition associated // Loop through all elements looking for the definition associated
// with the supplied value // with the supplied value
for (ColorArray color : colorList) { for (ColorArray rule : colorList) {
// Use a local state variable in case it gets overridden below if (allConditionsOk(rule.getConditions(), w)) {
State cmpState = state;
if (color.getState() == null) {
// If no state associated to the condition, we consider the condition as fulfilled.
// It allows defining a default color as last condition in particular.
colorString = color.getArg();
break;
}
// If there's an item defined here, get its state
String itemName = color.getItem();
if (itemName != null) {
// Try and find the item to test.
// If it's not found, return visible
Item item;
try {
item = itemRegistry.getItem(itemName);
// Get the item state
cmpState = item.getState();
} catch (ItemNotFoundException e) {
logger.warn("Cannot retrieve color item {} for widget", color.getItem());
}
}
// Handle the sign
String value;
if (color.getSign() != null) {
value = color.getSign() + color.getState();
} else {
value = color.getState();
}
if (cmpState != null && matchStateToValue(cmpState, value, color.getCondition())) {
// We have the color for this value - break! // We have the color for this value - break!
colorString = color.getArg(); colorString = rule.getArg();
break; break;
} }
} }
}
// Remove quotes off the colour - if they exist
if (colorString == null) { if (colorString == null) {
logger.debug("No {} color found for widget '{}'.", colorType, w.getLabel());
return null; return null;
} }
// Remove quotes off the colour - if they exist
if (colorString.startsWith("\"") && colorString.endsWith("\"")) { if (colorString.startsWith("\"") && colorString.endsWith("\"")) {
colorString = colorString.substring(1, colorString.length() - 1); colorString = colorString.substring(1, colorString.length() - 1);
} }
logger.debug("{} color for widget '{}' is '{}'.", colorType, w.getLabel(), colorString);
return colorString; return colorString;
} }
@Override @Override
public @Nullable String getLabelColor(Widget w) { public @Nullable String getLabelColor(Widget w) {
return processColorDefinition(getState(w), w.getLabelColor()); return processColorDefinition(w, w.getLabelColor(), "label");
} }
@Override @Override
public @Nullable String getValueColor(Widget w) { public @Nullable String getValueColor(Widget w) {
return processColorDefinition(getState(w), w.getValueColor()); return processColorDefinition(w, w.getValueColor(), "value");
} }
@Override @Override
public @Nullable String getIconColor(Widget w) { public @Nullable String getIconColor(Widget w) {
return processColorDefinition(getState(w), w.getIconColor()); return processColorDefinition(w, w.getIconColor(), "icon");
} }
@Override @Override
public boolean getVisiblity(Widget w) { public boolean getVisiblity(Widget w) {
// Default to visible if parameters not set // Default to visible if parameters not set
List<VisibilityRule> ruleList = w.getVisibility(); List<VisibilityRule> ruleList = w.getVisibility();
if (ruleList == null) { if (ruleList == null || ruleList.isEmpty()) {
return true;
}
if (ruleList.isEmpty()) {
return true; return true;
} }
logger.debug("Checking visiblity for widget '{}'.", w.getLabel()); logger.debug("Checking visiblity for widget '{}'.", w.getLabel());
for (VisibilityRule rule : w.getVisibility()) { for (VisibilityRule rule : ruleList) {
String itemName = rule.getItem(); if (allConditionsOk(rule.getConditions(), w)) {
if (itemName == null) {
continue;
}
if (rule.getState() == null) {
continue;
}
// Try and find the item to test.
// If it's not found, return visible
Item item;
try {
item = itemRegistry.getItem(itemName);
} catch (ItemNotFoundException e) {
logger.warn("Cannot retrieve visibility item {} for widget {}", rule.getItem(),
w.eClass().getInstanceTypeName());
// Default to visible!
return true;
}
// Get the item state
State state = item.getState();
// Handle the sign
String value;
if (rule.getSign() != null) {
value = rule.getSign() + rule.getState();
} else {
value = rule.getState();
}
if (matchStateToValue(state, value, rule.getCondition())) {
// We have the name for this value!
return true; return true;
} }
} }
logger.debug("Widget {} is not visible.", w.getLabel()); logger.debug("Widget {} is not visible.", w.getLabel());
// The state wasn't in the list, so we don't display it
return false; return false;
} }
private boolean allConditionsOk(@Nullable List<org.openhab.core.model.sitemap.sitemap.Condition> conditions,
Widget w) {
boolean allConditionsOk = true;
if (conditions != null) {
State defaultState = getState(w);
// Go through all AND conditions
for (org.openhab.core.model.sitemap.sitemap.Condition condition : conditions) {
// Use a local state variable in case it gets overridden below
State state = defaultState;
// If there's an item defined here, get its state
String itemName = condition.getItem();
if (itemName != null) {
// Try and find the item to test.
Item item;
try {
item = itemRegistry.getItem(itemName);
// Get the item state
state = item.getState();
} catch (ItemNotFoundException e) {
logger.warn("Cannot retrieve item {} for widget {}", itemName,
w.eClass().getInstanceTypeName());
}
}
// Handle the sign
String value;
if (condition.getSign() != null) {
value = condition.getSign() + condition.getState();
} else {
value = condition.getState();
}
if (state == null || !matchStateToValue(state, value, condition.getCondition())) {
allConditionsOk = false;
break;
}
}
}
return allConditionsOk;
}
enum Condition { enum Condition {
EQUAL("=="), EQUAL("=="),
GTE(">="), GTE(">="),

View File

@ -60,6 +60,7 @@ import org.openhab.core.library.types.QuantityType;
import org.openhab.core.library.types.StringType; import org.openhab.core.library.types.StringType;
import org.openhab.core.model.sitemap.sitemap.ColorArray; import org.openhab.core.model.sitemap.sitemap.ColorArray;
import org.openhab.core.model.sitemap.sitemap.Colorpicker; import org.openhab.core.model.sitemap.sitemap.Colorpicker;
import org.openhab.core.model.sitemap.sitemap.Condition;
import org.openhab.core.model.sitemap.sitemap.Group; import org.openhab.core.model.sitemap.sitemap.Group;
import org.openhab.core.model.sitemap.sitemap.Image; import org.openhab.core.model.sitemap.sitemap.Image;
import org.openhab.core.model.sitemap.sitemap.Mapping; import org.openhab.core.model.sitemap.sitemap.Mapping;
@ -70,6 +71,7 @@ import org.openhab.core.model.sitemap.sitemap.SitemapFactory;
import org.openhab.core.model.sitemap.sitemap.Slider; import org.openhab.core.model.sitemap.sitemap.Slider;
import org.openhab.core.model.sitemap.sitemap.Switch; import org.openhab.core.model.sitemap.sitemap.Switch;
import org.openhab.core.model.sitemap.sitemap.Text; import org.openhab.core.model.sitemap.sitemap.Text;
import org.openhab.core.model.sitemap.sitemap.VisibilityRule;
import org.openhab.core.model.sitemap.sitemap.Widget; import org.openhab.core.model.sitemap.sitemap.Widget;
import org.openhab.core.types.CommandDescriptionBuilder; import org.openhab.core.types.CommandDescriptionBuilder;
import org.openhab.core.types.CommandOption; import org.openhab.core.types.CommandOption;
@ -83,6 +85,7 @@ import org.openhab.core.ui.items.ItemUIProvider;
/** /**
* @author Kai Kreuzer - Initial contribution * @author Kai Kreuzer - Initial contribution
* @author Laurent Garnier - Tests updated to consider multiple AND conditions + tests added for getVisiblity
*/ */
@ExtendWith(MockitoExtension.class) @ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT) @MockitoSettings(strictness = Strictness.LENIENT)
@ -736,18 +739,27 @@ public class ItemUIRegistryImplTest {
when(widgetMock.getLabel()).thenReturn(testLabel); when(widgetMock.getLabel()).thenReturn(testLabel);
ColorArray colorArray = mock(ColorArray.class); Condition conditon = mock(Condition.class);
when(colorArray.getState()).thenReturn("21"); when(conditon.getState()).thenReturn("21");
when(colorArray.getCondition()).thenReturn("<"); when(conditon.getCondition()).thenReturn("<");
when(colorArray.getArg()).thenReturn("yellow"); BasicEList<Condition> conditions = new BasicEList<>();
BasicEList<ColorArray> colorArrays = new BasicEList<>(); conditions.add(conditon);
colorArrays.add(colorArray); ColorArray rule = mock(ColorArray.class);
when(widgetMock.getLabelColor()).thenReturn(colorArrays); when(rule.getConditions()).thenReturn(conditions);
when(rule.getArg()).thenReturn("yellow");
BasicEList<ColorArray> rules = new BasicEList<>();
rules.add(rule);
when(widgetMock.getLabelColor()).thenReturn(rules);
when(itemMock.getState()).thenReturn(new DecimalType(10f / 3f)); when(itemMock.getState()).thenReturn(new DecimalType(10f / 3f));
String color = uiRegistry.getLabelColor(widgetMock); String color = uiRegistry.getLabelColor(widgetMock);
assertEquals("yellow", color); assertEquals("yellow", color);
when(itemMock.getState()).thenReturn(new DecimalType(21f));
color = uiRegistry.getLabelColor(widgetMock);
assertNull(color);
} }
@Test @Test
@ -756,18 +768,27 @@ public class ItemUIRegistryImplTest {
when(widgetMock.getLabel()).thenReturn(testLabel); when(widgetMock.getLabel()).thenReturn(testLabel);
ColorArray colorArray = mock(ColorArray.class); Condition conditon = mock(Condition.class);
when(colorArray.getState()).thenReturn("20"); when(conditon.getState()).thenReturn("20");
when(colorArray.getCondition()).thenReturn("=="); when(conditon.getCondition()).thenReturn("==");
when(colorArray.getArg()).thenReturn("yellow"); BasicEList<Condition> conditions = new BasicEList<>();
BasicEList<ColorArray> colorArrays = new BasicEList<>(); conditions.add(conditon);
colorArrays.add(colorArray); ColorArray rule = mock(ColorArray.class);
when(widgetMock.getLabelColor()).thenReturn(colorArrays); when(rule.getConditions()).thenReturn(conditions);
when(rule.getArg()).thenReturn("yellow");
BasicEList<ColorArray> rules = new BasicEList<>();
rules.add(rule);
when(widgetMock.getLabelColor()).thenReturn(rules);
when(itemMock.getState()).thenReturn(new QuantityType<>("20 °C")); when(itemMock.getState()).thenReturn(new QuantityType<>("20 °C"));
String color = uiRegistry.getLabelColor(widgetMock); String color = uiRegistry.getLabelColor(widgetMock);
assertEquals("yellow", color); assertEquals("yellow", color);
when(itemMock.getState()).thenReturn(new QuantityType<>("20.1 °C"));
color = uiRegistry.getLabelColor(widgetMock);
assertNull(color);
} }
@Test @Test
@ -925,44 +946,108 @@ public class ItemUIRegistryImplTest {
when(widgetMock.getLabel()).thenReturn(testLabel); when(widgetMock.getLabel()).thenReturn(testLabel);
ColorArray colorArray = mock(ColorArray.class); Condition conditon = mock(Condition.class);
when(colorArray.getState()).thenReturn("21"); when(conditon.getState()).thenReturn("18");
when(colorArray.getCondition()).thenReturn("<"); when(conditon.getCondition()).thenReturn(">=");
when(colorArray.getArg()).thenReturn("yellow"); Condition conditon2 = mock(Condition.class);
BasicEList<ColorArray> colorArrays = new BasicEList<>(); when(conditon2.getState()).thenReturn("21");
colorArrays.add(colorArray); when(conditon2.getCondition()).thenReturn("<");
ColorArray colorArray2 = mock(ColorArray.class); BasicEList<Condition> conditions = new BasicEList<>();
when(colorArray2.getState()).thenReturn(null); conditions.add(conditon);
when(colorArray2.getCondition()).thenReturn(null); conditions.add(conditon2);
when(colorArray2.getArg()).thenReturn("blue"); ColorArray rule = mock(ColorArray.class);
colorArrays.add(colorArray2); when(rule.getConditions()).thenReturn(conditions);
when(widgetMock.getLabelColor()).thenReturn(colorArrays); when(rule.getArg()).thenReturn("yellow");
BasicEList<ColorArray> rules = new BasicEList<>();
rules.add(rule);
Condition conditon3 = mock(Condition.class);
when(conditon3.getState()).thenReturn("21");
when(conditon3.getCondition()).thenReturn(">=");
Condition conditon4 = mock(Condition.class);
when(conditon4.getState()).thenReturn("24");
when(conditon4.getCondition()).thenReturn("<");
BasicEList<Condition> conditions2 = new BasicEList<>();
conditions2.add(conditon3);
conditions2.add(conditon4);
ColorArray rule2 = mock(ColorArray.class);
when(rule2.getConditions()).thenReturn(conditions2);
when(rule2.getArg()).thenReturn("red");
rules.add(rule2);
BasicEList<Condition> conditions5 = new BasicEList<>();
ColorArray rule3 = mock(ColorArray.class);
when(rule3.getConditions()).thenReturn(conditions5);
when(rule3.getArg()).thenReturn("blue");
rules.add(rule3);
when(widgetMock.getLabelColor()).thenReturn(rules);
when(itemMock.getState()).thenReturn(new DecimalType(21.0)); when(itemMock.getState()).thenReturn(new DecimalType(20.9));
String color = uiRegistry.getLabelColor(widgetMock); String color = uiRegistry.getLabelColor(widgetMock);
assertEquals("yellow", color);
when(itemMock.getState()).thenReturn(new DecimalType(23.5));
color = uiRegistry.getLabelColor(widgetMock);
assertEquals("red", color);
when(itemMock.getState()).thenReturn(new DecimalType(24.0));
color = uiRegistry.getLabelColor(widgetMock);
assertEquals("blue", color);
when(itemMock.getState()).thenReturn(new DecimalType(17.5));
color = uiRegistry.getLabelColor(widgetMock);
assertEquals("blue", color);
conditions5 = null;
when(itemMock.getState()).thenReturn(new DecimalType(24.0));
color = uiRegistry.getLabelColor(widgetMock);
assertEquals("blue", color);
when(itemMock.getState()).thenReturn(new DecimalType(17.5));
color = uiRegistry.getLabelColor(widgetMock);
assertEquals("blue", color); assertEquals("blue", color);
} }
@Test @Test
public void getValueColor() { public void getValueColor() {
ColorArray colorArray = mock(ColorArray.class); Condition conditon = mock(Condition.class);
when(colorArray.getState()).thenReturn("21"); when(conditon.getState()).thenReturn("18");
when(colorArray.getCondition()).thenReturn("<"); when(conditon.getCondition()).thenReturn(">=");
when(colorArray.getArg()).thenReturn("yellow"); Condition conditon2 = mock(Condition.class);
BasicEList<ColorArray> colorArrays = new BasicEList<>(); when(conditon2.getState()).thenReturn("21");
colorArrays.add(colorArray); when(conditon2.getCondition()).thenReturn("<");
ColorArray colorArray2 = mock(ColorArray.class); BasicEList<Condition> conditions = new BasicEList<>();
when(colorArray2.getState()).thenReturn("24"); conditions.add(conditon);
when(colorArray2.getCondition()).thenReturn("<"); conditions.add(conditon2);
when(colorArray2.getArg()).thenReturn("red"); ColorArray rule = mock(ColorArray.class);
colorArrays.add(colorArray2); when(rule.getConditions()).thenReturn(conditions);
ColorArray colorArray3 = mock(ColorArray.class); when(rule.getArg()).thenReturn("yellow");
when(colorArray3.getState()).thenReturn(null); BasicEList<ColorArray> rules = new BasicEList<>();
when(colorArray3.getCondition()).thenReturn(null); rules.add(rule);
when(colorArray3.getArg()).thenReturn("blue"); Condition conditon3 = mock(Condition.class);
colorArrays.add(colorArray3); when(conditon3.getState()).thenReturn("21");
when(widgetMock.getValueColor()).thenReturn(colorArrays); when(conditon3.getCondition()).thenReturn(">=");
Condition conditon4 = mock(Condition.class);
when(conditon4.getState()).thenReturn("24");
when(conditon4.getCondition()).thenReturn("<");
BasicEList<Condition> conditions2 = new BasicEList<>();
conditions2.add(conditon3);
conditions2.add(conditon4);
ColorArray rule2 = mock(ColorArray.class);
when(rule2.getConditions()).thenReturn(conditions2);
when(rule2.getArg()).thenReturn("red");
rules.add(rule2);
BasicEList<Condition> conditions5 = new BasicEList<>();
ColorArray rule3 = mock(ColorArray.class);
when(rule3.getConditions()).thenReturn(conditions5);
when(rule3.getArg()).thenReturn("blue");
rules.add(rule3);
when(widgetMock.getValueColor()).thenReturn(rules);
when(itemMock.getState()).thenReturn(new DecimalType(20.9)); when(itemMock.getState()).thenReturn(new DecimalType(20.9));
@ -974,7 +1059,24 @@ public class ItemUIRegistryImplTest {
color = uiRegistry.getValueColor(widgetMock); color = uiRegistry.getValueColor(widgetMock);
assertEquals("red", color); assertEquals("red", color);
when(itemMock.getState()).thenReturn(new DecimalType(30.0)); when(itemMock.getState()).thenReturn(new DecimalType(24.0));
color = uiRegistry.getValueColor(widgetMock);
assertEquals("blue", color);
when(itemMock.getState()).thenReturn(new DecimalType(17.5));
color = uiRegistry.getValueColor(widgetMock);
assertEquals("blue", color);
conditions5 = null;
when(itemMock.getState()).thenReturn(new DecimalType(24.0));
color = uiRegistry.getValueColor(widgetMock);
assertEquals("blue", color);
when(itemMock.getState()).thenReturn(new DecimalType(17.5));
color = uiRegistry.getValueColor(widgetMock); color = uiRegistry.getValueColor(widgetMock);
assertEquals("blue", color); assertEquals("blue", color);
@ -982,23 +1084,39 @@ public class ItemUIRegistryImplTest {
@Test @Test
public void getIconColor() { public void getIconColor() {
ColorArray colorArray = mock(ColorArray.class); Condition conditon = mock(Condition.class);
when(colorArray.getState()).thenReturn("21"); when(conditon.getState()).thenReturn("18");
when(colorArray.getCondition()).thenReturn("<"); when(conditon.getCondition()).thenReturn(">=");
when(colorArray.getArg()).thenReturn("yellow"); Condition conditon2 = mock(Condition.class);
BasicEList<ColorArray> colorArrays = new BasicEList<>(); when(conditon2.getState()).thenReturn("21");
colorArrays.add(colorArray); when(conditon2.getCondition()).thenReturn("<");
ColorArray colorArray2 = mock(ColorArray.class); BasicEList<Condition> conditions = new BasicEList<>();
when(colorArray2.getState()).thenReturn("24"); conditions.add(conditon);
when(colorArray2.getCondition()).thenReturn("<"); conditions.add(conditon2);
when(colorArray2.getArg()).thenReturn("red"); ColorArray rule = mock(ColorArray.class);
colorArrays.add(colorArray2); when(rule.getConditions()).thenReturn(conditions);
ColorArray colorArray3 = mock(ColorArray.class); when(rule.getArg()).thenReturn("yellow");
when(colorArray3.getState()).thenReturn(null); BasicEList<ColorArray> rules = new BasicEList<>();
when(colorArray3.getCondition()).thenReturn(null); rules.add(rule);
when(colorArray3.getArg()).thenReturn("blue"); Condition conditon3 = mock(Condition.class);
colorArrays.add(colorArray3); when(conditon3.getState()).thenReturn("21");
when(widgetMock.getIconColor()).thenReturn(colorArrays); when(conditon3.getCondition()).thenReturn(">=");
Condition conditon4 = mock(Condition.class);
when(conditon4.getState()).thenReturn("24");
when(conditon4.getCondition()).thenReturn("<");
BasicEList<Condition> conditions2 = new BasicEList<>();
conditions2.add(conditon3);
conditions2.add(conditon4);
ColorArray rule2 = mock(ColorArray.class);
when(rule2.getConditions()).thenReturn(conditions2);
when(rule2.getArg()).thenReturn("red");
rules.add(rule2);
BasicEList<Condition> conditions5 = new BasicEList<>();
ColorArray rule3 = mock(ColorArray.class);
when(rule3.getConditions()).thenReturn(conditions5);
when(rule3.getArg()).thenReturn("blue");
rules.add(rule3);
when(widgetMock.getIconColor()).thenReturn(rules);
when(itemMock.getState()).thenReturn(new DecimalType(20.9)); when(itemMock.getState()).thenReturn(new DecimalType(20.9));
@ -1010,9 +1128,60 @@ public class ItemUIRegistryImplTest {
color = uiRegistry.getIconColor(widgetMock); color = uiRegistry.getIconColor(widgetMock);
assertEquals("red", color); assertEquals("red", color);
when(itemMock.getState()).thenReturn(new DecimalType(30.0)); when(itemMock.getState()).thenReturn(new DecimalType(24.0));
color = uiRegistry.getIconColor(widgetMock);
assertEquals("blue", color);
when(itemMock.getState()).thenReturn(new DecimalType(17.5));
color = uiRegistry.getIconColor(widgetMock);
assertEquals("blue", color);
conditions5 = null;
when(itemMock.getState()).thenReturn(new DecimalType(24.0));
color = uiRegistry.getIconColor(widgetMock);
assertEquals("blue", color);
when(itemMock.getState()).thenReturn(new DecimalType(17.5));
color = uiRegistry.getIconColor(widgetMock); color = uiRegistry.getIconColor(widgetMock);
assertEquals("blue", color); assertEquals("blue", color);
} }
@Test
public void getVisibility() {
Condition conditon = mock(Condition.class);
when(conditon.getState()).thenReturn("21");
when(conditon.getCondition()).thenReturn(">=");
Condition conditon2 = mock(Condition.class);
when(conditon2.getState()).thenReturn("24");
when(conditon2.getCondition()).thenReturn("<");
BasicEList<Condition> conditions = new BasicEList<>();
conditions.add(conditon);
conditions.add(conditon2);
VisibilityRule rule = mock(VisibilityRule.class);
when(rule.getConditions()).thenReturn(conditions);
BasicEList<VisibilityRule> rules = new BasicEList<>();
rules.add(rule);
when(widgetMock.getVisibility()).thenReturn(rules);
when(itemMock.getState()).thenReturn(new DecimalType(20.9));
assertFalse(uiRegistry.getVisiblity(widgetMock));
when(itemMock.getState()).thenReturn(new DecimalType(21.0));
assertTrue(uiRegistry.getVisiblity(widgetMock));
when(itemMock.getState()).thenReturn(new DecimalType(23.5));
assertTrue(uiRegistry.getVisiblity(widgetMock));
when(itemMock.getState()).thenReturn(new DecimalType(24.0));
assertFalse(uiRegistry.getVisiblity(widgetMock));
}
} }