/******************************************************************************* * 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.controller; import java.lang.reflect.Modifier; import java.util.Collection; import java.util.HashMap; import java.util.Map; import org.eclipse.core.runtime.Assert; import org.eclipse.riena.core.RienaStatus; import org.eclipse.riena.core.annotationprocessor.DisposerList; import org.eclipse.riena.core.annotationprocessor.IDisposer; import org.eclipse.riena.core.util.RienaConfiguration; import org.eclipse.riena.ui.core.context.IContext; import org.eclipse.riena.ui.ridgets.ClassRidgetMapper; import org.eclipse.riena.ui.ridgets.IActionListener; import org.eclipse.riena.ui.ridgets.IActionRidget; import org.eclipse.riena.ui.ridgets.IDefaultActionManager; import org.eclipse.riena.ui.ridgets.IRidget; import org.eclipse.riena.ui.ridgets.IRidgetContainer; import org.eclipse.riena.ui.ridgets.IShellRidget; import org.eclipse.riena.ui.ridgets.IStatuslineRidget; import org.eclipse.riena.ui.ridgets.IWindowRidget; import org.eclipse.riena.ui.ridgets.RidgetToStatuslineSubscriber; /** * Controller for a view that is or has a window. * */ public abstract class AbstractWindowController implements IController, IContext { /** * Implementations handle the <tt>'blocked'</tt> state. * * @see IController#setBlocked(boolean) * @since 6.0 */ public interface Blocker { void setBlocked(boolean blocked); boolean isBlocked(); } /** * @since 3.0 */ public static final String RIDGET_ID_OK = "dialogOkButton"; //$NON-NLS-1$ /** * @since 3.0 */ public static final String RIDGET_ID_CANCEL = "dialogCancelButton"; //$NON-NLS-1$ /** * The ridget id to use for the window ridget. */ public static final String RIDGET_ID_WINDOW = "windowRidget"; //$NON-NLS-1$ /** * The ridget id to use for the statusline. * * @since 5.0 */ // if changing this constant, also adjust AbstractDialogView.RIDGET_ID_STATUSLINE public static final String RIDGET_ID_STATUSLINE = "dlg_statusline"; //$NON-NLS-1$ /** * Return code to indicate that the window was a OK-ed (value: {@value} ). * * @see #getReturnCode() * @since 1.2 */ public static final int OK = 0; /** * Return code to indicate that the window was canceled (value: {@value} ). * * @see #getReturnCode() * @since 1.2 */ public static final int CANCEL = 1; private final Map<String, IRidget> ridgets; private final Map<String, Object> context; private IWindowRidget windowRidget; private Blocker blocker; private int returnCode; private boolean configured = false; private IDefaultActionManager actionManager; private final RidgetToStatuslineSubscriber ridgetToStatusLineSubscriber = new RidgetToStatuslineSubscriber(); private DisposerList annotationDisposerList; public AbstractWindowController() { super(); ridgets = new HashMap<String, IRidget>(); context = new HashMap<String, Object>(); } /** * Make {@code action} the default action while the focus is within {@code focusRidget} including it's children. * <p> * If a default action is available and enabled, it will be invoked whenever the user presses ENTER within the window. * <p> * Note: the algorithm stops at the first match. It will check the most specific (innermost) ridget first and check the most general (outermost) ridget * last. * * @param focusRidget * the ridget that needs to have the focus to activate this rule. Never null. * @param action * this ridget will become the default action, while focusRidget has the focus. Never null. * * @since 2.0 */ public void addDefaultAction(final IRidget focusRidget, final IActionRidget action) { actionManager = getWindowRidget().addDefaultAction(focusRidget, action); } public void addRidget(final String id, final IRidget ridget) { ridgets.put(id, ridget); ridgetToStatusLineSubscriber.addRidget(ridget); } /** * {@inheritDoc} * * @since 5.0 */ public boolean removeRidget(final String id) { ridgetToStatusLineSubscriber.removeRidget(getRidget(id)); return ridgets.remove(id) != null; } /** * {@inheritDoc} * * @since 5.0 */ public void setStatuslineToShowMarkerMessages(final IStatuslineRidget statuslineToShowMarkerMessages) { ridgetToStatusLineSubscriber.setStatuslineToShowMarkerMessages(statuslineToShowMarkerMessages, getRidgets()); } public void afterBind() { returnCode = OK; getWindowRidget().updateFromModel(); if (actionManager != null) { actionManager.activate(); } if (shouldEnableStatuslineMessageViewer()) { setStatuslineToShowMarkerMessages((IStatuslineRidget) getRidget(RIDGET_ID_STATUSLINE)); } else { setStatuslineToShowMarkerMessages(null); } } /** * Controls if the ridget messages from this dialog are displayed in the status line (if any). * <p> * This behavior is: * <ul> * <li>disabled by default, * <li>can be defined globally by setting '<code>riena.showRidgetMessagesInStatusline=true</code>' using extension point * <tt>org.eclipse.riena.core.configuration</tt>, * <li>can be defined individually (overriding the global setting) for this dialog using this method. * </ul> * <p> * This method will be called by {@link #afterBind()} <strong>after</strong> {@link #configureRidgets()} was executed. * * @return <code>true</code> if the ridget messages should be displayed in the status line * @since 5.0 * @see IRidgetContainer#setStatuslineToShowMarkerMessages(IStatuslineRidget) */ protected boolean shouldEnableStatuslineMessageViewer() { final String value = RienaConfiguration.getInstance().getProperty(RidgetToStatuslineSubscriber.SHOW_RIDGET_MESSAGES_IN_STATUSLINE_KEY); return Boolean.parseBoolean(value); } public void configureRidgets() { setWindowRidget((IWindowRidget) getRidget(RIDGET_ID_WINDOW)); configureOkCancelButtons(); } /** * @since 3.0 */ protected void configureOkCancelButtons() { final IActionRidget okAction = getRidget(IActionRidget.class, RIDGET_ID_OK); if (okAction != null) { okAction.setText("&Okay"); //$NON-NLS-1$ okAction.addListener(new IActionListener() { public void callback() { close(OK); } }); } final IActionRidget cancelAction = getRidget(IActionRidget.class, RIDGET_ID_CANCEL); if (cancelAction != null) { cancelAction.addListener(new IActionListener() { public void callback() { close(CANCEL); } }); } } /** * @since 1.2 */ public Object getContext(final String key) { return context.get(key); } public <R extends IRidget> R getRidget(final String id) { return (R) ridgets.get(id); } /** * @since 2.0 */ public <R extends IRidget> R getRidget(final Class<R> ridgetClazz, final String id) { R ridget = getRidget(id); if (ridget != null) { return ridget; } if (RienaStatus.isTest()) { try { if (ridgetClazz.isInterface() || Modifier.isAbstract(ridgetClazz.getModifiers())) { final Class<R> mappedRidgetClazz = (Class<R>) ClassRidgetMapper.getInstance().getRidgetClass(ridgetClazz); if (mappedRidgetClazz != null) { ridget = mappedRidgetClazz.newInstance(); } Assert.isNotNull(ridget, "Could not find a corresponding implementation for " + ridgetClazz.getName() + " in " + ClassRidgetMapper.class.getName()); //$NON-NLS-1$ //$NON-NLS-2$ } else { ridget = ridgetClazz.newInstance(); } } catch (final InstantiationException e) { throw new RuntimeException(e); } catch (final IllegalAccessException e) { throw new RuntimeException(e); } addRidget(id, ridget); } return ridget; } public Collection<? extends IRidget> getRidgets() { return ridgets.values(); } /** * @return The window ridget. */ public IWindowRidget getWindowRidget() { if (RienaStatus.isTest() && windowRidget == null) { final Class<IWindowRidget> mappedRidgetClazz = (Class<IWindowRidget>) ClassRidgetMapper.getInstance().getRidgetClass(IShellRidget.class); try { if (mappedRidgetClazz != null) { windowRidget = mappedRidgetClazz.newInstance(); } Assert.isNotNull(windowRidget, "Could not find a corresponding implementation for IWindowRidget in " + ClassRidgetMapper.class.getName()); //$NON-NLS-1$ } catch (final InstantiationException e) { throw new RuntimeException(e); } catch (final IllegalAccessException e) { throw new RuntimeException(e); } } return windowRidget; } /** * Returns the return code for this window. * <p> * These codes are window specific, but two return codes are already defined: {@link #OK} and {@link #CANCEL}. * * @since 1.2 */ public int getReturnCode() { return returnCode; } /** * @param blocker * the blocker to set * @since 6.0 */ public void setBlocker(final Blocker blocker) { this.blocker = blocker; } /** * Set a {@link Blocker} implementation to handle the <tt>'blocked'</tt> state or <code>null</code> if blocking is not relevant. * * @since 6.0 */ public Blocker getBlocker() { return blocker; } @Override public boolean isBlocked() { return blocker != null && blocker.isBlocked(); } /** * {@inheritDoc} * <p> * Calls to this method are ignored if no {@link Blocker} is set. * * @see Blocker */ @Override public void setBlocked(final boolean blocked) { if (blocker != null) { blocker.setBlocked(blocked); } } /** * @since 1.2 */ public void setContext(final String key, final Object value) { context.put(key, value); } /** * Set the return code for this window. * <p> * These codes are window specific, but two return codes are already defined: {@link #OK} and {@link #CANCEL}. * * @since 1.2 */ public void setReturnCode(final int returnCode) { this.returnCode = returnCode; } /** * Sets the window ridget. * * @param windowRidget * The window ridget. */ public void setWindowRidget(final IWindowRidget windowRidget) { this.windowRidget = windowRidget; } /** * Closes the dialog and sets given return code. * * @param returnCode * the return code to set. These codes are window specific, but two return codes are already defined: {@link #OK} and {@link #CANCEL}. * @since 3.0 */ public void close(final int returnCode) { disposeAnnotations(); setReturnCode(returnCode); getWindowRidget().dispose(); } /** * {@inheritDoc} * * @since 4.0 */ public void setConfigured(final boolean configured) { this.configured = configured; } /** * {@inheritDoc} * * @since 4.0 */ public boolean isConfigured() { return configured; } /** * @since 6.1 */ public void disposeAnnotations() { if (annotationDisposerList != null) { annotationDisposerList.dispose(); } } /** * @since 6.1 */ public void addAnnotationDisposer(final IDisposer disposer) { if (annotationDisposerList == null) { annotationDisposerList = new DisposerList(); } annotationDisposerList.add(disposer); } }