/******************************************************************************* * Copyright (c) 2007, 2014 compeople AG and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * compeople AG - initial API and implementation *******************************************************************************/ package org.eclipse.riena.ui.ridgets; import org.eclipse.riena.ui.core.marker.MandatoryMarker; /** * Delegate for {@link IMasterDetailsRidget}, responsible for driving the * details area by: * <ul> * <li>configuring the ridgets for the details area</li> * <li>creating object instances for the master table</li> * <li>creating object instances for the details area</li> * <li>updating the details area from a value from the master table</li> * <li>updating a value in the master table from the details area</li> * <li>deciding if data in the details area has been changed</li> * <li>deciding if data in the details area is valid</li> * <li>optionally – participating at life-cycle events, such as selection, * creation, apply and removal</li> * </ul> * <p> * It is recommended to extend AbstractMasterDetailsDelegate instead of * implementing the interface yourself. * <p> * Developers using a {@link IMasterDetailsRidget} must introduce an appropriate * implementation of this interface to the ridget, by invoking * {@link IMasterDetailsRidget#setDelegate(IMasterDetailsDelegate)}. * <p> * * @see AbstractMasterDetailsDelegate * */ public interface IMasterDetailsDelegate { /** * This method is called once, after all ridgets are injected. * <p> * Implementors must use this method to bind the ridgets from the details * area to the appropriate data. The recommended approach is to create an * instance of the working copy object and bind that instance to the * ridgets. The bound instance should remain the same over the lifetime of * the delegate (see {@link #getWorkingCopy()}). It should be updated as * necessary (see {@link #updateDetails(IRidgetContainer)}). * * @param container * an IRidgetContainer container that holds the ridgets available * to the delegate. Invoke {@code container#getRidget(String id)} * to obtain a reference to a ridget with that id. Never null. */ void configureRidgets(IRidgetContainer container); /** * Create a 'master entry' instance. The object represents the model driving * the master area (i.e. a row entry in the table). * <p> * The 'master entry' is always an instance of the '{@code rowClass'} * specified in the {@code bindToModel(...)} method of the corresponding * {@link IMasterDetailsRidget}. Note that the copyXXX() methods in this * interface must be able to work with the type returned by this method. * * @return an Object; never null. * @see IMasterDetailsRidget#bindToModel(org.eclipse.core.databinding.observable.list.IObservableList, * Class, String[], String[]) * @see IMasterDetailsRidget#bindToModel(Object, String, Class, String[], * String[]) * @since 3.0 */ Object createMasterEntry(); /** * Creates a 'working copy' instance. The object represents the model * driving the details area. * <p> * The 'working copy' any type but is typically an instance of the * 'rowClass' specified in the {@code bindToModel(...) } method of the * corresponding {@link IMasterDetailsRidget}. Note that the copyXXX() * methods in this interface must be able to work with the type returned by * this method. * * @return an Object; never null. * @see IMasterDetailsRidget#bindToModel(org.eclipse.core.databinding.observable.list.IObservableList, * Class, String[], String[]) * @see IMasterDetailsRidget#bindToModel(Object, String, Class, String[], * String[]) */ Object createWorkingCopy(); /** * Copies the content of the source object into the target object. * Implementors only need to copy attributes that can be modified in the * details area. * <p> * Notes: * <ul> * <li>if the same type is returned by {@link #createMasterEntry()} and * {@link #createWorkingCopy()}: implement {@link #copyBean(Object, Object)} * and ignore the other copy-methods</li> * <li>if different types are returned by {@link #createMasterEntry()} and * {@link #createWorkingCopy()}: implement * {@link #copyMasterEntry(Object, Object)} and * {@link #copyWorkingCopy(Object, Object)} and ignore * {@link #copyBean(Object, Object)}</li> * </ul> * * @param source * The source object; never null * @param target * The target object; never null * @return the target object; never null. */ Object copyBean(Object source, Object target); /** * Copies the content of a 'master entry' into a 'working copy'. * <p> * The 'master entry' is an instance of the '{@code rowClass'} specified in * {@code bindToModel(...)} method of the corresponding * {@link IMasterDetailsRidget}. The 'working copy' is the type used to * store the content of the details area. * <p> * Notes: * <ul> * <li>if the same type is returned by {@link #createMasterEntry()} and * {@link #createWorkingCopy()}: implement {@link #copyBean(Object, Object)} * and ignore the other copy-methods</li> * <li>if different types are returned by {@link #createMasterEntry()} and * {@link #createWorkingCopy()}: implement * {@link #copyMasterEntry(Object, Object)} and * {@link #copyWorkingCopy(Object, Object)} and ignore * {@link #copyBean(Object, Object)}</li> * </ul> * * @param masterEntry * a source object of the type created by * {@link #createMasterEntry()}; never null. * @param workingCopy * a target object of the type created by * {@link #createWorkingCopy()}; never null. * @since 3.0 */ Object copyMasterEntry(Object masterEntry, Object workingCopy); /** * Copies the content of a 'working copy' into a 'master entry'. * <p> * The 'master entry' is an instance of the '{@code rowClass'} specified in * {@code bindToModel(...)} method of the corresponding * {@link IMasterDetailsRidget}. The 'working copy' is the type used to * store the content of the details area. * <p> * Notes: * <ul> * <li>if the same type is returned by {@link #createMasterEntry()} and * {@link #createWorkingCopy()}: implement {@link #copyBean(Object, Object)} * and ignore the other copy-methods</li> * <li>if different types are returned by {@link #createMasterEntry()} and * {@link #createWorkingCopy()}: implement * {@link #copyMasterEntry(Object, Object)} and * {@link #copyWorkingCopy(Object, Object)} and ignore * {@link #copyBean(Object, Object)}</li> * </ul> * * @param workingCopy * a source object of the type created by * {@link #createWorkingCopy()}; never null. * @param masterEntry * a target object of the type created by * {@link #createMasterEntry()}; never null. * @since 3.0 */ Object copyWorkingCopy(Object workingCopy, Object masterEntry); /** * Returns the 'working copy' object. This object represents the model * driving the details area. * <p> * It is recommended that the instance returned by this method stays the * same over the lifetime of the delegate (i.e. always return the same * instance). * * @return an Object; never null * @see IMasterDetailsRidget#bindToModel(org.eclipse.core.databinding.observable.list.IObservableList, * Class, String[], String[]) * @see IMasterDetailsRidget#bindToModel(Object, String, Class, String[], * String[]) */ Object getWorkingCopy(); /** * Returns true, if there there is a difference between the two objects, * with respect to the data that is editable in the details area. Returns * false is both objects are the equal, with respect to that data. * <p> * The return value determines the enablement state of the 'update' button * in the {@link IMasterDetailsRidget}. * <p> * The minimal recommended implementation of this method is: * * <pre> * public boolean isChanged(Object source, Object target) { * return true; * } * * </pre> * * @param source * the source object; never null. Holds the original values * @param target * the target object; never null. Holds the latest values from * the details area. * @return true if there is a difference between {@code source} and * {@code target}; otherwise false */ boolean isChanged(Object source, Object target); /** * Returns null if the current item can be removed. * <p> * If removal is not possible, a non-null explaining the reason is returned * and shown to the user. * * @param item * the item behind the master row. Can never be null. * @return null if the item is removable; otherwise an error message when * removal is not possible. * * @since 2.0 */ String isRemovable(Object item); /** * Returns null, if the data in details area (i.e. working copy) is valid. * This will be invoked before apply writes the data back from the details * area into the model. * <p> * The minimal recommended implementation of this method is: * * <pre> * public String isValid() { * return null; * } * </pre> * * @param container * an IRidgetContainer container that holds the ridgets available * to the delegate. Invoke {@code container#getRidget(String id)} * to obtain a reference to a ridget with that id. Never null. * @return null if the data is valid; an error message if the data is * invalid */ String isValid(IRidgetContainer container); /** * When this method returns true, an enabled mandatory marker is added to * all markable ridgets in the details area. The marker is removed * automatically when an entry is changed or the 'Apply' action is invoked. * <p> * The method is evaluated before a new entry is made editable. This happens * when the user invoked the 'New' action or when an entry is suggested via * API. * * @param mdRidget * the {@link IMasterDetailsRidget} associated with this * delegate; never null. * @return true to hide the global mandatory marker, false to show it * * @see MandatoryMarker * @since 3.0 */ boolean isValidMaster(final IMasterDetailsRidget mdRidget); /** * Updates all details from the model. * <p> * Typically this is called when the selection in the master/details ridget * has changed. The {@link IMasterDetailsRidget} will first update the * working copy by invoking {@code copyBean(selection, getWorkingCopy())} * and then invoke this method. * <p> * The minimal recommended implementation of this method is: * * <pre> * public void updateDetails(IRidgetContainer container) { * for (IRidget ridget : container.getRidgets()) { * ridget.updateFromModel(); * } * } * </pre> * * @param container * an IRidgetContainer container that holds the ridgets available * to the delegate. Invoke {@code container#getRidget(String id)} * to obtain a reference to a ridget with that id. Never null. */ void updateDetails(IRidgetContainer container); /** * This method the <b>first</b> method called during an apply operation. It * is invoked <b>before</b> any changes are made. * * @param selection * the selected item behind the master row. Can never be null. * * @since 3.0 */ void prepareItemApplied(Object selection); /** * This is the <b>first</b> method called when a row in the master table is * selected. It will be called before any other methods of the delegate. The * given <code>newSelection</code> is the selection. * * @param newSelection * the selected item behind the master row. <b>May be null</b>, * if nothing becomes selected */ void prepareItemSelected(Object newSelection); /** * This is the <b>last</b> method called when a row in the master table * becomes selected. It will be called after any other methods of the * delegate. The given <code>newSelection</code> is the selection. * * @param newSelection * the selected item behind the master row. <b>May be null</b>, * if nothing becomes selected * * @since 2.0 */ void itemSelected(Object newSelection); /** * This method is called when a new item is created. * * @param newItem * the added item behind the master row. Can never be null. * * @since 2.0 */ void itemCreated(Object newItem); /** * This method is called when an item is removed from the master table. * * @param oldItem * the removed item behind the master row. Can never be null. * * @since 2.0 */ void itemRemoved(Object oldItem); /** * This method is called after a new master record changes are applied to an * item. * * @param changedItem * the changed item behind the master row. Can never be null. * * @since 2.0 */ void itemApplied(Object changedItem); /** * Hook to provide safe control over the state of the * {@link IMasterDetailsRidget} inner action ridgets (create, remove, apply) * * @param actionRidgetFacade * facade for convenient access to {@link IActionRidget}s of the * {@link IMasterDetailsRidget} * @param selection * the selected item behind the master row. <b>May be null</b>, * if nothing is selected * @since 3.0 * */ void updateMasterDetailsActionRidgets(IMasterDetailsActionRidgetFacade actionRidgetFacade, Object selection); }