All Downloads are FREE. Search and download functionalities are using the official Maven repository.

de.iwes.widgets.pattern.widget.patternedit.PatternEditor Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2014-2018 Fraunhofer-Gesellschaft zur Förderung der angewandten Wissenschaften e.V.
 *
 * 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 de.iwes.widgets.pattern.widget.patternedit;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.ogema.core.application.ApplicationManager;
import org.ogema.core.model.Resource;
import org.ogema.core.resourcemanager.pattern.ResourcePattern;

import de.iwes.widgets.api.extended.OgemaWidgetBase;
import de.iwes.widgets.api.extended.html.bricks.PageSnippet;
import de.iwes.widgets.api.extended.pattern.PatternSelector;
import de.iwes.widgets.api.services.NameService;
import de.iwes.widgets.api.widgets.WidgetGroup;
import de.iwes.widgets.api.widgets.WidgetPage;
import de.iwes.widgets.api.widgets.WidgetStyle;
import de.iwes.widgets.api.widgets.dynamics.TriggeredAction;
import de.iwes.widgets.api.widgets.dynamics.TriggeringAction;
import de.iwes.widgets.api.widgets.html.StaticTable;
import de.iwes.widgets.api.widgets.localisation.LocaleDictionary;
import de.iwes.widgets.api.widgets.localisation.OgemaLocale;
import de.iwes.widgets.api.widgets.sessionmanagement.OgemaHttpRequest;
import de.iwes.widgets.html.alert.Alert;
import de.iwes.widgets.html.alert.AlertData;
import de.iwes.widgets.html.buttonconfirm.ButtonConfirm;
import de.iwes.widgets.html.buttonconfirm.ButtonConfirmData;
import de.iwes.widgets.html.form.button.Button;
import de.iwes.widgets.html.form.dropdown.DropdownOption;
import de.iwes.widgets.html.form.dropdown.DropdownData;
import de.iwes.widgets.html.form.label.Label;
import de.iwes.widgets.pattern.page.impl.ControllableDropdown;
import de.iwes.widgets.pattern.page.impl.FieldUtils;
import de.iwes.widgets.pattern.page.impl.FilterRange;
import de.iwes.widgets.pattern.page.impl.LocalisationUtil;
import de.iwes.widgets.pattern.page.impl.PatternPageUtilInternal;
import de.iwes.widgets.pattern.widget.dropdown.PatternDropdown;
import de.iwes.widgets.pattern.widget.init.PatternInitDropdown;
import de.iwes.widgets.pattern.widget.patternedit.PatternPageAnnotations.DisplayValue;
import de.iwes.widgets.pattern.widget.patternedit.PatternPageAnnotations.SetValue;

/**
 * A widget that allows the user to edit resource pattern instances (see {@link ResourcePattern}). 
 * This only exists as a global widget, in particular the pattern type cannot be changed for individual 
 * users. Configuration for the individual pattern fields is possible via special annotations defined in
 * {@link PatternPageAnnotations}. 
 *
 * @param 

* @param */ public class PatternEditor

