提交 66911f3b 编写于 作者: P peterz

6591875: Nimbus Swing Look and Feel

Reviewed-by: jasper, ohair
上级 b93964d4
......@@ -9,25 +9,35 @@ Simple Build Instructions:
http://java.sun.com/javase/downloads/index.jsp
Set the environment variable ALT_BOOTDIR to the location of this JDK 6.
2. Download and install the Binary Plugs for the most recent JDK7 from
2. Download and install the JIBX libraries, version 1.1.5 from
http://sourceforge.net/project/showfiles.php?group_id=69358&package_id=68290
You'll need the following four JAR files:
bcel.jar
jibx-bind.jar
jibx-run.jar
xpp3.jar
Set the environment variable ALT_JIBX_LIBS_PATH to the location of
these JAR files.
3. Download and install the Binary Plugs for the most recent JDK7 from
http://download.java.net/openjdk/jdk7/
Set the environment variable ALT_BINARY_PLUGS_PATH to the location of
these binary plugs.
3. Either download and install the latest JDK7 from
4. Either download and install the latest JDK7 from
http://download.java.net/openjdk/jdk7/, or build your own complete
OpenJDK7 by using the top level Makefile in the OpenJDK Mercurial forest.
Set the environment variable ALT_JDK_IMPORT_PATH to the location of
this latest JDK7 or OpenJDK7 build.
4. Check the sanity of doing a build with the current machine:
5. Check the sanity of doing a build with the current machine:
cd make && gnumake sanity
See README-builds.html if you run into problems.
5. Do a partial build of the jdk:
6. Do a partial build of the jdk:
cd make && gnumake all
6. Construct the images:
7. Construct the images:
cd make && gnumake images
The resulting JDK image should be found in build/*/j2sdk-image
......
......@@ -92,7 +92,8 @@ sanity-all:: sanity-base \
sane-ld_run_path \
sane-alt_bootdir \
sane-bootdir \
sane-alsa-headers
sane-alsa-headers \
sane-jibx
ifdef OPENJDK
sanity-all:: sane-freetype
......
......@@ -515,6 +515,15 @@ endif
# NOTE: ISA_DIR is usually empty, on Solaris it might be /sparcv9 or /amd64
BINDIR = $(OUTPUTDIR)/bin$(ISA_DIR)
# JIBX_LIBS_PATH: path to JIBX libraries, needed for NimbusLookAndFeel
ifdef ALT_JIBX_LIBS_PATH
JIBX_LIBS_PATH:=$(call FullPath,$(ALT_JIBX_LIBS_PATH))
JIBX_LIBS_PATH:=$(call AltCheckSpaces,JIBX_LIBS_PATH)
JIBX_LIBS_PATH:=$(call AltCheckValue,JIBX_LIBS_PATH)
else
JIBX_LIBS_PATH=$(JDK_DEVTOOLS_DIR)/share/jibx/lib
endif
# MOZILLA_HEADERS_PATH: path to mozilla header files for plugin
ifdef ALT_MOZILLA_HEADERS_PATH
MOZILLA_HEADERS_PATH :=$(call FullPath,$(ALT_MOZILLA_HEADERS_PATH))
......@@ -529,7 +538,7 @@ ifneq ($(PLATFORM), windows)
JDK_CUPS_HEADERS_PATH=$(JDK_DEVTOOLS_DIR)/share/cups/include
ifdef ALT_CUPS_HEADERS_PATH
CUPS_HEADERS_PATH:=$(call FullPath,$(ALT_CUPS_HEADERS_PATH))
CUP_HEADERS_PATH:=$(call AltCheckValue,CUPS_HEADERS_PATH)
CUPS_HEADERS_PATH:=$(call AltCheckValue,CUPS_HEADERS_PATH)
else
CUPS_HEADERS_PATH:= \
$(shell if [ -d "$(JDK_CUPS_HEADERS_PATH)" ]; then \
......
......@@ -89,8 +89,8 @@ PLATFORM_SHARED=done
SYSTEM_UNAME := $(shell uname)
# Normal boot jdk is previous release, but a hard requirement is a 1.5 boot
REQUIRED_BOOT_VER = 1.5
# Normal boot jdk is previous release, but a hard requirement is a 1.6 boot
REQUIRED_BOOT_VER = 1.6
# If we are using freetype, this is the required version
REQUIRED_FREETYPE_VERSION=2.3.0
......
......@@ -237,6 +237,7 @@ ifeq ($(PLATFORM),windows)
endif
endif
ALL_SETTINGS+=$(call addAltSetting,CACERTS_FILE)
ALL_SETTINGS+=$(call addAltSetting,JIBX_LIBS_PATH)
ifndef OPENJDK
ALL_SETTINGS+=$(call addAltSetting,MOZILLA_HEADERS_PATH)
endif
......
......@@ -169,6 +169,7 @@ include $(JDK_MAKE_SHARED_DIR)/Sanity-Settings.gmk
sane-cacerts \
sane-alsa-versioncheck \
sane-alsa-headers \
sane-jibx \
sane-ant_version \
sane-zip_version \
sane-unzip_version \
......@@ -1503,6 +1504,18 @@ ifeq ($(PLATFORM), solaris)
endif
######################################################
# JIBX_LIBS_PATH must be valid
######################################################
sane-jibx:
@if [ ! -r $(subst \,/,$(JIBX_LIBS_PATH))/jibx-run.jar ]; then \
$(ECHO) "ERROR: You do not have access to valid JIBX library files. \n" \
" Please check your access to \n" \
" $(subst \,/,$(JIBX_LIBS_PATH))/jibx-run.jar \n" \
" and/or check your value of ALT_JDK_DEVTOOLS_DIR, ALT_JIBX_LIBS_PATH \n" \
"" >> $(ERROR_FILE) ; \
fi
######################################################
# MOZILLA_HEADERS_PATH must be valid
######################################################
......
......@@ -34,9 +34,14 @@ include $(BUILDDIR)/common/Defs.gmk
#
include FILES.gmk
AUTO_FILES_JAVA_DIRS = javax/swing/plaf sun/swing com/sun/java/swing/plaf
SUBDIRS = nimbus
# Nimbus is handled in its own directory
AUTO_JAVA_PRUNE = nimbus
ifeq ($(PLATFORM), windows)
# Don't build GTK L&F on Windows
AUTO_JAVA_PRUNE = gtk
AUTO_JAVA_PRUNE += gtk
endif
MISC_FILES = $(MISC_SWING_FILES)
......@@ -68,8 +73,10 @@ endif
# Process LOGO_ICONS and Motif Icons first.
#
build: $(LOGO_ICONS) $(MISC_SWING_FILES_MOTIF_GIF) $(MISC_SWING_FILES_MOTIF_PNG) other_files
$(SUBDIRS-loop)
clean:: classes.clean
clean clobber::
$(SUBDIRS-loop)
#
# Include
......
#
# Copyright 1998-2007 Sun Microsystems, Inc. All Rights Reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Sun designates this
# particular file as subject to the "Classpath" exception as provided
# by Sun in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
# CA 95054 USA or visit www.sun.com if you need additional information or
# have any questions.
#
BUILDDIR = ../../../..
PACKAGE = javax.swing.plaf.nimbus
PRODUCT = com
SWING_SRC = $(SHARE_SRC)/classes/javax/swing
include $(BUILDDIR)/common/Defs.gmk
#
# Files
#
NIMBUS_PKG = javax/swing/plaf/nimbus
NIMBUS_COMPAT_PKG = com/sun/java/swing/plaf/nimbus
NIMBUS_GENSRC_DIR = $(GENSRCDIR)/$(NIMBUS_PKG)
NIMBUS_SKIN_FILE = $(SHARE_SRC)/classes/$(NIMBUS_PKG)/skin.laf
NIMBUS_GENERATOR_JAR = $(BUILDTOOLJARDIR)/nimbus_generator.jar
AUTO_FILES_JAVA_DIRS = $(NIMBUS_PKG) $(NIMBUS_COMPAT_PKG)
#
# Rules
#
CLASSES_INIT = $(NIMBUS_GENSRC_DIR)
include $(BUILDDIR)/common/Classes.gmk
$(NIMBUS_GENSRC_DIR): $(NIMBUS_SKIN_FILE) $(NIMBUS_GENERATOR_JAR)
@$(ECHO) "Generating Nimbus source files:"
$(BOOT_JAVA_CMD) -jar $(NIMBUS_GENERATOR_JAR) \
-skinFile $(NIMBUS_SKIN_FILE) \
-buildDir $(GENSRCDIR) -srcDir $(GENSRCDIR) \
-packagePrefix $(PACKAGE) -lafName Nimbus
@$(ECHO) "Finished generating Nimbus source files"
clean clobber::
$(RM) -r $(NIMBUS_GENSRC_DIR)
......@@ -51,6 +51,7 @@ SUBDIRS = \
makeclasslist \
strip_properties \
spp \
swing-nimbus \
CharsetMapping
all build clean clobber::
......
#
# Copyright 1998-2005 Sun Microsystems, Inc. All Rights Reserved.
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
# This code is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License version 2 only, as
# published by the Free Software Foundation. Sun designates this
# particular file as subject to the "Classpath" exception as provided
# by Sun in the LICENSE file that accompanied this code.
#
# This code is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
# version 2 for more details (a copy is included in the LICENSE file that
# accompanied this code).
#
# You should have received a copy of the GNU General Public License version
# 2 along with this work; if not, write to the Free Software Foundation,
# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
# CA 95054 USA or visit www.sun.com if you need additional information or
# have any questions.
#
#
# Makefile for building the Nimbus generator
#
BUILDDIR = ../..
PACKAGE = org.jdesktop.synthdesigner.generator
PRODUCT = tools
PROGRAM = nimbus_generator
include $(BUILDDIR)/common/Defs.gmk
BUILDTOOL_SOURCE_ROOT = classes
BUILDTOOL_MAIN = $(PKGDIR)/Generator.java
#
# Files
#
MAIN_CLASS_FILE = $(BUILDTOOLCLASSDIR)/$(BUILDTOOL_MAIN:%.java=%.class)
SOURCE_FILES = $(shell $(FIND) $(BUILDTOOL_SOURCE_ROOT) -name '*.java' -print)
TEMPLATE_FILES = $(SHARE_SRC)/classes/javax/swing/plaf/nimbus/*.template
TEMPLATE_DEST = $(BUILDTOOLCLASSDIR)/org/jdesktop/synthdesigner/generator/resources
JIBX_FILES = $(BUILDTOOL_SOURCE_ROOT)/org/jdesktop/swingx/designer/Designer.jibx.xml \
$(BUILDTOOL_SOURCE_ROOT)/org/jdesktop/synthdesigner/synthmodel/SynthModel.jibx.xml
JIBX_LIBS_CP = $(JIBX_LIBS_PATH)/bcel.jar$(CLASSPATH_SEPARATOR)$(JIBX_LIBS_PATH)/xpp3.jar$(CLASSPATH_SEPARATOR)$(JIBX_LIBS_PATH)/jibx-bind.jar$(CLASSPATH_SEPARATOR)$(JIBX_LIBS_PATH)/jibx-run.jar
JIBX_LIBS_LIST = $(subst $(CLASSPATH_SEPARATOR), ,$(JIBX_LIBS_CP))
#
# Rules
#
include $(BUILDDIR)/common/BuildToolJar.gmk
$(MAIN_CLASS_FILE): $(SOURCE_FILES) $(JIBX_LIBS_LIST)
@$(MKDIR) -p $(BUILDTOOLCLASSDIR)
$(BOOT_JAVAC_CMD) -classpath "$(JIBX_LIBS_CP)" \
-d $(BUILDTOOLCLASSDIR) -sourcepath $(BUILDTOOL_SOURCE_ROOT) \
$(SOURCE_FILES)
$(TEMPLATE_DEST): $(TEMPLATE_FILES)
$(MKDIR) -p $(TEMPLATE_DEST)
$(RM) $(TEMPLATE_DEST)/*.template
$(CP) $(TEMPLATE_FILES) $(TEMPLATE_DEST)
$(BUILDTOOL_MANIFEST_FILE): $(MAIN_CLASS_FILE)
$(ECHO) "Main-Class: $(BUILTTOOL_MAINCLASS)" > $@
$(ECHO) "Class-Path: $(JIBX_LIBS_LIST:$(JIBX_LIBS_PATH)/%=%)" >> $@
$(CP) $(JIBX_LIBS_LIST) $(BUILDTOOLJARDIR)
$(BUILDTOOL_JAR_FILE): $(MAIN_CLASS_FILE) $(TEMPLATE_DEST) \
$(JIBX_FILES) $(BUILDTOOL_MANIFEST_FILE)
@$(prep-target)
$(BOOT_JAVA_CMD) \
-classpath "$(JIBX_LIBS_CP)$(CLASSPATH_SEPARATOR)$(BUILDTOOLCLASSDIR)" \
org.jibx.binding.Compile $(JIBX_FILES)
$(BOOT_JAR_CMD) cfm $@ $(BUILDTOOL_MANIFEST_FILE) \
-C $(BUILDTOOLCLASSDIR) org \
$(BOOT_JAR_JFLAGS) || $(RM) $@
@$(java-vm-cleanup)
clean clobber::
$(RM) -r $(TEMPLATE_DEST)
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.beans;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyVetoException;
import java.beans.VetoableChangeListener;
import java.beans.VetoableChangeSupport;
/**
* <p>A convenience class from which to extend all non-visual AbstractBeans. It
* manages the PropertyChange notification system, making it relatively trivial
* to add support for property change events in getters/setters.</p>
*
* <p>A non-visual java bean is a Java class that conforms to the AbstractBean
* patterns to allow visual manipulation of the bean's properties and event
* handlers at design-time.</p>
*
* <p>Here is a simple example bean that contains one property, foo, and the
* proper pattern for implementing property change notification:
* <pre><code>
* public class ABean extends AbstractBean {
* private String foo;
*
* public void setFoo(String newFoo) {
* String old = getFoo();
* this.foo = newFoo;
* firePropertyChange("foo", old, getFoo());
* }
*
* public String getFoo() {
* return foo;
* }
* }
* </code></pre></p>
*
* <p>You will notice that "getFoo()" is used in the setFoo method rather than
* accessing "foo" directly for the gets. This is done intentionally so that if
* a subclass overrides getFoo() to return, for instance, a constant value the
* property change notification system will continue to work properly.</p>
*
* <p>The firePropertyChange method takes into account the old value and the new
* value. Only if the two differ will it fire a property change event. So you can
* be assured from the above code fragment that a property change event will only
* occur if old is indeed different from getFoo()</p>
*
* <p><code>AbstractBean</code> also supports {@link VetoablePropertyChange} events.
* These events are similar to <code>PropertyChange</code> events, except a special
* exception can be used to veto changing the property. For example, perhaps the
* property is changing from "fred" to "red", but a listener deems that "red" is
* unexceptable. In this case, the listener can fire a veto exception and the property must
* remain "fred". For example:
* <pre><code>
* public class ABean extends AbstractBean {
* private String foo;
*
* public void setFoo(String newFoo) throws PropertyVetoException {
* String old = getFoo();
* this.foo = newFoo;
* fireVetoableChange("foo", old, getFoo());
* }
*
* public String getFoo() {
* return foo;
* }
* }
*
* public class Tester {
* public static void main(String... args) {
* try {
* ABean a = new ABean();
* a.setFoo("fred");
* a.addVetoableChangeListener(new VetoableChangeListener() {
* public void vetoableChange(PropertyChangeEvent evt) throws PropertyVetoException {
* if ("red".equals(evt.getNewValue()) {
* throw new PropertyVetoException("Cannot be red!", evt);
* }
* }
* }
* a.setFoo("red");
* } catch (Exception e) {
* e.printStackTrace(); // this will be executed
* }
* }
* }
* </code></pre></p>
*
* @status REVIEWED
* @author rbair
*/
public abstract class AbstractBean {
/**
* Helper class that manages all the property change notification machinery.
* PropertyChangeSupport cannot be extended directly because it requires
* a bean in the constructor, and the "this" argument is not valid until
* after super construction. Hence, delegation instead of extension
*/
private transient PropertyChangeSupport pcs;
/**
* Helper class that manages all the veto property change notification machinery.
*/
private transient VetoableChangeSupport vcs;
/** Creates a new instance of AbstractBean */
protected AbstractBean() {
pcs = new PropertyChangeSupport(this);
vcs = new VetoableChangeSupport(this);
}
/**
* Creates a new instance of AbstractBean, using the supplied PropertyChangeSupport and
* VetoableChangeSupport delegates. Neither of these may be null.
*/
protected AbstractBean(PropertyChangeSupport pcs, VetoableChangeSupport vcs) {
if (pcs == null) {
throw new NullPointerException("PropertyChangeSupport must not be null");
}
if (vcs == null) {
throw new NullPointerException("VetoableChangeSupport must not be null");
}
this.pcs = pcs;
this.vcs = vcs;
}
/**
* Add a PropertyChangeListener to the listener list.
* The listener is registered for all properties.
* The same listener object may be added more than once, and will be called
* as many times as it is added.
* If <code>listener</code> is null, no exception is thrown and no action
* is taken.
*
* @param listener The PropertyChangeListener to be added
*/
public final void addPropertyChangeListener(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
}
/**
* Remove a PropertyChangeListener from the listener list.
* This removes a PropertyChangeListener that was registered
* for all properties.
* If <code>listener</code> was added more than once to the same event
* source, it will be notified one less time after being removed.
* If <code>listener</code> is null, or was never added, no exception is
* thrown and no action is taken.
*
* @param listener The PropertyChangeListener to be removed
*/
public final void removePropertyChangeListener(PropertyChangeListener listener) {
pcs.removePropertyChangeListener(listener);
}
/**
* Returns an array of all the listeners that were added to the
* PropertyChangeSupport object with addPropertyChangeListener().
* <p>
* If some listeners have been added with a named property, then
* the returned array will be a mixture of PropertyChangeListeners
* and <code>PropertyChangeListenerProxy</code>s. If the calling
* method is interested in distinguishing the listeners then it must
* test each element to see if it's a
* <code>PropertyChangeListenerProxy</code>, perform the cast, and examine
* the parameter.
*
* <pre>
* PropertyChangeListener[] listeners = bean.getPropertyChangeListeners();
* for (int i = 0; i < listeners.length; i++) {
* if (listeners[i] instanceof PropertyChangeListenerProxy) {
* PropertyChangeListenerProxy proxy =
* (PropertyChangeListenerProxy)listeners[i];
* if (proxy.getPropertyName().equals("foo")) {
* // proxy is a PropertyChangeListener which was associated
* // with the property named "foo"
* }
* }
* }
*</pre>
*
* @see java.beans.PropertyChangeListenerProxy
* @return all of the <code>PropertyChangeListeners</code> added or an
* empty array if no listeners have been added
*/
public final PropertyChangeListener[] getPropertyChangeListeners() {
return pcs.getPropertyChangeListeners();
}
/**
* Add a PropertyChangeListener for a specific property. The listener
* will be invoked only when a call on firePropertyChange names that
* specific property.
* The same listener object may be added more than once. For each
* property, the listener will be invoked the number of times it was added
* for that property.
* If <code>propertyName</code> or <code>listener</code> is null, no
* exception is thrown and no action is taken.
*
* @param propertyName The name of the property to listen on.
* @param listener The PropertyChangeListener to be added
*/
public final void addPropertyChangeListener(String propertyName, PropertyChangeListener listener) {
pcs.addPropertyChangeListener(propertyName, listener);
}
/**
* Remove a PropertyChangeListener for a specific property.
* If <code>listener</code> was added more than once to the same event
* source for the specified property, it will be notified one less time
* after being removed.
* If <code>propertyName</code> is null, no exception is thrown and no
* action is taken.
* If <code>listener</code> is null, or was never added for the specified
* property, no exception is thrown and no action is taken.
*
* @param propertyName The name of the property that was listened on.
* @param listener The PropertyChangeListener to be removed
*/
public final void removePropertyChangeListener(String propertyName, PropertyChangeListener listener) {
pcs.removePropertyChangeListener(propertyName, listener);
}
/**
* Returns an array of all the listeners which have been associated
* with the named property.
*
* @param propertyName The name of the property being listened to
* @return all of the <code>PropertyChangeListeners</code> associated with
* the named property. If no such listeners have been added,
* or if <code>propertyName</code> is null, an empty array is
* returned.
*/
public final PropertyChangeListener[] getPropertyChangeListeners(String propertyName) {
return pcs.getPropertyChangeListeners(propertyName);
}
/**
* Report a bound property update to any registered listeners.
* No event is fired if old and new are equal and non-null.
*
* <p>
* This is merely a convenience wrapper around the more general
* firePropertyChange method that takes {@code
* PropertyChangeEvent} value.
*
* @param propertyName The programmatic name of the property
* that was changed.
* @param oldValue The old value of the property.
* @param newValue The new value of the property.
*/
protected final void firePropertyChange(String propertyName, Object oldValue, Object newValue) {
pcs.firePropertyChange(propertyName, oldValue, newValue);
}
/**
* Fire an existing PropertyChangeEvent to any registered listeners.
* No event is fired if the given event's old and new values are
* equal and non-null.
* @param evt The PropertyChangeEvent object.
*/
protected final void firePropertyChange(PropertyChangeEvent evt) {
pcs.firePropertyChange(evt);
}
/**
* Report a bound indexed property update to any registered
* listeners.
* <p>
* No event is fired if old and new values are equal
* and non-null.
*
* <p>
* This is merely a convenience wrapper around the more general
* firePropertyChange method that takes {@code PropertyChangeEvent} value.
*
* @param propertyName The programmatic name of the property that
* was changed.
* @param index index of the property element that was changed.
* @param oldValue The old value of the property.
* @param newValue The new value of the property.
*/
protected final void fireIndexedPropertyChange(String propertyName,
int index, Object oldValue, Object newValue) {
pcs.fireIndexedPropertyChange(propertyName, index, oldValue, newValue);
}
/**
* Check if there are any listeners for a specific property, including
* those registered on all properties. If <code>propertyName</code>
* is null, only check for listeners registered on all properties.
*
* @param propertyName the property name.
* @return true if there are one or more listeners for the given property
*/
protected final boolean hasPropertyChangeListeners(String propertyName) {
return pcs.hasListeners(propertyName);
}
/**
* Check if there are any listeners for a specific property, including
* those registered on all properties. If <code>propertyName</code>
* is null, only check for listeners registered on all properties.
*
* @param propertyName the property name.
* @return true if there are one or more listeners for the given property
*/
protected final boolean hasVetoableChangeListeners(String propertyName) {
return vcs.hasListeners(propertyName);
}
/**
* Add a VetoableListener to the listener list.
* The listener is registered for all properties.
* The same listener object may be added more than once, and will be called
* as many times as it is added.
* If <code>listener</code> is null, no exception is thrown and no action
* is taken.
*
* @param listener The VetoableChangeListener to be added
*/
public final void addVetoableChangeListener(VetoableChangeListener listener) {
vcs.addVetoableChangeListener(listener);
}
/**
* Remove a VetoableChangeListener from the listener list.
* This removes a VetoableChangeListener that was registered
* for all properties.
* If <code>listener</code> was added more than once to the same event
* source, it will be notified one less time after being removed.
* If <code>listener</code> is null, or was never added, no exception is
* thrown and no action is taken.
*
* @param listener The VetoableChangeListener to be removed
*/
public final void removeVetoableChangeListener(VetoableChangeListener listener) {
vcs.removeVetoableChangeListener(listener);
}
/**
* Returns the list of VetoableChangeListeners. If named vetoable change listeners
* were added, then VetoableChangeListenerProxy wrappers will returned
* <p>
* @return List of VetoableChangeListeners and VetoableChangeListenerProxys
* if named property change listeners were added.
*/
public final VetoableChangeListener[] getVetoableChangeListeners(){
return vcs.getVetoableChangeListeners();
}
/**
* Add a VetoableChangeListener for a specific property. The listener
* will be invoked only when a call on fireVetoableChange names that
* specific property.
* The same listener object may be added more than once. For each
* property, the listener will be invoked the number of times it was added
* for that property.
* If <code>propertyName</code> or <code>listener</code> is null, no
* exception is thrown and no action is taken.
*
* @param propertyName The name of the property to listen on.
* @param listener The VetoableChangeListener to be added
*/
public final void addVetoableChangeListener(String propertyName,
VetoableChangeListener listener) {
vcs.addVetoableChangeListener(propertyName, listener);
}
/**
* Remove a VetoableChangeListener for a specific property.
* If <code>listener</code> was added more than once to the same event
* source for the specified property, it will be notified one less time
* after being removed.
* If <code>propertyName</code> is null, no exception is thrown and no
* action is taken.
* If <code>listener</code> is null, or was never added for the specified
* property, no exception is thrown and no action is taken.
*
* @param propertyName The name of the property that was listened on.
* @param listener The VetoableChangeListener to be removed
*/
public final void removeVetoableChangeListener(String propertyName,
VetoableChangeListener listener) {
vcs.removeVetoableChangeListener(propertyName, listener);
}
/**
* Returns an array of all the listeners which have been associated
* with the named property.
*
* @param propertyName The name of the property being listened to
* @return all the <code>VetoableChangeListeners</code> associated with
* the named property. If no such listeners have been added,
* or if <code>propertyName</code> is null, an empty array is
* returned.
*/
public final VetoableChangeListener[] getVetoableChangeListeners(String propertyName) {
return vcs.getVetoableChangeListeners(propertyName);
}
/**
* Report a vetoable property update to any registered listeners. If
* anyone vetos the change, then fire a new event reverting everyone to
* the old value and then rethrow the PropertyVetoException.
* <p>
* No event is fired if old and new are equal and non-null.
*
* @param propertyName The programmatic name of the property
* that is about to change..
* @param oldValue The old value of the property.
* @param newValue The new value of the property.
* @exception PropertyVetoException if the recipient wishes the property
* change to be rolled back.
*/
protected final void fireVetoableChange(String propertyName,
Object oldValue, Object newValue)
throws PropertyVetoException {
vcs.fireVetoableChange(propertyName, oldValue, newValue);
}
/**
* Fire a vetoable property update to any registered listeners. If
* anyone vetos the change, then fire a new event reverting everyone to
* the old value and then rethrow the PropertyVetoException.
* <p>
* No event is fired if old and new are equal and non-null.
*
* @param evt The PropertyChangeEvent to be fired.
* @exception PropertyVetoException if the recipient wishes the property
* change to be rolled back.
*/
protected final void fireVetoableChange(PropertyChangeEvent evt)
throws PropertyVetoException {
vcs.fireVetoableChange(evt);
}
/**
* @inheritDoc
*/
public Object clone() throws CloneNotSupportedException {
AbstractBean result = (AbstractBean) super.clone();
result.pcs = new PropertyChangeSupport(result);
result.vcs = new VetoableChangeSupport(result);
return result;
}
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer;
import java.awt.BasicStroke;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.GeneralPath;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* BezierControlPoint
*
* @author Created by Jasper Potts (May 29, 2007)
*/
public class BezierControlPoint extends ControlPoint {
private HandleControlPoint cp1 = new HandleControlPoint();
private HandleControlPoint cp2 = new HandleControlPoint();
private transient boolean makingChange = false;
private transient PropertyChangeListener cpListener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
// if (!makingChange) {
// makingChange = true;
// if (evt.getSource() == cp1) {
// double angle = Math.tan((cp1.getY() - getY())/(cp1.getX() - getX()));
// double cp2len = Math.sqrt(
// Math.pow(cp2.getX() - getX(),2) +
// Math.pow(cp2.getY() - getY(),2)
// );
// double offsetX = cp2len * Math.sin(angle);
// double offsetY = cp2len * Math.cos(angle);
// cp2.setPosition(getX() - offsetX, getY() - offsetY);
// } else {
// double angle = Math.tan((cp2.getY() - getY())/(cp2.getX() - getX()));
// double cp1len = Math.sqrt(
// Math.pow(cp1.getX() - getX(),2) +
// Math.pow(cp1.getY() - getY(),2)
// );
// double offsetX = cp1len * Math.sin(angle);
// double offsetY = cp1len * Math.cos(angle);
// cp1.setPosition(getX() - offsetX, getY() - offsetY);
// }
//// if (evt.getSource() == cp1) {
//// double offsetX = cp1.getX() - getX();
//// double offsetY = cp1.getY() - getY();
//// cp2.setPosition(getX() - offsetX, getY() - offsetY);
//// } else {
//// double offsetX = cp2.getX() - getX();
//// double offsetY = cp2.getY() - getY();
//// cp1.setPosition(getX() - offsetX, getY() - offsetY);
//// }
// makingChange = false;
// firePropertyChange("cp1", null, cp1);
// firePropertyChange("cp2", null, cp1);
// }
firePropertyChange("shape",null,getShape());
}
};
public BezierControlPoint() {
cp1.addPropertyChangeListener(cpListener);
cp2.addPropertyChangeListener(cpListener);
}
public BezierControlPoint(double x, double y) {
super(x, y);
cp1.addPropertyChangeListener(cpListener);
cp2.addPropertyChangeListener(cpListener);
cp1.setPosition(x, y);
cp2.setPosition(x, y);
}
public boolean isSharpCorner() {
return
(cp1.getX() == x.getValue()) &&
(cp1.getY() == y.getValue()) &&
(cp2.getX() == x.getValue()) &&
(cp2.getY() == y.getValue());
}
public void flip(int width, int height){
makingChange = true;
if (width > 0){
x.setValue(width - x.getValue());
cp1.x.setValue(width - cp1.x.getValue());
cp2.x.setValue(width - cp2.x.getValue());
}
if (height > 0){
y.setValue(height - y.getValue());
cp1.y.setValue(height - cp1.y.getValue());
cp2.y.setValue(height - cp2.y.getValue());
}
makingChange = false;
}
public void convertToSharpCorner() {
cp1.setPosition(x.getValue(), y.getValue());
cp2.setPosition(x.getValue(), y.getValue());
}
public List<ControlPoint> getControlPoints() {
if (isSharpCorner()) {
return Collections.emptyList();
} else {
List<ControlPoint> points = new ArrayList<ControlPoint>();
points.add(cp1);
points.add(cp2);
return points;
}
}
public HandleControlPoint getCp1() {
return cp1;
}
public HandleControlPoint getCp2() {
return cp2;
}
public void paintControls(Graphics2D g2, double pixelSize, boolean paintControlLines) {
g2.setStroke(new BasicStroke((float) pixelSize));
// paint control line
g2.setColor(GraphicsHelper.BEZIER_CONTROL_LINE);
g2.draw(new Line2D.Double(cp1.getX(), cp1.getY(), getX(), getY()));
g2.draw(new Line2D.Double(getX(), getY(), cp2.getX(), cp2.getY()));
// paint this control point
Shape s;
if (isSharpCorner()) {
double size = pixelSize * 4d;
GeneralPath path = new GeneralPath();
path.moveTo(getX() - size, getY());
path.lineTo(getX(), getY() + size);
path.lineTo(getX() + size, getY());
path.lineTo(getX(), getY() - size);
path.closePath();
s = path;
} else {
double size = pixelSize * 3d;
s = new Ellipse2D.Double(getX() - size, getY() - size,
size * 2, size * 2);
}
g2.setColor(GraphicsHelper.BEZIER_CONTROL_POINT_FILL);
g2.fill(s);
g2.setColor(GraphicsHelper.BEZIER_CONTROL_POINT_LINE);
g2.draw(s);
// paint child control points
if (!isSharpCorner()) {
cp1.paintControls(g2, pixelSize, true);
cp2.paintControls(g2, pixelSize, true);
}
}
public void move(double moveX, double moveY, boolean snapPixels) {
makingChange = true;
super.move(moveX, moveY, snapPixels);
cp1.move(moveX, moveY, snapPixels);
cp2.move(moveX, moveY, snapPixels);
makingChange = false;
}
public double getCp1X() {
return cp1.getX();
}
public void setCp1X(double v) {
cp1.setX(v);
}
public double getCp1Y() {
return cp1.getY();
}
public void setCp1Y(double v) {
cp1.setY(v);
}
public double getCp2X() {
return cp2.getX();
}
public void setCp2X(double v) {
cp2.setX(v);
}
public double getCp2Y() {
return cp2.getY();
}
public void setCp2Y(double v) {
cp2.setY(v);
}
// =================================================================================================================
// Bezier handle control point
public class HandleControlPoint extends ControlPoint {
public void paintControls(Graphics2D g2, double pixelSize, boolean paintControlLines) {
if (!isSharp()){
double size = pixelSize * 3d;
Shape s = new Ellipse2D.Double(getX() - size, getY() - size,
size * 2, size * 2);
g2.setColor(GraphicsHelper.BEZIER_CONTROL_POINT_FILL);
g2.fill(s);
g2.setColor(GraphicsHelper.BEZIER_CONTROL_POINT_LINE);
g2.draw(s);
g2.draw(new Rectangle2D.Double(getX() - (pixelSize / 2), getY() - (pixelSize / 2), pixelSize, pixelSize));
}
}
public boolean isHit(Point2D p, double pixelSize) {
return !isSharp() && super.isHit(p, pixelSize);
}
/**
* Is the line controled by this handle in or out of the parent BezierControlPoint sharp.
*
* @return <code>true</code> If this is the exact same point as the parent BezierControlPoint.
*/
public boolean isSharp(){
return x.getValue() == BezierControlPoint.this.x.getValue() &&
y.getValue() == BezierControlPoint.this.y.getValue();
}
public void convertToSharp(){
setPosition(BezierControlPoint.this.x.getValue(),BezierControlPoint.this.y.getValue());
}
public BezierControlPoint getParentControlPoint(){
return BezierControlPoint.this;
}
}
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer;
/**
* BlendingMode - Enum of composite blending modes, setup to match photoshop as closely as possible
*
* @author Created by Jasper Potts (May 31, 2007)
*/
public enum BlendingMode {
NORMAL,
// DISSOLVE, missing
// -----------------------------
DARKEN,
MULTIPLY,
COLOR_BURN,
LINEAR_BURN, // (SUBTRACT)
// -----------------------------
LIGHTEN,
SCREEN,
COLOR_DODGE,
LINEAR_DODGE, // (ADD)
// -----------------------------
OVERLAY,
SOFT_LIGHT,
HARD_LIGHT,
VIVID_LIGHT, // (HEAT) is close
LINEAR_LIGHT, // (GLOW) is close
//PIN_LIGHT, missing
//HARD_MIX, missing
// -----------------------------
DIFFERENCE,
EXCLUSION,
// -----------------------------
HUE, // nowhere close
SATURATION,
COLOR,
LUMINOSITY, // close but not exact
//LIGHTER_COLOR, missing
//DARKER_COLOR, missing
;
// =================================================================================================================
// Helper methods for creating Blending Mode Combo Box
public static final Object[] BLENDING_MODES = new Object[]{
BlendingMode.NORMAL,
// DISSOLVE, missing
"-",
BlendingMode.DARKEN,
BlendingMode.MULTIPLY,
BlendingMode.COLOR_BURN,
BlendingMode.LINEAR_BURN, // (SUBTRACT)
"-",
BlendingMode.LIGHTEN,
BlendingMode.SCREEN,
BlendingMode.COLOR_DODGE,
BlendingMode.LINEAR_DODGE, // (ADD)
"-",
BlendingMode.OVERLAY,
BlendingMode.SOFT_LIGHT,
BlendingMode.HARD_LIGHT,
BlendingMode.VIVID_LIGHT, // (HEAT) is close
BlendingMode.LINEAR_LIGHT, // (GLOW) is close
//PIN_LIGHT, missing
//HARD_MIX, missing
"-",
BlendingMode.DIFFERENCE,
BlendingMode.EXCLUSION,
"-",
BlendingMode.HUE, // nowhere close
BlendingMode.SATURATION,
BlendingMode.COLOR,
BlendingMode.LUMINOSITY, // close but not exact
};
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer;
import org.jdesktop.beans.AbstractBean;
import org.jdesktop.swingx.designer.utils.HasResources;
import org.jdesktop.swingx.designer.utils.HasUIDefaults;
import org.jibx.runtime.IUnmarshallingContext;
import javax.swing.UIDefaults;
import java.awt.AlphaComposite;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Insets;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* ComponentRegion
*
* @author Created by Jasper Potts (May 22, 2007)
*/
public class Canvas extends AbstractBean implements LayerContainer, HasUIDefaults, HasResources {
private Dimension size;
/** list of all layers in the canvas, the first layer is painted on top */
private List<Layer> layers;
private int nextLayerNameIndex = 1;
private BufferedImage buffer;
private boolean isValid = false;
private Insets stretchingInsets = null;
private Layer workingLayer = null;
private PropertyChangeListener layersPropertyChangeListener;
private UIDefaults canvasUIDefaults = null;
private transient File resourcesDir;
private transient File imagesDir;
private transient File templatesDir;
// =================================================================================================================
// Constructor
/** Private constructor for JIBX */
protected Canvas() {
layersPropertyChangeListener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
isValid = false;
// pass on layer change
int index = layers.indexOf((Layer) evt.getSource());
if (index != -1) {
firePropertyChange("layers[" + index + "]." + evt.getPropertyName(), evt.getOldValue(),
evt.getNewValue());
}
}
};
}
public Canvas(int width, int height) {
this();
stretchingInsets = new Insets(1, 1, 1, 1);
layers = new ArrayList<Layer>();
setSize(new Dimension(width, height));
addLayer(new Layer());
}
// =================================================================================================================
// JIBX Methods
/**
* Called by JIBX before all fields have been set
*
* @param context The JIBX Unmarshalling Context
*/
private void preSet(IUnmarshallingContext context) {
canvasUIDefaults = (UIDefaults) context.getUserContext();
}
// =================================================================================================================
// Bean Methods
/**
* Get the UIDefaults for this canvas. The UIDefaults is used to store default pallet of colors, fonts etc.
*
* @return Canvas UIDefaults
*/
public UIDefaults getUiDefaults() {
return canvasUIDefaults;
}
/**
* Set the UIDefaults for this canvas. The UIDefaults is used to store default pallet of colors, fonts etc.
*
* @param canvasUIDefaults Canvas UIDefaults
*/
public void setUiDefaults(UIDefaults canvasUIDefaults) {
this.canvasUIDefaults = canvasUIDefaults;
}
/**
* Get the current working layer, is is the layer that new shapes will be drawn into
*
* @return The current working layer, may be null if there is no working layer
*/
public Layer getWorkingLayer() {
return workingLayer;
}
/**
* Set the current working layer, is is the layer that new shapes will be drawn into
*
* @param workingLayer the new working layer, must be a child of this canvas
*/
public void setWorkingLayer(Layer workingLayer) {
Layer old = getWorkingLayer();
this.workingLayer = workingLayer;
firePropertyChange("workingLayer", old, getWorkingLayer());
}
public int getNextLayerNameIndex() {
return nextLayerNameIndex++;
}
public Dimension getSize() {
return size;
}
public void setSize(Dimension size) {
Dimension old = getSize();
this.size = size;
buffer = new BufferedImage(this.size.width, this.size.height, BufferedImage.TYPE_INT_ARGB);
isValid = false;
firePropertyChange("size", old, getSize());
}
public Insets getStretchingInsets() {
return stretchingInsets;
}
public void setStretchingInsets(Insets stretchingInsets) {
Insets old = getStretchingInsets();
this.stretchingInsets = stretchingInsets;
firePropertyChange("stretchingInsets", old, getStretchingInsets());
}
public BufferedImage getRenderedImage() {
if (!isValid) {
Graphics2D g2 = buffer.createGraphics();
// clear
g2.setComposite(AlphaComposite.Clear);
g2.fillRect(0, 0, buffer.getWidth(), buffer.getHeight());
// paint
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2.setComposite(AlphaComposite.SrcOver);
for (int i = layers.size() - 1; i >= 0; i--) {
layers.get(i).paint(g2, 1);
}
g2.dispose();
}
return buffer;
}
/**
* @return true if this Canvas has not been edited.
* <p/>
* TODO Currently this is not a bound property, but should be. That is, when the Canvas becomes edited
* (usually due to the Layer having a shape added to it), then a property change event should be fired.
*/
public boolean isBlank() {
return layers.size() == 0 || (layers.size() == 1 && layers.get(0).isEmpty());
}
public File getResourcesDir() {
return resourcesDir;
}
public void setResourcesDir(File resourcesDir) {
File old = getResourcesDir();
this.resourcesDir = resourcesDir;
firePropertyChange("resourcesDir", old, getResourcesDir());
}
public File getImagesDir() {
return imagesDir;
}
public void setImagesDir(File imagesDir) {
File old = getImagesDir();
this.imagesDir = imagesDir;
firePropertyChange("imagesDir", old, getImagesDir());
}
public File getTemplatesDir() {
return templatesDir;
}
public void setTemplatesDir(File templatesDir) {
File old = getTemplatesDir();
this.templatesDir = templatesDir;
firePropertyChange("templatesDir", old, getTemplatesDir());
}
// =================================================================================================================
// LayerContainer Methods
public LayerContainer getParent() {
// we are root so null
return null;
}
public void addLayerToBottom(Layer layer) {
layers.add(layer);
layer.setParent(this);
layer.addPropertyChangeListener(layersPropertyChangeListener);
// no single layer changes so fire all changed event
firePropertyChange("layers", null, layers);
}
public void addLayer(int i, Layer layer) {
layers.add(i, layer);
layer.setParent(this);
layer.addPropertyChangeListener(layersPropertyChangeListener);
// no single layer changes so fire all changed event
firePropertyChange("layers", null, layers);
}
public void addLayer(Layer layer) {
layers.add(0, layer);
layer.setParent(this);
layer.addPropertyChangeListener(layersPropertyChangeListener);
// no single layer changes so fire all changed event
firePropertyChange("layers", null, layers);
}
public Layer getLayer(int index) {
return layers.get(index);
}
public int getLayerCount() {
return layers.size();
}
public Iterator<Layer> getLayerIterator() {
return Collections.unmodifiableList(layers).iterator();
}
public Collection<Layer> getLayers() {
return Collections.unmodifiableList(layers);
}
public int indexOfLayer(Layer layer) {
return layers.indexOf(layer);
}
public void removeLayer(Layer layer) {
int index = layers.indexOf(layer);
if (index != -1) {
layers.remove(layer);
layer.removePropertyChangeListener(layersPropertyChangeListener);
fireIndexedPropertyChange("layers", index, layer, null);
}
}
public Dimension getRootSize() {
return getSize();
}
// =================================================================================================================
// JIBX Helper Methods
/** Called by JIBX after "layers" has been filled so we can set parents and listeners */
private void setupLayers() {
for (Layer layer : layers) {
layer.setParent(this);
layer.addPropertyChangeListener(layersPropertyChangeListener);
}
// no single layer changes so fire all changed event
firePropertyChange("layers", null, layers);
}
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Collections;
import java.util.List;
/**
* ControlPoint
*
* @author Created by Jasper Potts (May 24, 2007)
*/
public class ControlPoint extends SimpleShape {
protected Color fillColor;
protected Color lineColor;
protected DoubleBean x, y;
public ControlPoint() {
this(new DoubleBean(), new DoubleBean());
}
public ControlPoint(Color fillColor, Color lineColor) {
this(new DoubleBean(), new DoubleBean(), fillColor, lineColor);
}
public ControlPoint(double x, double y) {
this(new DoubleBean(x), new DoubleBean(y));
}
public ControlPoint(DoubleBean x, DoubleBean y) {
this(x, y, GraphicsHelper.CONTROL_POINT_FILL, GraphicsHelper.CONTROL_POINT_LINE);
}
public ControlPoint(DoubleBean x, DoubleBean y, Color fillColor, Color lineColor) {
this.x = x;
this.y = y;
this.fillColor = fillColor;
this.lineColor = lineColor;
x.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
firePropertyChange("position",
new Point2D.Double((Double) evt.getOldValue(), getY()),
getPosition());
}
});
y.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
firePropertyChange("position",
new Point2D.Double(getX(), (Double) evt.getOldValue()),
getPosition());
}
});
}
public double getX() {
return x.getValue();
}
public double getY() {
return y.getValue();
}
public void setX(double x) {
this.x.setValue(x);
}
public void setY(double y) {
this.y.setValue(y);
}
public void setPosition(Point2D position) {
x.setValue(position.getX());
y.setValue(position.getY());
}
public void setPosition(double x, double y) {
setPosition(new Point2D.Double(x, y));
}
public Point2D getPosition() {
return new Point2D.Double(getX(), getY());
}
public Rectangle2D getBounds(double pixelSize) {
double size = pixelSize * 4d;
return new Rectangle2D.Double(getX() - size, getY() - size,
size * 2, size * 2);
}
public boolean isHit(Point2D p, double pixelSize) {
return getBounds(pixelSize).contains(p);
}
public Shape getShape() {
return getBounds(0);
}
public void paint(Graphics2D g2, double pixelSize) {
}
public void paintControls(Graphics2D g2, double pixelSize, boolean paintControlLines) {
g2.setStroke(new BasicStroke((float) pixelSize));
Shape s = getBounds(pixelSize);
g2.setColor(fillColor);
g2.fill(s);
g2.setColor(lineColor);
g2.draw(s);
}
public List<ControlPoint> getControlPoints() {
return Collections.emptyList();
}
public void move(double moveX, double moveY, boolean snapPixels) {
if (snapPixels) {
setPosition(
Math.round(x.getValue() + moveX),
Math.round(y.getValue() + moveY));
} else {
setPosition(x.getValue() + moveX, y.getValue() + moveY);
}
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright 1998-2004 Sun Microsystems, Inc. All Rights Reserved.
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
This code is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License version 2 only, as
published by the Free Software Foundation. Sun designates this
particular file as subject to the "Classpath" exception as provided
by Sun in the LICENSE file that accompanied this code.
This code is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
version 2 for more details (a copy is included in the LICENSE file that
accompanied this code).
You should have received a copy of the GNU General Public License version
2 along with this work; if not, write to the Free Software Foundation,
Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
CA 95054 USA or visit www.sun.com if you need additional information or
have any questions.
-->
<!DOCTYPE binding SYSTEM "http://jibx.sourceforge.net">
<binding>
<!-- == PAINTS =========================================================================================== -->
<mapping class="java.awt.Color"
marshaller="org.jdesktop.swingx.designer.jibxhelpers.ColorMapper"
unmarshaller="org.jdesktop.swingx.designer.jibxhelpers.ColorMapper"/>
<mapping name="matte" class="org.jdesktop.swingx.designer.paint.Matte" post-set="postSet">
<value name="red" field="red" style="attribute"/>
<value name="green" field="green" style="attribute"/>
<value name="blue" field="blue" style="attribute"/>
<value name="alpha" field="alpha" style="attribute"/>
<value name="uiDefaultParentName" field="uiDefaultParentName" style="attribute" usage="optional"/>
<value name="componentPropertyName" field="componentPropertyName" style="attribute" usage="optional"/>
<value name="hueOffset" field="hueOffset" style="attribute"/>
<value name="saturationOffset" field="saturationOffset" style="attribute"/>
<value name="brightnessOffset" field="brightnessOffset" style="attribute"/>
<value name="alphaOffset" field="alphaOffset" style="attribute"/>
<value name="uiResource" field="uiResource" style="attribute" usage="optional" default="true"/>
</mapping>
<mapping class="org.jdesktop.swingx.designer.paint.AbstractGradient" abstract="true">
<value name="cycleMethod" field="cycleMethod" style="attribute"/>
<collection field="stops" set-method="setStops" pre-set="clear" create-type="java.util.ArrayList">
<structure name="stop" type="org.jdesktop.swingx.designer.paint.GradientStop">
<value name="position" field="position" style="attribute"/>
<value name="midpoint" field="midpoint" style="attribute"/>
<structure field="color" set-method="setColor"/>
</structure>
</collection>
</mapping>
<mapping name="gradient" class="org.jdesktop.swingx.designer.paint.Gradient"
extends="org.jdesktop.swingx.designer.paint.AbstractGradient">
<structure map-as="org.jdesktop.swingx.designer.paint.AbstractGradient"/>
</mapping>
<mapping name="radialGradient" class="org.jdesktop.swingx.designer.paint.RadialGradient"
extends="org.jdesktop.swingx.designer.paint.AbstractGradient">
<structure map-as="org.jdesktop.swingx.designer.paint.AbstractGradient"/>
</mapping>
<!-- == SHAPES =========================================================================================== -->
<mapping class="org.jdesktop.swingx.designer.SimpleShape" abstract="true">
<!--protected AffineTransform transform = new AffineTransform();-->
</mapping>
<mapping class="org.jdesktop.swingx.designer.PaintedShape" abstract="true"
extends="org.jdesktop.swingx.designer.SimpleShape">
<structure map-as="org.jdesktop.swingx.designer.SimpleShape"/>
<structure field="paint"/>
<structure name="paintPoints">
<value name="x1" get-method="getPaintX1" set-method="setPaintX1" style="attribute"/>
<value name="y1" get-method="getPaintY1" set-method="setPaintY1" style="attribute"/>
<value name="x2" get-method="getPaintX2" set-method="setPaintX2" style="attribute"/>
<value name="y2" get-method="getPaintY2" set-method="setPaintY2" style="attribute"/>
</structure>
</mapping>
<mapping name="rectangle" class="org.jdesktop.swingx.designer.RectangleShape"
extends="org.jdesktop.swingx.designer.PaintedShape">
<structure map-as="org.jdesktop.swingx.designer.PaintedShape"/>
<value name="x1" get-method="getX1" set-method="setX1" style="attribute"/>
<value name="x2" get-method="getX2" set-method="setX2" style="attribute"/>
<value name="y1" get-method="getY1" set-method="setY1" style="attribute"/>
<value name="y2" get-method="getY2" set-method="setY2" style="attribute"/>
<value name="rounding" get-method="getRounding" set-method="setRounding" style="attribute"/>
</mapping>
<mapping name="ellipse" class="org.jdesktop.swingx.designer.EllipseShape"
extends="org.jdesktop.swingx.designer.PaintedShape">
<structure map-as="org.jdesktop.swingx.designer.PaintedShape"/>
<value name="x1" get-method="getX1" set-method="setX1" style="attribute"/>
<value name="x2" get-method="getX2" set-method="setX2" style="attribute"/>
<value name="y1" get-method="getY1" set-method="setY1" style="attribute"/>
<value name="y2" get-method="getY2" set-method="setY2" style="attribute"/>
</mapping>
<mapping name="path" class="org.jdesktop.swingx.designer.PathShape"
extends="org.jdesktop.swingx.designer.PaintedShape">
<structure map-as="org.jdesktop.swingx.designer.PaintedShape"/>
<collection name="points" get-method="getBezierControlPoints"
set-method="setControlPoints" create-type="java.util.ArrayList">
<structure name="point" type="org.jdesktop.swingx.designer.BezierControlPoint">
<value name="x" get-method="getX" set-method="setX" style="attribute"/>
<value name="y" get-method="getY" set-method="setY" style="attribute"/>
<value name="cp1x" get-method="getCp1X" set-method="setCp1X" style="attribute"/>
<value name="cp1y" get-method="getCp1Y" set-method="setCp1Y" style="attribute"/>
<value name="cp2x" get-method="getCp2X" set-method="setCp2X" style="attribute"/>
<value name="cp2y" get-method="getCp2Y" set-method="setCp2Y" style="attribute"/>
</structure>
</collection>
</mapping>
<!-- == EFFECTS =========================================================================================== -->
<mapping class="org.jdesktop.swingx.designer.effects.ShadowEffect" abstract="true">
<structure field="color"/>
<value name="blendingMode" field="blendingMode" style="attribute"/>
<value name="opacity" field="opacity" style="attribute"/>
<value name="angle" field="angle" style="attribute"/>
<value name="distance" field="distance" style="attribute"/>
<value name="spread" field="spread" style="attribute"/>
<value name="size" field="size" style="attribute"/>
</mapping>
<mapping name="dropShadow" class="org.jdesktop.swingx.designer.effects.DropShadowEffect"
extends="org.jdesktop.swingx.designer.effects.ShadowEffect">
<structure map-as="org.jdesktop.swingx.designer.effects.ShadowEffect"/>
</mapping>
<mapping name="innerShadow" class="org.jdesktop.swingx.designer.effects.InnerShadowEffect"
extends="org.jdesktop.swingx.designer.effects.ShadowEffect">
<structure map-as="org.jdesktop.swingx.designer.effects.ShadowEffect"/>
</mapping>
<mapping name="innerGlow" class="org.jdesktop.swingx.designer.effects.InnerGlowEffect"
extends="org.jdesktop.swingx.designer.effects.ShadowEffect">
<structure map-as="org.jdesktop.swingx.designer.effects.ShadowEffect"/>
</mapping>
<mapping name="outerGlow" class="org.jdesktop.swingx.designer.effects.OuterGlowEffect"
extends="org.jdesktop.swingx.designer.effects.ShadowEffect">
<structure map-as="org.jdesktop.swingx.designer.effects.ShadowEffect"/>
</mapping>
<!-- == TEMPLATE LAYER ================================================================================== -->
<mapping name="templateLayer" class="org.jdesktop.swingx.designer.TemplateLayer"
extends="org.jdesktop.swingx.designer.Layer" post-set="postInit">
<structure map-as="org.jdesktop.swingx.designer.Layer"/>
<value name="fileName" field="fileName" style="attribute"/>
</mapping>
<!-- == LAYER =========================================================================================== -->
<mapping name="layer" class="org.jdesktop.swingx.designer.Layer"
extends="org.jdesktop.swingx.designer.SimpleShape" post-set="postInit">
<structure map-as="org.jdesktop.swingx.designer.SimpleShape"/>
<value name="name" field="name" style="attribute"/>
<value name="type" field="type" style="attribute" default="standard"/>
<value name="opacity" field="opacity"/>
<value name="fillOpacity" field="fillOpacity"/>
<value name="blendingMode" field="blendingMode"/>
<value name="locked" field="locked"/>
<value name="visible" field="visible"/>
<structure name="shapes">
<collection field="shapes" create-type="java.util.ArrayList"/>
</structure>
<structure name="effects">
<collection field="effects" create-type="java.util.ArrayList"/>
</structure>
</mapping>
<!-- == CANVAS =========================================================================================== -->
<mapping name="canvas" class="org.jdesktop.swingx.designer.Canvas" pre-set="preSet" post-set="setupLayers">
<structure name="size" get-method="getSize" set-method="setSize"
marshaller="org.jdesktop.swingx.designer.jibxhelpers.DimensionMapper"
unmarshaller="org.jdesktop.swingx.designer.jibxhelpers.DimensionMapper"/>
<value name="nextLayerNameIndex" field="nextLayerNameIndex"/>
<structure name="stretchingInsets" field="stretchingInsets"
marshaller="org.jdesktop.swingx.designer.jibxhelpers.InsetsMapper"
unmarshaller="org.jdesktop.swingx.designer.jibxhelpers.InsetsMapper"/>
<collection field="layers" create-type="java.util.ArrayList"/>
</mapping>
</binding>
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer;
import org.jdesktop.beans.AbstractBean;
/**
* DoubleBean - Simple bean for a observable double value
*
* @author Created by Jasper Potts (May 25, 2007)
*/
public class DoubleBean extends AbstractBean {
private double value = 0;
public DoubleBean() {}
public DoubleBean(double value) {
this.value = value;
}
public double getValue() {
return value;
}
public void setValue(double value) {
double old = this.value;
this.value = value;
firePropertyChange("value", old, this.value);
}
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
DoubleBean that = (DoubleBean) o;
if (Double.compare(that.value, value) != 0) return false;
return true;
}
public int hashCode() {
long temp = value != +0.0d ? Double.doubleToLongBits(value) : 0L;
return (int) (temp ^ (temp >>> 32));
}
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
/**
* EllipseShape
*
* @author Created by Jasper Potts (May 22, 2007)
*/
public class EllipseShape extends PaintedShape {
private DoubleBean x1 = new DoubleBean();
private DoubleBean x2 = new DoubleBean();
private DoubleBean y1 = new DoubleBean();
private DoubleBean y2 = new DoubleBean();
private ControlPoint tl = new ControlPoint(x1, y1);
private ControlPoint tr = new ControlPoint(x2, y1);
private ControlPoint bl = new ControlPoint(x1, y2);
private ControlPoint br = new ControlPoint(x2, y2);
// =================================================================================================================
// Constructors
/** private noargs constructor for JIBX */
private EllipseShape() {
this(null);
}
public EllipseShape(UIDefaults canvasUiDefaults) {
super(canvasUiDefaults);
PropertyChangeListener listener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
firePropertyChange("bounds", null, getBounds(0));
}
};
x1.addPropertyChangeListener(listener);
y1.addPropertyChangeListener(listener);
x2.addPropertyChangeListener(listener);
y2.addPropertyChangeListener(listener);
}
public EllipseShape(double x, double y, double w, double h) {
this();
x1.setValue(x);
y1.setValue(y);
x2.setValue(x + w);
y2.setValue(y + h);
}
public Rectangle2D getBounds(double pixelSize) {
double left = Math.min(x1.getValue(), x2.getValue());
double right = Math.max(x1.getValue(), x2.getValue());
double top = Math.min(y1.getValue(), y2.getValue());
double bottom = Math.max(y1.getValue(), y2.getValue());
return new Rectangle2D.Double(left, top, right - left, bottom - top);
}
public Ellipse2D getShape() {
double left = Math.min(x1.getValue(), x2.getValue());
double right = Math.max(x1.getValue(), x2.getValue());
double top = Math.min(y1.getValue(), y2.getValue());
double bottom = Math.max(y1.getValue(), y2.getValue());
return new Ellipse2D.Double(left, top, right - left, bottom - top);
}
public boolean isHit(Point2D p, double pixelSize) {
return getBounds(pixelSize).contains(p);
}
public void paint(Graphics2D g2, double pixelSize) {
g2.setPaint(getPaint());
g2.fill(getShape());
}
public void setFrame(double x1, double y1, double x2, double y2) {
this.x1.setValue(x1);
this.y1.setValue(y1);
this.x2.setValue(x2);
this.y2.setValue(y2);
}
@Override
public String toString() {
Rectangle2D bounds = getBounds(0);
return "ELLIPSE { x=" + bounds.getX() + ", y=" + bounds.getY() + ", w=" + bounds.getWidth() + ", h=" + bounds.getHeight() + " }";
}
public List<ControlPoint> getControlPoints() {
List<ControlPoint> points = new ArrayList<ControlPoint>();
points.addAll(super.getControlPoints());
points.add(tl);
points.add(tr);
points.add(bl);
points.add(br);
return points;
}
public void paintControls(Graphics2D g2, double pixelSize, boolean paintControlLines) {
if (paintControlLines) {
g2.setStroke(new BasicStroke((float) pixelSize));
g2.setColor(GraphicsHelper.CONTROL_LINE);
g2.draw(getShape());
}
tl.paintControls(g2, pixelSize, true);
tr.paintControls(g2, pixelSize, true);
bl.paintControls(g2, pixelSize, true);
br.paintControls(g2, pixelSize, true);
// super.paintControls(g2, pixelSize, paintControlLines);
}
public void move(double moveX, double moveY, boolean snapPixels) {
if (snapPixels) {
x1.setValue(Math.round(x1.getValue() + moveX));
x2.setValue(Math.round(x2.getValue() + moveX));
y1.setValue(Math.round(y1.getValue() + moveY));
y2.setValue(Math.round(y2.getValue() + moveY));
} else {
x1.setValue(x1.getValue() + moveX);
x2.setValue(x2.getValue() + moveX);
y1.setValue(y1.getValue() + moveY);
y2.setValue(y2.getValue() + moveY);
}
}
public double getX1() {
return x1.getValue();
}
public void setX1(double x1) {
this.x1.setValue(x1);
}
public double getX2() {
return x2.getValue();
}
public void setX2(double x2) {
this.x2.setValue(x2);
}
public double getY1() {
return y1.getValue();
}
public void setY1(double y1) {
this.y1.setValue(y1);
}
public double getY2() {
return y2.getValue();
}
public void setY2(double y2) {
this.y2.setValue(y2);
}
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer;
import java.awt.Color;
/**
* GraphicsHelper
*
* @author Created by Jasper Potts (May 29, 2007)
*/
public class GraphicsHelper {
public static final Color FILL_LINE = Color.BLUE;
public static final Color FILL_CP_LINE = Color.BLUE;
public static final Color FILL_CP_FILL = Color.WHITE;
public static final Color CONTROL_LINE = Color.RED;
public static final Color CONTROL_POINT_LINE = Color.RED;
public static final Color CONTROL_POINT_FILL = Color.WHITE;
public static final Color BEZIER_CONTROL_POINT_LINE = CONTROL_POINT_LINE;
public static final Color BEZIER_CONTROL_POINT_FILL = CONTROL_POINT_FILL;
public static final Color BEZIER_CONTROL_LINE = Color.DARK_GRAY;
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer;
import org.jdesktop.swingx.designer.effects.Effect;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
/**
* Layer
*
* @author Created by Jasper Potts (May 22, 2007)
*/
public class Layer extends SimpleShape implements Iterable<SimpleShape>, LayerContainer {
public static enum LayerType {
standard, template
}
private String name;
protected LayerType type = LayerType.standard;
/** List of shapes in this layer, first shape is painted on top */
private List<SimpleShape> shapes = new ArrayList<SimpleShape>();
private List<Effect> effects = new ArrayList<Effect>();
private double opacity = 1;
private double fillOpacity = 1;
private BlendingMode blendingMode = BlendingMode.NORMAL;
private boolean locked = false;
private boolean visible = true;
private PropertyChangeListener shapeChangeListener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
int index = shapes.indexOf((SimpleShape) evt.getSource());
firePropertyChange("shapes[" + index + "]." + evt.getPropertyName(), evt.getOldValue(), evt.getNewValue());
}
};
private PropertyChangeListener effectChangeListener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
int index = effects.indexOf((Effect) evt.getSource());
System.out.println(
"Layer.propertyChange EFFECT PROPERTY CHANGED " + evt.getSource() + " -- " + evt.getPropertyName());
firePropertyChange("effects[" + index + "]." + evt.getPropertyName(), evt.getOldValue(), evt.getNewValue());
}
};
private BufferedImage buffer = null;
// =================================================================================================================
// Constructors
public Layer() {
}
public Layer(String name) {
this();
this.name = name;
}
/** Called by JIBX after populating this layer so we can add listeners to children */
protected void postInit() {
for (SimpleShape shape : shapes) {
shape.addPropertyChangeListener(shapeChangeListener);
shape.setParent(this);
}
for (Effect effect : effects) {
effect.addPropertyChangeListener(effectChangeListener);
}
}
// =================================================================================================================
// Bean Methods
public LayerType getType() {
return type;
}
public boolean isLocked() {
return locked;
}
public void setLocked(boolean locked) {
boolean old = isLocked();
this.locked = locked;
firePropertyChange("locked", old, isLocked());
}
public boolean isVisible() {
return visible;
}
public void setVisible(boolean visible) {
boolean old = isVisible();
this.visible = visible;
firePropertyChange("visible", old, isVisible());
}
public String getName() {
return name;
}
public void setName(String name) {
String old = getName();
this.name = name;
firePropertyChange("name", old, getName());
}
public void setParent(LayerContainer parent) {
super.setParent(parent);
// generate a name if null
if (name == null) {
Canvas c = null;
LayerContainer p = parent;
while (true) {
if (p instanceof Canvas) {
c = (Canvas) p;
break;
} else if (p == null) {
break;
}
p = p.getParent();
}
if (c != null) {
setName("Layer " + c.getNextLayerNameIndex());
}
}
}
/**
* Add shape to top of layer so it paints above all other shapes
*
* @param shape The shape to add
*/
public void add(SimpleShape shape) {
shapes.add(0, shape);
shape.setParent(this);
shape.addPropertyChangeListener(shapeChangeListener);
fireIndexedPropertyChange("shapes", 0, null, shape);
}
public void remove(SimpleShape shape) {
int index = shapes.indexOf(shape);
if (index != -1) {
shapes.remove(shape);
shape.setParent(null);
fireIndexedPropertyChange("shapes", index, shape, null);
}
}
/**
* Returns an unmodifianle iterator over a set of elements of type SimpleShape.
*
* @return an Iterator.
*/
public Iterator<SimpleShape> iterator() {
return Collections.unmodifiableList(shapes).iterator();
}
public List<Effect> getEffects() {
return Collections.unmodifiableList(effects);
}
public void addEffect(Effect effect) {
int index = effects.size();
effects.add(effect);
effect.addPropertyChangeListener(effectChangeListener);
fireIndexedPropertyChange("effects", index, null, effects);
}
public void removeEffect(Effect effect) {
int index = effects.indexOf(effect);
if (index != -1) {
effects.remove(effect);
effect.removePropertyChangeListener(effectChangeListener);
fireIndexedPropertyChange("effects", index, effect, null);
}
}
public double getOpacity() {
return opacity;
}
public void setOpacity(double opacity) {
if (opacity < 0 || opacity > 1) return;
double old = getOpacity();
this.opacity = opacity;
firePropertyChange("opacity", old, getOpacity());
}
public double getFillOpacity() {
return fillOpacity;
}
public void setFillOpacity(double fillOpacity) {
if (fillOpacity < 0 || fillOpacity > 1) return;
double old = getFillOpacity();
this.fillOpacity = fillOpacity;
firePropertyChange("fillOpacity", old, getFillOpacity());
}
public BlendingMode getBlendingMode() {
return blendingMode;
}
public void setBlendingMode(BlendingMode blendingMode) {
BlendingMode old = getBlendingMode();
this.blendingMode = blendingMode;
firePropertyChange("blendingMode", old, getBlendingMode());
}
// =================================================================================================================
// Layer Methods
/**
* Get the parent canvas that contains this layer
*
* @return Parant canvas, or null if the layer is not in a canvas
*/
public Canvas getCanvas() {
LayerContainer lc = this;
while (lc != null) {
if (lc instanceof Canvas) return (Canvas) lc;
lc = lc.getParent();
}
return null;
}
public List<SimpleShape> getShapes() {
return new ArrayList<SimpleShape>(shapes);
}
public List<SimpleShape> getIntersectingShapes(Point2D p, double pixelSize) {
if (isLocked() || !isVisible()) return Collections.emptyList();
List<SimpleShape> intersectingShapes = new ArrayList<SimpleShape>();
for (SimpleShape shape : shapes) {
if (shape instanceof Layer) {
intersectingShapes.addAll(((Layer) shape).getIntersectingShapes(p, pixelSize));
} else {
if (shape.isHit(p, pixelSize)) intersectingShapes.add(shape);
}
}
return intersectingShapes;
}
public List<SimpleShape> getIntersectingShapes(Rectangle2D rect, double pixelSize) {
if (isLocked() || !isVisible()) return Collections.emptyList();
List<SimpleShape> intersectingShapes = new ArrayList<SimpleShape>();
for (SimpleShape shape : shapes) {
if (shape instanceof Layer) {
intersectingShapes.addAll(((Layer) shape).getIntersectingShapes(rect, pixelSize));
} else {
if (shape.intersects(rect, pixelSize)) intersectingShapes.add(shape);
}
}
return intersectingShapes;
}
public boolean isEmpty() {
return shapes.isEmpty();
}
// =================================================================================================================
// SimpleShape Methods
public Rectangle2D getBounds(double pixelSize) {
Rectangle2D.Double rect = new Rectangle2D.Double();
for (SimpleShape shape : shapes) {
rect.add(shape.getBounds(pixelSize));
}
return rect;
}
public Shape getShape() {
return getBounds(0);
}
public boolean isHit(Point2D p, double pixelSize) {
if (isLocked() || !isVisible()) return false;
for (SimpleShape shape : shapes) {
if (shape.isHit(p, pixelSize)) return true;
}
return false;
}
public boolean intersects(Rectangle2D rect, double pixelSize) {
if (isLocked() || !isVisible()) return false;
for (SimpleShape shape : shapes) {
if (shape.intersects(rect, pixelSize)) return true;
}
return false;
}
public List<ControlPoint> getControlPoints() {
return Collections.emptyList();
}
public void paint(Graphics2D g2, double pixelSize) {
}
public void paintControls(Graphics2D g2, double pixelSize, boolean paintControlLines) {
}
public String toString() {
return getName();
}
// =================================================================================================================
// LayerContainer Methods
public void addLayer(int i, Layer layer) {
// get existing layer at index i
Layer existingLayer = getLayer(i);
if (existingLayer == null) {
addLayer(layer);
} else {
int index = indexOfLayer(existingLayer);
shapes.add(index, layer);
layer.setParent(this);
layer.addPropertyChangeListener(shapeChangeListener);
fireIndexedPropertyChange("layers", index, null, layer);
}
}
public void addLayer(Layer layer) {
shapes.add(layer);
layer.setParent(this);
layer.addPropertyChangeListener(shapeChangeListener);
int index = indexOfLayer(layer);
fireIndexedPropertyChange("layers", index, null, layer);
}
public Layer getLayer(int index) {
int i = -1;
for (SimpleShape shape : shapes) {
if (shape instanceof Layer) i++;
if (i == index) return (Layer) shape;
}
return null;
}
public int getLayerCount() {
int count = 0;
for (SimpleShape shape : shapes) {
if (shape instanceof Layer) count++;
}
return count;
}
public Collection<Layer> getLayers() {
List<Layer> layers = new ArrayList<Layer>();
for (SimpleShape shape : shapes) {
if (shape instanceof Layer) layers.add((Layer) shape);
}
return Collections.unmodifiableList(layers);
}
public Iterator<Layer> getLayerIterator() {
return new Iterator<Layer>() {
private int index = 0;
public boolean hasNext() {
for (int i = index; i < shapes.size(); i++) {
if (shapes.get(i) instanceof Layer) {
return true;
}
}
return false;
}
public Layer next() {
for (; index < shapes.size(); index++) {
if (shapes.get(index) instanceof Layer) {
Layer nextLayer = (Layer) shapes.get(index);
index++; // increment index so we don't find the same one again
return nextLayer;
}
}
return null;
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
public int indexOfLayer(Layer layer) {
int i = -1;
for (SimpleShape s : shapes) {
if (s instanceof Layer) i++;
if (s == layer) return i;
}
return -1;
}
public void removeLayer(Layer layer) {
int index = indexOfLayer(layer);
if (index != -1) {
shapes.remove(layer);
layer.removePropertyChangeListener(shapeChangeListener);
fireIndexedPropertyChange("layers", index, layer, null);
}
}
public Dimension getRootSize() {
return getParent().getRootSize();
}
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer;
import java.awt.Dimension;
import java.beans.PropertyChangeListener;
import java.util.Collection;
import java.util.Iterator;
/**
* LayerContainer
*
* @author Created by Jasper Potts (May 31, 2007)
*/
public interface LayerContainer {
public void addPropertyChangeListener(PropertyChangeListener listener);
public void removePropertyChangeListener(PropertyChangeListener listener);
public LayerContainer getParent();
public void addLayer(Layer layer);
public void addLayer(int i, Layer layer);
public void removeLayer(Layer layer);
public int getLayerCount();
public Layer getLayer(int index);
public int indexOfLayer(Layer layer);
public Iterator<Layer> getLayerIterator();
public Collection<Layer> getLayers();
/**
* Get the size in pixels of the root of the layer tree, this is usualy a canvas
*
* @return The size of the whole layer tree
*/
public Dimension getRootSize();
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer;
import org.jdesktop.swingx.designer.paint.Matte;
import org.jdesktop.swingx.designer.paint.PaintModel;
import javax.swing.UIDefaults;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.GradientPaint;
import java.awt.Graphics2D;
import java.awt.LinearGradientPaint;
import java.awt.Paint;
import java.awt.RadialGradientPaint;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
* PaintedShape
*
* @author Created by Jasper Potts (May 22, 2007)
*/
public abstract class PaintedShape extends SimpleShape {
private PaintModel paint;
// control points for paint control types
private DoubleBean px1 = new DoubleBean(0.25);
private DoubleBean px2 = new DoubleBean(0.75);
private DoubleBean py1 = new DoubleBean(0);
private DoubleBean py2 = new DoubleBean(1);
private ControlPoint ptl = new PaintControlPoint(px1, py1);
private ControlPoint ptr = new PaintControlPoint(px2, py1);
private ControlPoint pbl = new PaintControlPoint(px1, py2);
private ControlPoint pbr = new PaintControlPoint(px2, py2);
private PropertyChangeListener paintListener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
firePropertyChange("paint." + evt.getPropertyName(), evt.getOldValue(), evt.getNewValue());
}
};
protected PaintedShape() {
px1.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
firePropertyChange("x1", evt.getOldValue(), evt.getNewValue());
}
});
py1.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
firePropertyChange("y1", evt.getOldValue(), evt.getNewValue());
}
});
px2.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
firePropertyChange("x2", evt.getOldValue(), evt.getNewValue());
}
});
py2.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
firePropertyChange("y2", evt.getOldValue(), evt.getNewValue());
}
});
}
protected PaintedShape(UIDefaults canvasUiDefaults) {
this();
setPaintModel(new Matte(Color.ORANGE, canvasUiDefaults));
}
public PaintModel getPaintModel() {
return paint;
}
public void setPaintModel(PaintModel paint) {
PaintModel old = getPaintModel();
if (old != null) old.removePropertyChangeListener(paintListener);
this.paint = paint;
this.paint.addPropertyChangeListener(paintListener);
firePropertyChange("paintModel", old, getPaintModel());
}
public Paint getPaint() {
Paint p = getPaintModel().getPaint();
if (p instanceof Color) {
return p;
}
//resize p as necessary to fit the bounds of this PaintedShape
Rectangle2D bounds = getBounds(0);
if (p instanceof LinearGradientPaint) {
LinearGradientPaint lgp = (LinearGradientPaint) p;
return new LinearGradientPaint(
convertLocalPoint(ptl.getPosition(), bounds),
convertLocalPoint(pbr.getPosition(), bounds),
lgp.getFractions(),
lgp.getColors());
} else if (p instanceof RadialGradientPaint) {
RadialGradientPaint rgp = (RadialGradientPaint) p;
Point2D outer = convertLocalPoint(ptl.getPosition(), bounds);
Point2D center = convertLocalPoint(pbr.getPosition(), bounds);
double deltaX = Math.abs(center.getX() - outer.getX());
double deltaY = Math.abs(center.getY() - outer.getY());
float radius = (float) Math.sqrt((deltaX * deltaX) + (deltaY * deltaY));
return new RadialGradientPaint(
center,
radius,
rgp.getFractions(),
rgp.getColors());
} else {
return p;
}
}
public List<? extends ControlPoint> getControlPoints() {
switch (paint.getPaintControlType()) {
case control_line:
return Arrays.asList(ptl, pbr);
case control_rect:
return Arrays.asList(ptl, ptr, pbl, pbr);
default:
return Collections.emptyList();
}
}
public void paintFillControls(Graphics2D g2, double pixelSize, boolean paintControlLines) {
switch (paint.getPaintControlType()) {
case control_line:
Point2D p1 = convertLocalPoint(ptl.getPosition(), PaintedShape.this.getBounds(0));
Point2D p2 = convertLocalPoint(pbr.getPosition(), PaintedShape.this.getBounds(0));
g2.setStroke(new BasicStroke((float) pixelSize));
g2.setColor(GraphicsHelper.FILL_LINE);
g2.draw(new Line2D.Double(p1.getX(), p1.getY(), p2.getX(), p2.getY()));
ptl.paintControls(g2, pixelSize, true);
pbr.paintControls(g2, pixelSize, true);
break;
case control_rect:
g2.setStroke(new BasicStroke((float) pixelSize));
g2.setColor(GraphicsHelper.FILL_LINE);
g2.draw(new Rectangle2D.Double(
px1.getValue(),
py1.getValue(),
px2.getValue() - px1.getValue(),
py2.getValue() - py1.getValue()));
ptl.paintControls(g2, pixelSize, true);
ptr.paintControls(g2, pixelSize, true);
pbl.paintControls(g2, pixelSize, true);
pbr.paintControls(g2, pixelSize, true);
break;
}
}
public void move(double moveX, double moveY, boolean snapPixels) {
for (ControlPoint controlPoint : getControlPoints()) {
if (!(controlPoint instanceof PaintControlPoint)) controlPoint.move(moveX, moveY, snapPixels);
}
}
public double getPaintX1() {
return px1.getValue();
}
public void setPaintX1(double x1) {
this.px1.setValue(x1);
}
public double getPaintX2() {
return px2.getValue();
}
public void setPaintX2(double x2) {
this.px2.setValue(x2);
}
public double getPaintY1() {
return py1.getValue();
}
public void setPaintY1(double y1) {
this.py1.setValue(y1);
}
public double getPaintY2() {
return py2.getValue();
}
public void setPaintY2(double y2) {
this.py2.setValue(y2);
}
// =================================================================================================================
// Private helper methods
private Point2D convertLocalPoint(Point2D point, Rectangle2D bounds) {
point.setLocation(
bounds.getX() + (point.getX() * bounds.getWidth()),
bounds.getY() + (point.getY() * bounds.getHeight())
);
return point;
}
private Point2D convertScreenPoint(Point2D point, Rectangle2D bounds) {
return new Point2D.Double(
(point.getX() - bounds.getX()) / bounds.getWidth(),
(point.getY() - bounds.getY()) / bounds.getHeight()
);
}
// =================================================================================================================
// Gradient ControlPoint
/**
* A Special ControlPoint thats internal values are in coordinates relative to the shapes bounds. With 0,0 being the
* top left of the shape and 1.0X == shape width and 1.0Y == shapes height.
*/
public class PaintControlPoint extends ControlPoint {
public PaintControlPoint() {
super(GraphicsHelper.FILL_CP_FILL, GraphicsHelper.FILL_CP_LINE);
}
public PaintControlPoint(DoubleBean x, DoubleBean y) {
super(x, y, GraphicsHelper.FILL_CP_FILL, GraphicsHelper.FILL_CP_LINE);
}
public void paintControls(Graphics2D g2, double pixelSize, boolean paintControlLines) {
Point2D p = convertLocalPoint(getPosition(), PaintedShape.this.getBounds(0));
g2.setStroke(new BasicStroke((float) pixelSize));
double size = pixelSize * 4d;
Shape s = new Ellipse2D.Double(p.getX() - size, p.getY() - size,
size * 2, size * 2);
g2.setPaint(new GradientPaint(
(float) p.getX(), (float) (p.getY() - size), Color.CYAN,
(float) p.getX(), (float) (p.getY() + size), Color.WHITE
));
g2.fill(s);
g2.setColor(GraphicsHelper.FILL_CP_LINE);
g2.draw(s);
}
public void move(double moveX, double moveY, boolean snapPixels) {
Rectangle2D bounds = PaintedShape.this.getBounds(0);
moveX = moveX / bounds.getWidth();
moveY = moveY / bounds.getHeight();
if (snapPixels) {
// snap to neareast 0.5
double newX = Math.round((x.getValue() + moveX) * 2d) / 2d;
double newY = Math.round((y.getValue() + moveY) * 2d) / 2d;
setPosition(newX, newY);
} else {
setPosition(x.getValue() + moveX, y.getValue() + moveY);
}
}
public Rectangle2D getBounds(double pixelSize) {
Point2D p = convertLocalPoint(getPosition(), PaintedShape.this.getBounds(0));
double size = pixelSize * 4d;
return new Rectangle2D.Double(p.getX() - size, p.getY() - size,
size * 2, size * 2);
}
}
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.GeneralPath;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
/**
* PathShape
*
* @author Created by Jasper Potts (May 29, 2007)
*/
public class PathShape extends PaintedShape {
private Shape cachedShape = null;
private List<BezierControlPoint> controlPoints = new ArrayList<BezierControlPoint>();
private PropertyChangeListener cpListener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
rebuildShape();
}
};
// =================================================================================================================
// Constructors
/** private noargs constructor for JIBX */
private PathShape() {
this(null);
}
public PathShape(UIDefaults canvasUiDefaults) {
super(canvasUiDefaults);
}
public BezierControlPoint addPoint(double x, double y) {
BezierControlPoint cp = new BezierControlPoint(x, y);
controlPoints.add(cp);
cp.addPropertyChangeListener(cpListener);
// update shape
rebuildShape();
// return new control point
return cp;
}
public Shape getShape() {
if (cachedShape == null) {
rebuildShape();
}
return cachedShape;
}
private void rebuildShape() {
GeneralPath path = new GeneralPath();
BezierControlPoint first, last;
first = last = controlPoints.get(0);
path.moveTo((float) first.getX(), (float) first.getY());
for (int i = 0; i < controlPoints.size(); i++) {
BezierControlPoint controlPoint = controlPoints.get(i);
if (last.getCp2().isSharp() && controlPoint.getCp1().isSharp()) {
path.lineTo(controlPoint.getX(), controlPoint.getY());
} else {
path.curveTo(
(float) last.getCp2().getX(), (float) last.getCp2().getY(),
(float) controlPoint.getCp1().getX(), (float) controlPoint.getCp1().getY(),
(float) controlPoint.getX(), (float) controlPoint.getY()
);
}
last = controlPoint;
}
// close path
if (last.getCp2().isSharp() && first.getCp1().isSharp()) {
path.lineTo(first.getX(), first.getY());
} else {
path.curveTo(
(float) last.getCp2().getX(), (float) last.getCp2().getY(),
(float) first.getCp1().getX(), (float) first.getCp1().getY(),
(float) first.getX(), (float) first.getY()
);
}
path.closePath();
// fire change
cachedShape = path;
firePropertyChange("shape", null, cachedShape);
}
@Override
public String toString() {
String p = "PATH {\n";
BezierControlPoint first, last;
first = last = controlPoints.get(0);
p += " path.moveTo(" + first.getX() + "," + first.getY() + ");";
for (int i = 0; i < controlPoints.size(); i++) {
BezierControlPoint controlPoint = controlPoints.get(i);
p += " path.curveTo(" +
(float) last.getCp2().getX() + "," + (float) last.getCp2().getY() + "," +
(float) controlPoint.getCp1().getX() + "," + (float) controlPoint.getCp1().getY() + "," +
(float) controlPoint.getX() + "," + (float) controlPoint.getY() +
");\n";
last = controlPoint;
}
// close path
p += " path.curveTo(" +
(float) last.getCp2().getX() + "," + (float) last.getCp2().getY() + "," +
(float) first.getCp1().getX() + "," + (float) first.getCp1().getY() + "," +
(float) first.getX() + "," + (float) first.getY() +
");\n";
p += "}\n";
return p;
}
// =================================================================================================================
// Shape Methods
public Rectangle2D getBounds(double pixelSize) {
return getShape().getBounds2D();
}
public List<? extends ControlPoint> getControlPoints() {
List<ControlPoint> pts = new ArrayList<ControlPoint>();
for (BezierControlPoint controlPoint : controlPoints) {
pts.add(controlPoint);
}
for (ControlPoint controlPoint : super.getControlPoints()) {
pts.add(controlPoint);
}
return pts;
}
public void setControlPoints(List<BezierControlPoint> controlPoints) {
List<BezierControlPoint> old = this.controlPoints;
for (BezierControlPoint cp : old) {
cp.removePropertyChangeListener(cpListener);
}
this.controlPoints = controlPoints;
for (BezierControlPoint cp : this.controlPoints) {
cp.addPropertyChangeListener(cpListener);
}
// update shape
rebuildShape();
}
public boolean isHit(Point2D p, double pixelSize) {
return getShape().contains(p);
}
public void paint(Graphics2D g2, double pixelSize) {
g2.setPaint(getPaint());
g2.fill(getShape());
}
public void paintControls(Graphics2D g2, double pixelSize, boolean paintControlLines) {
if (paintControlLines) {
g2.setStroke(new BasicStroke((float) pixelSize));
g2.setColor(GraphicsHelper.CONTROL_LINE);
g2.draw(getShape());
}
for (BezierControlPoint controlPoint : controlPoints) {
if (!controlPoint.isSharpCorner()) controlPoint.paintControls(g2, pixelSize, true);
}
}
public List<BezierControlPoint> getBezierControlPoints() {
return controlPoints;
}
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.List;
/**
* RectangleShape
*
* @author Created by Jasper Potts (May 22, 2007)
*/
public class RectangleShape extends PaintedShape {
private DoubleBean x1 = new DoubleBean();
private DoubleBean x2 = new DoubleBean();
private DoubleBean y1 = new DoubleBean();
private DoubleBean y2 = new DoubleBean();
private ControlPoint tl = new ControlPoint(x1, y1);
private ControlPoint tr = new ControlPoint(x2, y1);
private ControlPoint bl = new ControlPoint(x1, y2);
private ControlPoint br = new ControlPoint(x2, y2);
private DoubleBean roundingX = new DoubleBean() {
public void setValue(double value) {
// contrain y = y1 and x is between x1+1 and (x2-x1)/2
boolean x1isLess = x1.getValue() < x2.getValue();
double min = x1isLess ? x1.getValue() + 1 : x1.getValue() - 1;
double max = x1isLess ? x1.getValue() + ((x2.getValue() - x1.getValue()) / 2) :
x2.getValue() + ((x1.getValue() - x2.getValue()) / 2);
double newX = value;
if (newX < min) newX = min;
if (newX > max) newX = max;
super.setValue(newX);
}
};
private ControlPoint rounding = new ControlPoint(roundingX, y1) {
public void paintControls(Graphics2D g2, double pixelSize, boolean paintControlLines) {
double size = pixelSize * 3d;
Shape s = new Ellipse2D.Double(getX() - size, getY() - size,
size * 2, size * 2);
g2.setColor(GraphicsHelper.BEZIER_CONTROL_POINT_FILL);
g2.fill(s);
g2.setColor(GraphicsHelper.BEZIER_CONTROL_POINT_LINE);
g2.draw(s);
}
public void setPosition(Point2D position) {
// only alow X to change
x.setValue(position.getX());
}
};
// =================================================================================================================
// Constructors
/** private noargs constructor for JIBX */
private RectangleShape() {
this(null);
}
public RectangleShape(UIDefaults canvasUiDefaults) {
super(canvasUiDefaults);
x1.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
// keep rounding point in sync
roundingX.setValue(roundingX.getValue() +
((Double) evt.getNewValue() - (Double) evt.getOldValue()));
firePropertyChange("bounds", null, getBounds(0));
}
});
x2.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
// keep rounding point in sync
double distanceFromX1 = Math.abs(roundingX.getValue() - x1.getValue());
roundingX.setValue(
(x1.getValue() < x2.getValue()) ? x1.getValue() + distanceFromX1 :
x1.getValue() - distanceFromX1
);
firePropertyChange("bounds", null, getBounds(0));
}
});
PropertyChangeListener listener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
firePropertyChange("bounds", null, getBounds(0));
}
};
y1.addPropertyChangeListener(listener);
y2.addPropertyChangeListener(listener);
rounding.addPropertyChangeListener(listener);
}
public RectangleShape(double x, double y, double w, double h) {
this();
x1.setValue(x);
y1.setValue(y);
x2.setValue(x + w);
y2.setValue(y + h);
}
public Shape getShape() {
double rounding = getRounding();
double left = Math.min(x1.getValue(), x2.getValue());
double right = Math.max(x1.getValue(), x2.getValue());
double top = Math.min(y1.getValue(), y2.getValue());
double bottom = Math.max(y1.getValue(), y2.getValue());
if (rounding > 0) {
return new RoundRectangle2D.Double(
left, top, right - left, bottom - top, rounding, rounding
);
} else {
return new Rectangle2D.Double(left, top, right - left, bottom - top);
}
}
public double getRounding() {
double rounding = Math.abs(roundingX.getValue() - x1.getValue()) * 2;
return rounding > 2 ? rounding : 0;
}
public void setRounding(double rounding) {
if (rounding > 0 && rounding < 2) rounding = 0;
roundingX.setValue((rounding / 2d) + x1.getValue());
}
public boolean isRounded() {
return getRounding() > 0;
}
public double getX1() {
return x1.getValue();
}
public void setX1(double x1) {
this.x1.setValue(x1);
}
public double getX2() {
return x2.getValue();
}
public void setX2(double x2) {
this.x2.setValue(x2);
}
public double getY1() {
return y1.getValue();
}
public void setY1(double y1) {
this.y1.setValue(y1);
}
public double getY2() {
return y2.getValue();
}
public void setY2(double y2) {
this.y2.setValue(y2);
}
// =================================================================================================================
// SimpleShape Methods
public Rectangle2D getBounds(double pixelSize) {
double left = Math.min(x1.getValue(), x2.getValue());
double right = Math.max(x1.getValue(), x2.getValue());
double top = Math.min(y1.getValue(), y2.getValue());
double bottom = Math.max(y1.getValue(), y2.getValue());
return new Rectangle2D.Double(left, top, right - left, bottom - top);
}
public boolean isHit(Point2D p, double pixelSize) {
return getShape().contains(p);
}
public void paint(Graphics2D g2, double pixelSize) {
g2.setPaint(getPaint());
g2.fill(getShape());
}
public void setFrame(double x1, double y1, double x2, double y2) {
this.x1.setValue(x1);
this.y1.setValue(y1);
this.x2.setValue(x2);
this.y2.setValue(y2);
}
@Override
public String toString() {
Rectangle2D bounds = getBounds(0);
if (isRounded()) {
return "ROUND RECT { x=" + bounds.getX() + ", y=" + bounds.getY() + ", w=" + bounds.getWidth() + ", h=" + bounds.getHeight() + ", rounding=" + getRounding() + " }";
} else {
return "ROUND RECT { x=" + bounds.getX() + ", y=" + bounds.getY() + ", w=" + bounds.getWidth() + ", h=" + bounds.getHeight() + " }";
}
}
public List<ControlPoint> getControlPoints() {
List<ControlPoint> points = new ArrayList<ControlPoint>();
points.addAll(super.getControlPoints());
points.add(tl);
points.add(tr);
points.add(bl);
points.add(br);
points.add(rounding);
return points;
}
public void paintControls(Graphics2D g2, double pixelSize, boolean paintControlLines) {
if (paintControlLines) {
g2.setStroke(new BasicStroke((float) pixelSize));
g2.setColor(GraphicsHelper.CONTROL_LINE);
g2.draw(getShape());
}
tl.paintControls(g2, pixelSize, true);
tr.paintControls(g2, pixelSize, true);
bl.paintControls(g2, pixelSize, true);
br.paintControls(g2, pixelSize, true);
rounding.paintControls(g2, pixelSize, true);
}
public void move(double moveX, double moveY, boolean snapPixels) {
if (snapPixels) {
x1.setValue(Math.round(x1.getValue() + moveX));
x2.setValue(Math.round(x2.getValue() + moveX));
y1.setValue(Math.round(y1.getValue() + moveY));
y2.setValue(Math.round(y2.getValue() + moveY));
} else {
x1.setValue(x1.getValue() + moveX);
x2.setValue(x2.getValue() + moveX);
y1.setValue(y1.getValue() + moveY);
y2.setValue(y2.getValue() + moveY);
}
}
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer;
import org.jdesktop.beans.AbstractBean;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.List;
/**
* SimpleShape
*
* @author Created by Jasper Potts (May 22, 2007)
*/
public abstract class SimpleShape extends AbstractBean {
protected AffineTransform transform = new AffineTransform();
protected LayerContainer parent = null;
public void applyTransform(AffineTransform t) {
transform.concatenate(t);
}
public abstract Rectangle2D getBounds(double pixelSize);
public abstract void paint(Graphics2D g2, double pixelSize);
public abstract boolean isHit(Point2D p, double pixelSize);
public boolean intersects(Rectangle2D rect, double pixelSize) {
return getBounds(pixelSize).intersects(rect);
}
public abstract List<? extends ControlPoint> getControlPoints();
public abstract void paintControls(Graphics2D g2, double pixelSize, boolean paintControlLines);
public void move(double moveX, double moveY, boolean snapPixels) {
for (ControlPoint controlPoint : getControlPoints()) {
controlPoint.move(moveX, moveY, snapPixels);
}
}
public LayerContainer getParent() {
return parent;
}
public void setParent(LayerContainer parent) {
LayerContainer old = getParent();
this.parent = parent;
firePropertyChange("parent", old, getParent());
}
public abstract Shape getShape();
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer;
import org.jdesktop.swingx.designer.effects.Effect;
import javax.imageio.ImageIO;
import javax.swing.JOptionPane;
import javax.swing.SwingUtilities;
import java.awt.Color;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.Image;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.lang.ref.SoftReference;
/**
* TemplateLayer
*
* @author Created by Jasper Potts (Jul 2, 2007)
*/
public class TemplateLayer extends Layer {
private String fileName;
private transient SoftReference<BufferedImage> imgRef = null;
public TemplateLayer() {
type = LayerType.template;
}
public TemplateLayer(String fileName, BufferedImage templateImage) {
super("Template");
this.fileName = fileName;
type = LayerType.template;
if (templateImage != null) {
imgRef = new SoftReference<BufferedImage>(templateImage);
}
}
// =================================================================================================================
// Methods
public String getName() {
return super.getName();
}
/**
* template layers are always locked
*
* @return <code>true</code>
*/
public boolean isLocked() {
return true;
}
public void add(SimpleShape shape) {
throw new IllegalStateException("Template layers can't contain shapes");
}
public void addEffect(Effect effect) {
throw new IllegalStateException("Template layers can't contain effects");
}
public void addLayer(int i, Layer layer) {
throw new IllegalStateException("Template layers can't contain sub layers");
}
public void addLayer(Layer layer) {
throw new IllegalStateException("Template layers can't contain sub layers");
}
public void paint(Graphics2D g2, double pixelSize) {
if (isVisible()) {
BufferedImage img = getTemplateImage();
if (img != null) g2.drawImage(img, 0, 0, null);
}
}
public Image getBuffer(GraphicsConfiguration graphicsConfiguration) {
return getTemplateImage();
}
public BufferedImage getTemplateImage() {
BufferedImage img = null;
if (imgRef == null || (img = imgRef.get()) == null) {
// can not access canvas
final File templateImgFile = new File(getCanvas().getTemplatesDir(), fileName);
System.out.println("templateImgFile = " + templateImgFile.getAbsolutePath());
System.out.println("templateImgFile.exists = " + templateImgFile.exists());
try {
img = ImageIO.read(templateImgFile);
imgRef = new SoftReference<BufferedImage>(img);
} catch (IOException e) {
e.printStackTrace();
// create error image
img = new BufferedImage(getCanvas().getSize().width, getCanvas().getSize().height,
BufferedImage.TYPE_INT_RGB);
Graphics2D g2 = img.createGraphics();
g2.setColor(Color.RED);
g2.fillRect(0, 0, img.getWidth(), img.getHeight());
g2.setColor(Color.WHITE);
g2.setFont(g2.getFont().deriveFont(8f));
FontMetrics fontMetrics = g2.getFontMetrics();
Rectangle2D stringBounds = fontMetrics.getStringBounds("Missing Image", g2);
int offsetX = (int) ((img.getWidth() - stringBounds.getWidth()) / 2d);
int offsetY = (int) (((img.getHeight() - stringBounds.getHeight()) / 2d) - stringBounds.getY());
g2.drawString("Missing Image", offsetX, offsetY);
g2.dispose();
imgRef = new SoftReference<BufferedImage>(img);
}
}
return img;
}
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer.effects;
import org.jdesktop.swingx.designer.paint.Matte;
import javax.swing.UIDefaults;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.util.Arrays;
/**
* DropShadowEffect
*
* @author Created by Jasper Potts (Jun 18, 2007)
*/
public class DropShadowEffect extends ShadowEffect {
protected DropShadowEffect() {}
;
public DropShadowEffect(UIDefaults uiDefaults) {
color = new Matte(Color.BLACK, uiDefaults);
}
// =================================================================================================================
// Effect Methods
/**
* Get the display name for this effect
*
* @return The user displayable name
*/
public String getDisplayName() {
return "Drop Shadow";
}
/**
* Get the type of this effect, one of UNDER,BLENDED,OVER. UNDER means the result of apply effect should be painted
* under the src image. BLENDED means the result of apply sffect contains a modified src image so just it should be
* painted. OVER means the result of apply effect should be painted over the src image.
*
* @return The effect type
*/
public EffectType getEffectType() {
return EffectType.UNDER;
}
/**
* Apply the effect to the src image generating the result . The result image may or may not contain the source
* image depending on what the effect type is.
*
* @param src The source image for applying the effect to
* @param dst The dstination image to paint effect result into. If this is null then a new image will be created
* @param w The width of the src image to apply effect to, this allow the src and dst buffers to be bigger than
* the area the need effect applied to it
* @param h The height of the src image to apply effect to, this allow the src and dst buffers to be bigger than
* the area the need effect applied to it
* @return The result of appl
*/
public BufferedImage applyEffect(BufferedImage src, BufferedImage dst, int w, int h) {
// calculate offset
double trangleAngle = Math.toRadians(angle - 90);
int offsetX = (int) (Math.sin(trangleAngle) * distance);
int offsetY = (int) (Math.cos(trangleAngle) * distance);
// clac expanded size
int tmpOffX = offsetX + size;
int tmpOffY = offsetY + size;
int tmpW = w + offsetX + size + size;
int tmpH = h + offsetY + size + size;
// create tmp buffers
int[] lineBuf = getTmpIntArray(w);
byte[] tmpBuf1 = getTmpByteArray1(tmpW * tmpH);
Arrays.fill(tmpBuf1, (byte) 0x00);
byte[] tmpBuf2 = getTmpByteArray2(tmpW * tmpH);
// extract src image alpha channel and inverse and offset
Raster srcRaster = src.getRaster();
for (int y = 0; y < h; y++) {
int dy = (y + tmpOffY);
int offset = dy * tmpW;
srcRaster.getDataElements(0, y, w, 1, lineBuf);
for (int x = 0; x < w; x++) {
int dx = x + tmpOffX;
tmpBuf1[offset + dx] = (byte) ((lineBuf[x] & 0xFF000000) >>> 24);
}
}
// blur
float[] kernel = EffectUtils.createGaussianKernel(size);
EffectUtils.blur(tmpBuf1, tmpBuf2, tmpW, tmpH, kernel, size); // horizontal pass
EffectUtils.blur(tmpBuf2, tmpBuf1, tmpH, tmpW, kernel, size);// vertical pass
//rescale
float spread = Math.min(1 / (1 - (0.01f * this.spread)), 255);
for (int i = 0; i < tmpBuf1.length; i++) {
int val = (int) (((int) tmpBuf1[i] & 0xFF) * spread);
tmpBuf1[i] = (val > 255) ? (byte) 0xFF : (byte) val;
}
// create color image with shadow color and greyscale image as alpha
if (dst == null) dst = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
WritableRaster shadowRaster = dst.getRaster();
int red = color.getRed(), green = color.getGreen(), blue = color.getBlue();
for (int y = 0; y < h; y++) {
int srcY = y + tmpOffY;
int shadowOffset = (srcY - offsetY) * tmpW;
for (int x = 0; x < w; x++) {
int srcX = x + tmpOffX;
lineBuf[x] = tmpBuf1[shadowOffset + (srcX - offsetX)] << 24 | red << 16 | green << 8 | blue;
}
shadowRaster.setDataElements(0, y, w, 1, lineBuf);
}
return dst;
}
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer.effects;
import org.jdesktop.beans.AbstractBean;
import org.jdesktop.swingx.designer.BlendingMode;
import java.awt.image.BufferedImage;
import java.lang.ref.SoftReference;
/**
* Effect
*
* @author Created by Jasper Potts (Jun 18, 2007)
*/
public abstract class Effect extends AbstractBean {
protected boolean visible = true;
public enum EffectType {
UNDER, BLENDED, OVER
}
public boolean isVisible() {
return visible;
}
public void setVisible(boolean visible) {
boolean old = isVisible();
this.visible = visible;
firePropertyChange("visible", old, isVisible());
}
public String toString() {
return getDisplayName();
}
// =================================================================================================================
// Abstract Methods
/**
* Get the display name for this effect
*
* @return The user displayable name
*/
public abstract String getDisplayName();
/**
* Get the type of this effect, one of UNDER,BLENDED,OVER. UNDER means the result of apply effect should be painted
* under the src image. BLENDED means the result of apply sffect contains a modified src image so just it should be
* painted. OVER means the result of apply effect should be painted over the src image.
*
* @return The effect type
*/
public abstract EffectType getEffectType();
/**
* Get the blending mode to use to paint the result effected image if the EffectType is UNDER or OVER.
*
* @return The blending mode for the effect
*/
public abstract BlendingMode getBlendingMode();
/**
* Get the opacity to use to paint the result effected image if the EffectType is UNDER or OVER.
*
* @return The opactity for the effect, 0.0f -> 1.0f
*/
public abstract float getOpacity();
/**
* Apply the effect to the src image generating the result . The result image may or may not contain the source
* image depending on what the effect type is.
*
* @param src The source image for applying the effect to
* @param dst The dstination image to paint effect result into. If this is null then a new image will be created
* @param w The width of the src image to apply effect to, this allow the src and dst buffers to be bigger than
* the area the need effect applied to it
* @param h The height of the src image to apply effect to, this allow the src and dst buffers to be bigger than
* the area the need effect applied to it
* @return The result of appl
*/
public abstract BufferedImage applyEffect(BufferedImage src, BufferedImage dst, int w, int h);
// =================================================================================================================
// Static data cache
private static SoftReference<int[]> tmpIntArray = null;
private static SoftReference<byte[]> tmpByteArray1 = null;
private static SoftReference<byte[]> tmpByteArray2 = null;
private static SoftReference<byte[]> tmpByteArray3 = null;
protected static int[] getTmpIntArray(int size) {
int[] tmp;
if (tmpIntArray == null || (tmp = tmpIntArray.get()) == null || tmp.length < size) {
// create new array
tmp = new int[size];
tmpIntArray = new SoftReference<int[]>(tmp);
}
return tmp;
}
protected static byte[] getTmpByteArray1(int size) {
byte[] tmp;
if (tmpByteArray1 == null || (tmp = tmpByteArray1.get()) == null || tmp.length < size) {
// create new array
tmp = new byte[size];
tmpByteArray1 = new SoftReference<byte[]>(tmp);
}
return tmp;
}
protected static byte[] getTmpByteArray2(int size) {
byte[] tmp;
if (tmpByteArray2 == null || (tmp = tmpByteArray2.get()) == null || tmp.length < size) {
// create new array
tmp = new byte[size];
tmpByteArray2 = new SoftReference<byte[]>(tmp);
}
return tmp;
}
protected static byte[] getTmpByteArray3(int size) {
byte[] tmp;
if (tmpByteArray3 == null || (tmp = tmpByteArray3.get()) == null || tmp.length < size) {
// create new array
tmp = new byte[size];
tmpByteArray3 = new SoftReference<byte[]>(tmp);
}
return tmp;
}
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer.effects;
/**
* EffectUtils
*
* @author Created by Jasper Potts (Jun 18, 2007)
*/
public class EffectUtils {
/**
* <p>Blurs the source pixels into the destination pixels. The force of the blur is specified by the radius which
* must be greater than 0.</p> <p>The source and destination pixels arrays are expected to be in the BYTE_GREY
* format.</p> <p>After this method is executed, dstPixels contains a transposed and filtered copy of
* srcPixels.</p>
*
* @param srcPixels the source pixels
* @param dstPixels the destination pixels
* @param width the width of the source picture
* @param height the height of the source picture
* @param kernel the kernel of the blur effect
* @param radius the radius of the blur effect
*/
public static void blur(byte[] srcPixels, byte[] dstPixels,
int width, int height,
float[] kernel, int radius) {
float p;
int cp;
for (int y = 0; y < height; y++) {
int index = y;
int offset = y * width;
for (int x = 0; x < width; x++) {
p = 0.0f;
for (int i = -radius; i <= radius; i++) {
int subOffset = x + i;
if (subOffset < 0 || subOffset >= width) {
subOffset = (x + width) % width;
}
int pixel = srcPixels[offset + subOffset] & 0xFF;
float blurFactor = kernel[radius + i];
p += blurFactor * pixel;
}
cp = (int) (p + 0.5f);
dstPixels[index] = (byte) (cp > 255 ? 255 : cp);
index += height;
}
}
}
public static float[] createGaussianKernel(int radius) {
if (radius < 1) {
throw new IllegalArgumentException("Radius must be >= 1");
}
float[] data = new float[radius * 2 + 1];
float sigma = radius / 3.0f;
float twoSigmaSquare = 2.0f * sigma * sigma;
float sigmaRoot = (float) Math.sqrt(twoSigmaSquare * Math.PI);
float total = 0.0f;
for (int i = -radius; i <= radius; i++) {
float distance = i * i;
int index = i + radius;
data[index] = (float) Math.exp(-distance / twoSigmaSquare) / sigmaRoot;
total += data[index];
}
for (int i = 0; i < data.length; i++) {
data[i] /= total;
}
return data;
}
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer.effects;
import java.awt.Composite;
import java.awt.CompositeContext;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
/**
* EffectUtilsTemp - effect utils methods that are not being used for now but we might want later
*
* @author Created by Jasper Potts (Jun 18, 2007)
*/
public class EffectUtilsTemp {
/**
* Extract the alpha channel of a image into new greyscale buffered image
*
* @param src Must but INT_ARGB buffered image
* @return new TYPE_BYTE_GRAY image of just the alpha channel
*/
public static BufferedImage extractAlpha(BufferedImage src) {
int w = src.getWidth();
int h = src.getHeight();
// extract image alpha channel as greyscale image
final BufferedImage greyImg = new BufferedImage(w, h, BufferedImage.TYPE_BYTE_GRAY);
Graphics2D g2 = greyImg.createGraphics();
g2.setComposite(new Composite() {
public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel,
RenderingHints hints) {
return new CompositeContext() {
public void dispose() {}
public void compose(Raster src, Raster dstIn, WritableRaster dstOut) {
int width = Math.min(src.getWidth(), dstIn.getWidth());
int height = Math.min(src.getHeight(), dstIn.getHeight());
int[] srcPixels = new int[width];
byte[] dstPixels = new byte[width];
for (int y = 0; y < height; y++) {
src.getDataElements(0, y, width, 1, srcPixels);
for (int x = 0; x < width; x++) {
dstPixels[x] = (byte) ((srcPixels[x] & 0xFF000000) >>> 24);
}
dstOut.setDataElements(0, y, width, 1, dstPixels);
}
}
};
}
});
g2.drawImage(src, 0, 0, null);
g2.dispose();
return greyImg;
}
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer.effects;
import org.jdesktop.swingx.designer.paint.Matte;
import javax.swing.UIDefaults;
import java.awt.Color;
/**
* InnerGlowEffect
*
* @author Created by Jasper Potts (Jun 21, 2007)
*/
public class InnerGlowEffect extends InnerShadowEffect {
protected InnerGlowEffect() {
distance = 0;
}
public InnerGlowEffect(UIDefaults uiDefaults) {
color = new Matte(new Color(255, 255, 211), uiDefaults);
}
/**
* Get the display name for this effect
*
* @return The user displayable name
*/
public String getDisplayName() {
return "Inner Glow";
}
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer.effects;
import org.jdesktop.swingx.designer.paint.Matte;
import javax.swing.UIDefaults;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;
import java.util.Arrays;
/**
* InnerShadowEffect
*
* @author Created by Jasper Potts (Jun 18, 2007)
*/
public class InnerShadowEffect extends ShadowEffect {
protected InnerShadowEffect() {}
;
public InnerShadowEffect(UIDefaults uiDefaults) {
color = new Matte(Color.BLACK, uiDefaults);
}
// =================================================================================================================
// Effect Methods
/**
* Get the display name for this effect
*
* @return The user displayable name
*/
public String getDisplayName() {
return "Inner Shadow";
}
/**
* Get the type of this effect, one of UNDER,BLENDED,OVER. UNDER means the result of apply effect should be painted
* under the src image. BLENDED means the result of apply sffect contains a modified src image so just it should be
* painted. OVER means the result of apply effect should be painted over the src image.
*
* @return The effect type
*/
public Effect.EffectType getEffectType() {
return Effect.EffectType.OVER;
}
/**
* Apply the effect to the src image generating the result . The result image may or may not contain the source
* image depending on what the effect type is.
*
* @param src The source image for applying the effect to
* @param dst The dstination image to paint effect result into. If this is null then a new image will be created
* @param w The width of the src image to apply effect to, this allow the src and dst buffers to be bigger than
* the area the need effect applied to it
* @param h The height of the src image to apply effect to, this allow the src and dst buffers to be bigger than
* the area the need effect applied to it
* @return The result of appl
*/
public BufferedImage applyEffect(BufferedImage src, BufferedImage dst, int w, int h) {
// calculate offset
double trangleAngle = Math.toRadians(angle - 90);
int offsetX = (int) (Math.sin(trangleAngle) * distance);
int offsetY = (int) (Math.cos(trangleAngle) * distance);
// clac expanded size
int tmpOffX = offsetX + size;
int tmpOffY = offsetY + size;
int tmpW = w + offsetX + size + size;
int tmpH = h + offsetY + size + size;
// create tmp buffers
int[] lineBuf = getTmpIntArray(w);
byte[] srcAlphaBuf = getTmpByteArray1(tmpW * tmpH);
Arrays.fill(srcAlphaBuf, (byte) 0xFF);
byte[] tmpBuf1 = getTmpByteArray2(tmpW * tmpH);
byte[] tmpBuf2 = getTmpByteArray3(tmpW * tmpH);
// extract src image alpha channel and inverse and offset
Raster srcRaster = src.getRaster();
for (int y = 0; y < h; y++) {
int dy = (y + tmpOffY);
int offset = dy * tmpW;
srcRaster.getDataElements(0, y, w, 1, lineBuf);
for (int x = 0; x < w; x++) {
int dx = x + tmpOffX;
srcAlphaBuf[offset + dx] = (byte) ((255 - ((lineBuf[x] & 0xFF000000) >>> 24)) & 0xFF);
}
}
// blur
float[] kernel = EffectUtils.createGaussianKernel(size * 2);
EffectUtils.blur(srcAlphaBuf, tmpBuf2, tmpW, tmpH, kernel, size * 2); // horizontal pass
EffectUtils.blur(tmpBuf2, tmpBuf1, tmpH, tmpW, kernel, size * 2);// vertical pass
//rescale
float spread = Math.min(1 / (1 - (0.01f * this.spread)), 255);
for (int i = 0; i < tmpBuf1.length; i++) {
int val = (int) (((int) tmpBuf1[i] & 0xFF) * spread);
tmpBuf1[i] = (val > 255) ? (byte) 0xFF : (byte) val;
}
// create color image with shadow color and greyscale image as alpha
if (dst == null) dst = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
WritableRaster shadowRaster = dst.getRaster();
int red = color.getRed(), green = color.getGreen(), blue = color.getBlue();
for (int y = 0; y < h; y++) {
int srcY = y + tmpOffY;
int offset = srcY * tmpW;
int shadowOffset = (srcY - offsetY) * tmpW;
for (int x = 0; x < w; x++) {
int srcX = x + tmpOffX;
int origianlAlphaVal = 255 - ((int) srcAlphaBuf[offset + srcX] & 0xFF);
int shadowVal = (int) tmpBuf1[shadowOffset + (srcX - offsetX)] & 0xFF;
int alphaVal = Math.min(origianlAlphaVal, shadowVal);
lineBuf[x] = ((byte) alphaVal & 0xFF) << 24 | red << 16 | green << 8 | blue;
}
shadowRaster.setDataElements(0, y, w, 1, lineBuf);
}
return dst;
}
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer.effects;
import org.jdesktop.swingx.designer.paint.Matte;
import javax.swing.UIDefaults;
import java.awt.Color;
/**
* OuterGlowEffect
*
* @author Created by Jasper Potts (Jun 21, 2007)
*/
public class OuterGlowEffect extends DropShadowEffect {
protected OuterGlowEffect() {
distance = 0;
}
public OuterGlowEffect(UIDefaults uiDefaults) {
color = new Matte(new Color(255, 255, 211), uiDefaults);
}
/**
* Get the display name for this effect
*
* @return The user displayable name
*/
public String getDisplayName() {
return "Outer Glow";
}
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer.effects;
import org.jdesktop.swingx.designer.BlendingMode;
import org.jdesktop.swingx.designer.paint.Matte;
import javax.swing.UIDefaults;
import java.awt.Color;
/**
* ShadowEffect - base class with all the standard properties for shadow effects
*
* @author Created by Jasper Potts (Jun 18, 2007)
*/
public abstract class ShadowEffect extends Effect {
protected Matte color;
protected BlendingMode blendingMode = BlendingMode.NORMAL;
/** Opacity a float 0-1 for percentage */
protected float opacity = 0.75f;
/** Angle in degrees between 0-360 */
protected int angle = 135;
/** Distance in pixels */
protected int distance = 5;
/** The shadow spread between 0-100 % */
protected int spread = 0;
/** Size in pixels */
protected int size = 5;
protected ShadowEffect() {}
;
public ShadowEffect(UIDefaults uiDefaults) {
color = new Matte(Color.BLACK, uiDefaults);
}
// =================================================================================================================
// Bean methods
public Matte getColor() {
return color;
}
public void setColor(Matte color) {
Matte old = getColor();
this.color = color;
firePropertyChange("color", old, getColor());
}
public BlendingMode getBlendingMode() {
return blendingMode;
}
public void setBlendingMode(BlendingMode blendingMode) {
BlendingMode old = getBlendingMode();
this.blendingMode = blendingMode;
firePropertyChange("blendingMode", old, getBlendingMode());
}
public float getOpacity() {
return opacity;
}
public void setOpacity(float opacity) {
float old = getOpacity();
this.opacity = opacity;
firePropertyChange("opacity", old, getOpacity());
}
public int getAngle() {
return angle;
}
public void setAngle(int angle) {
int old = getAngle();
this.angle = angle;
firePropertyChange("angle", old, getAngle());
}
public int getDistance() {
return distance;
}
public void setDistance(int distance) {
int old = getDistance();
this.distance = distance;
firePropertyChange("distance", old, getDistance());
}
public int getSpread() {
return spread;
}
public void setSpread(int spread) {
int old = getSpread();
this.spread = spread;
firePropertyChange("spread", old, getSpread());
}
public int getSize() {
return size;
}
public void setSize(int size) {
int old = getSize();
this.size = size;
firePropertyChange("size", old, getSize());
}
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer.font;
import java.awt.Font;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import javax.swing.UIDefaults;
import org.jdesktop.beans.AbstractBean;
import org.jdesktop.swingx.designer.utils.HasUIDefaults;
import org.jibx.runtime.IUnmarshallingContext;
/**
* I don't think the name is technically correct (ie: a typeface is not a font),
* but I wanted something besides "font" so, here it is.
*
* This is a mutable font, much like Matte is a mutable color. Also like Matte,
* Typeface can be derived.
*
* @author rbair
*/
public class Typeface extends AbstractBean {
//specifies whether to derive bold, or italic.
//Default means, get my value from my parent.
//Off means, leave bold/italic off.
//On means, make bold/italic on.
public enum DeriveStyle { Default, Off, On }
private String uiDefaultParentName;
/** This is a local UIDefaults that contains all the UIDefaults in the Model. */
private transient UIDefaults uiDefaults = new UIDefaults();
private PropertyChangeListener uiDefaultsChangeListener = new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
if (uiDefaultParentName != null && uiDefaultParentName.equals(evt.getPropertyName())) {
updateFontFromOffsets();
}
}
};
/**
* The name of the font. If uiDefaultParentName is specified, then this name
* will be set to be equal to the name of the parent font.
*/
private String name;
/**
* The size of the font. If uiDefaultParentName is set, then this value is
* updated to reflect the size of the parent font * the sizeOffset.
*/
private int size;
//this field is not publically accessible. Rather, it is updated based on
//"bold" and "italic" as necessary.
private int style = Font.PLAIN;
private DeriveStyle bold = DeriveStyle.Default;
private DeriveStyle italic = DeriveStyle.Default;
/**
* The size offset. Only used if uiDefaultParentName is specified. This offset
* will be multiplied with the parent font's size to determine the size of this
* typeface. The offset is specified as a percentage, either positive or negative.
*
* The reason a percentage was used, was so that things would look correctly
* when scaled, such as with high DPI situations.
*/
private float sizeOffset;
/**
* Create a new Typeface. Note that, without specifying the uiDefaults,
* you cannot have font derivation. Thus, this constructor should never
* be called, except for the XML binding stuff.
*/
public Typeface() { }
/**
* Creates a new Typeface.
*
* @param f The font from which to get the font name, size, and style to use
* to initialize this typeface. Note that this font is not used as a parent
* font for derivation purposes. Rather, it is used as a source from which to
* copy initial settings.
*
* @param uiDefaults The uiDefaults to use for font derivation purposes.
* When the uiDefaultParentName is specified, then this Typeface will inspect
* the given UIDefaults for that parent <em>font</em>. Note that the UIDefaults
* should be populated with a font, and not with a typeface.
*/
public Typeface(Font f, UIDefaults uiDefaults) {
if (f != null) {
this.name = f.getName();
this.size = f.getSize();
this.style = f.getStyle();
}
setUiDefaults(uiDefaults);
}
// =================================================================================================================
// JIBX Methods
/**
* Called by JIBX after all fields have been set
*
* @param context The JIBX Unmarshalling Context
*/
protected void postSet(IUnmarshallingContext context) {
// walk up till we get synth model
for (int i = 0; i < context.getStackDepth(); i++) {
if (context.getStackObject(i) instanceof HasUIDefaults) {
UIDefaults uiDefaults = ((HasUIDefaults) context.getStackObject(i)).getUiDefaults();
if (uiDefaults != null) {
setUiDefaults(uiDefaults);
break;
}
}
}
}
// =================================================================================================================
// Typeface methods
/**
* Is the Typeface an absolute Font not derived from a parent ui default
*
* @return <code>true</code> if this is a absolute not uidefault derived font
*/
public boolean isAbsolute() {
return uiDefaultParentName == null;
}
/**
* Set all properties of this Typeface to be the same as <code>src</code> and fire all the change events
*
* @param src the Typeface to copy properties from
*/
public void copy(Typeface src) {
// keep old values
Font oldFont = getFont();
String oldParentName = uiDefaultParentName;
String oldName = name;
int oldSize = size;
float oldSizeOffset = sizeOffset;
DeriveStyle oldBold = bold, oldItalic = italic;
style = src.style;
//Note, I don't just call the setters here, because I want to make
//sure the "font" PCE is only fired once, at the end.
name = src.name;
firePropertyChange("name", oldName, name);
size = src.size;
firePropertyChange("size", oldSize, size);
bold = src.bold;
firePropertyChange("bold", oldBold, bold);
italic = src.italic;
firePropertyChange("italic", oldItalic, italic);
sizeOffset = src.sizeOffset;
firePropertyChange("sizeOffset", oldSizeOffset, sizeOffset);
uiDefaultParentName = src.uiDefaultParentName;
firePropertyChange("uiDefaultParentName", oldParentName, uiDefaultParentName);
setUiDefaults(src.uiDefaults);
firePropertyChange("font", oldFont, getFont());
}
// =================================================================================================================
// Bean Methods
/**
* Get the local UIDefaults that contains all the UIDefaults in the Model.
*
* @return The UIDefaults for the model that contains this Typeface, can be null if this Typeface is not part of a bigger
* model
*/
public UIDefaults getUiDefaults() {
return uiDefaults;
}
/**
* Set the local UIDefaults that contains all the UIDefaults in the Model.
*
* @param uiDefaults The UIDefaults for the model that contains this Typeface, can be null if this Typeface is not part of
* a bigger model
*/
public void setUiDefaults(UIDefaults uiDefaults) {
if (uiDefaults != this.uiDefaults) {
UIDefaults old = getUiDefaults();
if (old != null) old.removePropertyChangeListener(uiDefaultsChangeListener);
this.uiDefaults = uiDefaults;
if (uiDefaults != null) this.uiDefaults.addPropertyChangeListener(uiDefaultsChangeListener);
firePropertyChange("uiDefaults", old, getUiDefaults());
}
}
/**
* Get the name if the uidefault font that is the parent that this Typeface is derived from. If null then this is a
* absolute font.
*
* @return Parent font ui default name
*/
public String getUiDefaultParentName() {
return uiDefaultParentName;
}
/**
* Set the name if the uidefault font that is the parent that this Typeface is derived from. If null then this is a
* absolute font.
*
* @param uiDefaultParentName Parent font ui default name
*/
public void setUiDefaultParentName(String uiDefaultParentName) {
String old = getUiDefaultParentName();
this.uiDefaultParentName = uiDefaultParentName;
firePropertyChange("uiDefaultParentName", old, getUiDefaultParentName());
if (isAbsolute()) {
// reset offsets
float oldSizeOffset = sizeOffset;
sizeOffset = 0;
firePropertyChange("sizeOffset", oldSizeOffset, sizeOffset);
} else {
updateFontFromOffsets();
}
}
/**
* @return Gets the name of the font
*/
public final String getName() {
return name;
}
/**
* Sets the name of the font. This method call <em>only</em> works if
* <code>isAbsolute</code> returns true. Otherwise, it is ignored.
* @param name the name of the font
*/
public void setName(String name) {
if (isAbsolute()) {
String old = this.name;
Font oldF = getFont();
this.name = name;
firePropertyChange("name", old, this.name);
firePropertyChange("font", oldF, getFont());
}
}
/**
* @return gets the size of the font.
*/
public final int getSize() {
return size;
}
/**
* <p>Sets the size of the font. THis method call will work whether
* <code>isAbsolute</code> returns true or false. If this is an absolute
* typeface, then the size is set directly. Otherwise, if this is a
* derived typeface, then the sizeOffset will be updated to reflect the
* proper offset based on this size, and the size of the parent font.</p>
*
* <p>For example, if the parent font's size was 12, and the sizeOffset was
* -2 (thus yielding as size on this typeface of 10), and you call setSize
* passing in "14" as the size, then the sizeOffset will be updated to be
* equal to "2".</p>
*
* @param size the new size for this typeface.
*/
public void setSize(int size) {
int old = this.size;
Font oldF = getFont();
this.size = size;
firePropertyChange("size", old, this.size);
firePropertyChange("font", oldF, getFont());
updateOffsetsFromFont();
}
/**
* @return the size offset
*/
public final float getSizeOffset() {
return sizeOffset;
}
/**
* Sets the percentage by which the size of this font should be different
* from its parent font. This property is kept in synch with the size property.
*
* @param sizeOffset the size offset. May be any float. The value "1" means,
* 100%. -1 means "-100%". 2 means "200%", and so on.
*/
public void setSizeOffset(float sizeOffset) {
float old = this.sizeOffset;
Font oldF = getFont();
this.sizeOffset = sizeOffset;
firePropertyChange("sizeOffset", old, this.sizeOffset);
firePropertyChange("font", oldF, getFont());
updateFontFromOffsets();
}
public DeriveStyle getBold() {
return bold;
}
public void setBold(DeriveStyle bold) {
DeriveStyle old = this.bold;
this.bold = bold == null ? DeriveStyle.Default : bold;
firePropertyChange("bold", old, this.bold);
updateFontFromOffsets();
}
public DeriveStyle getItalic() {
return italic;
}
public void setItalic(DeriveStyle italic) {
DeriveStyle old = this.italic;
this.italic = italic == null ? DeriveStyle.Default : italic;
firePropertyChange("italic", old, this.italic);
updateFontFromOffsets();
}
/**
* @return whether or not the font represented by this typeface is supported
* on this operating system platform.
*/
public boolean isFontSupported() {
return true;//Font.getFont(name) != null;
}
/**
* @return Gets the font associated with this Typeface. If font derivation is
* being used, then the Font returned is the result of that derivation.
*/
public Font getFont() {
return new Font(name, style, size);
}
/**
* Sets the font from which this Typeface should extract the font name, style,
* and size. If font derivation is being used, then the font name will be ignored,
* the style will be used (and always override the parent font), and the size
* will be set and the sizeOffset updated appropriately.
*
* @param f the Font
*/
public void setFont(Font f) {
Font oldFont = getFont();
String oldName = name;
int oldSize = size;
DeriveStyle oldBold = bold, oldItalic = italic;
name = f.getName();
size = f.getSize();
style = f.getStyle();
updateOffsetsFromFont();
firePropertyChange("name", oldName, name);
firePropertyChange("size", oldSize, size);
firePropertyChange("bold", oldBold, bold);
firePropertyChange("italic", oldItalic, italic);
firePropertyChange("font", oldFont, getFont());
}
/**
* @inheritDoc
*
* @return A formatted string representing this Typeface. This String should
* not be considered public API, as it may change in a future release.
*/
@Override public String toString() {
Font f = getFont();
String strStyle;
if (f.isBold()) {
strStyle = f.isItalic() ? "bolditalic" : "bold";
} else {
strStyle = f.isItalic() ? "italic" : "plain";
}
if (isAbsolute()) {
return Typeface.class.getName() + "[name=" + name + ", size=" + size + ", style=" + strStyle + "]";
} else {
return Typeface.class.getName() + "[base=" + uiDefaultParentName +
", name=" + name + ", size=" + size + "(offset " + sizeOffset + ")" +
", style=" + strStyle + "]";
}
}
@Override public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Typeface typeface = (Typeface) o;
if (!typeface.name.equals(name)) return false;
if (size != typeface.size) return false;
if (bold != typeface.bold) return false;
if (italic != typeface.italic) return false;
if (sizeOffset != typeface.sizeOffset) return false;
if (uiDefaultParentName != null ? !uiDefaultParentName.equals(typeface.uiDefaultParentName) :
typeface.uiDefaultParentName != null) return false;
return true;
}
@Override public int hashCode() {
int result;
result = name.hashCode();
result = 31 * result + size;
result = 31 * result + bold.ordinal();
result = 31 * result + italic.ordinal();
result = 31 * result + (int)(sizeOffset*100);
result = 31 * result + (uiDefaultParentName != null ? uiDefaultParentName.hashCode() : 0);
return result;
}
@Override public Typeface clone() {
Typeface clone = new Typeface();
clone.name = name;
clone.size = size;
clone.style = style;
clone.bold = bold;
clone.italic = italic;
clone.sizeOffset = sizeOffset;
clone.uiDefaultParentName = uiDefaultParentName;
clone.setUiDefaults(uiDefaults);
return clone;
}
// =================================================================================================================
// Private Helper Methods
private void updateOffsetsFromFont() {
if (!isAbsolute()) {
float oldSizeOffset = sizeOffset;
Font parentFont = uiDefaults.getFont(uiDefaultParentName);
if (parentFont != null) {
float s = size;
float p = parentFont.getSize();
sizeOffset = (s/p) - 1f;
firePropertyChange("sizeOffset", oldSizeOffset, sizeOffset);
}
}
}
private void updateFontFromOffsets() {
if (!isAbsolute()) {
Font oldFont = getFont();
// get parent font data
Font parentFont = uiDefaults.getFont(uiDefaultParentName);
if (parentFont != null) {
String oldName = name;
int oldSize = size;
name = parentFont.getName();
size = Math.round(parentFont.getSize() * (1f + sizeOffset));
boolean isBold = (bold == DeriveStyle.Default && parentFont.isBold()) || bold == DeriveStyle.On;
boolean isItalic = (italic == DeriveStyle.Default && parentFont.isItalic()) || italic == DeriveStyle.On;
style = Font.PLAIN;
if (isBold) style = style | Font.BOLD;
if (isItalic) style = style | Font.ITALIC;
// update fire events
firePropertyChange("name", oldName, name);
firePropertyChange("size", oldSize, size);
firePropertyChange("font", oldFont, getFont());
}
}
}
}
/*
* Copyright 2002-2007 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package org.jdesktop.swingx.designer.jibxhelpers;
import org.jibx.runtime.IMarshaller;
import org.jibx.runtime.IMarshallingContext;
import org.jibx.runtime.IUnmarshaller;
import org.jibx.runtime.IUnmarshallingContext;
import org.jibx.runtime.JiBXException;
import org.jibx.runtime.impl.MarshallingContext;
import org.jibx.runtime.impl.UnmarshallingContext;
import java.awt.Color;
/**
* ColorMapper
*
* @author Created by Jasper Potts (Jun 8, 2007)
*/
public class ColorMapper implements IMarshaller, IUnmarshaller {
private static final String ELEMENT_NAME = "color";
private static final String RED_NAME = "red";
private static final String GREEN_NAME = "green";
private static final String BLUE_NAME = "blue";
private static final String ALPHA_NAME = "alpha";
public boolean isExtension(int i) {
return false;
}
public boolean isPresent(IUnmarshallingContext iUnmarshallingContext) throws JiBXException {
return iUnmarshallingContext.isAt(null, ELEMENT_NAME);
}
public void marshal(Object object, IMarshallingContext iMarshallingContext) throws JiBXException {
if (!(object instanceof Color)) {
throw new JiBXException("Invalid object type for marshaller");
} else if (!(iMarshallingContext instanceof MarshallingContext)) {
throw new JiBXException("Invalid object type for marshaller");
} else {
MarshallingContext ctx = (MarshallingContext) iMarshallingContext;
Color color = (Color) object;
ctx.startTagAttributes(0, ELEMENT_NAME).
attribute(0, RED_NAME, color.getRed()).
attribute(0, GREEN_NAME, color.getGreen()).
attribute(0, BLUE_NAME, color.getBlue()).
attribute(0, ALPHA_NAME, color.getAlpha()).
closeStartEmpty();
}
}
public Object unmarshal(Object object, IUnmarshallingContext iUnmarshallingContext) throws JiBXException {
// make sure we're at the appropriate start tag
UnmarshallingContext ctx = (UnmarshallingContext) iUnmarshallingContext;
if (!ctx.isAt(null, ELEMENT_NAME)) {
ctx.throwStartTagNameError(null, ELEMENT_NAME);
}
// get values
int red = ctx.attributeInt(null, RED_NAME, 0);
int green = ctx.attributeInt(null, GREEN_NAME, 0);
int blue = ctx.attributeInt(null, BLUE_NAME, 0);
int alpha = ctx.attributeInt(null, ALPHA_NAME, 0);
ctx.parsePastEndTag(null, ELEMENT_NAME);
// create
return new Color(red, green, blue, alpha);
}
}
此差异已折叠。
......@@ -1009,6 +1009,7 @@ public class WindowsLookAndFeel extends BasicLookAndFeel
"PopupMenu.background", MenuBackgroundColor,
"PopupMenu.foreground", MenuTextColor,
"PopupMenu.popupSound", "win.sound.menuPopup",
"PopupMenu.consumeEventOnClose", Boolean.TRUE,
// Menus
"Menu.font", MenuFont,
......
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册