/* * Copyright (c) 2003,2009 Declarative Engineering LLC. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Declarative Engineering LLC * verson 1 which accompanies this distribution, and is available at * http://declarativeengineering.com/legal/DE_Developer_License_v1.txt */ package com.foundation.tcv.swt.client; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.graphics.Color; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Pattern; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import com.common.thread.IRunnable; import com.common.thread.Scheduler; import com.common.util.IIterator; import com.common.util.IList; import com.common.util.LiteList; import com.common.comparison.Comparator; import com.foundation.view.*; import com.foundation.view.swt.util.SwtUtilities; import com.foundation.tcv.client.view.ResourceHolder; import com.foundation.tcv.swt.*; import com.foundation.tcv.view.*; /* * The component is the base class for all standard view components. */ public abstract class Component extends AbstractComponent implements IComponent, IControlLocator, KeyListener { /** DEBUG ONLY - See server component class for the DEBUG flag. */ private String name = null; /** The container containing this component. */ private Container container = null; /** The reference to the popup menu. Not all components must allow a popup menu. */ private Menu menu = null; /** Whether the parent container has been disabled. The active enabled state for this component is: isParentEnabled && isLocallyEnabled. */ protected boolean isParentEnabled = true; /** Whether this component has been disabled. The active enabled state for this component is: isParentEnabled && isLocallyEnabled. */ protected boolean isLocallyEnabled = true; /** Whether the component was given a specific size and thus should not be packed. */ private boolean hasSpecificSize = false; /** The optional decimal scale to be used by the component if it deals with decimal values. */ private Integer decimalScale = null; /** A holder for the value of the tool tip text. */ private ResourceHolder toolTipTextHolder = new ResourceHolder(this); /** A holder for the value of the foreground color. */ private ResourceHolder foregroundColorHolder = new ResourceHolder(this); /** A holder for the value of the background color. */ private ResourceHolder backgroundColorHolder = new ResourceHolder(this); /** A holder for the value of the font. */ private ResourceHolder fontHolder = new ResourceHolder(this); /** A holder for the value of the visibility flag. */ private ResourceHolder isVisibleHolder = new ResourceHolder(this); /** A holder for the value of the enabled state flag. */ private ResourceHolder isEnabledHolder = new ResourceHolder(this); /** A holder for the value of the container title. */ private ResourceHolder containerTitleHolder = new ResourceHolder(this); /** A holder for the value of the container image. */ private ResourceHolder containerImageHolder = new ResourceHolder(this); /** A holder for the value of the background image. */ private ResourceHolder backgroundImageHolder = new ResourceHolder(this); /** A holder for the value of the change notification image. */ private Object changeImage = null; /** A holder for the value of the change notification text. */ private Object changeText = null; /** A holder for the value of the update notification image. */ private Object updateImage = null; /** A holder for the value of the update notification text. */ private Object updateText = null; /** A holder for the value of the update notification timeout. */ private Integer updateTimeout = null; /** The task used to remove the update decoration. */ private UpdateControlDecorationRemovalTask updateControlDecorationRemovalTask = null; /** The currently displayed control decoration notifying the user that the value in the control has been updated. */ private ControlDecoration updateControlDecoration = null; /** The swt image used by the container of this component to represent the component. */ private Image swtContainerImage = null; /** The set of key bindings in search order. */ private IList keyBindings = null; /** The swt image used by the component as the background. This overrides the background gradient. */ private Image currentBackgroundImage = null; /** The gradient to be used for the background gradient, or null if none is to be used. */ private JefGradient currentBackgroundGradient = null; /** The gradient to be used for the background gradient image, or null if none is to be used. */ private Image currentBackgroundGradientImage = null; /** The currently active background color (if using a solid color - versus a gradient. This is used to ensure that the correct color is destroyed when cleaning up. */ private Color currentBackgroundColor = null; /** The currently active foreground color. This is used to ensure that the correct color is destroyed when cleaning up. */ private Color currentForegroundColor = null; /** The currently active font. This is used to ensure that the correct font is destroyed when cleaning up. */ private Font currentFont = null; /** Whether the initialization routine has completed. */ //private boolean isInitializationComplete = false; /** The listener for the resize event that refreshes the background image. */ private Listener backgroundImageResizeListener = null; /** Whether the control should render a custom background. */ private boolean useCustomBackground = false; /** * Encapsulates the images used by the overlay rendering (utilized when the component is a composite and has no background but does have a background color). */ private static class OverlayBufferSet { public Image originalImage = null; public Image bufferImage = null; }//OverlayBufferSet// /** * The task used to remove stale updated decorations on controls. */ private class UpdateControlDecorationRemovalTask implements Runnable { public UpdateControlDecorationRemovalTask() { Integer timeout = getUpdateDecorationTimeout(); getSwtControl().getDisplay().timerExec(timeout == null || timeout.intValue() <= 0 ? 10000 : timeout.intValue(), this); }//UpdateControlDecorationRemovalTask()// public void reset() { Integer timeout = getUpdateDecorationTimeout(); getSwtControl().getDisplay().timerExec(timeout == null || timeout.intValue() <= 0 ? 10000 : timeout.intValue(), this); }//reset()// public void run() { if(updateControlDecoration != null && updateControlDecorationRemovalTask == UpdateControlDecorationRemovalTask.this && !getSwtControl().isDisposed()) { removeDecoration(updateControlDecoration); updateControlDecoration = null; updateControlDecorationRemovalTask = null; }//if// }//evaluate()// }//UpdateControlDecorationRemovalTask// /** * A listener interface so that other interested components can get notification when the tool tip text is altered. */ public interface IComponentListener { /** * Notifies the listener when the component's tool tip has been altered. * @param component The component whose tool tip was modified. * @param newToolTipText The new tool tip. */ public void toolTipTextChanged(Component component, String newToolTipText); /** * Notifies the listener when the container's title is altered. * @param component The component whose title was modified. * @param newTitle The new title. */ public void titleChanged(Component component, String newTitle); /** * Notifies the listener when the container's image is altered. * @param component The component whose image was modified. * @param newImage The new image. */ public void imageChanged(Component component, Image newImage); }//IComponentListener// /** * Component constructor. */ public Component() { }//Component()// /** * Gets the change decoration text by recursively navigating the component hierarchy searching for text that was set by the view. * @return The change decoration's text resource reference or actual text. */ public Object getChangeDecorationText() { return changeText != null ? changeText : getContainer() instanceof Component ? ((Component) getContainer()).getChangeDecorationText() : null; }//getChangeDecorationText()// /** * Gets the change decoration image by recursively navigating the component hierarchy searching for an image that was set by the view. * @return The change decoration's resource reference. */ public Object getChangeDecorationImage() { return changeImage != null ? changeImage : getContainer() instanceof Component ? ((Component) getContainer()).getChangeDecorationImage() : null; }//getChangeDecorationImage()// /** * Gets the ControlDecoration for displaying a change in the data. * @return The decoration used to display a data change or null if not enough data was provided. */ public ControlDecoration getChangeControlDecoration() { Object text = getChangeDecorationText(); Object image = getChangeDecorationImage(); return image != null ? new ControlDecoration(image, text) : null; }//getChangeControlDecoration()// /** * Gets the update decoration text by recursively navigating the component hierarchy searching for text that was set by the view. * @return The update decoration's text resource reference or actual text. */ public Object getUpdateDecorationText() { return updateText != null ? updateText : getContainer() instanceof Component ? ((Component) getContainer()).getUpdateDecorationText() : null; }//getUpdateDecorationText()// /** * Gets the update decoration image by recursively navigating the component hierarchy searching for an image that was set by the view. * @return The update decoration's resource reference. */ public Object getUpdateDecorationImage() { return updateImage != null ? updateImage : getContainer() instanceof Component ? ((Component) getContainer()).getUpdateDecorationImage() : null; }//getUpdateDecorationImage()// /** * Gets the update decoration timeout by recursively navigating the component hierarchy searching for timeout that was set by the view. * @return The update decoration's timeout resource reference or actual timeout. */ public Integer getUpdateDecorationTimeout() { return updateTimeout != null ? updateTimeout : getContainer() instanceof Component ? ((Component) getContainer()).getUpdateDecorationTimeout() : null; }//getUpdateDecorationTimeout()// /** * Gets the ControlDecoration for displaying an update of the data. *
Note: This differs from the change control decoration in that the user has not made any local changes.
* @return The decoration used to display a data update or null if not enough data was provided. */ public ControlDecoration getUpdateControlDecoration() { Object text = getUpdateDecorationText(); Object image = getUpdateDecorationImage(); return image != null ? new ControlDecoration(image, text) : null; }//getUpdateControlDecoration()// /** * Displays the update control decoration. */ public void displayUpdateControlDecoration() { if(updateControlDecoration != null) { updateControlDecorationRemovalTask.reset(); }//if// else { updateControlDecoration = getUpdateControlDecoration(); updateControlDecorationRemovalTask = new UpdateControlDecorationRemovalTask(); if(updateControlDecoration != null) { Control control = addDecoration(updateControlDecoration); if(control != null) { control.addMouseListener(new MouseListener() { public void mouseUp(MouseEvent e) { }//mouseUp()// public void mouseDown(MouseEvent e) { removeDecoration(updateControlDecoration); updateControlDecoration = null; Scheduler.removeTask(updateControlDecorationRemovalTask); updateControlDecorationRemovalTask = null; }//mouseDown()// public void mouseDoubleClick(MouseEvent e) { }//mouseDoubleClick()// }); }//if// }//if// }//else// }//displayUpdateControlDecoration()// /* (non-Javadoc) * @see AbstractComponent#destroy() */ protected void destroy() { if(getSwtControl() != null) { if(!getSwtControl().isDisposed()) { getSwtControl().setVisible(false); }//if// super.destroy(); }//if// }//destroy()// /** * Gets the component's given name (from the VML). *DEBUG ONLY - See server component class's DEBUG flag.
* @return The name for the component or null if unknown. */ public String getName() { return name; }//getName()// /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#getContainer() */ public Container getContainer() { return container; }//getContainer()// /** * Sets the parent container for this component. * @param container The view component containing this component. */ protected void setContainer(Container container) { this.container = container; }//setContainer()// /* (non-Javadoc) * @see com.foundation.view.swt.IDecoration#getMenuBar() */ public Menu getMenu() { return menu; }//getMenuBar()// /* (non-Javadoc) * @see com.foundation.view.swt.IDecoration#setMenuBar(com.foundation.view.swt.Menu) */ public void setMenu(Menu menu) { this.menu = menu; getSwtControl().setMenu(menu != null ? menu.getSwtMenu() : null); }//setMenu()// /** * Gets the widget encapsulated by this component. * @return The encapsulated widget, or null if this component does not have a viewable element. */ public Control getSwtControl() { return (Control) getSwtWidget(); }//getSwtControl()// /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#getShell() */ public Shell getShell() { return getSwtControl() != null && !getSwtControl().isDisposed() ? getSwtControl().getShell() : null; }//getShell()// /** * Gets the optional decimal scale to be used by the component if it deals with decimal values. *Note: Controls can override this to handle a change in the scale.
* @return The optional decimal scale which if negative by default should trim extra zeros (note that BigDecimal does not automatically do this). */ public Integer getDecimalScale() { return decimalScale; }//getDecimalScale()// /** * Sets the optional decimal scale to be used by the component if it deals with decimal values. * @param decimalScale The optional decimal scale which if negative by default should trim extra zeros (note that BigDecimal does not automatically do this). */ public void setDecimalScale(Integer decimalScale) { this.decimalScale = decimalScale; }//setDecimalScale()// /** * Searches this component and all child components for the control with the focus. * @return The control with the focus, or null if no control has the focus. */ protected Control getFocusControl() { return getSwtControl().isFocusControl() ? getSwtControl() : null; }//getFocusControl()// /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#inernalViewInitializeAll() */ protected void internalViewInitializeAll() { if(getMenu() != null) { getMenu().internalViewInitializeAll(); }//if// super.internalViewInitializeAll(); }//inernalViewInitializeAll()// /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#internalViewReleaseAll() */ protected void internalViewReleaseAll() { if(getMenu() != null) { getMenu().internalViewReleaseAll(); }//if// super.internalViewReleaseAll(); }//internalViewReleaseAll()// /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#internalViewInitialize() */ protected void internalViewInitialize() { if(keyBindings != null && keyBindings.getSize() > 0) { getSwtControl().addKeyListener(this); }//if// if(useCustomBackground) { registerCustomBackgroundRenderer(); }//if// super.internalViewInitialize(); }//internalViewInitialize()// /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#internalViewRelease() */ protected void internalViewRelease() { if(getContainer() != null) { getContainer().getComponents().remove(this); }//if// toolTipTextHolder.release(); foregroundColorHolder.release(); backgroundColorHolder.release(); fontHolder.release(); isVisibleHolder.release(); isEnabledHolder.release(); containerImageHolder.release(); containerTitleHolder.release(); backgroundImageHolder.release(); if(getCurrentBackgroundImage() != null) { destroyImage(getCurrentBackgroundImage()); setCurrentBackgroundImage(null); }//if// if(getCurrentBackgroundGradientImage() != null) { getCurrentBackgroundGradientImage().dispose(); setCurrentBackgroundGradientImage(null); }//if// if(getCurrentForegroundColor() != null) { destroyColor(getCurrentForegroundColor()); setCurrentForegroundColor(null); }//if// if(getCurrentBackgroundColor() != null) { destroyColor(getCurrentBackgroundColor()); setCurrentBackgroundColor(null); }//if// if(getCurrentFont() != null) { destroyFont(getCurrentFont()); setCurrentFont(null); }//if// if(swtContainerImage != null) { destroyImage(swtContainerImage); swtContainerImage = null; }//if// super.internalViewRelease(); }//internalViewRelease()// /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#internalViewSynchronizeAll() */ protected void internalViewSynchronizeAll() { if(getMenu() != null) { getMenu().internalViewSynchronizeAll(); }//if// super.internalViewSynchronizeAll(); }//internalViewSynchronizeAll()// /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#internalResourceHolderChanged(com.foundation.tcv.client.view.ResourceHolder, java.lang.Object, java.lang.Object, int) */ protected void internalResourceHolderChanged(ResourceHolder resourceHolder, Object oldValue, Object newValue, int flags) { if(resourceHolder == toolTipTextHolder) { String value = newValue != null ? newValue.toString() : null; setToolTipText(value); }//if// else if(resourceHolder == containerTitleHolder) { IIterator listeners = getListeners(IComponentListener.class); //Notify all the listeners.// while(listeners.hasNext()) { ((IComponentListener) listeners.next()).titleChanged(this, (String) newValue); }//while// }//else if// else if(resourceHolder == containerImageHolder) { IIterator listeners = getListeners(IComponentListener.class); destroyImage(swtContainerImage); swtContainerImage = createImage((JefImage) containerImageHolder.getValue()); //Notify all the listeners.// while(listeners.hasNext()) { ((IComponentListener) listeners.next()).imageChanged(this, swtContainerImage); }//while// }//else if// else if(resourceHolder == backgroundColorHolder) { internalSetBackgroundColor(newValue instanceof JefColor ? new JefGradient((JefColor) newValue, null, JefGradient.DIAGONAL) : (JefGradient) newValue); }//else if// else if(resourceHolder == foregroundColorHolder) { internalSetForegroundColor((JefColor) newValue); }//else if// else if(resourceHolder == fontHolder) { internalSetFont(newValue == null || newValue instanceof JefFont[] ? (JefFont[]) newValue : new JefFont[] {(JefFont) newValue}); resize(); }//else if// else if(resourceHolder == isVisibleHolder) { if(!getSwtControl().isDisposed()) { getSwtControl().setVisible(((Boolean) newValue).booleanValue()); //Never resize shells when changing visibility since nothing about the size should have changed from when the shell was first created.// if(!(getSwtControl() instanceof Shell)) { resize(); }//if// }//if// }//else if// else if(resourceHolder == isEnabledHolder) { internalSetEnabledState(((Boolean) newValue).booleanValue(), true); //Never resize shells when changing visibility since nothing about the size should have changed from when the shell was first created.// if(!(getSwtControl() instanceof Shell)) { resize(); }//if// }//else if// else if(resourceHolder == backgroundImageHolder) { internalSetBackgroundImage((JefImage) backgroundImageHolder.getValue()); }//else if// else { super.internalResourceHolderChanged(resourceHolder, oldValue, newValue, flags); }//else// }//internalOnAssociationChanged()// /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#internalOnLinkInvoked(int, java.lang.Object) */ protected void internalOnLinkInvoked(int linkTarget, Object data) { switch(linkTarget) { case LINK_TARGET_IS_VISIBLE: { boolean isVisible = data != null && data instanceof Boolean ? ((Boolean) data).booleanValue() : false; if(getSwtControl().getVisible() != isVisible) { getSwtControl().setVisible(isVisible); //Never resize shells when changing visibility since nothing about the size should have changed from when the shell was first created.// if(!(getSwtControl() instanceof Shell)) { resize(); }//if// }//if// break; }//case// case LINK_TARGET_IS_ENABLED: { internalSetEnabledState(data != null && data instanceof Boolean ? ((Boolean) data).booleanValue() : false, true); break; }//case// case LINK_TARGET_GAIN_FOCUS: { getSwtControl().setFocus(); break; }//case// case LINK_TARGET_TOOL_TIP_TEXT: { getSwtControl().setToolTipText(data instanceof String ? (String) data : ""); break; }//case// case LINK_TARGET_BACKGROUND_COLOR: { internalSetBackgroundColor(data instanceof JefGradient ? (JefGradient) data : data instanceof JefColor ? new JefGradient((JefColor) data) : null); break; }//case// case LINK_TARGET_FOREGROUND_COLOR: { internalSetForegroundColor(data instanceof JefColor ? (JefColor) data : null); break; }//case// case LINK_TARGET_FONT: { internalSetFont(data instanceof JefFont ? new JefFont[] {(JefFont) data} : data instanceof JefFont[] ? (JefFont[]) data : null); break; }//case// default: { super.internalOnLinkInvoked(linkTarget, data); break; }//default// }//switch// }//internalOnLinkInvoked()// /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#internalProcessMessage(com.foundation.tcv.model.ViewMessage) */ public Object internalProcessMessage(ViewMessage viewMessage) { Object retVal = null; switch(viewMessage.getMessageNumber()) { case MESSAGE_GET_BOUNDS: { retVal = getSwtControl().getBounds(); break; }//case// case MESSAGE_GET_LOCATION: { retVal = getSwtControl().getLocation(); break; }//case// case MESSAGE_GET_SIZE: { retVal = getSwtControl().getSize(); break; }//case// case MESSAGE_GET_IS_FOCUS_CONTROL: { retVal = getSwtControl().isFocusControl() ? Boolean.TRUE : Boolean.FALSE; break; }//case// case MESSAGE_SET_BOUNDS: { getSwtControl().setBounds(((int[]) viewMessage.getMessageData())[0], ((int[]) viewMessage.getMessageData())[1], ((int[]) viewMessage.getMessageData())[2], ((int[]) viewMessage.getMessageData())[3]); break; }//case// case MESSAGE_SET_LOCATION: { getSwtControl().setLocation(((int[]) viewMessage.getMessageData())[0], ((int[]) viewMessage.getMessageData())[1]); break; }//case// case MESSAGE_SET_SIZE: { hasSpecificSize = true; getSwtControl().setSize(((int[]) viewMessage.getMessageData())[0], ((int[]) viewMessage.getMessageData())[1]); break; }//case// case MESSAGE_SET_FOCUS: { getSwtControl().setFocus(); break; }//case// case MESSAGE_SET_IS_VISIBLE: { isVisibleHolder.setValue(viewMessage.getMessageData()); break; }//case// case MESSAGE_SET_IS_ENABLED: { isEnabledHolder.setValue(viewMessage.getMessageData()); break; }//case// case MESSAGE_SET_LAYOUT_DATA: { getSwtControl().setLayoutData(((LayoutData) viewMessage.getMessageData()).createSwtLayoutData(this)); resize(); break; }//case// case MESSAGE_SET_TOOL_TIP_TEXT: { toolTipTextHolder.setValue(viewMessage.getMessageData()); break; }//case// case MESSAGE_SET_BACKGROUND_COLOR: { backgroundColorHolder.setValue(viewMessage.getMessageData()); break; }//case// case MESSAGE_SET_FOREGROUND_COLOR: { foregroundColorHolder.setValue(viewMessage.getMessageData()); break; }//case// case MESSAGE_SET_FONTS: { fontHolder.setValue(viewMessage.getMessageData()); break; }//case// case MESSAGE_PACK: { if(!isSuspendingLayouts()) { if(viewMessage.getMessageData() instanceof Boolean) { getSwtControl().pack(((Boolean) viewMessage.getMessageData()).booleanValue()); }//if// else { getSwtControl().pack(); }//else// }//if// break; }//case// case MESSAGE_SET_DECIMAL_SCALE: { setDecimalScale((Integer) viewMessage.getMessageData()); break; }//case// case MESSAGE_SET_CONTAINER_TITLE: { containerTitleHolder.setValue(viewMessage.getMessageData()); break; }//case// case MESSAGE_SET_CONTAINER_IMAGE: { containerImageHolder.setValue(viewMessage.getMessageData()); break; }//case// case MESSAGE_ADD_KEY_BINDING: { if(keyBindings == null) { keyBindings = new LiteList(10, 40); }//if// keyBindings.add((KeyBindingData) viewMessage.getMessageData()); if(isInitialized()) { if(keyBindings.getSize() == 1) { getSwtControl().addKeyListener(this); }//if// }//if// break; }//case// case MESSAGE_SET_BACKGROUND_IMAGE: { backgroundImageHolder.setValue(viewMessage.getMessageData()); break; }//case// case MESSAGE_SET_CHANGE_IMAGE: { changeImage = viewMessage.getMessageData(); break; }//case// case MESSAGE_SET_CHANGE_TEXT: { changeText = viewMessage.getMessageData(); break; }//case// case MESSAGE_SET_UPDATE_IMAGE: { updateImage = viewMessage.getMessageData(); break; }//case// case MESSAGE_SET_UPDATE_TEXT: { updateText = viewMessage.getMessageData(); break; }//case// case MESSAGE_SET_UPDATE_TIMEOUT: { updateTimeout = (Integer) viewMessage.getMessageData(); break; }//case// case MESSAGE_DISPLAY_UPDATE_CONTROL_DECORATION: { //Notify the user that the value has changed from the model.// displayUpdateControlDecoration(); break; }//case// case MESSAGE_SET_NAME: { this.name = (String) viewMessage.getMessageData(); break; }//case// case MESSAGE_USE_CUSTOM_BACKGROUND: { useCustomBackground = true; break; }//case// default: { retVal = super.internalProcessMessage(viewMessage); }//case// }//switch// return retVal; }//internalProcessMessage()// /** * Updates the background image for the control. * The subclass can override this method if there is more than one potential source for the background image. */ protected void controlUpdateBackgroundImage() { if(getCurrentBackgroundImage() != null) { getSwtControl().setBackgroundImage(getCurrentBackgroundImage()); }//if// else { getSwtControl().setBackgroundImage(getCurrentBackgroundGradientImage()); }//else// }//controlUpdateBackgroundImage()// /** * Updates the background color for the control. * The subclass can override this method if there is more than one potential source for the background color. */ protected void controlUpdateBackgroundColor() { getSwtControl().setBackground(getCurrentBackgroundColor()); }//controlUpdateBackgroundColor()// /** * Updates the foreground color for the control. * The subclass can override this method if there is more than one potential source for the foreground color. */ protected void controlUpdateForegroundColor() { getSwtControl().setForeground(getCurrentForegroundColor()); }//controlUpdateForegroundColor()// /** * Updates the font for the control. * The subclass can override this method if there is more than one potential source for the font. */ protected void controlUpdateFont() { getSwtControl().setFont(getCurrentFont()); }//controlUpdateFont()// /** * Sets the background image using the gradient data. * Note that any previous background image will be disposed. *Warning: Don't call this method if there is a background image set since the gradient shouldn't over write it and won't properly dispose of the resources.
* @param gradient The gradient to be used. */ protected void internalSetBackgroundImage(JefGradient gradient) { Image image = null; //Dispose of the old gradient background image.// if(getCurrentBackgroundGradientImage() != null) { getCurrentBackgroundGradientImage().dispose(); }//if// setCurrentBackgroundColor(gradient != null ? createColor(gradient.getStartColor()) : null); if(gradient != null) { Rectangle clientArea = getSwtControl() instanceof Composite ? ((Composite) getSwtControl()).getClientArea() : getSwtControl().getBounds(); if(clientArea.width != 0 && clientArea.height != 0) { Display display = getSwtControl().getDisplay(); Color c1 = createColor(gradient.getStartColor()); Color c2 = createColor(gradient.getEndColor()); Pattern pattern = new Pattern(display, (gradient.getDirection() == JefGradient.REVERSE_DIAGONAL ? clientArea.width : 0), 0, (gradient.getDirection() == JefGradient.VERTICAL ? 1 : gradient.getDirection() == JefGradient.REVERSE_DIAGONAL ? 0 : clientArea.width), (gradient.getDirection() == JefGradient.HORIZONTAL ? 1 : clientArea.height), c1, gradient.getStartColor().getAlpha(), c2, gradient.getEndColor().getAlpha()); GC gc; image = new Image(display, Math.max(1, clientArea.width), Math.max(1, clientArea.height)); gc = new GC(image); //Force the x/y values to zero since getBounds uses them to provide the upper left point of the control.// clientArea.x = 0; clientArea.y = 0; clientArea.width = Math.max(1, clientArea.width); clientArea.height = Math.max(1, clientArea.height); gc.setBackgroundPattern(pattern); gc.fillRectangle(clientArea); gc.dispose(); destroyColor(c1); destroyColor(c2); pattern.dispose(); }//if// }//if// setCurrentBackgroundGradient(gradient); setCurrentBackgroundGradientImage(image); controlUpdateBackgroundColor(); controlUpdateBackgroundImage(); }//controlSetBackgroundImage()// /** * Sets the control's background image. * @param image The image to use for the background. */ protected void internalSetBackgroundImage(JefImage image) { if(getCurrentBackgroundImage() != null) { destroyImage(getCurrentBackgroundImage()); }//if// setCurrentBackgroundImage(createImage(image)); controlUpdateBackgroundImage(); }//internalSetBackgroundImage()// /** * Sets the control's background color. * @param color The background color. */ protected void internalSetBackgroundColor(JefGradient color) { if(useCustomBackground) { setCurrentBackgroundGradient(color); }//if// else if((color == null) || (color != null && color.getEndColor() == null)) { //Dispose of the old background color.// if(getCurrentBackgroundColor() != null) { destroyColor(getCurrentBackgroundColor()); }//if// //Dispose of the old background gradient since you can't have both a color and a gradient.// if(getCurrentBackgroundGradientImage() != null) { getCurrentBackgroundGradientImage().dispose(); setCurrentBackgroundGradientImage(null); controlUpdateBackgroundImage(); unregisterBackgroundImageResizeListener(); }//if// setCurrentBackgroundColor(createColor(color == null ? null : color.getStartColor())); controlUpdateBackgroundColor(); }//else if// else { //Dispose of the old background color since you can't have both a color and a gradient.// if(getCurrentBackgroundColor() != null) { destroyColor(getCurrentBackgroundColor()); }//if// setCurrentBackgroundGradient(color); registerBackgroundImageResizeListener(); internalSetBackgroundImage(color); }//else// }//controlSetBackgroundColor()// /** * Sets up the listener to render a custom background. */ protected void registerCustomBackgroundRenderer() { if(!getSwtControl().isDisposed()) { getSwtControl().addListener(SWT.Paint, new Listener() { private OverlayBufferSet overlayBufferSet = new OverlayBufferSet(); public void handleEvent(Event event) { renderCustomBackground(event.gc, overlayBufferSet); }//handleEvent()// }); }//if// }//registerCustomBackgroundRenderer()// /** * Renders a custom overlay background. */ protected void renderCustomBackground(GC gc, OverlayBufferSet overlayBufferSet) { JefGradient gradient = getCurrentBackgroundGradient(); if(gradient != null && gradient.getStartColor() != null) { Rectangle bounds = getSwtControl().getBounds(); if(overlayBufferSet.originalImage == null) { overlayBufferSet.originalImage = new Image(getDisplay(), bounds.width, bounds.height); gc.copyArea(overlayBufferSet.originalImage, 0, 0); }//if// if(overlayBufferSet.bufferImage == null || bounds.width != overlayBufferSet.bufferImage.getImageData().width || bounds.height != overlayBufferSet.bufferImage.getImageData().height) { JefColor jefColor = gradient.getStartColor(); Color color = createColor(jefColor); GC bufferGc = null; if(overlayBufferSet.bufferImage != null) { overlayBufferSet.bufferImage.dispose(); }//if// overlayBufferSet.bufferImage = new Image(getDisplay(), bounds.width, bounds.height); bufferGc = new GC(overlayBufferSet.bufferImage); bufferGc.setAdvanced(true); bufferGc.drawImage(overlayBufferSet.originalImage, 0, 0); bufferGc.setAlpha(jefColor.getAlpha()); bufferGc.setBackground(color); bufferGc.fillRectangle(bounds); bufferGc.dispose(); destroyColor(color); }//if// gc.drawImage(overlayBufferSet.bufferImage, 0, 0); }//if// }//renderCustomBackground()// /** * Unregisters the resize listener that updates the background image. */ protected void unregisterBackgroundImageResizeListener() { if(!getSwtControl().isDisposed() && backgroundImageResizeListener != null) { getSwtControl().removeListener(SWT.Resize, backgroundImageResizeListener); backgroundImageResizeListener = null; }//if// }//unregisterBackgroundImageResizeListener()// /** * Registers the resize listener that updates the background image. */ protected void registerBackgroundImageResizeListener() { if(!getSwtControl().isDisposed() && backgroundImageResizeListener == null) { getSwtControl().addListener(SWT.Resize, backgroundImageResizeListener = new Listener() { public void handleEvent(Event event) { internalSetBackgroundImage(getCurrentBackgroundGradient()); }//handleEvent()// }); }//if// }//registerBackgroundImageResizeListener()// /** * Sets the control's foreground color. * @param color The foreground color. */ protected void internalSetForegroundColor(JefColor color) { if(currentForegroundColor != null) { destroyColor(currentForegroundColor); }//if// setCurrentForegroundColor(createColor(color)); controlUpdateForegroundColor(); }//controlSetForegroundColor()// /** * Sets the control's font. * @param color The font. */ protected void internalSetFont(JefFont[] font) { if(currentFont != null) { destroyFont(currentFont); }//if// setCurrentFont(createFont(font)); controlUpdateFont(); }//controlSetFont()// /** * Gets the current background image used by the component. * @return The currently used background image, or null if none is provided. */ protected Image getCurrentBackgroundImage() { return currentBackgroundImage; }//getCurrentBackgroundImage()// /** * Sets the current background image used by the component. * @param currentBackgroundImage The currently used background image, or null if none is provided. */ protected void setCurrentBackgroundImage(Image currentBackgroundImage) { this.currentBackgroundImage = currentBackgroundImage; }//setCurrentBackgroundImage()// /** * Gets the current background gradient used by the component. * @return The currently used background gradient, or null if none is provided. */ protected JefGradient getCurrentBackgroundGradient() { return currentBackgroundGradient; }//getCurrentBackgroundGradient()// /** * Sets the current background gradient used by the component. * @param currentBackgroundGradient The currently used background gradient, or null if none is provided. */ protected void setCurrentBackgroundGradient(JefGradient currentBackgroundGradient) { this.currentBackgroundGradient = currentBackgroundGradient; }//setCurrentBackgroundGradient()// /** * Gets the current background gradient image used by the component. * @return The currently used background gradient image, or null if none is provided. */ protected Image getCurrentBackgroundGradientImage() { return currentBackgroundGradientImage; }//getCurrentBackgroundGradientImage()// /** * Sets the current background gradient image used by the component. * @param currentBackgroundGradientImage The currently used background gradient image, or null if none is provided. */ protected void setCurrentBackgroundGradientImage(Image currentBackgroundGradientImage) { this.currentBackgroundGradientImage = currentBackgroundGradientImage; }//setCurrentBackgroundGradientImage()// /** * Gets the current foreground color used by the component. * @return The currently used foreground color, or null if none is provided. */ protected Color getCurrentForegroundColor() { return currentForegroundColor; }//getCurrentForegroundColor()// /** * Sets the current foreground color used by the component. * @param currentForegroundColor The currently used foreground color, or null if none is provided. */ protected void setCurrentForegroundColor(Color currentForegroundColor) { this.currentForegroundColor = currentForegroundColor; }//setCurrentForegroundColor()// /** * Gets the current background color used by the component. * @return The currently used background color, or null if none is provided. */ protected Color getCurrentBackgroundColor() { return currentBackgroundColor; }//getCurrentBackgroundColor()// /** * Sets the current background color used by the component. * @param currentBackgroundColor The currently used background color, or null if none is provided. */ protected void setCurrentBackgroundColor(Color currentBackgroundColor) { this.currentBackgroundColor = currentBackgroundColor; }//setCurrentBackgroundColor()// /** * Gets the current font used by the component. * @return The currently used font, or null if none is provided. */ protected Font getCurrentFont() { return currentFont; }//getCurrentFont()// /** * Sets the current font used by the component. * @param currentFont The currently used font, or null if none is provided. */ protected void setCurrentFont(Font currentFont) { this.currentFont = currentFont; }//setCurrentFont()// /** * Performs the actual work of enable or disabling the component. * @param isEnabled Whether the enabled state should be altered to be enabled, otherwise it is altered to be disabled. * @param isLocal Whether this change in state is locally generated, or from the parent container. */ protected void internalSetEnabledState(boolean isEnabled, boolean isLocal) { //Some components may not have controls, such as value holders.// if(getSwtControl() != null && !getSwtControl().isDisposed()) { if(isLocal) { isLocallyEnabled = isEnabled; }//if// else { isParentEnabled = isEnabled; }//else// getSwtControl().setEnabled(isLocallyEnabled && isParentEnabled); }//if// }//internalSetEnabledState()// /** * Gets the container's title. *Note: Also see IComponentListener and addListener(..) to receive notification when the title changes.
* @return The container's title to be used when needed (example: a tab in a tab panel, or title bar of the window). */ public String getContainerTitle() { return (String) this.containerTitleHolder.getValue(); }//setContainerTitle()// /** * Gets the container's image. *Note: Also see IComponentListener and addListener(..) to receive notification when the title changes.
* @return The image data that will be displayed by the container when an image is needed to represent it (example: a tab in a tab panel). */ public Image getContainerImage() { return swtContainerImage; }//getContainerImage()// /** * Gets this component's assigned tool tip text. * @return The tool tip for this component. */ public String getToolTipText() { return (String) toolTipTextHolder.getValue(); }//getToolTipText()// /** * Sets this component's assigned tool tip text. * @param toolTipText The tool tip for this component. */ public void setToolTipText(String toolTipText) { if(!Comparator.equals(toolTipText, getSwtControl().getToolTipText())) { IIterator listeners = getListeners(IComponentListener.class); //Notify all the listeners.// while(listeners.hasNext()) { ((IComponentListener) listeners.next()).toolTipTextChanged(this, toolTipText); }//while// //Update the control.// getSwtControl().setToolTipText(toolTipText); }//if// }//setToolTipText()// /* (non-Javadoc) * @see com.foundation.tcv.swt.IControlLocator#getControl(int) */ public Control getControl(int componentNumber) { return ((Component) getSessionViewController().getComponent(componentNumber)).getSwtControl(); }//getControl()// /* (non-Javadoc) * @see com.foundation.tcv.swt.client.AbstractComponent#internalInitializationComplete() */ protected void internalInitializationComplete() { /* This doesn't work at this time because it doesn't make the startup of complex views faster and doesn't fix odd rendering in the table/tree cell components. if(getSwtControl() instanceof Composite) { if(!hasSpecificSize) { getSwtControl().pack(true); }//if// ((Composite) getSwtControl()).layout(); }//if// else { if(!hasSpecificSize) { getSwtControl().pack(true); }//if// }//else// isInitializationComplete = true; */ }//internalInitializationComplete()// /** * Forces the component to resize and requests that the window layout. */ public void resize() { if(getSwtControl() != null && !getSwtControl().isDisposed()) { flushLayoutCache(); }//if// if(isInitialized() && !isSuspendingLayouts()) { if(!hasSpecificSize) { getSwtControl().pack(true); }//if// if(getSwtControl() instanceof Shell) { ((Shell) getSwtControl()).layout(); }//if// else if(getSwtControl().getParent() != null) { getSwtControl().getParent().layout(); }//else if// //Allow the parents of this component to adjust to the children resizing.// if(!hasSpecificSize && getContainer() != null) { getContainer().postResize(); }//if// }//if// }//resize()// /** * Clears any cached data in the component's layout due to a change in the component's state that would invalidate any cached layout information. */ public void flushLayoutCache() { Control control = getSwtControl(); if(control.getLayoutData() instanceof com.foundation.view.swt.layout.LayoutData) { ((com.foundation.view.swt.layout.LayoutData) control.getLayoutData()).flushCache(); }//if// if(getContainer() != null) { getContainer().flushLayoutCache(); }//if// }//flushLayoutCache()// /* (non-Javadoc) * @see org.eclipse.swt.events.KeyListener#keyPressed(org.eclipse.swt.events.KeyEvent) */ public void keyPressed(KeyEvent event) { int modifiers = SwtUtilities.convertKeyModifiers(event.stateMask); int character = event.keyCode; if(keyBindings != null) { for(int index = 0; (event.doit) && (index < keyBindings.getSize()); index++) { KeyBindingData keyBinding = (KeyBindingData) keyBindings.get(index); if(keyBinding.getModifiers() == modifiers) { if(keyBinding.getKeyCode() != null) { if(keyBinding.getKeyCode().intValue() == character) { sendRoundTripMessage(MESSAGE_INVOKE_KEY_BINDING, null, null, modifiers, character, null); event.doit = false; }//if// }//if// else { //TODO: Can we detect a modifier key being pressed without a non-modifier key? }//else// }//if// }//for// }//if// }//keyPressed()// /* (non-Javadoc) * @see org.eclipse.swt.events.KeyListener#keyReleased(org.eclipse.swt.events.KeyEvent) */ public void keyReleased(KeyEvent event) { }//keyReleased()// }//Component//