@ -0,0 +1,9 @@ |
|||||||
|
<component name="CopyrightManager"> |
||||||
|
<copyright> |
||||||
|
<option name="notice" value="Copyright 2000-&#36;today.year JetBrains s.r.o. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License." /> |
||||||
|
<option name="keyword" value="Copyright" /> |
||||||
|
<option name="allowReplaceKeyword" value="" /> |
||||||
|
<option name="myName" value="JetBrains" /> |
||||||
|
<option name="myLocal" value="true" /> |
||||||
|
</copyright> |
||||||
|
</component> |
@ -1,3 +1,7 @@ |
|||||||
<component name="CopyrightManager"> |
<component name="CopyrightManager"> |
||||||
<settings default="" /> |
<settings default=""> |
||||||
|
<module2copyright> |
||||||
|
<element module="Darcula" copyright="JetBrains" /> |
||||||
|
</module2copyright> |
||||||
|
</settings> |
||||||
</component> |
</component> |
@ -0,0 +1,7 @@ |
|||||||
|
<?xml version="1.0" encoding="UTF-8"?> |
||||||
|
<project version="4"> |
||||||
|
<component name="SharedFileColors"> |
||||||
|
<fileColor scope="Demos" color="Blue" /> |
||||||
|
</component> |
||||||
|
</project> |
||||||
|
|
@ -0,0 +1,13 @@ |
|||||||
|
<component name="libraryTable"> |
||||||
|
<library name="SwingSet3 Libraries"> |
||||||
|
<CLASSES> |
||||||
|
<root url="jar://$PROJECT_DIR$/lib/demo/AnimatedTransitions.jar!/" /> |
||||||
|
<root url="jar://$PROJECT_DIR$/lib/demo/AppFramework.jar!/" /> |
||||||
|
<root url="jar://$PROJECT_DIR$/lib/demo/swing-worker.jar!/" /> |
||||||
|
<root url="jar://$PROJECT_DIR$/lib/demo/swingx.jar!/" /> |
||||||
|
<root url="jar://$PROJECT_DIR$/lib/demo/TimingFramework.jar!/" /> |
||||||
|
</CLASSES> |
||||||
|
<JAVADOC /> |
||||||
|
<SOURCES /> |
||||||
|
</library> |
||||||
|
</component> |
@ -0,0 +1,3 @@ |
|||||||
|
<component name="DependencyValidationManager"> |
||||||
|
<scope name="Darcula" pattern="file:src//*" /> |
||||||
|
</component> |
@ -0,0 +1,3 @@ |
|||||||
|
<component name="DependencyValidationManager"> |
||||||
|
<scope name="Demos" pattern="file:swingset2//*||file:swingset3//*" /> |
||||||
|
</component> |
@ -0,0 +1,98 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2000-2014 JetBrains s.r.o. |
||||||
|
* |
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||||
|
* you may not use this file except in compliance with the License. |
||||||
|
* You may obtain a copy of the License at |
||||||
|
* |
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
* |
||||||
|
* Unless required by applicable law or agreed to in writing, software |
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||||
|
* See the License for the specific language governing permissions and |
||||||
|
* limitations under the License. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.bulenkov.darcula; |
||||||
|
|
||||||
|
import javax.swing.plaf.ColorUIResource; |
||||||
|
import javax.swing.plaf.metal.DefaultMetalTheme; |
||||||
|
import java.awt.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Konstantin Bulenkov |
||||||
|
*/ |
||||||
|
public class DarculaMetalTheme extends DefaultMetalTheme { |
||||||
|
private final ColorUIResource myControlHighlightColor = new ColorUIResource(108, 111, 113); |
||||||
|
private final ColorUIResource myControlDarkShadowColor = new ColorUIResource(39, 42, 44); |
||||||
|
private final ColorUIResource myControlColor = new ColorUIResource(0x3c3f41); |
||||||
|
private static final ColorUIResource white = new ColorUIResource(255, 255, 255); |
||||||
|
private static final ColorUIResource darkBlue = new ColorUIResource(82, 108, 164); |
||||||
|
private static final ColorUIResource lightGray = new ColorUIResource(214, 214, 214); |
||||||
|
private final ColorUIResource mySeparatorForeground = new ColorUIResource(53, 56, 58); |
||||||
|
|
||||||
|
public static final ColorUIResource primary1 = new ColorUIResource(53, 56, 58); |
||||||
|
private static final ColorUIResource primary2 = new ColorUIResource(91, 135, 206); |
||||||
|
private static final ColorUIResource primary3 = new ColorUIResource(166, 202, 240); |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public String getName() { |
||||||
|
return "Darcula theme"; |
||||||
|
} |
||||||
|
|
||||||
|
public ColorUIResource getControl() { |
||||||
|
return myControlColor; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ColorUIResource getControlHighlight() { |
||||||
|
return myControlHighlightColor; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public ColorUIResource getControlDarkShadow() { |
||||||
|
return myControlDarkShadowColor; |
||||||
|
} |
||||||
|
|
||||||
|
public ColorUIResource getSeparatorBackground() { |
||||||
|
return getControl(); |
||||||
|
} |
||||||
|
|
||||||
|
public ColorUIResource getSeparatorForeground() { |
||||||
|
return mySeparatorForeground; |
||||||
|
} |
||||||
|
|
||||||
|
public ColorUIResource getMenuBackground() { |
||||||
|
return lightGray; |
||||||
|
} |
||||||
|
|
||||||
|
public ColorUIResource getMenuSelectedBackground() { |
||||||
|
return darkBlue; |
||||||
|
} |
||||||
|
|
||||||
|
public ColorUIResource getMenuSelectedForeground() { |
||||||
|
return white; |
||||||
|
} |
||||||
|
|
||||||
|
public ColorUIResource getAcceleratorSelectedForeground() { |
||||||
|
return white; |
||||||
|
} |
||||||
|
|
||||||
|
public ColorUIResource getFocusColor() { |
||||||
|
return new ColorUIResource(Color.black); |
||||||
|
} |
||||||
|
|
||||||
|
protected ColorUIResource getPrimary1() { |
||||||
|
return primary1; |
||||||
|
} |
||||||
|
|
||||||
|
protected ColorUIResource getPrimary2() { |
||||||
|
return primary2; |
||||||
|
} |
||||||
|
|
||||||
|
protected ColorUIResource getPrimary3() { |
||||||
|
return primary3; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,22 @@ |
|||||||
|
com.sun.swingset3.demos.frame.FrameDemo |
||||||
|
com.sun.swingset3.demos.dialog.DialogDemo |
||||||
|
com.sun.swingset3.demos.window.WindowDemo |
||||||
|
com.sun.swingset3.demos.internalframe.InternalFrameDemo |
||||||
|
com.sun.swingset3.demos.tabbedpane.TabbedPaneDemo |
||||||
|
com.sun.swingset3.demos.scrollpane.ScrollPaneDemo |
||||||
|
com.sun.swingset3.demos.splitpane.SplitPaneDemo |
||||||
|
com.sun.swingset3.demos.gridbaglayout.GridBagLayoutDemo |
||||||
|
com.sun.swingset3.demos.table.TableDemo |
||||||
|
com.sun.swingset3.demos.tree.TreeDemo |
||||||
|
com.sun.swingset3.demos.list.ListDemo |
||||||
|
com.sun.swingset3.demos.togglebutton.ToggleButtonDemo |
||||||
|
com.sun.swingset3.demos.button.ButtonDemo |
||||||
|
com.sun.swingset3.demos.combobox.ComboBoxDemo |
||||||
|
com.sun.swingset3.demos.progressbar.ProgressBarDemo |
||||||
|
com.sun.swingset3.demos.slider.SliderDemo |
||||||
|
com.sun.swingset3.demos.spinner.SpinnerDemo |
||||||
|
com.sun.swingset3.demos.textfield.TextFieldDemo |
||||||
|
com.sun.swingset3.demos.editorpane.EditorPaneDemo |
||||||
|
com.sun.swingset3.demos.colorchooser.ColorChooserDemo |
||||||
|
com.sun.swingset3.demos.optionpane.OptionPaneDemo |
||||||
|
com.sun.swingset3.demos.tooltip.ToolTipDemo |
@ -0,0 +1,57 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
|
||||||
|
package com.sun.swingset3; |
||||||
|
|
||||||
|
import java.awt.image.BufferedImage; |
||||||
|
import javax.imageio.ImageIO; |
||||||
|
import javax.swing.JPanel; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author Amy Fowler |
||||||
|
*/ |
||||||
|
public class AboutBox extends JPanel { |
||||||
|
private BufferedImage bgImage; |
||||||
|
|
||||||
|
public AboutBox() { |
||||||
|
try { |
||||||
|
bgImage = ImageIO.read(AboutBox.class.getResource("resources/images/about.jpg")); |
||||||
|
} catch (Exception ex) { |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,350 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.sun.swingset3; |
||||||
|
|
||||||
|
import java.awt.Component; |
||||||
|
import java.beans.PropertyChangeListener; |
||||||
|
import java.beans.PropertyChangeSupport; |
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.net.URL; |
||||||
|
import java.util.*; |
||||||
|
import java.util.logging.Level; |
||||||
|
import javax.swing.Icon; |
||||||
|
import javax.swing.ImageIcon; |
||||||
|
|
||||||
|
/** |
||||||
|
* Wrapper class which encapsulates a GUI component to be displayed |
||||||
|
* as a SwingSet3 demo. |
||||||
|
* @author Amy Fowler |
||||||
|
*/ |
||||||
|
public class Demo { |
||||||
|
|
||||||
|
public enum State { UNINITIALIZED, INITIALIZING, INITIALIZED, RUNNING, STOPPED, FAILED } |
||||||
|
|
||||||
|
private static final String IMAGE_EXTENSIONS[] = {".gif", ".png", ".jpg"}; |
||||||
|
|
||||||
|
public static String deriveCategoryFromPackageName(String className) { |
||||||
|
String parts[] = className.split("\\."); |
||||||
|
// return the right-most package name
|
||||||
|
return parts.length >= 2? parts[parts.length-2] : "general"; |
||||||
|
} |
||||||
|
|
||||||
|
public static String deriveCategoryFromPackageName(Class demoClass) { |
||||||
|
String packageName = demoClass.getPackage() != null? |
||||||
|
demoClass.getPackage().getName() : null; |
||||||
|
if (packageName != null) { |
||||||
|
// if root package is swingset3, then remove it
|
||||||
|
String swingsetPackageName = Demo.class.getPackage().getName(); |
||||||
|
if (packageName.startsWith(swingsetPackageName + ".demos.")) { |
||||||
|
packageName = packageName.replaceFirst(swingsetPackageName + ".demos.", |
||||||
|
""); |
||||||
|
} |
||||||
|
} |
||||||
|
return packageName != null? packageName : "general"; |
||||||
|
} |
||||||
|
|
||||||
|
public static String deriveNameFromClassName(String className) { |
||||||
|
String simpleName = className.substring(className.lastIndexOf(".")+1, className.length()); |
||||||
|
return convertToDemoName(simpleName); |
||||||
|
} |
||||||
|
|
||||||
|
public static String deriveNameFromClassName(Class demoClass) { |
||||||
|
String className = demoClass.getSimpleName(); |
||||||
|
return convertToDemoName(className); |
||||||
|
} |
||||||
|
|
||||||
|
private static String convertToDemoName(String simpleClassName) { |
||||||
|
StringBuffer nameBuffer = new StringBuffer(); |
||||||
|
if (simpleClassName.endsWith("Demo")) { |
||||||
|
nameBuffer.append(simpleClassName.substring(0, simpleClassName.indexOf("Demo"))); |
||||||
|
nameBuffer.append(" "); |
||||||
|
nameBuffer.append("Demo"); |
||||||
|
} |
||||||
|
return nameBuffer.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
private Class<?> demoClass; |
||||||
|
private String name; |
||||||
|
private String category; |
||||||
|
private String shortDescription; // used for tooltips
|
||||||
|
private String iconPath; |
||||||
|
private Icon icon; |
||||||
|
private String[] sourceFilePaths; |
||||||
|
private URL[] sourceFiles; |
||||||
|
|
||||||
|
private Component component; |
||||||
|
|
||||||
|
private State state; |
||||||
|
|
||||||
|
private Exception failException; |
||||||
|
|
||||||
|
private PropertyChangeSupport pcs; |
||||||
|
|
||||||
|
public Demo(Class<?> demoClass) { |
||||||
|
this.demoClass = demoClass; |
||||||
|
|
||||||
|
initializeProperties(); |
||||||
|
} |
||||||
|
|
||||||
|
protected void initializeProperties() { |
||||||
|
|
||||||
|
// First look for DemoProperties annotation if it exists
|
||||||
|
DemoProperties properties = demoClass.getAnnotation(DemoProperties.class); |
||||||
|
if (properties != null) { |
||||||
|
this.name = properties.value(); |
||||||
|
this.category = properties.category(); |
||||||
|
this.shortDescription = properties.description(); |
||||||
|
this.iconPath = properties.iconFile(); |
||||||
|
this.sourceFilePaths = properties.sourceFiles(); |
||||||
|
} else { |
||||||
|
this.name = deriveNameFromClassName(demoClass); |
||||||
|
this.category = deriveCategoryFromPackageName(demoClass); |
||||||
|
this.shortDescription = "No demo description, run it to find out..."; |
||||||
|
} |
||||||
|
state = State.UNINITIALIZED; |
||||||
|
pcs = new PropertyChangeSupport(this); |
||||||
|
} |
||||||
|
|
||||||
|
public Class getDemoClass() { |
||||||
|
return demoClass; |
||||||
|
} |
||||||
|
|
||||||
|
public String getName() { |
||||||
|
return name; |
||||||
|
} |
||||||
|
|
||||||
|
public String getCategory() { |
||||||
|
return category; |
||||||
|
} |
||||||
|
|
||||||
|
public Icon getIcon() { |
||||||
|
if (icon == null) { |
||||||
|
if (iconPath != null && !iconPath.equals("")) { |
||||||
|
// icon packageName was specified in DemoProperties annotation
|
||||||
|
icon = getIconFromPath(iconPath); |
||||||
|
} else { |
||||||
|
// Look for icon with same name as demo class
|
||||||
|
for(String ext : IMAGE_EXTENSIONS) { |
||||||
|
icon = getIconFromPath(getIconImagePath(ext)); |
||||||
|
if (icon != null) { |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return icon; |
||||||
|
} |
||||||
|
|
||||||
|
protected String getIconImagePath(String extension) { |
||||||
|
// by default look for an image with the same name as the demo class
|
||||||
|
return "resources/images/" + |
||||||
|
demoClass.getSimpleName() + extension; |
||||||
|
} |
||||||
|
|
||||||
|
private Icon getIconFromPath(String path) { |
||||||
|
Icon icon = null; |
||||||
|
URL imageURL = demoClass.getResource(path); |
||||||
|
if (imageURL != null) { |
||||||
|
icon = new ImageIcon(imageURL); |
||||||
|
} |
||||||
|
return icon; |
||||||
|
} |
||||||
|
|
||||||
|
public String getShortDescription() { |
||||||
|
return shortDescription; |
||||||
|
} |
||||||
|
|
||||||
|
public URL getHTMLDescription() { |
||||||
|
// by default look for an html file with the same name as the demo class
|
||||||
|
return demoClass.getResource("resources/" + |
||||||
|
demoClass.getSimpleName() + ".html"); |
||||||
|
} |
||||||
|
|
||||||
|
public URL[] getSourceFiles() { |
||||||
|
// If not already cached, then look them up
|
||||||
|
if (sourceFiles == null) { |
||||||
|
ArrayList<URL> pathURLs = new ArrayList<URL>(); |
||||||
|
|
||||||
|
// Get any names registered in DemoProperties meta-data.
|
||||||
|
// If meta-data is not specified then sourceFilePaths contains
|
||||||
|
// one empty string. In this case we skip it.
|
||||||
|
if (!(sourceFilePaths.length == 1 && sourceFilePaths[0].length() == 0)) { |
||||||
|
for (String path : sourceFilePaths) { |
||||||
|
URL url = getClass().getClassLoader().getResource(path); |
||||||
|
if (url == null) { |
||||||
|
SwingSet3.logger.log(Level.WARNING, |
||||||
|
"unable to load source file '" + path + "'"); |
||||||
|
} else { |
||||||
|
pathURLs.add(url); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
this.sourceFiles = pathURLs.toArray(new URL[pathURLs.size()]); |
||||||
|
} |
||||||
|
|
||||||
|
return sourceFiles; |
||||||
|
} |
||||||
|
|
||||||
|
void startInitializing() { |
||||||
|
setState(Demo.State.INITIALIZING); |
||||||
|
} |
||||||
|
|
||||||
|
void setDemoComponent(Component component) { |
||||||
|
if (component != null && !demoClass.isInstance(component)) { |
||||||
|
setState(State.FAILED); |
||||||
|
IllegalArgumentException e = |
||||||
|
new IllegalArgumentException("component must be an instance of " + |
||||||
|
demoClass.getCanonicalName()); |
||||||
|
failException = e; |
||||||
|
throw e; |
||||||
|
} |
||||||
|
Component old = this.component; |
||||||
|
this.component = component; |
||||||
|
|
||||||
|
if (component != null) { |
||||||
|
init(); |
||||||
|
} else { |
||||||
|
setState(State.UNINITIALIZED); |
||||||
|
} |
||||||
|
pcs.firePropertyChange("demoComponent", old, component); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public Component createDemoComponent() { |
||||||
|
Component component = null; |
||||||
|
try { |
||||||
|
component = (Component)demoClass.newInstance(); |
||||||
|
setDemoComponent(component); |
||||||
|
} catch (Exception e) { |
||||||
|
System.err.println(e); |
||||||
|
e.printStackTrace(); |
||||||
|
failException = e; |
||||||
|
setState(State.FAILED); |
||||||
|
} |
||||||
|
return component; |
||||||
|
} |
||||||
|
|
||||||
|
public Component getDemoComponent() { |
||||||
|
return component; |
||||||
|
} |
||||||
|
|
||||||
|
public State getState() { |
||||||
|
return state; |
||||||
|
} |
||||||
|
|
||||||
|
protected void setState(State state) { |
||||||
|
State oldState = this.state; |
||||||
|
this.state = state; |
||||||
|
SwingSet3.logger.log(Level.FINE, "***>" +getName() + ":setState="+state); |
||||||
|
pcs.firePropertyChange("state", oldState, state); |
||||||
|
} |
||||||
|
|
||||||
|
public void addPropertyChangeListener(PropertyChangeListener pcl) { |
||||||
|
pcs.addPropertyChangeListener(pcl); |
||||||
|
} |
||||||
|
|
||||||
|
public void removePropertyChangeListener(PropertyChangeListener pcl) { |
||||||
|
pcs.removePropertyChangeListener(pcl); |
||||||
|
} |
||||||
|
|
||||||
|
private void init() { |
||||||
|
setState(State.INITIALIZED); |
||||||
|
try { |
||||||
|
Method initMethod = demoClass.getMethod("init", (Class[])null); |
||||||
|
initMethod.invoke(component, (Object[])null); |
||||||
|
} catch (NoSuchMethodException nsme) { |
||||||
|
// okay, no init method exists
|
||||||
|
} catch (IllegalAccessException iae) { |
||||||
|
SwingSet3.logger.log(Level.SEVERE, "unable to init demo: "+demoClass.getName(), iae); |
||||||
|
failException = iae; |
||||||
|
setState(State.FAILED); |
||||||
|
} catch (java.lang.reflect.InvocationTargetException ite) { |
||||||
|
SwingSet3.logger.log(Level.SEVERE, "init method failed for demo: "+demoClass.getName(), ite); |
||||||
|
failException = ite; |
||||||
|
setState(State.FAILED); |
||||||
|
} catch (NullPointerException npe) { |
||||||
|
SwingSet3.logger.log(Level.SEVERE, "init method called before demo was instantiated: " |
||||||
|
+demoClass.getName(), npe); |
||||||
|
failException = npe; |
||||||
|
setState(State.FAILED); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void start() { |
||||||
|
|
||||||
|
try { |
||||||
|
Method startMethod = demoClass.getMethod("start", (Class[])null); |
||||||
|
startMethod.invoke(component, (Object[])null); |
||||||
|
setState(State.RUNNING); |
||||||
|
} catch (NoSuchMethodException nsme) { |
||||||
|
setState(State.RUNNING); |
||||||
|
// okay, no start method exists
|
||||||
|
} catch (IllegalAccessException iae) { |
||||||
|
SwingSet3.logger.log(Level.SEVERE, "unable to start demo: "+demoClass.getName(), iae); |
||||||
|
failException = iae; |
||||||
|
setState(State.FAILED); |
||||||
|
} catch (java.lang.reflect.InvocationTargetException ite) { |
||||||
|
SwingSet3.logger.log(Level.SEVERE, "start method failed for demo: "+demoClass.getName(), ite); |
||||||
|
failException = ite; |
||||||
|
setState(State.FAILED); |
||||||
|
} catch (NullPointerException npe) { |
||||||
|
SwingSet3.logger.log(Level.SEVERE, "start method called before demo was instantiated: " |
||||||
|
+demoClass.getName(), npe); |
||||||
|
failException = npe; |
||||||
|
setState(State.FAILED); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void stop() { |
||||||
|
setState(State.STOPPED); |
||||||
|
try { |
||||||
|
Method stopMethod = demoClass.getMethod("stop", (Class[])null); |
||||||
|
stopMethod.invoke(component, (Object[])null); |
||||||
|
|
||||||
|
} catch (NoSuchMethodException nsme) { |
||||||
|
// okay, no stop method exists
|
||||||
|
|
||||||
|
} catch (IllegalAccessException iae) { |
||||||
|
SwingSet3.logger.log(Level.SEVERE, "unable to stop demo: "+demoClass.getName(), iae); |
||||||
|
failException = iae; |
||||||
|
setState(State.FAILED); |
||||||
|
} catch (java.lang.reflect.InvocationTargetException ite) { |
||||||
|
SwingSet3.logger.log(Level.SEVERE, "stop method failed for demo: "+demoClass.getName(), ite); |
||||||
|
failException = ite; |
||||||
|
setState(State.FAILED); |
||||||
|
} catch (NullPointerException npe) { |
||||||
|
SwingSet3.logger.log(Level.SEVERE, "stop method called before demo was instantiated: " |
||||||
|
+demoClass.getName(), npe); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,291 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.sun.swingset3; |
||||||
|
|
||||||
|
import com.sun.swingset3.utilities.HTMLPanel; |
||||||
|
|
||||||
|
import java.awt.BorderLayout; |
||||||
|
import java.awt.Color; |
||||||
|
import java.awt.Dimension; |
||||||
|
import java.awt.FontMetrics; |
||||||
|
import java.awt.Graphics; |
||||||
|
import java.awt.Graphics2D; |
||||||
|
import java.awt.Insets; |
||||||
|
import java.awt.Rectangle; |
||||||
|
import java.awt.geom.Rectangle2D; |
||||||
|
import java.io.IOException; |
||||||
|
import java.net.URL; |
||||||
|
import javax.swing.JComponent; |
||||||
|
import javax.swing.JEditorPane; |
||||||
|
import javax.swing.UIManager; |
||||||
|
import javax.swing.border.Border; |
||||||
|
|
||||||
|
import org.jdesktop.animation.timing.Animator; |
||||||
|
import org.jdesktop.animation.timing.interpolation.PropertySetter; |
||||||
|
import org.jdesktop.animation.timing.triggers.TimingTrigger; |
||||||
|
import org.jdesktop.animation.timing.triggers.TimingTriggerEvent; |
||||||
|
import org.jdesktop.swingx.JXPanel; |
||||||
|
import com.sun.swingset3.utilities.RoundedBorder; |
||||||
|
import com.sun.swingset3.utilities.RoundedPanel; |
||||||
|
import com.sun.swingset3.utilities.RoundedTitleBorder; |
||||||
|
import com.sun.swingset3.utilities.Utilities; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author aim |
||||||
|
*/ |
||||||
|
public class DemoPanel extends JXPanel { |
||||||
|
private static final Border roundedBorder = new RoundedBorder(10); |
||||||
|
private static final Insets margin = new Insets(8, 10, 8, 8); |
||||||
|
|
||||||
|
private Demo demo; |
||||||
|
|
||||||
|
public DemoPanel(Demo demo) { |
||||||
|
this.demo = demo; |
||||||
|
setLayout(new BorderLayout()); |
||||||
|
// remind(aim): how to access resourceMap?
|
||||||
|
//resourceMap = getContext().getResourceMap();
|
||||||
|
|
||||||
|
LoadAnimationPanel loadAnimationPanel = new LoadAnimationPanel(); |
||||||
|
|
||||||
|
add(loadAnimationPanel); |
||||||
|
loadAnimationPanel.setAnimating(true); |
||||||
|
|
||||||
|
LoadedDemoPanel demoPanel = new LoadedDemoPanel(demo); |
||||||
|
|
||||||
|
try { |
||||||
|
loadAnimationPanel.setAnimating(false); |
||||||
|
Animator fadeOutAnimator = new Animator(400, |
||||||
|
new FadeOut(DemoPanel.this, |
||||||
|
loadAnimationPanel, demoPanel)); |
||||||
|
fadeOutAnimator.setAcceleration(.2f); |
||||||
|
fadeOutAnimator.setDeceleration(.3f); |
||||||
|
Animator fadeInAnimator = new Animator(400, |
||||||
|
new PropertySetter(DemoPanel.this, "alpha", 0.3f, 1.0f)); |
||||||
|
TimingTrigger.addTrigger(fadeOutAnimator, fadeInAnimator, TimingTriggerEvent.STOP); |
||||||
|
fadeOutAnimator.start(); |
||||||
|
} catch (Exception ignore) { |
||||||
|
System.err.println(ignore); |
||||||
|
ignore.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public Demo getDemo() { |
||||||
|
return demo; |
||||||
|
} |
||||||
|
|
||||||
|
private static class FadeOut extends PropertySetter { |
||||||
|
private JXPanel parent; |
||||||
|
private JXPanel out; |
||||||
|
private JComponent in; |
||||||
|
|
||||||
|
public FadeOut(JXPanel parent, JXPanel out, JComponent in) { |
||||||
|
super(out, "alpha", 1.0f, 0.3f); |
||||||
|
this.parent = parent; |
||||||
|
this.out = out; |
||||||
|
this.in = in; |
||||||
|
} |
||||||
|
|
||||||
|
public void end() { |
||||||
|
parent.setAlpha(0.3f); |
||||||
|
parent.remove(out); |
||||||
|
parent.add(in); |
||||||
|
parent.revalidate(); |
||||||
|
} |
||||||
|
} // Fader
|
||||||
|
|
||||||
|
private static class LoadAnimationPanel extends RoundedPanel { |
||||||
|
private String message; |
||||||
|
private int triState = 0; |
||||||
|
private boolean animating = false; |
||||||
|
private Animator animator; |
||||||
|
|
||||||
|
public LoadAnimationPanel() { |
||||||
|
super(10); |
||||||
|
setBorder(roundedBorder); |
||||||
|
setBackground(Utilities.deriveColorHSB( |
||||||
|
UIManager.getColor("Panel.background"), 0, 0, -.06f)); |
||||||
|
|
||||||
|
// remind(aim): get from resource map
|
||||||
|
message = "demo loading"; |
||||||
|
|
||||||
|
PropertySetter rotator = new PropertySetter(this, "triState", 0, 3); |
||||||
|
animator = new Animator(500, Animator.INFINITE, |
||||||
|
Animator.RepeatBehavior.LOOP, rotator); |
||||||
|
// Don't animate gears if loading is quick
|
||||||
|
animator.setStartDelay(200); |
||||||
|
} |
||||||
|
|
||||||
|
public void setAnimating(boolean animating) { |
||||||
|
this.animating = animating; |
||||||
|
if (animating) { |
||||||
|
animator.start(); |
||||||
|
} else { |
||||||
|
animator.stop(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isAnimating() { |
||||||
|
return animating; |
||||||
|
} |
||||||
|
|
||||||
|
public void setTriState(int triState) { |
||||||
|
this.triState = triState; |
||||||
|
repaint(); |
||||||
|
} |
||||||
|
|
||||||
|
public int getTriState() { |
||||||
|
return triState; |
||||||
|
} |
||||||
|
|
||||||
|
public void paintComponent(Graphics g) { |
||||||
|
super.paintComponent(g); |
||||||
|
Graphics2D g2 = (Graphics2D) g.create(); |
||||||
|
Dimension size = getSize(); |
||||||
|
|
||||||
|
Color textColor = Utilities.deriveColorHSB(getBackground(), 0, 0, -.3f); |
||||||
|
Color dotColor = Utilities.deriveColorHSB(textColor, 0, .2f, -.08f); |
||||||
|
g2.setColor(textColor); |
||||||
|
g2.setFont(UIManager.getFont("Label.font").deriveFont(32f)); |
||||||
|
FontMetrics metrics = g2.getFontMetrics(); |
||||||
|
Rectangle2D rect = metrics.getStringBounds(message, g2); |
||||||
|
Rectangle2D dotRect = metrics.getStringBounds(".", g2); |
||||||
|
float x = (float) (size.width - (rect.getWidth() + 3 * dotRect.getWidth())) / 2; |
||||||
|
float y = (float) (size.height - rect.getHeight()) / 2; |
||||||
|
g2.drawString(message, x, y); |
||||||
|
int tri = getTriState(); |
||||||
|
float dx = 0; |
||||||
|
for (int i = 0; i < 3; i++) { |
||||||
|
g2.setColor(animator.isRunning() && i == tri ? |
||||||
|
dotColor : |
||||||
|
textColor); |
||||||
|
g2.drawString(".", x + (float) (rect.getWidth() + dx), y); |
||||||
|
dx += dotRect.getWidth(); |
||||||
|
} |
||||||
|
} |
||||||
|
} // LoadAnimationPanel
|
||||||
|
|
||||||
|
private static class LoadedDemoPanel extends RoundedPanel { |
||||||
|
private String demoName; |
||||||
|
private JComponent descriptionArea; |
||||||
|
private JComponent demoPanel; |
||||||
|
|
||||||
|
public LoadedDemoPanel(Demo demo) { |
||||||
|
super(10); |
||||||
|
setLayout(null); |
||||||
|
demoName = demo.getName(); |
||||||
|
|
||||||
|
URL description = demo.getHTMLDescription(); |
||||||
|
if (description != null) { |
||||||
|
descriptionArea = createDescriptionArea(description); |
||||||
|
add(descriptionArea); |
||||||
|
|
||||||
|
demoPanel = new RoundedPanel(new BorderLayout()); |
||||||
|
demoPanel.setBorder(roundedBorder); |
||||||
|
|
||||||
|
} else { |
||||||
|
// no description
|
||||||
|
demoPanel = new JXPanel(new BorderLayout()); |
||||||
|
} |
||||||
|
demoPanel.add(demo.createDemoComponent()); |
||||||
|
add(demoPanel); |
||||||
|
|
||||||
|
applyDefaults(); |
||||||
|
} |
||||||
|
|
||||||
|
private static JComponent createDescriptionArea(URL descriptionURL) { |
||||||
|
JEditorPane descriptionPane = new HTMLPanel(); |
||||||
|
descriptionPane.setEditable(false); |
||||||
|
descriptionPane.setMargin(margin); |
||||||
|
descriptionPane.setOpaque(true); |
||||||
|
try { |
||||||
|
descriptionPane.setPage(descriptionURL); |
||||||
|
} catch (IOException e) { |
||||||
|
System.err.println("couldn't load description from URL:" + descriptionURL); |
||||||
|
} |
||||||
|
return descriptionPane; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void doLayout() { |
||||||
|
if (demoPanel != null) { |
||||||
|
Dimension size = getSize(); |
||||||
|
Insets insets = getInsets(); |
||||||
|
|
||||||
|
if (descriptionArea == null) { |
||||||
|
// Make demo fill entire area within border
|
||||||
|
demoPanel.setBounds(insets.left, insets.top, |
||||||
|
size.width - insets.left - insets.right, |
||||||
|
size.height - insets.top - insets.bottom); |
||||||
|
} else { |
||||||
|
// Split space between HTML description and running demo
|
||||||
|
Dimension demoSize = demoPanel.getPreferredSize(); |
||||||
|
int margin = insets.top / 2; |
||||||
|
Rectangle bounds = new Rectangle(); |
||||||
|
bounds.width = Math.max(demoSize.width, (int) (size.width * .50)); |
||||||
|
bounds.height = Math.max(demoSize.height, size.height - |
||||||
|
2 * margin); |
||||||
|
bounds.x = size.width - bounds.width - margin; |
||||||
|
bounds.y = margin; |
||||||
|
demoPanel.setBounds(bounds); |
||||||
|
descriptionArea.setBounds(insets.left, insets.top, |
||||||
|
size.width - margin - insets.right - bounds.width, |
||||||
|
size.height - insets.top - insets.bottom); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void updateUI() { |
||||||
|
super.updateUI(); |
||||||
|
applyDefaults(); |
||||||
|
} |
||||||
|
|
||||||
|
private void applyDefaults() { |
||||||
|
setBorder(new RoundedTitleBorder(demoName, |
||||||
|
UIManager.getColor(SwingSet3.TITLE_GRADIENT_COLOR1_KEY), |
||||||
|
UIManager.getColor(SwingSet3.TITLE_GRADIENT_COLOR2_KEY))); |
||||||
|
|
||||||
|
setFont(UIManager.getFont(SwingSet3.TITLE_FONT_KEY)); |
||||||
|
Color bg = Utilities.deriveColorHSB( |
||||||
|
UIManager.getColor("Panel.background"), 0, 0, -.06f); |
||||||
|
setBackground(bg); |
||||||
|
setForeground(UIManager.getColor(SwingSet3.TITLE_FOREGROUND_KEY)); |
||||||
|
if (demoPanel != null) { |
||||||
|
demoPanel.setBackground(Utilities.deriveColorHSB(bg, 0, 0, .04f)); |
||||||
|
} |
||||||
|
if (descriptionArea != null) { |
||||||
|
descriptionArea.setBackground(bg); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,48 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.sun.swingset3; |
||||||
|
|
||||||
|
import java.lang.annotation.Retention; |
||||||
|
import java.lang.annotation.RetentionPolicy; |
||||||
|
|
||||||
|
/** |
||||||
|
* Annotation type for specifying meta-data about Demo |
||||||
|
* @author aim |
||||||
|
*/ |
||||||
|
@Retention(RetentionPolicy.RUNTIME) |
||||||
|
public @interface DemoProperties { |
||||||
|
String value(); // Name
|
||||||
|
String category(); |
||||||
|
String description(); |
||||||
|
String iconFile() default ""; |
||||||
|
String[] sourceFiles() default ""; |
||||||
|
} |
@ -0,0 +1,370 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.sun.swingset3; |
||||||
|
|
||||||
|
import com.sun.swingset3.utilities.GradientPanel; |
||||||
|
import com.sun.swingset3.utilities.CollapsiblePanel; |
||||||
|
import com.sun.swingset3.utilities.ArrowIcon; |
||||||
|
import java.awt.BorderLayout; |
||||||
|
import java.awt.Color; |
||||||
|
import java.awt.Component; |
||||||
|
import java.awt.Dimension; |
||||||
|
import java.awt.Font; |
||||||
|
import java.awt.Graphics; |
||||||
|
import java.awt.GridBagConstraints; |
||||||
|
import java.awt.GridBagLayout; |
||||||
|
import java.awt.Insets; |
||||||
|
import java.awt.event.ActionEvent; |
||||||
|
import java.awt.event.ActionListener; |
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.List; |
||||||
|
import javax.swing.AbstractButton; |
||||||
|
import javax.swing.Box; |
||||||
|
import javax.swing.BoxLayout; |
||||||
|
import javax.swing.ButtonGroup; |
||||||
|
import javax.swing.Icon; |
||||||
|
import javax.swing.JComboBox; |
||||||
|
import javax.swing.JComponent; |
||||||
|
import javax.swing.JLabel; |
||||||
|
import javax.swing.JPanel; |
||||||
|
import javax.swing.JScrollPane; |
||||||
|
import javax.swing.JToggleButton; |
||||||
|
import javax.swing.UIManager; |
||||||
|
import javax.swing.border.Border; |
||||||
|
import javax.swing.border.CompoundBorder; |
||||||
|
import javax.swing.border.EmptyBorder; |
||||||
|
import javax.swing.border.MatteBorder; |
||||||
|
import com.sun.swingset3.utilities.Utilities; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author Administrator |
||||||
|
*/ |
||||||
|
public class DemoSelectorPanel extends JPanel { |
||||||
|
private static final Border chiselBorder = new ChiselBorder(); |
||||||
|
private static final Border panelBorder = new CompoundBorder( |
||||||
|
chiselBorder, new EmptyBorder(6,8,6,0)); |
||||||
|
private static final Border categoryBorder = new CompoundBorder( |
||||||
|
chiselBorder, new EmptyBorder(0,0,10,0)); |
||||||
|
private static final Border buttonBorder = new CompoundBorder( |
||||||
|
new DemoButtonBorder(), new EmptyBorder(0, 18, 0, 0)); |
||||||
|
|
||||||
|
private GradientPanel titlePanel; |
||||||
|
private JLabel demoListLabel; |
||||||
|
private JPanel viewPanel; |
||||||
|
private JScrollPane scrollPane; |
||||||
|
// need to track components that have defaults customizations
|
||||||
|
private final List<CollapsiblePanel> collapsePanels = new ArrayList<CollapsiblePanel>(); |
||||||
|
private Icon expandedIcon; |
||||||
|
private Icon collapsedIcon; |
||||||
|
private Color visitedForeground; |
||||||
|
private Color failedForeground; |
||||||
|
|
||||||
|
private ButtonGroup group; |
||||||
|
private final ActionListener demoActionListener = new DemoActionListener(); |
||||||
|
private int buttonHeight = 0; |
||||||
|
|
||||||
|
private Demo selectedDemo; |
||||||
|
|
||||||
|
public DemoSelectorPanel(String demoSetTitle, List<Demo> demoSet) { |
||||||
|
super(new BorderLayout()); |
||||||
|
|
||||||
|
visitedForeground = new Color(100, 100, 150); |
||||||
|
failedForeground = new Color(245, 20, 80); |
||||||
|
|
||||||
|
// only one demo may be selected at a time
|
||||||
|
group = new ButtonGroup(); |
||||||
|
|
||||||
|
// create demo set title area at top
|
||||||
|
add(createTitleArea(demoSetTitle), BorderLayout.NORTH); |
||||||
|
|
||||||
|
// create scrollable demo panel at bottom
|
||||||
|
JComponent selector = createDemoSelector(demoSet); |
||||||
|
scrollPane = new JScrollPane(selector); |
||||||
|
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); |
||||||
|
add(scrollPane, BorderLayout.CENTER); |
||||||
|
|
||||||
|
applyDefaults(); |
||||||
|
} |
||||||
|
|
||||||
|
protected JComponent createTitleArea(String demoSetTitle) { |
||||||
|
JPanel titleAreaPanel = new JPanel(new BorderLayout()); |
||||||
|
titlePanel = new GradientPanel( |
||||||
|
UIManager.getColor(SwingSet3.TITLE_GRADIENT_COLOR1_KEY), |
||||||
|
UIManager.getColor(SwingSet3.TITLE_GRADIENT_COLOR2_KEY)); |
||||||
|
titlePanel.setLayout(new BorderLayout()); |
||||||
|
titlePanel.setBorder(panelBorder); |
||||||
|
demoListLabel = new JLabel(demoSetTitle); |
||||||
|
demoListLabel.setOpaque(false); |
||||||
|
demoListLabel.setHorizontalAlignment(JLabel.LEADING); |
||||||
|
titlePanel.add(demoListLabel, BorderLayout.CENTER); |
||||||
|
titleAreaPanel.add(titlePanel, BorderLayout.NORTH); |
||||||
|
|
||||||
|
// Add panel with view combobox
|
||||||
|
viewPanel = new JPanel(); |
||||||
|
viewPanel.setLayout(new BoxLayout(viewPanel, BoxLayout.X_AXIS)); |
||||||
|
viewPanel.setBorder(new CompoundBorder(chiselBorder, |
||||||
|
new EmptyBorder(12,8,12,8))); |
||||||
|
JLabel viewLabel = new JLabel("View:"); |
||||||
|
viewPanel.add(viewLabel); |
||||||
|
viewPanel.add(Box.createHorizontalStrut(6)); |
||||||
|
JComboBox viewComboBox = new JComboBox(); |
||||||
|
viewComboBox.addItem("by category"); |
||||||
|
viewPanel.add(viewComboBox); |
||||||
|
titleAreaPanel.add(viewPanel, BorderLayout.CENTER); |
||||||
|
|
||||||
|
return titleAreaPanel; |
||||||
|
} |
||||||
|
|
||||||
|
protected JComponent createDemoSelector(List<Demo> demoSet) { |
||||||
|
JPanel selectorPanel = new JPanel(); |
||||||
|
GridBagLayout gridbag = new GridBagLayout(); |
||||||
|
selectorPanel.setLayout(gridbag); |
||||||
|
GridBagConstraints c = new GridBagConstraints(); |
||||||
|
c.gridx = c.gridy = 0; |
||||||
|
c.fill = GridBagConstraints.HORIZONTAL; |
||||||
|
c.weightx = 1; |
||||||
|
|
||||||
|
HashMap<String,JPanel> categoryMap = new HashMap<String,JPanel>(); |
||||||
|
GridBagLayout categoryGridbag = null; |
||||||
|
GridBagConstraints cc = new GridBagConstraints(); |
||||||
|
cc.gridx = cc.gridy = 0; |
||||||
|
cc.weightx = 1; |
||||||
|
cc.fill = GridBagConstraints.HORIZONTAL; |
||||||
|
CollapsiblePanel collapsePanel; |
||||||
|
for(Demo demo: demoSet) { |
||||||
|
String category = demo.getCategory(); |
||||||
|
JPanel categoryPanel = categoryMap.get(category); |
||||||
|
if (categoryPanel == null) { |
||||||
|
// Create category collapsible panel
|
||||||
|
categoryPanel = new JPanel(); |
||||||
|
categoryGridbag = new GridBagLayout(); |
||||||
|
categoryPanel.setLayout(categoryGridbag); |
||||||
|
collapsePanel = new CollapsiblePanel(categoryPanel, category, |
||||||
|
"click to expand or contract category"); |
||||||
|
collapsePanels.add(collapsePanel); |
||||||
|
collapsePanel.setBorder(categoryBorder); |
||||||
|
categoryMap.put(category, categoryPanel); |
||||||
|
gridbag.addLayoutComponent(collapsePanel, c); |
||||||
|
selectorPanel.add(collapsePanel); |
||||||
|
c.gridy++; |
||||||
|
} |
||||||
|
DemoButton demoButton = new DemoButton(demo); |
||||||
|
categoryGridbag.addLayoutComponent(demoButton, cc); |
||||||
|
cc.gridy++; |
||||||
|
group.add(demoButton); |
||||||
|
categoryPanel.add(demoButton); |
||||||
|
if (buttonHeight == 0) { |
||||||
|
buttonHeight = demoButton.getPreferredSize().height; |
||||||
|
} |
||||||
|
} |
||||||
|
// add empty component to take up any extra room on bottom
|
||||||
|
JPanel trailer = new JPanel(); |
||||||
|
c.weighty = 1.0; |
||||||
|
gridbag.addLayoutComponent(trailer, c); |
||||||
|
selectorPanel.add(trailer); |
||||||
|
|
||||||
|
applyDefaults(); |
||||||
|
|
||||||
|
return selectorPanel; |
||||||
|
} |
||||||
|
|
||||||
|
public void updateUI() { |
||||||
|
super.updateUI(); |
||||||
|
applyDefaults(); |
||||||
|
} |
||||||
|
|
||||||
|
protected void applyDefaults() { |
||||||
|
|
||||||
|
expandedIcon = new ArrowIcon(ArrowIcon.SOUTH, |
||||||
|
UIManager.getColor(SwingSet3.TITLE_FOREGROUND_KEY)); |
||||||
|
collapsedIcon = new ArrowIcon(ArrowIcon.EAST, |
||||||
|
UIManager.getColor(SwingSet3.TITLE_FOREGROUND_KEY)); |
||||||
|
|
||||||
|
setBorder(new MatteBorder(0,0,0,1, |
||||||
|
UIManager.getColor(SwingSet3.CONTROL_MID_SHADOW_KEY))); |
||||||
|
|
||||||
|
if (titlePanel != null) { |
||||||
|
titlePanel.setGradientColor1( |
||||||
|
UIManager.getColor(SwingSet3.TITLE_GRADIENT_COLOR1_KEY)); |
||||||
|
titlePanel.setGradientColor2( |
||||||
|
UIManager.getColor(SwingSet3.TITLE_GRADIENT_COLOR2_KEY)); |
||||||
|
} |
||||||
|
|
||||||
|
if (demoListLabel != null) { |
||||||
|
demoListLabel.setForeground(UIManager.getColor(SwingSet3.TITLE_FOREGROUND_KEY)); |
||||||
|
demoListLabel.setFont(UIManager.getFont(SwingSet3.TITLE_FONT_KEY)); |
||||||
|
} |
||||||
|
if (viewPanel != null) { |
||||||
|
viewPanel.setBackground(UIManager.getColor(SwingSet3.SUB_PANEL_BACKGROUND_KEY)); |
||||||
|
} |
||||||
|
if (collapsePanels != null) { |
||||||
|
for (CollapsiblePanel collapsePanel : collapsePanels) { |
||||||
|
collapsePanel.setFont( |
||||||
|
UIManager.getFont("CheckBox.font").deriveFont(Font.BOLD)); |
||||||
|
collapsePanel.setForeground(UIManager.getColor(SwingSet3.TITLE_FOREGROUND_KEY)); |
||||||
|
collapsePanel.setExpandedIcon(expandedIcon); |
||||||
|
collapsePanel.setCollapsedIcon(collapsedIcon); |
||||||
|
} |
||||||
|
} |
||||||
|
revalidate(); |
||||||
|
} |
||||||
|
|
||||||
|
public Demo getSelectedDemo() { |
||||||
|
return selectedDemo; |
||||||
|
} |
||||||
|
|
||||||
|
protected void setSelectedDemo(Demo demo) { |
||||||
|
Demo oldSelectedDemo = selectedDemo; |
||||||
|
selectedDemo = demo; |
||||||
|
firePropertyChange("selectedDemo", oldSelectedDemo, demo); |
||||||
|
} |
||||||
|
|
||||||
|
private class DemoButton extends JToggleButton { |
||||||
|
private Demo demo; |
||||||
|
|
||||||
|
public DemoButton(Demo demo) { |
||||||
|
super(); |
||||||
|
this.demo = demo; |
||||||
|
String demoName = demo.getName(); |
||||||
|
if (demoName.endsWith("Demo")) { |
||||||
|
setText(demoName.substring(0, demoName.indexOf("Demo"))); |
||||||
|
} else { |
||||||
|
setText(demoName); |
||||||
|
} |
||||||
|
setIcon(demo.getIcon()); |
||||||
|
setIconTextGap(10); |
||||||
|
setHorizontalTextPosition(JToggleButton.TRAILING); |
||||||
|
setHorizontalAlignment(JToggleButton.LEADING); |
||||||
|
setOpaque(false); |
||||||
|
setBorder(buttonBorder); |
||||||
|
setFocusPainted(false); |
||||||
|
setContentAreaFilled(false); |
||||||
|
setToolTipText(demo.getShortDescription()); |
||||||
|
addActionListener(demoActionListener); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void updateUI() { |
||||||
|
super.updateUI(); |
||||||
|
// some look and feels replace our border, so take it back
|
||||||
|
setBorder(buttonBorder); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void paintComponent(Graphics g) { |
||||||
|
if (isSelected()) { |
||||||
|
setBackground(UIManager.getColor("Tree.selectionBackground")); |
||||||
|
g.setColor(UIManager.getColor("Tree.selectionBackground")); |
||||||
|
Dimension size = getSize(); |
||||||
|
g.fillRect(0, 0, size.width, size.height); |
||||||
|
setForeground(UIManager.getColor("Tree.selectionForeground")); |
||||||
|
} else { |
||||||
|
setBackground(UIManager.getColor("ToggleButton.background")); |
||||||
|
Color foreground = UIManager.getColor("ToggleButton.foreground"); |
||||||
|
switch(demo.getState()) { |
||||||
|
case STOPPED: { |
||||||
|
foreground = visitedForeground; |
||||||
|
break; |
||||||
|
} |
||||||
|
case FAILED: { |
||||||
|
foreground = failedForeground; |
||||||
|
} |
||||||
|
} |
||||||
|
setForeground(foreground); |
||||||
|
} |
||||||
|
super.paintComponent(g); |
||||||
|
} |
||||||
|
|
||||||
|
public Demo getDemo() { |
||||||
|
return demo; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class DemoActionListener implements ActionListener { |
||||||
|
public void actionPerformed(ActionEvent event) { |
||||||
|
DemoButton demoButton = (DemoButton)event.getSource(); |
||||||
|
setSelectedDemo(demoButton.getDemo()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static class DemoButtonBorder implements Border { |
||||||
|
private Insets insets = new Insets(2, 1, 1, 1); |
||||||
|
|
||||||
|
public DemoButtonBorder() { |
||||||
|
} |
||||||
|
|
||||||
|
public Insets getBorderInsets(Component c) { |
||||||
|
return insets; |
||||||
|
} |
||||||
|
public boolean isBorderOpaque() { |
||||||
|
return true; |
||||||
|
} |
||||||
|
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { |
||||||
|
AbstractButton b = (AbstractButton)c; |
||||||
|
if (b.isSelected()) { |
||||||
|
Color color = c.getBackground(); |
||||||
|
g.setColor(Utilities.deriveColorHSB(color, 0, 0, -.20f)); |
||||||
|
g.drawLine(x, y, x + width, y); |
||||||
|
g.setColor(Utilities.deriveColorHSB(color, 0, 0, -.10f)); |
||||||
|
g.drawLine(x, y + 1, x + width, y + 1); |
||||||
|
g.drawLine(x, y + 2, x, y + height - 2); |
||||||
|
g.setColor(Utilities.deriveColorHSB(color, 0, 0, .24f)); |
||||||
|
g.drawLine(x, y + height - 1, x + width, y + height-1); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static class ChiselBorder implements Border { |
||||||
|
private Insets insets = new Insets(1, 0, 1, 0); |
||||||
|
|
||||||
|
public ChiselBorder() { |
||||||
|
} |
||||||
|
|
||||||
|
public Insets getBorderInsets(Component c) { |
||||||
|
return insets; |
||||||
|
} |
||||||
|
public boolean isBorderOpaque() { |
||||||
|
return true; |
||||||
|
} |
||||||
|
public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { |
||||||
|
Color color = c.getBackground(); |
||||||
|
// render highlight at top
|
||||||
|
g.setColor(Utilities.deriveColorHSB(color, 0, 0, .2f)); |
||||||
|
g.drawLine(x, y, x + width, y); |
||||||
|
// render shadow on bottom
|
||||||
|
g.setColor(Utilities.deriveColorHSB(color, 0, 0, -.2f)); |
||||||
|
g.drawLine(x, y + height - 1, x + width, y + height - 1); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,131 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.sun.swingset3; |
||||||
|
|
||||||
|
import com.sun.swingset3.utilities.RoundedPanel; |
||||||
|
import java.awt.Dimension; |
||||||
|
import java.awt.Graphics; |
||||||
|
import java.awt.Insets; |
||||||
|
import java.awt.event.MouseAdapter; |
||||||
|
import java.awt.event.MouseEvent; |
||||||
|
import javax.swing.Icon; |
||||||
|
import javax.swing.ImageIcon; |
||||||
|
import javax.swing.JLabel; |
||||||
|
import org.jdesktop.animation.timing.Animator; |
||||||
|
import org.jdesktop.animation.timing.interpolation.PropertySetter; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author Amy Fowler |
||||||
|
*/ |
||||||
|
public class IntroPanel extends RoundedPanel { |
||||||
|
private JLabel introImage; |
||||||
|
private SlidingLabel introText; |
||||||
|
|
||||||
|
public IntroPanel() { |
||||||
|
setLayout(null); |
||||||
|
setOpaque(false); |
||||||
|
|
||||||
|
introImage = new JLabel(new ImageIcon( |
||||||
|
SwingSet3.class.getResource("resources/images/home_notext.png"))); |
||||||
|
introImage.setVerticalAlignment(JLabel.TOP); |
||||||
|
|
||||||
|
introText = new SlidingLabel(new ImageIcon( |
||||||
|
SwingSet3.class.getResource("resources/images/home_text.png"))); |
||||||
|
introText.setVisible(false); |
||||||
|
|
||||||
|
introImage.addMouseListener(new MouseAdapter() { |
||||||
|
public void mousePressed(MouseEvent event) { |
||||||
|
slideTextIn(); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
add(introText); |
||||||
|
add(introImage); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void doLayout() { |
||||||
|
Dimension size = getSize(); |
||||||
|
Insets insets = getInsets(); |
||||||
|
int w = size.width - insets.left - insets.right; |
||||||
|
|
||||||
|
Dimension prefSize = introImage.getPreferredSize(); |
||||||
|
introImage.setBounds(0, 0, prefSize.width, prefSize.height); |
||||||
|
|
||||||
|
if (introText.isVisible()) { |
||||||
|
prefSize = introText.getPreferredSize(); |
||||||
|
introText.setBounds(introText.getX(), introText.getY(), |
||||||
|
prefSize.width, prefSize.height); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void paint(Graphics g) { |
||||||
|
super.paint(g); |
||||||
|
if (!introText.isVisible()) { |
||||||
|
introText.setLocation(1000, 110); |
||||||
|
introText.setVisible(true); |
||||||
|
slideTextIn(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void slideTextIn() { |
||||||
|
Animator animator = new Animator(800, |
||||||
|
new PropertySetter(introText, "x", getWidth(), 30)); |
||||||
|
animator.setStartDelay(800); |
||||||
|
animator.setAcceleration(.2f); |
||||||
|
animator.setDeceleration(.5f); |
||||||
|
animator.start(); |
||||||
|
} |
||||||
|
|
||||||
|
public void slideTextOut() { |
||||||
|
Animator animator = new Animator(600, |
||||||
|
new PropertySetter(introText, "x", introText.getX(), -introText.getWidth())); |
||||||
|
animator.setStartDelay(10); |
||||||
|
animator.setAcceleration(.5f); |
||||||
|
animator.setDeceleration(.2f); |
||||||
|
animator.start(); |
||||||
|
} |
||||||
|
|
||||||
|
public class SlidingLabel extends JLabel { |
||||||
|
public SlidingLabel(Icon icon) { |
||||||
|
super(icon); |
||||||
|
} |
||||||
|
|
||||||
|
public void setX(int x) { |
||||||
|
setLocation(x, getY()); |
||||||
|
revalidate(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,707 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2007 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.sun.swingset3; |
||||||
|
|
||||||
|
import com.sun.swingset3.codeview.CodeViewer; |
||||||
|
import com.sun.swingset3.utilities.AnimatingSplitPane; |
||||||
|
import com.sun.swingset3.utilities.RoundedBorder; |
||||||
|
import com.sun.swingset3.utilities.RoundedPanel; |
||||||
|
import com.sun.swingset3.utilities.Utilities; |
||||||
|
import org.jdesktop.application.Action; |
||||||
|
import org.jdesktop.application.ResourceMap; |
||||||
|
import org.jdesktop.application.SingleFrameApplication; |
||||||
|
import org.jdesktop.application.View; |
||||||
|
|
||||||
|
import javax.swing.*; |
||||||
|
import javax.swing.border.Border; |
||||||
|
import javax.swing.border.EmptyBorder; |
||||||
|
import javax.swing.event.ChangeEvent; |
||||||
|
import javax.swing.event.ChangeListener; |
||||||
|
import java.awt.*; |
||||||
|
import java.awt.event.ActionEvent; |
||||||
|
import java.awt.event.HierarchyEvent; |
||||||
|
import java.awt.event.HierarchyListener; |
||||||
|
import java.beans.PropertyChangeEvent; |
||||||
|
import java.beans.PropertyChangeListener; |
||||||
|
import java.io.*; |
||||||
|
import java.util.*; |
||||||
|
import java.util.List; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author Amy Fowler |
||||||
|
*/ |
||||||
|
public class SwingSet3 extends SingleFrameApplication { |
||||||
|
static final Logger logger = Logger.getLogger(SwingSet3.class.getName()); |
||||||
|
|
||||||
|
private static final ServiceLoader<LookAndFeel> LOOK_AND_FEEL_LOADER = ServiceLoader.load(LookAndFeel.class); |
||||||
|
|
||||||
|
public static String title; |
||||||
|
|
||||||
|
public static final String CONTROL_VERY_LIGHT_SHADOW_KEY = "controlVeryLightShadowColor"; |
||||||
|
public static final String CONTROL_LIGHT_SHADOW_KEY = "controlLightShadowColor"; |
||||||
|
public static final String CONTROL_MID_SHADOW_KEY = "controlMidShadowColor"; |
||||||
|
public static final String CONTROL_VERY_DARK_SHADOW_KEY = "controlVeryDarkShadowColor"; |
||||||
|
public static final String CONTROL_DARK_SHADOW_KEY = "controlDarkShadowColor"; |
||||||
|
public static final String TITLE_GRADIENT_COLOR1_KEY = "titleGradientColor1"; |
||||||
|
public static final String TITLE_GRADIENT_COLOR2_KEY = "titleGradientColor2"; |
||||||
|
public static final String TITLE_FOREGROUND_KEY = "titleForegroundColor"; |
||||||
|
public static final String CODE_HIGHLIGHT_KEY = "codeHighlightColor"; |
||||||
|
public static final String TITLE_FONT_KEY = "titleFont"; |
||||||
|
public static final String SUB_PANEL_BACKGROUND_KEY = "subPanelBackgroundColor"; |
||||||
|
|
||||||
|
public static final int MAIN_FRAME_WIDTH = 880; |
||||||
|
public static final int MAIN_FRAME_HEIGHT = 640; |
||||||
|
public static final int DEMO_SELECTOR_WIDTH = 186; |
||||||
|
public static final int DEMO_PANEL_HEIGHT = 400; |
||||||
|
public static final int DEMO_PANEL_WIDTH = MAIN_FRAME_WIDTH - DEMO_SELECTOR_WIDTH; |
||||||
|
|
||||||
|
private static final Border EMPTY_BORDER = new EmptyBorder(0, 0, 0, 0); |
||||||
|
private static final Border PANEL_BORDER = new EmptyBorder(10, 10, 10, 10); |
||||||
|
|
||||||
|
private static final String DEMO_LIST_FILE = "/META-INF/demolist"; |
||||||
|
|
||||||
|
static { |
||||||
|
// Property must be set *early* due to Apple Bug#3909714
|
||||||
|
if (System.getProperty("os.name").equals("Mac OS X")) { |
||||||
|
System.setProperty("apple.laf.useScreenMenuBar", "true"); |
||||||
|
} |
||||||
|
|
||||||
|
// temporary workaround for problem with Nimbus classname
|
||||||
|
UIManager.LookAndFeelInfo lafInfo[] = UIManager.getInstalledLookAndFeels(); |
||||||
|
for(int i = 0; i < lafInfo.length; i++) { |
||||||
|
if (lafInfo[i].getName().equals("Nimbus")) { |
||||||
|
lafInfo[i] = new UIManager.LookAndFeelInfo("Nimbus", |
||||||
|
"com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel"); |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
UIManager.setInstalledLookAndFeels(lafInfo); |
||||||
|
UIManager.put("swing.boldMetal", Boolean.FALSE); |
||||||
|
} |
||||||
|
|
||||||
|
public static void main(String[] args) { |
||||||
|
launch(SwingSet3.class, args); |
||||||
|
} |
||||||
|
|
||||||
|
public static boolean runningOnMac() { |
||||||
|
return System.getProperty("os.name").equals("Mac OS X"); |
||||||
|
} |
||||||
|
|
||||||
|
public static boolean usingNimbus() { |
||||||
|
return UIManager.getLookAndFeel().getName().equals("Nimbus"); |
||||||
|
} |
||||||
|
|
||||||
|
private static List<String> readDemoClassNames(Reader reader) throws IOException { |
||||||
|
List<String> demoClassNames = new ArrayList<String>(); |
||||||
|
|
||||||
|
BufferedReader breader = new BufferedReader(reader); |
||||||
|
String line; |
||||||
|
while((line = breader.readLine()) != null) { |
||||||
|
demoClassNames.add(line); |
||||||
|
} |
||||||
|
breader.close(); |
||||||
|
return demoClassNames; |
||||||
|
} |
||||||
|
// End of statics
|
||||||
|
|
||||||
|
private ResourceMap resourceMap; |
||||||
|
|
||||||
|
// Application models
|
||||||
|
private String demoListTitle; |
||||||
|
private List<Demo> demoList; |
||||||
|
private PropertyChangeListener demoPropertyChangeListener; |
||||||
|
private Map<String, DemoPanel> runningDemoCache; |
||||||
|
private Demo currentDemo; |
||||||
|
|
||||||
|
// GUI components
|
||||||
|
private JPanel mainPanel; |
||||||
|
private DemoSelectorPanel demoSelectorPanel; |
||||||
|
private AnimatingSplitPane demoSplitPane; |
||||||
|
private JPanel demoContainer; |
||||||
|
private JComponent currentDemoPanel; |
||||||
|
private JComponent demoPlaceholder; |
||||||
|
private JPanel codeContainer; |
||||||
|
private CodeViewer codeViewer; |
||||||
|
private JCheckBoxMenuItem sourceCodeCheckboxItem; |
||||||
|
private ButtonGroup lookAndFeelRadioGroup; |
||||||
|
|
||||||
|
private JPopupMenu popup; |
||||||
|
|
||||||
|
// Properties
|
||||||
|
private String lookAndFeel; |
||||||
|
private boolean sourceVisible = true; |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void initialize(String args[]) { |
||||||
|
try { |
||||||
|
UIManager.setLookAndFeel("com.bulenkov.darcula.DarculaLaf"); |
||||||
|
} catch (Exception ex) { |
||||||
|
// not catestrophic
|
||||||
|
} |
||||||
|
resourceMap = getContext().getResourceMap(); |
||||||
|
|
||||||
|
title = resourceMap.getString("mainFrame.title"); |
||||||
|
runningDemoCache = new HashMap<String, DemoPanel>(); |
||||||
|
setDemoList(resourceMap.getString("demos.title"), getDemoClassNames(args)); |
||||||
|
|
||||||
|
IntroPanel intro = new IntroPanel(); |
||||||
|
setDemoPlaceholder(intro); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
private List<String>getDemoClassNames(String args[]) { |
||||||
|
List<String> demoList = new ArrayList<String>(); |
||||||
|
boolean augment = false; |
||||||
|
Exception exception = null; |
||||||
|
|
||||||
|
// First look for any demo list files specified on the command-line
|
||||||
|
for(String arg : args) { |
||||||
|
if (arg.equals("-a") || arg.equals("-augment")) { |
||||||
|
augment = true; |
||||||
|
} else { |
||||||
|
// process argument as filename containing names of demo classes
|
||||||
|
try { |
||||||
|
demoList.addAll(readDemoClassNames(new FileReader(arg) /*filename*/)); |
||||||
|
} catch (IOException ex) { |
||||||
|
exception = ex; |
||||||
|
logger.log(Level.WARNING, "unable to read demo class names from file: "+arg, ex); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (demoList.isEmpty() || augment) { |
||||||
|
// Load default Demos
|
||||||
|
try { |
||||||
|
demoList.addAll(readDemoClassNames(new InputStreamReader(getClass().getResourceAsStream(DEMO_LIST_FILE)))); |
||||||
|
} catch (IOException ex) { |
||||||
|
exception = ex; |
||||||
|
logger.log(Level.WARNING, "unable to read resource: " + DEMO_LIST_FILE, ex); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (demoList.isEmpty()) { |
||||||
|
displayErrorMessage(resourceMap.getString("error.noDemosLoaded"), |
||||||
|
exception); |
||||||
|
} |
||||||
|
return demoList; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void setDemoList(String demoListTitle, List<String> demoClassNamesList) { |
||||||
|
List<Demo> demoList = new ArrayList<Demo>(); |
||||||
|
for(String demoClassName: demoClassNamesList) { |
||||||
|
Demo demo = createDemo(demoClassName); |
||||||
|
|
||||||
|
if (demo != null) { |
||||||
|
demoList.add(demo); |
||||||
|
} |
||||||
|
} |
||||||
|
this.demoListTitle = demoListTitle; |
||||||
|
this.demoList = demoList; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
*/ |
||||||
|
protected Demo createDemo(String demoClassName) { |
||||||
|
Class<?> demoClass = null; |
||||||
|
Demo demo = null; |
||||||
|
try { |
||||||
|
demoClass = Class.forName(demoClassName); |
||||||
|
} catch (ClassNotFoundException cnfe) { |
||||||
|
logger.log(Level.WARNING, "demo class not found:"+ demoClassName); |
||||||
|
} |
||||||
|
if (demoClass != null) { |
||||||
|
// Wrap Demo
|
||||||
|
demo = new Demo(demoClass); |
||||||
|
demo.addPropertyChangeListener(getDemoPropertyChangeListener()); |
||||||
|
} |
||||||
|
return demo; |
||||||
|
} |
||||||
|
|
||||||
|
protected PropertyChangeListener getDemoPropertyChangeListener() { |
||||||
|
if (demoPropertyChangeListener == null) { |
||||||
|
demoPropertyChangeListener = new DemoPropertyChangeListener(); |
||||||
|
} |
||||||
|
return demoPropertyChangeListener; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void startup() { |
||||||
|
UIManager.addPropertyChangeListener(new PropertyChangeListener() { |
||||||
|
public void propertyChange(PropertyChangeEvent event) { |
||||||
|
if (event.getPropertyName().equals("lookAndFeel")) { |
||||||
|
configureDefaults(); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
configureDefaults(); |
||||||
|
|
||||||
|
View view = getMainView(); |
||||||
|
view.setComponent(createMainPanel()); |
||||||
|
view.setMenuBar(createMenuBar()); |
||||||
|
|
||||||
|
applyDefaults(); |
||||||
|
|
||||||
|
// application framework should handle this
|
||||||
|
getMainFrame().setIconImage(resourceMap.getImageIcon("Application.icon").getImage()); |
||||||
|
|
||||||
|
show(view); |
||||||
|
} |
||||||
|
|
||||||
|
private void configureDefaults() { |
||||||
|
|
||||||
|
// Color palette algorithm courtesy of Jasper Potts
|
||||||
|
Color controlColor = UIManager.getColor("control"); |
||||||
|
|
||||||
|
UIManager.put(CONTROL_VERY_LIGHT_SHADOW_KEY, |
||||||
|
Utilities.deriveColorHSB(controlColor, 0, 0, -0.02f)); |
||||||
|
UIManager.put(CONTROL_LIGHT_SHADOW_KEY, |
||||||
|
Utilities.deriveColorHSB(controlColor, 0, 0, -0.06f)); |
||||||
|
UIManager.put(CONTROL_MID_SHADOW_KEY, |
||||||
|
Utilities.deriveColorHSB(controlColor, 0, 0, -0.16f)); |
||||||
|
UIManager.put(CONTROL_VERY_DARK_SHADOW_KEY, |
||||||
|
Utilities.deriveColorHSB(controlColor, 0, 0, -0.5f)); |
||||||
|
UIManager.put(CONTROL_DARK_SHADOW_KEY, |
||||||
|
Utilities.deriveColorHSB(controlColor, 0, 0, -0.32f)); |
||||||
|
|
||||||
|
// Calculate gradient colors for title panels
|
||||||
|
Color titleColor = UIManager.getColor(usingNimbus()? "nimbusBase" : "activeCaption"); |
||||||
|
|
||||||
|
// Some LAFs (e.g. GTK) don't contain "activeCaption"
|
||||||
|
if (titleColor == null) { |
||||||
|
titleColor = controlColor; |
||||||
|
} |
||||||
|
float hsb[] = Color.RGBtoHSB( |
||||||
|
titleColor.getRed(), titleColor.getGreen(), titleColor.getBlue(), null); |
||||||
|
UIManager.put(TITLE_GRADIENT_COLOR1_KEY, |
||||||
|
Color.getHSBColor(hsb[0]-.013f, .15f, .85f)); |
||||||
|
UIManager.put(TITLE_GRADIENT_COLOR2_KEY, |
||||||
|
Color.getHSBColor(hsb[0]-.005f, .24f, .80f)); |
||||||
|
UIManager.put(TITLE_FOREGROUND_KEY, |
||||||
|
Color.getHSBColor(hsb[0], .54f, .40f)); |
||||||
|
|
||||||
|
// Calculate highlight color for code pane
|
||||||
|
UIManager.put(CODE_HIGHLIGHT_KEY, |
||||||
|
Color.getHSBColor(hsb[0]-.005f, .20f, .95f)); |
||||||
|
|
||||||
|
Font labelFont = UIManager.getFont("Label.font"); |
||||||
|
UIManager.put(TITLE_FONT_KEY, labelFont.deriveFont(Font.BOLD, labelFont.getSize()+4f)); |
||||||
|
|
||||||
|
Color panelColor = UIManager.getColor("Panel.background"); |
||||||
|
UIManager.put(SUB_PANEL_BACKGROUND_KEY, |
||||||
|
Utilities.deriveColorHSB(panelColor, 0, 0, -.06f)); |
||||||
|
|
||||||
|
applyDefaults(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
protected void applyDefaults() { |
||||||
|
if (codeViewer != null) { |
||||||
|
codeViewer.setHighlightColor(UIManager.getColor(CODE_HIGHLIGHT_KEY)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected JComponent createMainPanel() { |
||||||
|
|
||||||
|
// Create main panel with demo selection on left and demo/source on right
|
||||||
|
mainPanel = new JPanel(); |
||||||
|
mainPanel.setLayout(new BorderLayout()); |
||||||
|
|
||||||
|
// Create demo selector panel on left
|
||||||
|
demoSelectorPanel = new DemoSelectorPanel(demoListTitle, demoList); |
||||||
|
demoSelectorPanel.setPreferredSize(new Dimension(DEMO_SELECTOR_WIDTH, MAIN_FRAME_HEIGHT)); |
||||||
|
demoSelectorPanel.addPropertyChangeListener(new DemoSelectionListener()); |
||||||
|
mainPanel.add(demoSelectorPanel, BorderLayout.WEST); |
||||||
|
|
||||||
|
// Create splitpane on right to hold demo and source code
|
||||||
|
demoSplitPane = new AnimatingSplitPane(JSplitPane.VERTICAL_SPLIT); |
||||||
|
demoSplitPane.setBorder(EMPTY_BORDER); |
||||||
|
mainPanel.add(demoSplitPane, BorderLayout.CENTER); |
||||||
|
|
||||||
|
// Create panel to contain currently running demo
|
||||||
|
demoContainer = new JPanel(); |
||||||
|
demoContainer.setLayout(new BorderLayout()); |
||||||
|
demoContainer.setBorder(PANEL_BORDER); |
||||||
|
demoContainer.setPreferredSize(new Dimension(DEMO_PANEL_WIDTH, DEMO_PANEL_HEIGHT)); |
||||||
|
demoSplitPane.setTopComponent(demoContainer); |
||||||
|
|
||||||
|
currentDemoPanel = demoPlaceholder; |
||||||
|
demoContainer.add(demoPlaceholder, BorderLayout.CENTER); |
||||||
|
|
||||||
|
// Create collapsible source code pane
|
||||||
|
|
||||||
|
codeViewer = new CodeViewer(); |
||||||
|
codeContainer = new JPanel(new BorderLayout()); |
||||||
|
codeContainer.add(codeViewer); |
||||||
|
codeContainer.setBorder(PANEL_BORDER); |
||||||
|
codeContainer.setMinimumSize(new Dimension(0,0)); |
||||||
|
demoSplitPane.setBottomComponent(codeContainer); |
||||||
|
|
||||||
|
addPropertyChangeListener(new SwingSetPropertyListener()); |
||||||
|
|
||||||
|
// Create shareable popup menu for demo actions
|
||||||
|
popup = new JPopupMenu(); |
||||||
|
popup.add(new EditPropertiesAction()); |
||||||
|
popup.add(new ViewCodeSnippetAction()); |
||||||
|
|
||||||
|
return mainPanel; |
||||||
|
} |
||||||
|
|
||||||
|
protected JMenuBar createMenuBar() { |
||||||
|
|
||||||
|
JMenuBar menubar = new JMenuBar(); |
||||||
|
menubar.setName("menubar"); |
||||||
|
|
||||||
|
// File menu
|
||||||
|
JMenu fileMenu = new JMenu(); |
||||||
|
fileMenu.setName("file"); |
||||||
|
menubar.add(fileMenu); |
||||||
|
|
||||||
|
// File -> Quit
|
||||||
|
if (!runningOnMac()) { |
||||||
|
JMenuItem quitItem = new JMenuItem(); |
||||||
|
quitItem.setName("quit"); |
||||||
|
quitItem.setAction(getAction("quit")); |
||||||
|
fileMenu.add(quitItem); |
||||||
|
} |
||||||
|
|
||||||
|
// View menu
|
||||||
|
JMenu viewMenu = new JMenu(); |
||||||
|
viewMenu.setName("view"); |
||||||
|
// View -> Look and Feel
|
||||||
|
viewMenu.add(createLookAndFeelMenu()); |
||||||
|
// View -> Source Code Visible
|
||||||
|
sourceCodeCheckboxItem = new JCheckBoxMenuItem(); |
||||||
|
sourceCodeCheckboxItem.setSelected(isSourceCodeVisible()); |
||||||
|
sourceCodeCheckboxItem.setName("sourceCodeCheckboxItem"); |
||||||
|
sourceCodeCheckboxItem.addChangeListener(new SourceVisibilityChangeListener()); |
||||||
|
viewMenu.add(sourceCodeCheckboxItem); |
||||||
|
menubar.add(viewMenu); |
||||||
|
|
||||||
|
return menubar; |
||||||
|
} |
||||||
|
|
||||||
|
protected JMenu createLookAndFeelMenu() { |
||||||
|
JMenu menu = new JMenu(); |
||||||
|
menu.setName("lookAndFeel"); |
||||||
|
|
||||||
|
// Look for toolkit look and feels first
|
||||||
|
UIManager.LookAndFeelInfo lookAndFeelInfos[] = UIManager.getInstalledLookAndFeels(); |
||||||
|
lookAndFeel = UIManager.getLookAndFeel().getClass().getName(); |
||||||
|
lookAndFeelRadioGroup = new ButtonGroup(); |
||||||
|
for(UIManager.LookAndFeelInfo lafInfo: lookAndFeelInfos) { |
||||||
|
menu.add(createLookAndFeelItem(lafInfo.getName(), lafInfo.getClassName())); |
||||||
|
} |
||||||
|
// Now load any look and feels defined externally as service via java.util.ServiceLoader
|
||||||
|
LOOK_AND_FEEL_LOADER.iterator(); |
||||||
|
for (LookAndFeel laf : LOOK_AND_FEEL_LOADER) { |
||||||
|
menu.add(createLookAndFeelItem(laf.getName(), laf.getClass().getName())); |
||||||
|
} |
||||||
|
|
||||||
|
return menu; |
||||||
|
} |
||||||
|
|
||||||
|
protected JRadioButtonMenuItem createLookAndFeelItem(String lafName, String lafClassName) { |
||||||
|
JRadioButtonMenuItem lafItem = new JRadioButtonMenuItem(); |
||||||
|
|
||||||
|
lafItem.setSelected(lafClassName.equals(lookAndFeel)); |
||||||
|
lafItem.setHideActionText(true); |
||||||
|
lafItem.setAction(getAction("setLookAndFeel")); |
||||||
|
lafItem.setText(lafName); |
||||||
|
lafItem.setActionCommand(lafClassName); |
||||||
|
lookAndFeelRadioGroup.add(lafItem); |
||||||
|
|
||||||
|
return lafItem; |
||||||
|
} |
||||||
|
|
||||||
|
private javax.swing.Action getAction(String actionName) { |
||||||
|
return getContext().getActionMap().get(actionName); |
||||||
|
} |
||||||
|
|
||||||
|
// For displaying error messages to user
|
||||||
|
protected void displayErrorMessage(String message, Exception ex) { |
||||||
|
JPanel messagePanel = new JPanel(new BorderLayout()); |
||||||
|
JLabel label = new JLabel(message); |
||||||
|
messagePanel.add(label); |
||||||
|
if (ex != null) { |
||||||
|
RoundedPanel panel = new RoundedPanel(new BorderLayout()); |
||||||
|
panel.setBorder(new RoundedBorder()); |
||||||
|
|
||||||
|
// remind(aim): provide way to allow user to see exception only if desired
|
||||||
|
StringWriter writer = new StringWriter(); |
||||||
|
ex.printStackTrace(new PrintWriter(writer)); |
||||||
|
JTextArea exceptionText = new JTextArea(); |
||||||
|
exceptionText.setText("Cause of error:\n" + |
||||||
|
writer.getBuffer().toString()); |
||||||
|
exceptionText.setBorder(new RoundedBorder()); |
||||||
|
exceptionText.setOpaque(false); |
||||||
|
exceptionText.setBackground( |
||||||
|
Utilities.deriveColorHSB(UIManager.getColor("Panel.background"), |
||||||
|
0, 0, -.2f)); |
||||||
|
JScrollPane scrollpane = new JScrollPane(exceptionText); |
||||||
|
scrollpane.setBorder(EMPTY_BORDER); |
||||||
|
scrollpane.setPreferredSize(new Dimension(600,240)); |
||||||
|
panel.add(scrollpane); |
||||||
|
messagePanel.add(panel, BorderLayout.SOUTH); |
||||||
|
} |
||||||
|
JOptionPane.showMessageDialog(getMainFrame(), messagePanel, |
||||||
|
resourceMap.getString("error.title"), |
||||||
|
JOptionPane.ERROR_MESSAGE); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public void setDemoPlaceholder(JComponent demoPlaceholder) { |
||||||
|
JComponent oldDemoPlaceholder = this.demoPlaceholder; |
||||||
|
this.demoPlaceholder = demoPlaceholder; |
||||||
|
firePropertyChange("demoPlaceholder", oldDemoPlaceholder, demoPlaceholder); |
||||||
|
} |
||||||
|
|
||||||
|
public JComponent getDemoPlaceholder() { |
||||||
|
return demoPlaceholder; |
||||||
|
} |
||||||
|
|
||||||
|
public void setCurrentDemo(Demo demo) { |
||||||
|
if (currentDemo == demo) { |
||||||
|
return; // already there
|
||||||
|
} |
||||||
|
Demo oldCurrentDemo = currentDemo; |
||||||
|
currentDemo = demo; |
||||||
|
if (demo != null) { |
||||||
|
DemoPanel demoPanel = runningDemoCache.get(demo.getName()); |
||||||
|
if (demoPanel == null || demo.getDemoComponent() == null) { |
||||||
|
demo.startInitializing(); |
||||||
|
demoPanel = new DemoPanel(demo); |
||||||
|
demoPanel.setPreferredSize(currentDemoPanel.getPreferredSize()); |
||||||
|
runningDemoCache.put(demo.getName(), demoPanel); |
||||||
|
} |
||||||
|
demoContainer.remove(currentDemoPanel); |
||||||
|
currentDemoPanel = demoPanel; |
||||||
|
demoContainer.add(currentDemoPanel, BorderLayout.CENTER); |
||||||
|
demoContainer.revalidate(); |
||||||
|
demoContainer.repaint(); |
||||||
|
getMainFrame().validate(); |
||||||
|
} |
||||||
|
|
||||||
|
if (currentDemo == null) { |
||||||
|
demoContainer.add(demoPlaceholder, BorderLayout.CENTER); |
||||||
|
} |
||||||
|
|
||||||
|
if (isSourceCodeVisible()) { |
||||||
|
codeViewer.setSourceFiles(currentDemo != null? |
||||||
|
currentDemo.getSourceFiles() : null); |
||||||
|
} |
||||||
|
|
||||||
|
firePropertyChange("currentDemo", oldCurrentDemo, demo); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public Demo getCurrentDemo() { |
||||||
|
return currentDemo; |
||||||
|
} |
||||||
|
|
||||||
|
public void setLookAndFeel(String lookAndFeel) throws ClassNotFoundException, |
||||||
|
InstantiationException, IllegalAccessException, UnsupportedLookAndFeelException { |
||||||
|
|
||||||
|
String oldLookAndFeel = this.lookAndFeel; |
||||||
|
|
||||||
|
if (oldLookAndFeel != lookAndFeel) { |
||||||
|
UIManager.setLookAndFeel(lookAndFeel); |
||||||
|
this.lookAndFeel = lookAndFeel; |
||||||
|
updateLookAndFeel(); |
||||||
|
firePropertyChange("lookAndFeel", oldLookAndFeel, lookAndFeel); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Action |
||||||
|
public void setLookAndFeel() { |
||||||
|
ButtonModel model = lookAndFeelRadioGroup.getSelection(); |
||||||
|
String lookAndFeelName = model.getActionCommand(); |
||||||
|
try { |
||||||
|
setLookAndFeel(lookAndFeelName); |
||||||
|
} catch (Exception ex) { |
||||||
|
displayErrorMessage(resourceMap.getString("error.unableToChangeLookAndFeel") + |
||||||
|
"to "+lookAndFeelName, ex); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public String getLookAndFeel() { |
||||||
|
return lookAndFeel; |
||||||
|
} |
||||||
|
|
||||||
|
public void setSourceCodeVisible(boolean sourceVisible) { |
||||||
|
boolean oldSourceVisible = this.sourceVisible; |
||||||
|
this.sourceVisible = sourceVisible; |
||||||
|
firePropertyChange("sourceCodeVisible", oldSourceVisible, sourceVisible); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isSourceCodeVisible() { |
||||||
|
return sourceVisible; |
||||||
|
} |
||||||
|
|
||||||
|
private void updateLookAndFeel() { |
||||||
|
Window windows[] = Frame.getWindows(); |
||||||
|
|
||||||
|
for(Window window : windows) { |
||||||
|
SwingUtilities.updateComponentTreeUI(window); |
||||||
|
for(DemoPanel demoPanel : runningDemoCache.values()) { |
||||||
|
SwingUtilities.updateComponentTreeUI(demoPanel); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// hook used to detect if any components in the demo have registered a
|
||||||
|
// code snippet key for the their creation code inside the source
|
||||||
|
private void registerPopups(Component component) { |
||||||
|
|
||||||
|
if (component instanceof Container) { |
||||||
|
Component children[] = ((Container)component).getComponents(); |
||||||
|
for(Component child: children) { |
||||||
|
if (child instanceof JComponent) { |
||||||
|
registerPopups(child); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (component instanceof JComponent) { |
||||||
|
JComponent jcomponent = (JComponent)component; |
||||||
|
String snippetKey = (String)jcomponent.getClientProperty("snippetKey"); |
||||||
|
if (snippetKey != null) { |
||||||
|
jcomponent.setComponentPopupMenu(popup); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class DemoSelectionListener implements PropertyChangeListener { |
||||||
|
public void propertyChange(PropertyChangeEvent event) { |
||||||
|
if (event.getPropertyName().equals("selectedDemo")) { |
||||||
|
setCurrentDemo((Demo)event.getNewValue()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
// registered on Demo to detect when the demo component is instantiated.
|
||||||
|
// we need this because when we embed the demo inside an HTML description pane,
|
||||||
|
// we don't have control over the demo component's instantiation
|
||||||
|
private class DemoPropertyChangeListener implements PropertyChangeListener { |
||||||
|
public void propertyChange(PropertyChangeEvent e) { |
||||||
|
String propertyName = e.getPropertyName(); |
||||||
|
if (propertyName.equals("demoComponent")) { |
||||||
|
Demo demo = (Demo)e.getSource(); |
||||||
|
JComponent demoComponent = (JComponent)e.getNewValue(); |
||||||
|
if (demoComponent != null) { |
||||||
|
demoComponent.putClientProperty("swingset3.demo", demo); |
||||||
|
demoComponent.addHierarchyListener(new DemoVisibilityListener()); |
||||||
|
registerPopups(demoComponent); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class DemoVisibilityListener implements HierarchyListener { |
||||||
|
public void hierarchyChanged(HierarchyEvent event) { |
||||||
|
if ((event.getChangeFlags() & HierarchyEvent.SHOWING_CHANGED) > 0) { |
||||||
|
JComponent component = (JComponent)event.getComponent(); |
||||||
|
final Demo demo = (Demo)component.getClientProperty("swingset3.demo"); |
||||||
|
if (!component.isShowing()) { |
||||||
|
demo.stop(); |
||||||
|
} else { |
||||||
|
demoContainer.revalidate(); |
||||||
|
EventQueue.invokeLater(new Runnable() { |
||||||
|
public void run() { |
||||||
|
demo.start(); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
// activated when user selects/unselects checkbox menu item
|
||||||
|
private class SourceVisibilityChangeListener implements ChangeListener { |
||||||
|
public void stateChanged(ChangeEvent event) { |
||||||
|
setSourceCodeVisible(sourceCodeCheckboxItem.isSelected()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class SwingSetPropertyListener implements PropertyChangeListener { |
||||||
|
public void propertyChange(PropertyChangeEvent event) { |
||||||
|
String propertyName = event.getPropertyName(); |
||||||
|
if (propertyName.equals("sourceCodeVisible")) { |
||||||
|
boolean sourceVisible = ((Boolean)event.getNewValue()).booleanValue(); |
||||||
|
if (sourceVisible) { |
||||||
|
// update codeViewer in case current demo changed while
|
||||||
|
// source was invisible
|
||||||
|
codeViewer.setSourceFiles(currentDemo != null? |
||||||
|
currentDemo.getSourceFiles() : null); |
||||||
|
} |
||||||
|
demoSplitPane.setExpanded(!sourceVisible); |
||||||
|
sourceCodeCheckboxItem.setSelected(sourceVisible); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class ViewCodeSnippetAction extends AbstractAction { |
||||||
|
public ViewCodeSnippetAction() { |
||||||
|
super("View Source Code"); |
||||||
|
} |
||||||
|
public void actionPerformed(ActionEvent actionEvent) { |
||||||
|
Container popup = (JComponent)actionEvent.getSource(); |
||||||
|
while(popup != null && !(popup instanceof JPopupMenu)) { |
||||||
|
popup = popup.getParent(); |
||||||
|
} |
||||||
|
JComponent target = (JComponent)((JPopupMenu)popup).getInvoker(); |
||||||
|
setSourceCodeVisible(true); |
||||||
|
|
||||||
|
String snippetKey = (String)target.getClientProperty("snippetKey"); |
||||||
|
if (snippetKey != null) { |
||||||
|
codeViewer.highlightSnippetSet(snippetKey); |
||||||
|
} else { |
||||||
|
logger.log(Level.WARNING, "can't find source code snippet for:" + snippetKey); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static class EditPropertiesAction extends AbstractAction { |
||||||
|
public EditPropertiesAction() { |
||||||
|
super("Edit Properties"); |
||||||
|
} |
||||||
|
public boolean isEnabled() { |
||||||
|
return false; |
||||||
|
} |
||||||
|
public void actionPerformed(ActionEvent actionEvent) { |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,410 @@ |
|||||||
|
/** |
||||||
|
* CodeStyler.java |
||||||
|
* |
||||||
|
* Bill Lynch & Matt Tucker |
||||||
|
* CoolServlets.com, October 1999 |
||||||
|
* |
||||||
|
* Please visit CoolServlets.com for high quality, open source Java servlets. |
||||||
|
* |
||||||
|
* Copyright (C) 1999 CoolServlets.com |
||||||
|
* |
||||||
|
* Any errors or suggested improvements to this class can be reported |
||||||
|
* as instructed on Coolservlets.com. We hope you enjoy |
||||||
|
* this program... your comments will encourage further development! |
||||||
|
* |
||||||
|
* This software is distributed under the terms of The BSD License. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions are met: |
||||||
|
* * Redistributions of source code must retain the above copyright notice, |
||||||
|
* this list of conditions and the following disclaimer. |
||||||
|
* * Redistributions in binary form must reproduce the above copyright notice, |
||||||
|
* this list of conditions and the following disclaimer in the documentation |
||||||
|
* and/or other materials provided with the distribution. |
||||||
|
* Neither name of CoolServlets.com nor the names of its contributors may be |
||||||
|
* used to endorse or promote products derived from this software without |
||||||
|
* specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY COOLSERVLETS.COM AND CONTRIBUTORS ``AS IS'' AND |
||||||
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
||||||
|
* DISCLAIMED. IN NO EVENT SHALL COOLSERVLETS.COM OR CONTRIBUTORS BE LIABLE FOR |
||||||
|
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
/* |
||||||
|
* @(#)CodeStyler.java 1.6 02/06/13 |
||||||
|
*/ |
||||||
|
package com.sun.swingset3.codeview; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* A class that syntax highlights Java code by turning it into html. |
||||||
|
* |
||||||
|
* <p> A <code>CodeStyler</code> object is created and then keeps state as |
||||||
|
* lines are passed in. Each line passed in as java text, is returned as syntax |
||||||
|
* highlighted html text. (note: this class was originally named CodeViewer) |
||||||
|
* |
||||||
|
* <p> Users of the class can set how the java code will be highlighted with |
||||||
|
* setter methods. |
||||||
|
* |
||||||
|
* <p> Only valid java lines should be passed in since the object maintains |
||||||
|
* state and may not handle illegal code gracefully. |
||||||
|
* |
||||||
|
* <p> The actual system is implemented as a series of filters that deal with |
||||||
|
* specific portions of the java code. The filters are as follows: |
||||||
|
* |
||||||
|
* <pre> |
||||||
|
* htmlFilter |
||||||
|
* |__ |
||||||
|
* multiLineCommentFilter |
||||||
|
* |___ |
||||||
|
* inlineCommentFilter |
||||||
|
* |___ |
||||||
|
* stringFilter |
||||||
|
* |__ |
||||||
|
* keywordFilter |
||||||
|
* </pre> |
||||||
|
* |
||||||
|
* @author Bill Lynch, Matt Tucker, CoolServlets.com |
||||||
|
* @version 1.6 06/13/02 |
||||||
|
*/ |
||||||
|
public class CodeStyler { |
||||||
|
|
||||||
|
private final static Map<String, String> RESERVED_WORDS = new HashMap<String, String>(); // >= Java2 only (also, not thread-safe)
|
||||||
|
private boolean inMultiLineComment = false; |
||||||
|
private String commentStart = "</font><font size=4 color=\"#0000aa\"><i>"; |
||||||
|
private String commentEnd = "</font></i><font size=4 color=black>"; |
||||||
|
private String stringStart = "</font><font size=4 color=\"#00bb00\">"; |
||||||
|
private String stringEnd = "</font><font size=4 color=black>"; |
||||||
|
private String reservedWordStart = "<b>"; |
||||||
|
private String reservedWordEnd = "</b>"; |
||||||
|
|
||||||
|
static { |
||||||
|
loadHash(); |
||||||
|
} |
||||||
|
|
||||||
|
public CodeStyler() { |
||||||
|
} |
||||||
|
|
||||||
|
public void setCommentStart(String commentStart) { |
||||||
|
this.commentStart = commentStart; |
||||||
|
} |
||||||
|
public void setCommentEnd(String commentEnd) { |
||||||
|
this.commentEnd = commentEnd; |
||||||
|
} |
||||||
|
public void setStringStart(String stringStart) { |
||||||
|
this.stringStart = stringStart; |
||||||
|
} |
||||||
|
public void setStringEnd(String stringEnd) { |
||||||
|
this.stringEnd = stringEnd; |
||||||
|
} |
||||||
|
public void setReservedWordStart(String reservedWordStart) { |
||||||
|
this.reservedWordStart = reservedWordStart; |
||||||
|
} |
||||||
|
public void setReservedWordEnd(String reservedWordEnd) { |
||||||
|
this.reservedWordEnd = reservedWordEnd; |
||||||
|
} |
||||||
|
|
||||||
|
public String getCommentStart() { |
||||||
|
return commentStart; |
||||||
|
} |
||||||
|
public String getCommentEnd() { |
||||||
|
return commentEnd; |
||||||
|
} |
||||||
|
public String getStringStart() { |
||||||
|
return stringStart; |
||||||
|
} |
||||||
|
public String getStringEnd() { |
||||||
|
return stringEnd; |
||||||
|
} |
||||||
|
public String getReservedWordStart() { |
||||||
|
return reservedWordStart; |
||||||
|
} |
||||||
|
public String getReservedWordEnd() { |
||||||
|
return reservedWordEnd; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Passes off each line to the first filter. |
||||||
|
* @param line The line of Java code to be highlighted. |
||||||
|
*/ |
||||||
|
public String syntaxHighlight( String line ) { |
||||||
|
return htmlFilter(line); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Filter html tags into more benign text. |
||||||
|
*/ |
||||||
|
private String htmlFilter( String line ) { |
||||||
|
if( line == null || line.equals("") ) { |
||||||
|
return ""; |
||||||
|
} |
||||||
|
|
||||||
|
// replace ampersands with HTML escape sequence for ampersand;
|
||||||
|
line = replace(line, "&", "&"); |
||||||
|
|
||||||
|
// replace the \\ with HTML escape sequences. fixes a problem when
|
||||||
|
// backslashes preceed quotes.
|
||||||
|
line = replace(line, "\\\\", "\\" ); |
||||||
|
|
||||||
|
// replace \" sequences with HTML escape sequences;
|
||||||
|
line = replace(line, "" + (char)92 + (char)34, "\""); |
||||||
|
|
||||||
|
// replace less-than signs which might be confused
|
||||||
|
// by HTML as tag angle-brackets;
|
||||||
|
line = replace(line, "<", "<"); |
||||||
|
// replace greater-than signs which might be confused
|
||||||
|
// by HTML as tag angle-brackets;
|
||||||
|
line = replace(line, ">", ">"); |
||||||
|
|
||||||
|
return multiLineCommentFilter(line); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Filter out multiLine comments. State is kept with a private boolean |
||||||
|
* variable. |
||||||
|
*/ |
||||||
|
private String multiLineCommentFilter(String line) { |
||||||
|
if (line == null || line.equals("")) { |
||||||
|
return ""; |
||||||
|
} |
||||||
|
StringBuffer buf = new StringBuffer(); |
||||||
|
int index; |
||||||
|
//First, check for the end of a multi-line comment.
|
||||||
|
if (inMultiLineComment && (index = line.indexOf("*/")) > -1 && !isInsideString(line,index)) { |
||||||
|
inMultiLineComment = false; |
||||||
|
buf.append(line.substring(0,index)); |
||||||
|
buf.append("*/").append(commentEnd); |
||||||
|
if (line.length() > index+2) { |
||||||
|
buf.append(inlineCommentFilter(line.substring(index+2))); |
||||||
|
} |
||||||
|
return buf.toString(); |
||||||
|
} |
||||||
|
//If there was no end detected and we're currently in a multi-line
|
||||||
|
//comment, we don't want to do anymore work, so return line.
|
||||||
|
else if (inMultiLineComment) { |
||||||
|
return line; |
||||||
|
} |
||||||
|
//We're not currently in a comment, so check to see if the start
|
||||||
|
//of a multi-line comment is in this line.
|
||||||
|
else if ((index = line.indexOf("/*")) > -1 && !isInsideString(line,index)) { |
||||||
|
inMultiLineComment = true; |
||||||
|
//Return result of other filters + everything after the start
|
||||||
|
//of the multiline comment. We need to pass the through the
|
||||||
|
//to the multiLineComment filter again in case the comment ends
|
||||||
|
//on the same line.
|
||||||
|
buf.append(inlineCommentFilter(line.substring(0,index))); |
||||||
|
buf.append(commentStart).append("/*"); |
||||||
|
buf.append(multiLineCommentFilter(line.substring(index+2))); |
||||||
|
return buf.toString(); |
||||||
|
} |
||||||
|
//Otherwise, no useful multi-line comment information was found so
|
||||||
|
//pass the line down to the next filter for processesing.
|
||||||
|
else { |
||||||
|
return inlineCommentFilter(line); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Filter inline comments from a line and formats them properly. |
||||||
|
*/ |
||||||
|
private String inlineCommentFilter(String line) { |
||||||
|
if (line == null || line.equals("")) { |
||||||
|
return ""; |
||||||
|
} |
||||||
|
StringBuffer buf = new StringBuffer(); |
||||||
|
int index; |
||||||
|
if ((index = line.indexOf("//")) > -1 && !isInsideString(line,index)) { |
||||||
|
buf.append(stringFilter(line.substring(0,index))); |
||||||
|
buf.append(commentStart); |
||||||
|
buf.append(line.substring(index)); |
||||||
|
buf.append(commentEnd); |
||||||
|
} |
||||||
|
else { |
||||||
|
buf.append(stringFilter(line)); |
||||||
|
} |
||||||
|
return buf.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Filters strings from a line of text and formats them properly. |
||||||
|
*/ |
||||||
|
private String stringFilter(String line) { |
||||||
|
if (line == null || line.equals("")) { |
||||||
|
return ""; |
||||||
|
} |
||||||
|
StringBuffer buf = new StringBuffer(); |
||||||
|
if (!line.contains("\"")) { |
||||||
|
return keywordFilter(line); |
||||||
|
} |
||||||
|
int start = 0; |
||||||
|
int startStringIndex = -1; |
||||||
|
int endStringIndex; |
||||||
|
int tempIndex; |
||||||
|
//Keep moving through String characters until we want to stop...
|
||||||
|
while ((tempIndex = line.indexOf("\"")) > -1) { |
||||||
|
//We found the beginning of a string
|
||||||
|
if (startStringIndex == -1) { |
||||||
|
startStringIndex = 0; |
||||||
|
buf.append( stringFilter(line.substring(start,tempIndex)) ); |
||||||
|
buf.append(stringStart).append("\""); |
||||||
|
line = line.substring(tempIndex+1); |
||||||
|
} |
||||||
|
//Must be at the end
|
||||||
|
else { |
||||||
|
startStringIndex = -1; |
||||||
|
endStringIndex = tempIndex; |
||||||
|
buf.append(line.substring(0,endStringIndex+1)); |
||||||
|
buf.append(stringEnd); |
||||||
|
line = line.substring(endStringIndex+1); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
buf.append( keywordFilter(line) ); |
||||||
|
|
||||||
|
return buf.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Filters keywords from a line of text and formats them properly. |
||||||
|
*/ |
||||||
|
private String keywordFilter( String line ) { |
||||||
|
if( line == null || line.equals("") ) { |
||||||
|
return ""; |
||||||
|
} |
||||||
|
StringBuffer buf = new StringBuffer(); |
||||||
|
Map<String, String> usedReservedWords = new HashMap<String, String>(); // >= Java2 only (not thread-safe)
|
||||||
|
//Hashtable usedReservedWords = new Hashtable(); // < Java2 (thread-safe)
|
||||||
|
int i=0; |
||||||
|
char ch; |
||||||
|
StringBuffer temp = new StringBuffer(); |
||||||
|
while( i < line.length() ) { |
||||||
|
temp.setLength(0); |
||||||
|
ch = line.charAt(i); |
||||||
|
// 65-90, uppercase letters
|
||||||
|
// 97-122, lowercase letters
|
||||||
|
while( i<line.length() && ( ( ch >= 65 && ch <= 90 ) |
||||||
|
|| ( ch >= 97 && ch <= 122 ) ) ) { |
||||||
|
temp.append(ch); |
||||||
|
i++; |
||||||
|
if( i < line.length() ) { |
||||||
|
ch = line.charAt(i); |
||||||
|
} |
||||||
|
} |
||||||
|
String tempString = temp.toString(); |
||||||
|
if( RESERVED_WORDS.containsKey(tempString) && !usedReservedWords.containsKey(tempString)) { |
||||||
|
usedReservedWords.put(tempString,tempString); |
||||||
|
line = replace( line, tempString, (reservedWordStart+tempString+reservedWordEnd) ); |
||||||
|
i += (reservedWordStart.length() + reservedWordEnd.length()); |
||||||
|
} |
||||||
|
else { |
||||||
|
i++; |
||||||
|
} |
||||||
|
} |
||||||
|
buf.append(line); |
||||||
|
return buf.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* All important replace method. Replaces all occurences of oldString in |
||||||
|
* line with newString. |
||||||
|
*/ |
||||||
|
private static String replace( String line, String oldString, String newString ) { |
||||||
|
int i=0; |
||||||
|
while( ( i=line.indexOf( oldString, i ) ) >= 0 ) { |
||||||
|
line = (new StringBuffer().append(line.substring(0,i)).append(newString).append(line.substring(i+oldString.length()))).toString(); |
||||||
|
i += newString.length(); |
||||||
|
} |
||||||
|
return line; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Checks to see if some position in a line is between String start and |
||||||
|
* ending characters. Not yet used in code or fully working :) |
||||||
|
*/ |
||||||
|
private static boolean isInsideString(String line, int position) { |
||||||
|
if (!line.contains("\"")) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
int index; |
||||||
|
String left = line.substring(0,position); |
||||||
|
String right = line.substring(position); |
||||||
|
int leftCount = 0; |
||||||
|
int rightCount = 0; |
||||||
|
while ((index = left.indexOf("\"")) > -1) { |
||||||
|
leftCount ++; |
||||||
|
left = left.substring(index+1); |
||||||
|
} |
||||||
|
while ((index = right.indexOf("\"")) > -1) { |
||||||
|
rightCount ++; |
||||||
|
right = right.substring(index+1); |
||||||
|
} |
||||||
|
return rightCount % 2 != 0 && leftCount % 2 != 0; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Load Hashtable (or HashMap) with Java reserved words. |
||||||
|
*/ |
||||||
|
private static void loadHash() { |
||||||
|
RESERVED_WORDS.put("abstract", "abstract"); |
||||||
|
RESERVED_WORDS.put("do", "do"); |
||||||
|
RESERVED_WORDS.put("inner", "inner"); |
||||||
|
RESERVED_WORDS.put("public", "public"); |
||||||
|
RESERVED_WORDS.put("var", "var"); |
||||||
|
RESERVED_WORDS.put("boolean", "boolean"); |
||||||
|
RESERVED_WORDS.put("continue", "continue"); |
||||||
|
RESERVED_WORDS.put("int", "int"); |
||||||
|
RESERVED_WORDS.put("return", "return"); |
||||||
|
RESERVED_WORDS.put("void", "void"); |
||||||
|
RESERVED_WORDS.put("break", "break"); |
||||||
|
RESERVED_WORDS.put("else", "else"); |
||||||
|
RESERVED_WORDS.put("interface", "interface"); |
||||||
|
RESERVED_WORDS.put("short", "short"); |
||||||
|
RESERVED_WORDS.put("volatile", "volatile"); |
||||||
|
RESERVED_WORDS.put("byvalue", "byvalue"); |
||||||
|
RESERVED_WORDS.put("extends", "extends"); |
||||||
|
RESERVED_WORDS.put("long", "long"); |
||||||
|
RESERVED_WORDS.put("static", "static"); |
||||||
|
RESERVED_WORDS.put("while", "while"); |
||||||
|
RESERVED_WORDS.put("case", "case"); |
||||||
|
RESERVED_WORDS.put("final", "final"); |
||||||
|
RESERVED_WORDS.put("naive", "naive"); |
||||||
|
RESERVED_WORDS.put("super", "super"); |
||||||
|
RESERVED_WORDS.put("transient", "transient"); |
||||||
|
RESERVED_WORDS.put("cast", "cast"); |
||||||
|
RESERVED_WORDS.put("float", "float"); |
||||||
|
RESERVED_WORDS.put("new", "new"); |
||||||
|
RESERVED_WORDS.put("rest", "rest"); |
||||||
|
RESERVED_WORDS.put("catch", "catch"); |
||||||
|
RESERVED_WORDS.put("for", "for"); |
||||||
|
RESERVED_WORDS.put("null", "null"); |
||||||
|
RESERVED_WORDS.put("synchronized", "synchronized"); |
||||||
|
RESERVED_WORDS.put("char", "char"); |
||||||
|
RESERVED_WORDS.put("finally", "finally"); |
||||||
|
RESERVED_WORDS.put("operator", "operator"); |
||||||
|
RESERVED_WORDS.put("this", "this"); |
||||||
|
RESERVED_WORDS.put("class", "class"); |
||||||
|
RESERVED_WORDS.put("generic", "generic"); |
||||||
|
RESERVED_WORDS.put("outer", "outer"); |
||||||
|
RESERVED_WORDS.put("switch", "switch"); |
||||||
|
RESERVED_WORDS.put("const", "const"); |
||||||
|
RESERVED_WORDS.put("goto", "goto"); |
||||||
|
RESERVED_WORDS.put("package", "package"); |
||||||
|
RESERVED_WORDS.put("throw", "throw"); |
||||||
|
RESERVED_WORDS.put("double", "double"); |
||||||
|
RESERVED_WORDS.put("if", "if"); |
||||||
|
RESERVED_WORDS.put("private", "private"); |
||||||
|
RESERVED_WORDS.put("true", "true"); |
||||||
|
RESERVED_WORDS.put("default", "default"); |
||||||
|
RESERVED_WORDS.put("import", "import"); |
||||||
|
RESERVED_WORDS.put("protected", "protected"); |
||||||
|
RESERVED_WORDS.put("try", "try"); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,927 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.sun.swingset3.codeview; |
||||||
|
|
||||||
|
import java.awt.AlphaComposite; |
||||||
|
import java.awt.BorderLayout; |
||||||
|
import java.awt.Color; |
||||||
|
import java.awt.Component; |
||||||
|
import java.awt.Dimension; |
||||||
|
import java.awt.Font; |
||||||
|
import java.awt.FontMetrics; |
||||||
|
import java.awt.Graphics; |
||||||
|
import java.awt.Graphics2D; |
||||||
|
import java.awt.GridBagConstraints; |
||||||
|
import java.awt.GridBagLayout; |
||||||
|
import java.awt.Rectangle; |
||||||
|
import java.awt.Toolkit; |
||||||
|
import java.awt.event.ActionEvent; |
||||||
|
import java.awt.event.ActionListener; |
||||||
|
import java.awt.image.BufferedImage; |
||||||
|
import java.io.*; |
||||||
|
import java.net.URL; |
||||||
|
import java.util.*; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
import javax.imageio.ImageIO; |
||||||
|
import javax.swing.*; |
||||||
|
import javax.swing.border.EmptyBorder; |
||||||
|
import javax.swing.text.BadLocationException; |
||||||
|
import javax.swing.text.Highlighter; |
||||||
|
import com.sun.swingset3.utilities.RoundedBorder; |
||||||
|
import com.sun.swingset3.utilities.RoundedPanel; |
||||||
|
import com.sun.swingset3.utilities.Utilities; |
||||||
|
|
||||||
|
/** |
||||||
|
* GUI component for viewing a set of one or more Java source code files, |
||||||
|
* providing the user with the ability to easily highlight specific code fragments. |
||||||
|
* A tabbedpane is used to control which source code file is shown within the set |
||||||
|
* if more than one file is loaded. |
||||||
|
* <p> |
||||||
|
* Example usage: |
||||||
|
* <pre><code> |
||||||
|
* CodeViewer codeViewer = new CodeViewer(); |
||||||
|
* codeViewer.setSourceFiles(mySourceURLs); |
||||||
|
* frame.add(codeViewer); |
||||||
|
* </code></pre> |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* When loading the source code, this viewer will automatically parse the files for |
||||||
|
* any source fragments which are marked with "snippet" start/end tags that |
||||||
|
* are embedded within Java comments. The viewer will allow the user to highlight |
||||||
|
* these code snippets for easier inspection of specific code. |
||||||
|
* <p> |
||||||
|
* The text following immediately after the start tag will be used |
||||||
|
* as the key for that snippet. Multiple snippets may share the same |
||||||
|
* key, defining a "snippet set". Snippet sets may even span across |
||||||
|
* multiple source files. |
||||||
|
* The key for each snippet set is displayed in a combobox to allow the user to |
||||||
|
* select which snippet set should be highlighted. For example:<p> |
||||||
|
* <pre><code> |
||||||
|
* //<snip>Create dog array
|
||||||
|
* ArrayList dogs = new ArrayList(); |
||||||
|
* //</snip>
|
||||||
|
* |
||||||
|
* [other code...] |
||||||
|
* |
||||||
|
* //<snip>Create dog array
|
||||||
|
* dogs.add("Labrador"); |
||||||
|
* dogs.add("Golden Retriever"); |
||||||
|
* dogs.add("Australian Shepherd"); |
||||||
|
* //</snip>
|
||||||
|
* </code></pre> |
||||||
|
* The above code would create a snippet set (containing 2 snippets) with the key |
||||||
|
* "Create dog array". |
||||||
|
* <p> |
||||||
|
* The viewer will allow the user to easily navigate across the currently highlighted |
||||||
|
* snippet set by pressing the navigation buttons or using accelerator keys. |
||||||
|
* |
||||||
|
* @author aim |
||||||
|
*/ |
||||||
|
public class CodeViewer extends JPanel { |
||||||
|
public static final String SOURCES_JAVA = ".+\\.java"; |
||||||
|
|
||||||
|
public static final String SOURCES_TEXT = ".+\\.properties|.+\\.txt|.+\\.html|.+\\.xml"; |
||||||
|
|
||||||
|
public static final String SOURCES_IMAGES = ".+\\.jpg|.+\\.gif|.+\\.png"; |
||||||
|
|
||||||
|
private static final Color DEFAULT_HIGHLIGHT_COLOR = new Color(255,255,176); |
||||||
|
private static BufferedImage SNIPPET_GLYPH; |
||||||
|
private static String NO_SNIPPET_SELECTED; |
||||||
|
|
||||||
|
static final Logger logger = Logger.getLogger(CodeViewer.class.getName()); |
||||||
|
|
||||||
|
static { |
||||||
|
try { |
||||||
|
URL imageURL = CodeViewer.class.getResource("resources/images/snippetglyph.png"); |
||||||
|
SNIPPET_GLYPH = ImageIO.read(imageURL); |
||||||
|
} catch (Exception e) { |
||||||
|
System.err.println(e); |
||||||
|
} |
||||||
|
} |
||||||
|
// Cache all processed code files in case they are reloaded later
|
||||||
|
private final Map<URL,CodeFileInfo> codeCache = new HashMap<URL,CodeFileInfo>(); |
||||||
|
|
||||||
|
private JComponent codeHighlightBar; |
||||||
|
private JComboBox snippetComboBox; |
||||||
|
private JComponent codePanel; |
||||||
|
private JLabel noCodeLabel; |
||||||
|
private JTabbedPane codeTabbedPane; |
||||||
|
|
||||||
|
private Color highlightColor; |
||||||
|
private Highlighter.HighlightPainter snippetPainter; |
||||||
|
|
||||||
|
private ResourceBundle bundle; |
||||||
|
|
||||||
|
// Current code file set
|
||||||
|
private Map<URL, CodeFileInfo> currentCodeFilesInfo; |
||||||
|
private List<URL> additionalSourceFiles; |
||||||
|
|
||||||
|
// Map of all snippets in current code file set
|
||||||
|
private final SnippetMap snippetMap = new SnippetMap(); |
||||||
|
|
||||||
|
private Action firstSnippetAction; |
||||||
|
private Action nextSnippetAction; |
||||||
|
private Action previousSnippetAction; |
||||||
|
private Action lastSnippetAction; |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new instance of CodeViewer |
||||||
|
*/ |
||||||
|
public CodeViewer() { |
||||||
|
setHighlightColor(DEFAULT_HIGHLIGHT_COLOR); |
||||||
|
|
||||||
|
initActions(); |
||||||
|
|
||||||
|
setLayout(new BorderLayout()); |
||||||
|
codeHighlightBar = createCodeHighlightBar(); |
||||||
|
codeHighlightBar.setVisible(false); |
||||||
|
add(codeHighlightBar, BorderLayout.NORTH); |
||||||
|
codePanel = createCodePanel(); |
||||||
|
add(codePanel, BorderLayout.CENTER); |
||||||
|
|
||||||
|
applyDefaults(); |
||||||
|
} |
||||||
|
|
||||||
|
protected JComponent createCodeHighlightBar() { |
||||||
|
GridBagLayout gridbag = new GridBagLayout(); |
||||||
|
GridBagConstraints c = new GridBagConstraints(); |
||||||
|
JPanel bar = new JPanel(gridbag); |
||||||
|
|
||||||
|
bar.setBorder(new EmptyBorder(0, 0, 10, 0)); |
||||||
|
|
||||||
|
NO_SNIPPET_SELECTED = getString("CodeViewer.snippets.selectOne", |
||||||
|
"Select One"); |
||||||
|
|
||||||
|
JLabel snippetSetsLabel = new JLabel(getString("CodeViewer.snippets.highlightCode", |
||||||
|
"Highlight code to: ")); |
||||||
|
c.gridx = 0; |
||||||
|
c.gridy = 0; |
||||||
|
c.anchor = GridBagConstraints.WEST; |
||||||
|
c.weightx = 0; |
||||||
|
gridbag.addLayoutComponent(snippetSetsLabel, c); |
||||||
|
bar.add(snippetSetsLabel); |
||||||
|
|
||||||
|
snippetComboBox = new JComboBox(); |
||||||
|
snippetComboBox.setMaximumRowCount(20); |
||||||
|
snippetComboBox.setRenderer(new SnippetCellRenderer(snippetComboBox.getRenderer())); |
||||||
|
snippetComboBox.addActionListener(new SnippetActivator()); |
||||||
|
snippetSetsLabel.setLabelFor(snippetComboBox); |
||||||
|
c.gridx++; |
||||||
|
c.weightx = 1; |
||||||
|
gridbag.addLayoutComponent(snippetComboBox, c); |
||||||
|
bar.add(snippetComboBox); |
||||||
|
|
||||||
|
SnippetNavigator snippetNavigator = new SnippetNavigator(snippetMap); |
||||||
|
snippetNavigator.setNavigateNextAction(nextSnippetAction); |
||||||
|
snippetNavigator.setNavigatePreviousAction(previousSnippetAction); |
||||||
|
c.gridx++; |
||||||
|
c.anchor = GridBagConstraints.EAST; |
||||||
|
c.weightx = 0; |
||||||
|
gridbag.addLayoutComponent(snippetNavigator, c); |
||||||
|
bar.add(snippetNavigator); |
||||||
|
|
||||||
|
return bar; |
||||||
|
} |
||||||
|
|
||||||
|
protected JComponent createCodePanel() { |
||||||
|
|
||||||
|
JPanel panel = new RoundedPanel(new BorderLayout(), 10); |
||||||
|
panel.setBorder(new RoundedBorder(10)); |
||||||
|
|
||||||
|
noCodeLabel = new JLabel(getString("CodeViewer.noCodeLoaded", "no code loaded")); |
||||||
|
noCodeLabel.setHorizontalAlignment(JLabel.CENTER); |
||||||
|
panel.add(noCodeLabel, BorderLayout.CENTER); |
||||||
|
return panel; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void updateUI() { |
||||||
|
super.updateUI(); |
||||||
|
applyDefaults(); |
||||||
|
} |
||||||
|
|
||||||
|
protected void applyDefaults() { |
||||||
|
if (noCodeLabel != null) { |
||||||
|
noCodeLabel.setOpaque(false); |
||||||
|
noCodeLabel.setFont(UIManager.getFont("Label.font").deriveFont(24f)); |
||||||
|
noCodeLabel.setForeground( |
||||||
|
Utilities.deriveColorAlpha(UIManager.getColor("Label.foreground"), 110)); |
||||||
|
} |
||||||
|
if (codePanel != null) { |
||||||
|
Color base = UIManager.getColor("Panel.background"); |
||||||
|
codePanel.setBackground(Utilities.deriveColorHSB(base, 0, 0, -.06f)); |
||||||
|
} |
||||||
|
if (snippetComboBox != null) { |
||||||
|
// Now that the look and feel has changed, we need to wrap the new delegate
|
||||||
|
snippetComboBox.setRenderer(new SnippetCellRenderer( |
||||||
|
new JComboBox().getRenderer())); |
||||||
|
} |
||||||
|
if (currentCodeFilesInfo != null) { |
||||||
|
Collection<CodeFileInfo> codeFiles = currentCodeFilesInfo.values(); |
||||||
|
for(CodeFileInfo cfi : codeFiles) { |
||||||
|
makeSelectionTransparent(cfi.textPane, 180); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void makeSelectionTransparent(JEditorPane textPane, int alpha) { |
||||||
|
Color c = textPane.getSelectionColor(); |
||||||
|
textPane.setSelectionColor( |
||||||
|
new Color(c.getRed(), c.getGreen(), c.getBlue(), alpha)); |
||||||
|
} |
||||||
|
|
||||||
|
protected String getString(String key, String fallback) { |
||||||
|
String value = fallback; |
||||||
|
if (bundle == null) { |
||||||
|
String bundleName = getClass().getPackage().getName()+".resources."+getClass().getSimpleName(); |
||||||
|
bundle = ResourceBundle.getBundle(bundleName); |
||||||
|
} |
||||||
|
try { |
||||||
|
value = bundle != null? bundle.getString(key) : fallback; |
||||||
|
|
||||||
|
} catch (MissingResourceException e) { |
||||||
|
logger.log(Level.WARNING, "missing String resource " + key + |
||||||
|
"; using fallback \"" +fallback + "\""); |
||||||
|
} |
||||||
|
return value; |
||||||
|
} |
||||||
|
|
||||||
|
protected void initActions() { |
||||||
|
firstSnippetAction = new FirstSnippetAction(); |
||||||
|
nextSnippetAction = new NextSnippetAction(); |
||||||
|
previousSnippetAction = new PreviousSnippetAction(); |
||||||
|
lastSnippetAction = new LastSnippetAction(); |
||||||
|
|
||||||
|
firstSnippetAction.setEnabled(false); |
||||||
|
nextSnippetAction.setEnabled(false); |
||||||
|
previousSnippetAction.setEnabled(false); |
||||||
|
lastSnippetAction.setEnabled(false); |
||||||
|
|
||||||
|
getActionMap().put("NextSnippet", nextSnippetAction); |
||||||
|
getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ctrl N"),"NextSnippet"); |
||||||
|
|
||||||
|
getActionMap().put("PreviousSnippet", previousSnippetAction); |
||||||
|
getInputMap(WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("ctrl P"),"PreviousSnippet"); |
||||||
|
} |
||||||
|
|
||||||
|
public void setHighlightColor(Color highlight) { |
||||||
|
if (!highlight.equals(highlightColor)) { |
||||||
|
highlightColor = highlight; |
||||||
|
snippetPainter = new SnippetHighlighter.SnippetHighlightPainter(highlightColor); |
||||||
|
if (getCurrentSnippetKey() != null) { |
||||||
|
repaint(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public Color getHighlightColor() { |
||||||
|
return highlightColor; |
||||||
|
} |
||||||
|
|
||||||
|
public void setSourceFiles(URL sourceFiles[]) { |
||||||
|
if (currentCodeFilesInfo != null && additionalSourceFiles != null && sourceFiles != null && |
||||||
|
currentCodeFilesInfo.size() + additionalSourceFiles.size() == sourceFiles.length) { |
||||||
|
List<URL> list = Arrays.asList(sourceFiles); |
||||||
|
|
||||||
|
if (list.containsAll(currentCodeFilesInfo.keySet()) && list.containsAll(additionalSourceFiles)) { |
||||||
|
// already loaded
|
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// clear everything
|
||||||
|
clearAllSnippetHighlights(); |
||||||
|
snippetMap.clear(); |
||||||
|
|
||||||
|
if (sourceFiles == null) { |
||||||
|
// being reset to having no source files; need to clear everything
|
||||||
|
currentCodeFilesInfo = null; |
||||||
|
additionalSourceFiles = null; |
||||||
|
configureCodePane(false); |
||||||
|
configureSnippetSetsComboBox(); |
||||||
|
|
||||||
|
} else { |
||||||
|
// Use LinkedHashMap to save source order
|
||||||
|
currentCodeFilesInfo = new LinkedHashMap<URL, CodeFileInfo>(); |
||||||
|
additionalSourceFiles = new ArrayList<URL>(); |
||||||
|
|
||||||
|
boolean needProcessing = false; |
||||||
|
for (URL sourceFile : sourceFiles) { |
||||||
|
if (sourceFile.getFile().matches(SOURCES_JAVA)) { |
||||||
|
// look in cache first to avoid unnecessary processing
|
||||||
|
CodeFileInfo cachedFilesInfo = codeCache.get(sourceFile); |
||||||
|
|
||||||
|
currentCodeFilesInfo.put(sourceFile, cachedFilesInfo); |
||||||
|
|
||||||
|
if (cachedFilesInfo == null) { |
||||||
|
needProcessing = true; |
||||||
|
} |
||||||
|
} else { |
||||||
|
additionalSourceFiles.add(sourceFile); |
||||||
|
} |
||||||
|
} |
||||||
|
configureCodePane(true); |
||||||
|
|
||||||
|
if (needProcessing) { |
||||||
|
// Do it on a separate thread
|
||||||
|
new SourceProcessor(currentCodeFilesInfo).execute(); |
||||||
|
} else { |
||||||
|
for (CodeFileInfo codeFileInfo : currentCodeFilesInfo.values()) { |
||||||
|
registerSnippets(codeFileInfo); |
||||||
|
createCodeFileTab(codeFileInfo); |
||||||
|
} |
||||||
|
|
||||||
|
createAdditionalTabs(); |
||||||
|
configureSnippetSetsComboBox(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void createAdditionalTabs() { |
||||||
|
JPanel pnImages = null; |
||||||
|
|
||||||
|
for (URL sourceFile : additionalSourceFiles) { |
||||||
|
String sourcePath = sourceFile.getPath(); |
||||||
|
|
||||||
|
int i = sourcePath.indexOf('!'); |
||||||
|
|
||||||
|
if (i >= 0) { |
||||||
|
sourcePath = sourcePath.substring(i + 1); |
||||||
|
} |
||||||
|
|
||||||
|
if (sourceFile.getFile().matches(SOURCES_IMAGES)) { |
||||||
|
if (pnImages == null) { |
||||||
|
pnImages = new JPanel(); |
||||||
|
|
||||||
|
pnImages.setLayout(new BoxLayout(pnImages, BoxLayout.Y_AXIS)); |
||||||
|
} |
||||||
|
|
||||||
|
JLabel label = new JLabel(); |
||||||
|
|
||||||
|
label.setIcon(new ImageIcon(sourceFile)); |
||||||
|
label.setBorder(new EmptyBorder(10, 0, 40, 0)); |
||||||
|
|
||||||
|
pnImages.add(new JLabel(sourcePath)); |
||||||
|
pnImages.add(label); |
||||||
|
} |
||||||
|
|
||||||
|
if (sourceFile.getFile().matches(SOURCES_TEXT)) { |
||||||
|
BufferedReader reader = null; |
||||||
|
|
||||||
|
try { |
||||||
|
reader = new BufferedReader(new InputStreamReader(sourceFile.openStream())); |
||||||
|
|
||||||
|
StringBuilder content = new StringBuilder(); |
||||||
|
|
||||||
|
String line; |
||||||
|
|
||||||
|
while ((line = reader.readLine()) != null) { |
||||||
|
content.append(line).append('\n'); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
JTextArea textArea = new JTextArea(content.toString()); |
||||||
|
Font font = textArea.getFont(); |
||||||
|
textArea.setEditable(false); |
||||||
|
textArea.setFont(new Font("Monospaced", font.getStyle(), font.getSize())); |
||||||
|
|
||||||
|
JScrollPane scrollPane = new JScrollPane(textArea); |
||||||
|
scrollPane.setBorder(null); |
||||||
|
|
||||||
|
codeTabbedPane.addTab(Utilities.getURLFileName(sourceFile), scrollPane); |
||||||
|
} catch (IOException e) { |
||||||
|
System.err.println(e); |
||||||
|
} finally { |
||||||
|
if (reader != null) { |
||||||
|
try { |
||||||
|
reader.close(); |
||||||
|
} catch (IOException e) { |
||||||
|
System.err.println(e); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (pnImages != null) { |
||||||
|
JScrollPane scrollPane = new JScrollPane(pnImages); |
||||||
|
scrollPane.setBorder(null); |
||||||
|
|
||||||
|
codeTabbedPane.addTab(getString("CodeViewer.images", "Images"), scrollPane); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class SourceProcessor extends SwingWorker<Void, CodeFileInfo> { |
||||||
|
private final Map<URL, CodeFileInfo> codeFilesInfo; |
||||||
|
|
||||||
|
public SourceProcessor(Map<URL, CodeFileInfo> codeFilesInfo) { |
||||||
|
this.codeFilesInfo = codeFilesInfo; |
||||||
|
} |
||||||
|
|
||||||
|
public Void doInBackground() { |
||||||
|
for (Map.Entry<URL, CodeFileInfo> entry : codeFilesInfo.entrySet()) { |
||||||
|
// if not already fetched from cache, then process source code
|
||||||
|
if (entry.getValue() == null) { |
||||||
|
entry.setValue(initializeCodeFileInfo(entry.getKey())); |
||||||
|
} |
||||||
|
|
||||||
|
// We don't publish intermediate to avoid tab mixing
|
||||||
|
codeCache.put(entry.getKey(), entry.getValue()); |
||||||
|
} |
||||||
|
|
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
private CodeFileInfo initializeCodeFileInfo(URL sourceFile) { |
||||||
|
CodeFileInfo codeFileInfo = new CodeFileInfo(); |
||||||
|
codeFileInfo.url = sourceFile; |
||||||
|
codeFileInfo.styled = loadSourceCode(sourceFile); |
||||||
|
codeFileInfo.textPane = new JEditorPane(); |
||||||
|
codeFileInfo.textPane.setHighlighter(new SnippetHighlighter()); |
||||||
|
makeSelectionTransparent(codeFileInfo.textPane, 180); |
||||||
|
codeFileInfo.veneer = new CodeVeneer(codeFileInfo); |
||||||
|
Stacker layers = new Stacker(codeFileInfo.textPane); |
||||||
|
layers.add(codeFileInfo.veneer, JLayeredPane.POPUP_LAYER); |
||||||
|
codeFileInfo.textPane.setContentType("text/html"); |
||||||
|
codeFileInfo.textPane.setEditable(false); // HTML won't display correctly without this!
|
||||||
|
codeFileInfo.textPane.setText(codeFileInfo.styled); |
||||||
|
codeFileInfo.textPane.setCaretPosition(0); |
||||||
|
|
||||||
|
// MUST parse AFTER textPane Document has been created to ensure
|
||||||
|
// snippet offsets are relative to the editor pane's Document model
|
||||||
|
codeFileInfo.snippets = SnippetParser.parse(codeFileInfo.textPane.getDocument()); |
||||||
|
return codeFileInfo; |
||||||
|
} |
||||||
|
|
||||||
|
protected void done() { |
||||||
|
try { |
||||||
|
// It's possible that by now another set of source files has been loaded.
|
||||||
|
// so check first before adding the source tab;'
|
||||||
|
if (currentCodeFilesInfo == codeFilesInfo) { |
||||||
|
for (CodeFileInfo codeFileInfo : currentCodeFilesInfo.values()) { |
||||||
|
registerSnippets(codeFileInfo); |
||||||
|
createCodeFileTab(codeFileInfo); |
||||||
|
} |
||||||
|
} else { |
||||||
|
logger.log(Level.FINEST, "source files changed before sources was processed."); |
||||||
|
} |
||||||
|
|
||||||
|
createAdditionalTabs(); |
||||||
|
configureSnippetSetsComboBox(); |
||||||
|
} catch (Exception ex) { |
||||||
|
System.err.println(ex); |
||||||
|
} |
||||||
|
} |
||||||
|
} // SourceProcessor
|
||||||
|
|
||||||
|
// Called from Source Processing Thread in SwingWorker
|
||||||
|
|
||||||
|
private void configureCodePane(boolean hasCodeFiles) { |
||||||
|
if (hasCodeFiles) { |
||||||
|
if (codeTabbedPane == null) { |
||||||
|
codeTabbedPane = new JTabbedPane(); |
||||||
|
codePanel.remove(noCodeLabel); |
||||||
|
codePanel.add(codeTabbedPane); |
||||||
|
revalidate(); |
||||||
|
} else { |
||||||
|
codeTabbedPane.removeAll(); |
||||||
|
} |
||||||
|
} else { |
||||||
|
// No code files
|
||||||
|
if (codeTabbedPane != null) { |
||||||
|
codePanel.remove(codeTabbedPane); |
||||||
|
codeTabbedPane = null; |
||||||
|
codePanel.add(noCodeLabel); |
||||||
|
revalidate(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void createCodeFileTab(CodeFileInfo codeFileInfo) { |
||||||
|
JLayeredPane layeredPane = JLayeredPane.getLayeredPaneAbove(codeFileInfo.textPane); |
||||||
|
JScrollPane scrollPane = new JScrollPane(layeredPane); |
||||||
|
scrollPane.setBorder(null); |
||||||
|
JPanel tabPanel = new JPanel(); |
||||||
|
tabPanel.setLayout(new BorderLayout()); |
||||||
|
|
||||||
|
tabPanel.add(scrollPane, BorderLayout.CENTER); |
||||||
|
|
||||||
|
codeTabbedPane.addTab(Utilities.getURLFileName(codeFileInfo.url), tabPanel); |
||||||
|
} |
||||||
|
|
||||||
|
private void registerSnippets(CodeFileInfo codeFileInfo) { |
||||||
|
for(String snippetKey: codeFileInfo.snippets.keySet()) { |
||||||
|
List<Snippet> snippetCodeList = codeFileInfo.snippets.get(snippetKey); |
||||||
|
for(Snippet snippet: snippetCodeList) { |
||||||
|
snippetMap.add(snippetKey, codeFileInfo.url, snippet); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void configureSnippetSetsComboBox() { |
||||||
|
TreeSet sortedSnippets = new TreeSet(snippetMap.keySet()); |
||||||
|
String snippetSetKeys[] = (String[])sortedSnippets.toArray(new String[0]); |
||||||
|
|
||||||
|
DefaultComboBoxModel snippetModel = new DefaultComboBoxModel(); |
||||||
|
for(String snippetKey : snippetSetKeys) { |
||||||
|
snippetModel.addElement(snippetKey); |
||||||
|
} |
||||||
|
snippetModel.insertElementAt(NO_SNIPPET_SELECTED, 0); |
||||||
|
snippetModel.setSelectedItem(NO_SNIPPET_SELECTED); |
||||||
|
snippetComboBox.setModel(snippetModel); |
||||||
|
codeHighlightBar.setVisible(snippetModel.getSize() > 1); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads the java source file at the specified URL and returns an |
||||||
|
* HTML version stylized for display |
||||||
|
*/ |
||||||
|
protected String loadSourceCode(URL sourceUrl) { |
||||||
|
InputStreamReader isr = null; |
||||||
|
CodeStyler cv = new CodeStyler(); |
||||||
|
String styledCode = "<html><body bgcolor=\"#ffffff\"><pre>"; |
||||||
|
|
||||||
|
try { |
||||||
|
isr = new InputStreamReader(sourceUrl.openStream(), "UTF-8"); |
||||||
|
BufferedReader reader = new BufferedReader(isr); |
||||||
|
|
||||||
|
// Read one line at a time, htmlizing using super-spiffy
|
||||||
|
// html java code formating utility from www.CoolServlets.com
|
||||||
|
String line = reader.readLine(); |
||||||
|
while(line != null) { |
||||||
|
styledCode += cv.syntaxHighlight(line) + " \n "; |
||||||
|
line = reader.readLine(); |
||||||
|
} |
||||||
|
styledCode += "</pre></body></html>"; |
||||||
|
|
||||||
|
} catch (Exception ex) { |
||||||
|
ex.printStackTrace(); |
||||||
|
return "Could not load file from: " + sourceUrl; |
||||||
|
} finally { |
||||||
|
if (isr != null) { |
||||||
|
try { |
||||||
|
isr.close(); |
||||||
|
} catch (IOException e) { |
||||||
|
System.err.println(e); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return styledCode; |
||||||
|
} |
||||||
|
|
||||||
|
public void clearAllSnippetHighlights() { |
||||||
|
if (currentCodeFilesInfo != null) { |
||||||
|
snippetMap.setCurrentSet(null); |
||||||
|
for(CodeFileInfo code : currentCodeFilesInfo.values()) { |
||||||
|
if (code != null && code.textPane != null) { |
||||||
|
Highlighter highlighter = code.textPane.getHighlighter(); |
||||||
|
highlighter.removeAllHighlights(); |
||||||
|
code.textPane.repaint(); |
||||||
|
code.veneer.repaint(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void highlightSnippetSet(String snippetKey) { |
||||||
|
|
||||||
|
clearAllSnippetHighlights(); |
||||||
|
snippetMap.setCurrentSet(snippetKey); |
||||||
|
|
||||||
|
URL files[] = snippetMap.getFilesForSet(snippetKey); |
||||||
|
CodeFileInfo firstCodeFileInfo = null; |
||||||
|
Snippet firstSnippet = null; |
||||||
|
for(URL file : files) { |
||||||
|
CodeFileInfo codeFileInfo = codeCache.get(file); |
||||||
|
Highlighter highlighter = codeFileInfo.textPane.getHighlighter(); |
||||||
|
// now add highlight for each snippet in this file associated
|
||||||
|
// with the key
|
||||||
|
Snippet snippets[] = snippetMap.getSnippetsForFile(snippetKey, file); |
||||||
|
if (firstCodeFileInfo == null) { |
||||||
|
firstCodeFileInfo = codeFileInfo; |
||||||
|
firstSnippet = snippets[0]; |
||||||
|
} |
||||||
|
for (Snippet snippet : snippets) { |
||||||
|
try { |
||||||
|
highlighter.addHighlight(snippet.startLine, |
||||||
|
snippet.endLine, snippetPainter ); |
||||||
|
codeFileInfo.veneer.repaint(); |
||||||
|
} catch (BadLocationException e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
scrollToSnippet(firstCodeFileInfo, firstSnippet); |
||||||
|
snippetComboBox.setSelectedItem(snippetKey); |
||||||
|
} |
||||||
|
|
||||||
|
protected void scrollToSnippet(CodeFileInfo codeFileInfo, Snippet snippet) { |
||||||
|
if (!codeFileInfo.textPane.isShowing()) { |
||||||
|
// Need to switch tabs to source file with first snippet
|
||||||
|
// remind: too brittle - need to find component some other way
|
||||||
|
codeTabbedPane.setSelectedComponent( |
||||||
|
JLayeredPane.getLayeredPaneAbove(codeFileInfo.textPane).getParent().getParent().getParent()); |
||||||
|
} |
||||||
|
try { |
||||||
|
Rectangle r1 = codeFileInfo.textPane.modelToView(snippet.startLine); |
||||||
|
Rectangle r2 = codeFileInfo.textPane.modelToView(snippet.endLine); |
||||||
|
codeFileInfo.textPane.scrollRectToVisible( |
||||||
|
SwingUtilities.computeUnion(r1.x, r1.y, |
||||||
|
r1.width, r1.height, r2)); |
||||||
|
} catch (BadLocationException e) { |
||||||
|
System.err.println(e); |
||||||
|
} |
||||||
|
nextSnippetAction.setEnabled(snippetMap.nextSnippetExists()); |
||||||
|
previousSnippetAction.setEnabled(snippetMap.previousSnippetExists()); |
||||||
|
} |
||||||
|
|
||||||
|
protected String getCurrentSnippetKey() { |
||||||
|
String key = snippetMap.getCurrentSet(); |
||||||
|
return key != null? key : NO_SNIPPET_SELECTED; |
||||||
|
} |
||||||
|
|
||||||
|
protected Snippet getCurrentSnippet() { |
||||||
|
return snippetMap.getCurrentSnippet(); |
||||||
|
} |
||||||
|
|
||||||
|
protected void moveToFirstSnippet() { |
||||||
|
Snippet firstSnippet = snippetMap.firstSnippet(); |
||||||
|
if (firstSnippet != null) { |
||||||
|
CodeFileInfo codeFileInfo = codeCache.get(snippetMap.getFileForSnippet(firstSnippet)); |
||||||
|
scrollToSnippet(codeFileInfo, firstSnippet); |
||||||
|
} else { |
||||||
|
Toolkit.getDefaultToolkit().beep(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected void moveToNextSnippet() { |
||||||
|
Snippet nextSnippet = snippetMap.nextSnippet(); |
||||||
|
if (nextSnippet != null) { |
||||||
|
CodeFileInfo codeFileInfo = codeCache.get(snippetMap.getFileForSnippet(nextSnippet)); |
||||||
|
scrollToSnippet(codeFileInfo, nextSnippet); |
||||||
|
} else { |
||||||
|
Toolkit.getDefaultToolkit().beep(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected void moveToPreviousSnippet() { |
||||||
|
Snippet previousSnippet = snippetMap.previousSnippet(); |
||||||
|
if (previousSnippet != null) { |
||||||
|
CodeFileInfo codeFileInfo = codeCache.get(snippetMap.getFileForSnippet(previousSnippet)); |
||||||
|
scrollToSnippet(codeFileInfo, previousSnippet); |
||||||
|
} else { |
||||||
|
Toolkit.getDefaultToolkit().beep(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
protected void moveToLastSnippet() { |
||||||
|
Snippet lastSnippet = snippetMap.lastSnippet(); |
||||||
|
if (lastSnippet != null) { |
||||||
|
CodeFileInfo codeFileInfo = codeCache.get(snippetMap.getFileForSnippet(lastSnippet)); |
||||||
|
scrollToSnippet(codeFileInfo, lastSnippet); |
||||||
|
} else { |
||||||
|
Toolkit.getDefaultToolkit().beep(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class SnippetActivator implements ActionListener { |
||||||
|
public void actionPerformed(ActionEvent e) { |
||||||
|
String snippetKey = (String)snippetComboBox.getSelectedItem(); |
||||||
|
if (!snippetKey.equals(NO_SNIPPET_SELECTED)) { |
||||||
|
logger.log(Level.FINEST, "highlighting new snippet:"+snippetKey+"."); |
||||||
|
highlightSnippetSet(snippetKey); |
||||||
|
} else { |
||||||
|
clearAllSnippetHighlights(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private abstract class SnippetAction extends AbstractAction { |
||||||
|
public SnippetAction(String name, String shortDescription) { |
||||||
|
super(name); |
||||||
|
putValue(AbstractAction.SHORT_DESCRIPTION, shortDescription); |
||||||
|
} |
||||||
|
} |
||||||
|
private class FirstSnippetAction extends SnippetAction { |
||||||
|
public FirstSnippetAction() { |
||||||
|
super("FirstSnippet", |
||||||
|
getString("CodeViewer.snippets.navigateFirst", |
||||||
|
"move to first code snippet within highlighted set")); |
||||||
|
} |
||||||
|
public void actionPerformed(ActionEvent e) { |
||||||
|
moveToFirstSnippet(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class NextSnippetAction extends SnippetAction { |
||||||
|
public NextSnippetAction() { |
||||||
|
super("NextSnippet", |
||||||
|
getString("CodeViewer.snippets.navigateNext", |
||||||
|
"move to next code snippet within highlighted set")); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void actionPerformed(ActionEvent e) { |
||||||
|
moveToNextSnippet(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class PreviousSnippetAction extends SnippetAction { |
||||||
|
public PreviousSnippetAction() { |
||||||
|
super("PreviousSnippet", |
||||||
|
getString("CodeViewer.snippets.navigatePrevious", |
||||||
|
"move to previous code fragment within highlighted set")); |
||||||
|
} |
||||||
|
@Override |
||||||
|
public void actionPerformed(ActionEvent e) { |
||||||
|
moveToPreviousSnippet(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class LastSnippetAction extends SnippetAction { |
||||||
|
public LastSnippetAction() { |
||||||
|
super("LastSnippet", |
||||||
|
getString("CodeViewer.snippets.navigateLast", |
||||||
|
"move to last code snippet within highlighted set")); |
||||||
|
} |
||||||
|
public void actionPerformed(ActionEvent e) { |
||||||
|
moveToLastSnippet(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class SnippetCellRenderer implements ListCellRenderer { |
||||||
|
private JLabel delegate; |
||||||
|
|
||||||
|
public SnippetCellRenderer(ListCellRenderer delegate) { |
||||||
|
this.delegate = (JLabel)delegate; |
||||||
|
} |
||||||
|
public Component getListCellRendererComponent(JList list, |
||||||
|
Object value, |
||||||
|
int index, |
||||||
|
boolean isSelected, |
||||||
|
boolean cellHasFocus) { |
||||||
|
|
||||||
|
JLabel renderer = (JLabel)((ListCellRenderer)delegate).getListCellRendererComponent(list, |
||||||
|
value, index, isSelected, cellHasFocus); |
||||||
|
|
||||||
|
int count = snippetMap.getSnippetCountForSet((String)value); |
||||||
|
|
||||||
|
Color foreground = renderer.getForeground(); |
||||||
|
Color countForeground = Utilities.deriveColorHSB(foreground, |
||||||
|
0, 0, isSelected? .5f : .4f); |
||||||
|
|
||||||
|
String text = "<html><font color=\"" + |
||||||
|
Utilities.getHTMLColorString(foreground) + "\">" + value + |
||||||
|
"</font>" + |
||||||
|
"<font color=\"" + |
||||||
|
Utilities.getHTMLColorString(countForeground) + "\">" + |
||||||
|
(count > 0? " (" + count + (count > 1? " snippets)" : " snippet)") : "") + |
||||||
|
"</font></html>"; |
||||||
|
|
||||||
|
renderer.setText(text); |
||||||
|
return renderer; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
private static class CodeFileInfo { |
||||||
|
public URL url; |
||||||
|
public String styled; |
||||||
|
public HashMap<String, List<Snippet>> snippets = new HashMap<String, List<Snippet>>(); |
||||||
|
public JEditorPane textPane; |
||||||
|
public JPanel veneer; |
||||||
|
} |
||||||
|
|
||||||
|
private static class Stacker extends JLayeredPane { |
||||||
|
private Component master; // dictates sizing, scrolling
|
||||||
|
|
||||||
|
public Stacker(Component master) { |
||||||
|
this.master = master; |
||||||
|
setLayout(null); |
||||||
|
add(master, JLayeredPane.DEFAULT_LAYER); |
||||||
|
} |
||||||
|
|
||||||
|
public Dimension getPreferredSize() { |
||||||
|
return master.getPreferredSize(); |
||||||
|
} |
||||||
|
|
||||||
|
public void doLayout() { |
||||||
|
// ensure all layers are sized the same
|
||||||
|
Dimension size = getSize(); |
||||||
|
Component layers[] = getComponents(); |
||||||
|
for(Component layer : layers) { |
||||||
|
layer.setBounds(0, 0, size.width, size.height); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class CodeVeneer extends JPanel { |
||||||
|
private CodeFileInfo codeFileInfo; |
||||||
|
|
||||||
|
public CodeVeneer(CodeFileInfo codeFileInfo) { |
||||||
|
this.codeFileInfo = codeFileInfo; |
||||||
|
setOpaque(false); |
||||||
|
setLayout(null); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void paintComponent(Graphics g) { |
||||||
|
|
||||||
|
String snippetKey = getCurrentSnippetKey(); |
||||||
|
if (snippetKey != NO_SNIPPET_SELECTED) { |
||||||
|
// Count total number of snippets for key
|
||||||
|
int snippetTotal = 0; |
||||||
|
int snippetIndex = 0; |
||||||
|
List<Snippet> snippetList = null; |
||||||
|
URL files[] = snippetMap.getFilesForSet(snippetKey); |
||||||
|
for(URL file : files) { |
||||||
|
CodeFileInfo codeFileInfo = codeCache.get(file); |
||||||
|
if (this.codeFileInfo == codeFileInfo) { |
||||||
|
snippetList = codeFileInfo.snippets.get(snippetKey); |
||||||
|
snippetIndex = snippetTotal + 1; |
||||||
|
} |
||||||
|
snippetTotal += (codeFileInfo.snippets.get(snippetKey).size()); |
||||||
|
} |
||||||
|
|
||||||
|
if (snippetList != null) { |
||||||
|
Snippet currentSnippet = snippetMap.getCurrentSnippet(); |
||||||
|
CodeFileInfo currentSnippetCodeFileInfo = codeCache.get( |
||||||
|
snippetMap.getFileForSnippet(currentSnippet)); |
||||||
|
|
||||||
|
Font font = g.getFont(); |
||||||
|
g.setFont(font.deriveFont(10f)); |
||||||
|
FontMetrics metrics = g.getFontMetrics(); |
||||||
|
|
||||||
|
g.setColor(getHighlightColor()); |
||||||
|
|
||||||
|
Graphics2D g2Alpha = null; // cache composite
|
||||||
|
for(Snippet snippet : snippetList) { |
||||||
|
Graphics2D g2 = (Graphics2D)g; |
||||||
|
|
||||||
|
try { |
||||||
|
if (currentSnippetCodeFileInfo != codeFileInfo || |
||||||
|
currentSnippet != snippet) { |
||||||
|
// if not painting the "current" snippet, then fade the glyph
|
||||||
|
if (g2Alpha == null) { |
||||||
|
// first time, so create composite
|
||||||
|
g2Alpha = (Graphics2D)g2.create(); |
||||||
|
g2Alpha.setComposite(AlphaComposite.getInstance( |
||||||
|
AlphaComposite.SRC_OVER, 0.6f)); |
||||||
|
} |
||||||
|
g2 = g2Alpha; |
||||||
|
} |
||||||
|
Rectangle snipRect = codeFileInfo.textPane.modelToView(snippet.startLine); |
||||||
|
|
||||||
|
//String glyphLabel = snippetIndex++ + "/" + snippetTotal;
|
||||||
|
String glyphLabel = "" + snippetIndex++; |
||||||
|
Rectangle labelRect = metrics.getStringBounds(glyphLabel, g2).getBounds(); |
||||||
|
|
||||||
|
g2.drawImage(SNIPPET_GLYPH, 0, snipRect.y, this); |
||||||
|
g2.setColor(Color.black); |
||||||
|
g2.drawString(glyphLabel, |
||||||
|
(SNIPPET_GLYPH.getWidth(this) - labelRect.width)/2, |
||||||
|
snipRect.y + |
||||||
|
(SNIPPET_GLYPH.getHeight(this) - labelRect.height)/2 + |
||||||
|
metrics.getAscent()); |
||||||
|
|
||||||
|
} catch (BadLocationException e) { |
||||||
|
System.err.println(e); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,51 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.sun.swingset3.codeview; |
||||||
|
|
||||||
|
import javax.swing.text.Document; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author aim |
||||||
|
*/ |
||||||
|
public class Snippet { |
||||||
|
Document document; |
||||||
|
String key = null; |
||||||
|
int startLine = -1; |
||||||
|
int endLine = -1; |
||||||
|
|
||||||
|
public Snippet(Document document, String key, int startLine) { |
||||||
|
this.document = document; |
||||||
|
this.key = key; |
||||||
|
this.startLine = startLine; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,661 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.sun.swingset3.codeview; |
||||||
|
|
||||||
|
import java.awt.Color; |
||||||
|
import java.awt.Graphics; |
||||||
|
import java.awt.Insets; |
||||||
|
import java.awt.Rectangle; |
||||||
|
import java.awt.Shape; |
||||||
|
import java.util.*; |
||||||
|
import javax.swing.SwingUtilities; |
||||||
|
import javax.swing.plaf.TextUI; |
||||||
|
import javax.swing.text.BadLocationException; |
||||||
|
import javax.swing.text.Document; |
||||||
|
import javax.swing.text.Highlighter; |
||||||
|
import javax.swing.text.JTextComponent; |
||||||
|
import javax.swing.text.LayeredHighlighter; |
||||||
|
import javax.swing.text.Position; |
||||||
|
import javax.swing.text.View; |
||||||
|
|
||||||
|
/** |
||||||
|
* Implements the Highlighter interfaces. Implements a simple highlight |
||||||
|
* painter that renders in a solid color. |
||||||
|
* |
||||||
|
* @see Highlighter |
||||||
|
*/ |
||||||
|
public class SnippetHighlighter extends LayeredHighlighter { |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new DefaultHighlighther object. |
||||||
|
*/ |
||||||
|
public SnippetHighlighter() { |
||||||
|
drawsLayeredHighlights = true; |
||||||
|
} |
||||||
|
|
||||||
|
// ---- Highlighter methods ----------------------------------------------
|
||||||
|
|
||||||
|
/** |
||||||
|
* Renders the highlights. |
||||||
|
* |
||||||
|
* @param g the graphics context |
||||||
|
*/ |
||||||
|
public void paint(Graphics g) { |
||||||
|
// PENDING(prinz) - should cull ranges not visible
|
||||||
|
int len = highlights.size(); |
||||||
|
for (int i = 0; i < len; i++) { |
||||||
|
HighlightInfo info = highlights.elementAt(i); |
||||||
|
if (!(info instanceof LayeredHighlightInfo)) { |
||||||
|
// Avoid allocing unless we need it.
|
||||||
|
Rectangle a = component.getBounds(); |
||||||
|
Insets insets = component.getInsets(); |
||||||
|
a.x = insets.left; |
||||||
|
a.y = insets.top; |
||||||
|
a.width -= insets.left + insets.right; |
||||||
|
a.height -= insets.top + insets.bottom; |
||||||
|
for (; i < len; i++) { |
||||||
|
info = highlights.elementAt(i); |
||||||
|
if (!(info instanceof LayeredHighlightInfo)) { |
||||||
|
Highlighter.HighlightPainter p = info.getPainter(); |
||||||
|
p.paint(g, info.getStartOffset(), info.getEndOffset(), |
||||||
|
a, component); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Called when the UI is being installed into the |
||||||
|
* interface of a JTextComponent. Installs the editor, and |
||||||
|
* removes any existing highlights. |
||||||
|
* |
||||||
|
* @param c the editor component |
||||||
|
* @see Highlighter#install |
||||||
|
*/ |
||||||
|
public void install(JTextComponent c) { |
||||||
|
component = c; |
||||||
|
removeAllHighlights(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Called when the UI is being removed from the interface of |
||||||
|
* a JTextComponent. |
||||||
|
* |
||||||
|
* @param c the component |
||||||
|
* @see Highlighter#deinstall |
||||||
|
*/ |
||||||
|
public void deinstall(JTextComponent c) { |
||||||
|
component = null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds a highlight to the view. Returns a tag that can be used |
||||||
|
* to refer to the highlight. |
||||||
|
* |
||||||
|
* @param p0 the start offset of the range to highlight >= 0 |
||||||
|
* @param p1 the end offset of the range to highlight >= p0 |
||||||
|
* @param p the painter to use to actually render the highlight |
||||||
|
* @return an object that can be used as a tag |
||||||
|
* to refer to the highlight |
||||||
|
* @exception BadLocationException if the specified location is invalid |
||||||
|
*/ |
||||||
|
public Object addHighlight(int p0, int p1, Highlighter.HighlightPainter p) throws BadLocationException { |
||||||
|
Document doc = component.getDocument(); |
||||||
|
HighlightInfo i = (getDrawsLayeredHighlights() && |
||||||
|
(p instanceof LayeredHighlighter.LayerPainter)) ? |
||||||
|
new LayeredHighlightInfo() : new HighlightInfo(); |
||||||
|
i.painter = p; |
||||||
|
i.p0 = doc.createPosition(p0); |
||||||
|
i.p1 = doc.createPosition(p1); |
||||||
|
// For snippets, we want to make sure selection is layered ON TOP
|
||||||
|
// since we add transparency to the selection color; so rather
|
||||||
|
// than append the highlight, we insert it in the front.
|
||||||
|
highlights.insertElementAt(i, 0); |
||||||
|
safeDamageRange(p0, p1); |
||||||
|
return i; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Removes a highlight from the view. |
||||||
|
* |
||||||
|
* @param tag the reference to the highlight |
||||||
|
*/ |
||||||
|
public void removeHighlight(Object tag) { |
||||||
|
if (tag instanceof LayeredHighlightInfo) { |
||||||
|
LayeredHighlightInfo lhi = (LayeredHighlightInfo)tag; |
||||||
|
if (lhi.width > 0 && lhi.height > 0) { |
||||||
|
component.repaint(lhi.x, lhi.y, lhi.width, lhi.height); |
||||||
|
} |
||||||
|
} |
||||||
|
else { |
||||||
|
HighlightInfo info = (HighlightInfo) tag; |
||||||
|
safeDamageRange(info.p0, info.p1); |
||||||
|
} |
||||||
|
highlights.removeElement(tag); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Removes all highlights. |
||||||
|
*/ |
||||||
|
public void removeAllHighlights() { |
||||||
|
TextUI mapper = component.getUI(); |
||||||
|
if (getDrawsLayeredHighlights()) { |
||||||
|
int len = highlights.size(); |
||||||
|
if (len != 0) { |
||||||
|
int minX = 0; |
||||||
|
int minY = 0; |
||||||
|
int maxX = 0; |
||||||
|
int maxY = 0; |
||||||
|
int p0 = -1; |
||||||
|
int p1 = -1; |
||||||
|
for (int i = 0; i < len; i++) { |
||||||
|
HighlightInfo hi = highlights.elementAt(i); |
||||||
|
if (hi instanceof LayeredHighlightInfo) { |
||||||
|
LayeredHighlightInfo info = (LayeredHighlightInfo)hi; |
||||||
|
minX = Math.min(minX, info.x); |
||||||
|
minY = Math.min(minY, info.y); |
||||||
|
maxX = Math.max(maxX, info.x + info.width); |
||||||
|
maxY = Math.max(maxY, info.y + info.height); |
||||||
|
} |
||||||
|
else { |
||||||
|
if (p0 == -1) { |
||||||
|
p0 = hi.p0.getOffset(); |
||||||
|
p1 = hi.p1.getOffset(); |
||||||
|
} |
||||||
|
else { |
||||||
|
p0 = Math.min(p0, hi.p0.getOffset()); |
||||||
|
p1 = Math.max(p1, hi.p1.getOffset()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (minX != maxX && minY != maxY) { |
||||||
|
component.repaint(minX, minY, maxX - minX, maxY - minY); |
||||||
|
} |
||||||
|
if (p0 != -1) { |
||||||
|
try { |
||||||
|
safeDamageRange(p0, p1); |
||||||
|
} catch (BadLocationException e) {} |
||||||
|
} |
||||||
|
highlights.removeAllElements(); |
||||||
|
} |
||||||
|
} |
||||||
|
else if (mapper != null) { |
||||||
|
int len = highlights.size(); |
||||||
|
if (len != 0) { |
||||||
|
int p0 = Integer.MAX_VALUE; |
||||||
|
int p1 = 0; |
||||||
|
for (int i = 0; i < len; i++) { |
||||||
|
HighlightInfo info = highlights.elementAt(i); |
||||||
|
p0 = Math.min(p0, info.p0.getOffset()); |
||||||
|
p1 = Math.max(p1, info.p1.getOffset()); |
||||||
|
} |
||||||
|
try { |
||||||
|
safeDamageRange(p0, p1); |
||||||
|
} catch (BadLocationException e) {} |
||||||
|
|
||||||
|
highlights.removeAllElements(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Changes a highlight. |
||||||
|
* |
||||||
|
* @param tag the highlight tag |
||||||
|
* @param p0 the beginning of the range >= 0 |
||||||
|
* @param p1 the end of the range >= p0 |
||||||
|
* @exception BadLocationException if the specified location is invalid |
||||||
|
*/ |
||||||
|
public void changeHighlight(Object tag, int p0, int p1) throws BadLocationException { |
||||||
|
Document doc = component.getDocument(); |
||||||
|
if (tag instanceof LayeredHighlightInfo) { |
||||||
|
LayeredHighlightInfo lhi = (LayeredHighlightInfo)tag; |
||||||
|
if (lhi.width > 0 && lhi.height > 0) { |
||||||
|
component.repaint(lhi.x, lhi.y, lhi.width, lhi.height); |
||||||
|
} |
||||||
|
// Mark the highlights region as invalid, it will reset itself
|
||||||
|
// next time asked to paint.
|
||||||
|
lhi.width = lhi.height = 0; |
||||||
|
lhi.p0 = doc.createPosition(p0); |
||||||
|
lhi.p1 = doc.createPosition(p1); |
||||||
|
safeDamageRange(Math.min(p0, p1), Math.max(p0, p1)); |
||||||
|
} |
||||||
|
else { |
||||||
|
HighlightInfo info = (HighlightInfo) tag; |
||||||
|
int oldP0 = info.p0.getOffset(); |
||||||
|
int oldP1 = info.p1.getOffset(); |
||||||
|
if (p0 == oldP0) { |
||||||
|
safeDamageRange(Math.min(oldP1, p1), |
||||||
|
Math.max(oldP1, p1)); |
||||||
|
} else if (p1 == oldP1) { |
||||||
|
safeDamageRange(Math.min(p0, oldP0), |
||||||
|
Math.max(p0, oldP0)); |
||||||
|
} else { |
||||||
|
safeDamageRange(oldP0, oldP1); |
||||||
|
safeDamageRange(p0, p1); |
||||||
|
} |
||||||
|
info.p0 = doc.createPosition(p0); |
||||||
|
info.p1 = doc.createPosition(p1); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Makes a copy of the highlights. Does not actually clone each highlight, |
||||||
|
* but only makes references to them. |
||||||
|
* |
||||||
|
* @return the copy |
||||||
|
* @see Highlighter#getHighlights |
||||||
|
*/ |
||||||
|
public Highlighter.Highlight[] getHighlights() { |
||||||
|
int size = highlights.size(); |
||||||
|
if (size == 0) { |
||||||
|
return noHighlights; |
||||||
|
} |
||||||
|
Highlighter.Highlight[] h = new Highlighter.Highlight[size]; |
||||||
|
highlights.copyInto(h); |
||||||
|
return h; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* When leaf Views (such as LabelView) are rendering they should |
||||||
|
* call into this method. If a highlight is in the given region it will |
||||||
|
* be drawn immediately. |
||||||
|
* |
||||||
|
* @param g Graphics used to draw |
||||||
|
* @param p0 starting offset of view |
||||||
|
* @param p1 ending offset of view |
||||||
|
* @param viewBounds Bounds of View |
||||||
|
* @param editor JTextComponent |
||||||
|
* @param view View instance being rendered |
||||||
|
*/ |
||||||
|
public void paintLayeredHighlights(Graphics g, int p0, int p1, |
||||||
|
Shape viewBounds, |
||||||
|
JTextComponent editor, View view) { |
||||||
|
for (int counter = highlights.size() - 1; counter >= 0; counter--) { |
||||||
|
Object tag = highlights.elementAt(counter); |
||||||
|
if (tag instanceof LayeredHighlightInfo) { |
||||||
|
LayeredHighlightInfo lhi = (LayeredHighlightInfo)tag; |
||||||
|
int start = lhi.getStartOffset(); |
||||||
|
int end = lhi.getEndOffset(); |
||||||
|
if ((p0 < start && p1 > start) || |
||||||
|
(p0 >= start && p0 < end)) { |
||||||
|
lhi.paintLayeredHighlights(g, p0, p1, viewBounds, |
||||||
|
editor, view); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Queues damageRange() call into event dispatch thread |
||||||
|
* to be sure that views are in consistent state. |
||||||
|
*/ |
||||||
|
private void safeDamageRange(final Position p0, final Position p1) { |
||||||
|
safeDamager.damageRange(p0, p1); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Queues damageRange() call into event dispatch thread |
||||||
|
* to be sure that views are in consistent state. |
||||||
|
*/ |
||||||
|
private void safeDamageRange(int a0, int a1) throws BadLocationException { |
||||||
|
Document doc = component.getDocument(); |
||||||
|
safeDamageRange(doc.createPosition(a0), doc.createPosition(a1)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* If true, highlights are drawn as the Views draw the text. That is |
||||||
|
* the Views will call into <code>paintLayeredHighlight</code> which |
||||||
|
* will result in a rectangle being drawn before the text is drawn |
||||||
|
* (if the offsets are in a highlighted region that is). For this to |
||||||
|
* work the painter supplied must be an instance of |
||||||
|
* LayeredHighlightPainter. |
||||||
|
*/ |
||||||
|
public void setDrawsLayeredHighlights(boolean newValue) { |
||||||
|
drawsLayeredHighlights = newValue; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean getDrawsLayeredHighlights() { |
||||||
|
return drawsLayeredHighlights; |
||||||
|
} |
||||||
|
|
||||||
|
// ---- member variables --------------------------------------------
|
||||||
|
|
||||||
|
private final static Highlighter.Highlight[] noHighlights = |
||||||
|
new Highlighter.Highlight[0]; |
||||||
|
private final Vector<HighlightInfo> highlights = new Vector<HighlightInfo>(); |
||||||
|
private JTextComponent component; |
||||||
|
private boolean drawsLayeredHighlights; |
||||||
|
private final SafeDamager safeDamager = new SafeDamager(); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Default implementation of LayeredHighlighter.LayerPainter that can |
||||||
|
* be used for painting highlights. |
||||||
|
* <p> |
||||||
|
* As of 1.4 this field is final. |
||||||
|
*/ |
||||||
|
public static LayeredHighlighter.LayerPainter SnippetPainter = new SnippetHighlightPainter(null); |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Simple highlight painter that fills a highlighted area with |
||||||
|
* a solid color. |
||||||
|
*/ |
||||||
|
public static class SnippetHighlightPainter extends LayeredHighlighter.LayerPainter { |
||||||
|
|
||||||
|
/** |
||||||
|
* Constructs a new highlight painter. If <code>c</code> is null, |
||||||
|
* the JTextComponent will be queried for its selection color. |
||||||
|
* |
||||||
|
* @param c the color for the highlight |
||||||
|
*/ |
||||||
|
public SnippetHighlightPainter(Color c) { |
||||||
|
color = c; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the color of the highlight. |
||||||
|
* |
||||||
|
* @return the color |
||||||
|
*/ |
||||||
|
public Color getColor() { |
||||||
|
return color; |
||||||
|
} |
||||||
|
|
||||||
|
// --- HighlightPainter methods ---------------------------------------
|
||||||
|
|
||||||
|
/** |
||||||
|
* Paints a highlight. |
||||||
|
* |
||||||
|
* @param g the graphics context |
||||||
|
* @param offs0 the starting model offset >= 0 |
||||||
|
* @param offs1 the ending model offset >= offs1 |
||||||
|
* @param bounds the bounding box for the highlight |
||||||
|
* @param c the editor |
||||||
|
*/ |
||||||
|
public void paint(Graphics g, int offs0, int offs1, Shape bounds, JTextComponent c) { |
||||||
|
Rectangle alloc = bounds.getBounds(); |
||||||
|
try { |
||||||
|
// --- determine locations ---
|
||||||
|
TextUI mapper = c.getUI(); |
||||||
|
Rectangle p0 = mapper.modelToView(c, offs0); |
||||||
|
Rectangle p1 = mapper.modelToView(c, offs1); |
||||||
|
|
||||||
|
// --- render ---
|
||||||
|
Color color = getColor(); |
||||||
|
|
||||||
|
if (color == null) { |
||||||
|
g.setColor(c.getSelectionColor()); |
||||||
|
} |
||||||
|
else { |
||||||
|
g.setColor(color); |
||||||
|
} |
||||||
|
if (p0.y == p1.y) { |
||||||
|
// same line, render a rectangle
|
||||||
|
Rectangle r = p0.union(p1); |
||||||
|
g.fillRect(r.x, r.y, r.width, r.height); |
||||||
|
} else { |
||||||
|
// different lines
|
||||||
|
int p0ToMarginWidth = alloc.x + alloc.width - p0.x; |
||||||
|
g.fillRect(p0.x, p0.y, p0ToMarginWidth, p0.height); |
||||||
|
if ((p0.y + p0.height) != p1.y) { |
||||||
|
g.fillRect(alloc.x, p0.y + p0.height, alloc.width, |
||||||
|
p1.y - (p0.y + p0.height)); |
||||||
|
} |
||||||
|
g.fillRect(alloc.x, p1.y, (p1.x - alloc.x), p1.height); |
||||||
|
} |
||||||
|
} catch (BadLocationException e) { |
||||||
|
// can't render
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// --- LayerPainter methods ----------------------------
|
||||||
|
/** |
||||||
|
* Paints a portion of a highlight. |
||||||
|
* |
||||||
|
* @param g the graphics context |
||||||
|
* @param offs0 the starting model offset >= 0 |
||||||
|
* @param offs1 the ending model offset >= offs1 |
||||||
|
* @param bounds the bounding box of the view, which is not |
||||||
|
* necessarily the region to paint. |
||||||
|
* @param c the editor |
||||||
|
* @param view View painting for |
||||||
|
* @return region drawing occured in |
||||||
|
*/ |
||||||
|
public Shape paintLayer(Graphics g, int offs0, int offs1, |
||||||
|
Shape bounds, JTextComponent c, View view) { |
||||||
|
Color base = getColor(); |
||||||
|
// use transparency so selection isn't clobbered
|
||||||
|
Color color = base != null? |
||||||
|
new Color(base.getRed(), base.getGreen(), base.getBlue(), |
||||||
|
255) : null; |
||||||
|
|
||||||
|
if (color == null) { |
||||||
|
g.setColor(c.getSelectionColor()); |
||||||
|
} |
||||||
|
else { |
||||||
|
g.setColor(color); |
||||||
|
} |
||||||
|
if (offs0 == view.getStartOffset() && |
||||||
|
offs1 == view.getEndOffset()) { |
||||||
|
// Contained in view, can just use bounds.
|
||||||
|
Rectangle alloc; |
||||||
|
if (bounds instanceof Rectangle) { |
||||||
|
alloc = (Rectangle)bounds; |
||||||
|
} |
||||||
|
else { |
||||||
|
alloc = bounds.getBounds(); |
||||||
|
} |
||||||
|
// For CodeViewer Snippet painting, this is the paint block that is called.
|
||||||
|
// We want to paint the highlight on the full width of the text pane,
|
||||||
|
// so we only need to do this when the region is the beginning of a new
|
||||||
|
// line.
|
||||||
|
//g.fillRect(alloc.x, alloc.y, alloc.width, alloc.height);
|
||||||
|
g.fillRect(alloc.x, alloc.y, c.getWidth() - alloc.x, alloc.height); |
||||||
|
|
||||||
|
} |
||||||
|
else { |
||||||
|
// Should only render part of View.
|
||||||
|
try { |
||||||
|
// --- determine locations ---
|
||||||
|
Shape shape = view.modelToView(offs0, Position.Bias.Forward, |
||||||
|
offs1,Position.Bias.Backward, |
||||||
|
bounds); |
||||||
|
Rectangle r = (shape instanceof Rectangle) ? |
||||||
|
(Rectangle)shape : shape.getBounds(); |
||||||
|
|
||||||
|
g.fillRect(0, r.y, c.getWidth(), r.height); |
||||||
|
return r; |
||||||
|
} catch (BadLocationException e) { |
||||||
|
// can't render
|
||||||
|
} |
||||||
|
} |
||||||
|
// Only if exception
|
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
private Color color; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
private static class HighlightInfo implements Highlighter.Highlight { |
||||||
|
|
||||||
|
public int getStartOffset() { |
||||||
|
return p0.getOffset(); |
||||||
|
} |
||||||
|
|
||||||
|
public int getEndOffset() { |
||||||
|
return p1.getOffset(); |
||||||
|
} |
||||||
|
|
||||||
|
public Highlighter.HighlightPainter getPainter() { |
||||||
|
return painter; |
||||||
|
} |
||||||
|
|
||||||
|
Position p0; |
||||||
|
Position p1; |
||||||
|
Highlighter.HighlightPainter painter; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* LayeredHighlightPainter is used when a drawsLayeredHighlights is |
||||||
|
* true. It maintains a rectangle of the region to paint. |
||||||
|
*/ |
||||||
|
private static class LayeredHighlightInfo extends HighlightInfo { |
||||||
|
|
||||||
|
void union(Shape bounds) { |
||||||
|
if (bounds == null) |
||||||
|
return; |
||||||
|
|
||||||
|
Rectangle alloc; |
||||||
|
if (bounds instanceof Rectangle) { |
||||||
|
alloc = (Rectangle)bounds; |
||||||
|
} |
||||||
|
else { |
||||||
|
alloc = bounds.getBounds(); |
||||||
|
} |
||||||
|
if (width == 0 || height == 0) { |
||||||
|
x = alloc.x; |
||||||
|
y = alloc.y; |
||||||
|
width = alloc.width; |
||||||
|
height = alloc.height; |
||||||
|
} |
||||||
|
else { |
||||||
|
width = Math.max(x + width, alloc.x + alloc.width); |
||||||
|
height = Math.max(y + height, alloc.y + alloc.height); |
||||||
|
x = Math.min(x, alloc.x); |
||||||
|
width -= x; |
||||||
|
y = Math.min(y, alloc.y); |
||||||
|
height -= y; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Restricts the region based on the receivers offsets and messages |
||||||
|
* the painter to paint the region. |
||||||
|
*/ |
||||||
|
void paintLayeredHighlights(Graphics g, int p0, int p1, |
||||||
|
Shape viewBounds, JTextComponent editor, |
||||||
|
View view) { |
||||||
|
int start = getStartOffset(); |
||||||
|
int end = getEndOffset(); |
||||||
|
// Restrict the region to what we represent
|
||||||
|
p0 = Math.max(start, p0); |
||||||
|
p1 = Math.min(end, p1); |
||||||
|
// Paint the appropriate region using the painter and union
|
||||||
|
// the effected region with our bounds.
|
||||||
|
union(((LayeredHighlighter.LayerPainter)painter).paintLayer |
||||||
|
(g, p0, p1, viewBounds, editor, view)); |
||||||
|
} |
||||||
|
|
||||||
|
int x; |
||||||
|
int y; |
||||||
|
int width; |
||||||
|
int height; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* This class invokes <code>mapper.damageRange</code> in |
||||||
|
* EventDispatchThread. The only one instance per Highlighter |
||||||
|
* is cretaed. When a number of ranges should be damaged |
||||||
|
* it collects them into queue and damages |
||||||
|
* them in consecutive order in <code>run</code> |
||||||
|
* call. |
||||||
|
*/ |
||||||
|
class SafeDamager implements Runnable { |
||||||
|
private final List<Position> p0 = new ArrayList<Position>(); |
||||||
|
private final List<Position> p1 = new ArrayList<Position>(); |
||||||
|
private Document lastDoc = null; |
||||||
|
|
||||||
|
/** |
||||||
|
* Executes range(s) damage and cleans range queue. |
||||||
|
*/ |
||||||
|
public synchronized void run() { |
||||||
|
if (component != null) { |
||||||
|
TextUI mapper = component.getUI(); |
||||||
|
if (mapper != null && lastDoc == component.getDocument()) { |
||||||
|
// the Document should be the same to properly
|
||||||
|
// display highlights
|
||||||
|
int len = p0.size(); |
||||||
|
for (int i = 0; i < len; i++){ |
||||||
|
mapper.damageRange(component, |
||||||
|
p0.get(i).getOffset(), |
||||||
|
p1.get(i).getOffset()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
p0.clear(); |
||||||
|
p1.clear(); |
||||||
|
|
||||||
|
// release reference
|
||||||
|
lastDoc = null; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Adds the range to be damaged into the range queue. If the |
||||||
|
* range queue is empty (the first call or run() was already |
||||||
|
* invoked) then adds this class instance into EventDispatch |
||||||
|
* queue. |
||||||
|
* |
||||||
|
* The method also tracks if the current document changed or |
||||||
|
* component is null. In this case it removes all ranges added |
||||||
|
* before from range queue. |
||||||
|
*/ |
||||||
|
private synchronized void damageRange(Position pos0, Position pos1) { |
||||||
|
if (component == null) { |
||||||
|
p0.clear(); |
||||||
|
lastDoc = null; |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
boolean addToQueue = p0.isEmpty(); |
||||||
|
Document curDoc = component.getDocument(); |
||||||
|
if (curDoc != lastDoc) { |
||||||
|
if (!p0.isEmpty()) { |
||||||
|
p0.clear(); |
||||||
|
p1.clear(); |
||||||
|
} |
||||||
|
lastDoc = curDoc; |
||||||
|
} |
||||||
|
p0.add(pos0); |
||||||
|
p1.add(pos1); |
||||||
|
|
||||||
|
if (addToQueue) { |
||||||
|
SwingUtilities.invokeLater(this); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,339 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.sun.swingset3.codeview; |
||||||
|
|
||||||
|
import java.beans.PropertyChangeListener; |
||||||
|
import java.beans.PropertyChangeSupport; |
||||||
|
import java.net.URL; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* Data structure to support maintaining Snippet information across a |
||||||
|
* set of source code files: |
||||||
|
* |
||||||
|
* SnippetMap |
||||||
|
* | |
||||||
|
* --------------------------------------- |
||||||
|
* | | | |
||||||
|
* snippet key "A" Snippet key "B" Snippet key "C" |
||||||
|
* | | | |
||||||
|
* ---------------- ------ ------------- |
||||||
|
* | | | | |
||||||
|
* File1.java File3.java File2.java File3.java |
||||||
|
* | | | | |
||||||
|
* ---------- --- --- ----- |
||||||
|
* | | | | | |
||||||
|
* snipA-1 snipA-2 snipA-3 snipB-1 snipC-1 |
||||||
|
* |
||||||
|
* |
||||||
|
* This class also maintains a pointer to a "current" snippet within |
||||||
|
* a selected set. |
||||||
|
* |
||||||
|
* |
||||||
|
* @author aim |
||||||
|
*/ |
||||||
|
public class SnippetMap { |
||||||
|
private final HashMap<String, List<FileSnippets>> snippetSets = new HashMap<String, List<FileSnippets>>(); |
||||||
|
|
||||||
|
private String currentKey; |
||||||
|
private List<FileSnippets> currentSet; |
||||||
|
private FileSnippets currentFileSnippets; |
||||||
|
private int currentFileSnippetsIndex; |
||||||
|
private int currentSnippetIndex; |
||||||
|
private Snippet currentSnippet; |
||||||
|
|
||||||
|
private PropertyChangeSupport pcs; |
||||||
|
|
||||||
|
/** Creates a new instance of SnippetMap */ |
||||||
|
public SnippetMap() { |
||||||
|
pcs = new PropertyChangeSupport(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void addPropertyChangeListener(PropertyChangeListener pcl) { |
||||||
|
pcs.addPropertyChangeListener(pcl); |
||||||
|
} |
||||||
|
|
||||||
|
public void add(String key, URL codeFile, Snippet snippet) { |
||||||
|
List<FileSnippets> fileSnippetList = snippetSets.get(key); |
||||||
|
if (fileSnippetList == null) { |
||||||
|
// new key! so create new set...
|
||||||
|
fileSnippetList = new ArrayList<FileSnippets>(); |
||||||
|
snippetSets.put(key, fileSnippetList); |
||||||
|
} |
||||||
|
|
||||||
|
FileSnippets fileSnippets = findFileSnippetsForFile(fileSnippetList, codeFile); |
||||||
|
if (fileSnippets == null) { |
||||||
|
// found first snippet in this file
|
||||||
|
fileSnippets = new FileSnippets(key, codeFile); |
||||||
|
fileSnippetList.add(fileSnippets); |
||||||
|
} |
||||||
|
if (!fileSnippets.snippets.contains(snippet)) { |
||||||
|
fileSnippets.snippets.add(snippet); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public Set<String> keySet() { |
||||||
|
return snippetSets.keySet(); |
||||||
|
} |
||||||
|
|
||||||
|
public int getSnippetCountForSet(String key) { |
||||||
|
int count = 0; |
||||||
|
URL files[] = getFilesForSet(key); |
||||||
|
for(URL file : files) { |
||||||
|
Snippet snippets[] = getSnippetsForFile(key, file); |
||||||
|
count += snippets.length; |
||||||
|
} |
||||||
|
return count; |
||||||
|
} |
||||||
|
|
||||||
|
public URL[] getFilesForSet(String key) { |
||||||
|
List<FileSnippets> fileSnippetList = snippetSets.get(key); |
||||||
|
URL files[]; |
||||||
|
if (fileSnippetList != null) { |
||||||
|
files = new URL[fileSnippetList.size()]; |
||||||
|
int i = 0; |
||||||
|
for(FileSnippets fileSnippets : fileSnippetList) { |
||||||
|
files[i++] = fileSnippets.file; |
||||||
|
} |
||||||
|
} else { |
||||||
|
files = new URL[0]; |
||||||
|
} |
||||||
|
return files; |
||||||
|
} |
||||||
|
|
||||||
|
public Snippet[] getSnippetsForFile(String key, URL file) { |
||||||
|
List<FileSnippets> fileSnippetList = snippetSets.get(key); |
||||||
|
FileSnippets fileSnippets = findFileSnippetsForFile(fileSnippetList, file); |
||||||
|
if (fileSnippets != null) { |
||||||
|
if (fileSnippets.snippets != null) { |
||||||
|
return fileSnippets.snippets.toArray(new Snippet[0]); |
||||||
|
} |
||||||
|
} |
||||||
|
return new Snippet[0]; |
||||||
|
} |
||||||
|
|
||||||
|
public int getIndexForSnippet(Snippet snippet) { |
||||||
|
List<FileSnippets> fileSnippetList = snippetSets.get(snippet.key); |
||||||
|
if (fileSnippetList != null) { |
||||||
|
int index = 1; |
||||||
|
for(FileSnippets fileSnippets : fileSnippetList) { |
||||||
|
for(Snippet snippetInFile : fileSnippets.snippets) { |
||||||
|
if (snippetInFile == snippet) { |
||||||
|
return index; |
||||||
|
} else { |
||||||
|
index++; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return -1; |
||||||
|
} |
||||||
|
|
||||||
|
public URL getFileForSnippet(Snippet snippet) { |
||||||
|
List<FileSnippets> fileSnippetList = snippetSets.get(snippet.key); |
||||||
|
if (fileSnippetList != null) { |
||||||
|
for(FileSnippets fileSnippets : fileSnippetList) { |
||||||
|
for(Snippet snippetInFile : fileSnippets.snippets) { |
||||||
|
if (snippetInFile == snippet) { |
||||||
|
return fileSnippets.file; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isEmpty() { |
||||||
|
return snippetSets.isEmpty(); |
||||||
|
} |
||||||
|
|
||||||
|
public int getSize() { |
||||||
|
return snippetSets.size(); |
||||||
|
} |
||||||
|
|
||||||
|
public void clear() { |
||||||
|
snippetSets.clear(); |
||||||
|
setCurrentSnippet(null); |
||||||
|
setCurrentSet(null); |
||||||
|
} |
||||||
|
|
||||||
|
public void setCurrentSet(String key) { |
||||||
|
String oldKey = currentKey; |
||||||
|
|
||||||
|
if (key == null) { |
||||||
|
// current snippet being cleared
|
||||||
|
currentKey = null; |
||||||
|
currentSet = null; |
||||||
|
currentFileSnippets = null; |
||||||
|
currentFileSnippetsIndex = -1; |
||||||
|
currentSnippetIndex = -1; |
||||||
|
} else { |
||||||
|
List<FileSnippets> fileSnippetList = snippetSets.get(key); |
||||||
|
if (fileSnippetList == null) { |
||||||
|
throw new IllegalArgumentException("snippet key " + key + " does not exist."); |
||||||
|
} |
||||||
|
currentKey = key; |
||||||
|
currentSet = fileSnippetList; |
||||||
|
currentFileSnippetsIndex = 0; |
||||||
|
currentFileSnippets = currentSet.get(currentFileSnippetsIndex); |
||||||
|
currentSnippetIndex = 0; |
||||||
|
currentSnippet = currentFileSnippets.snippets.get(currentSnippetIndex); |
||||||
|
} |
||||||
|
pcs.firePropertyChange("currentSet", oldKey, currentKey); |
||||||
|
pcs.firePropertyChange("currentSnippet", null, currentSnippet); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public String getCurrentSet() { |
||||||
|
return currentKey; |
||||||
|
} |
||||||
|
|
||||||
|
public Snippet getCurrentSnippet() { |
||||||
|
return currentSnippet; |
||||||
|
} |
||||||
|
|
||||||
|
protected void setCurrentSnippet(Snippet snippet) { |
||||||
|
Snippet oldCurrentSnippet = currentSnippet; |
||||||
|
currentSnippet = snippet; |
||||||
|
pcs.firePropertyChange("currentSnippet", oldCurrentSnippet, snippet); |
||||||
|
} |
||||||
|
|
||||||
|
public Snippet firstSnippet() { |
||||||
|
if (currentKey != null) { |
||||||
|
currentFileSnippetsIndex = 0; |
||||||
|
currentFileSnippets = currentSet.get(currentFileSnippetsIndex); |
||||||
|
currentSnippetIndex = 0; |
||||||
|
Snippet firstSnippet = currentFileSnippets.snippets.get(currentSnippetIndex); |
||||||
|
setCurrentSnippet(firstSnippet); |
||||||
|
return getCurrentSnippet(); |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean nextSnippetExists() { |
||||||
|
if (currentKey != null) { |
||||||
|
if (currentSnippetIndex+1 < currentFileSnippets.snippets.size()) { |
||||||
|
// There is a next snippet in the current file
|
||||||
|
return true; |
||||||
|
} |
||||||
|
if (currentFileSnippetsIndex+1 < currentSet.size()) { |
||||||
|
// There is another file containing the next snippet
|
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public Snippet nextSnippet() { |
||||||
|
if (currentKey != null) { |
||||||
|
if (currentSnippetIndex+1 < currentFileSnippets.snippets.size()) { |
||||||
|
// There is a next snippet in the current file
|
||||||
|
setCurrentSnippet(currentFileSnippets.snippets.get(++currentSnippetIndex)); |
||||||
|
return getCurrentSnippet(); |
||||||
|
} |
||||||
|
if (currentFileSnippetsIndex+1 < currentSet.size()) { |
||||||
|
// The next snippet is contained in the next file
|
||||||
|
currentFileSnippets = currentSet.get(++currentFileSnippetsIndex); |
||||||
|
currentSnippetIndex = 0; |
||||||
|
setCurrentSnippet(currentFileSnippets.snippets.get(currentSnippetIndex)); |
||||||
|
return getCurrentSnippet(); |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean previousSnippetExists() { |
||||||
|
if (currentKey != null) { |
||||||
|
if (currentSnippetIndex-1 >= 0) { |
||||||
|
// There is a previous snippet in the current file
|
||||||
|
return true; |
||||||
|
} |
||||||
|
if (currentFileSnippetsIndex-1 >= 0) { |
||||||
|
// There is a previous file containing the previous snippet
|
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public Snippet previousSnippet() { |
||||||
|
if (currentKey != null) { |
||||||
|
if (currentSnippetIndex-1 >= 0) { |
||||||
|
// There is a previous snippet in the current file
|
||||||
|
setCurrentSnippet(currentFileSnippets.snippets.get(--currentSnippetIndex)); |
||||||
|
return getCurrentSnippet(); |
||||||
|
} |
||||||
|
if (currentFileSnippetsIndex-1 >= 0) { |
||||||
|
// The previous snippet is contained in the previous file
|
||||||
|
currentFileSnippets = currentSet.get(--currentFileSnippetsIndex); |
||||||
|
currentSnippetIndex = currentFileSnippets.snippets.size() - 1; |
||||||
|
setCurrentSnippet(currentFileSnippets.snippets.get(currentSnippetIndex)); |
||||||
|
return getCurrentSnippet(); |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
public Snippet lastSnippet() { |
||||||
|
if (currentKey != null) { |
||||||
|
currentFileSnippetsIndex = currentSet.size() - 1; |
||||||
|
currentFileSnippets = currentSet.get(currentFileSnippetsIndex); |
||||||
|
currentSnippetIndex = currentFileSnippets.snippets.size() - 1; |
||||||
|
setCurrentSnippet(currentFileSnippets.snippets.get(currentSnippetIndex)); |
||||||
|
return getCurrentSnippet(); |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
private static FileSnippets findFileSnippetsForFile(List<FileSnippets> fileSnippetList, URL file) { |
||||||
|
for(FileSnippets fileSnippets : fileSnippetList) { |
||||||
|
if (fileSnippets.file == file) { |
||||||
|
return fileSnippets; |
||||||
|
} |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
// data structure for keeping track of a particular snippet set's snippets within one file'
|
||||||
|
private static class FileSnippets { |
||||||
|
public final String key; |
||||||
|
public final URL file; |
||||||
|
public final ArrayList<Snippet> snippets; |
||||||
|
|
||||||
|
public FileSnippets(String key, URL file) { |
||||||
|
this.key = key; |
||||||
|
this.file = file; |
||||||
|
snippets = new ArrayList<Snippet>(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,322 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.sun.swingset3.codeview; |
||||||
|
|
||||||
|
import com.sun.swingset3.utilities.ArrowIcon; |
||||||
|
import java.awt.Color; |
||||||
|
import java.awt.Component; |
||||||
|
import java.awt.Dimension; |
||||||
|
import java.awt.Graphics; |
||||||
|
import java.awt.Image; |
||||||
|
import java.awt.Insets; |
||||||
|
import java.awt.image.BufferedImage; |
||||||
|
import java.beans.PropertyChangeEvent; |
||||||
|
import java.beans.PropertyChangeListener; |
||||||
|
import java.util.MissingResourceException; |
||||||
|
import java.util.ResourceBundle; |
||||||
|
import java.util.logging.Level; |
||||||
|
import javax.swing.Action; |
||||||
|
import javax.swing.Icon; |
||||||
|
import javax.swing.JButton; |
||||||
|
import javax.swing.JLabel; |
||||||
|
import javax.swing.JPanel; |
||||||
|
import javax.swing.UIManager; |
||||||
|
import javax.swing.border.Border; |
||||||
|
import org.jdesktop.swingx.graphics.GraphicsUtilities; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author Amy Fowler |
||||||
|
*/ |
||||||
|
// This is more complicated thn it needs to be because it was an attempt to
|
||||||
|
// create a seamless control where the label was integrated into the buttons;
|
||||||
|
// this integration is temporarily turned off due to visual problems with focus
|
||||||
|
// and enabled state of the buttons
|
||||||
|
public class SnippetNavigator extends JPanel { |
||||||
|
private String NO_SNIPPET; |
||||||
|
private SnippetMap snippetMap; |
||||||
|
private JLabel statusLabel; |
||||||
|
private JButton prevButton; |
||||||
|
private JButton nextButton; |
||||||
|
private int arrowSize = 8; |
||||||
|
private int overlap = 0; |
||||||
|
private int labelPad = 6; |
||||||
|
private boolean needLabelBorder = true; |
||||||
|
|
||||||
|
public SnippetNavigator(SnippetMap snippetMap) { |
||||||
|
this.snippetMap = snippetMap; |
||||||
|
snippetMap.addPropertyChangeListener(new SnippetHighlightListener()); |
||||||
|
|
||||||
|
setLayout(null); |
||||||
|
|
||||||
|
NO_SNIPPET = getString("CodeViewer.snippets.noCodeHighlighted", |
||||||
|
"No Code highlight selected"); |
||||||
|
|
||||||
|
statusLabel = new JLabel(NO_SNIPPET); |
||||||
|
statusLabel.setHorizontalAlignment(JLabel.CENTER); |
||||||
|
add(statusLabel); |
||||||
|
|
||||||
|
prevButton = (JButton) add(new NavButton()); |
||||||
|
prevButton.setDefaultCapable(false); |
||||||
|
prevButton.setVisible(false); |
||||||
|
|
||||||
|
nextButton = (JButton) add(new NavButton()); |
||||||
|
nextButton.setDefaultCapable(false); |
||||||
|
nextButton.setVisible(false); |
||||||
|
|
||||||
|
applyDefaults(); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
protected String getString(String key, String fallback) { |
||||||
|
String value = fallback; |
||||||
|
String bundleName = getClass().getPackage().getName()+".resources.CodeViewer"; |
||||||
|
ResourceBundle bundle = ResourceBundle.getBundle(bundleName); |
||||||
|
try { |
||||||
|
value = bundle != null? bundle.getString(key) : fallback; |
||||||
|
|
||||||
|
} catch (MissingResourceException e) { |
||||||
|
CodeViewer.logger.log(Level.WARNING, "missing String resource " + key + |
||||||
|
"; using fallback \"" +fallback + "\""); |
||||||
|
} |
||||||
|
return value; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void doLayout() { |
||||||
|
Dimension size = getSize(); |
||||||
|
Insets insets = getInsets(); |
||||||
|
Dimension labelSize = statusLabel.getPreferredSize(); |
||||||
|
|
||||||
|
if (prevButton.isVisible()) { |
||||||
|
if (needLabelBorder) { |
||||||
|
matchLabelBorderToButtons(); |
||||||
|
} |
||||||
|
Dimension buttonSize = prevButton.getPreferredSize(); |
||||||
|
|
||||||
|
prevButton.setBounds(insets.left, insets.top, |
||||||
|
buttonSize.width, size.height - insets.top - insets.bottom); |
||||||
|
|
||||||
|
statusLabel.setBounds(insets.left + buttonSize.width - overlap, |
||||||
|
insets.top, |
||||||
|
labelSize.width + (2 * overlap) + labelPad, |
||||||
|
size.height - insets.top - insets.bottom); |
||||||
|
|
||||||
|
nextButton.setBounds(size.width - buttonSize.width, |
||||||
|
insets.top, |
||||||
|
buttonSize.width, size.height - insets.top - insets.bottom); |
||||||
|
} else { |
||||||
|
statusLabel.setBounds(insets.left, insets.top, |
||||||
|
size.width - insets.left - insets.right, |
||||||
|
size.height - insets.top - insets.bottom); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Dimension getPreferredSize() { |
||||||
|
Dimension prefSize; |
||||||
|
Insets insets = getInsets(); |
||||||
|
Dimension buttonSize = prevButton.getPreferredSize(); |
||||||
|
Dimension labelSize = statusLabel.getPreferredSize(); |
||||||
|
if (prevButton.isVisible()) { |
||||||
|
prefSize = new Dimension(buttonSize.width * 2 + labelSize.width + |
||||||
|
labelPad + |
||||||
|
insets.left + insets.right, |
||||||
|
buttonSize.height + insets.top + insets.bottom); |
||||||
|
} else { |
||||||
|
prefSize = new Dimension(labelSize.width + insets.left + insets.right, |
||||||
|
buttonSize.height + insets.top + insets.bottom); |
||||||
|
} |
||||||
|
return prefSize; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void updateUI() { |
||||||
|
super.updateUI(); |
||||||
|
applyDefaults(); |
||||||
|
} |
||||||
|
|
||||||
|
protected void applyDefaults() { |
||||||
|
if (prevButton != null) { |
||||||
|
Color arrowColor = UIManager.getColor("Label.foreground"); |
||||||
|
Color inactiveColor = UIManager.getColor("Label.disabledText"); |
||||||
|
Dimension buttonSize = new Dimension(arrowSize + 12 + overlap, |
||||||
|
arrowSize + 12); |
||||||
|
|
||||||
|
prevButton.setIcon(new ArrowIcon(ArrowIcon.WEST, arrowSize, arrowColor)); |
||||||
|
prevButton.setDisabledIcon(new ArrowIcon(ArrowIcon.WEST, arrowSize, inactiveColor)); |
||||||
|
prevButton.setPreferredSize(buttonSize); |
||||||
|
nextButton.setIcon(new ArrowIcon(ArrowIcon.EAST, arrowSize, arrowColor)); |
||||||
|
nextButton.setDisabledIcon(new ArrowIcon(ArrowIcon.EAST, arrowSize, inactiveColor)); |
||||||
|
nextButton.setPreferredSize(buttonSize); |
||||||
|
|
||||||
|
statusLabel.setOpaque(true); |
||||||
|
statusLabel.setFont(UIManager.getFont("Label.font").deriveFont(12f)); |
||||||
|
|
||||||
|
//needLabelBorder = true;
|
||||||
|
needLabelBorder = false; |
||||||
|
} |
||||||
|
} |
||||||
|
// this doesn't get called because label integration is disabled
|
||||||
|
private void matchLabelBorderToButtons() { |
||||||
|
Insets insets = new Insets(4, 6, 4, 6); |
||||||
|
Dimension buttonSize = prevButton.getPreferredSize(); |
||||||
|
prevButton.setSize(buttonSize); |
||||||
|
|
||||||
|
BufferedImage image = GraphicsUtilities. |
||||||
|
createCompatibleTranslucentImage( |
||||||
|
buttonSize.width, buttonSize.height); |
||||||
|
prevButton.paint(image.getGraphics()); |
||||||
|
BufferedImage labelTopImage = GraphicsUtilities. |
||||||
|
createCompatibleTranslucentImage( |
||||||
|
buttonSize.width - insets.left - insets.right, |
||||||
|
insets.top); |
||||||
|
labelTopImage.getGraphics().drawImage(image, 0, 0, |
||||||
|
buttonSize.width - insets.left - insets.right, |
||||||
|
insets.top, |
||||||
|
insets.left, 0, |
||||||
|
buttonSize.width - insets.right, insets.top, |
||||||
|
null, |
||||||
|
null); |
||||||
|
|
||||||
|
BufferedImage labelBottomImage = GraphicsUtilities.createCompatibleTranslucentImage(buttonSize.width - insets.left - insets.right, |
||||||
|
insets.bottom); |
||||||
|
labelBottomImage.getGraphics().drawImage(image, 0, 0, |
||||||
|
buttonSize.width - insets.left - insets.right, insets.top, |
||||||
|
insets.left, buttonSize.height - insets.bottom, |
||||||
|
buttonSize.width - insets.right, buttonSize.height, |
||||||
|
null, |
||||||
|
null); |
||||||
|
|
||||||
|
statusLabel.setBorder(new CenterLabelBorder(labelTopImage, labelBottomImage)); |
||||||
|
needLabelBorder = false; |
||||||
|
} |
||||||
|
|
||||||
|
public void setNavigatePreviousAction(Action action) { |
||||||
|
setButtonAction(prevButton, action); |
||||||
|
} |
||||||
|
|
||||||
|
public void setNavigateNextAction(Action action) { |
||||||
|
setButtonAction(nextButton, action); |
||||||
|
} |
||||||
|
|
||||||
|
private void setButtonAction(JButton button, Action action) { |
||||||
|
Icon icon = button.getIcon(); |
||||||
|
button.setAction(action); |
||||||
|
button.setHideActionText(true); |
||||||
|
button.setIcon(icon); // icon gets obliterated when action set!
|
||||||
|
} |
||||||
|
|
||||||
|
private class SnippetHighlightListener implements PropertyChangeListener { |
||||||
|
|
||||||
|
public void propertyChange(PropertyChangeEvent e) { |
||||||
|
String propertyName = e.getPropertyName(); |
||||||
|
if (propertyName.equals("currentSet")) { |
||||||
|
String key = (String) e.getNewValue(); |
||||||
|
setComponentState(key); |
||||||
|
|
||||||
|
} else if (propertyName.equals("currentSnippet")) { |
||||||
|
setComponentState(snippetMap.getCurrentSet()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private void setComponentState(String currentKey) { |
||||||
|
if (currentKey == null) { |
||||||
|
statusLabel.setText(NO_SNIPPET); |
||||||
|
|
||||||
|
} else { |
||||||
|
|
||||||
|
String place = "<html><b>" + |
||||||
|
snippetMap.getIndexForSnippet(snippetMap.getCurrentSnippet()) + |
||||||
|
"</b>" + |
||||||
|
" of " + snippetMap.getSnippetCountForSet(currentKey) + "</html>"; |
||||||
|
statusLabel.setText(place); |
||||||
|
|
||||||
|
} |
||||||
|
boolean moreThanOne = snippetMap.getSnippetCountForSet(currentKey) > 1; |
||||||
|
|
||||||
|
prevButton.setVisible(moreThanOne); |
||||||
|
nextButton.setVisible(moreThanOne); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class NavButton extends JButton { |
||||||
|
public NavButton() { |
||||||
|
super(); |
||||||
|
} |
||||||
|
protected void paintComponent(Graphics g) { |
||||||
|
// need to make sure overlapping label paints after buttons otherwise
|
||||||
|
// the buttons paint over the label when they gain focus (which is really
|
||||||
|
// a Swing bug, as the clip should be properly set based on zorder
|
||||||
|
// within the container)
|
||||||
|
super.paintComponent(g); |
||||||
|
statusLabel.repaint(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private class CenterLabelBorder implements Border { |
||||||
|
private Image topImage; |
||||||
|
private Image bottomImage; |
||||||
|
|
||||||
|
public CenterLabelBorder(Image topImage, Image bottomImage) { |
||||||
|
this.topImage = topImage; |
||||||
|
this.bottomImage = bottomImage; |
||||||
|
} |
||||||
|
|
||||||
|
public Insets getBorderInsets(Component c) { |
||||||
|
return new Insets(topImage.getHeight(null), |
||||||
|
0, bottomImage.getHeight(null), 0); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isBorderOpaque() { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) { |
||||||
|
if (prevButton.isVisible()) { |
||||||
|
int xx = x; |
||||||
|
int imageWidth = topImage.getWidth(c); |
||||||
|
while (xx < x + w) { |
||||||
|
g.drawImage(topImage, xx, y, c); |
||||||
|
xx += imageWidth; |
||||||
|
} |
||||||
|
xx = x; |
||||||
|
imageWidth = bottomImage.getWidth(c); |
||||||
|
while (xx < x + w) { |
||||||
|
g.drawImage(bottomImage, xx, y + h - bottomImage.getHeight(c), c); |
||||||
|
xx += imageWidth; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,143 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.sun.swingset3.codeview; |
||||||
|
|
||||||
|
import java.text.CharacterIterator; |
||||||
|
import java.util.*; |
||||||
|
import javax.swing.text.BadLocationException; |
||||||
|
import javax.swing.text.Document; |
||||||
|
import javax.swing.text.Segment; |
||||||
|
|
||||||
|
/** |
||||||
|
* Parses a source code document, looking for blocks of code |
||||||
|
* bracketed by comments including start and ending "snippet" markers. |
||||||
|
* |
||||||
|
* @author aim |
||||||
|
*/ |
||||||
|
public class SnippetParser { |
||||||
|
private final static String START_MARKER = "<snip>"; |
||||||
|
private final static String END_MARKER = "</snip>"; |
||||||
|
|
||||||
|
protected SnippetParser() { |
||||||
|
// never instantiate
|
||||||
|
} |
||||||
|
|
||||||
|
public static HashMap<String,List<Snippet>> parse(Document document) { |
||||||
|
|
||||||
|
return parse(document, START_MARKER, END_MARKER); |
||||||
|
} |
||||||
|
|
||||||
|
private static HashMap<String,List<Snippet>> parse(Document document, |
||||||
|
String startMarker, String endMarker) { |
||||||
|
HashMap<String,List<Snippet>> snippetMap = new HashMap<String,List<Snippet>>(); |
||||||
|
Stack<Snippet> stack = new Stack<Snippet>(); // snippets may be nested
|
||||||
|
char startMarkerChars[] = startMarker.toCharArray(); |
||||||
|
char endMarkerChars[] = endMarker.toCharArray(); |
||||||
|
int nleft = document.getLength(); |
||||||
|
Segment segment = new Segment(); |
||||||
|
int offset = 0; |
||||||
|
int lineStart = 0; |
||||||
|
int charCount = 0; |
||||||
|
int startMarkerIndex = 0; |
||||||
|
int endMarkerIndex = 0; |
||||||
|
StringBuffer keyBuf = new StringBuffer(); |
||||||
|
|
||||||
|
segment.setPartialReturn(true); |
||||||
|
try { |
||||||
|
while (nleft > 0) { |
||||||
|
|
||||||
|
document.getText(offset, nleft, segment); |
||||||
|
|
||||||
|
for(char c = segment.first(); c != CharacterIterator.DONE; |
||||||
|
c = segment.next()) { |
||||||
|
|
||||||
|
if (!stack.isEmpty()) { |
||||||
|
// already found a begin marker, so looking for end marker
|
||||||
|
if (c == endMarkerChars[endMarkerIndex]) { |
||||||
|
endMarkerIndex++; |
||||||
|
if (endMarkerIndex == endMarkerChars.length) { |
||||||
|
// found end marker, so register snippet
|
||||||
|
Snippet snippet = stack.pop(); |
||||||
|
if (snippet.key.equals("tempkey")) { |
||||||
|
// haven't stored key yet
|
||||||
|
snippet.key = keyBuf.toString().trim(); |
||||||
|
} |
||||||
|
snippet.endLine = charCount + 1; |
||||||
|
List<Snippet> snippetList = snippetMap.get(snippet.key); |
||||||
|
|
||||||
|
if (snippetList == null) { |
||||||
|
snippetList = new ArrayList<Snippet>(); |
||||||
|
snippetMap.put(snippet.key, snippetList); |
||||||
|
} |
||||||
|
snippetList.add(snippet); |
||||||
|
endMarkerIndex = 0; |
||||||
|
} |
||||||
|
} else { |
||||||
|
endMarkerIndex = 0; |
||||||
|
|
||||||
|
if (stack.peek().startLine == lineStart){ |
||||||
|
// build snippet key
|
||||||
|
keyBuf.append(c); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
if (c == startMarkerChars[startMarkerIndex]) { |
||||||
|
startMarkerIndex++; |
||||||
|
if (startMarkerIndex == startMarkerChars.length) { |
||||||
|
// found new begin marker
|
||||||
|
if (!stack.isEmpty()) { |
||||||
|
// nested snippet, save previous key before pushing new one
|
||||||
|
Snippet snippet = stack.peek(); |
||||||
|
snippet.key = keyBuf.toString().trim(); |
||||||
|
} |
||||||
|
stack.push(new Snippet(document, "tempkey", lineStart)); |
||||||
|
keyBuf.setLength(0); |
||||||
|
startMarkerIndex = 0; |
||||||
|
} |
||||||
|
|
||||||
|
} else { |
||||||
|
startMarkerIndex = 0; |
||||||
|
} |
||||||
|
charCount++; |
||||||
|
if (c == '\n') { |
||||||
|
lineStart = charCount; |
||||||
|
} |
||||||
|
} |
||||||
|
nleft -= segment.count; |
||||||
|
offset += segment.count; |
||||||
|
} |
||||||
|
} catch (BadLocationException e) { |
||||||
|
System.err.println(e); |
||||||
|
} |
||||||
|
return snippetMap; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,16 @@ |
|||||||
|
# CodeViewer ResourceBundle properties file |
||||||
|
|
||||||
|
CodeViewer.images=Images |
||||||
|
CodeViewer.noCodeLoaded=no code loaded |
||||||
|
CodeViewer.noCodeAvailable=no code available |
||||||
|
|
||||||
|
CodeViewer.snippets.highlightCode=Highlight code to: |
||||||
|
CodeViewer.snippets.selectOne=Select One |
||||||
|
CodeViewer.snippets.navigateFirst=move to first code snippet within highlighted set |
||||||
|
CodeViewer.snippets.navigateNext=move to next code snippet within highlighted set |
||||||
|
CodeViewer.snippets.navigatePrevious=move to previous code fragment within highlighted set |
||||||
|
CodeViewer.snippets.navigateLast=move to last code snippet within highlighted set |
||||||
|
|
||||||
|
CodeViewer.snippets.noCodeHighlighted=No highlight selected |
||||||
|
|
||||||
|
|
After Width: | Height: | Size: 3.7 KiB |
@ -0,0 +1,129 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
package com.sun.swingset3.demos; |
||||||
|
|
||||||
|
import java.awt.*; |
||||||
|
import java.net.URI; |
||||||
|
import java.io.IOException; |
||||||
|
import javax.swing.*; |
||||||
|
import javax.jnlp.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Pavel Porvatov |
||||||
|
*/ |
||||||
|
public class DemoUtilities { |
||||||
|
private DemoUtilities() { |
||||||
|
// Hide constructor
|
||||||
|
} |
||||||
|
|
||||||
|
public static void setToplevelLocation(Window toplevel, Component component, |
||||||
|
int relativePosition) { |
||||||
|
|
||||||
|
Rectangle compBounds = component.getBounds(); |
||||||
|
|
||||||
|
// Convert component location to screen coordinates
|
||||||
|
Point p = new Point(); |
||||||
|
SwingUtilities.convertPointToScreen(p, component); |
||||||
|
|
||||||
|
int x; |
||||||
|
int y; |
||||||
|
|
||||||
|
// Set frame location to be centered on panel
|
||||||
|
switch (relativePosition) { |
||||||
|
case SwingConstants.NORTH: { |
||||||
|
x = (p.x + (compBounds.width / 2)) - (toplevel.getWidth() / 2); |
||||||
|
y = p.y - toplevel.getHeight(); |
||||||
|
break; |
||||||
|
} |
||||||
|
case SwingConstants.EAST: { |
||||||
|
x = p.x + compBounds.width; |
||||||
|
y = (p.y + (compBounds.height / 2)) - (toplevel.getHeight() / 2); |
||||||
|
break; |
||||||
|
} |
||||||
|
case SwingConstants.SOUTH: { |
||||||
|
x = (p.x + (compBounds.width / 2)) - (toplevel.getWidth() / 2); |
||||||
|
y = p.y + compBounds.height; |
||||||
|
break; |
||||||
|
} |
||||||
|
case SwingConstants.WEST: { |
||||||
|
x = p.x - toplevel.getWidth(); |
||||||
|
y = (p.y + (compBounds.height / 2)) - (toplevel.getHeight() / 2); |
||||||
|
break; |
||||||
|
} |
||||||
|
case SwingConstants.NORTH_EAST: { |
||||||
|
x = p.x + compBounds.width; |
||||||
|
y = p.y - toplevel.getHeight(); |
||||||
|
break; |
||||||
|
} |
||||||
|
case SwingConstants.NORTH_WEST: { |
||||||
|
x = p.x - toplevel.getWidth(); |
||||||
|
y = p.y - toplevel.getHeight(); |
||||||
|
break; |
||||||
|
} |
||||||
|
case SwingConstants.SOUTH_EAST: { |
||||||
|
x = p.x + compBounds.width; |
||||||
|
y = p.y + compBounds.height; |
||||||
|
break; |
||||||
|
} |
||||||
|
case SwingConstants.SOUTH_WEST: { |
||||||
|
x = p.x - toplevel.getWidth(); |
||||||
|
y = p.y + compBounds.height; |
||||||
|
break; |
||||||
|
} |
||||||
|
default: |
||||||
|
case SwingConstants.CENTER: { |
||||||
|
x = (p.x + (compBounds.width / 2)) - (toplevel.getWidth() / 2); |
||||||
|
y = (p.y + (compBounds.height / 2)) - (toplevel.getHeight() / 2); |
||||||
|
} |
||||||
|
} |
||||||
|
toplevel.setLocation(x, y); |
||||||
|
} |
||||||
|
|
||||||
|
public static boolean browse(URI uri) throws IOException, UnavailableServiceException { |
||||||
|
// Try using the Desktop api first
|
||||||
|
try { |
||||||
|
Desktop desktop = Desktop.getDesktop(); |
||||||
|
desktop.browse(uri); |
||||||
|
|
||||||
|
return true; |
||||||
|
} catch (SecurityException e) { |
||||||
|
// Running in sandbox, try using WebStart service
|
||||||
|
BasicService basicService = |
||||||
|
(BasicService) ServiceManager.lookup("javax.jnlp.BasicService"); |
||||||
|
|
||||||
|
if (basicService.isWebBrowserSupported()) { |
||||||
|
return basicService.showDocument(uri.toURL()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,238 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
package com.sun.swingset3.demos; |
||||||
|
|
||||||
|
import java.awt.*; |
||||||
|
import javax.swing.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* JGridPanel |
||||||
|
* |
||||||
|
* @author Pavel Porvatov |
||||||
|
*/ |
||||||
|
public class JGridPanel extends JPanel { |
||||||
|
public static final int DEFAULT_GAP = 5; |
||||||
|
|
||||||
|
public enum Layout { |
||||||
|
FIRST, |
||||||
|
CENTER, |
||||||
|
LAST, |
||||||
|
FILL |
||||||
|
} |
||||||
|
|
||||||
|
private enum ComponentType { |
||||||
|
NO_RESIZABLE, |
||||||
|
HORIZONTAL_FILL, |
||||||
|
FULL |
||||||
|
} |
||||||
|
|
||||||
|
private final int cols; |
||||||
|
|
||||||
|
private int bigCol = -1; |
||||||
|
|
||||||
|
private int bigRow = -1; |
||||||
|
|
||||||
|
private int vGap = -1; |
||||||
|
|
||||||
|
private int hGap = -1; |
||||||
|
|
||||||
|
public JGridPanel(int cols) { |
||||||
|
this(cols, -1, -1); |
||||||
|
} |
||||||
|
|
||||||
|
public JGridPanel(int cols, int bigCol) { |
||||||
|
this(cols, bigCol, -1); |
||||||
|
} |
||||||
|
|
||||||
|
public JGridPanel(int cols, int bigCol, int bigRow) { |
||||||
|
super(new GridBagLayout()); |
||||||
|
|
||||||
|
assert cols > 0; |
||||||
|
assert bigCol >= -1 && bigCol < cols; |
||||||
|
assert bigRow >= -1; |
||||||
|
|
||||||
|
this.cols = cols; |
||||||
|
this.bigCol = bigCol; |
||||||
|
this.bigRow = bigRow; |
||||||
|
} |
||||||
|
|
||||||
|
public void setVGap(int vGap) { |
||||||
|
this.vGap = vGap; |
||||||
|
} |
||||||
|
|
||||||
|
public void setHGap(int hGap) { |
||||||
|
this.hGap = hGap; |
||||||
|
} |
||||||
|
|
||||||
|
public JGridPanel cell() { |
||||||
|
return cell(null, getHLayout(null), getVLayout(null), null); |
||||||
|
} |
||||||
|
|
||||||
|
public JGridPanel cell(Component component) { |
||||||
|
return cell(component, getHLayout(component), getVLayout(component), null); |
||||||
|
} |
||||||
|
|
||||||
|
public JGridPanel cell(Component component, Layout hLayout) { |
||||||
|
return cell(component, hLayout, getVLayout(component), null); |
||||||
|
} |
||||||
|
|
||||||
|
public JGridPanel cell(Component component, Layout hLayout, Layout vLayout) { |
||||||
|
return cell(component, hLayout, vLayout, null); |
||||||
|
} |
||||||
|
|
||||||
|
public JGridPanel cell(Component component, Insets insets) { |
||||||
|
assert insets != null; |
||||||
|
|
||||||
|
return cell(component, getHLayout(component), getVLayout(component), insets); |
||||||
|
} |
||||||
|
|
||||||
|
private JGridPanel cell(Component component, Layout hLayout, Layout vLayout, Insets insets) { |
||||||
|
int componentCount = getComponentCount(); |
||||||
|
int x = componentCount % cols; |
||||||
|
int y = componentCount / cols; |
||||||
|
|
||||||
|
int weightx = x == bigCol || (bigCol < 0 && hLayout == Layout.FILL) ? 1 : 0; |
||||||
|
int weighty = y == bigRow || (bigRow < 0 && vLayout == Layout.FILL) ? 1 : 0; |
||||||
|
|
||||||
|
if (insets == null) { |
||||||
|
int topGap = y == 0 ? 0 : vGap; |
||||||
|
int leftGap = x == 0 ? 0 : hGap; |
||||||
|
|
||||||
|
insets = new Insets(topGap < 0 ? DEFAULT_GAP : topGap, |
||||||
|
leftGap < 0 ? DEFAULT_GAP : leftGap, 0, 0); |
||||||
|
} |
||||||
|
|
||||||
|
add(component == null ? createSeparator() : component, |
||||||
|
new GridBagConstraints(x, y, |
||||||
|
1, 1, |
||||||
|
weightx, weighty, |
||||||
|
getAnchor(hLayout, vLayout), getFill(hLayout, vLayout), |
||||||
|
insets, 0, 0)); |
||||||
|
|
||||||
|
return this; |
||||||
|
} |
||||||
|
|
||||||
|
public void setComponent(Component component, int col, int row) { |
||||||
|
assert col >= 0 && col < cols; |
||||||
|
assert row >= 0; |
||||||
|
|
||||||
|
GridBagLayout layout = (GridBagLayout) getLayout(); |
||||||
|
|
||||||
|
for (int i = 0; i < getComponentCount(); i++) { |
||||||
|
Component oldComponent = getComponent(i); |
||||||
|
|
||||||
|
GridBagConstraints constraints = layout.getConstraints(oldComponent); |
||||||
|
|
||||||
|
if (constraints.gridx == col && constraints.gridy == row) { |
||||||
|
remove(i); |
||||||
|
|
||||||
|
add(component == null ? createSeparator() : component, constraints); |
||||||
|
|
||||||
|
validate(); |
||||||
|
repaint(); |
||||||
|
|
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Cell not found
|
||||||
|
assert false; |
||||||
|
} |
||||||
|
|
||||||
|
private static JComponent createSeparator() { |
||||||
|
return new JLabel(); |
||||||
|
} |
||||||
|
|
||||||
|
private static int getFill(Layout hLayout, Layout vLayout) { |
||||||
|
if (hLayout == Layout.FILL) { |
||||||
|
return vLayout == Layout.FILL ? GridBagConstraints.BOTH : GridBagConstraints.HORIZONTAL; |
||||||
|
} |
||||||
|
|
||||||
|
return vLayout == Layout.FILL ? GridBagConstraints.VERTICAL : GridBagConstraints.NONE; |
||||||
|
} |
||||||
|
|
||||||
|
private static ComponentType getComponentType(Component component) { |
||||||
|
if (component == null || |
||||||
|
component instanceof JLabel || |
||||||
|
component instanceof JRadioButton || |
||||||
|
component instanceof JCheckBox || |
||||||
|
component instanceof JButton) { |
||||||
|
return ComponentType.NO_RESIZABLE; |
||||||
|
} |
||||||
|
|
||||||
|
if (component instanceof JComboBox || |
||||||
|
component instanceof JTextField) { |
||||||
|
return ComponentType.HORIZONTAL_FILL; |
||||||
|
} |
||||||
|
|
||||||
|
return ComponentType.FULL; |
||||||
|
} |
||||||
|
|
||||||
|
private static Layout getHLayout(Component component) { |
||||||
|
if (getComponentType(component) == ComponentType.NO_RESIZABLE) { |
||||||
|
return Layout.FIRST; |
||||||
|
} else { |
||||||
|
return Layout.FILL; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static Layout getVLayout(Component component) { |
||||||
|
if (getComponentType(component) == ComponentType.FULL) { |
||||||
|
return Layout.FILL; |
||||||
|
} else { |
||||||
|
return Layout.CENTER; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static final int[][] ANCHORS = new int[][]{ |
||||||
|
{GridBagConstraints.NORTHWEST, GridBagConstraints.NORTH, GridBagConstraints.NORTHEAST}, |
||||||
|
{GridBagConstraints.WEST, GridBagConstraints.CENTER, GridBagConstraints.EAST}, |
||||||
|
{GridBagConstraints.SOUTHWEST, GridBagConstraints.SOUTH, GridBagConstraints.SOUTHEAST} |
||||||
|
}; |
||||||
|
|
||||||
|
private static int getAnchorIndex(Layout layout) { |
||||||
|
if (layout == Layout.CENTER) { |
||||||
|
return 1; |
||||||
|
} else if (layout == Layout.LAST) { |
||||||
|
return 2; |
||||||
|
} else { |
||||||
|
return 0; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static int getAnchor(Layout hLayout, Layout vLayout) { |
||||||
|
return ANCHORS[getAnchorIndex(vLayout)][getAnchorIndex(hLayout)]; |
||||||
|
} |
||||||
|
|
||||||
|
public void setBorderEqual(int border) { |
||||||
|
setBorder(BorderFactory.createEmptyBorder(border, border, border, border)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,244 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.sun.swingset3.demos; |
||||||
|
|
||||||
|
import java.awt.Color; |
||||||
|
import java.awt.Cursor; |
||||||
|
import java.awt.Graphics; |
||||||
|
import java.awt.Insets; |
||||||
|
import java.awt.Rectangle; |
||||||
|
import java.awt.event.ActionEvent; |
||||||
|
import java.net.URI; |
||||||
|
import java.net.URISyntaxException; |
||||||
|
import javax.swing.AbstractAction; |
||||||
|
import javax.swing.Action; |
||||||
|
import javax.swing.ButtonModel; |
||||||
|
import javax.swing.Icon; |
||||||
|
import javax.swing.JButton; |
||||||
|
import javax.swing.SwingUtilities; |
||||||
|
import javax.swing.UIManager; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author aim |
||||||
|
*/ |
||||||
|
//<snip>Create HTML hyperlink
|
||||||
|
//<snip>Create HTML image hyperlink
|
||||||
|
public class JHyperlink extends JButton { |
||||||
|
private static final BrowseAction defaultBrowseAction = new BrowseAction(); |
||||||
|
|
||||||
|
private URI targetURI; |
||||||
|
private boolean visited; |
||||||
|
|
||||||
|
private final transient Rectangle viewRect = new Rectangle(); |
||||||
|
private final transient Rectangle iconRect = new Rectangle(); |
||||||
|
private final transient Rectangle textRect = new Rectangle(); |
||||||
|
|
||||||
|
//remind(aim): lookup colors instead of hardcoding them
|
||||||
|
private Color normalForeground; |
||||||
|
private Color activeForeground; |
||||||
|
private Color visitedForeground; |
||||||
|
private boolean drawUnderline = true; |
||||||
|
|
||||||
|
static { |
||||||
|
UIManager.put("Hyperlink.foreground", Color.blue); |
||||||
|
UIManager.put("Hyperlink.activeForeground", Color.red); |
||||||
|
UIManager.put("Hyperlink.visitedForeground", new Color(85, 145, 90)); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new instance of JHyperlink |
||||||
|
*/ |
||||||
|
public JHyperlink() { |
||||||
|
super(); |
||||||
|
normalForeground = UIManager.getColor("Hyperlink.foreground"); |
||||||
|
activeForeground = UIManager.getColor("Hyperlink.activeForeground"); |
||||||
|
visitedForeground = UIManager.getColor("Hyperlink.visitedForeground"); |
||||||
|
setBorderPainted(false); |
||||||
|
setContentAreaFilled(false); |
||||||
|
setForeground(normalForeground); |
||||||
|
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); |
||||||
|
setMargin(new Insets(0,0,0,0)); |
||||||
|
setAction(defaultBrowseAction); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Creates a new instance of JHyperlink |
||||||
|
*/ |
||||||
|
public JHyperlink(String text) { |
||||||
|
this(); |
||||||
|
setText(text); // override the inheritence of the action's name
|
||||||
|
} |
||||||
|
|
||||||
|
public JHyperlink(String text, String targetURI) throws URISyntaxException { |
||||||
|
this(text, new URI(targetURI)); |
||||||
|
} |
||||||
|
|
||||||
|
public JHyperlink(String text, URI target) { |
||||||
|
this(text); |
||||||
|
setTarget(target); |
||||||
|
} |
||||||
|
|
||||||
|
public JHyperlink(String text, Action action) { |
||||||
|
this(text); |
||||||
|
setAction(action); // replaces default browse action
|
||||||
|
setText(text); // override the inheritence of the action's name
|
||||||
|
} |
||||||
|
|
||||||
|
public JHyperlink(String text, Icon icon) { |
||||||
|
this(text); |
||||||
|
setIcon(icon); |
||||||
|
} |
||||||
|
|
||||||
|
public JHyperlink(Icon icon, String targetURI) throws URISyntaxException { |
||||||
|
this(null, icon, targetURI); |
||||||
|
} |
||||||
|
|
||||||
|
public JHyperlink(String text, Icon icon, String targetURI) throws URISyntaxException { |
||||||
|
this(text, new URI(targetURI)); |
||||||
|
setIcon(icon); |
||||||
|
} |
||||||
|
|
||||||
|
public JHyperlink(String text, Icon icon, URI target) { |
||||||
|
this(text); |
||||||
|
setIcon(icon); |
||||||
|
setTarget(target); |
||||||
|
} |
||||||
|
|
||||||
|
public void setTarget(URI target) { |
||||||
|
this.targetURI = target; |
||||||
|
setToolTipText(target.toASCIIString()); |
||||||
|
} |
||||||
|
|
||||||
|
public URI getTarget() { |
||||||
|
return targetURI; |
||||||
|
} |
||||||
|
|
||||||
|
public void setVisited(boolean visited) { |
||||||
|
this.visited = visited; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isVisited() { |
||||||
|
return visited; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void setForeground(Color foreground) { |
||||||
|
normalForeground = foreground; |
||||||
|
super.setForeground(foreground); |
||||||
|
} |
||||||
|
|
||||||
|
public void setVisitedForeground(Color visited) { |
||||||
|
visitedForeground = visited; |
||||||
|
} |
||||||
|
|
||||||
|
public void setDrawUnderline(boolean drawUnderline) { |
||||||
|
this.drawUnderline = drawUnderline; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean getDrawUnderline() { |
||||||
|
return drawUnderline; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
protected void paintComponent(Graphics g) { |
||||||
|
// Set the foreground on the fly to ensure the text is painted
|
||||||
|
// with the proper color in super.paintComponent
|
||||||
|
ButtonModel model = getModel(); |
||||||
|
if (model.isArmed()) { |
||||||
|
super.setForeground(activeForeground); |
||||||
|
} else if (visited) { |
||||||
|
super.setForeground(visitedForeground); |
||||||
|
} else { |
||||||
|
super.setForeground(normalForeground); |
||||||
|
} |
||||||
|
super.paintComponent(g); |
||||||
|
|
||||||
|
if (drawUnderline) { |
||||||
|
Insets insets = getInsets(); |
||||||
|
viewRect.x = insets.left; |
||||||
|
viewRect.y = insets.top; |
||||||
|
viewRect.width = getWidth() - insets.left - insets.right; |
||||||
|
viewRect.height = getHeight() - insets.top - insets.bottom; |
||||||
|
int baseline = getBaseline(viewRect.width, viewRect.height); |
||||||
|
|
||||||
|
iconRect.x = iconRect.y = iconRect.width = iconRect.height = 0; |
||||||
|
textRect.x = textRect.y = textRect.width = textRect.height = 0; |
||||||
|
SwingUtilities.layoutCompoundLabel(g.getFontMetrics(), getText(), |
||||||
|
getIcon(), getVerticalAlignment(), getHorizontalAlignment(), |
||||||
|
getVerticalTextPosition(), getHorizontalTextPosition(), |
||||||
|
viewRect, iconRect, textRect, getIconTextGap()); |
||||||
|
|
||||||
|
// getBaseline not returning correct results, so workaround for now
|
||||||
|
if (UIManager.getLookAndFeel().getName().equals("Nimbus")) { |
||||||
|
baseline += 7; |
||||||
|
} else { |
||||||
|
baseline += 3; |
||||||
|
} |
||||||
|
|
||||||
|
g.setColor(getForeground()); |
||||||
|
g.drawLine(textRect.x, |
||||||
|
baseline, |
||||||
|
textRect.x + textRect.width, |
||||||
|
baseline); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
// This action is stateless and hence can be shared across hyperlinks
|
||||||
|
private static class BrowseAction extends AbstractAction { |
||||||
|
public BrowseAction() { |
||||||
|
super(); |
||||||
|
} |
||||||
|
public void actionPerformed(ActionEvent e) { |
||||||
|
JHyperlink hyperlink = (JHyperlink)e.getSource(); |
||||||
|
|
||||||
|
URI targetURI = hyperlink.getTarget(); |
||||||
|
if (targetURI != null) { |
||||||
|
try { |
||||||
|
DemoUtilities.browse(targetURI); |
||||||
|
hyperlink.setVisited(true); |
||||||
|
} catch (Exception ex) { |
||||||
|
ex.printStackTrace(); |
||||||
|
System.err.println(ex); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
//</snip>
|
||||||
|
//</snip>
|
||||||
|
|
||||||
|
} |
||||||
|
|
@ -0,0 +1,84 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
package com.sun.swingset3.demos; |
||||||
|
|
||||||
|
import java.net.URL; |
||||||
|
import java.util.MissingResourceException; |
||||||
|
import java.util.ResourceBundle; |
||||||
|
import java.util.logging.Level; |
||||||
|
import java.util.logging.Logger; |
||||||
|
import javax.swing.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Pavel Porvatov |
||||||
|
*/ |
||||||
|
public class ResourceManager { |
||||||
|
private static final Logger logger = Logger.getLogger(ResourceManager.class.getName()); |
||||||
|
|
||||||
|
private final Class demoClass; |
||||||
|
|
||||||
|
// Resource bundle for internationalized and accessible text
|
||||||
|
private ResourceBundle bundle = null; |
||||||
|
|
||||||
|
public ResourceManager(Class demoClass) { |
||||||
|
this.demoClass = demoClass; |
||||||
|
|
||||||
|
String bundleName = demoClass.getPackage().getName() + ".resources." + demoClass.getSimpleName(); |
||||||
|
|
||||||
|
try { |
||||||
|
bundle = ResourceBundle.getBundle(bundleName); |
||||||
|
} catch (MissingResourceException e) { |
||||||
|
logger.log(Level.SEVERE, "Couldn't load bundle: " + bundleName); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public String getString(String key) { |
||||||
|
return bundle != null ? bundle.getString(key) : key; |
||||||
|
} |
||||||
|
|
||||||
|
public char getMnemonic(String key) { |
||||||
|
return (getString(key)).charAt(0); |
||||||
|
} |
||||||
|
|
||||||
|
public ImageIcon createImageIcon(String filename, String description) { |
||||||
|
String path = "resources/images/" + filename; |
||||||
|
|
||||||
|
URL imageURL = demoClass.getResource(path); |
||||||
|
|
||||||
|
if (imageURL == null) { |
||||||
|
logger.log(Level.SEVERE, "unable to access image file: " + path); |
||||||
|
|
||||||
|
return null; |
||||||
|
} else { |
||||||
|
return new ImageIcon(imageURL, description); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,132 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2008 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.sun.swingset3.demos; |
||||||
|
|
||||||
|
import java.awt.Component; |
||||||
|
import java.awt.Dimension; |
||||||
|
import java.awt.GridBagConstraints; |
||||||
|
import java.awt.GridBagLayout; |
||||||
|
import javax.swing.JComponent; |
||||||
|
import javax.swing.JLayeredPane; |
||||||
|
import javax.swing.JPanel; |
||||||
|
import javax.swing.SwingUtilities; |
||||||
|
import org.jdesktop.animation.timing.Animator; |
||||||
|
import org.jdesktop.animation.timing.interpolation.PropertySetter; |
||||||
|
import org.jdesktop.swingx.JXPanel; |
||||||
|
|
||||||
|
/** |
||||||
|
* Container class which extends JLayeredPane to ensure its sizing |
||||||
|
* tracks its "master" child component and supported fading a message |
||||||
|
* component in/out of the top layer |
||||||
|
* @author Amy Fowler |
||||||
|
*/ |
||||||
|
public class Stacker extends JLayeredPane { |
||||||
|
private Component master; // dictates sizing, scrolling
|
||||||
|
private JPanel messageLayer; |
||||||
|
private JXPanel messageAlpha; |
||||||
|
|
||||||
|
public Stacker(Component master) { |
||||||
|
this.master = master; |
||||||
|
setLayout(null); |
||||||
|
add(master, JLayeredPane.DEFAULT_LAYER); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Dimension getPreferredSize() { |
||||||
|
return master.getPreferredSize(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void doLayout() { |
||||||
|
// ensure all layers are sized the same
|
||||||
|
Dimension size = getSize(); |
||||||
|
Component layers[] = getComponents(); |
||||||
|
for (Component layer : layers) { |
||||||
|
layer.setBounds(0, 0, size.width, size.height); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Fades in the specified message component in the top layer of this |
||||||
|
* layered pane. |
||||||
|
* @param message the component to be displayed in the message layer |
||||||
|
* @param finalAlpha the alpha value of the component when fade in is complete |
||||||
|
*/ |
||||||
|
public void showMessageLayer(JComponent message, final float finalAlpha) { |
||||||
|
messageLayer = new JPanel(); |
||||||
|
messageLayer.setOpaque(false); |
||||||
|
GridBagLayout gridbag = new GridBagLayout(); |
||||||
|
messageLayer.setLayout(gridbag); |
||||||
|
GridBagConstraints c = new GridBagConstraints(); |
||||||
|
c.anchor = GridBagConstraints.CENTER; |
||||||
|
|
||||||
|
messageAlpha = new JXPanel(); |
||||||
|
messageAlpha.setOpaque(false); |
||||||
|
messageAlpha.setAlpha(0.0f); |
||||||
|
gridbag.addLayoutComponent(messageAlpha, c); |
||||||
|
messageLayer.add(messageAlpha); |
||||||
|
messageAlpha.add(message); |
||||||
|
|
||||||
|
add(messageLayer, JLayeredPane.POPUP_LAYER); |
||||||
|
revalidate(); |
||||||
|
SwingUtilities.invokeLater(new Runnable() { |
||||||
|
public void run() { |
||||||
|
Animator animator = new Animator(2000, |
||||||
|
new PropertySetter(messageAlpha, "alpha", 0.0f, finalAlpha)); |
||||||
|
animator.setStartDelay(200); |
||||||
|
animator.setAcceleration(.2f); |
||||||
|
animator.setDeceleration(.5f); |
||||||
|
animator.start(); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Fades out and removes the current message component |
||||||
|
*/ |
||||||
|
public void hideMessageLayer() { |
||||||
|
if (messageLayer != null && messageLayer.isShowing()) { |
||||||
|
Animator animator = new Animator(500, |
||||||
|
new PropertySetter(messageAlpha, "alpha", messageAlpha.getAlpha(), 0.0f) { |
||||||
|
public void end() { |
||||||
|
remove(messageLayer); |
||||||
|
revalidate(); |
||||||
|
} |
||||||
|
}); |
||||||
|
animator.setStartDelay(300); |
||||||
|
animator.setAcceleration(.2f); |
||||||
|
animator.setDeceleration(.5f); |
||||||
|
animator.start(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,226 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.sun.swingset3.demos.button; |
||||||
|
|
||||||
|
|
||||||
|
import java.awt.Color; |
||||||
|
import java.awt.FlowLayout; |
||||||
|
import java.awt.GridLayout; |
||||||
|
import java.awt.event.ActionEvent; |
||||||
|
import java.awt.event.ActionListener; |
||||||
|
import java.net.URISyntaxException; |
||||||
|
import javax.swing.BorderFactory; |
||||||
|
import javax.swing.ImageIcon; |
||||||
|
import javax.swing.JButton; |
||||||
|
import javax.swing.JFrame; |
||||||
|
import javax.swing.JPanel; |
||||||
|
import javax.swing.SwingUtilities; |
||||||
|
|
||||||
|
import com.sun.swingset3.DemoProperties; |
||||||
|
import com.sun.swingset3.demos.JHyperlink; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author aim |
||||||
|
*/ |
||||||
|
@DemoProperties( |
||||||
|
value = "JButton Demo", |
||||||
|
category = "Controls", |
||||||
|
description = "Demonstrates the many uses of JButton, Swing's push button component.", |
||||||
|
sourceFiles = { |
||||||
|
"com/sun/swingset3/demos/button/ButtonDemo.java", |
||||||
|
"com/sun/swingset3/demos/JHyperlink.java", |
||||||
|
"com/sun/swingset3/demos/button/resources/ButtonDemo.html", |
||||||
|
"com/sun/swingset3/demos/button/resources/images/blogs.png", |
||||||
|
"com/sun/swingset3/demos/button/resources/images/ButtonDemo.gif", |
||||||
|
"com/sun/swingset3/demos/button/resources/images/document-print.png", |
||||||
|
"com/sun/swingset3/demos/button/resources/images/earth_day.gif", |
||||||
|
"com/sun/swingset3/demos/button/resources/images/earth_night.gif", |
||||||
|
"com/sun/swingset3/demos/button/resources/images/edit-find.png", |
||||||
|
"com/sun/swingset3/demos/button/resources/images/redbutton.png", |
||||||
|
"com/sun/swingset3/demos/button/resources/images/redbutton_dark.png", |
||||||
|
"com/sun/swingset3/demos/button/resources/images/redbutton_glow.png" |
||||||
|
} |
||||||
|
) |
||||||
|
public class ButtonDemo extends JPanel { |
||||||
|
|
||||||
|
public ButtonDemo() { |
||||||
|
setToolTipText("Demonstrates JButton, Swing's push button component."); |
||||||
|
initComponents(); |
||||||
|
setOpaque(false); |
||||||
|
} |
||||||
|
|
||||||
|
protected void initComponents() { |
||||||
|
setLayout(new GridLayout(0, 1)); |
||||||
|
|
||||||
|
add(createSimpleButtonPanel()); |
||||||
|
add(createCreativeButtonPanel()); |
||||||
|
} |
||||||
|
|
||||||
|
protected JPanel createSimpleButtonPanel() { |
||||||
|
JPanel panel = new JPanel(); |
||||||
|
panel.setLayout(new FlowLayout(FlowLayout.CENTER, 20, 8)); |
||||||
|
panel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), |
||||||
|
"Simple Buttons")); |
||||||
|
|
||||||
|
//<snip>Create simple button
|
||||||
|
final JButton simpleButton = new JButton("Do it"); |
||||||
|
simpleButton.setToolTipText("simple button"); |
||||||
|
//</snip>
|
||||||
|
//<snip>Add action listener using anonymous inner class
|
||||||
|
// This style is useful when the action code is tied to a
|
||||||
|
// single button instance and it's useful for simplicity
|
||||||
|
// sake to keep the action code located near the button.
|
||||||
|
// More global application actions should be implemented
|
||||||
|
// using Action classes instead.
|
||||||
|
simpleButton.addActionListener(new ActionListener() { |
||||||
|
public void actionPerformed(ActionEvent event) { |
||||||
|
simpleButton.setText("Do it again"); |
||||||
|
// Need to force toplevel to relayout to accommodate new button size
|
||||||
|
SwingUtilities.getWindowAncestor(simpleButton).validate(); |
||||||
|
} |
||||||
|
}); |
||||||
|
//</snip>
|
||||||
|
simpleButton.putClientProperty("snippetKey", "Create simple button"); |
||||||
|
panel.add(simpleButton); |
||||||
|
|
||||||
|
//<snip>Create image button
|
||||||
|
// Image is from the Java Look and Feel Graphics Repository:
|
||||||
|
// http://java.sun.com/developer/techDocs/hi/repository
|
||||||
|
JButton button = new JButton(new ImageIcon(getClass(). |
||||||
|
getResource("resources/images/document-print.png"))); |
||||||
|
button.setToolTipText("image button"); |
||||||
|
//</snip>
|
||||||
|
button.putClientProperty("snippetKey", "Create image button"); |
||||||
|
panel.add(button); |
||||||
|
|
||||||
|
//<snip>Create button with text and image
|
||||||
|
// Image is from the Java Look and Feel Graphics Repository:
|
||||||
|
// http://java.sun.com/developer/techDocs/hi/repository
|
||||||
|
button = new JButton("Find", |
||||||
|
new ImageIcon(getClass(). |
||||||
|
getResource("resources/images/edit-find.png"))); |
||||||
|
button.setToolTipText("button with text and image"); |
||||||
|
button.setHorizontalTextPosition(JButton.LEADING); |
||||||
|
button.setIconTextGap(6); |
||||||
|
//</snip>
|
||||||
|
button.putClientProperty("snippetKey", "Create button with text and image"); |
||||||
|
panel.add(button); |
||||||
|
|
||||||
|
//<snip>Create button with background color
|
||||||
|
button = new JButton("Go"); |
||||||
|
button.setBackground(Color.green); |
||||||
|
button.setContentAreaFilled(true); |
||||||
|
button.setOpaque(false); |
||||||
|
button.setToolTipText("button with background color"); |
||||||
|
//</snip>
|
||||||
|
button.putClientProperty("snippetKey", "Create button with background color"); |
||||||
|
panel.add(button); |
||||||
|
|
||||||
|
return panel; |
||||||
|
} |
||||||
|
|
||||||
|
protected JPanel createCreativeButtonPanel() { |
||||||
|
JPanel panel = new JPanel(); |
||||||
|
panel.setLayout(new FlowLayout(FlowLayout.CENTER, 16, 8)); |
||||||
|
panel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createEmptyBorder(), |
||||||
|
"More Interesting Buttons")); |
||||||
|
|
||||||
|
//<snip>Create button with no border
|
||||||
|
JButton button = new JButton(); |
||||||
|
button.setText("Connect"); |
||||||
|
button.setIcon(new ImageIcon(getClass().getResource("resources/images/earth_day.gif"))); |
||||||
|
button.setPressedIcon(new ImageIcon(getClass().getResource("resources/images/earth_night.gif"))); |
||||||
|
button.setBorderPainted(false); |
||||||
|
button.setContentAreaFilled(false); |
||||||
|
button.setVerticalTextPosition(JButton.BOTTOM); |
||||||
|
button.setHorizontalTextPosition(JButton.CENTER); |
||||||
|
button.setIconTextGap(0); |
||||||
|
button.setToolTipText("button with no border"); |
||||||
|
//</snip>
|
||||||
|
button.putClientProperty("snippetKey", "Create button with no border"); |
||||||
|
panel.add(button); |
||||||
|
|
||||||
|
//<snip>Create image button with rollover image
|
||||||
|
button = new JButton(); |
||||||
|
button.setBorderPainted(false); |
||||||
|
button.setContentAreaFilled(false); |
||||||
|
button.setIcon(new ImageIcon(getClass().getResource("resources/images/redbutton.png"))); |
||||||
|
button.setRolloverEnabled(true); |
||||||
|
button.setRolloverIcon(new ImageIcon(getClass().getResource("resources/images/redbutton_glow.png"))); |
||||||
|
button.setPressedIcon(new ImageIcon(getClass().getResource("resources/images/redbutton_dark.png"))); |
||||||
|
button.setToolTipText("button with rollover image"); |
||||||
|
//</snip>
|
||||||
|
button.putClientProperty("snippetKey", "Create image button with rollover image"); |
||||||
|
panel.add(button); |
||||||
|
|
||||||
|
//<snip>Create HTML hyperlink
|
||||||
|
JHyperlink hyperlink; |
||||||
|
try { |
||||||
|
hyperlink = new JHyperlink("Get More Info", "http://java.sun.com/j2se"); |
||||||
|
} catch (URISyntaxException use) { |
||||||
|
use.printStackTrace(); |
||||||
|
hyperlink = new JHyperlink("Get More Info"); |
||||||
|
} |
||||||
|
//</snip>
|
||||||
|
hyperlink.putClientProperty("snippetKey", "Create HTML hyperlink"); |
||||||
|
panel.add(hyperlink); |
||||||
|
|
||||||
|
//<snip>Create HTML image hyperlink
|
||||||
|
try { |
||||||
|
hyperlink = new JHyperlink( |
||||||
|
new ImageIcon(getClass().getResource("resources/images/blogs.png")), |
||||||
|
"http://weblogs.java.net"); |
||||||
|
} catch (URISyntaxException use) { |
||||||
|
use.printStackTrace(); |
||||||
|
} |
||||||
|
//</snip>
|
||||||
|
button.putClientProperty("snippetKey", "Create HTML image hyperlink"); |
||||||
|
panel.add(hyperlink); |
||||||
|
|
||||||
|
return panel; |
||||||
|
} |
||||||
|
|
||||||
|
public static void main(String args[]) { |
||||||
|
final ButtonDemo buttonDemo = new ButtonDemo(); |
||||||
|
|
||||||
|
javax.swing.SwingUtilities.invokeLater(new Runnable() { |
||||||
|
public void run() { |
||||||
|
JFrame frame = new JFrame("JButton Demo"); |
||||||
|
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); |
||||||
|
frame.add(buttonDemo); |
||||||
|
frame.pack(); |
||||||
|
frame.setVisible(true); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1 @@ |
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<body>
<p> Today's modern GUIs often use buttons which don't look like the traditional "push" button. Swing's button component, <a href="http://java.sun.com/javase/6/docs/api/javax/swing/JButton.html">javax.swing.JButton</a>,
can be used to create both ordinary and more creative button visuals. In the end, they all perform an action when clicked.
</p>
<p>
To highlight the source code used to create a particular button, popup the context menu over that button.
</p>
</body>
</html> |
After Width: | Height: | Size: 1.1 KiB |
After Width: | Height: | Size: 9.0 KiB |
After Width: | Height: | Size: 1.5 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.6 KiB |
After Width: | Height: | Size: 1.2 KiB |
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 6.9 KiB |
After Width: | Height: | Size: 7.4 KiB |
@ -0,0 +1,270 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.sun.swingset3.demos.colorchooser; |
||||||
|
|
||||||
|
import java.awt.*; |
||||||
|
import java.awt.event.HierarchyEvent; |
||||||
|
import java.awt.event.HierarchyListener; |
||||||
|
import java.awt.geom.GeneralPath; |
||||||
|
import java.awt.image.BufferedImage; |
||||||
|
import java.util.Hashtable; |
||||||
|
import java.util.Map; |
||||||
|
import javax.swing.*; |
||||||
|
|
||||||
|
import static com.sun.swingset3.demos.colorchooser.BezierAnimationPanel.BezierColor.*; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* BezierAnimationPanel |
||||||
|
* |
||||||
|
* @author Jim Graham |
||||||
|
* @author Jeff Dinkins (removed dynamic setting changes, made swing friendly) |
||||||
|
* @version 1.16 11/17/05 |
||||||
|
*/ |
||||||
|
class BezierAnimationPanel extends JPanel implements Runnable { |
||||||
|
public enum BezierColor { |
||||||
|
BACKGROUND, |
||||||
|
OUTER, |
||||||
|
GRADIENT_A, |
||||||
|
GRADIENT_B |
||||||
|
} |
||||||
|
|
||||||
|
private final Map<BezierColor, Color> colors = new Hashtable<BezierColor, Color>(); |
||||||
|
|
||||||
|
private GradientPaint gradient = null; |
||||||
|
|
||||||
|
private static final int NUMPTS = 6; |
||||||
|
|
||||||
|
private final float[] animpts = new float[NUMPTS * 2]; |
||||||
|
|
||||||
|
private final float[] deltas = new float[NUMPTS * 2]; |
||||||
|
|
||||||
|
private BufferedImage img; |
||||||
|
|
||||||
|
private Thread anim; |
||||||
|
|
||||||
|
private final Object lock = new Object(); |
||||||
|
|
||||||
|
/** |
||||||
|
* BezierAnimationPanel Constructor |
||||||
|
*/ |
||||||
|
public BezierAnimationPanel() { |
||||||
|
setOpaque(true); |
||||||
|
|
||||||
|
colors.put(BACKGROUND, new Color(0, 0, 153)); |
||||||
|
colors.put(OUTER, new Color(255, 255, 255)); |
||||||
|
colors.put(GRADIENT_A, new Color(255, 0, 101)); |
||||||
|
colors.put(GRADIENT_B, new Color(255, 255, 0)); |
||||||
|
|
||||||
|
addHierarchyListener(new HierarchyListener() { |
||||||
|
public void hierarchyChanged(HierarchyEvent e) { |
||||||
|
if (isShowing()) { |
||||||
|
start(); |
||||||
|
} else { |
||||||
|
stop(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
public Color getBezierColor(BezierColor bezierColor) { |
||||||
|
return colors.get(bezierColor); |
||||||
|
} |
||||||
|
|
||||||
|
public void setBezierColor(BezierColor bezierColor, Color value) { |
||||||
|
if (value != null) { |
||||||
|
colors.put(bezierColor, value); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void start() { |
||||||
|
Dimension size = getSize(); |
||||||
|
for (int i = 0; i < animpts.length; i += 2) { |
||||||
|
animpts[i] = (float) (Math.random() * size.width); |
||||||
|
animpts[i + 1] = (float) (Math.random() * size.height); |
||||||
|
deltas[i] = (float) (Math.random() * 4.0 + 2.0); |
||||||
|
deltas[i + 1] = (float) (Math.random() * 4.0 + 2.0); |
||||||
|
if (animpts[i] > size.width / 6.0f) { |
||||||
|
deltas[i] = -deltas[i]; |
||||||
|
} |
||||||
|
if (animpts[i + 1] > size.height / 6.0f) { |
||||||
|
deltas[i + 1] = -deltas[i + 1]; |
||||||
|
} |
||||||
|
} |
||||||
|
anim = new Thread(this); |
||||||
|
anim.setPriority(Thread.MIN_PRIORITY); |
||||||
|
anim.start(); |
||||||
|
} |
||||||
|
|
||||||
|
public synchronized void stop() { |
||||||
|
anim = null; |
||||||
|
notify(); |
||||||
|
} |
||||||
|
|
||||||
|
private static void animate(float[] pts, float[] deltas, int index, int limit) { |
||||||
|
float newpt = pts[index] + deltas[index]; |
||||||
|
if (newpt <= 0) { |
||||||
|
newpt = -newpt; |
||||||
|
deltas[index] = (float) (Math.random() * 3.0 + 2.0); |
||||||
|
} else if (newpt >= (float) limit) { |
||||||
|
newpt = 2.0f * limit - newpt; |
||||||
|
deltas[index] = -(float) (Math.random() * 3.0 + 2.0); |
||||||
|
} |
||||||
|
pts[index] = newpt; |
||||||
|
} |
||||||
|
|
||||||
|
public void run() { |
||||||
|
Thread me = Thread.currentThread(); |
||||||
|
while (getSize().width <= 0) { |
||||||
|
try { |
||||||
|
Thread.sleep(500); |
||||||
|
} catch (InterruptedException e) { |
||||||
|
return; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
Graphics2D g2d = null; |
||||||
|
Graphics2D bufferG2D = null; |
||||||
|
BasicStroke solid = new BasicStroke(9.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 9.0f); |
||||||
|
GeneralPath gp = new GeneralPath(GeneralPath.WIND_NON_ZERO); |
||||||
|
int rule = AlphaComposite.SRC_OVER; |
||||||
|
AlphaComposite opaque = AlphaComposite.SrcOver; |
||||||
|
AlphaComposite blend = AlphaComposite.getInstance(rule, 0.9f); |
||||||
|
AlphaComposite set = AlphaComposite.Src; |
||||||
|
Dimension oldSize = getSize(); |
||||||
|
Shape clippath = null; |
||||||
|
while (anim == me) { |
||||||
|
Dimension size = getSize(); |
||||||
|
if (size.width != oldSize.width || size.height != oldSize.height) { |
||||||
|
img = null; |
||||||
|
clippath = null; |
||||||
|
if (bufferG2D != null) { |
||||||
|
bufferG2D.dispose(); |
||||||
|
bufferG2D = null; |
||||||
|
} |
||||||
|
} |
||||||
|
oldSize = size; |
||||||
|
|
||||||
|
if (img == null) { |
||||||
|
img = (BufferedImage) createImage(size.width, size.height); |
||||||
|
} |
||||||
|
|
||||||
|
if (bufferG2D == null) { |
||||||
|
bufferG2D = img.createGraphics(); |
||||||
|
bufferG2D.setRenderingHint(RenderingHints.KEY_RENDERING, |
||||||
|
RenderingHints.VALUE_RENDER_DEFAULT); |
||||||
|
bufferG2D.setClip(clippath); |
||||||
|
} |
||||||
|
g2d = bufferG2D; |
||||||
|
|
||||||
|
float[] ctrlpts; |
||||||
|
for (int i = 0; i < animpts.length; i += 2) { |
||||||
|
animate(animpts, deltas, i, size.width); |
||||||
|
animate(animpts, deltas, i + 1, size.height); |
||||||
|
} |
||||||
|
ctrlpts = animpts; |
||||||
|
int len = ctrlpts.length; |
||||||
|
gp.reset(); |
||||||
|
float prevx = ctrlpts[len - 2]; |
||||||
|
float prevy = ctrlpts[len - 1]; |
||||||
|
float curx = ctrlpts[0]; |
||||||
|
float cury = ctrlpts[1]; |
||||||
|
float midx = (curx + prevx) / 2.0f; |
||||||
|
float midy = (cury + prevy) / 2.0f; |
||||||
|
gp.moveTo(midx, midy); |
||||||
|
for (int i = 2; i <= ctrlpts.length; i += 2) { |
||||||
|
float x1 = (midx + curx) / 2.0f; |
||||||
|
float y1 = (midy + cury) / 2.0f; |
||||||
|
prevx = curx; |
||||||
|
prevy = cury; |
||||||
|
if (i < ctrlpts.length) { |
||||||
|
curx = ctrlpts[i]; |
||||||
|
cury = ctrlpts[i + 1]; |
||||||
|
} else { |
||||||
|
curx = ctrlpts[0]; |
||||||
|
cury = ctrlpts[1]; |
||||||
|
} |
||||||
|
midx = (curx + prevx) / 2.0f; |
||||||
|
midy = (cury + prevy) / 2.0f; |
||||||
|
float x2 = (prevx + midx) / 2.0f; |
||||||
|
float y2 = (prevy + midy) / 2.0f; |
||||||
|
gp.curveTo(x1, y1, x2, y2, midx, midy); |
||||||
|
} |
||||||
|
gp.closePath(); |
||||||
|
|
||||||
|
synchronized (lock) { |
||||||
|
g2d.setComposite(set); |
||||||
|
g2d.setBackground(getBezierColor(BACKGROUND)); |
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, |
||||||
|
RenderingHints.VALUE_ANTIALIAS_OFF); |
||||||
|
|
||||||
|
// g2d.clearRect(bounds.x-5, bounds.y-5, bounds.x + bounds.width + 5, bounds.y + bounds.height + 5);
|
||||||
|
g2d.clearRect(0, 0, getWidth(), getHeight()); |
||||||
|
|
||||||
|
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, |
||||||
|
RenderingHints.VALUE_ANTIALIAS_ON); |
||||||
|
g2d.setColor(getBezierColor(OUTER)); |
||||||
|
g2d.setComposite(opaque); |
||||||
|
g2d.setStroke(solid); |
||||||
|
g2d.draw(gp); |
||||||
|
g2d.setPaint(gradient); |
||||||
|
|
||||||
|
Rectangle bounds = gp.getBounds(); |
||||||
|
|
||||||
|
gradient = new GradientPaint(bounds.x, bounds.y, getBezierColor(GRADIENT_A), |
||||||
|
bounds.x + bounds.width, bounds.y + bounds.height, |
||||||
|
getBezierColor(GRADIENT_B), true); |
||||||
|
|
||||||
|
g2d.setComposite(blend); |
||||||
|
g2d.fill(gp); |
||||||
|
} |
||||||
|
|
||||||
|
repaint(); |
||||||
|
|
||||||
|
Thread.yield(); |
||||||
|
} |
||||||
|
if (g2d != null) { |
||||||
|
g2d.dispose(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void paint(Graphics g) { |
||||||
|
synchronized (lock) { |
||||||
|
Graphics2D g2d = (Graphics2D) g; |
||||||
|
if (img != null) { |
||||||
|
g2d.setComposite(AlphaComposite.Src); |
||||||
|
g2d.drawImage(img, null, 0, 0); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,186 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.sun.swingset3.demos.colorchooser; |
||||||
|
|
||||||
|
import java.awt.*; |
||||||
|
import java.awt.event.ActionEvent; |
||||||
|
import java.awt.event.ActionListener; |
||||||
|
import javax.swing.*; |
||||||
|
import javax.swing.border.EmptyBorder; |
||||||
|
|
||||||
|
import com.sun.swingset3.demos.JGridPanel; |
||||||
|
import com.sun.swingset3.demos.ResourceManager; |
||||||
|
import com.sun.swingset3.DemoProperties; |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* JColorChooserDemo |
||||||
|
* |
||||||
|
* @author Jeff Dinkins |
||||||
|
* @version 1.1 07/16/99 |
||||||
|
*/ |
||||||
|
@DemoProperties( |
||||||
|
value = "JColorChooser Demo", |
||||||
|
category = "Choosers", |
||||||
|
description = "Demonstrates JColorChooser, a component which allows the user to pick a color.", |
||||||
|
sourceFiles = { |
||||||
|
"com/sun/swingset3/demos/colorchooser/ColorChooserDemo.java", |
||||||
|
"com/sun/swingset3/demos/colorchooser/BezierAnimationPanel.java", |
||||||
|
"com/sun/swingset3/demos/JGridPanel.java", |
||||||
|
"com/sun/swingset3/demos/ResourceManager.java", |
||||||
|
"com/sun/swingset3/demos/colorchooser/resources/ColorChooserDemo.properties", |
||||||
|
"com/sun/swingset3/demos/colorchooser/resources/images/ColorChooserDemo.gif" |
||||||
|
} |
||||||
|
) |
||||||
|
public class ColorChooserDemo extends JPanel { |
||||||
|
private final ResourceManager resourceManager = new ResourceManager(this.getClass()); |
||||||
|
|
||||||
|
private final BezierAnimationPanel bezAnim = new BezierAnimationPanel(); |
||||||
|
|
||||||
|
private final JButton outerColorButton = new JButton(resourceManager.getString("ColorChooserDemo.outer_line")); |
||||||
|
|
||||||
|
private final JButton backgroundColorButton = new JButton(resourceManager.getString("ColorChooserDemo.background")); |
||||||
|
|
||||||
|
private final JButton gradientAButton = new JButton(resourceManager.getString("ColorChooserDemo.grad_a")); |
||||||
|
|
||||||
|
private final JButton gradientBButton = new JButton(resourceManager.getString("ColorChooserDemo.grad_b")); |
||||||
|
|
||||||
|
/** |
||||||
|
* main method allows us to run as a standalone demo. |
||||||
|
*/ |
||||||
|
public static void main(String[] args) { |
||||||
|
JFrame frame = new JFrame(ColorChooserDemo.class.getAnnotation(DemoProperties.class).value()); |
||||||
|
|
||||||
|
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); |
||||||
|
frame.getContentPane().add(new ColorChooserDemo()); |
||||||
|
frame.setPreferredSize(new Dimension(800, 600)); |
||||||
|
frame.pack(); |
||||||
|
frame.setLocationRelativeTo(null); |
||||||
|
frame.setVisible(true); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* ColorChooserDemo Constructor |
||||||
|
*/ |
||||||
|
public ColorChooserDemo() { |
||||||
|
setLayout(new BorderLayout()); |
||||||
|
|
||||||
|
outerColorButton.setIcon(new ColorSwatch(BezierAnimationPanel.BezierColor.OUTER)); |
||||||
|
|
||||||
|
backgroundColorButton.setIcon(new ColorSwatch(BezierAnimationPanel.BezierColor.BACKGROUND)); |
||||||
|
|
||||||
|
gradientAButton.setIcon(new ColorSwatch(BezierAnimationPanel.BezierColor.GRADIENT_A)); |
||||||
|
|
||||||
|
gradientBButton.setIcon(new ColorSwatch(BezierAnimationPanel.BezierColor.GRADIENT_B)); |
||||||
|
|
||||||
|
ActionListener l = new ActionListener() { |
||||||
|
public void actionPerformed(ActionEvent e) { |
||||||
|
JButton button = (JButton) e.getSource(); |
||||||
|
|
||||||
|
final BezierAnimationPanel.BezierColor bezierColor = |
||||||
|
((ColorSwatch) button.getIcon()).getBezierColor(); |
||||||
|
|
||||||
|
Color current = bezAnim.getBezierColor(bezierColor); |
||||||
|
|
||||||
|
final JColorChooser chooser = new JColorChooser(current != null ? |
||||||
|
current : |
||||||
|
Color.WHITE); |
||||||
|
|
||||||
|
ActionListener colorChooserListener = new ActionListener() { |
||||||
|
public void actionPerformed(ActionEvent ae) { |
||||||
|
bezAnim.setBezierColor(bezierColor, chooser.getColor()); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
JDialog dialog = JColorChooser.createDialog(ColorChooserDemo.this, |
||||||
|
resourceManager.getString("ColorChooserDemo.chooser_title"), |
||||||
|
true, |
||||||
|
chooser, |
||||||
|
colorChooserListener, |
||||||
|
null); |
||||||
|
|
||||||
|
dialog.setVisible(true); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
outerColorButton.addActionListener(l); |
||||||
|
backgroundColorButton.addActionListener(l); |
||||||
|
gradientAButton.addActionListener(l); |
||||||
|
gradientBButton.addActionListener(l); |
||||||
|
|
||||||
|
// Add control buttons
|
||||||
|
JPanel buttonPanel = new JPanel(new GridLayout(1, 4, 15, 0)); |
||||||
|
|
||||||
|
buttonPanel.add(backgroundColorButton); |
||||||
|
buttonPanel.add(gradientAButton); |
||||||
|
buttonPanel.add(gradientBButton); |
||||||
|
buttonPanel.add(outerColorButton); |
||||||
|
|
||||||
|
// Add everything to the panel
|
||||||
|
JGridPanel pnContent = new JGridPanel(1, 0, 1); |
||||||
|
|
||||||
|
pnContent.cell(buttonPanel, JGridPanel.Layout.CENTER). |
||||||
|
cell(bezAnim); |
||||||
|
|
||||||
|
pnContent.setBorder(new EmptyBorder(10, 0, 0, 0)); |
||||||
|
|
||||||
|
add(pnContent); |
||||||
|
} |
||||||
|
|
||||||
|
private class ColorSwatch implements Icon { |
||||||
|
private final BezierAnimationPanel.BezierColor bezierColor; |
||||||
|
|
||||||
|
public ColorSwatch(BezierAnimationPanel.BezierColor bezierColor) { |
||||||
|
this.bezierColor = bezierColor; |
||||||
|
} |
||||||
|
|
||||||
|
public int getIconWidth() { |
||||||
|
return 11; |
||||||
|
} |
||||||
|
|
||||||
|
public int getIconHeight() { |
||||||
|
return 11; |
||||||
|
} |
||||||
|
|
||||||
|
public BezierAnimationPanel.BezierColor getBezierColor() { |
||||||
|
return bezierColor; |
||||||
|
} |
||||||
|
|
||||||
|
public void paintIcon(Component c, Graphics g, int x, int y) { |
||||||
|
g.setColor(Color.black); |
||||||
|
g.fillRect(x, y, getIconWidth(), getIconHeight()); |
||||||
|
g.setColor(bezAnim.getBezierColor(bezierColor)); |
||||||
|
g.fillRect(x + 2, y + 2, getIconWidth() - 4, getIconHeight() - 4); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,11 @@ |
|||||||
|
### ColorChooser Demo ### |
||||||
|
|
||||||
|
ColorChooserDemo.accessible_description=The ColorChooser allows a user to pick a color either from a pallete or by choosing RGB or HSB values |
||||||
|
ColorChooserDemo.tooltip=JColorChooser demo |
||||||
|
ColorChooserDemo.name=ColorChooser Demo |
||||||
|
ColorChooserDemo.chooser_title=Choose a Color |
||||||
|
ColorChooserDemo.background=Background |
||||||
|
ColorChooserDemo.grad_a=Gradient 1 |
||||||
|
ColorChooserDemo.grad_b=Gradient 2 |
||||||
|
ColorChooserDemo.outer_line=Perimeter |
||||||
|
ColorChooserDemo.cup=Image of the Java Trademark Coffee Cup |
After Width: | Height: | Size: 1.3 KiB |
@ -0,0 +1,445 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2007-2008 Sun Microsystems, Inc. All Rights Reserved. |
||||||
|
* |
||||||
|
* Redistribution and use in source and binary forms, with or without |
||||||
|
* modification, are permitted provided that the following conditions |
||||||
|
* are met: |
||||||
|
* |
||||||
|
* - Redistributions of source code must retain the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer. |
||||||
|
* |
||||||
|
* - Redistributions in binary form must reproduce the above copyright |
||||||
|
* notice, this list of conditions and the following disclaimer in the |
||||||
|
* documentation and/or other materials provided with the distribution. |
||||||
|
* |
||||||
|
* - Neither the name of Sun Microsystems nor the names of its |
||||||
|
* contributors may be used to endorse or promote products derived |
||||||
|
* from this software without specific prior written permission. |
||||||
|
* |
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS |
||||||
|
* IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
||||||
|
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR |
||||||
|
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
||||||
|
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
||||||
|
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF |
||||||
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING |
||||||
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
||||||
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
||||||
|
*/ |
||||||
|
|
||||||
|
package com.sun.swingset3.demos.combobox; |
||||||
|
|
||||||
|
import java.awt.*; |
||||||
|
import java.awt.event.ActionEvent; |
||||||
|
import java.awt.event.ActionListener; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
import javax.accessibility.AccessibleRelation; |
||||||
|
import javax.swing.*; |
||||||
|
import javax.swing.border.BevelBorder; |
||||||
|
|
||||||
|
import com.sun.swingset3.demos.ResourceManager; |
||||||
|
import com.sun.swingset3.DemoProperties; |
||||||
|
|
||||||
|
/** |
||||||
|
* JComboBox Demo |
||||||
|
* |
||||||
|
* @author Jeff Dinkins |
||||||
|
* @version 1.13 11/17/05 |
||||||
|
*/ |
||||||
|
@DemoProperties( |
||||||
|
value = "JComboBox Demo", |
||||||
|
category = "Controls", |
||||||
|
description = "Demonstrates JComboBox, a control which allows the user to make a selection from a popup list", |
||||||
|
sourceFiles = { |
||||||
|
"com/sun/swingset3/demos/combobox/ComboBoxDemo.java", |
||||||
|
"com/sun/swingset3/demos/ResourceManager.java", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/ComboBoxDemo.properties", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/brenteyes.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/brenthair.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/brentmouth.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/ComboBoxDemo.gif", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/georgeseyes.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/georgeshair.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/georgesmouth.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/hanseyes.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/hanshair.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/hansmouth.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/howardeyes.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/howardhair.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/howardmouth.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/jameseyes.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/jameshair.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/jamesmouth.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/jeffeyes.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/jeffhair.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/jeffmouth.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/joneyes.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/jonhair.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/jonmouth.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/laraeyes.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/larahair.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/laramouth.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/larryeyes.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/larryhair.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/larrymouth.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/lisaeyes.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/lisahair.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/lisamouth.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/michaeleyes.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/michaelhair.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/michaelmouth.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/philipeyes.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/philiphair.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/philipmouth.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/scotteyes.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/scotthair.jpg", |
||||||
|
"com/sun/swingset3/demos/combobox/resources/images/scottmouth.jpg" |
||||||
|
} |
||||||
|
) |
||||||
|
public class ComboBoxDemo extends JPanel implements ActionListener { |
||||||
|
private static final Dimension VGAP15 = new Dimension(1, 15); |
||||||
|
private static final Dimension HGAP20 = new Dimension(20, 1); |
||||||
|
private static final Dimension VGAP20 = new Dimension(1, 20); |
||||||
|
private static final Dimension HGAP30 = new Dimension(30, 1); |
||||||
|
private static final Dimension VGAP30 = new Dimension(1, 30); |
||||||
|
|
||||||
|
private final ResourceManager resourceManager = new ResourceManager(this.getClass()); |
||||||
|
|
||||||
|
private Face face; |
||||||
|
private JLabel faceLabel; |
||||||
|
|
||||||
|
private JComboBox hairCB; |
||||||
|
private JComboBox eyesCB; |
||||||
|
private JComboBox mouthCB; |
||||||
|
|
||||||
|
private JComboBox presetCB; |
||||||
|
|
||||||
|
private final Map<String, Object> parts = new HashMap<String, Object>(); |
||||||
|
|
||||||
|
/** |
||||||
|
* main method allows us to run as a standalone demo. |
||||||
|
*/ |
||||||
|
public static void main(String[] args) { |
||||||
|
JFrame frame = new JFrame(ComboBoxDemo.class.getAnnotation(DemoProperties.class).value()); |
||||||
|
|
||||||
|
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); |
||||||
|
frame.getContentPane().add(new ComboBoxDemo()); |
||||||
|
frame.setPreferredSize(new Dimension(800, 600)); |
||||||
|
frame.pack(); |
||||||
|
frame.setLocationRelativeTo(null); |
||||||
|
frame.setVisible(true); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* ComboBoxDemo Constructor |
||||||
|
*/ |
||||||
|
public ComboBoxDemo() { |
||||||
|
createComboBoxDemo(); |
||||||
|
} |
||||||
|
|
||||||
|
private void createComboBoxDemo() { |
||||||
|
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS)); |
||||||
|
|
||||||
|
JPanel innerPanel = new JPanel(); |
||||||
|
innerPanel.setLayout(new BoxLayout(innerPanel, BoxLayout.X_AXIS)); |
||||||
|
|
||||||
|
add(Box.createRigidArea(VGAP20)); |
||||||
|
add(innerPanel); |
||||||
|
add(Box.createRigidArea(VGAP20)); |
||||||
|
|
||||||
|
innerPanel.add(Box.createRigidArea(HGAP20)); |
||||||
|
|
||||||
|
// Create a panel to hold buttons
|
||||||
|
JPanel comboBoxPanel = new JPanel() { |
||||||
|
public Dimension getMaximumSize() { |
||||||
|
return new Dimension(getPreferredSize().width, super.getMaximumSize().height); |
||||||
|
} |
||||||
|
}; |
||||||
|
comboBoxPanel.setLayout(new BoxLayout(comboBoxPanel, BoxLayout.Y_AXIS)); |
||||||
|
|
||||||
|
comboBoxPanel.add(Box.createRigidArea(VGAP15)); |
||||||
|
|
||||||
|
JLabel l = (JLabel) comboBoxPanel.add(new JLabel(resourceManager.getString("ComboBoxDemo.presets"))); |
||||||
|
l.setAlignmentX(JLabel.LEFT_ALIGNMENT); |
||||||
|
presetCB = (JComboBox) comboBoxPanel.add(createPresetComboBox()); |
||||||
|
presetCB.setAlignmentX(JComboBox.LEFT_ALIGNMENT); |
||||||
|
l.setLabelFor(presetCB); |
||||||
|
comboBoxPanel.add(Box.createRigidArea(VGAP30)); |
||||||
|
|
||||||
|
l = (JLabel) comboBoxPanel.add(new JLabel(resourceManager.getString("ComboBoxDemo.hair_description"))); |
||||||
|
l.setAlignmentX(JLabel.LEFT_ALIGNMENT); |
||||||
|
hairCB = (JComboBox) comboBoxPanel.add(createHairComboBox()); |
||||||
|
hairCB.setAlignmentX(JComboBox.LEFT_ALIGNMENT); |
||||||
|
l.setLabelFor(hairCB); |
||||||
|
comboBoxPanel.add(Box.createRigidArea(VGAP15)); |
||||||
|
|
||||||
|
l = (JLabel) comboBoxPanel.add(new JLabel(resourceManager.getString("ComboBoxDemo.eyes_description"))); |
||||||
|
l.setAlignmentX(JLabel.LEFT_ALIGNMENT); |
||||||
|
eyesCB = (JComboBox) comboBoxPanel.add(createEyesComboBox()); |
||||||
|
eyesCB.setAlignmentX(JComboBox.LEFT_ALIGNMENT); |
||||||
|
l.setLabelFor(eyesCB); |
||||||
|
comboBoxPanel.add(Box.createRigidArea(VGAP15)); |
||||||
|
|
||||||
|
l = (JLabel) comboBoxPanel.add(new JLabel(resourceManager.getString("ComboBoxDemo.mouth_description"))); |
||||||
|
l.setAlignmentX(JLabel.LEFT_ALIGNMENT); |
||||||
|
mouthCB = (JComboBox) comboBoxPanel.add(createMouthComboBox()); |
||||||
|
mouthCB.setAlignmentX(JComboBox.LEFT_ALIGNMENT); |
||||||
|
l.setLabelFor(mouthCB); |
||||||
|
comboBoxPanel.add(Box.createRigidArea(VGAP15)); |
||||||
|
|
||||||
|
// Fill up the remaining space
|
||||||
|
comboBoxPanel.add(new JPanel(new BorderLayout())); |
||||||
|
|
||||||
|
// Create and place the Face.
|
||||||
|
|
||||||
|
face = new Face(); |
||||||
|
JPanel facePanel = new JPanel(); |
||||||
|
facePanel.setLayout(new BorderLayout()); |
||||||
|
facePanel.setBorder(new BevelBorder(BevelBorder.LOWERED)); |
||||||
|
|
||||||
|
faceLabel = new JLabel(face); |
||||||
|
facePanel.add(faceLabel, BorderLayout.CENTER); |
||||||
|
// Indicate that the face panel is controlled by the hair, eyes and
|
||||||
|
// mouth combo boxes.
|
||||||
|
Object[] controlledByObjects = new Object[3]; |
||||||
|
controlledByObjects[0] = hairCB; |
||||||
|
controlledByObjects[1] = eyesCB; |
||||||
|
controlledByObjects[2] = mouthCB; |
||||||
|
AccessibleRelation controlledByRelation = |
||||||
|
new AccessibleRelation(AccessibleRelation.CONTROLLED_BY_PROPERTY, |
||||||
|
controlledByObjects); |
||||||
|
facePanel.getAccessibleContext().getAccessibleRelationSet().add(controlledByRelation); |
||||||
|
|
||||||
|
// Indicate that the hair, eyes and mouth combo boxes are controllers
|
||||||
|
// for the face panel.
|
||||||
|
AccessibleRelation controllerForRelation = |
||||||
|
new AccessibleRelation(AccessibleRelation.CONTROLLER_FOR_PROPERTY, |
||||||
|
facePanel); |
||||||
|
hairCB.getAccessibleContext().getAccessibleRelationSet().add(controllerForRelation); |
||||||
|
eyesCB.getAccessibleContext().getAccessibleRelationSet().add(controllerForRelation); |
||||||
|
mouthCB.getAccessibleContext().getAccessibleRelationSet().add(controllerForRelation); |
||||||
|
|
||||||
|
// add buttons and image panels to inner panel
|
||||||
|
innerPanel.add(comboBoxPanel); |
||||||
|
innerPanel.add(Box.createRigidArea(HGAP30)); |
||||||
|
innerPanel.add(facePanel); |
||||||
|
innerPanel.add(Box.createRigidArea(HGAP20)); |
||||||
|
|
||||||
|
// load up the face parts
|
||||||
|
addFace("brent", resourceManager.getString("ComboBoxDemo.brent")); |
||||||
|
addFace("georges", resourceManager.getString("ComboBoxDemo.georges")); |
||||||
|
addFace("hans", resourceManager.getString("ComboBoxDemo.hans")); |
||||||
|
addFace("howard", resourceManager.getString("ComboBoxDemo.howard")); |
||||||
|
addFace("james", resourceManager.getString("ComboBoxDemo.james")); |
||||||
|
addFace("jeff", resourceManager.getString("ComboBoxDemo.jeff")); |
||||||
|
addFace("jon", resourceManager.getString("ComboBoxDemo.jon")); |
||||||
|
addFace("lara", resourceManager.getString("ComboBoxDemo.lara")); |
||||||
|
addFace("larry", resourceManager.getString("ComboBoxDemo.larry")); |
||||||
|
addFace("lisa", resourceManager.getString("ComboBoxDemo.lisa")); |
||||||
|
addFace("michael", resourceManager.getString("ComboBoxDemo.michael")); |
||||||
|
addFace("philip", resourceManager.getString("ComboBoxDemo.philip")); |
||||||
|
addFace("scott", resourceManager.getString("ComboBoxDemo.scott")); |
||||||
|
|
||||||
|
// set the default face
|
||||||
|
presetCB.setSelectedIndex(0); |
||||||
|
} |
||||||
|
|
||||||
|
private void addFace(String name, String i18n_name) { |
||||||
|
ImageIcon i; |
||||||
|
String i18n_hair = resourceManager.getString("ComboBoxDemo.hair"); |
||||||
|
String i18n_eyes = resourceManager.getString("ComboBoxDemo.eyes"); |
||||||
|
String i18n_mouth = resourceManager.getString("ComboBoxDemo.mouth"); |
||||||
|
|
||||||
|
parts.put(i18n_name, name); // i18n name lookup
|
||||||
|
parts.put(name, i18n_name); // reverse name lookup
|
||||||
|
|
||||||
|
i = resourceManager.createImageIcon(name + "hair.jpg", i18n_name + i18n_hair); |
||||||
|
parts.put(name + "hair", i); |
||||||
|
|
||||||
|
i = resourceManager.createImageIcon(name + "eyes.jpg", i18n_name + i18n_eyes); |
||||||
|
parts.put(name + "eyes", i); |
||||||
|
|
||||||
|
i = resourceManager.createImageIcon(name + "mouth.jpg", i18n_name + i18n_mouth); |
||||||
|
parts.put(name + "mouth", i); |
||||||
|
} |
||||||
|
|
||||||
|
private JComboBox createHairComboBox() { |
||||||
|
JComboBox cb = new JComboBox(); |
||||||
|
fillComboBox(cb); |
||||||
|
cb.addActionListener(this); |
||||||
|
return cb; |
||||||
|
} |
||||||
|
|
||||||
|
private JComboBox createEyesComboBox() { |
||||||
|
JComboBox cb = new JComboBox(); |
||||||
|
fillComboBox(cb); |
||||||
|
cb.addActionListener(this); |
||||||
|
return cb; |
||||||
|
} |
||||||
|
|
||||||
|
private JComboBox createMouthComboBox() { |
||||||
|
JComboBox cb = new JComboBox(); |
||||||
|
fillComboBox(cb); |
||||||
|
cb.addActionListener(this); |
||||||
|
return cb; |
||||||
|
} |
||||||
|
|
||||||
|
private JComboBox createPresetComboBox() { |
||||||
|
JComboBox cb = new JComboBox(); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.preset1")); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.preset2")); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.preset3")); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.preset4")); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.preset5")); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.preset6")); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.preset7")); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.preset8")); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.preset9")); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.preset10")); |
||||||
|
cb.addActionListener(this); |
||||||
|
return cb; |
||||||
|
} |
||||||
|
|
||||||
|
private void fillComboBox(JComboBox cb) { |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.brent")); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.georges")); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.hans")); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.howard")); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.james")); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.jeff")); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.jon")); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.lara")); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.larry")); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.lisa")); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.michael")); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.philip")); |
||||||
|
cb.addItem(resourceManager.getString("ComboBoxDemo.scott")); |
||||||
|
} |
||||||
|
|
||||||
|
public void actionPerformed(ActionEvent e) { |
||||||
|
if (e.getSource() == hairCB) { |
||||||
|
String name = (String) parts.get((String) hairCB.getSelectedItem()); |
||||||
|
face.setHair((ImageIcon) parts.get(name + "hair")); |
||||||
|
faceLabel.repaint(); |
||||||
|
} else if (e.getSource() == eyesCB) { |
||||||
|
String name = (String) parts.get((String) eyesCB.getSelectedItem()); |
||||||
|
face.setEyes((ImageIcon) parts.get(name + "eyes")); |
||||||
|
faceLabel.repaint(); |
||||||
|
} else if (e.getSource() == mouthCB) { |
||||||
|
String name = (String) parts.get((String) mouthCB.getSelectedItem()); |
||||||
|
face.setMouth((ImageIcon) parts.get(name + "mouth")); |
||||||
|
faceLabel.repaint(); |
||||||
|
} else if (e.getSource() == presetCB) { |
||||||
|
String hair = null; |
||||||
|
String eyes = null; |
||||||
|
String mouth = null; |
||||||
|
switch (presetCB.getSelectedIndex()) { |
||||||
|
case 0: |
||||||
|
hair = (String) parts.get("philip"); |
||||||
|
eyes = (String) parts.get("howard"); |
||||||
|
mouth = (String) parts.get("jeff"); |
||||||
|
break; |
||||||
|
case 1: |
||||||
|
hair = (String) parts.get("jeff"); |
||||||
|
eyes = (String) parts.get("larry"); |
||||||
|
mouth = (String) parts.get("philip"); |
||||||
|
break; |
||||||
|
case 2: |
||||||
|
hair = (String) parts.get("howard"); |
||||||
|
eyes = (String) parts.get("scott"); |
||||||
|
mouth = (String) parts.get("hans"); |
||||||
|
break; |
||||||
|
case 3: |
||||||
|
hair = (String) parts.get("philip"); |
||||||
|
eyes = (String) parts.get("jeff"); |
||||||
|
mouth = (String) parts.get("hans"); |
||||||
|
break; |
||||||
|
case 4: |
||||||
|
hair = (String) parts.get("brent"); |
||||||
|
eyes = (String) parts.get("jon"); |
||||||
|
mouth = (String) parts.get("scott"); |
||||||
|
break; |
||||||
|
case 5: |
||||||
|
hair = (String) parts.get("lara"); |
||||||
|
eyes = (String) parts.get("larry"); |
||||||
|
mouth = (String) parts.get("lisa"); |
||||||
|
break; |
||||||
|
case 6: |
||||||
|
hair = (String) parts.get("james"); |
||||||
|
eyes = (String) parts.get("philip"); |
||||||
|
mouth = (String) parts.get("michael"); |
||||||
|
break; |
||||||
|
case 7: |
||||||
|
hair = (String) parts.get("philip"); |
||||||
|
eyes = (String) parts.get("lisa"); |
||||||
|
mouth = (String) parts.get("brent"); |
||||||
|
break; |
||||||
|
case 8: |
||||||
|
hair = (String) parts.get("james"); |
||||||
|
eyes = (String) parts.get("philip"); |
||||||
|
mouth = (String) parts.get("jon"); |
||||||
|
break; |
||||||
|
case 9: |
||||||
|
hair = (String) parts.get("lara"); |
||||||
|
eyes = (String) parts.get("jon"); |
||||||
|
mouth = (String) parts.get("scott"); |
||||||
|
break; |
||||||
|
} |
||||||
|
if (hair != null) { |
||||||
|
hairCB.setSelectedItem(hair); |
||||||
|
eyesCB.setSelectedItem(eyes); |
||||||
|
mouthCB.setSelectedItem(mouth); |
||||||
|
faceLabel.repaint(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static class Face implements Icon { |
||||||
|
private ImageIcon hair; |
||||||
|
private ImageIcon eyes; |
||||||
|
private ImageIcon mouth; |
||||||
|
|
||||||
|
void setHair(ImageIcon i) { |
||||||
|
hair = i; |
||||||
|
} |
||||||
|
|
||||||
|
void setEyes(ImageIcon i) { |
||||||
|
eyes = i; |
||||||
|
} |
||||||
|
|
||||||
|
void setMouth(ImageIcon i) { |
||||||
|
mouth = i; |
||||||
|
} |
||||||
|
|
||||||
|
public void paintIcon(Component c, Graphics g, int x, int y) { |
||||||
|
int height = y; |
||||||
|
x = c.getWidth() / 2 - getIconWidth() / 2; |
||||||
|
|
||||||
|
if (hair != null) { |
||||||
|
hair.paintIcon(c, g, x, height); |
||||||
|
height += hair.getIconHeight(); |
||||||
|
} |
||||||
|
|
||||||
|
if (eyes != null) { |
||||||
|
eyes.paintIcon(c, g, x, height); |
||||||
|
height += eyes.getIconHeight(); |
||||||
|
} |
||||||
|
|
||||||
|
if (mouth != null) { |
||||||
|
mouth.paintIcon(c, g, x, height); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public int getIconWidth() { |
||||||
|
return 344; |
||||||
|
} |
||||||
|
|
||||||
|
public int getIconHeight() { |
||||||
|
return 455; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,42 @@ |
|||||||
|
### ComboBox Demo ### |
||||||
|
|
||||||
|
ComboBoxDemo.accessible_description=This demo shows an example of using the JComboBox component. |
||||||
|
ComboBoxDemo.tooltip=JComboBox demo |
||||||
|
ComboBoxDemo.name=ComboBox Demo |
||||||
|
|
||||||
|
ComboBoxDemo.hair=hair |
||||||
|
ComboBoxDemo.eyes=eyes |
||||||
|
ComboBoxDemo.mouth=mouth |
||||||
|
ComboBoxDemo.presets=Presets: |
||||||
|
|
||||||
|
ComboBoxDemo.preset1=Philip, Howard, Jeff |
||||||
|
ComboBoxDemo.preset2=Jeff, Larry, Philip |
||||||
|
ComboBoxDemo.preset3=Howard, Scott, Hans |
||||||
|
ComboBoxDemo.preset4=Philip, Jeff, Hans |
||||||
|
ComboBoxDemo.preset5=Brent, Jon, Scott |
||||||
|
ComboBoxDemo.preset6=Lara, Larry, Lisa |
||||||
|
ComboBoxDemo.preset7=James, Philip, Michael |
||||||
|
ComboBoxDemo.preset8=Philip, Lisa, Brent |
||||||
|
ComboBoxDemo.preset9=James, Philip, Jon |
||||||
|
ComboBoxDemo.preset10=Lara, Jon, Scott |
||||||
|
|
||||||
|
|
||||||
|
ComboBoxDemo.hair_description=Hair: |
||||||
|
ComboBoxDemo.eyes_description=Eyes & Nose: |
||||||
|
ComboBoxDemo.mouth_description=Mouth: |
||||||
|
|
||||||
|
ComboBoxDemo.amy=Amy |
||||||
|
ComboBoxDemo.brent=Brent |
||||||
|
ComboBoxDemo.georges=Georges |
||||||
|
ComboBoxDemo.hans=Hans |
||||||
|
ComboBoxDemo.howard=Howard |
||||||
|
ComboBoxDemo.james=James |
||||||
|
ComboBoxDemo.jeff=Jeff |
||||||
|
ComboBoxDemo.jon=Jon |
||||||
|
ComboBoxDemo.lara=Lara |
||||||
|
ComboBoxDemo.larry=Larry |
||||||
|
ComboBoxDemo.lisa=Lisa |
||||||
|
ComboBoxDemo.michael=Michael |
||||||
|
ComboBoxDemo.philip=Philip |
||||||
|
ComboBoxDemo.scott=Scott |
||||||
|
|
After Width: | Height: | Size: 672 B |
After Width: | Height: | Size: 2.1 KiB |
After Width: | Height: | Size: 3.5 KiB |