/* * 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.form; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.xml.namespace.QName; import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.form.AjaxFormComponentUpdatingBehavior; import org.apache.wicket.ajax.markup.html.AjaxLink; import org.apache.wicket.feedback.ComponentFeedbackMessageFilter; import org.apache.wicket.markup.html.WebMarkupContainer; import org.apache.wicket.markup.html.form.TextField; import org.apache.wicket.markup.html.panel.FeedbackPanel; import org.apache.wicket.model.AbstractReadOnlyModel; import org.apache.wicket.model.IModel; import com.evolveum.midpoint.gui.api.component.BasePanel; import com.evolveum.midpoint.gui.api.component.ObjectBrowserPanel; import com.evolveum.midpoint.gui.api.util.WebComponentUtil; import com.evolveum.midpoint.prism.PrismReferenceValue; import com.evolveum.midpoint.prism.query.InOidFilter; import com.evolveum.midpoint.prism.query.NotFilter; import com.evolveum.midpoint.prism.query.ObjectFilter; import com.evolveum.midpoint.prism.query.ObjectQuery; import com.evolveum.midpoint.schema.util.ObjectTypeUtil; import com.evolveum.midpoint.util.MiscUtil; import com.evolveum.midpoint.util.logging.Trace; import com.evolveum.midpoint.util.logging.TraceManager; import com.evolveum.midpoint.web.page.admin.dto.ObjectViewDto; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectReferenceType; import com.evolveum.midpoint.xml.ns._public.common.common_3.ObjectType; /** * * TODO: rename to ValueObjectChoicePanel, PrismValueObjectSelectorPanel or * something better * * @param <T> * @param <O> * common superclass for all the options of objects that this panel * should choose */ public class ValueChoosePanel<T, O extends ObjectType> extends BasePanel<T> { private static final long serialVersionUID = 1L; private static final Trace LOGGER = TraceManager.getTrace(ValueChoosePanel.class); private static final String ID_TEXT_WRAPPER = "textWrapper"; private static final String ID_TEXT = "text"; private static final String ID_FEEDBACK = "feedback"; private static final String ID_EDIT = "edit"; protected static final String MODAL_ID_OBJECT_SELECTION_POPUP = "objectSelectionPopup"; private Collection<Class<? extends O>> types; public ValueChoosePanel(String id, IModel<T> value, Collection<Class<? extends O>> types) { this(id, value, null, false, types); } public ValueChoosePanel(String id, IModel<T> value, List<PrismReferenceValue> values, boolean required, Collection<Class<? extends O>> types) { super(id, value); setOutputMarkupId(true); this.types = types; initLayout(value, values, required, types); } private void initLayout(final IModel<T> value, final List<PrismReferenceValue> values, final boolean required, Collection<Class<? extends O>> types) { WebMarkupContainer textWrapper = new WebMarkupContainer(ID_TEXT_WRAPPER); textWrapper.setOutputMarkupId(true); TextField<String> text = new TextField<String>(ID_TEXT, createTextModel(value)); text.add(new AjaxFormComponentUpdatingBehavior("blur") { private static final long serialVersionUID = 1L; @Override protected void onUpdate(AjaxRequestTarget ajaxRequestTarget) { } }); text.setRequired(required); text.setEnabled(false); textWrapper.add(text); FeedbackPanel feedback = new FeedbackPanel(ID_FEEDBACK, new ComponentFeedbackMessageFilter(text)); textWrapper.add(feedback); AjaxLink<String> edit = new AjaxLink<String>(ID_EDIT) { private static final long serialVersionUID = 1L; @Override public void onClick(AjaxRequestTarget target) { editValuePerformed(values, target); } }; textWrapper.add(edit); add(textWrapper); initButtons(); } protected void replaceIfEmpty(ObjectType object) { ObjectReferenceType ort = ObjectTypeUtil.createObjectRef(object); ort.setTargetName(object.getName()); getModel().setObject((T) ort.asReferenceValue()); } protected ObjectQuery createChooseQuery(List<PrismReferenceValue> values) { ArrayList<String> oidList = new ArrayList<>(); ObjectQuery query = new ObjectQuery(); // TODO we should add to filter currently displayed value // not to be displayed on ObjectSelectionPanel instead of saved value // for (PrismReferenceValue ref : values) { // if (ref != null) { // if (ref.getOid() != null && !ref.getOid().isEmpty()) { // oidList.add(ref.getOid()); // } // } // } // if (isediting) { // oidList.add(orgModel.getObject().getObject().asObjectable().getOid()); // } if (oidList.isEmpty()) { return null; } ObjectFilter oidFilter = InOidFilter.createInOid(oidList); query.setFilter(NotFilter.createNot(oidFilter)); return query; } /** * @return css class for off-setting other values (not first, left to the * first there is a label) */ protected String getOffsetClass() { return "col-md-offset-4"; } protected IModel<String> createTextModel(final IModel<T> model) { return new AbstractReadOnlyModel<String>() { private static final long serialVersionUID = 1L; @Override public String getObject() { T ort = (T) model.getObject(); if (ort instanceof PrismReferenceValue) { PrismReferenceValue prv = (PrismReferenceValue) ort; return prv == null ? null : (prv.getTargetName() != null ? (prv.getTargetName().getOrig() + (prv.getTargetType() != null ? ": " + prv.getTargetType().getLocalPart() : "")) : prv.getOid()); } else if (ort instanceof ObjectReferenceType) { ObjectReferenceType prv = (ObjectReferenceType) ort; return prv == null ? null : (prv.getTargetName() != null ? (prv.getTargetName().getOrig() + (prv.getType() != null ? ": " + prv.getType().getLocalPart() : "")) : prv.getOid()); } else if (ort instanceof ObjectViewDto) { return ((ObjectViewDto) ort).getName(); } return ort != null ? ort.toString() : null; } }; } protected void editValuePerformed(List<PrismReferenceValue> values, AjaxRequestTarget target) { List<QName> supportedTypes = WebComponentUtil.resolveObjectTypesToQNames(types, getPageBase().getPrismContext()); ObjectFilter filter = createChooseQuery(values) == null ? null : createChooseQuery(values).getFilter(); Class<O> defaultType = (Class<O>) types.iterator().next(); ObjectBrowserPanel<O> objectBrowserPanel = new ObjectBrowserPanel<O>( getPageBase().getMainPopupBodyId(), defaultType, supportedTypes, false, getPageBase(), filter) { private static final long serialVersionUID = 1L; @Override protected void onSelectPerformed(AjaxRequestTarget target, O object) { getPageBase().hideMainPopup(target); ValueChoosePanel.this.choosePerformed(target, object); } }; getPageBase().showMainPopup(objectBrowserPanel, target); } /* * TODO - this method contains check, if chosen object already is not in * selected values array This is a temporary solution until we well be able * to create "already-chosen" query */ protected void choosePerformed(AjaxRequestTarget target, O object) { choosePerformedHook(target, object); if (isObjectUnique(object)) { replaceIfEmpty(object); } if (LOGGER.isTraceEnabled()) { LOGGER.trace("New object instance has been added to the model."); } target.add(getTextWrapperComponent()); } public WebMarkupContainer getTextWrapperComponent(){ return (WebMarkupContainer)get(ID_TEXT_WRAPPER); } protected void initButtons() { } protected boolean isObjectUnique(O object) { T modelObject = getModelObject(); if (modelObject instanceof PrismReferenceValue) { PrismReferenceValue old = (PrismReferenceValue) modelObject; if (old == null || old.isEmpty()) { return true; } return !old.getOid().equals(object.getOid()); } else if (modelObject instanceof ObjectReferenceType) { ObjectReferenceType old = (ObjectReferenceType) modelObject; if (old == null) { return true; } return !MiscUtil.equals(old.getOid(),object.getOid()); } return true; } /** * A custom code in form of hook that can be run on event of choosing new * object with this chooser component */ protected void choosePerformedHook(AjaxRequestTarget target, O object) { } }