/*
* Copyright (c) 2010-2016 Evolveum
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.evolveum.midpoint.web.component.prism;
import com.evolveum.midpoint.common.refinery.RefinedAttributeDefinition;
import com.evolveum.midpoint.gui.api.model.LoadableModel;
import com.evolveum.midpoint.gui.api.page.PageBase;
import com.evolveum.midpoint.prism.*;
import com.evolveum.midpoint.prism.delta.ItemDelta;
import com.evolveum.midpoint.prism.path.ItemPath;
import com.evolveum.midpoint.schema.DeltaConvertor;
import com.evolveum.midpoint.util.exception.SchemaException;
import com.evolveum.midpoint.util.logging.LoggingUtils;
import com.evolveum.midpoint.util.logging.Trace;
import com.evolveum.midpoint.util.logging.TraceManager;
import com.evolveum.midpoint.web.component.util.VisibleEnableBehaviour;
import com.evolveum.midpoint.web.util.InfoTooltipBehavior;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType;
import com.evolveum.midpoint.xml.ns._public.common.common_3.ShadowType;
import com.evolveum.prism.xml.ns._public.types_3.ItemDeltaType;
import com.evolveum.prism.xml.ns._public.types_3.ObjectDeltaType;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.Validate;
import org.apache.wicket.AttributeModifier;
import org.apache.wicket.markup.html.WebMarkupContainer;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.*;
import java.util.List;
/**
* @author lazyman
*/
public class PrismPropertyPanel<IW extends ItemWrapper> extends Panel {
private static final long serialVersionUID = 1L;
private static final Trace LOGGER = TraceManager.getTrace(PrismPropertyPanel.class);
private static final String ID_HAS_PENDING_MODIFICATION = "hasPendingModification";
private static final String ID_HELP = "help";
private static final String ID_LABEL = "label";
private static final String ID_LABEL_CONTAINER = "labelContainer";
private PageBase pageBase;
private boolean labelContainerVisible = true;
public PrismPropertyPanel(String id, final IModel<IW> model, Form form, PageBase pageBase) {
super(id);
Validate.notNull(model, "no model");
this.pageBase = pageBase;
LOGGER.trace("Creating property panel for {}", model.getObject());
setOutputMarkupId(true);
add(new VisibleEnableBehaviour() {
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible() {
IW propertyWrapper = model.getObject();
boolean visible = propertyWrapper.isVisible();
LOGGER.trace("isVisible: {}: {}", propertyWrapper, visible);
return visible;
}
@Override
public boolean isEnabled() {
return !model.getObject().isReadonly();
}
});
initLayout(model, form);
}
private void initLayout(final IModel<IW> model, final Form form) {
WebMarkupContainer labelContainer = new WebMarkupContainer(ID_LABEL_CONTAINER);
labelContainer.setOutputMarkupId(true);
labelContainer.add(new VisibleEnableBehaviour() {
private static final long serialVersionUID = 1L;
@Override public boolean isVisible() {
return labelContainerVisible;
}
});
add(labelContainer);
final IModel<String> label = createDisplayName(model);
labelContainer.add(new Label(ID_LABEL, label));
final IModel<String> helpText = new LoadableModel<String>(false) {
private static final long serialVersionUID = 1L;
@Override
protected String load() {
return loadHelpText(model);
}
};
Label help = new Label(ID_HELP);
help.add(AttributeModifier.replace("title", helpText));
help.add(new InfoTooltipBehavior());
help.add(new VisibleEnableBehaviour() {
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible() {
return StringUtils.isNotEmpty(helpText.getObject());
}
});
labelContainer.add(help);
WebMarkupContainer required = new WebMarkupContainer("required");
required.add(new VisibleEnableBehaviour() {
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible() {
IW wrapper = model.getObject();
ItemDefinition def = wrapper.getItemDefinition();
if (ObjectType.F_NAME.equals(def.getName())) {
//fix for "name as required" MID-789
return true;
}
return def.isMandatory();
}
});
labelContainer.add(required);
WebMarkupContainer hasOutbound = new WebMarkupContainer("hasOutbound");
hasOutbound.add(new VisibleEnableBehaviour() {
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible() {
return hasOutbound(model);
}
});
labelContainer.add(hasOutbound);
WebMarkupContainer hasPendingModification = new WebMarkupContainer(ID_HAS_PENDING_MODIFICATION);
hasPendingModification.add(new VisibleEnableBehaviour() {
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible() {
return hasPendingModification(model);
}
});
labelContainer.add(hasPendingModification);
ListView<ValueWrapper> values = new ListView<ValueWrapper>("values",
new PropertyModel<List<ValueWrapper>>(model, "values")) {
private static final long serialVersionUID = 1L;
@Override
protected void populateItem(final ListItem<ValueWrapper> item) {
PrismValuePanel panel = new PrismValuePanel("value", item.getModel(), label, form, getValueCssClass(), getInputCssClass(), pageBase);
item.add(panel);
item.add(AttributeModifier.append("class", createStyleClassModel(item.getModel())));
item.add(new VisibleEnableBehaviour() {
private static final long serialVersionUID = 1L;
@Override
public boolean isVisible() {
return isVisibleValue(item.getModel());
}
});
}
};
values.add(new AttributeModifier("class", getValuesClass()));
values.setReuseItems(true);
add(values);
}
protected String getInputCssClass() {
return"col-xs-10";
}
protected String getValuesClass() {
return "col-md-6";
}
protected String getValueCssClass() {
return "row";
}
private String loadHelpText(IModel<IW> model) {
IW property = (IW) model.getObject();
ItemDefinition def = property.getItemDefinition();
String doc = def.getHelp();
if (StringUtils.isEmpty(doc)) {
return null;
}
return PageBase.createStringResourceStatic(this, doc).getString();
// return StringResourceModelMigration.of(doc, null, doc).getString();
}
protected IModel<String> createStyleClassModel(final IModel<ValueWrapper> value) {
return new AbstractReadOnlyModel<String>() {
private static final long serialVersionUID = 1L;
@Override
public String getObject() {
if (getIndexOfValue(value.getObject()) > 0) {
return "col-md-offset-2 prism-value";
}
return null;
}
};
}
private int getIndexOfValue(ValueWrapper value) {
ItemWrapper property = value.getItem();
List<ValueWrapper> values = property.getValues();
for (int i = 0; i < values.size(); i++) {
if (values.get(i).equals(value)) {
return i;
}
}
return -1;
}
private boolean hasOutbound(IModel<IW> model) {
ItemWrapper wrapper = model.getObject();
// Item property = wrapper.getItem();
ItemDefinition def = wrapper.getItemDefinition();
if (!(def instanceof RefinedAttributeDefinition)) {
return false;
}
RefinedAttributeDefinition refinedDef = (RefinedAttributeDefinition) def;
return refinedDef.hasOutboundMapping();
}
private boolean hasPendingModification(IModel<IW> model) {
ItemWrapper propertyWrapper = model.getObject();
ContainerWrapper containerWrapper = propertyWrapper.getContainer();
if (containerWrapper == null) {
return false; // TODO - ok?
}
ObjectWrapper objectWrapper = containerWrapper.getObject();
if (objectWrapper == null) {
return false;
}
PrismObject prismObject = objectWrapper.getObject();
if (!ShadowType.class.isAssignableFrom(prismObject.getCompileTimeClass())) {
return false;
}
PrismProperty objectChange = prismObject.findProperty(ShadowType.F_OBJECT_CHANGE);
if (objectChange == null || objectChange.getValue() == null) {
return false;
}
ItemPath path = propertyWrapper.getItem().getPath();
ObjectDeltaType delta = (ObjectDeltaType) objectChange.getValue().getValue();
try {
for (ItemDeltaType itemDelta : delta.getItemDelta()) {
ItemDelta iDelta = DeltaConvertor.createItemDelta(itemDelta, (Class<? extends Objectable>)
prismObject.getCompileTimeClass(), prismObject.getPrismContext());
if (iDelta.getPath().equivalent(path)) {
return true;
}
}
} catch (SchemaException ex) {
LoggingUtils.logUnexpectedException(LOGGER, "Couldn't check if property has pending modification", ex);
}
return false;
}
private IModel<String> createDisplayName(final IModel<IW> model) {
return new AbstractReadOnlyModel<String>() {
private static final long serialVersionUID = 1L;
@Override
public String getObject() {
IW wrapper = model.getObject();
String displayName = wrapper.getDisplayName();
String displayNameValueByKey = PageBase.createStringResourceStatic(PrismPropertyPanel.this, displayName).getString();
return StringUtils.isEmpty(displayNameValueByKey) ?
getString(displayName, null, displayName) : displayNameValueByKey;
}
};
}
private boolean isVisibleValue(IModel<ValueWrapper> model) {
ValueWrapper value = model.getObject();
return !ValueStatus.DELETED.equals(value.getStatus());
}
public boolean isLabelContainerVisible() {
return labelContainerVisible;
}
public void setLabelContainerVisible(boolean labelContainerVisible) {
this.labelContainerVisible = labelContainerVisible;
}
}