Files
Brainstorm/Foundation TCV SWT Client/src/com/foundation/tcv/swt/client/Component.java

1160 lines
43 KiB
Java
Raw Normal View History

2014-05-30 10:31:51 -07:00
/*
* 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.
* <p>Note: This differs from the change control decoration in that the user has not made any local changes.</p>
* @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).
* <p>DEBUG ONLY - See server component class's DEBUG flag.</p>
* @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.
* <p>Note: Controls can override this to handle a change in the scale.</p>
* @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.
* <p>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.</p>
* @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.
* <p>Note: Also see IComponentListener and addListener(..) to receive notification when the title changes.</p>
* @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.
* <p>Note: Also see IComponentListener and addListener(..) to receive notification when the title changes.</p>
* @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//