, D extends LocaleDictionary> extends PageSnippet { private static final long serialVersionUID = 1L; // private final PageSnippet snippet; final Class

pattern; final ApplicationManager am; private final NameService nameService; private volatile Method patternSelectLabel; // final private final Field[] fields; private final Method[] methods; // keys are always (?) field names or method names private final Map> labelWidgets = new LinkedHashMap>(); private final Map> valueWidgets = new LinkedHashMap>(); private final Map references = new LinkedHashMap(); // values are String, Integer, Boolean, Long, Byte for StringResource, IntegerResource, etc.; only relevant for SingleValueResource & ByteArrayResource fields private final Map> fieldTypes = new LinkedHashMap>(); private final Map externalStringFilters = new LinkedHashMap(); private final Map externalRangeFilters = new LinkedHashMap(); @SuppressWarnings("unused") private final WidgetGroup labelGroup; private final WidgetGroup valueGroup; private final Alert alert; private final SubmitButton createButton; private final Label selectLabel; final PatternDropdown

select; @SuppressWarnings("unused") private final Label deleteLabel; private final ButtonConfirm deleteButton; private final String widgetID; // TODO use // this construction is required for permission reasons public static

, D extends LocaleDictionary> PatternEditor getInstance(final WidgetPage page, final String widgetID, final Class

pattern, final ApplicationManager am, final Class dictionary, final boolean forceUnmodifiable) { return AccessController.doPrivileged(new PrivilegedAction>() { @Override public PatternEditor run() { return new PatternEditor(page, widgetID, pattern, am, dictionary, forceUnmodifiable); } }); } @SuppressWarnings({ "unchecked", "rawtypes" }) private PatternEditor(final WidgetPage page, String widgetID, Class

pattern, ApplicationManager am, Class dictionary, boolean forceUnmodifiable) { super(page, widgetID, true); this.pattern = pattern; // if (widgetID != null && !widgetID.isEmpty()) this.widgetID = widgetID; // else // this.widgetID = pattern.getSimpleName(); this.nameService = getNameService(); this.am = am; if (dictionary == null) dictionary = (Class) LocaleDictionary.class; this.alert = new Alert(page, this.widgetID + "_alert", ""); alert.setDefaultVisibility(false); this.selectLabel = new Label(page, this.widgetID + "_selectLabel") { private static final long serialVersionUID = 1L; @Override public void onGET(OgemaHttpRequest req) { if (patternSelectLabel == null) return; D dict = page.getDictionary(req.getLocaleString()); try { String result = patternSelectLabel.invoke(dict).toString(); setText(result, req); } catch (Exception e) { // FIXME e.printStackTrace(); } } }; selectLabel.setDefaultText("Select a pattern"); // String selectID; // if (widgetID == null || widgetID.isEmpty()) // selectID = this.widgetID + "_patternSelectionDropdown"; // else // selectID = widgetID; this.select = new PatternInitDropdown(page,widgetID + "_selectionDropdown", pattern, am.getResourcePatternAccess()) { private static final long serialVersionUID = 1L; @Override public void onPOSTComplete(String data, OgemaHttpRequest req) { String selected = getSelectedPath(req); setDependentWidgetValues(selected,getItems(req),req); } @Override public void init(OgemaHttpRequest req) { super.init(req); String selected = getSelectedPath(req); setDependentWidgetValues(selected,getItems(req),req); } // // // this is only called when data is retrieved for the first time... in this case the selected value is set server-side (if at all), // // hence onPOSTComplete must be triggered manually, in order to report the selected value to dependent widgets // // -> moved to PatternDropdown // @Override // public void appendWidgetInformation(OgemaHttpRequest req) { // super.appendWidgetInformation(req); // onPOSTComplete("{}", req); // set dependent widgets // } }; select.setDefaultAddEmptyOption(true); // new PatternSelectionDropdown(page,"patternSelectionDropdown", this, pattern, am.getResourcePatternAccess()); if (!forceUnmodifiable) { this.createButton = new SubmitButton(page, this.widgetID + "_createButton","Save") { private static final long serialVersionUID = 1L; @Override public void onGET(OgemaHttpRequest req) { OgemaLocale loc = req.getLocale(); if (loc == null) loc = OgemaLocale.ENGLISH; setText(LocalisationUtil.saveButtonText(loc), req); } }; createButton.triggerAction(alert, TriggeringAction.POST_REQUEST, TriggeredAction.GET_REQUEST); // TODO // if (page instanceof WidgetPageSimpleSelectEditImpl) // ((WidgetPageSimpleSelectEditImpl) page).button = createButton; // select.button = createButton; this.deleteLabel = new Label(page,this.widgetID + "_deleteLabel","Delete pattern") { private static final long serialVersionUID = 1L; @Override public void onGET(OgemaHttpRequest req) { OgemaLocale loc = req.getLocale(); if (loc == null) loc = OgemaLocale.ENGLISH; setText(LocalisationUtil.deleteButtonText(loc), req); }; }; this.deleteButton = new DeleteButton(page, this.widgetID + "_deleteButton", "Delete pattern"); } else { this.deleteLabel = null; this.deleteButton = null; this.createButton = null; } // fields = pattern.getDeclaredFields(); fields = PatternPageUtilImpl.getResourceInfoRecursively(pattern); if (!dictionary.equals(LocaleDictionary.class)) { // methods = getAnnotatedMethods(pattern); try { patternSelectLabel = dictionary.getDeclaredMethod("patternSelectLabel"); } catch (NoSuchMethodException | SecurityException e) { patternSelectLabel = null; } } else { // methods = new Method[0]; // in this case there are no dictionary entries for the methods anyway patternSelectLabel = null; } methods = getAnnotatedMethods(pattern); PatternPageUtilInternal.createWidgets(page, this.widgetID, fields, methods, null, labelWidgets, valueWidgets, references, fieldTypes, externalStringFilters, externalRangeFilters, select, false, am, dictionary, false, forceUnmodifiable); if (labelWidgets.isEmpty()) { labelGroup = null; valueGroup = null; return; // ? } buildPage(!forceUnmodifiable); labelGroup = page.registerWidgetGroup(this.widgetID + "_labelWidgets", (Collection) labelWidgets.values()); // FIXME does this work?? valueGroup = page.registerWidgetGroup(this.widgetID + "_valueWidgets", (Collection) valueWidgets.values()); select.triggerAction(valueGroup, TriggeringAction.POST_REQUEST, TriggeredAction.GET_REQUEST); if (!forceUnmodifiable) { select.triggerAction(deleteButton, TriggeringAction.POST_REQUEST, TriggeredAction.GET_REQUEST); createButton.triggerAction(valueGroup, TriggeringAction.PRE_POST_REQUEST, TriggeredAction.POST_REQUEST); deleteButton.triggerAction(alert, TriggeringAction.POST_REQUEST, TriggeredAction.GET_REQUEST); deleteButton.triggerAction(select, TriggeringAction.POST_REQUEST, TriggeredAction.GET_REQUEST); deleteButton.triggerAction(valueGroup, TriggeringAction.POST_REQUEST, TriggeredAction.GET_REQUEST); } setInitialDropdownStatus(); } class SubmitButton extends Button { private static final long serialVersionUID = 1L; public SubmitButton(WidgetPage page, String id, String defaultText) { super(page, id, defaultText); } @Override public void onPOSTComplete(String data, OgemaHttpRequest req) { OgemaLocale locale = req.getLocale(); try { DropdownOption selected = select.getSelected(req); if (selected == null || selected.id().equals(DropdownData.EMPTY_OPT_ID)) return; String selectedModel = selected.id(); PatternPageUtilInternal.applyInternalAndExternalFilters(fieldTypes, valueWidgets, externalStringFilters, externalRangeFilters, req); // throws exceptions that will be displayed on UI P newPattern = getPattern(selectedModel, req); PatternPageUtilInternal.setValues(newPattern, fields, references, valueWidgets, req, am); PatternPageUtilInternal.setValues(pattern,newPattern, methods, valueWidgets, req, am); am.getResourcePatternAccess().activatePattern(newPattern); alert.setText(LocalisationUtil.patternModified(selectedModel, locale), req); alert.setStyle(AlertData.BOOTSTRAP_SUCCESS, req); } catch (Exception e) { alert.setText(LocalisationUtil.patternModificationFailed(locale) + ": " + e, req); alert.setStyle(AlertData.BOOTSTRAP_DANGER, req); } alert.setWidgetVisibility(true, req); alert.autoDismiss(6000, req); } } final static DropdownOption EMPTY_OPT_SELECTED =new DropdownOption(DropdownData.EMPTY_OPT_ID, "", true); final static DropdownOption EMPTY_OPT_DESELECTED =new DropdownOption(DropdownData.EMPTY_OPT_ID, "", false); private P getPattern(final String path, OgemaHttpRequest req) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Resource res = AccessController.doPrivileged(new PrivilegedAction() { @Override public Resource run() { return am.getResourceAccess().getResource(path); } }); if (res == null) throw new RuntimeException("Pattern resource is null... this should not happen;"); if (res.isTopLevel()) return am.getResourcePatternAccess().createResource(path, pattern); else { Resource parent = res.getParent(); return am.getResourcePatternAccess().addDecorator(parent, res.getName(), pattern); } } private void buildPage(boolean editable) { append(alert, null); int[] sizes = new int[] { 2, 4 }; StaticTable table = new StaticTable(labelWidgets.size()+2, 2, sizes); addLine(table, selectLabel, select); for (Map.Entry> entry : labelWidgets.entrySet()) { String id = entry.getKey(); OgemaWidgetBase label = entry.getValue(); OgemaWidgetBase value = valueWidgets.get(id); addLine(table, label, value); } append(table, null); if (editable) { append(createButton, null).linebreak(null); append(deleteButton, null); } } private int lineCounter = 0; private void addLine(StaticTable table, OgemaWidgetBase labelWidget, OgemaWidgetBase valueWidget) { table.setContent(lineCounter, 0, labelWidget).setContent(lineCounter++, 1, valueWidget); } private class DeleteButton extends ButtonConfirm { private static final long serialVersionUID = 1L; public DeleteButton(WidgetPage page, String id, String defaultText) { super(page, id, defaultText); Set> styles = new HashSet>(); styles.add(ButtonConfirmData.CANCEL_LIGHT_BLUE); styles.add(ButtonConfirmData.CONFIRM_RED); setDefaultStyles(styles); } @Override public void onGET(OgemaHttpRequest req) { String selected = getSelectedPath(req); OgemaLocale locale = req.getLocale(); if (selected != null) { setCancelBtnMsg(LocalisationUtil.cancelMsg(locale),req); setConfirmBtnMsg(LocalisationUtil.deleteButtonText(locale),req); setConfirmPopupTitle(LocalisationUtil.deleteConfirmationPopupTitle(locale),req); setConfirmMsg(LocalisationUtil.deleteConfirmationMsg(selected, locale), req); enable(req); } else { setCancelBtnMsg("Cancel",req); setConfirmBtnMsg("Cancel",req); setConfirmPopupTitle("I should be inactive!",req); setConfirmMsg("Nothing to be seen here.", req); disable(req); // TODO not working yet } setText(LocalisationUtil.deleteResource(locale), req); } @Override public void onPOSTComplete(String data, OgemaHttpRequest req) { String selected = getSelectedPath(req); if (selected == null) return; OgemaLocale locale = req.getLocale(); try { Resource res = am.getResourceAccess().getResource(selected); if (res == null) return; res.delete(); alert.setText(LocalisationUtil.deletionConfirmed(selected, locale),req); // TOOO localise alert.setStyle(AlertData.BOOTSTRAP_SUCCESS, req); } catch (Exception e) { alert.setText(LocalisationUtil.deletionFailed(selected, locale) + "; " + e,req); alert.setStyle(AlertData.BOOTSTRAP_DANGER, req); } alert.setWidgetVisibility(true, req); alert.autoDismiss(6000, req); select.selectSingleOption(DropdownData.EMPTY_OPT_ID, req); PatternPageUtilInternal.clearWidgets(valueWidgets, req); } }; String getSelectedPath(OgemaHttpRequest req) { DropdownOption opt =select.getSelected(req); if (opt == null || opt.id().equals(DropdownData.EMPTY_OPT_ID)) return null; return opt.id(); } void setDependentWidgetValues(String path, Collection

patterns, OgemaHttpRequest req) { P pattern = null; if (path != null) { for (P pt: patterns) { if (pt.model.getPath().equals(path)) { pattern =pt; break; } } } if (pattern == null) { PatternPageUtilInternal.clearWidgets(valueWidgets, req); } else { Boolean[] accessible = FieldUtils.setAccessiblePrivileged(fields); for (Map.Entry> entry : valueWidgets.entrySet()) { String name =entry.getKey(); Field field = getField(name); Method method = getMethod(name); if (field != null) { Resource res = FieldUtils.getResource(field, pattern); if (res == null) { am.getLogger().error("Resource " + name + " not found in pattern... ?"); continue; } PatternPageUtilInternal.setWidgetValue(entry.getValue(), res, req); } else if (method != null) { // PatternPageUtilInternal.setMethodValue(entry.getValue(), res, req); // see below... all set at once // do not continue yet, since labels are all set below } else { am.getLogger().error("Field of method " + name + " not found... ?"); continue; } } FieldUtils.setUnaccessiblePrivileged(fields, accessible); PatternPageUtilInternal.setMethodValues(pattern, methods, valueWidgets, req, am, nameService); } } private Field getField(String name) { for (Field field: fields) { if (field.getName().equals(name)) return field; } return null; } private Method getMethod(String name) { for (Method method: methods) { if (method.getName().equals(name)) return method; } return null; } private void setInitialDropdownStatus() { for (OgemaWidgetBase widget: valueWidgets.values()) { if (widget instanceof ControllableDropdown) { ((ControllableDropdown) widget).setInitialActiveStatus(false); } } } private static Method[] getAnnotatedMethods(Class> pattern) { Method[] methods = pattern.getDeclaredMethods(); List methodList = new ArrayList(); for (Method method:methods) { DisplayValue dv = method.getAnnotation(DisplayValue.class); SetValue sv = method.getAnnotation(SetValue.class); if (dv != null || sv != null) methodList.add(method); } Method[] result = new Method[methodList.size()]; int counter = 0; for (Method method: methodList) { result[counter++] = method; } return result; } /** * @return * the submit button, by means of which changes in the selected pattern are saved. */ public Button getSubmitButton() { return createButton; } /** * @return * the dropdown widget that offers the user the available patterns for selection. */ public PatternSelector

getSelector() { return select; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy