% latex generated by the script '/home/project-web/bumble/cgi-bin/text2latex.cgi' 
% with help from the sed script 'text2latex.sed' 
% query string: 'books/java/java-book' 
% sFileName= 'java-book' 
% sDirName = 'books/java' 
% sName = '' -->
% latex by http://bumble.sourceforge.net/scripts/text2latex.sed 
% this script is a work in progress 
\documentclass[11pt]{article} 
\usepackage[hmargin=2cm, vmargin=2cm]{geometry} 
\usepackage{url} 
\usepackage{hyperref} 
\begin{document}
 \\&\\& The Java Programming Language
 --------------------------------:

 quote: "A world in itself" (anon)
 Stroustrup: "bloated and inefficient"

 This booklet attempts to provide 'recipes' for how to carry out
 common tasks with the java language. The idea of this and other
 booklets at bumble.sf.net is to provide the most succint but complete
 code snippets which will get the job done. But the java language
 doesnt really lend itself to this type of succintness. Complete
 examples are given where possible.

LEARNING JAVA 

BOOKS ....

 "effective java programming" josh bloch
 Supposedly a good book 
 "filthy rich clients" chet haase, romain guy ...
 How to create nice looking interfaces in java using animation
 and other graphical effects
 "Java 6 New Features: A Tutorial" Budi Kurniawan 
 (ISBN-10: 0975212885, ISBN-13: 978-0975212882) Some good stuff
 about drag and drop
 "swing hacks" 
 
WEB RESOURCES ....

 @@ \url{http://www.stackoverflow.com}
 Possibly the best forum to get answers to tricky java
 programming problems.
 @@ \url{http://www.javarichclient.com}
 Very good examples of how to improve a java swing interface.
 @@ \url{http://docstore.mik.ua/orelly/java-ent/}
 text from the oreilly in a nutshell series on various java topics
 @@ tips4java.workpress.com/
 Very good advanced java tips by Rob Camick and Darryl Burke
 @@ \url{http://elliotth.blogspot.com/}
 a blog with some good code snippets, by an android developer
 elliott hughes with good android links- eg vogar.
 @@ \url{http://www.java2s.com/}
 a lot of examples but without any comments or explanation. Good
 drag and drop examples.
 @@ \url{http://leepoint.net/notes-java/}
 good introductory notes
 @@ rgagnon - real java howto
 Some good examples.
 @@ \url{http://rcforte.wordpress.com/author/rcforte/}
 A good blog about java swing etc.
 @@ \url{http://www.jguru.com/faq/}
 some good, advanced faqs about java topics, including javamail
 @@ \url{http://www.exampledepot.com/egs/} 
 short and clear examples but sometimes not very 'correct'
 @@ \url{http://devdaily} 
 short but good examples
 @@ \url{http://javagraphics.blogspot.com/}
 nice advanced java graphics, interface examples
 @@ \url{http://www.java-tips.org} 
 tips
 @@ \url{http://www.kodejava.org/examples/28.html}
 
DOCUMENTATION FOR JAVA

INSTALLING JAVA DOCUMENTATION

 The java api documentation contained in a file called something like
 jdk-6-doc.zip is a set of html files generated from the javadoc comments
 contained in the api source code.

 * download the java documentation package
 >> ... 
 
 * unzip the documentation file
 >> jar xvf jdk-6-doc.zip 
 >> unzip jdk-6-doc.zip \\#\\#(the same)

 * copy or move the doc file to any folder, or the jdk folder
 >> mv docs \texttt{/usr/lib/jvm/java-6-sun/}

 * open the index page in a browser
 >> docs/index.html
 
 * on a linux debian computer, install the java documentation
 >> sudo apt-get install sun-java6-doc

VIEWING JAVA API DOCUMENTATION ....

SOURCE CODE FOR THE JAVA API ....

 The src code for the java apis can be a valuable learning tool.
 Sun seems to be releasing its source code through the openjdk
 project, which is an open source implementation of the java
 platform.

 * on a debian linux system install java 6 source code
 >> sudo apt-get install sun-java6-source

 \url{http://download.java.net/openjdk/jdk6/}
 url to download source for the openjdk implementation of the 
 java apis.

JAVADOC 

 javadoc is a tool for generating documentation for java classes
 in (usually) html format from the java source files. Java documentation
 cannot be accessed via reflection because the information is not
 contained in the '.class' files.

BASIC JAVA

 @@ \url{http://www.java2s.com/Code/Java/Language-Basics/CatalogLanguage-Basics.htm}
 examples of language basics

 * possibly the simplest java program
 ------------------------------------
 public class Simple \{
 public static void main(String[] args) \{
 System.out.println("hello");
 \}
 \}
 ,,,

 The parameter to the main method is necessary.

VARIABLES MEMBER FIELDS AND PARAMETERS

VARARGS ....

 Some methods can take a variable number of parameters or arguments.
 This is sometimes referred to as 'varargs'. An example of this
 is the System.out.format() method and the String.format() method. 
 If the wrong number of arguments is given for a particular 
 invocation, then a Runtime exception is thrown, not a compile-time 
 error.

MEMBER FIELDS ....

 The class java.lang.reflect.Field can be used to obtain complete 
 information about member fields in classes. See the Reflection section
 for more information.

ACCESS MODIFIERS ....

 Access modifiers are a method to restrict access (by other classes or 
 objects) to the member fields and methods of a class.

 The class java.lang.reflect.Modifier and the method
 java.lang.reflect.Field.getModifiers() can be used to obtain lots 
 of information about the access and other modifiers applied to 
 particular member fields in a class. See the Reflection,Fields section
 for more detailed information


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents Access modifiers
 .. static - initialised at compile time, no object instance required
 .. final - cannot be changed (similar to 'const' in c?)
 .. public - can be used by another class
 .. private - can only be used by the declaring class
 .. protected - dont know about this one.
 ..

 In general member fields should be declared private to ensure 
 data hiding.

 * declare a JTable as a private member field
 >> private JTable table;

FINAL ....

 >> final String WORD = new String("tree");
 >> private final String WORD = new String("tree");

VARIABLE SCOPE ....

 * within a method the parameter name takes precedence over member
 -------------------------------------------------------------
 String s;
 public void doTask(s) \{
 this.s = s;
 \}
 ,,,

DECLARING VARIABLES ....

 * declare 2 variables as type integer
 >> int x, y;

INITIALISING VARIABLES ....

 It is reasonably common to see Objects initialised to 'null'. Often the
 point of this is to avoid compiler errors of the type 'variable o may not
 have been initialised'. These errors arise usually because of try/catch
 blocks containing another (real) initialisation of the object variable.

 * initialise a variable to null to avoid compiler errors with try/catch
 >> java.util.Properties p = null;

GOTCHAS FOR DECLARATIONS ....

 compile errors !!! variable uninitialised 
 >> int x; System.out.print("x=" + x); 
 >> int x; x=x+1

 but NO error if var is an instance variable
 >> private int x; !! initialised to zero

 * declare a constant array of strings as a private member variable
 -------------------------------------------------------------
 private static final String[] COLUMN\\_NAMES = 
 \{"Action", "When Focused", "When In Focused Window", "When Ancestor"\};
 ,,,

ENUM TYPE ....

 The enum enumerated data type was introduced into java 1.5 (2004)
 These are often called enumerations, but are not to be confused with
 the (oldish) java iterator Enumeration.

 * an example of using an enumerated type
 ---------------------------------------------------------
 enum ElectricalUnits \{
 AMPS("Amps"), OHMS("Ohms"), WATTS("Watts"), VOLTS("Volts");
 private String text;
 private ElectricalUnits(String text) \{
 this.text = text;
 \}
 public String getText() \{
 return text;
 \}
 @Override
 public String toString() \{
 return text;
 \}
 \}
 ,,,

PRIMITIVE TYPES ....

 In java certain data types are not (considered) proper classes and 
 are referred to as 'Primitive Types'. Since these data types are not
 classes they do not need nor can be instantiated with the 'new' 
 keyword. Each of the primitives types also has a wrapper class which
 can be used to perform common tasks.

 Strangely these types do have a class which can be got with eg int.class
 double.class etc.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents The 8 Java primitive types
 .. byte
 .. char -
 .. short
 .. int -
 .. long -
 .. double -
 .. float
 .. boolean -
 ..

 * check if the field of a class is an 'int' primitive type
 >> if (field.getType().equals(int.class)) \{ ... \}

CLASSES

 * Possibly the simplest compilable class
 -------------------------------------------------------------
 public class Minimal \{\} 
 ,,,
 
 * a simple class with a constructor
 -----------------------------------
 public class Name \{
 public String first;
 public String last;

 public Name(String f, String l) \{
 this.first = f; this.last = l;
 \}
 \}
 ,,,

 * another simple class with a constructor
 -----------------------------------
 public class Name \{
 private String first;
 private String last;

 public Name(String f, String l)
 \{ this.first = f; this.last = l; \}

 public void print()
 \{ System.out.println(this.first + " " + this.last); \}

 public static void main(String[] args) \{
 Name t = new Name("Bill", "King");
 t.print();
 \}
 \}
 ,,,

CONSTRUCTORS ....

 Constructors are the special method or function which creates a 
 new object instance of a particular class. 

 When we extend a class we have to reimplement any constructors we 
 want to use, but it is not necessary to reimplement methods.

 * an empty constructor doesnt seem necessary
 >> public DashStroke() \{\}

 * a private constructor is a way of preventing direct use (Factories etc) 
 >> private DashStroke() \{\}

 * make 2 object contructors, one using this() and a default value
 -------------------------------------------------------------
 public FileSystemModel() \{ 
 this(System.getProperty("user.home")); \}

 public FileSystemModel( String startPath ) \{
 root = startPath;
 \}
 ,,,


METHODS ....

 * a simple method declaration and body
 --------------------------------------
 public string getAge(String name)
 \{
 return this.age;
 \}
 ,,,

 !!! method names cant be reserved words ('do', 'while' etc)

 >> public void print() \{\}
 >> public boolean print() \{\}
 >> public String print(int i, double d) \{\}
 >> private static int[] doo() \{\}
 >> public static int doo(int i) \{\}
 >> public static void doo(char c) \{\}

STATIC METHODS ....

 A static method is the equivalent of a function in a procedural
 programming language. A static method can be invoked without any
 object being instantiated

 * use a static method of the 'Search' class to search for "tree"
 >> Search.start("tree");

RECURSIVE METHODS ....

 Recursion is a potentially powerful technique. It involves a 
 method which calls itself after or before performing some task.
 Recursion is often useful when dealing with heirarchical or 'tree' data
 structures (such as the file-system).

 Infinite recursion compiles but produces a stack overflow 
 error.

SUBCLASSES AND INHERITANCE ....

 One of the cornerstones of Object Oriented programming is the 
 idea of inheritance, or creating a subclass from an existing class.
 The purpose of subclassing is to take advantage of all the functionality
 and data modeling of the parent or ancestor class, and add to or 
 modify a small amount of that functionality. The majority or all of 
 the code of the parent class is in this way reused.

 The process of inheriting from a class is also known as 'extending' a
 class.

 * create a class 'Circle' which inherits from the 'Shape' class 
 >> public class Circle extends Shape \{\}

 Interestingly, when we create a subclass we are not obliged to 
 add or modify any functionality of the ancestor class. The 
 following example compiles and produces a class 'TextPanel' which
 is identical to the JPanel class, but has no constructors so that 
 you cant actually use it for anything.

 * create a subclass of a swing JPanel, but dont modify anything 
 --------
 import javax.swing.*;
 public class TextPanel extends JPanel \{\}
 ,,,

INNER CLASSES ....

 Inner classes are full class definitions which ocurr inside the 
 body of another class.

 * refer to method load() of outer class (ImageProcess) in inner class
 >> ImageProcess.this.load()

 * refer to member field 'text' of outer class (Glue) in inner class
 >> Glue.this.text
 >> text \\#\\#(the same, no qualifiers are necessary)

ABSTRACT CLASSES ....

 Abstract classes are classes which need to be subclassed before
 they can be used. Unlike interfaces, abstract classes may contain
 implementations of various methods and member variables, but this 
 code is necessarily incomplete, and it is the job of the subclass
 to provide the missing code.

 It is generally considered less 'work' for the programmer to 
 subclass an abstract class than implement an interface.

ANONYMOUS CLASSES

 Anonymous classes have no class name, and sometimes they dont even have
 an object name. But how do you define constructors for a class that has
 no name? The answer is to create a method with no name. In other words,
 just "\{ /* constructor */ \}". How odd.

 Anonymous classes may be a terse way to implement functionality, and can
 be an alternative to an inner class but are somewhat less readable than
 inner classes.

 * write a constructor in an anonymous AbstractAction class
 ----------------------
 Action colourAction = new AbstractAction() \{
 \{ putValue(Action.NAME, "Green On Black"); \}
 public void actionPerformed(ActionEvent e)
 \{ /* do something */ \}
 \};
 ,,,

 * an anonymous KeyAdapter (sub) class with no object name
 -------------------------------------------------------------
 jpanel.addKeyListener(new KeyAdapter() \{
 public void keyTyped(KeyEvent e) \{ /* do something */ \}
 \});
 ,,,

INTERFACES

 An interface is a powerful concept. An interface may be described
 as a 'contract' which a class must fulfill, or else a 'role' which
 it must play, or else a 'protocol' which is must obey. Whatever
 the language used, it is easiest to understand them by using them.

 When implementing an interface, the parameter names are not 
 important, only the parameter type. Empty implementations of 
 methods are also ok if the return type is void.

 * an empty implementation of an interface method
 >> public void sequenceComplete(ImageReader r) \{\}
 
OBJECTS
 
 An object is an instance of a class which has been created
 (that is: allocated memory, and initialized). Objects in java
 are created with the 'new' keyword and one of the classes 
 constructors.

 * check if an object is an instance of a class
 -------------------------------------------------------------
 BufferedImage bufImg = null;
 if (origImage instanceof BufferedImage) \{
 bufImg = (BufferedImage) origImage;
 \} else \{ bugImg = new BufferedImage(...); \}
 ,,,

 * create a new JTextArea and cast to a JComponent
 ------------------------------------
 Object o = Class.forName("javax.swing.JTextArea").newInstance();
 component = (JComponent)o;
 ,,,

CASTING OBJECTS ....

 * cast an object to a subclass and call a method on the new type
 >> ((Graphic2D) g).setRenderingHints(...);

BEANS OR JAVABEANS

 java.beans.* package.

 Java beans are a type of java class conforming to certain restrictions
 which allow them to be used in contexts like graphical interface
 builder tools. The most well know requirement is that javabeans must
 have 'getter' and 'setter' methods for all public member fields. 

 Java beans may have gone the same way as applets.

REFLECTION

 Reflection allows a program to find out information about
 java classes. This is also known as 'introspection' and allows
 a program at run-time to find out what methods a particular
 class or object has.
 
 @@ \url{http://java.sun.com/developer/technicalArticles/ALT/Reflection/}
 a good article about using reflection with java

CLASS OBJECTS

 The first step when using java reflection is to obtain a reference
 to the Class object for the class which you wish to inspect, invoke
 or modify. There are several ways to obtain this Class object.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents Different ways to obtain a Class object
 .. Class c = new Color().getClass() - get class from an object
 .. Class c = class.forName("java.lang.String") - throws Exception
 .. Class c = JPanel.class - get a class from the class name 
 ..

 * create a new JTextArea and cast to a JComponent
 ------------------------------------
 Object o = Class.forName("javax.swing.JTextArea").newInstance();
 JComponent c = (JComponent) o;
 ,,,

 Interestingly in the 2 examples below, the getClass() method does
 not return 'Object' as the class name, but rather the most 
 specific Class name.

 * get the specific class name
 >> Object o = ...; String s = o.getClass().getName();

 * a complete example of getting the specific class name of an object 
 -------------------------------------------------------------
 import javax.swing.*;
 public class ObjectClassName \{
 public static void main(String[] args) \{
 java.util.Enumeration keys = UIManager.getDefaults().keys();
 while (keys.hasMoreElements()) \{
 String key = keys.nextElement().toString();
 Object value = UIManager.get(key);
 if (value != null) \{
 String className = value.getClass().getName();
 System.out.println(key + ":" + className);
 \}
 \}
 \}
 \}
 ,,,

MAIN APPLICATION CLASS ....

 The main application class is the class containing the static 'main'
 method which is first executed when the java application is run.

 * get information about the main application class
 -------------------------------------------------------------
 import java.net.URL;
 public class MainName \{
 public static void main(String[] args) throws Exception \{
 URL main = Main.class.getResource("Main.class");
 System.out.format(
 "Main protocol: \\%s \\$\\backslash\\$nMain path: \\%s \\$\\backslash\\$nMain url: \\%s", 
 main.getProtocol(),
 main.getPath(),
 main.toString());
 \}
 \}
 ,,,

 * determine if the main class is within a jar file 
 -------------------------------------------------------------
 import java.net.URL;
 public class MainName \{
 public static void main(String[] args) throws Exception \{
 URL main = Main.class.getResource("Main.class");
 if (main.getProtocol().equals("jar"))
 System.out.println("yes: main in jar");
 else 
 System.out.println("no: main not in jar");
 \}
 \}
 ,,,

 
 
FIELDS ....

 A java.lang.reflect.Field represents the member field of some class.
 
 * get all public and private fields from the Color class 
 >> Field[] fields = Color.class.getDeclaredFields();

 * get all public fields from the Color class
 >> Field[] fields = Color.class.getFields();

 * check if a field is public 
 >> if (Modifier.isPublic(field.getModifiers())) \{ ... \}

 * check if a field is of type 'int'
 >> if (field.getType().equals(int.class))
 >> if (field.getType() == int.class) \{\} \\#\\#(Another way to do the same)

 The technique below has a practical use: since most java api classes
 dont use enum types to declare static fields, there is no simple way
 to loop through the fields.

 * display the public and private fields for the Color class 
 --------------------------------------------------------------------
 import java.lang.reflect.*;
 public class ColorFields \{
 public static void main(String args[]) \{
 for (Field f: java.awt.Color.class.getDeclaredFields())
 System.out.println(f);
 \}
 \}
 ,,,

 * display the public fields for the Color class 
 --------------------------------------------------------------------
 import java.lang.reflect.*;
 public class ColorFields \{
 public static void main(String args[]) \{
 for (Field f: java.awt.Color.class.getFields())
 System.out.println(f);
 \}
 \}
 ,,,

 The technique below has applications in many different java api 
 classes.

 * display the public static fields of type Color within the Color class 
 --------------------------------------------------------------------
 import java.lang.reflect.*;
 import java.awt.Color;
 public class ColorFields \{
 public static void main(String args[]) \{
 for (Field f: Color.class.getFields()) \{
 if (f.getType().equals(Color.class) \\&\\& 
 Modifier.isStatic(f.getModifiers())) \{
 System.out.println(f);
 \}
 \}
 \}
 \}
 ,,,

 * show information about the public fields for the Color class 
 --------------------------------------------------------------------
 import java.lang.reflect.*;
 public class ColorFields \{
 public static void main(String args[]) \{
 for (Field f: java.awt.Color.class.getFields()) \{
 System.out.println(f);
 System.out.format(
 "field.getName(): \\%s \\$\\backslash\\$n" +
 "field.getType(): \\%s \\$\\backslash\\$n", f.getName(), f.getType());
 \}
 \}
 \}
 ,,,

 * a method to return all static integer fields of a Color class
 -------------------------------------------------------------
 public static Integer[] getStaticFields(Class<Color> c) \{
 List<Integer> list = new ArrayList<Integer>();
 Field[] fields = c.getDeclaredFields();
 for (Field field : fields) \{
 try \{
 if (field.getType().equals(int.class) \\&\\& 
 Modifier.isStatic(field.getModifiers())) \{
 list.add(field.getInt(null));
 \}
 \}
 catch (IllegalAccessException e) \{ /* handle */ \}
 \}
 return list.toArray(new Integer[list.size()]);
 \}
 ,,,
 
FIELD VALUES ....

 * get the value of a static field (then cast the Object to something)
 >> Object o = field.get(null);

 * get the value of a static field which is a Color value
 >> Color c = (Color)field.get(null);

 * get the value of the first field from the 'text' object
 >> Field f = text.getClass().getFields()[0]; Object o = field.get(text);

DISPLAY METHODS ....

 We can use reflection to find out and display all the 
 methods, whether public or private which belong to a particular
 class.

 * display the public methods for the 'String' class including inherited
 --------------------------------------------------------------------
 import java.lang.reflect.*;
 public class Test 
 \{
 public static void main(String args[]) throws Exception
 \{
 Class c = Class.forName("java.lang.String");
 Method m[] = c.getMethods();
 for (int i = 0; i < m.length; i++)
 System.out.println(m[i]);
 \}
 \}
 ,,,

 * display public and private methods declared in the 'String' class
 -------------------------------------------------------------------
 import java.lang.reflect.*;
 public class Test 
 \{
 public static void main(String args[]) throws Exception
 \{
 Class c = Class.forName("java.lang.String");
 Method m[] = c.getDeclaredMethods();
 for (int i = 0; i < m.length; i++)
 System.out.println(m[i]);
 \}
 \}
 ,,,

 getDeclaredMethods() does not display methods inherited from
 superclasses. Use getMethods() to display all available methods

 * display the public methods for the 'String' class in a list box
 -----------------------------------------------------------
 import java.lang.reflect.*;
 import javax.swing.*;
 public class PublicMethodsTest 
 \{
 public static void main(String args[]) throws Exception
 \{
 Class c = Class.forName("java.lang.String");
 Method mm[] = c.getMethods();
 Object r = JOptionPane.showInputDialog(
 null, "Choose a method:", "Methods",
 JOptionPane.PLAIN\\_MESSAGE, null, mm, mm[0]);
 System.out.println( "value selected: " + r );
 \}
 \}
 ,,,

 The application below may become a useful way of inspecting
 a class.

 * display constructors, methods for a class named in a JTextField 
 --------------------------------------------------
 import javax.swing.*;
 import javax.swing.event.*;
 import java.awt.*;
 import java.awt.event.*;
 import java.lang.reflect.*;
 public class MethodPanel extends JPanel implements ActionListener,
 DocumentListener \{
 Font listFont = new Font("Monospaced", Font.PLAIN, 40);
 Font panelFont = new Font("Serif", Font.PLAIN, 40);
 Color sandstone = new Color(212, 191, 142);
 JList list;
 DefaultListModel model;
 JTextField box;
 JLabel statusLabel;
 String className;
 String filter; /* the part after the class-name and . */

 /** just checks if a class name exists or not */
 public static boolean classExists(String name) \{
 try \{
 Class c = Class.forName(name); return true;
 \} catch (ClassNotFoundException e) \{ return false; \}
 \}

 // document listener protocol
 @Override
 public void insertUpdate(DocumentEvent e)
 \{ this.setFilter(); \}
 @Override
 public void removeUpdate(DocumentEvent e)
 \{ this.setFilter(); \}
 @Override
 public void changedUpdate(DocumentEvent e)
 \{ \}
 

 public MethodPanel(String className) \{
 super(new BorderLayout());
 this.className = className;
 this.filter = new String();
 this.box = new JTextField(className);
 this.box.setFont(panelFont);
 this.box.addActionListener(this);
 this.box.getDocument().addDocumentListener(this);

 this.add(this.box, BorderLayout.NORTH);
 this.statusLabel = new JLabel("+/- change font size");
 this.statusLabel.setFont(panelFont);
 this.add(statusLabel, BorderLayout.SOUTH);

 this.model = new DefaultListModel();
 this.setListData();
 this.list = new JList(this.model);
 this.list.setSelectionBackground(sandstone);
 this.list.setFont(listFont);
 this.list.setForeground(Color.darkGray);
 this.list.setBorder(BorderFactory.createEmptyBorder(9,9,9,9));
 this.list.addKeyListener(new KeyAdapter() \{
 JList list = MethodPanel.this.list;
 JLabel label = MethodPanel.this.statusLabel;
 public void keyTyped(KeyEvent e) \{
 char key = e.getKeyChar();
 if ((key == '+') || (key == 'b')) \{
 Font font = list.getFont();
 float size = font.getSize() + 2.0f;
 list.setFont(font.deriveFont(size));
 label.setText("Font: " + size);
 \}
 if ((key == '-') || (key == 's')) \{
 Font font = MethodPanel.this.list.getFont();
 float size = font.getSize() - 2.0f;
 list.setFont(font.deriveFont(size));
 MethodPanel.this.statusLabel.setText("Font: " + size);
 \}
 list.requestFocusInWindow();
 \}
 \});

 JScrollPane scroll = new JScrollPane(list);
 scroll.setBorder(null);
 this.add(scroll, BorderLayout.CENTER);
 this.setBorder(BorderFactory.createEmptyBorder(9,9,9,9));
 \}

 public void setListData() \{
 // try to filter names based on text after '.'
 // this will be triggered by key events.
 // setting the class name is only triggered by <enter>
 this.model.removeAllElements();
 try \{
 Class c = Class.forName(this.className);
 Constructor co[] = c.getConstructors();
 for (int i = 0; i < co.length; i++)
 this.model.addElement(
 co[i].toString()
 .replace("public ", "").replace("java.lang.", "") 
 .replace(this.className + ".", "")
 );
 Method mm[] = c.getMethods();
 for (int i = 0; i < mm.length; i++) \{
 if (this.filter.length() > 0) \{
 if (mm[i].toString().matches("(?i).*" + this.filter + ".*")) \{
 this.model.addElement(
 mm[i].toString()
 .replace("public ", "").replace("java.lang.", "") 
 .replace(this.className + ".", "")
 );
 \}
 \} else \{
 this.model.addElement(
 mm[i].toString()
 .replace("public ", "").replace("java.lang.", "") 
 .replace(this.className + ".", "")
 );
 \}
 \}
 \}
 catch (ClassNotFoundException e) \{ 
 this.model.addElement(
 String.format("class '\\%s' not found", this.className)); 
 \}
 \}

 public void actionPerformed (ActionEvent e) \{
 if (e.getSource() == this.box) \{
 this.className = this.box.getText().trim();
 this.filter = "";
 if (!classExists(className)) \{
 // try to find the classname 
 if (className.indexOf('.') == -1) \{
 if (!Character.isUpperCase(className.charAt(0))) \{
 className = Character.toUpperCase(className.charAt(0)) + 
 className.substring(1);
 \}
 if (!Character.isUpperCase(className.charAt(1)) \\&\\&
 (className.charAt(0) == 'J')) \{
 className = "J" + Character.toUpperCase(className.charAt(1)) + 
 className.substring(2);
 \}
 \}
 if (classExists("java.lang." + className)) 
 \{ className = "java.lang." + className; \}
 else if (classExists("java.util." + className)) 
 \{ className = "java.util." + className; \}
 else if (classExists("java.io." + className)) 
 \{ className = "java.io." + className; \}
 else if (classExists("java.nio." + className)) 
 \{ className = "java.nio." + className; \}
 else if (classExists("javax.swing." + className)) 
 \{ className = "javax.swing." + className; \}
 else if (classExists("javax.swing.event." + className)) 
 \{ className = "javax.swing.event." + className; \}
 else if (classExists("java.awt." + className)) 
 \{ className = "java.awt." + className; \}
 else if (classExists("java.lang.reflect." + className)) 
 \{ className = "java.lang.reflect." + className; \}
 this.box.setText(className);
 \}
 this.setListData();
 \}
 \}
 
 public void setFilter() \{
 String ss;
 ss = box.getText().trim();
 if (ss.lastIndexOf('.') == MethodPanel.this.className.length()) \{
 this.filter = ss.substring(ss.lastIndexOf(".")+1);
 System.out.println("key! " + this.filter);
 this.box.setBackground(Color.orange);
 \} else \{
 this.box.setBackground(Color.white);
 \}
 // apply the filter to the method names
 this.setListData();
 \}

 public static void main(String[] args) throws Exception \{
 MethodPanel p = new MethodPanel("javax.swing.JList");
 JFrame f = new JFrame("Java Constructors \\& Methods");
 f.add(p);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); 
 f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.setVisible(true);
 p.list.requestFocusInWindow();
 \}
 \}
 ,,,

 * display all the public methods for the current class 
 -----------------------------------------------
 import java.lang.reflect.*;
 import javax.swing.*;
 public class Test 
 \{
 public static void main(String args[]) throws Exception
 \{
 Test t = new Test();
 Class c = t.getClass();
 Method mm[] = c.getMethods();
 Object r = JOptionPane.showInputDialog(
 null, "Choose method:", "Methods", JOptionPane.PLAIN\\_MESSAGE, 
 null, mm, mm[0]);
 System.out.println( "Method selected was: " + r );
 \}
 \}
 ,,,

 * display all the methods for the 'Integer' class
 ------------------------------------------------
 import java.lang.reflect.*;
 public class Test 
 \{
 public static void main(String args[]) throws Exception
 \{
 Class c = Integer.TYPE;
 Method m[] = c.getMethods();
 for (int i = 0; i < m.length; i++)
 System.out.println(m[i].toString());
 \}
 \}
 ,,,

 This does not display any results for me. 

 * display the public method names and return type for the 'Method' class
 ------------------------------------------------------------------
 import java.lang.reflect.*;
 import javax.swing.*;
 import java.awt.GridLayout;
 public class MethodGrid 
 \{
 public static void main(String args[]) throws Exception
 \{
 Class c = Class.forName("java.lang.reflect.Method");
 JPanel p = new JPanel(new GridLayout(0, 2));
 Method m[] = c.getMethods();
 for (int i = 0; i < m.length; i++)
 \{
 p.add(new JLabel(m[i].getName()));
 p.add(new JLabel(m[i].getReturnType()+""));
 \}
 JFrame f = new JFrame("A panel which can scroll");
 f.add(new JScrollPane(p));
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setVisible(true);
 \}
 \}
 ,,,

 * display a list of methods with checkboxes for the 'URL' class 
 --------------------------------------------------------------
 import java.lang.reflect.*;
 import javax.swing.*;
 import java.awt.GridLayout;
 public class Test \{
 public static void main(String[] args) throws Exception
 \{
 JFrame f = new JFrame("Methods with checkboxes for 'URL'");
 JPanel p = new JPanel(new GridLayout(0,1));
 Class c = Class.forName("java.net.URL");
 Method mm[] = c.getDeclaredMethods();
 for (int ii = 0; ii < mm.length; ii++)
 \{
 p.add(new JCheckBox(mm[ii].toString()));
 \}
 f.getContentPane().add(new JScrollPane(p));
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents useful methods of the Method class
 .. m.getParameterTypes() - the types of all the method parameters
 .. m.getDeclaringClass() - the class which declared the method
 .. m.getReturnType() - type of object returned by the method 
 ..

 * display the constructors for the 'String' class
 -------------------------------------------------
 import java.lang.reflect.*;
 public class Test 
 \{
 public static void main(String args[]) throws Exception
 \{
 Class c = Class.forName("java.lang.String");
 Constructor co[] = c.getDeclaredConstructors();
 for (int i = 0; i < co.length; i++)
 System.out.println(co[i].toString());
 \}
 \}
 ,,,

 * display all the field variables for the 'String' class
 --------------------------------------------------------
 import java.lang.reflect.*;
 public class Test 
 \{
 public static void main(String args[]) throws Exception
 \{
 Class c = Class.forName("java.lang.String");
 Field f[] = c.getDeclaredFields();
 for (int i = 0; i < f.length; i++)
 System.out.println(f[i].toString());
 \}
 \}
 ,,,

METHOD INFORMATION ....

 Reflection allows us to get lots of information about each
 method in a class, such as whether it is public, its return type
 etc

 * check if a method is static
 >> if (Modifier.isStatic(method.getModifiers())) \{ ... \}

 * check if the return type of a method is void
 >> if (method.getReturnType() == void.class) \{ ... \}

 * check if a method is public
 >> if (Modifier.isPublic(method.getModifiers())) \{ ... \}

 * check if a method is a valid 'main' method for a class
 -------------------------------------------------------------
 int mods = m.getModifiers();
 if (m.getReturnType() != void.class || !Modifier.isStatic(mods) ||
 !Modifier.isPublic(mods)) \{
 throw new NoSuchMethodException("main");
 \}
 ,,,

EXECUTING METHODS ....

 Java reflection is not only 'introspection' (the ability to find out what
 methods and constructors exist) but also the capability to invoke or
 execute those methods with parameters.

 * execute a method with parameters
 -------------------------------------------------------------
 try \{
 m.invoke(null, new Object[] \{ args \});
 \} catch (IllegalAccessException e) \{\}
 ,,,

CLASS LISTINGS ....

 It seems impossible using normal reflection, or introspection to get a
 list of class names contained in a given package. However we can get a
 list by inspecting the runtime jar file 'rt.jar' or the java api
 documentation or by inspecting the source code.

 The runtime file rt.jar resides at lib/rt.jar in the "java.home"
 folder. Listing the rt.jar will show 'internal' sun java classes 
 which should not actually be used by an application since other java
 platforms (runtime engines \\& class api) may not have these classes

 * search the class files in the rt.jar for a class name
 --------------------------------------------------
 import java.util.jar.*;
 import java.util.zip.*;
 import java.io.*;
 import java.util.Enumeration;
 import javax.swing.*;
 import java.awt.*;
 public class ListRuntimeJar extends JPanel \{
 private JList list;
 private String className;
 public ListRuntimeJar(String className) \{
 super();
 this.className = className;
 this.list = new JList(new DefaultListModel());
 this.list.setFont(new Font(Font.SERIF, Font.PLAIN, 22));
 try \{
 JarFile jar = new JarFile(
 new File(System.getProperty("java.home") + "/lib/rt.jar"));
 Enumeration<? extends JarEntry> enumeration = jar.entries();
 while (enumeration.hasMoreElements()) \{
 ZipEntry zipEntry = enumeration.nextElement();
 if (zipEntry.getName().endsWith(className + ".class")) \{
 ((DefaultListModel)this.list.getModel())
 .addElement(zipEntry.getName());
 \}
 \}
 \} catch (IOException e) \{\}
 this.add(new JScrollPane(this.list));
 \}
 public static void main(String[] args) throws Exception \{
 SwingUtilities.invokeLater( new Runnable() \{
 public void run() \{
 ListRuntimeJar l = new ListRuntimeJar("ZipEntry");
 JOptionPane.showMessageDialog(null, new JScrollPane(l));
 \}
 \});
 \}
 \}
 ,,,

 
 * get a list of full java class names from the java api docs 
 -------------------------------------------------------------
 import java.io.*;
 import java.util.*;
 public class ClassNames \{
 List classNames;
 File apiDocFolder;
 public ClassNames() \{
 this.classNames = new ArrayList();
 \}
 public void list(File dir) \{
 FileFilter filter = new FileFilter()\{
 public boolean accept(File file) \{
 if (file.getAbsolutePath().indexOf("class-use") > 0) 
 return false;
 if (file.getAbsolutePath().indexOf("package-") > 0) 
 return false;
 if (file.getAbsolutePath().indexOf("doc-files") > 0) 
 return false;
 return (file.getAbsolutePath().endsWith(".html") || 
 file.isDirectory());
 \}
 \};
 File[] files = dir.listFiles(filter);
 if (files != null) \{
 for (File f : files) \{
 if (f.isDirectory()) \{ this.list(f); \}
 else \{
 System.out.println(
 f.getPath()
 .replaceAll("/usr/lib/jvm/java-6-sun/docs/api/","")
 .replaceAll("[.]html","")
 .replace('/','.'));
 \}
 \}
 \}
 \}
 public static void main(String[] args) throws Exception \{
 ClassNames cn = new ClassNames();
 cn.list(new File("/usr/lib/jvm/java-6-sun/docs/api/java"));
 cn.list(new File("/usr/lib/jvm/java-6-sun/docs/api/javax"));
 \}
 \}
 ,,,

 * put all java. and javax. class names into a JList component 
 -------------------------------------------------------------
 import java.io.*;
 import java.awt.Font;
 import java.util.*;
 import javax.swing.*;
 public class ClassList extends JList \{
 List classNames;
 String apiDocFolder;
 public ClassList(String apiDocFolder) \{
 super();
 this.setModel(new DefaultListModel());
 this.setFont(new Font("Georgia", Font.PLAIN, 18));
 this.classNames = new ArrayList();
 this.apiDocFolder = apiDocFolder;
 this.search(new File(this.apiDocFolder + "/java"));
 this.search(new File(this.apiDocFolder + "/javax"));
 \}
 public void search(File dir) \{
 FileFilter filter = new FileFilter()\{
 public boolean accept(File file) \{
 if (file.getAbsolutePath().indexOf("class-use") > 0) 
 return false;
 if (file.getAbsolutePath().indexOf("package-") > 0) 
 return false;
 if (file.getAbsolutePath().indexOf("doc-files") > 0) 
 return false;
 return (file.getAbsolutePath().endsWith(".html") || 
 file.isDirectory());
 \}
 \};
 File[] files = dir.listFiles(filter);
 String sName = new String();
 DefaultListModel lm;
 if (files != null) \{
 for (File f : files) \{
 if (f.isDirectory()) \{ this.search(f); \}
 else \{
 sName =
 f.getPath()
 .replaceAll("/usr/lib/jvm/java-6-sun/docs/api/","")
 .replaceAll("[.]html","")
 .replace('/','.');
 this.classNames.add(sName);
 lm = (DefaultListModel)this.getModel();
 lm.addElement(sName);
 \}
 \}
 \}
 \}
 public static void main(String[] args) throws Exception \{
 SwingUtilities.invokeLater( new Runnable() \{
 public void run() \{
 ClassList c = new ClassList("/usr/lib/jvm/java-6-sun/docs/api");
 JOptionPane.showMessageDialog(null, new JScrollPane(c));
 \}
 \});
 \}
 \}
 ,,,

 * todo: create a JCombobox with java class names and searchable 
 ---------------------------------------------------------
 import java.io.*;
 import java.awt.Font;
 import java.util.*;
 import javax.swing.*;
 public class ClassList extends JList \{
 List classNames;
 String apiDocFolder;
 public ClassList(String apiDocFolder) \{
 super();
 this.setModel(new DefaultListModel());
 this.setFont(new Font("Georgia", Font.PLAIN, 18));
 this.classNames = new ArrayList();
 this.apiDocFolder = apiDocFolder;
 this.search(new File(this.apiDocFolder + "/java"));
 this.search(new File(this.apiDocFolder + "/javax"));
 \}
 public void search(File dir) \{
 FileFilter filter = new FileFilter()\{
 public boolean accept(File file) \{
 if (file.getAbsolutePath().indexOf("class-use") > 0) 
 return false;
 if (file.getAbsolutePath().indexOf("package-") > 0) 
 return false;
 if (file.getAbsolutePath().indexOf("doc-files") > 0) 
 return false;
 return (file.getAbsolutePath().endsWith(".html") || 
 file.isDirectory());
 \}
 \};
 File[] files = dir.listFiles(filter);
 String sName = new String();
 DefaultListModel lm;
 if (files != null) \{
 for (File f : files) \{
 if (f.isDirectory()) \{ this.search(f); \}
 else \{
 sName =
 f.getPath()
 .replaceAll("/usr/lib/jvm/java-6-sun/docs/api/","")
 .replaceAll("[.]html","")
 .replace('/','.');
 this.classNames.add(sName);
 lm = (DefaultListModel)this.getModel();
 lm.addElement(sName);
 \}
 \}
 \}
 \}
 public static void main(String[] args) throws Exception \{
 SwingUtilities.invokeLater( new Runnable() \{
 public void run() \{
 ClassList c = new ClassList("/usr/lib/jvm/java-6-sun/docs/api");
 JOptionPane.showMessageDialog(null, new JScrollPane(c));
 \}
 \});
 \}
 \}
 ,,,

REFLECTION APPS ....

 This section may contain some useful small applications for getting
 information about classes.

 The following is a development on the MethodPanel class, hopefully
 more useful.

 In the following we need to sort out what the actioncommand is
 when the combobox elements are changed. Too many events are firing.
 The program below is useful to see the methods and constructors for 
 a class, and search for the class in the rt.jar file, but it needs 
 alot of refining.

 It can be used from the command line with
 >> java ClassInfo <searchclass>

 * select a class to display constructors and methods
 --------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 import java.awt.event.*;
 import java.lang.reflect.*;
 import java.util.jar.*;
 import java.util.zip.*;
 import java.io.*;
 import java.awt.*;
 import java.util.Enumeration;
 public class ClassInfo extends JPanel implements ActionListener \{
 JList list;
 DefaultListModel model;
 JComboBox box;
 String className;
 String filterName; 
 public ClassInfo(String filterName) \{
 super(new BorderLayout());
 this.filterName = filterName;
 this.className = new String(" ");
 this.box = new JComboBox(new DefaultComboBoxModel());
 this.box.setEditable(true);
 this.box.setFont(new Font("Georgia", Font.PLAIN, 24));
 this.add(this.box, BorderLayout.NORTH);
 this.model = new DefaultListModel();
 this.list = new JList(this.model);
 this.list.setFont(new Font("Georgia", Font.PLAIN, 20));
 this.list.setForeground(Color.darkGray);
 this.list.setBorder(BorderFactory.createEmptyBorder(9,9,9,9));
 this.setComboItems();
 this.box.addActionListener(this);
 JScrollPane scroll = new JScrollPane(list);
 scroll.setBorder(null);
 this.add(scroll, BorderLayout.CENTER);
 this.setBorder(BorderFactory.createEmptyBorder(9,9,9,9));
 \}

 public void setComboItems() \{
 this.box.removeAllItems();
 String name = new String();
 int index = 0;
 try \{
 JarFile jar = new JarFile(
 new File(System.getProperty("java.home") + "/lib/rt.jar"));
 Enumeration<? extends JarEntry> enumeration = jar.entries();
 while (enumeration.hasMoreElements()) \{
 ZipEntry zipEntry = enumeration.nextElement();
 name = zipEntry.getName().replace(".class", "")
 .replace("/", ".");
 //if (name.startsWith("com.") || name.startsWith("sun."))
 // continue;

 if (name.endsWith(this.filterName)) \{
 this.box.addItem(name);
 \}
 if (name.matches(this.filterName)) \{
 this.box.addItem(name);
 \}


 \}
 \} catch (IOException e) \{\}
 // this is throwing an exception because the box is not visible
 //this.box.showPopup();
 //this.box.setSelectedIndex(index);
 \}

 public void setListData() \{
 this.model.removeAllElements();
 if (this.className == null) return;
 try \{
 Class c = Class.forName(this.className);
 Constructor co[] = c.getConstructors();
 for (int i = 0; i < co.length; i++)
 this.model.addElement(
 co[i].toString()
 .replace("public ", "").replace("java.lang.", "") 
 .replace(this.className + ".", "")
 );
 Method mm[] = c.getMethods();
 for (int i = 0; i < mm.length; i++)
 this.model.addElement(
 mm[i].toString()
 .replace("public ", "").replace("java.lang.", "") 
 .replace(this.className + ".", "")
 );

 \}
 catch (ClassNotFoundException e) \{ 
 this.model.addElement(
 String.format("class '\\%s' not found", this.className)); 
 \}
 \}

 public void actionPerformed (ActionEvent e) \{
 if (e.getSource() == this.box) \{
 if ("comboBoxEdited".equals(e.getActionCommand())) \{
 this.filterName = (String)this.box.getSelectedItem();
 this.setComboItems();
 \}
 else if ("comboBoxChanged".equals(e.getActionCommand())) \{
 System.out.println("action command=" + e.getActionCommand());
 this.className = (String)this.box.getSelectedItem();
 this.setListData();
 \}
 \}
 \}
 
 public static void main(String[] args) throws Exception \{
 String filter;
 if (args.length > 0)
 filter = args[0];
 else
 filter = "ImageReader";
 ClassInfo p = new ClassInfo(filter);
 JFrame f = new JFrame("Information About Classes");
 f.add(p);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.setVisible(true);
 \}
 \}
 ,,,

CLASS LOADERS

 We can use a class loader such as java.net.URLClassLoader or 
 along with the java.lang.reflect.Method.invoke(...) method to 
 load and execute methods on classes at runtime. 

 * load a class at runtime
 ----------------------
 File outputDir = new File("c:/bin");
 URL[] urls = new URL[]\{outputDir.toURL()\};
 URLClassLoader ucl = new URLClassLoader(urls, cl);
 Class clazz = ucl.loadClass("com.juixe.Entity");
 ,,,

 * load and execute a class with URLClassLoader and method.invoke()
 ----------------------------------
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.InvocationTargetException;
 public class LoadClass \{
 public static void main(String[] args) throws Exception \{
 URL url = new URL("file:MethodPanel.class");
 URLClassLoader cl = new URLClassLoader(new URL[] \{url\});
 Class c = cl.loadClass("MethodPanel");
 Method m = c.getMethod("main", new Class[] \{ args.getClass() \});
 m.setAccessible(true);
 // check for valid java 'main' method
 int mods = m.getModifiers();
 if (m.getReturnType() != void.class || !Modifier.isStatic(mods) ||
 !Modifier.isPublic(mods)) \{
 throw new NoSuchMethodException("main");
 \}
 try \{
 m.invoke(null, new Object[] \{ args \});
 \} catch (IllegalAccessException e) \{
 // This should not happen, as we have disabled access checks
 \}
 \}
 \}
 ,,,

SERIALIZATION OF OBJECTS

 The serialization of objects is a way to turn the state of an
 object in memory (in the java virtual machine) into a stream which
 can then be written to a permanent data storage device. In other 
 words serialization allows the programmer to save the state of objects.

 Not all objects are serializable: for example Thread or streams
 
 \url{http://java.sun.com/developer/technicalArticles/Programming/serialization/}
 An chatty article about serialization

 * a simple serialisable object and code to write the object to file
 -------------------------------------------------------------
 import java.io.ObjectOutputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.Serializable;
 import java.util.Date;
 import java.util.Calendar;
 public class PersistentTime implements Serializable
 \{
 private Date time;
 public PersistentTime() \{
 time = Calendar.getInstance().getTime();
 \}
 
 public Date getTime() \{ return time; \}
 public static void main(String [] args) \{
 String filename = "time.ser";
 if (args.length > 0) \{ filename = args[0]; \}
 PersistentTime time = new PersistentTime();
 FileOutputStream fos = null;
 ObjectOutputStream out = null;
 try
 \{
 fos = new FileOutputStream(filename);
 out = new ObjectOutputStream(fos);
 out.writeObject(time);
 out.close();
 \}
 catch (IOException ex)
 \{
 ex.printStackTrace();
 \}
 \}
 \}
 ,,,

 * restore an object saved with serialization
 ----------------------------------------------
 import java.io.*;
 import java.util.Calendar;
 public class InflateTime \{
 public static void main(String [] args) \{
 String filename = "time.ser";
 if (args.length > 0) \{
 filename = args[0];
 \}
 PersistentTime time = null;
 FileInputStream fis = null;
 ObjectInputStream in = null;
 try \{
 fis = new FileInputStream(filename);
 in = new ObjectInputStream(fis);
 time = (PersistentTime)in.readObject();
 in.close();
 \}
 catch (IOException ex) \{
 ex.printStackTrace();
 \}
 catch (ClassNotFoundException ex) \{
 ex.printStackTrace();
 \}
 // print out restored time
 System.out.println("Flattened time: " + time.getTime());
 System.out.println();
 // print out the current time
 System.out.println("Current time: " + Calendar.getInstance().getTime());
 \}
 \}
 ,,,

MEMORY USAGE

 Java has 2 main memory areas: the heap memory and the stack memory. The
 heap is the area where objects are created. If you create a lot of large
 objects (say loaded BufferedImages) then you may run out of heap space.
 The stack memory area is where local variables and references to method
 calls are placed when a new method is executed. If you have very deeply
 nested method calls (using recursion for example) you may run out of
 stack memory space)
 
 * set the minimum heap size to 64m and the maximum to 256megabytes
 >> java -Xms64m -Xmx256m ..
 
 The default value for the minimum is 2Mb, for the maximum it's 64Mb.
 
 * find out how much memory is available and free in a java program
 -------------------------------------------------------------
 Runtime rt = Runtime.getRuntime();
 long freeMemory = rt.freeMemory();
 long totalMemory = rt.totalMemory();
 ,,,

PERFORMANCE OF JAVA PROGRAMS 

 The performance of the java runtime engine has long been something of 
 a sore point. One can often increase the users perception of the 
 performance of an application by performing tasks in the background
 using thread.
 
 In the following FileFilter accept method the commented out code
 was about 25\\% slower than the uncommented code. This is perhaps
 owing to the fact that the majority of Files were not directories.

 * return efficiently from a FileFilter accept method 
 -------------------------------------------------------------
 public boolean accept(File file) \{
 /*
 if (file.isDirectory()) return true;
 if (file.getAbsolutePath().indexOf(this.text)>0) return true;
 return false;
 */
 return ((file.getAbsolutePath().indexOf(this.text)>0) ||
 file.isDirectory());
 \}
 ,,,

RUNNING JAVA PROGRAMS

COMMAND LINE ARGUMENTS ....

 Command line arguments are strings typed after the name of 
 the java class or application, for example in
 >> java ViewImage tree.jpg 
 The first command line argument (args[0]) is 'tree.jpg'
 
 * use the first command line argument, or provide a default
 -------------------------------------------------------------
 if (args.length > 0)
 testData = new StringSelection( args[0] );
 else
 testData = new StringSelection( "Test Data" );
 ,,,

COMPILING JAVA PROGRAMS

 * compile and run a java program
 >> javac Test.java
 >> java Test
 
 In the example below the class Symbol in the file Symbol.java is
 not in a any package.

 * compile file ./eg/Symbol.java which depends on other classes in eg/ 
 >> javac -cp eg eg/Symbol.java

COMPILING WITH PACKAGES ....

 Packages are a way of organising classes.

 * compile and run a single java file in package (and folder) greetings
 -------------------------------------------------------------
 \\% cat greetings/Hello.java
 package greetings;
 public class Hello \{
 public static void main(String[] args) \{
 for (int i=0; i < args.length; i++) \{
 System.out.println("Hello " + args[i]);
 \}
 \}
 \}
 \\% javac greetings/Hello.java
 \\% ls greetings
 Hello.class Hello.java
 \\% java greetings.Hello World Universe Everyone
 ,,,
 
CROSS COMPILATION

 In this context we mean compiling for older jre's using a newer javac
 version. This is important for deploying an application on the web where
 browsers may have older versions of the jre plugin installed

 * compile some code for jre version 1.5 with 1.5 class library
 >> javac -target 1.5 -bootclasspath jdk1.5.0/lib/rt.jar -extdirs "" OldCode.java

 The above requires that the old jdk 'rt.jar' file is present on the local
 computer

 * try: compile code for jre version 1.5 from newer, without checking api 
 >> javac -target 1.5 OldCode.java

 The above code is not tested and will not check if the code in question
 uses java classes which were not available in the jre version specified.
 In other words the code may compile but fail to run on the old (1.5) jre.

RUNTIME COMPILING OF JAVA CODE ....

 Around about java 1.6 an api (in the javax.tools.* package) was added to
 java to allow a java program to compile a java source code contained in
 a file, string, or anything else.

 \url{http://www.javabeat.net/2007/04/the-java-6-0-compiler-api/}
 a very good article about doing this

 \url{http://juixe.com/techknow/index.php/2006/12/13/java-se-6-compiler-api/}
 another article about this

 * create a list of files to compile
 -------------------------------------------------------------
 File f1, f2, f3; ...
 Iterable<? extends JavaFileObject> list = 
 fm.getJavaFileObjects(f1, f2, f3);
 ,,,

 * another way to create the list of files to compile
 -------------------------------------------------------------
 File[] files = \{new File(...), new File(...)\};
 Iterable<? extends JavaFileObject> compileList =
 fm.getJavaFileObjectsFromFiles(Arrays.asList(files));
 ,,,

 In the example below, the class file is placed in the same folder 
 as the source file (in this case 'eg/Test.java'). If the compilation
 fails, then the compiler (javac) prints message to standard-out or 
 standard-error.

 Apparently the jdk is required for the example below to work because it
 accesses the tools.jar file in the jdk lib/tools folder...

 * a simple programmatic compiling example 
 -------------------------
 import javax.tools.*;
 public class SimpleCompiler \{
 public static void main(String[] args) \{
 String fileToCompile = "Test.java";
 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
 int compilationResult = 
 compiler.run(null, null, null, "eg/Test.java");
 if (compilationResult == 0) \{
 System.out.println("Compilation is successful");
 \} else \{
 System.out.println("Compilation Failed");
 \}
 \}
 \}
 // the class that will be compiled
 class Test \{
 public void myMethod() \{
 System.out.println("My Method Called");
 \}
 \}
 ,,,

 The getJavaFileObjects() parameter is a vararg (variable number of
 arguments)

 If there are errors during the compilation below, they will be printed to
 'standard-error'. The code Arrays.asList(options) is necessary because a
 String array is not regarded as Iterable, which seems strange.

 * compile java code specifying (command-line) options to the compiler 
 -------------
 import javax.tools.*;
 import java.net.*;
 import java.io.*;
 import java.util.Arrays;
 public class ApiCompiler \{
 public static void main(String[] args) throws IOException \{
 JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
 StandardJavaFileManager fm = 
 jc.getStandardFileManager(null, null, null);
 File sourceFile = new File("eg/Test.java");
 Iterable<? extends JavaFileObject> compileList = 
 fm.getJavaFileObjects(sourceFile);
 String[] options = new String[] \{"-d", "."\};
 jc.getTask(null, fm, null, Arrays.asList(options), null, compileList)
 .call();
 /* Add more compilation tasks if required */
 fm.close();
 \}
 \}
 ,,,

 The example below takes advantage of the fact that the
 fm.getJavaFileObjects(...) has a 'vararg' parameter, meaning that it can
 take a variable number of parameter arguments, and can take either a list
 of Strings or a list of Files

 * compile 2 java source files in the same compiler task
 -------------------------------------------------------------
 import javax.tools.*;
 import java.net.*;
 import java.io.*;
 import java.util.Arrays;
 public class TwoFileCompiler \{
 public static void main(String[] args) throws IOException \{
 JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
 StandardJavaFileManager fm = 
 jc.getStandardFileManager(null, null, null);
 Iterable<? extends JavaFileObject> compileList = 
 fm.getJavaFileObjects("eg/Test.java", "eg/SumArray.java");
 jc.getTask(null, fm, null, null, null, compileList)
 .call();
 /* Add more compilation tasks if required */
 fm.close();
 \}
 \}
 ,,,

 The example below might be useful when building some kind of java
 code editor: the user can jump to the line number where the error
 occurs.

 * compile a java file and print 'diagnostics' (errors and warnings) 
 -------------------------------------------------------------
 import javax.tools.*;
 import java.net.*;
 import java.io.*;
 import java.util.Arrays;
 public class ErrorCompiler \{
 public static void main(String[] args) throws IOException \{
 JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
 File[] files = \{new File("eg/Test.java")\};
 DiagnosticCollector<JavaFileObject> diagnostics =
 new DiagnosticCollector<JavaFileObject>();
 StandardJavaFileManager fm =
 compiler.getStandardFileManager(diagnostics, null, null);
 Iterable<? extends JavaFileObject> compileList =
 fm.getJavaFileObjectsFromFiles(Arrays.asList(files));
 compiler.getTask(null, fm, diagnostics, null, null, compileList)
 .call();
 for (Diagnostic d: diagnostics.getDiagnostics())
 System.out.format(
 "On line \\%d: (file \\%s)\\$\\backslash\\$n\\%s\\$\\backslash\\$n\\$\\backslash\\$n",
 d.getLineNumber(), 
 ((JavaFileObject) d.getSource()).toUri(),
 d.getMessage(null));
 fm.close();
 \}
 \}
 ,,,

 * the old way: before java 1.6 compile java code at runtime
 --------------------------
 //put tools.jar from the jdk in your classpath,
 com.sun.tools.javac.Main javac = new com.sun.tools.javac.Main();
 String[] options = new String[] \{
 "-classpath", classpath, "-d", outputDir, filename
 \};
 javac.compile(options);
 ,,,

COMPILING STRINGS AND STREAMS ....

 By extending the SimpleJavaFileObject class we can use the
 javax.tools.JavaCompiler to compile programs that are contained in
 Strings, streams or other exotic and interesting imaginary spaces. This
 gives those of us hankering for lisp-like functional languages something
 to think about.

 To compile from a stream, we should extend the SimpleJavaFileObject 
 and somehow convert the url.openStream() method to a CharSequence

 In the example below, the 'name' parameter of the StringSource class is
 important because the java compiler requires that public classes be
 declared in 'files' with the class name, even if those classes are really
 contained in Strings, streams or what-not.

 * compile some java source contained in a String
 -------------------------------------------------------------
 import javax.tools.*;
 import java.net.*;
 import java.io.*;
 import java.util.Arrays;
 public class StringCompiler \{
 public static void main(String[] args) throws IOException \{
 String s = "public class Test1 \{ String n = 2; \}";
 JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
 StringSource[] compileList = \{new StringSource("Test1", s)\};
 jc.getTask(null, null, null, null, null, Arrays.asList(compileList))
 .call();
 \}
 \}
 /* A file object used to represent java source code in a string.*/
 class StringSource extends SimpleJavaFileObject \{
 final String code;
 public StringSource(String name, String code) \{
 super(URI.create(
 "string:///" + name.replace('.','/') + Kind.SOURCE.extension),
 Kind.SOURCE);
 this.code = code;
 \}
 public CharSequence getCharContent(boolean ignoreEncodingErrors) \{
 return code;
 \}
 \}
 ,,,

 * compile 2 java sources contained in strings with command-line options 
 -------------------------------------------------------------
 import javax.tools.*;
 import java.net.*;
 import java.io.*;
 import java.util.Arrays;
 public class TwoStringCompiler \{
 public static void main(String[] args) \{
 String s = "public class Test1 \{ String m; \}";
 String r = "public class Test2 \{ String n; \}";
 JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
 StringSource[] compileList = 
 \{new StringSource("Test1", s), new StringSource("Test2", r)\};
 String[] options = new String[] \{"-d", "."\};
 jc.getTask(null, null, null, Arrays.asList(options), null, 
 Arrays.asList(compileList)).call();
 \}
 \}
 /* A file object used to represent java source code in a string.*/
 class StringSource extends SimpleJavaFileObject \{
 final String code;
 public StringSource(String name, String code) \{
 super(URI.create(
 "string:///" + name.replace('.','/') + Kind.SOURCE.extension),
 Kind.SOURCE);
 this.code = code;
 \}
 public CharSequence getCharContent(boolean ignoreEncodingErrors) \{
 return code;
 \}
 \}
 ,,,

 todo: we have to get the class name, and hand it to the StringSource
 class. Get all the diagnostics, and allow to jump to the line number,
 Display compiler messages somewhere.

 * the beginning of an example to compile text in a JTextArea 
 -------------------------------------------------------------
 import javax.tools.*;
 import java.net.*;
 import java.io.*;
 import java.util.Arrays;
 import javax.swing.*;
 import java.awt.*;
 import java.awt.event.*;
 
 public class TextCompiler extends JPanel \{
 JTextArea area;
 public TextCompiler() \{
 super(new java.awt.BorderLayout());
 this.area = new JTextArea(20, 60);
 this.area.setFont(new Font("Courier", Font.PLAIN, 20));
 this.add(this.area);
 this.setActionKeys();
 this.skeleton();
 \}
 public void setActionKeys() \{
 InputMap im = area.getInputMap(JComponent.WHEN\\_IN\\_FOCUSED\\_WINDOW);
 ActionMap am = area.getActionMap();
 im.put(KeyStroke.getKeyStroke("control J"), "compile");
 am.put("compile", new CompileAction());
 \}
 public void compile() \{
 //String s = "public class Test1 \{ String n = 2; \}";
 System.out.println("compiling...");
 String s = this.area.getText(); 
 JavaCompiler jc = ToolProvider.getSystemJavaCompiler();
 StringSource[] compileList = \{new StringSource("Test", s)\};
 jc.getTask(null, null, null, null, null, Arrays.asList(compileList))
 .call();
 \}
 /** adds some java skeleton code to the text area */
 public void skeleton() \{
 this.area.append("public class Test \{\\$\\backslash\\$n");
 this.area.append("\}\\$\\backslash\\$n");
 \}
 public static void main(String[] args) \{
 JFrame f = new JFrame();
 f.add(new TextCompiler()); f.pack();
 f.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);
 f.setExtendedState(JFrame.MAXIMIZED\\_BOTH);
 f.setVisible(true);
 \}
 class CompileAction extends AbstractAction \{
 public void actionPerformed(ActionEvent ev) \{
 compile();
 \}
 \}
 
 \}
 /* A file object used to represent java source code in a string.*/
 class StringSource extends SimpleJavaFileObject \{
 final String code;
 public StringSource(String name, String code) \{
 super(URI.create(
 "string:///" + name.replace('.','/') + Kind.SOURCE.extension),
 Kind.SOURCE);
 this.code = code;
 \}
 public CharSequence getCharContent(boolean ignoreEncodingErrors) \{
 return code;
 \}
 \}
 ,,,


DIAGNOSTICS WITH THE COMPILER API ....

 The so-called javax.tools.Diagnostic class encapsulates both errors
 and warnings which are encountered during compilation. In the 
 sun java implementation the getMessage() method returns the explanatory
 text (String) which includes the file-name, class name and line number.

ERROR MESSAGES WHILE COMPILING ....

 * reached end of file while parsing
 You've missed a close-bracket somewhere.

 * Symbol not found:
 This either means that you have mispelled a java api class name,
 not included the appropriate import statement for a class which
 you are using, or, if the Symbol (class name) is a class which
 you have written, this compiler error message indicates that the 
 class path has not been set properly. The following line will compile
 Test.java and use classes on which it depends which are located in the 
 'eg' subfolder. 
 >> javac -cp eg Test.java

BUILDING PROJECTS ....

 For large projects with many source files a build tool is often used
 to ensure that all files are properly built.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents tools 
 .. Ant -
 .. maven - finds and solves class dependencies
 .. make - the c language tool, but maybe useful
 ..

 The Maven Central repository maybe the closest things Java
 has to the Perl cpan repository.

JAR ARCHIVES

 The 'jar' archive tool is a way to package several java class files
 and other application resources (such as images ...) in a single
 zip compressed file. Jar files may also be signed. The actual name
 of the jar file is not important (unlike java class files). Jar 
 file metadata must be in UTF8 format
 
CREATING JAR ARCHIVES ....

 The jar tool will by default also create a manifest file 
 'manifest.mf' in the 'meta-inf' folder, but you still have to 
 add the 'Main-Class:' field to the manifest.mf file 
 (using a text editor for example) in order to run the jar file
 as an application with 'java -jar app.jar' 
 
 * create a jar archive with entry point 'MyApp' (since java 1.6)
 >> jar cvfe app.jar MyApp MyApp.class

 Using the 'e' option to jar avoids the annoying necessity to edit the jar
 manifest file to add the 'Main-Class:' field.

 * set the entry point in the manifest file to 'ViewImage' in 'Images' package
 >> echo "Main-Class: Images.ViewImage" > manifest.txt
 >> jar cfm MyJar.jar Manifest.txt MyPackage/*

 This creates a manifest with:
 -----------
 Manifest-Version: 1.0
 Created-By: 1.6.0 (Sun Microsystems Inc.)
 Main-Class: Images.ViewImage
 ,,,

 * do the same thing using the modern 'e' switch
 >> jar cfe Main.jar foo.Main foo/Main.class

 * create a jar file 'app.jar' from all .java file in this folder
 >> jar cf app.jar *.java

 This also creates the default manifest file META-INF/MANIFEST.MF

 * create a jar file 'app.jar' from all .java file in this folder
 >> jar cf app.jar ViewData.class Utils.class
 >> echo "Main-Class: ViewData

 * create a jar file showing verbose information (file names archived ...)
 >> jar cvf app.jar Main.java Panel.java

 * create a jar file containing all files and folders in the current one
 >> jar cvf app.jar *
 
 * create an archive of all the files in the 'imorg' folder
 >> jar cvf app.jar imorg 

 * create a jar including one class file and all files in 'audio' \\& 'images'
 >> jar cvf TicTacToe.jar TicTacToe.class audio images
 
 * create a jar archive without compressing the files
 >> jar 0cf app.jar imorg 
 
 Uncompressed jar files can be loaded more quickly than compressed
 ones (improving the startup time of an application or applet)

 * create a jar archive with an existing manifest file
 >> jar cmf existing-manifest jar-file input-file(s)
 
MANIFEST FILES FOR JAR ....

 The jar manifest file contains meta information. The last line 
 must end with a newline character


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents tools
 .. fastjar - creates jar files
 ..

RUNNING JAR APPLICATIONS ....
 
 * run an archived application (need the 'main-class' manifest header)
 >> java -jar app.jar

 * run class MethodPane in jar file without using the -jar switch 
 >> java -classpath m.jar MethodPanel 

 * view the contents of a jar file
 >> jar tf jar-file

 * a more complicated example with dependencies (on linux use ":" not ";" )
 >> java -classpath .;myjar.jar;lib/referenced-class.jar my.package.MainClass

EXTRACTING FROM JAR ARCHIVES ....
 
 jar files are compressed (if they are compressed) in the standard
 'zip' format. the Jar tool can be used as a replacement for 
 unzip or gunzip etc.

 * extract all files from "app.jar"
 >> jar xf app.jar

 * extract only some files from a jar archive
 >> jar xf jar-file archived-file(s)

 * unzip a normal zip file using the jar tool
 >> jar xvf jdk-6-doc.zip 

USING JAR FILES ....

 * create a web page with an applet packaged as a jar
 ------
 <html>
 <applet code=AppletClassName.class
 archive="JarFileName.jar"
 width=width height=height>
 </applet>
 </html>
 ,,,
 
PROGRAMATIC USE OF JAR FILES ....

 To list Jar files one can use either ZipFile and a ZipEntry or their
 children classes java.util.jar.JarFile and java.util.jar.JarEntry.

 * convert a jar file to a URL
 >> JarFile j = new JarFile(new File("x.jar")); j.toURI().toURL()

 * list the class files in a jar file (the java 'runtime' jar file)
 --------------------------------------------------
 import java.util.jar.*;
 import java.util.zip.*;
 import java.io.File;
 import java.util.Enumeration;
 public class ListJar \{
 public static void main(String[] args) throws Exception \{
 JarFile jar = new JarFile(
 new File("/usr/lib/jvm/java-6-sun-1.6.0.15/jre/lib/rt.jar"));
 Enumeration<? extends JarEntry> enumeration = jar.entries();
 while (enumeration.hasMoreElements()) \{
 ZipEntry zipEntry = enumeration.nextElement();
 if (zipEntry.getName().endsWith(".class")) \{
 System.out.println(zipEntry.getName());
 \}
 \}
 \}
 \}
 ,,,

 
 * create a jar file programmatically with JarOutputStream
 -------------------------------------------------------------
 import java.util.jar.*; 
 ...
 public void run() throws IOException
 \{
 Manifest manifest = new Manifest();
 manifest.getMainAttributes().put(
 Attributes.Name.MANIFEST\\_VERSION, "1.0");
 JarOutputStream target = 
 new JarOutputStream(new FileOutputStream("output.jar"), manifest);
 add(new File("inputDirectory"), target);
 target.close();
 \}
 
 private void add(File source, JarOutputStream target) throws IOException
 \{
 BufferedInputStream in = null;
 try \{
 if (source.isDirectory()) \{
 String name = source.getPath().replace("\\$\\backslash\\$\\$\\backslash\\$", "/");
 if (!name.isEmpty()) \{
 if (!name.endsWith("/"))
 name += "/";
 JarEntry entry = new JarEntry(name);
 entry.setTime(source.lastModified());
 target.putNextEntry(entry);
 target.closeEntry();
 \}
 for (File nestedFile: source.listFiles())
 add(nestedFile, target);
 return;
 \}
 
 JarEntry entry = new JarEntry(source.getPath().replace("\\$\\backslash\\$\\$\\backslash\\$", "/"));
 entry.setTime(source.lastModified());
 target.putNextEntry(entry);
 in = new BufferedInputStream(new FileInputStream(source));
 
 byte[] buffer = new byte[1024];
 while (true) \{
 int count = in.read(buffer);
 if (count == -1) break;
 target.write(buffer, 0, count);
 \}
 target.closeEntry();
 \}
 finally \{
 if (in != null) in.close();
 \}
 \}
 ,,,

JAR API ....

 Since java 1.2 there are apis to load and run jars programmatically
 @@ \url{http://java.sun.com/developer/Books/javaprogramming/JAR/api/}
 A short article about this

 @@ \url{http://docs.oracle.com/javase/tutorial/deployment/jar/apiindex.html}
 How to use the jar apis to load a jar app in a program


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents jar api packages and classes
 .. java.util.jar - package
 .. java.net.JarURLConnection class
 .. java.net.URLClassLoader class
 ..

 * create a jar archive url from a normal url.
 >> URL url = new URL("http://bumble.sf.net/books/java/m.jar"); 
 >> URL u = new URL("jar", "", url + "!/");

 Jar style urls have a strange syntax.

 * download a jar archive
 -------------------------------------------------------------
 import java.net.URL;

 try \{
 URL url = new URL("jar:http://hostname/my.jar!/");
 JarURLConnection conn = (JarURLConnection)url.openConnection();
 JarFile jarfile = conn.getJarFile();
 String entryName = conn.getEntryName(); // null
 \} catch (MalformedURLException e) \{
 \} catch (IOException e) \{\}
 ,,,

 * create a jar url for a local jar archive
 >> URL url = new URL("jar:file:/c:/almanac/my.jar!/");

 * get just one file from a jar archive 
 -------------------------------------------------------------
 try \{
 url = new URL("jar:file:/c:/almanac/my.jar!/com/mycompany/MyClass.class");
 conn = (JarURLConnection)url.openConnection();
 jarfile = conn.getJarFile();
 // Get the entry name; it should be the same as specified on URL
 entryName = conn.getEntryName();
 JarEntry jarEntry = conn.getJarEntry();
 \} catch (MalformedURLException e) \{
 \} catch (IOException e) \{\}
 ,,,

 * load a jar and find out the main class (if there is one)
 -------------------------------------------------------------
 import java.net.URL;
 import java.net.JarURLConnection;
 import java.util.jar.Attributes;
 public class MainJar \{
 public static void main(String[] args) throws Exception \{
 URL url = new URL("jar:http://bumble.sf.net/books/java/m.jar!/"); 
 JarURLConnection uc = (JarURLConnection)url.openConnection();
 Attributes aa = uc.getMainAttributes();
 if (aa != null) \{
 System.out.format(
 "Main class is: \\%s\\$\\backslash\\$n", aa.getValue(Attributes.Name.MAIN\\_CLASS));
 \}
 else \{ System.out.println("No main class"); \}
 \}
 \}
 ,,,


 * load and execute a class with URLClassLoader and method.invoke()
 ----------------------------------
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.lang.reflect.InvocationTargetException;
 public class LoadClass \{
 public static void main(String[] args) throws Exception \{
 URL url = new URL("file:MethodPanel.class");
 URLClassLoader cl = new URLClassLoader(new URL[] \{url\});
 Class c = cl.loadClass("MethodPanel");
 Method m = c.getMethod("main", new Class[] \{ args.getClass() \});
 m.setAccessible(true);
 // check for valid java 'main' method
 int mods = m.getModifiers();
 if (m.getReturnType() != void.class || !Modifier.isStatic(mods) ||
 !Modifier.isPublic(mods)) \{
 throw new NoSuchMethodException("main");
 \}
 try \{
 m.invoke(null, new Object[] \{ args \});
 \} catch (IllegalAccessException e) \{
 // This should not happen, as we have disabled access checks
 \}
 \}
 \}
 ,,,

 * load and execute the main class from a remote jar archive 
 -----------------------------------------------------------
 import java.net.URL;
 import java.net.URLClassLoader;
 import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.net.JarURLConnection;
 import java.util.jar.Attributes;

 public class LoadJar \{
 public static void main(String[] args) throws Exception \{
 String mainClass = new String("");
 URL url = new URL("jar:http://bumble.sf.net/books/java/m.jar!/"); 
 JarURLConnection uc = (JarURLConnection)url.openConnection();
 Attributes aa = uc.getMainAttributes();
 if (aa != null) \{
 mainClass = aa.getValue(Attributes.Name.MAIN\\_CLASS);
 System.out.println(aa.getValue(Attributes.Name.MAIN\\_CLASS));
 \}
 else \{ 
 System.out.println("No main class");
 System.exit(0);
 \}
 URLClassLoader cl = new URLClassLoader(new URL[] \{url\});
 Class c = cl.loadClass(mainClass);
 Method m = c.getMethod("main", new Class[] \{ args.getClass() \});
 m.setAccessible(true);
 // check for valid java 'main' method
 int mods = m.getModifiers();
 if (m.getReturnType() != void.class || !Modifier.isStatic(mods) ||
 !Modifier.isPublic(mods)) \{
 throw new NoSuchMethodException("main");
 \}
 try \{
 m.invoke(null, new Object[] \{ args \});
 \} catch (IllegalAccessException e) \{
 // This should not happen, as we have disabled access checks
 \}
 \}
 \}
 ,,,

 * run a class in subfolder 'eg' (but not in any package)
 >> java -cp eg Test


AN EXAMPLE JAR MANIFEST ....

 * an example manifest file with the class path set
 ----
 Main-Class: org.mypackage.HelloWorld
 Class-Path: lib/supportLib.jar
 ,,,

CLASSPATH

 The classpath is the mechanism which the jre using to locate
 classes which are used in an application. The current directory
 is always included in the classpath. The classpath has a reputation
 for giving rise to tricky configuration problems.

 * place multiple jar files on the classpath (windows)
 >> java -cp "Test.jar;lib/*" my.package.MainClass

 * the same on Linux (colons and not semicolons!)
 >> java -cp "Test.jar:lib/*" my.package.MainClass

 * jar files can also be placed in the extension directory 
 >> C:\\$\\backslash\\$JDK1.2.2\\$\\backslash\\$JRE\\$\\backslash\\$LIB\\$\\backslash\\$EXT \\#\\#(windows, very old java runtime)

 * a typical extension folder list for java 1.7 on Linux
 >> \texttt{/usr/lib/jvm/jdk1.7.0/jre/lib/ext:/usr/java/packages/lib/ext}

 * another way of copying a jar file to the extensions folder 
 >> cp mp3plugin.jar \\$\{JAVA\\_HOME\}/jre/lib/ext

 * display the java extensions folder
 ----
 public class GetClassPath
 \{
 public static void main(String[] args) \{
 System.out.println(System.getProperty("java.ext.dirs"));
 \}
 \}
 ,,,

 * display the java classpath and the extensions folder
 ----
 import java.util.Properties;
 public class GetClassPath
 \{
 static Properties p = System.getProperties();
 public static void main(String[] args) \{
 System.out.println(p.getProperty("java.class.path", null));
 System.out.println(System.getProperty("java.ext.dirs"));
 System.out.println(p.getProperty("java.ext.dirs", null));
 \}
 \}
 ,,,

RANDOMNESS

 Randomness is important since it is the seedling of artisticness
 and creativity. 

 * generate some random bytes
 -------------------------------------------------------------
 byte[] bytes = new byte[5];
 rand.nextBytes(bytes);
 ,,,

 * shuffle the order of elements in a java.util.List 
 -------------------------------------------------------------
 List list = new ArrayList();
 list.add("a"); list.add("b"); list.add("c");
 Collections.shuffle(list);
 ,,,

 * shuffle the order of elements in an array
 -------------------------------------------------------------
 String[] array = new String[]\{"a", "b", "c"\};
 Collections.shuffle(Arrays.asList(array))
 ,,,

SYNTAX AND KEYWORDS 

IF CONDITIONALS ....

 The 'if' statement is used to branch program flow depending on a
 particular condition. 

 * example
 >> String a="nn"; if (a.equals("NN")) \{ ... \}

TERNARY OPERATOR

 The ternary operator is a compact form of the if / else statement

 * find the minimum value
 >> minVal = a < b ? a : b;
 >> minVal = (a < b) ? a : b;

 * a print statement using a the ternary operator 
 >> System.out.println("will last " + icecreamLife + 
 >> " month" + (icecreamLife==1?"":"s") +" and " + icecreamFate);

 * use the ternary operator
 >> int i = 1; String s = (i==0?"zero":"non-zero");

SWITCH STATEMENT

 * a simple switch statement
 ---------------------------
 int result = 0;
 switch (result)
 \{
 case 0: 
 break;
 case 1: 
 break;
 default:
 break;
 \}
 ,,,

LOOPS

 Java does not have a 'map' function, which transforms each
 element of a collection using a function and without looping.

FOR LOOPS ....

 * loop over any type of collection (implements iterable)
 -------------------------------------------------------------
 for (Iterator<type> iter = coll.iterator(); iter.hasNext(); ) \{
 type var = iter.next();
 body-of-loop
 \}
 ,,,

 * the same as above, but only since java 1.5
 -------------------------------------------------------------
 for (type var : coll) \{
 body-of-loop
 \}
 ,,,

 * a simple counting loop
 ------------------------
 for (int ii = 0; ii < 7; ii++) 
 \{
 System.out.println("ii=" + ii + " ");
 \}
 ,,,

 * a loop which runs until the user enters 'q' 
 ---------------------------------------------
 import java.util.Scanner;
 public class Test \{
 public static void main(String[] args)
 \{
 Scanner scan = new Scanner(System.in);
 for (String s = ""; !s.equals("q"); s = scan.nextLine())
 \{
 System.out.println("You entered: " + s);
 System.out.println("Type q to quit");
 \}
 \} \}
 ,,,

FOREACH LOOP ....
 
 In java 1.5 a "for each" loop was introduced to allow 
 programmers to use a more pleasant syntax for a very common 
 task (looping over a collection or array) 
 
 * loop through a the words of a string
 ---------------------------------------------------
 public class ForSplit \{
 public static void main(String[] args) \{
 String s = "red yellow blue";
 String[] splitString = (s.split("\\$\\backslash\\$\\$\\backslash\\$s+"));
 for (String ss: splitString) \{
 System.out.println(ss);
 \}
 \}
 \}
 ,,,

 * a for each loop to add all elements in an array (>= java 1.5)
 ---------
 import java.util.Arrays;
 public class SumArray \{
 public static void main(String[] args) \{
 double[] aa = \{1.2, 3.0, 0.8\};
 double sum = 0;
 for (double d : aa) \{
 sum += d; // d gets each value in aa.
 \}
 System.out.format(
 "The sum of array \\%s is \\%g", Arrays.toString(aa), sum);
 \}
 \}
 ,,,

 
 This loop only allows access to the elements and can only loop forward

 * print out command line arguments using foreach
 ------------
 public class Freq \{
 public static void main(String[] args) \{
 for (String a : args) \{
 System.out.println(a);
 \}
 \}
 \}
 ,,,

 * iterate over a collection of Strings using explicit iterator 
 --------------
 void cancelAll(Collection<String> c) \{
 for (Iterator<String> i = c.iterator(); i.hasNext(); )
 i.next().cancel();
 \}
 ,,,

 Use the explicit iterator if you have to modify elements of the collection

 * iterate over a collection of Strings with a foreach loop (java 1.5 >=) 
 --------------
 void cancelAll(Collection<String> c) \{
 for (String t : c)
 t.cancel();
 \}
 ,,,

 * iterate over a List collection using a foreach loop
 ----------
 import java.util.*;
 public class ListLoop \{
 public static void main(String[] args) \{
 List<String> list = new ArrayList<String>();
 list.add("oak");
 list.add("yew");
 list.add("acacia");
 for (String item: list ) \{
 System.out.println(item);
 \}
 \}
 \}
 ,,,
 
 * loop over a list with an iterator to allow removal of elements
 --------
 import java.util.*;
 public class ListLoop \{
 public static void main(String[] args) \{
 List<String> list = new ArrayList<String>()
 list.add("oak");
 list.add("yew");
 list.add("acacia");
 for (Iterator<String> i = someList.iterator(); i.hasNext(); ) \{
 String item = i.next();
 System.out.println(item);
 \}
 \}
 \}
 ,,,

ITERATORS AND ENUMERATIONS ....

 Iterators are a way of performing some task for every element of
 a Collection without retrieving the entire collection.

 Enumerations are the older class to facilitate iterating over 
 a set of objects. Iterators are the newer way to do the same thing.
 Enumerations are still used because many older api classes still
 in use return Enumerations.

 In the code below, the for loop has the advantage of limiting the 
 scope of the iterator variable to the for loop.

 * an iterator can be used with a while or a for loop
 -------------------------------------------------------------
 Iterator<Integer> iterator = set.iterator();
 while (iterator.hasNext()) \{
 Integer element = iterator.next();
 if (element \\% 2 == 0) \{
 iterator.remove();
 \}
 \}
 //You will often see this pattern using a for loop 
 //rather than a while loop:
 for (Iterator<Integer> i = set.iterator(); i.hasNext();) \{
 Integer element = i.next();
 if (element \\% 2 == 0) \{
 i.remove();
 \}
 \}
 ,,,

WHILE LOOPS ....

 * a while loop
 --------------
 String s = ""; 
 Scanner scan = new Scanner(System.in);
 while (!s.equals("q"))
 \{
 System.out.print("type q to quit> "); 
 s = scan.nextLine();
 \}
 ,,,

ARRAYS 

 Arrays can be passed to methods or functions, but changes made
 to the elements are permanent (no copy of the array is made 
 when it is passed to the method).

 * declare a method 'do' which takes an integ
 >> public void do(int [] array);

 * create an anonymous String array to pass to a method or constructor
 >> object.doSomething(new String[]\{"one","two"\}));

DECLARING ARRAYS ....

 * create an array of 4 integers, with the values initialized
 >> int[] ii = \{100, 200, 300, 400\};

 * declare an array of 30 integers
 >> int[30] a; 

 * declare and initialise an array of colours
 >> Color[] colors = \{Color.orange, Color.green, Color.yellow\};

 * declare an array with space for 25 strings
 >> String[] ss = new String[25]; \\#\\#(???)

 * declare an array of characters
 >> char[] c = \{'a', 'b', 'c'\};

 * declare an array of strings 
 >> String[] ss = \{"oak", "alder", "amber"\};

 * another way?
 >> String[] ss = new String[]\{"oak", "alder", "amber"\};

INITIALISING ARRAYS ....

 * create and initialise an array of double values
 >> double[] array = new double[]\{0D, 2D, 4D, 5D\}

 * create a byte array and fill all items with the value 0xFF
 >> byte[] bytes = new byte[10]; Arrays.fill(bytes, (byte)0xFF);

 * create a 10 element 'char' array and initialise all elements to 'a'
 >> char[] cc = new char[10]; Arrays.fill(cc, 'a');

 The example below will work for any type of object, not just 
 Strings.

 * create an array of Strings and initialise all values to 'none'
 >> String[] ss = new String[10]; Arrays.fill(ss, "none");
 
 * initialise only values 0 to 3 to 'none'
 >> String[] ss = new String[10]; Arrays.fill(ss, 0, 4, "none");
 
OBJECT ARRAYS ....

 Arrays may contain any type of Object, but only one type

 * declare and array of File objects 
 ----------------------------------------
 import java.io.File;
 public class FileArray \{
 public static void main(String[] args) \{
 File[] ff = \{new File("."), new File("a")\};
 \}
 \}
 ,,,
 
ANONYMOUS ARRAYS ....

 Anonymous arrays are useful for testing and making code more
 succint/obfuscated. The syntax is not immediately obvious.

 * pass an anonymous array of 2 colours to a method call
 >> object.doSomething(new Color[]\{Color.orange, Color.green\})

DISPLAYING ARRAYS ....

 * print an array with Arrays.toString (since 1.5)
 -------------------------------------------------
 import java.util.Arrays; 
 public class ArrayTest \{
 public static void main(String[] args) \{
 String[] ss = \{"gold", "green", "red"\};
 System.out.println(Arrays.toString(ss));
 \}
 \}
 ,,,

 * display an array with a JOptionPane list-box
 -------------------------------------------------
 import javax.swing.*;
 public class Test \{
 public static void main(String[] args) \{
 String[] ss = \{"gold", "green", "red"\};
 Object r = JOptionPane.showInputDialog(
 null, "Choose one element:", "Displaying arrays",
 JOptionPane.PLAIN\\_MESSAGE, null, ss, ss[0]);
 System.out.println("element selected: " + r);
 \}
 \}
 ,,,

LOOPING THROUGH ARRAYS ....

 Java does have a way to apply a function to all elements
 of an array at once (although apparently scala does), so you
 have to loop through the array one element at a time.

 * Add all elements of the array nn 
 ----------------------------------
 int sum = 0;
 for (int v : nn) \{ sum += v; \}
 ,,,

 The above loop cannot be used to set the values of the array

 * assign random numbers to the elements of an array
 -------------------------------------------------------------
 int[] a = new int[1000];
 for (int i = 0; i < a.length(); i++) \{
 // Random number 0-99999
 a[i] = (int)(Math.random() * 100000);
 \}
 ,,,

COMPARING ARRAYS ....

 * check if 2 arrays are equal (contain the same objects) 
 -------------------------------------------------
 import java.util.Arrays; 
 public class Test \{
 public static void main(String[] args) \{
 String[] ss = \{"gold", "green", "red"\};
 String[] tt = \{"gold", "green", "red"\};
 System.out.println("equal? " + Arrays.equals(ss, tt));
 \}
 \}
 ,,,

 * check if arrays of long, float, and double are equal
 -------------------------------------------------------------
 b = Arrays.equals(new long[]\{0L\}, new long[]\{0L\}); // true
 b = Arrays.equals(new float[]\{0F\}, new float[]\{0F\}); // true
 b = Arrays.equals(new double[]\{0D\}, new double[]\{0D\}); // true
 ,,,
 
 * create an array of 10 integers
 >> anArray = new int[10]; 

 * copy one array to another
 ---------------------------
 public class Test \{
 public static void main(String[] args) \{
 char[] copyFrom = \{ 'd', 'e', 'c', 'a', 'f', 'f', 'e'\};
 char[] copyTo = new char[7];
 System.arraycopy(copyFrom, 2, copyTo, 0, 3);
 System.out.println(new String(copyTo));
 \}
 \}
 ,,,

JOINING ARRAYS ....

 * concatenate 2 arrays of strings
 ---------------------------------
 String[] concat(String[] aa, String[] bb) \{
 String[] C= new String[A.length+B.length];
 System.arraycopy(aa, 0, cc, 0, aa.length);
 System.arraycopy(B, 0, C, A.length, B.length);
 return C;
 \}
 ,,,,

SORTING ARRAYS ....

 * sort an array of integers into ascending order 
 -------------------------------------------------
 import java.util.Arrays; 
 public class Test \{
 public static void main(String[] args) \{
 int[] ii = \{5, 3, 8, 1\};
 System.out.println("array: " + Arrays.toString(ii));
 Arrays.sort(ii);
 System.out.println("sorted: " + Arrays.toString(ii));
 \}
 \}
 ,,,

 * using a comparator to sort an array 
 ---------------
 Action actions[] = component.getActions();
 Comparator<Action> comparator = new Comparator<Action>() \{
 public int compare(Action a1, Action a2) \{
 String firstName = (String) a1.getValue(Action.NAME);
 String secondName = (String) a2.getValue(Action.NAME);
 return firstName.compareTo(secondName);
 \}
 \};
 Arrays.sort(actions, comparator);
 ,,,

SEARCHING ARRAYS ....

 * determine if an array contains a certain element
 >> String ss = \{"a","b","c"\}; Arrays.asList(ss).contains("b");
 
TWO DIMENSIONAL ARRAYS ....

 * declare and initialise a 2 dimensional array
 -------------------------------------------------------------
 Object[][] data = \{
 \{aboutIcon, "About"\},
 \{addIcon, "Add"\},
 \{copyIcon, "Copy"\},
 \};
 ,,,

MORE ARRAYS ....

 CAN create and return an array from a method
 arrays passed in are changed by methods.

 * different ways to initialize arrays
 >> int[] ii = \{100, 200, 300, 400\};
 >> int[30] a; 
 >> char[] c = \{'a', 'b', 'c'\};
 >> double[] d = new double[5]; 
 >> String[] ss = new String[25]; 
 >> int[] aa = \{1, 2, 3\}; ob.doo(aa);

 All c is initialised to (int)0

 char[] c = new char[20]; 
 for (int i=0; i < c.length; i++)
 System.out.println("c1=" + (int)c[i]);

CONVERTING BETWEEN ARRAYS AND COLLECTIONS ....

FROM MAPS ....

 * create an array of objects containing the keys in a map
 >> Object[] array = map.keySet().toArray();

 * create an array of strings containing the keys in a map
 >> array = (String[])map.keySet().toArray(new String[set.size()]);

 * Create an array containing the values in a map
 >> Object[] array = map.values().toArray();
 >> array = (MyClass[])map.values().toArray(new MyClass[set.size()]);

FROM SETS ....

 * Create an array containing the elements in a set
 >> objectArray = set.toArray();
 >> array = (MyClass[])set.toArray(new MyClass[set.size()]);

FROM LISTS ....

 * Create an array containing the elements in a list
 >> Object[] objectArray = list.toArray();
 >> MyClass[] array = (MyClass[])list.toArray(new MyClass[list.size()]);

ENUMERATIONS ....

 * list all the system properties using an Enumeration
 ------------------------------------
 public class SystemProps \{
 public static void main(String[] args) \{
 java.util.Properties p = System.getProperties();
 java.util.Enumeration en = p.propertyNames();
 while (en.hasMoreElements()) \{
 String name = (String) en.nextElement();
 System.out.format("\\%s: \\%s\\$\\backslash\\$n", name, p.getProperty(name));
 \}
 \}
 \}
 ,,,

 * loop through an enumeration using a for loop 
 ---------------------------------------
 import java.io.*;
 import java.net.*;
 import java.util.*;
 public class ListNetInterfaces \{
 public static void main(String args[]) throws SocketException \{
 Enumeration<NetworkInterface> nets =
 NetworkInterface.getNetworkInterfaces();
 for (NetworkInterface ni : Collections.list(nets)) \{
 System.out.println(
 "Display name:" + ni.getDisplayName());
 System.out.println("Hardware address:" +
 Arrays.toString(ni.getHardwareAddress()));
 \}
 \}
 \}
 ,,,

GENERICS

 Since Java 1.5 (September 30, 2004) an important feature 
 became part of the Java language: Generics. From a pragmatic point
 of view, generics avoid the need to cast objects to a specific
 object type when using Collections

 * declare and initialise a java.util.List of Strings.
 >> List<String> list = new ArrayList<String>();

 * specify a generic which is a descendant of JarEntry
 >> Enumeration<? extends JarEntry> enumeration = jar.entries();

COLLECTIONS

 Collections are the name java gives to objects which contain
 multiple object elements. Examples of these are sets, lists and
 maps. The collection framework was apparently designed by Joshua
 Bloch. Each collection type has a number of implementations, for
 example, the List type has the ArrayList, LinkedList etc. 
 these implementations relate mainly to performance issues, and
 sometimes functionality. 

 In more recent versions of Java, use is made of 'generics' which
 allow the programmer to specify at compile time what type of 
 object a collection will contain. 


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents main collection types
 .. set - an unordered collection, with no duplicates
 .. list - an ordered set of objects
 .. map - a type of dictionary of key value pairs
 ..

 * use ArrayList for resizable arrays

 * Vector is older (synchronised for multi threads?)

SETS 

 A set is an unordered collection of things which cannot 
 contain duplicates.

 * create a set collection d from collection c with no duplicates
 >> Collection<Type> d = new HashSet<Type>(c);

LISTS 

 A list is an ordered collection of objects. In general, and as with 
 other collections you declare a variable as a List and then instantiate
 it as a particular List implementation.

 * create a List from a set of strings
 >> List<String> list = Arrays.asList( "first", "second", "third");

 * get the first element (an integer) from the array list
 >> Integer one = (Integer) arrayList.get(0)

CONVERTING LISTS ....

 Even if the list.size() == 0 in the code below, a valid, zero
 length array is returned.

 * convert a java.util.List to an array of Integers
 >> return list.toArray(new Integer[list.size()]);

ARRAYLISTS ....

 @@ \url{http://www.java2s.com/Code/Java/Collections-Data-Structure/ArrayList.htm}
 arraylist examples

 * create and add a mutable string to an array list.
 ---------------------------------------------------
 List l = new ArrayList();
 l.add(new StringBuffer());
 ,,,

 * loop through each element of an array list by index number
 ------------------------------------------------------------
 import java.util.ArrayList;
 import java.util.List;
 public class LoopList \{
 public static void main(String[] args) \{
 List list = new ArrayList();
 for (int jj = 0; jj < list.size(); jj++) \{
 System.out.println("[" + jj + "] - " + list.get(jj));
 \}
 \}
 \}
 ,,,

LIST GOTCHAS ....

 If you import java.awt.* but not java.util.List you will get some
 quite baffling error messages when you try to use you List (because
 java.awt.List exists, but is an old gui component)

MAPS 
 
 A map is a type of 'dictionary' consisting of keys and 
 their corresponding values. In perl these are called 'hashes'
 and in other languages 'dictionaries'. 

 * create a map to contain the frequency of words in a document 
 -------------------------------------------------------------
 Map<String, Long> doc = new HashMap<String, Long>();
 doc.put("file", 6);
 doc.put("channel", 4);
 doc.put("size", 3);
 ,,,

 * get a value from a map by specifying its key
 >> doc.get("file");

 * create a new map and put some keys and values into it
 -------------------------------------------------------------
 Map<String, Double> times = new HashMap<String, Double>();
 times.put("file", 0.0);
 times.put("channel", 0.0);
 times.put("raf", 0.0);
 ,,,

 
 * create a map contained string keys and arraylists
 >> Map<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>;
 
 Tree maps are sorted by some ordering of keys or by a comparator 
 specificied in the constructor.

 * create a frequency word list of from command line arguments
 ---------- 
 import java.util.*;
 
 public class Freq \{
 public static void main(String[] args) \{
 Map<String, Integer> m = new HashMap<String, Integer>();
 
 // Initialize frequency table from command line
 for (String a : args) \{
 Integer freq = m.get(a);
 m.put(a, (freq == null) ? 1 : freq + 1);
 \}
 
 System.out.println(m.size() + " distinct words:");
 System.out.println(m);
 \}
 \}
 ,,,

 * a tree map stores its keys in alphabetical order (if they are strings)
 >> Map<String, Integer> m = new TreeMap<String, Integer>();

 * copy map m to map copy
 >> Map<K, V> copy = new HashMap<K, V>(m);

 * loop over the keys in a map
 ---
 import java.util.*;
 ...
 for (KeyType key : m.keySet())
 System.out.println(key);
 ,,,

 * loop over the values of a map, getting the keys and values
 import java.util.*;
 for (Map.Entry<KeyType, ValType> e : m.entrySet())
 System.out.println(e.getKey() + ": " + e.getValue());
 ,,,

 * test if 2 maps have the same set of keys
 >> if (m1.keySet().equals(m2.keySet())) \{ ... \}

 * test if map m1 contains all the key/value pairs of map m2
 >> if (m1.entrySet().containsAll(m2.entrySet())) \{ ... \}

 * determine which keys are common to both maps m1 and m2
 -----------------
 Set<KeyType>commonKeys = new HashSet<KeyType>(m1.keySet());
 commonKeys.retainAll(m2.keySet());
 ,,,

NUMBERS

OPERATORS ....

OPERATOR PRECEDENCE ....

 In normal order, prints '2'
 >> System.out.println("\\$\\backslash\\$n result=" + 10*2\\%3);

RANDOM NUMBERS ....

 * generate a random integer from 0-99
 -------------------------
 Random rand = new Random();
 selected = rand.nextInt(100);
 ,,,

 * generate a random number from 0 to 100
 >> int r = (int)(Math.random() * 100)

 * generate a random boolean value
 -------------------------
 import java.util.Random;
 public class RandomBoolean \{
 public static void main(String[] args) \{ Random rand = new Random();
 boolean b = rand.nextBoolean();
 System.out.format("boolean value: \\%s", b);
 \}
 \}
 ,,,

 * A random number from 0-9
 -------------------------------------------------------------
 public class RandomInteger \{
 public static void main(String[] args) \{
 java.util.Random g = new java.util.Random();
 int i = g.nextInt(10); System.out.println("i=" + i);
 \}
 \}
 ,,,

 * A random element of an array 
 -------------------------------------------------------------
 public class RandomArray \{
 public static void main(String[] args) \{
 java.util.Random g = new java.util.Random();
 char[] cc = \{'a', 'b', 'c', 'd'\};
 System.out.println(cc[g.nextInt(cc.length)]);
 \}
 \}
 ,,,

DOUBLE ....
 
 A double is a number which can hold fractional (decimal) values
 and bigger values than an integer.
 
 * Convert a string to a double
 >> double d = Double.parseDouble("-0.223");
 
 * powers
 >> java.lang.Math.pow(3,4)
 
 float f = rand.nextFloat(); // 0.0 <= f < 1.0

 * generate a random double number (0.0 <= d < 1.0)
 >> double d = rand.nextDouble(); 

INTEGERS ....
 
 * declare an integer
 >> int x = 2;
 
 * parseInt is FUSSY, examples below throw number format exception
 >> int i = Integer.parseInt("123 ")' !!! NO
 >> int i = Integer.parseInt(" 123")' !!! NO
 >> int i = Integer.parseInt("123\\$\\backslash\\$n")' !!! NO

 * convert a negative number from a string to an integer
 >> int i = Integer.parseInt("-123")'
 
MATHEMATICS 

TRANSENDENTAL NUMBERS ....

 * get an approximate value for PI 
 >> Math.PI

MODULUS ....
 
 The modulus is a mathematical idea investigated by Gauss amongst
 others. Java provides support for this through the '\\%' operator.
 
 * get the hundreds digit (0-9) from an integer
 >> i = 1234; i=i/100\\%10; 

CHARACTERS
 
 * get information about a character
 -----------------------------------
 import java.text.*;
 char cc = 'a';
 if (Character.isLowerCase(cc)) \{ //true \}
 ,,,

CHAR 

 The 'char' is the java primitive type for a character.

 >> char letter = 'a';
 >> char c = 'a' + 4; (c='e')

 * implicitly cast a 'char' to an integer
 >> char c = 'A'; int i = 4 + c;

 * Implicit casts to integer are NOT allowed in methods calls
 >> Test.doo(25); !!! no if "doo(char c)"

 * greater/less than comparisons with 'char' type is ok
 >> char c = 'A'; if (c <= 'B') \{\}
 >> 'a'=97, 'A'=65

 * check if a char is a lower case roman letter (not a good way)
 >> lower case letter: if ((c >= 'a') \\&\\& (c <= 'z'))

 * Convert case
 >> char c = Character.toLowerCase('A');
 >> char c = Character.toUpperCase('a');

 Convert a decimal digit to a character
 >> char c = Character.forDigit(4, 10);

BOOLEAN VALUES 

 A Boolean value is either true or false, and nothing else. In Java
 there is both a primitive type 'boolean' with a little b and 
 a 'wrapper' object 'Boolean' with a big B.

 * initialize a boolean array (all element false)
 >> boolean[] array = new boolean[size];

 * initialize a boolean array to true
 -------------------------------------------------------------
 Boolean[] array = new Boolean[size];
 Arrays.fill(array, Boolean.TRUE);
 ,,,

UNICODE 

 Unicode is an important standard for mapping characters from any human
 language writing system or symbol system to 'code points' which are
 basically numbers.

 One of the great strength of java is that it was designed 
 with the unicode character set in mind. However a java 'char' primitive
 type is a 16 bit value. This means that a char or Character value
 can only contain unicode character in the BMP (Basic Multilingual Plane),
 not supplementary characters. A java 'int' value can contain any
 Unicode code point.

 On a Linux system the Droid Sans Fallback font seems to have the largest 
 number of glyphs and therefore is the font to use for displaying
 weird and wonderful characters


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents useful Unicode Character methods
 .. getName() - gets the unicode descriptive name (since jre 1.7) 
 ..

 The code below progressively adds glyphs to a JPanel and updates
 the panel with revalidate(). For some reason panel.setVisible() 
 must be called before maximising the window with Frame.MAXIMIZED\\_BOTH 
 Adding the JLabels while the JPanel is visible is much slower than
 adding them all before it is visible, but the application remains
 responsive.

 * displays some unicode characters in a grid, with descriptions
 --------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class Glyphs \{ public static void main(String[] args) \{
 long startTime = System.currentTimeMillis();
 JFrame t = new JFrame();
 Font font; JLabel label;
 String name = new String();
 JPanel p = new JPanel(new GridLayout(0, 10));
 font = new Font("Droid Sans Fallback", Font.PLAIN, 30);
 t.getContentPane().add(new JScrollPane(p));
 t.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);
 t.setVisible(true);
 t.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 String tipText;
 for (int i = (int)Character.MIN\\_VALUE; i < (int)Character.MAX\\_VALUE - 20000; i++)
 \{
 if (font.canDisplay(i)) \{
 label = new JLabel("" + (char)i); label.setFont(font);
 tipText = String.format("decimal: \\%d", i);
 //jre1.7: "decimal: \\%d name: \\%s", i, Character.getName(i));
 label.setToolTipText(tipText);
 p.add(label); p.revalidate();
 \}
 \}
 long endTime = System.currentTimeMillis();
 long loadTime = endTime - startTime;
 t.setTitle("glyphs displayed in: " + loadTime + " miliseconds");
 \}
 \}
 ,,,

 The code above takes about a minute to display on a modern
 laptop.


SPECIFYING UNICODE CHARACTERS ....

 It is possible to use the backslash u (\\$\\backslash\\$u) notation to specify a 
 unicode character. This is an alternative to actually 'pasteing' in
 the character itself.

 The \\$\\backslash\\$u notation uses the unicode 'code point' (which is a hexadecimal
 number). 

 * initialise the 'symbol' variable to the 'fleur-de-lys' character
 >> String symbol = "\\$\\backslash\\$u269c";
 >> String symbol = "\\$\\backslash\\$u269C"; \\#\\#(the same, upper or lower hex letters)

 * initialise a character to the fleur-de-lys
 >> char c = '\\$\\backslash\\$u269c'; 

 * display the fleur-de-lys and snowman glyphs in a JLabel
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.Font;
 public class UniLabel \{
 public static void main(String[] args) \{
 JLabel l = new JLabel("\\$\\backslash\\$u269C \\$\\backslash\\$u2603");
 l.setFont(new Font("FreeSerif", Font.PLAIN, 40));
 JOptionPane.showMessageDialog(null, l);
 \}
 \}
 ,,,

 The static method below is generally useful when trying to 
 display a glyph, but is a tad slow.

 * get a list of fonts which contain a glyph
 -------------------------------------------------------------
 import java.util.*;
 import java.awt.*;
 public class FontHelp \{
 public static String[] getGlyphFonts(char c) \{
 java.util.List<String> names = new ArrayList<String>();
 GraphicsEnvironment gre =
 GraphicsEnvironment.getLocalGraphicsEnvironment();
 for (Font f: gre.getAllFonts()) \{
 if (f.canDisplay(c)) names.add(f.getName());
 \}
 return (String[])names.toArray(new String[names.size()]);
 \}
 public static void main(String[] args) \{
 for (String s: FontHelp.getGlyphFonts('\\$\\backslash\\$u269c'))
 System.out.println(s);
 \}
 \}
 ,,,

MATCHING UNICODE CHARACTERS ....

 We can use java regular expressions (since j2se 1.4 -febuary 2002) to 

 @@ \url{http://www.regular-expressions.info/unicode.html}
 A good explanation of matching unicode letters in regular expression

 * match all characters in the Mongolian unicode block
 >> \\$\\backslash\\$p\{InMongolian\} 

 * match any unicode letter
 >> \\$\\backslash\\$p\{L\}\\$\\backslash\\$p\{M\}*

 * determine if a char/codePoint is CJKV (Chinese, Japanese, Korean and Vietnamese) ideograph, as defined by the Unicode Standard (since Java 1.7)
 >> static boolean isIdeographic(int codePoint)

UNICODE CHARACTER BLOCKS

 The unicode code blocks are part of the unicode standard, and group
 together characters which have a similar function or usage. For example
 characters which form part of a particular language writing system are
 grouped together in a block.

 Code blocks seem to be contiguous in the unicode standard but there seems
 no simple way to get the block starting code point (character) nor the
 last code point. This means that we may have to interate over all 
 characters to retrieve the characters belonging to that block.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents Character.UnicodeBlock methods
 .. forName(String blockName) - returns the block with the given name.
 .. of(char c) - returns the block containing the given character, or null 
 .. of(int codePoint) - the same but for a codepoint not a Character.
 ..

 * get a block by name
 >> Character.UnicodeBlock b = Character.UnicodeBlock.forName("BasicLatin");

 * print the name of the unicode block (calls toString() implicitly)
 ------------------------------------
 public class UnicodeBlocks \{
 public static void main(String[] args) \{
 System.out.println("block name: " + Character.UnicodeBlock.CHEROKEE);
 \}
 \}
 ,,,


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents permissable block names
 .. "Basic Latin" - official unicode name defined in 'blocks-<ver>.txt'
 .. "BasicLatin" - official name but with no spaces
 .. "BASIC\\_LATIN" - java class name
 .. "basic\\_latin" - case insensitive java class name
 ..

 The following works on my Linux Mint system, with gnome. Whether 
 you can see the glyphs or not will probably depend on the console
 ('command line') having a suitable font installed.

 * displays some greek unicode characters 
 --------------------------------------------------
 public class GreekGlyphs \{
 public static void main(String[] args) \{
 long startTime = System.currentTimeMillis();
 int ii = (int)Character.MIN\\_VALUE;
 while (ii <= (int)Character.MAX\\_VALUE)
 \{
 if (Character.UnicodeBlock.GREEK == Character.UnicodeBlock.of(ii)) 
 \{
 System.out.print(String.format("\\%d: \\%c, ", ii, (char)ii));
 //jre1.7: "decimal: \\%d name: \\%s", i, Character.getName(i));
 if ((ii\\%5) == 0) System.out.println("");
 \}
 ii++;
 \}
 long endTime = System.currentTimeMillis();
 long loadTime = endTime - startTime;
 System.out.println(
 "glyphs displayed in: " + loadTime + " miliseconds");
 \}
 \}
 ,,,

 As a side note about string matching, there is not a huge difference
 in performance between string.matches() and string.startsWith() in
 the code below (400ms compared to 700ms on my asus netbook)

 * displays characters from various miscelaneous symbol unicode blocks
 --------------------------------------------------
 public class SymbolGlyphs \{
 public static void main(String[] args) \{
 long startTime = System.currentTimeMillis();
 Character.UnicodeBlock block = null;
 int ii = (int)Character.MIN\\_VALUE;
 while (ii <= (int)Character.MAX\\_VALUE) \{
 ii++;
 block = Character.UnicodeBlock.of(ii);
 if (block == null) continue;
 if (block.toString().startsWith("MISC")) \{
 System.out.print(String.format("\\%d: \\%c, ", ii, (char)ii));
 if ((ii\\%5) == 0) System.out.println("");
 \}
 \}
 long endTime = System.currentTimeMillis();
 long loadTime = endTime - startTime;
 System.out.println(
 "glyphs displayed in: " + loadTime + " miliseconds");
 \}
 \}
 ,,,
 
 The default font on my linux system (Dialog, 12pt) doesnt have many
 glyphs, unfortunately. Another problem is that one needs to work out
 which font will be able to display the glyph, and this may change from
 computer to computer. Also if the font doesnt exist, no exception is
 thrown in the font constructor, the font just defaults to 'dialog' (on a
 linux system).

 * displays characters from miscelaneous symbol blocks in a JPanel
 --------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class SymbolPanel extends JPanel \{
 String blockPrefix;
 Font font;
 public SymbolPanel(String blockPrefix) \{
 super(new GridLayout(0, 4)); 
 this.blockPrefix = blockPrefix;
 this.font = new Font("FreeSerif", Font.PLAIN, 50);
 this.showGlyphs();
 \}
 private void showGlyphs() \{
 // first remove all JLabels, but how?
 long startTime = System.currentTimeMillis();
 Character.UnicodeBlock block = null;
 int ii = (int)Character.MIN\\_VALUE;
 JLabel label = new JLabel();
 int missingGlyphs = 0;
 GraphicsEnvironment gr = 
 GraphicsEnvironment.getLocalGraphicsEnvironment();
 boolean isFound = false;
 while (ii <= (int)Character.MAX\\_VALUE) \{
 ii++;
 block = Character.UnicodeBlock.of(ii);
 if (block == null) continue;
 if (block.toString().startsWith(this.blockPrefix)) \{
 // search for a font which has a glyph for this character
 /*
 // this code is working but produces ugly results
 if (!this.font.canDisplay(ii)) \{
 isFound = false; 
 for (Font f: gr.getAllFonts()) \{
 if (f.canDisplay(ii)) \{
 if (f.getFamily().equals("unifont")) continue;
 this.font = f.deriveFont(Font.PLAIN, 50); isFound = true;
 System.out.println("using font:" + this.font.toString());
 break;
 \}
 \}
 \}
 */ 
 if (this.font.canDisplay(ii)) \{
 label.setFont(this.font);
 label.setBorder(new RoundedBorder(Color.gray, 4));
 label = new JLabel(" " + (char)ii); 
 label.setToolTipText(String.format(
 "<html><big><big><ul>" +
 "<li>Font-family: \\%s<li>font-size, \\%d<li>decimal: \\%d</ul>",
 this.font.getFamily(), this.font.getSize(), ii));
 this.add(label);
 \}
 else missingGlyphs++; 
 \}
 \}
 long endTime = System.currentTimeMillis();
 long loadTime = endTime - startTime;
 label = new JLabel(String.format(
 "time: \\%d ms, missing: \\%d", 
 loadTime, missingGlyphs));
 this.add(label);
 \}

 public void copy() \{
 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
 StringSelection testData = new StringSelection("Clipboard testing");
 c.setContents(testData, testData);
 \}

 public static void main(String[] args) \{
 System.setProperty("awt.useSystemAAFontSettings","on");
 SymbolPanel p = new SymbolPanel("DING");
 JFrame f = new JFrame();
 f.add(new KeyScrollPane(p));
 f.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);
 f.setVisible(true);
 f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 \}
 \}
 ,,,

 The code below is freezing the computer.

 * displays some unicode characters from the 'greek' code block 
 --------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class UnicodeBlocks \{
 public static void main(String[] args) \{
 long startTime = System.currentTimeMillis();
 JFrame t = new JFrame();
 Font font;
 JLabel label;
 String name = new String();
 JPanel p = new JPanel(new GridLayout(0, 10));
 font = new Font("Droid Sans Fallback", Font.PLAIN, 30);
 t.getContentPane().add(new JScrollPane(p));
 t.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);
 t.setVisible(true);
 t.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 String tipText;
 for (int i = (int)Character.MIN\\_VALUE; i < (int)Character.MAX\\_VALUE - 20000; i++)
 \{
 if (font.canDisplay(i) \\&\\&
 (Character.UnicodeBlock.GREEK == Character.UnicodeBlock.of(i))) \{
 \{
 label = new JLabel("" + (char)i);
 label.setFont(font);
 tipText = String.format("decimal: \\%d", i);
 //jre1.7: "decimal: \\%d name: \\%s", i, Character.getName(i));
 label.setToolTipText(tipText);
 p.add(label);
 p.revalidate();
 \}
 \}
 long endTime = System.currentTimeMillis();
 long loadTime = endTime - startTime;
 t.setTitle("glyphs displayed in: " + loadTime + " miliseconds");
 \}
 \}
 \}
 ,,,

 By iterating over all characters (or more precisely, Unicode code
 points) it is possible to check each to find its Unicode Block:
 
 * iterate over all characters in a unicode block
 ---------------
 // Character.UnicodeBlock block = Character.UnicodeBlock.ARABIC;

 public static void main(String[] args) \{
 Set<Character> arabicChars = 
 getUnicodeBlock(Character.UnicodeBlock.ARABIC);
 Set<Character> bengaliChars = 
 getUnicodeBlock(Character.UnicodeBlock.BENGALI);
 \}
 
 private static Set<Character> getUnicodeBlock(final Character.UnicodeBlock block) \{
 final Set<Character> chars = new HashSet<Character>();
 for (int codePoint = Character.MIN\\_CODE\\_POINT; codePoint <= Character.MAX\\_CODE\\_POINT; codePoint++) \{
 if (block == Character.UnicodeBlock.of(codePoint)) \{
 chars.add((char) codePoint);
 \}
 \}
 return chars;
 \}
 ,,,

APP TO SHOW GLYPHS ....

 A simple application which displays glyphs in a block and
 copies the glyph to the system clipboard when the button is pressed.

 ideas:
 It would be nice to append to the clipboard, but thats a bit more
 work. An information label at the bottom would be nice: load time,
 number of glyphs. Show all fonts in which the glyph exists.
 Use reflection to interate through the unicode blocks and make 
 a combobox to choose them.

 * displays characters from symbol blocks in a JPanel
 --------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 import java.awt.event.*;
 import java.awt.datatransfer.*;
 public class GlyphApp extends JPanel implements ActionListener \{
 String blockPrefix;
 JTextField blockField;
 JPanel glyphPanel;
 Font font;

 public GlyphApp() \{
 super(new BorderLayout(20, 20)); 
 this.blockField = new JTextField("dingbat");
 this.blockField.setFont(new Font("Georgia", Font.ITALIC, 22));
 this.blockField.addActionListener(this);
 //this.blockPrefix = blockPrefix;
 this.font = new Font("FreeSerif", Font.PLAIN, 50);
 this.glyphPanel = new JPanel(new GridLayout(0, 4));
 this.add(this.blockField, BorderLayout.NORTH);
 this.add(new KeyScrollPane(this.glyphPanel), BorderLayout.CENTER);
 this.showGlyphs();
 \}
 public void actionPerformed(ActionEvent e) \{
 if (e.getSource() instanceof JButton) \{
 JButton b = (JButton) e.getSource();
 System.out.println("button push:" + b.getText());
 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
 StringSelection ss = new StringSelection(b.getText());
 c.setContents(ss, ss);
 \}
 else if (e.getSource() == this.blockField) \{
 System.out.println("enter press");
 this.removeGlyphs(); this.revalidate();
 this.showGlyphs(); this.revalidate();
 \}
 \}
 /** removes all the buttons containing glyphs */
 private void removeGlyphs() \{
 for (Component c: this.glyphPanel.getComponents()) \{
 if (c instanceof JButton) this.glyphPanel.remove(c);
 \}
 \}
 private void showGlyphs() \{
 // first remove all JLabels
 // this.glyphPanel.removeAll();
 long startTime = System.currentTimeMillis();
 Character.UnicodeBlock block = null;
 int ii = (int)Character.MIN\\_VALUE;
 JButton button = new JButton();
 int missingGlyphs = 0;
 GraphicsEnvironment gr = 
 GraphicsEnvironment.getLocalGraphicsEnvironment();
 boolean isFound = false;
 while (ii <= (int)Character.MAX\\_VALUE) \{
 ii++;
 block = Character.UnicodeBlock.of(ii);
 if (block == null) continue;
 String pattern = "(?i).*" + this.blockField.getText() + ".*";
 if (block.toString().matches(pattern)) \{
 // search for a font which has a glyph for this character
 /*
 // this code is working but produces ugly results
 if (!this.font.canDisplay(ii)) \{
 isFound = false; 
 for (Font f: gr.getAllFonts()) \{
 if (f.canDisplay(ii)) \{
 if (f.getFamily().equals("unifont")) continue;
 this.font = f.deriveFont(Font.PLAIN, 50); isFound = true;
 System.out.println("using font:" + this.font.toString());
 break;
 \}
 \}
 \}
 */ 
 if (this.font.canDisplay(ii)) \{
 button.setFont(this.font);
 button.setBorder(new RoundedBorder(Color.gray, 4));
 button = new JButton(" " + (char)ii); 
 button.addActionListener(this);
 button.setToolTipText(String.format(
 "<html><big><big><ul>" +
 "<li>Font-family: \\%s<li>font-size, \\%d<li>decimal: \\%d" +
 "<li>hexadecimal: \\%x</ul>",
 this.font.getFamily(), this.font.getSize(), ii, ii));
 this.glyphPanel.add(button);
 \}
 else missingGlyphs++; 
 \}
 \}
 long endTime = System.currentTimeMillis();
 long loadTime = endTime - startTime;
 button = new JButton(String.format(
 "time: \\%d ms, missing: \\%d", 
 loadTime, missingGlyphs));
 this.glyphPanel.add(button);
 \}

 public static void main(String[] args) \{
 System.setProperty("awt.useSystemAAFontSettings","on");
 JFrame f = new JFrame("Unicode Block Explorer");
 f.add(new GlyphApp());
 f.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);
 f.setVisible(true);
 f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 \}
 \}
 ,,,

GOTCHAS FOR UNICODE CHARACTER BLOCKS ....

 The Character.UnicodeBlock.of(...) methods can return null, 
 throwing around some nullpointer exceptions unless you are on
 your toes.

SYMBOLS IN UNICODE ....

 Many symbols are contained in the dingbats, and miscelaneous unicode
 blocks.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents some interesting symbols
 .. u+2708, dec:9992 - airplane
 ..

 * display a character/codepoint in all fonts which have a glyph 
 --------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class CodePointPanel extends JPanel \{
 int codePoint;
 Font font;
 public CodePointPanel(int codePoint) \{
 super(new GridLayout(0, 4));
 this.codePoint = codePoint;
 this.showGlyphs();
 \}
 private void showGlyphs() \{
 long startTime = System.currentTimeMillis();
 int missingGlyphs = 0;
 JLabel label = new JLabel();
 GraphicsEnvironment gr =
 GraphicsEnvironment.getLocalGraphicsEnvironment();
 Character.UnicodeBlock block = null;
 block = Character.UnicodeBlock.of(this.codePoint);
 for (Font font: gr.getAllFonts()) \{
 if (font.canDisplay(this.codePoint)) \{
 font = font.deriveFont(Font.PLAIN, 50);
 label.setFont(font);
 label.setBorder(new RoundedBorder(Color.gray, 4));
 label = new JLabel(" " + (char)this.codePoint);
 label.setToolTipText(String.format(
 "<html><big><big><ul>" +
 "<li>Font-family: \\%s<li>font-size, \\%d" + 
 "<li>Unicode Block: \\%s<li>decimal: \\%d</ul>",
 font.getFamily(), font.getSize(), 
 block.toString(), this.codePoint));
 this.add(label);
 \}
 else missingGlyphs++;
 \}
 
 long endTime = System.currentTimeMillis();
 long loadTime = endTime - startTime;
 label = new JLabel(String.format("time: \\%d ms, missing: \\%d",
 loadTime, missingGlyphs));
 this.add(label);
 \}
 
 public static void main(String[] args) \{
 System.setProperty("awt.useSystemAAFontSettings","on");
 CodePointPanel p = new CodePointPanel(9992);
 JFrame f = new JFrame();
 f.add(new KeyScrollPane(p));
 f.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);
 f.setVisible(true);
 f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 \}
 \}
 ,,,

INTERESTING UNICODE CHARACTERS ....

 \url{http://unicode.org/Public/UNIDATA/NamesList.txt}
 the official list of unicode character names. 
 Helpful for finding something

 U+2620 skull and cross bones
 U+2603 snow man
 U+2368 APL FUNCTIONAL SYMBOL TILDE DIAERESIS, looks like a sad face
 U+0E5B a spirally curly symbol, thai character khomut

 @@ \url{http://coolunicodecharacters.blogspot.com/}
 some interesting fancy letter unicode characters

 @@ \url{http://fsymbols.com/}
 graphical unicode characters, such as an aeroplane etc organised by 
 type. Have to look at the source code for the numbers

 The miscelaneous technical page has some clock symbols

 \\#592 to \\#780 linguistic phonetic symbols

 note:
 jdk7 has a String getName(int codepoint) function 
 that will convert a codepoint into its official Unicode name.

STRINGS

 Text (which is a series of characters) is referred to as a 'string'
 in nearly all programming languages.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents useful classes for dealing with strings
 .. String - the most important class, has lots of good methods
 .. StringBuilder - for concatenating strings progressively
 .. StringBuffer - exactly like StringBuilder, but synchronized
 ..

 * declare a private string constant in a class file
 >> private static final String PACKAGE = "javax.swing.";
 
 * determine of a string contains a character
 >> if ("abcd".indexOf('e') == -1) System.out.println("no 'e' in string");

 * append something to a string (but use a StringBuilder instead)
 >> String text = "tree"; text += ": "; 
 
 * use regular expressions to check if a string is an integer
 >> boolean b = java.util.regex.Pattern.matches("\\^\\$\\backslash\\$\\$\\backslash\\$d*\\$", "1245");

 * write a string 'text' to a file 'test.txt'
 -------------------------------------------------------------
 PrintWriter out = new PrintWriter("test.txt");
 out.println(text); out.flush(); out.close();
 ,,,

 StringBuilder (since Java 1.5) is not synchronized, and is therefore more
 efficient, but not to be used in threads. StringBuffer can be used in
 threads. They have the same methods. Use StringBuilder unless you really
 are trying to share a buffer between threads

 * insert integers at the beginning of a StringBuilder (inefficient)
 ----------------------
 StringBuilder sb = new StringBuilder();
 for (int i=0;i<100;i++) \{
 sb.insert(0, Integer.toString(i));
 \}
 ,,,

 >> if (s.equals("tree") \{\}
 >> if (s.equalsIgnoreCase("trEE")) \{\}
 >> t = "TTR".toLowerCase();
 >> t = "TTR ".trim();
 >> t = "TTR".indexOf('R');
 >> t = "TTR".indexOf("TT");

 Starts with and ends with
 >> if ("big".startsWith("bi"))
 >> if ("big".endsWith("ig"))

 Matches
 >> if ("009".matches("\\$\\backslash\\$\\$\\backslash\\$d")) System.out.println("\\$\\backslash\\$n\\$\\backslash\\$nyes");

 Split a string into words
 >> String[] ss = ("Some new words".split("\\$\\backslash\\$\\$\\backslash\\$s+")); System.out.println(ss[1]);

 Substrings
 >> "big".substring(0,2) == "bi" 

ANALYSING STRINGS ....

 * check if the 2nd character of a String is uppercase
 >> Character.isUpperCase("hEllo".charAt(1))
 
PARSING STRINGS ....

 The topic of parsing is a large one, and probably not well understood
 by many people. Yet it is one of the most fundamental programming 
 processes. Here we will not go into 'pumping lemmas' context free
 languages or push-down automata. No no no. We will just be dealing
 with simple cases, using regular expression, tokenising, etc.

 * process each word in a string using split()
 -------------------------------------------------------------
 String s = "word1 word2 word3";
 for (String word : s.split())
 \{
 processWord(word);
 \}
 ,,,
 
 The use of StringTokenizer below may well be outdated.

 * process each word using a StringTokenizer
 ----------------------------------------------
 String aString = "word1 word2 word3";
 StringTokenizer parser = new StringTokenizer(aString);
 while (parser.hasMoreTokens()) \{
 processWord(parser.nextToken());
 \}
 ,,,

SPLITTING STRINGS ....

 * get 2 values from a JOptionPane input dialog using split
 -------------------------------------------------------------
 import javax.swing.JOptionPane;
 public class SplitDialogResult \{
 public static void main(String[] args) \{
 String namepass = JOptionPane.showInputDialog(
 "enter 'name:password'", "<name:password>");
 String[] info = namepass.split(":", 2);
 System.out.format("name:\\%s\\$\\backslash\\$npass:\\%s\\$\\backslash\\$n", info[0], info[1]);
 \}
 \}
 ,,,

DECLARING STRINGS ....

 >> String r, s, t;
 
 >> String s = new String("cat"); 

CONVERTING TO AND FROM STRINGS ....

 * convert a String to a double
 >> double d = Double.valueOf("2.333").doubleValue();

 * convert an integer to a String
 ---------------------------------
 public class ConvertInteger \{
 public static void main(String[] args) \{
 String s = String.valueOf(200);
 System.out.println("length:" + s.length());
 \}
 \}
 ,,,

 * convert a double to a String
 >> String s = String.valueOf(2.333);

 * convert a string to an integer (throws NumberFormatException)
 >> int i = Integer.parseInt("124")

 * parse a string with whitespace into an integer
 >> int test= Integer.parseInt(s.trim());

SUBSTITUTING IN STRINGS ....
 
 * make string capital case
 >> name = Character.toUpperCase(name.charAt(0)) + name.substring(1);

 * substitute in strings
 -----------------------
 String t = new String("Content: one"
 String s = t.replace("Content:", "").replace("o", "O");
 ,,,
 
STRING BUFFERS ....

 * create and append something to a string buffer
 ------------------------------------------------
 StringBuffer s = new StringBuffer("");
 s.append("hi");
 ,,,

CONCATENATING STRINGS ....

 One can use either StringBuffer or StringBuilder to progressively
 add things to a string. Or else the format() method is similar
 to the c language 'sprintf' function.

 * concatenate two strings to create a third
 >> String s = string1.concat(string2);

 * using printf style format strings, for those who live in the 80s
 >> String.format("http://\\%s/manager/list", host + ":8080"));

 * format an integer or a long value
 >> String new = String.format("The rename status is (\\%d)", RENAME\\_SUCCEEDED);

 * use multiple values with String.format
 >> String new = String.format("\\%s is \\%d years old", "James", 45);

 * print a formatted string to standard output 
 ------------------------------------
 public class FormatPrint \{
 public static void main(String[] args) \{
 System.out.format("\\%s is \\%d years old", "James", 45);
 \}
 \}
 ,,,


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents summary of the available format specifiers:
 \\%c character
 \\%d decimal (integer) number (base 10)
 \\%e exponential floating-point number
 \\%f floating-point number
 \\%i integer (base 10)
 \\%o octal number (base 8)
 \\%s a string of characters
 \\%u unsigned decimal (integer) number
 \\%x number in hexadecimal (base 16)
 \\%\\% print a percent sign
 \\$\\backslash\\$\\% print a percent sign
 ...

 * concatenate 2 strings
 >> "A" + "B"

 * concatenate a string and an integer
 >> "A" + 2

COMPARING STRINGS ....

 Comparing strings
 >> System.out.println("this".compareTo("this")); // prints 0
 >> System.out.println("zed".compareTo("this")); // prints 6
 >> System.out.println("us".compareTo("this")); // prints 1
 >> System.out.println("this".compareTo("us")); // prints -1
 >> System.out.println("this".compareTo("thks")); // prints -2

REGULAR EXPRESSIONS

 @@ java.util.regex

 Regular expressions are a way of describing text patterns. Regular
 expressions are also a way of defining a regular language which is the
 simplest type of formal language in the Chomski hierarchy of languages.
 These patterns have great significance mathematically and linguistically,
 but they are also of considerable practical use to programmers carrying
 out everyday tasks involving text processing.

 Regular expressions have been available in Unix systems for many years
 (for example with grep, awk, sed) but became popularised through the Perl
 language and the need to do text processsing in (cgi) web applications.

 With java, special character classes (such as \\$\\backslash\\$w) when written in
 string literals (which is nearly always) need to be 
 escaped with 2 backslashes (for example "\\$\\backslash\\$\\$\\backslash\\$w") which looks messy.

 * replace all text between tree and leaf with "new" (this is 'non-greedy')
 >> String ResultString = subjectString.replaceAll("(tree).*?(leaf)", "\\$1new\\$2");

 The \\$1 and \\$2 are back references. The .*? is non greedy matching

 * double all sequences of "a"s using a compiled regular expression
 ------------------
 Pattern p = Pattern.compile("(a+)");
 String ret = p.matcher(input).replaceAll("\\$1 \\$1");
 ,,,

 Compiling the regular expression or pattern is supposed to be more
 efficient or provide better runtime performance.

 * match any sequence of characters which are not word chars or \\# or \\$
 >> Pattern p = Pattern.compile("\\^[\\$\\backslash\\$\\$\\backslash\\$w\\#\\$]+\\$");

 * use a matcher to print each occurence of the 2nd subgroup found
 -----------------------------------------
 String input = " ;1=2011-10-23T16:16:53+0530; 2=2011-10-23T16:17:53+0530;3=2011-10-23T16:18:53+0530;4=2011-10-23T16:19:53+0530;";
 Pattern p = Pattern.compile("(;\\$\\backslash\\$\\$\\backslash\\$d+?)?=(.+?);");
 Matcher m = p.matcher(input);
 while(m.find())\{
 System.out.println(m.group(2));
 \}
 ,,,

 * match a string starting with a digit, non-word char or whitespace char
 -------------
 Pattern p = Pattern.compile("\\^\\$\\backslash\\$\\$\\backslash\\$d|\\^\\$\\backslash\\$\\$\\backslash\\$W|\\^\\$\\backslash\\$\\$\\backslash\\$s");
 Matcher m = p.matcher("stack overflow"); // no matches with this input
 ,,,

BASIC USAGE ....

 * A typical invocation using Pattern, Matcher and matcher.matchers() 
 -------------------------------------------------------------
 Pattern p = Pattern.compile("a*b");
 Matcher m = p.matcher("aaaaab");
 boolean b = m.matches();
 ,,,
 
 * a simple usage with the convenience method
 >> boolean b = Pattern.matches("a*b", "aaaaab");

METACHARACTERS ....

 The meta characters supported by java regular expressions are 
 <([\{\\$\\backslash\\$\\^-=\\$!|]\})?*+.>

CHARACTER CLASSES ....


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents examples of character classes
 .. [\\^01] - matches any character which is not 0 or 1
 .. [0-2[6-8]] - matches 012678, this is a union class
 .. [0-4\\&\\&[3-9]] - matches only 3 or 4, this is an intersection class
 .. [1-6\\&\\&[\\^345]] - matches 1,2 or 6, a subtraction class
 ..


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents predefined character classes
 .. \\$\\backslash\\$d A digit: [0-9]
 .. \\$\\backslash\\$D A non-digit: [\\^0-9]
 .. \\$\\backslash\\$s A whitespace character: [ \\$\\backslash\\$t\\$\\backslash\\$n\\$\\backslash\\$x0B\\$\\backslash\\$f\\$\\backslash\\$r]
 .. \\$\\backslash\\$S A non-whitespace character: [\\^\\$\\backslash\\$s]
 .. \\$\\backslash\\$w A word character: [a-zA-Z\\_0-9]
 .. \\$\\backslash\\$W A non-word character: [\\^\\$\\backslash\\$w]
 ..


GROUPS ....


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents examples of groups
 .. (it)\{3\} - matches 'ititit'
 ..

BACKREFERENCES ....


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents examples of backreferences
 .. (it)\\$\\backslash\\$1 - matches the string 'itit'
 ..

MATCHING PATTERNS ....

 The String.matches() and Pattern.matches() methods both match
 on all of the supplied string- in other words
 "hello".matches("lo") returns false but "hello".matches(".*lo")
 will return true. This may be surprising to the unsuspecting.

 * check if '1245' contains only digits. 
 >> boolean b = java.util.regex.Pattern.matches("\\^\\$\\backslash\\$\\$\\backslash\\$d*\\$", "1245");

 The code above is a simple way to perform a pattern match check
 on a string, using the static method.

 * a matcher loop example
 -------------------------------------------------------------
 import java.util.regex.Pattern;
 import java.util.regex.Matcher;
 public class MatcherLoop \{
 public static void main(String[] args) \{
 Pattern pattern =
 Pattern.compile("[\\^ ]*");
 Matcher matcher =
 pattern.matcher("one fine day in the forest");
 boolean found = false;
 while (matcher.find()) \{
 System.out.format(
 "Found the text '\\%s' starting at " +
 "index \\%d and ending at index \\%d.\\%n",
 matcher.group(), matcher.start(), matcher.end());
 found = true;
 \}
 if (!found) System.out.format("No match found.\\%n");
 \}
 \}
 ,,,

 * see if a string starts with a space (this prints 'false')
 >> System.out.println("A big tree".matches("\\^ .*")); 

 * test if a string starts with a 'word' character (letter)
 >> System.out.println("A big tree".matches("\\^\\$\\backslash\\$\\$\\backslash\\$w.*"));

 This prints 'true'

REPLACING PATTERNS ....

 * Replace all whitespace with tab characters
 >> System.out.println("the green grass".replaceAll("\\$\\backslash\\$\\$\\backslash\\$s+", "\\$\\backslash\\$t"));

 * Replace all whitespace with a dot '.' 
 >> System.out.println("the green grass".replaceAll("\\$\\backslash\\$\\$\\backslash\\$s+", "."));

 * split a string into words using the 'split' method 
 ----------------------------------------------------
 public class Test
 \{
 public static void main(String[] args) \{
 String[] splitString = ("Some new words".split("\\$\\backslash\\$\\$\\backslash\\$s+"));
 for (String word : splitString) \{
 System.out.println(word);
 \}
 \}
 \}
 ,,,

 * use compiled patterns and matching loops
 ------------------------------------------
 Pattern pattern = Pattern.compile("\\$\\backslash\\$\\$\\backslash\\$w+");
 Matcher matcher = pattern.matcher("some test string");
 
 while (matcher.find()) \{
 System.out.print("Start index: " + matcher.start());
 System.out.print(" End index: " + matcher.end() + " ");
 System.out.println(matcher.group());
 \}
 ,,,

 * replace all occurances of whitespace with tabs
 -----------------------------------------------
 Pattern pat = Pattern.compile("\\$\\backslash\\$\\$\\backslash\\$s+");
 Matcher m = pat.matcher("The green grass");
 System.out.println(m.replaceAll("\\$\\backslash\\$t"));
 ,,,


 * use the String built in pattern matching
 ------------------------------------------
 public class PatternTest \{
 public static final String S = 
 "This is my small example string for testing";
 public static void main(String[] args) \{
 System.out.println(S.matches("\\$\\backslash\\$\\$\\backslash\\$w.*"));
 String[] splitString = (S.split("\\$\\backslash\\$\\$\\backslash\\$s+"));
 for (String string : splitString) \{
 System.out.println(string);
 \}
 // Replace all whitespace with tabs
 System.out.println(S.replaceAll("\\$\\backslash\\$\\$\\backslash\\$s+", "\\$\\backslash\\$t"));
 \}
 \}
 ,,,

 * use compiled patterns and matching loops
 -------
 Pattern pattern = Pattern.compile("\\$\\backslash\\$\\$\\backslash\\$w+");
 Matcher matcher = pattern.matcher("some test string");
 
 // Check all occurances
 while (matcher.find()) \{
 System.out.print("Start index: " + matcher.start());
 System.out.print(" End index: " + matcher.end() + " ");
 System.out.println(matcher.group());
 \}
 ,,,

 * replace all occurance of whitespace with tabs
 ------------------------------------------------
 Pattern replace = Pattern.compile("\\$\\backslash\\$\\$\\backslash\\$s+");
 Matcher matcher2 = replace.matcher("some example string");
 System.out.println(matcher2.replaceAll("\\$\\backslash\\$t"));
 ,,,

COMPILED PATTERNS ....

 * compile a pattern to match without regard for letter case
 >> Pattern.compile("s+", Pattern.CASE\\_INSENSITIVE);
 
CASE INSENSITIVE MATCHING ....
 
 Before jdk 6update2 there were some problems with case insensitive
 matching for unicode characters in java regular expressions. 
 Namely UNICODE\\_CASE was equivalent to case insensitive matching.

 * create a case-insensitive pattern for Ascii characters only >jdk6u2
 >> Pattern p = Pattern.compile("YOUR\\_REGEX", Pattern.CASE\\_INSENSITIVE);

 * a case-insensitive pattern for Unicode characters
 >> Pattern p = Pattern.compile("YOUR\\_REGEX", Pattern.CASE\\_INSENSITIVE | Pattern.UNICODE\\_CASE);

 * case-insensitive matching on a String for ascii characters only
 >> "XYZxyz".matches("(?i)[a-z]+")
 
 * case-insensitive matching on a String for unicode characters >jdk6u2
 >> "XYZxyz".matches("(?iu)[a-z]+")

 * match 'green' and 'tree' case insensitively but only those words
 >> strText.Matches("(?i:green)[a-z ]+(?i:tree)" )

USER INPUT FROM THE CONSOLE

 * a loop to receive user input from the console
 -------------------------------------------------------------
 import java.io.Console;
 public class ConsoleLoop \{
 public static void main(String[] args) \{
 Console console = System.console();
 if (console == null) \{
 System.err.println("No console.");
 System.exit(1);
 \}
 while (true) \{
 String s = console.readLine("\\%nEnter your regex: ");
 boolean found = false;
 \}
 \}
 \}
 ,,,

UNICODE REGULAR EXPRESSIONS

 * match a range of unicode characters
 >> "[\\$\\backslash\\$\\$\\backslash\\$u00e0-\\$\\backslash\\$\\$\\backslash\\$u00e5]" 


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents unicode classes
 .. \\$\\backslash\\$*\\$\\backslash\\$\\$\\backslash\\$u0400-\\$\\backslash\\$\\$\\backslash\\$u04f9 - Cyrillic
 .. *\\$\\backslash\\$\\$\\backslash\\$u0080-\\$\\backslash\\$\\$\\backslash\\$u00ff - Latin-1 Supplement
 ..



PRINTING

 Java includes support for printing Java2D graphics and other
 information. 


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents relevant packages 
 .. java.awt.print.* - print Graphic2D objects
 .. javax.print.* - java print service, discover printers 
 ..


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents printing methods
 .. job.print() - send a job to the printer, cant detect paper jam
 .. job.printDialog() - show a print dialog for selecting copies etc
 ..

 * show a page setup dialog
 -------------------------------------------------------------
 PrinterJob pj = PrinterJob.getPrinterJob();
 PageFormat pf = pj.pageDialog(pj.defaultPage());
 ,,,

 * display a print dialog for setting number of copies etc 
 -------------------------------------------------------------
 import java.awt.print.*;
 ...
 PrinterJob job = PrinterJob.getPrinterJob();
 job.setPrintable(new HelloWorldPrinter());
 boolean doPrint = job.printDialog();
 ...
 class HelloWorldPrinter implements Printable \{ ... \}
 ,,,

 * a 2d printing example 
 -----------------------
 import java.awt.print.*;
 ...
 PrinterJob job = PrinterJob.getPrinterJob();
 job.setPrintable(new HelloWorldPrinter());
 boolean doPrint = job.printDialog();
 if (doPrint) \{
 try \{
 job.print();
 \} catch (PrinterException e) \{
 // The job did not successfully complete
 \}
 \}
 class HelloWorldPrinter implements Printable \{\}
 ,,,

 * a complete example of 2d printing
 -------------------------------------------------------------
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import java.awt.print.*;
 
 public class HelloWorldPrinter implements Printable, ActionListener \{
 public int print(Graphics g, PageFormat pf, int page) throws
 PrinterException \{
 if (page > 0) \{ 
 /* only one page, and page is zero-based */
 return NO\\_SUCH\\_PAGE;
 \}
 /* User (0,0) is typically outside the imageable area, so we must
 * translate by the X and Y values in the PageFormat to avoid clipping
 */
 Graphics2D g2d = (Graphics2D) g;
 g2d.translate(pf.getImageableX(), pf.getImageableY());
 /* Now we perform our rendering */
 g.drawString("Hello world!", 100, 100);
 // tell the caller that this page is part of the printed document 
 return PAGE\\_EXISTS;
 \}
 
 public void actionPerformed(ActionEvent e) \{
 PrinterJob job = PrinterJob.getPrinterJob();
 job.setPrintable(this);
 boolean ok = job.printDialog();
 if (ok) \{
 try \{ job.print(); \}
 catch (PrinterException ex) \{
 // The job did not successfully complete 
 ex.printStackTrace();
 \}
 \}
 \}
 
 public static void main(String args[]) \{
 JButton printButton = new JButton("Print Something");
 printButton.addActionListener(new HelloWorldPrinter());
 JFrame f = new JFrame("A Simple Printing Example");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.add("Center", printButton);
 f.pack(); f.setVisible(true);
 \}
 \}
 ,,,

SYSTEM INFORMATION 
 
SYSTEMPROPERTIES ....

 Using the System.getProperties() method we can retrieve some important
 information about the system on which the current java vm is running.
 unsigned Applets may only be able to access some of these system
 properties.

 * list all the system properties
 ------------------------------------
 public class SystemProps \{
 public static void main(String[] args) \{
 java.util.Properties p = System.getProperties();
 java.util.Enumeration en = p.propertyNames();
 while (en.hasMoreElements()) \{
 String name = (String) en.nextElement();
 System.out.format("\\%s: \\%s\\$\\backslash\\$n", name, p.getProperty(name));
 \}
 \}
 \}
 ,,,

OPERATING SYSTEM INTERACTION ....
 
 While Java is supposed to be a 'platform independant' system, at
 times one wants to know about, and use, features of the operating
 system on which the Java Runtime Engine is running.

 * display the operating system name and version
 ------------------
 import javax.swing.JOptionPane;
 public class OsType \{
 public static void main(String[] args) \{
 String info = String.format("os.name: \\%s, os.version: \\%s",
 System.getProperty("os.name"), System.getProperty("os.version"));
 JOptionPane.showMessageDialog(null, info);
 \}
 \}
 ,,,

EXECUTING PROGRAMS ....

 There may be an occasion when Java is unable to perform the task 
 that is required. In this case you may execute a program which is 
 installed in the underlying operating system from within your Java
 program.

 * start the 'notepad' text editor in a new thread
 >> proc = Runtime.getRuntime().exec("notepad");

 In the example below, the input and error streams should probably
 be closed in a 'finally' block.

 * a simple method to execute an 'external' program and read the output
 -------------------------------------------------------------
 import java.io.*;
 public class Sys \{
 public static void exec(String command) \{
 System.out.println(":> " + command);
 try \{
 String line;
 Process p = Runtime.getRuntime().exec(command);
 BufferedReader input =
 new BufferedReader(new InputStreamReader(p.getInputStream()));
 BufferedReader error =
 new BufferedReader(new InputStreamReader(p.getErrorStream()));
 while ((line = input.readLine()) != null) \{ 
 System.out.println(line);
 \}
 while ((line = error.readLine()) != null) \{ 
 System.out.println(line);
 \}
 input.close();
 error.close();
 \} catch (Exception err) \{ err.printStackTrace(); \}
 \}
 public static void main(String[] args) \{
 Sys.exec("javac -version");
 \}
 \}
 ,,,

 * run a system command with environment variable
 ----------------------------
 ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2");
 Map<String, String> env = pb.environment();
 env.put("VAR1", "myValue");
 env.remove("OTHERVAR");
 env.put("VAR2", env.get("VAR1") + "suffix");
 pb.directory("myDir");
 Process p = pb.start();
 ,,,

FILES AND DIRECTORIES


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents File information methods
 .. File[] listFiles() - returns all the files in the folder
 .. long length() - returns the size of the file in bytes
 .. boolean isDirectory() - if the file is a folder
 .. boolean isFile() - if the file is not a folder
 ..
 

\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents File manipulation methods
 .. boolean renameTo(File) - rename (move) the file 
 ..

 The code below requires the toURI() call because toURL() does not do
 its esaping work properly.

 * convert a file object to a URL 
 >> URL u = new File("hi.txt").toURI().toURL();
 
 * get the absolute file name from a relative name.
 --------------------------------------------------
 file = new File("dir" + File.separatorChar + "filename.txt");
 file = file.getAbsoluteFile(); // c:\\$\\backslash\\$temp\\$\\backslash\\$dir\\$\\backslash\\$filename.txt
 ,,, 

 * create a temporary file and delete it when the program exits
 --------------------
 File file = File.createTempFile("realhowto",".vbs");
 file.deleteOnExit();
 ,,,

 * get the size of a file in bytes
 ------------------------------------
 import java.io.File;
 public class FileSize \{
 public static void main(String[] args) \{
 File file = new File("FileSize.class");
 long length = file.length();
 System.out.format("The size of the file is \\%d bytes", length);
 \}
 \}
 ,,,

 * print a list of files in the current directory
 ----------------------------------------------
 import java.io.File;
 import java.util.Arrays;
 public class Test \{
 public static void main(String[] args) \{
 File[] ff = (new File(".")).listFiles();
 System.out.println(Arrays.toString(ff));
 \}
 \}
 ,,,

 * print a list of files and their sizes in the current directory
 ----------------------------------------------------------------
 import java.io.File;
 import java.util.Arrays;
 public class FileList \{
 public static void main(String[] args) \{
 File[] ff = (new File(".")).listFiles();
 for (File file: ff)
 System.out.println(file.toString() + " " + file.length());
 \}
 \}
 ,,,

 * open a file within a jar file or in the local file system.
 >> URL url = this.getClass().getClassLoader().getResource("gameover.wav");
 
 * print the java runtime engine folder
 -------------------------------------------------------------
 public class JavaHome \{
 public static void main(String[] args) throws Exception \{
 System.out.println(System.getProperty("java.home"));
 \}
 \}
 ,,,

 * List all files recursively 
 --------------------
 import java.io.*;
 public class FileList \{
 public static void listFiles(File dir) \{
 File[] files = dir.listFiles();
 if (files != null) \{
 for (File f : files) \{
 if (f.isDirectory()) \{
 listFiles(f);
 \}
 else \{ System.out.println(f.getPath()); \}
 \}
 \}
 \}
 public static void main(String[] args) throws Exception \{
 listFiles(new File("/usr/lib/jvm/java-6-sun/docs/api/java")); 
 \}
 \}
 ,,,

FILE PATHS ....

 The File object has a number of methods for extracting the path
 from an object.

 * file paths 
 -------------------------------------------------------------
 import java.io.*;
 public class NewFile \{
 public static void main(String[] args) throws IOException \{
 File f = new File("..");
 System.out.println(f.getCanonicalPath());
 \}
 \}
 ,,,

 * construct a file path in a cross-platform kind of way
 >> String file = "eg" + java.io.File.separator +"MyClass.java";

INITIALISING FILE OBJECTS ....

 The code below does not throw an exception but doesnt produce a 
 useful existing file.

 * you cant initialise a file with a url string string
 >> File f = new File("file:.") \\#\\#( no wrong )

 * try to initialise a file object 
 -------------------------------------------------------------
 import java.io.*;
 public class NewFile \{
 public static void main(String[] args) throws IOException \{
 File f = new File("..");
 System.out.println(f.getCanonicalPath());
 \}
 \}
 ,,,

SEARCHING FOR FILES ....

 * search files using grep
 >> Runtime.getRuntime().exec("grep", new String[]\{"-r"\}, <searchText>);
 
 The code below is possibly the simplest recursive file search class.
 It might be simpler to use a static method.

 * List all files in a folder tree that contain a string in the path 
 --------------------
 import java.io.*;
 public class FileList implements FileFilter \{
 String searchText;
 public FileList(String searchText) \{
 this.searchText = searchText;
 \}
 public boolean accept(File file) \{
 return ((file.getAbsolutePath().indexOf(this.searchText)>0) || 
 file.isDirectory());
 \}
 public void list(File dir) \{
 for (File f: dir.listFiles(this)) \{
 if (f.isDirectory()) \{ this.list(f); \}
 else System.out.println(f.getPath());
 \}
 \}
 public static void main(String[] args) throws Exception \{
 File dir = new File("/home/");
 FileList searcher = new FileList(".mp3");
 searcher.list(dir);
 \}
 \}
 ,,,

 * List all files recursively that contain a string in the path 
 --------------------
 import java.io.*;
 public class FileList \{
 public static void list(File dir, final String filter) \{
 FileFilter ff = new FileFilter()\{
 public boolean accept(File file) \{
 return ((file.getAbsolutePath().indexOf(filter)>0) || 
 file.isDirectory());
 \}
 \};
 File[] files = dir.listFiles(ff);
 if (files != null) \{
 for (File f : files) \{
 if (f.isDirectory()) \{ FileList.list(f, filter); \}
 else System.out.println(f.getPath());
 \}
 \}
 \}
 public static void main(String[] args) throws Exception \{
 File dir = new File("/usr/lib/jvm/java-6-sun/docs/api/");
 FileList.list(dir, "String");
 \}
 \}
 ,,,

 A non-static version of the folder search. The code below may form a
 useful way to select a folder which contains a certain type of file.
 Using 2 endsWith() methods to check for .jpg and .JPG files is slightly
 faster than using string.matches() The code could be made faster by
 returning only folders from the .list() method using a FileFilter. No
 the FileFilter doesnt seem to speed anything up.
 Also could experiment using a compiled pattern for the regular expression

 * With a regular expression (string.matches) on an eee netbook 
 >> Searched 3261 folders in 3048 miliseconds

 * Using 2 'endsWith()' method calls to search the results were
 >> Searched 3261 folders in 2698 miliseconds

 * List all folders that contain at least one '.jpg' file in them 
 --------------------
 import java.io.*;
 import java.util.*;
 public class JpegFolderList \{
 List<File> folders;
 int foldersSearched;
 File rootFolder;
 boolean searchHidden;

 public JpegFolderList(String rootFolder) \{
 this.searchHidden = false;
 this.rootFolder = new File(rootFolder);
 this.foldersSearched = 0;
 this.folders = new ArrayList<File>(); 
 \}

 public List<File> getFolders() \{ return this.folders; \}
 public int getFoldersSearched() \{ return this.foldersSearched; \}
 public File getRoot() \{ return this.rootFolder; \}
 public void searchHidden(boolean b) \{
 // set if unix hidden folders (.xxx) will be searched
 \}
 /** tests if a folder contains at least one .jpg file */
 public boolean hasJpeg(File file) \{
 if (!file.isDirectory()) return false;
 for (String name: file.list()) \{
 if (name.matches(".*(?i)\\$\\backslash\\$\\$\\backslash\\$.jpg\\$")) return true; 
 \}
 return false;
 \}
 /** compiles a List of folders containing jpegs */
 public void findJpegFolders(File dir) \{
 this.foldersSearched++;
 /*
 if ((foldersSearched \\% 20) == 0)
 System.out.println("Folders searched: " + this.foldersSearched);
 */
 if (!dir.isDirectory()) return;
 // whether to search unix hidden folders
 if (!this.searchHidden) \{
 if (dir.getPath().startsWith(".")) return;
 \}
 for (File f: dir.listFiles()) \{
 if (f.isDirectory()) \{ 
 if (this.hasJpeg(f)) \{ this.folders.add(f); \}
 this.findJpegFolders(f);
 \}
 \}
 \}
 public static void main(String[] args) \{
 long startTime = System.currentTimeMillis();
 File dir = new File("/home/matth3wbishop/");
 JpegFolderList list = new JpegFolderList("/home/matth3wbishop/");
 list.findJpegFolders(list.getRoot());
 for (File f: list.getFolders())
 System.out.println(f.getPath());
 long loadTime = System.currentTimeMillis() - startTime;
 System.out.format(
 "Searched \\%d folders in \\%d miliseconds\\$\\backslash\\$n" +
 "Found \\%d folders containing .jpg files", 
 list.getFoldersSearched(), loadTime, list.getFolders().size());
 \}
 \}
 ,,,

 * List all folders that contain at least one '.jpg' file in them 
 --------------------
 import java.io.*;
 import java.util.*;
 public class JpegFolderList \{
 public static List<File> folders = new ArrayList<File>(); 
 public static int progress = 0;
 /** tests if a folder contains at least one .jpg file */
 public static boolean hasJpeg(File file) \{
 if (!file.isDirectory()) return false;
 for (String name: file.list()) \{
 if (name.endsWith(".jpg") || name.endsWith(".JPG")) 
 return true; 
 \}
 return false;
 \}

 /** compiles a List of folders containing jpegs */
 public static void getJpegFolders(File dir) \{
 progress++;
 if ((progress \\% 20) == 0)
 System.out.println("Folders searched: " + progress);
 if (!dir.isDirectory()) return;
 // dont search hidden folders
 if (dir.getPath().startsWith(".")) return;
 for (File f: dir.listFiles()) \{
 if (f.isDirectory()) \{ 
 //System.out.println(f.getPath());
 if (JpegFolderList.hasJpeg(f)) \{ folders.add(f); \}
 JpegFolderList.getJpegFolders(f);
 \}
 \}
 \}
 public static void main(String[] args) throws Exception \{
 File dir = new File("/home/matth3wbishop/");
 JpegFolderList.getJpegFolders(dir);
 for (File f: JpegFolderList.folders)
 System.out.println(f.getPath());
 \}
 \}
 ,,,

FILTERING FILES ....

 It is possible to use the FileFilter and FilenameFilter interfaces
 to limit the number of files returned by file.listFiles(...) and 
 file.list() respectively. These filters only have one method to
 implement namely accept(...)

OPENING FILES ....

 The term 'opening' a file refers to the process of obtain some
 object (usually a stream) which can read from or write to the 
 file.

 * open a file in the same folder as the Main application class
 >> this.getClass().getResourceAsStream()
 >> Class.getResourceAsStream()

 In the example below, the current working directory is usually the 
 folder from which the java application was run (and this is 
 not necessarily the same folder where the main application class or
 jar resides)

 * open a jpg file which is in the current working directory
 -------------------------------------------------------------
 URL imgUrl = new URL("file:big.jpg");
 InputStream is = imgUrl.openStream();
 ,,,

 * read a file which is in the same folder as the compiled class 
 -------------------------------------------------------------
 import java.net.URL;
 import java.io.*;
 public class ClassFolder \{
 public static void main(String[] args) \{
 try \{
 InputStream in = 
 Main.class.getResourceAsStream("ClassFolder.java");
 BufferedReader br = new BufferedReader(new InputStreamReader(in));
 String line;
 while ((line = br.readLine()) != null)
 System.out.println(line);
 in.close();
 \} catch (IOException e) \{ e.printStackTrace(); \}
 \}
 \}
 ,,,

 * get information about the main application class
 -------------------------------------------------------------
 import java.net.URL;
 public class MainName \{
 public static void main(String[] args) throws Exception \{
 URL main = Main.class.getResource("Main.class");
 System.out.format(
 "Main protocol: \\%s \\$\\backslash\\$nMain path: \\%s \\$\\backslash\\$nMain url: \\%s", 
 main.getProtocol(),
 main.getPath(),
 main.toString());
 \}
 \}
 ,,,

 * open the compiled main class within a jar or normal class file 
 -------------------------------------------------------------
 import java.net.URL;
 import java.io.*;
 public class OpenMain \{
 public static void main(String[] args) \{
 try \{
 InputStream in = Main.class.getResourceAsStream("Main.class");
 /* do something here */
 in.close();
 \} catch (IOException e) \{ e.printStackTrace(); \}
 \}
 \}
 ,,,

 
TEXT FILES ....
 
 * read and display text file line by line, using default encoding
 ----
 import java.io.*;
 public class FileReadTest \{
 public static void main(String[] args) throws Exception \{
 String line;
 File f = new File("FileReadTest.java");
 BufferedReader in = new BufferedReader(new FileReader(f));
 while ((line = in.readLine()) != null)
 System.out.println(line);
 in.close();
 \}
 \}
 ,,,

 * read a text file into a string buffer line by line
 -------------------------------------------------------------
 import java.io.*;
 public class FileReadTest \{
 public static void main(String[] args) throws Exception \{
 String line;
 File f = new File("FileReadTest.java");
 BufferedReader in = new BufferedReader(new FileReader(f));
 StringBuffer result = new StringBuffer();
 while ((line = in.readLine()) != null)
 result.append(line + "\\$\\backslash\\$n");
 in.close();
 System.out.println(result);
 \}
 \}
 ,,,

 ----
 BufferedReader br = new BufferedReader(fr);
 String buffer;
 StringBuffer result = new StringBuffer();
 while ((buffer = br.readLine()) != null)
 \{
 result.append(buffer);
 \}
 ,,,

 It would probably be faster to read into a larger buffer (8k ?)
 rather than just one line.

FOLDERS ....

 * list all files in the current folder
 ----------------------------------------
 import java.io.File;
 import java.util.Arrays;
 public class ListFiles \{
 public static void main(String[] args) \{
 System.out.format("\\%s is \\%d years old", "James", 45);
 File f = new File(".");
 File[] ff = f.listFiles();
 System.out.println(Arrays.toString(ff));
 \}
 \}
 ,,,

 * list java files in the current folder
 ----------------------------------------
 import java.io.*;
 import java.util.Arrays;
 public class ListFiles \{
 public static void main(String[] args) \{
 System.out.format("\\%s is \\%d years old", "James", 45);
 File f = new File(".");
 File[] ff = f.listFiles(new FilenameFilter() \{
 public boolean accept(File dir, String name) \{
 return name.endsWith("java");
 \}
 \});
 System.out.println(Arrays.toString(ff));
 \}
 \}
 ,,,

FILE SYSTEM TYPES

 * list file system labels or names
 ------------------------------------
 import java.io.File;
 import java.util.Arrays;
 import java.util.List;
 import javax.swing.filechooser.FileSystemView;
 
 public class FileSystemLabels \{
 public static void main(String args[]) \{
 List <File>files = Arrays.asList(File.listRoots());
 for (File f : files) \{
 String s = 
 FileSystemView.getFileSystemView().getSystemDisplayName(f);
 System.out.println("*" + s);
 \}
 \}
 \}
 ,,,

 On a Microsoft Windows computer the code above may produce
 something like:
 *
 *REGA1 (C:)
 *
 *My Book (F:)
 But on linux there is only one root, namely '/' 

 * print the types of storage devices currently mounted as filesystems
 ---------------------
 import java.io.File;
 import java.util.Arrays;
 import java.util.List;
 import javax.swing.filechooser.FileSystemView;
 
 public class FileSystemTest \{
 public static void main(String args[]) \{
 List <File>files = Arrays.asList(File.listRoots());
 for (File f : files) \{
 String s = FileSystemView.getFileSystemView().getSystemTypeDescription(f);
 System.out.println("*" + s);
 \}
 /* sample output (French WinXP)
 *Disquette 3 1/2 pouces
 *Disque local
 *Lecteur CD
 *Disque local
 */
 \}
 \}
,,,

 The code above doesnt produce any results on a linux computer.
 the above is from rgagnon.com


INPUT AND OUTPUT

 * get one line of input from the user
 -------------------------------------
 BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
 in.readLine();
 ,,,

SCANNER

 * use the Scanner class to get and parse user input 
 ----------------
 import java.util.Scanner;
 public class ScannerTest \{
 public static void main(String[] args) \{
 String s = "";
 Scanner input = new Scanner(System.in);
 System.out.println("enter something, 'q' to end");
 while (!s.equals("q")) \{
 s = input.next();
 System.out.println("entered: " + s);
 \}
 \}
 \}
 ,,,

 * read all numbers from a string, ignoring anything else 
 -------------------------------------------------------------
 import java.util.Scanner;
 public class NumberScanner \{
 public static void main(String args[]) \{
 String s = "10 99.88 words 44.1 are ignored. Only numbers 3.1";
 Scanner scan = new Scanner(s);
 while (scan.hasNext()) \{
 if (scan.hasNextDouble()) 
 System.out.println(scan.nextDouble());
 else scan.next();
 \} 
 \}
 \}
 ,,,

STREAMS

 Streams are an important concept. Essentially a stream is a first in
 last out (filo) queue or buffer. An important feature of a stream is
 that a program can start reading from the beginning of a stream before
 the entire contents of the stream become available.

FILTERING STREAMS ....

 The Unix/Linux operating system makes heavy use of stream 'filters'
 which are programs which operate on a stream changing its content
 is some way. The importance of these filters is that they can be
 'chained' together (using pipes - represented by the | bar symbol
 in a command shell) thus creating more complex filters from simpler
 ones.

STANDARD INPUT STREAM ....

TEXT FILES

 * read long integers from a text file
 -------------------------------------
 // since 1.6
 Scanner scanner = new Scanner(new File("numbers.txt"));
 while (scanner.hasNextLong())
 \{ long aLong = scanner.nextLong(); \}
 ,,,

 * read a textfile line by line
 ------------------------------
 try \{
 BufferedReader in = 
 new BufferedReader (new FileReader("infilename"));
 String s;
 while ((s = in.readLine()) != null)
 \{ System.out.println(s); \}
 in.close ();
 \} catch (IOException e) \{ \}
 ,,,

 * read either a file or a Url (file://c:/.. or \url{http://)}
 -------------------------------------------------------
 URL url = new URI(http://www.google.com).toURL();
 URLConnection conn = url.openConnection ();
 Reader rd = new InputStreamReader (conn.getInputStream ());
 ,,,

 * reading a utf-8 file in a non utf-8 locale
 --------------------------------------------
 FileInputStream fis = new FileInputStream("test.txt");
 InputStreamReader in = new InputStreamReader(fis, "UTF-8"); 
 ,,,

READING AND WRITING TEXT FILES

 FileReader and FileWriter can only use the default system encoding

 * read a file which is encoded in utf8
 -----------
 FileInputStream fis = new FileInputStream("test.txt"); 
 InputStreamReader in = new InputStreamReader(fis, "UTF-8");
 ,,,

 * write a text file encoded as utf8
 -------------
 FileOutputStream fos = new FileOutputStream("test.txt"); 
 OutputStreamWriter out = new OutputStreamWriter(fos, "UTF-8");
 ,,,

 If the encoding is not specified then the default system encoding is used

 * read utf8 text data from a file
 --------------------------
 import java.io.*;
 public class FileReadTest \{
 public static void main(String[] args) \{
 try \{
 File file = new File("c:\\$\\backslash\\$\\$\\backslash\\$temp\\$\\backslash\\$\\$\\backslash\\$test.txt");
 BufferedReader in = new BufferedReader(
 new InputStreamReader(new FileInputStream(file), "UTF8"));
 String str;
 while ((str = in.readLine()) != null) \{
 System.out.println(str);
 \}
 in.close();
 \}
 catch (UnsupportedEncodingException e)
 \{
 System.out.println(e.getMessage());
 \}
 catch (IOException e)
 \{
 System.out.println(e.getMessage());
 \}
 catch (Exception e)
 \{
 System.out.println(e.getMessage());
 \}
 \}
 \}
,,,

WRITING TEXT

 * write utf8 text data to a file
 --------------------------

import java.io.*; 
public class test \{
 public static void main(String[] args)\{
 try \{
 File file = new File("c:\\$\\backslash\\$\\$\\backslash\\$temp\\$\\backslash\\$\\$\\backslash\\$test.txt");
 Writer out = new BufferedWriter(new OutputStreamWriter(
 new FileOutputStream(file), "UTF8"));
 out.append("Website UTF-8").append("\\$\\backslash\\$r\\$\\backslash\\$n");
 out.append("??????? UTF-8").append("\\$\\backslash\\$r\\$\\backslash\\$n"); 
 out.flush();
 out.close();
 \} 
 catch (UnsupportedEncodingException e) 
 \{ System.out.println(e.getMessage()); \} 
 catch (IOException e) 
 \{ System.out.println(e.getMessage());\}
 catch (Exception e)
 \{ System.out.println(e.getMessage());\} 
 \} 
\}
,,,

The BufferedWriter class has a .newLine() method, but it uses the default
newline character(s) for the system.

WORKING WITH HTML ....

 \url{http://www.exampledepot.com/egs/javax.swing.text.html/pkg.html}
 an example of getting the links in an html document

FONTS
 
 The default fonts for Java are not very pleasant. They dont seem
 to be well antialiases or smoothed and this does alot to put
 people of developing in Java even before they get started

 Fonts bundled with the Java development kit are stored in
 >> J:\\$\\backslash\\$Program Files\\$\\backslash\\$java\\$\\backslash\\$jdk1.7.0\\_04 \\$\\backslash\\$jre\\$\\backslash\\$lib\\$\\backslash\\$fonts\\$\\backslash\\$. 

 They are only available to java applications unless they are 
 explicitly installed in the Windows or Unix font repositories

 Fonts like "Monospaced" and "Serif" seem generically available.

LOGICAL FONTS ....

 The logical font families may span several actual fonts in order
 to include many glyphs.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents the Java logical font families
 .. Serif, 
 .. SansSerif,
 .. Monospaced - fixed-width pitch glyphs
 .. Dialog
 .. DialogInput. 
 ..


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents some notes about particular fonts
 .. unifont - has a lot of glyphs but unpleasant 
 .. freeserif - nice symbols for the 'miscelaneous' unicode blocks
 .. Georgia Italic - a nice font (used by El Pais newspaper)
 ..

 * create a new monospace courier font, size 20 points
 >> Font font = new Font("Courier", Font.PLAIN, 20);

 * make a bold serifed font, 10 points in size
 >> Font font = new Font("Serif", Font.BOLD, 10);

 * create a 24 point italic font
 >> Font f = new Font("Times New Roman", Font.ITALIC, 24);

 * get all available font family names
 -------------------------------------
 GraphicsEnvironment ge = 
 GraphicsEnvironment.getLocalGraphicsEnvironment();
 String fontNames[] = ge.getAvailableFontFamilyNames();
 ,,,

 * show a list of all available font families and select one 
 ------------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class FontList \{
 public static void main(String[] args) \{
 SwingUtilities.invokeLater( new Runnable() \{
 public void run() \{
 GraphicsEnvironment ge = 
 GraphicsEnvironment.getLocalGraphicsEnvironment();
 String fontNames[] = ge.getAvailableFontFamilyNames();
 Object r = JOptionPane.showInputDialog(
 null, "Choose a font:", "Available Fonts",
 JOptionPane.PLAIN\\_MESSAGE, null, fontNames, fontNames[0]);
 System.out.println("font selected: " + r);
 \}
 \});
 \}
 \}
 ,,,


 * displays fonts in a listbox and uses the font for the item 
 -------------------------------------------------------------
 import java.awt.*;
 import javax.swing.*;

 public class ShowFonts \{
 public static void main(String[] args) \{
 SwingUtilities.invokeLater( new Runnable() \{
 public void run() \{
 GraphicsEnvironment ge = GraphicsEnvironment.
 getLocalGraphicsEnvironment();
 String[] fonts = ge.getAvailableFontFamilyNames();
 JList fontChooser = new JList(fonts);
 fontChooser.setCellRenderer(new FontCellRenderer());
 JOptionPane.showMessageDialog(
 null, new JScrollPane(fontChooser));
 \}
 \});
 \}
 \}
 
 class FontCellRenderer extends DefaultListCellRenderer \{
 public Component getListCellRendererComponent(
 JList list, Object value, int index, boolean isSelected,
 boolean cellHasFocus) 
 \{
 JLabel label = (JLabel)super.getListCellRendererComponent(
 list,value,index,isSelected,cellHasFocus);
 Font font = new Font((String)value, Font.PLAIN, 20);
 label.setFont(font);
 return label;
 \}
 \}
 ,,,

 * displays fonts in a combobox and uses the font for the item 
 -------------------------------------------------------------
 import java.awt.*;
 import javax.swing.*;

 public class ShowFonts \{
 public static void main(String[] args) \{
 SwingUtilities.invokeLater( new Runnable() \{
 public void run() \{
 GraphicsEnvironment ge = GraphicsEnvironment.
 getLocalGraphicsEnvironment();
 String[] fonts = ge.getAvailableFontFamilyNames();
 JComboBox fontChooser = new JComboBox(fonts);
 fontChooser.setRenderer(new FontCellRenderer());
 JOptionPane.showMessageDialog(null, fontChooser);
 \}
 \});
 \}
 \}
 
 class FontCellRenderer extends DefaultListCellRenderer \{
 public Component getListCellRendererComponent(
 JList list, Object value, int index, boolean isSelected,
 boolean cellHasFocus)
 \{
 JLabel label = (JLabel)super.getListCellRendererComponent(
 list,value,index,isSelected,cellHasFocus);
 Font font = new Font((String)value, Font.PLAIN, 20);
 label.setFont(font);
 return label;
 \}
 \}
 ,,,

 * displays a list of fonts available in a list box
 --------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class FontList \{
 public static void main(String[] args) \{
 JFrame t = new JFrame();
 GraphicsEnvironment ge = 
 GraphicsEnvironment.getLocalGraphicsEnvironment();
 String fontNames[] = ge.getAvailableFontFamilyNames();
 JList lb = new JList(fontNames);
 JPanel p = new JPanel();
 p.add(new JScrollPane(lb));
 t.getContentPane().add(p);
 t.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 t.pack(); t.setLocationRelativeTo(null);
 t.setVisible(true);
 \}
 \}
 ,,,

 * displays all fonts in labels 
 --------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class FontList \{
 public static void main(String[] args) \{
 JFrame t = new JFrame();
 Font font; JLabel label;
 String name = new String();
 String[] fonts = 
 GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames();
 JPanel p = new JPanel(new GridLayout(0, 1));
 for (int i = 0; i < fonts.length; i++) \{
 name = fonts[i]; 
 font = new Font(name, Font.PLAIN, 20);
 label = new JLabel(name + " glyphs:" + font.getNumGlyphs());
 label.setFont(font);
 p.add(label); 
 \}
 t.getContentPane().add(new JScrollPane(p));
 t.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 t.setExtendedState(Frame.MAXIMIZED\\_BOTH); t.pack(); 
 t.setVisible(true);
 \}
 \}
 ,,,

 * create a JLabel with a large Georgia font in grey colour
 --------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class LabelFont \{
 public static void main(String[] args) \{
 JFrame t = new JFrame();
 Font font = new Font("Georgia", Font.PLAIN, 40);
 JLabel l = new JLabel("This is the Georgia Font size 40");
 l.setFont(font);
 l.setForeground(Color.gray);
 JPanel p = new JPanel(); p.add(l);
 t.getContentPane().add(p);
 t.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 t.pack(); t.setVisible(true);
 \}
 \}
 ,,,

 By using grey instead of black the java fonts dont look quite as bad
 as normal.

 * print something like "mono bold" etc
 >> fonts.getName();

 * print all font family names to standard output
 -----------------------------------------------------
 import java.awt.Font; 
 import java.awt.GraphicsEnvironment;
 public class FontTest \{
 public static void main(String[] args) \{
 Font[] fonts = 
 GraphicsEnvironment.getLocalGraphicsEnvironment().getAllFonts();
 for (int i = 0; i < fonts.length; i++)
 \{
 String familyName = fonts[i].getFamily();
 System.out.println(i + ": " + familyName);
 \}
 \}
 \}
 ,,,

ANTIALIASING FONTS ....

 The Graphics2D class and Swing components support high quality
 anti-aliasing through the java.awt.RenderingHints class which allows us to
 specify the algorithm used, which in some cases can be optimised for the
 type of LCD screen in use.

 We can antialias fonts drawn with the Graphics2D.drawString() method by
 setting some rendering hints. The improvement is very noticeable.
 
 @@ \url{http://mindprod.com/jgloss/antialiasing.html}
 good antialias info for different versions of java

 @@ \url{http://download.oracle.com/javase/7/docs/technotes/guides/2d/flags.html\\#aaFonts}
 what sun says about text antialiasing in Java 1.6 >

 The following noticeably improved text antialiasing on my Gnome Linux
 netbook.

 * In java 1.6 ensure that text antialiasing is switched on 
 >> System.setProperty("awt.useSystemAAFontSettings","on");

 The java 1.6/1.7 JRE may take its text antialiasing settings from the
 Computer Desktop settings. In some cases this results in an
 inferior, or no, antialiasing technique to be used. The line above
 remedies that problem


\title{= values for AAFontSettings in >} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents Java 1.6 
 .. lcd use ClearType style sub-pixel anti-aliasing.
 .. false no anti-aliasing. Fast with jaggies.
 .. on Gnome Best shapes/Best contrast. Not available in Windows.
 .. gasp Windows standard anti-aliasing.
 ..


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents more text antialias settings for java 1.6
 System Property Value | java.awt.RenderingHint value
 "off"|"false"|"default" : VALUE\\_TEXT\\_ANTIALIAS\\_DEFAULT
 "on" : VALUE\\_TEXT\\_ANTIALIAS\\_ON
 "gasp" : VALUE\\_TEXT\\_ANTIALIAS\\_GASP
 "lcd"|"lcd\\_hrgb" : VALUE\\_TEXT\\_ANTIALIAS\\_LCD\\_HRGB
 "lcd\\_hbgr" : VALUE\\_TEXT\\_ANTIALIAS\\_LCD\\_HBGR
 "lcd\\_vrgb" : VALUE\\_TEXT\\_ANTIALIAS\\_LCD\\_VRGB
 "lcd\\_vbgr" : VALUE\\_TEXT\\_ANTIALIAS\\_LCD\\_VBGR


 In java 1.6 it seems that some AA settings come from the os.
 You can see these in Toolkit.getDesktopProperty(awt.font.desktophints)

 * turn on antialiased text in Java 1.5
 >> java.exe -Dswing.aatext=true 

 * we can antialias g2d.drawString() text with either of the following
 -------------------------------------------------------------
 g.setRenderingHint(RenderingHints.KEY\\_ANTIALIASING,
 RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 //or
 g.setRenderingHint(RenderingHints.KEY\\_TEXT\\_ANTIALIASING,
 RenderingHints.VALUE\\_TEXT\\_ANTIALIAS\\_ON);
 ,,, 

 * comparing aliased and antialiased fonts with g2d.drawString() 
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 import java.text.AttributedString;
 import java.awt.font.TextAttribute;
 import java.util.*;
 public class AntialiasTextPanel extends JPanel \{
 public AntialiasTextPanel() \{
 super();
 \}
 @Override
 public void paintComponent(Graphics gg) \{
 Graphics2D g = (Graphics2D) gg;
 super.paintComponent(g);
 Font font = new Font("Georgia", Font.PLAIN, 60);
 g.setFont(font);
 g.drawString("Not Anti-aliased", 50, 50);
 g.setRenderingHint(RenderingHints.KEY\\_TEXT\\_ANTIALIASING,
 RenderingHints.VALUE\\_TEXT\\_ANTIALIAS\\_ON);
 g.drawString("Anti-aliased", 50, 130);
 \}
 public Dimension getPreferredSize() \{
 return new Dimension(500, 500);
 \}
 public static void main(String[] args) \{
 JOptionPane.showMessageDialog(null, new AntialiasTextPanel());
 \}
 \}
 ,,,
 
 In the example below, the quality of the anti-aliasing for the drawString()
 method and the text contained in the JTextField seems to be the same.

 * compare antialiasing in a JTextField and with drawString() 
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class TextPanel extends JPanel \{
 JTextField field;
 Font font;
 public TextPanel() \{
 super();
 this.font = new Font("Georgia", Font.PLAIN, 60);
 this.field = new JTextField("Aliased");
 this.field.setFont(this.font);
 this.add(this.field);
 \}
 @Override
 public void paintComponent(Graphics gg) \{
 Graphics2D g = (Graphics2D) gg;
 super.paintComponent(g);
 g.setFont(this.font);
 g.drawString("Not Anti-aliased", 50, 130);
 g.setRenderingHint(RenderingHints.KEY\\_TEXT\\_ANTIALIASING,
 RenderingHints.VALUE\\_TEXT\\_ANTIALIAS\\_ON);
 g.drawString("Anti-aliased", 50, 200);
 \}
 public Dimension getPreferredSize() \{
 return new Dimension(500, 500);
 \}
 public static void main(String[] args) \{
 // the next line may improve Swing JTextComponent antialiasing
 System.setProperty("awt.useSystemAAFontSettings","on");
 JOptionPane.showMessageDialog(null, new TextPanel());
 \}
 \}
 ,,,
 
 * antialias text in a JLabel - untested, this seems unnecessary
 ---------------------------------------------
 JLabel lblFont = new JLabel() \{
 @Override
 public void paintComponent(Graphics g) \{
 Graphics2D graphics2d = (Graphics2D) g;
 graphics2d.setRenderingHint(RenderingHints.KEY\\_ANTIALIASING,
 RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 super.paintComponent(g);
 \}
 \};
 ,,,

 * turn on/off? antialiasing in some older java versions - untested
 -------------------------------------------------------------
 jtextcomponent.putClientProperty(
 com.sun.java.swing.SwingUtilities2.AA\\_TEXT\\_PROPERTY\\_KEY, Boolean.TRUE);
 ,,,


DRAWING WITH FONTS ....

 * create shapes from character glyphs and then use those shapes to draw
 -------------------------
 Font font = new Font("Serif", Font.BOLD, 10); // a basic font
 // a scaled up version
 Font bigfont =
 font.deriveFont(AffineTransform.getScaleInstance(30.0, 30.0));
 GlyphVector gv = bigfont.createGlyphVector(g.getFontRenderContext(), "JAV");
 Shape jshape = gv.getGlyphOutline(0); // Shape of letter J
 Shape ashape = gv.getGlyphOutline(1); // Shape of letter A
 Shape vshape = gv.getGlyphOutline(2); // Shape of letter V
 g.fill(jshape);
 ,,,


 \url{http://www.javadocexamples.com/java\\_source/\\_\\_/tt/TTFontDemo.java.html}
 an example of loading a true type font from an input stream

 \url{http://www.javadocexamples.com/java/awt/Font/deriveFont(int\\%20style,float\\%20size).html}
 some interesting java examples

LOADING FONTS ....

 * how to load a font from a file
 --------------------
 // First, see if we can load the font file.
 InputStream is = this.getClass().getResourceAsStream(fontFileName);
 if (is == null) \{
 throw new IOException("Cannot open " + fontFileName);
 \}
 // createFont makes a 1-point font, bit hard to read :-)
 Font ttfBase = Font.createFont(Font.TRUETYPE\\_FONT, is);
 // So scale it to 24 pt.
 Font ttfReal = ttfBase.deriveFont(Font.PLAIN, 24);
 ,,,

 * a japanese font loading example
 -----------------------------
 // Create a label in Japanese.
 String message = "かつ、尊厳と権利とについて平等である。";
 JLabel label = new JLabel(message);
 // Load the TrueType font with Japanese characters and apply it.
 File file = new File("msmincho.ttf");
 Font font = Font.createFont(Font.TRUETYPE\\_FONT, file);
 font = font.deriveFont(Font.PLAIN, 14f);
 label.setFont(font);
 ,,,


 * check whether a font has a glyph to display a specified character
 >> font.canDisplay(char c)

 there are a number of other canDisplay methods

 * create a font from a file or stream bundled with an application
 >> font.createFont(int fontFormat, InputStream fontStream) 

TRANSFORMING FONTS ....

 * we apply rotates/scales/shears to fonts
 >> deriveFont(AffineTransform trans) 
 
 * create a backward slanting font with a shear transform
 --------------
 Graphics2D g2 = (Graphics2D) g;
 g2.setRenderingHint(RenderingHints.KEY\\_ANTIALIASING,
 RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 Font font = new Font("Serif", Font.PLAIN, 24);
 float x = 20, y = 20;
 AffineTransform at = new AffineTransform();
 at.shear(.2, 0);
 Font fontShear = font.deriveFont(at);
 g2.setFont(fontShear);
 g2.drawString("font.deriveFont(at)", x, y += 30);
 ,,,

DERIVED FONTS ....

 * increase the size of a font by 2 points 
 >> font = font.deriveFont(font.getSize2D() + 2.0f);
 
 getSize2D returns a float value

 * make a bold italic version of the current font
 >> font = font.deriveFont(Font.ITALIC + Font.BOLD);

 * create a derived font with a map of text attributes
 --------------
 Font font = new Font("Serif", Font.PLAIN, 24);
 float x = 20, y = 20;
 Hashtable attributes = new Hashtable();
 attributes.put(TextAttribute.WEIGHT, TextAttribute.WEIGHT\\_BOLD);
 Font fontBold = font.deriveFont(attributes);
 g2.setFont(fontBold);
 g2.drawString("font.deriveFont(attributes)", x, y += 30);
 ,,,

FONT SIZE ....

 * increase the size of a font in a JTextArea component
 -------------------------------------------------------------
 Font font = textArea.getFont();
 float size = font.getSize() + 1.0f;
 textArea.setFont( font.deriveFont(size) );
 ,,,

 * the same as above but conflated
 >> ta.setFont(font.deriveFont(ta.getFont().getSize()+1.0f));

FONT METRICS ....

 * create a new image and determine its font metrics 
 ----------------------------------------------------
 BufferedImage image = 
 new BufferedImage(800, 600, BufferedImage.TYPE\\_INT\\_RGB);
 Graphics2D g = (Graphics2D)image.getGraphics();
 FontMetrics fm = g.getFontMetrics();
 int w = fm.stringWidth("Hello");
 int h = fm.getHeight() + fm.getMaxDescent();
 ,,,
 
 The Java2D api allow more precise ways to get font metrics than
 the old AWT FontMetrics class.

 * get the bounding rectangle for a string in a font
 -------------------------------------------------------------

 Graphics2D g; 
 Font f; // Initialized elsewhere
 String message = "Hello World!"; 
 Rectangle2D box; // The display box: initialized elsewhere

 // Measure the font and the message
 FontRenderContext frc = g.getFontRenderContext();
 Rectangle2D bounds = f.getStringBounds(message, frc);
 LineMetrics metrics = f.getLineMetrics(message, frc);
 float width = (float) bounds.getWidth(); // The width of our text
 float lineheight = metrics.getHeight(); // Total line height
 float ascent = metrics.getAscent(); // Top of text to baseline

 // Now display the message centered horizontally and vertically in box
 float x0 = (float) (box.getX() + (box.getWidth() - width)/2);
 float y0 = (float) (box.getY() + (box.getHeight() - lineheight)/2 + ascent);
 g.setFont(f);
 g.drawString(message, x0, y0);
 ,,,
 
FONT INFORMATION ....

 * get the number of glyphs contained in a font
 >> font.getNumGlyphs()

JAPANESE FONTS ....

 1) Download one of the truetype fonts from here : \url{http://www.wazu.jp/gallery/Fonts\\_Japanese2.html}

 2) Use the following code to allow your swing clients to use your fonts:

 InputStream fontStream = getClass().getResourceAsStream("/locationoffontonclasspath/myfontname.ttf");
 Font japaneseEnabledFont = null;
 boolean japaneseDisplayEnabled = false;
 try \{
 japaneseEnabledFont = Font.createFont(Font.TRUETYPE\\_FONT, fontStream);
 GraphicsEnvironment.getLocalGraphicsEnvironment().registerFont(japaneseEnabledFont);
 japaneseDisplayEnabled = true;
 \} catch (Exception e) \{
 // handle exceptions here
 \} finally \{
 if (fontStream != null) \{
 try \{fontStream.close();\} catch (Exception e1) \{\}
 \}
 \}

COLORS

 In Java colours are colors. And grey is gray. In general when creating
 rgb (red, green, blue) colours, the higher the numbers the lighter the
 colour, and the lower the numbers the darker the colours.

 \url{http://docs.oracle.com/javase/7/docs/}
 nice colors in the java api table

 * create a new rgb colour
 >> Color c = new Color(int red, int green, int blue) 

 * create a light turqoisy colour
 >> Color c = new Color(0, 230, 230);

 In order to set the background color for many JComponent, we 
 first have to set the component to be opaque (since by default
 the component will be transparent).

 * set the background colour for a JLabel
 -------------------------------------------------------------
 JLabel label = new JLabel("A rounded corner border");
 label.setOpaque(true);
 label.setBackground(Color.orange);
 ,,,

 * set the background for a component using a hex string for the colour
 >> this.setBackground(new Color(Integer.decode("\\#eeff99")));

 * colours in rgb format
 >> red is (255, 0, 0) 
 >> green is (0, 255, 0) 
 >> white is (255, 255, 255) 
 >> black is (0,0,0)
 
 * mix colors using the HSB color model when creating a new colour 
 >> Color c = Color.getHSBColor(hue, saturation, brightness)

 The hue parameter is a decimal number between 0.0 and 1.0 which indicates
 the hue of the color. You'll have to experiment with the hue number to
 find out what color it represents.

 The saturation is a decimal number between 0.0 and 1.0 which indicates
 how deep the color should be. Supplying a "1" will make the color as deep
 as possible, and to the other extreme, supplying a "0," will take all the
 color out of the mixture and make it a shade of gray.

 The brightness is also a decimal number between 0.0 and 1.0 which
 obviously indicates how bright the color should be. A 1 will make the
 color as light as possible and a 0 will make it very dark.
 
 * A swing textarea with a foreground and background colour 
 --------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class ColourArea \{
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JTextArea ta = new JTextArea("Botany and Trees");
 ta.setForeground(Color.gray);
 ta.setBackground(Color.white);
 ta.setFont(new Font("Georgia", Font.PLAIN, 30));
 JOptionPane.showMessageDialog(null, ta);
 \}
 \});
 \}
 \}
 ,,,

ANALYSING COLORS ....

 * use the tostring method 
 --------------------------------------------------
 import java.awt.*;
 public class ColorValues \{
 public static void main(String[] args) \{
 //Color c = new Color(Color.orange);
 Color c = Color.orange;
 System.out.format("toString(): \\%s\\$\\backslash\\$n", c.toString());
 \}
 \}
 ,,,

MIXING COLORS ....

 It would be nice to be able to 'mix' colours in the same way that
 an artist mixes them on a palette. But what is the mathematics of this.

BRIGHTNESS AND DARKNESS ....

 Java has some useful methods for making a colour brighter or darker.
 This has to do with the amount of saturation (I think).
 
 * a trick to create nice gradients using the brighter() and darker()
 -------------------------------------------------------------
 GradientPaint gp = new GradientPaint(0, 0,
 getBackground().brighter().brighter(), 0, getHeight(),
 getBackground().darker().darker());
 ,,,

 The example below may allow us to learn how to mix darker colours.

 * display named colours, darker variants and rgb values 
 -------------------------------------------------------
 import java.lang.reflect.*;
 import javax.swing.*;
 import java.awt.*;
 public class NamedColors extends JPanel \{
 public NamedColors() \{
 super(new GridLayout(0, 3)); 
 JLabel label;
 try \{
 for (Field f: Color.class.getFields()) \{
 if (f.getType().equals(Color.class) \\&\\& 
 !Character.isUpperCase(f.getName().charAt(0)) \\&\\&
 Modifier.isStatic(f.getModifiers())) \{
 Color c = (Color)f.get(null);
 Color[] colors = \{c, c.darker(), c.darker().darker()\};
 for (Color color: colors) \{
 label = new JLabel();
 label.setText(String.format(
 "<html><center>\\%s<br> rgb[\\%d,\\%d,\\%d]", 
 f.getName(), color.getRed(), color.getBlue(), 
 color.getGreen()));
 label.setFont(new Font("Georgia", Font.ITALIC, 20));
 label.setBackground(color);
 label.setOpaque(true);
 this.add(label);
 \}
 \}
 \}
 \} catch (IllegalAccessException e) \{\}
 \}
 public static void main(String args[]) \{
 NamedColors c = new NamedColors(); 
 JFrame frame = new JFrame("Named Colors and darker");
 frame.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 frame.getContentPane().add(new JScrollPane(c));
 frame.pack(); frame.setVisible(true);
 \}
 \}
 ,,,

TRANSLUCENT COLORS OR COLORS WITH THE ALPHA CHANNEL ....

 Around about java 1.2 an interesting new capability was added to Java
 Colors, that is the ability to define colours with an alpha channel. The
 alpha channel is just a fancy name for translucency. Really the alpha
 channel just indicates how this color will be mixed with other colours to
 create the illusion of translucency. Transparency is total (1.0)
 traslucency and opaqueness is zero translucency.

 * create a darkish red color half translucent.
 >> Color translucentRed = new Color(150, 0, 0, 0.5);

 You can create interesting GradientPaints using a translucent colour
 at one end and an opaque colour at the other end of the paint.

NAMED COLORS ....

 The java.awt.Color class contains several named Color fields in 
 upper and lower case.

 * display the named Colors within the Color class using reflection 
 --------------------------------------------------------------------
 import java.lang.reflect.*;
 import javax.swing.*;
 import java.awt.*;
 public class NamedColors extends JPanel \{
 public NamedColors() \{
 super(new GridLayout(0, 3)); 
 JLabel colorLabel;
 try \{
 for (Field f: Color.class.getFields()) \{
 if (f.getType().equals(Color.class) \\&\\& 
 !Character.isUpperCase(f.getName().charAt(0)) \\&\\&
 Modifier.isStatic(f.getModifiers())) \{
 colorLabel = new JLabel(f.getName());
 colorLabel.setFont(new Font("Georgia", Font.ITALIC, 22));
 colorLabel.setBackground((Color)f.get(null));
 colorLabel.setOpaque(true);
 this.add(colorLabel);
 \}
 \}
 \} catch (IllegalAccessException e) \{\}
 \}
 public static void main(String args[]) \{
 JOptionPane.showMessageDialog(null, new NamedColors());
 \}
 \}
 ,,,

CHOOSING COLORS ....

 Use the JColorChooser dialog

 The example below could be used as a very basic colour chooser for the
 java named colours. The only problem is that the color names are not
 displayed, because the Field.getName() method is not available to the
 cellrenderer.

 Ideas: 
 we could add darker() colors, and make the component a JPopupMenu, which
 allows multiple columns. Also the code should subclass a JComboBox or a
 JPanel, not be entirely in the 'main' method.

 * a combobox in which each row has a color 
 ------------------------------------------
 import java.awt.*;
 import java.io.File;
 import javax.swing.*;
 import java.lang.reflect.*;
 public class ChooseColorComboBox \{
 public static void main(String[] args) \{
 SwingUtilities.invokeLater( new Runnable() \{
 public void run() \{
 JComboBox box = new JComboBox(new DefaultComboBoxModel());
 box.setFont(new Font("Georgia", Font.ITALIC, 22));
 try \{
 for (Field f: Color.class.getFields()) \{
 if (f.getType().equals(Color.class) \\&\\& 
 !Character.isUpperCase(f.getName().charAt(0)) \\&\\&
 Modifier.isStatic(f.getModifiers())) \{
 //colorLabel = new JLabel(f.getName());
 box.addItem((Color)f.get(null));
 \}
 \}
 \} catch (IllegalAccessException e) \{\}
 box.setRenderer(new ChooseColorRenderer());
 JOptionPane.showMessageDialog(null, box);
 \}
 \});
 \}
 \}
 class ChooseColorRenderer extends DefaultListCellRenderer \{
 public Component getListCellRendererComponent(
 JList list, Object value, int index,
 boolean isSelected, boolean cellHasFocus) \{
 JLabel label = (JLabel)super.getListCellRendererComponent(
 list,value,index,isSelected,cellHasFocus);
 if (value instanceof Color) \{
 Color c = (Color)value;
 label.setBackground(c);
 label.setText(String.format("rgb color (\\%d,\\%d,\\%d)", 
 c.getRed(), c.getGreen(), c.getBlue()));
 \} 
 return label;
 \}
 \}
 ,,,

GOTCHAS FOR COLORS ....

 You cant make the named colours any brighter because they are already as
 bright as they can be, but you can make them darker.

INTERNATIONALIZATION
 
LOCALIZING MESSAGES ....

 * an example of using a properties file for messages in other languages
 -----------------------------------------------------------------------
 file 'messages\\_en.properties':
 hello = Hello bye = Goodbye
 ...
 file 'messages\\_fr.properties':
 hello = Bonjour bye = Au Revoir
 ...

 try
 \{
 // Get the resource bundle for the default locale
 ResourceBundle rb = ResourceBundle.getBundle("messages");
 String key = "hello"; String s = rb.getString (key); 
 key = "bye"; s = rb.getString(key); 
 rb = ResourceBundle.getBundle("messages", Locale.FRENCH);
 key = "hello"; s = rb.getString(key); // Bonjour
 key = "bye"; s = rb.getString(key); // Au Revoir
 \}
 catch (MissingResourceException e)
 \{
 // No ResourceBundle file or no key in the file
 \}
 ,,,

PACKAGES

 * how to create a package
 \begin{enumerate}
  \item put 'package namea.nameb;' at the top of the .java file
 \item place the .java file in the folder namea/nameb 
 \item compile from 'nameb' with javac class.java
 \item run with java namea.nameb.class 
\end{enumerate}
  
SWING GUI APPLICATIONS

 The Swing set of components (called generally JComponents) is a set
 of graphical user interface components designed to replace the 
 older AWT component set. The Swing apis provide a comprehensive and 
 highly flexible set of components for building user interfaces. 
 However at times, the Swing system can seem like a labyrinth to the 
 new user (programmer). Hopefully the notes which follow will provide
 some guidance.

 The term 'gui' (graphical user interface) application refers to an
 application which uses 'windows' in order to display various graphical
 components to interact with the user, such as 'text boxes', 'buttons',
 'labels' and various other elements. The swing tool set replaced the
 older awt set in java version 1.2

 @@ \url{http://www.rgagnon.com/topics/java-swing.html}
 good practical examples of using swing

 * possibly the simplest java 'gui' application 
 --------------------------------------------
 import javax.swing.*;
 public class SimpleGui \{
 public static void main(String[] args) \{
 JOptionPane.showMessageDialog(null, "Hello!");
 \}
 \}
 ,,,

 * make an application exit when the window is closed
 >> frame.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);

 According to the experts one should use the
 SwingUtilities.invokeLater(runnable) method to launch a swing
 application. Apparently this is to start the application on the 
 'Event Dispatch Thread' (EDT)
 which is the main swing thread which updates each of the
 graphical components in the application. The thread which starts
 from the java static main() method is *not* the EDT, in fact the 
 main method thread exits after starting the swing edt thread.
 
 On Linux I have noted at times some strange behaviors when using this
 invokeLater() method.

 * the correct way to start an application
 -------------------------------------------------------------
 public class MainFrame extends javax.swing.JFrame \{
 ...
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 new MainFrame().setVisible(true);
 \}
 \});
 \}
 \}
 ,,,

 * apparently the following 2 methods are exactly the same
 >> jframe.getContentPane().add(new ApplicationPanel());
 >> jframe.add(new ApplicationPanel()); 

 * create a simple 'windowed' application
 -------------------------------
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 
 public class ApplicationPanel extends JPanel \{
 public ApplicationPanel() \{
 super();
 JLabel label = new JLabel("A very simple Swing application");
 this.add(label);
 \}
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JFrame frame = new JFrame("LabelDemo");
 frame.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 frame.getContentPane().add(new ApplicationPanel());
 frame.pack(); frame.setVisible(true);
 \}
 \});
 \}
 \}
 ,,,

 * another way to start a swing application (correct)
 -----------------------
 public static void main(String[] args) \{
 Runnable r = new Runnable() \{
 public void run() \{
 final JFrame frame = new JFrame("Testing swing");
 ...
 \}
 \};
 SwingUtilities.invokeLater(r);
 \}
 ,,,

 * create an empty window 300x300 pixels, centered in the screen 
 ----------------------------------------------
 import javax.swing.*;
 public class FrameTest \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("a centered empty window");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setSize(new java.awt.Dimension(300, 300));
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

 * a application skeleton which extends the JFrame window class
 ------------------------------------
 import javax.swing.*;
 public class ExtendFrame extends JFrame \{
 public ExtendFrame () \{
 super();
 JLabel label = new JLabel("extending a jframe");
 this.getContentPane().add(label);
 this.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 this.pack(); this.setLocationRelativeTo(null);
 this.setVisible(true);
 \}
 public static void main(String[] args) \{
 JFrame f = new ExtendFrame();
 \}
 \}
 ,,,

JCOMPONENTS ....
 
 All javax.swing components descend from the JComponent and thus inherit
 its capabilities. The JComponent in-turn descends from the older
 java.awt.Component which is much less capable than the JComponent.
 Interestingly, all JComponents are containers which means that you
 essentially add any set of components you like to any swing component. An
 example of this is adding multiple components to a JToolTip, which by
 default only displays (html) text. All JComponents all support
 keybindings, borders, drag-and-drop and the list goes on. ...

 All the swing components are subclasses of JComponent. We can therefore
 manipulate components in a gui in a generic way.

 * get a component from a built gui and cast it to its type.
 ------------------
 Component c = tabPane.getComponentAt(tabPane.getSelectedIndex());
 JScrollPane sp = (JScrollPane)c;
 ,,,

EXTENDING AND CUSTOMISING JCOMPONENTS ....

PAINTCOMPONENT METHOD ....

 On common technique for customising the appearance of swing components is
 to override the paintComponent() method for the JComponent. (Note that in
 the AWT component system, it was the paint() method which was usually
 overridden). This technique allows, for example, a GradientPaint to be
 used as the background for the swing component, or an Image.
 
 When drawing shapes with paintComponent() it is necessary to subtract
 one from the width and height of the component.

 * a simple paintComponent method override for a JLabel. 
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class PaintLabel extends JLabel \{
 public PaintLabel(String text) \{
 super(text);
 \}
 public void paintComponent(Graphics g) \{
 g.setColor(Color.green);
 g.fillRect(0, 0, this.getWidth(), this.getHeight());
 super.paintComponent(g);
 \}
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JOptionPane.showMessageDialog(null, new PaintLabel("hi"));
 \}
 \});
 \}
 \}
 ,,,

 The example below draws an oval underneath the text of a JLabel.

 * override the paintComponent() method for an anonymous JLabel subclass 
 ---------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class AnonymousLabel extends JLabel \{
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JLabel label = new JLabel("paint component") \{
 @Override
 public void paintComponent(Graphics g) \{
 Graphics2D g2d = (Graphics2D) g;
 g2d.setRenderingHint(RenderingHints.KEY\\_ANTIALIASING,
 RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 g2d.drawOval(0,0,this.getWidth()-1,this.getHeight()-1);
 super.paintComponent(g);
 \}
 \};
 label.setFont(new Font("Georgia", Font.PLAIN, 30));
 JOptionPane.showMessageDialog(null, label);
 \}
 \});
 \}
 \}
 ,,,

CONTAINER COMPONENTS

REMOVING COMPONENTS FROM A CONTAINER ....

 * remove all components from a JPanel
 >> jpanel.removeAll();

 * to remove all JLabels from a JPanel, try
 ----------------------------------------------------------
 for (Component c: jpanel.getComponents()) \{
 if (c instanceof JLabel) jpanel.remove(c);
 \}
 ,,,,

FOCUS ....
 
 In an active Java Swing application one component has the 'keyboard focus'
 at any one time. This focus is important because it determines
 which component or components will fire and receive events- especially
 keyboard events. Knowing which component will be focussed is a times
 tricky.

 When a component is placed in a JScrollPane, the component receives focus
 (for example by tabbing, mouse click) but it seems the scrollpane does
 not. This means, for keybindings on a JTextArea in a JScrollPane we use
 the WHEN\\_FOCUSED input map to set up the binding.

 \url{http://docs.oracle.com/javase/tutorial/uiswing/misc/focus.html}
 The Sun tutorial on keyboard focus.

 * attempt to set the focus on a JPanel component
 >> panel.requestFocusInWindow();

 This method apparently only works after a frame.pack() method
 (for some arcane reasons). AncestorListeners may be used in cases
 where the above method is not available.

 * another method for focussing recommended by camickr- investigate
 >> jpanel.setFocusable()

 * make textField get the focus whenever frame is activated.
 -------------------------------------------------------------
 jframe.addWindowFocusListener(new WindowAdapter() \{
 public void windowGainedFocus(WindowEvent e) \{
 textField.requestFocusInWindow();
 \}
 \});
 ,,,

 According to the Sun tutorial on component focussing, you can request
 focus "after the component has been realized (ie after frame.pack()), but
 before the frame is displayed."

 * set a JButton to have focus before the frame is displayed
 -------------------------------------------------------------
 ... 
 JButton button = new JButton("I am first");
 panel.add(button);
 frame.getContentPane().add(panel); 
 
 frame.pack(); // Realize the components.
 button.requestFocusInWindow();
 frame.setVisible(true);
 ,,,
 

\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents old methods (before java 1.4), discouraged
 .. requestFocus
 .. setNextFocusableComponent
 .. etc
 ..

 * make a jlabel focusable and draw a border when focussed
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.event.*;
 import java.awt.BorderLayout;
 public class FocusLabel extends JLabel \{
 public FocusLabel(String text) \{
 super(text);
 this.setFocusable(true);
 this.addMouseListener(new MouseAdapter() \{
 public void mouseClicked(MouseEvent e) \{ requestFocus(); \}
 \});
 this.addFocusListener(new FocusListener() \{
 public void focusGained(FocusEvent e) \{
 setBorder(BorderFactory.createEtchedBorder());
 \}
 public void focusLost(FocusEvent e) \{ setBorder(null); \}
 \});
 \}
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JFrame f = new JFrame();
 f.setSize(new java.awt.Dimension(300, 300));
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.add(new FocusLabel("A focusable JLabel"));
 f.add(new JTextField("south"), BorderLayout.SOUTH);
 f.add(new JTextField("north"), BorderLayout.NORTH);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \});
 \}
 \}
 ,,,

FOCUSLISTENERS AND FOCUSEVENTS ....

 It is possible to perform actions when a JComponent receives or
 loses focus. This is achieved with a FocusListener.

 * a JTextField which turns background blue when it has keyboard focus 
 -------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.plaf.*;
 import java.awt.event.*;
 import java.awt.*;
 public class FocusField extends JTextField \{
 public FocusField(String text) \{
 super(text);
 this.setFocusable(true);
 this.addFocusListener(new FocusListener() \{
 public void focusGained(FocusEvent e) \{
 FocusField.this.setBackground(Color.green); 
 \} 
 public void focusLost(FocusEvent e) \{ 
 FocusField.this.setBackground(Color.white); 
 \}
 \});
 \}
 public static void main(String[] args) \{
 UIManager.put("TextField.font", 
 new FontUIResource("Georgia", Font.PLAIN, 30));
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JFrame f = new JFrame();
 f.setSize(new java.awt.Dimension(300, 300));
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.add(new FocusField("Click in here"));
 f.add(new JTextField("south"), BorderLayout.SOUTH);
 f.add(new JTextField("north"), BorderLayout.NORTH);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \});
 \}
 \}
 ,,,

FOCUSTRAVERSALPOLICY ....
 
 If we want to change the order in which components receive the focus in a
 swing application we can create a custom FocusTraversalPolicy to the
 frame.
 
 To set the initially focussed component we call the getDefaultComponent()
 method of the FocusTraversalPolicy

SIZE OF JCOMPONENTS ....

 This section will discuss general techniques for dealing with swing gui
 components.

 * set a component to fill all the area of its parent
 -------------------------------------------------------------
 public Dimension getPreferredSize() \{
 return this.getParent().getSize(); 
 \}
 ,,,
 

\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents size methods for java.awt.Components
 .. getMinimumSize() — smallest could be shrunk to.
 .. getMaximumSize() — largest it makes sense to grow it to.
 .. getPreferredSize() — ideal size.
 .. getSize() — actual size it is now.
 ..

 These methods often return 0,0 as the size. The reason is, they rely on
 the underlying GUI (Graphic User Interface) to compute the size, and if
 there is no peer object yet, there is no hook to ask the native GUI. See
 addNotify. If you want to manually control any of these sizes, e.g. to
 create a fixed size Component, override : getMinimumSize(),
 getMaximumSize() and getPreferredSize(). 
 
 In Java version 1.5 or later, alternatively you can use Component.
 setMinimumSize, Component. setMaximumSize, and Component.
 setPreferredSize instead of overriding getXXXXsize methods.

EXITING SWING APPLICATIONS ....

 * The people who know seem to prefer DISPOSE\\_ON\\_CLOSE to EXIT\\_ON\\_CLOSE
 >> f.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);

JFRAME WINDOWS .... 

 @@ \url{http://java.sun.com/docs/books/tutorial/uiswing/components/frame.html}

 Application windows are created using the JFrame class. These are also
 known as top level windows because they are not contained by any other
 element (window, container component ...). In order to create a new
 window, which will in turn contain panels, buttons, textboxes and all
 the other bricabrac, there are 2 choices: Create a JFrame within a main
 method (or other suitable method)
 >> JFrame f = new JFrame(); 
 and then add stuff to it, or else subclass the JFrame, for example
 >> public class NewFrame extends JFrame \{ ...
 and add the bric-abrac within the constructor method of the of the
 NewFrame class
 
 * create a 300x300 Window which is centered in the screen 
 ---------------------------------
 import javax.swing.*;
 public class NewFrame \{
 public static void main(String[] args) \{
 JFrame f = new JFrame();
 f.setSize(new java.awt.Dimension(300, 300));
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack();
 f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

 It is necessary to call the "pack" method before the "setLocationRelativeTo"
 because java uses the pack method to work out how big the window will need
 to be in order to contain all its elements, so it wont be able to centre the 
 window on the screen before that.
 * set the size of a window. Its better to call .pack()
 >> jframe.setSize(220, 90);

 If you call setSize, its difficult to know if the window will be big enough
 to display all the stuff it contains.

 * set the title of the window to hi
 >> jframe.setTitle("hi");

 * set the image icon in a window
 >> jframe.setIconImage(new ImageIcon(imgURL).getImage());

 * set the absolute location of the window
 >> f.setLocation(200,300); 

 * make a JFrame open in the centre of the screen
 >> jframe.setLocationRelativeTo(null);

 * make the jframe open big enough to contain its components 
 >> jframe.pack();

 * make the application exit when the window is closed
 >> f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);

 * set the size of a jframe window
 ---------------------------------
 import javax.swing.*;
 public class Test \{
 public static void main(String[] args) \{
 JFrame f = new JFrame();
 f.setSize(new java.awt.Dimension(300, 300));
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

CONTENTPANE FOR JFRAME ....

 The JFrame windows component contains a JPanel swing component which is
 referred to as the 'contentpane'. This content pane by default has a
 BorderLayout manager. Components can not be added to a JFrame directly
 but instead to its contentpane. This is done with
 jframe.getContentPane().add() method. The jframe.add() method is a
 convenience method which adds a component to the content pane (by default
 to the BorderLayout.CENTER position). 

 "The default content pane is a JPanel that uses a BorderLayout. When you
 add a component and don't specify a constraint, then it defaults to the
 CENTER. However you can only add a single component in the center so the
 layout manager only knows about the last one added. When the layout
 manager is invoked it sets the size() and location() of that component.
 The other component has a size of 0, so it is never painted."
 (camickr)

FULL SCREEN WINDOWS ....
 
 On a linux system it appears that the setVisible or the show
 method needs to be invoked before the maximized property is 
 set, strangely. On an ubuntu linux system pack() must be called 
 before the "frame.setExtendedState(Frame.MAXIMIZED\\_BOTH)" code

 For complete full screen applications (to change the screen resolution
 etc) search for the sun tutorial on fullscreen applications

 * make the application window maximized 
 -------------------------------------------------------------
 import java.awt.Frame; 
 import javax.swing.*; 
 public class MaxFrame 
 \{ 
 JFrame frame; 
 public MaxFrame() 
 \{ 
 frame = new JFrame("Test"); 
 frame.setVisible(true); 
 frame.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 \} 
 public static void main(String[] args) \{ new MaxFrame(); \} 
 \} 
 ,,, 

 The frame.show method is probably not very good anymore

 * make the application window maximized and no window decorations
 -------------------------------------------------------------
 import java.awt.Frame; 
 import javax.swing.*; 
 public class UndecoratedFrame 
 \{ 
 JFrame frame; 
 public UndecoratedFrame() 
 \{ 
 frame = new JFrame("Test"); 
 frame.setUndecorated(true);
 frame.show(); 
 frame.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 \} 
 public static void main(String[] args)
 \{ new UndecoratedFrame(); \} 
 \} 
 ,,,

 * make the application window as big as the screen (but not maximized)
 -------------------------------------------------------------
 import javax.swing.JFrame; 
 import java.awt.Toolkit; 
 public class Test 
 \{ 
 JFrame frame; 
 public Test() 
 \{ 
 frame = new JFrame("Test"); 
 Toolkit tk = Toolkit.getDefaultToolkit(); 
 int xSize = ((int) tk.getScreenSize().getWidth()); 
 int ySize = ((int) tk.getScreenSize().getHeight()); 
 frame.setSize(xSize,ySize); 
 frame.setVisible(true); 
 \} 
 public static void main(String[] args) 
 \{ Test app = new Test(); \} 
 \} 
 ,,, 

JINTERNALFRAME

 Dont know much about this. A frame within a window which can
 be minimized etc.

DIALOG BOXES

 A dialog box or window is a window which displays some message
 and refuses to go away until you click one of its buttons. They
 are intensely annoying and should be avoided like botulism.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents Alternative tools
 .. tk - a script based dialog tool
 .. perl-tk - the perl version of the 'tk' tool
 .. zenity - a linux command line dialog tool
 ..


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents JOptionPane dialog boxes
 .. JOptionPane.showMessageDialog()
 .. JOptionPane.showInputDialog()
 .. JOptionPane.showConfirmDialog()
 .. JOptionPane.showOptionDialog()
 ..

 * A simple use of a joptionpane dialog box
 --------------------------------------------
 import javax.swing.*;
 public class MessageDialog \{
 public static void main(String[] args) \{
 JOptionPane.showMessageDialog(null, "Hello!");
 \}
 \}
 ,,,

 According to Oracle, there are some thread problems with directly 
 executing the showMessageDialog() method. The following technique
 is supposed to solve these problems.

 * display a message dialog using a 'thread-safe' technique
 --------------------------------------------
 import javax.swing.*;
 public class MessageDialog \{
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() 
 \{ JOptionPane.showMessageDialog(null, "A thread safe dialog"); \}
 \});
 \}
 \}
 ,,,

 * a dialog box with no icon and a window title 
 --------------------------------------------
 import javax.swing.*;
 public class Test \{
 public static void main(String[] args) \{
 JOptionPane.showMessageDialog(
 null, "Hello!", "Testing Dialogs", JOptionPane.PLAIN\\_MESSAGE);
 \}
 \}
 ,,,

 * a dialog box with a custom icon image 
 ---------------------------------------
 import javax.swing.*;
 public class Test \{
 public static void main(String[] args) \{
 int messageType = JOptionPane.PLAIN\\_MESSAGE; 
 String s = "/usr/share/icons/gnome/24x24/apps/config-users.png";
 ImageIcon icon = new ImageIcon(s, "blob");
 JOptionPane.showMessageDialog(
 null, "New User", "User System", messageType, icon);
 \}
 \}
 ,,,


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents Option Pane button configuration
 .. JOptionPane.DEFAULT\\_OPTION - OK button
 .. JOptionPane.YES\\_NO\\_OPTION - YES and NO buttons
 .. JOptionPane.YES\\_NO\\_CANCEL\\_OPTION - YES, NO, and CANCEL buttons
 .. JOptionPane.OK\\_CANCEL\\_OPTION - OK and CANCEL buttons
 ..

INPUT DIALOGS ....

 * an inputbox which returns the text 
 -------------------------------------
 import javax.swing.*;
 public class InputBox \{
 public static void main(String[] args) \{
 String r = JOptionPane.showInputDialog(
 "Enter address:", "<your address>");
 System.out.println("text entered: " + r);
 \}
 \}
 ,,,

COMBOBOX DIALOG ....

 In Java a combobox is a small box with one line of text in it, and
 a down-arrow which allows the user to select a different value to
 place in the combobox. In html these are called "select boxes".
 
 * a combobox dialog with an array of values which return the selected value 
 --------------------------------------------------------------------
 import javax.swing.*;
 public class ListBoxDialog \{
 public static void main(String[] args) \{
 Object[] values = \{ "Almond", "Oak", "Cork Oak" \};
 Object result = JOptionPane.showInputDialog(
 null, "Choose a tree to plant:", "Testing the Combobox Dialog",
 JOptionPane.PLAIN\\_MESSAGE, null, values, values[0]);
 System.out.println("value selected: " + result);
 \}
 \}
 ,,,

 * a list box with an array of values with a custom icon image 
 -------------------------------------------------------------
 import javax.swing.*;
 public class Test \{
 public static void main(String[] args) \{
 Object[] selValues = \{ "abc", "def", "ghi" \};
 ImageIcon icon = new ImageIcon("blob.gif", "blob");
 Object res = JOptionPane.showInputDialog(
 null, "Enter value:", "Message Title",
 JOptionPane.PLAIN\\_MESSAGE, icon, selValues, selValues[0]);
 System.out.println( "value selected: " + res );
 \}
 \}
 ,,,

JOPTIONPANE ....

 The JOptionPane is useful for prototyping applications since
 the showMessageDialog(...) method can contain any swing component
 It can also be used as a simple way to get some input from the 
 user. The javadocs for JOptionPane are very informative. 

 One can also use an internalFrame format for the dialog.

 * display a JLabel in a option pane message dialog
 >> JOptionPane.showMessageDialog(null, new JLabel("Message"));

 * set the window title for a JOptionPane.showMessageDialog
 -------------------------------------------------------------
 JOptionPane.showMessageDialog(frame,
 "A Message with a window title",
 "The Window Title",
 JOptionPane.PLAIN\\_MESSAGE);
 ,,,

 * a dialog box with a row of buttons to choose from 
 ------------------------------------------------------
 import javax.swing.*;
 public class OptionDialog \{
 public static void main(String[] args) \{
 Object[] trees = \{ "oak", "yew", "elm" \};
 int r = JOptionPane.showOptionDialog(
 null, 
 "Choose a letter", // dialog message string
 "Letters", // dialog window title
 JOptionPane.DEFAULT\\_OPTION, 
 JOptionPane.PLAIN\\_MESSAGE, // no default icon
 null, // no icon
 trees, // an array of objects to choose from 
 trees[0] // default element
 );
 System.out.format("Option selected: \\%s", trees[r]);
 \}
 \}
 ,,,

 * a dialog with a row buttons and an image 
 -------------------------------------------------------------
 import javax.swing.*;
 public class ImageOptionPane \{
 public static void main(String[] args) \{
 ImageIcon icon = new ImageIcon("blob.gif", "blob");
 Object[] vv = \{ "oak", "yew", "jarrah" \};
 int result = JOptionPane.showOptionDialog(
 null, 
 "Which Tree?", // the message in the dialog
 "Trees", // the dialog window title 
 JOptionPane.DEFAULT\\_OPTION, 
 JOptionPane.PLAIN\\_MESSAGE, // no standard icon
 icon,
 vv, vv[0]);
 System.out.format("Option selected: \\%s", result);
 \}
 \}
 ,,,

 If the image doesnt exist no exception is thrown.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents JOptionPane dialog types
 .. showInputDialog() - allows the user to enter some text
 .. showInternalInputDialog() - 
 .. showConfirmDialog() - 
 .. showInternalConfirmDialog() -
 .. showMessageDialog() - display a message or any component
 .. showInternalMessageDialog() - 
 .. showOptionDialog() - 
 .. 
 
 * allow the user to enter a password
 >> String password = JOptionPane.showInputDialog("Enter mail password:");

JCOLORCHOOSER

 The swing component JColorChooser allows the user to choose a 
 colour using different colour models. The component can be used
 as a dialog box or as a component within a container (for example
 a JPanel)

 * create a swing colorchooser component
 >> colorChooser = new JColorChooser();

JCOLORCHOOSER DIALOG ....

 * show a color chooser dialog and determine the result
 -----------------------------------------------------
 import javax.swing.*;
 public class ChooseColor \{
 public static void main(String[] args) \{
 JColorChooser chooser = new JColorChooser();
 int result = chooser.showDialog(...); 
 \}
 \}
 ,,,

JFILECHOOSER 

 The JFileChooser and JColorChooser components can be used either as 
 components added to a container, such as a panel, or else as dialog
 boxes, that is, contained within a new window.

FILECHOOSER DIALOG ....
 
 * display a file chooser with nimbus look and feel 
 ------------------------------------------------
 import javax.swing.*;
 public class NiceFileDialog \{
 public static void main(String[] args) throws Exception \{
 UIManager.setLookAndFeel(
 "javax.swing.plaf.nimbus.NimbusLookAndFeel");
 JFileChooser c = new JFileChooser();
 c.showOpenDialog(null);
 System.exit(-1);
 \}
 \}
 ,,, 

 * show a file chooser dialog and determine the result
 -----------------------------------------------------
 import javax.swing.*;
 public class ChooseFile \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("test file chooser");
 JFileChooser chooser = new JFileChooser();
 int result = chooser.showOpenDialog(f);
 java.io.File file = chooser.getSelectedFile();
 switch (result)
 \{
 case JFileChooser.APPROVE\\_OPTION:
 break;
 case JFileChooser.CANCEL\\_OPTION:
 break;
 \}
 \}
 \}
 ,,,

 Using setFont to set the font for a builtin dialog box doesnt work.
 Another technique is to set the FileChooser font in the
 UIManager defaults.

 * display only directories in a file chooser box
 ------------------------------------------------
 import javax.swing.*;
 public class ChooseFile \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("test file chooser");
 JFileChooser c = new JFileChooser();
 c.setFileSelectionMode(JFileChooser.DIRECTORIES\\_ONLY);
 int result = c.showOpenDialog(f);
 java.io.File file = c.getSelectedFile();
 switch (result)
 \{
 case JFileChooser.APPROVE\\_OPTION:
 break;
 case JFileChooser.CANCEL\\_OPTION:
 System.exit(-1);
 break;
 \}
 \}
 \}
 ,,, 
 
 The example below is by a thompson and illustrate several techniques.

ACCESORIES WITH JFILECHOOSER ....

 The accessory is a panel which can be inserted in the JFileChooser
 dialog to add extra functionality to the file chooser (for example
 a list of recent files). 
 
 According to A.Thompson the FileSystemView.getSystemIcon(File) method
 should return a nicer icon than the standard look and feel, but on a
 gnome-linux computer this doesnt seem to be true. (On windows yes)

 * customising a JFileChooser with an 'accessory' and system icons
 -------------------------------------------------------------
 import java.awt.*;
 import java.io.File;
 import javax.swing.*;
 import javax.swing.border.EmptyBorder;
 import javax.swing.event.*;
 import javax.swing.filechooser.FileSystemView;
 public class Chooser extends JPanel \{
 private static final File[] RECENT\\_DIRECTORIES = File.listRoots();
 public Chooser() \{
 this.setLayout(new BorderLayout());
 JPanel labelPanel = new JPanel(new BorderLayout());
 JLabel label = new JLabel("Recent Directories:");
 labelPanel.add(label, BorderLayout.LINE\\_START);
 labelPanel.setBackground(Color.LIGHT\\_GRAY);
 labelPanel.setBorder(new EmptyBorder(5, 10, 5, 0));
 
 JList list = new JList(RECENT\\_DIRECTORIES);
 list.setCellRenderer(new DefaultListCellRenderer() \{
 FileSystemView fsv = FileSystemView.getFileSystemView();
 @Override
 public Component getListCellRendererComponent(
 JList list, Object value, int index, 
 boolean isSelected, boolean cellHasFocus) \{
 JLabel label = (JLabel) super.getListCellRendererComponent(
 list, value, index, isSelected, cellHasFocus);
 if (value instanceof File) \{
 label.setIcon(fsv.getSystemIcon((File)value));
 \}
 return label;
 \}
 \});
 
 list.setBorder(new EmptyBorder(0, 5, 5, 0));
 list.addListSelectionListener(new ListSelectionListener() \{
 public void valueChanged(ListSelectionEvent e) \{
 // respond to selection here
 \}
 \});
 
 add(labelPanel, BorderLayout.PAGE\\_START);
 add(new JScrollPane(list), BorderLayout.CENTER);
 \}
 
 public static void main(String[] args) throws Exception \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JFileChooser fileChooser = new JFileChooser();
 Chooser c = new Chooser();
 fileChooser.setAccessory(c);
 fileChooser.showOpenDialog(null);
 \}
 \});
 \}
 \}
 ,,,

JCOMBOBOX

 The JComboBox component provides an one line text box which may or may
 not be editable and an attached pop-up or drop-down list of items to
 choose from. The combobox can be either editable or non-editable and
 mutable or non-mutable which means that items can be added and removed
 from the list.

 @@ \url{http://www.exampledepot.com/egs/javax.swing/combobox\\_CbKeyPopup.html}
 Good JComboBox examples


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents useful methods for the JComboBox
 .. setSelectedIndex(4) - make the 5th element the selected one
 .. setEditable(true) - make the JComboBox editable
 .. setEditor(ComboBoxEditor) - sets the editor to use
 .. getItemCount() - how many items are in the dropdown menu
 .. getSelectedItem() - get the text in the box for an editable combobox
 .. setModel(model) - sets the ComboBoxModel
 .. getModel() - returns the ComboBoxModel
 .. isPopupVisible() - whether the dropdown (or popup) menu can be seen
 .. showPopup(true) - shows the dropdown menu 
 .. setMaximumRowCount(20) - make 20 items visible in the dropdown menu
 .. getMaximumRowCount() - how many items are visible (the default is 8) 
 ..

 Strangely, the methods for a mutable JComboBox which change the box
 dropdown menu do not act upon the ComboBoxModel but on the box itself.
 This is in contrast to the JList component.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents methods for a mutable JComboBox (uses MutableComboBoxModel)
 .. addItem("oak") - adds "oak" at the end of the box menu
 .. insertItem("acacia", 1) - adds 'acacia' just after the first item
 .. removeAllItems() - removes all items from the JComboBox menu
 ..
 
 * initialize a JComboBox with an array of strings
 -------------------------------------------------------------
 String[] animals = \{ "Bird", "Cat", "Dog", "Rabbit", "Pig" \};
 JComboBox box = new JComboBox(animals);
 ,,,

POPUPMENU FOR JCOMBOBOX ....

 How to keep the popup menu from closing
 \url{http://stackoverflow.com/questions/2778682/how-to-keep-the-popup-menu-of-a-jcombobox-open-on-populating-it}
 
EDITABLE JCOMBOBOXES ....

 The default editing component for a JComboBox is a JTextField

 An editable Swing JComboBox allows the user to modify the text in the
 field. Since JComboBox has a setEditor() method, it seems possible to use
 any JTextComponent as the editor for a combobox. This means we could use
 a styled editor such as JTextPane.

 But first some simple examples of editable comboboxes.

 * create an editable JComboBox 
 -----------
 import java.awt.*;
 import javax.swing.*;
 public class ComboPanel extends JPanel \{
 JComboBox box;
 public ComboPanel() \{
 super(new BorderLayout());
 String[] aa = \{ "Bird", "Cat", "Dog", "Rabbit", "Pig" \};
 this.box = new JComboBox(aa);
 this.box.setEditable(true); 
 this.box.setFont(new Font("Georgia", Font.PLAIN, 30));
 this.add(this.box, BorderLayout.CENTER);
 \}
 public static void main(String[] args) throws Exception \{
 JPanel p = new ComboPanel();
 JOptionPane.showMessageDialog(null, p);
 \} 
 \}
 ,,,

 In the example above the box uses the default editor (what
 ever that may be) to allow editing of the box.

 In the example below, when the user modifies the text in the 
 JComboBox and presses enter, a new item with the modified text
 is added to the items of the dropdown menu for the box.

 The component below can become a very useful user interface element
 since it provides an easy way for a user to add items to a list,
 or search a list.

 * create an editable and mutable JComboBox, add new items
 -----------
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 public class ComboPanel extends JPanel implements ActionListener \{
 JComboBox box;
 public ComboPanel() \{
 super(new BorderLayout());
 this.box = new JComboBox(new DefaultComboBoxModel());
 this.box.setEditable(true); 
 this.box.setFont(new Font("Georgia", Font.PLAIN, 30));
 this.box.addItem("Oak"); this.box.addItem("Acacia");
 this.box.addItem("Yew");
 this.box.addActionListener(this);
 this.add(this.box, BorderLayout.CENTER);
 \}
 public void actionPerformed(ActionEvent e) \{
 JComboBox cb = (JComboBox) e.getSource();
 String s = (String) cb.getSelectedItem();
 if ("comboBoxEdited".equals(e.getActionCommand())) 
 this.box.addItem(s);
 \}
 public static void main(String[] args) throws Exception \{
 JPanel p = new ComboPanel();
 JFrame t = new JFrame();
 t.getContentPane().add(p);
 t.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 t.pack(); t.setLocationRelativeTo(null);
 t.setVisible(true);
 \} 
 \}
 ,,,

CELLRENDERERS AND CUSTOMISING COMBOBOX ITEM APPEARANCE ....

 The JComboBox uses, by default, the same cell renderer as the JList
 component. This is the DefaultListCellRenderer component, which is really
 just a type of JLabel with some performance modifications.

 To customise the appearance of items in the 'pop-up' menu
 for a JComboBox there are 3 choices (in increasing order of 
 flexibility): set a property on the default renderer with for example
 >> ((JLabel)combobox.getCellRenderer()).setBackground(Color.orange);

 Or, subclass (extend) the DefaultListCellRenderer and the new subclass
 to the JComboBox with the setCellRenderer() method. Or finally, 
 implement the ListCellRenderer interface. The 2nd method is probably
 the best, since it offers great flexibility for the appearance of the 
 combobox pop-up menu items, without much complexity for the programmer.

 Another technique maybe to override the toString() method for the 
 class which is contained in the pop-up list.

 * displays fonts in a combobox and uses the font for the item 
 -------------------------------------------------------------
 import java.awt.*;
 import javax.swing.*;
 public class ShowFonts \{
 public static void main(String[] args) \{
 SwingUtilities.invokeLater( new Runnable() \{
 public void run() \{
 GraphicsEnvironment ge = GraphicsEnvironment.
 getLocalGraphicsEnvironment();
 String[] fonts = ge.getAvailableFontFamilyNames();
 JComboBox fontChooser = new JComboBox(fonts);
 fontChooser.setRenderer(new FontCellRenderer());
 JOptionPane.showMessageDialog(null, fontChooser);
 \}
 \});
 \}
 \}
 class FontCellRenderer extends DefaultListCellRenderer \{
 public Component getListCellRendererComponent(
 JList list, Object value, int index,
 boolean isSelected, boolean cellHasFocus) \{
 JLabel label = (JLabel)super.getListCellRendererComponent(
 list,value,index,isSelected,cellHasFocus);
 Font font = new Font((String)value, Font.PLAIN, 20);
 label.setFont(font);
 return label;
 \}
 \}
 ,,,

 * make alternate rows in the pop-up menu different colours 
 -------------------------------------------------------------
 import java.awt.*;
 import java.io.File;
 import javax.swing.*;
 public class RowColorBox \{
 public static void main(String[] args) \{
 SwingUtilities.invokeLater( new Runnable() \{
 public void run() \{
 JComboBox box = new JComboBox(new File(".").list());
 box.setRenderer(new RowColorRenderer());
 JOptionPane.showMessageDialog(null, box);
 \}
 \});
 \}
 \}
 class RowColorRenderer extends DefaultListCellRenderer \{
 public Component getListCellRendererComponent(
 JList list, Object value, int index,
 boolean isSelected, boolean cellHasFocus) \{
 JLabel label = (JLabel)super.getListCellRendererComponent(
 list,value,index,isSelected,cellHasFocus);
 if ((index \\% 2)==0) label.setBackground(Color.orange);
 return label;
 \}
 \}
 ,,,

 * another cellrenderer eg from camickr, not compiling (setdragenabled?)
 -------------------------------------------------------------
 import java.awt.*;
 import java.awt.event.*;
 import java.util.*;
 import javax.swing.*;
 import javax.swing.plaf.basic.*;
 
 public class ComboBoxItem extends JFrame implements ActionListener \{
 public ComboBoxItem() \{
 Vector model = new Vector();
 model.addElement( new Item(1, "car" ) );
 model.addElement( new Item(2, "plane" ) );
 model.addElement( new Item(3, "train" ) );
 model.addElement( new Item(4, "boat" ) );
 
 JComboBox comboBox;
 
 // Easiest approach is to just override toString() method
 // of the Item class
 comboBox = new JComboBox( model );
 //comboBox.setDragEnabled(true);
 comboBox.addActionListener( this );
 getContentPane().add(comboBox, BorderLayout.NORTH );
 
 // Most flexible approach is to create a custom renderer
 // to display the Item data
 comboBox = new JComboBox( model );
 //comboBox.setDragEnabled(true);
 comboBox.setRenderer( new ItemRenderer() );
 comboBox.addActionListener( this );
 getContentPane().add(comboBox, BorderLayout.SOUTH );
 \}
 
 public void actionPerformed(ActionEvent e) \{
 JComboBox comboBox = (JComboBox)e.getSource();
 Item item = (Item)comboBox.getSelectedItem();
 System.out.println( item.getId() + " : " + item.getDescription() );
 \}
 
 class ItemRenderer extends BasicComboBoxRenderer \{
 public Component getListCellRendererComponent(
 JList list, Object value, int index,
 boolean isSelected, boolean cellHasFocus) \{
 super.getListCellRendererComponent(list, value, index,
 isSelected, cellHasFocus);
 if (value != null) \{
 Item item = (Item)value;
 setText( item.getDescription().toUpperCase() );
 \}
 if (index == -1) \{
 Item item = (Item)value;
 setText( "" + item.getId() );
 \}
 return this;
 \}
 \}
 
 class Item \{
 private int id;
 private String description;
 public Item(int id, String description) \{
 this.id = id;
 this.description = description;
 \}
 
 public int getId() \{
 return id;
 \}
 public String getDescription() \{ return description; \}
 public String toString() \{ return description; \}
 \}
 
 public static void main(String[] args) \{
 JFrame frame = new ComboBoxItem();
 frame.setDefaultCloseOperation( EXIT\\_ON\\_CLOSE );
 frame.pack();
 frame.setVisible( true );
 \}
 \}
 ,,,

COMBOBOXMODELS ....

 In order to supply data, or items to the JComboBox we use 
 the ComboBoxModel interface or one of its implementations.
 The simplest model to use is the DefaultComboBoxModel which is
 an implementation of MutableComboBoxModel (an abstract class) and
 therefore allows the adding and removal of items in the drop down
 menu.

 * create a box and pass some values to its (mutable) ComboBoxModel
 >> JComboBox box = new JComboBox(new DefaultComboBoxModel(new String[]\{"one","two"\}));

 * pass an array of initial values to a combobox's (mutable) ComboBoxModel
 -------------------------------------------------------------
 String[] ss = \{"cloud", "star", "sky"\};
 JComboBox box = new JComboBox(new DefaultComboBoxModel(ss));
 ,,,

 This is a simple way to initialize the dropdown (or pop-up) menu for a
 mutable JComboBox. After the box is created items can be added with
 box.addItem(object)

 The Vector use here below seems unnecessarily outdated.

 * create a combobox model which maintains its items sorted alphabetically
 -------------------------------------------------------------
 import java.util.Vector;
 import javax.swing.DefaultComboBoxModel;
 public class SortedComboBoxModel extends DefaultComboBoxModel \{
 public SortedComboBoxModel(Object[] element) \{
 for (int i =0, l =element.length; i <l; i++) \{
 addElement(element[i]);
 \}
 \}
 public SortedComboBoxModel(Vector element) \{
 for (int i =0, l =element.size(); i <l; i++) \{
 addElement(element.elementAt(i));
 \}
 \}
 public void addElement(Object element) \{
 int i, l;
 for (i =0, l =getSize(); i <l; i++) \{
 if (((String)element).compareTo(getElementAt(i)) <0) break;
 \}
 insertElementAt(element, i);
 \}
 \}
 ,,,

JCOMBOBOX EVENTS AND LISTENERS

ITEMLISTENERS ....

 * implement ItemListener interface
 -------------------------------------------------------------
 public void itemStateChanged(ItemEvent e) \{
 String componentName = (String)e.getItem();
 selectedItem = componentName;
 \}
 ,,,

 * when we change the elements the box we have to remove itemlistener
 -------------------------------------------------------------
 comboBox.removeItemListener( this );
 comboBox.setModel( new DefaultComboBoxModel( comboBoxItems ) );
 comboBox.setSelectedIndex(-1);
 comboBox.addItemListener( this );
 ,,,

DOCUMENTLISTENER FOR A JCOMBOBOX ....

 Probably the correct way to listen for changes in the text field
 of an editable combobox is to use a DocumentListener.

 When a JComboBox is editable, the editable text field, like all
 JTextComponents, has an associated Document (which is the model which
 manages the text in the component). That means that you can 
 create a DocumentListener to listen to changes made by typing in
 the editable JComboBox.
 
 * install a DocumentListener for a JComboBox
 -----------------------------------------------
 final JTextComponent tc = 
 (JTextComponent) combo.getEditor().getEditorComponent();
 tc.getDocument().addDocumentListener(this);
 ,,,

 * install an anonymous DocumentListener
 -------------------------------------------------------------
 final JTextComponent tc = (JTextComponent) comboA.getEditor().getEditorComponent();
 tc.getDocument().addDocumentListener(new DocumentListener() \{
 ...
 \});
 ,,,

 The following code needs alot of work to stop IllegalStateExceptions. I
 think I am violating the principle of not modifying a document from
 within the Event handler. Also this should extend the JComboBox class to
 allow it to be easily used. Also there is the problem of how to keep the
 popup menu open (not reopen it, because that causes an unpleasant
 flashing effect). All this might be easier with a KeyListener because
 the DocumentListener has a tendency to go into an infinite loop. 

 Despite these problems, this component has the potential to be 
 a useful searcher and selector.

 * filter a combobox list of class methods based on keystrokes
 -----------
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import javax.swing.text.*;
 import javax.swing.event.*;
 import java.lang.reflect.*;
 public class ComboPanel extends JPanel implements ActionListener, DocumentListener \{
 JComboBox box;
 public ComboPanel() \{
 super(new BorderLayout());
 Class c = "s".getClass();
 Method mm[] = c.getMethods();
 this.box = new JComboBox(new DefaultComboBoxModel(mm));
 this.box.setEditable(true);
 this.box.setFont(new Font("Georgia", Font.PLAIN, 30));
 this.box.addItem("Oak");
 this.box.addItem("Acacia");
 this.box.addItem("Yew");
 this.box.addActionListener(this);
 final JTextComponent tc = (JTextComponent) this.box.getEditor().getEditorComponent();
 tc.getDocument().addDocumentListener(this);
 this.add(this.box, BorderLayout.CENTER);
 \}
 public void insertUpdate(DocumentEvent e) \{
 this.filter(e);
 \}
 public void removeUpdate(DocumentEvent e) \{
 this.filter(e);
 \}
 public void changedUpdate(DocumentEvent e) \{
 //JTextFields dont fire these events
 \}
 
 public void filter(DocumentEvent e) \{
 // this.box.showPopup();
 String s =
 String.format(
 "Action type: \\%s, Doc Offset: \\%d, Change Length: \\%d \\$\\backslash\\$n",
 e.getType().toString(), e.getOffset(), e.getLength());
 System.out.println(s);
 // a trick
 SwingUtilities.invokeLater(new Runnable() \{
 @Override
 public void run() \{
 ComboPanel.this.box.removeItemAt(ComboPanel.this.box.getSelectedIndex());
 \}
 \});
 
 /*
 for (int i = 0; i < this.box.getItemCount(); i++)
 \{
 if (this.box.getItemAt(i).toString().toLowerCase().indexOf(s) > 0)
 System.out.println(this.box.getItemAt(i));
 \}
 */
 \}
 public void actionPerformed(ActionEvent e) \{
 JComboBox cb = (JComboBox) e.getSource();
 String s = (String) cb.getSelectedItem().toString();
 //if ("comboBoxEdited".equals(e.getActionCommand()))
 //this.box.addItem(s);
 \}
 public static void main(String[] args) throws Exception \{
 JPanel p = new ComboPanel();
 JFrame t = new JFrame();
 t.getContentPane().add(p);
 t.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 t.pack();
 t.setLocationRelativeTo(null);
 t.setVisible(true);
 \}
 \}
 ,,,

 
KEYLISTENERS FOR A JCOMBOBOX ....

 The sun/oracle swing tutorial for JComboBoxes explicitly recommends not
 to use KeyListeners on a combobox, since it is a compound component.
 Apparently a keylistener would be dependant on the look and feel of the
 interface. However this makes implementing a search box (where the
 dropdown list is progressively filtered based on the contents of the
 editable text box) difficult. The alternative is to use a DocumentListener
 but that fires events when the user selects from the list.

 We will ignore the advice, for the time being.

 * listen to any printable keystroke and show the combobox popupmenu
 -------------------------------------------------------
 JComboBox cb = new JComboBox(items);
 cb.addKeyListener(new MyKeyListener());
 class MyKeyListener extends KeyAdapter \{
 public void keyPressed(KeyEvent evt) \{
 JComboBox cb = (JComboBox)evt.getSource();
 char ch = evt.getKeyChar();
 // If not a printable character, do nothing
 if (ch != KeyEvent.CHAR\\_UNDEFINED) \{
 cb.showPopup();
 \}
 \}
 \}
 ,,,

 * handle how keystrokes select an item in a JComboBox
 -------------------------------------------------------------
 cb.setKeySelectionManager(new MyKeySelectionManager());
 class MyKeySelectionManager implements JComboBox.KeySelectionManager \{
 ...
 ,,,

 
ACTIONLISTENER FOR A JCOMBOBOX ....

 The ActionEvent for a JComboBox is fired when a user select a 
 new item from the combobox drop down menu. It is also fired when
 the JComboBox is editable and the user presses the Enter key.

 The code snippet below is important because a JComboBox fires an
 ActionEvent when a user presses enter in an editable box, and also when
 the user selects a new item. And maybe also when the user moves the
 selection down the dropdown menu.

 * distinguish between a text edit and new selection in an ActionListener
 -------------------------------------------------------------
 if ("comboBoxEdited".equals(evt.getActionCommand())) \{
 // User has typed in a string; only possible with an editable combobox
 \} else if ("comboBoxChanged".equals(evt.getActionCommand())) \{
 // User has selected an item; it may be the same item
 \}
 ,,,
 
 * write information about JComboBox ActionEvents to a JTextArea 
 -----------
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 public class ComboPanel extends JPanel implements ActionListener \{
 JComboBox box;
 JTextArea area;
 public ComboPanel() \{
 super(new BorderLayout());
 String[] aa = \{ "Bird", "Cat", "Dog", "Rabbit", "Pig" \};
 this.box = new JComboBox(aa);
 this.box.addActionListener(this);
 this.area = new JTextArea(60, 10);
 this.area.setLineWrap(true);
 this.add(this.area, BorderLayout.CENTER);
 this.add(this.box, BorderLayout.NORTH);
 \}
 public void actionPerformed(ActionEvent e) \{
 JComboBox cb = (JComboBox) e.getSource();
 String s = (String) cb.getSelectedItem();
 this.area.append(e.toString());
 \}
 public static void main(String[] args) throws Exception \{
 JPanel p = new ComboPanel(); 
 p.setPreferredSize(new Dimension(300, 600));
 JOptionPane.showMessageDialog(null, p);
 \} 
 \}
 ,,,

ITEMLISTENERS FOR JCOMBOBOX ....

 An ItemEvent is fired by a JComboBox when an item in the 
 drop down menu is selected or unselected (eg: highlighted blue)
 This is subtly different from the ActionEvent selection event.
 An ItemListener can be used to react to changes in the item
 selection state.

JLISTS
 
 The Swing JList component displays a vertical list of items (objects).
 Like many Swing components the data is supplied by a model, in this case
 a ListModel.

 To supply content to the JList box the programmer has several choices:
 implement the ListModel interface, extend the AbstractListModel, or use
 the DefaultListModel. JLists can also be initialized with an array but
 in that case it is not possible to add or remove elements in the JList
 after it has been created.
 

\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents useful methods for the JList box 
 .. getSelectedIndex - get the index number of the selected item
 .. getSelectedValue - get the value (usually text) associated with selected item
 .. setSelectionBackground(Color.RED) - set the selection backgroud color
 ..
 .. 

 * set some parameters for a listbox
 -------------------------------------------------------------
 list = new JList(data); //data has type Object[]
 list.setSelectionMode(ListSelectionModel.SINGLE\\_INTERVAL\\_SELECTION);
 list.setLayoutOrientation(JList.HORIZONTAL\\_WRAP);
 list.setVisibleRowCount(-1);
 ,,,

 * set the selectmode, but is all this necessary?
 >> list.getSelectionModel().setSelectionMode(ListSelectionModel.MULTIPLE\\_INTERVAL\\_SELECTION);
 
 * get the value of an element in a list at in 4
 >> s = (String)list.getModel().getElementAt(4);
 
 * create an immutable JList supplying the elements from an array 
 --------------------------------------------------
 import javax.swing.*;
 import java.io.*;
 public class ListBox \{
 public static void main(String[] args) throws Exception \{
 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
 JFrame t = new JFrame();
 String[] ss = \{"Eucalypt", "Oak", "Apple", "Walnut"\};
 JList trees = new JList(ss);
 JPanel pl = new JPanel();
 pl.add(new JScrollPane(trees));
 t.getContentPane().add(pl);
 t.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 t.pack(); t.setLocationRelativeTo(null);
 t.setVisible(true);
 \}
 \}
 ,,,

 * a listbox with a different font and colour 
 --------------------------------------------------
 import javax.swing.*;
 import java.awt.Font;
 public class Box \{
 public static void main(String[] args) \{
 JFrame t = new JFrame();
 String[] ss = \{"Eucalypt", "Cork Oak", "Apple", "Walnut"\};
 JList trees = new JList(ss);
 trees.setFont(new Font("Georgia", Font.PLAIN, 30));
 JPanel p = new JPanel(); p.add(trees);
 t.getContentPane().add(p);
 t.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 t.setLocationRelativeTo(null);
 t.pack(); t.setVisible(true);
 \}
 \}
 ,,,

 If we explicitly use the DefaultListModel as the 'data model' for the 
 swing listbox, then we can add and remove elements from the listbox
 after it has been created.

 * create a list box to which elements can be added or removed 
 --------------------------------------------------
 import javax.swing.*;
 import java.awt.Font;
 public class Box \{
 public static void main(String[] args) \{
 JFrame t = new JFrame();
 DefaultListModel listModel = new DefaultListModel();
 listModel.addElement("Tibouchina");
 listModel.addElement("Siete Cueros");
 listModel.addElement("Hevea Brasiliensis");
 JList trees = new JList(listModel);
 trees.setFont(new Font("Georgia", Font.PLAIN, 30));
 JPanel p = new JPanel(); p.add(trees);
 t.getContentPane().add(p);
 t.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 t.setLocationRelativeTo(null);
 t.pack(); t.setVisible(true);
 \}
 \}
 ,,,

 * displays a file list in the center of the screen
 --------------------------------------------------
 import javax.swing.*;
 import java.io.*;
 import java.awt.Font;
 public class FileList \{
 public static void main(String[] args) \{
 JFrame t = new JFrame();
 JList fileList = new JList((new File(".")).listFiles());
 fileList.setFont(new Font("Georgia", Font.PLAIN, 50));
 JPanel pl = new JPanel();
 pl.add(new JScrollPane(fileList));
 t.getContentPane().add(pl);
 t.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 t.pack(); t.setLocationRelativeTo(null);
 t.setVisible(true);
 \}
 \}
 ,,,

SELECTIONS FOR JLISTS ....

 A JList can allow the user to select items from the list in
 various ways- such as only allowing one item to be selected,
 several contiguous items selected or non-contiguous multiple
 items selected.

 * set the selection mode for a JList component.
 >> list.setSelectionMode(ListSelectionModel.SINGLE\\_INTERVAL\\_SELECTION);


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents selection modes of the ListSelectionModel
 .. SINGLE\\_INTERVAL\\_SELECTION - multiple contiguous items
 ..
 ..

LISTMODELS ....

 The task of the ListModel is to supply data, or objects to the 
 JList component. The interface contains a set of methods which the 
 JList can use to interrogate the ListModel for available data.

 The simplest way to use a model with a JList box is to 
 use the ListModel subclass DefaultListModel. The most flexible
 way is to implement the ListModel interface.

 * jlist box with lots of numbers using an AbstractListModel 
 ---------------------------------------------------
 import javax.swing.*;
 public class Test \{
 public static void main(String[] args) \{
 ListModel bigData = new AbstractListModel() \{
 public int getSize() \{ return Short.MAX\\_VALUE; \}
 public Object getElementAt(int index) \{ return "Index " +
 index; \}
 \};
 JList dataList = new JList(bigData);
 // the following makes rendering quicker
 dataList.setPrototypeCellValue("Index 1234567890");
 JFrame f = new JFrame();
 f.getContentPane().add(new JScrollPane(dataList));
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLocationRelativeTo(null); 
 f.pack();
 f.setVisible(true);
 \}
 \}
 ,,,

 * a list box with an AbstractListModel and unicode characters
 ------------------------------------------------
 import javax.swing.*;
 public class UnicodeBox \{
 public static void main(String[] args) \{
 ListModel bigData = new AbstractListModel() \{
 public int getSize() \{ return Short.MAX\\_VALUE; \}
 public Object getElementAt(int index)
 \{ return "unicode " + index + 1000 + ":" + (char)(index + 1000); \}
 \};
 JList unicodeList = new JList(bigData);
 unicodeList.setPrototypeCellValue("Index 1234567890");
 JPanel p = new JPanel(); 
 p.add(new JScrollPane(unicodeList));
 JFrame f = new JFrame();
 f.getContentPane().add(p);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLocationRelativeTo(null); 
 f.pack();
 f.setVisible(true);
 \}
 \}
 ,,,

DEFAULTLISTCELLRENDERER ....

 The javax.swing.JList component by default uses a type of JLabel to
 render each item in the list- this is called a DefaultListCellRenderer.
 It is possible to customise the elements in a JList by setting
 properties of the CellRenderer. The default cell renderer is an opaque
 label, whereas JLabels by default are not.

 The JComboBox also uses the DefaultListCellRenderer class to display
 each item of its 'pop-up' list, so all the techniques learnt here 
 are applicable also to that component.

 * right align text in JList elements
 -------------------------------------------------------------
 DefaultListCellRenderer r = 
 (DefaultListCellRenderer)list.getCellRenderer();
 r.setHorizontalAlignment(SwingConstants.RIGHT);
 ,,,

 * another way to set a property of each element of a list
 -------------------------------------------------------------
 JLabel l = (JLabel) list.getCellRenderer();
 l.setHorizontalAlignment(SwingConstants.RIGHT);
 ,,,

 * a more succint method to do the same
 >> ((JLabel)list.getCellRenderer()).setHorizontalAlignment(JLabel.RIGHT);

 * right align all elements in a jlist using the default cell renderer 
 --------------------------------------------------
 import javax.swing.*;
 import java.io.*;
 import java.awt.Font;
 public class ListRenderer \{
 public static void main(String[] args) \{
 JList list = new JList((new File(".")).list());
 list.setFont(new Font("Georgia", Font.PLAIN, 20));
 DefaultListCellRenderer r = 
 (DefaultListCellRenderer) list.getCellRenderer();
 r.setHorizontalAlignment(JLabel.RIGHT);
 JOptionPane.showMessageDialog(null, list);
 \}
 \}
 ,,,

 It seems that it is necessary to subclass the DefaultListCellRenderer
 in order to put a Border or an Icon in each JList item cell. This
 is because these properties get 'cleared' by the default renderer
 and so we *cant* just use:
 >> ((JLabel)list.getCellRenderer().setIcon(...)

EXTENDING THE DEFAULTLISTCELLRENDERER ....

 Possibly the simplest way to customise the appearance of JList cells (the
 component which contains each item), is to extend the
 DefaultListCellRenderer (which is a type of JLabel). It may only be
 necessary to override the getListCellRendererComponent() method, which
 returns the component which contains each item of the list.

 * set a border for each JList item 
 -------------------------------------------------------------
 import javax.swing.*;
 import java.io.File;
 import java.awt.Component;
 public class BorderList \{
 public static void main(String[] args) \{
 JList list = new JList(new File(".").list());
 list.setCellRenderer(new BorderRenderer());
 JOptionPane.showMessageDialog(null, list);
 \}
 \}
 class BorderRenderer extends DefaultListCellRenderer \{
 public Component getListCellRendererComponent(
 JList list, Object o, int index, 
 boolean isSelected, boolean cellHasFocus) \{
 JLabel label = (JLabel) super.getListCellRendererComponent(
 list, o, index, isSelected, cellHasFocus); 
 label.setBorder(BorderFactory.createEtchedBorder());
 return label;
 \}
 \}
 ,,,

 The code below may have the problem that the 'index' value is 
 apparently not alway valid, so use instead:
 >> int selectedIndex = ((Integer)object).intValue(); 

 * make the rows of the JList alternate colours
 ----------------------------------------------
 import javax.swing.*;
 import java.io.File;
 import java.awt.*;
 public class RowColorList \{
 public static void main(String[] args) \{
 JList list = new JList(new File(".").list());
 list.setCellRenderer(new ColorRenderer());
 JFrame f = new JFrame("A JList with alternate coloured rows");
 f.add(new JScrollPane(list));
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 class ColorRenderer extends DefaultListCellRenderer \{
 public Component getListCellRendererComponent(
 JList list, Object o, int index, 
 boolean isSelected, boolean cellHasFocus) \{
 JLabel label = (JLabel) super.getListCellRendererComponent(
 list, o, index, isSelected, cellHasFocus); 
 if ((index \\% 2) == 0) label.setBackground(Color.lightGray);
 return label;
 \}
 \}
 ,,,

 The icons which are displayed in the example below are not very nice, at
 least on my gnome-linux system, they are not the same icons used by the
 nautilus file browser for example.

 The example below is succint and powerful. By subclassing the 
 DefaultListCellRenderer not much code needs to be written in order to 
 achieve interesting things.
 
 * a technique to display the system file/folder icon for each item 
 -------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.filechooser.FileSystemView;
 import java.io.File;
 import java.awt.*;
 public class FileIconList \{
 public static void main(String[] args) \{
 JList list = new JList(new File(".").listFiles());
 list.setFont(new Font("Georgia", Font.PLAIN, 20));
 list.setCellRenderer(new DefaultListCellRenderer() \{
 FileSystemView fsv = FileSystemView.getFileSystemView();
 @Override
 public Component getListCellRendererComponent(
 JList list, Object value, int index,
 boolean isSelected, boolean cellHasFocus) \{
 JLabel label = (JLabel) super.getListCellRendererComponent(
 list, value, index, isSelected, cellHasFocus);
 if (value instanceof File) \{
 label.setIcon(fsv.getSystemIcon((File)value));
 label.setText(((File)value).getName());
 \}
 return label;
 \}
 \});
 JOptionPane.showMessageDialog(null, list);
 \}
 \}
 ,,,

 According to "howard": The DefaultListCellRenderer clears the icon
 whenever its getListCellRendererComponent method is called. So the 
 same probably applies to the border property

 The method below (suggested by howard@stackoverflow) creates an
 anonymous subclass of the default renderer for JList cells. The
 technique below could also be used to set the border for all
 JList items.
 
 * one method to set the icon for each item in a JList
 -------------------------------------------------------------
 list.setCellRenderer(new DefaultListCellRenderer() \{
 @Override
 public Component getListCellRendererComponent(
 JList list, Object value, int index, 
 boolean isSelected, boolean cellHasFocus) \{
 JLabel label = (JLabel) super.getListCellRendererComponent(
 list, value, index, isSelected, cellHasFocus);
 label.setIcon(icon);
 return label;
 \}
 \});
 ,,,

LISTCELLRENDERER INTERFACE ....

 It is possible to customize the way that each list element in a swing
 list box is rendered by implementing the ListCellRenderer interface.
 This involves writing a body for the getListCellRendererComponent method

 Another method is simply to customize the DefaultListCellRenderer 
 which is a type of opaque JLabel.

 Extending a JLabel to implement a ListCellRenderer probably will
 have performance problems.

 * An example of a ListCellRenderer implementation
 -------------------------------------------------------------
 import javax.swing.*;
 class ColourCell extends JLabel implements ListCellRenderer \{
 public ColourCell() \{ setOpaque(true); \}
 public Component getListCellRendererComponent(
 JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)
 \{
 this.setText(value.toString());
 // Is the listbox item currently selected?
 if (isSelected) \{
 this.setBackground(Color.RED);
 this.setForeground(Color.WHITE);
 \} else \{
 this.setBackground(Color.WHITE);
 this.setForeground(Color.GRAY);
 \}
 return this;
 \}
 \}
 ,,,

 There maybe performance problems with the technique used below because
 of the JLabel. For this reason it may be preferable to extend the 
 DefaultListCellRenderer class, since that class uses a modified JLabel
 with the performance problems fixed.

 * create a cellrenderer to make the selection white on red and the font big 
 --------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 import java.io.File;
 public class ColorSelectionList \{
 public static void main(String[] args) \{
 JFrame t = new JFrame();
 JList fileList = new JList((new File(".")).listFiles());
 ColourCell renderer = new ColourCell();
 //renderer.setPreferredSize(new Dimension(200, 130));
 fileList.setCellRenderer(renderer);
 JPanel pl = new JPanel();
 pl.add(new JScrollPane(fileList));
 t.add(pl); t.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 t.pack(); t.setLocationRelativeTo(null);
 t.setVisible(true);
 \}
 \}
 class ColourCell extends JLabel implements ListCellRenderer \{
 public ColourCell() \{
 this.setOpaque(true);
 this.setFont(new Font("Georgia", Font.PLAIN, 30));
 \}
 
 public Component getListCellRendererComponent(
 JList list, Object o, int index, boolean isSelected, boolean cellHasFocus)
 \{
 this.setText(value.toString());
 // Is the listbox item currently selected?
 if (isSelected) \{
 this.setBackground(Color.RED);
 this.setForeground(Color.WHITE);
 \} else \{
 this.setBackground(Color.WHITE);
 this.setForeground(Color.GRAY);
 \}
 return this;
 \}
 \}
 ,,,

 According to the Sun java tutorial site the índex parameter to the 
 getListCellRendererComponent is not always valid. Which seems odd.
 So instead we can use
 >> int selectedIndex = ((Integer)value).intValue(); ???

 See the DefaultListCellRenderer section above for an alternative
 (and probably better) way to do this.

 * create a cellrenderer to colour alternate rows light blue in the jlistbox 
 --------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 import java.io.File;
 public class AlternateRowList \{
 public static void main(String[] args) \{
 JFrame t = new JFrame();
 JList fileList = new JList((new File("..")).listFiles());
 ColourCell renderer = new ColourCell();
 fileList.setCellRenderer(renderer);
 JPanel pl = new JPanel();
 pl.add(new JScrollPane(fileList));
 t.getContentPane().add(pl);
 t.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 t.setLocationRelativeTo(null);
 t.pack();
 t.setVisible(true);
 \}
 \}
 
 class ColourCell extends JLabel implements ListCellRenderer \{
 public ColourCell() \{
 this.setOpaque(true);
 this.setFont(new Font("Georgia", Font.PLAIN, 20));
 \}
 
 public Component getListCellRendererComponent(
 JList list, Object value, int index, boolean isSelected, boolean cellHasFocus)
 \{
 this.setText(value.toString());
 if (isSelected) /* if the listbox element is currently selected */
 \{
 this.setBackground(Color.blue);
 this.setForeground(Color.white);
 \} else \{
 this.setForeground(Color.darkGray);
 if ((index \\% 2) == 0)
 this.setBackground(Color.white);
 else
 this.setBackground(new Color(Integer.decode("\\#ffffdd")));
 //this.setBackground(new Color(0, 220, 250));
 \}
 return this;
 \}
 \}
 ,,,

 If the opacity of the cell renderer is false then the renderer doesnt
 seem to do its job properly
 >> this.setOpaque(true);
 
JLIST EVENTS AND LISTENERS ....

 In order to fire events when an item is selected in a JListBox you need
 to implement an ListSelectionListener by defining one method
 valueChanged(ListSelectionEvent e). 

 The getValueIsAdjusting() method returns true if the user is still
 manipulating the selection for example, is dragging the selection to
 include more elements. 


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents relevant listeners for a JList
 .. 
 * An example of a valueChanged method for responding to listbox selections 
 -------------------------------------------------------------
 public void valueChanged(ListSelectionEvent e) \{
 if (e.getValueIsAdjusting() == false) \{
 if (list.getSelectedIndex() == -1) \{ /* No selection */ \}
 else \{ /* do something */ \}
 \}
 \}
 ,,,

 * create a listbox which reacts to changes of the selected item(s) 
 --------------------------------------------------
 import javax.swing.*;
 import javax.swing.event.*;
 import java.awt.*;
 public class BoxEvent extends JFrame implements ListSelectionListener \{
 String[] ss = \{"Yew", "Oak", "Elder", "Myoporum"\};
 JList list;
 public BoxEvent() \{
 list = new JList(ss); 
 list.addListSelectionListener(this);
 list.setFont(new Font("Georgia", Font.PLAIN, 40));
 JPanel p = new JPanel(); p.add(list);
 this.getContentPane().add(p);
 this.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 this.setLocationRelativeTo(null);
 this.pack(); this.setVisible(true);
 \}
 public void valueChanged(ListSelectionEvent e) \{
 if (e.getValueIsAdjusting() == false) \{
 if (list.getSelectedIndex() == -1) \{ /* No selection */ \}
 else \{ 
 System.out.println(list.getSelectedIndex()); 
 \}
 \}
 \}
 public static void main(String[] args)
 \{ BoxEvent b = new BoxEvent(); \}
 \}
 ,,,

 * do something when a jlist item is double clicked
 --------------------------------------------------
 final JList list = new JList(dataModel);
 MouseListener mouseListener = new MouseAdapter() \{
 public void mouseClicked(MouseEvent e)
 \{
 if (e.getClickCount() == 2) \{
 int index = list.locationToIndex(e.getPoint());
 System.out.println("Double clicked on Item " + index);
 \}
 \}
 \};
 list.addMouseListener(mouseListener);
 ,,,

MOUSELISTENERS WITH THE JLIST COMPONENT ....

 * do something when a jlist item is double clicked
 --------------------------------------------------
 final JList list = new JList(dataModel);
 MouseListener mouseListener = new MouseAdapter() \{
 public void mouseClicked(MouseEvent e) \{
 if (e.getClickCount() == 2) \{
 int index = list.locationToIndex(e.getPoint());
 System.out.println("Double clicked on Item " + index);
 \}
 \}
 \};
 list.addMouseListener(mouseListener);
 ,,,

GOTCHAS FOR JLIST ....

 If you add a very large number of elements to a swing JList 
 component (or rather to its ListModel) without placing the JList
 in a JScrollPane, Exceptions will be generated, and on Linux at least
 the window will flash eternally.

JPANELS 

 Panels are important for grouping and laying out graphical components on
 a window. Panels can be created with a 'layout' which determines how the
 components (such as text-boxes, labels list boxes etc will be placed
 within the panel when the the 'add()' method of the panel is used.

 Panels, unless they have a border, are usually invisible to the user.

 * create a panel with a 2 by 2 gridlayout
 >> JPanel p = new JPanel(new GridLayout(2, 2)); 

 * create a panel with 2 columns and unlimited rows
 >> JPanel p = new JPanel(new GridLayout(0, 2); 

 * add a component to a visible jpanel
 >> panel.add(component); panel.revalidate();

 * a simple frame window with a panel and 3 labels 
 -------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class Test \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("a simple window");
 JPanel p = new JPanel(new GridLayout(0, 1));
 p.add(new JLabel("1st label"));
 p.add(new JLabel("2nd label"));
 p.add(new JLabel("3rd label"));
 f.getContentPane().add(p);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLocationRelativeTo(null);
 f.pack();
 f.setVisible(true);
 \}
 \}
 ,,,

 * create a 2 column grid layout, 5px vertical separation, 1px horizontal
 >> java.awt.GridLayout g = new GridLayout(0, 2, 5, 1));

 * a panel containing a user-name and password entry fields
 ----------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class Test \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("a simple window");
 JPanel p = new JPanel(new GridLayout(0, 2, 5, 1));
 p.add(new JLabel("user"));
 p.add(new JTextField());
 p.add(new JLabel("password"));
 p.add(new JPasswordField());
 f.getContentPane().add(p);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLocationRelativeTo(null);
 f.pack();
 f.setVisible(true);
 \}
 \}
 ,,,

 The problem with the window above, it that it doesnt resize
 is a pleasant fashion, the text boxes become very large and 
 the space between the labels increases.

 * remove a JLabel from a JPanel or JFrame
 -------------------------------------------------------------
 Container parent = label.getParent();
 parent.remove(label);
 parent.validate();
 parent.repaint();
 ,,,

BORDERS

 Just about any swing JComponent can have a border or to be 
 more precise, a javax.swing.border.Border. Borders in general make
 things look nicer and are a good way of grouping sets of components.

 @@ \url{http://leepoint.net/notes-java/GUI-appearance/borders/15bordersex.html}
 some good notes about creating borders


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents border types
 .. BevelBorder - the raised style looks like an old-fashioned button
 .. EtchedBorder - looks like a groove
 ..

 In the code below the LineBorder with rounded corners doesnt really
 produce noticeably rounded corners.

 * show what various borders look like
 -------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.border.*;
 import javax.swing.plaf.*;
 import java.awt.*;
 public class BorderPanel extends JPanel \{
 public BorderPanel() \{
 super(new GridLayout(0, 1, 10, 10));
 this.setBorder(new EmptyBorder(10,10,10,10));
 UIManager.put(
 "Label.font", new FontUIResource("Georgia", Font.PLAIN, 18));
 JLabel label;
 label = new JLabel("BevelBorder raised");
 label.setBorder(new BevelBorder(BevelBorder.RAISED)); 
 this.add(label);
 label = new JLabel("BevelBorder lowered");
 label.setBorder(new BevelBorder(BevelBorder.LOWERED)); 
 this.add(label);
 label = new JLabel("EtchedBorder");
 label.setBorder(new EtchedBorder()); 
 this.add(label);
 label = new JLabel("EtchedBorder raised");
 label.setBorder(new EtchedBorder(EtchedBorder.RAISED)); 
 this.add(label);
 label = new JLabel("MatteBorder with insets (10,5,5,5)");
 label.setBorder(
 new MatteBorder(new Insets(10,5,5,5), Color.blue)); 
 this.add(label);
 label = new JLabel("4px blue LineBorder, rounded corners");
 label.setBorder(new LineBorder(Color.blue, 4, true)); 
 this.add(label);
 label = new JLabel("1px black LineBorder, rounded corners");
 label.setBorder(new LineBorder(Color.black, 1, true)); 
 this.add(label);
 \} 

 public static void main(String[] args) \{
 BorderPanel p = new BorderPanel(); 
 JOptionPane.showMessageDialog(null, new JScrollPane(p)); 
 \}
 \}
 ,,,

 * a username and password panel with a titled, etched border
 --------------------------------------
 import javax.swing.*;
 import javax.swing.border.*;
 import java.awt.*;
 public class EtchedBorderTest \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("an EtchedBorder example");
 JPanel p = new JPanel(new GridLayout(0, 2, 5, 1));
 Border eb = BorderFactory.createEtchedBorder();
 Border tb = BorderFactory.createTitledBorder(eb, "Login");
 p.setBorder(tb);
 p.add(new JLabel("User")); p.add(new JTextField());
 p.add(new JLabel("Password")); p.add(new JPasswordField());
 f.getContentPane().add(p);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLocationRelativeTo(null);
 f.pack();
 f.setVisible(true);
 \}
 \}
 ,,,

 The problem with the panel above is that it doesnt resize
 well. The text boxes become very large.

 * JPanel with titled etched border with some extra space inside it 
 --------------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.border.*;
 import java.awt.*;
 public class SpacedBorder \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("An Etched, Titled and Empty border");
 JPanel p = new JPanel(new GridLayout(0, 2, 5, 1));
 Border etb = BorderFactory.createEtchedBorder();
 Border tb = BorderFactory.createTitledBorder(etb, "Login");
 Border eb = BorderFactory.createEmptyBorder(5,5,5,5);
 Border cb = BorderFactory.createCompoundBorder(tb, eb);
 p.setBorder(cb);
 p.add(new JLabel("User")); p.add(new JTextField());
 p.add(new JLabel("Password")); p.add(new JPasswordField());
 f.getContentPane().add(p);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

 The technique about adds some extra space (5 pixels) inside the
 titled etched border, but not outside of it. To place the 
 extra space outside of the titled border, reverse the order of
 the arguments to createCompoundBorder()
 >> Border cb = BorderFactory.createCompoundBorder(eb, tb);

 * create an etched border, with a title and some extra space
 ------------------------------------------------------------
 import javax.swing.border.*;
 . . .
 JPanel p = new JPanel();
 Border etchedBdr = BorderFactory.createEtchedBorder();
 Border titledBdr = 
 BorderFactory.createTitledBorder(etchedBdr, "Process");
 Border emptyBdr = BorderFactory.createEmptyBorder(10,10,10,10);
 Border compoundBdr = 
 BorderFactory.createCompoundBorder(titledBdr, emptyBdr);
 processPanel.setBorder(p);
 ,,, 


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents different kinds of borders
 .. BorderFactory.createLineBorder(Color.black);
 .. BorderFactory.createEtchedBorder();
 .. BorderFactory.createRaisedBevelBorder();
 .. BorderFactory.createLoweredBevelBorder();
 ..

ETCHEDBORDER ....

 * an etched border example 
 --------------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.border.*;
 import java.awt.*;
 public class EtchedBorder \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("An Etched border");
 JPanel p = new JPanel(new GridLayout(0, 2, 5, 1));
 for (String s: new java.io.File(".").list()) \{
 JLabel l = new JLabel(s);
 l.setBorder(BorderFactory.createEtchedBorder());
 p.add(l);
 \}
 f.add(p);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

EMPTYBORDER ....

 The javax.swing.border.EmptyBorder is useful for making everything
 look nicer by placing space around a component. In a gnome linux
 java1.6 system, a JScrollBar occupies some of the empty space in
 the EmptyBorder. 

 * put 20 pixels of space around the outside of a JPanel
 >> JPanel p = new JPanel(); p.setBorder(new EmptyBorder(20,20,20,20));

CUSTOM BORDERS ....

 Java swing provides a great deal of flexibility with how borders are
 painted around components. 

 @@ \url{http://www.javarichclient.com/how-to-create-a-custom-swing-border/}


\title{= notes =} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents

 The Insets push the contents of the JComponent away from the border.
 For example, increasing the size of the Insets places more space
 around text in a JLabel with a Border. The Insets do not create any
 extra space outside of the Border.

 Setting the label to opaque and a background colour for the JLabel
 is useful for detecting problems when painting Borders.

 the isBorderOpaque() method may be important 
 ...

 * how to extend AbstractBorder to create a custom Border
 -------------------------------------------------------------
 public class NewBorder extends AbstractBorder \{
 private int thickness;
 public NewBorder(int thick) \{
 this.thickness = thick;
 \}
 public void paintBorder(
 Component c, Graphics g, int x, int y, int width, int height) \{
 // draw the border
 \}
 
 public Insets getBorderInsets(Component c) \{
 return new Insets(thickness, thickness, thickness, thickness);
 \}
 
 public Insets getBorderInsets(Component c, Insets insets) \{
 insets.left = insets.top = insets.right = insets.bottom = thickness;
 return insets;
 \}
 \}
 ,,,

 The javadoc comments for the parameters of the paintBorder() method are
 confusing. The (x,y,width,height) parameters basically mark the bounding
 rectangle of the component (JLabel, JPanel etc) on which the border is
 being painted. If a thick stroke is used then this rectangle has to be
 shrunk so that all of the stroke is painted on the component, since half
 of a BasicStroke gets painted outside of the shape which it paints.

 * the parameters for the paintBorder method
 -------------------------------------------------------------
 public void paintBorder(
 Component c, // the component on which to paint the border
 Graphics g, // cast this to a Graphics2D for nice drawing 
 int x, // (x,y) the top left corner of the component (label..) 
 int y,
 int width, // the width of the component which will have the border
 int height) // the height of the component with the border
 )
 ,,,

 In the code below, if a compound border is not used with the custom
 border the left and bottom dashed border draws at half the thickness.
 why?

 * create a dashed border 
 ------------------------
 import java.awt.*;
 import javax.swing.*;
 import javax.swing.border.AbstractBorder;
 public class DashBorder extends AbstractBorder \{
 protected int strokeWidth;
 protected int margin;
 protected Color lineColor;
 
 public DashBorder(Color color, int thickness) \{
 this.lineColor = color;
 this.strokeWidth = thickness;
 this.margin = thickness + 5;
 \}
 
 public void paintBorder(
 Component c, Graphics g, int x, int y, int width, int height) \{
 Graphics2D g2d = (Graphics2D) g;
 g2d.setColor(lineColor);
 g2d.setRenderingHint(RenderingHints.KEY\\_ANTIALIASING, 
 RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 float dash[] = \{strokeWidth * 2\};
 g2d.setStroke(new BasicStroke(
 this.strokeWidth, BasicStroke.CAP\\_SQUARE, 
 BasicStroke.JOIN\\_MITER, 1f, dash, 0));
 // shrink the painting rectangle by half the stroke width
 int halfWidth = 1 + this.strokeWidth/2;
 g2d.drawRect(x+halfWidth, y+halfWidth, 
 width-(2*halfWidth), height-(2*halfWidth));
 \}
 
 public Insets getBorderInsets(Component c) \{
 return new Insets(this.margin,this.margin,this.margin,this.margin);
 \}
 public Insets getBorderInsets(Component c, Insets insets) \{
 insets.left = insets.top = insets.right = insets.bottom=this.margin;
 return insets;
 \}
 public boolean isBorderOpaque() \{ return true; \}
 public static void main(String[] args) \{
 JLabel label = new JLabel("A Dashed Border");
 label.setFont(new Font("Georgia", Font.PLAIN, 25));
 //label.setOpaque(true);
 //label.setBackground(Color.orange);
 label.setBorder(new DashBorder(Color.blue, 6));
 JOptionPane.showMessageDialog(null, label); 
 \}
 \}
,,,

 If a border uses a thick BasicStroke to paint itself, then half of the
 width of that stroke is painted outside of the bounding rectangle for the
 component, and is therefore not visible (or not painted at all). This
 means that we have to adjust the painting position and size parameters of
 the paintBorder() method (which by default use the position and size of
 the component on which the border will be painted.

 * the algorithm for painting a border with a stroke width 'width'
 -------------------------------------------------------------
 public void paintBorder(
 Component c, Graphics g, int x, int y, int width, int height) \{
 Graphics2D g2d = (Graphics2D)g;
 ...
 // half of the stoke width is outside of the component (truncated)
 int halfWidth = 1 + this.strokeWidth/2;
 g2d.drawRoundRect(x+halfWidth, y+halfWidth, 
 width-(2*halfWidth), height-(2*halfWidth), 20, 20);
 \}
 ,,,

 If the component (JLabel) has an odd number of pixels then there
 will be a 1 pixel row outside of the border.

 * a nice border with rounded corners, painting problems fixed
 ------------------------------
 import java.awt.*;
 import javax.swing.*;
 import javax.swing.border.AbstractBorder;
 public class RoundedBorder extends AbstractBorder \{
 private int margin;
 private static final long serialVersionUID = 1L;
 private Color color;
 int strokeWidth; // line stroke thickness
 int cornerRadius; // how much rounding to do
 
 public RoundedBorder(Color color, int width, int radius) \{ 
 this.color = color;
 this.strokeWidth = width;
 this.cornerRadius = radius;
 this.margin = width + 4;
 \}
 public RoundedBorder(Color color, int width) \{ 
 this(color, width, 20);
 \}
 public RoundedBorder() \{ 
 this(Color.black, 2, 20);
 \}

 public void paintBorder(
 Component c, Graphics g, int x, int y, int width, int height) \{
 Graphics2D g2d = (Graphics2D)g;
 g2d.setRenderingHint(RenderingHints.KEY\\_ANTIALIASING, 
 RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 g2d.setColor(color);
 g2d.setStroke(new BasicStroke(this.strokeWidth));
 int halfWidth = 1 + this.strokeWidth/2;
 g2d.drawRoundRect(x+halfWidth, y+halfWidth, 
 width-(2*halfWidth), height-(2*halfWidth), 
 this.cornerRadius, this.cornerRadius);
 //System.out.println("halfWidth:" + halfWidth);
 \}
 
 public Insets getBorderInsets(Component c) \{
 return new Insets(margin, margin, margin, margin);
 \}
 public Insets getBorderInsets(Component c, Insets insets) \{
 insets.left = insets.top = insets.right = insets.bottom=this.margin; 
 return insets;
 \}

 public static void main(String[] args) \{
 Font font = new Font("Georgia", Font.PLAIN, 30);
 JLabel l = new JLabel("A rounded corner border");
 l.setFont(font);
 //l.setOpaque(true);
 //l.setBackground(Color.orange);
 l.setBorder(new RoundedBorder(Color.blue, 6));
 JOptionPane.showMessageDialog(null, l);
 \} 
 \}
 ,,,

BORDER INTERFACE ....

 It is also possible to create a new type of Border by implementing
 the Border interface.

 * create a new type of border by implementing the interface, untested
 -----------------------------
 public static class GradientBorder implements Border \{
 private Insets margin;
 public GradientBorder (int top, int left, int bottom, int right) \{
 super ();
 margin = new Insets ( top, left, bottom, right );
 \}
 
 public void paintBorder(
 Component c, Graphics g, int x, int y, int width, int height )
 \{
 Graphics2D g2d = (Graphics2D) g;
 g2d.setPaint (new GradientPaint(
 x, y, Color.RED, x + width, y, Color.BLUE));
 Area border = new Area ( new Rectangle ( x, y, width, height ) );
 border.subtract ( new Area ( new Rectangle ( x + margin.left, y + margin.top, width - margin.left - margin.right, height - margin.top - margin.bottom ) ) );
 g2d.fill ( border );
 \}
 
 public Insets getBorderInsets ( Component c )
 \{ return margin; \}
 public boolean isBorderOpaque ()
 \{ return true; \}
 \}
 ,,,

GOTCHAS FOR CUSTOM BORDERS ....

 When we create a custom border by extending AbstractBorder, it 
 is usually used in conjunction with a CompoundBorder and an EmptyBorder-
 if not, the border is 'truncated' or not drawn properly, because there
 is not enough space outside of the border. One remedy might be to 
 adjust the x,y,width,height parameters of the paintBorder() method
 to give the Border more space, but then we may get background painting
 problems

TITLED BORDERS .... 

 * putting a title in the border
 -------------------------------
 TitledBorder titledBorder = BorderFactory.createTitledBorder ("Title");
 //titledBorder = BorderFactory.createTitledBorder (border, "Title");
 titledBorder.setTitleJustification (TitledBorder.CENTER);
 titledBorder.setTitlePosition (TitledBorder.BELOW\\_TOP);
 component.setBorder (titledBorder);
 ,,,

 * a panel with a titled, rounded corner border
 ----------------------------------------------
 import javax.swing.*;
 import javax.swing.border.*;
 import java.awt.*;
 public class RoundedCornerBorder \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("a simple window");
 JPanel p = new JPanel(new GridLayout(0, 2, 5, 1));
 Border eb = new LineBorder(Color.gray, 1, true);
 //Border eb = BorderFactory.createLineBorder(Color.gray, 2, true);
 Border tb = BorderFactory.createTitledBorder(eb, "Login");
 p.setBorder(tb);
 p.add(new JLabel("User")); p.add(new JTextField());
 p.add(new JLabel("Password")); p.add(new JPasswordField());
 f.getContentPane().add(p);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

 * a green italic center aligned title border with extra space
 -------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.border.*;
 import java.awt.*;
 public class FancyTitleBorder \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("Green italic titled border");
 JPanel p = new JPanel(new GridLayout(0, 2, 5, 1));
 Border eb = BorderFactory.createEtchedBorder();
 Border tb = BorderFactory.createTitledBorder(
 eb, "Login", TitledBorder.CENTER, TitledBorder.TOP, 
 new Font("Serif", Font.ITALIC, 10), Color.blue);
 Border sb = BorderFactory.createEmptyBorder(5,5,5,5);
 Border cb = BorderFactory.createCompoundBorder(tb, sb);
 p.setBorder(cb);
 p.add(new JLabel("User")); p.add(new JTextField());
 p.add(new JLabel("Password")); p.add(new JPasswordField());
 f.getContentPane().add(p);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

 * a green italic center aligned title border 
 --------------------------------------------
 import javax.swing.*;
 import javax.swing.border.*;
 import java.awt.*;
 public class Test \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("a simple window");
 JPanel p = new JPanel(new GridLayout(0, 2, 5, 1));
 Border eb = BorderFactory.createEtchedBorder();
 Border tb = BorderFactory.createTitledBorder(
 eb, "Login", TitledBorder.CENTER, TitledBorder.TOP, 
 new Font("Serif", Font.ITALIC, 10), Color.blue);
 p.setBorder(tb);
 p.add(new JLabel("User")); p.add(new JTextField());
 p.add(new JLabel("Password")); p.add(new JPasswordField());
 f.getContentPane().add(p);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLocationRelativeTo(null);
 f.pack();
 f.setVisible(true);
 \}
 \}
 ,,,

TABBED PANES

 Tabbed panes are useful, and represent a modern and simple user
 interface element. The actual default shape of the tabs is not
 very attractive. A better style would be the Google chrome 
 curved tabs.

 * a simple tabbed pane example
 ------------------------------
 import javax.swing.*;
 public class SimpleTabbedPane \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("A simple JTabbedPane example");
 JTabbedPane jtp = new JTabbedPane();
 JPanel p1 = new JPanel(); p1.add(new JLabel("The 1st Tab Area"));
 JPanel p2 = new JPanel(); p2.add(new JLabel("The 2nd Tab Area"));
 jtp.addTab("Tab1", p1);
 jtp.addTab("Tab2", p2);
 jtp.addTab("Tab3", 
 new JPanel().add(new JLabel("The 3rd Tab Area")));
 JOptionPane.showMessageDialog(null, jtp);
 \}
 \}
 ,,,

 * a tabbed pane with tool tip text for the tabs
 -----------------------------------------------
 import javax.swing.*;
 import java.awt.event.KeyEvent;
 public class TooltipTabbedPane \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("Testing Tabs");
 JTabbedPane tp = new JTabbedPane();
 JPanel p1 = new JPanel();
 p1.add(new JLabel("The 1st Tab Area"));
 JPanel p2 = new JPanel();
 p2.add(new JLabel("The 2nd Tab Area"));
 tp.addTab("Tab1", null, p1, "View the first");
 tp.addTab("Tab2", null, p2, "View the second");
 JOptionPane.showMessageDialog(null, tp);
 \}
 \}
 ,,,

 * a tabbed pane with tabs at the right of the pane 
 --------------------------------------------------
 import javax.swing.*;
 public class RightTabbedPane \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("A JTabbedPane- tabs on right");
 JTabbedPane tp = new JTabbedPane();
 tp.setTabPlacement(JTabbedPane.RIGHT);
 tp.setPreferredSize(new java.awt.Dimension(400, 400));
 JPanel p1 = new JPanel();
 p1.add(new JLabel("Information about mimosas"));
 JPanel p2 = new JPanel();
 p2.add(new JLabel("Images of Gardenias"));
 tp.addTab("Mimosa", null, p1);
 tp.addTab("Gardenia", null, p2);
 JOptionPane.showMessageDialog(null, tp);
 \}
 \}
 ,,,

 * a tabbed pane with icons for the tabs and short cut keys (alt s/d)
 --------------------------------------------------------------------
 import javax.swing.*;
 import java.awt.event.KeyEvent;
 public class Test \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("Testing Tabs");
 JTabbedPane tp = new JTabbedPane();
 JPanel p1 = new JPanel();
 p1.add(new JLabel("This the screen Tab Area (first)"));
 JPanel p2 = new JPanel();
 p2.add(new JLabel("This is the drive Tab Area (second)"));
 ImageIcon icon1 = new ImageIcon(
 "/usr/share/icons/gnome/24x24/devices/chardevice.png");
 tp.addTab("Screen", icon1, p1, "View the screen tab");
 tp.setMnemonicAt(0, KeyEvent.VK\\_S);
 ImageIcon icon2 = new ImageIcon(
 "/usr/share/icons/gnome/24x24/devices/drive-cdrom.png");
 tp.addTab("Drive", icon2, p2, "View the drive tab");
 tp.setMnemonicAt(1, KeyEvent.VK\\_D);
 f.getContentPane().add(tp);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLocationRelativeTo(null);
 f.pack();
 f.setVisible(true);
 \}
 \}
 ,,,

 * set the shortcut key for first tab on the pane to 'alt' + s
 >> tp.setMnemonicAt(0, KeyEvent.VK\\_S);

 If the text for the first tab on the tabbed pane contains an
 's' then that letter will be automatically underlined.

 * set the shortcut key for second tab on the pane to 'alt' + D
 >> tp.setMnemonicAt(0, KeyEvent.VK\\_D);

 * a tabbed pane with icons but no text on the tabs 
 --------------------------------------------------
 import javax.swing.*;
 import java.awt.event.KeyEvent;
 public class Test \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("Testing Tabs");
 JTabbedPane tp = new JTabbedPane();
 JPanel p1 = new JPanel();
 p1.add(new JLabel("The 1st Tab Area"));
 JPanel p2 = new JPanel();
 p2.add(new JLabel("The 2nd Tab Area"));
 ImageIcon icon1 = new ImageIcon(
 "/usr/share/icons/gnome/24x24/devices/chardevice.png");
 tp.addTab(null, icon1, p1, "View the screen tab");
 ImageIcon icon2 = new ImageIcon(
 "/usr/share/icons/gnome/24x24/devices/drive-cdrom.png");
 tp.addTab(null, icon2, p2, "View the drive tab");
 f.getContentPane().add(tp);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLocationRelativeTo(null);
 f.pack();
 f.setVisible(true);
 \}
 \}
 ,,,

 * a tabbed pane with icons and grid layout panels 
 --------------------------------------------------
 import javax.swing.*;
 import java.awt.event.KeyEvent;
 import java.awt.GridLayout;
 public class Test \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("Testing Tabs");
 JTabbedPane tp = new JTabbedPane();
 JPanel p1 = new JPanel(new GridLayout(0, 1));
 p1.add(new JLabel("The 1st Tab Area"));
 p1.add(new JLabel(" another label"));
 p1.add(new JLabel(" another label"));
 JPanel p2 = new JPanel(new GridLayout(0, 1));
 p2.add(new JLabel("The 2nd Tab Area"));
 p2.add(new JLabel(" another label"));
 p2.add(new JLabel(" another label"));
 ImageIcon icon1 = new ImageIcon(
 "/usr/share/icons/gnome/24x24/devices/chardevice.png");
 tp.addTab(null, icon1, p1, "View the screen tab");
 ImageIcon icon2 = new ImageIcon(
 "/usr/share/icons/gnome/24x24/devices/drive-cdrom.png");
 tp.addTab(null, icon2, p2, "View the drive tab");
 f.getContentPane().add(tp);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLocationRelativeTo(null);
 f.pack();
 f.setVisible(true);
 \}
 \}
 ,,,


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents useful methods for tabbed panes
 .. insertTab(String, Icon, Component, String, int) - insert a tab
 .. removeTabAt(3) - remove the 3rd tab
 .. pane.removeAll() - remove all the tabs
 .. pane.setSelectedIndex(2) - select the 2nd tab
 .. pane.setTitleAt(2, "file") - set the title of the 2nd tab to 'file'
 .. pane.setIconAt(2, icon) - set the icon for the 2nd tab
 ..
 
TRANSLUCENCY AND OPACITY 

 Translucency is partial transparency. Computer screens display
 translucency by 'compositing' (combining or blending) the forground and
 the background colours to give the illusion of translucency.

 The bit field in an image format which determines the tranlucency of a
 pixel is known as the 'alpha channel' as opposed to the red, green, and
 blue channels. Not all image formats support translucency or even
 transparency.

 We use the java.awt.AlphaComposite class to blend forground and 
 background colours to create the illusion of translucency.
 In Java an alpha value of 1.0f is completely opaque and 0.0f 
 completely transparent.

 * create an AlphaCompositing object
 >> AlphaComposite.getInstance(AlphaComposite.SRC\\_OVER, 0.5f)


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents compositing rules used with AlphaComposite

 SRC\\_OVER 
 places the source color over destination color, blends them based
 on the transparency of the source. This is the most common
 compositing rule.
 
 * create a half translucent red colour (will get blended with background)
 >> Color c = new Color(1.0f, 0.0f, 0.0f, 0.5f)

 In the example below the red Color is opaque but the AlphaComposite
 for the graphics2D object is 50\\% translucent, thereby causing the 
 rectangle to be painting with 50\\% translucency. Basically the 
 translucent square appears paler because its colour is combined with
 the white background colour.

 * draw a half translucent rectangle using an alpha composite
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class TranslucentPaint extends JPanel \{
 public TranslucentPaint() \{ super(); \}
 public void paintComponent(Graphics g) \{
 Graphics2D gg = (Graphics2D) g;
 Color c = new Color(1.0f, 0.0f, 0.0f);
 gg.setPaint(c);
 gg.fillRect(0, 0, 100, 100);
 gg.setComposite(
 AlphaComposite.getInstance(AlphaComposite.SRC\\_OVER, 0.5f));
 gg.fillRect(100, 100, 100, 100);
 \}
 public Dimension getPreferredSize() 
 \{ return new Dimension(300, 300); \}
 public static void main(String[] args) \{
 JOptionPane.showMessageDialog(null, new TranslucentPaint()); 
 \}
 \}
 ,,,

TRANSLUCENCY AND IMAGES ....

 * code for making translucent images, and extending a JLabel
 -------------------------------------------------------------
 import java.awt.*;
 import java.awt.image.*;
 import javax.swing.*;
 import javax.imageio.ImageIO;
 import java.net.URL;
 
 public class TransparentIcon \{
 public static void main(String[] args) throws Exception \{
 String imgURL =
 "http://www.gravatar.com/avatar/" +
 "a1ab0af4997654345d7a949877f8037e";
 final BufferedImage image = ImageIO.read(new URL(imgURL));
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 ImageIcon icon = new ImageIcon(image);
 JPanel p = new JPanel(new GridLayout(2,3));
 for (int ii=0; ii<6; ii++) \{
 TransparentLabel tl = new TransparentLabel();
 tl.setOpacity((ii+1)/6f);
 tl.setIcon(icon);
 p.add(tl);
 \}
 JOptionPane.showMessageDialog(null, p);
 \}
 \});
 \}
 \}
 
 class TransparentLabel extends JLabel \{
 float opacity = 1f;
 public void setOpacity(float opacity) \{
 this.opacity = opacity;
 \}
 private Icon getTranslucentIcon(Icon icon) \{
 if (icon!=null) \{
 BufferedImage bi = new BufferedImage(
 icon.getIconWidth(),
 icon.getIconHeight(),
 BufferedImage.TYPE\\_INT\\_ARGB);
 Graphics2D g = bi.createGraphics();
 AlphaComposite ac = AlphaComposite.getInstance(
 AlphaComposite.SRC\\_OVER,
 opacity);
 g.setComposite(ac);
 icon.paintIcon(this,g,0,0);
 g.dispose();
 return new ImageIcon(bi);
 \} else \{
 return null;
 \}
 \}
 
 public void setIcon(Icon icon) \{
 super.setIcon( getTranslucentIcon(icon) );
 \}
 \}
 ,,,
 
OPACITY TRANSLUCENCY TRANSPARENCY IN USER INTERFACES

 A feature of modern user interfaces is the use of semi-transparency or
 semi-opacity of components to create glass-like effect. This section
 concentrates on using these effects in user interfaces and should
 complement the section on translucency in the DRAWING AND JAVA2D
 section
 
 @@ \url{http://java.sun.com/products/jfc/tsc/articles/painting/index.html}
 An article about painting an opacity

 * make a button completely transparent except for the text
 -----------------------------------------------------------
 button.setOpaque(false);
 button.setContentAreaFilled(false);
 button.setBorderPainted(false);
 ,,,

 * create a semi (50\\%) transparent red button
 -------------------------------------------------------------
 JButton myButton =new JButton(“press me”);
 myButton.setBackground(new Color(255,0,0,128)); 
 ,,,

 * another way to make a transparent top level window, w opaque component, but not on linux
 ----------------------------
 JFrame f = new JFrame();
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setBackground(new Color(0f, 0f, 0f, 0.1f));
 f.setUndecorated(true);
 f.add(new JLabel("<html>Testing<br>1, 2, 3</html>"));
 f.pack();
 ,,,

 The following is based on a suggestion by camickr. The transparent
 background for the JTextArea is set when it is instantiated, but I am not
 sure why this couldnt be in the constructor for the subclass.

 The code below is incomplete.

 * create a semi transparent JTextArea with an image drawn behind it
 -------------------------------------------------------------
 public class TransparentText extends JTextArea \{
 @Override
 public void paintComponent(Graphics g) \{
 Graphics2D g2 = (Graphics2D) g;
 g2.setComposite(???
 g.drawImage(...);
 super.paintComponent(g);
 \}
 \}
 ...
 TransparentText t = new TransparentText();
 t.setBackground(new Color(r, g, b, alpha));
 ,,,

 * make a button semi-opaque, untested
 --------------------------------------------
 @Override
 public void paintComponent(Graphics g) \{
 Graphics2D g2 = (Graphics2D) g;
 g2.setComposite(
 AlphaComposite.getInstance(AlphaComposite.SRC\\_OVER, 0));
 super.paint(g2);
 g2.dispose();
 \}
 ,,,

 Apparently, it is difficult or impossible to make a semi-transparent
 cursor in Java (according to Andrew Thompson)

 * a complete transparent JTextArea example
 -------------------------------------------------------
 import java.awt.*;
 import javax.swing.*;
 import java.awt.Font;
 
 public class TransparentTextArea extends JTextArea \{
 int alpha;
 public TransparentTextArea(int alpha) \{
 super(4, 16);
 this.alpha = alpha;
 this.setBackground(new Color(0, 0, 0, alpha));
 this.setFont(new Font("Serif", Font.ITALIC, 24));
 this.setEditable(false);
 this.setText("Twas brillig and the slithy toves,\\$\\backslash\\$n"
 + "Did gyre and gimble in the wabe;\\$\\backslash\\$n"
 + "All mimsy were the borogoves,\\$\\backslash\\$n"
 + "And the mome raths outgrabe.");
 \}
 
 private static void create() \{
 JFrame f = new JFrame();
 f.setLayout(new FlowLayout());
 f.getContentPane().setBackground(new Color(0xffffc0));
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 JPanel panel = new JPanel();
 panel.setBackground(new Color(0xffffc0));
 panel.add(new TransparentTextArea(128));
 f.add(panel); f.pack();
 f.setVisible(true);
 \}
 
 public static void main(String[] args) \{
 try \{
 UIManager.setLookAndFeel(
 "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel");
 \} catch (Exception e) \{ e.printStackTrace(); \}
 
 EventQueue.invokeLater(new Runnable() \{
 @Override
 public void run() \{ create(); \}
 \});
 \}
 \}
 ,,,


TRANSITIONS 

 Transitions are a modern (animated) way of moving from one 'screen'
 or layout to another based on user input. The idea behind transitions
 is to provide visual clues to the user about the logical flow of the 
 application. See the filthy rich client book...

LAYOUTS AND LAYOUT MANAGERS
 
 A layout manager is a way of managing the way the components are
 arranged in a panel or other container component. The idea is to 
 arrange components (buttons, boxes etc) in a way that is both 
 aesthetically pleasing and reflects the logic of the application.

DYNAMIC LAYOUTS ....
 
 A dynamic layout is one in which elements of the layout change
 according to the state of the application and user input.

 In the code below, if no revalidate() method is called after the
 setVisible() method calls, the JTextField becomes invisible but the
 JTextArea does not expand to fill the extra space. With revalidate the
 JTextArea expands itself. If the JTextArea were editable we would probably
 have to use modifier (control etc) so that the character would not be
 inserted in the text area. 
 
 We could also use an AbstractAction subclass along with the ActionMap and
 InputMap for the JTextArea, but this is just an example.
 
 * hide a textfield on keypress enter and show with '/' keystroke
 ------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 import java.awt.event.*;
 public class HideAndShow extends JPanel implements ActionListener \{
 JTextField field;
 JTextArea area;
 public HideAndShow() \{
 super(new BorderLayout());
 this.field = new JTextField();
 this.field.setFont(new Font("Georgia", Font.ITALIC, 24));
 this.field.addActionListener(this);
 this.area = new JTextArea(20, 60);
 this.area.setEditable(false);
 this.area.addKeyListener(new KeyAdapter() \{
 public void keyTyped(KeyEvent e) \{
 if (e.getKeyChar() == '/') \{
 HideAndShow.this.field.setVisible(true);
 HideAndShow.this.field.requestFocusInWindow();
 \}
 \}
 \});

 this.add(this.field, BorderLayout.NORTH);
 this.add(this.area, BorderLayout.CENTER);
 \} 
 public void actionPerformed(ActionEvent e) \{
 this.field.setVisible(false);
 this.revalidate();
 \}
 public static void main(String[] args) throws Exception \{ 
 JFrame f = new JFrame("Enter to hide, '/' to show");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.getContentPane().add(new HideAndShow());
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,


GOTCHAS FOR LAYOUT MANAGERS ....

 Some layout managers do not respect the size (java.awt.Dimension)
 returned by the getPreferredSize() method. For example the BorderLayout
 seems to make the BorderLayout.CENTER component as big a possible
 despite the preferred size.

FLOWLAYOUT ....

 The java.awt.FlowLayout, which is the default for JPanels (except for the
 JFrame contentPane) simply places JComponents flowing across the screen
 (usually) from left to right, and wrapping to the next 'line' when the end
 of the screen space is reached.

 The FlowLayout doesnt seem to know how to report its dimensions 
 properly. For example if you put lots of JComponents into a panel
 with a FlowLayout only the first line of components may be displayed

 \url{http://tips4java.wordpress.com/2008/11/06/wrap-layout/}
 extends a FlowLayout to make the container calculate its size

 BoxLayouts are said to be similar to FlowLayouts but offer more
 flexibility (vertical flow, etc)

 * create a panel with a left-aligned flowlayout (all rows align to left)
 >> JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT));
 
 On my debian-linux Gnome computer (java 1.6), the java application window
 is only made big enough to display the first line of JButtons. In other
 words the pack() method doesnt seem to be doing its job properly. This
 seems to be Gnome, or java bug. Calling revalidate on the panel doesnt
 help either. Make full screen to avoid the problem.

 * create a panel with a left aligned FlowLayout
 -------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.plaf.FontUIResource;
 import java.awt.*;
 public class FlowPanel extends JPanel \{
 public FlowPanel() \{
 super(new FlowLayout(FlowLayout.LEFT));
 for (String s: new java.io.File("..").list()) \{ 
 JButton b = new JButton(s); this.add(b);
 \}
 \} 
 public static void main(String[] args) throws Exception \{ 
 UIManager.put("Button.font", 
 new FontUIResource("Georgia", Font.PLAIN, 18));
 JFrame f = new JFrame("");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.add(new FlowPanel()); f.pack(); 
 f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.setVisible(true);
 \}
 \}
 ,,,

GOTCHAS FOR FLOWLAYOUT ....

 On a Gnome Linux computer (java 1.6) only the first line of the FlowLayout
 displays.

BORDERLAYOUT ....

 A border layout is a simple design consisting of a centre location
 and north, south, east, west locations. The component which ocupies
 the BorderLayout.CENTER position is expanded to fill the available
 space, even if that component has is preferred size set. 

 The default layout for a JFrame.getContentFrame is a BorderLayout

 * a panel with a border layout
 -------------------------------------------------------------
 JPanel panel = new JPanel(new BorderLayout());
 panel.add(comp, BorderLayout.CENTER);
 ,,,

 The default position for a component added to a BorderLayout is 
 the center.

 * add a JLabel to the center of a JPanel with a BorderLayout
 >> JPanel panel = new JPanel(new BorderLayout()); panel.add(jlabel);

 * a borderlayout with gaps and a title
 --------------------------
 JPanel p = new JPanel(new BorderLayout(5,5));
 p.setBorder(new TitledBorder("Main GUI"));
 ,,,
 
 * create a panel with a border layout 
 -------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.plaf.FontUIResource;
 import java.awt.*;
 public class BorderPanel extends JPanel \{
 public BorderPanel() \{
 super(new BorderLayout());
 JButton b = new JButton("Center");
 this.add(b, BorderLayout.CENTER);
 JButton bn = new JButton("North");
 this.add(bn, BorderLayout.NORTH);
 JButton bw = new JButton("West");
 this.add(bw, BorderLayout.WEST);
 \} 
 public static void main(String[] args) throws Exception \{ 
 try \{
 UIManager.setLookAndFeel(
 "javax.swing.plaf.nimbus.NimbusLookAndFeel");
 \} catch (ClassNotFoundException e) \{ \}
 UIManager.put(
 "Button.font", new FontUIResource("Georgia", Font.PLAIN, 18));
 JFrame f = new JFrame("");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.getContentPane().add(new BorderPanel());
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

GOTCHAS WITH BORDERLAYOUT

 even if you set the rows and columns for a JTextArea (for example)
 with something like:
 >> JTextArea t = new JTextArea(40, 30);
 the BorderLayout will ignore this if you place the JTextArea in 
 the CENTER position.

GRIDLAYOUT ....

 In a grid layout all elements of the grid are given an
 equal amout of space. This is often not pretty. Also, when
 the window is resized components such as text boxes will
 be large and ungainly. 

 It's not possible to add a component to a grid layout at
 a particular cell. One must add all components to the layout
 sequencially (left to right, top to bottom). Use empty labels
 to not add anything to a partiular cell.

 @@ \url{http://leepoint.net/notes-java/GUI/layouts/30gridlayout.html}
 notes about grid layouts 

 * create a layout with 1 column and unlimited rows
 >> GridLayout layout = new GridLayout(0, 1);

 * create a layout with a horizontal gap of 10 and vertical gap of 20
 >> GridLayout layout = new GridLayout(0, 1, 10, 20);

 * create a swing panel with a gridlayout and a titled border
 JPanel p = new JPanel(new GridLayout(0,1));
 p.setBorder(new TitledBorder("Main GUI"));
 ,,,

 The example below could be the basis of a different kind of file-browser,
 with keyboard on-the-fly search, sorting by folder/file, files sorted
 alphabetically, an action listener to do something when the file or folder
 is clicked.

 * a panel with a 4 column GridLayout, 10px spacing with filename buttons 
 -------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.border.EmptyBorder;
 import javax.swing.plaf.FontUIResource;
 import java.awt.*;
 import java.awt.event.*;
 public class GridPanel extends JPanel implements ActionListener \{
 public GridPanel() \{
 super(new GridLayout(0,4,10,10));
 this.setBorder(new EmptyBorder(20,20,20,20));
 for (String s: new java.io.File("..").list()) \{ 
 JButton b = new JButton(s); this.add(b); b.addActionListener(this);
 \}
 \} 
 public void actionPerformed(ActionEvent e) \{ /*do something here*/ \}
 public static void main(String[] args) throws Exception \{ 
 UIManager.put("Button.font", 
 new FontUIResource("Georgia", Font.PLAIN, 18));
 JFrame f = new JFrame("A GridLayout Example");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.add(new JScrollPane(new GridPanel())); f.pack(); 
 f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

 * a 2 by 2 grid layout with gaps between cells
 -----------------------------------------------
 import javax.swing.*;
 import java.awt.GridLayout;
 public class TwoByTwoGrid \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("A 2x2 Grid Layout");
 JPanel content = new JPanel(new GridLayout(2, 2, 5, 5));
 content.add(new JButton("Walnut"));
 content.add(new JButton("Eucalypt"));
 content.add(new JLabel("")); // for empty cell
 content.add(new JButton("Myoporum"));
 f.getContentPane().add(content);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

 * create a panel with a 3 by 2 grid layout
 >> JPanel content = new JPanel(new GridLayout(3, 2, 10, 10));

 * combine 2 gridlayout panels in a single frame 
 -----------------------------------------------
 import javax.swing.*;
 import java.awt.GridLayout;
 public class Test \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("Testing Grid Layouts");
 JPanel content = new JPanel(new GridLayout(2, 1));
 JPanel buttonPane = new JPanel(new GridLayout(3, 3, 5, 5));
 for (int ii = 0; ii < 9; ii++)
 \{ buttonPane.add(new JButton("" + ii)); \}
 JPanel textPane = new JPanel(new GridLayout(3, 1, 5, 5));
 for (int ii = 0; ii < 3; ii++)
 \{ textPane.add(new JTextField(20)); \}
 content.add(buttonPane);
 content.add(textPane);

 f.getContentPane().add(content);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLocationRelativeTo(null);
 f.pack();
 f.setVisible(true);
 \}
 \}
 ,,,

GRIDBAGLAYOUT 

 The GridBagLayout has a bad reputation amongst those who know
 a great deal about Swing. Excessively complicated and easy to 
 muck up. Maybe use BoxLayouts with nested panels.

 The GridBagLayout is possibly the most flexible of the layout
 managers. See also the 'GroupLayout' or use a graphical tool.

 * a simple use of GridBayLayout and GridBagConstraints
 ------------------------------------------------------
 
 GridBagConstraints c = new GridBagConstraints ();
 c.gridwidth = GridBagConstraints.REMAINDER;
 c.fill = GridBagConstraints.HORIZONTAL;
 add (textField, c);

 c.fill = GridBagConstraints.BOTH;
 c.weightx = 1.0;
 c.weighty = 1.0;
 ,,,

 using a grid bag, its not so hard, just like a table but with spans
 ---------------------------
 getContentPane().setLayout(new GridBagLayout());
 GridBagConstraints c = new GridBagConstraints();
 c.gridwidth = 2;
 c.gridheight = 1;
 c.anchor = GridBagConstraints.CENTER;
 c.fill = GridBagConstraints.BOTH;
 c.weightx = 1.0;
 c.weighty = 1.0;
 c.gridx = 0;
 c.gridy = 0;
 c.insets = new Insets(2, 2, 2, 2);
 getContentPane().add(new JScrollPane(pane), c);
 ,,,

BOXLAYOUT ....

 The javax.swing.BoxLayout arranges components in either a vertical or 
 horizontal line. It has several ways to customize the arrangement.
 The BoxLayout does not wrap components unlike the FlowLayout

 The BoxLayout is often used in conjuction with the javax.swing.Box
 which allows the creation of invisible elements such as glue, struts
 and rigid areas. These elements effect the position of the elements
 within a BoxLayout.

 * create a horizontal BoxLayout
 >> panel.setLayout(new BoxLayout(panel, BoxLayout.LINE\\_AXIS));

 * create a BoxLayout with a vertical orientation
 >> listPane.setLayout(new BoxLayout(listPane, BoxLayout.PAGE\\_AXIS));
 
 * what does this do
 >> listPane.add(Box.createRigidArea(new Dimension(0,5)));

 * stop a JTextField from expanding in a BoxLayout
 >> textField.setMaximumSize( textField.getPreferredSize() );

 * a simple box example
 -------------------------------------------------------------

 content.setLayout(new BoxLayout(content, BoxLayout.Y\\_AXIS));
 content.add(new JLabel("one"));
 ,,,
 
 When the application window is made larger in the example below the extra
 space is put after the elements. See the 'glue' sections for how 
 to change this behavior.

 * a vertical BoxLayout example with lots of buttons
 ----------------------------------------------
 import java.awt.*;
 import javax.swing.*;
 public class BoxPanel extends JPanel \{
 public BoxPanel() \{
 super();
 this.setLayout(new BoxLayout(this, BoxLayout.Y\\_AXIS));
 for (String s: new String[]\{"yew", "oak", "elm", "walnut"\}) 
 this.add(new JButton(s)); 
 \}
 public static void main(String args[]) \{
 EventQueue.invokeLater(new Runnable() \{
 public void run() \{
 JFrame f = new JFrame("A vertical BoxLayout with JButtons");
 f.add(new BoxPanel());
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setVisible(true);
 \}
 \});
 \}
 \}
 ,,,

 The example below seems to demostrate that the BoxLayout tries
 to make the components of the same width for a Y\\_AXIS layout

 * a simple BoxLayout example 
 ----------------------------------------------
 import javax.swing.*;
 public class BoxPanel extends JPanel \{
 JTextField field;
 JTextArea area;
 public BoxPanel() \{
 super();
 this.setLayout(new BoxLayout(this, BoxLayout.Y\\_AXIS));
 this.field = new JTextField(40);
 this.area = new JTextArea(20, 80);
 this.add(this.field);
 this.add(new JScrollPane(this.area));
 \}
 public static void main(String args[]) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JFrame f = new JFrame("A BoxLayout in a JPanel");
 f.add(new BoxPanel());
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \});
 \}
 \}
 ,,,

GLUE WITH A BOXLAYOUT .....


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents box concepts
 * glue
 determines how the BoxLayout gets resized. 'glue' fills space.
 Put glue where you want space to be put when the window is made
 bigger.

 In the example below, to see the glue in action make the application
 window bigger. When the JFrame is enlarged extra space is put
 between the "oak" and "elm" buttons, not after all the buttons.

 * a vertical BoxLayout with some 'glue' after the second button
 ----------------------------------------------
 import javax.swing.*;
 public class BoxPanel extends JPanel \{
 public BoxPanel() \{
 super();
 this.setLayout(new BoxLayout(this, BoxLayout.Y\\_AXIS));
 for (String s: new String[]\{"yew", "oak", "elm", "walnut"\}) \{
 this.add(new JButton(s)); 
 // java 1.6 bug? have to write javax.swing.Box
 if (s.equals("oak")) this.add(javax.swing.Box.createGlue());
 \}
 \}
 public static void main(String args[]) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JFrame f = new JFrame("A vertical BoxLayout with JButtons");
 f.add(new BoxPanel());
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \});
 \}
 \}
 ,,,

 In the example below, when the window is made larger the extra space
 is given equally between the 2nd and 3rd buttons.

 * a vertical BoxLayout with some 'glue' after 2nd and 3rd buttons
 ----------------------------------------------
 import javax.swing.*;
 public class GlueBoxPanel extends JPanel \{
 public GlueBoxPanel() \{
 super();
 this.setLayout(new BoxLayout(this, BoxLayout.Y\\_AXIS));
 for (String s: new String[]\{"yew", "oak", "elm", "walnut"\}) \{
 this.add(new JButton(s)); 
 // java 1.6 bug? have to write javax.swing.Box
 if (s.equals("oak") || s.equals("elm"))
 this.add(javax.swing.Box.createGlue());
 \}
 \}
 public static void main(String args[]) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JFrame f = new JFrame("A vertical BoxLayout with JButtons");
 f.add(new GlueBoxPanel());
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \});
 \}
 \}
 ,,,

VERTICALSTRUTS AND HORIZONTALSTRUTS WITH THE BOXLAYOUT ....

 The vertical strut (Box.createVerticalStrut(int)) is used to put space
 between components in a vertical BoxLayout or to force a horizontal
 BoxLayout to have a certain height. The horizontal strut does 
 something completely analagous but horizontally

 * a vertical BoxLayout with 10-pixel vertical struts 
 ----------------------------------------------
 import javax.swing.*;
 public class GlueBoxPanel extends JPanel \{
 public GlueBoxPanel() \{
 super();
 this.setLayout(new BoxLayout(this, BoxLayout.Y\\_AXIS));
 for (String s: new String[]\{"yew", "oak", "elm", "walnut"\}) \{
 this.add(new JButton(s)); 
 // java 1.6 bug? have to write javax.swing.Box
 this.add(javax.swing.Box.createVerticalStrut(10));
 \}
 \}
 public static void main(String args[]) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JFrame f = new JFrame("A vertical BoxLayout with JButtons");
 f.add(new GlueBoxPanel());
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \});
 \}
 \}
 ,,,

RIGIDAREAS AND BOXLAYOUTS ....

 creates an invisible component which is always the same size.
 Not quite sure what the purpose of this is.

GOTCHAS FOR BOXES ....

 In the code below, java 1.6, I get a "symbol not found" compile error
 but can fix it by writing javax.swing.Box.createGlue() even though
 the correct import statement is already present.

 * is there another 'Box' class?
 -------------------------------------------------------------
 import java.awt.*;
 import javax.swing.*;
 ...
 jpanel.add(Box.createGlue());
 ,,,

CARDLAYOUT ....

 A cardlayout consists in a set of panels which sit on top of each other:
 only one is visible at any one time.

 * a complete card layout example
 -------------------------------------------------------------
 public class CardLayoutDemo \{
 private static JFrame createGUI() \{
 JFrame testFrame = new JFrame( );
 testFrame.setDefaultCloseOperation( JFrame.EXIT\\_ON\\_CLOSE );
 List<String> layoutConstraints = Arrays.asList( "first", "second", "third");
 
 final JPanel contentsPane = new JPanel( );
 final CardLayout cardLayout = new CardLayout( );
 contentsPane.setLayout( cardLayout );
 
 ActionListener listener = new ActionListener() \{
 public void actionPerformed( ActionEvent aActionEvent ) \{
 String constraint = aActionEvent.getActionCommand();
 cardLayout.show( contentsPane, constraint ); \}
 \};
 
 //add components to card layout with specific constraint
 for ( String constraints : layoutConstraints ) \{
 contentsPane.add( new JLabel( constraints ), constraints );
 \}
 
 //create buttons allowing to switch between the different layouts
 JPanel buttonPanel = new JPanel();
 for ( int i = 0; i < layoutConstraints.size(); i++ ) \{
 String constraint = layoutConstraints.get( i );
 JButton button = new JButton( "Layout " + i);
 button.setActionCommand( constraint );
 button.addActionListener( listener );
 buttonPanel.add( button );
 \}
 
 testFrame.add( contentsPane, BorderLayout.CENTER );
 testFrame.add( buttonPanel, BorderLayout.SOUTH );
 return testFrame;
 \}
 ,,,

GROUPLAYOUT ....

 The GroupLayout is, apparently, designed to be used by 'gui builder'
 tools. That means applications such as Netbeans or Eclipse which allow
 the user to create graphical interfaces by clicking and dragging.
 The disadvantage of the GroupLayout is that it seems necessary to 
 create large amounts of boiler-plate code. 
 
 The Swing expert Rob Camick says that he knows nothing about the
 GroupLayout. 

IMPLEMENTING A LAYOUTMANAGER ....

 \url{http://tips4java.wordpress.com/2008/11/06/wrap-layout/}
 extends a FlowLayout to make the container calculate its size
 but the code has a strange encoding.

JSCROLLPANES 

 JScrollPanes are a way of viewing components which are 2 big to fit onto
 the users screen or into the application layout. Scroll-panes can
 function with or without scrollbars, but alway contain a JViewPort (which
 is the component which actually displays the scrolled component).

 When the scrollpane is scrolling a textcomponent the caret may
 override the scrollpane scroll operations.

 \url{http://tips4java.wordpress.com/2010/05/09/scrolling-a-form/}
 how to automatically scroll a JScrollPane to the focussed element
 when the user tabs

 * If an element is likely to be too big, add a scrollpane to it 
 >> JScrollPane scrollpane = new JScrollPane(jcomponent);

 * enable mouse wheel scrolling
 >> JScrollPane.setWheelScrollingEnabled(boolean)

 * make scrolling faster by setting the increment (arrows, mouse wheel)
 >> jscrollpane.getVerticalScrollBar().setUnitIncrement(16);

 * scroll the JScrollPane all the way to the bottom
 -----------------------------------------------------
 JScrollBar v = scroll.getVerticalScrollBar():
 v.setValue(v.getMaximum());
 ,,,

 * scroll to the end of a panel which has just had something added to it
 -------------------------------------------------------------
 panel.add(new JLabel("Label " + ++counter));
 panel.revalidate();
 int height = (int)panel.getPreferredSize().getHeight();
 scroll.getVerticalScrollBar().setValue(height);
 ,,,

 * an important method for scrolling to make a rectangle visible 
 >> component.scrollRectToVisible(Rectangle r)

 * scroll all the way to the top of a JScrollPane
 >> scrollPane.getVerticalScrollBar().setValue(0);

 * another technique for scrolling to top, untested
 >> scrollPane.getViewport().setViewPosition(new Point(0,0));

 * set the height of a scroll pane to 1/3 of what it would be
 -------------------------------------------------------------
 Dimension tablePreferred = tableScroll.getPreferredSize();
 tableScroll.setPreferredSize(
 new Dimension(tablePreferred.width, tablePreferred.height/3) );
 ,,,

 * add a scroll pane to a panel 
 ------------------------------------------------------------------
 import javax.swing.*;
 import java.awt.GridLayout;
 public class ScrollPanel 
 \{
 public static void main(String args[]) throws Exception
 \{
 JPanel p = new JPanel(new GridLayout(0, 1));
 for (int i = 0; i < 400; i++)
 p.add(new JLabel("Label " + i));
 JFrame f = new JFrame("A panel which can scroll");
 f.add(new JScrollPane(p));
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setVisible(true);
 \}
 \}
 ,,,

 Using a scrollpane which a JOptionPane.showMessageDialog
 doesnt seem to work.


JVIEWPORTS AND VIEWS ....

 The JViewPort of a JScrollPane is the part of the JComponent which
 can actually be seen at any given time.

 The code oneliner below is very terse- but it should be the basis
 for the correct answer.

 * scroll a JEditorPane to some highlighted text
 >> editorPane.scrollRectToVisible( editorPane.modelToView(...) );
 
 The code below should work with any JTextComponent. Based on a camickr
 reply. 

 * get the text that is visible in the scrollpane of a JEditorPane
 -------------------------------------------------------------
 // use the viewport to get the view position and size.
 JViewport viewport = scrollPane.getViewport();
 Point startPoint = viewport.getViewPosition();
 Dimension size = viewport.getExtentSize();
 Point endPoint = 
 new Point(startPoint.x + size.width, startPoint.y + size.height);

 // convert the start/end points to document indexes 
 int start = editorPane.viewToModel(startPoint);
 int end = editorPane.viewToModel(endPoint);
 // use the document indexes to retrieve the text
 String text = editorPane.getText(start, end - start);
 ,,,

 The method textcomponent.modelToView(int) returns a one pixel wide
 rectangle with the height of the current line height (determined by
 the size of the font)

 The example below is designed to help understand the values returned
 by methods such as viewport.getPosition() verticalScrollBar.getValue()
 and textarea.modelToView(10)

 The code below demonstrate that the viewport position y value
 is the same as the verticalScrollBar value. And we can expect the 
 same to be true for horizontal scrolling. Now add modelToView
 The code is not working perfectly: the scrollbar position doesnt get
 updated properly.

 * an example to understand scrollbar and viewport positions
 ----------------------------------------------
 import java.io.*;
 import java.awt.*;
 import javax.swing.*;
 import javax.swing.event.*;
 import javax.swing.text.BadLocationException;
 public class ScrollBarTest extends JPanel implements CaretListener \{
 JLabel label;
 JTextArea area;
 JScrollPane scroll;
 String fileName;
 public ScrollBarTest() \{
 super(); 
 this.setLayout(new BorderLayout());
 this.fileName = "java-book.txt";
 this.label = new JLabel("<html>info:");
 this.area = new JTextArea();
 this.area.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 22));
 this.area.addCaretListener(this);
 try \{
 FileInputStream fis = new FileInputStream(this.fileName); 
 this.area.read(new InputStreamReader(fis, "UTF-8"), null);
 \} catch (IOException e) \{ e.printStackTrace(); \}
 this.scroll = new JScrollPane(this.area);
 this.add(this.label, BorderLayout.NORTH);
 this.add(scroll, BorderLayout.CENTER);
 \}
 public void caretUpdate(CaretEvent e) \{ this.info(e); \}
 public void info(CaretEvent e) \{
 try \{
 this.label.setText(String.format(
 "<html><ul><li> Caret Dot: \\%d<li> Caret Mark: \\%d" +
 "<li> Caret Rectangle: \\%s" +
 "<li> Vertical Scroll Bar Value: \\%d" +
 "<li> Viewport extent size: \\%s" +
 "<li> Viewport Position: \\%s</ul></html>",
 e.getDot(), e.getMark(),
 this.area.modelToView(e.getDot()).toString(),
 this.scroll.getVerticalScrollBar().getValue(),
 this.scroll.getViewport().getExtentSize().toString(), 
 this.scroll.getViewport().getViewPosition().toString())); 
 \} catch (BadLocationException er) \{ er.printStackTrace(); \}
 \}
 public static void main(String args[]) \{
 EventQueue.invokeLater(new Runnable() \{
 public void run() \{
 JFrame f = new JFrame("Searching Text in JEditorPane");
 f.add(new ScrollBarTest());
 f.pack(); f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);
 f.setVisible(true);
 \}
 \});
 \}
 \}
 ,,,

 * scroll the scrollpane to maintain the caret always in the center 
 -------------------------------------------------------------
 textarea.addCaretListener(new CaretListener \{
 public void caretUpdate(CaretEvent e) \{ 
 try \{
 Dimension view = scrollpane.getViewport().getExtentSize(); 
 JScrollBar bar = scrollpane.getVerticalScrollBar();
 bar.setValue(textarea.modelToView(e.getDot()).y - view.height/2);
 \} catch (BadLocationException err) \{ err.printStackTrace(); \}
 \}
 \});
 ,,,

 * the same as above but maintain the caret about 1/3 down the scrollpane
 >> bar.setValue(textarea.modelToView(e.getDot()).y - view.height/3);

 * scroll to maintain the caret always in the center of a jtextarea 
 ----------------------------------------------
 import java.io.*;
 import java.awt.*;
 import javax.swing.*;
 import javax.swing.event.*;
 import javax.swing.text.BadLocationException;
 public class CaretScroll extends JPanel implements CaretListener \{
 JTextArea area;
 JScrollPane scroll;
 public CaretScroll() \{
 super(new BorderLayout());
 this.area = new JTextArea();
 this.area.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 22));
 this.area.addCaretListener(this);
 try \{
 FileInputStream fis = new FileInputStream("java-book.txt"); 
 this.area.read(new InputStreamReader(fis, "UTF-8"), null);
 \} catch (IOException e) \{ e.printStackTrace(); \}
 this.scroll = new JScrollPane(this.area);
 this.add(scroll, BorderLayout.CENTER);
 \}
 public void caretUpdate(CaretEvent e) \{ 
 try \{
 Dimension view = this.scroll.getViewport().getExtentSize(); 
 JScrollBar bar = this.scroll.getVerticalScrollBar();
 bar.setValue(this.area.modelToView(e.getDot()).y - view.height/2);
 \} catch (BadLocationException err) \{ err.printStackTrace(); \}
 \}
 public static void main(String args[]) \{
 EventQueue.invokeLater(new Runnable() \{
 public void run() \{
 JFrame f = new JFrame("Scrolling with the caret");
 f.add(new CaretScroll());
 f.pack(); f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);
 f.setVisible(true);
 \}
 \});
 \}
 \}
 ,,,


KEYBOARD SCROLLING AND JSCROLLPANES ....

 By default a JScrollPane component cannot be scrolled using the keyboard
 up or down arrow keys. That is somewhat inconvenient. The technique
 below uses key-bindings and default swing actions to provide the simplest
 way to implement arrow key scrolling. See the keybindings section for 
 more detailed information.

 * make up/down arrow keys scroll a JScrollPane (JScrollBar)
 ------------------------------------------------------------
 JScrollBar vertical = scrollPane.getVerticalScrollBar();
 InputMap im = vertical.getInputMap(JComponent.WHEN\\_IN\\_FOCUSED\\_WINDOW);
 im.put(KeyStroke.getKeyStroke("DOWN"), "positiveUnitIncrement");
 im.put(KeyStroke.getKeyStroke("UP"), "negativeUnitIncrement");
 \}
 ,,,
 
 It seems that for JScrollBars it is necessary to use the
 WHEN\\_IN\\_FOCUSED\\_WINDOW input map in order to do anything because the
 JScrollBar never receives focus, and probably shouldnt

 * add arrow key scrolling to a panel in a scroll pane 
 ------------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class KeyScroll \{
 public static void main(String args[]) throws Exception \{
 JPanel p = new JPanel(new GridLayout(0, 1));
 Font font = new Font("Georgia", Font.ITALIC, 40);
 JLabel l;
 for (int i = 0; i < 200; i++) 
 \{ l = new JLabel("Label " + i); l.setFont(font); p.add(l); \}
 JFrame f = new JFrame("Scrolling with the up/down arrow keys");
 JScrollPane scroll = new JScrollPane(p);
 JScrollBar vertical = scroll.getVerticalScrollBar();
 InputMap im = vertical.getInputMap(JComponent.WHEN\\_IN\\_FOCUSED\\_WINDOW);
 im.put(KeyStroke.getKeyStroke("DOWN"), "positiveUnitIncrement");
 im.put(KeyStroke.getKeyStroke("UP"), "negativeUnitIncrement");
 f.add(scroll);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setVisible(true);
 \}
 \}
 ,,,

 * when the user presses 'G' scroll to the end of the JScrollPane
 -------------------------------------------------------------
 JScrollBar vertical = this.getVerticalScrollBar();
 InputMap im = vertical.getInputMap(JComponent.WHEN\\_IN\\_FOCUSED\\_WINDOW);
 im.put(KeyStroke.getKeyStroke("shift G"), "maxScroll");
 ,,,

 The code below may represent a useful component for those who like
 using the keyboard to move around. The following supports the keystrokes
 (j: down, J: page down, k: up, K: page up, g: top, G: bottom, 
 arrow keys up and down)

 * extend JScrollPane to support keyboard scrolling (j-down, k-up etc) 
 ------------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class KeyScrollPane extends JScrollPane
 \{
 public KeyScrollPane(JComponent c) \{
 super(c);
 JScrollBar vertical = this.getVerticalScrollBar();
 InputMap im = vertical.getInputMap(
 JComponent.WHEN\\_IN\\_FOCUSED\\_WINDOW);
 im.put(KeyStroke.getKeyStroke("G"), "minScroll");
 im.put(KeyStroke.getKeyStroke("shift G"), "maxScroll");
 im.put(KeyStroke.getKeyStroke("J"), "positiveUnitIncrement");
 im.put(KeyStroke.getKeyStroke("DOWN"), "positiveUnitIncrement");
 im.put(KeyStroke.getKeyStroke("shift J"), "positiveBlockIncrement");
 im.put(KeyStroke.getKeyStroke("K"), "negativeUnitIncrement");
 im.put(KeyStroke.getKeyStroke("UP"), "negativeUnitIncrement");
 im.put(KeyStroke.getKeyStroke("shift K"), "negativeBlockIncrement");
 \}
 public static void main(String args[]) throws Exception \{
 JPanel p = new JPanel(new GridLayout(0, 1));
 Font font = new Font("Georgia", Font.ITALIC, 40);
 JLabel l;
 for (int i = 0; i < 200; i++) 
 \{ l = new JLabel("Label " + i); l.setFont(font); p.add(l); \}
 JFrame f = new JFrame("Scrolling with the up/down arrow keys");
 KeyScrollPane scroll = new KeyScrollPane(p);
 scroll.getVerticalScrollBar().setUnitIncrement(10);
 f.add(scroll);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

SCROLLING JTEXTCOMPONENTS ....
 
 It is often useful to scroll a JTextComponent such as a JTextArea
 JEditorPane or JTextPane to the place in the component where are 
 particular piece of text occurs. 

 * another technique seems to be just to set the Caret position
 >> jtextarea.setCaretPosition(index);
 
 which actually seems alot easier. The scrollRectToVisible may be
 useful for non textcomponents.
 
 The code below finds the first instance of a text string in a JTextArea
 and scrolls the JScrollPane so that the text is visible. The code
 also adds a highlight to the text using a DefaultHighlightPainter

 The important methods in the code below are jtextarea.modelToView(int)
 and jtextarea.scrollRectToVisible(rect) The modelToView() method converts
 a document index to a pixel coordinates rectangle for the JTextArea.

 This could be the beginning of a useful document search application.
 We need to add a DocumentListener to the JTextField to do 'on the fly'
 searching and highlighting, and we need to highlight all instances 
 of the search text. Also it would be nice to display the found item
 in the middle of the JScrollPane and not at the beginning or the end.

 Also the code use setSelectionEnd/Start to select all text in the field
 this is useful.

 * scroll a JTextArea to a specific text string and highlight it
 ----------------------------------------------
 import java.io.*;
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import javax.swing.text.*;
 public class TextScroll extends JPanel implements ActionListener \{
 JTextField field;
 JTextArea area;
 public TextScroll() \{
 super();
 this.setLayout(new BoxLayout(this, BoxLayout.Y\\_AXIS));
 this.field = new JTextField(40);
 this.field.addActionListener(this);
 this.field.setFont(new Font("Monospaced", Font.PLAIN, 20));
 this.area = new JTextArea(20, 80);
 this.area.setFont(new Font("Monospaced", Font.PLAIN, 20));
 try \{
 FileInputStream fis = new FileInputStream("java-book.txt");
 InputStreamReader in = new InputStreamReader(fis, "UTF-8");
 this.area.read(in, null);
 \} catch (IOException e) \{
 e.printStackTrace();
 \}
 this.add(this.field);
 this.add(new JScrollPane(this.area));
 \}
 public void actionPerformed(ActionEvent evt) \{
 String search = this.field.getText();
 String docText = this.area.getText();
 int index = docText.indexOf(search);
 if (index < 0) \{
 this.field.setText(String.format(
 "The text '\\%s' was not found", search));
 this.field.setSelectionStart(0);
 this.field.setSelectionEnd(this.field.getText().length());
 return;
 \}
 try \{
 Rectangle rect = this.area.modelToView(index);
 this.area.scrollRectToVisible(rect);
 // the method below is probably simpler and better!!
 // this.area.setCaretPosition(index);
 this.area.getHighlighter().removeAllHighlights();
 this.area.getHighlighter().addHighlight(
 index, index + search.length(), 
 new DefaultHighlighter.DefaultHighlightPainter(Color.BLUE));
 \} catch (BadLocationException e) \{
 e.printStackTrace();
 \}
 \}
 public static void main(String args[]) \{
 EventQueue.invokeLater(new Runnable() \{
 public void run() \{
 JFrame f = new JFrame("TextScroll");
 f.add(new TextScroll());
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setVisible(true);
 \}
 \});
 \}
 \}
 ,,,


JSPINNER

 A JSpinner element is a small box which allows a user to 
 select a value by clicking the increment or decrement arrows

 * connect a JSpinner and a JSlider
 ----------------------------------

 import java.awt.*;
 import javax.swing.*;
 import javax.swing.SpinnerNumberModel;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;

 /** @see \url{http://stackoverflow.com/questions/6067898} */
 public class SpinSlider extends JPanel \{
 public static void main(String args[]) \{
 EventQueue.invokeLater(new Runnable() \{
 @Override
 public void run() \{
 JFrame f = new JFrame("SpinSlider!");
 f.add(new SpinSlider());
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack();
 f.setVisible(true);
 \}
 \});
 \}

 public SpinSlider() \{
 this.setLayout(new FlowLayout());
 final JSpinner spinner = new JSpinner();
 final JSlider slider = new JSlider();
 slider.addChangeListener(new ChangeListener() \{
 @Override
 public void stateChanged(ChangeEvent e) \{
 JSlider s = (JSlider) e.getSource();
 spinner.setValue(s.getValue());
 \}
 \});
 this.add(slider);
 spinner.setModel(new SpinnerNumberModel(50, 0, 100, 1));
 spinner.setEditor(new JSpinner.NumberEditor(spinner, "0'\\%'"));
 spinner.addChangeListener(new ChangeListener() \{
 @Override
 public void stateChanged(ChangeEvent e) \{
 JSpinner s = (JSpinner) e.getSource();
 slider.setValue((Integer) s.getValue());
 \}
 \});
 this.add(spinner);
 \}
 \}
,,,

EVENTS FOR JSPINNER ....

 addChangeLister()

JSLIDER

 * how to use sliders
 >> \url{http://docs.oracle.com/javase/tutorial/uiswing/components/slider.html}

 * a JSlider example
 ----------------------------------------------------
 JSlider slider= new JSlider(JSlider.HORIZONTAL,0,100,50); 
 //min value 0, max value 100, initial value 50
 slider.addChangeListener(this)
 JTextFox text = new JTextFox("50");
 //...
 public void stateChanged(ChangeEvent e)
 \{
 JSlider source = (JSlider)e.getSource();
 int value = (int)source.getValue();
 text.setText(Integer.toString(value));
 \}
 ,,,

 * create a JSlider and set some of its properties
 -------------------------------------------------
 gui = new JPanel(new BorderLayout(3,4));
 quality = new JSlider(JSlider.VERTICAL, 0, 100, 75);
 quality.setSnapToTicks(true);
 quality.setPaintTicks(true);
 quality.setPaintLabels(true);
 quality.setMajorTickSpacing(10);
 quality.setMinorTickSpacing(5);
 quality.addChangeListener( new ChangeListener()\{
 public void stateChanged(ChangeEvent ce) \{
 // do something when the slider slides 
 \}
 \} );
 gui.add(quality, BorderLayout.WEST);
 ,,,

JPROGRESSBAR

 The JProgressBar is a swing JComponent which shows the progress for some
 activity which takes a noticeable amount of time, such as downloading a
 file. 


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents ways to update a JProgressBar
 .. use a PropertyChangeListener
 .. use a Timer
 .. use a SwingWorker process() method
 ..

 

\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents jargon
 .. determinate progress bar - shows work done with a percentage
 .. indeterminate - shows that work is happening but not how much
 ..


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents useful methods
 .. setStringPainted(true); - display text in the bar indicated \\% done
 .. setValue(49); - set the value to 49
 .. setString("finished") - sets the string displayed in the bar
 .. setIndeterminate(true) - displays progress without values
 ..

 * how to use progress bars
 >> \url{http://docs.oracle.com/javase/tutorial/uiswing/components/progress.html}

 * create a new progress bar with a percentage displayed on it
 -------------------------------------------------------------
 progressBar = new JProgressBar(0, 100);
 progressBar.setValue(0);
 progressBar.setStringPainted(true);
 ,,,

INDETERMINATE JPROGRESSBARS ....

 An 'indeterminate' progress bar just shows that something is happening
 but doesnt attempt to say how much. The way this bar is displayed
 depends on the look-and-feel of the application.

 * an indeterminate jprogress bar 
 -------------------------------------------------------------
 import java.awt.event.*;
 import javax.swing.*;
 import java.awt.*;
 public class BorderProgressBar extends JPanel 
 implements ActionListener \{
 JProgressBar bar; JButton button; 
 BorderProgressBar() \{
 super(new FlowLayout());
 Font f = new Font("Georgia", Font.ITALIC, 20);
 this.bar = new JProgressBar();
 this.bar.setStringPainted(true);
 this.bar.setFont(f);
 this.button = new JButton("start");
 this.button.addActionListener(this);
 this.button.setFont(f);
 this.add(this.button); this.add(this.bar);
 \}
 public void actionPerformed(ActionEvent e) \{
 if (e.getSource() == this.button) \{
 this.bar.setString("working ...");
 this.bar.setIndeterminate(true);
 \} 
 \}
 public static void main(String[] args) \{
 SwingUtilities.invokeLater( new Runnable() \{
 public void run() \{
 JOptionPane.showMessageDialog(null, new BorderProgressBar());
 \}
 \});
 \}
 \}
 ,,,

SWINGWORKERS WITH JPROGRESSBARS ....

 Often a JProgressBar is updated based on the amount of progress 
 done for a task which is running in the background (a thread). One
 way to create this task is to use the SwingWorker class.

 A PropertyChangeListener listens for changes in any one of the 
 fields of a class

 * listen for changes in the fields of the 'task' class
 >> task.addPropertyChangeListener(this);

 In the example below the setProgress() method sets a value for a bound
 variable, which can be listened to with a PropertyChangeListener
 Another way to achieve the result below would be to use the 
 publish() and process() methods of the SwingWorker class. This 
 would eliminate the need for a PropertyChangeListener.

 * a progress bar used with a propertychangelistener and swingworker
 -------------------------------------------------------------
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import java.beans.*;
 import java.util.Random;
 public class ProgressBarDemo extends JPanel
 implements ActionListener, PropertyChangeListener \{
 private JProgressBar progressBar;
 private JButton startButton;
 private JTextArea taskOutput;
 private Task task;
 
 class Task extends SwingWorker<Void, Void> \{
 @Override
 public Void doInBackground() \{
 Random random = new Random();
 int totalProgress = 0;
 this.setProgress(0);
 while (totalProgress < 100) \{
 try \{
 Thread.sleep(random.nextInt(1000));
 \} catch (InterruptedException ignore) \{\}
 //Make random progress.
 totalProgress += random.nextInt(10);
 this.setProgress(Math.min(totalProgress, 100));
 \}
 return null;
 \}
 @Override
 public void done() \{
 startButton.setEnabled(true);
 setCursor(null); //turn off the wait cursor
 taskOutput.append("Done!\\$\\backslash\\$n");
 \}
 \}
 public ProgressBarDemo() \{
 super(new BorderLayout());
 startButton = new JButton("Start");
 startButton.addActionListener(this);
 progressBar = new JProgressBar(0, 100);
 progressBar.setValue(0);
 progressBar.setStringPainted(true);
 
 taskOutput = new JTextArea(5, 20);
 taskOutput.setMargin(new Insets(5,5,5,5));
 taskOutput.setEditable(false);
 
 JPanel panel = new JPanel();
 panel.add(startButton);
 panel.add(progressBar);
 
 this.add(panel, BorderLayout.PAGE\\_START);
 this.add(new JScrollPane(taskOutput), BorderLayout.CENTER);
 this.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20));
 \}
 
 public void actionPerformed(ActionEvent evt) \{
 startButton.setEnabled(false);
 setCursor(Cursor.getPredefinedCursor(Cursor.WAIT\\_CURSOR));
 this.task = new Task();
 this.task.addPropertyChangeListener(this);
 this.task.execute();
 \}
 
 // Invoked when task's progress property changes.
 public void propertyChange(PropertyChangeEvent evt) \{
 if ("progress" == evt.getPropertyName()) \{
 int progress = (Integer) evt.getNewValue();
 progressBar.setValue(progress);
 taskOutput.append(String.format(
 "Completed \\%d\\%\\% of task.\\$\\backslash\\$n", this.task.getProgress()));
 \}
 \}
 
 public static void main(String[] args) \{
 javax.swing.SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JOptionPane.showMessageDialog(null, new ProgressBarDemo());
 \}
 \});
 \}
 \}
 ,,,

 In the example below, the progress bar gets updated when it is set
 directly from the task thread with
 progressBar.setValue((int)percentageDone). In other words the
 PropertyChangeListener doesnt seem to be strictly necessary, but this is
 a tricky situation involving the event dispatch thread. I could be
 overlooking some important detail. The swing tutorial uses the property
 change listener to link the progress bar and the worker thread progress.

 * an image load with progress bar and swingworker, example working
 -------------------------------------------------------------
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import java.beans.*;
 import java.io.*;
 import java.net.*;
 import java.util.Iterator;
 import javax.imageio.*;
 import javax.imageio.event.IIOReadProgressListener;
 import javax.imageio.stream.*;
 //import java.util.concurrent.ExecutionException;

 public class ImageProgress extends JPanel implements ActionListener \{
 private JProgressBar progressBar;
 private JButton startButton;
 private Task task;
 
 class Task extends SwingWorker<Void, Void> \{
 @Override
 public Void doInBackground() \{
 ImageProgress.this.load();
 return null;
 \}
 @Override
 public void done() \{
 startButton.setEnabled(true);
 progressBar.setString("Download Completed");
 setCursor(null); //turn off the wait cursor
 \}
 \}
 
 public ImageProgress() \{
 super(new BorderLayout());
 startButton = new JButton("Load");
 startButton.addActionListener(this);
 this.progressBar = new JProgressBar(0, 100);
 this.progressBar.setValue(0); progressBar.setStringPainted(true);

 JPanel panel = new JPanel();
 panel.add(startButton); panel.add(progressBar);
 this.add(panel, BorderLayout.PAGE\\_START);
 \}
 
 private void load() \{ 
 //URL imgUrl = 
 // new URL("http://bumble.sourceforge.net/doc/cv/mjb-inchair.jpg");
 try \{
 URL imgUrl = new URL("file:big.jpg");
 InputStream is = imgUrl.openStream();
 ImageInputStream iis = ImageIO.createImageInputStream(is);
 Iterator<ImageReader> it = ImageIO.getImageReadersBySuffix("jpg");
 ImageReader reader = it.next();
 reader.setInput(iis);
 reader.addIIOReadProgressListener(new IIOReadProgressListener() \{
 public void sequenceStarted(ImageReader source, int minIndex) \{\}
 public void sequenceComplete(ImageReader r) \{\}
 public void imageStarted(ImageReader r, int imageIndex) \{\}
 public void imageProgress(ImageReader r, float percentageDone) \{
 System.out.format("Percent Downloaded: \\%f\\$\\backslash\\$n", percentageDone);
 ImageProgress.this.progressBar.setValue((int)percentageDone);
 \}
 public void imageComplete(ImageReader source) \{
 //ImageProgress.this.progressBar.setString("Download Completed");
 \}
 public void thumbnailStarted(ImageReader r, int imageIndex, int thumbnailIndex) \{ \}
 public void thumbnailProgress(ImageReader r, float percentDone) \{\}
 public void thumbnailComplete(ImageReader source) \{\}
 public void readAborted(ImageReader source) \{\}
 \});
 Image image = reader.read(0);
 //Icon icon = new ImageIcon(image);
 \} 
 catch (MalformedURLException e) \{\}
 catch (IOException e) \{\}
 \}

 public void actionPerformed(ActionEvent evt) \{
 startButton.setEnabled(false);
 setCursor(Cursor.getPredefinedCursor(Cursor.WAIT\\_CURSOR));
 this.task = new Task();
 //this.task.addPropertyChangeListener(this);
 this.task.execute();
 \}
 
 public static void main(String[] args) \{
 javax.swing.SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JOptionPane.showMessageDialog(null, new ImageProgress());
 \}
 \});
 \}
 \}
 ,,,

 The example above may be difficult to understand. The
 PropertyChangeListener updates the value of the progress bar. This
 listener fires whenever the 'progress' property of the SwingWorker task
 object changes. 

TIMERS AND JPROGRESSBARS ....

 * a simple jprogress bar used with a timer
 -------------------------------------------------------------
 import java.awt.event.*;
 import javax.swing.*;
 import java.awt.Font;
 public class SimpleProgressBar implements ActionListener \{
 Timer timer;
 JProgressBar bar;
 int counter;
 SimpleProgressBar() \{
 this.bar = new JProgressBar(0, 50);
 this.bar.setValue(0); this.bar.setStringPainted(true);
 this.bar.setFont(new Font("Georgia", Font.ITALIC, 20));
 this.counter = 0;
 this.timer = new Timer(80, this); this.timer.start();
 JOptionPane.showMessageDialog(null, bar);
 \}
 public void actionPerformed(ActionEvent e) \{
 this.counter++;
 this.bar.setValue(this.counter);
 if (this.counter > 49) \{
 this.bar.setString("finished"); timer.stop();
 \}
 \}
 public static void main(String[] args) \{
 SwingUtilities.invokeLater( new Runnable() \{
 public void run() \{
 SimpleProgressBar bar = new SimpleProgressBar();
 \}
 \});
 \}
 \}
 ,,,

 * a vertical jprogress bar used with a timer
 -------------------------------------------------------------
 import java.awt.event.*;
 import javax.swing.*;
 public class CountDownProgressBar \{
 Timer timer;
 JProgressBar progressBar;
 CountDownProgressBar() \{
 progressBar = new JProgressBar(JProgressBar.VERTICAL, 0, 10);
 progressBar.setValue(10);
 ActionListener listener = new ActionListener() \{
 int counter = 10;
 public void actionPerformed(ActionEvent ae) \{
 counter--;
 progressBar.setValue(counter);
 if (counter<1) \{
 JOptionPane.showMessageDialog(null, "Kaboom!");
 timer.stop();
 \}
 \}
 \};
 timer = new Timer(1000, listener);
 timer.start();
 JOptionPane.showMessageDialog(null, progressBar);
 \}
 public static void main(String[] args) \{
 SwingUtilities.invokeLater( new Runnable() \{
 public void run() \{
 CountDownProgressBar cdpb = new CountDownProgressBar();
 \}
 \});
 \}
 \}
 ,,,

APPEARANCE OF THE JPROGRESSBAR ....

 The progress bar seems to paint some kind of a border itself,
 which is doesnt look very good with a custom border.

 * a jprogress bar with a custom border
 -------------------------------------------------------------
 import java.awt.event.*;
 import javax.swing.*;
 import java.awt.*;
 public class BorderProgressBar extends JPanel 
 implements ActionListener \{
 Timer timer;
 JProgressBar bar;
 JButton button;
 int counter;
 BorderProgressBar() \{
 super(new FlowLayout());
 Font f = new Font("Georgia", Font.ITALIC, 20);
 this.bar = new JProgressBar(0, 50);
 this.bar.setValue(0); this.bar.setStringPainted(true);
 this.bar.setFont(f);
 this.bar.setBorder(new RoundedBorder());
 this.button = new JButton("start");
 this.button.addActionListener(this);
 this.button.setFont(f);
 this.add(this.button); this.add(this.bar);
 \}
 public void actionPerformed(ActionEvent e) \{
 if (e.getSource() == this.button) \{
 this.bar.setString(null);
 this.counter = 0;
 this.timer = new Timer(80, this); this.timer.start();
 \} 
 else \{
 this.counter++;
 this.bar.setValue(this.counter);
 if (this.counter > 49) \{
 this.bar.setString("finished"); this.timer.stop();
 \}
 \}
 \}
 public static void main(String[] args) \{
 SwingUtilities.invokeLater( new Runnable() \{
 public void run() \{
 JOptionPane.showMessageDialog(null, new BorderProgressBar());
 \}
 \});
 \}
 \}
 ,,,

GOTCHAS FOR JPROGRESSBAR ....

 If the setStringPainted() method is not set to true then the setString()
 method will do nothing, which is logical but maybe surprising.

 Once you use setString() on a JProgressBar, it wont display values until
 you call bar.setString(null)
 
JCHECKBOX

 A check box is a small box in which the user can place a 'tick' or
 'check' by clicking with the mouse. These elements are usually used in
 order to select more than one item in a list.

 * create a simple checkbox which is initially selected
 ------------------------------------------------------
 import javax.swing.*;
 public class SimpleCheckBox \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("A JCheckBox example");
 JCheckBox b = new JCheckBox("Shopping"); b.setSelected(true);
 f.add(b); f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

 * a check box with a short-cut (mnemonic) alt 's' and a tool tip
 --------------------------------------------------------------
 import javax.swing.*;
 import java.awt.event.KeyEvent;
 public class ShortCutCheckBox \{
 public static void main(String[] args) \{
 JCheckBox b = new JCheckBox("Grow Trees");
 b.setSelected(true); b.setMnemonic(KeyEvent.VK\\_G); 
 b.setToolTipText(
 "<html><big><big>Use 'alt g' to toggle the checkbox ");
 JPanel p = new JPanel(); p.add(b);
 JFrame f = new JFrame("JCheckBox with a Mnemonic Key");
 f.add(p);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

 * a check box with a large font 
 -------------------------------
 import javax.swing.*;
 import java.awt.Font;
 public class FontCheckBox \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("A JCheckBox with a large Font");
 JCheckBox b = new JCheckBox("Big Text");
 b.setFont(new Font("Serif", Font.PLAIN, 20));
 JPanel p = new JPanel(); p.add(b);
 f.add(p); f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

 * a check box with html text for the tool tip and the display text
 ------------------------------------------------------------------
 import javax.swing.*;
 public class HtmlCheckBox \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("Html in JCheckBoxes");
 JCheckBox b = new JCheckBox("<html>Vi<u>m</u></html>");
 b.setToolTipText("<html><em>Click</em> to go shopping</html>");
 JPanel p = new JPanel(); p.add(b);
 f.add(p); f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

 * a list of files with check boxes in the current folder
 --------------------------------------------------------
 import java.io.File;
 import javax.swing.*;
 import java.awt.GridLayout;
 public class FileListCheckBox \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("Check Boxes with a List of Files");
 JPanel p = new JPanel(new GridLayout(0,1));
 for (File file: new File(".").listFiles()) \{
 p.add(new JCheckBox(file.getName()));
 \}
 f.add(new JScrollPane(p));
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

 * create a checkbox and do something when it is checked 
 -------------------------------------------------------------
 JCheckBox box = new JCheckBox("Anti-aliasing", false);
 ItemListener listener = new ItemListener() \{
 public void itemStateChanged(ItemEvent e) \{
 // do something
 \}
 \};
 box.addItemListener(listener);
 ,,,

JRADIOBUTTON

 Radio Buttons are similar to check boxes but may be configured
 to only allow one to be 'checked' at once. Only one button within
 a group may be selected.
 
 * a list of files with radio buttons
 ------------------------------------
 import java.io.File;
 import javax.swing.*;
 import java.awt.GridLayout;
 public class Test \{
 public static void main(String[] args)
 \{
 JFrame f = new JFrame("one button");
 JPanel p = new JPanel(new GridLayout(0,1));
 ButtonGroup group = new ButtonGroup();
 JRadioButton r;
 File[] ff = (new File(".")).listFiles();
 for (int ii = 0; ii < ff.length; ii++)
 \{
 p.add(r = new JRadioButton(ff[ii].getName()));
 group.add(r);
 \}
 f.getContentPane().add(new JScrollPane(p));
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLocationRelativeTo(null);
 f.pack();
 f.setVisible(true);
 \}
 \}
 ,,,

JBUTTONS

 A button is a graphical component which can be 'clicked' with
 the users mouse device in order to carry out some action. 
 In java buttons are implemented with the swing JButton class.

 * add an 'access key' to a button (pressing the key, 'clicks' the button)
 >> jbutton.setMnemonic(KeyEvent.VK\\_I);

 * create a button with 2 lines of text
 >> JButton b = new JButton("<html><b><u>T</u>wo</b><br>lines</html>");

 * create a button with underlined 20 point text and a tool tip 
 --------------------------------------------------------------
 import javax.swing.*;
 import java.awt.Font;
 public class Test \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("one button");
 JButton button = new JButton("<html><u>Click</u></html>");
 button.setToolTipText("click to start the game");
 button.setFont(new Font("Serif", Font.PLAIN, 20));
 JPanel p = new JPanel();
 p.add(button);
 f.getContentPane().add(p);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLocationRelativeTo(null);
 f.pack();
 f.setVisible(true);
 \}
 \}
 ,,,

 The BasicArrowButton cant display text

 * create a button with a right pointing arrow or triangle in it 
 -------------------------------------
 import javax.swing.*;
 import javax.swing.plaf.basic.BasicArrowButton;
 import java.awt.Font;
 public class ArrowButton \{
 public static void main(String[] args) \{
 JButton button = new BasicArrowButton(SwingConstants.EAST);
 JOptionPane.showMessageDialog(null, button);
 \}
 \}
 ,,,

 * put a button in a JFrame window
 -------------------------------------------------------------
 import javax.swing.*;
 public class Test \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("one button");
 JButton button = new JButton("hello");
 JPanel p = new JPanel();
 p.add(button); f.add(p);
 f.getContentPane().add(p);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLocationRelativeTo(null);
 f.pack();
 f.setVisible(true);
 \}
 \}
 ,,,

 * set the font and colour for the JButton text 
 ---------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class ButtonFont \{
 public static void main(String[] args) \{
 JButton button = new JButton("hello");
 button.setFont(new Font("Serif", Font.ITALIC, 20));
 button.setForeground(Color.green);
 JOptionPane.showMessageDialog(null, button);
 \}
 \}
 ,,,

 * extend the jframe class and place a button in it 
 --------------------------------------------------
 import javax.swing.*;
 public class FrameButton extends JFrame \{
 public FrameButton () \{
 super();
 this.add(new JButton("A Button in a JFrame"));
 this.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 this.pack(); this.setLocationRelativeTo(null);
 this.setVisible(true);
 \}
 public static void main(String[] args) \{ new FrameButton(); \}
 \}
 ,,,

 * a jframe class which contains a button and listens for clicks 
 --------------------------------------------------------------
 import javax.swing.*;
 import java.awt.event.*;
 public class Test extends JFrame implements ActionListener \{
 JButton button;
 public Test () \{
 this.button = new JButton("hello");
 this.button.addActionListener(this);
 this.getContentPane().add(this.button);
 this.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 this.pack(); this.setLocationRelativeTo(null);
 this.setVisible(true);
 \}
 public void actionPerformed(ActionEvent e) \{
 JOptionPane.showMessageDialog(
 this, "clicked " + e.getActionCommand());
 \}
 public static void main(String[] args) \{ Test t = new Test(); \}
 \}
 ,,,

 * change a label when a button is clicked 
 -----------------------------------------
 import java.awt.event.*;
 import javax.swing.*;
 public class Test \{
 public static void main(String[] args)
 \{
 JFrame f = new JFrame("one button");
 JButton button = new JButton("click");
 final JLabel label = new JLabel("hello");
 button.addActionListener(new ActionListener()\{
 public void actionPerformed(ActionEvent e)
 \{ label.setText("bye"); \}\});
 JPanel p = new JPanel();
 p.add(button); p.add(label);
 f.add(p);
 f.getContentPane().add(p);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLocationRelativeTo(null);
 f.pack(); f.setVisible(true);
 \}
 \}
 ,,,

 * make a click event handler for the button
 -------------------------------------------
 final JButton b = new JButton("click");
 b.addActionListener(new ActionListener()\{
 public void actionPerformed(ActionEvent e)
 \{
 b.setText("click");
 \}
 \});
 ,,, 
 
 * make an action which is executed when a button is pushed
 ----------------------------------------------------------
 Action showMessage = new AbstractAction() \{
 \{ putValue(Action.NAME, "Message"); \}
 public void actionPerformed(ActionEvent e) \{ \}
 \};
 
 JButton loadButton = new JButton(loadAction);
 panel.add(loadButton);
 ,,,

 * set the gap between the text and the icon in a button
 >> button.setIconTextGap(8);
 
 * the position of the icon and text in the button.
 --------------------------------------------------
 button.setVerticalAlignment(SwingConstants.TOP);
 button.setHorizontalAlignment(SwingConstants.LEFT);
 ,,,

 * position the text relative to the icon in the button
 >> \url{http://www.exampledepot.com/egs/javax.swing/button\\_MoveIcon.html?l=rel}

JLABELS

 Swing labels or JLabels are used to display a small amount of text and/or
 an ImageIcon. They are also used as the element in JLists and JComboBoxes

 * declare a new JLabel
 >> JLabel testLabel;

 * create a new JLabel with some initial text
 >> testLabel = new JLabel("A new label");

 * change the text for the JLabel
 >> testLabel.setText("new file"); 

 * create a label with a mnemonic and associate with a comboBox
 -------------------------------------------------------------
 JLabel label = new JLabel("Select Component:");
 label.setDisplayedMnemonic('S');
 label.setLabelFor( comboBox );
 ,,,

 * create a label with an icon
 >> Icon icon = new Icon(...); JLabel l = new JLabel(icon);

 >> label.setIcon(...);

 * change the size of a label after setVisible()
 -------------------------------------------------------------
 JLabel label;
 label.setPreferredSize(new Dimension(100, 100) );
 label.revalidate();
 ,,,


 * create a JLabel with the standard information icon 
 -------------------------------------------------------------
 import java.awt.*;
 import javax.swing.*;
 public class IconLabel \{
 public static void main(String args[]) \{
 JFrame f = new JFrame("Icon in a JLabel");
 JLabel label = new JLabel("JLabel with Information icon");
 label.setIcon(UIManager.getIcon("OptionPane.informationIcon"));
 f.add(label, BorderLayout.NORTH);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null); 
 f.setVisible(true);
 \}
 \}
 ,,,

 * add a label to a window
 ------------------------------------------
 import javax.swing.*;
 public class LabelTest \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("a simple window");
 JLabel label = new JLabel("Just A Label");
 f.getContentPane().add(label);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLocationRelativeTo(null); f.pack();
 f.setVisible(true);
 \}
 \}
 ,,,

 * add a label and text field to a window frame 
 -------------------------------
 import javax.swing.*;
 public class Test \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("Testing Labels");
 JLabel label = new JLabel("Enter Name");
 JTextField box = new JTextField(10);
 JPanel pl = new JPanel();
 pl.add(label);
 pl.add(box);
 f.getContentPane().add(pl);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLocationRelativeTo(null);
 f.pack();
 f.setVisible(true);
 \}
 \}
 ,,,

 The rounded corners below dont seem to work, or the arc is so
 small that it is invisible.

 * set the preferred size of a label
 >> jlabel.setPreferredSize(100, 100);

HTML WITH JLABELS ....

 The text of a JLabel can be html and include css directives. For the 
 text to be interpreted as html it must start with '<html>' 

 * make text in a JLabel wrap to a particular pixel width
 -------------------------
 import javax.swing.*;
 class FixedWidthLabel \{
 public static void main(String[] srgs) \{
 String s = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Aenean eu nulla urna. Donec sit amet risus nisl, a porta enim. Quisque luctus, ligula eu scelerisque gravida, tellus quam vestibulum urna, ut aliquet sapien purus sed erat. Pellentesque consequat vehicula magna, eu aliquam magna interdum porttitor...";
 String html1 = "<html><body style='width: ";
 String html2 = "px'>";
 JOptionPane.showMessageDialog(null, new JLabel(html1+"200"+html2+s));
 JOptionPane.showMessageDialog(null, new JLabel(html1+"300"+html2+s));
 \}
 ,,,

BORDERS WITH JLABELS ....

 For a rounded corner border for a JLabel you have to write your
 own border class, because the LineBorder rounded corner option doesnt
 seem to work.

 * set the border for a label
 >> jlabel.setBorder(BorderFactory.createLineBorder(Color.black));
 
IMAGES IN JLABELS ....

 * put an image in a label
 >> jlabel.setIcon(new ImageIcon("imagefilename");

 * display a label with text and an image 
 ------------------------------------------
 import javax.swing.*;
 public class TextImageLabel \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("a simple window");
 ImageIcon icon = new ImageIcon(
 "/usr/share/icons/gnome/24x24/devices/chardevice.png");
 JLabel label = new JLabel("Image and Text", icon, JLabel.CENTER);
 f.getContentPane().add(label);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLocationRelativeTo(null);
 f.pack();
 f.setVisible(true);
 \}
 \}
 ,,,

 * create a label with just an icon image and no text 
 ----------------------------------------------------
 import javax.swing.*;
 public class Test \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("a simple window");
 ImageIcon icon = new ImageIcon(
 "/usr/share/icons/gnome/24x24/devices/chardevice.png");
 JLabel label = new JLabel(icon);
 f.getContentPane().add(label);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLocationRelativeTo(null);
 f.pack();
 f.setVisible(true);
 \}
 \}
 ,,,


COLORS IN JLABELS ....

 * set the background colour of a JLabel to orange
 >> jlabel.setBackground(Color.orange); jlabel.setOpaque(true);

ALIGNING TEXT AND IMAGES IN JLABELS ....

 * a label with text and an image
 >> l = new JLabel("Image and Text", icon, JLabel.CENTER);

 * create a label with right aligned text 
 >> JLabel label = new JLabel("label text", SwingConstants.RIGHT);

 * align the text of a label underneath its image icon
 -------------------------------------------------------------
 JLabel l = new JLabel("text underneath image");
 l.setHorizontalTextPosition(JLabel.CENTER);
 l.setVerticalTextPosition(JLabel.BOTTOM);
 ,,,

 * display a 48pt centre aligned label in the logical serifed font
 ------------------------------------------------------------------
 import javax.swing.*;
 import java.awt.Font;
 public class Test \{
 public static void main(String[] args) \{
 JLabel title = new JLabel("A Big Label", JLabel.CENTER);
 title.setFont(new Font("Serif", Font.BOLD, 48));
 JOptionPane.showMessageDialog(null, title);
 \}
 \}
 ,,,

CSS HTML AND JLABELS ....

 The text of a swing JLabel can be html and can include some 
 subset of cascading style sheets (css). The provides a way to style
 the text which is displayed in the label. Any label text which 
 begins with the tag <html> will be treated as html.

 * set the font size for a JLabel using a css style attribute 
 ------------------------------------------------------------------
 import javax.swing.*;
 import java.awt.Font;
 public class CssLabel \{
 public static void main(String[] args) \{
 JLabel l = new JLabel(
 "<html><body style='font-size: 30px'>A Big Label", JLabel.CENTER);
 JOptionPane.showMessageDialog(null, l);
 \}
 \}
 ,,,

 The css property seems to override and Font which is applied to the 
 JLabel with the setFont() method.

 * set the font size for a JLabel using a css style attribute 
 ------------------------------------------------------------------
 import javax.swing.*;
 import java.awt.Font;
 public class CssLabel \{
 public static void main(String[] args) \{
 JLabel l = new JLabel(
 "<html><body style='font-size: 30px'>A Big Label", JLabel.CENTER);
 l.setFont(new Font("Serif", Font.BOLD, 10));
 JOptionPane.showMessageDialog(null, l);
 \}
 \}
 ,,,

 In the code below the <style> tag must be within the <head> tag
 and before the body tag.

 * use the html <style> tag to add css to a JLabel html
 -------------------------------------------------------------
 StringBuffer sb = new StringBuffer();
 sb.append("<html><head><style type='text/css'>");
 sb.append("li \{ font-style: italic; font-size: 30pt; \}");
 sb.append("li \{ font-family: serif; color: \\#ff5555; \}");
 sb.append("ul \{ border-width: 4px; border-style: solid;
 border-color: \\#ff0000; \} ");
 sb.append("ul \{ background-color: \\#ffeeee; \}");
 sb.append("</style></head>");
 sb.append("<h3>H3 Header</h3>");
 sb.append("<ul><li>large serifed text</li><li>as list items</li>");
 sb.append("</html>");
 
 JLabel l3 = new JLabel(sb.toString());
 ,,,

PAINTCOMPONENT METHOD FOR JLABEL ....

 One way to customise the appearance of a JLabel component (especially
 its background) is to override the paintComponent() method of the 
 class. Within the paintComponent() method one should call the 
 super.paintComponent() method otherwise you are pretty much writing
 a swing component from scratch.

 Ideas:
 Include examples for translucent colors for the JLabel background
 and place stuff behind the JLabel (text, images ...) to see how
 it looks. Use translucent gradient paints. Use a custom paint
 with the paintComponent method- draw lots dingbats etc.

 The example below creates a JLabel subclass which is identical to a 
 JLabel except that it only has one constructor (instead of several).
 But the example provides a template for overriding the paintComponent
 method of a JLabel (or any other JComponent)

 * a skeleton example of overriding the paintComponent() method
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.Graphics;
 public class PaintLabel extends JLabel \{
 public PaintLabel(String text) \{
 super(text);
 \}
 public void paintComponent(Graphics g) \{
 super.paintComponent(g);
 \}
 public static void main(String[] args) \{
 JOptionPane.showMessageDialog(null, new PaintLabel("hi"));
 \}
 \}
 ,,,

 The example below shows that if the super.paintComponent() method is 
 called first within the paintComponent method, then whatever is painted
 will be painted on top of the JLabel text. This is usually not what
 is wanted.

 * example the JLabel text get covered by the painting code
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class PaintLabel extends JLabel \{
 public PaintLabel(String text) \{
 super(text);
 \}
 public void paintComponent(Graphics g) \{
 super.paintComponent(g);
 g.setColor(Color.green);
 g.fillRect(0, 0, this.getWidth(), this.getHeight());
 \}
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JOptionPane.showMessageDialog(null, new PaintLabel("hi"));
 \}
 \});
 \}
 \}
 ,,,

 * call super.paintComponent() last to draw the label text on top 
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class PaintLabel extends JLabel \{
 public PaintLabel(String text) \{
 super(text);
 \}
 public void paintComponent(Graphics g) \{
 g.setColor(Color.green);
 g.fillRect(0, 0, this.getWidth(), this.getHeight());
 super.paintComponent(g);
 \}
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JOptionPane.showMessageDialog(null, new PaintLabel("hi"));
 \}
 \});
 \}
 \}
 ,,,

 * painting with a background, the background is red, not green
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class PaintLabel extends JLabel \{
 public PaintLabel(String text) \{
 super(text);
 this.setOpaque(true); this.setBackground(Color.red);
 \}
 public void paintComponent(Graphics g) \{
 g.setColor(Color.green);
 g.fillRect(0, 0, this.getWidth(), this.getHeight());
 super.paintComponent(g);
 \}
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JOptionPane.showMessageDialog(null, new PaintLabel("hi"));
 \}
 \});
 \}
 \}
 ,,,

 In the example below, it is necessary to subtract one from the width
 and height properties in order for all sides of the rectangle to be
 visible.

 * draw a 1 pixel rectangle around a JLabel
 -------------------------------------------------------------
 g2d.draw(new Rectangle2D.Double(
 0, 0, this.getWidth()-1, this.getHeight()-1));
 ,,,

 Note that if you would like to use a rounded corner Border on a 
 JComponent with a background color, then you will need to use a 
 technique such as the one below.

 The example below gets the background color from the JLabel but
 does not honor the JLabel behaviour of being transparent by default.

 * paint a rounded corner background on a JLabel
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 import java.awt.geom.RoundRectangle2D;
 public class CornerLabel extends JLabel \{
 int cornerRadius;
 public CornerLabel(String text) \{
 super(text);
 this.cornerRadius = 12;
 \}
 public CornerLabel(String text, int cornerRadius) \{
 super(text);
 this.cornerRadius = cornerRadius;
 \}
 public void paintComponent(Graphics g) \{
 Graphics2D gg = (Graphics2D) g;
 int r = this.cornerRadius;
 gg.setRenderingHint(RenderingHints.KEY\\_ANTIALIASING, 
 RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 gg.setColor(this.getBackground());
 gg.fill(new RoundRectangle2D.Double(
 0, 0, this.getWidth()-1, this.getHeight()-1, r, r));
 super.paintComponent(g);
 \}
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JLabel l = new CornerLabel("Rounded Corner Background", 20);
 l.setBackground(Color.blue);
 l.setFont(new Font("Georgia", Font.PLAIN, 40));
 JOptionPane.showMessageDialog(null, l);
 \}
 \});
 \}
 \}
 ,,,

 In order to honor the JLabel behaviour of transparent by default
 we need to include code such 
 >> if (this.isOpaque()) \{ /* painting code */ \}

 * rounded corners background with a gradient paint
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 import java.awt.geom.RoundRectangle2D;
 public class RoundCornerLabel extends JLabel \{
 int cornerRadius;
 public RoundCornerLabel(String text) \{
 super(text);
 this.cornerRadius = 12;
 \}
 public void paintComponent(Graphics g) \{
 Graphics2D gg = (Graphics2D) g;
 int w = this.getWidth(); int h = this.getHeight();
 int r = this.cornerRadius;
 gg.setRenderingHint(RenderingHints.KEY\\_ANTIALIASING, 
 RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 Color startColor = this.getBackground().brighter().brighter();
 Color endColor = this.getBackground().darker().darker();
 GradientPaint gp = 
 new GradientPaint(0, 0, startColor, 0, h, endColor, true);
 gg.setPaint(gp);
 gg.fill(new RoundRectangle2D.Double(0, 0, w-1, h-1, r, r));
 super.paintComponent(g);
 \}
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JLabel l = new RoundCornerLabel("Rounded Corners \\& Gradient");
 l.setFont(new Font("Georgia", Font.PLAIN, 40));
 l.setBackground(Color.blue.darker());
 JOptionPane.showMessageDialog(null, l);
 \}
 \});
 \}
 \}
 ,,,

 The example below attempts to decorate a JLabel with fleur-de-lyses
 painted in the background, but it doesnt calculate the fontmetrics
 properly. Also the background image is distracting rather than attractive.
 Could use the FontHelp.getGlyphFonts() method to make sure that a 
 glyph exists.

 * paint a glyph repeatedly on the background of a jlabel 
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 import java.awt.geom.RoundRectangle2D;
 public class GlyphLabel extends JLabel \{
 public GlyphLabel(String text) \{
 super(text);
 \}
 public void paintComponent(Graphics g) \{
 Graphics2D gg = (Graphics2D) g;
 char c = '\\$\\backslash\\$u269c'; 
 gg.setRenderingHint(RenderingHints.KEY\\_ANTIALIASING, 
 RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 gg.setColor(this.getBackground());
 gg.setFont(new Font("FreeSerif", Font.PLAIN, 30));
 for (int ii = 0; ii < this.getWidth(); ii=ii+20) \{
 gg.drawString("" + c, ii, 40);
 \}
 super.paintComponent(g);
 \}
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JLabel l = new GlyphLabel("A fleur-de-lys background");
 l.setBackground(Color.lightGray);
 l.setFont(new Font("Georgia", Font.PLAIN, 60));
 JOptionPane.showMessageDialog(null, l);
 \}
 \});
 \}
 \}
 ,,,

GOTCHAS FOR JLABELS ....

 If you add an empty (with no text) JLabel to a BorderLayout.NORTH
 then you cant see the JLabel at all (at least until you set its
 text to something)

JTEXTCOMPONENTS 

 Text components are those components which allow the editing
 of text, including JTextField, JTextArea, JEditorPane ....
 These components can be divided into 2 categories: Those which allow
 the text to be 'styled' (have a variety of fonts, colours etc) and
 those which dont. The 'styled' components are considerably more
 complex.

 \url{http://stackoverflow.com/questions/6913983/jtextpane-removing-first-line}
 remove first line of a document, using elements

 @@ \url{http://es.scribd.com/doc/89923641/31/JTextComponent-features}
 very good summary of JTextComponent features.

 .createPosition in a text component is like creating a bookmark. The
 bookmark doesnt change even when its offset from the start of the 
 document changes


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents useful methods for JTextComponent
 .. modelToView() - convert document offsets (characters) into pixels
 .. viewToModel() - convert pixel location to document offset
 .. 

MODELTOVIEW ....

 The method modelToView is important for obtaining the pixel position
 (actually a java.awt.Rectangle) within a JTextComponent of a particular
 index in a document. Note that this pixel position is relative to the
 JTextComponent and not to any scrollpane/viewport nor to the panel.
 
 The method textcomponent.modelToView(int) returns a one pixel wide
 rectangle with the height of the current line height (determined by the
 size of the font). For example for a 22 point/pixel Font the line height
 (and the height of the rectangle will be 28 pixels). This height is the
 same as the default vertical scroll increment for a JVerticalScrollBar.

 The top of the rectangle is positioned at the top of the line
 corresponding to the document index, between characters. See
 ScrollBarTest to experiment with caret positions and modelToView
 co-ordinates.

DOCUMENTS ....

 All of the swing components which allow the editing of text (descendants
 of JTextComponent) have an associated Document which is
 javax.swing.text.Document. The document can have a structure which is
 represented by a heirarchy (or several heirarchies) of
 javax.swing.text.Element objects.

 If you want to listen to all changes to a document and modify the 
 document depending on some condition you probably need to subclass the
 Document and override the insertString() method. See below for an
 example of this.

 * add a property to the document for a JTextComponent
 >> tc.getDocument().putProperty("filename", "index.txt");
 
 These properties can be used for any purpose that occurs to the 
 programmer.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents useful methods of the Document class
 .. getLength() - the number of characters in the document
 .. getText(0,3) - get the 1st three letters of the document 
 .. createPosition(3) - create a 'bookmark' just after the 3rd character
 .. insertString(2, "hi", null) - insert 'hi' after 2nd char, no attribs
 .. remove(5, 2) - delete 2 characters just after the 5th character
 ..

 * an efficient scan of a large document using getText(int, int, segment)
 -------------------------------------------------------------
 int nleft = doc.getDocumentLength();
 Segment text = new Segment();
 int offs = 0;
 text.setPartialReturn(true);
 while (nleft > 0) \{
 doc.getText(offs, nleft, text);
 nleft -= text.count;
 offs += text.count;
 \}
 ,,,

 The code above is considered efficient because it doesnt involve
 copying the text from the document. The text is made accessible in
 the javax.swing.text.Segment object. The partialReturn(true) ensures
 that the text is not copied.

 * remove something from the end of a JTextArea
 -------------------------------------------------------------
 PlainDocument doc = (PlainDocument) textArea.getDocument();
 doc.remove(doc.getLength() - 1, 1);
 ,,,
 
 * remove 4 characters near the text component caret position
 -------------------------------------------------------------
 PlainDocument doc = (PlainDocument) area.getDocument();
 try \{ doc.remove(area.getCaretPosition() - 4, 4); \}
 catch (BadLocationException ex) \{ ex.printStackTrace(); \}
 ,,,

 * 2 text fields with the same document
 --------------------------------------------
 ,,,

 * make typing '>' in a textcomponent do something special
 --------------
 JFrame f = new JFrame();
 StyledDocument d = new DefaultStyledDocument() \{
 @Override
 public void insertString(int offs, String str, AttributeSet a) 
 throws BadLocationException \{
 if (">".equals(str)) \{
 // Do some action
 System.out.println("Run action corresponding to '" + str + "'");
 \} else \{
 super.insertString(offs, str, a);
 \}
 \}
 \};
 JTextPane t = new JTextPane(d);
 f.add(t);
 ,,,

SELECTIONS IN JTEXTCOMPONENTS ....

 All JTextComponent can have a part of the text 'selected' (which
 is different from 'highlighted'). Selected text is painted in a 
 different colour and is replaced as soon as the user types something.
 Which is handy. Selections are actually maintained in the Caret
 class but convenience methods are available to all JComponents


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents selection methods
 .. setSelectionStart(int)
 .. setSelectionEnd(int)
 ..

 * make all the text in a JTextField selected
 -------------------------------------------------------------
 textfield.setSelectionStart(0);
 textfield.setSelectionEnd(this.field.getText().length());
 ,,,

POSITIONS IN THE DOCUMENT ....

 In the swing Document interface, Positions occur *between* characters.
 For example, position 3 is just after the 3rd character and just
 before the 4th. etc.

DOCUMENT STRUCTURE ....

 The Document associated with a swing text component may have a 
 heirarchical structure. For example, a set of paragraphs will make
 up a chapter, which in turn will form a book. The Document provides
 a mechanism to specify this structure through the Element interface.
 Each Element object represents one node of this structure (one chapter,
 one paragraph etc), and attributes associated with the Element specify
 which type of node.

 In practice it seems uncommon to implement custom Document structures.
 If the programmer implements a new document structure she must
 listen to document changes (insert, remove) with a DocumentListener
 and use the documentEvent.getChange(Element elem) to update the structure
 when text is inserted or removed. This may be tricky.

 We can traverse the Document structure by calling methods of the 
 Element interface.

 @@ \url{http://java.sun.com/products/jfc/tsc/articles/text/element\\_interface/}
 An article about the Element interface and document structures

 Idea: create a JTree component with a Document structure, each node
 on the tree an Element.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents document structure methods 
 .. getDefaultRootElement() - the root (top-level) Element (eg: Book)
 .. getRootElements() - get all roots (if the doc has several structures)
 ..

 In theory the Document can have several parallel structures which are
 retrieved with getRootElements(). 
 
 The AttributeSet obtainable from an Element with getAttributes() is 
 often used for markup attributes (color, font etc)

PLAINDOCUMENT ....

 JTextComponents which do not display styled text use a PlainDocument
 as their model. This Document has a very simple document structure:
 a root element, and a set of child Elements which represent lines
 in the document.
 
 When a newline character '\\$\\backslash\\$n' is inserted into a PlainDocument the 
 document needs to update its structure. A new child element (line)
 is created and the position offsets for the existing child Elements
 are updated. This is done through a DocumentListener

DEFAULTSTYLEDDOCUMENT ....

 The DefaultStyledDocument represents text of which regions have 
 certain styles associated with them (for example, italic, green etc)
 The Document structure has 3 levels: root, paragraph, style. The single
 root contains a set of paragraphs which in turn contain a set of 
 styled regions (called 'styles').

 \url{http://www.exampledepot.com/egs/javax.swing.text/tp\\_StyledText.html}
 a good simple example of inserting styled text

 \url{http://stackoverflow.com/questions/10193550/appending-richtext-to-jtextpane-using-styleddocument-insertstring-doesnt-preser}
 inserting rich text in a jtextpane

 \url{http://www.exampledepot.com/egs/javax.swing.text/ListTextKeys.html}
 words of wisdom about keybindings and keymaps, read carefully


 more attribute magic for textcomponents
 ---------------
 You can get EditorKit from your JEditorPane. It's StyledEditorKit instance. So you can get InputAtributes from the kit and remove all the attributes. Thus all the typing will use the empty AttributeSet.
 stanislav

 The code below is a skeleton for inserting styled text in a styled
 document for example with a JTextPane. The insertString method takes a
 position param a string and a set of attributes

 * create some attributes to style text in a Styled document, then insert at end of doc
 ----------
 StyledDocument doc = textPane.getStyledDocument();
 // do we have to cast to AbstractDocument?? 
 // they do in java tutorial but why
 attrs[0] = new SimpleAttributeSet();
 StyleConstants.setFontFamily(attrs[0], "SansSerif");
 StyleConstants.setFontSize(attrs[0], 16);
 doc.insertString(doc.getLength(), "hello styles",
 attrs[0]);
 ,,,

 
 * add lots of style actions to a menu (works for a component with styled doc)
 ------------ 
 protected JMenu createStyleMenu() \{
 JMenu menu = new JMenu("Style");
 
 Action action = new StyledEditorKit.BoldAction();
 action.putValue(Action.NAME, "Bold");
 menu.add(action);
 action = new StyledEditorKit.ItalicAction();
 action.putValue(Action.NAME, "Italic");
 menu.add(action);
 
 action = new StyledEditorKit.UnderlineAction();
 action.putValue(Action.NAME, "Underline");
 menu.add(action);
 menu.addSeparator();
 
 menu.add(new StyledEditorKit.FontSizeAction("12", 12));
 menu.add(new StyledEditorKit.FontSizeAction("14", 14));
 menu.add(new StyledEditorKit.FontSizeAction("18", 18));
 
 menu.addSeparator();
 menu.add(new StyledEditorKit.FontFamilyAction("Serif",
 "Serif"));
 menu.add(new StyledEditorKit.FontFamilyAction("SansSerif",
 "SansSerif"));
 
 menu.addSeparator();
 menu.add(new StyledEditorKit.ForegroundAction("Red", Color.red));
 menu.add(new StyledEditorKit.ForegroundAction("Green", Color.green));
 menu.add(new StyledEditorKit.ForegroundAction("Blue", Color.blue));
 menu.add(new StyledEditorKit.ForegroundAction("Black", Color.black));
 return menu;
 \}
 ,,,

 \url{http://docs.oracle.com/javase/tutorial/uiswing/examples/components/TextComponentDemoProject/src/components/TextComponentDemo.java}
 an example implementation of undo redo on a text component. Also
 controlkey bindings and also installing a document filter on a
 document.

DOCUMENTFILTERS ....

 DocumentFilters allow the programmer to specify what kind of text 
 or how much text can be entered in a JTextComponent. 

 * a complete example of a document filter which only allows numbers
 -------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.text.*;
 import java.util.regex.*;
 public class NumberOnlyFilter extends DocumentFilter \{
 public void insertString(DocumentFilter.FilterBypass fb, int offset, String text, AttributeSet attr) throws BadLocationException \{
 StringBuilder sb = new StringBuilder();
 sb.append(fb.getDocument().getText(0, fb.getDocument().getLength()));
 sb.insert(offset, text);
 if (!containsOnlyNumbers(sb.toString())) return;
 fb.insertString(offset, text, attr);
 \}
 public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attr) throws BadLocationException \{
 StringBuilder sb = new StringBuilder();
 sb.append(fb.getDocument().getText(0, fb.getDocument().getLength()));
 sb.replace(offset, offset + length, text);
 if (!containsOnlyNumbers(sb.toString())) return;
 fb.replace(offset, length, text, attr);
 \}
 public boolean containsOnlyNumbers(String text) \{
 Pattern pattern = Pattern.compile("[\\$\\backslash\\$\\$\\backslash\\$d]");
 Matcher matcher = pattern.matcher(text);
 boolean isMatch = matcher.matches();
 return isMatch;
 \}
 \}
 // use this with
 // ((AbstractDocument)jtextfield.getDocument()).setDocumentFilter(new NumberOnlyFilter());
 ,,,

DOCUMENTLISTENERS ....

 A DocumentListener allows us to react to changes to the text
 in a JTextComponent. The DocumentListener is registered with 
 the Document associated with the JTextComponent. The Document
 fires javax.swing.event.DocumentEvents

 UndoableEditEvents are used for undoing changes.

 * add a subclass of DocumentListener to the Document of a text component 
 >> tc.getDocument().addDocumentListener(new DocListener());
 

\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents DocumentListener interface methods 
 .. public void insertUpdate(DocumentEvent e) \{\}
 .. public void removeUpdate(DocumentEvent e) \{\}
 .. public void changedUpdate(DocumentEvent e) \{\}
 ..

 However the changedUpdate() method in practice is not implemented
 for JTextComponent with a PlainDocument model (for example, 
 JTextField, or JTextArea components but only for text components
 with a StyledDocument model such as JEditorPane


 * retrieve the Document from the event
 ----------------------------------------------
 public void insertUpdate(DocumentEvent e) \{
 Document doc = (Document)e.getDocument();
 \}
 ,,,

 * retrieve the length of the change and the document offset of the event
 ----------------------------------------------
 public void insertUpdate(DocumentEvent e) \{
 Document doc = (Document)e.getDocument();
 int changeLength = e.getLength();
 int offset = e.getOffset();
 \}
 ,,,

 * determine the type of change to the document (insert, remove, change) 
 ----------------------------------------------
 public void insertUpdate(DocumentEvent e) \{
 String type = e.getType().toString();
 \}
 ,,,

 The above code will always return 'insert' because it is called
 in the insertUpdate() method.

 The DocumentEvent.toString() method doesnt produce anything particularly
 readable.

 * display info about DocumentEvents fired by a JTextField 
 --------
 import javax.swing.*;
 import javax.swing.event.*;
 import java.awt.*;
 public class ListenPanel extends JPanel implements DocumentListener 
 \{
 JTextField field;
 JTextArea area;
 public ListenPanel() \{
 super(new BorderLayout());
 this.field = new JTextField(60);
 this.field.getDocument().addDocumentListener(this);
 this.field.setFont(new Font("Georgia", Font.PLAIN, 18));
 this.area = new JTextArea("Action", 60, 10);
 this.area.setFont(new Font("Georgia", Font.PLAIN, 18));
 this.add(field, BorderLayout.NORTH);
 this.add(area, BorderLayout.CENTER);
 \}
 
 private String eventInfo(DocumentEvent e) \{
 return String.format(
 "Action type: \\%s, Doc Offset: \\%d, Change Length: \\%d \\$\\backslash\\$n", 
 e.getType().toString(), e.getOffset(), e.getLength());
 \}

 public void insertUpdate(DocumentEvent e) \{
 this.area.append(this.eventInfo(e));
 \}
 public void removeUpdate(DocumentEvent e) \{
 this.area.append(this.eventInfo(e));
 \}
 public void changedUpdate(DocumentEvent e) \{
 //JTextFields dont fire these events
 \}

 public static void main(String[] args) throws Exception \{
 ListenPanel p = new ListenPanel(); 
 JOptionPane.showMessageDialog(null, p);
 \}
 \} 
 ,,,

DOCUMENT GOTCHAS ....

 Notes: On a Linux computer, when you select text with the mouse all the
 way to the end of the textfield, an exception
 java.lang.ArrayIndexOutOfBoundsException is sometimes thrown from the
 Caret moving code. This seems like some kind of bug in the swing caret
 painting or selection code.

 If you select text in a JTextComponent with the mouse or caret,
 and then type one letter, all the selected text will be replaced 
 with the one letter, and 2 events will be fired rapidly in succession,
 one 'remove' event with length of the selected text, and one 
 'insert' event with length 1. This is logical but your code needs 
 to handle both events.

CARETS ....

 The caret is the usually vertical blinking line or box which 
 indicates the 'insertion point' in a text component. The insertion
 point is the position in the document where text will be inserted
 when the user types something or performs a 'paste' operation.
 The caret is often also called a 'cursor' but in Java this word is
 reserved for the mouse position indicator.

 If you change the background colour for a text component, you 
 may also need to change the caret colour so that it can be seen.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents useful caret methods
 .. tf.setCaretPosition(0) - set the caret to the beginning of a textfield
 .. 
 ..

 * make sure the caret is visible
 -------------------------------------------------------------
 textArea.getCaret().setVisible(true); /* or */
 textArea.getCaret().setSelectionVisible(true);
 ,,,

 The code below can be useful for stopping a JTextArea from automatically
 scrolling to the end of the document when text is appended.

 * stop the caret position from being updated on insertion deletion etc
 -------------------------------------------------------------
 JTextArea textArea = new JTextArea();
 DefaultCaret caret = (DefaultCaret)textArea.getCaret();
 caret.setUpdatePolicy(DefaultCaret.NEVER\\_UPDATE);
 ,,,
 
 \url{http://tips4java.wordpress.com/2008/10/22/text-area-scrolling/}
 about caret and scrolling and text area

CARETLISTENERS AND CARETEVENTS ....

 We can add a CaretListener to a text component in order to be 
 notified whenever the caret changes position or state. The listener
 fires a CaretEvent


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents the 2 CaretEvent methods
 .. getDot() - fetches the location of the caret.
 .. getMark() - fetches the location of other end of a logical selection
 ..

 * create an inner class CaretListener and add it to a JTextArea
 -------------------------------------------------------------
 CaretListener listener = new CaretListener() \{
 public void caretUpdate(CaretEvent caretEvent) \{
 System.out.println("Dot:" + caretEvent.getDot());
 System.out.println("Mark:" + caretEvent.getMark());
 \}
 \};
 jtextarea.addCaretListener(listener);
 ,,,

HIGHLIGHTERS ....

 Highlighters are used in java text components to highlight
 some piece of text. For example when the user searches for some
 text in a JTextArea, the matched text may be highlighted by
 the application. Also the user may be able to manually select
 text with the mouse, and this text is also highlighted

 code adapted from
 \url{http://tips4java.wordpress.com/2008/10/28/rectangle-painter/}

 The second parameter to addHighlight() is an integer which is Not
 a length but a character position in the document, somewhat 
 surprisingly.

 * highlight from position 3 to position 6
 -------------------------------------------------------------
 this.area.getHighlighter().addHighlight(3, 6, 
 new DefaultHighlighter.DefaultHighlightPainter(Color.BLUE));
 ,,,

 * add a highlight from position 3 to 6 in a textarea
 -------------------------------------------------------------
 import javax.swing.text.*;
 import javax.swing.*;
 import java.awt.*;
 public class HighlightPanel extends JPanel \{
 JTextArea area;
 public HighlightPanel() \{
 super(new BorderLayout());
 this.area = new JTextArea(
 "Testing Highlights\\$\\backslash\\$nAnd and character\\$\\backslash\\$nPositions", 20, 70);
 this.area.setFont(new Font("Georgia", Font.ITALIC, 24));
 this.add(this.area);
 this.highlight();
 \}
 public void highlight() \{
 try \{
 this.area.getHighlighter().addHighlight(3, 6, 
 new DefaultHighlighter.DefaultHighlightPainter(Color.BLUE));
 \}
 catch (BadLocationException e) \{
 this.area.setText("Invalid Location:\\$\\backslash\\$n" + e);
 \}
 \}
 public static void main(String[] args) \{
 System.setProperty("awt.useSystemAAFontSettings","on");
 JFrame f = new JFrame();
 f.add(new HighlightPanel());
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null); 
 f.setVisible(true);
 \}
 \}
 ,,,

CHANGING EXISTING HIGHLIGHTS ....

 It does not seem possible to just paint a new highlight on top
 of any old one- you need to actually change or remove the 
 existing highlight.

 * change a highlight for a highlighter
 ---------------------------
 Highlighter.Highlight myHighlight = null;
 Highlighter.Highlight[] highlights = 
 textPane.getHighlighter().getHighlights();
 myHighlight = highlights[0]; //assuming there is one only
 try \{
 hl.changeHighlight(myHighlight, myHighlight.getStartOffset() + 1, 
 myHighlight.getEndOffset());
 \}
 catch (BadLocationException e) \{ e.printStackTrace(); \}
 ,,,

 * move a highlight right when the user presses 'm' 
 -------------------------------------------------------------
 import javax.swing.text.*;
 import javax.swing.*;
 import java.awt.*;
 import java.awt.event.*;
 public class MoveHighlight extends JPanel implements KeyListener \{
 JTextArea area;
 public MoveHighlight() \{
 super(new BorderLayout());
 this.area = new JTextArea(
 "Testing Highlights\\$\\backslash\\$nAnd and character\\$\\backslash\\$nPositions", 20, 70);
 this.area.setFont(new Font("Georgia", Font.ITALIC, 24));
 this.area.setEditable(false);
 this.add(this.area);
 this.highlight();
 this.area.addKeyListener(this);
 \}
 public void keyTyped(KeyEvent e) \{
 char key = e.getKeyChar();
 switch (key) \{
 case 'm': this.moveHighlight(); break;
 default: break;
 \}
 \}
 public void keyPressed(KeyEvent e) \{\}
 public void keyReleased(KeyEvent e) \{\}
 public void moveHighlight() \{
 Highlighter hl = this.area.getHighlighter();
 Highlighter.Highlight first = hl.getHighlights()[0];
 try \{
 hl.changeHighlight(
 first, first.getStartOffset() + 1, first.getEndOffset() + 1);
 \}
 catch (BadLocationException e) \{ e.printStackTrace(); \}
 \}
 
 public void highlight() \{
 try \{
 this.area.getHighlighter().addHighlight(3, 6,
 new DefaultHighlighter.DefaultHighlightPainter(Color.BLUE));
 \}
 catch (BadLocationException e) \{
 this.area.setText("Invalid Location:\\$\\backslash\\$n" + e);
 \}
 \}
 public static void main(String[] args) \{
 System.setProperty("awt.useSystemAAFontSettings","on");
 JFrame f = new JFrame();
 f.add(new MoveHighlight());
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack();
 f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

CUSTOM HIGHLIGHTERS ....

 * add some highlights to a JTextArea using a custom highlight painter
 -------------------------
 RectanglePainter red = new RectanglePainter( Color.RED );
 RectanglePainter cyan = new RectanglePainter( Color.CYAN );
 textArea.getHighlighter().addHighlight(5, 9, red);
 textArea.getHighlighter().addHighlight(61, 69, cyan);
 textArea.getHighlighter().addHighlight(106, 110, red);
 ,,,


 The example below is a simple modification of the
 DefaultHighlighter.DefaultHighLightPainter java swing code. This shows the
 value of looking at the java source code. We use Graphic2D object instead
 of normal graphics, with antialiasing and a rounded corner highlight

 The Code is the same as the DefaultHighlightPainter except we use
 Graphics2D and a RoundRectangle2D to paint the highlight

 * make a custom text highlighter (can be used with any text component)
 ---------------------------------
 import java.awt.*;
 import java.awt.geom.*;
 import javax.swing.text.*;
 import javax.swing.*;
 public class RectanglePainter extends DefaultHighlighter.DefaultHighlightPainter
 \{
 public RectanglePainter(Color color) \{ super(color); \}
 /**
 * 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 gg, int offs0, int offs1, Shape bounds, JTextComponent c, View view)
 \{
 Graphics2D g = (Graphics2D) gg;
 g.setRenderingHint(RenderingHints.KEY\\_ANTIALIASING, 
 RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 Rectangle r = getDrawingArea(offs0, offs1, bounds, view);
 if (r == null) return null;
 // Do your custom painting
 Color color = getColor();
 g.setColor(color == null ? c.getSelectionColor() : color);
 //g.fillRect(r.x, r.y, r.width, r.height);
 //g.drawRect(r.x, r.y, r.width - 1, r.height - 1);
 g.draw(new RoundRectangle2D.Double(r.x, r.y, r.width, r.height, 10, 10));
 return r;
 \}
 
 private Rectangle getDrawingArea(int offs0, int offs1, Shape bounds, View view) \{
 // Contained in view, can just use bounds.
 if (offs0 == view.getStartOffset() \\&\\& offs1 == view.getEndOffset()) \{
 Rectangle alloc;
 
 if (bounds instanceof Rectangle)
 \{ alloc = (Rectangle)bounds; \}
 else
 \{ alloc = bounds.getBounds(); \}
 return alloc;
 \}
 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();
 return r;
 \}
 catch (BadLocationException e) \{ \}
 \}
 // Can't render
 return null;
 \}

 public static void main(String[] args) throws Exception \{
 JTextArea textArea = new JTextArea(
 "Testing a custom highlighter with RoundRectangle2D", 30, 5);
 textArea.setFont(new Font("Georgia", Font.PLAIN, 30));
 RectanglePainter red = new RectanglePainter( Color.RED );
 RectanglePainter cyan = new RectanglePainter( Color.CYAN );
 textArea.getHighlighter().addHighlight(5, 9, red);
 textArea.getHighlighter().addHighlight(11, 14, cyan);
 JOptionPane.showMessageDialog(null, textArea);
 \}
 \}
 ,,,

 A cyclic GradientPaint is used below which is probably not ideal
 but at least it stops the lines > 1 being solid colour (as opposed
 to a gradient colour).

 The code makes the caret use the same HighlightPainter. I dont
 really understand the code that gets the area to paint, mainly because I
 dont know what the 'view' is in this context.

 * custom text highlighter using a gradient paint and same caret painter
 ---------------------------------
 import java.awt.*;
 import java.awt.geom.*;
 import javax.swing.text.*;
 import javax.swing.*;
 public class GradientHighlightPainter extends DefaultHighlighter.DefaultHighlightPainter
 \{
 public GradientHighlightPainter(Color color) \{ 
 super(color); 
 \}

 /**
 * 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 gg, int offs0, int offs1, Shape bounds, JTextComponent c, View view) \{
 Graphics2D g = (Graphics2D) gg;
 g.setRenderingHint(RenderingHints.KEY\\_ANTIALIASING, 
 RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 Rectangle r = getDrawingArea(offs0, offs1, bounds, view);
 if (r == null) return null;
 Color color = getColor();
 color = (color == null ? c.getSelectionColor() : color);
 GradientPaint gp = new GradientPaint(0, 0,
 color.brighter().brighter(), 0, r.height,
 color.darker().darker(), true);
 g.setPaint(gp);
 g.fill(new RoundRectangle2D.Double(r.x, r.y, r.width, r.height, 10, 10));
 return r;
 \}
 
 private Rectangle getDrawingArea(int offs0, int offs1, Shape bounds, View view) \{
 // Contained in view, just use bounds.
 if (offs0 == view.getStartOffset() \\&\\& offs1 == view.getEndOffset()) \{
 Rectangle alloc;
 if (bounds instanceof Rectangle)
 \{ alloc = (Rectangle)bounds; \}
 else
 \{ alloc = bounds.getBounds(); \}
 return alloc;
 \}
 else \{
 // only render part of View.
 try \{
 Shape shape = view.modelToView(
 offs0, Position.Bias.Forward, 
 offs1, Position.Bias.Backward, bounds);
 Rectangle r = 
 (shape instanceof Rectangle) ? 
 (Rectangle)shape : shape.getBounds();
 return r;
 \}
 catch (BadLocationException e) \{ \}
 \}
 // Can't render
 return null;
 \}

 public static void main(String[] args) throws Exception \{
 JTextArea textArea = new JTextArea(
 "Testing custom text highlighters \\$\\backslash\\$n" +
 "We can use gradient paints rounded corners and \\$\\backslash\\$n" +
 "Any thing else that java2D allows us to use", 30, 5);
 textArea.setFont(new Font("Georgia", Font.PLAIN, 30));
 GradientHighlightPainter red = 
 new GradientHighlightPainter(Color.RED);
 GradientHighlightPainter cyan = 
 new GradientHighlightPainter(Color.CYAN);
 textArea.getHighlighter().addHighlight(1, 4, red);
 textArea.getHighlighter().addHighlight(11, 16, cyan);
 textArea.getHighlighter().addHighlight(30, 37, cyan);
 Caret caretPainter = new DefaultCaret() \{
 private Highlighter.HighlightPainter rp = 
 new GradientHighlightPainter(Color.CYAN);
 protected Highlighter.HighlightPainter getSelectionPainter() \{
 return rp;
 \}
 \};
 textArea.setCaret(caretPainter);
 //area.setLineWrap(true);
 //area.setWrapStyleWord(true);
 JOptionPane.showMessageDialog(null, textArea);
 \}
 \}
 ,,,

 * make the caret use the custom highlighter 
 -------------------------------------------
 JTextArea area = new JTextArea("hello")
 Caret caretPainter = new DefaultCaret() \{
 private Highlighter.HighlightPainter lhp = new LineHighlightPainter();
 protected Highlighter.HighlightPainter getSelectionPainter() \{
 return lhp;
 \}
 \};
 area.setCaret(caretPainter);
 ,,,

 * implement a custom highlighter by implementing the interface
 -------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.text.*;
 import java.awt.*;
 public class LineHighlightPainter implements Highlighter.HighlightPainter \{
 // paint a thick line under one line of text, from r extending rightward to x2
 private void paintLine(Graphics g, Rectangle r, int x2) \{
 int ytop = r.y + r.height - 3;
 g.fillRect(r.x, ytop, x2 - r.x, 3);
 \}
 
 // paint thick lines under a block of text
 public void paint(Graphics g, int p0, int p1, Shape bounds, JTextComponent c) \{
 Rectangle r0 = null, r1 = null, rbounds = bounds.getBounds();
 int xmax = rbounds.x + rbounds.width; // x coordinate of right edge
 try \{ // convert positions to pixel coordinates
 r0 = c.modelToView(p0);
 r1 = c.modelToView(p1);
 \} catch (BadLocationException ex) \{
 return;
 \}
 if ((r0 == null) || (r1 == null)) return;
 
 g.setColor( c.getSelectionColor() );
 // special case if p0 and p1 are on the same line
 if (r0.y == r1.y) \{
 paintLine(g, r0, r1.x);
 return;
 \}
 
 // first line, from p1 to end-of-line
 paintLine(g, r0, xmax);
 
 // all the full lines in between, if any (assumes that all lines have
 // the same height--not a good assumption with JEditorPane/JTextPane)
 r0.y += r0.height; // move r0 to next line
 r0.x = rbounds.x; // move r0 to left edge
 while (r0.y < r1.y) \{
 paintLine(g, r0, xmax);
 r0.y += r0.height; // move r0 to next line
 \}
 
 // last line, from beginning-of-line to p1
 paintLine(g, r0, r1.x);
 \}
 ,,,
 
GOTCHAS FOR HIGHLIGHTS ....

 If the highlight includes the newline character "\\$\\backslash\\$n" in the text
 component (that is, it spans more than one line) your highlight will
 appear one character shorter than you expected.

 You can paint a new highlight on top of an old one: you need to 
 remove or change the existing highlight.

STYLED TEXT

ATTRIBUTEDSTRING ....

 The class java.text.AttributedString provides a way of specifying
 styles to apply to all or part of a string. It uses the 
 java.awt.font.TextAttribute class to specify the attributes to apply.

 * create a new attributed string, but without any attributes
 >> AttributedString as = new AttributedString("Text which can be styled");

 * create some styled text, make characters 3 to 9 bold and blue 
 --------------------------------------------
 AttributedString as = new AttributedString("Text which can be styled");
 as.addAttribute(
 TextAttribute.FONT, new Font("Courier New", Font.BOLD, 12), 3, 9);
 as.addAttribute(
 TextAttribute.FOREGROUND, Color.BLUE, 3, 9);
 ,,,

 * draw an styled string with graphics2D object 
 >> g2d.drawString(ss.getIterator(), 30, 30);

 An iterator is used to draw the styled text because the actual 
 storage class of the text is not known, and can be changed by the 
 programmer.

 Without antialiasing, the text displayed below is very jaggedy.
 With antialiasing it is much, much nicer.

 * a full example 
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 import java.text.AttributedString;
 import java.awt.font.TextAttribute;
 import java.util.*;
 public class TextStylePanel extends JPanel \{
 public TextStylePanel() \{ super(); \}
 @Override
 public void paintComponent(Graphics gg) \{
 Graphics2D g = (Graphics2D) gg;
 super.paintComponent(g);
 g.setRenderingHint(RenderingHints.KEY\\_TEXT\\_ANTIALIASING,
 RenderingHints.VALUE\\_TEXT\\_ANTIALIAS\\_ON);
 Font font = new Font("Georgia", Font.PLAIN, 60);
 g.setFont(font);
 String text = "Not Antialiased Text";
 AttributedString as = new AttributedString("Text which can be styled");
 as.addAttribute(
 TextAttribute.FONT, new Font("Georgia", Font.BOLD, 60), 3, 12);
 as.addAttribute(
 TextAttribute.FOREGROUND, Color.BLUE, 3, 12);
 g.drawString(as.getIterator(), 50, 50);
 \}
 public Dimension getPreferredSize() \{
 return new Dimension(500, 300);
 \}
 public static void main(String[] args) \{
 JOptionPane.showMessageDialog(null, new TextStylePanel());
 \}
 \}
 ,,,
 
 
TEXTATTRIBUTES ....

 Text attributes are way to apply different styles (or Attributes) to some
 text. Specifically we can use the java.awt.font.TextAttribute class. Text
 attributes are stored in pairs of keys and values, in a java.util.Map
 collection and can be applied to an existing Font with
 font.deriveFont(map). The TextAttribute class contains a large number of
 predefined attribute keys and values. For example there are 7 different
 underline styles supported by the TextAttribute class. 

 @@ \url{http://docs.oracle.com/javase/tutorial/2d/text/textattributes.html}
 The java tutorial about text attributes


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents examples of text attributes
 .. underline - a line that is drawn underneath text
 .. strikethrough - a horizontal line that is drawn through the text
 .. superscript or subscript - a text or a letter that appears above or below a line
 .. kerning – makes the spacing between characters more natural 
 ..

 The example below produces some very unpleasant, un-antialiased
 text. 

 * display text with kerning, underline and strikethrough 
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 import java.awt.font.TextAttribute;
 import java.util.*;
 public class TextStylePanel extends JPanel \{
 public TextStylePanel() \{
 super();
 \}
 @Override
 public void paintComponent(Graphics g) \{
 super.paintComponent(g);
 Font font = new Font(Font.SERIF, Font.PLAIN, 24);
 String text = "Not Antialiased Text";
 Hashtable<TextAttribute, Object> map =
 new Hashtable<TextAttribute, Object>();
 map.put(TextAttribute.KERNING, TextAttribute.KERNING\\_ON);
 map.put(TextAttribute.UNDERLINE, TextAttribute.UNDERLINE\\_ON);
 map.put(TextAttribute.STRIKETHROUGH, TextAttribute.STRIKETHROUGH\\_ON);
 font = font.deriveFont(map);
 g.setFont(font);
 g.drawString(text, 50, 50);
 \}
 public Dimension getPreferredSize() \{ return new Dimension(500, 300); \}
 public static void main(String[] args) \{
 JOptionPane.showMessageDialog(null, new TextStylePanel());
 \}
 \}
 ,,,
 
 * create a Map of text attributes and apply it to a font
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 import java.awt.font.*;
 import java.util.*;
 public class TextStylePanel extends JPanel \{
 public TextStylePanel() \{
 super();
 \}
 @Override
 public void paintComponent(Graphics g) \{
 super.paintComponent(g);
 Map<TextAttribute, Object> map =
 new Hashtable<TextAttribute, Object>();
 map.put(TextAttribute.KERNING,
 TextAttribute.KERNING\\_ON);
 Font font = new Font("Georgia", Font.PLAIN, 18);
 font = font.deriveFont(map);
 g.setFont(font);
 g.drawString("BLAH", 20, 20);
 g.drawRect(200, 200, 200, 200);
 \}
 public static void main(String[] args) \{
 JOptionPane.showMessageDialog(null, new TextStylePanel());
 \}
 \}
 ,,,
 
JTEXTFIELD TEXT BOX .... 

 A JTextField is a one line box in which the user can type
 and edit some text. The JTextField is a JTextComponent and has
 a Document model just like all JTextComponents. All of the text
 in the box has to have the same font, but you can highlight a
 portion of the text.

 @@ \url{http://javagraphics.blogspot.com/2009/12/text-prompts-and-search-fields.html}
 making a round corner bog with an icon and grey text


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents useful JTextField methods
 .. setHorizontalAlignment(JTextField.CENTER) - center align text
 ..

 * display a JTextField in a message dialog box 
 -------------------------------------------------------------
 import javax.swing.*;
 public class TextBox \{
 public static void main(String[] args)
 \{
 JOptionPane.showMessageDialog(null, new JTextField("hello"));
 \}
 \}
 ,,,

 * right justify the text 'hello' in a JTextField
 ------------------------------------------------
 import javax.swing.*;
 public class TextBox \{
 public static void main(String[] args)
 \{
 JTextField t = new JTextField("hello");
 t.setHorizontalAlignment(JTextField.RIGHT);
 JOptionPane.showMessageDialog(null, t);
 \}
 \}
 ,,,

 * right justify the text 'hello' in a JTextField
 ------------------------------------------------
 import javax.swing.*;
 public class TextBox \{
 public static void main(String[] args)
 \{
 JFrame f = new JFrame();
 JTextField t = new JTextField("hello");
 t.setHorizontalAlignment(JTextField.RIGHT);
 f.getContentPane().add(t);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null); 
 f.setVisible(true);
 \}
 \}
 ,,,

 * create a text field with 30 columns which does something 
 * when [enter] is pressed.
 ---------------------------
 JTextField textfield = new JTextField ("Initial Text", 30);
 textfield.addActionListener (new MyActionListener ());
 class MyActionListener implements ActionListener
 \{
 public void actionPerformed(ActionEvent e)
 \{
 JTextField textfield = (JTextField) e.getSource ();
 process (textfield.getText ());
 \}
 \}
 ,,,

 * right justify the text in the JTextField
 >> textfield.setHorizontalAlignment(JTextField.RIGHT);

 The example below adapted from the java tutorial for JTextFields

 * a text field with searching, and highlighting
 -------------------------------------------------------------
 import java.awt.Color;
 import java.awt.event.ActionEvent;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import javax.swing.*;
 import javax.swing.text.*;
 import javax.swing.event.*;
 import javax.swing.GroupLayout.*;
 
 public class TextFieldDemo extends JFrame
 implements DocumentListener \{
 
 private JTextField entry;
 private JLabel jLabel1;
 private JScrollPane jScrollPane1;
 private JLabel status;
 private JTextArea textArea;
 
 final static Color HILIT\\_COLOR = Color.LIGHT\\_GRAY;
 final static Color ERROR\\_COLOR = Color.PINK;
 final static String CANCEL\\_ACTION = "cancel-search";
 
 final Color entryBg;
 final Highlighter hilit;
 final Highlighter.HighlightPainter painter;
 
 public TextFieldDemo() \{
 initComponents();
 InputStream in = getClass().getResourceAsStream("content.txt");
 try \{
 textArea.read(new InputStreamReader(in), null);
 \} catch (IOException e) \{
 e.printStackTrace();
 \}
 
 hilit = new DefaultHighlighter();
 painter = new DefaultHighlighter.DefaultHighlightPainter(HILIT\\_COLOR);
 textArea.setHighlighter(hilit);
 entryBg = entry.getBackground();
 entry.getDocument().addDocumentListener(this);
 InputMap im = entry.getInputMap(JComponent.WHEN\\_IN\\_FOCUSED\\_WINDOW);
 ActionMap am = entry.getActionMap();
 im.put(KeyStroke.getKeyStroke("ESCAPE"), "cancel-search");
 am.put("cancel-search", new CancelAction());
 \}
 
 private void initComponents() \{
 entry = new JTextField();
 textArea = new JTextArea();
 status = new JLabel();
 jLabel1 = new JLabel();
 
 setDefaultCloseOperation(WindowConstants.EXIT\\_ON\\_CLOSE);
 setTitle("TextFieldDemo");
 textArea.setColumns(20);
 textArea.setRows(5);
 textArea.setLineWrap(true);
 textArea.setWrapStyleWord(true);
 textArea.setEditable(false);
 jScrollPane1 = new JScrollPane(textArea);
 jLabel1.setText("Enter text to search:");
 getContentPane().setLayout(layout);
 pack(); 
 \}
 
 public void search() \{
 hilit.removeAllHighlights();
 String s = entry.getText();
 if (s.length() <= 0) \{
 message("Nothing to search");
 return;
 \}
 
 String content = textArea.getText();
 int index = content.indexOf(s, 0);
 if (index >= 0) \{ // match found
 try \{
 int end = index + s.length();
 hilit.addHighlight(index, end, painter);
 textArea.setCaretPosition(end);
 entry.setBackground(entryBg);
 message("'" + s + "' found. Press ESC to end search");
 \} catch (BadLocationException e) \{
 e.printStackTrace();
 \}
 \} else \{
 entry.setBackground(ERROR\\_COLOR);
 message("'" + s + "' not found. Press ESC to start a new search");
 \}
 \}
 
 void message(String msg) \{ status.setText(msg); \}
 public void insertUpdate(DocumentEvent ev) \{ search(); \}
 public void removeUpdate(DocumentEvent ev) \{ search(); \}
 public void changedUpdate(DocumentEvent ev) \{ \}

 class CancelAction extends AbstractAction \{
 public void actionPerformed(ActionEvent ev) \{
 hilit.removeAllHighlights();
 entry.setText("");
 entry.setBackground(entryBg);
 \}
 \}
 
 public static void main(String args[]) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 //Turn off metal's use of bold fonts
 UIManager.put("swing.boldMetal", Boolean.FALSE);
 new TextFieldDemo().setVisible(true);
 \}
 \});
 \}
 \}
 ,,,

DOCUMENTMODEL FOR JTEXTFIELD ....

 The following example, taken from the java api docs for JTextField
 demonstrates how to override the insertString method for a 
 JTextComponent to add new functionality. This is simple and elegant.
 One cannot change a Document model from within a DocumentListener
 so the method below is very useful.

 something wrong with ,jc below

 * extend the PlainDocument model to only allow upper case letters
 -------------------------------------------------------------
 import javax.swing.*;
  public class UpperCaseField extends JTextField \{
   public UpperCaseField(int cols) \{
   super(cols);
   \}
   protected Document createDefaultModel() \{
   return new UpperCaseDocument();
   \}
   static class UpperCaseDocument extends PlainDocument \{
   public void insertString(int offs, String str, AttributeSet a) 
   throws BadLocationException \{
   if (str == null) \{ return; \}
   char[] upper = str.toCharArray();
   for (int i = 0; i < upper.length; i++) \{
   upper[i] = Character.toUpperCase(upper[i]);
   \}
   super.insertString(offs, new String(upper), a);
   \}
   \}
  \}

 ,,,


JFORMATTEDTEXTFIELD

 The JFormattedTextField is a one line text editing box which prevents the
 user from entering certain values. An alternative is to use a
 javax.swing.text.DocumentFilter on the underlying Document for the
 JTextField

PASSWORD BOXES ....

 A password box, or field is a field with one line of 
 text which does not display the text which is typed.

 * a simple password box 
 -----------------------
 import javax.swing.*;
 public class Text \{
 public static void main(String[] args)
 \{
 JFrame f = new JFrame();
 JPasswordField t = new JPasswordField("hello");
 f.getContentPane().add(t);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLocationRelativeTo(null); 
 f.pack();
 f.setVisible(true);
 \}
 \}
 ,,,

 * make a password field which listens to the [enter] key
 --------------------------------------------------------
 JPasswordField textfield = new JPasswordField("Initial Text");
 textfield.setEchoChar('\\#');
 textfield.addActionListener(actionListener);
 ,,,

JTEXTAREAS 

 A JTextArea is a box with several lines in which text can be
 entered. The text in a JTextArea is 'plain', that is, all the 
 text is the box is the same font, font style and size. The only
 styling of text possible is through using a highlighter. For
 'rich text' (in which different segments of the text have different
 styles, such as italic, bold etc) use a JEditorPane or a JTextPane

 The JTextArea seems to have good performance even with large 
 documents.

 @@ \url{http://www.exampledepot.com/egs/javax.swing.text/ta\\_EnumLines.html}
 how to get the document, paragraphs and lines from a jtextarea


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents useful methods of JTextArea
 .. setMargin(new Insets(5,5,5,5)) - create a margin inside the area
 ..

 * create a text area with 20 rows and 30 columns
 ------------------------------------------------
 JTextArea textarea = new JTextArea ("Initial Text");
 textarea = new JTextArea ("Initial Text", 20, 30);
 ,,,

 * set the background colour of a JTextArea
 ------------------------------------------
 JTextArea t = new JTextArea("hi");
 t.setBackground (Color.green);
 ,,,

 * set the font, forground and background colours of a jtextarea
 ---------------------------------------------------------------
 import java.awt.*;
 import javax.swing.*;
 public class TextAreaExample \{
 public static void main(String[] args) throws Exception \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 final JTextArea ta = new JTextArea("edit", 2, 60);
 Font font = new Font("Courier", Font.PLAIN, 20);
 ta.setFont(font);
 ta.setForeground(Color.green);
 ta.setBackground(Color.black);
 JOptionPane.showMessageDialog(null, ta);
 \}
 \});
 \}
 \}
 ,,,
 
 We also need to set the caret (cursor) color to something other
 (than black, so that we can see it.

READING CONTENT INTO A JTEXTAREA ....

 The JTextArea has a convenient read() method to load content into
 the area.

 * read a webpage encoded as utf8 into a JTextArea
 >> jtextarea.read(new InputStreamReader(url.openStream(), "UTF-8"), null);

 * use the read() method to load the text from a file into a JTextArea 
 ---------------------------------------------------------------
 import java.awt.*;
 import javax.swing.*;
 import java.io.*;
 public class TextRead \{
 public static void main(String[] args) throws Exception \{
 JTextArea ta = new JTextArea("edit", 20, 80);
 ta.setFont(new Font("courier", Font.PLAIN, 20));
 FileInputStream fis = new FileInputStream("java-book.txt"); 
 InputStreamReader in = new InputStreamReader(fis, "UTF-8");
 ta.read(in, null);
 JFrame frame = new JFrame("Reading a File into a JTextArea");
 frame.add(new JScrollPane(ta));
 frame.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 frame.pack(); frame.setLocationRelativeTo(null);
 frame.setVisible(true);
 \}
 \}
 ,,,
 
 * use the read() method to load the text from a url into a JTextArea 
 ---------------------------------------------------------------
 import java.awt.*;
 import javax.swing.*;
 import java.io.*;
 import java.net.*;
 public class WebTextArea extends JTextArea \{
 URL url;
 public WebTextArea(String sUrl) \{
 super(30, 80);
 try \{
 this.url = new URL(sUrl);
 this.setFont(new Font("courier", Font.PLAIN, 20));
 this.read(new InputStreamReader(url.openStream()), null);
 this.setEditable(false);
 \} catch (IOException e) \{ e.printStackTrace(); \}
 \}
 public static void main(String[] args) throws Exception \{
 WebTextArea area = 
 new WebTextArea("http://bumble.sf.net/books/vim/vim-book.txt");
 JFrame frame = new JFrame("The WebTextArea");
 frame.add(new JScrollPane(area));
 frame.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 frame.pack(); frame.setLocationRelativeTo(null);
 frame.setVisible(true);
 \}
 \}
 ,,,

SCROLLING JTEXTAREAS ....

 To scroll to a particular piece of text in a JTextArea one can just
 set the caret position to that piece of text. Or you could use the 
 c.scrollRectToVisible(Rectangle r) method but I cant see any reason to
 do that for a JTextComponent.

 * set the caret to the end of the textarea (and scroll to the end)
 -------------------------------------------------------------
 textArea.append(...);
 textArea.setCaretPosition(textArea.getDocument().getLength());
 ,,,

 * make a JTextArea always show last appended text (scroll to end) java1.5+
 -------------------------------------------------------------
 JTextArea textArea = new JTextArea();
 DefaultCaret caret = (DefaultCaret)textArea.getCaret();
 caret.setUpdatePolicy(DefaultCaret.ALWAYS\\_UPDATE);
 ,,,

 The code below uses the KeyScrollPane class which uses key-bindings to
 link key-strokes to scrolling actions. The JTextArea must be non-editable
 for this to work. If the text area is editable then the typed key gets
 inserted in the document- then the keybinding fires which scrolls the
 viewport, but then the caret seems to force the JTextArea to scroll back
 to where-ever the caret happens to be. Interesting.

 * scrolling a non editable JTextArea using keystrokes
 ---------------------------------------------------------------
 import java.awt.*;
 import javax.swing.*;
 import java.io.*;
 import java.net.*;
 public class KeyTextArea extends JTextArea \{
 URL url;
 public KeyTextArea(String sUrl) \{
 super(30, 80);
 try \{
 this.url = new URL(sUrl);
 this.setFont(new Font("courier", Font.PLAIN, 20));
 this.read(new InputStreamReader(url.openStream()), null);
 this.setEditable(false);
 \} catch (IOException e) \{ e.printStackTrace(); \}
 \}
 public static void main(String[] args) throws Exception \{
 KeyTextArea area = 
 new KeyTextArea("http://bumble.sf.net/books/vim/vim-book.txt");
 JFrame frame = new JFrame("The WebTextArea");
 frame.add(new KeyScrollPane(area));
 frame.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 frame.pack(); frame.setLocationRelativeTo(null);
 frame.setVisible(true);
 \}
 \}
 ,,,

 * an example of using scrollRectToVisible()
 -------------------------------------------------------------
 import java.awt.BorderLayout;
 import java.awt.Rectangle;
 import javax.swing.*;
 import javax.swing.event.ListSelectionEvent;
 import javax.swing.event.ListSelectionListener;
 import javax.swing.text.BadLocationException;
 public class TestScrollRectToVisible extends JPanel \{
 private static final int MAX\\_LOOP = 10000;
 private DefaultListModel listModel = new DefaultListModel();
 private JTextArea textarea = new JTextArea(20, 30);
 private JList jList = new JList(listModel);
 JScrollPane textareaScrollPane = new JScrollPane(textarea);
 public TestScrollRectToVisible() \{
 jList.addListSelectionListener(new ListSelectionListener() \{
 public void valueChanged(ListSelectionEvent e) \{
 if (!e.getValueIsAdjusting()) \{
 String text = jList.getSelectedValue().toString();
 text += ": ";
 String docText = textarea.getText();
 int index = docText.indexOf(text);
 if (index < 0) \{
 return;
 \}
 try \{
 Rectangle rect = textarea.modelToView(index);
 textarea.scrollRectToVisible(rect);
 \} catch (BadLocationException e1) \{
 e1.printStackTrace();
 \}

 \}
 \}
 \});
 
 jList.setSelectionMode(ListSelectionModel.SINGLE\\_SELECTION);
 StringBuilder strBuilder = new StringBuilder();
 for (int i = 0; i < MAX\\_LOOP; i++) \{
 String text = String.valueOf(i);
 listModel.addElement(text);
 strBuilder.append(text + ": abcdefghijklmnopqrstuvwxyz" + "\\$\\backslash\\$n");
 \}
 textarea.setText(strBuilder.toString());
 
 setLayout(new BorderLayout());
 add(textareaScrollPane, BorderLayout.CENTER);
 add(new JScrollPane(jList), BorderLayout.EAST);
 \}
 
 private static void createAndShowUI() \{
 JFrame frame = new JFrame("TestScrollRectToVisible");
 frame.getContentPane().add(new TestScrollRectToVisible());
 frame.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 frame.pack();
 frame.setLocationRelativeTo(null);
 frame.setVisible(true);
 \}
 
 public static void main(String[] args) \{
 java.awt.EventQueue.invokeLater(new Runnable() \{
 public void run() \{
 createAndShowUI();
 \}
 \});
 \}
 \}
 ,,,

VI STYLE JTEXTAREA

 A problem in the code below is that the events to not 'consume' the 
 keystrokes which generate them. So the 'i' key puts the JTextArea
 into edit mode, but an 'i' is inserted into the textarea. The 
 'i' gets inserted after the ActionEvent is fired, so its difficult
 to stop it being inserted.

 It is necessary to change the actions for different modes.

 * Attempt to implement a 2 mode vi style JTextArea
 ---------------------------------------------------------------
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import javax.swing.text.*;
 import java.io.*;
 import java.net.*;
 public class ViTextArea extends JTextArea \{
 URL url;
 public ViTextArea(String sUrl) \{
 super(30, 80);
 this.setFont(new Font("courier", Font.PLAIN, 20));
 this.setEditable(false);
 this.getCaret().setVisible(true); /* or */
 this.getCaret().setSelectionVisible(true);
 this.setActionKeys();
 try \{
 this.url = new URL(sUrl);
 this.read(new InputStreamReader(url.openStream()), null);
 \} catch (IOException e) \{
 e.printStackTrace();
 \}
 \}

 private void setActionKeys() \{
 ActionMap actionMap = this.getActionMap();
 InputMap inputMap = this.getInputMap(JComponent.WHEN\\_FOCUSED);
 inputMap.put(KeyStroke.getKeyStroke("I"), "insert-mode");
 actionMap.put("insert-mode", new InsertModeAction());
 inputMap.put(KeyStroke.getKeyStroke("ESCAPE"), "normal-mode");
 actionMap.put("normal-mode", new NormalModeAction());
 inputMap.put(KeyStroke.getKeyStroke("shift J"), "page-down");
 inputMap.put(KeyStroke.getKeyStroke("shift K"), "page-up");
 inputMap.put(KeyStroke.getKeyStroke("shift D"), "delete-next-word");
 inputMap.put(KeyStroke.getKeyStroke("shift S"), "select-paragraph");
 inputMap.put(KeyStroke.getKeyStroke("X"), "exit");
 actionMap.put("exit", new ExitAction());
 \}
 
 public static void main(String[] args) throws Exception \{
 ViTextArea area =
 new ViTextArea("file:java-book.txt");
 JFrame frame = new JFrame("The WebTextArea");
 //frame.add(new KeyScrollPane(area));
 frame.add(new JScrollPane(area));
 frame.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 frame.pack(); frame.setLocationRelativeTo(null);
 frame.setVisible(true);
 \}
 \}
 
 class ExitAction extends AbstractAction \{
 public ExitAction() \{
 putValue(Action.NAME, "Exit");
 putValue(Action.SHORT\\_DESCRIPTION, "Exits the application");
 //putValue(Action.MNEMONIC\\_KEY, new Integer(KeyEvent.VK\\_X));
 \}
 public void actionPerformed(ActionEvent e) \{
 System.exit(0);
 \}
 \}

 class NormalModeAction extends AbstractAction \{
 public NormalModeAction() \{
 putValue(Action.NAME, "Normal Mode");
 putValue(Action.SHORT\\_DESCRIPTION, 
 "Places the text area into vi style 'normal mode'");
 \}
 public void actionPerformed(ActionEvent e) \{
 JTextArea area = (JTextArea) e.getSource();
 area.setEditable(false);
 area.setBackground(Color.GRAY);
 \}
 \}

 class InsertModeAction extends AbstractAction \{
 public InsertModeAction() \{
 putValue(Action.NAME, "Enter Insert Mode");
 putValue(Action.SHORT\\_DESCRIPTION, 
 "Places the text area into vi style 'insert mode'");
 \}
 public void actionPerformed(ActionEvent e) \{
 JTextArea area = (JTextArea) e.getSource();
 area.setEditable(true);
 area.setBackground(Color.WHITE);
 PlainDocument doc = (PlainDocument) area.getDocument();
 try \{
 doc.remove(area.getCaretPosition() -2, 6);
 \}
 catch (BadLocationException ex) \{ ex.printStackTrace(); \}
 \}
 \}
 ,,,

JTEXTPANES

 A JTextPane has a reputation for being complicated to use. This swing
 component can display embedded components such as images and other
 JComponents. The JTextPane is a subclass of the JEditorPane

 JTextPane is similar JEditorPane but with the additional ability to edit
 styles and character attributes.

 * get plain text content from a html JTextPane (from its Document)
 >> textPane.getDocument().getText(0, textPane.getDocument().getLength()));

 * add some text to the end of a JTextPane
 -------------------------------------------------------------
 StyledDocument doc = textPane.getStyledDocument();
 doc.insertString("text", doc.getLength(), attributes);
 ,,,

 * show an html page in a JTextPane
 -----
 import javax.swing.*;
 import java.net.*;
 public class WebPane \{
 public static void main(String args[]) throws Exception \{
 JFrame f = new JFrame();
 JScrollPane scroll = new JScrollPane();
 JTextPane tp = new JTextPane();
 tp.setText("loading...");
 scroll.getViewport().add(tp);
 f.getContentPane().add(scroll);
 //jf.pack();
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 //jf.setSize(400,500);
 f.setVisible(true);
 
 URL url = new URL("http://bumble.sf.net");
 tp.setPage(url);
 \}
 \}
 ,,,

 * get the default font for a text pane
 >> System.out.println(UIManager.get("TextPane.font"));

 * get the pixel position of the cursor (caret) in jtextpane
 ------------
 Rectangle caretCoords = textpane.modelToView(caretposition);
 y = (int) caretCoords.getY();
 ,,,
 

 * loop through a textpanes different styles
 ----------------
 JTextPane jtp = new JTextPane();
 ...
 HTMLDocument doc = (HTMLDocument) jtp.getDocument();
 StyleSheet styles = doc.getStyleSheet();
 Enumeration rules = styles.getStyleNames();
 while (rules.hasMoreElements()) \{
 String name = (String) rules.nextElement();
 Style rule = styles.getStyle(name);
 System.out.println(rule.toString());
 \}
 ,,,

JEDITORPANE

 The JEditorPane is the base swing component for displaying styled (or
 formatted) text. JTextPane is a subclass of JEditorPane. JEditorPane can
 display images but only when 'embedded' in HTML.

 \url{http://www.artima.com/forums/flat.jsp?forum=1\\&thread=1276}
 how to edit html in an JEditorPane

LOADING CONTENT INTO THE JEDITOR PANE ....

 setText(String s) 
 the current editor kit is used (and therefore the 
 content type of that editor kit)
 read(Reader r, HTMLDocument object) 
 text read from a reader, the content type of the current EditorKit
 is used. Set the Base property on the HTMLDocument to allow
 relative image references to be resolved. This technique could be 
 useful when initialising from a zipped file.
 setPage(URL url) 
 content is read from a (local or remote) URL. The content type
 and EditorKit is determined automatically.

 * force a JEditorPane to reload a document
 -------------------------------------------------------------
 Document doc = jEditorPane.getDocument();
 doc.putProperty(Document.StreamDescriptionProperty, null);
 jEditorPane.setPage(this.page);
 ,,,

 * can we specify the character set??
 >> editor.setContentType("text/html; charset=UTF-8"); 

 * load content into an editor pane from a File object
 -------------------------------------------------------------
 File f = new File("index.html");
 JEditorPane jep = new JEditorPane(f.toURI().toURL());
 ,,,
 
 * display a local text file in a JEditorPane 
 --------------
 import javax.swing.*;
 import java.awt.Font;
 import java.net.*;
 public class FileEditorPane \{
 public static void main(String[] args) throws Exception \{
 JEditorPane ed = new JEditorPane("file:java-book.txt");
 ed.setFont(new Font(Font.MONOSPACED, Font.PLAIN, 20));
 JFrame f = new JFrame("displaying file");
 f.add(new JScrollPane(ed));
 f.pack(); f.setExtendedState(JFrame.MAXIMIZED\\_BOTH);
 f.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);
 f.setVisible(true);
 \}
 \}
 ,,,


READ TO LOAD A JEDITORPANE ....

 * initialize a JEditorPane with the read() method
 -------------------------------------------------------------
 FileReader reader = new FileReader("form.html");
 JEditorPane editor = new JEditorPane();
 editor.setContentType("text/html");
 editor.setEditable(false);
 editor.read(reader, null);
 ,,,

 The example below is similar to that above, except that it allows the
 developer to set the 'documentBase' property which allows the editor pane
 to resolve (and display) relative links, including embedded images.

 * load a stream into a JEditorPane with the read() method
 -------------------------------------------------------------
 FileReader reader = new FileReader("form.html");
 JEditorPane editor = new JEditorPane();
 HTMLDocument doc = new HTMLDocument();
 doc.setBase(...);
 //editor.setContentType("text/html");
 editor.setEditable(false);
 editor.read(reader, doc);
 ,,,

 The example below works but images are not displayed because the 
 'base' property is not set on the htmldocument and also because the 
 images are are within the zip file and therefor not available.

 * read the file JList.html from zipped api docs into a JEditorPane
 --------------------------------------------------------
 import java.util.zip.*;
 import java.util.Enumeration;
 import java.io.*;
 import javax.swing.*;
 import java.awt.*;
 public class EditorPaneZip extends JPanel \{
 JEditorPane area;
 public EditorPaneZip() \{
 super(new BorderLayout());
 this.area = new JEditorPane();
 this.area.setContentType("text/html");
 this.area.setEditable(false);
 this.area.setFont(new Font("courier", Font.PLAIN, 20));
 this.loadPageFromZip();
 this.add(new JScrollPane(this.area), BorderLayout.CENTER);
 \}
 public void loadPageFromZip() \{
 try \{
 ZipFile zf = new ZipFile("jdk-6-doc.zip");
 ZipEntry ze = 
 zf.getEntry("docs/api/javax/swing/JList.html");
 InputStream in = zf.getInputStream(ze);
 BufferedReader reader = 
 new BufferedReader(new InputStreamReader(in));
 this.area.read(reader, "zip entry");
 zf.close();
 \}
 catch (IOException e) \{ e.printStackTrace(); \}
 \}
 public static void main(String[] args) \{
 JFrame f = new JFrame("....");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.add(new EditorPaneZip());
 f.pack(); f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.setVisible(true); 
 \}
 \}
 ,,,

EDITORKITS ....

 The EditorKit for the JEditor pane determines the content type of 
 the document.

 * display an html document as plain text in a JEditorPane
 -------------------------------------------------------------
 String text = this.ed.getText();
 this.ed.setContentType("text/plain");
 this.ed.setText(text);
 ,,,

SEARCHING IN A JEDITORPANE ....

 How can we search the text in a jeditor pane? We need to search the text
 of the editor pane's document. We can do this with document.getText()
 which returns a plain text representaton of the Document contents. This
 should be fast in the case where there are no matches, but indexes into
 the Document are slightly wrong. So we have to use an iterator as pointed
 out by elliott hughes.

 >> String docText = this.area.getDocument().getText();
 >> int index = docText.indexOf(search);

 The code below searches the 'visible' text of an html document in
 JEditorPane and highlights matches. It also moves the scroll window
 of the JEditorPane down to the first match. I probably need to store
 the matches in a List so that we can go to the next one with 'n' like
 in 'less'. 

 An alternative to setCaretPosition() in the code below is to use
 //Rectangle rect = this.area.modelToView(index);
 //this.area.scrollRectToVisible(rect);
 but I cant see much difference

 If the search string is not a regular expression we can use 
 search.length() to determine the end of the highlight.

 * do 'on the fly' searching for some text in an html JEditorPane 
 ----------------------------------------------
 import java.io.*;
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import javax.swing.text.*;
 import javax.swing.event.*;
 import javax.swing.text.html.*;
 import java.util.regex.*;
 public class SearchEditor extends JPanel implements DocumentListener \{
 JTextField field;
 JEditorPane area;
 String page;
 public SearchEditor() \{
 super(); 
 this.setLayout(new BorderLayout());
 this.page = "file:/usr/lib/jvm/java-6-sun-1.6.0.15/docs/api/" +
 "javax/swing/JTree.html";
 this.field = new JTextField(40);
 this.field.getDocument().addDocumentListener(this);
 this.field.setFont(new Font("Monospaced", Font.PLAIN, 20));
 try \{
 this.area = new JEditorPane(page);
 this.area.setEditable(false);
 \} catch (IOException e) \{ e.printStackTrace(); \}
 this.add(this.field, BorderLayout.NORTH);
 this.add(new JScrollPane(this.area), BorderLayout.CENTER);
 \}
 public void insertUpdate(DocumentEvent e) \{ this.search(); \}
 public void removeUpdate(DocumentEvent e) \{ this.search(); \}
 public void changedUpdate(DocumentEvent e) \{ \}

 /** searches for a pattern in the editor pane and highlights matches */
 public void search() \{
 String search = this.field.getText();
 if (search.length() < 2) return;
 int matchCount = 0; int matchStart = 0; int matchEnd = 0;
 Pattern pattern = Pattern.compile(search);
 Highlighter highlighter = this.area.getHighlighter();
 DefaultHighlighter.DefaultHighlightPainter painter = 
 new DefaultHighlighter.DefaultHighlightPainter(Color.GREEN);
 HTMLDocument document = (HTMLDocument) this.area.getDocument();
 for (HTMLDocument.Iterator it = 
 document.getIterator(HTML.Tag.CONTENT); it.isValid(); 
 it.next()) \{
 try \{
 String fragment = document.getText(
 it.getStartOffset(), it.getEndOffset() - it.getStartOffset());
 Matcher matcher = pattern.matcher(fragment);
 while (matcher.find()) \{
 if (matchCount == 0) \{
 highlighter.removeAllHighlights();
 this.field.setBackground(Color.WHITE);
 \}
 matchStart = it.getStartOffset() + matcher.start();
 matchEnd = it.getStartOffset() + matcher.end();
 highlighter.addHighlight(matchStart, matchEnd, painter);
 System.out.format("start: \\%d, end: \\%d \\$\\backslash\\$n",matchStart, matchEnd);
 if (matchCount == 0) \{
 this.area.setCaretPosition(it.getStartOffset());
 \}
 matchCount++;
 \}
 \} catch (BadLocationException ex) \{ 
 System.out.println("bad location:");
 \}
 \}
 if (matchCount == 0) \{
 // error! cant modify the document from within a 
 // documentlistener
 //this.field.setText(String.format(
 // "The text '\\%s' was not found", search));
 highlighter.removeAllHighlights();
 this.field.setBackground(Color.PINK);
 //this.field.setSelectionStart(0);
 //this.field.setSelectionEnd(this.field.getText().length());
 return;
 \}
 \}
 public void actionPerformed(ActionEvent evt) \{ this.search(); \}
 public static void main(String args[]) \{
 EventQueue.invokeLater(new Runnable() \{
 public void run() \{
 JFrame f = new JFrame("Searching Text in JEditorPane");
 f.add(new SearchEditor());
 f.pack(); f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);
 f.setVisible(true);
 \}
 \});
 \}
 \}
 ,,,

 The version below of searching a JEditorPane with HTML content has
 some enhancements: 
 * The 1st or Nth match will be displayed about 1/3 of the way down 
 the JScrollPane (see the CaretScroll example for this technique). 
 * case insensitive - is this a good idea. 
 * The 'n' key will be bound with a keybinding to go to the display 
 the next match. 
 * added currentmatch in a different colour.
 todo:
 * The enter key will hide the search box.
 * The '/' key will show and focus the search box.

 I added a class to hold the matches.
 Also I need to paint the highlight for the current match differently
 to the other matches. Shouldnt be too difficult.

 Bug: this is throwing an exception from scrollToMatch when deleting
 items. This is probably trying to retrieve matches.get(0) when 
 there are no matches.

 * enhanced 'on the fly' searching for some text in an html JEditorPane 
 ----------------------------------------------
 import java.io.*;
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import javax.swing.text.*;
 import javax.swing.event.*;
 import javax.swing.text.html.*;
 import java.util.regex.*;
 import java.util.*;
 public class SearchHtmlPane extends JPanel implements DocumentListener \{
 JTextField field;
 JEditorPane area;
 JScrollPane scroll;
 String page;
 java.util.List<Match> matches;
 int currentMatch;
 Action nextMatch = new AbstractAction() \{
 public void actionPerformed(ActionEvent e) \{
 if (matches.isEmpty()) return;
 currentMatch++;
 currentMatch = currentMatch \\% matches.size();
 System.out.println(
 String.format("currentMatch: \\%d\\$\\backslash\\$nmatches.size:\\%d\\$\\backslash\\$n", 
 currentMatch, matches.size()));
 SearchHtmlPane.this.goToMatch();
 \}
 \};
 public SearchHtmlPane() \{
 super(); 
 this.setLayout(new BorderLayout());
 this.currentMatch = 0;
 this.matches = new ArrayList<Match>();
 this.page = "file:/usr/lib/jvm/java-6-sun-1.6.0.15/docs/api/" +
 "javax/swing/JTree.html";
 this.field = new JTextField(40);
 this.field.getDocument().addDocumentListener(this);
 this.field.setFont(new Font("Monospaced", Font.PLAIN, 20));
 try \{
 this.area = new JEditorPane(page);
 this.area.setEditable(false);
 \} catch (IOException e) \{ e.printStackTrace(); \}

 KeyStroke keyStroke = KeyStroke.getKeyStroke("N");
 this.area.getInputMap(WHEN\\_FOCUSED).put(keyStroke, "next-match");
 this.area.getActionMap().put("next-match", nextMatch);

 this.scroll = new JScrollPane(this.area);
 this.add(this.field, BorderLayout.NORTH);
 this.add(this.scroll, BorderLayout.CENTER);
 \}
 public void insertUpdate(DocumentEvent e) \{ this.search(); \}
 public void removeUpdate(DocumentEvent e) \{ this.search(); \}
 public void changedUpdate(DocumentEvent e) \{ \}
 public void search() \{
 String search = this.field.getText();
 if (search.length() < 2) return;
 int matchCount = 0; int matchStart = 0; int matchEnd = 0;
 Pattern pattern = Pattern.compile("(?i)" + search);
 HTMLDocument document = (HTMLDocument) this.area.getDocument();
 HTMLDocument.Iterator it = document.getIterator(HTML.Tag.CONTENT);
 while (it.isValid()) \{
 try \{
 String fragment = document.getText(
 it.getStartOffset(), it.getEndOffset() - it.getStartOffset());
 Matcher matcher = pattern.matcher(fragment);
 while (matcher.find()) \{
 if (matchCount == 0) \{
 this.matches.clear();
 this.currentMatch = 0;
 this.field.setBackground(Color.WHITE);
 \}
 matchStart = it.getStartOffset() + matcher.start();
 matchEnd = it.getStartOffset() + matcher.end();
 this.matches.add(new Match(matchStart, matchEnd));
 if (matchCount == 0) \{
 this.goToMatch();
 \}
 matchCount++;
 \}
 \} catch (BadLocationException ex) \{ 
 System.out.println("bad location:");
 \}
 it.next();
 \}
 this.highlight();
 if (matchCount == 0) \{
 this.area.getHighlighter().removeAllHighlights();
 this.field.setBackground(Color.PINK);
 return;
 \}
 \}

 public void highlight() \{
 int ii = 0;
 DefaultHighlighter.DefaultHighlightPainter bluepainter = 
 new DefaultHighlighter.DefaultHighlightPainter(Color.BLUE);
 DefaultHighlighter.DefaultHighlightPainter painter = 
 new DefaultHighlighter.DefaultHighlightPainter(Color.GREEN);
 this.area.getHighlighter().removeAllHighlights();
 try \{
 for (Match m: this.matches) \{
 if (ii == this.currentMatch) \{
 this.area.getHighlighter().addHighlight(
 m.start, m.end, bluepainter);
 \}
 else \{
 this.area.getHighlighter().addHighlight(
 m.start, m.end, painter);
 \}
 ii++;
 \}
 \}
 catch (BadLocationException e) \{\}
 \}

 public void goToMatch() \{
 if (this.matches.isEmpty()) return;
 this.area.setCaretPosition(
 this.matches.get(this.currentMatch).start);
 this.highlight();
 try \{
 Dimension view = this.scroll.getViewport().getExtentSize(); 
 JScrollBar bar = this.scroll.getVerticalScrollBar();
 bar.setValue(this.area.modelToView(
 this.area.getCaretPosition()).y - view.height/3);
 \} catch (BadLocationException ex) \{ 
 System.out.println("bad location:");
 \}
 \}

 public void actionPerformed(ActionEvent evt) \{ this.search(); \}
 public static void main(String args[]) \{
 EventQueue.invokeLater(new Runnable() \{
 public void run() \{
 JFrame f = new JFrame("Searching Text in JEditorPane");
 f.add(new SearchHtmlPane());
 f.pack(); f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);
 f.setVisible(true);
 \}
 \});
 \}
 \}

 /** just hold the start and end indexes of a match */
 class Match \{
 public int start;
 public int end;
 public Match(int start, int end) \{
 this.start = start; this.end = end;
 \}
 \}
 ,,,

 I will try to use the code below to test that everything is working and
 also to see the values for the fragment indexes. Things like <br>
 seem to generate elements which dont appear in the 'content' iterator
 but which add to the indexes. An idea: create a character array
 initialized to space and then insert the content

 * testing searching for some text in an html JEditorPane 
 ----------------------------------------------
 import java.io.*;
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import javax.swing.text.*;
 import javax.swing.event.*;
 import javax.swing.text.html.*;
 import java.util.regex.*;
 public class SearchHtmlPane extends JPanel implements DocumentListener \{
 JTextField field;
 JEditorPane area;
 JScrollPane scroll;
 int currentMatch;
 public SearchHtmlPane() \{
 super(); 
 this.setLayout(new BorderLayout());
 this.currentMatch = 0;
 this.field = new JTextField(40);
 this.field.getDocument().addDocumentListener(this);
 this.field.setFont(new Font("Monospaced", Font.PLAIN, 20));
 this.area = new JEditorPane(
 "text/html", 
 "<html><font>is</font> tree<br><br><br>is<big>here<tt></html>");
 this.area.setEditable(false);
 this.scroll = new JScrollPane(this.area);
 this.add(this.field, BorderLayout.NORTH);
 this.add(this.scroll, BorderLayout.CENTER);
 \}
 public void insertUpdate(DocumentEvent e) \{ this.search(); \}
 public void removeUpdate(DocumentEvent e) \{ this.search(); \}
 public void changedUpdate(DocumentEvent e) \{ \}

 public void search() \{
 String search = this.field.getText();
 if (search.length() < 2) return;
 int matchCount = 0; int matchStart = 0; int matchEnd = 0;
 Pattern pattern = Pattern.compile("(?i)" + search);
 Highlighter highlighter = this.area.getHighlighter();
 DefaultHighlighter.DefaultHighlightPainter painter = 
 new DefaultHighlighter.DefaultHighlightPainter(Color.GREEN);

 HTMLDocument document = (HTMLDocument) this.area.getDocument();
 HTMLDocument.Iterator it = document.getIterator(HTML.Tag.CONTENT);
 while (it.isValid()) \{
 try \{
 String fragment = document.getText(
 it.getStartOffset(), it.getEndOffset() - it.getStartOffset());
 System.out.println(String.format(
 "fragment:\\%s\\$\\backslash\\$nStartOffset:\\%d\\$\\backslash\\$nEndOffset:\\%d\\$\\backslash\\$n", 
 fragment, it.getStartOffset(), it.getEndOffset()));
 Matcher matcher = pattern.matcher(fragment);
 while (matcher.find()) \{
 if (matchCount == 0) \{
 highlighter.removeAllHighlights();
 this.field.setBackground(Color.WHITE);
 \}
 matchStart = it.getStartOffset() + matcher.start();
 matchEnd = it.getStartOffset() + matcher.end();
 highlighter.addHighlight(matchStart, matchEnd, painter);
 //System.out.format(
 // "start: \\%d, end: \\%d \\$\\backslash\\$n",matchStart, matchEnd);
 if (matchCount == 0) \{
 this.area.setCaretPosition(it.getStartOffset());
 Dimension view = this.scroll.getViewport().getExtentSize(); 
 JScrollBar bar = this.scroll.getVerticalScrollBar();
 bar.setValue(this.area.modelToView(
 this.area.getCaretPosition()).y - view.height/3);
 \}
 matchCount++;
 \}
 \} catch (BadLocationException ex) \{ 
 System.out.println("bad location:");
 \}
 it.next();
 \}
 if (matchCount == 0) \{
 highlighter.removeAllHighlights();
 this.field.setBackground(Color.PINK);
 return;
 \}
 \}
 public void actionPerformed(ActionEvent evt) \{ this.search(); \}
 public static void main(String args[]) \{
 EventQueue.invokeLater(new Runnable() \{
 public void run() \{
 JFrame f = new JFrame("Searching Text in JEditorPane");
 f.add(new SearchHtmlPane());
 f.pack(); f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);
 f.setVisible(true);
 \}
 \});
 \}
 \}
 ,,,

HTML IN JEDITORPANE ....

 "JEditorPane has inherent problems with specifying size using \\%. 
 Few developers consider JEditorPane to be suitable for anything 
 beyond carefully controlled and very limited HTML/CSS." 
 (Andrew Thompson)
 
 Interestingly, the content of a JEditorPane (and JTextPane) which has
 content type "text/html" is actually stored in a javax.swing.text.Document
 in plain text format (no html tags) but with an associated set of
 attributes (which correspond to the html tags). When you call 
 the getText() method, html text is returned (generated from the 
 Document) but the html may not be the same html that you put in to
 the JEditorPane.

 When a JEditorPane has content type "text/html" then its associated 
 document is a HTMLDocument which you can retrieve with something like
 >> doc = (HTMLDocument)editorpane.getDocument();

 Then you can iterate over all the tags, if you so desire.

 * create and load html text into a new JEditorPane from a local file
 >> JEditorPane ed = new JEditorPane("file:a.html");

 * instantiate a JEditorPane to display html content from a String 'text'
 >> JEditorPane ed = new JEditorPane("text/html", text);

 * get plain text content from a html JEditorPane (from its Document)
 >> textPane.getDocument().getText(0, textPane.getDocument().getLength()));

 The setPage() method is not really necessary, nor is a URL in the
 constructor since you can just use a String

 \url{http://www.gutenberg.org/files/2600/2600-h/2600-h.htm}
 The url for 'War and Peace' in html format

 Gutenberg doesnt seem to allow programmatic access and I dont know how to
 set the 'user-agent' for a JEditorPane. The book takes about a minute to
 load and render. But the scrolling performance seems ok once the book is
 loaded.

 The method below for creating an HTMLDocument (which can be used
 with the editorpane.setDocument() method?) is verbose and is only
 necessary if you have some special requirement. Untested code.

 * create an HTMLDocument from a string containing html
 -------------------------------------------------------------
 JEditorPane p; ...
 Reader stringReader = new StringReader(string);
 HTMLEditorKit htmlKit = new HTMLEditorKit();
 HTMLDocument htmlDoc = (HTMLDocument) htmlKit.createDefaultDocument();
 htmlKit.read(stringReader, htmlDoc, 0);
 p.setDocument(htmlDoc);
 ,,,,

 The example below shows how the html returned from editor.getText() is
 not the same html text as was used to initialise the editor pane.
 The html printed has been 'fixed' (end tags inserted etc). Also
 the method editor.getDocument().getText() returns plain text, not
 html.

 * load some html content and extract the plain text from the document
 -------------------------------------------------------------
 import javax.swing.*;
 public class HtmlEdPane \{
 public static void main(String[] args) throws Exception \{
 JEditorPane ed = new JEditorPane("text/html", 
 "<html>hi<br><big>sky</big><br>trees");
 ed.setEditable(true);
 JOptionPane.showMessageDialog(null, ed);
 System.out.println(
 ed.getDocument().getText(0, ed.getDocument().getLength()));
 System.out.println("Text is: " + ed.getText());
 \}
 \}
 ,,,

 * try to display War and Peace in a JEditorPane (3.1 megabytes)
 --------------
 import javax.swing.*;
 import java.awt.Frame;
 import java.net.*;
 public class BigBookPane \{
 public static void main(String[] args) throws Exception \{
 long startTime = System.currentTimeMillis();
 JEditorPane ed = new JEditorPane("file:eg/war.and.peace.html");
 ed.setEditable(false);
 JFrame f = new JFrame("Project Gutenberg in a JEditorPane");
 f.getContentPane().add(new KeyScrollPane(ed));
 f.pack(); f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);
 f.setVisible(true);
 long loadTime = System.currentTimeMillis() - startTime;
 f.setTitle(String.format("Book loaded in \\%d miliseconds", loadTime));
 \}
 \}
 ,,,

 * display the java api web documentation for JTree using JEditorPane
 --------------
 import javax.swing.*;
 import java.awt.Frame;
 import java.net.*;
 public class WebPane \{
 public static void main(String[] args) throws Exception \{
 JEditorPane ed = new JEditorPane(
 "http://docs.oracle.com/javase/1.5.0/docs/api/javax/swing/JTree.html");
 ed.setEditable(false);
 JFrame f = new JFrame();
 f.getContentPane().add(new JScrollPane(ed));
 f.pack(); f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);
 f.setVisible(true);
 \}
 \}
 ,,,

 The code below is a way of getting only html content (without the 
 actual tags). We can then use those indexes to highlight content
 in the JEditorPane. This can form the basic of searching a JEditorPane
 which contains html text. This is working.

 The highlights need to be put at indexes reflecting the underlying
 document text (not the html that was loaded). This is because the
 JEditor/TextPane does not store the text as html, but rather as a document
 with attributes. 
 
 We cant just use ed.getDocument.getText(0, ...); and iterate over that
 for matches because the document seems to store newline characters or
 something strange for <br> and these are not returned by
 e.getDocument.getText(...).

 * iterate over the html tags in HTMLDocument from a JEditor/TextPane
 -------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.text.*;
 import javax.swing.text.html.*;
 import java.util.regex.*;
 import java.awt.Color;
 public class SearchEditorPane \{
 public static void main(String[] args) throws Exception \{
 JEditorPane ed = new JEditorPane("text/html",
 "<html><br><br>hitre<br><big>sky</big><br>trees");
 ed.setEditable(true);

 Pattern pattern = Pattern.compile("tre");
 Highlighter highlighter = ed.getHighlighter();
 HTMLDocument document = (HTMLDocument) ed.getDocument();
 for (HTMLDocument.Iterator it = 
 document.getIterator(HTML.Tag.CONTENT); it.isValid(); 
 it.next()) \{
 try \{
 String fragment = document.getText(
 it.getStartOffset(), it.getEndOffset() - it.getStartOffset());
 Matcher matcher = pattern.matcher(fragment);
 while (matcher.find()) \{
 highlighter.addHighlight(
 it.getStartOffset() + matcher.start(),
 it.getStartOffset() + matcher.end(),
 new DefaultHighlighter.DefaultHighlightPainter(Color.BLUE));
 System.out.format("start: \\%d, end: \\%d \\$\\backslash\\$n", 
 it.getStartOffset() + matcher.start(),
 it.getStartOffset() + matcher.end());
 //++matchCount;
 \}
 \} catch (BadLocationException ex) \{ 
 System.out.println("bad location:");
 \}
 \}
 
 JOptionPane.showMessageDialog(null, ed);
 System.out.println(ed.getDocument().getText(
 0, ed.getDocument().getLength()));
 System.out.println("Text is: " + ed.getText());
 \}
 \}
 ,,,

 * use a while loop to iterate over an HTMLDocument
 -------------------------------------------------------------
 HTMLDocument document = (HTMLDocument) this.area.getDocument();
 HTMLDocument.Iterator it = document.getIterator(HTML.Tag.CONTENT);
 while (it.isValid()) \{
 try \{
 String fragment = document.getText(
 it.getStartOffset(), it.getEndOffset() - it.getStartOffset());
 System.out.println(fragment);
 \} catch (BadLocationException ex) \{ 
 System.out.println("bad location:");
 \}
 it.next();
 \}
 ,,,

HYPERLINKS AND THE JEDITORPANE ....

 To make the hyperlinks work in a JEditorPane with the content type set to
 "text/html" it is necessary to implement the HyperlinkListener interface.

 The JEditorPane only generates hyperlink events in a non editable pane.
 Also, if there is no reference then the method scrollToReference() does
 nothing (it doesnt scroll to the top of the page)

 * display an html file with activated (local only) link references 
 --------------
 import javax.swing.*;
 import javax.swing.event.*;
 import java.net.*;
 public class JavaDocPane \{
 public static void main(String[] args) throws Exception \{
 String docHome = new String("/usr/lib/jvm/java-6-sun/docs/api/");
 final URL url = 
 new URL("file:" + docHome + "javax/swing/JTree.html");
 final JEditorPane ed = new JEditorPane(url);
 ed.setEditable(false);
 ed.addHyperlinkListener(new HyperlinkListener() \{
 public void hyperlinkUpdate(HyperlinkEvent e) \{
 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) \{
 if (e.getURL().sameFile(url)) \{
 ed.scrollToReference(e.getURL().getRef());
 \}
 \}
 \}
 \});
 JFrame f = new JFrame(); f.add(new JScrollPane(ed));
 f.pack(); f.setExtendedState(JFrame.MAXIMIZED\\_BOTH);
 f.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);
 f.setVisible(true);
 \}
 \}
 ,,,

 * a hyperlink listener that loads a new html page in the JEditorPane
 -------------------------------------------
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import java.net.*;
 import javax.swing.event.*;
 import java.io.IOException;
 import java.util.logging.*;
 public class BrowsePanel extends JPanel implements HyperlinkListener \{
 JEditorPane ed;
 JLabel info;
 URL page;
 public BrowsePanel(URL page) throws IOException \{
 this.ed = new JEditorPane(page);
 this.ed.addHyperlinkListener(this);
 this.ed.setEditable(false);
 this.info = new JLabel("info:");
 this.page = page;
 this.add(this.info, BorderLayout.NORTH);
 // not displaying well
 //this.add(new JScrollPane(this.ed), BorderLayout.CENTER);
 \}
 public void hyperlinkUpdate(HyperlinkEvent ev) \{
 if (ev.getEventType() == HyperlinkEvent.EventType.ACTIVATED) \{
 try \{
 if (ev.getURL().sameFile(this.page)) \{
 ed.scrollToReference(ev.getURL().getRef());
 \}
 else ed.setPage(ev.getURL());
 this.info.setText(ev.getURL().toExternalForm());
 this.page = ev.getURL();
 \} catch (IOException ex) \{
 Logger.getLogger(
 BrowsePanel.class.getName()).log(Level.SEVERE, null, ex);
 \}
 \}
 \}
 public static void main(String[] args) throws Exception \{
 BrowsePanel p = new BrowsePanel(new URL(
 "file:/usr/lib/jvm/java-6-sun/docs/api/javax/swing/JTree.html"));
 JFrame f = new JFrame();
 f.getContentPane().add(p);
 f.pack(); f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);
 f.setVisible(true);
 \}
 \}
 ,,,

 In the code below, I think the scrollToReference does not 
 actually throw any Exceptions, hence you could dispense with
 try/catch

 * a hyperlinklistener that scrolls the JEditorPane to link reference
 -------------------------------------------------------------
 htmlPane.addHyperlinkListener(new HyperlinkListener() \{
 public void hyperlinkUpdate(HyperlinkEvent e) \{
 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) \{
 if (e.getURL().sameFile(url)) \{
 try \{
 htmlPane.scrollToReference(e.getURL().getRef());
 \} catch (Throwable t) \{
 t.printStackTrace();
 \}
 \}
 \}
 \}
 \});
 ,,,

 In the code below creating the EditorKit is not actually necessary: we
 can just use the setPage(URL page) method of the JEditorPane

 * activate the default browser when a hyperlink is clicked, untested 
 --------------------------------------
 final JEditorPane editor = new JEditorPane();
 editor.setEditorKit(JEditorPane.createEditorKitForContentType("text/html"));
 editor.setEditable(false);
 editor.setText("<a href=\\$\\backslash\\$"http://www.google.com/finance?q=NYSE:C\\$\\backslash\\$">C</a>, <a href=\\$\\backslash\\$"http://www.google.com/finance?q=NASDAQ:MSFT\\$\\backslash\\$">MSFT</a>");
 editor.addHyperlinkListener(new HyperlinkListener() \{
 public void hyperlinkUpdate(HyperlinkEvent e) \{
 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) \{
 // java 1.6+
 if (Desktop.isDesktopSupported()) \{
 Desktop.getDesktop().browse(e.getURL().toURI());
 \}
 \}
 \}
 \});
 ,,,

HYPERLINK EVENTS ....

 To implement functionality for hovering over a link (rather than
 actually clicking on it) check the HyperlinkEvent.EventType

 * check if a link was hovered over (not clicked)
 >> if (e.getEventType() != HyperlinkEvent.EventType.ACTIVATED) \{...\}

MODIFYING HTML IN THE JEDITORPANE ...

 The code below requires that we know the structure of the html
 document (the order and nesting of the tags).

 * change the value of an html table cell in a JEditorPane document
 -------------------------------------------------------------
 Document doc = editorpane.getDocument();
 Element html = doc.getRootElements()[0];
 Element body = html.getElement(1);
 Element table = body.getElement(1);
 try \{
 Element tr2 = table.getElement(1);
 Element tr2td1 = tr2.getElement(0);
 doc.insertString(tr2td1.getStartOffset(), "1: 123,456",
 SimpleAttributeSet.EMPTY);
 
 Element tr3 = table.getElement(2);
 Element tr3td1 = tr3.getElement(0);
 doc.insertString(tr3td1.getStartOffset(), "2: 765.123",
 SimpleAttributeSet.EMPTY);
 \} catch (BadLocationException e) \{
 e.printStackTrace();
 \}
 ,,,

CSS WITH JEDITORPANE ....

 To see a list of supported css attributes see the api docs for the 
 class javax.swing.text.html.css

 The JEditorPane claims to support css style sheets to style html documents
 displayed in the pane.

 * add some css styling to an editor pane
 -----------------------------------------------
 JEditorPane ed = new JEditorPane(new URL("file:test.html"));
 ed.setEditable(false);
 StyleSheet styles = ((HTMLEditorKit)ed.getEditorKit()).getStyleSheet();
 styles.addRule("body \{font-size: xx-large; color:\\#000; font-family:times; margin: 4px; \}");
 ,,,

 * add css styles to a JEditorPane html document
 ------------------------------------------------------
 import javax.swing.*;
 import javax.swing.text.html.*;
 import javax.swing.text.*;
 public class CssPane \{
 public static void main(String[] args) \{
 JEditorPane ed = new JEditorPane();
 ed.setEditable(false);
 HTMLEditorKit kit = new HTMLEditorKit();
 ed.setEditorKit(kit);
 JScrollPane scrollPane = new JScrollPane(ed);
 // add some styles to the html
 StyleSheet styleSheet = kit.getStyleSheet();
 styleSheet.addRule(
 "body \{font-size: xx-large; font-family:times; margin: 4px; \}");
 styleSheet.addRule("h1 \{color: blue;\}");
 styleSheet.addRule("h2 \{color: \\#ff0000;\}");
 styleSheet.addRule("pre \{font: 10px monaco; color: black; background-color: \\#fafafa; \}");
 Document doc = kit.createDefaultDocument();
 ed.setDocument(doc);
 String s = "<body><h1>hello</h1>Big font<pre>code text</pre></body>";
 ed.setText(s);
 JOptionPane.showMessageDialog(null, ed);
 \}
 \}
 ,,,
 
 The <body> css font setting in the example below is not percolating down
 to the <code> font attribute. So it must be set seperately
 font-size: x-large produces a nice sized font for reading (for me
 at least)

 See the apps section for a simple javadoc browser based on
 JEditorPane

 * add css styles (big font) to an existing page and show html source code
 --------------
 import javax.swing.*;
 import javax.swing.event.*;
 import javax.swing.text.html.*;
 import java.net.*;
 import java.awt.*;
 import java.awt.event.*;
 public class HtmlSourcePanel extends JPanel 
 implements ActionListener, HyperlinkListener \{
 JEditorPane ed;
 JToggleButton button;
 String className;
 URL page;
 final static String docHome = "/usr/lib/jvm/java-6-sun/docs/api";

 public HtmlSourcePanel(String className) \{
 super(new BorderLayout());
 this.className = className;
 try \{
 this.page = new URL(String.format(
 "file:\\%s/\\%s.html", this.docHome, className.replace(".", "/")));
 this.ed = new JEditorPane(page);
 this.ed.setEditable(false);
 this.ed.addHyperlinkListener(this);

 StyleSheet styles = 
 ((HTMLEditorKit)ed.getEditorKit()).getStyleSheet();
 styles.addRule("body \{font-size: x-large; color:\\#000; font-family:Georgia; margin: 20px; \}");
 styles.addRule("code \{font-size: large; \}");

 this.button = new JToggleButton("Toggle Source View");
 this.button.addActionListener(this);
 this.add(this.button, BorderLayout.NORTH);
 this.add(new JScrollPane(this.ed), BorderLayout.CENTER);
 \}
 catch (java.net.MalformedURLException e) \{\}
 catch (java.io.IOException e) \{\}
 \}
 public void hyperlinkUpdate(HyperlinkEvent e) \{
 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) \{
 if (e.getURL().sameFile(this.page)) \{
 try \{
 this.ed.scrollToReference(e.getURL().getRef());
 \} catch (Throwable t) \{ t.printStackTrace(); \}
 \}
 else if (!e.getURL().sameFile(this.page)) \{
 try \{
 this.ed.setPage(e.getURL());
 \} catch (Throwable t) \{ t.printStackTrace(); \}
 \}
 \}
 \}
 public void actionPerformed(ActionEvent e) \{
 if (this.button.isSelected()) \{
 String text = this.ed.getText();
 this.ed.setContentType("text/plain");
 this.ed.setFont(new Font("Monospaced", Font.PLAIN, 16));
 this.ed.setText(text);
 \} else \{
 String text = this.ed.getText();
 this.ed.setContentType("text/html"); 
 this.ed.setText(text);
 \}
 \}
 public static void main(String[] args) throws Exception
 \{
 HtmlSourcePanel j = new HtmlSourcePanel("java.lang.String");
 JFrame f = new JFrame(); f.add(j);
 f.pack(); f.setExtendedState(JFrame.MAXIMIZED\\_BOTH);
 f.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);
 f.setVisible(true);
 \}
 \}
 ,,,

 The code below works but is slow, since the html page has to rerender
 each time the font size is changed, and the rendering process is slow.
 The java css renderer has problems with relative font sizes and 
 doesnt inherit the body font size to some elements (eg <code>).
 This means that some of the elements dont display at the size 
 asked for.

 * change the css font size for a JEditorPane
 --------------
 import javax.swing.*;
 import javax.swing.event.*;
 import javax.swing.text.html.*;
 import javax.swing.text.*;
 import java.net.*;
 import java.io.*;
 import java.awt.*;
 import java.awt.event.*;
 public class FontSizeEditorPane extends JPanel 
 implements ActionListener \{
 URL page;
 JEditorPane ed;
 JButton smallerButton;
 JButton biggerButton;
 int fontSize;

 final static String docHome = "file:/usr/lib/jvm/java-6-sun/docs/api";
 public FontSizeEditorPane() \{
 super(new BorderLayout());
 this.fontSize = 18;
 this.smallerButton = new JButton("--Font");
 this.smallerButton.addActionListener(this);
 this.biggerButton = new JButton("++Font");
 this.biggerButton.addActionListener(this);
 try \{
 this.page = new URL(docHome + "/java/lang/String.html");
 this.ed = new JEditorPane(); this.ed.setPage(this.page);
 this.ed.setEditable(false);
 this.setFontSize(this.fontSize);

 this.add(new JScrollPane(this.ed), BorderLayout.CENTER);
 JPanel buttonPanel = new JPanel();
 buttonPanel.add(this.smallerButton);
 buttonPanel.add(this.biggerButton);
 this.add(buttonPanel, BorderLayout.NORTH);
 \}
 catch (java.net.MalformedURLException e) \{ e.printStackTrace(); \}
 catch (java.io.IOException e) \{ e.printStackTrace(); \}
 \}
 public void setFontSize(int size) \{
 this.fontSize = size;
 StyleSheet styles = 
 ((HTMLEditorKit) this.ed.getEditorKit()).getStyleSheet();
 styles.addRule(String.format(
 "body \{font-size: \\%dpx; color:\\#000; " +
 " font-family:Georgia; margin: 20px; \}", this.fontSize));
 styles.addRule(String.format(
 "code \{font-size: \\%dpx; \}", this.fontSize-1));
 styles.addRule(String.format(
 "font \{font-size: \\%dpx; \}", this.fontSize-1));
 this.reloadPage();
 \}
 /** clears the stream to force the page to be reloaded */
 public void reloadPage() \{
 try \{
 Document doc = this.ed.getDocument();
 doc.putProperty(Document.StreamDescriptionProperty, null);
 this.ed.setPage(this.page);
 \} catch (IOException err) \{ err.printStackTrace(); \}
 \}
 public void actionPerformed(ActionEvent e) \{
 if (e.getSource() == this.biggerButton) \{
 this.setFontSize(this.fontSize+2);
 \}
 else if (e.getSource() == this.smallerButton) \{
 this.setFontSize(this.fontSize-2);
 \}
 \}
 public static void main(String[] args) throws Exception \{
 FontSizeEditorPane p = new FontSizeEditorPane();
 JFrame f = new JFrame("Css and Editor Panes"); f.add(p);
 f.pack(); f.setExtendedState(JFrame.MAXIMIZED\\_BOTH);
 f.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);
 f.setVisible(true);
 \}
 \}
 ,,,

 The code below doesnt seem to work for me, where as the
 stylesheet.addRule(...) does work.

 * attempt to make html text in a JEditorPane larger using css, untested
 -------------------------------------------------------------
 private void makeItBig()
 \{
 HTMLDocument doc = (HTMLDocument) pane.getDocument();
 MutableAttributeSet attr = new SimpleAttributeSet();
 doc.getStyleSheet().addCSSAttribute(
 attr, CSS.Attribute.FONT\\_SIZE, "xx-large");
 doc.setCharacterAttributes(
 0, pane.getDocument().getLength(), attr, false);
 \}
 ,,,

PLAIN TEXT WITH JEDITORPANE ....

 * make the JEditorPane fixed pitch font, plain text
 -------------------------------------------------------------
 pane.setContentType("text/plain");
 pane.setFont(new Font("Monospaced", Font.PLAIN, 16));
 pane.setText(text);
 ,,,

LISTENERS AND EVENTS FOR THE JEDITORPANE ....

 * do something when a new page is loaded in the JEditorPane
 -------------------------------------------------------------
 ed.setPage(getClass().getResource("htmlFormatTable.html"));
 ed.addPropertyChangeListener(new PropertyChangeListener() \{
 @Override
 public void propertyChange(PropertyChangeEvent evt) \{
 if ("page".equals(evt.getPropertyName())) \{
 //do something here
 \}
 \}
 \});
 ,,,

 The setPage() method is asynchronous, that is it returns immediately even
 if the page takes a while to load, parse and render. Once the page
 finishes loading the PropertyChangeEvent for 'page' will fire.

 * do something when the first page finishes loading 
 -------------------------------------------------------------
 ed.setPage("file:test.html");
 ed.addPropertyChangeListener(new PropertyChangeListener() \{
 @Override
 public void propertyChange(PropertyChangeEvent evt) \{
 if ("page".equals(evt.getPropertyName())) \{
 //do something here
 \}
 ed.removePropertyChangeListener(this);
 \}
 \});
 ,,,

GOTCHAS FOR THE JEDITORPANE

 - if you dont setEditable(false) for html content the content does
 not render properly, lots of html artifacts.
 - It seems that you have to call pane.getText() after the 
 JEditorPane is visible or at least a while after pane.setPage()
 otherwise truncated text is returned.
 - The JEditorPane has a limited html and css rendering capability

JTREE TREE COMPONENT 

 Like most other swing components the swing tree component uses a "model"
 interface to supply data to the tree component. To the new-comer to
 interface or object oriented programming this may seem daunting, but its
 not. There arrangement is simple: The model has a series of methods
 which allow the tree component to display each node or leaf on the tree.
 But the tree doesnt mind where that data comes from. This gives a great
 deal of flexibility to the programmer, who can use any kind of data to
 create a tree. 
 
 Linux notes: The JTree looks much nicer with a largish georgia font.

 * show a JTree component with some example values 
 -------------------------------------
 import javax.swing.*;
 public class DefaultTree \{
 public static void main(String[] args)
 \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JFrame f = new JFrame();
 JTree t = new JTree();
 f.getContentPane().add(t);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \});
 \}
 \}
 ,,,

 * exand all nodes in a JTree
 ---------------------------------
 import javax.swing.*;
 import java.awt.Dimension;
 public class ExpandTree extends JPanel \{
 JTree tree;
 public ExpandTree() \{
 tree = new JTree();
 for (int i = 0; i < tree.getRowCount(); i++) \{
 tree.expandRow(i);
 \}
 this.add(this.tree);
 this.setPreferredSize(new Dimension(300, 600));
 \}
 public static void main(String[] args)
 \{
 ExpandTree p = new ExpandTree();
 JOptionPane.showMessageDialog(null, p);
 \}
 \}
 ,,,

 * collapse all nodes in a JTree
 >> tree.collapsePath(tree.getPathForRow(0));

 * collapse all nodes in a JTree component
 -------------------------------------------------------------
 JTree jtree;
 for (int i = 0; i < jTree.getRowCount(); i++) \{
 jTree.collapseRow(i);
 \}
 ,,,

CONFIGURE JTREES ....

 * Create a tree that allows one selection at a time.
 ---------------------------------------------------------
 tree = new JTree();
 tree.getSelectionModel().setSelectionMode
 (TreeSelectionModel.SINGLE\\_TREE\\_SELECTION);
 ,,,
 
 * create JTree with a horizontal lineStyle
 >> tree.putClientProperty("JTree.lineStyle", "Horizontal");

 The possible values are: "Angled" (the default), "Horizontal", and "None".

NODES OF TREES ....

 Nodes are either branch (which can contain child nodes) or leaf
 (which cant). Nodes can be identified either by their path (TreePath)
 or my their display row.

 The JTree must be instantiated with the root node after all the 
 nodes have been added to the tree.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents JTree useful node methods
 .. node.getUserObject() - returns the object of a node (should be cast)
 .. node.isLeaf() - check if this is a leaf node
 ..

 * add nodes to a tree with DefaultMutableTreeNode
 ------------------------------------------------
 import javax.swing.*;
 import javax.swing.tree.*;
 import java.awt.*;
 public class NodeTree \{
 public static void main(String[] args)
 \{
 System.setProperty("awt.useSystemAAFontSettings","on");
 DefaultMutableTreeNode top, category, node;
 top = new DefaultMutableTreeNode("A JTree Example");
 category = new DefaultMutableTreeNode("Trees");
 top.add(category);
 for (String s: new String[]\{"oak", "yew", "elder", "acacia"\}) \{
 node = new DefaultMutableTreeNode(s);
 category.add(node);
 \}
 JTree tree = new JTree(top);
 tree.setFont(new Font(Font.SERIF, Font.PLAIN, 22));
 tree.setPreferredSize(new Dimension(300, 600));
 //tree.putClientProperty("JTree.lineStyle", "None");
 JOptionPane.showMessageDialog(null, tree);
 \}
 \}
 ,,,


TREE MODELS ....

 The TreeModel supplies the data for JTree component (which is also
 know as a 'view' of the data). We basically have to implement a 
 handfull of methods relating to parent and child nodes in the 
 TreeModel.

 * a file and directory TreeModel for use with a JTree element
 ---------
 import javax.swing.*;
 import java.awt.Font;
 import javax.swing.plaf.FontUIResource;
 import javax.swing.tree.*;
 import javax.swing.event.*;
 import java.io.*;

 public class FileSystemModel implements TreeModel \{
 String root;
 public FileSystemModel() \{
 this( System.getProperty("user.home"));
 \}
 public FileSystemModel( String startPath ) 
 \{ root = startPath; \}
 public Object getRoot() 
 \{ return new File( root ); \}
 public Object getChild( Object parent, int index ) \{
 File directory = (File)parent;
 String[] children = directory.list();
 return new File( directory, children[index] );
 \}
 public int getChildCount( Object parent ) \{
 File file = (File)parent;
 if ( file.isDirectory() ) \{
 String[] children = file.list();
 if (children == null) return 0;
 return children.length;
 \}
 return 0;
 \}
 public boolean isLeaf(Object node)
 \{ return ((File)node).isFile(); \}
 public void valueForPathChanged( TreePath path, Object newValue ) \{\}
 public void removeTreeModelListener(TreeModelListener l) \{\}
 public void addTreeModelListener(TreeModelListener l) \{\}
 public int getIndexOfChild( Object parent, Object child ) \{
 File directory = (File)parent;
 File fileSysEntity = (File)child;
 String[] children = directory.list();
 int result = -1;
 for ( int i = 0; i < children.length; ++i ) \{
 if ( fileSysEntity.getName().equals( children[i] )) 
 result = i; break;
 \}
 return result;
 \}
 public static void main(String[] args) throws Exception
 \{
 //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
 JFrame f = new JFrame("A File System Tree");
 JTree t = new JTree(new FileSystemModel());
 t.setFont(new Font("Georgia", Font.PLAIN, 18));
 f.getContentPane().add(new JScrollPane(t));
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

JTREE EVENTS AND LISTENERS ....

 * Listen for when the selected node changes 
 >> tree.addTreeSelectionListener(this);

 * a tree with a SelectionChangeListener 
 --------------------------------------------------------
 import javax.swing.*;
 import javax.swing.tree.*;
 import javax.swing.event.*;
 import java.awt.*;
 public class ListenTree extends JPanel
 implements TreeSelectionListener \{
 JTree tree;
 JTextArea area;
 public ListenTree() \{
 super(new GridLayout(0, 1));
 this.tree = new JTree();
 this.tree.addTreeSelectionListener(this);
 this.tree.setFont(new Font(Font.SERIF, Font.PLAIN, 22));
 this.area = new JTextArea("Listening for Events \\$\\backslash\\$n");
 this.area.setFont(new Font(Font.SERIF, Font.PLAIN, 12));
 this.area.setLineWrap(true);
 this.add(new JScrollPane(this.tree));
 this.add(new JScrollPane(this.area));
 this.setPreferredSize(new Dimension(400, 600));
 \}
 
 public void valueChanged(TreeSelectionEvent e) \{
 DefaultMutableTreeNode node =
 (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
 this.area.append("Selection Event! " + e + "\\$\\backslash\\$n");
 if (node == null) return;
 Object nodeInfo = node.getUserObject();
 if (node.isLeaf()) \{ \}
 \}
 public static void main(String[] args) throws Exception \{
 JOptionPane.showMessageDialog(null, new ListenTree()); 
 \}
 \}
,,,
,,,


JTABLE SWING TABLE COMPONENT ....

 If you do not add a swing table to a scrollpane, then it is 
 necessary to add the table header seperately to the container 
 component.

 * using tables and cell renderers
 >> \url{http://docs.oracle.com/javase/tutorial/uiswing/components/table.html\\#editrender}

 * create a swing table using a default table model
 -------------------------------------------------------------
 DefaultTableModel tm = new DefaultTableModel();
 tm.addColumn("Column 0");
 tm.addColumn("Column 1");
 tm.addColumn("Column 2");
 tm.addRow(new String[]\{"Table 00", "Table 01", "Table 02"\});
 tm.addRow(new String[]\{"Table 10", "Table 11", "Table 12"\});
 tm.addRow(new String[]\{"Table 20", "Table 21", "Table 22"\});
 tm.addRow(new String[]\{"Table 30", "Table 31", "Table 32"\});
 table = new JTable(tm); 
 ,,,

 * create a table using the DefaultTableModel 
 -------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.table.*;
 import javax.swing.plaf.FontUIResource;
 import java.awt.Font;
 public class TableTest extends JPanel \{
 JTable table;
 public TableTest() \{
 super();
 DefaultTableModel m = new DefaultTableModel();
 m.addColumn("Tree");
 m.addColumn("Origin");
 m.addRow(new String[]\{"Eucalypt", "Australia"\});
 m.addRow(new String[]\{"Cork Oak", "Europe"\});
 m.addRow(new String[]\{"Siete Cueros", "Colombia"\});
 m.addRow(new String[]\{"Walnut", "Europe"\});
 table = new JTable(m); 
 this.table = new JTable(m);
 this.add(new JScrollPane(this.table));
 \} 
 public static void main(String[] args) throws Exception \{ 
 UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
 UIManager.put("Table.font", new FontUIResource("Georgia", Font.PLAIN, 18));
 JFrame f = new JFrame("A Table with the default table model");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.getContentPane().add(new TableTest());
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

 * create a table using the AbstractTableModel
 -------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.table.*;
 import javax.swing.plaf.FontUIResource;
 import java.awt.Font;
 public class TableTest extends JPanel \{
 JTable table;
 TableModel model = new AbstractTableModel() \{
 public int getColumnCount() \{ return 10; \}
 public int getRowCount() \{ return 10;\}
 public Object getValueAt(int row, int col) \{ 
 return new Integer(row*col); 
 //return "row 
 \}
 \};
 public TableTest() \{
 super();
 this.table = new JTable(this.model);
 //this.table.setFont(new Font("Monospaced", Font.PLAIN, 20));
 this.add(new JScrollPane(this.table));
 \} 

 public static void main(String[] args) throws Exception \{ 
 UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
 UIManager.put("Table.font", new FontUIResource("Serif", Font.PLAIN, 38));
 JFrame f = new JFrame("A Table with an AbstractTableModel");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.getContentPane().add(new TableTest());
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

 * a swing table with java properties values in it, sortable
 --------------------------------
 import javax.swing.*;
 import javax.swing.border.*;
 import javax.swing.table.*;
 import javax.swing.plaf.FontUIResource;
 import java.awt.*;
 public class PropertiesTable extends JPanel \{
 public PropertiesTable() \{
 super();
 this.setBorder(new TitledBorder("Properties Table"));
 String[] header = \{"Name", "Value"\};
 String[] a = new String[0];
 String[] names =
 System.getProperties().stringPropertyNames().toArray(a);
 String[][] data = new String[names.length][2];
 for (int ii=0; ii<names.length; ii++) \{
 data[ii][0] = names[ii];
 data[ii][1] = System.getProperty(names[ii]);
 \}
 DefaultTableModel model = new DefaultTableModel(data, header);
 JTable table = new JTable(model);
 try \{ // java version 1.6+
 table.setAutoCreateRowSorter(true);
 \} catch (Exception continuewithNoSort) \{ \}
 this.add(new JScrollPane(table));
 \}
 
 public static void main(String[] args) throws Exception \{
 UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JOptionPane.showMessageDialog(null, new PropertiesTable());
 \}
 \});
 \}
 \}
 ,,,

IMAGES IN TABLES ....

 * put image icons into jtable cells
 -------------------------------
 import java.awt.*;
 import javax.swing.*;
 import javax.swing.table.*;
 public class TableIcon extends JFrame \{
 public TableIcon() \{
 ImageIcon aboutIcon = new ImageIcon("about16.gif");
 ImageIcon addIcon = new ImageIcon("add16.gif");
 ImageIcon copyIcon = new ImageIcon("copy16.gif");
 
 String[] columnNames = \{"Picture", "Description"\};
 Object[][] data = \{
 \{aboutIcon, "About"\},
 \{addIcon, "Add"\},
 \{copyIcon, "Copy"\},
 \};
 
 DefaultTableModel model = new DefaultTableModel(data, columnNames);
 JTable table = new JTable( model ) \{
 // Returning the Class of each column will allow different
 // renderers to be used based on Class
 public Class getColumnClass(int column) \{
 return getValueAt(0, column).getClass();
 \}
 \};
 table.setPreferredScrollableViewportSize(table.getPreferredSize());
 JScrollPane scrollPane = new JScrollPane( table );
 getContentPane().add( scrollPane );
 \}
 
 public static void main(String[] args) \{
 TableIcon frame = new TableIcon();
 frame.setDefaultCloseOperation( EXIT\\_ON\\_CLOSE );
 frame.pack();
 frame.setVisible(true);
 \}
 \}
 ,,,

MENUS JMENUBARS AND JMENUS AND JMENUITEMS

 Menus in general are annoying but maybe the popup menu in java
 could be put to good use. The popup menu can contain any swing 
 component. 

 * build menus with JMenuBar, JMenu, JMenuItem

 * add a JMenuBar to a Window (JFrame)
 >> JMenuBar menubar = new JMenuBar(); frame.setJMenuBar(menubar);

 * remove the icon from a menu item 
 --------------------------
 menuItem = new JMenuItem();
 menuItem.setIcon(null); 
 ,,,

 * create a menu with control 0 shortcut key and an action listener
 -----------------------------------
 JMenuItem screenshot = new JMenuItem("Screenshot");
 screenshot.setAccelerator(KeyStroke.getKeyStroke(
 KeyEvent.VK\\_0, InputEvent.CTRL\\_DOWN\\_MASK));
 screenshot.addActionListener(new ActionListener() \{
 public void actionPerformed(ActionEvent ae) \{
 \}\};
 JMenu menu = new JMenu("Other");
 menu.add(screenshot);
 JMenuBar mb = new JMenuBar();
 mb.add(menu);
 jframe.setJMenuBar(mb);
 ,,,

 * make a menu creating objects within method calls
 -----------------
 Menu vm = mkMenu(b, "page");
 vm.add(mi = mkMenuItem(b, "page", "first"));
 mi.addActionListener(firster);
 vm.add(mi = mkMenuItem(b, "page", "prev"));
 mi.addActionListener(previouser);
 vm.add(mi = mkMenuItem(b, "page", "next"));
 mi.addActionListener(nexter);
 vm.add(mi = mkMenuItem(b, "page", "last"));
 mi.addActionListener(laster);
 vm.add(mi = mkMenuItem(b, "page", "goto"));
 mi.addActionListener(new ActionListener() \{
 public void actionPerformed(ActionEvent e) \{
 Unicode.this.gotoPageUI.setVisible(true);
 \}
 \});
 mb.add(vm);COLLECTIONS
 ,,,

JPOPUPMENU ....

 The JPopupMenu can contain any Component or JComponent not just a 
 list of JMenuItems. The popup menu is usually used in conjunction with
 a MouseListener or a MouseAdapter which shows the menu when the user
 clicks on a particular part of the interface.

 The 'popupTrigger' refers to the mouse action (which button, and whether
 clicked or pressed etc) which displays a popup menu on the operating
 system on which the java application is running. This property can be
 checked to maintain consistency with the operating system.

 * add a new item to a menu (the JMenuItem is created implicitly) 
 >> jpopupmenu.add("oak") 

 * check whether the mousebutton is the operating system popup trigger
 >> mouseevent.isPopTrigger() 

 * set the horizontal alignment
 >> menuitem.setHorizontalTextPosition(JMenuItem.RIGHT);

 * a simple example using a JPopupMenu
 ---------------------------------
 import java.awt.event.*;
 import java.awt.*;
 import javax.swing.*;
 import javax.swing.event.*;
 
 public class SimplePopupMenu extends JPanel 
 implements ActionListener, MouseListener \{
 JPopupMenu popup;
 JLabel label;

 public SimplePopupMenu() \{
 super(new BorderLayout());
 this.label = new JLabel("info");
 this.label.setFont(new Font("Georgia", Font.ITALIC, 20));
 this.popup = new JPopupMenu();
 JMenuItem item;
 for (String s: new String[]\{"oak", "yew", "elm", "tree"\}) \{
 popup.add(item = new JMenuItem(s));
 item.addActionListener(this);
 item.setFont(new Font("Georgia", Font.ITALIC, 20));
 \}
 popup.setLabel("Justification");
 this.addMouseListener(this);
 this.add(this.label, BorderLayout.NORTH);
 \}
 public void actionPerformed(ActionEvent event) \{
 this.label.setText(String.format(
 "menu item '\\%s' was clicked", event.getActionCommand()));
 \}
 
 public void mouseExited(MouseEvent e) \{ \}
 public void mouseEntered(MouseEvent e) \{ \}
 public void mousePressed(MouseEvent e) \{ checkPopup(e); \}
 public void mouseClicked(MouseEvent e) \{ checkPopup(e); \}
 public void mouseReleased(MouseEvent e) \{ checkPopup(e); \}
 private void checkPopup(MouseEvent e) \{
 if (e.isPopupTrigger()) \{
 popup.show(this, e.getX(), e.getY());
 \}
 \}
 
 public static void main(String s[]) \{
 JFrame f = new JFrame("JPopupMenu example");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setContentPane(new SimplePopupMenu()); f.pack();
 //f.setLocationRelativeTo(null);
 f.setSize(300, 300); f.setVisible(true);
 \}
 \}
 ,,,

 In the code below the popup menu shows displaced vertically because
 the MouseEvent returns coordinates relative to the JTextArea, not
 the panel. With a small amount of code a lot of functionality 
 is added.

 * add a JPopupMenu to a JTextArea with all default actions 
 ---------------------------------
 import java.awt.event.*;
 import java.awt.*;
 import javax.swing.*;
 import javax.swing.plaf.*;
 import javax.swing.event.*;
 
 public class TextAreaPopup extends JPanel implements MouseListener \{
 JPopupMenu popup;
 JTextArea area;
 JLabel label;
 public TextAreaPopup() \{
 super(new BorderLayout());
 this.area = new JTextArea("right click for actions", 20, 60);
 this.area.setFont(new Font("Georgia", Font.ITALIC, 20));
 this.area.addMouseListener(this);
 this.label = new JLabel("info");
 this.label.setFont(new Font("Georgia", Font.ITALIC, 20));
 this.popup = new JPopupMenu();
 this.popup.setLayout(new GridLayout(0,4));
 JMenuItem item;
 for (Action a: this.area.getActions()) \{
 this.popup.add(a);
 this.popup.getComponent(this.popup.getComponentCount()-1)
 .setFont(new Font("Georgia", Font.ITALIC, 20));
 \}
 popup.setLabel("JTextArea actions");
 this.add(this.label, BorderLayout.NORTH);
 this.add(this.area, BorderLayout.CENTER);
 \}
 public void mouseExited(MouseEvent e) \{ \}
 public void mouseEntered(MouseEvent e) \{ \}
 public void mousePressed(MouseEvent e) \{ checkPopup(e); \}
 public void mouseClicked(MouseEvent e) \{ checkPopup(e); \}
 public void mouseReleased(MouseEvent e) \{ checkPopup(e); \}
 private void checkPopup(MouseEvent e) \{
 if (e.isPopupTrigger()) \{ 
 this.label.setText(String.format(
 "Click Position(x, y) = (\\%d, \\%d)", e.getX(), e.getY()));
 popup.show(this, e.getX(), e.getY());
 \}
 \}
 public static void main(String s[]) \{
 JFrame f = new JFrame("JTextArea Action popup menu example");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.add(new TextAreaPopup()); f.pack();
 f.setLocationRelativeTo(null); f.setVisible(true);
 \}
 \}
 ,,,


 The example below may become a prototype for retrieving the files
 in a certain folder, and allowing the user to choose which folder.

 * add a JPopupMenu to a JTextArea with directories containing jpegs
 ---------------------------------
 import java.awt.event.*;
 import java.awt.*;
 import java.io.File;
 import javax.swing.*;
 //import javax.swing.plaf.*;
 import javax.swing.event.*;
 
 public class FolderPopup extends JPanel implements MouseListener \{
 JPopupMenu popup;
 JTextArea area;
 JLabel label;
 public FolderPopup() \{
 super(new BorderLayout());
 this.area = new JTextArea("right click to insert files", 20, 60);
 this.area.setFont(new Font("Georgia", Font.ITALIC, 20));
 this.area.addMouseListener(this);
 this.label = new JLabel("info");
 this.label.setFont(new Font("Georgia", Font.ITALIC, 20));
 this.popup = new JPopupMenu();
 this.popup.setLayout(new GridLayout(0,4));
 JMenuItem item;
 /*
 for (Action a: this.area.getActions()) \{
 this.popup.add(a);
 this.popup.getComponent(this.popup.getComponentCount()-1)
 .setFont(new Font("Georgia", Font.ITALIC, 20));
 \}
 */
 Action a = new InsertFileListAction(new File("."));
 this.popup.add(a);
 this.popup.getComponent(this.popup.getComponentCount()-1)
 .setFont(new Font("Georgia", Font.ITALIC, 20));
 popup.setLabel("JTextArea insert file list");
 this.add(this.label, BorderLayout.NORTH);
 this.add(new JScrollPane(this.area), BorderLayout.CENTER);
 \}
 public void mouseExited(MouseEvent e) \{ \}
 public void mouseEntered(MouseEvent e) \{ \}
 public void mousePressed(MouseEvent e) \{ checkPopup(e); \}
 public void mouseClicked(MouseEvent e) \{ checkPopup(e); \}
 public void mouseReleased(MouseEvent e) \{ checkPopup(e); \}
 private void checkPopup(MouseEvent e) \{
 if (e.isPopupTrigger()) \{ 
 this.label.setText(String.format(
 "Click Position(x, y) = (\\%d, \\%d)", e.getX(), e.getY()));
 popup.show(this, e.getX(), e.getY());
 \}
 \}
 /** inserts a list of files into the text area */
 public void insertFileList(File folder) \{
 this.area.append("file list...");
 for (File f: folder.listFiles()) \{
 this.area.append(f.getAbsolutePath() + "\\$\\backslash\\$n");
 \} 
 \}
 public static void main(String s[]) \{
 JFrame f = new JFrame("JTextArea Action popup menu example");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.add(new FolderPopup()); f.pack();
 f.setLocationRelativeTo(null); f.setVisible(true);
 \}
 class InsertFileListAction extends AbstractAction \{
 File folder;
 public InsertFileListAction(File folder) \{
 this.folder = folder;
 putValue(Action.NAME, "Insert * " + this.folder.toString());
 putValue(Action.SHORT\\_DESCRIPTION, 
 "Inserts a list of files into a text area");
 putValue(Action.MNEMONIC\\_KEY, new Integer(KeyEvent.VK\\_I));
 \}
 public void actionPerformed(ActionEvent e) \{
 FolderPopup.this.insertFileList(this.folder);
 \}
 \}
 \}
 ,,,

JMENUITEMS AND OTHER ELEMENTS ....

 We can retrieve a JMenuItem with the getComponent(int) method
 or maybe also with getSubElements()

 * retrieve the last added JMenuItem from a JPopupMenu
 >> item = popup.getComponent(popup.getComponentCount()-1);

 * iterate through the JMenuItems of a popup menu java1.5+
 -------------------------------------------------------------
 for (Component child : jpopupmenu.getComponents()) \{
 if (child instanceof JMenuItem) \{
 //...
 \}
 \}
 ,,,

 * another way to iterate through JMenuItems java < 1.5
 -------------------------------------------------------------
 JPopupMenu menu = new JPopupMenu();
 ...
 for (int ii = menu.getComponentCount()-1; ii >= 0; ii--) \{
 Component child = menu.getComponent(ii);
 if (child instanceof JMenuItem) \{ ... \}
 \}
 ,,,
 
APPEARANCE OF THE JPOPUPMENU ....

 One can set the layout manager for a JPopupMenu just as for 
 any JPanel or other container component. This is handy.

 * create a JPopupMenu which displays its item in 3 columns
 -------------------------------------------------------------
 this.popup = new JPopupMenu();
 this.popup.setLayout(new GridLayout(0,2));
 JMenuItem item;
 for (String s: new String[]\{"a", "b", c", "d", "e", "f"\}) \{
 popup.add(new JMenuItem(s));
 \}
 ,,,

 * set the font of menu items when adding Actions
 -------------------------------------------------------------
 popup.add(action);
 popup.getComponent(popup.getComponentCount()-1)
 .setFont(new Font("Georgia", Font.ITALIC, 20));
 ,,,

 * change the default font, not working for me
 -------------------------------------------------------------
 import javax.swing.plaf.*;
 ...
 UIManager.put("PopupMenu.font", 
 new FontUIResource(Font.SERIF, Font.PLAIN, 20));
 ,,,
 

\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents Look and Feel UIManager properties for JPopupMenu
 PopupMenu.actionMap ActionMap
 PopupMenu.background Color
 PopupMenu.border Border
 PopupMenu.consumeEventOnClose Boolean
 PopupMenu.font Font
 PopupMenu.foreground Color
 PopupMenu.popupSound String
 PopupMenu.selectedWindowInputMapBindings Object[ ]
 PopupMenu.selectedWindowInputMapBindings.RightToLeft Object[ ]
 PopupMenuSeparatorUI String
 PopupMenuUI String
 ..
 .. 

ADDING ITEMS TO A JPOPUPMENU ....

 There are many different ways to add JMenuItems or other elements
 to a popup menu.

 We can add items explicitly to a JPopupMenu by creating JMenuItems and
 using the add() method of the popup menu. Another alternative is to add
 Actions directly to the JPopupMenu. The menu extracts the information
 which it needs to create the JMenuItems (implicitly) from the Action
 properties (name, description, icon etc). Also, strings can be added
 directly to the menu

 * place any sort of component in a JPopupMenu with insert
 >> public void insert(Component component, int index)

 Strangely the add() methods dont support adding any sort of Component
 but insert() does.

 * add a JTextField as the third element in a JPopupMenu 
 ---------------------------------
 import java.awt.event.*;
 import java.awt.*;
 import javax.swing.*;
 import javax.swing.event.*;
 
 public class TextFieldPopup extends JPanel 
 implements ActionListener, MouseListener \{
 JPopupMenu popup;
 JLabel label;

 public TextFieldPopup() \{
 super(new BorderLayout());
 this.label = new JLabel("info");
 this.label.setFont(new Font("Georgia", Font.ITALIC, 20));
 this.popup = new JPopupMenu();
 JMenuItem item;
 for (String s: new String[]\{"oak", "yew", "elm", "tree"\}) \{
 popup.add(item = new JMenuItem(s));
 item.addActionListener(this);
 item.setFont(new Font("Georgia", Font.ITALIC, 20));
 \}
 popup.insert(new JTextField("type here"), 2);
 this.addMouseListener(this);
 this.add(this.label, BorderLayout.NORTH);
 \}
 public void actionPerformed(ActionEvent event) \{
 this.label.setText(String.format(
 "menu item '\\%s' was clicked", event.getActionCommand()));
 \}
 
 public void mouseExited(MouseEvent e) \{ \}
 public void mouseEntered(MouseEvent e) \{ \}
 public void mousePressed(MouseEvent e) \{ checkPopup(e); \}
 public void mouseClicked(MouseEvent e) \{ checkPopup(e); \}
 public void mouseReleased(MouseEvent e) \{ checkPopup(e); \}
 private void checkPopup(MouseEvent e) \{
 if (e.isPopupTrigger()) \{
 popup.show(this, e.getX(), e.getY());
 \}
 \}
 
 public static void main(String s[]) \{
 JFrame f = new JFrame("JPopupMenu example");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setContentPane(new TextFieldPopup()); f.pack();
 f.setSize(300, 300); f.setVisible(true);
 \}
 \}
 ,,,

EVENTS AND THE JPOPUPMENU ....

 JPopupMenus have 3 classes of events associated with them. The 
 mouse events which are captured to show the menu; the click events
 which select an item in the menu; and the menu showing and disappearing
 events.

 >> popup.addPopupMenuListener(new PopupMenuListener());
 
 * an example using a JPopupMenu and a PopupMenuListener
 ---------------------------------
 import java.awt.event.*;
 import java.awt.*;
 import javax.swing.*;
 import javax.swing.border.BevelBorder;
 import javax.swing.event.*;
 
 public class PopupListener extends JPanel implements ActionListener \{
 JPopupMenu popup;
 JLabel label;
 public PopupListener() \{
 super(new BorderLayout());
 this.label = new JLabel("info");
 this.popup = new JPopupMenu();
 JMenuItem item;
 for (String s: new String[]\{"oak", "yew", "elm", "tree"\}) \{
 popup.add(item = new JMenuItem(s));
 item.addActionListener(this);
 item.setFont(new Font("Georgia", Font.ITALIC, 20));
 \}
 popup.addPopupMenuListener(new PopupPrintListener());
 this.addMouseListener(new MousePopupListener());
 this.add(this.label, BorderLayout.NORTH);
 \}
 
 public void actionPerformed(ActionEvent event) \{
 this.label.setText(String.format(
 "Popup menu item [\\%s] was pressed.", event.getActionCommand()));
 \}
 class MousePopupListener extends MouseAdapter \{
 public void mousePressed(MouseEvent e) \{ checkPopup(e); \}
 public void mouseClicked(MouseEvent e) \{ checkPopup(e); \}
 public void mouseReleased(MouseEvent e) \{ checkPopup(e); \}
 
 private void checkPopup(MouseEvent e) \{
 if (e.isPopupTrigger()) \{
 popup.show(PopupListener.this, e.getX(), e.getY());
 \}
 \}
 \}
 
 // show when popup events occur
 class PopupPrintListener implements PopupMenuListener \{
 public void popupMenuWillBecomeVisible(PopupMenuEvent e) \{
 System.out.println("Popup menu will be visible!");
 \}
 public void popupMenuWillBecomeInvisible(PopupMenuEvent e) \{
 System.out.println("Popup menu will be invisible!");
 \}
 public void popupMenuCanceled(PopupMenuEvent e) \{
 System.out.println("Popup menu is hidden!");
 \}
 \}
 public static void main(String s[]) \{
 JFrame frame = new JFrame("JPopupMenu example");
 frame.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 frame.setContentPane(new PopupListener());
 frame.setSize(300, 300); frame.setVisible(true);
 \}
 \}
 ,,,

GOTCHAS FOR THE JPOPUPMENU

 JTextComponents such as JTextArea seem to consume mouseclicks,
 so you need to add the MouseListener to the JTextComponent itself
 rather than its parent container.

ACTIONS AND MENUS ....

 If we add Actions directly to the JMenu, we dont have to create
 JMenuItems; the Action does all the work of providing text and possibly an
 icon and also an action for the JMenuItem.

 * test out the default actions for a text area by building a menu
 ------------------------
 import javax.swing.*;
 public class TextAreaActions \{
 public static void main(String[] args) \{
 JTextArea ta = new JTextArea();
 ta.setLineWrap(true);
 
 Action[] actions = ta.getActions();
 JMenuBar menubar = new JMenuBar();
 JMenu actionmenu = new JMenu("Actions");
 menubar.add(actionmenu);
 
 JMenu firstHalf = new JMenu("1st Half");
 JMenu secondHalf = new JMenu("2nd Half");
 actionmenu.add(firstHalf);
 actionmenu.add(secondHalf);
 int mid = actions.length / 2;
 for (int i = 0; i < mid; i++) \{
 firstHalf.add(actions[i]);
 \}
 for (int i = mid; i < actions.length; i++) \{
 secondHalf.add(actions[i]);
 \}
 JFrame f = new JFrame("Default Actions for JTextArea");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.getContentPane().add(ta); f.setJMenuBar(menubar);
 f.setSize(300, 200); f.setVisible(true);
 \}
 \}
 ,,,

 Textareas have a 'dump-model' default action which is interesting.

 The code below shows and easy way to create a menu of actions, this can
 be used to test the default actions for a JTextComponent.

 * add some custom actions and some defaulteditorkit actions to a menu
 -------------------
 JMenu menu = new JMenu("Edit");
 //the actions below extend AbstractAction
 undoAction = new UndoAction();
 menu.add(undoAction);
 redoAction = new RedoAction();
 menu.add(redoAction);
 menu.addSeparator();
 
 menu.add(getActionByName(DefaultEditorKit.cutAction));
 menu.add(getActionByName(DefaultEditorKit.copyAction));
 menu.add(getActionByName(DefaultEditorKit.pasteAction));
 
 JMenuBar mb = new JMenuBar();
 mb.add(menu);
 jframe.setJMenuBar(mb);
 ,,,

 * if we dont use Actions we have to create menu items and then attached event
 listeners to each of them.
 -------------------
 frame = new JFrame("Java Menubar Example");
 // build the Edit menu
 editMenu = new JMenu("Edit");
 cutMenuItem = new JMenuItem("Cut");
 cutMenuItem.addActionListener(this);
 copyMenuItem = new JMenuItem("Copy");
 copyMenuItem.addActionListener(this);
 editMenu.add(cutMenuItem);
 editMenu.add(copyMenuItem);
 JMenuBar menuBar = new JMenuBar();
 menuBar.add(editMenu);
 // put the menubar on the frame
 frame.setJMenuBar(menuBar);
 ,,,


JTOOLTIPS

 Tooltips, known by various other names, are little boxes that can
 pop up when the user places a pointing device (ok, lets just call it
 a mouse) over a component in a user-interface. The tooltip could also
 be triggered by other user actions. In java this functionality is 
 provided by the javax.swing.JToolTip class.

 Tool-tips are actually very useful as a user-help feature, since 
 they are an unobtrusive and context-sensitive way to give the user
 information about the interface when he or she wants it. Also they
 fit reasonably well with touch-screen devices where the human finger
 replaces the mouse as the 'pointing device'

 \url{http://www.javarichclient.com/how-to-create-a-callout-border/}
 a nice baloon label, using a custom border with a JLabel, rounded
 corners and a triangle arrow. This can
 be used as a tool tip replacement.

 * turn off the tooltip for JComponent 'c'
 >> c.setToolTipText(null);

 If the method below returns null, the swing system will determine
 the location of the tooltip

 * override this method to determine the location of the tooltip
 >> Point getToolTipLocation(MouseEvent)

 * set tooltips on jbuttons 
 -------------------------------------------------------------
 import javax.swing.*;
 import java.io.File;
 public class TipPanel extends JPanel \{
 public TipPanel() \{
 super(new java.awt.GridLayout(0,2));
 for (File f: new File(".").listFiles()) \{
 JButton b = new JButton(f.getName());
 b.setToolTipText("File length: " + f.length());
 this.add(b);
 \}
 \} 
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JOptionPane.showMessageDialog(null, new TipPanel());
 \}
 \});
 \}
 \}
 ,,,

APPEARANCE OF JTOOLTIP ....


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents uimanager properties for JToolTip
 .. ToolTip.background - Color
 .. ToolTip.backgroundInactive - Color
 .. ToolTip.border - Border
 .. ToolTip.borderInactive - Color 
 .. ToolTip.font - Font
 .. ToolTip.foreground - Color
 .. ToolTip.foregroundInactive - Color
 .. ToolTip.hideAccelerator - Boolean
 .. ToolTipUI - String
 ..

 * list all look-and-feel keys and values which relate to ToolTips
 -------------------------------------------------------------
 import javax.swing.*;
 public class ToolTipDefaults \{
 public static void main(String[] args) \{
 java.util.Enumeration keys = UIManager.getDefaults().keys();
 while (keys.hasMoreElements()) \{
 String key = keys.nextElement().toString();
 if (key.startsWith("ToolTip")) \{ 
 System.out.println(key);
 Object value = UIManager.get(key);
 //String name = value.getClass().getName();
 System.out.println(" " + value);
 \}
 \}
 \}
 \}
 ,,,

 In the example below the background painting of the tooltip 
 does not suit the RoundedBorder because the background is a normal
 rectangle and the RoundedBorder paints a RoundedRectangle, so that
 the background extends outside of the Border.

 * set a new Font and a custom RoundedBorder for JToolTips on JButtons 
 -------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.plaf.*;
 import java.io.File;
 import java.awt.*;
 public class TipPanel extends JPanel \{
 public TipPanel() \{
 super(new java.awt.GridLayout(0,2));
 Font font = new Font("Georgia", Font.ITALIC, 20);
 UIManager.put("ToolTip.font", new FontUIResource(font));
 UIManager.put("ToolTip.border", new RoundedBorder());
 for (File f: new File(".").listFiles()) \{
 JButton b = new JButton(f.getName());
 b.setToolTipText("File length: " + f.length());
 this.add(b);
 \}
 \} 
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JOptionPane.showMessageDialog(null, new TipPanel());
 \}
 \});
 \}
 \}
 ,,,

 Idea set a translucent color for the background of a tooltip,
 but the tooltip seems to be alway opaque, so this doesnt work

 >> Color translucentRed = new Color(150, 0, 0, 0);

CUSTOM TOOLTIP ....

 \url{http://rcforte.wordpress.com/2010/10/10/custom-jtooltip/}
 a complete example of creating a multicomponet jtooltip 

 To create a custom JToolTip, override JComponent.createToolTip()
 and use a subclass of JToolTip.

 * the basic skeleton for creating a custom JToolTip
 -------------------------------------------------------------
 checkBox = new JCheckBox() \{
 @Override
 public JToolTip createToolTip() \{
 System.out.println("creating tip");
 return new ImageToolTip(m.getImage());
 \}
 \};
 ,,,

 * customise a jtooltip by anonymously subclassing JButton
 ------------------------------------------------------------
 import javax.swing.*;
 public class TipButton \{
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JButton b = new JButton("Anonymous JButton") \{
 public JToolTip createToolTip() \{
 JToolTip tip = super.createToolTip();
 tip.setBackground(java.awt.Color.yellow);
 return tip;
 \}
 \};
 b.setToolTipText("custom tool tip");
 JOptionPane.showMessageDialog(null, b);
 \}
 \});
 \}
 \}
 ,,,
 
 In the example below, there are 2 interesting points: that the 
 setToolTipText() method actually triggers the creation of the 
 tooltip (and hence fires the createToolTip() method) and secondly
 that the text set within the createToolTip() method for the tooltip
 is ignored, or rather gets overwritten.

 * override the createToolTip method to install a custom JToolTip 
 -------------------------------------------------------------
 import javax.swing.*;
 public class TipBox extends JCheckBox \{
 public TipBox(String s) \{ super(s); \}
 @Override
 public JToolTip createToolTip() \{
 System.out.println("creating custom tooltip");
 JToolTip tt = new JToolTip(); 
 tt.setTipText("this text is ignored");
 return tt;
 \}
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 TipBox t = new TipBox("tip box"); 
 t.setToolTipText("hi");
 JOptionPane.showMessageDialog(null, t);
 \}
 \});
 \}
 \}
 ,,,

 To just use the standard (rather ugly) java tool-tip, call
 component.setToolTipText("help text") on any swing component.

MULTICOMPONENT JTOOLTIP ....

 If you want to do something fancy you may want to display many components
 in your JToolTip, here is how. The following example seems to work but the
 m\\_ coding style is bizarre. 

 * a multi-component JToolTip example (by rcforte)
 -------------------------------------------------------------
 import java.awt.BorderLayout;
 import java.awt.Dimension;
 import java.awt.EventQueue;
 import javax.swing.JButton;
 import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JToolTip;
 
 public class CustomTooltipSample extends JFrame \{
 private CustomLabel m\\_label;
 
 public CustomTooltipSample() \{
 setTitle("Custom tooltip sample");
 setSize(300, 200);
 setDefaultCloseOperation(EXIT\\_ON\\_CLOSE);
 m\\_label = new CustomLabel("My Label");
 m\\_label.setToolTipText("Yo, I am a tooltip with components!"); // activate tooltips for this component
 add(m\\_label);
 \}
 
 public static void main(String[] args) \{
 EventQueue.invokeLater(new Runnable() \{
 @Override public void run() \{
 JFrame frame = new CustomTooltipSample();
 frame.setVisible(true);
 \}
 \});
 \}
 
 private static class CustomLabel extends JLabel \{
 private CustomTooltip m\\_tooltip;
 public CustomLabel(String text) \{ super(text); \}
 @Override public JToolTip createToolTip() \{
 if (m\\_tooltip == null) \{
 m\\_tooltip = new CustomTooltip();
 m\\_tooltip.setComponent(this);
 \}
 return m\\_tooltip;
 \}
 \}
 
 private static class CustomTooltip extends JToolTip \{
 private JLabel m\\_label;
 private JButton m\\_button;
 private JPanel m\\_panel;
 public CustomTooltip() \{
 super();
 m\\_label = new JLabel();
 m\\_button = new JButton("See, I am a button!");
 m\\_panel = new JPanel(new BorderLayout());
 m\\_panel.add(BorderLayout.CENTER, m\\_label);
 m\\_panel.add(BorderLayout.SOUTH, m\\_button);
 setLayout(new BorderLayout());
 add(m\\_panel);
 \}
 
 @Override public Dimension getPreferredSize() \{
 return m\\_panel.getPreferredSize();
 \}
 
 @Override public void setTipText(String tipText) \{
 if (tipText != null \\&\\& !tipText.isEmpty()) \{
 m\\_label.setText(tipText);
 \} else \{
 super.setTipText(tipText);
 \}
 \}
 \}
 \}
 ,,,


LOCATION SPECIFIC TOOLTIP ....

 subclass and JComponent and override getToolTipText(MouseEvent)

TOOLTIPMANAGER ....

 books.google.com.au/books?isbn=1590594479 page 84
 a book with good info

 The manager controls delay of appearance and such things.

 * disable all tooltips
 >> ToolTipManager.sharedInstance().setEnabled(false);

MOUSE 

 The venerable 'mouse' is a pointing device. The mouse interface
 techniques are worth learning since they are easily translated to
 more modern world of touch screens, tablet computer and 'smart'
 phones.

MOUSEEVENTS AND MOUSELISTENERS ....

MOUSELISTENERS ....

 The java.awt.event.MouseListener listens for mouse clicks, presses
 and releases. The MouseEvent contains information about where the 
 mouse was clicked. The x and y coordinates of the mouse click will 
 probably be relative to the Component or JComponent on which the 
 MouseListener was registered with the addMouseListener() method.
 
 * check if the left mouse button was clicked
 >> if (SwingUtilities.isLeftMouseButton(ev)) \{...\}

 * add a mouselistener to a jtextarea, only listens for clicks
 -------------------------
 textArea.addMouseListener(new MouseAdapter() \{
 @Override
 public void mouseClicked(MouseEvent e) \{
 if (SwingUtilities.isLeftMouseButton(e) \\&\\& e.getClickCount() == 1) \{
 // do something here
 \}
 \});
 ,,, 

 * a simple mouseadaptor example (the label doesnt block the clicks)
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.BorderLayout;
 import java.awt.event.*;
 public class LabelOnPanel \{
 public static void main(String[] args) \{
 final JPanel mainPanel = new JPanel(new BorderLayout());
 mainPanel.add(new JLabel(
 "This is a JLabel covering the entire panel"));
 mainPanel.addMouseListener(new MouseAdapter() \{
 @Override
 public void mouseClicked(MouseEvent e) \{
 JOptionPane.showMessageDialog(mainPanel, "Panel received click");
 \}
 \});
 JFrame frame = new JFrame("Testing mouse clicks on a panel");
 frame.setBounds(100, 100, 300, 300);
 frame.add(mainPanel, BorderLayout.CENTER);
 frame.setVisible(true);
 \}
 \}
 ,,,
 
MOUSEMOTIONLISTENERS ....

 The java.awt.event.MouseMotionListener as its name states clearly,
 listens for movement of the mouse, rather than clicks or presses.

 * add a mousemotionlistener to a JPanel
 -------------------------------------------------------------
 jpanel.addMouseMotionListener(new MouseMotionAdapter() \{
 public void mouseDragged(MouseEvent evt) \{ ... \}
 \});
 ,,,

CURSOR ....

 The cursor is the small icon which indicates the position of the mouse.
 The cursor is set for a particular (swing) component, and all the
 components contained in that component. In a swing text component the
 'cursor' (usually a little flashing vertical line) is referred to as the
 'caret'

 * set the cursor to a wait symbol when it is over the container
 >> component.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT\\_CURSOR));

 * set the cursor
 >> setCursor (Cursor.getPredefinedCursor(Cursor.HAND\\_CURSOR));

 * set cursor to an image icon
 -------------------------------------------
 Toolkit toolkit = Toolkit.getDefaultToolkit();
 Image image = toolkit.getImage("icons/handwriting.gif");
 Cursor c = toolkit.createCustomCursor(
 image, newPoint(mainPane.getX(), mainPane.getY()), "img");
 mainPane.setCursor(c);
 ,,,

 * set the cursor for the root pane
 >> frame.getRootPane().setCursor(...);

CALENDARS

 java.util.Calendar and java.util.Timezone are useful classes for 
 getting information about times and dates. The Calendar class seems
 to have a bad reputation for being confusing. The Android api
 reimplements the Calendar class.

 * use some methods of the Calendar class
 -------------------------------------------------------------
 Calender c = Calendar.getInstance();
 miliSecond = c.get(Calendar.MILLISECOND);
 second = c.get(Calendar.SECOND);
 minute = c.get(Calendar.MINUTE);
 hour = c.get(Calendar.HOUR\\_OF\\_DAY);
 dayOfMonth = c.get(Calendar.DAY\\_OF\\_MONTH);
 dayOfYear = c.get(Calendar.DAY\\_OF\\_YEAR);
 dayOfWeek = c.get(Calendar.DAY\\_OF\\_WEEK);
 month = c.get(Calendar.MONTH);
 daysInMonth = c.getActualMaximum(Calendar.DAY\\_OF\\_MONTH);
 daysInYear = c.getActualMaximum(Calendar.DAY\\_OF\\_YEAR);
 ,,,

 * print the current date and time as a 'formatted' string
 --------------------------------------
 import java.util.Calendar;
 public class PrintTime \{
 public static void main(String[] args) \{
 System.out.println("Time: " + Calendar.getInstance().getTime());
 \}
 \}
 ,,,


DATES ....

 Apparently JodaTime should be used instead of the standard
 java classes.

 The 'epoch' which is midnight 1 jan 1970 UTC is important in
 some date and time manipulations.

 * convert miliseconds since the 'epoch' (midnight 1 jan 1970) to readable 
 -------------------------------------------------------------
 import java.util.Calendar;
 public class EpochTime \{
 public static void main(String[] args) \{
 Calendar cal = Calendar.getInstance();
 cal.setTimeInMillis(System.currentTimeMillis());
 //String dateStr = String.format("\\%tc", cal);
 System.out.format("\\%tc", cal);
 \}
 \}
 ,,,

 * parse a string into a date using a SimpleDateFormat
 --------------------
 SimpleDateFormat parser = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
 try \{
 final Date date = parser.parse(dateString);
 System.out.println(integer + " -> " + date);
 \} catch (final ParseException pe) \{
 System.err.println("bad date: " + dateString + ": " + pe);
 \}
 ,,,

 The example below does not consider if the start and end dates
 are included in the calculation.

 * get the number of days between to dates
 -------------------------------------------------------------
 import java.util.*;
 public class DayDiff \{
 public static void main(String[] args) \{
 GregorianCalendar cal1 = new GregorianCalendar(2012,7,17);
 GregorianCalendar cal2 = new GregorianCalendar(2012,10,21);
 long ms1 = cal1.getTime().getTime();
 long ms2 = cal2.getTime().getTime();
 long difMs = ms2-ms1;
 long msPerDay = 1000*60*60*24;
 double days = difMs / msPerDay;
 //System.out.format("number of days: \\%g", days);
 System.out.println(days);
 \}
 \}
 ,,,

TIME

 getLocale() ?? below

 * create a readable date format for this local and get the current time
 -------------------------------------------------------------
 import java.text.DateFormat;
 import java.util.Date;
 public class TimerTest \{
 public static void main(String[] args) \{
 DateFormat f =
 DateFormat.getTimeInstance(DateFormat.MEDIUM, getLocale());
 String s = f.format(new Date());
 \}
 \}
 
 ,,,

 * get the current time in nanoseconds
 >> long lastTime = System.nanoTime(); 

 * get the current time in milli seconds
 >> long startTime = System.currentTimeMillis();

 * a simple way to find out roughly how long some code takes
 -------------------------------------------------------------
 long startTime = System.currentTimeMillis();
 // ... code that takes time
 long endTime = System.currentTimeMillis();
 jframe.setTitle("took " + (endTime - startTime) + " ms");
 ,,,

TIMERS ....

 A javax.swing.Timer can be used to execute an action periodically. They are
 said to be superior to using a technique such as 'Thread.sleep()'
 
 * use a timer to update the text of a label each second 
 -------------------------------------------------------
 import java.awt.*;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import javax.swing.*;
 public class TimerTest \{
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 final JLabel label = new JLabel("Timed Label");
 ActionListener listener = new ActionListener() \{
 @Override
 public void actionPerformed(ActionEvent ae) \{
 label.setText(String.valueOf(System.nanoTime()));
 label.repaint();
 \}
 \};
 Timer timer = new Timer(1000, listener);
 timer.start();
 JOptionPane.showMessageDialog(null, label);
 \}

 \});
 \}
 \}
 ,,,

 * use a timer to change the color of textfield text every second
 -------------------------------------------------------------

 import java.awt.Color;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import javax.swing.*;

 public class BlinkColorTextField \{
 BlinkColorTextField() \{
 final JTextField blinkingText = new JTextField("Red \\& Blue");
 ActionListener blinker = new ActionListener() \{
 boolean isRed = true;
 public void actionPerformed(ActionEvent ae) \{
 if (isRed) \{
 blinkingText.setForeground(Color.BLUE);
 \} else \{
 blinkingText.setForeground(Color.RED);
 \}
 isRed = !isRed;
 \}
 \};
 Timer timer = new Timer(1000, blinker);
 timer.start();
 JOptionPane.showMessageDialog(null, blinkingText);
 \}
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable()\{
 public void run() \{
 new BlinkColorTextField();
 \}
 \});
 \}
 \}
 ,,,

 * add a word to a JTextArea one per second
 ----------------------------------------------
 ActionListener l = new ActionListener() \{
 @Override
 public void actionPerformed(...) \{
 textArea.append(words.remove(0));
 \}
 \};
 Timer timer = new Timer(1000, l);
 timer.start();
 ,,,

EVENTS AND LISTENERS

 Events in java are any type of user input action or change of computer
 state. These events are fired (create event objects) and can be listened
 to by other objects. The listener is responsible for doing something when
 the event occurs. 
 
 There are always 2 steps to set up a Listener to react when a certain
 event occurs. 1. Implement the Listener interface or extend the Adapter
 class. 2. Attach the Listener to the component you want to listen to with
 the method component.add?Listener where the ? symbol stands for the type
 of Listener you are using (eg ActionListener, PropertyChangeListener etc)
 
PROPERTYCHANGELISTENERS AND PROPERTYCHANGEEVENTS ....

 A Java bean (such as Swing Components) may have certain bound variables.
 These variables can be listened to for changes by a
 PropertyChangeListener.

 Only one method is required to implement the PropertyChangeListener
 interface, namely propertyChange(...). In the example below, the 
 name of the bound variable in the javabean object is 'progress'
 
 * an example of a propertyChange() method
 -------------------------------------------------------------
 public class Example implements PropertyChangeListener \{
 ...
 javabean.addPropertyChangeListener(this);
 ...
 public void propertyChange(PropertyChangeEvent e) \{
 if ("progress" == e.getPropertyName()) \{
 int progress = (Integer) e.getNewValue();
 jprogressbar.setValue(progress);
 \}
 \}
 \}
 ,,,

ACTIONLISTENERS AND ACTIONEVENTS ....

 * A button which beeps when clicked
 ---------------------------------------
 import java.awt.*;
 import javax.swing.*;
 import java.awt.Toolkit;
 import java.awt.BorderLayout;
 import java.awt.event.ActionListener;
 import java.awt.event.ActionEvent;
 
 public class Beeper extends JPanel implements ActionListener \{
 JButton button;
 public Beeper() \{
 super(new BorderLayout());
 button = new JButton("Beep Button");
 button.setPreferredSize(new Dimension(200, 80));
 add(button, BorderLayout.CENTER);
 button.addActionListener(this);
 \}
 
 public void actionPerformed(ActionEvent e) \{
 Toolkit.getDefaultToolkit().beep();
 \}
 
 public static void main(String[] args) \{
 javax.swing.SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JFrame frame = new JFrame("Beeper");
 frame.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 JComponent newContentPane = new Beeper();
 newContentPane.setOpaque(true); 
 frame.setContentPane(newContentPane);
 frame.pack();
 frame.setVisible(true);
 \}
 \});
 \}
 \}
 ,,, 

KEYLISTENERS KEYADAPTERS AND KEY STROKE EVENTS ....
 
 Keystroke events occur when the user types, presses or releases
 keyboard keys. 
 

\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents different ways to react to keystrokes
 .. use mnemonics and shortcut keys on JComponents 
 .. use ActionMap and InputMap to make keybindings (since 1.3)
 .. implement a KeyListener - 
 .. extend a KeyAdapter - this is almost the same as KeyListener
 .. use a DocumentListener on a JTextComponent
 ..

 For information on DocumentListeners see the section in 
 JTextComponents.

 KeyListeners do not seem to 'consume' the keystroke. That is the same key
 stroke will be passed to any parent components which are also listening
 for keystrokes. So if you put a JTextField in a
 JOptionPane.showMessageDialog() and listen for ActionEvents on the
 JTextField, the message dialog will exit after the event is handled by
 the ActionListener.

KEYADAPTER ....

 A KeyAdapter is an abstract class which implements the KeyListener
 interface. The only advantage of using a KeyAdapter as opposed to a
 KeyListener is that you do only have to implement the method which is of
 interest. In other words if you are only interested in reacting to
 keyTyped() events and not keyPressed() or keyReleased() then you just
 implement keyTyped(). This is really not a big advantage- it only saves
 you 2 lines of code.

 * listen to any printable keystroke and show the combobox popupmenu
 -------------------------------------------------------
 JComboBox cb = new JComboBox(items);
 cb.addKeyListener(new MyKeyListener());
 class MyKeyListener extends KeyAdapter \{
 public void keyPressed(KeyEvent evt) \{
 JComboBox cb = (JComboBox)evt.getSource();
 char ch = evt.getKeyChar();
 // If not a printable character, do nothing
 if (ch != KeyEvent.CHAR\\_UNDEFINED) \{
 cb.showPopup();
 \}
 \}
 \}
 ,,,

KEYEVENTS ....

 KeyEvents are fired by user keystrokes and are processed
 by KeyListeners.
 
 * show a text representation of the key typed
 -------------------------------------------------------------
 public void keyTyped(KeyEvent e) \{
 String s = e.getKeyText(e.getKeyCode());
 \}
 ,,,

KEYSTROKES 

 Java has a class call javax.swing.KeyStroke that allows you to
 specify keystrokes to bind to actions (see 'keybindings').

 There are various ways to specify keystrokes, using strings in a 
 particular format or virtual key specifiers. If using strings the 
 modifier keys must be in lower case, and the key itself in upper 
 case.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents Valid ways to specify keystrokes
 .. KeyStroke.getKeyStroke("control Z") -
 .. KeyStroke.getKeyStroke("ESCAPE")
 .. KeyStroke.getKeyStroke((char)KeyEvent.VK\\_SLASH) - slash '/'
 .. KeyStroke.getKeyStroke('/')
 .. 

 see also KeyMap
 
 * specify the 'control b' keystrokes
 >> KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK\\_B, Event.CTRL\\_MASK);

 * specify shift + '-' keystroke in an InputMap
 >> inputmap.put(KeyStroke.getKeyStroke("shift MINUS"), "x.bigger.font");
 
 * specify control a
 -------------------------------------------------------------
 KeyStroke controlA = KeyStroke.getKeyStroke(
 KeyEvent.VK\\_A, InputEvent.CTRL\\_MASK); 
 ,,,

 * make the escape key put a text component into read only mode
 >> inputMap.put(KeyStroke.getKeyStroke("ESCAPE"), "set-read-only");

KEYMAPS 

 KeyMaps are older than InputMap and ActionMaps, and probably InputMaps
 are the preferred method for creating keybindings. This is because the
 Input/ActionMap system has a level of 'indirection', that is, 
 KeyStrokes are bound to a (String) key in the InputMap, which is then
 bound to the same string key in the ActionMap.

 \url{http://www.java2s.com/Code/JavaAPI/javax.swing/JTextAreagetActions.htm}
 create a custom TextAction and install it with a KeyMap

 * install a new keymap that has all the functionality of default keymap
 --------------
 JTextField field = new JTextField();
 Keymap laf = field.getKeymap();
 Keymap myMap = JTextComponent.addKeymap(null, laf);
 myMap.addActionForKeyStroke(
 getKeyStroke(VK\\_PERIOD, SHIFT\\_DOWN\\_MASK), myAction);
 field.setKeymap(myMap);
 ,,,

 * make control L select the current line using a KeyMap
 ----------------
 import javax.swing.*;
 import javax.swing.text.*;
 import java.util.Hashtable;
 import java.awt.event.*;
 import java.awt.BorderLayout;
 
 public class KeymapExample \{
 public static void main(String[] args) \{
 JTextArea area = new JTextArea(6, 32);
 Keymap parent = area.getKeymap();
 Keymap newmap = JTextComponent.addKeymap("KeymapExampleMap", parent);
 KeyStroke u = 
 KeyStroke.getKeyStroke(KeyEvent.VK\\_U, InputEvent.CTRL\\_MASK);
 Action actionU = new UpWord();
 newmap.addActionForKeyStroke(u, actionU);
 
 Action actionList[] = area.getActions();
 Hashtable lookup = new Hashtable();
 for (int j=0; j < actionList.length; j+=1)
 lookup.put(actionList[j].getValue(Action.NAME), actionList[j]);
 KeyStroke L = 
 KeyStroke.getKeyStroke(KeyEvent.VK\\_L, InputEvent.CTRL\\_MASK);
 Action actionL = 
 (Action)lookup.get(DefaultEditorKit.selectLineAction);
 newmap.addActionForKeyStroke(L, actionL);
 KeyStroke W = KeyStroke.getKeyStroke(
 KeyEvent.VK\\_W, InputEvent.CTRL\\_MASK);
 Action actionW = (Action)lookup.get(DefaultEditorKit.selectWordAction);
 newmap.addActionForKeyStroke(W, actionW);
 area.setKeymap(newmap);
 JFrame f = new JFrame("KeymapExample");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.getContentPane().add(new JScrollPane(area), BorderLayout.CENTER);
 area.setText("www.\\$\\backslash\\$n java2s \\$\\backslash\\$n .com.");
 f.pack();
 f.setVisible(true);
 \}
 public static class UpWord extends TextAction \{
 public UpWord() \{
 super("uppercase-word-action");
 \}
 
 public void actionPerformed(ActionEvent e) \{
 JTextComponent comp = getTextComponent(e);
 if (comp == null) return;
 Document doc = comp.getDocument();
 int start = comp.getSelectionStart();
 int end = comp.getSelectionEnd();
 try \{
 int left = javax.swing.text.Utilities.getWordStart(comp, start);
 int right = javax.swing.text.Utilities.getWordEnd(comp, end);
 String word = doc.getText(left, right-left);
 doc.remove(left, right-left);
 doc.insertString(left, word.toUpperCase(), null);
 comp.setSelectionStart(start); // restore previous position/selection
 comp.setSelectionEnd(end);
 \} catch (BadLocationException ble) \{
 return;
 \}
 \}
 \}
 \}
 ,,,


KEYBINDINGS

 Keybindings are a way of associating keystrokes with Actions
 via the 3 InputMaps and the ActionMap.

 Keybindings have several big advantages. Firstly the action associated
 with the keybinding can be activated (shared) by other interface
 components such a JButtons or JMenuItems. Secondly the Swing components
 already have many default Actions which the programmer may be able to
 reuse without creating a new Action. The only real difficulty is finding
 the default (String) action name, so that it can be associated with a new
 keystroke. Also the element with the keybinding does not necessarily
 have to have focus in order for the binding to work.

 Key bindings are a slightly lower level interface than Keyboard Memonics
 for triggering events. Swing components have an ActionMap and an
 InputMap which can be used to bind keystrokes to Actions.
 
 Many swing components already have keybindings established for them.
 For example the JList binds the up and down arrows to move the selected
 item up and down. The programmer can add to or modify these 
 preset bindings, if she feels that it will enhance the functionality
 of the component.

 @@ \url{http://java.sun.com/docs/books/tutorial/uiswing/misc/keybinding.html}
 The Sun tutorial on using keybindings

 @@ \url{http://tips4java.wordpress.com/2008/10/10/key-bindings/}
 An application and post by rob camick which shows keybindings


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents Get the 3 keybinding InputMaps associated with a JComponent.
 .. c.getInputMap(JComponent.WHEN\\_FOCUSED); // the default InputMap
 .. c.getInputMap(JComponent.WHEN\\_IN\\_FOCUSED\\_WINDOW);
 .. c.getInputMap(JComponent.WHEN\\_ANCESTOR\\_OF\\_FOCUSED\\_COMPONENT);
 ..

 * return the 'when focused' input map for a component
 >> c.getInputMap()

 The code below may well fail if some input keys have no 
 action defined for them. Also, it uses keys() not allKeys() so
 it only retrieves the keys defined in the current input map
 not its parents.

 * returns an html list of keystrokes and actions defined 
 -------------------------------------------------------------
 public String keyStrokeHelp() \{
 InputMap im = jtextarea.getInputMap(WHEN\\_FOCUSED);
 ActionMap am = jtextarea.getActionMap();
 StringBuilder sb = new StringBuilder();
 sb.append("<h3>keystrokes and actions</h3>");
 sb.append("<dl>");
 for (KeyStroke key: im.keys()) \{
 String actionKey = (String)im.get(key); 
 Action action = am.get(actionKey);
 sb.append(String.format("<dt>\\%s<dd>\\%s", 
 key.toString(), action.getValue(Action.SHORT\\_DESCRIPTION)));
 \}
 sb.append("</dl>");
 return sb.toString();
 \}
 ,,,

 We link together the InputMaps and the ActionMaps with a string
 key which can describe the keystroke, or describe the action (better)
 or be any old unique string.

 * make control-a select all text in a JTextField when it is focussed
 -------------------------------------------------------
 JTextField field = new JTextField("hello");
 Action action = new AbstractAction() \{
 public void actionPerformed(ActionEvent e) \{
 System.out.println("selecting all text");
 // code to select all text in the JTextField
 \}
 \};
 KeyStroke keyStroke = KeyStroke.getKeyStroke("control A");
 field.getInputMap(WHEN\\_FOCUSED).put(keyStroke, "select-all");
 field.getActionMap().put("select-all", action);
 ,,,

 * make 'control b' go back one character using a default editor action
 -----------
 InputMap inputMap = textPane.getInputMap();
 KeyStroke key = KeyStroke.getKeyStroke(KeyEvent.VK\\_B, Event.CTRL\\_MASK);
 inputMap.put(key, DefaultEditorKit.backwardAction);
 ,,,

 * replace the Action of an existing key binding
 -----------------------------------------------
 Action action = new AbstractAction() \{...\};
 KeyStroke keyStroke = KeyStroke.getKeyStroke("control Z");
 InputMap im = component.getInputMap(...);
 component.getActionMap().put(im.get(keyStroke), action);
 ,,,

 In the code below, control-z will now do whatever it is that 
 <enter> does 

 * share an Action with a different KeyStroke
 -----------------------------------------------
 InputMap im = component.getInputMap(WHEN\\_IN\\_FOCUSED\\_WINDOW);
 im.put(KeyStroke.getKeyStroke("control Z"), 
 im.get(KeyStroke.getKeyStroke("ENTER"));
 ,,,

 * remove the default key binding for up-arrow, when component is focussed
 -------------------------------------------------------------
 InputMap im = component.getInputMap(JComponent.WHEN\\_FOCUSED);
 im.put(KeyStroke.getKeyStroke("UP"), "none");
 ,,,

 To add a keybinding to a JFrame or Dialog you need to use the 
 RootPane.

 * get the ActionMap of the application RootPane
 -------------------------------------------------------------
 frame.getRootPane()
 .getInputMap(JComponent.WHEN\\_ANCESTOR\\_OF\\_FOCUSED\\_COMPONENT)...
 frame.getRootPane().getActionMap()...
 ,,,

 * add arrow key scrolling in a scrollpane with default actions
 ----------------------------------------------------------
 JScrollPane scroll = new JScrollPane(jpanel);
 JScrollBar vertical = scroll.getVerticalScrollBar();
 InputMap im = vertical.getInputMap(
 JComponent.WHEN\\_IN\\_FOCUSED\\_WINDOW);
 im.put(KeyStroke.getKeyStroke("DOWN"), "positiveUnitIncrement");
 im.put(KeyStroke.getKeyStroke("UP"), "negativeUnitIncrement");
 ,,,

 In the keystroke below the word 'shift' has to be lower case

 * bind shift-j (capital letter J) to move a page down a scrollbar
 >> im.put(KeyStroke.getKeyStroke("shift J"), "positiveBlockIncrement");

 * another way to specify the 'control A' key stroke
 -------------------------------------------------------------
 KeyStroke controlA = 
 KeyStroke.getKeyStroke(KeyEvent.VK\\_A, InputEvent.CTRL\\_MASK); 
 ,,,

 * an example of linking keystrokes to actions
 -------------------------------------------------------------
 import java.awt.event.*;
 import javax.swing.*;
 public class KeyStrokeTest \{
 public static void main(String[] args) \{
 JPanel panel = new JPanel();
 panel.getActionMap().put("hello", new AbstractAction() \{
 public void actionPerformed(ActionEvent e) \{
 System.out.println("hello keystrokes");
 \}
 \});
 // connect two keystrokes with the "hello" action:
 InputMap inputMap = panel.getInputMap();
 inputMap.put(KeyStroke.getKeyStroke("A"), "hello");
 inputMap.put(KeyStroke.getKeyStroke("control A"), "hello");
 JFrame frame = new JFrame();
 frame.getContentPane().add(panel);
 frame.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 frame.setSize(400, 400);
 frame.setVisible(true);
 \}
 \}
 ,,,

 Using a JOptionPane for this example doesnt seem to work. Maybe the
 option pane doesnt handle the events ....

DEFAULT KEYBINDINGS ....

 Swing provides many default keybinding for JComponents such as 
 JTextAreas, JLists and also the default actions to be executed.
 Modifying these defaults can save the programmer a great deal of 
 work when customizing a swing component.

 The default keybindings for swing components are usually associated
 with the WHEN\\_FOCUSED InputMap.

 @@ \url{http://tips4java.wordpress.com/2008/10/10/key-bindings/}
 An application which shows default keybindings for JComponents

GOTCHAS FOR KEYBINDINGS ....

 Some key-binding are used by the operating system (eg control-C) and
 cannot be bound to a java Action

 * no, no, no. The following probably wont work
 -------------------------------------------------------------
 ActionMap actionMap = jcomponent.getActionMap();
 InputMap inputMap = jcomponent.getInputMap(JComponent.WHEN\\_FOCUSED);
 inputMap.put(KeyStroke.getKeyStroke("control C"), "cancel-search");
 actionMap.put("cancel-search", new CancelSearchAction());
 ,,,

DEFAULT ACTIONS ....

 All the JTextComponents contain a set of useful default actions 
 which can be used to implement editing functions.

 The short description and long description fields for text component
 default actions appear to be null.

 * one way to list all default actions for a JTextComponent 
 -------------------------------------------------------------
 import javax.swing.text.JTextComponent;
 import javax.swing.Action;
 import java.util.*;
 public class TextComponentActions \{
 public static void main(String[] args) throws Exception \{
 Object o = Class.forName("javax.swing.JTextArea").newInstance();
 JTextComponent t = (JTextComponent)o;
 Action[] actions = t.getActions();
 //Arrays.sort(actions);
 for (Action a: actions) \{
 System.out.println(a.getValue(Action.NAME));
 \}
 \}
 \}
 ,,,

 * display default actions for a JTextArea in JLabels
 -------------------------------------------------------------
 import javax.swing.text.JTextComponent;
 import javax.swing.*;
 import java.awt.*;
 public class DisplayActions extends JPanel \{
 public DisplayActions() throws Exception \{
 super(new GridLayout(0, 2));
 JLabel label = new JLabel(); 
 for (Action a: new JTextArea().getActions()) \{
 label = new JLabel(a.getValue(Action.NAME).toString()); 
 label.setFont(new Font("Georgia", Font.ITALIC, 24));
 this.add(label); 
 \}
 \}
 public static void main(String[] args) throws Exception \{
 JScrollPane p = new JScrollPane(new DisplayActions());
 JFrame f = new JFrame("JTextArea Default Actions");
 f.getContentPane().add(p);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

 The following code shows all default actions which are defined 
 for a particular JComponent. As we can see from the example, lots
 of useful actions are defined for the JTextArea. The following
 does not show what keys are bound to those actions (if any).
 
 * another way to show all actions which are defined for a swing component
 -------------------------------------------------------------
 import javax.swing.*;
 import java.util.*;
 public class DefaultActions \{
 public static void main(String[] args) throws Exception \{
 Object o = Class.forName("javax.swing.JScrollBar").newInstance();
 JComponent component = (JComponent)o;
 ActionMap actionMap = component.getActionMap();
 Object[] keys = actionMap.allKeys();
 if (keys == null) \{
 System.out.println("No actions found");
 System.exit(0);
 \}
 // In some ActionMaps a key of type Object is found (why?) 
 // causing a ClassCastException when sorting. 
 // Convert these to a String
 for (int i = 0; i < keys.length; i++) \{
 if (!(keys[i] instanceof String)) keys[i] = "[?]";
 \}
 Arrays.sort(keys);
 for (Object action: keys) 
 if ((action != "") \\&\\& (action instanceof String)) 
 System.out.println(action);
 \}
 \}
 ,,,

 * get an action by (string) name from a textarea
 ---------------------
 final Action selectLine = getAction(
 textArea, DefaultEditorKit.selectLineAction);
 ...
 public static Action getAction(JTextArea textArea, String name) \{
 Action action = null;
 Action[] actions = textArea.getActions();
 for (int i = 0; i < actions.length; i++) \{
 if (name.equals(actions[i].getValue(Action.NAME).toString())) \{
 action = actions[i];
 break;
 \}
 \}
 return action;
 \}
 ,,,

 * list all actions for a jtextpane
 -----------
 import java.util.Arrays;
 import java.util.Comparator;
 import javax.swing.Action;
 import javax.swing.JTextPane;
 import javax.swing.text.JTextComponent;

 public class ListActionsJTextPane \{
 public static void main(String args[]) \{
 JTextComponent component = new JTextPane();

 // Process action list
 Action actions[] = component.getActions();
 // Define comparator to sort actions
 Comparator<Action> comparator = new Comparator<Action>() \{
 public int compare(Action a1, Action a2) \{
 String firstName = (String) a1.getValue(Action.NAME);
 String secondName = (String) a2.getValue(Action.NAME);
 return firstName.compareTo(secondName);
 \}
 \};
 Arrays.sort(actions, comparator);

 int count = actions.length;
 System.out.println("Count: " + count);
 for (int i = 0; i < count; i++) \{
 System.out.printf("\\%28s : \\%s\\$\\backslash\\$n",actions[i].getValue(Action.NAME),actions[i].getClass().getName());
 \}
 \}
 \}
 ,,,

 * explicitly fire an actionperformed method but with no event object
 >> selectLine.actionPerformed(null);

ACTIONS 

 Actions are a way of centralizing the action that is performed when
 the user interacts with a swing interface. The same action can be 
 set on several gui components. When an action is added to a 
 JComponent, the Action is added as an ActionListener for that 
 component.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents how adding an Action affects the component
 .. the Action is added as an ActionListener to the component.
 .. component configures some of its properties to match the Action.
 .. component installs PropertyChangeListener on the Action so that the component can change its properties to reflect changes in the Action's properties.
 ..

 If the same action is used on a JButton and JMenuItem, both will use the
 same 'shortcut' key combination and the short description as a tool tip.
 The text and icon will be used on both the menu item and the button. 

 Another advantage is that actions can be used in conjunction
 with keybindings, which is an easy way to modify the behavior of swing
 components. Finally actions can provide description of themselves
 allowing the developer to implement 'reflective' functionality.

 Actions are usually created by subclassing the AbstractAction class

 * create an action which exits the application
 -------------------------------------------------------------
 class ExitAction extends AbstractAction \{
 public ExitAction() \{
 putValue(Action.NAME, "Exit");
 putValue(Action.SHORT\\_DESCRIPTION, getValue(Action.NAME));
 putValue(Action.MNEMONIC\\_KEY, new Integer(KeyEvent.VK\\_X));
 \}
 public void actionPerformed(ActionEvent e) \{
 System.exit(0);
 \}
 \}
 ,,,

 * a quick way to configure a button to do something when clicked
 -------------------
 JButton button = new JButton(new AbstractAction("Close") \{
 @Override
 public void actionPerformed(ActionEvent e) \{ System.exit(0); \}
 \});
 ,,,

 * create an action class with icon, text, tooltip and alt/shortcut key.
 ------------------------
 leftAction = new LeftAction(
 "Go left", anIcon, "This is the left button.", new Integer(KeyEvent.VK\\_L));
 JButton test = new JButton(leftAction);
 class LeftAction extends AbstractAction \{
 public LeftAction(String text, ImageIcon icon,
 String desc, Integer mnemonic) \{
 super(text, icon);
 putValue(Action.SHORT\\_DESCRIPTION, desc);
 putValue(Action.MNEMONIC\\_KEY, mnemonic);
 \}
 public void actionPerformed(ActionEvent e) \{
 displayResult("Action for first button/menu item", e);
 \}
 \}
 ,,,

 In the code below, the braces \{\} with no method name is an anonymous
 constructor. This is a very odd java idiom.

 * another way to create a new Action using an anonymous class
 ----------------------
 Action colourAction = new AbstractAction() \{
 \{ putValue(Action.NAME, "Green On Black"); \}
 public void actionPerformed(ActionEvent e)
 \{ /* do something */ \}
 \};
 ,,,

 The strange curly braces without any method signature are actually a way
 to define the constructor within an anonymous inner class. How odd.

 Actions consume KeyEvents (unlike KeyListeners which may or may not
 consume them)

 jrootpane.setDefaultButton() make enter activate/click that button no
 matter where the focuss of the window is The
 actionEvent.getActionCommand() for a keybinding returns the keystroke

 * an actionlistener that listens to several JTextFields
 -----------
 ActionListener commonListener = new ActionListener() \{
 public void actionPerformed(ActionEvent e) \{
 Object o = e.getSource();
 if (o instanceof JTextField) \{
 JTextField textField = (JTextField)o;
 input[5] = textField.getText();
 textField.setVisible(true);
 \}
 \}
 \};
 ,,,

 getActionCommand() returns a string: for a JButton the text of the button
 or something specified with setActionCommand. For a JTextField, the text
 of the field

 getSource() returns a reference to an object, must be cast. All EventObjects
 have getSource method 


CUT AND PASTE

 JTextComponents have default 'cut and paste' functionality usually 
 activated with control-c and control-v or shift-insert and control-insert
 but JTextComponent dont, by default, have a right click pop up menu
 for copying or pasting text. See the JPopupMenu section for how to 
 implement this functionality.

CLIPBOARD

 The term 'clipboard' refers to a facility provided by the operating
 system to allow data to be copied by the user from one application
 to another. Usually text data is copied, but other data types are 
 usually supported, such as images. The data appears to be stored in
 a mime encoded format(?). The use of the clipboard often combines
 with 'drag-and-drop' features.

 * get text from the system clipboard (copy some text in another app)
 ------------------------------------
 import java.awt.*;
 import java.awt.datatransfer.*;
 import java.io.*;
 public class ClipboardTest
 \{
 public static void main(String[] args)
 throws UnsupportedFlavorException, IOException
 \{
 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
 Transferable t = c.getContents(null);
 if ( t.isDataFlavorSupported(DataFlavor.stringFlavor) )
 \{
 Object o = t.getTransferData(DataFlavor.stringFlavor);
 String data = (String)t.getTransferData(DataFlavor.stringFlavor);
 System.out.println("Clipboard contents: " + data);
 \}
 System.exit(0);
 \}
 \}
 ,,,

 * copy a string to the system clipboard
 -------------------------------------------------------------
 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
 StringSelection testData = new StringSelection("Clipboard testing");
 c.setContents(testData, testData);
 ,,,

 * code which copies a string to and from the system clipboard
 -------------------------------------------------------------
 import java.awt.*;
 import java.awt.datatransfer.*;
 import java.io.*;
 public class ClipboardTest \{
 public static void main(String[] args)
 throws UnsupportedFlavorException, IOException
 \{
 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
 StringSelection testData;
 // Add some test data
 if (args.length > 0)
 testData = new StringSelection(args[0]);
 else
 testData = new StringSelection("Clipboard testing- cut and paste");
 c.setContents(testData, testData);
 // Get clipboard contents, as a String
 Transferable t = c.getContents(null);
 if ( t.isDataFlavorSupported(DataFlavor.stringFlavor) )
 \{
 Object o = t.getTransferData(DataFlavor.stringFlavor);
 String data = (String)t.getTransferData(DataFlavor.stringFlavor);
 System.out.println("Clipboard contents: " + data);
 \}
 System.exit(0);
 \}
 \}
 ,,,

DRAG AND DROP

 Drag-and-Drop ('DnD' or 'dnd') refers to moving components and data
 from one area in a java application to another, or moving the 
 components from an external application into the java application or
 the reverse. This is achieved by using some kind of a 'gesture' with
 a pointing device, which means, in the usual case, clicking on
 a component, holding the left mouse button down, moving the mouse
 to the desired position and then releasing the mouse button.

 Drag-and-drop is a very powerful facility to include in a java 
 application because it mimics the way that human beings naturally
 and intuitively manipulate objects. DnD is also important because of 
 the proliferation of 'touch-screen' devices ('tablet' computers,
 'smart-phones') which are well suited to drag-and-drop functionality,
 where the human finger replaces the mouse.

 Cut and Paste is considered to be a variation of drag-and-drop 
 functionality in the java DnD system.

 \url{http://www.java2s.com/Tutorial/Java/0240\\_\\_Swing/TransferbothTextandColorbetweenJTextFieldandJTextArea.htm}
 A complete example of dragging colour as well as text. Implements
 a TransferHandler and a Transferable to contain the color (in 
 a color DataFlavor) and text (the Transferable contains an array 
 of 2 DataFlavors). This is a very good example.

 \url{http://stackoverflow.com/questions/8558876/drag-and-drop-for-a-jlabel-how-to-get-the-drag-source}
 an example of dragging a label. also how to define a new DataFlavor

 \url{http://stackoverflow.com/questions/811248/how-can-i-use-drag-and-drop-in-swing-to-get-file-path}
 an interesting question about drag and drop

 \url{http://www.java2s.com/Code/JavaAPI/java.awt.dnd/DropTargetListener.htm}
 good drag and drop examples, including an example of dragging a file
 list into a text area- this example iterates through the dataflavour
 mime types

 * enable drag and drop on various components
 -----------------------
 textArea.setDragEnabled(toggle);
 textField.setDragEnabled(toggle);
 list.setDragEnabled(toggle);
 table.setDragEnabled(toggle);
 tree.setDragEnabled(toggle);
 colorChooser.setDragEnabled(toggle);
 ,,,,

SIMPLE DRAG AND DROP ....

 Before becoming overwhelmed by the complexity of the java 
 drag-and-drop api, consider the following 2 examples:

 In the 1st example only 1 line of code "list.setDragEnabled(true);"
 is required to enable items to be dragged out of a JList 
 component.

 In the 2nd example only 9 lines of code are required to allow
 any property of a JComponent to be dragged.

 * simple DnD functionality for a JList and a JTextArea 
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 import java.awt.datatransfer.*;
 public class DefaultDragAndDrop extends JPanel \{
 JList list;
 JTextArea area;
 public DefaultDragAndDrop() \{
 super(new BorderLayout(10, 10));
 Font f = new Font("Georgia", Font.ITALIC, 20);
 this.list = new JList(new java.io.File(".").list()); 
 this.list.setFont(f); list.setDragEnabled(true);
 this.area = new JTextArea("drop here", 20, 40);
 this.area.setFont(f);
 this.add(new JScrollPane(this.list), BorderLayout.WEST);
 this.add(this.area, BorderLayout.CENTER);
 \}
 public static void main(String args[]) \{
 JFrame f = new JFrame("testing default dnd"); 
 f.add(new DefaultDragAndDrop());
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null); 
 f.setVisible(true);
 \}
 \}
 ,,,

 * drag the text of a JLabel into a JTextArea
 -------------------------------------------------------------
 import java.awt.BorderLayout;
 import java.awt.event.*;
 import javax.swing.*;
 public class DragLabel \{
 public static void main(String args[]) \{
 JFrame frame = new JFrame("Drag Label");
 frame.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 JLabel label = new JLabel("Drag the text from this JLabel");
 label.setTransferHandler(new TransferHandler("text"));
 MouseListener listener = new MouseAdapter() \{
 public void mousePressed(MouseEvent me) \{
 JComponent comp = (JComponent) me.getSource();
 TransferHandler handler = comp.getTransferHandler();
 handler.exportAsDrag(comp, me, TransferHandler.COPY);
 \}
 \};
 label.addMouseListener(listener);
 frame.add(label, BorderLayout.SOUTH);
 JTextField text = new JTextField();
 frame.add(text, BorderLayout.NORTH);
 frame.setSize(300, 150);
 frame.setVisible(true);
 \}
 \}
 ,,,


 The simplest way to use drag-and-drop in java is to make use of the
 built-in functionality of many swing components. In this case, one only
 needs to c.setDragEnabled(true) on the component, to activate its drag
 functionality. 
 
 Another simple way in to use drag-and-drop is to call the method
 c.setTransferHandler(new TransferHandler("text")). The string which is
 this case is "text" can be the name of any JComponent 'property' such as
 "icon", "border", "background" etc. This one line of code, combined with a
 MouseListener provides a lot of functionality: it allows the component (a
 JLabel for example) to drag-out and drop-in on its 'text' property (the
 text you see on the JLabel). Any property including the "icon" property of
 the JComponent can be used.

 A number of swing components have a built-in (default) drag or drop
 functionality. For example you can drag a selected row from a JTable to
 a JTextArea and the row will be copied as text into the textarea. However
 if you wish to control how the information is dragged or dropped you need
 to implement a TransferHandler class.

DRAG AND DROP OVERVIEW ....
 
 The java drag-and-drop api is quite large and can be somewhat daunting
 to the programmer. Here is an overview of the main classes, what
 they do, and what the programmer needs to implement. Drag-and-drop
 can be thought of as 2 separate areas: the data aspect and the 
 visual aspects. 
 
 When you drag a component what you are actually 
 dragging is some kind of data, an Object, a String, a Color. This data
 needs to be 'packaged' and 'exported' from the source JComponent
 and then 'unpackaged' and 'imported' to the target JComponent. 

 * TransferHandler
 This class handles the exporting of data from the source 
 JComponent and the importing of data into the target JComponent.
 The TransferHandler uses a Transferable to actually contain the 
 data, and a DataFlavor to indicate what sort of data is being
 transported. You only need to extend a TransferHandler class if you 
 wish to customise how the data is exported or imported from or 
 into a JComponent.
 * Transferable
 Actually contains the dragged data. You only need to implement a 
 Transferable if you are transporting data of a type other than
 string, image, or a list of Files.
 * DataFlavor
 Just indicates the type of data being dragged/transported (in a
 Transferable object) using a MIME type string. The DataFlavor doesnt
 contain the data being transported. A single Transferable object 
 can have one or many different DataFlavors. These different DataFlavors
 can indicate different 'packets' (objects) of data within the 
 Transferable (eg text and the text-color) or the different DataFlavors
 can just indicate a different way of accessing the same 'packet' of 
 data (eg text data provided as an InputStream, or else the same 
 text data provided in a String).

DEFAULT DRAG AND DROP BEHAVIORS ....

 Many Swing component include default drag-and-drop behaviors. For
 example JTextComponents can export (drag out) and import (drop into) text
 data. JList components can drag out list items but not (by default)
 import data. In order to enable the default drag action it is often only
 necessary to call the setDragEnable(true) method on the JComponent.

 In the example below the default drag action for a JList is used,
 and the default drop action for a JTextArea. For this reason is
 is not necessary to write a TransferHandler class. 
 
 However if we wanted to have more control over how the data is imported
 into the JTextArea, we would have to write a TransferHandler class,
 implement the canImport() and importData() methods, and install the
 handler on the JTextArea with setTransferHandler()

 * an example of default dnd actions for a JList and a JTextArea 
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 import java.awt.datatransfer.*;
 public class DefaultDragAndDrop extends JPanel \{
 JList list;
 JTextArea area;
 public DefaultDragAndDrop() \{
 super(new BorderLayout(10, 10));
 Font f = new Font("Georgia", Font.ITALIC, 20);
 this.list = new JList(new java.io.File(".").list()); 
 this.list.setFont(f); list.setDragEnabled(true);
 this.area = new JTextArea("drop here", 20, 40);
 this.area.setFont(f);
 this.add(new JScrollPane(this.list), BorderLayout.WEST);
 this.add(this.area, BorderLayout.CENTER);
 \}
 public static void main(String args[]) \{
 JFrame f = new JFrame("testing default dnd"); 
 f.add(new DefaultDragAndDrop());
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null); 
 f.setVisible(true);
 \}
 \}
 ,,,

ENABLING DRAG AND DROP ....

 * enable dragging out of (exporting data from) a JComponent
 >> jcomponent.setDragEnabled(true)

 * make dropped data replace the list item which is under the mouse cursor 
 >> jlist.setDropMode(DropMode.ON)

 * specify the handler which deals with data export/import during dnd
 >> jcomponent.setTransferHandler(transferHandler)

PROCESS OF DRAG AND DROP ....

 A drag-and-drop from a JList to a JTextArea consists of the 
 following stages:
 * drag gesture within the JList
 the user holds down the mouse button and moves the mouse,
 while optionally holding down the control or shift key.
 * JList packages data and declares what operation it supports
 eg MOVE, COPY, LINK
 TransportHandler.exportDone() method called
 * Mouse moves into target JComponent (JTextArea)
 TransportHandler.canImport(...) is called continuously while
 the mouse move over the target component.
 * Drop gesture
 The user releases the mouse button
 * The JTextField imports the data by calling the method
 TransportHandler.import(...)

TRANSFERHANDLER ....

 The javax.swing.TransferHandler class performs most of the work and logic
 with java drag-and-drop. This class is responsable for exporting and
 importing data.

 If a new TransferHandler is installed on a JComponent with
 component.setTransferHandler(...) then that new handler should
 re-implement (at least some) default drag-and-drop behaviors for the
 component, since the TransferHandler replaces the default TransferHandler
 for the JComponent.

 The TransferHandler class can either be extended to provide special
 behaviors or else used as is

 The example below shows the simplicity of icon drag and drop
 using the standard TransferHander class. With only one line of 
 code we allow icons to be dragged into and out of a JLabel.
 
 * enable both icon drag out of and icon drop into a JLabel
 >> jlabel.setTransferHandler(new TransferHandler("icon"));

 In the example below it does not seem possible to drag images
 into the labels or buttons from an external application (web-browser
 for example). Nor is it possible to drag the icon from the 
 JButton but it is possible to drop and icon into the JButton

 * drag icons from one JLabel to another JLabel or JButton 
 -------------------------------------------------------------
 import java.awt.GridLayout;
 import java.awt.event.*;
 import javax.swing.*;
 public class IconDnD \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("Icon Drag \\& Drop");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLayout(new GridLayout(0, 3));
 MouseListener listener = new DragMouseAdapter();
 String[] ss = \{
 "FileView.directoryIcon", "FileView.fileIcon",
 "FileView.computerIcon", "FileView.hardDriveIcon",
 "FileView.floppyDriveIcon", "FileChooser.newFolderIcon",
 "FileChooser.upFolderIcon", "FileChooser.homeFolderIcon",
 "FileChooser.detailsViewIcon",
 \};
 Icon icon;
 JLabel label;
 for (String s: ss) \{
 label = new JLabel(s, UIManager.getIcon(s), JLabel.CENTER);
 label.addMouseListener(listener);
 label.setTransferHandler(new TransferHandler("icon"));
 f.add(label);
 \}
 f.pack();
 f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 class DragMouseAdapter extends MouseAdapter \{
 public void mousePressed(MouseEvent e) \{
 JComponent c = (JComponent) e.getSource();
 TransferHandler handler = c.getTransferHandler();
 handler.exportAsDrag(c, e, TransferHandler.COPY);
 \}
 \}
 ,,,
 
 The example below also gives an idea of how to drag colors from
 a color chooser into a gui interface.

 * drag colors from foreground to background in JLabels, working
 -------------------------------------------------------------
 import java.awt.Color;
 import java.awt.FlowLayout;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseMotionAdapter;
 
 import javax.swing.JFrame;
 import javax.swing.JLabel;
 import javax.swing.TransferHandler;
 
 /* also try with JColorChooser component with dragEnabled=true. */
 public class ColorDrag \{
 public static void main(String args[]) \{
 final JLabel label1 = new JLabel("Drag here");
 final JLabel label2 = new JLabel("Drop here");
 label1.setTransferHandler(new TransferHandler("foreground"));
 label2.setTransferHandler(new TransferHandler("background"));
 
 // Give label1 a foreground color other than the default
 // Make label2 opaque so it displays its background color
 label1.setForeground(new Color(100, 100, 200));
 label1.setOpaque(true);
 label2.setBackground(Color.orange);
 label2.setOpaque(true);
 
 // Now look for drag gestures over label1. When one occurs,
 // tell the TransferHandler to begin a drag.
 // Exercise: modify this gesture recognition so that the drag doesn't
 // begin until the mouse has moved 4 pixels. This helps to keep
 // drags distinct from sloppy clicks. To do this, you'll need both
 // a MouseListener and a MouseMotionListener.
 label1.addMouseMotionListener(new MouseMotionAdapter() \{
 public void mouseDragged(MouseEvent e) \{
 // should use e.getSource()
 TransferHandler handler = label1.getTransferHandler();
 handler.exportAsDrag(label1, e, TransferHandler.COPY);
 \}
 \});
 // Create a window, add the labels, and make it all visible.
 JFrame f = new JFrame("ColorDrag");
 f.setLayout(new FlowLayout());
 f.add(label1); f.add(label2); f.pack(); f.setVisible(true);
 \}
 \}
 ,,,

 The example below doesnt work because the default TransferHandler
 for a JTextArea cannot import images or icons
 
 * drag a property of a JLabel into a JTextArea, 
 -------------------------------------------------------------
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 public class DragLabel \{
 public static void main(String args[]) \{
 JFrame frame = new JFrame("Drag Label");
 frame.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 JLabel label = new JLabel("Hello, World");
 label.setTransferHandler(new TransferHandler("icon"));
 //label.setForeground(Color.orange);
 label.setIcon(UIManager.getIcon("OptionPane.informationIcon"));
 MouseListener listener = new MouseAdapter() \{
 public void mousePressed(MouseEvent me) \{
 JComponent comp = (JComponent) me.getSource();
 TransferHandler handler = comp.getTransferHandler();
 handler.exportAsDrag(comp, me, TransferHandler.COPY);
 \}
 \};
 label.addMouseListener(listener);
 frame.add(label, BorderLayout.SOUTH);
 JTextPane text = new JTextPane();
 frame.add(text, BorderLayout.NORTH);
 frame.setSize(300, 150);
 frame.setVisible(true);
 \}
 \}
 ,,,

EXPORT METHODS FOR TRANSPORTHANDLER ....

 * getSourceActions(jcomponent)
 This method declares what dnd actions the source JComponent 
 supports- eg MOVE, COPY, LINK. The value returned is a 'or' bit
 combination
 * createTransferable(jcomponent)
 bundles the data to be exported into a Transferable object
 * exportDone(jcomponent, transferable, int action)
 This method is called after the data is exported. This method
 is where changed to the source component are made. For example
 in a MOVE drag operation, the dragged item would be deleted from
 the JList in this method.
 
 * an example of export methods for a TransferHandler
 -------------------------------------------------------------
 int getSourceActions(JComponent c) \{ return COPY\\_OR\\_MOVE; \}

 Transferable createTransferable(JComponent c) \{
 return new StringSelection(c.getSelection());
 \}

 void exportDone(JComponent c, Transferable t, int action) \{
 if (action == MOVE) \{ c.removeSelection(); \}
 \}
 ,,,

IMPORT METHODS FOR TRANSPORTHANDLER ....

 2 methods need to be implemented within the TransportHandler 
 class in order to support the dropping or importing of data into
 a JComponent

 * canImport(TransferHandler.TransferSupport)
 this method is called repeatedly (since java 1.6) as the mouse
 cursor hovers over the target component. If the area under the 
 cursor can accept the drop (or paste) action then the method
 returns true, otherwise false. Using this method, some areas 
 of a component can accept a drop, and other areas reject it.
 * importData(TransferHandler.TransferSupport)
 This method actually imports the data into the target component.

 * example data import methods for a TransferHandler implementation
 -------------------------------------------------------------
 public boolean acceptLocation(DropLocation dl) \{ ... \}
 public void insertAt(DropLocation dl, String data) \{ ... \}
 public boolean canImport(TransferSupport ts) \{
 if (!ts.isDataFlavorSupported(stringFlavor)) \{ return false; \}
 DropLocation loc = ts.getDropLocation();
 return acceptLocation(loc);
 \}
 
 public boolean importData(TransferSupport ts) \{
 if (!this.canImport(ts)) \{ return false; \}
 Transferable t = ts.getTransferable();
 String data = t.getTransferData(stringFlavor);
 DropLocation loc = supp.getDropLocation();
 this.insertAt(loc, data);
 return true;
 \}
 ,,,

 * a complete TransferHandler for importing string data into a JList
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 import java.awt.datatransfer.*;
 /* 
 enable drop on the JList with the following 1 or 2 lines
 jlist.setTransferHandler(new ListTransferHandler());
 jlist.setDropMode(DropMode.ON\\_OR\\_INSERT); // optional
 */
 public class ListTransferHandler extends TransferHandler \{
 public boolean canImport(TransferHandler.TransferSupport ts) \{
 if (!ts.isDataFlavorSupported(DataFlavor.stringFlavor)) \{
 return false;
 \}
 return true;
 \}
 public boolean importData(TransferHandler.TransferSupport ts) \{
 if (!ts.isDrop()) \{ return false; \}
 JList list = (JList)ts.getComponent();
 DefaultListModel listModel = (DefaultListModel)list.getModel();
 JList.DropLocation dl = (JList.DropLocation)info.getDropLocation();
 int index = dl.getIndex();
 //boolean insert = dl.isInsert();
 Transferable t = info.getTransferable();
 String data;
 try \{
 data = (String)t.getTransferData(DataFlavor.stringFlavor);
 \}
 catch (Exception e) \{ return false; \}
 if (insert) \{
 listModel.add(index, data);
 \} else \{
 listModel.set(index, data);
 \}
 return true;
 \}
 \}
 ,,,

TRANSFERABLE ....

 The Transferable class is the class which actually contains the data
 (text, an image, a color) which is being dragged and dropped. When you
 want to retrieve the data from the Transferable you call
 tranferable.getTransferData(DataFlavor.stringFlavor); The
 getTransferData() method takes a DataFlavor parameter. This parameter
 specifies the type of data you would like to get from the transferable
 (if data of that type is available). Transferable objects may contain
 many packets of data (for example, a string of text, the color of 
 that text, and the font of the text). The DataFlavor specifies which
 packet (object) of data you would like to retrieve from the 
 Transferable.

 If you would like to drag or drop a data type for which there is 
 no pre-defined DataFlavor then you can implement a Tranferable 
 along with a TransferHandler. The example below demonstrates this.

 The example is very complete and demonstrates all the processes
 of implementing a Transferable and a TransferHandler

 * how to implement a transferable to transfer a Color and a String
 -------------------------------------------------------------
 import java.awt.Color;
 import java.awt.datatransfer.*;
 import java.io.IOException;
 import java.util.Arrays;
 
 import javax.swing.*;
 import javax.swing.text.JTextComponent;
 
 public class TransferableDragAndDrop \{
 public static void main(String[] args) \{
 JFrame frame = new JFrame();
 frame.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 frame.setContentPane(new JPanel());
 
 JTextField textField = new JTextField(25);
 textField.setText("Let's swing higher");
 frame.add(textField);
 
 JTextArea textArea = new JTextArea("Demonstrating\\$\\backslash\\$ndrag and drop");
 textArea.setForeground(Color.red);
 frame.add(new JScrollPane(textArea));
 
 textArea.setDragEnabled(true);
 textField.setDragEnabled(true);
 TextColorTransferHandler transferHandler = 
 new TextColorTransferHandler();
 textArea.setTransferHandler(transferHandler);
 textField.setTransferHandler(transferHandler);
 frame.pack(); frame.setVisible(true);
 \}
 \}
 
 class TextColorTransferHandler extends TransferHandler \{
 public int getSourceActions(JComponent c) \{ return COPY\\_OR\\_MOVE; \}
 protected Transferable createTransferable(JComponent component) \{
 String text = ((JTextComponent) component).getText();
 Color color = component.getForeground();
 TextColor transferable = new TextColor(text, color);
 return transferable;
 \}
 public boolean canImport(JComponent c, DataFlavor[] flavors) \{
 return true;
 \}
 public boolean importData(JComponent co, Transferable tf) \{
 String colorMimeType = 
 DataFlavor.javaJVMLocalObjectMimeType + ";class=java.awt.Color";
 JTextComponent textComponent = (JTextComponent) co;
 try \{
 DataFlavor colorFlavor = new DataFlavor(colorMimeType);
 Color color = (Color) tf.getTransferData(colorFlavor);
 String text = 
 (String) tf.getTransferData(DataFlavor.stringFlavor);
 textComponent.setForeground(color);
 textComponent.setText(text);
 \}
 catch (ClassNotFoundException e) \{ e.printStackTrace(); \}
 catch (IOException e) \{ e.printStackTrace(); \}
 catch (UnsupportedFlavorException e) \{ e.printStackTrace(); \}
 return true;
 \}
 \}
 
 class TextColor implements Transferable \{
 private String text;
 private Color color;
 private DataFlavor[] flavors;
 
 public TextColor(String text, Color color) \{
 String colorMimeType = 
 DataFlavor.javaJVMLocalObjectMimeType + ";class=java.awt.Color";
 DataFlavor colorFlavor = null;
 try \{
 colorFlavor = new DataFlavor(colorMimeType);
 \} catch (ClassNotFoundException e) \{\}
 this.flavors = 
 new DataFlavor[]\{DataFlavor.stringFlavor, colorFlavor\};
 this.text = text; this.color = color;
 \}
 public DataFlavor[] getTransferDataFlavors() \{
 return (DataFlavor[]) flavors.clone();
 \}
 public boolean isDataFlavorSupported(DataFlavor flavor) \{
 // another way
 // return Arrays.asList(this.flavors).contains(flavor);
 for (DataFlavor f: this.flavors) 
 \{ if (flavor.equals(f)) return true; \}
 return false;
 \}
 
 public Object getTransferData(DataFlavor flavor) 
 throws UnsupportedFlavorException, IOException \{
 if (flavor.equals(flavors[0])) \{
 return text;
 \} else if (flavor.equals(flavors[1])) \{
 return color;
 \} else \{
 throw new UnsupportedFlavorException(flavor);
 \}
 \}
 \}
 ,,,

TRANSPORTSUPPORT INNER CLASS ....

 The TransferHandler.TransportSupport class (since java 1.6) provides
 information about the transfer (drag-and-drop) currently underway.
 

\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents some methods
 * getComponent() 
 returns the target component of the transfer
 * isDrop() 
 returns if this is a drop (dnd) or a paste action
 * getDataFlavors() 
 gets all available DataFlavors. This seems to be a list of DataFlavors
 supported by the source component. For example, if you drag an
 image from a web-page, you can import that component into your
 application as html text or as image data (java.awt.Data).
 * isDataFlavorSupport(DataFlavor.stringFlavor)
 determines if the target compenent of the drop or paste action
 supports importing data of the text or string type.
 ..
 
EXPORTING OR DRAGGING DATA ....

 * a complete TransferHandler implementation for exporting data
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 import java.awt.datatransfer.*;
 public class ListTransferHandler extends TransferHandler \{
 private int[] indices = null;
 private int addIndex = -1; //Location where items were added
 private int addCount = 0; //Number of items added.
 public boolean canImport(TransferHandler.TransferSupport info) \{
 // Check for String flavor
 if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) \{
 return false;
 \}
 return true;
 \}
 protected Transferable createTransferable(JComponent c) \{
 return new StringSelection(exportString(c));
 \}
 public int getSourceActions(JComponent c) \{
 return TransferHandler.COPY\\_OR\\_MOVE;
 \}

 protected void exportDone(
 JComponent c, Transferable data, int action) \{
 cleanup(c, action == TransferHandler.MOVE);
 \}

 //Bundle up the selected items in the list as a string, for export.
 protected String exportString(JComponent c) \{
 JList list = (JList)c;
 indices = list.getSelectedIndices();
 Object[] values = list.getSelectedValues();
 StringBuffer buff = new StringBuffer();
 for (int i = 0; i < values.length; i++) \{
 Object val = values[i];
 buff.append(val == null ? "" : val.toString());
 if (i != values.length - 1) \{
 buff.append("\\$\\backslash\\$n");
 \}
 \}
 return buff.toString();
 \}
 
 //If the remove argument is true, the drop has been
 //successful and it's time to remove the selected items
 //from the list. If the remove argument is false, it
 //was a Copy operation and the original list is left
 //intact.
 protected void cleanup(JComponent c, boolean remove) \{
 if (remove \\&\\& indices != null) \{
 JList source = (JList)c;
 DefaultListModel model = (DefaultListModel)source.getModel();
 //If we are moving items around in the same list, we
 //need to adjust the indices accordingly, since those
 //after the insertion point have moved.
 if (addCount > 0) \{
 for (int i = 0; i < indices.length; i++) \{
 if (indices[i] > addIndex) \{
 indices[i] += addCount;
 \}
 \}
 \}
 for (int i = indices.length - 1; i >= 0; i--) \{
 model.remove(indices[i]);
 \}
 \}
 indices = null;
 addCount = 0;
 addIndex = -1;
 \}
 \}
 ,,,

DROPPING OR IMPORTING DATA ....

 * a simple location sensitive drop implementation
 -------------------------------------------------------------
 public boolean acceptLocation(DropLocation dl) \{ ... \}
 public boolean canImport(TransferSupport ts) \{
 if (!ts.isDataFlavorSupported(stringFlavor)) \{ return false; \}
 DropLocation loc = ts.getDropLocation();
 return acceptLocation(loc);
 \}
 ,,,

 * import on text data via (drag and) drop, not via (cut and) paste
 -------------------------------------------------------------
 public boolean canImport(TransferHandler.TransferSupport info) \{
 if (!ts.isDrop()) return false;
 if (!ts.isDataFlavorSupported(DataFlavor.stringFlavor)) return false; 
 return true;
 \}
 ,,,

 In the example below you can drag text into the JList from outside the
 java application or also from another component in the application. The
 text will either replace a list item or else insert a new item depending
 on where the mouse cursor is when the button is released (dropped).

 * a complete example for importing string data into a JList
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 import java.awt.datatransfer.*;
 public class DropList extends JPanel \{
 JList list;
 public DropList() \{
 super(new BorderLayout());
 DefaultListModel model = new DefaultListModel();
 for (String s: new java.io.File(".").list()) model.addElement(s);
 this.list = new JList(model);
 this.list.setFont(new Font("Georgia", Font.ITALIC, 20));
 list.setTransferHandler(new ListTransferHandler());
 list.setDropMode(DropMode.ON\\_OR\\_INSERT);
 this.add(new JScrollPane(this.list));
 \}
 public static void main(String args[]) \{
 JFrame f = new JFrame(); f.add(new DropList());
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null); 
 f.setVisible(true);
 \}
 \}
 class ListTransferHandler extends TransferHandler \{
 public boolean canImport(TransferHandler.TransferSupport ts) \{
 if (!ts.isDataFlavorSupported(DataFlavor.stringFlavor)) \{
 return false;
 \}
 return true;
 \}
 public boolean importData(TransferHandler.TransferSupport ts) \{
 if (!ts.isDrop()) \{ return false; \}
 JList list = (JList)ts.getComponent();
 DefaultListModel listModel = (DefaultListModel)list.getModel();
 JList.DropLocation dl = (JList.DropLocation)ts.getDropLocation();
 int index = dl.getIndex();
 boolean insert = dl.isInsert();
 Transferable t = ts.getTransferable();
 String data;
 try \{
 data = (String)t.getTransferData(DataFlavor.stringFlavor);
 \}
 catch (Exception e) \{ return false; \}
 if (insert) \{
 listModel.add(index, data);
 \} else \{
 listModel.set(index, data);
 \}
 return true;
 \}
 \}
 ,,,

 hooray the example below is importing image data into textarea.
 It works from an image in chrome but not from the EyeOfGnome image
 viewer, strangely. The getTransferDataFlavors and getDataFlavors
 seem to return the same thing

 * a text area which displays information when something is dropped 
 -------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.text.*;
 import java.awt.*;
 import java.awt.datatransfer.*;
 public class FlavorArea extends JPanel \{
 JTextArea area;
 public FlavorArea() \{
 super(new BorderLayout());
 this.area = new JTextArea("drop something here\\$\\backslash\\$n", 20, 30);
 this.area.setFont(new Font("Georgia", Font.ITALIC, 20));
 this.area.setTransferHandler(new AreaTransferHandler());
 this.add(new JScrollPane(this.area));
 \}
 public static void main(String args[]) \{
 JFrame f = new JFrame(); f.add(new FlavorArea());
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null); 
 f.setVisible(true);
 \}
 \}
 class AreaTransferHandler extends TransferHandler \{
 public boolean canImport(TransferHandler.TransferSupport ts) \{
 /*
 if (!ts.isDataFlavorSupported(DataFlavor.imageFlavor)) \{
 return false;
 \}
 */
 return true;
 \}
 public boolean importData(TransferHandler.TransferSupport ts) \{
 //if (!ts.isDrop()) \{ return false; \}
 int index = -1;
 JTextArea area = (JTextArea)ts.getComponent();
 if (ts.isDrop()) \{
 JTextComponent.DropLocation dl = 
 (JTextComponent.DropLocation)ts.getDropLocation();
 index = dl.getIndex();
 \}
 Transferable t = ts.getTransferable();
 String data = "-";
 Image i; 
 try \{
 //data = (String)t.getTransferData(DataFlavor.stringFlavor);
 /*
 i = (Image)t.getTransferData(DataFlavor.imageFlavor);
 JLabel imageLabel = new JLabel(new ImageIcon(i));

 JOptionPane.showMessageDialog(null, imageLabel);
 */
 //JOptionPane.showMessageDialog(null, 
 // "image width:" + i.getWidth(null) + " height:" + i.getHeight(null));
 \}
 catch (Exception e) \{ 
 e.printStackTrace();
 //return false; 
 \}
 
 /*
 area.append("TransferDataFlavors: \\$\\backslash\\$n");
 for (DataFlavor df: t.getTransferDataFlavors()) \{
 area.append(df.toString() + "\\$\\backslash\\$n");
 \}
 */
 StringBuilder sb = new StringBuilder();
 sb.append("DataFlavors: \\$\\backslash\\$n");
 for (DataFlavor df: ts.getDataFlavors()) \{
 sb.append(df.toString() + "\\$\\backslash\\$n");
 if (df.isFlavorJavaFileListType()) 
 sb.append(" javaFileListFlavor\\$\\backslash\\$n");
 if (df.isFlavorTextType()) sb.append(" stringFlavor\\$\\backslash\\$n");
 \}
 String info = String.format(
 "DropLocation.getIndex():\\%d \\$\\backslash\\$nisDrop():\\%s \\$\\backslash\\$ndata:\\%s \\$\\backslash\\$n", 
 index, ts.isDrop(), data);
 sb.append(info);
 area.setText(sb.toString());
 return true;
 \}
 \}
 ,,,

IMAGE DRAG AND DROP ....

 When dragging an image from a webbrowser, for example, DataFlavor
 will probably be imageFlavor (mime type 'image') but when dragging
 from an image viewer, the DataFlavor may well be javaFileListFlavor

 The TransferHandler class supports by default, supports importing
 IconImages into JLabels and JButtons, so this makes drag and drop
 very easy to implement. We just call 
 >> jlabel.setTransferHandler(new TransferHandler("icon"));

 The example below is incomplete.

 * a JLabel which displays information when something is dropped 
 -------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.text.*;
 import java.awt.*;
 import java.awt.datatransfer.*;
 public class ImageDrop extends JPanel \{
 JTextArea area;
 JLabel label;
 public ImageDrop() \{
 super(new BorderLayout());
 this.area = new JTextArea("drop something here\\$\\backslash\\$n", 20, 30);
 this.area.setFont(new Font("Georgia", Font.ITALIC, 20));
 this.area.setTransferHandler(new ImageTransferHandler());
 this.label = new JLabel();
 this.add(new JScrollPane(this.area));
 \}
 public static void main(String args[]) \{
 JFrame f = new JFrame(); f.add(new ImageDrop());
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null); 
 f.setVisible(true);
 \}
 \}
 class ImageTransferHandler extends TransferHandler \{
 public boolean canImport(TransferHandler.TransferSupport ts) \{
 if (!ts.isDataFlavorSupported(DataFlavor.imageFlavor)) \{
 return false;
 \}
 return true;
 \}
 public boolean importData(TransferHandler.TransferSupport ts) \{
 if (!ts.isDrop()) \{ return false; \}
 int index = -1;
 JTextArea area = (JTextArea)ts.getComponent();
 TransferHandler.DropLocation dl = 
 (TransferHandler.DropLocation)ts.getDropLocation();
 Transferable t = ts.getTransferable();
 String data = "-";
 Image i; 
 try \{
 //data = (String)t.getTransferData(DataFlavor.stringFlavor);
 i = (Image)t.getTransferData(DataFlavor.imageFlavor);
 JLabel imageLabel = new JLabel(new ImageIcon(i));
 JOptionPane.showMessageDialog(null, imageLabel);
 \}
 catch (Exception e) \{ 
 e.printStackTrace();
 //return false; 
 \}
 
 StringBuilder sb = new StringBuilder();
 sb.append("DataFlavors: \\$\\backslash\\$n");
 for (DataFlavor df: ts.getDataFlavors()) \{
 sb.append(df.getMimeType() + "\\$\\backslash\\$n");
 if (df.isFlavorJavaFileListType()) 
 sb.append(" javaFileListFlavor\\$\\backslash\\$n");
 if (df.isFlavorTextType()) sb.append(" stringFlavor\\$\\backslash\\$n");
 \}
 String info = String.format(
 "DropPoint:\\%s \\$\\backslash\\$nisDrop():\\%s \\$\\backslash\\$ndata:\\%s \\$\\backslash\\$n", 
 dl.getDropPoint().toString(), ts.isDrop(), data);
 sb.append(info);
 area.setText(sb.toString());
 return true;
 \}
 \}
 ,,,

JLIST DRAG AND DROP ....

 The JList component support export (drag out) by default but not
 import (drop in).

 JList.DropLocation
 This class converts the pixel location of the drop location into
 JList item indexes which are much more convenient. Also this class
 can determine whether the location is an 'insert' location or a
 replace location.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents JList.DropLocation methods
 .. getIndex() - returns the list item index of the drop location
 .. isInsert() - returns if the location is an insert location or not
 ..

 The setDropMode() method is defined for the JList, JTable, and JTree
 components but the semantics and DropModes for each component are 
 slightly different.


 * replace or insert dropped (or pasted?) items into a JList 
 >> list.setDropMode(DropMode.ON\\_OR\\_INSERT);


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents JList setDropMode() modes (since java 1.6)
 DropMode.USE\\_SELECTION
 The dropped data replaces the item under the mouse cursor.
 The currently selected item of the JList is set to the item just
 replaced. This is the default but is apparently not recommended- 
 and is only included for backwards compatibility.
 DropMode.ON
 The dropped data replaces the item under the mouse cursor.
 The current selected item is not changed
 DropMode.INSERT
 The dropped data is inserted between the items closest to the 
 mouse cursor. The selected item is unchanged. It is not possible
 to replace JList items with this DropMode
 DropMode.ON\\_OR\\_INSERT
 The dropped data either replaces the item under the mouse cursor
 or is inserted between the closest items, depending on the 
 position of the mouse cursor.

 * a complete TransferHandler inserting data into a JList component
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 import java.awt.datatransfer.*;
 public class ListTransferHandler extends TransferHandler \{
 public boolean canImport(TransferHandler.TransferSupport ts) \{
 if (!ts.isDataFlavorSupported(DataFlavor.stringFlavor)) \{
 return false;
 \}
 return true;
 \}
 public boolean importData(TransferHandler.TransferSupport ts) \{
 if (!ts.isDrop()) \{ return false; \}
 JList list = (JList)ts.getComponent();
 DefaultListModel listModel = (DefaultListModel)list.getModel();
 JList.DropLocation dl = (JList.DropLocation)info.getDropLocation();
 int index = dl.getIndex();
 boolean insert = dl.isInsert();
 Transferable t = info.getTransferable();
 String data;
 try \{
 data = (String)t.getTransferData(DataFlavor.stringFlavor);
 \}
 catch (Exception e) \{ return false; \}

 if (insert) \{ listModel.add(index, data); \} 
 else \{ listModel.set(index, data); \}
 return true;
 \}
 \}
 ,,,

 In the following example it is possible to drag a listbox item ontop of
 another (thereby replacing it) or drag it between two listbox items,
 inserting a new item (with the same text as the dragged item). It is also
 possible to drag a multiple selection. The several items get concatenated
 as a string and become the new element. This is not very useful but
 demonstrates what can be done within the createTransferable() method. 

 * A JList box which can drag and drop items onto itself 
 --------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 import java.awt.datatransfer.*;
 public class DragBox \{
 public static void main(String[] args) \{
 JFrame t = new JFrame();
 DefaultListModel listModel = new DefaultListModel();
 for (String s: new String[]\{"Acacia", "Yew", "Oak", "Gum"\})
 listModel.addElement(s);
 final JList list = new JList(listModel);
 list.setFont(new Font("Georgia", Font.PLAIN, 30));
 list.setTransferHandler(new TransferHandler() \{
 public boolean canImport(TransferHandler.TransferSupport info) \{
 if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) \{
 return false;
 \}
 JList.DropLocation dl = 
 (JList.DropLocation)info.getDropLocation();
 if (dl.getIndex() == -1) \{ return false; \}
 return true;
 \}
 public boolean importData(TransferHandler.TransferSupport info) \{
 if (!info.isDrop()) \{ return false; \}
 if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) \{
 JOptionPane.showMessageDialog(null, 
 "List doesn't accept a drop of this type.");
 return false;
 \}

 JList.DropLocation dl = 
 (JList.DropLocation)info.getDropLocation();
 DefaultListModel listModel = (DefaultListModel)list.getModel();
 // Get the string that is being dropped.
 Transferable t = info.getTransferable();
 String data;
 try \{ data = (String)t.getTransferData(DataFlavor.stringFlavor); \} 
 catch (Exception e) \{ return false; \}
 if (dl.isInsert()) \{
 System.out.println("'" + data + "' inserted at index " + dl.getIndex());
 \} else \{
 System.out.println("'" + data + "' replacing index " + dl.getIndex());
 \}
 if (dl.isInsert()) \{ listModel.add(dl.getIndex(), data); \} 
 else \{ listModel.set(dl.getIndex(), data); \}
 return true;
 \}
 
 public int getSourceActions(JComponent c) \{ return COPY; \}
 protected Transferable createTransferable(JComponent c) \{
 JList list = (JList)c;
 Object[] values = list.getSelectedValues();
 StringBuffer buff = new StringBuffer();
 for (int i = 0; i < values.length; i++) \{
 Object val = values[i];
 buff.append(val == null ? "" : val.toString());
 if (i != values.length - 1) \{ buff.append("\\$\\backslash\\$n"); \}
 \}
 return new StringSelection(buff.toString());
 \}
 \});
 list.setDropMode(DropMode.ON\\_OR\\_INSERT);
 list.setDragEnabled(true);
 JPanel p = new JPanel(); p.add(list);
 t.getContentPane().add(p);
 t.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 t.pack(); t.setLocationRelativeTo(null);
 t.setVisible(true);
 \}
 \}
 ,,,

JTREE DRAG AND DROP ....

 The JTree uses the some DropModes as the JList component


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents JTree.DropLocation methods
 .. getChildIndex()
 .. getPath()
 
JTABLE DRAG AND DROP ....

 The JTable as several additional DropModes for inserting rows
 and columns.

JTEXTCOMPONENT DRAG AND DROP ....


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents JTextComponent.DropLocation methods
 .. getIndex() - returns the document (model) index of the drop location
 .. getBias() - ?
 ..
 
 In the example below, if the user tries to paste text into the text
 component (say a JTextArea, or a JTextField) then an
 IllegalStateException will be thrown by the getDropLocation() method.
 This is because there is no 'drop location' for a (cut and) paste
 operation- you just check the position of the document caret and paste
 the data there (or any where else you like)

 * get the drop location for a text component.
 -------------------------------------------------------------
 JTextComponent.DropLocation dl = 
 (JTextComponent.DropLocation)ts.getDropLocation();
 ,,,

DATAFLAVORS ....

 The DataFlavor is the class which specifies the type of data which is
 contained in the Transferable object. The DataFlavor does not actually
 contain the data. The Transferable object is the object which 
 contains the data which is being dragged (an image, text, a color etc).
 The DataFlavor class uses a MIME type string to specify the type of data.

 rfc2045 and rfc2046 are the technical specification of MIME (or content)
 types. The java DnD implementation interprets the paramater of the 
 mime type string as the class returned by Transferable.getTransferData()


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents MIME types
 imageFlavor - "image/x-java-image;class=java.awt.Image"
 media (primary) type: image
 subtype: x-java-image
 parameter (representation class): java.awt.Image
 stringFlavor - 
 javaFileListFlavor - 
 .. 
 

\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents DataFlavor important methods
 .. selectBestTextFlavor() - 
 .. getMimeType()
 ..


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents some predefined DataFlavors
 .. DataFlavor.stringFlavor - for text data
 .. DataFlavor.imageFlavor - a mime type for java.awt.Image 
 .. DataFlavor.javaFileListFlavor - a java.util.List of File objects
 ..

 If you want to transfer a type of data for which there is no predefined
 DataFlavor (stringFlavor, imageFlavor etc), then you instantiate a new
 DataFlavor using the technique in the example below. This dataflavor
 will only function for drag-and-drop or cut-and-paste within the java
 application, not to or from external applications. The new DataFlavor
 object is then placed in a Transferable. See the Transferable section for
 a complete example of dragging and dropping a Color data type.

 * create a new DataFlavor for dragging and dropping Color objects 
 -------------------------------------------------------------
 String colorMimeType = 
 DataFlavor.javaJVMLocalObjectMimeType + ";class=java.awt.Color";
 DataFlavor colorFlavor = null;
 try \{
 colorFlavor = new DataFlavor(colorMimeType);
 \} catch (ClassNotFoundException e) \{ \}
 ,,,

 In the example below the DataFlavor constructor can throw a 
 ClassNotFoundException because it checks that the 'class=' parameter
 classname exists or not.

 * create a new image DataFlavor using a mime type string
 -------------------------------------------------------------
 String mimeType = "image/x-java-image;class=java.awt.Image";
 DataFlavor flavor = null
 try \{ flavor = new DataFlavor(mimeType); \} 
 catch (ClassNotFoundException e) \{\}
 ,,,

IMPORT FILE LIST ....

 Doesnt seem to be working

 * drag a file list into application
 -------------------------------------------------------------
 import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.datatransfer.DataFlavor;
 import java.awt.datatransfer.Transferable;
 import java.awt.dnd.*;
 import javax.swing.*;
 
 public class DropTest extends JFrame implements DropTargetListener \{
 
 DropTarget dt;
 JTextArea ta = new JTextArea();
 public DropTest() \{
 super("Drop Test");
 setSize(300, 300);
 setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 add(new JLabel("Drop a list from your file chooser here:"), BorderLayout.NORTH);
 ta.setBackground(Color.white);
 getContentPane().add(ta, BorderLayout.CENTER);
 
 dt = new DropTarget(ta, this);
 setVisible(true);
 \}
 
 public void dragEnter(DropTargetDragEvent dtde) \{
 System.out.println("Drag Enter");
 \}
 
 public void dragExit(DropTargetEvent dte) \{
 System.out.println("Source: " + dte.getSource());
 System.out.println("Drag Exit");
 \}
 
 public void dragOver(DropTargetDragEvent dtde) \{
 System.out.println("Drag Over");
 \}
 
 public void dropActionChanged(DropTargetDragEvent dtde) \{
 System.out.println("Drop Action Changed");
 \}
 
 public void drop(DropTargetDropEvent dtde) \{
 try \{
 Transferable tr = dtde.getTransferable();
 DataFlavor[] flavors = tr.getTransferDataFlavors();
 for (int i = 0; i < flavors.length; i++) \{
 System.out.println("Possible flavor: " + flavors[i].getMimeType());
 if (flavors[i].isFlavorJavaFileListType()) \{
 dtde.acceptDrop(DnDConstants.ACTION\\_COPY);
 ta.setText("Successful file list drop.\\$\\backslash\\$n\\$\\backslash\\$n");
 java.util.List list = 
 (java.util.List) tr.getTransferData(flavors[i]);
 for (int j = 0; j < list.size(); j++) \{
 ta.append(list.get(j) + "\\$\\backslash\\$n");
 \}
 dtde.dropComplete(true);
 return;
 \}
 \}
 System.out.println("Drop failed: " + dtde);
 dtde.rejectDrop();
 \} catch (Exception e) \{
 e.printStackTrace();
 dtde.rejectDrop();
 \}
 \}
 
 public static void main(String args[]) \{
 new DropTest();
 \}
 \}
 ,,,


LOOK AND FEEL

 The "look and feel" of a windowed application refers to the 
 general style of the graphics used to display the application and
 the way that buttons change when they are clicked with the mouse
 Generally each look and feel may correspond to the visual style of an
 operating system. The default look and feel for java is not particularly
 attractive, which is why we want to change it.

 \url{http://weblogs.java.net/blog/ljnelson/archive/2007/12/useful\\_swing\\_th.html}
 an interesting article about look and feel and how to get escape
 to cancel a window.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents commonly installed look and feel classes
 .. Metal, javax.swing.plaf.metal.MetalLookAndFeel
 .. Nimbus, javax.swing.plaf.nimbus.NimbusLookAndFeel
 .. CDE/Motif, com.sun.java.swing.plaf.motif.MotifLookAndFeel
 .. Windows, com.sun.java.swing.plaf.windows.WindowsLookAndFeel
 .. Windows Classic, com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel
 ..

 The Windows classic is basically Windows 95 style components,
 Windows looks a lot better, Motif is an old X windows style, Metal
 is the default java style quite ugly, and Nimbus is the Apple osx
 style and therefor quite pretty.

 * The className is used with UIManager.setLookAndFeel()
 >> String className = info[i].getClassName();

 * print out the names and classnames of available look and feels 
 ------------------------------------------
 import javax.swing.UIManager;
 public class LookAndFeel 
 \{
 public static void main(String[] args) throws Exception
 \{
 UIManager.LookAndFeelInfo[] info = UIManager.getInstalledLookAndFeels();
 for (int i = 0; i < info.length; i++)
 \{
 System.out.println("L \\& F name:" + info[i].getName());
 System.out.println("L \\& F classname:" + info[i].getClassName());
 \}
 \}
 \}
 ,,,

 * print the name of the native look and feel 
 ------------------------------------------
 import javax.swing.UIManager;
 public class LookAndFeel \{
 public static void main(String[] args) throws Exception
 \{
 System.out.println("Native look and feel: " + 
 UIManager.getSystemLookAndFeelClassName());
 \}
 \}
 ,,,

 * display a file chooser with the native operating system look and feel 
 ------------------------------------------------
 import javax.swing.*;
 public class NiceFileDialog \{
 public static void main(String[] args) throws Exception \{
 UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
 JFrame f = new JFrame("Trying to make the FileChooser look nicer");
 JFileChooser c = new JFileChooser();
 if (c.showOpenDialog(f) == JFileChooser.CANCEL\\_OPTION)
 System.exit(-1);
 \}
 \}
 ,,, 
 
 The result on a windows computer of using the system look and feel is much
 more aesthetically pleasing. Nimbus has a nice rounded corners but the colours
 are very cold and the fonts dont seem very good.

 * display a file chooser with the nimbus look and feel
 ------------------------------------------------
 import javax.swing.*;
 import java.awt.Font;
 public class NiceFileDialog \{
 public static void main(String[] args) throws Exception \{
 UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
 JFrame f = new JFrame("A Nimbus Style File Chooser");
 JFileChooser c = new JFileChooser("C:\\$\\backslash\\$\\$\\backslash\\$");
 c.setFont(new Font("Georgia", Font.PLAIN, 40));
 if (c.showOpenDialog(f) == JFileChooser.CANCEL\\_OPTION)
 System.exit(-1);
 \}
 \}
 ,,, 
 

 * a listbox with names of looks and feels 
 -----------------------------------------
 import javax.swing.*;
 import java.awt.*;
 public class LookAndFeelBox \{
 public static void main(String[] args) \{
 ListModel looks = new AbstractListModel() \{
 UIManager.LookAndFeelInfo[] info = UIManager.getInstalledLookAndFeels();
 public int getSize() \{ return info.length; \}
 public Object getElementAt(int index) 
 \{ return info[index].getClassName(); \} 
 \};

 Font font = new Font("Georgia", Font.PLAIN, 30);
 JList list = new JList(looks);
 list.setFont(font); list.setForeground(Color.gray);
 //JPanel p = new JPanel(); p.add(l);
 JFrame f = new JFrame();
 f.getContentPane().add(list);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setLocationRelativeTo(null); 
 f.pack(); f.setVisible(true);
 \}
 \}
 ,,,

 The Look and Feel does not effect the window decorations, which 
 are controlled by the host operating system.

 The following fragment works but generates runtime exceptions,
 possible because I update the gui from within a function rather
 than from within the paint method. The nimbus look and feel seems
 to be the most pleasant at least on an ms windows computer.

 * show look and feels and change the look and feel when clicked 
 --------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.event.*;
 import java.awt.*;
 public class LookAndFeel extends JFrame implements ListSelectionListener \{
 JList list;
 ListModel looks = new AbstractListModel() \{
 UIManager.LookAndFeelInfo[] info = UIManager.getInstalledLookAndFeels();
 public int getSize() \{ return info.length; \}
 public Object getElementAt(int index)
 \{ return info[index].getClassName(); \}
 \};
 public LookAndFeel()
 \{
 Font font = new Font("Georgia", Font.PLAIN, 20);
 list = new JList(looks);
 list.addListSelectionListener(this);
 list.setFont(font);
 list.setForeground(Color.gray);
 JButton button = new JButton("Does Nothing");
 JPanel p = new JPanel();
 p.add(list);
 p.add(button);
 JFrame f = new JFrame();
 this.getContentPane().add(p);
 this.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 this.pack();
 this.setVisible(true);
 \}
 
 public void valueChanged(ListSelectionEvent e) \{
 if (e.getValueIsAdjusting() == false) \{
 if (list.getSelectedIndex() == -1) \{ /* No selection */ \}
 else \{
 try
 \{
 UIManager.setLookAndFeel(list.getSelectedValue().toString());
 SwingUtilities.updateComponentTreeUI(this.getContentPane());
 \}
 catch (Exception ex) \{\}
 \}
 \}
 \}
 public static void main(String[] args)
 \{
 LookAndFeel t = new LookAndFeel();
 \}
 \}
 ,,,


 * set the native system look and feel. 
 ------------------------
 public static void main(String[] args) \{
 SwingUtilities.invokeLater( new Runnable() \{
 public void run() \{
 try \{
 UIManager.setLookAndFeel(
 UIManager.getSystemLookAndFeelClassName());
 \} catch (Exception useDefault) \{\}
 initGui();
 \}
 \});
 \}
 ,,,


 * install a new look and feel.
 ------------------------------
 try \{
 UIManager.
 setLookAndFeel ("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
 \}
 catch (InstantiationException e) \{ \}
 catch (ClassNotFoundException e) \{ \}
 catch (UnsupportedLookAndFeelException e) \{ \}
 catch (IllegalAccessException e) \{ \}
 ,,,

 * change the look and feel
 >> UIManager.setLookAndFeel("...");
 >> SwingUtilities.updateComponentTreeUI(getContentPane());

 * set native look and feel
 >> UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

 * set java look and feel
 >> Manager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
 
 * set the window decorations to the host system look and feel
 >> JFrame.setDefaultLookAndFeelDecorated(true); 
 >> JFrame frame = new JFrame("A window");

MODIFYING A LOOK AND FEEL ....

 We can modify any look and feel by changing its default attributes. For
 example we can change the default font or the default panel colours etc.

 * show the default font for a textfield in the current look and feel
 >> Font font = UIManager.getFont("TextField.font");
 
 * change the default font for all textfield components
 >> UIManager.put("TextField.font", new FontUIResource(<font>));

 * change the default font for a colorchooser
 >> UIManager.put("ColorChooser.font", new FontUIResource("Georgia", Font.PLAIN, 18));

 * change the default font for all labels and anti-alias fonts (>= 1/6)
 --------------------------------------------------
 import javax.swing.*;
 import javax.swing.plaf.*;
 import java.awt.*;
 public class LabelFont \{
 public static void main(String[] args) \{
 System.setProperty("awt.useSystemAAFontSettings","on");
 UIManager.put("Label.font", 
 new FontUIResource(Font.SERIF, Font.PLAIN, 60));
 JPanel p = new JPanel(new GridLayout(0, 1));
 for (String s: new String[]\{"jl1", "jl2", "jl3"\}) \{
 JLabel l = new JLabel(s); p.add(l);
 \}
 JOptionPane.showMessageDialog(null, p);
 \}
 \}
 ,,,

GETDEFAULTS ....

 * see all look and feel keys whose values are Icons 
 -------------------------------------------------------------
 import java.util.Enumeration;
 import javax.swing.plaf.*;
 import javax.swing.*;
 import java.awt.*;
 public class IconList \{
 public static void main(String[] args) \{
 java.util.Enumeration keys = UIManager.getDefaults().keys();
 while (keys.hasMoreElements()) \{
 Object key = keys.nextElement();
 Object value = UIManager.get(key);
 if (value instanceof javax.swing.Icon) System.out.println(key); 
 \}
 \}
 \}
 ,,,

 * a method to set the default font for all swing elements 
 -------------------------------------------------------------
 public static void setUIFont (javax.swing.plaf.FontUIResource f)\{
 java.util.Enumeration keys = UIManager.getDefaults().keys();
 while (keys.hasMoreElements()) \{
 Object key = keys.nextElement();
 Object value = UIManager.get(key);
 if (value instanceof javax.swing.plaf.FontUIResource)
 UIManager.put(key, f);
 \}
 \} 
 \} 
 ,,,

 * List the UIManager keys in a listbox 
 --------------------------------------------------
 import java.util.Enumeration;
 import javax.swing.plaf.*;
 import javax.swing.*;
 import java.awt.Font;
 public class UIListBox \{
 public static void main(String[] args) \{
 System.setProperty("awt.useSystemAAFontSettings","on");
 DefaultListModel listModel = new DefaultListModel();
 java.util.Enumeration keys = UIManager.getDefaults().keys();
 while (keys.hasMoreElements()) 
 listModel.addElement(keys.nextElement().toString());
 JList list = new JList(listModel);
 list.setFont(new Font("Georgia", Font.PLAIN, 30));
 JPanel p = new JPanel(); p.add(new JScrollPane(list));
 JOptionPane.showMessageDialog(null, p);
 \}
 \}
 ,,,

 * List the UIManager keys in a listbox 
 --------------------------------------------------
 import java.util.Enumeration;
 import javax.swing.plaf.*;
 import javax.swing.*;
 import java.awt.Font;
 public class KeysBox extends JList \{
 public KeysBox() \{
 super();
 DefaultListModel model = new DefaultListModel();
 Enumeration keys = UIManager.getDefaults().keys();
 while (keys.hasMoreElements()) 
 model.addElement(keys.nextElement().toString());
 this.setModel(model); 
 this.setFont(new Font("Georgia", Font.PLAIN, 25));
 \}
 public static void main(String[] args) \{
 JFrame t = new JFrame();
 JPanel p = new JPanel(); 
 p.add(new JScrollPane(new KeysBox()));
 t.getContentPane().add(p);
 t.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 t.pack(); t.setLocationRelativeTo(null);
 t.setVisible(true);
 \}
 \}
 ,,,

 * the above method can be executed with
 >> setUIFont(new javax.swing.plaf.FontUIResource("Serif",Font.ITALIC,12));

 * set the default font for all swing components. 
 --------------------------------------------------
 import javax.swing.*;
 import javax.swing.plaf.*;
 import java.awt.*;
 public class LabelFont \{
 public static void setUIFont (FontUIResource f)\{
 java.util.Enumeration keys = UIManager.getDefaults().keys();
 while (keys.hasMoreElements()) \{
 Object key = keys.nextElement();
 Object value = UIManager.get(key);
 if (value instanceof javax.swing.plaf.FontUIResource)
 UIManager.put(key, f);
 \} 
 \} 
 public static void main(String[] args) \{
 Font font = new Font("Georgia", Font.PLAIN, 40);
 LabelFont.setUIFont(new FontUIResource("Georgia",Font.ITALIC,25));
 JFrame f = new JFrame();
 JPanel p = new JPanel();
 JLabel l = new JLabel("This is the Georgia Font"); p.add(l);
 JButton b = new JButton("Elm Trees"); p.add(b);
 f.getContentPane().add(p);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

 * show a file chooser dialog and determine the result
 -----------------------------------------------------
 import javax.swing.*;
 import javax.swing.plaf.*;
 import java.awt.Font;
 public class ChooseFile \{
 public static void main(String[] args) \{
 Font font = new Font("Georgia", Font.PLAIN, 30);
 UIManager.put("FileChooser.font", new FontUIResource(font));
 JFrame f = new JFrame("test file chooser");
 JFileChooser chooser = new JFileChooser();
 int result = chooser.showOpenDialog(f);
 java.io.File file = chooser.getSelectedFile();
 \}
 \}
 ,,,

CUSTOM JCOMPONENTS AND UI DELEGATES ....

 It is possible to create a new UI for a swing component. These are
 referred to as 'delegates'. Basically, the component delegates the task
 of its display details to another class. To create a new look for a
 JTextField create a TextFieldUI by extending a BasicTextFieldUI. For any
 component it is possible to create a ComponentUI to change the default
 look and feel for a component.
 
 \url{http://today.java.net/pub/a/today/2007/02/22/how-to-write-custom-swing-component.html}
 a good article about custom swing components and the ComponentUI

 * a simple TextFieldUI example
 -------------------------------------------------------------
 public class MyTextUI extends BasicTextFieldUI \{
 @Override
 protected String getPropertyPrefix() \{
 return "TextField";
 \}
 protected void paintBackground(Graphics g) \{
 g.setColor(new Color(0, 0, 0));
 g.fillRect(0, 0, getComponent().getWidth(), getComponent().getHeight());
 \}
 \}
 textField.setUI(new MyTextUI());
 ,,,

JAVA DOCUMENTATION

 * includes a link to a method using suns online api documentation
 >> \url{http://java.sun.com/javase/6/docs/api/javax/sound/sampled/AudioSystem.html\\#getAudioInputStream(java.io.File)}
 
 * consult the java 1.5 documentation for the sound 'Clip' class
 >> \url{http://java.sun.com/j2se/1.5.0/docs/api/javax/sound/sampled/Clip.html}

 * look up the online api documentation for the 'Class' class
 >> firefox java.sun.com/javase/6/docs/api/java/lang/Class.html

 This will open the javadoc documentation for the 'Class' class
 (used with the reflection classes) in a new firefox tab if firefox
 is already running

 * look up the java 6 documentation for the 'File' class
 >> firefox java.sun.com/javase/6/docs/api/java/io/File.html

 * a bash function to look up the documentation for a class 
 >> jdoc()\{ firefox "java.sun.com/javase/6/docs/api/java/lang/\\$1.html"; \}

 This function can be used by typing 'jdoc String' to look up
 the Sun documentation for the 'String' class

 * a better java api documentation look-up bash function 
 -------------------------------------------------
 jdoc() \{ 
 [ -z "\\$1" ] \\&\\& echo "usage: \\$FUNCNAME <java-class>" \\&\\& return 1
 c=\\$1; [[ \\$c != *.* ]] \\&\\& c=java/lang/\\$c || c=\\$\{c//./\\$\\backslash\\$/\}
 firefox "java.sun.com/javase/6/docs/api/\\$c.html";
 \}
 jdoc java.io.File; jdoc String
 ,,,

SOUND 

 Java programs using sound can be written with javax.sound.sampled

 Since the early days, computers have been able to beep, and they still can.

 * play the classic beep
 >> java.awt.Toolkit.getDefaultToolkit().beep();

PLAYING SOUND ....

 @@ \url{http://forums.sun.com/thread.jspa?threadID=5401845}
 A Thread which talks about using Applet audioClip etc.
 @@ \url{http://forums.sun.com/thread.jspa?messageID=10780561\\#10780561}
 Simple code to play a sound file (as a 'clip')

 AndrewThompson65 (forums.sun.com)
 \url{http://forums.sun.com/profile.jspa?userID=590366}
 his posts on the sun forums, read and learn

 Richard G. Baldwin wrote some java audio tutorials

 @@ \url{http://forums.sun.com/thread.jspa?forumID=31\\&threadID=792949}
 Simple code for playing a sound using a SourceDataLine (not a Clip)

PLAYING MP3 AND OGG VORBIS ....

 * example code for using mp3plugin.jar to play mp3s
 >> https://blogs.oracle.com/kashmir/entry/java\\_sound\\_api\\_2\\_mp3

 * download mp3plugin.jar (from sun) and put in the current folder 
 >> mp3plugin.jar 

 * run your mp3 application with jar in current folder 
 >> java -cp "mp3plugin.jar:." Mp3App \\#\\#(Linux)
 >> java -cp "mp3plugin.jar;." Mp3App \\#\\#(Windows)

 See below for code that actually plays mp3s. The mp3 format
 must be first converted to something that the java sound api
 can deal with.

 * copy the mp3plugin.jar to the extensions folder
 >> cp mp3plugin.jar \texttt{/usr/lib/jvm/jdk1.7.0/jre/lib/ext/}

 The above procedure avoids having to set the classpath on the
 command line, since the jre automatically loads classes from the
 \texttt{/lib/ext} folder. The jar file above does not need the JMF Java Media
 Framework in order to run.

 Strangely, even with the plugin you cant use the same code
 to play an mp3 as a wav. You need to convert the format first

 * play an mp3 with the mp3plugin.jar 
 -------------------------------------------------------------
 import javax.sound.sampled.*;
 import java.io.File;
 public class Player2 \{
 // Buffer size = 44100 x 16 x 2 / 8
 private static final int BUFFER\\_SIZE = 176400; 
 public static void main(String[] args) throws Exception \{
 byte[] buffer = new byte[BUFFER\\_SIZE];
 AudioInputStream in = 
 AudioSystem.getAudioInputStream(
 AudioFormat.Encoding.PCM\\_SIGNED, 
 //AudioSystem.getAudioInputStream(new File(args[0])));
 AudioSystem.getAudioInputStream(new File("abuztuan.mp3")));
 AudioFormat audioFormat = in.getFormat();
 SourceDataLine line = 
 (SourceDataLine) AudioSystem.getLine(
 new DataLine.Info(SourceDataLine.class, audioFormat));
 line.open(audioFormat);
 line.start();
 while (true) \{
 int n = in.read(buffer, 0, buffer.length);
 if (n < 0) \{ break; \}
 line.write(buffer, 0, n);
 \}
 line.drain();
 line.close();
 \}
 \}
,,,
 Success! The above code works. After many tries 

 * the only difference in the code above is
 ------------------------------------------
 AudioInputStream in = AudioSystem.getAudioInputStream(
 AudioFormat.Encoding.PCM\\_SIGNED, 
 AudioSystem.getAudioInputStream(new File("abuztuan.mp3")));
 ,,,

USING TRITONIUS ....

 This procedure is untested.

 * play an mp3 file
 \begin{enumerate}
  \item get \url{http://www.javazoom.net/javalayer/sources.html}
 \item put the jar in the class path or current directory
 \item see \url{http://www.cs.princeton.edu/introcs/faq/mp3/MP3.java.html}
\end{enumerate}
  
 put these in your classpath
 tritonus\\_share.jar, .... 

 * put the tritonus class on the class path and run 'Test'
 >> java -cp ".:tritonus\\_share.jar:..." Test

 @@ \url{http://www.javazoom.net/mp3spi/documents.html}
 example code for playing mp3s
 @@ \url{http://www.jsresources.org}
 More examples of how to play mp3 sound files using the
 tritonius decoder classes. These examples tend to be difficult
 to understand because they include so much unnecessary code

FORMATS AND ENCODERS ....

 Service Provider Interface

 The Java Sound API uses a Service Provider Interface to identify
 encoders \\& decoders for sound formats and sequence types. This way,
 adding support for a new format or type is as simple as providing a
 decoder and/or encoder for it, adding an SPI file to the manifest of
 the Jar it is in, then adding the Jar to the run-time class-path of
 the application.
 
 The mp3plugin.jar of the Java Media Framework supports decoding MP3s.

AUDIO INFORMATION ....


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents sound glossary 
 .. PCM - pulse-code modulation, a simple encoding technique
 .. encoding - eg PCM, mu-law, a-law. Turns wave pressure into numbers
 .. herz - the a frequency (eg samples/frames) per second
 .. sample - a digital approximation of a sound wave at a point in time 
 .. frame - contains stereo samples and possibly other information
 .. frame rate - the number of frames per second (herz)
 .. sample rate - the number of samples per second (herz)
 ..

 Sound files consist of a file format (which in java is represented
 by the AudioFileFormat class). This file format contains header
 information and other metadata such as frame length. The sound file
 also has an audio format (represented by the class AudioFormat)
 which consists of the sampling rate, the sample bit size, mono or
 stereo etc.

 An audio format consists of the number of samples per second (hz),
 number of channels (stereo=2), bits per sample, and sample
 encoding

 * show the audio format for the file 'test.wav' 
 --------------------------------------------
 import javax.sound.sampled.*;
 import java.io.File;
 public class Test
 \{
 public static void main(String[] args) throws Exception
 \{
 File file = new File("test.wav");
 AudioInputStream ais = AudioSystem.getAudioInputStream(file);
 AudioFormat format = ais.getFormat();
 System.out.println(format);
 \}
 \}
 ,,,

 This produces output such as
 >> PCM\\_SIGNED 22050.0 Hz, 16 bit, mono, 2 bytes/frame, little-endian

 * show more detailed audio format information 
 --------------------------------------------
 import javax.sound.sampled.*;
 import java.io.File;
 public class Test
 \{
 public static void main(String[] args) throws Exception
 \{
 File file = new File("test.wav");
 AudioInputStream ais = AudioSystem.getAudioInputStream(file);
 AudioFormat format = ais.getFormat();
 System.out.println(
 "encoding: " + format.getEncoding());
 System.out.println(
 "frame rate: " + format.getFrameRate());
 System.out.println(
 "frame size: " + format.getFrameSize() + "(bytes)");
 System.out.println(
 "sample rate: " + format.getSampleRate());
 System.out.println(
 "sample size: " + format.getSampleSizeInBits() + "(bits)");
 System.out.println(
 "channels: " + format.getChannels());
 System.out.println(
 "big endian: " + format.isBigEndian());
 \}
 \}
 ,,,

 * show the audio file format for an audio file 
 --------------------------------------------
 import javax.sound.sampled.*;
 import java.io.File;
 public class Test
 \{
 public static void main(String[] args) throws Exception
 \{
 File file = new File("abuztuan.mp3");
 AudioFileFormat af = AudioSystem.getAudioFileFormat(file);
 System.out.println("Audio Type: " + af.getType());
 System.out.println("Audio File Format: " + af);
 \}
 \}
 ,,,

 * show what audio file formats can be written by the java sound system
 --------------------------------------------
 import javax.sound.sampled.*;
 public class FileFormatList 
 \{
 public static void main(String[] args) throws Exception
 \{
 AudioFileFormat.Type[] aa = AudioSystem.getAudioFileTypes();
 for (int i = 0; i < aa.length; i++)
 System.out.println(aa[i].toString());
 \}
 \}
 ,,,

 * check for a particular type of audio format
 -------------------------------------------------------------
 af = AudioSystem.getAudioFileFormat(new File("Test.wav");
 if (af.getType() != AudioFileFormat.Type.AIFF) 
 ,,,

 * open a local file or within a jar file
 >> URL url = this.getClass().getClassLoader().getResource("test.wav");
 
 * new audioformat in PCM encoding
 >> new AudioFormat(sampleRate, sampleSizeInBits, channels, signed, bigEndian);

 * create an 8khz 8bit sample mono signed bigendian PCM format
 >> AudioFormat format = new AudioFormat(8000, 8, 1, true, true);
 
 This is a very low quality audioformat, but also of a small
 file size.

 * audio format constructor
 >> AudioFormat(AudioFormat.Encoding encoding, float sampleRate, int sampleSizeInBits, int channels, int frameSize, float frameRate, boolean bigEndian) 

 * a PCM format at 44100 hz stereo, 16 bit sample, 4 byte frame
 >> AudioFormat(AudioFormat.Encoding.PCM\\_SIGNED, 44100.0, 16, 2, 4, 44100.0, false) 

 * calculate bytes per second
 >> format.getFrameRate() * format.getFrameSize();
 
 The above calculation is important if you wish to read, play
 or record a certain number of seconds of audio, which is a 
 reasonably common request.

SOURCE DATA LINES ....

 @@ \url{http://forums.sun.com/thread.jspa?forumID=31\\&threadID=5310813}
 very clear code for using source data lines in a class

 * a simple example of playing a sound found with a SourceDataLine 
 -------------------------------------------------------------
 import java.io.*;
 import javax.sound.sampled.*;
 public class SoundLineTest \{
 public static void main(String[] args) throws Exception \{
 SourceDataLine line = null;
 int BUFFERSIZE = 64*1024; // 64 KB
 File f = new File("rec.wav");
 AudioInputStream stream = AudioSystem.getAudioInputStream(f);
 AudioFormat format = stream.getFormat();
 DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
 line = (SourceDataLine) AudioSystem.getLine(info);
 line.open(format); line.start();
 int nBytesRead = 0;
 byte[] sampledData = new byte[BUFFERSIZE];
 boolean stopped = false;
 while (!stopped) \{
 nBytesRead = stream.read(sampledData, 0, sampledData.length);
 if (nBytesRead == -1) break; 
 line.write(sampledData, 0, nBytesRead);
 \}
 line.drain();
 line.close();
 \}
 \}
 ,,,

 The boolean 'stopped' variable in the code above can be used to 
 stop the play back if the user presses a button (which will set 
 the stopped variable to true)

 * play a sound using a SourceDataLine catching Exceptions
 -------------------------------------------------------------
 import java.io.*;
 import javax.sound.sampled.*;
 public class SoundLineTest \{
 public static void main(String[] args) \{
 SourceDataLine soundLine = null;
 int BUFFER\\_SIZE = 64*1024; // 64 KB
 try \{
 File soundFile = new File("test.wav");
 AudioInputStream audioInputStream = 
 AudioSystem.getAudioInputStream(soundFile);
 AudioFormat audioFormat = audioInputStream.getFormat();
 DataLine.Info info = new DataLine.Info(SourceDataLine.class, audioFormat);
 soundLine = (SourceDataLine) AudioSystem.getLine(info);
 soundLine.open(audioFormat);
 soundLine.start();
 int nBytesRead = 0;
 byte[] sampledData = new byte[BUFFER\\_SIZE];
 while (nBytesRead != -1) \{
 nBytesRead = audioInputStream.read(sampledData, 0, sampledData.length);
 if (nBytesRead >= 0) \{
 soundLine.write(sampledData, 0, nBytesRead);
 \}
 \}
 \} catch (UnsupportedAudioFileException ex) \{
 ex.printStackTrace();
 \} catch (IOException ex) \{
 ex.printStackTrace();
 \} catch (LineUnavailableException ex) \{
 ex.printStackTrace();
 \} finally \{
 soundLine.drain();
 soundLine.close();
 \}
 \}
 \}
 ,,,

 In the code above if the nBytesRead > 0 test is removed then an 
 IllegalArgumentException is thrown at the end of the sound file
 
CUTTING SOUND FILES ....
 
 One strategy for cutting an audio file is to construct a new 
 AudioInputStream from another but limit the number of frames

 * create a new shorter stream 
 -------------------------------------------------------------
 AudioInputStream newStream = 
 new AudioInputStream(
 oldStream, format, seconds * (int)format.getFrameRate());
 AudioSystem.write(shortenedStream, fileFormat.getType(), destinationFile);
 ,,,

 Another strategy is to write bytes to an output stream. Then create an
 audio input stream from those bytes.

 * cut a section of a wav file and save to a new file
 -------------------------------------------------------------
 import java.io.*;
 import javax.sound.sampled.*;
 class AudioFileProcessor \{
 public static void copyAudio(
 String sourceFileName, String destinationFileName, 
 int startSecond, int secondsToCopy) \{
 AudioInputStream inputStream = null;
 AudioInputStream shortenedStream = null;
 try \{
 File file = new File(sourceFileName);
 AudioFileFormat fileFormat = AudioSystem.getAudioFileFormat(file);
 AudioFormat format = fileFormat.getFormat();
 inputStream = AudioSystem.getAudioInputStream(file);
 int bytesPerSecond = format.getFrameSize() * (int)format.getFrameRate();
 inputStream.skip(startSecond * bytesPerSecond);
 long framesOfAudioToCopy = secondsToCopy * (int)format.getFrameRate();
 shortenedStream = new AudioInputStream(inputStream, format, framesOfAudioToCopy);
 File destinationFile = new File(destinationFileName);
 AudioSystem.write(shortenedStream, fileFormat.getType(), destinationFile);
 \} catch (Exception e) \{
 println(e);
 \} finally \{
 if (inputStream != null) 
 try \{ inputStream.close(); \} 
 catch (Exception e) \{ println(e); \}
 if (shortenedStream != null) 
 try \{ shortenedStream.close(); \} 
 catch (Exception e) \{ println(e); \}
 \}
 \}
 public static void main(String[] args) \{
 copyAudio("/tmp/uke.wav", "/tmp/uke-shortened.wav", 2, 1);
 \}

 \}
 ,,,

 * A technique to write a byte array to a wav file, incomplete example
 ------------------------------------
 File f = new File(exportFileName + ".tmp");
 File f2 = new File(exportFileName);
 long l = f.length();
 //byte[] buffer;
 // read into byte array using AudioInputStream
 ByteArrayInputStream bs = new ByteArrayInputStream(buffer);
 AudioInputStream ai = new AudioInputStream(bs,mainFormat,l/4);
 AudioSystem.write(ai, Type.WAVE, f2);
 fi.close();
 f.delete();
 ,,,

 * another technique for writing bytes to an audio file, incomplete example
 --------------------
 ByteArrayOutputStream b\\_out = new ByteArrayOutputStream();
 // Read a frame from the file.
 while (audioInputStream.read(audioBytes) != -1) \{ 
 //Do stuff here....
 b\\_out.write(outputvalue);
 \} 
 // Hook output stream to output file
 ByteArrayInputStream b\\_in = new ByteArrayInputStream(b\\_out.toByteArray());
 AudioInputStream ais = new AudioInputStream(b\\_in, format, length);
 AudioSystem.write(ais, inFileFormat.getType(), outputFile);
 ,,,

CONVERT RAW AUDIO DATA TO WAV ....

 File f = new File(exportFileName+".tmp");
 File f2 = new File(exportFileName);
 long l = f.length();
 FileInputStream fi = new FileInputStream(f);
 AudioInputStream ai = new AudioInputStream(fi,mainFormat,l/4);
 AudioSystem.write(ai, Type.WAVE, f2);
 fi.close();
 f.delete();
 
JOINING SOUND FILES ....

 * join 2 wav files
 --------------------------
 import java.io.File;
 import java.io.IOException;
 import java.io.SequenceInputStream;
 import javax.sound.sampled.AudioFileFormat;
 import javax.sound.sampled.AudioInputStream;
 import javax.sound.sampled.AudioSystem;

 public class WavAppender \{
 public static void main(String[] args) \{
 String wavFile1 = "wav1.wav";
 String wavFile2 = "wav2.wav";
 try \{
 AudioInputStream clip1 = AudioSystem.getAudioInputStream(new File(wavFile1));
 AudioInputStream clip2 = AudioSystem.getAudioInputStream(new File(wavFile2));
 AudioInputStream appendedFiles = new AudioInputStream(
 new SequenceInputStream(clip1, clip2), clip1.getFormat(), 
 clip1.getFrameLength() + clip2.getFrameLength());
 AudioSystem.write(appendedFiles, AudioFileFormat.Type.WAVE, 
 new File("joinwav.wav"));
 \} catch (Exception e) \{
 e.printStackTrace();
 \}
 \}
 \}
 ,,,
 
PLAYING AUDIO ....

 * use a JToggleButton to stop and start a sound clip
 -------------------------------------------------------------
 import java.net.URL;
 import java.awt.event.*;
 import javax.swing.*;
 import javax.sound.sampled.*;

 public class RestartableLoopSound \{
 public static void main(String[] args) throws Exception \{
 URL url = new URL("http://pscode.org/media/leftright.wav");
 final Clip clip = AudioSystem.getClip();
 AudioInputStream ais = AudioSystem.getAudioInputStream(url);
 clip.open(ais);
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 final JToggleButton b = new JToggleButton("Loop");
 ActionListener listener = new ActionListener() \{
 public void actionPerformed(ActionEvent ae) \{
 if (b.isSelected()) \{
 clip.loop(Clip.LOOP\\_CONTINUOUSLY);
 \} else \{ clip.stop(); \}
 \}
 \};
 b.addActionListener(listener);
 JOptionPane.showMessageDialog(null, b);
 \}
 \});
 \}
 \}
 ,,,

CLIPS ....

 Clips are used for non streamed audio data. That is, all audio
 data is loaded into memory before playback


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents Things doable with a javax.sound.sampled.Clip 
 .. getMicrosecondLength() - how many microseconds long is the audio
 .. getFrameLength() - how many sound frames the audio has
 .. setMicrosecondPosition(long) - set the current play position 
 .. setLoopPoints(int, int) - loop between 2 particular frames in the audio
 .. long getMicrosecondPosition() - how long the audio has been playing for
 .. long getLongFramePosition() - the current frame position of the audio
 .. AudioFormat getFormat() - the format of the playing audio

 If a sound file/url is too large then the Clip will throw a
 javax.sound.sampled.LineUnavailableException with the message "Failed to
 allocate clip data: Requested buffer too large."

 * play a clip catching exceptions
 -------------------------------------------------------------
 import java.io.*;
 import java.net.URL;
 import javax.sound.sampled.*;
 import javax.swing.*;
 public class SoundClipTest extends JFrame \{
 
 public SoundClipTest() \{
 this.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 this.setTitle("Test Sound Clip");
 this.setSize(300, 200);
 this.setVisible(true);
 try \{
 File f = new File("test.wav");
 AudioInputStream audioIn = AudioSystem.getAudioInputStream(f);
 Clip clip = AudioSystem.getClip();
 clip.open(audioIn);
 clip.start();
 \} catch (UnsupportedAudioFileException e) \{
 e.printStackTrace();
 \} catch (IOException e) \{
 e.printStackTrace();
 \} catch (LineUnavailableException e) \{
 e.printStackTrace();
 \}
 \}
 
 public static void main(String[] args) \{
 new SoundClipTest();
 \}
 \}
 ,,,

 * play an audio file (obtained from the web) continuously
 ---------------------------------------------------------
 import javax.sound.sampled.*;
 import java.net.URL;
 import javax.swing.JOptionPane;
 public class AudioClipTest \{
 public static void main(String[] args) throws Exception \{
 URL url = new URL("http://pscode.org/media/100\\_2817.au");
 AudioInputStream ais = AudioSystem.getAudioInputStream(url);
 Clip clip = AudioSystem.getClip();
 clip.open(ais);
 clip.loop(Clip.LOOP\\_CONTINUOUSLY);
 JOptionPane.showMessageDialog(null, "Close to end..");
 \}
 \}
 ,,,,,
 ,,,

 * play an audio clip beginning 1/2 a second after the beginning (using code above)
 >> clip.open(); clip.setMicrosecondPosition(); clip.start();

 * play a sound file starting just after the beginning 
 -------------------------------------------------------------
 import javax.sound.sampled.*;
 import java.io.File;
 import javax.swing.JOptionPane;
 public class ClipTest \{
 public static void main(String[] args) throws Exception \{
 File f = new File("asagohan.wav");
 AudioInputStream ais = AudioSystem.getAudioInputStream(f);
 Clip clip = AudioSystem.getClip();
 clip.open(ais); 
 clip.setMicrosecondPosition(500000); clip.start();
 JOptionPane.showMessageDialog(null, "Close to end..");
 \}
 \}
 ,,, 

 * play the local file 'sound.wav' (in the current folder) 6 times 
 -------------------------------------------------------------
 import javax.sound.sampled.*;
 import java.io.File;
 import javax.swing.JOptionPane;
 public class MpgPlay \{
 public static void main(String[] args) throws Exception \{
 File f = new File("abuztuan.mp3");
 AudioInputStream ais = AudioSystem.getAudioInputStream(f);
 Clip clip = AudioSystem.getClip();
 clip.open(ais); clip.loop(6); clip.start();
 JOptionPane.showMessageDialog(null, "Close to end..");
 \}
 \}
 ,,, 

 * check if the system supports playing mp3 sound files
 ------------------------------------------------------
 import javax.sound.sampled.*;
 import java.io.File;
 public class MpgSupport \{
 public static void main(String[] args) throws Exception \{
 File f = new File("abuztuan.mp3");
 try
 \{
 AudioInputStream ais = AudioSystem.getAudioInputStream(f);
 System.out.println("Mp3 is Ok to play");
 \}
 catch (UnsupportedAudioFileException e)
 \{
 System.out.println("Mp3 is NOT supported");
 \}
 \}
 \}
 ,,,

 The following may fail if the sound file is too big

 * create a simple loop to pause and restart a sound clip
 --------------
 import javax.sound.sampled.*;
 import java.util.*;
 import java.io.File;
 
 public class PauseClip \{
 public static void main(String[] args) throws Exception \{
 File file = new File("test.wav");
 AudioInputStream ais = AudioSystem.getAudioInputStream(file);
 Clip clip = AudioSystem.getClip();
 clip.open(ais); clip.loop(1); clip.start();
 Scanner scan = new Scanner(System.in);
 String s = "";
 while (!s.equals("q"))
 \{
 System.out.print("what? (p/s/q)>");
 s = scan.nextLine();
 if (s.equals("p")) \{ clip.stop(); \}
 if (s.equals("s")) \{
 //clip.flush();
 clip.start();
 \}
 \}
 \}
 \}
 ,,,

RECORDING SOUND ....

 @@ \url{http://www.jsresources.org}
 terribly complicated examples of using the javax.sound.sampled
 api. This will put you right off ever trying to use it.
 @@ \url{http://www.developer.com/java/other/article.php/2105421/Java-Sound-Capturing-Microphone-Data-into-an-Audio-File.htm} 
 A tutorial on recording sound by Baldwin.

 * record cd quality stereo audio
 >> AudioFormat format = new AudioFormat(
 >> AudioFormat.Encoding.PCM\\_SIGNED,
 >> 44100.0F, 16, 2, 4, 44100.0F, false);

 * record a sound file from the computer microphone
 ------------------------
 import java.io.*;
 import javax.sound.sampled.*;
 public class RecordAudio 
 \{
 public static void main(String[] args) throws Exception
 \{
 /* Cd quality PCM 44.1 kHz, 16 bit signed, stereo. */
 AudioFormat format = new AudioFormat(
 AudioFormat.Encoding.PCM\\_SIGNED,
 44100.0F, 16, 2, 4, 44100.0F, false);
 DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
 TargetDataLine line = (TargetDataLine) AudioSystem.getLine(info);
 line.open(format); line.start();
 AudioInputStream ais = new AudioInputStream(line);
 System.out.println("Recording into 't.wav', [Cntrl] c to stop");
 AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File("rec.wav"));
 line.stop(); 
 line.close();
 \} \}
 ,,,

 * record audio in a thread, this code is very messy and redundant
 -------------------------------------------------------------
 import javax.sound.sampled.*;
 import javax.swing.*;
 import java.awt.event.*;
 import java.io.*;
 public class RecordAudio \{
 private File audioFile;
 protected boolean running;
 private ByteArrayOutputStream out;
 private AudioInputStream inputStream;
 private AudioFormat format;
 private float level;
 private int frameSize;

 public RecordAudio()\{ getFormat(); \}
 private AudioFormat getFormat() \{
 File file = new File("test.wav");
 AudioInputStream stream;
 try \{
 stream = AudioSystem.getAudioInputStream(file);
 format=stream.getFormat();
 frameSize=stream.getFormat().getFrameSize();
 return stream.getFormat();
 \}
 catch (UnsupportedAudioFileException e) \{\} 
 catch (IOException e) \{ \}
 return null;
 \}
 public void stopRecording() \{ running = false; \}
 public void recordAudio() \{
 try \{
 final AudioFormat format = getFormat();
 DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
 final TargetDataLine line = (TargetDataLine)
 AudioSystem.getLine(info);
 line.open(format);
 line.start();
 Runnable runner = new Runnable() \{
 int bufferSize = (int) format.getSampleRate()
 * format.getFrameSize();
 byte buffer[] = new byte[bufferSize];
 public void run() \{
 int readPoint = 0;
 out = new ByteArrayOutputStream();
 running = true;
 int sum=0;
 while (running) \{
 int count = line.read(buffer, 0, buffer.length);
 System.out.println(level);
 if (count > 0) \{ out.write(buffer, 0, count); \}
 \}
 line.stop();
 \}
 \};

 Thread captureThread = new Thread(runner);
 captureThread.start();
 \} catch (LineUnavailableException e) \{
 System.err.println("Line unavailable: " + e);
 System.exit(-2);
 \}
 \}

 public File getAudioFile() \{
 byte[] audio = out.toByteArray();
 InputStream input = new ByteArrayInputStream(audio);
 try \{
 final AudioFormat format = getFormat();
 final AudioInputStream ais =
 new AudioInputStream(input, format,
 audio.length / format.getFrameSize());
 AudioSystem.write(ais, AudioFileFormat.Type.WAVE, new File("rec.wav"));
 input.close();
 System.out.println("New file created!");
 \} catch (IOException e) \{
 System.out.println(e.getMessage());
 \}
 return new File("rec.wav");
 \}
 
 public static void main(String[] args) throws Exception \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 final RecordAudio a = new RecordAudio();
 final JToggleButton b = new JToggleButton("start recording");
 ActionListener listener = new ActionListener() \{
 public void actionPerformed(ActionEvent ae) \{
 if (b.isSelected()) \{
 a.recordAudio();
 b.setText("stop recording");
 \} else \{ 
 b.setText("start recording");
 a.stopRecording();
 File f = a.getAudioFile();
 \}
 \}
 \};
 b.addActionListener(listener);
 JOptionPane.showMessageDialog(null, b);
 \}
 \});
 \}
 \}
 ,,,

SILENCE ....

 Silence can be calculated either by decibel dB levels or else 
 by the RMS, or Root Mean Square.

 * Computes the Root Mean Square volume of signal sizes from -1 to 1. 
 -------------------------------------------------------------

 public double volumeRMS(double[] raw) \{
 double sum = 0d;
 if (raw.length == 0) \{
 return sum;
 \} else \{
 for (int ii=0; ii < raw.length; ii++) \{
 sum += raw[ii];
 \}
 \}
 double average = sum/raw.length;

 double sumMeanSquare = 0d;
 for (int ii=0; ii<raw.length; ii++) \{
 sumMeanSquare += Math.pow(raw[ii]-average,2d);
 \}
 double averageMeanSquare = sumMeanSquare/raw.length;
 double rootMeanSquare = Math.pow(averageMeanSquare,0.5d);

 return rootMeanSquare;
 \}
 ,,,

MIXERS ....

 * show the available audio mixers on a system
 ---------------------------------------
 import javax.sound.sampled.*;
 public class MixerTest
 \{
 public static void main(String[] args) throws Exception
 \{
 Mixer.Info[] mixerInfo = AudioSystem.getMixerInfo();
 System.out.println("Available mixers:");
 for (int ii = 0; ii < mixerInfo.length; ii++)
 \{
 System.out.println(mixerInfo[ii].getName());
 \} \} \}
 ,,,

TONES ....

 * code for generating tones 
 >> \url{http://stackoverflow.com/questions/7782721/java-raw-audio-output/7782749\\#7782749}

MIDI ....

 Midi is a way of representing electronic music, symbolically rather than
 as a series of samples.

 * Playing a MIDI Sequence (a song)
 ------------------------
 import javax.sound.midi.*;
 import javax.swing.JOptionPane;
 import java.net.URL;

 public class PlayMidi \{
 public static void main(String[] args) throws Exception \{
 URL url = new URL("http://pscode.org/media/EverLove.mid");
 Sequence sequence = MidiSystem.getSequence(url);
 Sequencer sequencer = MidiSystem.getSequencer();
 sequencer.open();
 sequencer.setSequence(sequence);
 sequencer.start();
 JOptionPane.showMessageDialog(null, "Everlasting Love");
 \}
 \}
 ,,,

THREADS 

 Threads are a type of concurrent process. The subject of concurrency
 in programming is large and often requires very precise thinking.
 The word 'concurrent' (ie running at the same time) is misleading. 
 The JVM handles the switching between all concurrent threads
 Each time a thread is run by the virtual machine, its run()
 method is called.

 Threads may be creating in (at least) two ways: By subclassing
 the Thread class, or by implementing the Runnable interface and
 passing it as a parameter to the Thread constructor
 eg: Thread p = new Thread(runnable);

 The second method allows existing classes to act as threads.

 * create an anonymous thread
 ----------------------------
 new Thread() \{
 public void run()
 \{
 // do something
 \}
 \}.start();
 ,,,

SWINGWORKER

 The swingworker class is a type of Thread and is a way of performing long
 running tasks without blocking the Swing user interface. As a general
 guide, it is only ok to update Swing components from the process() and
 the done() methods of the SwingWorker thread. This is because these
 methods are executed on the swing event dispatch thread (EDT).
 SwingWorker subclasses are usually implemented as inner or anonymous
 inner classes.

 @@ \url{http://java.sun.com/developer/technicalArticles/javase/swingworker/}
 A very good article about swingworker and an example image
 download application.

 @@ \url{http://stackoverflow.com/questions/6113944/how-cancel-the-execution-of-a-swingworker/6114890\\#6114890}
 a verbose but exegesic SwingWorkder example 

 * a worker thread that returns an array of icons and publishes one by one
 >> SwingWorker worker = new SwingWorker<ImageIcon[], ImageIcon>() \{

 * set the progress property, for use with a progress bar, and listener
 >> this.setProgress(4);

 * cancel a SwingWorker thread (check isCancelled in doInBackground)
 >> swingWorker.cancel(true);

 The code below is working, and is the basis of a file search utility.
 A SwingWorker thread is created to search for files having a 
 certain string in their path or name. 
 
 Enhancements: 
 to allow the search to be cancelled with worker.cancel(true). 
 Allow the user to determine the root of the file search/ if
 unix hidden folders should be searched. etc

 * publish file search results in a JList using process()
 -------------------------------------------------------------
 import javax.swing.*;
 import java.io.*;
 import java.util.*;
 import java.awt.event.*;
 import java.awt.*;
 public class SearchList extends JPanel implements ActionListener \{
 JList list;
 JButton button;
 JTextField field;
 public SearchList() \{
 super(new BorderLayout());
 Font georgia = new Font("Georgia", Font.ITALIC, 22);
 this.list = new JList(new DefaultListModel());
 this.button = new JButton("search");
 this.button.setFont(georgia);
 this.button.addActionListener(this);
 this.field = new JTextField(".mp3", 20);
 this.field.setFont(georgia);
 this.field.addActionListener(this);
 JPanel topPanel = new JPanel();
 topPanel.add(this.button); topPanel.add(this.field); 
 this.add(new JScrollPane(this.list), BorderLayout.CENTER);
 this.add(topPanel, BorderLayout.NORTH);
 \}
 public void actionPerformed(ActionEvent e) \{
 ((DefaultListModel)this.list.getModel()).removeAllElements();
 SearchTask t = new SearchTask(this.field.getText());
 t.execute();
 \}
 public static void main(String[] args) \{
 javax.swing.SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JFrame f = new JFrame("Search for Files with SwingWorker");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.add(new SearchList());
 f.pack(); f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.setVisible(true);
 \}
 \});
 \}
 class SearchTask extends SwingWorker<Void, File> \{
 int filesFound;
 String text;
 File root;
 public SearchTask(String text) \{
 super();
 this.filesFound = 0;
 this.text = text;
 this.root = new File("/home/");
 \}
 protected Void doInBackground() \{
 this.list(this.root, this.text);
 //while (!this.isCancelled()) \{ \}
 return null;
 \}
 protected void process(java.util.List<File> results) \{
 DefaultListModel model = 
 (DefaultListModel) SearchList.this.list.getModel();
 for (File file: results) \{ model.addElement(file); \}
 \}
 /** find files with names matching a certain string */
 public void list(File dir, final String filter) \{
 FileFilter ff = new FileFilter() \{
 public boolean accept(File file) \{
 return ((file.getAbsolutePath().indexOf(filter)>0) ||
 file.isDirectory());
 \}
 \};
 File[] files = dir.listFiles(ff);
 for (File f: files) \{
 if (f.isDirectory()) this.list(f, filter);
 else \{
 this.publish(f);
 this.filesFound++;
 \}
 \}
 \}
 \}
 \}
 ,,,

 Ideas: improve speed of search

 * enhanced file search with an information label 
 -------------------------------------------------------------
 import javax.swing.*;
 import java.io.*;
 import java.util.*;
 import java.awt.event.*;
 import java.awt.*;
 import java.util.concurrent.*;
 public class SearchList extends JPanel implements ActionListener \{
 JList list;
 JButton button;
 JTextField field;
 JLabel info;
 public SearchList() \{
 super(new BorderLayout());
 Font georgia = new Font("Georgia", Font.ITALIC, 22);
 this.list = new JList(new DefaultListModel());
 this.button = new JButton("search");
 this.button.setFont(georgia);
 this.button.addActionListener(this);
 this.field = new JTextField(".mp3", 20);
 this.field.setFont(georgia);
 this.field.addActionListener(this);
 this.info = new JLabel("info:");
 this.info.setFont(georgia);
 JPanel topPanel = new JPanel();
 topPanel.add(this.button); topPanel.add(this.field); 
 this.add(new JScrollPane(this.list), BorderLayout.CENTER);
 this.add(topPanel, BorderLayout.NORTH);
 this.add(this.info, BorderLayout.SOUTH);
 \}
 public void actionPerformed(ActionEvent e) \{
 ((DefaultListModel)this.list.getModel()).removeAllElements();
 SearchTask t = new SearchTask(this.field.getText());
 t.execute();
 \}
 public static void main(String[] args) \{
 javax.swing.SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JFrame f = new JFrame("Search for Files with SwingWorker");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.add(new SearchList());
 f.pack(); f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.setVisible(true);
 \}
 \});
 \}
 class SearchTask extends SwingWorker<Void, File> \{
 int filesFound;
 String text;
 File root;
 long searchTime;
 public SearchTask(String text) \{
 super();
 this.filesFound = 0;
 this.text = text;
 this.root = new File("/home/");
 this.searchTime = -1;
 \}
 protected Void doInBackground() \{
 this.searchTime = System.currentTimeMillis();
 this.list(this.root, this.text);
 this.searchTime = System.currentTimeMillis() - this.searchTime;
 //while (!this.isCancelled()) \{ \}
 return null;
 \}
 protected void done() \{
 SearchList.this.info.setText(String.format(
 "Files found: \\%d, Time taken: \\%d ms, Root folder: \\%s",
 this.filesFound, this.searchTime, this.root)); 
 \}
 protected void process(java.util.List<File> results) \{
 SearchList.this.info.setText(String.format(
 "Files found: \\%d", this.filesFound));
 DefaultListModel model = 
 (DefaultListModel) SearchList.this.list.getModel();
 for (File file: results) \{ model.addElement(file); \}
 \}
 /** find files with names matching a certain string */
 public void list(File dir, final String filter) \{
 FileFilter ff = new FileFilter() \{
 public boolean accept(File file) \{
 return ((file.getAbsolutePath().indexOf(filter)>0) ||
 file.isDirectory());
 \}
 \};
 File[] files = dir.listFiles(ff);
 for (File f: files) \{
 if (f.isDirectory()) this.list(f, filter);
 else \{
 this.publish(f);
 this.filesFound++;
 \}
 \}
 \}
 \}
 \}
 ,,,

PUBLISHING RESULTS ....

 The SwingWorker class allows us to obtain 'intermediate' results
 from the worker thread. These results are produced while the thread
 is still active. To obtain these results we use the publish() method
 and the process() method.

 Successive calls to publish() are coalesced into a java.util.List, 
 which is what is received by process()

 * using publish() and process()
 -------------------------------------------------------------
 this.publish(file);
 ...
 protected void process(java.util.List<File> results) \{...\}
 ,,,

 The code below is not complete, see the SearchList example for a 
 compilable example.

 * publish intermediate results of the worker thread using process(...)
 -------------------------------------------------------------
 public class FlipTask extends SwingWorker<Void, FlipPair> \{
 @Override
 protected Void doInBackground() \{
 long heads = 0;
 long total = 0;
 Random random = new Random();
 while (!isCancelled()) \{
 total++;
 if (random.nextBoolean()) \{ heads++; \}
 publish(new FlipPair(heads, total));
 \}
 return null;
 \}
 protected void process(List<FlipPair> pairs) \{
 FlipPair pair = pairs.get(pairs.size() - 1);
 headsText.setText(String.format("\\%d", pair.heads));
 totalText.setText(String.format("\\%d", pair.total));
 devText.setText(String.format(
 "\\%.10g", ((double) pair.heads)/((double) pair.total) - 0.5));
 \}
 \}
 ,,,

GETTING RESULTS WITH SWINGWORKER ....

 When the SwingWorker completes its work, it makes available the 
 final results with the done() and the get() methods.

 The SwingWorker's get method returns an item of the same type as
 specified as the first type parameter given to the SwingWorker class.

 >> class Worker extends SwingWorker<ArrayList<Integer>, Integer> \{...\}

 The first template argument, in this case, ArrayList<Integer>, is whats
 returned by doInBackground(), and by get(). The second template argument,
 in this case, Integer, is what is published with the publish method. It
 is also the data type which is stored by the java.util.List that is the
 parameter for the process method, which recieves the information
 published by the publish method.

 * using the done() and get() methods to obtain final worker results
 -------------------------------------------------------------
 import javax.swing.*;
 import java.io.*;
 import java.util.*;
 import java.awt.event.*;
 import java.awt.*;
 import java.util.concurrent.ExecutionException;
 public class SomeTask extends SwingWorker<File[], File> \{
 @Override
 protected File[] doInBackground() \{
 File[] list = new File[]\{\};
 while (!this.isCancelled()) \{
 /* do some lengthy task filling File[] array 'list' */
 \}
 return list;
 \}
 
 @Override
 protected void done() \{
 /* here we can update our gui, because this is the EDT */
 System.out.println("doInBackground is complete");
 try \{
 File[] results = this.get();
 for (File f: results) \{ \}
 \} catch (InterruptedException e) \{
 System.out.println("Interrupted: " + e);
 \} catch (ExecutionException e) \{
 System.out.println("Execution: " + e);
 \}
 \}

 \}
 ,,,

CANCELLING A SWINGWORKER THREAD ....

 Its often nice to be able to stop a long running task before it finishes.
 This is called cancelling the task. 
 
 When we call the swingWorker.cancel(true) method, is caused isCancelled()
 method to return true. We call this method frequently in the
 doInBackground() code and stop all work if it returns true.

 * create a button which cancels the SwingWorker
 -------------------------------------------------------------
 JButton b = new JButton("cancel work");
 b.addActionListener(this);
 ...
 @Override
 public void actionPerformed(ActionEvent e) \{
 swingWorker.cancel(true);
 swingWorker = null;
 \}
 ,,,

VERBOSE EXAMPLE ....

 * a verbose example showing how to use the done() method
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.*;
 import java.awt.event.*;
 import java.util.ArrayList;
 
 public class SwingWorkerExample extends JFrame implements ActionListener \{
 
 private static final long serialVersionUID = 1L;
 private final JButton startButton, stopButton;
 private JScrollPane scrollPane = new JScrollPane();
 private JList listBox = null;
 private DefaultListModel listModel = new DefaultListModel();
 private final JProgressBar progressBar;
 private mySwingWorker swingWorker;
 
 public SwingWorkerExample() \{
 super("SwingWorkerExample");
 setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 getContentPane().setLayout(new GridLayout(2, 2));
 startButton = makeButton("Start");
 stopButton = makeButton("Stop");
 stopButton.setEnabled(false);
 progressBar = makeProgressBar(0, 99);
 listBox = new JList(listModel);
 scrollPane.setViewportView(listBox);
 getContentPane().add(scrollPane);
 //Display the window.
 pack();
 setVisible(true);
 \}
 
 private class mySwingWorker extends SwingWorker<ArrayList<Integer>, Integer> \{

 @Override
 protected ArrayList<Integer> doInBackground() \{
 if (SwingUtilities.isEventDispatchThread()) \{
 System.out.println(
 "SwingUtilities.isEventDispatchThread() returned true.");
 \}
 Integer tmpValue = new Integer(1);
 List<Integer> list = new ArrayList<Integer>();
 for (int i = 0; i < 100; i++) \{
 for (int j = 0; j < 100; j++) \{ 
 //find every 100th prime, just to make it slower
 tmpValue = FindNextPrime(tmpValue.intValue());
 if (isCancelled()) \{
 System.out.println("SwingWorker - isCancelled");
 return list;
 \}
 \}
 publish(new Integer(i));
 list.add(tmpValue);
 \}
 return list;
 \}
 
 @Override
 protected void process(java.util.List<Integer> progressList) \{
 if (!javax.swing.SwingUtilities.isEventDispatchThread()) \{
 System.out.println(
 "SwingUtilities.isEventDispatchThread() + returned false.");
 \}
 Integer percentComplete = 
 progressList.get(progressList.size() - 1);
 progressBar.setValue(percentComplete.intValue());
 \}
 
 @Override
 protected void done() \{
 System.out.println("doInBackground is complete");
 if (!SwingUtilities.isEventDispatchThread()) \{
 System.out.println(
 "SwingUtilities.isEventDispatchThread() returned false.");
 \}
 try \{
 ArrayList<Integer> results = get();
 for (Integer i : results) \{
 listModel.addElement(i.toString());
 \}
 \} catch (Exception e) \{
 System.out.println("Caught an exception: " + e);
 \}
 startButton();
 \}
 //... 
 \}
 
 @Override
 public void actionPerformed(ActionEvent e) \{
 if ("Start" == null ? e.getActionCommand() == null : "Start".equals(e.getActionCommand())) \{
 startButton.setEnabled(false);
 stopButton.setEnabled(true);
 // Note that it creates a new instance of the SwingWorker-derived class. Never reuse an old one.
 (swingWorker = new mySwingWorker()).execute(); // new instance
 \} else if ("Stop" == null ? e.getActionCommand() == null : "Stop".equals(e.getActionCommand())) \{
 startButton.setEnabled(true);
 stopButton.setEnabled(false);
 swingWorker.cancel(true); // causes isCancelled to return true in doInBackground
 swingWorker = null;
 \}
 \}
 \}
 
 ,,,

DRAWING WITH JAVA TWO D

 This section will almost exclusively concentrate on the Java2D
 drawing apis instead of the older AWT drawing system. The Java2D
 system allows high quality, antialiased drawing both to the 
 screen and to other output devices, such as printers.
 
 Drawing usually takes place within the 'paint' method of an
 awt component, or within the 'paintComponent' method of a swing
 component. This seems to mean that you have to subclass a component in
 order to draw. See below for specific examples.
 

\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents General drawing procedure:
 .. Create a new shape eg new Ellipse2D.Double(x, y, w, h) 
 .. set the stroke eg g.setStroke(new BasicStroke(...)) 
 .. set the fill on the graphics objects, 
 .. the draw with g.draw(shape) or g.fill(shape)
 ..


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents notes about drawing: 
 .. Swing is doubled buffered by default (according to camickr)
 ..

GRAPHICS2D ....

 The Graphic2D class, which is part of the Java2D api, provides lots
 advantages over the older java.awt.Graphics class. Just one 
 example is using anti-aliasing with text and shape drawing commands.
 (that is the g2d.setRenderingHints() method). Without anti-aliasing
 everything looks pretty terrible.

 @@ \url{http://docstore.mik.ua/orelly/java-ent/jfc/}
 Some chapters from a good, but old book on Java2D

 To take advantage of all these advantages we just cast the Graphics
 object

 * cast a Graphics object to a Graphics2D object when painting a jcomponent
 -----------------------------------------------------
 public void paintComponent(Graphics g) \{
 Graphics2D g2d = (Graphics2D) g;
 ...
 \}
 ,,,

COORDINATE SYSTEM FOR GRAPHICS2D ....

 The coordinate system for the Java 2D api is cartesian, with the origen
 (by default) in the top left corner. Coordinates are measured in pixels
 when drawing to the screen, but in points when drawing to a printer.
 These coordinates are the 'user space' system. Unlike AWT, coordinates
 can be float or double values, to take advantage of very high resolution
 output devices (eg printers). These float values also allow high quality
 transforms of the coordinate system. This is referred to as 
 converting from user space to device space.

 The coordinate system can be transformed by various methods.
 Transformations on the coordinate system are cumulative and are save in
 an AffineTransform object which can be obtained with g2d.getTransform()


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents coordinate transform methods
 .. g2d.translate(x, y) - set the coodinate origen to point (x,y)
 .. g2d.scale() - scale the coordinate system
 .. g2d.rotate(Math.PI/4) - rotate coordinates by 45 degrees about origin
 .. g2d.rotate(r,x,y) - rotate coordinates by radians about point (x,y) 
 .. g2d.shear(float, float) - shear the coordinate system
 ..

 * set the coodinate origen to point (13,10)
 >> g2d.translate(13.0, 10.0) 

 * scale the coordinate system by 2 along both axis
 >> g2d.scale(2.0, 2.0)

 After this method call, the point (0,0) will infact refer to the 
 point (13,10) and all other points will be suitably translated

 * set the origen to lower left corner on a 500x500 pixel screen
 >> g.translate(0.0, 500.0); g.scale(1.0, -1.0);
 
 The negative scaling by 1 means that the y coordinates will increase
 going upwards, instead of downwards (which is the default)

 * save the current transform, apply a new one, and then restore
 -------------------------------------------------------------
 Graphics2D g = ...;
 AffineTransform t = g.getTransform(); 
 g.rotate(theta); 
 g.drawRect(100, 100, 200, 200); 
 g.setTransform(t); 
 ,,,

COORDINATE ROTATIONS ....

 Rotations of the coordinate systems are expressed in radians and
 are about the origin or about a particular point.

 * rotate the coordinate system by 45 degrees about the origin
 >> g2d.rotate(Math.PI/4)

 * rotate the coordinates by 90 degrees about point (20,20) 
 >> g2d.rotate(Math.PI/4, 20, 20)

 * draw some text at 45 degrees and then restore the default coordinates
 -------------------------------------------------------------
 import java.awt.*;
 import java.awt.geom.*;
 import javax.swing.*;
 public class RotateCoords extends JPanel \{
 public void paintComponent(Graphics g) \{
 super.paintComponent(g);
 Graphics2D gg = (Graphics2D) g;
 gg.setRenderingHint(
 RenderingHints.KEY\\_ANTIALIASING, RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 gg.setFont(new Font("Georgia", Font.ITALIC, 30));
 gg.drawString("Hello world", 30, 30);
 gg.rotate(Math.PI/4);
 gg.drawString("Hello world", 30, 30);
 gg.rotate(-Math.PI/4);
 \}
 public Dimension getPreferredSize() \{ return new Dimension(400, 400); \}
 public static void main(String[] args) \{
 JOptionPane.showMessageDialog(null, new RotateCoords());
 \}
 \}
 ,,,

DRAWING TEXT ....

 \url{http://docstore.mik.ua/orelly/java-ent/jfc/ch04\\_09.htm}
 stuff about glyph vectors etc.

GLYPHVECTORS ....

 A glyph vector (java.awt.font.GlyphVector) is a kind of precalculated set
 of glyph measurements for a particular (one-line?) string and one font.
 GlyphVectors are useful for creating Shapes, Areas and Images from 
 text or characters.

 The GlyphVector is created using a FontRenderContext object which
 contains, for example, information about whether anti-aliasing or
 fractional metrics are currently in use for the given Font.

 Apparently creating a GlyphVector can speed up drawing text for a
 particular Font and String but its hard to see when that would be
 important


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents useful methods for GlyphVector
 .. getOutline() - returns a Shape representing the text
 .. getGlyphOutline(1) - a Shape of the 2nd glyph in the string
 .. getGlyphMetrics() - gets detailed measurements for one Glyph
 .. setGlyphPosition() - adjust position of one glyph in the vector
 .. setGlyphTransform() - add an AffineTransform to one glyph 
 .. 

 See also java.awt.font.TextLayout for multifont vectors and
 java.awt.font.LineBreakMeasurer for multiline vectors.

 * create a glyph vector for the text 'hello' 
 -----------------------------------------------
 GlyphVector msg = 
 font.createGlyphVector(g.getFontRenderContext(), "Hello");
 g.drawGlyphVector(msg, 100.0f, 100.0f);
 ,,,

 * a complete text art example 
 -------------------------
 import java.awt.*;
 import java.awt.geom.*;
 import java.awt.font.GlyphVector;
 import javax.swing.*;
 public class TextArt extends JPanel \{
 public void paintComponent(Graphics g) \{
 Graphics2D gg = (Graphics2D) g;
 gg.setRenderingHint(RenderingHints.KEY\\_ANTIALIASING,
 RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 Font font = new Font("Georgia", Font.ITALIC, 10); 
 Font bigfont = font.deriveFont(
 AffineTransform.getScaleInstance(25.0, 25.0));
 GlyphVector gv = bigfont.createGlyphVector(
 gg.getFontRenderContext(), "Hello");
 Shape outline = gv.getOutline();
 gg.translate(10,300); 
 gg.setStroke(new BasicStroke(5));
 gg.setColor(Color.gray);
 gg.draw(outline);
 \}
 public Dimension getPreferredSize() \{ return new Dimension(600, 800); \}
 public static void main(String[] args) \{ 
 JOptionPane.showMessageDialog(null, new TextArt());
 \}
 \}
 ,,,

 * create shapes from character glyphs and then use those shapes to draw
 -------------------------
 Graphics2D g;
 Font font = new Font("Serif", Font.BOLD, 10); // a basic font
 Font bigfont =
 font.deriveFont(AffineTransform.getScaleInstance(30.0, 30.0));
 GlyphVector gv = 
 bigfont.createGlyphVector(g.getFontRenderContext(), "JAV");
 Shape jshape = gv.getGlyphOutline(0); // Shape of letter J
 Shape ashape = gv.getGlyphOutline(1); // Shape of letter A
 Shape vshape = gv.getGlyphOutline(2); // Shape of letter V
 g.fill(jshape);
 ,,,

TEXTLAYOUTS ....

 A java.awt.font.TextLayout is a way of drawing (with a Graphics2D 
 object) strings of text in multiple fonts. It supports bi-directional
 text (mixing English with Arabic for example)

ANTIALIASING ....

 Antialiasing is a technique for smoothing curves. Antialiasing makes
 everything look much nicer so there is really no reason why you would not
 use it, ever.

 * turn on antialiasing for all drawing operations
 >> g2.setRenderingHint(
 >> RenderingHints.KEY\\_ANTIALIASING, RenderingHints.VALUE\\_ANTIALIAS\\_ON);

 With java2D text can also be antialiased

 * turn on antialiasing for text (with g2d.drawString()) 
 ---------------------------------------------------------
 graphics2D.setRenderingHint(
 RenderingHints.KEY\\_TEXT\\_ANTIALIASING,
 RenderingHints.VALUE\\_TEXT\\_ANTIALIAS\\_ON);
 ,,,

 This doesnt seem to affect text in JTextComponents or JLabels etc.

 * draw shapes with antialiasing and without, to see the difference
 -------------------------------------------------------------
 import java.awt.*;
 import java.awt.geom.*;
 import javax.swing.*;
 public class AntialiasDraw extends Component \{ 
 public void paint(Graphics g) \{ 
 Graphics2D g2 = (Graphics2D) g;
 g2.setStroke(new BasicStroke(20));
 g2.draw(new RoundRectangle2D.Double(0, 0, 200, 200, 40, 40));
 g2.draw(new Ellipse2D.Double(10, 20, 180, 120)); 
 CubicCurve2D c = new CubicCurve2D.Double();
 c.setCurve(80, 80, 100, 100, 120, 60, 150, 80);
 g2.draw(c);
 g2.setRenderingHint(
 RenderingHints.KEY\\_ANTIALIASING, RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 g2.draw(new RoundRectangle2D.Double(240, 0, 440, 200, 40, 40));
 g2.draw(new Ellipse2D.Double(250, 20, 420, 120)); 
 CubicCurve2D d = new CubicCurve2D.Double();
 d.setCurve(320, 80, 340, 100, 360, 60, 390, 80);
 g2.draw(d);
 \}
 public AntialiasDraw() \{\}
 public Dimension getPreferredSize() \{ return new Dimension(800, 300); \}
 public static void main(String[] args) \{ 
 JFrame f = new JFrame("Drawing Shapes");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.getContentPane().add(new AntialiasDraw());
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

ARCS ....

 * draw a filled arc and get its start point
 -------------------------------------------
 Graphics2D g2 = (Graphics2D) g;
 Arc2D arc = new Arc2D.Float(x, y, n, m, w, z, Arc2D.PIE);
 g2.fill(arch);
 Point2D p = arch.getStartPoint();
 ,,,

BEZIER CURVES ....
 
 Quadratic Bezier curves use one control point
 Cubic Bezier curves use two control points

QUADRATIC BEZIER CURVES ....

 A parabola is an example of a quadratic curve. In java, these curves have
 2 end points and a point of inflexion (where the curve bends).

 * draw a quadratic curve
 -------------------------------------------------------------
 QuadCurve2D q = new QuadCurve2D.Float();
 q.setCurve(0, 0, 80, 80, 160, 0);
 g2.draw(q);
 ,,,

 >> q.setCurve(x1, y1, controlx, controly, x2, y2); 


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents quadratic curve parameters
 .. x1 y1 - the first end point of the curve
 .. controlx controly - the point of inflexion of the curve
 .. x2 y2 - the 2nd end point of the curve
 ..

CUBIC BEZIER CURVES ....

 // c.setCurve(x1, y1, ctrlx1, ctrly1, ctrlx2, ctrly2, x2, y2);

GENERALPATHS ....

 A GeneralPath which is a java.awt.geom.GeneralPath is a specific type
 of java.awt.Shape . By using moveTo(), lineTo(), quadTo() and 
 curveTo() a complex Shape can be constructed. Also one can add 
 other shapes to the path.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents GeneralPath methods
 .. moveTo(10.0f, 20.0f) - Moves to point 
 .. lineTo(float x, float y) - Adds a line segment to the current path
 .. quadTo(float ctrlx, float ctrly, float x2, floaty2) Adds a quadratic bezier curve segment to the current path
 curveTo(float ctrlx1, float ctrly1, float ctrlx2, float ctrly2, float x3, floaty3) - Adds a cubic bezier curve segment to the current path
 .. closePath() Closes the current path and makes a closed Shape
 ..

 * draw a polygon using the GeneralPath class
 --------------------------------------------
 import java.awt.*;
 import java.awt.geom.*;
 import javax.swing.*;
 public class PolyDraw extends Component \{ 
 public void paint(Graphics g) \{ 
 Graphics2D g2 = (Graphics2D) g;
 g2.setStroke(new BasicStroke(5));
 int x1Points[] = \{0, 100, 0, 100\};
 int y1Points[] = \{0, 50, 50, 0\};
 GeneralPath polygon = 
 new GeneralPath(GeneralPath.WIND\\_EVEN\\_ODD, x1Points.length);
 polygon.moveTo(x1Points[0], y1Points[0]);
 for (int index = 1; index < x1Points.length; index++) \{
 polygon.lineTo(x1Points[index], y1Points[index]);
 \};
 polygon.closePath();
 g2.draw(polygon);
 \}
 public PolyDraw() \{ \}
 public Dimension getPreferredSize() \{ return new Dimension(250, 250); \}
 public static void main(String[] args) \{ 
 JFrame f = new JFrame("Drawing a Polygon");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.getContentPane().add(new PolyDraw());
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

EXAMPLES ....

 * draw a line
 ------------------------------
 public void paint (Graphics g) \{
 Graphics2D g2 = (Graphics2D) g;
 g2.draw(new Line2D.Double(x1, y1, x2, y2));
 \}
 ,,,

 The getPreferredSize() method is necessary because otherwise the java jre
 doesnt know how big to make the window, and makes it very small.

 * draw a line on a component using the Graphics2D class
 ----------------------
 import java.awt.*;
 import java.awt.geom.*;
 import javax.swing.*;
 public class LineDraw extends Component \{ 
 public void paint(Graphics g) \{ 
 Graphics2D g2 = (Graphics2D) g;
 g2.draw(new Line2D.Double(0, 0, 200, 200));
 \}
 public LineDraw() \{ \}
 public Dimension getPreferredSize() \{ return new Dimension(220, 220); \}
 public static void main(String[] args) \{ 
 JFrame f = new JFrame("Drawing a Line");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.getContentPane().add(new LineDraw());
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

 * draw a rounded rectangle, an oval and a quadratic curve
 -------------------------------------------------------------
 import java.awt.*;
 import java.awt.geom.*;
 import javax.swing.*;
 public class LineDraw extends Component \{ 
 public void paint(Graphics g) \{ 
 Graphics2D g2 = (Graphics2D) g;
 g2.setRenderingHint(
 RenderingHints.KEY\\_ANTIALIASING, RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 g2.setStroke(new BasicStroke(5));
 g2.draw(new RoundRectangle2D.Double(0, 0, 200, 200, 40, 40));
 g2.draw(new Ellipse2D.Double(10, 20, 180, 120)); 
 QuadCurve2D q = new QuadCurve2D.Float();
 q.setCurve(0, 0, 80, 80, 160, 0);
 g2.draw(q);
 CubicCurve2D c = new CubicCurve2D.Double();
 c.setCurve(80, 80, 100, 100, 120, 60, 150, 80);
 g2.draw(c);
 \}
 public LineDraw() \{ \}
 public Dimension getPreferredSize() \{ return new Dimension(250, 250); \}
 public static void main(String[] args) \{ 
 JFrame f = new JFrame("Drawing a Line");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.getContentPane().add(new LineDraw());
 f.pack();
 f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

 * draw with a thick stroke and colours and gradient colours
 -------------------------------------------------------------
 import java.awt.*;
 import java.awt.geom.*;
 import javax.swing.*;
 public class Draw extends Component \{ 
 public void paint(Graphics g) \{
 Graphics2D g2 = (Graphics2D)g;
 Line2D line = new Line2D.Double(10, 10, 40, 40);
 g2.setColor(Color.blue);
 g2.setStroke(new BasicStroke(10));
 g2.draw(line);
 Rectangle2D rect = new Rectangle2D.Double(20, 20, 100, 100);
 g2.draw(rect);
 g2.setPaint(new GradientPaint(0, 0, Color.blue, 50, 25, Color.green, true));
 g2.fill(rect);
 \}
 public Draw() \{ \}
 public Dimension getPreferredSize() \{ return new Dimension(150, 150); \}
 public static void main(String[] args) \{ 
 JFrame f = new JFrame("Drawing a Line");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.getContentPane().add(new Draw());
 f.pack();
 f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

STROKES ....

 The stroke of a line or curve refers to its thickness, texture etc. By
 defining new strokes it is possible to create dotted lines, textured lines.
 The simplest technique is to use the BasicStroke class, and for more
 complicated needs, one can implement a stroke class. The stroke is set on
 the graphics object and then applies for all drawing operations until the
 stroke is changed.

 * set the stroke to 40 pixels wide
 >> g2d.setStroke(new BasicStroke(40));

 * draw with a thick stroke using the BasicStroke class
 -------------------------------------------------------------
 import java.awt.*;
 import java.awt.geom.*;
 import javax.swing.*;
 public class ThickStroke extends JComponent \{ 
 public void paintComponent(Graphics g) \{
 Graphics2D g2 = (Graphics2D)g;
 g2.setRenderingHint(
 RenderingHints.KEY\\_ANTIALIASING, RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 RoundRectangle2D rect = 
 new RoundRectangle2D.Double(40, 40, 300, 300, 80, 80);
 g2.setStroke(new BasicStroke(40));
 g2.setColor(Color.darkGray);
 g2.draw(rect);
 \}
 public ThickStroke() \{\}
 public Dimension getPreferredSize() \{ return new Dimension(400, 400); \}
 public static void main(String[] args) \{ 
 JFrame f = new JFrame("Thick Strokes");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.getContentPane().add(new ThickStroke());
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

 * draw a rounded rectangle with a dashed (10px blank) line 6 pixels wide
 -------------------------------------------------------------
 import java.awt.*;
 import java.awt.geom.*;
 import javax.swing.*;
 public class DashStroke extends JComponent \{ 
 public void paintComponent(Graphics g) \{
 Graphics2D g2 = (Graphics2D)g;
 g2.setRenderingHint(
 RenderingHints.KEY\\_ANTIALIASING, RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 RoundRectangle2D rect = 
 new RoundRectangle2D.Double(40, 40, 300, 300, 80, 80);
 BasicStroke dashed = new BasicStroke(
 6, BasicStroke.CAP\\_BUTT, BasicStroke.JOIN\\_MITER, 
 10.0f, new float[]\{10.0f\}, 0.0f);
 g2.setStroke(dashed); g2.setColor(Color.darkGray);
 g2.draw(rect);
 \}
 //public DashStroke() \{\}
 public Dimension getPreferredSize() \{ return new Dimension(400, 400); \}
 public static void main(String[] args) \{ 
 JOptionPane.showMessageDialog(null, new DashStroke());
 \}
 \}
 ,,,

BASICSTROKES ....

 BasicStrokes are immutable- they have no set() methods. So instances
 can be shared.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents BasicStroke end-cap attribute, where a line ends
 .. BasicStroke.CAP\\_BUTT - not line 'cap', line ends at point specified 
 .. BasicStroke.CAP\\_SQUARE - line projects beyond end point, square end
 .. BasicStroke.CAP\\_ROUND - line projects beyond end point, round end
 .. 


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents BasicStroke join-style values, where 2 lines meet
 .. JOIN\\_BEVEL - a flat corner a little beyond the join point
 .. JOIN\\_MITER - a pointed corner just beyond the join point (default)
 .. JOIN\\_ROUND - a round corner just beyond the join point.
 ..

 * a BasicStroke example with no dash parameters
 -------------------------------------------------------------
 g.setStroke(new BasicStroke(
 5.0f, // The pixel width of the line 
 BasicStroke.CAP\\_ROUND, // how lines end 
 BasicStroke.JOIN\\_ROUND)); // how lines are joined together 
 ,,,

STROKE INTERFACE ....

 We can also create new strokes by implementing the stroke interface.
 which only involves implementing one method createStrokedShape()

DASHED STROKES ....

 The BasicStroke can also take a dash array and a dash phase parameter.
 The dash phase is useful for creating animations (see the marching
 ants example). 

 The dash pattern array can consist in any number of values indicating
 alternate dashes and gaps.

 * a dash pattern: draw 21px, blank 9px, draw 3px, blank 9px
 >> new float[] \{21.0f, 9.0f, 3.0f, 9.0\}

 * a BasicStroke with miter limit and dash pattern
 -------------------------------------------------------------
 Stroke s = new BasicStroke(
 4.0f, // width of the line 
 BasicStroke.CAP\\_SQUARE, // extend line end in square ending 
 BasicStroke.JOIN\\_MITER, // join lines with points 
 10.0f, // truncate miter if longer than 10px 
 new float[] \{16.0f, 20.0f\},// draw 16pixels, blank 20pixels 
 0.0f); // Dash phase (start position in pixels)
 ,,,

FILLING SHAPES ....

 Filling refers to painting the interior of a shape with a colour, 
 a colour gradient or a texture.

 The .fill method draws the interior of a shape but not its border

 To create a GradientPaint, you specify a beginning position and
 color and an ending position and color. The gradient changes
 proportionally from one color to the other color along the line
 connecting the two positions.

 The position parameters for the gradient paint appear to be
 absolute, not relative to the shape you are trying to paint.

 * paint a rounded rectangle with gradient paint with no border 
 -------------------------------------------------------------
 import java.awt.*;
 import java.awt.geom.*;
 import javax.swing.JFrame;
 public class Draw extends Component \{ 
 public void paint(Graphics g) \{
 Graphics2D g2 = (Graphics2D)g;
 GradientPaint grad = new GradientPaint(20,20,Color.BLUE,180, 180,Color.WHITE);
 g2.setPaint(grad);
 g2.fill(new RoundRectangle2D.Double(40, 40, 140, 140, 30, 30));
 \}
 public Draw() \{ \}
 public Dimension getPreferredSize() \{ return new Dimension(200, 200); \}
 public static void main(String[] args) \{ 
 JFrame f = new JFrame("Strokes");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.getContentPane().add(new Draw());
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

 The example above uses the technique of placing the gradient end points
 outside of the shape to make the gradient more subtle. A better way would
 be to use colour shades which are closer together

 The following is an attempt to produce the bulgeing effect that is common
 in interfaces these days, but doesnt quite work.

 * a horizontal bar with a vertical green gradient paint 
 -------------------------------------------------------------
 import java.awt.*;
 import java.awt.geom.*;
 import javax.swing.JFrame;
 public class Draw extends Component \{ 
 public void paint(Graphics g) \{
 Graphics2D g2 = (Graphics2D)g;
 Color limeGreen = new Color(Integer.decode("\\#32cd32"));
 Color drabOlive = new Color(Integer.decode("\\#6b8e23"));
 //Color lawnGreen = new Color(Integer.decode("\\#7CFC00"));
 //Color yellowGreen = new Color(Integer.decode("\\#ADFF2F"));
 GradientPaint grad = 
 new GradientPaint(20, 20, limeGreen, 20, 40, drabOlive);
 g2.setPaint(grad);
 g2.fill(new Rectangle2D.Double(20, 20, 500, 40));
 \}
 public Draw() \{ \}
 public Dimension getPreferredSize() \{ return new Dimension(550, 100); \}
 public static void main(String[] args) \{ 
 JFrame f = new JFrame("Strokes");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.getContentPane().add(new Draw());
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

 * draw a dashed rounded rectangle and filled with a gradient paint
 -------------------------------------------------------------
 import java.awt.*;
 import java.awt.geom.*;
 import javax.swing.JFrame;
 public class Draw extends Component \{ 
 public void paint(Graphics g) \{
 Graphics2D g2 = (Graphics2D)g;
 RoundRectangle2D rect = 
 new RoundRectangle2D.Double(40, 40, 200, 200, 80, 80);
 float dash1[] = \{10.0f\};
 BasicStroke dashed = new BasicStroke(
 6, BasicStroke.CAP\\_BUTT, BasicStroke.JOIN\\_MITER, 10.0f, dash1, 0.0f);
 g2.setStroke(dashed);
 g2.draw(rect);
 GradientPaint grad = new GradientPaint(0,0,Color.GREEN,200, 0,Color.WHITE);
 g2.setPaint(grad);
 g2.fill(rect);
 \}
 public Draw() \{ \}
 public Dimension getPreferredSize() \{ return new Dimension(400, 400); \}
 public static void main(String[] args) \{ 
 JFrame f = new JFrame("Strokes");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.getContentPane().add(new Draw());
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

SHAPES ....

 A Shape or java.awt.Shape is an interface which represents either
 an open curve or else a closed area. With an AffineTransform we 
 can scale, rotate, translate, and shear Shapes.

 \url{http://docstore.mik.ua/orelly/java-ent/jfc/ch04\\_04.htm}
 A good chapter on shapes.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents methods operating on shapes
 .. g2d.fill(shape) - fills with a colour or paint, closes an open shape
 .. g2d.draw(shape) - draws the outline of the shape
 .. g2d.clip(shape) - restricts drawing area to the shape bounds
 .. g2d.hit(...) - check if a rectangle touches a shape


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents some shape implementations in java.awt and java.awt.geom
 .. java.awt.Rectangle, Rectangle2D.Float, Rectangle2D.Double - Rectangle 
 .. java.awt.Polygon - Polygon 
 .. RoundRectangle2D.Float, RoundRectangle2D.Double - Rounded rectangle
 .. Ellipse2D.Float, Ellipse2D.Double - Ellipse (and circle) 
 .. Line2D.Float, Line2D.Double - Line segment 
 .. Arc2D.Float, Arc2D.Double - Arc (ellipse segment) 
 .. QuadCurve2D.Float, QuadCurve2D.Double - Bezier curve (quadratic) 
 .. CubicCurve2D.Float, CubicCurve2D.Double - Bezier curve (cubic) 
 ..

 With ovals or ellipses, the x and y parameters represent the top left
 hand corner of the bounding rectangle for the ellipse (not its centre).

 * create a square shape
 >> Shape square = new Rectangle2D.Float(100.0f, 100.0f, 100.0f, 100.0f);

 * create a shape by subtracting one area from another
 -------------------------
 Area area = new Area(new Rectangle2D.Double(...));
 Area inner = new Area(new Rectangle2D.Double(...));
 area.subtract(inner);
 ,,,

 * create a shape (based on some text) and draw it on an image with a stroke
 ------------------------------
 final BufferedImage textImage = new BufferedImage(
 width, height, BufferedImage.TYPE\\_INT\\_ARGB);
 Graphics2D g = textImage.createGraphics();
 FontRenderContext frc = g.getFontRenderContext();
 Font font = new Font("Arial", Font.BOLD, 250);
 GlyphVector gv = font.createGlyphVector(frc, "Cat");
 Rectangle2D box = gv.getVisualBounds();
 int xOff = 25+(int)-box.getX();
 int yOff = 80+(int)-box.getY();
 Shape shape = gv.getOutline(xOff,yOff);
 g.setColor(Color.WHITE);
 //g.setClip(null);
 g.setStroke(new BasicStroke(2f));
 g.setColor(Color.BLACK);
 g.setRenderingHint(
 RenderingHints.KEY\\_ANTIALIASING,
 RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 g.draw(shape);
 g.dispose();
 ,,,

 The code above draws the word cat in a big hollow font (its not really a font)

 * create a shape by adding two contigous areas, java2d
 ---------------------------------------
 Graphics2D g2d = (Graphics2D) g;
 // turn Anti-aliasing on to make the corners smooth
 g2d.setRenderingHint(RenderingHints.KEY\\_ANTIALIASING, RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 g2d.setStroke(new BasicStroke(2));
 g.setColor(Color.BLACK);
 // create the callout "tip"
 int tipCenter = x+width/3;
 GeneralPath p = new GeneralPath();
 p.moveTo(tipCenter-insets.top/2, y+insets.top/2);
 p.lineTo(tipCenter, 0);
 p.lineTo(tipCenter+insets.top/2, y+insets.top/2);
 p.closePath();
 // create the shape
 RoundRectangle2D rect = new RoundRectangle2D.Double(x, y+insets.top/2, width-1, height-1-insets.top/2, 20, 20);
 Area area = new Area(rect);
 area.add( new Area(p) );
 g2d.draw(area); // draw the shape
,,,

AREAS ....

 Areas (java.awt.geom.Areas) are a particular type of java.awt.Shape (they
 implement the Shape interface) and they allow one to define areas by
 subtracting or by the union of other areas or shapes. Unlike Shapes,
 Areas are alway closed. An interesting point is that if an Area is
 constructed from several intersecting shapes, it will form a single non
 intersecting area.

 Like Shapes we can scale, rotate, translate and shear areas with 
 an AffineTransform.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents interesting Area methods
 .. new Area(shape) - make a new Area from a Shape
 .. getBounds2D() - get a Rectangle2D which just encloses this area 
 .. isRectangular() - tests if this Area is a rectangle
 .. intersect(area) - sets the area to intersection of this and other
 ..


 * define and show a shape (area) which is a square less a circle 
 -------------------------------------------------------------
 import javax.swing.*;
 import java.awt.geom.*;
 import java.awt.*;
 public class SubtractArea extends JPanel \{
 protected void paintComponent(Graphics g) \{
 super.paintComponent(g);
 Graphics2D g2d = (Graphics2D) g;
 g2d.setRenderingHint(RenderingHints.KEY\\_ANTIALIASING,
 RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 Shape square = new Rectangle2D.Float(100.0f, 100.0f, 100.0f, 100.0f);
 Shape circle = new Ellipse2D.Float(100.0f, 100.0f, 100.0f, 100.0f);
 Area area = new Area(square);
 area.subtract(new Area(circle));
 g2d.fill(area);
 \}
 public Dimension getPreferredSize() \{ return new Dimension(400, 600); \}
 public static void main(String[] args) \{ 
 JOptionPane.showMessageDialog(null, new SubtractArea());
 \}
 \}
 
 ,,,

GRADIENT PAINTS ....

 GradientPaints are either cyclic or acyclic. Interesting effects 
 can be achieved by creating gradient paints with translucent colours
 (colours which will be blended with the component background colour)

 The technique below creates a nice looking gradient for 
 a professional looking interface.

 * a trick to create nice gradients
 -------------------------------------------------------------
 GradientPaint gp = new GradientPaint(0, 0,
 getBackground().brighter().brighter(), 0, getHeight(),
 getBackground().darker().darker());
 ,,,

 A problem with the following example is that if the background color is
 already as bright as possible (for example rgb(255,0,0) then the
 brighter() method does nothing, and therefor the GradientPaint will have
 much less 'range' of color than otherwise.

 * a complete gradient paint example using brighter etc
 ------------------------------------------------------
 import java.awt.*;
 import javax.swing.*;
 public class GradientBackgroundDemo \{
 public static void main(String args[]) \{
 JFrame f = new JFrame("Gradient Background Demo");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 JPanel contentPane = new JPanel() \{
 @Override
 protected void paintComponent(Graphics g) \{
 Graphics2D g2d = (Graphics2D) g;
 g2d.setRenderingHint(RenderingHints.KEY\\_ANTIALIASING,
 RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 GradientPaint gp = new GradientPaint(0, 0,
 getBackground().brighter().brighter(), 0, getHeight(),
 getBackground().darker().darker());
 g2d.setPaint(gp);
 g2d.fillRect(0, 0, getWidth(), getHeight());
 super.paintComponent(g);
 \}
 \};
 contentPane.setOpaque(false);
 contentPane.setBackground(Color.green);
 f.setContentPane(contentPane);
 contentPane.add(new JLabel("A Gradient Paint"));
 f.setSize(200, 200);
 f.setVisible(true);
 \}
 \}
,,,

 Setting opaque to false is vital in the above example to 
 stop swing painting a solid colour with super.paintComponent
 On my linux computer I cant see any difference with antialiasing
 switched on or off
 >> g2d.setRenderingHint(RenderingHints.KEY\\_ANTIALIASING, ....);

 * a gradient paint from red to orange, top left to bottom right
 ---------------------------
 Graphics2D imageGraphics = image.createGraphics();
 GradientPaint gp = new GradientPaint(
 20f, 20f, Color.red, 380f, 280f, Color.orange);
 imageGraphics.setPaint(gp);
 imageGraphics.fillRect(0, 0, 400, 300);
 ,,,

 The above is a reasonably nice effect

 * another type of gradient paint with several colors\\$\\backslash\\$
 ---------------
 Color[] colors = \{ Color.RED, Color.YELLOW, Color.GREEN \};
 g2.setPaint(new LinearGradientPaint(start, end, dist, colors));
 g2.fillRect(x, y, 100, 10);
 ,,,

 * draw a box with a green gradient paint
 --------------------
 // This one alternates between deep opaque green and transparent green.
 // Note: the 4th arg to Color() constructor specifies color opacity
 g.setPaint(new GradientPaint(0, 0, new Color(0, 150, 0),
 20, 20, new Color(0, 150, 0, 0), true));
 g.setStroke(new BasicStroke(15)); // use wide lines
 g.drawRect(25, 25, WIDTH-50, HEIGHT-50); // draw the box
 ,,,

 * make a radial paint
 >> RadialPaint

 * CompoundPaint can use several different types of paint

CYCLIC GRADIENTPAINTS ....

 * paint a square with a diagonal cyclic gradient paint
 --------------------------------------------------
 import java.awt.*;
 import javax.swing.*;
 public class CyclicPaint extends JPanel \{
 public void paintComponent(Graphics g) \{
 super.paintComponent(g);
 Graphics2D gg = (Graphics2D) g;
 Paint p =
 new GradientPaint(0, 0, Color.red, 50, 50, Color.pink, true);
 gg.setPaint(p);
 gg.fillRect(0, 0, 300, 300);
 \}
 public Dimension getPreferredSize() \{ return new Dimension(400, 400); \}
 public static void main(String[] args) \{
 JOptionPane.showMessageDialog(null, new CyclicPaint());
 \}
 \}
 ,,,

TEXTURE PAINTS ....

 Another technique for filling shapes is to tile an image within the
 shape. This uses the TexturePaint class.

 The pattern for the tiling of a TexturePaint class is defined by a
 BufferedImage class. To create a TexturePaint object, you specify
 the image that contains the pattern and a Rectangle2D that is used to
 replicate and anchor the pattern. Then you use the setPaint() method
 as for gradient paints

ADVANCED PAINTING ....

 If none of the available painting classes is suitable, you may
 implement the Paint interface, and pass your class to the setPaint
 method of the graphics object
 
DRAWING ONTO IMAGES ....

 It is possible to draw onto a blank image. The purpose of this is to
 allow you to save the drawing.

 * skeleton code
 -------------------------------------------------------------
 import java.awt.image.*;
 class Painting extends JPanel \{
 BufferedImage grid; // declare the image
 public void paintComponent(Graphics g) \{
 super.paintComponent(g); // paint background
 Graphics2D g2 = (Graphics2D)g; // we need a Graphics2D context
 if (grid == null) \{
 // Compute the grid only one time
 int w = this.getWidth();
 int h = this.getHeight();
 grid = (BufferedImage)(this.createImage(w,h));
 Graphics2D gc = grid.createGraphics();
 for (int x=0; x<w; x+=10) \{
 gc.drawLine(x, 0, x, h);
 \}
 for (int y=0; y<h; y+=10) \{
 gc.drawLine(0, y, w, y);
 \}
 \}
 // Draw the grid from the precomputed image
 g2.drawImage(grid, null, 0, 0);
 . . . // d
 incomplete
 
 ,,,

 * draw a filled rectangle onto a buffered image and display in JLabel
 --------------------------------- 
 BufferedImage bi = new BufferedImage(200,200,BufferedImage.TYPE\\_INT\\_ARGB);
 Graphics2D g = bi.createGraphics();
 GradientPaint gp = new GradientPaint(
 20f,20f,Color.red, 180f,180f,Color.yellow);
 g.setPaint(gp);
 g.fillRect(0,0,200,200);
 ImageIcon ii = new ImageIcon(bi);
 JLabel imageLabel = new JLabel(ii);
 ,,,

 Why does A. Thompson use an argb image here, and not an rgb image?
 that is the question.


TRANSFORMS ....

 * a tutorial on transforming shapes with Graphics2D
 >> \url{http://docs.oracle.com/javase/tutorial/2d/advanced/transforming.html}

 * how to use the AffineTransform with Graphics2D
 >> \url{http://docs.oracle.com/javase/7/docs/api/java/awt/geom/AffineTransform.html}


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents some transformation methods for the Graphics2D class
 .. rotate()
 .. scale()
 .. translate()
 .. translate(AffineTransform)
 ..

AWT DRAWING ....

 The old awt drawing methods are extremely limited. Here is an 
 example 

 * draw a some shapes using the old awt graphics class (limited) 
 -------------------------------------------------------------
 import java.awt.*;
 import java.awt.geom.*;
 import javax.swing.*;
 public class ShapeDraw extends Component \{ 
 public void paint(Graphics g) \{
 g.drawLine(10,10,40,40);
 g.drawRect(20, 20, 100, 100);
 g.fillRect(120, 120, 200, 200);
 \}
 public ShapeDraw() \{\}
 public Dimension getPreferredSize() \{ return new Dimension(400, 600); \}
 public static void main(String[] args) \{ 
 JFrame f = new JFrame("Drawing Stuff");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.getContentPane().add(new ShapeDraw());
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

IMAGES

IMAGE INFORMATION ....
 
 * read an image from a url and get its height and width
 -----------------
 URL url = new URL("http://i.stack.imgur.com/Nqf3H.jpg");
 final BufferedImage originalImage = ImageIO.read(url);
 int width = originalImage.getWidth();
 int height = originalImage.getHeight();
 ,,,

 * create a new image icon
 >> ImageIcon i = new ImageIcon(imgURL, "some image"); 

 * get an image size without reading the whole image
 --------------
 ImageInputStream in = ImageIO.createImageInputStream(resourceFile);
 try \{
 final Iterator readers = ImageIO.getImageReaders(in);
 if (readers.hasNext()) \{
 ImageReader reader = (ImageReader) readers.next();
 try \{
 reader.setInput(in);
 return new Dimension(reader.getWidth(0), reader.getHeight(0));
 \}
 finally \{ reader.dispose(); \}
 \}
 \}
 finally \{if (in != null) in.close(); \}
,,,

 * load an image into a component 
 --------------------------------
 import java.awt.*;
 import java.awt.event.*;
 import java.awt.image.*;
 import java.io.*;
 import javax.imageio.*;
 import javax.swing.*;

 public class ImageApp extends Component implements KeyListener \{ 
 BufferedImage img;
 File[] imageList;
 public ImageApp() \{
 try \{ this.img = ImageIO.read(new File("test.jpg"));\}
 catch (IOException e) \{ System.out.println("Image File not found"); \}
 // this.addKeyListener(this);
 \}
 
 public void paint(Graphics g) \{ 
 g.drawImage(
 img, 0, 0, 400, (img.getHeight() * 400)/img.getWidth(), null);
 g.setFont(new Font("Georgia", Font.ITALIC, 20));
 g.drawString("Hello graphics", 20, 30); 
 \}
 
 public void keyTyped(KeyEvent e) 
 \{
 char key = e.getKeyChar();
 System.out.println("key typed:" + key); 
 switch (key)
 \{
 case 'h': 
 this.setVisible(false);
 break;
 case 'l': 
 JFileChooser c = new JFileChooser();
 c.setFileSelectionMode(JFileChooser.DIRECTORIES\\_ONLY);
 int result = c.showOpenDialog(this);
 java.io.File folder = c.getSelectedFile();
 System.out.println("folder selected:" + folder ); 
 this.imageList = folder.listFiles();
 System.out.println("Files:" + java.util.Arrays.toString(this.imageList));
 break;
 default:
 break;
 \}
 \}
 public void keyPressed(KeyEvent e) \{\} 
 public void keyReleased(KeyEvent e) \{\}
 
 public Dimension getPreferredSize() \{
 if (img == null) \{
 return new Dimension(100,100);
 \} else \{
 //return new Dimension(img.getWidth(null), img.getHeight(null));
 return new Dimension(400, 600);
 \}
 \}
 
 public static void main(String[] args) \{ 
 JFrame f = new JFrame("Load Image Sample");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 ImageApp li = new ImageApp();
 f.add(li);
 f.addKeyListener(li);
 li.requestFocusInWindow();
 f.pack();
 f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \}
 ,,,

LOADING IMAGES ....

 * load an image
 ------------------------
 try \{ img = ImageIO.read(new File("villa.jpg"));\}
 catch (IOException e) \{ System.out.println("Image File not found"); \}
 ,,,

 Trying to read a file which is not an image but exists, doesnt seem to
 throw an IOException, it just leaves the image object as null.

 * The 'im' object will be null after the following statement
 >> Buffered im = ImageIO.read("doc.pdf"); 

 * load an image from a jar file
 ----------------
 java.net.URL imgURL = ImageDemo.class.getResource("path/to/image");
 if (imgURL != null)
 \{ return new ImageIcon(imgURL, "a description"); \}
 else \{
 System.err.println("Couldn't find file: " + path);
 return null;
 \}
 ,,,
 
PROGRESS OF IMAGE OPERATIONS ....

 Operations on images may well take noticeable time. For that reason
 it would usually be a good idea do display to the user some indication
 of progress during the read/write/filter operation. This can be done
 with interfaces such as IIOReadProgressListener added to an ImageReader
 object, or and IIOWriteProgressListener added to an ImageWriter (?) 
 object.

 See the jprogressbar section for another example of displaying progress
 using a SwingWorker thread.

 The code below works but seems unnecessarily complicated. Need
 to simplify. Also, there is a problem when painting the JPanel- it
 appears to only paint the BorderLayout.CENTER part of the panel.

 * an image load with progress bar and swingworker, working
 -------------------------------------------------------------
 import java.awt.*;
 import java.awt.event.*;
 import java.awt.image.*;
 import javax.swing.*;
 import java.beans.*;
 import java.io.*;
 import java.net.*;
 import java.util.Iterator;
 import javax.imageio.*;
 import javax.imageio.event.IIOReadProgressListener;
 import javax.imageio.stream.*;
 import java.util.concurrent.ExecutionException;
 public class ImageProgress extends JPanel implements ActionListener \{
 private JProgressBar progressBar;
 private JButton startButton;
 private Task task;
 BufferedImage image;
 public BufferedImage getImage() \{
 return this.image;
 \}
 public ImageProgress() \{
 super(new BorderLayout());
 this.image = null;
 this.startButton = new JButton("Load");
 this.startButton.addActionListener(this);
 this.progressBar = new JProgressBar(0, 100);
 this.progressBar.setValue(0); progressBar.setStringPainted(true);
 JPanel panel = new JPanel();
 panel.add(startButton); panel.add(progressBar);
 this.add(panel, BorderLayout.PAGE\\_START);
 \}
 private Image load() \{ 
 //URL imgUrl = 
 // new URL("http://bumble.sourceforge.net/doc/cv/mjb-inchair.jpg");
 Image image = null;
 try \{
 URL imgUrl = new URL("file:big.jpg");
 InputStream is = imgUrl.openStream();
 ImageInputStream iis = ImageIO.createImageInputStream(is);
 Iterator<ImageReader> it = ImageIO.getImageReadersBySuffix("jpg");
 ImageReader reader = it.next();
 reader.setInput(iis);
 reader.addIIOReadProgressListener(new IIOReadProgressListener() \{
 public void sequenceStarted(ImageReader source, int minIndex) \{\}
 public void sequenceComplete(ImageReader r) \{\}
 public void imageStarted(ImageReader r, int imageIndex) \{\}
 public void imageProgress(ImageReader r, float percentageDone) \{
 //System.out.format("Percent Downloaded: \\%f\\$\\backslash\\$n", percentageDone);
 ImageProgress.this.progressBar.setValue((int)percentageDone);
 \}
 public void imageComplete(ImageReader source) \{ \}
 public void thumbnailStarted(
 ImageReader r, int imageIndex, int thumbnailIndex) \{ \}
 public void thumbnailProgress(ImageReader r, float percentDone) 
 \{ \}
 public void thumbnailComplete(ImageReader source) \{\}
 public void readAborted(ImageReader source) \{\}
 \});
 image = reader.read(0);
 \} 
 catch (MalformedURLException e) \{\}
 catch (IOException e) \{\}
 return image;
 \}
 public void paintComponent(Graphics g) \{ 
 super.paintComponent(g);
 if (this.image != null) \{
 int scaleWidth = 500;
 int scaleHeight = 10;
 float factor = (float) scaleWidth / image.getWidth();
 scaleHeight = (int) (factor * image.getHeight());
 g.drawImage(this.image, 0, 0, scaleWidth, scaleHeight, null);
 \}
 \}
 public Dimension getPreferredSize() \{
 return (new Dimension(600, 600)); 
 \}
 public void actionPerformed(ActionEvent evt) \{
 startButton.setEnabled(false);
 setCursor(Cursor.getPredefinedCursor(Cursor.WAIT\\_CURSOR));
 this.task = new Task();
 this.task.execute();
 \}
 public static void main(String[] args) \{
 javax.swing.SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JFrame f = new JFrame("Image Load");
 f.add(new ImageProgress()); 
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 \}
 \});
 \}
 class Task extends SwingWorker<Image, Void> \{
 @Override
 public Image doInBackground() \{
 Image i = ImageProgress.this.load();
 return i;
 \}
 @Override
 public void done() \{
 try \{
 ImageProgress.this.startButton.setEnabled(true);
 ImageProgress.this.progressBar.setValue(100);
 ImageProgress.this.progressBar.setString("Image Loaded");
 ImageProgress.this.image = (BufferedImage) this.get();
 ImageProgress.this.setCursor(null); //turn off the wait cursor
 ImageProgress.this.repaint();
 \} catch (InterruptedException e) \{\}
 catch (ExecutionException e) \{\}
 \}
 \}
 \}
 ,,,
 
 * code to demostrate how to show the progress of an image (down)load
 -------------------------------------------------------------
 import java.awt.Image;
 import java.io.*;
 import java.net.MalformedURLException;
 import java.net.URL;
 import java.util.Iterator;
 import java.util.concurrent.ExecutionException;
 import javax.imageio.*;
 import javax.imageio.event.IIOReadProgressListener;
 import javax.imageio.stream.*;
 import javax.swing.*;
 public class ImageProgress \{
 public static void main(String[] args) throws MalformedURLException, IOException \{
 //URL imgUrl = new URL("http://bumble.sourceforge.net/doc/cv/mjb-inchair.jpg");
 URL imgUrl = new URL("file:big.jpg");
 InputStream is = imgUrl.openStream();
 ImageInputStream iis = ImageIO.createImageInputStream(is);
 Iterator<ImageReader> it = ImageIO.getImageReadersBySuffix("jpg");
 ImageReader reader = it.next();
 reader.setInput(iis);
 reader.addIIOReadProgressListener(new IIOReadProgressListener() \{
 public void sequenceStarted(ImageReader source, int minIndex) \{\}
 public void sequenceComplete(ImageReader r) \{\}
 public void imageStarted(ImageReader r, int imageIndex) \{\}
 public void imageProgress(ImageReader r, float percentageDone) \{
 System.out.format("Percent Downloaded: \\%f\\$\\backslash\\$n", percentageDone);
 \}
 public void imageComplete(ImageReader source) \{
 System.out.println("Download Completed");
 \}
 public void thumbnailStarted(
 ImageReader r, int imageIndex, int thumbnailIndex) \{ \}
 public void thumbnailProgress(ImageReader r, float percentDone) \{\}
 public void thumbnailComplete(ImageReader source) \{\}
 public void readAborted(ImageReader source) \{\}
 \});
 Image image = reader.read(0);
 Icon icon = new ImageIcon(image);
 \}
 \}
 ,,,
 


DISPLAYING IMAGES ....

 * display an image without scaling
 >> g.drawImage(img, 0, 0, null);

 * display an image in a JLabel using an image icon
 -------------------------------------------------------------
 import java.awt.*;
 import java.awt.image.*;
 import javax.swing.*;
 import javax.imageio.ImageIO;
 import java.io.*;
 public class ImageLabel \{
 public static void main(String[] args) throws Exception \{
 final BufferedImage image = ImageIO.read(new File("villa.jpg"));
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JLabel l = new JLabel(new ImageIcon(image)); 
 JOptionPane.showMessageDialog(null, l);
 \}
 \});
 \}
 \}
 ,,,

 The technique below leaves the job of loading the image to the container
 component. This may facilitate using a ProgressListener during the
 ImageIO.read process.

 * a simple image display component 
 ----------------------------------
 import java.awt.*;
 import java.awt.image.*;
 import java.io.*;
 import javax.imageio.*;
 import javax.swing.*;
 public class ImageComponent extends Component \{ 
 BufferedImage image;
 public void paint(Graphics g) \{ 
 g.drawImage(this.image, 0, 0, null);
 \}
 public ImageComponent(BufferedImage image) \{
 this.image = image;
 \}
 public Dimension getPreferredSize() \{
 return this.getParent().getSize(); 
 \}
 public static void main(String[] args) \{ 
 long startTime = System.currentTimeMillis(); 
 BufferedImage i;
 try \{ 
 i = ImageIO.read(new File("test.jpg")); 
 ImageComponent c = new ImageComponent(i); 
 JFrame f = new JFrame();
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.add(c); f.pack(); f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.setVisible(true);
 long endTime = System.currentTimeMillis(); 
 f.setTitle("Image loaded in " + (endTime-startTime) + " ms");
 \}
 catch (IOException e) 
 \{ System.out.println("Image file couldnt be read"); \}
 \}
 \}
 ,,,

 * a simple panel which displays an image, name and size
 ----------------------------------
 import java.awt.*;
 import java.awt.image.*;
 import java.io.*;
 import javax.imageio.*;
 import javax.swing.*;
 class ImageComponent extends Component \{ 
 BufferedImage image;
 public ImageComponent(BufferedImage image) \{
 this.image = image;
 \}
 public BufferedImage getImage() \{
 return this.image;
 \}
 public void paint(Graphics g) \{ 
 g.drawImage(this.image, 0, 0, null);
 \}
 public Dimension getPreferredSize() \{
 return this.getParent().getSize(); 
 \}
 \}
 public class ImagePanel extends JPanel \{ 
 ImageComponent imageDisplay;
 JLabel info;
 public ImagePanel(String imageName) \{
 super(new BorderLayout());
 try \{ 
 BufferedImage i = ImageIO.read(new File(imageName)); 
 this.imageDisplay = new ImageComponent(i);
 this.info = new JLabel(String.format(
 "Image: \\%s, Dimensions: \\%dx\\%d", 
 imageName, i.getWidth(), i.getHeight()));
 this.add(this.imageDisplay, BorderLayout.CENTER);
 this.add(this.info, BorderLayout.SOUTH);
 \}
 catch (IOException e) \{
 this.add(new JLabel("Image file couldnt be read"));
 \} 
 \}
 public static void main(String[] args) \{ 
 long startTime = System.currentTimeMillis(); 
 ImagePanel p = new ImagePanel("test.jpg"); 
 JFrame f = new JFrame();
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.add(p); f.pack(); f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.setVisible(true);
 long endTime = System.currentTimeMillis(); 
 f.setTitle("Image loaded in " + (endTime-startTime) + " ms");
 \}
 \}
 ,,,

 * display an image in a JLabel allowing the user to choose a file 
 -------------------------------------------------------------
 import java.awt.*;
 import java.awt.event.*;
 import java.awt.image.*;
 import javax.swing.*;
 import javax.imageio.ImageIO;
 import java.io.*;
 public class ChooseImage extends JPanel implements ActionListener \{
 JButton button; 
 JLabel imageLabel;
 String imageName;
 Image image;
 public ChooseImage()
 \{
 super(new BorderLayout());
 this.button = new JButton("Choose an Image");
 this.button.addActionListener(this);
 this.imageLabel = new JLabel();
 this.imageName = new String("...");
 this.add(this.button, BorderLayout.NORTH);
 this.add(this.imageLabel, BorderLayout.CENTER);
 \}

 public void setImage(File imageFile)
 \{
 try \{ 
 this.image = ImageIO.read(imageFile); 
 //this.imageName = imageName;
 this.imageLabel.setIcon(new ImageIcon(this.image));
 \}
 catch (IOException e) 
 \{ System.out.println("Image file couldnt be read"); \}
 \}

 public void actionPerformed(ActionEvent e) 
 \{
 if (e.getSource() == this.button) \{
 JFileChooser chooser = new JFileChooser();
 int result = chooser.showOpenDialog(null);
 File file = chooser.getSelectedFile();
 if (result == JFileChooser.APPROVE\\_OPTION) \{
 this.setImage(file);
 this.imageLabel.setText("yes");
 \}
 \}
 repaint();
 \}

 public static void main(String[] args) throws Exception \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 try \{
 UIManager.setLookAndFeel(
 "javax.swing.plaf.nimbus.NimbusLookAndFeel");
 \} catch (Exception eee) \{\} 

 long startTime = System.currentTimeMillis(); 
 JFrame f = new JFrame();
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.getContentPane().add(new ChooseImage());
 f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.pack(); 
 f.setVisible(true);
 long endTime = System.currentTimeMillis(); 
 f.setTitle("Image loaded in " + (endTime-startTime) + " ms");

 \}
 \});
 \}
 \}
 ,,,

 * load an image and display it scaled to 400 by 600 
 --------------------------------------------
 import java.awt.*;
 import java.awt.image.*;
 import java.io.*;
 import javax.imageio.*;
 import javax.swing.*;
 public class DisplayImage extends Component \{ 
 BufferedImage img;
 public void paint(Graphics g) \{ 
 g.drawImage(img, 0, 0, 400, 600, null);
 \}
 public DisplayImage() \{
 try 
 \{ img = ImageIO.read(new File("test.jpg")); \}
 catch (IOException e) 
 \{ System.out.println("Image file couldnt be read"); \}
 \}
 public Dimension getPreferredSize() 
 \{ return new Dimension(400, 600); \}
 public static void main(String[] args) \{ 
 long startTime = System.currentTimeMillis(); 
 JFrame f = new JFrame("Load and Display Image Example");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.getContentPane().add(new DisplayImage());
 f.pack(); f.setLocationRelativeTo(null);
 f.setVisible(true);
 long endTime = System.currentTimeMillis(); 
 f.setTitle("Image loaded in " + (endTime-startTime) + " ms");
 \}
 \}
 ,,,

 * displaying an image in a tooltip for a JLabel using swing html (A. Thompson)
 ------------------------------
 import javax.swing.*;
 import java.awt.GridLayout;
 class ThumbTip \{
 private static final String HTML = "<html><body>";
 ThumbTip(String[] album) \{
 JPanel p = new JPanel(new GridLayout(1,0,2,2));
 for (String url : album) \{
 String s = HTML + "<img src='" + url.toString() + "'";
 String size = " width=200 height=150";
 JLabel l = new JLabel(s + size + ">");
 l.setToolTipText(s + ">");
 p.add(l);
 \}
 JOptionPane.showMessageDialog(null, p);
 \}
 public static void main(String[] args) \{
 final String[] urls = \{
 "http://pscode.org/media/stromlo1.jpg",
 "http://pscode.org/media/stromlo2.jpg"
 \};
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 new ThumbTip(urls);
 \}
 \});
 \}
\}
,,,

GOTCHAS ....
 
 * The getPreferredSize must be less than the screen width
 -------------------------------------------------------------
 public Dimension getPreferredSize() \{
 return new Dimension(image.getWidth(), image.getHeight());
 \}
 ,,,

 The above may produce an 'out of heap space error'

SCALING IMAGES ....

 Images can be scaled with the old (since java 1.1)
 image.getScaledInstance() or else with the more modern
 graphics.drawImage(). The getScaledInstance method produces
 reasonable results but may be slower than drawImage. Another
 technique is to use AffineTransforms to do the scaling, but this is
 considered more complicated that the drawImage method. To
 summarise, the drawImage method is prefered.

 @@ \url{http://weblogs.java.net/blog/chet/archive/2004/07/imageio\\_just\\_an.html}
 good stuff about image scaling

 @@ \url{http://today.java.net/pub/a/today/2007/04/03/perils-of-image-getscaledinstance.html}
 An important article about how to scale with drawImage(...) and
 produce good results- basically scale by half until a good size
 is reached

GETSCALEDINSTANCE TO SCALE AN IMAGE ....

 >> Image.getScaledInstance(SCALE\\_AREA\\_AVERAGING)


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents hints for the getScaledInstance(...) method
 SCALE\\_REPLICATE: Specific hint that provides
 higher performance, but lower-quality, "blocky" results.
 SCALE\\_FAST: General hint meaning "I prefer speed
 over quality, but I'm not picky about the exact algorithm;" in
 Sun's current implementation (JDK 6 at the time of this writing)
 this is synonymous with SCALE\\_REPLICATE.
 SCALE\\_AREA\\_AVERAGING: Specific hint that is
 slower, but provides higher-quality, "filtered" results.
 SCALE\\_SMOOTH: General hint meaning "I prefer
 quality over speed, but I'm not picky about the exact algorithm;"
 in Sun's current implementation, this is generally synonymous with
 SCALE\\_AREA\\_AVERAGING. (As with the other hints, this
 mapping is implementation-dependent and subject to change; read the
 Performance Notes section below for more
 on how this mapping could change in an upcoming release of Sun's
 JDK implementation.)
 SCALE\\_DEFAULT: General hint meaning "I don't
 care, just pick something for me;" in Sun's current implementation,
 this is synonymous with SCALE\\_FAST.
 ... 


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents hints for drawImage() RenderingHints.KEY\\_INTERPOLATION
 VALUE\\_INTERPOLATION\\_NEAREST\\_NEIGHBOR: Specific
 hint that provides higher performance, but lower-quality, "blocky"
 results.
 VALUE\\_INTERPOLATION\\_BILINEAR: Specific hint that
 is typically a bit slower, but provides higher-quality, "filtered"
 results.
 VALUE\\_INTERPOLATION\\_BICUBIC: Specific hint that
 is similar to BILINEAR except that it uses more
 samples when filtering and therefore has generally higher quality
 than BILINEAR. (Note: this hint constant has been
 available since JDK 1.2, but was not implemented by Sun until the
 JDK 5 release; prior to that release, this hint was synonymous with
 BILINEAR.)
 ...

 * scale an image to 400x200 and display in JLabel
 -------------------------------------------------
 import java.awt.*;
 import java.awt.image.*;
 import javax.swing.*;
 import javax.imageio.ImageIO;
 import java.io.*;
 public class ImageLabel \{
 public static void main(String[] args) throws Exception \{
 final BufferedImage image = ImageIO.read(new File("villa.jpg"));
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 Image scaledImage = 
 image.getScaledInstance (400, 200, Image.SCALE\\_SMOOTH);
 ImageIcon icon = new ImageIcon(scaledImage);
 JPanel p = new JPanel();
 p.add(new JLabel(icon));
 JOptionPane.showMessageDialog(null, p);
 \}
 \});
 \}
 \}
 ,,,

 * a simple algorithm to scale preserving image aspect ration
 -------------------------------------------------------------
 final int newWidth = 400;
 float factor = (float) newWidth / image.getWidth();
 int newHeight = (int) (factor * image.getHeight());
 ,,,

 App Notes: 

 The application below could be the skeleton for a useful application
 for manipulating an image using keystrokes

 the method call repaint() is necessary after setting a new image in the
 ImageComponent. This shows that the paint method is only called when
 strictly necessary (when the window is resized etc).

 RenderingHints.VALUE\\_INTERPOLATION\\_BICUBIC gives much higher
 quality results than RenderingHints.VALUE\\_INTERPOLATION\\_BILINEAR
 but is very slow.

 In the example above for some reason adding the keylistener on the
 JPanel doesnt work, but on the JFrame, yes. Probably because the panel
 doesnt have focus.

 It is proving difficult to get the ImageComponent to resize
 to the image size, probably because the BorderLayout does not
 respect the getPreferredSize() method, and just makes the CENTER
 component as big as possible. 

 * a simple panel which can scale an image on a keystroke
 ----------------------------------
 import java.awt.*;
 import java.awt.image.*;
 import java.awt.event.*;
 import java.io.*;
 import javax.imageio.*;
 import javax.swing.*;
 public class ImagePanel extends JPanel implements KeyListener \{ 
 BufferedImage original;
 BufferedImage image;
 ImageComponent imageDisplay;
 JLabel info;
 public ImagePanel(String imageName) \{
 super(new BorderLayout());
 try \{ 
 this.image = ImageIO.read(new File(imageName)); 
 this.imageDisplay = new ImageComponent(this.image);
 this.info = new JLabel(String.format(
 "Image: \\%s, Dimensions: \\%dx\\%d", 
 imageName, this.image.getWidth(), this.image.getHeight()));
 this.add(this.imageDisplay, BorderLayout.CENTER);
 this.add(this.info, BorderLayout.SOUTH);
 \}
 catch (IOException e) \{
 this.add(new JLabel("Image file couldnt be read"));
 \} 
 \}
 public void keyTyped(KeyEvent e) \{
 switch (e.getKeyChar()) \{
 case 's': 
 this.scale(0.8f); break;
 case 'S': 
 this.scale(0.5f); break;
 case 'b': 
 this.scale(1.2f); break;
 case 'B': 
 this.scale(2.0f); break;
 case 'x': 
 System.exit(0); break;
 default:
 break;
 \}
 \} 
 public void keyPressed(KeyEvent e) \{\} 
 public void keyReleased(KeyEvent e) \{\}
 private void scale(float factor) \{
 int newWidth = (int) (this.image.getWidth() * factor);
 int newHeight = (int) (this.image.getHeight() * factor);
 int type = (this.image.getTransparency() == Transparency.OPAQUE) ?
 BufferedImage.TYPE\\_INT\\_RGB : BufferedImage.TYPE\\_INT\\_ARGB;
 BufferedImage tmp = new BufferedImage(newWidth, newHeight, type);
 Graphics2D g2 = tmp.createGraphics();
 g2.setRenderingHint(RenderingHints.KEY\\_INTERPOLATION,
 RenderingHints.VALUE\\_INTERPOLATION\\_BICUBIC);
 g2.drawImage(this.image, 0, 0, newWidth, newHeight, null);
 g2.dispose();
 this.image = tmp;
 this.imageDisplay.setImage(this.image);
 //this.revalidate();
 this.repaint();
 \}

 public static void main(String[] args) \{ 
 long startTime = System.currentTimeMillis(); 
 ImagePanel p = new ImagePanel("test.jpg"); 
 JFrame f = new JFrame();
 f.addKeyListener(p);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.add(p); f.pack(); f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.setVisible(true);
 long endTime = System.currentTimeMillis(); 
 f.setTitle("Image loaded in " + (endTime-startTime) + " ms");
 \}
 \}
 class ImageComponent extends JComponent \{ 
 BufferedImage image;
 public ImageComponent(BufferedImage image) \{
 this.image = image;
 \}
 public BufferedImage getImage() \{
 return this.image;
 \}
 public void setImage(BufferedImage image) \{
 this.image = image; 
 \}
 public void paintComponent(Graphics g) \{ 
 super.paintComponent(g);
 int x = 0; int y = 0;
 // draw the image in the center of the component
 if (this.getSize().getWidth() > this.image.getWidth()) 
 x = (int)(this.getSize().getWidth() - this.image.getWidth())/2; 
 if (this.getSize().getHeight() > this.image.getHeight()) 
 y = (int)(this.getSize().getHeight() - this.image.getHeight())/2; 
 g.drawImage(this.image, x, y, null);
 \}
 public Dimension getPreferredSize() \{
 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
 if (this.image.getWidth() >= screen.getWidth() ||
 this.image.getHeight() >= screen.getHeight())
 return this.getParent().getSize(); 
 else
 return new Dimension(this.image.getWidth(), this.image.getHeight());
 \}
 \}
 
 ,,,

 * scale an image to width 400 preserving the aspect ratio 
 ---------------------------------------------------------
 import java.awt.*;
 import java.awt.image.*;
 import javax.swing.*;
 import javax.imageio.ImageIO;
 import java.io.*;
 public class ImageLabel \{
 public static void main(String[] args) throws Exception \{
 final BufferedImage image = ImageIO.read(new File("villa.jpg"));
 final int newWidth = 400;
 float factor = (float) newWidth / image.getWidth();
 int newHeight = (int) (factor * image.getHeight());
 Image scaledImage = 
 image.getScaledInstance(
 newWidth, newHeight, Image.SCALE\\_SMOOTH);
 ImageIcon icon = new ImageIcon(scaledImage);
 JPanel p = new JPanel();
 p.add(new JLabel("A scaled image", icon, JLabel.CENTER));
 JOptionPane.showMessageDialog(null, p);
 \}
 \}
 ,,,

 * scale an image and display information about load times etc 
 -----------------------------------------------------------
 import java.awt.*;
 import java.awt.image.*;
 import javax.swing.*;
 import javax.imageio.ImageIO;
 import java.io.*;
 public class ImageLabel \{
 public static void main(String[] args) throws Exception \{
 long startTime = System.currentTimeMillis();
 File imageFile = new File("test.jpg");
 final BufferedImage image = ImageIO.read(imageFile);
 long readTime = System.currentTimeMillis() - startTime;
 final int newWidth = 400;
 float factor = (float) newWidth / image.getWidth();
 int newHeight = (int) (factor * image.getHeight());
 long startScale = System.currentTimeMillis();
 Image scaledImage = 
 image.getScaledInstance(
 newWidth, newHeight, Image.SCALE\\_SMOOTH);
 long scaleTime = System.currentTimeMillis() - startScale;
 long iconTime = System.currentTimeMillis();
 ImageIcon icon = new ImageIcon(scaledImage);
 iconTime = System.currentTimeMillis() - iconTime;
 JLabel label = new JLabel(icon);
 // put the text under the image
 label.setHorizontalTextPosition(JLabel.CENTER);
 label.setVerticalTextPosition(JLabel.BOTTOM);
 long totalTime = System.currentTimeMillis() - startTime;
 String text = String.format(
 "<html><ul>" +
 "<li>original width: \\%d" +
 "<li>original height: \\%d" +
 "<li>Image file size: \\%d bytes" +
 "<li>Image read in \\%d ms (ImageIO.read)" +
 "<li>Image scaled in \\%d ms (getScaledInstance)" +
 "<li>Time to create the ImageIcon was \\%d ms" +
 "<li>Total time taken was \\%d ms" +
 "</ul>",
 image.getWidth(), image.getHeight(), imageFile.length(),
 readTime, scaleTime, iconTime, totalTime);
 label.setText(text);
 JOptionPane.showMessageDialog(null, label);
 \}
 \}
 ,,,

 What we can see from the above is that the creation of the ImageIcon
 takes a very long time, and reading the image takes a considerable amount
 of time, but scaling the image even though we are using the older
 getScaledInstance method is relatively fast.

 * align the text of a label underneath its image icon
 -------------------------------------------------------------
 label.setHorizontalTextPosition(JLabel.CENTER);
 label.setVerticalTextPosition(JLabel.BOTTOM);
 ,,,

 * some hints for drawImage()
 -------------------------------------------------------------
 g.setComposite(AlphaComposite.Src);
 g.setRenderingHint(RenderingHints.KEY\\_INTERPOLATION,
 RenderingHints.VALUE\\_INTERPOLATION\\_BILINEAR);
 g.setRenderingHint(RenderingHints.KEY\\_RENDERING,
 RenderingHints.VALUE\\_RENDER\\_QUALITY);
 g.setRenderingHint(RenderingHints.KEY\\_ANTIALIASING,
 RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 ,,,

 * A component to scale an image to a width and maintain aspect ratio 
 --------------------------------------------
 import java.awt.*;
 import java.awt.image.*;
 import java.io.*;
 import javax.imageio.*;
 import javax.swing.*;
 public class DisplayImage extends Component \{ 
 private int scaleWidth;
 private int scaleHeight;
 BufferedImage image;
 public void paint(Graphics G) \{ 
 Graphics2D g = (Graphics2D) G; 
 g.drawImage(image, 0, 0, scaleWidth, scaleHeight, null);
 \}
 public DisplayImage(String imageName, int scaleWidth) \{
 this.scaleWidth = scaleWidth;
 try \{
 image = ImageIO.read(new File(imageName)); 
 float factor = (float) scaleWidth / image.getWidth();
 this.scaleHeight = (int) (factor * image.getHeight());
 \}
 catch (IOException e) 
 \{ System.out.println("Image file couldnt be read"); \}
 \}
 public Dimension getPreferredSize() 
 \{ return new Dimension(this.scaleWidth, this.scaleHeight); \}
 public static void main(String[] args) \{ 
 JOptionPane.showMessageDialog(
 null, new DisplayImage("test.jpg", 400));
 \}
 \}
 ,,,

 The drawImage() method produces noticeably bad results when 
 scaling to a small factor

 * scale an image with drawImage() and show benchmark times etc 
 --------------------------------------------
 import java.awt.*;
 import java.awt.image.*;
 import java.io.*;
 import javax.imageio.*;
 import javax.swing.*;
 public class DisplayImage extends Component \{ 
 private int scaleWidth;
 private int scaleHeight;
 public long scaleTime;
 public long readTime;
 BufferedImage image;
 public void paint(Graphics g) \{ 
 this.scaleTime = System.currentTimeMillis();
 g.drawImage(image, 0, 0, scaleWidth, scaleHeight, null);
 this.scaleTime = System.currentTimeMillis() - this.scaleTime;
 \}
 public DisplayImage(int scaleWidth) \{
 this.scaleWidth = scaleWidth;
 try \{
 this.readTime = System.currentTimeMillis();
 image = ImageIO.read(new File("test.jpg")); 
 this.readTime = System.currentTimeMillis() - this.readTime;
 float factor = (float) scaleWidth / image.getWidth();
 this.scaleHeight = (int) (factor * image.getHeight());
 \}
 catch (IOException e) 
 \{ System.out.println("Image file couldnt be read"); \}
 \}
 public Dimension getPreferredSize() 
 \{ return new Dimension(this.scaleWidth, this.scaleHeight); \}
 public static void main(String[] args) \{ 
 long totalTime = System.currentTimeMillis();
 DisplayImage component = new DisplayImage(300);
 totalTime = System.currentTimeMillis() - totalTime;
 JLabel label = new JLabel();
 String text = String.format(
 "<html><ul>" +
 "<li>Image read in \\%d ms (ImageIO.read)" +
 "<li>Image scaled in \\%d ms with g.drawImage(...)" +
 "<li>Total time taken was \\%d ms" +
 "</ul>",
 component.readTime, component.scaleTime, totalTime);
 label.setText(text);
 JPanel p = new JPanel(new GridLayout(0,1));
 p.add(component); p.add(new JLabel(text));
 JOptionPane.showMessageDialog(null, p);
 \}
 \}
 ,,,

 * scale an image by 50\\% with getScaledInstance and a 'hint'
 -------------------------------------------------------------
 Image image = imageIcon.getImage ();
 int width = (int) (0.5 * image.getWidth (null));
 int height = (int) (0.5 * image.getHeight (null));
 Image newImage = image.getScaledInstance (width, height, Image.SCALE\\_SMOOTH);
 ImageIcon newImageIcon = new ImageIcon(newImage);
 ,,, 

 * draw an image scaling to frame size, but this ignores aspect ratio
 >> g.drawImage(BuffImg,0,0,getWidth(),getHeight(),this):
 
 * resize (scale) an image
 -----------
 BufferedImage resizedImage = new BufferedImage(IMG\\_WIDTH, IMG\\_HEIGHT, type);
 Graphics2D g = resizedImage.createGraphics();
 g.drawImage(originalImage, 0, 0, IMG\\_WIDTH, IMG\\_HEIGHT, null);
 g.dispose();
 ,,,

 This example is incomplete, because you still need to actually write
 the new image to file- but that is not difficult

 * scale all image files in a folder
 --------------------------
 import java.awt.*;
 import java.awt.image.*;
 import javax.imageio.ImageIO;
 import java.io.File;
 
 /** ImageScaler
 *
 * This class loads all images in a given directory and scales them to
 * the given sizes, saving the results as JPEG files in a new "scaled/"
 * subdirectory of the original directory.
 */

 public class ImageScaler \{
 
 // Default w/h values; overriden by command-line -width/-height parameters
 static int IMAGE\\_W = 150;
 static int IMAGE\\_H = 250;

 public static void main(String args[]) \{
 // Default directory is current directory, overridden by -dir parameter
 String imagesDir = ".";
 for (int i = 0; i < args.length; ++i) \{
 if (args[i].equals("-dir") \\&\\& ((i + 1) < args.length)) \{
 imagesDir = args[++i];
 \} else if (args[i].equals("-width") \\&\\& ((i + 1) < args.length)) \{
 IMAGE\\_W = Integer.parseInt(args[++i]);
 \} else if (args[i].equals("-height") \\&\\& ((i + 1) < args.length)) \{
 IMAGE\\_H = Integer.parseInt(args[++i]);
 \}
 \}
 // new subdirectory for scaled images
 String scaledImagesDir = imagesDir + File.separator + "scaled";
 // directory that holds original images
 File cwd = new File(imagesDir);
 // directory for scaled images
 File subdir = new File(scaledImagesDir);
 subdir.mkdir();
 File files[] = cwd.listFiles();
 // temporary image for every scaled instance
 BufferedImage scaledImg = new BufferedImage(IMAGE\\_W, IMAGE\\_H,
 BufferedImage.TYPE\\_INT\\_RGB);
 Graphics2D gScaledImg = scaledImg.createGraphics();
 // Note the use of BILNEAR filtering to enable smooth scaling
 gScaledImg.setRenderingHint(RenderingHints.KEY\\_INTERPOLATION,
 RenderingHints.VALUE\\_INTERPOLATION\\_BILINEAR);
 for (int i = 0; i < files.length; ++i) \{
 try \{
 // For every file in the directory, assume it's an image and
 // load it
 BufferedImage img = ImageIO.read(files[i]);
 // If we get here, we must have read the image file successfully.
 // Create a new File in the scaled subdirectory
 File scaledImgFile = new File(scaledImagesDir + File.separator +
 files[i].getName());
 // Scale the original image into the temporary image
 gScaledImg.drawImage(img, 0, 0, IMAGE\\_W, IMAGE\\_H, null);
 // Save the scaled version out to the file
 ImageIO.write(scaledImg, "jpeg", scaledImgFile);
 \} catch (Exception e) \{
 System.out.println("Problem with " + files[i]);
 \}
 \}
 \}
 \}
,,,

 According to romain guy antialiasing is useless, the best
 way is rescale by half with 'bilinear'

 * a method to resize an image
 --------------------------------
 private static BufferedImage resize(
 BufferedImage image, int width, int height) \{
 int type = 
 image.getType() == 0? BufferedImage.TYPE\\_INT\\_ARGB : image.getType();
 BufferedImage resizedImage = new BufferedImage(width, height, type);
 Graphics2D g = resizedImage.createGraphics();
 g.setComposite(AlphaComposite.Src);
 g.setRenderingHint(RenderingHints.KEY\\_INTERPOLATION,
 RenderingHints.VALUE\\_INTERPOLATION\\_BILINEAR);
 g.setRenderingHint(RenderingHints.KEY\\_RENDERING,
 RenderingHints.VALUE\\_RENDER\\_QUALITY);
 g.drawImage(image, 0, 0, width, height, null);
 g.dispose();
 return resizedImage;
 \}
 ,,,

 * using affinetransforms to do scaling, not a complete example
 -------------------------------------------------------------
 public void paintComponent(Graphics g) \{
 Graphics2D g2 = (Graphics2D)g;
 AffineTransform oldXform = g2.getTransform();
 g2.scale(2.0, 2.0);
 g2.drawImage(img, 0, 0, null);
 // Or I sometimes see this even more complicated approach...
 // AffineTransform xform = AffineTransform.getScaleInstance(2, 2);
 // g2.drawImage(img, xform, null);
 g2.setTransform(oldXform); // restore transform
 \}
 ,,,
 
 * an attempt to blur an image, but blurring is probably more complex
 --------------------
 public static BufferedImage blurImage(BufferedImage image) \{
 float ninth = 1.0f/9.0f;
 float[] blurKernel = \{
 ninth, ninth, ninth,
 ninth, ninth, ninth,
 ninth, ninth, ninth
 \};
 
 Map map = new HashMap();
 map.put(RenderingHints.KEY\\_INTERPOLATION,
 RenderingHints.VALUE\\_INTERPOLATION\\_BILINEAR);
 map.put(RenderingHints.KEY\\_RENDERING, RenderingHints.VALUE\\_RENDER\\_QUALITY);
 map.put(RenderingHints.KEY\\_ANTIALIASING, RenderingHints.VALUE\\_ANTIALIAS\\_ON);
 RenderingHints hints = new RenderingHints(map);
 BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, blurKernel), ConvolveOp.EDGE\\_NO\\_OP, hints);
 return op.filter(image, null);
 \}
 
 private static BufferedImage createCompatibleImage(BufferedImage image) \{
 GraphicsConfiguration gc = BufferedImageGraphicsConfig.getConfig(image);
 int w = image.getWidth();
 int h = image.getHeight();
 BufferedImage result = gc.createCompatibleImage(w, h, Transparency.TRANSLUCENT);
 Graphics2D g2 = result.createGraphics();
 g2.drawRenderedImage(image, null);
 g2.dispose();
 return result;
 \}
,,,

 * an on the fly scale method
 -------------------------------------------------------------
 private float xScaleFactor, yScaleFactor = ...;
 private BufferedImage originalImage = ...;

 public void paintComponent(Graphics g) \{
 Graphics2D g2 = (Graphics2D)g;
 int newW = (int)(originalImage.getWidth() * xScaleFactor);
 int newH = (int)(originalImage.getHeight() * yScaleFactor);
 g2.setRenderingHint(RenderingHints.KEY\\_INTERPOLATION,
 RenderingHints.VALUE\\_INTERPOLATION\\_BILINEAR);
 g2.drawImage(originalImage, 0, 0, newW, newH, null);
 \}
 ,,,


 * downscale by 2 until the correct width/ height is achieved
 -------------------------------------------------------------
 public BufferedImage getScaledInstance(BufferedImage img,
 int targetWidth,
 int targetHeight)
 \{
 int type = (img.getTransparency() == Transparency.OPAQUE) ?
 BufferedImage.TYPE\\_INT\\_RGB : BufferedImage.TYPE\\_INT\\_ARGB;
 BufferedImage ret = (BufferedImage)img;
 int w, h;
 // Use multi-step technique: start with original size, then
 // scale down in multiple passes with drawImage()
 // until the target size is reached
 w = img.getWidth();
 h = img.getHeight();
 
 do \{
 if (w > targetWidth) \{
 w /= 2;
 if (w < targetWidth) \{ w = targetWidth; \}
 \}
 
 if (h > targetHeight) \{
 h /= 2;
 if (h > targetHeight) \{ h = targetHeight; \}
 \}
 BufferedImage tmp = new BufferedImage(w, h, type);
 Graphics2D g2 = tmp.createGraphics();
 g2.setRenderingHint(RenderingHints.KEY\\_INTERPOLATION,
 RenderingHints.VALUE\\_INTERPOLATION\\_BILINEAR);
 g2.drawImage(ret, 0, 0, w, h, null);
 g2.dispose();
 ret = tmp;
 \} while (w != targetWidth || h != targetHeight);
 return ret;
 \}
 ,,,

 * a complete example of multistep downscale 
 --------------------------------------------
 import java.awt.*;
 import java.awt.image.*;
 import java.io.*;
 import javax.imageio.*;
 import javax.swing.*;
 public class DisplayImage extends Component \{
 private int scaleWidth;
 private int scaleHeight;
 BufferedImage image;
 public void paint(Graphics G) \{
 // some hints to improve quality, but dont work
 Graphics2D g = (Graphics2D) G;
 BufferedImage scaled = this.getScaledInstance(image, scaleWidth, scaleHeight);
 //g.drawImage(image, 0, 0, scaleWidth, scaleHeight, null);
 g.drawImage(scaled, 0, 0, null);
 \}
 public DisplayImage(String imageName, int scaleWidth) \{
 this.scaleWidth = scaleWidth;
 try \{
 image = ImageIO.read(new File(imageName));
 float factor = (float) scaleWidth / image.getWidth();
 this.scaleHeight = (int) (factor * image.getHeight());
 \}
 catch (IOException e)
 \{ System.out.println("Image file couldnt be read"); \}
 \}
 public Dimension getPreferredSize()
 \{ return new Dimension(this.scaleWidth, this.scaleHeight); \}
 
 public static void main(String[] args) \{
 JOptionPane.showMessageDialog(
 null, new DisplayImage("test.jpg", 400));
 \}

 // Use multi-step technique: scale by 1/2 until target size.
 public BufferedImage getScaledInstance(BufferedImage img,
 int targetWidth,
 int targetHeight)
 \{
 int type = (img.getTransparency() == Transparency.OPAQUE) ?
 BufferedImage.TYPE\\_INT\\_RGB : BufferedImage.TYPE\\_INT\\_ARGB;
 BufferedImage ret = (BufferedImage)img;
 int w, h;
 w = img.getWidth();
 h = img.getHeight();
 do \{
 if (w > targetWidth) \{
 w /= 2; if (w < targetWidth) w = targetWidth; 
 \}
 
 if (h > targetHeight) \{
 h /= 2; if (h > targetHeight) h = targetHeight;
 \}
 BufferedImage tmp = new BufferedImage(w, h, type);
 Graphics2D g2 = tmp.createGraphics();
 g2.setRenderingHint(RenderingHints.KEY\\_INTERPOLATION,
 RenderingHints.VALUE\\_INTERPOLATION\\_BILINEAR);
 g2.drawImage(ret, 0, 0, w, h, null);
 g2.dispose();
 ret = tmp;
 \} while (w != targetWidth || h != targetHeight);
 return ret;
 \}
 
 \}
 ,,,

 * multistep downscale with more parameters 
 -------------------------------------------------------------
 public BufferedImage getScaledInstance(
 BufferedImage img, int targetWidth, int targetHeight, Object hint,
 boolean higherQuality)
 \{
 int type = (img.getTransparency() == Transparency.OPAQUE) ?
 BufferedImage.TYPE\\_INT\\_RGB : BufferedImage.TYPE\\_INT\\_ARGB;
 BufferedImage ret = (BufferedImage)img;
 int w, h;
 if (higherQuality) \{
 // Use multi-step technique: start with original size, then
 // scale down in multiple passes with drawImage()
 // until the target size is reached
 w = img.getWidth(); h = img.getHeight();
 \} else \{
 // Use one-step technique: scale directly from original
 // size to target size with a single drawImage() call
 w = targetWidth; h = targetHeight;
 \}
 
 do \{
 if (higherQuality \\&amp;\\&amp; w > targetWidth) \{
 w /= 2;
 if (w < targetWidth) \{ w = targetWidth; \}
 \}
 
 if (higherQuality \\&amp;\\&amp; h \\&gt; targetHeight) \{
 h /= 2;
 if (h < targetHeight) \{ h = targetHeight; \}
 \}
 
 BufferedImage tmp = new BufferedImage(w, h, type);
 Graphics2D g2 = tmp.createGraphics();
 g2.setRenderingHint(RenderingHints.KEY\\_INTERPOLATION, hint);
 g2.drawImage(ret, 0, 0, w, h, null);
 g2.dispose();
 ret = tmp;
 \} while (w != targetWidth || h != targetHeight);
 return ret;
 \}
 ,,,

CLIPPING IMAGES ....

 Clipping in this context refers to drawing an image within
 a particular shape, such as an oval or within the shape of text.

 * draw an image in the shape of some text using a clip, save image as png file
 ----------------------------------------------------------
 // get the width and the height from the original image
 URL url = new URL("http://i.stack.imgur.com/Nqf3H.jpg");
 final BufferedImage originalImage = ImageIO.read(url);
 int width = originalImage.getWidth();
 int height = originalImage.getHeight();
 final BufferedImage textImage = new BufferedImage(
 width, height, BufferedImage.TYPE\\_INT\\_ARGB);
 Graphics2D g = textImage.createGraphics();
 FontRenderContext frc = g.getFontRenderContext();
 Font font = new Font("Arial", Font.BOLD, 250);
 GlyphVector gv = font.createGlyphVector(frc, "Cat");
 Rectangle2D box = gv.getVisualBounds();
 int xOff = 25+(int)-box.getX();
 int yOff = 80+(int)-box.getY();
 Shape shape = gv.getOutline(xOff,yOff);
 g.setColor(Color.WHITE);
 g.setClip(shape);
 g.drawImage(originalImage,0,0,null);
 g.dispose();
 ImageIO.write(textImage,"png",new File("cat-text.png"));
 ,,,

ICONS ....

 javax.swing.Icon is an interface designed to allow the creation
 of decorations for components

 An idea: we can create a 'symbol' icon class which implements the 
 icon interface and paints a glyph from the dingbats or miscelanous
 unicode blocks onto an icon. Or even a random icon class which 
 paints a selection of dingbats. Maybe for decoration. We could then
 convert the icon to a BufferedImage as per below and save it into
 a gif file etc.

 * a simple implementation of the icon interface which just paints a color
 -------------------------------------------------------------
 import java.awt.*;
 import javax.swing.Icon;
 public class ColorIcon implements Icon \{
 private Color color;
 private int width;
 private int height;
 
 public ColorIcon(Color color, int width, int height) \{
 this.color = color;
 this.width = width;
 this.height = height;
 \}
 
 public int getIconWidth() \{ return width; \}
 public int getIconHeight() \{ return height; \}
 public void paintIcon(Component c, Graphics g, int x, int y) \{
 g.setColor(color);
 g.fillRect(x, y, width, height);
 \}
 \}
 ,,,

IMAGEICONS ....

 * create a jlabel with icon from a scaled buffered image
 ----------------------------
 BufferedImage img = ...;
 JLable l = new JLabel(new ImageIcon(img.getScaledInstance(
 img.getWidth(null)/2, img.getHeight(null)/2, Image.SCALE\\_SMOOTH))); 
 ,,,

 * convert an ImageIcon to a BufferedImage
 -------------------------------------------
 ImageIcon imageIcon = 
 new ImageIcon("http://pscode.org/media/stromlo2.jpg");
 JLabel imageLabel = new JLabel(
 "A Horse", imageIcon, SwingConstants.CENTER);
 JOptionPane.showMessageDialog(null, imageLabel);
 Icon icon = imageLabel.getIcon();
 BufferedImage bi = new BufferedImage(
 icon.getIconWidth(),
 icon.getIconHeight(),
 BufferedImage.TYPE\\_INT\\_RGB);
 Graphics g = bi.createGraphics();
 // paint the Icon to the BufferedImage.
 icon.paintIcon(null, g, 0,0);
 ,,,

PREDEFINED ICONS ....

 You can obtain access to some of javas 'built-in' icons through
 the UIManager class and its static getIcon() method.

 * Get the option pane 'information' icon (usually a big blue 'I')
 >> Icon infoIcon = UIManager.getIcon("OptionPane.informationIcon");
 
 * get the icon which the operating system uses to display the File f
 >> FileSystemView.getFileSystemView().getSystemDisplayName(f);

 * show the icon which the system uses to display a folder 
 -------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.filechooser.FileSystemView;
 public class SystemIcon \{
 public static void main(String[] args) \{
 JOptionPane.showMessageDialog(null, 
 new JLabel(FileSystemView.getFileSystemView().getSystemIcon(
 new java.io.File("."))));
 \}
 \}
 ,,,

 * show the the system file and folder icons 
 -------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.filechooser.FileSystemView;
 import java.io.File;
 public class SystemIcon \{
 public static void main(String[] args) \{
 Icon folderIcon = 
 FileSystemView.getFileSystemView().getSystemIcon(new File("."));
 Icon fileIcon = 
 FileSystemView.getFileSystemView().getSystemIcon(
 new File("eg/SystemIcon.java"));
 JOptionPane.showMessageDialog(null, new JLabel(fileIcon));
 \}
 \}
 ,,,

 The icons below are not particularly attractive but maybe better than
 nothing. To change the example below to a JList, only 2 lines of code need
 to be changed: JList box = new JList(icons); box.setCellRenderer(...)

 Strangely the JList component has a setCellRenderer() method and 
 the JComboBox a setRenderer() method

 * a combobox displaying most of the java standard icons and names
 ------------------------------------------
 import java.awt.*;
 import java.io.File;
 import javax.swing.*;
 import java.lang.reflect.*;
 public class IconComboBox \{
 public static void main(String[] args) \{
 SwingUtilities.invokeLater( new Runnable() \{
 public void run() \{
 String[] icons = \{
 "OptionPane.questionIcon", "OptionPane.errorIcon",
 "OptionPane.informationIcon", "OptionPane.warningIcon",
 "FileView.directoryIcon", "FileView.fileIcon",
 "FileView.computerIcon", "FileView.hardDriveIcon",
 "FileView.floppyDriveIcon", "FileChooser.newFolderIcon",
 "FileChooser.upFolderIcon", "FileChooser.homeFolderIcon",
 "FileChooser.detailsViewIcon", "FileChooser.listViewIcon",
 "Tree.expandedIcon", "Tree.collapsedIcon",
 "Tree.openIcon", "Tree.leafIcon", "Tree.closedIcon"
 \};
 JComboBox box = new JComboBox(icons);
 box.setFont(new Font("Georgia", Font.ITALIC, 22));
 box.setRenderer(new IconRenderer());
 JOptionPane.showMessageDialog(null, box);
 \}
 \});
 \}
 \}
 class IconRenderer extends DefaultListCellRenderer \{
 public Component getListCellRendererComponent(
 JList list, Object value, int index,
 boolean isSelected, boolean cellHasFocus) \{
 JLabel label = (JLabel)super.getListCellRendererComponent(
 list,value,index,isSelected,cellHasFocus);
 if (value instanceof String) \{
 String s = (String)value;
 label.setIcon(UIManager.getIcon(s));
 \} 
 return label;
 \}
 \}
 ,,,


 * trying to retrieve all predefined icons but throwing weird exceptions 
 -------------------------------------------------------------
 import java.awt.GridLayout;
 import java.awt.event.*;
 import javax.swing.*;
 public class AllIconsDragAndDrop \{
 public static void main(String[] args) \{
 JFrame f = new JFrame("Icon Drag \\& Drop");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 JPanel p = new JPanel(new GridLayout(0,4));
 MouseListener listener = new DragMouseAdapter();
 String[] ss = \{"informationIcon", "warningIcon", "errorIcon"\};
 Icon icon; JLabel label;
 java.util.Enumeration keys = UIManager.getDefaults().keys();
 while (keys.hasMoreElements()) \{
 Object k = keys.nextElement();
 Object value = UIManager.get(k);
 if (value instanceof javax.swing.Icon) \{
 System.out.println(k);
 icon = UIManager.getIcon((String)k);
 label = new JLabel(icon);
 p.add(label);
 //label = new JLabel((String)k);
 //label.setIcon(icon);
 //JOptionPane.showMessageDialog(null, icon);
 \}
 \}
 f.getContentPane().add(p); 
 try \{
 f.pack();
 f.setLocationRelativeTo(null); 
 \}
 catch (ClassCastException e) \{
 System.out.println("noooo");
 System.exit(-1);
 \}
 f.setVisible(true);
 \}
 \}
 ,,,
 
SCREEN SHOTS ....

 A screen-shot is an image taken of what happens to be on the 
 computer screen at a given time.

 @@ \url{http://www.javarichclient.com/4-ways-to-capture-a-screenshot/}
 Complete info about ways to get screen shots

 4 methods to capture a screen shot.

 * capture the entire screen
 -------------------------------------------------------------
 import java.awt.image.*;
 public class ScreenShotPanel extends JPanel implements KeyListener \{
 public BufferedImage captureEntireScreen() throws AWTException \{
 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
 Rectangle screenBounds = new Rectangle(screenSize);
 return new Robot().createScreenCapture(screenBounds);
 \}
 public void keyTyped(KeyEvent e) \{
 switch (e.getKeyChar()) \{
 case 's':
 this.captureEntireScreen();
 break;
 case 'S':
 break;
 default:
 break;
 \}
 //this.setInfo();
 //repaint();
 \}
 public void keyPressed(KeyEvent e) \{\}
 public void keyReleased(KeyEvent e) \{\}
 \}
 ,,,

 * capture a region of the screen
 -------------------------------------------------------------
 public BufferedImage captureScreenRegion(int x, int y, int width, int height) throws AWTException \{
 Rectangle screenRegion = new Rectangle(x, y, width, height);
 return new Robot().createScreenCapture(screenRegion);
 \}
 ,,,

 * Capture the region of a component using the Robot class.
 -------------------------------------------------------------
 public BufferedImage captureComponentUsingRobot(Component c) throws AWTException \{
 Rectangle bounds = c.getBounds();
 Point location = new Point(0, 0);
 SwingUtilities.convertPointToScreen(location, c);
 bounds.setLocation(location);
 return new Robot().createScreenCapture(bounds);
 \}
 ,,,

 * Capture the region of a component using an image buffer.
 -------------------------------------------------------------
 public BufferedImage captureComponentUsingImageBuffer(Component c) \{
 Dimension preferredSize = c.getPreferredSize();
 BufferedImage img = new BufferedImage(preferredSize.width, preferredSize.height, BufferedImage.TYPE\\_INT\\_ARGB);
 c.paint(img.getGraphics());
 return img;
 \}
 ,,,

 The method above can capture an image of a component even when
 it is hidden.

 * capture a screen shot. 
 ------------------------
 try
 \{
 Robot robot = new Robot ();
 // Capture a particular area on the screen
 int x = 100; int y = 100; int width = 200; int height = 200;
 Rectangle area = new Rectangle (x, y, width, height);
 BufferedImage bufferedImage = robot.createScreenCapture (area);

 // Capture the whole screen
 area = new Rectangle (Toolkit.getDefaultToolkit ().getScreenSize ());
 bufferedImage = robot.createScreenCapture (area);
 \}
 catch (AWTException e) \{ \}
 ,,,

 * get a buffered image of a jframe and write it to a png file
 ---------------------------------------------
 Component c = f.getContentPane();
 BufferedImage i = getScreenShot(c);
 try \{
 ImageIO.write(img, "png", new File("screenshot.png"));
 \} catch (Exception e) \{
 e.printStackTrace();
 \}
 public static BufferedImage getScreenShot(Component component) \{
 BufferedImage image = new BufferedImage(
 component.getWidth(), 
 component.getHeight(), BufferedImage.TYPE\\_INT\\_RGB
 );
 // call the Component's paint method, using
 // the Graphics object of the image.
 component.paint(image.getGraphics());
 return image;
 \}
 ,,,

SAVING IMAGES ....

COMPRESSING JPEG IMAGES ....
 
 The jpeg format allows the reduction of the file size of the image
 by reducing the quality of the image. This can be important for 
 emailing images or placing images in webpages.

 * compress a jpeg image with quality 85\\%, a tested example
 -----------------------------------------------------
 import javax.imageio.*;
 import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
 import javax.imageio.stream.ImageOutputStream;
 import java.io.File;
 import java.util.Locale;
 import java.awt.image.BufferedImage;
 public class ImageCompress \{
 public static void main(String[] args) \{
 float quality = 0.85f;
 File inFile = new File("big.jpg");
 File outFile = new File("compress.jpg" );
 try \{
 BufferedImage image = ImageIO.read(inFile);
 ImageWriter imgWriter =
 ImageIO.getImageWritersByFormatName("jpg").next();
 ImageOutputStream ioStream = 
 ImageIO.createImageOutputStream(outFile);
 imgWriter.setOutput(ioStream);
 JPEGImageWriteParam jpegParams =
 new JPEGImageWriteParam(Locale.getDefault());
 jpegParams.setCompressionMode(ImageWriteParam.MODE\\_EXPLICIT);
 jpegParams.setCompressionQuality(quality);
 imgWriter.write(null, new IIOImage(image, null, null), jpegParams);
 ioStream.flush();
 ioStream.close();
 imgWriter.dispose();
 System.out.format(
 "big.jpg size = \\%d, compress.jpg size = \\%d",
 inFile.length(), outFile.length());
 \} catch (java.io.IOException e) \{
 e.printStackTrace();
 \}
 \}
 \}
 ,,,

 The class IIOWriteProgressListener allows use to display the progress
 of the write and reduce quality operation (which will take a few seconds)

 * compress a jpeg image, quality 85\\%, with a write progress listener
 -----------------------------------------------------
 import javax.imageio.*;
 import javax.imageio.event.IIOWriteProgressListener;
 import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
 import javax.imageio.stream.ImageOutputStream;
 import java.io.File;
 import java.util.Locale;
 import java.awt.image.BufferedImage;
 public class ImageCompress implements IIOWriteProgressListener \{
 public static void main(String[] args) \{
 float quality = 0.85f;
 File inFile = new File("big.jpg");
 File outFile = new File("compress.jpg" );
 try \{
 BufferedImage image = ImageIO.read(inFile);
 ImageWriter imgWriter =
 ImageIO.getImageWritersByFormatName("jpg").next();
 ImageOutputStream ioStream = 
 ImageIO.createImageOutputStream(outFile);
 imgWriter.setOutput(ioStream);
 JPEGImageWriteParam jpegParams =
 new JPEGImageWriteParam(Locale.getDefault());
 jpegParams.setCompressionMode(ImageWriteParam.MODE\\_EXPLICIT);
 jpegParams.setCompressionQuality(quality);
 imgWriter.addIIOWriteProgressListener(new ImageCompress());
 imgWriter.write(null, new IIOImage(image, null, null), jpegParams);
 ioStream.flush();
 ioStream.close();
 imgWriter.dispose();
 System.out.format(
 "big.jpg size = \\%d, compress.jpg size = \\%d",
 inFile.length(), outFile.length());
 \} catch (java.io.IOException e) \{
 e.printStackTrace();
 \}
 \}
 //progress listener methods
 public void imageProgress(ImageWriter w, float percentageDone) \{
 System.out.format("Percent written: \\%f\\$\\backslash\\$n", percentageDone);
 \}
 public void imageComplete(ImageWriter w) \{
 System.out.println("Write complete");
 \}
 public void imageStarted(ImageWriter w, int imageIndex) \{\}
 public void thumbnailStarted(ImageWriter w, int index, int thumbi) \{\}
 public void thumbnailProgress(ImageWriter w, float percentDone) \{\}
 public void thumbnailComplete(ImageWriter w) \{\}
 public void writeAborted(ImageWriter w) \{\}
 \}
,,,

 * reduce the file size of a jpeg image, to an output stream
 -------------------------------------------------------------
 private Image getJpegCompressedImage(BufferedImage image) throws IOException \{
 float qualityFloat = 0.85f;
 ByteArrayOutputStream outStream = new ByteArrayOutputStream();
 ImageWriter imgWriter = 
 ImageIO.getImageWritersByFormatName("jpg").next();
 ImageOutputStream ioStream = 
 ImageIO.createImageOutputStream(outStream);
 imgWriter.setOutput(ioStream);
 JPEGImageWriteParam jpegParams = 
 new JPEGImageWriteParam(Locale.getDefault());
 jpegParams.setCompressionMode(ImageWriteParam.MODE\\_EXPLICIT);
 jpegParams.setCompressionQuality(qualityFloat);
 imgWriter.write(null, new IIOImage(image, null, null), jpegParams );
 ioStream.flush();
 ioStream.close();
 imgWriter.dispose();
 jpgSize = outStream.toByteArray().length;
 BufferedImage compressedImage = ImageIO.read(new ByteArrayInputStream(outStream.toByteArray()));
 return compressedImage;
 \}
 ,,,

CONVERTING IMAGE FORMATS ....

 * convert to a png compressed image without saving
 ----------------------------------------------------
 BufferedImage image = ...;
 ByteArrayOutputStream outStream = new ByteArrayOutputStream();
 ImageIO.write(image, "png", outStream);
 pngSize = outStream.toByteArray().length;
 BufferedImage compressedImage =
 ImageIO.read(new ByteArrayInputStream(outStream.toByteArray()));
 ,,,

IMAGE DATA

 The data for a BufferedImage is stored in a WritableRaster combined
 with a ColorModel.

 * write all image data to a new RGB image, pixel by pixel 
 -------------------------------------------------------------
 BufferedImage image = ...;
 BufferedImage newImage = 
 new BufferedImage(
 image.getWidth(), image.getHeight(), BufferedImage.TYPE\\_INT\\_RGB);
 for (int i=0; i<width; i++) \{
 for (int j = 0; j < height; j++)
 newImage.setRGB(i, j, image.getRGB(i, j));
 \}
 ,,,

 The y loop (horizontal) should be the outer loop because that 
 is how the image data is stored and therefore the code will execute
 faster.

 * loop through all the pixels in an image.
 --------------------------------------------------
 
 for (int y = 0; y < image.getHeight(); y++) \{
 for (int x = 0; x < image.getWidth(); x++) \{
 int clr = image.getRGB(x, y);
 int red = (clr \\& 0x00ff0000) >> 16;
 int green = (clr \\& 0x0000ff00) >> 8;
 int blue = clr \\& 0x000000ff;
 image.setRGB(x, y, clr);
 \}
 \}
 ,,,
BUFFEREDIMAGESOPS AND IMAGE MANIPULATION

 Java provides the interface BufferedImageOp and a number of
 implementations of this interface to carry out various 'filtering'
 operations on BufferedImages. These operation include blurring,
 converting to greyscale (black and white), changing colours et.

 \url{http://docstore.mik.ua/orelly/java-ent/jfc/ch04\\_10.htm}
 A introduction to image operations.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents Image filtering class
 @@ ConvolveOp - can be used for blurring an image
 @@ ColorConvertOp - convert to greyscale
 @@ and more ...
 ..


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents a summary of available BufferedImageOps
 @@ AffineTransformOp 
 Performs an arbitrary geometric transformation--specified by an
 AffineTransform--on an image. The transform can include scaling,
 rotation, translation, and shearing in any combination. This operator
 interpolates pixel values when needed, using either a fast,
 nearest-neighbor algorithm or a slower, higher-quality bilinear
 interpolation algorithm. This class cannot process images in place.
 @@ ColorConvertOp 
 Converts an image to a new java.awt.color.ColorSpace. It can process an
 image in place.
 @@ ConvolveOp 
 Performs a powerful and flexible type of image processing called
 convolution, which is used for blurring or sharpening images and
 performing edge detection, among other things. ConvolveOp uses a
 java.awt.image.Kernel object to hold the matrix of numbers that specify
 exactly what convolution operation is performed. Convolution operations
 cannot be performed in place.
 @@ LookupOp 
 Processes the color channels of an image using a lookup table, which is
 an array that maps color values in the source image to color values in
 the new image. The use of lookup tables makes LookupOp a very flexible
 image-processing class. For example, you can use it to brighten or
 darken an image, to invert the colors of an image, or to reduce the
 number of distinct color levels in an image. LookupOp can use either a
 single lookup table to operate on all color channels in an image or a
 separate lookup table for each channel. LookupOp can be used to process
 images in place. You typically use LookupOp in conjunction with
 java.awt.image.ByteLookupTable.
 @@ RescaleOp 
 Like LookupOp, RescaleOp is used to modify the values of the individual
 color components of an image. Instead of using a lookup table, however,
 RescaleOp uses a simple linear equation. The color values of the
 destination are obtained by multiplying the source values by a constant
 and then adding another constant. You can specify either a single pair
 of constants for use on all color channels or individual pairs of
 constants for each of the channels in the image. RescaleOp can process
 images in place.


\title{=} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents

 The requestFocusInWindow() below is necessary to set the focus
 onto the JPanel (GreyScale). 

 * convert an image to greyscale when the user presses g
 -------------------------------------
 import java.awt.image.*;
 import java.awt.color.*; import java.awt.*; import java.awt.event.*;
 import javax.imageio.ImageIO; import java.io.*;
 import javax.swing.*;
 public class GreyScale extends JPanel implements KeyListener \{
 BufferedImage original;
 BufferedImage display;
 BufferedImage grey;
 public GreyScale() \{
 try \{
 this.original = ImageIO.read(new File("scale.jpg"));
 this.display = this.original;
 \}
 catch (IOException e) \{
 System.out.println("Image File not found");
 \}
 this.addKeyListener(this);
 \}
 public void makeGrey() \{
 System.out.println("makeGrey");
 ColorConvertOp op = new ColorConvertOp(
 ColorSpace.getInstance(ColorSpace.CS\\_GRAY), null);
 this.grey = op.filter(this.original, null);
 this.display = this.grey;
 this.repaint();
 \}
 public void restore() \{
 System.out.println("restore");
 this.display = this.original;
 this.repaint();
 \}
 public void keyTyped(KeyEvent e) \{
 switch (e.getKeyChar()) \{
 case 'g': this.makeGrey(); break;
 case 'r': this.restore(); break;
 case 'x': System.exit(0); break;
 default: break;
 \}
 \}
 public void keyPressed(KeyEvent e) \{\}
 public void keyReleased(KeyEvent e) \{\}
 public Dimension getPreferredSize() \{
 return new Dimension(500, 500);
 \}
 public void paintComponent(Graphics g) \{
 super.paintComponent(g);
 Graphics2D gg = (Graphics2D) g;
 gg.drawImage(this.display, 0, 0, null);
 this.requestFocusInWindow();
 \}
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JFrame frame = new JFrame("Greyscale test");
 frame.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 frame.setContentPane(new GreyScale()); frame.pack();
 //frame.setSize(500,300);
 frame.setVisible(true);
 \}
 \});
 \} 
 \}
 ,,,

LOOKUPOP ....

 * make an image brighter with a LookupOp but this seems to change colors
 -------------------------------------------------------------
 public void makeBrighter() \{
 byte[] data = new byte[256];
 for(int i = 0; i < 256; i++) 
 data[i] = (byte)(Math.sqrt((float)i/255.0) * 255);
 ByteLookupTable table = new ByteLookupTable(0, data);
 LookupOp op = new LookupOp(table, null);
 this.brighter = op.filter(this.original, null);
 \}
 ,,,

RESCALEOP ....

 The RescaleOp can scale the colours of an image, lighter darker
 negative etc.

 The code below was actually crashing the java virtual machine. The
 problem was with TYPE\\_BYTE and TYPE\\_USHORT data type images. A work
 around is to copy the image to a BGR type before the rescaleop. 
 
 \url{http://bugs.sun.com/bugdatabase/view\\_bug.do;jsessionid=c863c92fdd734ffffffffc12241b21250538?bug\\_id=4886506}
 The sun bug report for jre crashes on rescaleop

 * make a darker image
 >> RescaleOp op = new RescaleOp(0.5f, 0.5f, null);

 * make a negative type image
 >> RescaleOp op = new RescaleOp(-1.0f, 255f, null);

 * make a brighter image
 >> RescaleOp op = new RescaleOp(1.1f, 0.0f, null);

 * make an image like a negative or brighter
 -------------------------------------
 import java.awt.image.*;
 import java.awt.color.*; import java.awt.*; import java.awt.event.*;
 import javax.imageio.ImageIO; import java.io.*;
 import javax.swing.*;
 public class NegativeImage extends JPanel implements KeyListener \{
 BufferedImage original;
 BufferedImage display;
 BufferedImage negative;
 BufferedImage brighter;
 public NegativeImage() \{
 try \{
 this.original = ImageIO.read(new File("test1.jpg"));
 this.display = this.original;
 \}
 catch (IOException e) \{
 System.out.println("Image File not found");
 \}
 this.addKeyListener(this);
 \}
 public void rescale() \{
 System.out.println("rescale");
 // copy the image to compatible to stop jre crashes
 BufferedImage adjusted=new BufferedImage(
 this.original.getWidth(),this.original.getHeight(),
 BufferedImage.TYPE\\_INT\\_BGR);
 Graphics2D ug = adjusted.createGraphics();
 ug.drawImage(this.original,0,0,null);
 ug.dispose();
 //RescaleOp op = new RescaleOp(-1.0f, 255f, null);
 RescaleOp op = new RescaleOp(1.1f, 0.0f, null);
 this.negative = op.filter(adjusted, null);
 this.display = this.negative;
 this.repaint();
 \}
 // producing weird results
 public void makeBrighter() \{
 byte[] data = new byte[256];
 for(int i = 0; i < 256; i++) 
 data[i] = (byte)(Math.sqrt((float)i/255.0) * 255);
 ByteLookupTable table = new ByteLookupTable(0, data);
 LookupOp op = new LookupOp(table, null);
 this.brighter = op.filter(this.original, null);
 this.display = this.brighter;
 this.repaint();
 \}
 public void restore() \{
 System.out.println("restore");
 this.display = this.original;
 this.repaint();
 \}
 public void keyTyped(KeyEvent e) \{
 switch (e.getKeyChar()) \{
 case 'n': this.rescale(); break;
 case 'b': this.makeBrighter(); break;
 case 'r': this.restore(); break;
 case 'x': System.exit(0); break;
 default: break;
 \}
 \}
 public void keyPressed(KeyEvent e) \{\}
 public void keyReleased(KeyEvent e) \{\}
 public Dimension getPreferredSize() \{
 return new Dimension(600, 600);
 \}
 public void paintComponent(Graphics g) \{
 super.paintComponent(g);
 Graphics2D gg = (Graphics2D) g;
 gg.drawImage(this.display, 0, 0, null);
 this.requestFocusInWindow();
 \}
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JFrame frame = new JFrame("Rescale an image");
 frame.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 frame.setContentPane(new NegativeImage()); frame.pack();
 frame.setVisible(true);
 \}
 \});
 \} 
 \}
 ,,,


CONVOLVEOP AND BLURRING IMAGES ....

 \url{http://www.jhlabs.com/ip/blurring.html}
 a good article about blurring in java.

 When blurring an image each pixel is computed from itself and its
 surrounding pixels. This process is known as 'convolution' (hence the
 name of the ConvolveOp class). The matrix below represents the
 contribution of a pixel and the eight surrounding pixels to the blurred
 pixel.

 * increasing luminosity with convolution and a 1x1 matrix
 -------------------------------------------------------------
 float[] matrix = \{ 1.1f \};
 BufferedImageOp op = new ConvolveOp(new Kernel(1, 1, matrix));
 newImage = op.filter(original, newImage);
 ,,,
 
 * a basic blur example
 ------------------------------------------------
 float[] matrix = \{
 0.111f, 0.111f, 0.111f,
 0.111f, 0.111f, 0.111f,
 0.111f, 0.111f, 0.111f,
 \};
 BufferedImageOp op = new ConvolveOp( new Kernel(3, 3, matrix) );
 blurredImage = op.filter(sourceImage, destImage);
 ,,,

 * a workaround for ImageOpException
 -------------------------------------------------------------
 BufferedImage tmp = 
 new BufferedImage(width, height, BufferedImage.TYPE\\_INT\\_RGB);
 for (int i=0; i<width; i++) \{
 for (int j = 0; j < height; j++)
 tmp.setRGB(i, j, img.getRGB(i, j));
 \}
 destImage = op.filter(tmp, null);
 ,,,

 The below was throwing an exception ImagingOpException: 
 The solution was to create a new simple rgb image but writing each
 pixel of the original image to a temporary one, and blurring the 
 temporary image.

 * blur an image or make brighter, the brighter is throwing an Exception
 -------------------------------------
 import java.awt.image.*;
 import java.awt.color.*; import java.awt.*; import java.awt.event.*;
 import javax.imageio.ImageIO; import java.io.*;
 import javax.swing.*;
 public class BlurImage extends JPanel implements KeyListener \{
 BufferedImage original;
 BufferedImage display;
 BufferedImage blurred;
 public BlurImage() \{
 try \{
 this.original = ImageIO.read(new File("scale.jpg"));
 this.display = this.original;
 \}
 catch (IOException e) \{
 System.out.println("Image File not found");
 \}
 this.addKeyListener(this);
 \}
 public void blur() \{
 System.out.println("blur");

 float[] matrix = \{
 0.111f, 0.111f, 0.111f,
 0.111f, 0.111f, 0.111f,
 0.111f, 0.111f, 0.111f,
 \};
 BufferedImageOp op = new ConvolveOp(new Kernel(3, 3, matrix));
 //this.blurred = op.createCompatibleDestImage(
 // this.original, this.original.getColorModel());
 
 // the following is a workaround for the ImagingOpException
 BufferedImage tmp = new BufferedImage(
 this.original.getWidth(), this.original.getHeight(),
 BufferedImage.TYPE\\_INT\\_RGB);
 for (int i=0; i<tmp.getWidth(); i++) \{
 for (int j = 0; j < tmp.getHeight(); j++)
 tmp.setRGB(i, j, this.original.getRGB(i, j));
 \}
 this.blurred = op.filter(tmp, null);
 //this.blurred = op.filter(this.original, this.blurred);
 this.display = this.blurred;
 this.repaint();
 \}
 public void makeBrighter() \{
 float[] matrix = \{ 1.1f \};
 BufferedImageOp op = new ConvolveOp(new Kernel(1, 1, matrix));
 this.blurred = op.filter(this.original, this.blurred);
 this.display = this.blurred;
 this.repaint();
 \}
 public void restore() \{
 System.out.println("restore");
 this.display = this.original;
 this.repaint();
 \}
 public void keyTyped(KeyEvent e) \{
 switch (e.getKeyChar()) \{
 case 'g': this.blur(); break;
 case 'b': this.makeBrighter(); break;
 case 'r': this.restore(); break;
 case 'x': System.exit(0); break;
 default: break;
 \}
 \}
 public void keyPressed(KeyEvent e) \{\}
 public void keyReleased(KeyEvent e) \{\}
 public Dimension getPreferredSize() \{
 return new Dimension(600, 600);
 \}
 public void paintComponent(Graphics g) \{
 super.paintComponent(g);
 Graphics2D gg = (Graphics2D) g;
 gg.drawImage(this.display, 0, 0, null);
 this.requestFocusInWindow();
 \}
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JFrame frame = new JFrame("Blur image with a ConvolveOp");
 frame.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 frame.setContentPane(new BlurImage()); frame.pack();
 //frame.setSize(500,300);
 frame.setVisible(true);
 \}
 \});
 \} 
 \}
 ,,,

ANIMATION

 * animation advice to reduce flicker
 
 In a JPanel, override paintComponent(Graphics) rather than
 paint(Graphics) Instead of calling Thread.sleep(n) implement a Swing
 Timer for repeating tasks or a SwingWorker for long running tasks. See
 "Concurrency in Swing" for more details.
 
 According to some, Swing is double buffered by default, apparently
 removing the need to write to an offscreen image buffer- need
 to investigate this.

 @@ \url{http://www.javarichclient.com/animated-transitions-timingframeworks/}
 how to use the timingframworks library (created by Chet Haase) to
 'transition' swing elements using animation. For example animate the
 closing of a window, etc

 * an animation to create 'marching ants' rectangle
 -------------------------------------------------------------
 import java.awt.*;
 import java.awt.event.*;
 import java.awt.geom.Rectangle2D;
 import java.awt.image.BufferedImage;
 import java.io.File;
 import java.io.IOException;
 import javax.imageio.ImageIO;
 import javax.swing.*;
 public class AnimatedStroke \{
 public static void main(String[] args) \{
 SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 BasicStroke dashedStroke;
 final int width = 100;
 final int height = 30;
 final BufferedImage image = new BufferedImage(
 width,height,BufferedImage.TYPE\\_INT\\_ARGB);
 final JLabel label = new JLabel(new ImageIcon(image));
 int pad = 5;
 final Shape rectangle = new Rectangle2D.Double(
 (double)pad,(double)pad,
 (double)(width-2*pad),
 (double)(height-2*pad));
 
 ActionListener listener = new ActionListener() \{
 float dashPhase = 0f;
 float dash[] = \{5.0f,5.0f\};
 @Override
 public void actionPerformed(ActionEvent ae) \{
 dashPhase += 9.0f;
 BasicStroke dashedStroke = new BasicStroke(
 1.5f,
 BasicStroke.CAP\\_ROUND,
 BasicStroke.JOIN\\_MITER,
 1.5f, //miter limit
 dash, dashPhase
 );
 Graphics2D g = image.createGraphics();
 g.setColor(Color.WHITE);
 g.fillRect(0,0,width,height);
 g.setColor(Color.BLACK);
 g.setStroke(dashedStroke);
 g.draw(rectangle);
 g.dispose();
 label.repaint();
 
 /*
 if (dashPhase<100f) \{
 try \{ ImageIO.write(image, "PNG",
 new File("img" + dashPhase + ".png"));
 \} catch(IOException ioe) \{\}
 \}*/
 \}
 \};
 Timer timer = new Timer(40, listener);
 timer.start();
 JOptionPane.showMessageDialog(null, label);
 \}
 \});
 \}
 \}
 ,,,

 The following animation doesnt flicker much on my pc.

 * a waveform animation
 ------------------------------------------
 import java.awt.*;
 import javax.swing.*;
 public class FlickerPanel extends JPanel implements Runnable \{
 private float[] pixelMap = new float[0];
 // Cached graphics objects to reduce flicker 
 private Image screenBuffer;
 private Graphics bufferGraphics;
 
 public FlickerPanel () \{
 Thread t = new Thread(this);
 t.start();
 \}
 private float addNoise () \{
 return (float)((Math.random()*2)-1);
 \}
 private synchronized void advance () \{
 if (pixelMap == null || pixelMap.length == 0) return;
 float[] newPixelMap = new float[pixelMap.length];
 for (int i=1; i<pixelMap.length; i++) \{
 newPixelMap[i-1] = pixelMap[i];
 \}
 newPixelMap[newPixelMap.length-1] = addNoise();
 pixelMap = newPixelMap;
 \}
 public void run() \{
 while (true) \{
 advance();
 repaint();
 try \{
 Thread.sleep(25);
 \} catch (InterruptedException e) \{\}
 \}
 \}
 private int getY (float height) \{
 double proportion = (1-height)/2;
 return (int)(getHeight()*proportion);
 \}
 public void paint (Graphics g) \{
 if (screenBuffer == null || screenBuffer.getWidth(this) != getWidth() || screenBuffer.getHeight(this) != getHeight()) \{
 screenBuffer = createImage(getWidth(), getHeight());
 bufferGraphics = screenBuffer.getGraphics();
 \}
 
 if (pixelMap == null || getWidth() != pixelMap.length) \{
 pixelMap = new float[getWidth()];
 \}
 bufferGraphics.setColor(Color.BLACK);
 bufferGraphics.fillRect(0, 0, getWidth(), getHeight());
 bufferGraphics.setColor(Color.GREEN);
 int lastX = 0;
 int lastY = getHeight()/2;
 for (int x=0; x<pixelMap.length; x++) \{
 int y = getY(pixelMap[x]);
 bufferGraphics.drawLine(lastX, lastY, x, y);
 lastX = x;
 lastY = y;
 \}
 g.drawImage(screenBuffer, 0, 0, this);
 \}
 public void update(Graphics g) \{
 paint(g);
 \}
 public static void main (String [] args) \{
 JFrame frame = new JFrame("Flicker test");
 frame.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 frame.setContentPane(new FlickerPanel());
 frame.setSize(500,300);
 frame.setVisible(true);
 \}
 \}
 ,,,

CHARTS

 One option is to use JFreeChart
 
 * a simple example with jfreechart
 -------------------------------------------------------------
 HistogramDataset dataset = new HistogramDataset();
 dataset.addSeries("series label",arrayOfValues,noOfBins);
 //Create a chart object

 JFreeChart chart = ChartFactory.
 createHistogram("plotTitle", "xaxis label", "yaxis label", 
 dataset, PlotOrientation.VERTICAL, false, false, false);
 //If swing application use ChartPanel to render chart

 ChartPanel chartPanel = new ChartPanel(chart)
 chartPanel.setPreferredSize(new java.awt.Dimension JavaDoc(500, 270));
 chartPanel.setMouseZoomable(true, false);
 If need to write chart to a file/stream use ChartUtilities.saveChartAsPNG(...)

 ChartUtilities.saveChartAsPNG(new File("histogram.PNG"), chart, width, height);
 ,,,

NETWORKS

 This is a big topic and I havent even started yet

 * connect through a proxy host to the net
 >> java -Dhttp.proxyHost=proxyhost [-Dhttp.proxyPort=portNumber] URLReader


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents useful classes
 .. NetworkInterface - very useful for getting card information
 ..

 * list network card interfaces java1.6+
 ---------------------------------------
 import java.io.*;
 import java.net.*;
 import java.util.*;
 public class ListNetInterfaces
 \{
 public static void main(String args[]) throws SocketException \{
 Enumeration<NetworkInterface> nets =
 NetworkInterface.getNetworkInterfaces();
 for (NetworkInterface ni : Collections.list(nets)) \{
 System.out.println(
 "Display name:" + ni.getDisplayName());
 System.out.println("Hardware address:" +
 Arrays.toString(ni.getHardwareAddress()));
 \}
 \}
 \}
 ,,,

 * get the computer name and ip address
 -------------------------------------------------------------
 public class NetInfo \{
 public static void main(String[] args) \{
 try \{
 java.net.InetAddress i = java.net.InetAddress.getLocalHost();
 System.out.println(i); // name and IP address
 System.out.println(i.getHostName()); // name
 System.out.println(i.getHostAddress()); // IP address only
 \}
 catch (Exception e) \{ e.printStackTrace(); \}
 \}
 \}
 ,,,

 * list interfaces an associated ip addresses
 ---------------------------------------------
 import java.net.*;
 import java.util.*;
 import java.io.*;
 import java.nio.*;
 public class IPAdress \{
 public void getInterfaces () \{
 try \{
 Enumeration e = NetworkInterface.getNetworkInterfaces();
 while (e.hasMoreElements()) \{
 NetworkInterface ni = (NetworkInterface) e.nextElement();
 System.out.println("Net interface: "+ni.getName());
 Enumeration e2 = ni.getInetAddresses();
 while (e2.hasMoreElements()) \{
 InetAddress ip = (InetAddress) e2.nextElement();
 System.out.println("IP address: "+ ip.toString());
 \}
 \}
 \}
 catch (Exception e) \{ e.printStackTrace(); \}
 \}
 
 public static void main(String[] args) \{
 IPAdress ip = new IPAdress();
 ip.getInterfaces();
 \}
 \}
 ,,,

SOCKETS

 A socket is a tcp connection occuring on a particular port
 between 2 computers. Java makes these kinds of connections 
 quite simple to set up. The entire net is based on them, so
 it worth knowing how to do it.

SERVER SOCKETS ....
 
 Server sockets listen on a port for an incoming connection or request.

 Socket aSock = myServerSocket.accept();

 * determine where a connection to a ServerSocket is coming from
 -------------------------------------------------------------
 System.out.println
 ("Connection from : "
 + aSock.getInetAddress().getHostAddress()
 + ':' + aSock.getPort());
 ,,,

 In the examples below, we can use streams directly rather than
 creating arrays of bytes. Examples from rgagnon. need to be 
 adapted.

 * create a ServerSocket to send the file 'source.pdf' to a client
 --------------------------------------------------
 import java.net.*;
 import java.io.*;
 public class FileServer \{
 public static void main (String [] args ) throws IOException \{
 // create socket
 ServerSocket servsock = new ServerSocket(13267);
 while (true) \{
 System.out.println("Waiting...");
 Socket sock = servsock.accept();
 System.out.println("Accepted connection : " + sock);
 
 // send a file
 File file = new File ("source.pdf");
 byte[] byteArray = new byte[(int)file.length()];
 FileInputStream fis = new FileInputStream(file);
 BufferedInputStream bis = new BufferedInputStream(fis);
 bis.read(byteArray, 0, byteArray.length);
 OutputStream os = sock.getOutputStream();
 System.out.println("Sending...");
 os.write(byteArray, 0, byteArray.length);
 os.flush();
 sock.close();
 \}
 \}
 \}
 ,,,

 * the client application which receives a file from the server
 -------------------------------------------------------------
 import java.net.*;
 import java.io.*;
 public class FileClient \{
 public static void main (String[] args ) throws IOException \{
 int filesize=6022386; // filesize temporary hardcoded
 long start = System.currentTimeMillis();
 int bytesRead;
 int current = 0;
 // localhost for testing
 Socket sock = new Socket("127.0.0.1", 13267);
 System.out.println("Connecting...");
 // receive file
 byte[] mybytearray = new byte[filesize];
 InputStream is = sock.getInputStream();
 FileOutputStream fos = new FileOutputStream("source-copy.pdf");
 BufferedOutputStream bos = new BufferedOutputStream(fos);
 bytesRead = is.read(mybytearray, 0, mybytearray.length);
 current = bytesRead;
 do \{
 bytesRead =
 is.read(mybytearray, current, (mybytearray.length-current));
 if (bytesRead >= 0) current += bytesRead;
 \} while (bytesRead > -1);
 
 bos.write(mybytearray, 0 , current);
 bos.flush();
 long end = System.currentTimeMillis();
 System.out.println("Time taken:" + end - start);
 bos.close();
 sock.close();
 \}
 \}
 ,,,

URLS
 
 Urls are the unique names given to resources on the local 
 computer or the internet. There is some subtle distinction between
 Uri and Url but lets not worry. Java has the java.net.URL class.
 
 * a url which refers to a local file in same folder as the application
 >> URL url = new URL("file:MethodPanel.class");

 * a url for a local file using an absolute pathname
 >> URL url = new URL("file:/home/arjuna/MethodPanel.class");

 * a jar url for a local jar archive on a ms windows computer
 >> URL url = new URL("jar:file:/c:/almanac/my.jar!/");

 * a jar url referring to a remote jar archive
 >> URL url = new URL("jar:http://bumble.sf.net/books/java/m.jar!/"); 

 * check if the url 'webDoc' points to the same file as 'url'
 >> webDoc.sameFile(url)

 * check if a url supplied as an argument has a valid format
 -------------------------------------------------------------
 import java.net.*;
 public class ValidUrl \{
 public static void main(String[] args) \{
 if (args.length < 1) \{
 System.out.println("usage: java ValidUrl url");
 System.exit(-1);
 \}
 URL url = null;
 try \{
 url = new URL(args[0]);
 \} catch (MalformedURLException e) \{
 System.out.println("Invalid URL: " + args[0]);
 \}
 \}
 \}
 ,,,

 * check if a url host is valid and the file exists
 --------------------------------------------------
 import java.net.*;
 import java.io.*;
 public class ValidUrl \{
 public static void main(String[] args) throws Exception \{
 URL url = new URL("http://bumble.sf.net/notes/index.txt");
 try
 \{
 url.openStream();
 System.out.println("ok");
 \}
 catch (UnknownHostException e)
 \{ System.out.println("unknown host: " + e); \}
 catch (FileNotFoundException e)
 \{ System.out.println("file not found: " + e); \}
 \}
 \}
 ,,,

 Actually the UnkownHostException doesnt seem to get triggered,
 only the FileNotFoundException

PARTS OF THE URL ....
 
 A url can be divided into parts such as hostname, filename, path etc.
 All this may seem rather trivial and boring, but since URLs are such
 as important part of the web, and therefore the world, its probably
 worth knowing.

 getFile(), and getPath(), seem to return the same thing- that is all 
 of the url after the protocol and host section.

 * display some of the parts of a url 
 -------------------------------------------------------------
 import java.net.*;
 public class UrlParts \{
 public static void main(String[] args) \{
 URL url;
 try \{
 url = new URL(
 "http://www.eg.com/java/net/URI.html");
 //"file:/usr/lib/jvm/java-6-sun/docs/api/java/net/URI.html");
 System.out.format(
 "url.getFile(): \\%s \\$\\backslash\\$n" +
 "url.getPath(): \\%s \\$\\backslash\\$n" +
 "url.getHost(): \\%s \\$\\backslash\\$n" +
 "url.getPort(): \\%s \\$\\backslash\\$n" +
 "url.getProtocol(): \\%s \\$\\backslash\\$n" +
 "url.getDefaultPort(): \\%s \\$\\backslash\\$n" +
 "url.toString(): \\%s \\$\\backslash\\$n" +
 "url.toExternalForm(): \\%s \\$\\backslash\\$n", 
 url.getFile(), url.getPath(), url.getHost(), url.getPort(),
 url.getProtocol(), url.getDefaultPort(), url.toString(), 
 url.toExternalForm());
 \} catch (MalformedURLException e) \{
 System.out.println("Invalid URL: " + args[0]);
 \}
 \}
 \}
 ,,,

REFERENCES FOR URLS ....

 The reference of a URL is the part after the hash '\\#' and indicates
 a section within the current (html) page.

 * check if there is no reference for the url
 >> if (url.getRef() == null) \{...\}

 * check if 2 urls point to the same file (with possibly different refs)
 >> if (urlA.sameFile(urlB)) \{...\}

CONVERTING URLS TO OTHER FORMATS OR OBJECTS ....

 * convert a URL to a File object
 >> File f = new File(url.toURI());

 * experiment with converting to uri and files 
 -------------------------------------------------------------
 import java.net.*;
 public class ConvertUrl \{
 public static void main(String[] args) \{
 URL url;
 try \{
 url = new URL(
 "file:/usr/lib/jvm/java-6-sun/docs/api/java/net/URI.html");
 System.out.format(
 "url.toString(): \\%s \\$\\backslash\\$n" +
 "url.toExternalForm(): \\%s \\$\\backslash\\$n", 
 url.toString(), url.toExternalForm());
 \} catch (MalformedURLException e) \{
 System.out.println("Invalid URL: " + args[0]);
 \}
 \}
 \}
 ,,,

JAVAMAIL

 Sending and receiving email can be done with the Javamail package
 javax.mail using an account on an smtp server, imap server or pop
 server.

INSTALLING JAVAMAIL ....

 The javamail api does not come, by default, with the Java SE
 developer kit (only with the enterprise edition). 

 If you are using java 1.5 or less then you have to install
 the java beans framework or something like that. But really, just
 upgrade.

 * download the zip file from oracle
 >> javamail1\\_4\\_5.zip 

 * unzip the file
 >> unzip javamail*

 * find out where your java extensions folder is with something like 
 ----
 public class ExtensionPath
 \{
 public static void main(String[] args) \{
 System.out.println(System.getProperty("java.ext.dirs"));
 \}
 \}
 ,,,

 * copy the ./javamail*/mail.jar to an extensions folder
 >> sudo cp javamail-1.4.5/mail.jar \texttt{/usr/lib/jvm/java-6-sun-1.6.0.15/jre/lib/ext}

 Or you could copy it to a user extensions folder which doesnt
 require administrator priviledges.

SENDING EMAIL ....

 \url{http://java.sun.com/developer/onlineTraining/JavaMail/contents.html}
 A javamail howto

 * send email using a tls connection
 -------------------------------------------------------------
 import java.util.Properties;
 import javax.mail.Message;
 import javax.mail.MessagingException;
 import javax.mail.PasswordAuthentication;
 import javax.mail.Session;
 import javax.mail.Transport;
 import javax.mail.internet.InternetAddress;
 import javax.mail.internet.MimeMessage;
 public class SendMailTLS \{
 public static void main(String[] args) \{
 final String username = "username@gmail.com";
 final String password = "password";
 Properties props = new Properties();
 props.put("mail.smtp.auth", "true");
 props.put("mail.smtp.starttls.enable", "true");
 props.put("mail.smtp.host", "smtp.gmail.com");
 props.put("mail.smtp.port", "587");
 
 Session session = Session.getInstance(props,
 new javax.mail.Authenticator() \{
 protected PasswordAuthentication getPasswordAuthentication() \{
 return new PasswordAuthentication(username, password);
 \}
 \});
 
 try \{
 Message message = new MimeMessage(session);
 message.setFrom(new InternetAddress("from-email@gmail.com"));
 message.setRecipients(Message.RecipientType.TO,
 InternetAddress.parse("to-email@gmail.com"));
 message.setSubject("Testing Subject");
 message.setText("Dear Mail Crawler,"
 + "\\$\\backslash\\$n\\$\\backslash\\$n No spam to my email, please!");
 Transport.send(message);
 System.out.println("Done");
 \} catch (MessagingException e) \{
 throw new RuntimeException(e);
 \}
 \}
 \}
 ,,,

 It worked!!

 * settings for connecting to a gmail account to send mail via smtp
 -------------------------------------------------------------
 props.put("mail.smtp.host", "smtp.gmail.com");
 props.put("mail.smtp.socketFactory.port", "465");
 props.put("mail.smtp.socketFactory.class",
 "javax.net.ssl.SSLSocketFactory");
 props.put("mail.smtp.auth", "true");
 props.put("mail.smtp.port", "465");
 ,,,

 * send an email via smtp and an ssl connection
 -------------------------------------------------------------
 import java.util.Properties;
 import javax.mail.*;
 import java.io.*;
 import javax.mail.internet.InternetAddress;
 import javax.mail.internet.MimeMessage;
 
 public class SendMailSSL \{
 public static void main(String[] args) \{
 Properties props = new Properties();
 
 // fastmail settings
 props.put("mail.smtp.host", "mail.messagingengine.com");
 props.put("mail.smtp.socketFactory.port", "465");
 props.put("mail.smtp.socketFactory.class",
 "javax.net.ssl.SSLSocketFactory");
 props.put("mail.smtp.auth", "true");
 props.put("mail.smtp.port", "465");
 
 Session session = Session.getDefaultInstance(props,
 new javax.mail.Authenticator() \{
 protected PasswordAuthentication getPasswordAuthentication() \{
 String password = JOptionPane.showInputDialog(
 "Enter mail password'");
 return new PasswordAuthentication(
 "mjbishop@fastmail.fm", password);
 \}
 \});
 
 try \{
 Message message = new MimeMessage(session);
 message.setFrom(new InternetAddress("me@fastmail.fm"));
 message.setRecipients(Message.RecipientType.TO,
 InternetAddress.parse("shop@fastmail.fm"));
 message.setSubject("Testing Javamail");
 message.setText("Dear Javamail,\\$\\backslash\\$n\\$\\backslash\\$n Send this now!");
 Transport.send(message);
 System.out.println("Sent");
 \} catch (MessagingException e) \{
 throw new RuntimeException(e);
 \}
 \}
 \}
 ,,,

 * reply to a message
 -------------------------
 MimeMessage reply = (MimeMessage)message.reply(false);
 reply.setFrom(new InternetAddress("president@whitehouse.gov"));
 reply.setText("Thanks");
 Transport.send(reply);
 ,,,

EMAIL APP ....

 The example below is supposed to be a minimalist form for sending
 email with the javamail classes and smtp. But it requires an account
 on an smtp server. Currently using a fastmail account.

 Ideas: an image search to insert an image in the mail. Clear fields
 function. Insert symbol glyphs in the message text (but using what
 font?). An action to make the font bigger and smaller.

 * a simple interface to send an email 
 -------------------------------------------------------------
 import java.util.Properties;
 import javax.mail.*;
 import java.io.*;
 import java.net.URL; import java.net.MalformedURLException;
 import javax.mail.internet.*;
 import javax.swing.*;
 import javax.swing.border.*;
 import javax.swing.plaf.*;
 import java.awt.*;
 import java.awt.event.*;
 import java.util.*;
 public class MailForm extends JPanel implements ActionListener \{
 JTextField fromField; JComboBox toField; 
 JTextField subjectField; JButton sendButton;
 JTextArea mailArea;
 JPanel headPanel;
 public MailForm() \{
 super(new BorderLayout(10, 10));
 Font f = new Font("Georgia", Font.ITALIC, 20);
 Font g = new Font("FreeSerif", Font.PLAIN, 30);
 UIManager.put("TextField.font", new FontUIResource(f));
 UIManager.put("ComboBox.font", new FontUIResource(f));
 UIManager.put("TextArea.font", new FontUIResource(g));
 UIManager.put("Label.font", new FontUIResource(g));
 UIManager.put("Button.font", new FontUIResource(g));
 this.fromField = new JTextField("mjbishop <at> fastmail.fm"); 
 this.toField = new JComboBox(this.getAddresses()); 
 this.toField.setEditable(true);
 this.subjectField = new JTextField(); 
 this.sendButton = new JButton("send \\$\\backslash\\$u2709");
 this.sendButton.addActionListener(this);
 this.headPanel = new JPanel(new GridLayout(0,2,10,10));

 headPanel.add(new JLabel("From \\$\\backslash\\$u269c", JLabel.RIGHT)); 
 headPanel.add(fromField); 
 headPanel.add(new JLabel("To \\$\\backslash\\$u269c", JLabel.RIGHT)); 
 headPanel.add(toField);
 headPanel.add(new JLabel("Subject \\$\\backslash\\$u269c", JLabel.RIGHT)); 
 headPanel.add(subjectField);
 headPanel.add(new JLabel());
 headPanel.add(sendButton);
 headPanel.setBorder(BorderFactory.createEmptyBorder(20,0,20,160));
 this.mailArea = new JTextArea(20, 60);
 this.mailArea.setBorder(new EtchedBorder()); 
 this.add(headPanel, BorderLayout.NORTH);
 this.add(mailArea, BorderLayout.CENTER);
 \}
 public void actionPerformed(ActionEvent e) \{ this.send(); \}

 /** get email address from a text file 'address.txt' */
 public String[] getAddresses() \{
 java.util.List<String> emails = new ArrayList<String>();
 try \{
 String abook = String.format(
 "file:\\%s/sf/htdocs/books/java/address.txt", 
 System.getProperty("user.home"));
 System.out.println(abook); 
 //URL url = new URL("file:address.txt");
 URL url = new URL(abook);
 BufferedReader in = new BufferedReader(
 new InputStreamReader(url.openStream()));
 /*
 InputStream is = 
 this.getClass().getResourceAsStream("../address.txt");
 BufferedReader in = new BufferedReader(new InputStreamReader(is));
 */
 String line;
 while ((line = in.readLine()) != null) \{
 if (line.matches(".*@.*")) \{
 emails.add(line.trim());
 \}
 \}
 in.close();
 \}
 catch (MalformedURLException e) \{ e.printStackTrace(); \}
 catch (IOException e) \{ e.printStackTrace(); \}
 return emails.toArray(new String[emails.size()]);
 \}

 /** send an email */
 public void send() \{
 Properties props = new Properties();
 // fastmail settings
 props.put("mail.smtp.host", "mail.messagingengine.com");
 props.put("mail.smtp.socketFactory.port", "465");
 props.put("mail.smtp.socketFactory.class",
 "javax.net.ssl.SSLSocketFactory");
 props.put("mail.smtp.auth", "true");
 props.put("mail.smtp.port", "465");

 String subject = this.subjectField.getText();
 String messageText = this.mailArea.getText();
 String toAddress = (String) toField.getSelectedItem();
 final String fromAddress = 
 fromField.getText().replace(" <at> ", "@");
 System.out.format(
 "subject:\\%s \\$\\backslash\\$ntoAddress:\\%s \\$\\backslash\\$nfromAddress:\\%s \\$\\backslash\\$nmessageText:\\%s\\$\\backslash\\$n",
 subject, toAddress, fromAddress, messageText);

 if (subject.equals("") || messageText.equals("")) \{
 JOptionPane.showMessageDialog(null,
 "write a subject and a message");
 return;
 \}

 Session session = Session.getDefaultInstance(props,
 new javax.mail.Authenticator() \{
 protected PasswordAuthentication getPasswordAuthentication() \{
 String password = JOptionPane.showInputDialog(
 "Enter mail password'");
 return new javax.mail.PasswordAuthentication(
 fromAddress, password);
 \}
 \});
 
 try \{
 Message message = new MimeMessage(session);
 //message.setFrom(new InternetAddress("me@fastmail.fm"));
 message.setFrom(new InternetAddress(fromAddress));
 message.setRecipients(Message.RecipientType.TO,
 InternetAddress.parse(toAddress));
 message.setSubject(subject);
 message.setText(messageText);
 Transport.send(message);
 System.out.println("Sent");
 \}
 catch (AuthenticationFailedException e) \{
 JOptionPane.showMessageDialog(this, 
 "Incorrect name or password? \\$\\backslash\\$n\\$\\backslash\\$n" + e);
 \}
 catch (MessagingException e) \{
 if (e.getMessage().startsWith("Unknown SMTP host:")) \{
 JOptionPane.showMessageDialog(this, 
 "No net connection? or bad smtp host \\$\\backslash\\$n\\$\\backslash\\$n" + e);
 \}
 e.printStackTrace();
 \}
 \}
 public static void main(String[] args) \{
 System.setProperty("awt.useSystemAAFontSettings","on");
 JFrame f = new JFrame("Simple Mail Form");
 f.add(new MailForm()); f.pack();
 f.setExtendedState(JFrame.MAXIMIZED\\_BOTH);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setVisible(true);
 \}
 \}
 ,,,

 
SENDING EMAIL WITHOUT JAVAMAIL ....

 Another way to send email via smtp is to 'speak' the smtp protocol
 directly using a socket connection on the appropriate port. This
 has the advantage of avoiding the \\$\\verb|~|2megabyte javamail dependency
 
ATTACHMENTS ....

 To send an attachment you create a message with several mime body
 parts

 * send a message with an attachment
 --------------------------------------
 
 // Define message
 Message message = new MimeMessage(session);
 message.setFrom(new InternetAddress(from));
 message.addRecipient(Message.RecipientType.TO,
 new InternetAddress(to));
 message.setSubject("JavaMail Attachment");
 // Create the message part
 BodyPart textPart = new MimeBodyPart();
 textPart.setText("Please see the file attached");
 
 // create the attachment
 BodyPart attachPart = new MimeBodyPart();
 DataSource source = new FileDataSource(filename);
 attachPart.setDataHandler(new DataHandler(source));
 attachPart.setFileName(filename);

 Multipart multipart = new MimeMultipart();
 multipart.addBodyPart(textPart);
 multipart.addBodyPart(attachPart);
 
 // Put parts in message
 message.setContent(multipart);
 
 // Send the message
 Transport.send(message);
 ,,,


HTML EMAIL MESSAGES ....

 * send an html email message
 -------------------------------------------------------------
 String htmlText = "<H1>Hello</H1>" + 
 "<img src=\\$\\backslash\\$"http://www.jguru.com/images/logo.gif\\$\\backslash\\$">";
 message.setContent(htmlText, "text/html"));
 ,,,

 The images above are fetched by the receivers email client
 (they are not embedded in the message)

 * display an html email message using a JEditorPane
 -------------------------------------------------------------
 String content = (String) message.getContent();
 JEditorPane text = new JEditorPane("text/html", content);
 text.setEditable(false);
 JScrollPane pane = new JScrollPane(text);
 ,,,

 * send an embedded image in an html email message
 -------------------------------------------------------------
 String file = "picnic.jpg";
 Message message = new MimeMessage(session);
 message.setSubject("Embedded Image");
 message.setFrom(new InternetAddress(from));
 message.addRecipient(Message.RecipientType.TO,
 new InternetAddress(to));
 
 // Create your new message part
 BodyPart htmlPart = new MimeBodyPart();
 String htmlText = "<H1>Hello</H1>" +
 "<img src=\\$\\backslash\\$"cid:memememe\\$\\backslash\\$">";
 htmlPart.setContent(htmlText, "text/html");
 
 // Create a related multi-part to combine the parts
 MimeMultipart multipart = new MimeMultipart("related");
 multipart.addBodyPart(htmlPart);
 
 // Fetch the image and associate to part
 BodyPart imagePart = new MimeBodyPart();
 DataSource fds = new FileDataSource(file);
 imagePart.setDataHandler(new DataHandler(fds));
 imagePart.setHeader("Content-ID","<memememe>");
 
 multipart.addBodyPart(imagePart);
 message.setContent(multipart);
 ,,,
 
 In the example above the "related" parameter to the 
 MultiPart constructor is necessary to advice the Multipart
 that the two parts of the message are related. The id string
 for the image can be anything.

 * get an attachment from a url
 >> DataSource fds = new URLDataSource(url);
 >> imagePart.setDataHandler(new DataHandler(fds));

CONNECTING TO THE MAIL BOX ....

 * connect using a javax.mail.URLName
 -------------------------------------------------------------
 javax.mail.Session session = javax.mail.Session.getInstance(props);
 javax.mail.Store store = 
 session.getStore(new javax.mail.URLName("imap://mailtest:mailtest@localhost/"));
 store.connect();
 System.out.println("connected to store.");
 ,,,

LISTING MESSAGES ....

 * open the drafts folder
 >> Folder folder = store.getFolder("INBOX.Drafts");
 >> folder.open(Folder.READ\\_ONLY);
 
 The problem with the code below is that the password is stored in
 plain text in the java source file. It is better to use an 
 Authenticator.

 * list messages in imap inbox: this worked !!
 -------------------------------------------------------------
 import java.util.Properties;
 import javax.mail.*;
 import java.io.*;
 import javax.swing.JOptionPane;
 import javax.mail.internet.InternetAddress;
 import javax.mail.internet.MimeMessage;
 
 public class FetchMail \{
 public static void main(String[] args) \{
 Properties props = new Properties();
 
 // fastmail settings
 props.put("mail.imaps.host", "mail.messagingengine.com");
 props.put("mail.imap.socketFactory.port", "993");
 props.put("mail.imap.socketFactory.class",
 "javax.net.ssl.SSLSocketFactory");
 props.put("mail.imap.auth", "true");
 props.put("mail.imap.port", "993");
 
 props.setProperty("mail.store.protocol", "imaps");
 try \{
 Session session = Session.getDefaultInstance(props, null);
 Store store = session.getStore("imaps");
 String password = JOptionPane.showInputDialog("Mail Password");
 store.connect("mail.messagingengine.com", "mjbishop@fastmail.fm", password);
 Folder folder = store.getFolder("INBOX");
 folder.open(Folder.READ\\_ONLY);
 // Get a list of messages
 Message messages[] = folder.getMessages();
 int ii = 0;
 for (Message m: messages) \{
 System.out.format(
 "\\%d: \\%s \\%s \\$\\backslash\\$n", ii++, m.getFrom()[0], m.getSubject());
 \}
 // Close connection
 folder.close(false);
 store.close();
 System.out.println("Fetched");
 \} catch (NoSuchProviderException e) \{
 e.printStackTrace();
 System.exit(1);
 \} catch (MessagingException e) \{
 e.printStackTrace();
 System.exit(2);
 \}
 \}
 \}
 ,,,

 The mail fetch is not very fast, a good candidate for a thread
 
 * fetch all messages from an imap inbox, with an authenticator
 -------------------------------------------------------------
 import java.util.Properties;
 import javax.mail.*;
 import java.io.*;
 import javax.mail.internet.InternetAddress;
 import javax.mail.internet.MimeMessage;
 import javax.swing.*;

 public class ListMailInbox \{
 public static void main(String[] args) \{
 Properties props = new Properties();
 
 // fastmail settings
 props.put("mail.imaps.host", "mail.messagingengine.com");
 props.put("mail.imaps.port", "993");
 
 Session session = Session.getDefaultInstance(props,
 new javax.mail.Authenticator() \{
 protected PasswordAuthentication getPasswordAuthentication() \{
 String pass = JOptionPane.showInputDialog("Mail password");
 return new PasswordAuthentication("mjbishop@fastmail.fm", pass);
 \}
 \});
 
 try \{
 Store store = session.getStore("imaps");
 store.connect();
 Folder folder = store.getFolder("INBOX");
 folder.open(Folder.READ\\_ONLY);
 // list all messages (slow)
 Message[] messages = folder.getMessages();
 int ii = 0;
 for (Message m: messages) \{
 System.out.format(
 "\\%d: \\%s \\%s \\$\\backslash\\$n", ii++, m.getFrom()[0], m.getSubject());
 \}
 folder.close(false); store.close();
 \} catch (MessagingException e) \{
 e.printStackTrace();
 \}
 \}
 \}
 ,,,


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents exceptions 
 .. NoSuchProviderException 
 ..

SEARCHING MAIL FOLDERS ....

 * search a folder for messages matching a logical expression
 -------------------------------------------------------------
 import javax.mail.search.*;
 ...
 SearchTerm st =
 new OrTerm(
 new SubjectTerm("ADV:"),
 new FromStringTerm("friend@public.com"));
 Message[] msgs = folder.search(st);
 ,,,
 

\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents available search term classes
 AND terms (class AndTerm)
 OR terms (class OrTerm)
 NOT terms (class NotTerm)
 SENT DATE terms (class SentDateTerm)
 CONTENT terms (class BodyTerm)
 HEADER terms (FromTerm / FromStringTerm, RecipientTerm / RecipientStringTerm, SubjectTerm, etc.)
 ,,,

 
 * search for messages with 'ticket' or 'plant' in the subject 
 -------------------------------------------------------------
 import java.util.Properties;
 import javax.mail.*;
 import java.io.*;
 import javax.mail.internet.InternetAddress;
 import javax.mail.internet.MimeMessage;
 import javax.mail.search.*;
 import javax.swing.*;
 
 public class SearchMailFolder \{
 public static void main(String[] args) \{
 Properties props = new Properties();
 
 // fastmail settings
 props.put("mail.imaps.host", "mail.messagingengine.com");
 props.put("mail.imaps.port", "993");
 
 Session session = Session.getDefaultInstance(props,
 new javax.mail.Authenticator() \{
 protected PasswordAuthentication getPasswordAuthentication() \{
 String password = JOptionPane.showInputDialog("Mail password");
 return new PasswordAuthentication(
 "mjbishop@fastmail.fm", password);
 \}
 \});
 
 try \{
 Store store = session.getStore("imaps");
 store.connect();
 Folder folder = store.getFolder("INBOX");
 folder.open(Folder.READ\\_ONLY);
 SearchTerm st =
 new OrTerm(
 new SubjectTerm("ticket"),
 new SubjectTerm("plant")
 );
 Message[] messages = folder.search(st);
 int ii = 0;
 for (Message m: messages) System.out.format(
 "\\%d: \\%s \\%s \\$\\backslash\\$n", ii++, m.getFrom()[0], m.getSubject());
 folder.close(false); store.close();
 \} catch (NoSuchProviderException e) \{
 e.printStackTrace();
 System.exit(1);
 \} catch (MessagingException e) \{
 e.printStackTrace();
 System.exit(2);
 \}
 \}
 \}
 ,,,

MAIL BOX FOLDERS ....

 * list available folders in an inbox
 -------------------------------------------------------------
 Folder[] f = store.getDefaultFolder().list("*");
 for (Folder fd:f)
 System.out.println(">> "+fd.getFullName());
 ,,,

 * only list top level folders
 >> Folder[] f = store.getDefaultFolder().list();

 * list available folders 
 -------------------------------------------------------------
 import java.util.Properties;
 import javax.mail.*;
 import java.io.*;
 import javax.mail.internet.*;
 import javax.swing.*;
 
 public class ListMailFolders \{
 public static void main(String[] args) \{
 Properties props = new Properties();
 
 // fastmail settings
 props.put("mail.imaps.host", "mail.messagingengine.com");
 props.put("mail.imaps.port", "993");
 Session session = Session.getDefaultInstance(props,
 new javax.mail.Authenticator() \{
 protected PasswordAuthentication getPasswordAuthentication() \{
 String password = JOptionPane.showInputDialog(
 "Enter mail password'");
 return new PasswordAuthentication(
 "mjbishop@fastmail.fm", password);
 \}
 \});
 
 try \{
 Store store = session.getStore("imaps");
 store.connect();
 Folder[] ff = store.getDefaultFolder().list("*");
 for (Folder folder: ff )
 System.out.println(
 folder.getFullName() + " " + folder.getMessageCount());
 store.close();
 \} catch (MessagingException e) \{
 e.printStackTrace();
 \}
 \}
 \}
 ,,,

 * a more comprehensive way to get a folder list 
 -------------------------------------------------------------
 Properties props = System.getProperties();
 props.setProperty("mail.store.protocol", "imaps");
 try \{
 Session session = Session.getDefaultInstance(props, null);
 javax.mail.Store store = session.getStore("imaps");
 store.connect("imap.gmail.com", "<username>@gmail.com", "<password>");
 javax.mail.Folder[] folders = store.getDefaultFolder().list("*");
 for (javax.mail.Folder folder : folders) \{
 if ((folder.getType() \\& javax.mail.Folder.HOLDS\\_MESSAGES) != 0) \{
 System.out.println(folder.getFullName() + ": " + folder.getMessageCount());
 \}
 \}
 \} catch (MessagingException e) \{
 e.printStackTrace();
 \}
 ,,,

DELETING MESSAGES ....

 * delete a message in a folder
 --------------------------------
 folder.open(Folder.READ\\_WRITE);
 ...
 message.setFlag(Flags.Flag.DELETED, true);
 folder.close(true);
 ,,,

 The 'true' value to the close() method makes the server
 expunge messages which are marked for deletion

 * check if a message is marked for deletion
 >> message.isSet(Flags.Flag.DELETED);

FLAGS FOR MESSAGES ....

 * check what flags a mail folder supports 
 >> folder.getPermanentFlags()


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents java mail flags 
 .. Flags.Flag.ANSWERED
 .. Flags.Flag.DELETED
 .. Flags.Flag.DRAFT
 .. Flags.Flag.FLAGGED
 .. Flags.Flag.RECENT
 .. Flags.Flag.SEEN
 .. Flags.Flag.USER
 ...

 These flags are not necessarily supported by the mail server.

WEB DEVELOPMENT

 Web development has 2 aspects: Server side development and client
 side development. In the case of java, this corresponds to 
 developing applications using Servlets, Java Server Pages (JSP), Java
 Server Faces (JSF), or a dismaying variety of other frameworks.
 Client side development in java would essentially be writing applets.
 
JAPPLETS

 When the java language was released there was considerable excitement, and
 hype, around the concept of applets, which were envisioned to perform all
 sorts of functions on the web. These hopes were never fulfilled as
 'dynamic' html, ajax and javascript were used to fulfill the role that
 applets might have. The JApplet is the swing version of the original
 java.awt.applet.

 Applets are embedded in web pages using the <object> tag within
 the html of the page. This replaces the older <applet> tag.

 Applet jar files do not need a 'main' file to be specified when 
 creating the jar file.

 * possibly the simplest applet and html code
 -------------
 import javax.swing.*;
 import java.awt.*;
 public class SimpleApplet extends JApplet \{
 public void init() \{
 getContentPane().add(new JLabel("A very simple (j)applet"));
 \}
 \}
 /* html code
 <object codetype="application/java"
 classid="java:SimpleApplet.class"
 width="500" height="500">
 This text is seen only if applets are not supported 
 </object>
 */
 ,,,

 * create a web page with (only) the applet "Editor.class" in it 
 -------------
 <html><body>
 <OBJECT codetype="application/java"
 classid="java:Editor.class"
 width="500" height="500">
 My first Java applet.
 </OBJECT>
 </body></html>
 ,,,

 The html (web page) and the java applet code "Editor.class" need
 to be uploaded to the webserver and be in the same folder.

 * create a simple applet, this may not be good code
 --------------
 import java.awt.*;
 import javax.swing.*;
 public class ImageWarp extends JApplet \{
 private Container c = getContentPane();
 public void init() \{
 try \{
 SwingUtilities.invokeAndWait(new Runnable() \{
 public void run() \{
 c.setSize(200,200);
 c.setBackground(Color.RED);
 // Possibly unnecessary:
 c.repaint();
 \}
 \});
 \} catch (Exception e) \{
 System.err.println("An error occurred: "
 + "ImageWarp > init() > new Runnable(). ");
 \}
 \}
 public void start() \{
 init(); //????
 \}
 public static void main(String[] args) \{
 (new ImageWarp()).init();
 \}
 \}
 ,,,

 * an applet which draws a pie chart on a panel
 ----------------------------------------------------
 import java.awt.*;
 import javax.swing.*;
 public class PieApplet extends JApplet \{
 public void init() \{
 Container c = this.getContentPane();
 c.add(new PiePanel());
 \}
 \}
 class PiePanel extends JPanel \{
 public void paint(Graphics g) \{
 g.setColor(Color.green);
 g.drawString("A Pie Chart", 20, 20);
 g.fillArc(20, 50, 200, 200 , 0 , 90);
 g.setColor(new Color(255, 128, 64));
 g.fillArc( 20, 50, 200, 200 , 90 , 40 );
 g.setColor(Color.pink);
 g.fillArc( 20, 50, 200, 200 , 130 , 230 );
 \}
 \}
 ,,,

 * use parameters specified in html, but shouldnt use applet tag
 ---------------
 /*
 <applet code="appdemo.class" codebase="." width=500 height=500>
 <param name=adds value=1100 />
 <param name=memberships value=300 />
 <param name=sales value=1000 />
 </APPLET>
 */
 public class AppDemo extends JApplet \{
 public void init() \{
 String adds = getParameter("adds");
 String memberships = getParameter("memberships");
 String sales = getParameter("sales");
 // more code ...
 \}
 \}
 ,,,

 * an applet to get info from the webserver it came from
 --------------
 import java.applet.*;
 import java.awt.*;
 import java.net.URLConnection;
 import java.net.URL;
 public class SendRequest extends Applet \{
 public void paint(Graphics g) \{
 g.drawRect(0, 0, 499, 149);
 g.drawString(getResponseText(), 5, 70);
 \}
 
 public String getResponseText() \{
 try \{
 URL url = new URL("http://www.server.com/");
 URLConnection urlconn = url.openConnection();
 
 Document doc = null;
 try \{
 urlconn.getInputStream();
 \} catch (Exception e) \{
 return "Can't get the string.";
 \}
 \} catch (Exception e) \{
 return "Problem accessing the response text.";
 \}
 \}
 \}
 ,,,


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents system properties which can be read from an applet
 java.version Java version number 
 java.vendor Java vendor-specific string 
 java.vendor.url Java vendor URL 
 os.name Operating system name 
 os.arch Operating system architecture 
 file.separator File separator (eg, "/") 
 path.separator Path separator (eg, ":") 
 line.separator Line separator 
 java.class.version Java class version number 
 ..
 ..
 
APPLETVIEWER ....

 The appletviewer is a 'command-line' tool to allow you to view your 
 applets without opening a web-browser or uploading anything to a 
 web-server. 

 * view an applet embedded in the page 'test.html'
 >> appletviewer test.html

 If you place an applet tag within your java source file 'Test.java' (in
 java comments), then compile the source-file, you can view the JApplet by
 typing "appletviewer Test.java". The advantage (?) of this is that you
 dont have to create a separate html file with the <object> or <applet> tag
 in it.
 
 * a simple japplet and html code: view with appletviewer SimpleApplet.java
 -------------
 import javax.swing.*;
 public class SimpleApplet extends JApplet \{
 public void init() \{
 getContentPane().add(new JLabel("A very simple (j)applet"));
 \}
 \}
 /*
 <applet code=SimpleApplet.class width=200 height=200> 
 </applet> 
 */
 ,,,

 * to view, type: appletviewer ObjectTagApplet
 -------------
 import javax.swing.*;
 import java.awt.*;
 public class ObjectTagApplet extends JApplet \{
 public void init() \{
 getContentPane().add(new JLabel("A very simple (j)applet"));
 \}
 \}
 /* html code
 <object codetype="application/java"
 classid="java:ObjectTagApplet.class"
 code="ObjectTagApplet.class"
 width="500" height="500">
 This text is seen only if applets are not supported 
 </object>
 */
 ,,,

APPLET TAGS ....

 * The 'new' way: add a Java Applet (jar) in HTML5 (uses object tag)
 -------------------------------------------------------------
 <object type="application/x-java-applet" height="300" width="550">
 <param name="code" value="Sample" />
 <param name="archive" value="Sample.jar" />
 Applet failed to run. No Java plug-in was found.
 </object>
 ,,,


 * The old way: add a java applet in a jar archive in HTML 4.01
 -------------------------------------------------------------
 <applet code="Sample" archive="Sample.jar" height="300" width="550">
 Applet failed to run. No Java plug-in was found.
 </applet>
 ,,,
 
 * add an applet to a web page using older (deprecated) applet tag
 -------------------------------------------------------------
 <applet code="ImageWarp.class" width="200" height="200"></applet>
 ,,,

COMPILING APPLETS ....
 
 The example below may become useful for displaying panel subclasses
 as signed applets.

 * create an applet and html page from a JPanel subclass 
 ----------------------------------------
 import javax.swing.*;
 import java.io.*;
 public class MakeApplet extends JPanel \{
 public MakeApplet() \{\}
 public static void main(String[] args) \{
 String panelName = "";
 if (args.length != 1) \{
 System.out.println("MakeApplet <panel-name>");
 System.exit(1);
 \}
 else
 panelName = args[0];

 try \{
 System.out.println("Creating applet \url{");}
 PrintWriter out = new PrintWriter("../applet/"+panelName + "Applet.java");
 out.println("import javax.swing.*;");
 out.println("public class " + panelName + "Applet extends JApplet \{");
 out.println(" public void init() \{");
 out.println(" getContentPane().add(new "+panelName+"());");
 out.println(" \}");
 out.println("\}");
 out.flush();
 out.close();
 \}
 catch (FileNotFoundException e) \{
 System.out.println("file not found " + e);
 System.exit(1);
 \}

 try \{
 System.out.println("Creating html \url{");}
 PrintWriter out = new PrintWriter("../applet/"+panelName + "Applet.html");
 out.println("<html><body>");
 out.println("<h2>Testing the "+panelName+" applet</h2>");
 out.println(
 "<object type='application/x-java-applet' height='300' width='550'>");
 out.println("<param name='code' value='"+panelName+"Applet' />");
 out.println(
 "<param name='archive' value='"+panelName+"Applet.jar' />");
 out.println("Applet failed to run. No Java plug-in was found.");
 out.println("</object>");
 out.println("</body></html>");
 out.flush();
 out.close();
 \}
 catch (FileNotFoundException e) \{
 System.out.println("file not found " + e);
 System.exit(1);
 \}

 String command = String.format(
 "javac -cp ../applet \\%sApplet.java", panelName); 
 exec(command);
 command = String.format( 
 "jar cvf ../applet/\\%sApplet.jar \\%sApplet.class", panelName, panelName); 
 exec(command);
 \}
 public static void exec(String command) \{
 System.out.println(":> " + command);
 try \{
 String line;
 Process p = Runtime.getRuntime().exec(command);
 BufferedReader input =
 new BufferedReader(new InputStreamReader(p.getInputStream()));
 BufferedReader error =
 new BufferedReader(new InputStreamReader(p.getErrorStream()));
 while ((line = input.readLine()) != null) \{ 
 System.out.println(line);
 \}
 while ((line = error.readLine()) != null) \{ 
 System.out.println(line);
 \}
 input.close();
 \} catch (Exception err) \{ err.printStackTrace(); \}
 \}
 \}
 ,,,
 
SIGNED APPLETS ....

 In order to create a signed applet (or JApplet) one needs a public and
 private pair of keys which are stored in a file called a 'keystore'. This
 file can store many keypairs and the public keys of other people. Each key
 or keypair in the 'keystore' file has a name or 'alias' which is used to
 access that key in the file. Both the keystore file and the key may
 (should) have a password required to access them.

 \url{http://www-personal.umich.edu/\\$\\verb|~|lsiden/tutorials/signed-applet/signed-applet.html}
 A good article about signed applets


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents tools
 .. keytool - create public and private keys
 .. jarsigner - create a signed copy of a jar file
 ..

 To see if an applet is trying to do something it shouldnt, open
 the 'java console window' for the webbrowser
 >> java.security.AccessControlException: 
 >> access denied (java.net.SocketPermission \url{http://www.google.com} connect,resolve)


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents steps to create a signed applet
 * package applet into a jar
 * create a public/private keypair
 * create a certificate for the keypair
 * sign the jar file with jarsigner
 * 

 * create a public and private keypair (the user will be prompted for info)
 >> keytool -genkey
 
 * create a new keypair in the keystore \\$\\verb|~|/.keystore with the name 'kp1'
 >> keytool -genkey -alias kp1
 
 * create a new 'keypair' in the file ./store specifying passwords etc
 >> keytool -genkey -alias kp1 -keystore store 
 >> -keypass pass1 -dname "cn=jones" -storepass pass2 

 * create a self-signed certificate for a public/private keypair. 
 >> keytool -selfcert
 
 Self-signed certificates are not verified by any third-party (company).

 In the example below the signed jar is created using a public/private
 keypair create previously with keytool and stored in a file called
 'kstore' with an alias of 'kpalias'. It uses a certificate created also
 with keytool

 * make a signed copy of a.jar called 'sa.jar'
 >> jarsigner -keystore kstore -storepass stpass -keypass kpass -signedjar 
 >> sa.jar a.jar kpalias 

HTTP 

 Http, hypertext transfer protocol is the text (or encrypted text)
 protocol, built on top of tcp/ip, which forms the basis of the 
 web, that is, requests and responses for webpages and other resources.

 @@ \url{http://stackoverflow.com/questions/2793150/how-to-use-java-net-urlconnection-to-fire-and-handle-http-requests}
 A good article about http requests from java
 
 * read a plain text webpage specified by a URL line by line
 -------------------------------------------------------------
 import java.net.*;
 import java.io.*;
 public class ReadPage \{
 public static void main(String[] args) throws Exception \{
 URL url = new URL("http://bumble.sf.net/notes/index.txt");
 BufferedReader in = new BufferedReader(
 new InputStreamReader(url.openStream()));
 String line;
 while ((line = in.readLine()) != null)
 System.out.println(line);
 in.close();
 \}
 \}
 ,,,


 * make a get request to a webserver
 --------------------------
 String url = "http://example.com";
 String charset = "UTF-8";
 String param1 = "value1";
 String param2 = "value2";
 // ...
 String query = String.format(
 "param1=\\%s¶m2=\\%s", URLEncoder.encode(param1, charset),
 URLEncoder.encode(param2, charset));
 URLConnection connection = new URL(url + "?" + query).openConnection();
 connection.setRequestProperty("Accept-Charset", charset);
 InputStream response = connection.getInputStream();
 ,,,

 * set headers for an http request
 >> urlconnection.setRequestProperty("Accept-Charset", charset);

 * open an input stream to read the response from a web server 
 >> InputStream is = new URL("http://example.com").openStream();

 If the above method is used, no request headers can be set

 If the request is made to an HttpServlet, then its doGet() method will be
 called and the parameters will be available by
 HttpServletRequest\\#getParameter().

POST DATA WITH HTTP

 \url{http://stackoverflow.com/questions/2793150/how-to-use-java-net-urlconnection-to-fire-and-handle-http-requests}
 Stackoverflow has a good article about posting data with a URLConnection

 !!A nasty gotcha for posting data: if you post to a page that then gets
 redirected (eg sf.net get redirected to sourceforge.net) then your post
 request may get turned into a get request. How funny

 * make a post data request to a webserver (setDoOutput(true))
 ----------------
 URLConnection connection = new URL(url).openConnection();
 connection.setDoOutput(true);
 ,,,

 * another equivalent way to set method to post data 
 -------------------------------------------------------------
 HttpURLConnection httpConnection = 
 (HttpURLConnection) new URL(url).openConnection();
 httpConnection.setRequestMethod("POST");
 ,,,

 * make a post data request to an authenticated page
 ----------------------------------------------------
 import java.net.*;
 import java.io.*;
 import javax.swing.*;
 public class PostAuthorisedData \{
 public static void main(String[] args) \{
 Authenticator.setDefault(new Auth());
 String charset = "UTF-8";
 String filename = "../htdocs/sf/books/java/test.txt";
 String filecontents = "test";
 URLConnection connection;
 OutputStream output = null;
 try \{
 String query = String.format(
 "filename=\\%s\\&filecontents=\\%s",
 URLEncoder.encode(filename, "UTF-8"),
 URLEncoder.encode(filecontents, "UTF-8"));
 connection = new URL(
 "http://bumble.sourceforge.net/cgi-bin/save.x.cgi").openConnection();
 connection.setDoOutput(true);
 connection.setRequestProperty("Accept-Charset", "UTF-8");
 connection.setRequestProperty(
 "Content-Type",
 "application/x-www-form-urlencoded;charset=UTF-8");
 output = connection.getOutputStream();
 output.write(query.getBytes(charset));
 InputStream response = connection.getInputStream();
 BufferedReader in = new BufferedReader(
 new InputStreamReader(response));
 String line;
 while ((line = in.readLine()) != null)
 System.out.println(line);
 in.close();
 \} 
 catch (UnsupportedEncodingException e) \{ e.printStackTrace(); \}
 catch (IOException e) \{ e.printStackTrace(); \}
 finally \{
 try \{ output.close(); \}
 catch (IOException e) \{\}
 \}
 \}
 \}
 class Auth extends Authenticator \{
 protected PasswordAuthentication getPasswordAuthentication() \{
 String prompt = String.format(
 "The host '\\%s' replied '\\%s'\\$\\backslash\\$nplease enter 'name:password'",
 this.getRequestingHost(), this.getRequestingPrompt());
 String namepass = JOptionPane.showInputDialog(
 prompt, "<name:password>");
 String[] info = namepass.split(":", 2);
 System.out.format("name:\\%s,pass:\\%s", info[0], info[1]);
 return new PasswordAuthentication(info[0], info[1].toCharArray());
 \}
 \}
 ,,,

 In the example below, when the user presses the 'enter' key in 
 the JTextField the text in the JTextArea is submitted (posted, sent,
 uploaded) to the webserver. 
 
 * post text from a JTextArea to an authenticated page 
 ----------------------------------------------------
 import java.net.*;
 import java.io.*;
 import javax.swing.*;
 import java.awt.event.*;
 import java.awt.*;
 public class PostTextArea extends JPanel implements ActionListener \{
 JTextField field;
 JTextArea area;
 JLabel label;
 public PostTextArea() \{
 super(new BorderLayout());
 Font f = new Font(Font.MONOSPACED, Font.PLAIN, 16);
 this.field = new JTextField("../htdocs/books/java/test.txt");
 this.field.addActionListener(this);
 this.field.setFont(f);
 this.area = new JTextArea(20, 75);
 this.area.setFont(f);
 this.label = new JLabel("info");
 this.label.setFont(f);
 this.add(this.field, BorderLayout.NORTH);
 this.add(new JScrollPane(this.area), BorderLayout.CENTER);
 this.add(this.label, BorderLayout.SOUTH);
 \}
 public void postText() \{
 System.out.println("posting ...");
 Authenticator.setDefault(new Auth());

 String page = "http://bumble.sourceforge.net/cgi-bin/save.x.cgi";
 String filename = this.field.getText();
 String filecontents = this.area.getText();
 try \{

 URL siteUrl = new URL(page);
 HttpURLConnection conn = 
 (HttpURLConnection) siteUrl.openConnection();
 conn.setDoOutput(true);
 conn.setRequestMethod("POST");
 conn.setRequestProperty(
 "Content-Type", "application/x-www-form-urlencoded"); 

 DataOutputStream out = new DataOutputStream(conn.getOutputStream());
 String content = String.format(
 "filename=\\%s\\&filecontents=\\%s",
 URLEncoder.encode(filename, "UTF-8"),
 URLEncoder.encode(filecontents, "UTF-8"));

 System.out.println(content);
 out.writeBytes(content);
 out.flush(); out.close();
 BufferedReader in = 
 new BufferedReader(new InputStreamReader(conn.getInputStream()));
 String line = "";
 while ((line=in.readLine())!=null) \{
 System.out.println(line);
 \}
 in.close();

 \}
 catch (UnsupportedEncodingException e) \{
 e.printStackTrace();
 \}
 catch (FileNotFoundException e) \{
 //could find the url
 e.printStackTrace();
 \}
 catch (IOException e) \{
 // couldnt connect to the internet
 e.printStackTrace();
 \}
 
 \}

 public void actionPerformed(ActionEvent e) \{
 this.postText();
 \}
 public static void main(String[] args) \{
 JFrame f = new JFrame("submit text to a webserver");
 f.getContentPane().add(new PostTextArea());
 f.pack();
 f.setExtendedState(JFrame.MAXIMIZED\\_BOTH);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setVisible(true);
 \}
 \}
 class Auth extends Authenticator \{
 protected PasswordAuthentication getPasswordAuthentication() \{
 String prompt = String.format(
 "The host '\\%s' replied '\\%s'\\$\\backslash\\$nplease enter 'name:password'",
 this.getRequestingHost(), this.getRequestingPrompt());
 String namepass = JOptionPane.showInputDialog(
 prompt, "<name:password>");
 String[] info = namepass.split(":", 2);
 System.out.format("name:\\%s,pass:\\%s", info[0], info[1]);
 return new PasswordAuthentication(info[0], info[1].toCharArray());
 \}
 \}
 ,,, 

HEADER INFORMATION ....

 An http server (webserver) returns certain useful meta information
 about the requested resources in the response 'headers'

 * find out when a webpage was last modified
 -------------------------------------------------------------
 URL u =null;
 long timestamp = 0;
 try \{
 u = new URL("http://bumble.sf.net/books/java/java-book.txt");
 URLConnection uc = u.openConnection();
 uc.setUseCaches(false);
 timestamp = uc.getLastModified();
 \}
 catch (Exception e) \{
 e.printStackTrace();
 \}
 ,,,

 * find the file size of a web resource
 -------------------------------------------------------------
 import java.io.*;
 import java.net.*;
 
 public class FileSizeFromURL \{
 public static final void main(String[] args) \{
 URL url;
 URLConnection conn;
 int size;
 try \{
 if (args.length != 1) 
 url = new URL("http://bumble.sf.net/books/java/java-book.txt"); 
 else 
 url = new URL(args[0]);

 conn = url.openConnection();
 size = conn.getContentLength();
 if (size < 0)
 System.out.println("Could not determine file size.");
 else
 System.out.println(url + "\\$\\backslash\\$nSize: " + size);
 conn.getInputStream().close();
 \}
 catch (Exception e) \{ e.printStackTrace(); \}
 \}
 \}
 ,,,

 The example below demonstrates how to make a request for only the 
 http headers.

 * check if a webpage exists
 ----------------------
 import java.net.*;
 import java.io.*;
 public class HttpHeaders \{
 public static void main(String s[]) \{
 try \{
 HttpURLConnection.setFollowRedirects(false);
 // note : you may also need
 // HttpURLConnection.setInstanceFollowRedirects(false)
 HttpURLConnection con =
 (HttpURLConnection) new URL("http://bumble.sf.net/")
 .openConnection();
 con.setRequestMethod("HEAD");
 System.out.println(con.getResponseCode());
 if (con.getResponseCode() == HttpURLConnection.OK)
 \{ /* ... */ \}
 \}
 catch (Exception e) \{ e.printStackTrace(); \}
 \}
 \}
 ,,,

HTTP BASIC AUTHENTICATION

 * a possible alternative for authenticating with "basic" auth on a url
 -----------------------------
 Authenticator.setDefault (new Authenticator() \{
 protected PasswordAuthentication getPasswordAuthentication() \{
 return new PasswordAuthentication ("username", "password".toCharArray());
 \}
 \});
 ,,,

 * use an authenticator to access password protected web page (basic auth) 
 -------------------------------------------------------------
 import java.net.*;
 import java.io.*;
 public class BasicAuth \{
 public static void main(String[] args) \{
 Authenticator.setDefault(new Auth());
 try \{
 URL url = new URL("http://bumble.sf.net/books/vim/vimrc.txt");
 BufferedReader in =
 new BufferedReader(new InputStreamReader(url.openStream()));
 String s;
 while ((s = in.readLine()) != null) \{
 System.out.println(s);
 \}
 in.close();
 \} catch (MalformedURLException e) \{
 \} catch (IOException e) \{
 \}
 \}
 \}
 
 class Auth extends Authenticator \{
 protected PasswordAuthentication getPasswordAuthentication() \{
 // Get information about the request
 String promptString = this.getRequestingPrompt();
 String hostname = this.getRequestingHost();
 InetAddress ip = this.getRequestingSite();
 int port = this.getRequestingPort();
 String username = "shop";
 // Get the password from the user...
 System.out.print("Enter your password: ");
 BufferedReader br =
 new BufferedReader(new InputStreamReader(System.in));
 String password = null;
 try \{ password = br.readLine(); \} catch (Exception e) \{\}
 return new PasswordAuthentication(username, password.toCharArray());
 \}
 \}
 ,,,

 * from a Java program, a FileNotFoundException is thrown when you try to read from an InputStream associated with the basic authenticated URL.
 
 * upload a file to a server. The server has to know how to receive it
 --------------------------------------
 public static void main(String[] args) throws IOException \{
 File textFile = new File("D:\\$\\backslash\\$\\$\\backslash\\$file.zip");
 String boundary = Long.toHexString(System.currentTimeMillis());
 // Just generate some unique value for the boundary.
 
 HttpURLConnection connection = (HttpURLConnection) new URL("http://localhost:8080/upslet/upload").openConnection();
 connection.setDoOutput(true);
 connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
 OutputStream output = connection.getOutputStream();
 
 PrintWriter writer = new PrintWriter(output, true);
 // Send text file.
 writer.println("--" + boundary);
 writer.println("Content-Disposition: form-data; name=\\$\\backslash\\$"file1\\$\\backslash\\$"; filename=\\$\\backslash\\$"" + textFile.getName() + "\\$\\backslash\\$"");
 writer.println("Content-Type: application/octet-stream");
 FileInputStream fin = new FileInputStream(textFile);
 writer.println();
 IOUtils.copy(fin, output);
 writer.println();
 // End of multipart/form-data.
 writer.println("--" + boundary + "--");
 output.flush();
 closeQuietly(fin, writer, output);
 // Above request will never be sent if .getInputStream() or .getResponseCode() or .getResponseMessage() does not get called.
 connection.getResponseCode();
 \}
 ,,,

 * apache httpclient provides more advanced authentication

 The method below is said to work with java 1.1. see the method above
 for a more modern technique (use an authenticator)

 * access a url which is protected by "basic" authentication, untested...
 ----------------------
 URL url = new URL("location address");
 URLConnection uc = url.openConnection();
 String authorizationString = "Basic " + Base64.encode("username:password");
 uc.setRequestProperty ("Authorization", authorizationString);
 InputStream in = url.openStream();
 ,,,

 but the Base64 encoding above is not part of standard java, try
 ------------
 byte[] data = ...;
 String encoded = javax.xml.bind.DataTypeConverter.printBase64Binary(data);
 byte[] decoded = javax.xml.bind.DatatypeConverter.parseBase64Binary(encoded);
 ,,,

 * read text from a url
 ----------------------
 try \{
 URL url = new URL("http://hostname:80/index.html");
 BufferedReader in = 
 new BufferedReader(new InputStreamReader(url.openStream()));
 String str;
 while ((str = in.readLine()) != null) \{
 // str is one line of text; 
 // readLine() strips the newline character(s)
 \}
 in.close();
 \} catch (MalformedURLException e) \{
 \} catch (IOException e) \{ \}
 ,,,

 * another almost identical way to read text from a webpage
 ----------------------------
 URLConnection urlConnection = url.openConnection();
 InputStream is = urlConnection.getInputStream();
 InputStreamReader reader = new InputStreamReader(is);
 
 int numCharsRead;
 char[] charArray = new char[1024];
 StringBuffer sb = new StringBuffer();
 while ((numCharsRead = reader.read(charArray)) > 0) \{
 sb.append(charArray, 0, numCharsRead);
 \}
 String result = sb.toString();
 ,,,

 I wonder if this is more efficient than readline///

 * post data using a url and read the reply from the webserver
 -----------------------------------
 try \{
 String data = 
 URLEncoder.encode("key1", "UTF-8") + "=" + 
 URLEncoder.encode("value1", "UTF-8") + "\\&" + 
 URLEncoder.encode("key2", "UTF-8") + "=" + 
 URLEncoder.encode("value2", "UTF-8");
 URL url = new URL("http://hostname:80/cgi");
 URLConnection conn = url.openConnection();
 conn.setDoOutput(true);
 OutputStreamWriter wr = new OutputStreamWriter(conn.getOutputStream());
 wr.write(data); wr.flush();
 // read response
 BufferedReader rd = 
 new BufferedReader(new InputStreamReader(conn.getInputStream()));
 String line;
 while ((line = rd.readLine()) != null) \{
 // Process line...
 \}
 wr.close();
 rd.close();
 \} catch (Exception e) \{\}
 ,,,

HTML
 
 The swing inner class javax.swing.text.html.HTML.Tag contains 
 useful information about many html tags.

PARSING HTML ....

 One can use the javax.swing.text.html.HTMLDocument.Iterator class to
 iterate over certain types of tags in an HTMLDocument. Or else just
 iterate over the content of the tags. This is yet another way to strip
 tags out of html text. See the JEditorPane Html section for a complete
 code example of how to do this.

 * create an HTMLDocument from a string then iterate over the content 
 -------------------------------------------------------------
 Reader stringReader = new StringReader(string);
 HTMLEditorKit htmlKit = new HTMLEditorKit();
 HTMLDocument htmlDoc = (HTMLDocument) htmlKit.createDefaultDocument();
 htmlKit.read(stringReader, htmlDoc, 0);
 for (HTMLDocument.Iterator it = document.getIterator(HTML.Tag.CONTENT); 
 it.isValid(); it.next()) \{
 try \{
 String fragment = document.getText(
 it.getStartOffset(), it.getEndOffset() - it.getStartOffset());
 System.out.println(fragment)
 \} catch (BadLocationException ex) \{ e.printStackTrace(); \}
 \}
 ,,,,

 Java can parse html in using a number of packages


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents html tools
 .. JSoup - easy to use
 .. HtmlEditorKit - a bit more tricky
 ..
 
 * parse html
 >> JSoup (jsoup.org)

CONVERTING HTML TO TEXT ....

 It is often desirable to convert the infernal tag soup that is modern
 html into plain text. This involves removing all the tags and trying to
 preserve some formatting in the converted text.

 implement the interface HTMLEditorKit.ParserCallback for 
 comprehensive html conversion

 * convert html to text using the Jsoup library
 ---------------------
 public static String html2text(String html) \{
 return Jsoup.parse(html).text();
 \}
 ,,,

 Or try 'TagSoup'

 The parser below handles '<br/>' (converts it to a newline character)
 so it seems to know what it is doing.

 * convert html to text using HTMLEditorKit, working
 -------------------------------------------------------------
 import java.io.*;
 import javax.swing.text.html.*;
 import javax.swing.text.html.parser.*;
 
 public class StripTags extends HTMLEditorKit.ParserCallback \{
 StringBuffer s;
 public StripTags() \{\}
 public void parse(Reader in) throws IOException \{
 s = new StringBuffer();
 ParserDelegator delegator = new ParserDelegator();
 delegator.parse(in, this, Boolean.TRUE);
 \}
 public void handleText(char[] text, int pos) \{
 s.append(text);
 s.append("\\$\\backslash\\$n");
 \}
 public String getText() \{
 return s.toString();
 \}
 
 public static void main(String[] args) \{
 StripTags parser = new StripTags();
 String s = "<html>hi<br/>trees<br>sky</html>";
 try \{
 parser.parse(new StringReader(s));
 \} catch (IOException ee) \{
 //handle exception
 \}
 System.out.println(parser.getText());
 \}
 \}
 ,,,

 * convert from html to text on android
 >> android.text.Html.fromHtml(instruction).toString();

DISPLAYING HTML ....

 Probably the easiest (although limited) way to display html in a 
 java application is to use the JEditorPane swing component.

 See the JEditorPane section for some more complete examples.

 * display the local file 'test.html' in a JEditorPane 
 --------------
 JFrame frame = new JFrame();
 JEditorPane text = new JEditorPane(new URL("file:test.html"));
 text.setEditable(false);
 frame.add(new JScrollPane(text));
 ,,,

GENERATING HTML

 * generate some html using the java 1.6+ XMLStreamWriter class
 -------------------------------------------------------------
 OutputStream destination = ...;
 XMLOutputFactory outputFactory = XMLOutputFactory.newInstance();
 XMLStreamWriter xml = outputFactory.createXMLStreamWriter(destination);

 xml.writeStartDocument();
 xml.writeStartElement("html");
 xml.writeDefaultNamespace("http://www.w3.org/1999/xhtml");
 xml.writeStartElement("head");
 xml.writeStartElement("title");
 xml.writeCharacters("The title of the page");
 xml.writeEndElement();
 xml.writeEndElement();
 xml.writeEndElement();
 xml.writeEndDocument();
 ,,,

HTML JAVA SOURCE CODE SYNTAX HIGHLIGHTING ....

 * convert 'Test.java' to syntax highlighted HTML
 >> webcpp Test.java Test.java.html -s

 * convert 'Test.java' to LaTeX and other formats
 >> highlight -i Test.java -o Test.java.html -L
 >> source-highlight .... \\#\\#(the gnu source highlighter)

EXCEPTIONS

 Exceptions are javas way of handling unexpected or undesirable 
 conditions.

 * another way to exit from an app when an exception occurs
 -------------------------------------------------------------
 \} catch (MessagingException e) \{
 throw new RuntimeException(e);
 \}
 ,,,


FINALLY ....
 
 The finally block of the try/catch block is useful for performing
 code which must be executed no matter what Exceptions may have 
 occured. Usually this means closing connections, freeing resources etc.

 * a common finally idiom
 -------------------------------------------------------------
 try \{...\}
 finally \{
 try \{ if (theConn != null) theConn.close(); \}
 catch (Exception e) \{\}
 \}
 ,,,

 * a more complete example of the finally idiom to close a stream 
 -------------------------------------------------------------
 Properties properties = new Properties();
 InputStream is = null;
 try \{
 is = new FileInputStream( "filename.properties" );
 properties.load( is );
 \} catch ( IOException e ) \{
 // ...
 \} finally \{
 if ( null != is ) 
 try \{ is.close(); \} catch ( IOException e ) \{ /* .... */ \}
 \}
 ,,,

GOTCHAS FOR EXCEPTIONS
 
 If you catch a specific Exception which is not thrown, the 
 compiler will let you know- but if you catch a throwable, the 
 compiler wont.

 * in the code below, no compiler warning or error, despite no exception
 -------------------------------------------------------------
 try \{ ed.scrollToReference(e.getURL().getRef()); \} 
 catch (Throwable t) \{ t.printStackTrace(); \}
 ,,,

 If an Exception is a more specific type (subclass?) of another
 exception then it must appear before the more general type in the
 'catch' list. Otherwise the compiler produces an error saying that 
 the 'exception has already been caught'. 

 In the code below, the IOException must come after the 
 UnsupoortedEncodingException.

 * a specific and general exception in a try/catch block
 -------------------------------------------------------------
 try \{ ... \}
 catch (UnsupportedEncodingException e) \{\}
 catch (IOException e) \{\}
 ,,,
 
COMPRESSION

COMMAND LINE TOOLS FOR JAVA COMPRESSION ....

 * repack a jar file to make it (slightly) smaller
 >> pack200 -r Sample.jar

 * repack a jar file to make it (alot) smaller (\\$\\verb|~| one third the size)
 >> pack200 Sample.jar.pack.gz Sample.jar

 * configure an applet to use a packed jar file if possible. 
 -------------------------------------------------------------
 <object type="application/x-java-applet" height="300" width="550">
 <param name="code" value="Sample" />
 <param name="archive" value="Sample.jar" />
 <param name="java\\_arguments" value="-Djnlp.packEnabled=true"/>
 Applet failed to run. No Java plug-in was found.
 </object>
 ,,,

ZIP FILES ....

 Apparently the java zip classes can handle zip and gzip compression
 formats. The path separator is always a '/' forward slash in zip files.

 There is no need to call close() on the individual InputStreams for
 subfiles, though you should close the ZipFile as below; the single-byte
 read() method has particularly poor performance; if you need single-byte
 reads on an InputStream from a zip file, wrap it in a
 BufferedInputStream.

 * read the compressed file "names.txt" from a zip compressed file
 ----------------------------------------------------
 ZipFile zf = new ZipFile(file);
 try \{
 InputStream in = zf.getInputStream(zf.getEntry("names.txt"));
 // ... read from 'in' as normal
 \} finally \{
 zf.close();
 \}
 ,,,

 * read the JList.html file from the zip compressed java api docs 
 --------------------------------------------------------
 import java.util.zip.*;
 import java.util.Enumeration;
 import java.io.*;
 public class OneFileFromZip \{
 public static void main(String[] args) \{
 try \{
 ZipFile zf = new ZipFile("jdk-6-doc.zip");
 ZipEntry ze = 
 zf.getEntry("docs/api/javax/swing/JList.html");
 InputStream in = zf.getInputStream(ze);
 BufferedReader reader = 
 new BufferedReader(new InputStreamReader(in));
 String s;
 while ((s = reader.readLine()) != null) 
 System.out.println(s); 
 reader.close(); zf.close();
 \}
 catch (IOException e) \{ e.printStackTrace(); \}
 \}
 \}
 ,,,

 * read the JList.html from zipped api docs into a JTextArea
 --------------------------------------------------------
 import java.util.zip.*;
 import java.util.Enumeration;
 import java.io.*;
 import javax.swing.*;
 import java.awt.*;
 public class TextAreaZip extends JPanel \{
 JTextArea area;
 public TextAreaZip() \{
 super(new BorderLayout());
 this.area = new JTextArea("xx", 20, 60);
 this.area.setFont(new Font("courier", Font.PLAIN, 20));
 this.loadFile();
 this.add(new JScrollPane(this.area), BorderLayout.CENTER);
 \}
 public void loadFile() \{
 try \{
 ZipFile zf = new ZipFile("jdk-6-doc.zip");
 ZipEntry ze = 
 zf.getEntry("docs/api/javax/swing/JList.html");
 InputStream in = zf.getInputStream(ze);
 BufferedReader reader = 
 new BufferedReader(new InputStreamReader(in));
 this.area.read(reader, "zip entry");
 zf.close();
 \}
 catch (IOException e) \{ e.printStackTrace(); \}
 \}
 public static void main(String[] args) \{
 JFrame f = new JFrame("....");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.add(new TextAreaZip());
 f.pack(); f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.setVisible(true); 
 \}
 \}
 ,,,


 The example below loops through all the ZipEntries in the ZipFile
 which is not efficient. 

 * read the JList.html file from the zip compressed java api docs 
 --------------------------------------------------------
 import java.util.zip.*;
 import java.util.Enumeration;
 import java.io.*;
 public class ListZip \{
 public static void main(String[] args) \{
 try \{
 ZipFile zf = new ZipFile("jdk-6-doc.zip");
 Enumeration<? extends ZipEntry> e = zf.entries();
 while (e.hasMoreElements()) \{
 ZipEntry ze = e.nextElement();
 if (ze.getName().endsWith("/JList.html")) \{
 InputStream in = zf.getInputStream(ze);
 BufferedReader reader = 
 new BufferedReader(new InputStreamReader(in));
 String s;
 while ((s = reader.readLine()) != null)
 \{ System.out.println(s); \}
 reader.close();
 System.out.println(ze.getName());
 \}
 \}
 zf.close();
 \}
 catch (IOException e) \{ e.printStackTrace(); \}
 \}
 \}
 ,,,

 In the code below, the zf.close() call shouuld be in a finally
 block, but it itself throws an Exception.

 * read the names of all files from a zip compressed file
 --------------------------------------------------------
 import java.util.zip.*;
 import java.util.Enumeration;
 import java.io.*;
 public class ListZip \{
 public static void main(String[] args) \{
 try \{
 ZipFile zf = new ZipFile("jdk-6-doc.zip");
 Enumeration<? extends ZipEntry> e = zf.entries();
 while (e.hasMoreElements()) \{
 ZipEntry ze = e.nextElement();
 System.out.println(ze.getName());
 \}
 zf.close();
 \}
 catch (IOException e) \{\}
 \}
 \}
 ,,,

 * read the names of all files from a zip compressed file
 --------------------------------------------------------
 import java.util.zip.*;
 import java.util.Enumeration;
 import java.io.*;
 public class ListZip \{
 public static void main(String[] args) \{
 try \{
 ZipFile zf = new ZipFile("jdk-6-doc.zip");
 for (Enumeration<? extends ZipEntry> e = zf.entries();
 e.hasMoreElements();) \{
 ZipEntry ze = e.nextElement();
 String name = ze.getName();
 System.out.println(name);
 if (name.endsWith(".txt")) \{
 InputStream in = zf.getInputStream(ze);
 // read from 'in'
 \}
 \}
 zf.close();
 \}
 catch (IOException e) \{\}
 //finally \{ zf.close(); \}
 \}
 \}
 ,,,

ZIP FILE METADATA ....

 Apparently there is no way to store the locale of the creation time
 for a zip file.

 * display the creation time of a file in human readable format.
 -------------------------------------------------------------
 Calendar cal = Calendar.getInstance();
 cal.setTimeInMillis(ze.getTime());
 String dateStr = String.format("\\%tc", cal);
 ,,,

CRYPTOGRAPHY 

SECURITY

 This is another big topic, but have to start somewhere.

 \url{http://docs.oracle.com/javase/tutorial/security/apisign/gensig.html}
 A reasonable clear tutorial about digital signatures etc.

 \url{http://docs.oracle.com/javase/tutorial/security/apisign/versig.html}
 how to write a digital signature verifying program.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents tools
 .. keytool - generate public and private keys
 .. jarsigner - create a signed copy of a jar file
 ..


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents relevant packages
 .. java.security.*
 ..

 * check the permissions for a new Socket connection
 -------------------------------------------------------------
 System.getSecurityManager().checkPermission(new SocketPermission("www.google.com", "connect"));
 ,,,

KEYPAIRS OR PUBLIC AND PRIVATE KEYS ....

 * generate a public/private key pair with dsa algorithm, sun provider
 -------------------------------------------------------------
 import java.security.*;
 public class GenSig \{
 public static void main(String[] args) \{
 if (args.length != 1) \{
 System.out.println("Usage: GenSig nameOfFileToSign");
 \}
 else try \{
 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "SUN");
 SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
 keyGen.initialize(1024, random);
 KeyPair pair = keyGen.generateKeyPair();
 PrivateKey priv = pair.getPrivate();
 PublicKey pub = pair.getPublic();
 \} catch (Exception e) \{
 System.err.println("Caught exception " + e.toString());
 \}
 \}
 \}
 ,,,
 
 * sign a file with a public/private key pair 
 -------------------------------------------------------------
 import java.io.*;
 import java.security.*;
 public class GenSig \{
 public static void main(String[] args) \{
 if (args.length != 1) \{
 System.out.println("Usage: GenSig nameOfFileToSign");
 \}
 else try \{
 KeyPairGenerator keyGen = KeyPairGenerator.getInstance("DSA", "SUN");
 SecureRandom random = SecureRandom.getInstance("SHA1PRNG", "SUN");
 keyGen.initialize(1024, random);
 KeyPair pair = keyGen.generateKeyPair();
 PrivateKey priv = pair.getPrivate();
 PublicKey pub = pair.getPublic();
 
 // sign file data with the keys 
 Signature dsa = Signature.getInstance("SHA1withDSA", "SUN");
 dsa.initSign(priv);
 FileInputStream fis = new FileInputStream(args[0]);
 BufferedInputStream bufin = new BufferedInputStream(fis);
 byte[] buffer = new byte[1024];
 int len;
 while ((len = bufin.read(buffer)) >= 0) \{
 dsa.update(buffer, 0, len);
 \};
 bufin.close();
 byte[] realSig = dsa.sign(); 

 /* save the signature in a file */
 FileOutputStream sigfos = new FileOutputStream("sig");
 sigfos.write(realSig);
 sigfos.close();

 /* save the public key in a file */
 byte[] key = pub.getEncoded();
 FileOutputStream keyfos = new FileOutputStream("suepk");
 keyfos.write(key);
 keyfos.close();

 \} catch (Exception e) \{
 System.err.println("Caught exception " + e.toString());
 \}
 \}
 \}
 ,,,
 
POLICY FILES ....

 * the default java security policy file is at
 >> \\$JAVA\\_HOME/jre/lib/security/java.policy

DATA STORAGE

 In this context data storage referrs to the 'permanent' storage
 of data, and where to do it- eg database, textfile, filesystem.

PROPERTIES FILES ....

 Properties files are plain text files which have a particular simple
 structure, or format. Basically they are in the format 'key=value' with
 one key per line. The convenience of java properties files is that they
 can be read and loaded into a Properties object without any parsing. Then
 the modified Properties object. Possibly they are the
 simplest (but very limited) form of permanent structured data storage
 available in java

 * an example of the contents of a .properties file
 -------------------------------------------------------------
 \\# a comment, this line is ignored
 ! a comment, this line is also ignored

 a = a simple string
 b = a string with escape sequences \\$\\backslash\\$t \\$\\backslash\\$n \\$\\backslash\\$r \\$\\backslash\\$\\$\\backslash\\$ \\$\\backslash\\$" \\$\\backslash\\$' \\$\\backslash\\$ (space) \\$\\backslash\\$u0123
 c = a string with a continuation line \\$\\backslash\\$
 continuation line
 d.e.f = another string
 ,,,

 In the example below, because the streams are implicit it is not 
 possible to close them.

 * read and write the 'data.properties' properties file, simplified
 -------------------------------------------------------------
 /* read */
 Properties p = new Properties();
 try \{
 p.load(new FileInputStream("data.properties"));
 \} catch (IOException e) \{ \}
 
 /* write */ 
 try \{
 p.store(new FileOutputStream("data.properties"), null);
 \} catch (IOException e) \{ \}
 ,,,

 * read and write and access the keys
 -----------------------------------------------------------
 Properties prop = new Properties();
 try \{
 FileInputStream in = new FileInputStream("a.properties");
 prop.load(in);
 String str = prop.getProperty("name");
 System.out.println(str);
 fis.close();
 FileOutputStream fos = null;
 prop.setProperty("name", "adam");
 prop.store((fos = new FileOutputStream("a.properties")), "Author: jasonX");
 \} catch (IOException e) \{
 e.printStackTrace();
 \}
 
 ,,,

READING OR LOADING PROPERTIES FILES ....

 * load a Properties object by reading a properties file
 -------------------------------------------------------------
 Properties p = new Properties();
 InputStream is = null;
 try \{
 is = new FileInputStream("data.properties");
 p.load(is);
 \} catch (IOException e) \{
 System.out.println("Couldnt read file: " + e); 
 \} finally \{
 if (null != is) 
 try \{ is.close(); \} catch (IOException e) \{ /* .... */ \}
 \}
 ,,,

XML

 Xml (for extensible markup language) is a text data transfer and
 storage format in which informational metadata is added to text 
 content with the use of 'tags' (which take the form '<name>adam</name>'

 \url{http://www.rgagnon.com/javadetails/java-0511.html}
 How to generate xml from a jdbc ResultSet.

JDBC AND DATABASES

 This section deals with relational databases, sql and java's way of
 interacting with those databases, jdbc.

 Apache Derby, or Java DB (the same thing) is a small 2M database
 included in the JDK (since Java 6 in December 2006)

 A java database app to retrieve data must do the following. 
 .. establish a connection
 .. create a Statement with conn.createStatement()
 .. executeQuery(...) to get a ResultSet
 .. loop through the ResultSet object with results.next()
 .. close the ResultSet with results.close()
 .. close the Statement with statement.close()
 ..

 * extract some data from a jdbc datase
 ---------------------------
 import java.sql.*;
 ...
 Statement stmt = conn.createStatement();
 ResultSet results = stmt.executeQuery("select * from " + tableName);
 while (results.next())
 \{
 int id = results.getInt(1);
 String restName = results.getString(2);
 String cityName = results.getString(3);
 System.out.println(id + "\\$\\backslash\\$t\\$\\backslash\\$t" + restName + "\\$\\backslash\\$t\\$\\backslash\\$t" + cityName);
 \}
 results.close();
 stmt.close();
 ...
 
CONNECTING TO A DATABASE ....

ODBC JDBC BRIDGE ....

 * connect to an 'access' database with a jdbc-odbc bridge (ms windows)
 -------------------------------------------------------------
 import java.net.URL;
 import java.sql.*;
 publi class JdbcOdbc \{
 static Connection theConn;
 public static void main (String args[]) \{
 try \{
 theConn = MyConnection.getConnection();
 String sql = "select subject from Email";
 Statement stmt = theConn.createStatement();
 ResultSet rs = stmt.executeQuery(sql);
 while (rs.next()) System.out.println(rs.getString("subject"));
 rs.close(); stmt.close();
 \}
 catch (Exception e) \{ e.printStackTrace(); \}
 finally \{
 try \{ if (theConn != null) theConn.close(); \}
 catch (Exception e) \{\}
 \}
 \}
 \}
 
 class MyConnection \{
 public static Connection getConnection() throws Exception \{
 Driver d = (Driver)Class.forName
 ("sun.jdbc.odbc.JdbcOdbcDriver").newInstance();
 Connection c = DriverManager.getConnection(
 "jdbc:odbc:Driver=\{Microsoft Access Driver (*.mdb)\};DBQ=c:/tech97.mdb"
 );
 return c;
 \}
 \}
 ,,,

 * use an already defined ODBC Datasource
 -------------------------------------------------------------
 String URL = "jdbc:odbc:myDSN";
 Connection c = DriverManager.getConnection(URL, "user", "pwd");
 ,,,

INSERT DATA INTO A TABLE ....

 * a simple sql insert- vulnerable to sql injection in a web app
 -------------------------------------------------------------
 Statement stmt;
 String sql;
 int rows;
 sql = "INSERT INTO tCust "
 + "(custId, custName, custAddr) "
 + "VALUES "
 + "('" + custId + "',"
 + "('" + custName + "',"
 + "('" + custAddr + "')";
 
 stmt = theConn.createStatement();
 rows = stmt.executeUpdate(sql);
 theConn.dbConn.commit();
 stmt.close();
 ,,,

 * a complete jdbc example with Apache Derby (also called Java DB)
 ---------------------
 import java.sql.*;
 
 public class Restaurants
 \{
 private static String dbURL = 
 "jdbc:derby://localhost:1527/myDB;create=true;user=me;password=mine";
 private static String tableName = "restaurants";
 // jdbc Connection
 private static Connection conn = null;
 private static Statement stmt = null;
 
 public static void main(String[] args) \{
 createConnection();
 insertRestaurants(5, "LaVals", "Berkeley");
 selectRestaurants();
 shutdown();
 \}
 
 private static void createConnection()
 \{
 try \{
 Class.forName("org.apache.derby.jdbc.ClientDriver").newInstance();
 conn = DriverManager.getConnection(dbURL);
 \}
 catch (Exception except) \{
 except.printStackTrace();
 \}
 \}
 
 private static void insertRestaurants(int id, String restName, String cityName)
 \{
 try \{
 stmt = conn.createStatement();
 stmt.execute(
 String.format("insert into \\%s values (\\%d,'\\%s','\\%s')", 
 tableName, id, restName, cityName));
 stmt.close();
 \}
 catch (SQLException sqlExcept) \{
 sqlExcept.printStackTrace();
 \}
 \}
 
 private static void selectRestaurants() \{
 try \{
 stmt = conn.createStatement();
 ResultSet results = stmt.executeQuery("select * from " + tableName);
 ResultSetMetaData rsmd = results.getMetaData();
 int numberCols = rsmd.getColumnCount();
 for (int i=1; i<=numberCols; i++)
 \{
 //print Column Names
 System.out.print(rsmd.getColumnLabel(i)+"\\$\\backslash\\$t\\$\\backslash\\$t");
 \}
 
 System.out.println("\\$\\backslash\\$n---------------------------------");
 
 while (results.next())
 \{
 int id = results.getInt(1);
 String restName = results.getString(2);
 String cityName = results.getString(3);
 System.out.println(id + "\\$\\backslash\\$t\\$\\backslash\\$t" + restName + "\\$\\backslash\\$t\\$\\backslash\\$t" + cityName);
 \}
 results.close();
 stmt.close();
 \}
 catch (SQLException sqlExcept) \{
 sqlExcept.printStackTrace();
 \}
 \}
 
 private static void shutdown()
 \{
 try \{
 if (stmt != null) \{ stmt.close(); \}
 if (conn != null) \{
 DriverManager.getConnection(dbURL + ";shutdown=true");
 conn.close();
 \}
 \}
 catch (SQLException sqlExcept) \{\}
 
 \}
 \}
,,,

 To change the above to use an embedded database (not a daemon) use
 Driver name: org.apache.derby.jdbc.EmbeddedDriver
 Database connection URL: jdbc:derby:myDB;create=true;user=me;password=mine

UPDATING DATA ....

 * modify data
 -------------------------------------------------------------
 PreparedStatement p;
 try \{
 p = theConn.prepareStatement
 ("UPDATE CustomerTable SET custName = ? WHERE custId = ?");
 p.setString(1,"Smith");
 p.setString(2, cust\\_id.getText());
 p.executeUpdate();
 conn.commit();
 p.close();
 \}
 catch (Exception e) \{ e.printStackTrace(); \}
 ,,,
 
DELETE DATA ....

 * delete some data from a table
 ----------------------------------------------------
 PreparedStatement p;
 try \{
 p = connection.prepareStatement
 ("DELETE FROM CustomerTable WHERE custId = ?");
 p.setString(1, jtextfield.getText());
 p.executeUpdate();
 connection.commit();
 p.close();
 \}
 catch (Exception e) \{ e.printStackTrace(); \}
 ,,,

SELECT QUERY OR RETRIEVE DATA ....

 * check if the query returned any results
 -------------------------------------------
 boolean found;
 ResultSet rs;
 ... // execute the query
 found = rs.next();
 if (found)
 System.out.println("Record found");
 else
 System.out.println("RECORD NOT FOUND");
 ,,,
 
 * retrieve data from a database using a prepared statement
 -------------------------------------------------------------
 String name = cust\\_name.getText();
 try \{
 Statement stmt;
 String sql = "select custName from tCust where custName = "
 + "'" + name + "'";
 stmt = theConn.createStatement();
 ResultSet rs = stmt.executeQuery();
 while (rs.next()) \{
 System.out.println(rs.getString("custName"));
 \}
 rs.close();
 stmt.close();
 \}
 catch (Exception e) \{
 e.printStackTrace();
 \}
 ,,,

 The setFetchSize() method provides a hint to the jdbc driver about 
 how many rows to retrieve on each iteration. This can increase
 performance when retrieving large datasets.

 * retrieve a large amount of data from an oracle data using fetchsize 
 -------------------------------------------------------------
 import java.io.FileWriter;
 import java.io.IOException;
 import java.sql.*;
 public class PerfSelect \{
 public static void main(String[] args) throws ClassNotFoundException,
 SQLException, IOException \{
 Class.forName("oracle.jdbc.driver.OracleDriver");
 String url = "jdbc:oracle:thin:@//oracle.server:1529/company";
 Connection conn = DriverManager.getConnection(url, "scott", "tiger");
 conn.setAutoCommit(false);
 String sql = "SELECT * FROM Company.Employees";
 Statement stmt = conn.createStatement(); stmt.setFetchSize(200);
 ResultSet rs = stmt.executeQuery(sql);
 FileWriter fw = new FileWriter("d:/temp/test.out");
 while (rs.next()) 
 fw.write(rs.getString(1) + " " + rs.getString(2) + "\\$\\backslash\\$n");
 stmt.close(); rs.close();
 fw.flush(); fw.close();
 \}
 \}
 ,,,

DISPLAYING DATA ....

 * display data from a table in a JTable component
 -------------------------------------------------------------
 String[] tableColumnsName = \{"col 1","col 2","col 3"\};
 DefaultTableModel aModel = (DefaultTableModel) aTable.getModel();
 aModel.setColumnIdentifiers(tableColumnsName);
 ResultSet rs =
 statement.executeQuery("select col1,col2,col3 from mytable");
 java.sql.ResultSetMetaData meta = rs.getMetaData();
 int colNo = meta.getColumnCount();
 while (rs.next()) \{
 Object[] objects = new Object[colNo];
 for (int i=0;i<colNo;i++) \{
 objects[i]=rs.getObject(i+1);
 \}
 aModel.addRow(objects);
 \}
 jtable.setModel(aModel);
 ,,,

PREPAREDSTATEMENTS ....

 * use query parameters in prepared statements
 -------------------------------------------------------------
 PreparedStatement stm = c.prepareStatement("UPDATE user\\_table SET name=? WHERE id=?");
 stm.setString(1, "the name");
 stm.setInt(2, 345);
 stm.executeUpdate();
 ,,,,

METADATA ABOUT DATABASES

 Metadata refers to information about the database itself, as 
 opposed to the information contained in the tables of the database.

 * check if a database contains the table 'employee'
 ---------------------------------------------------
 Connection c = ...
 DatabaseMetaData dbm = c.getMetaData();
 ResultSet tables = dbm.getTables(null, null, "employee", null);
 if (rs.next()) \{ /* Table exists */ \}
 else \{ /* Table does not exist */ \}
 ,,,

DERBY
 

IJ TOOL ....

 The 'ij' tool allows you to create and interact with a Derby database
 from a console window.

 * start the interactive sql query tool for Apache Derby
 >> java org.apache.derby.tools.ij
 
 * create a new derby database called Phone
 >> ij> connect 'jdbc:derby:Phone;create=true';

 * connect to an existing derby database
 >> ij> connect 'jdbc:derby:MyDbTest';

 * connect to a database in a different directory (not the current working folder)
 >> ij> connect 'jdbc:derby:/home/bill/databases/MyDbTest';

 * example sql commands using the ij tool and derby
 ----------------------------
 ij> create table Address(num int, street varchar(40));
 ij> insert into Address values (1956,'Webster St.');
 ij> insert into Address values (1910,'Union St.');
 ij> update Address set num=180, street='Grand Ave.' where num=1956;
 ij> select * from Address;
 ,,,

 * disconnect from the current database
 ij> disconnect;

 * exit ij and shutdown the database
 ij> exit;


 * run a sql script with ij
 ij> run 'my\\_file.sql';

 * run an sql script from the command line
 >> java org.apache.derby.tools.ij my\\_file.sql

INSTALLING JAVA

 There are several versions of the java 'run-time engine', libraries
 and 'java development kit', but the most complete still seems
 to be the version from Sun Microsystems, the inventors of Java.

INSTALLING THE JAVA RUNTIME ENGINE ....
 
 This can involve installing a plugin for a browser or installing
 directly on the computer.

INSTALLING THE JAVA DEVELOPMENT KIT ....
 
ON MICROSOFT WINDOWS .... 

 On Microsoft windows computers one needs to set the 'path'
 environment variable manually after the installer has completed 

ON UNIX ....

 The process is basically: download a .tar.gz file, unpack and
 uncompress it with tar xvzf ...., copy the files to somewhere, maybe
 \texttt{/opt/} set permissions, and more.

 All this is necessary because Sun/Oracle do not provide a .deb or
 .rpm package file which would make the process much simpler.

 Download the 32bit or 64bit Linux "compressed binary file" - it has a
 ".tar.gz" file extension and uncompress it

 * unpack the .tar.gz file
 >> tar -xvf jre-7-linux-i586.tar.gz

 a folder such as ./jre1.7.0 is created 

 * move this new folder into the \texttt{/usr/lib/jvm/} folder
 >> sudo mv ./jre1.7.0* \texttt{/usr/lib/jvm/jre1.7.0}

 * choose the sun version of the jre 
 >> sudo update-alternatives --config java
 
 and more stuff ....

DEVELOPMENT TOOLS FOR JAVA

ON MICROSOFT WINDOWS ....

 I am assuming that the Ms Windows computer is borrowed and that you dont
 really want to spend all your time developing in that environment.

 My preferences:
 install Vim, and GVim from \url{http://www.vim.org} - this is an somewhat annoying but
 useful text editor. 

 install 'putty' and 'pscp' or 'pftp' so that you can upload your java
 files to some server. If you like, just put the .exe files for these
 programs in the directory where you are developing, otherwise add the
 location of the .exe files to the microsoft 'path' environment variable.

 Set up some useful mappings in the \\_vimrc file. See the section 'Vim
 and Java' for a long list of useful mappings. Put your \\_vimrc file
 somewhere like c:\\$\\backslash\\$program files\\$\\backslash\\$Vim

VIM AND JAVA

 Its possible, though possibly not advisable to use the vim
 text editor as a java editor. By using mappings and commands we
 can simplify the process of compiling and running java programs.

 When using Microsoft windows the format of some of these commands are
 slightly different owing to the use of the \\$\\backslash\\$ backslash in Windows file
 names and the different command line syntax used by the Windows console
 (for example \\& and \\&\\& used to separated multiple commands on one line)
 
 For a great deal of detailed information and recipes about how to use Vim
 see bumble.sf.net/books/vim/vim-book.txt

 * save the current file to a sourceforge server 
 >> :!scp \\% user,project@web.sf.net:folder/subfolder/ (\\#\\# unix)
 >> :!pscp \\% user,project@web.sf.net:folder/subfolder/ (\\#\\# windows)

 For the ms windows command, this requires that the pscp program has
 been installed, available from the 'putty' website.

 * look up the word under the cursor with the ClassInfo java class
 >> nmap ,cc :!java -cp eg ClassInfo <cword> \\&<cr>

 * show java api docs for the word under the cursor using JavaDocPanel
 >> nmap ,jd :!java -cp eg JavaDocPanel <cword> \\&<cr>

 * make a command 'Sav' (placed in vimrc) to save the current file to sourceforge 
 >> com Sav !scp \\% user,project@web.sf.net:folder/subfolder/
 >> com Sav !pscp \\% user,project@web.sf.net:folder/subfolder/ (\\#\\# windows)

 The user can upload the current file to the sourceforge server by typing ':Sav'

 * map the key sequence ';jr' to compile and run the current file with java
 >> map ;jr :!javac \\% \\&\\& java \\%:r<cr>

 When the user types ';jr' in normal mode (not insert mode) the current
 file will be compiled and run. If the compilation with javac fails, then
 the mapping aborts

 * run a java fragment changing file name to class name, yay!
 >> map ,jr :?\\^ *---?+1,/\\^ *,,,/-1w! Test.java \\$\\backslash\\$| !name=\\$(sed -n '/\\^ *public class/\{s/\\^ *public class \\$\\backslash\\$([\\^ ]*\\$\\backslash\\$).*/\\$\\backslash\\$1/p;q\}' Test.java); cp Test.java \\$name.java; javac \\$name.java; java \\$name<cr>

ABBREVIATIONS AND SKELETON CODE ....

 * insert some java skeleton code into the current document
 -------------------------------------------------------------
 :com! -nargs=1 Skel
 \\$\\backslash\\$ .s/\\^/
 \\$\\backslash\\$ import javax.swing.*;<cr>
 \\$\\backslash\\$ public class <args> extends JPanel \{<cr>
 \\$\\backslash\\$ public <args>() \{\}<cr>
 \\$\\backslash\\$ public static void main(String[] args) \{<cr>
 \\$\\backslash\\$ SwingUtilities.invokeLater(new Runnable() \{<cr>
 \\$\\backslash\\$ public void run() \{<cr>
 \\$\\backslash\\$ JOptionPane.showMessageDialog(null, new <args>());<cr>
 \\$\\backslash\\$ \}<cr>
 \\$\\backslash\\$ \});<cr>
 \\$\\backslash\\$ \}<cr>
 \\$\\backslash\\$ \}<cr>/
 ,,,

 * a command to put some skeleton class code in the file
 :com! -nargs=1 Skel .s/\\^/public <args> \\$\\backslash\\$n/

 * make an abbreviation to insert the main method in the file
 >> ab jjmain public static void main(String[] args) \{<cr>\}

 * an abbreviation to insert a template 
 >> ab jjtemplate public class SomeClass \{<cr> public static void main(String[] args) \{\}<cr> \}

 * make a mapping of ',jt' which inserts a simple skeleton program
 >> map ,jt 0i public class Test \{<cr> public static void main(String[] args) \{\}<cr>\}

 * save a fragment (between '*' and ',,,') to a file 
 >> :?\\$\\backslash\\$*?+1,/,,,/-1w Test.java 

 * save a fragment to a file even if it exists
 >> :?\\$\\backslash\\$*?+1,/,,,/-1w! Test.java 

 * save a fragment to a file and compile
 >> :?\\^ *---?+1,/,,,/-1w! Test.java | !javac Test.java 

 * compile and run a java program (between '---' and ',,,')
 >> :?\\^ *---?+1,/,,,/-1w! Test.java | !javac Test.java; java Test

 Note that the java program between the markers must be complete with a main method

 * the same as above but also works on a Microsoft Windows computer
 >> :?\\^ *---?+1,/,,,/-1w! Test.java | !javac Test.java \\&\\& java Test

 * map ',jf' to compile and run a java program in the document on a unix system
 >> :map ,jf :?\\^ *---?+1,/,,,/-1w! Test.java \\$\\backslash\\$| !javac Test.java; java Test<cr>

 * and on Microsoft windows compile and run a java program 
 >> :map ,jf :?\\^ *---?+1,/,,,/-1w! Test.java \\$\\backslash\\$| !javac Test.java \\&\\& java Test<cr>
 
 Actually the Windows mapping will also work on Unix systems, since \\&\\& has the 
 same meaning in Unix (only execute the second command if the first was successful)

 For example, if the document contains the following text containing
 a simple java program.

 * the simplest java program
 ---
 public class Test \{
 public static void main(String[] args) \{
 System.out.println("hi");
 \}
 \}
 ,,,

 Then typing ',jf' in 'normal' or 'command' mode will extract
 and compile and then run the java program contained within the
 lines containing '---' and ',,,' The only problem is that
 the code must use the class 'Test'

 * save and compile a java multiline fragment, inserting a class
 >> :?\\^ *---?+1,/,,,/-1w ! (echo -e 'public class Test \{\\$\\backslash\\$n public static void main(String[] args) \{'; sed 's/a/a/'; echo -e ' \}\\$\\backslash\\$n\}') > Test.java; javac Test.java; java Test.java 

 * create a mapping which compiles and runs a java fragment
 >> map ,jfr :?\\^ *---?+1,/,,,/-1w ! (echo -e 'public class Test \{\\$\\backslash\\$n public static void main(String[] args) \{'; sed 's/a/a/'; echo -e ' \}\\$\\backslash\\$n\}') > Test.java; javac Test.java; java Test.java 

 The above will compile and run a fragment of java code in the 
 current document which is contained between '---' and ',,,,'

EXTRACTING THE JAVA CLASS NAME WITH VIM ....

 These recipes below are working towards a function which will extract
 the java class name from a program within a text document.

 * put the text of the current line into a variable
 >> :let t = getline('.') | echo t 

 * set a vim variable to the text of the line just above the next empty one
 >> :let line = search("\\^\\$") - 1
 >> :let text = getline(line)

 * set a vim variable to the text of the next line containing the word elephant 
 >> :let line = search("elephant")
 >> :let text = getline(line)

 * set the variable 't' to the next line containing the word 'public'
 >> :let l = search("public") | let t = getline(l) | echo t

 * split the words of the current line into an array and display the second word
 >> :let text = getline('.') | let words = split(text) | echo words[1]

 Using a one character variable name for the array doesnt seem to work.

 * use a variable as part of a shell command. 
 >> :let n = '..' | exe "!dir " . n
 
 In order to use the value of the variable in the shell command we need to
 use the exe command which evaluates the concatenated string as a vim command

 * split the current line on each '(' character
 >> :let t = getline(".") | let res = split(t, '(') | echo res[0]

 * go back to the first line above which contains split
 >> :exe "?split?"

 * find the next java class name definition
 >> exe "/\\^ *public class /" | let words = split(getline('.')) | echo words[2]

 * just a fragment to test the mapping below 
 -----------------------------------
 public class Person \{
 private String first;
 private String last;
 public Person(String f, String l)
 \{ this.first = f; this.last = l; \}
 public void print()
 \{ System.out.println(this.first + " " + this.last); \}
 public static void main(String[] args) \{
 Person t = new Person("Bill", "King");
 t.print();
 \}
 \}
 ,,,

 * a mapping to extract the class name from a java program in a document 
 >> :map ;jj ?\\^ *---?<cr> \\$\\backslash\\$| :let l = search("\\^ *public class ") \\$\\backslash\\$| echo split(getline(l))[2] <cr>

 The beginning of the java program in the document is marked by a line 
 which starts with '---' 

 * a mapping to extract the class name from a java program in a document 
 >> :map ;jj ?\\^ *---?<cr> \\$\\backslash\\$| :let l = search("\\^ *public class ") \\$\\backslash\\$| echo split(getline(l))[2] \\$\\backslash\\$| :?\\^ *---?+1,/,,,/-1w! Frag.java <cr>

 * extract the class name from a fragment and write to a file with that name
 >> :map ,jr ?\\^ *---?<cr> \\$\\backslash\\$| :let l = search("\\^ *public class ") \\$\\backslash\\$| let class = split(getline(l))[2] \\$\\backslash\\$| exe ":?\\^ *---?+1,/,,,/-1w! " . class . ".java" <cr>

 * save, compile and run a fragment using the java class name 
 >> :map ,jr ?\\^ *---?<cr> \\$\\backslash\\$| :let l = search("\\^ *public class ") \\$\\backslash\\$| let class = split(getline(l))[2] \\$\\backslash\\$| exe ":?\\^ *---?+1,/,,,/-1w! " . class . ".java" \\$\\backslash\\$| exe "!javac " . class . ".java \\&\\& java " . class <cr>

 The mapping above is the culmination of the entire preceding section. It
 uses several tricky aspects of Vims scripting language and variables.
 First is searches backwards for the start of the java code (---), then
 it finds the line with the java class name definition, then it assigned
 the class name to a variable by calling 2 functions to create an list of
 words and getting the 3rd word. Then it uses the "exe" function which
 is like an "eval" function in other languages to construct a shell
 command using the value of the variable which contains the Java class
 name. Finally it compiles and runs the java class

 >> :map ,jf :?\\^ *---?+1,/,,,/-1w! Test.java \\$\\backslash\\$| !javac Test.java \\&\\& java Test<cr>

VIEWING METHODS WITH VIM ....

 * a dubious but useful way to show public method declarations 
 >> :g/\\^ *public.*) *\{*\\$/

 * a command to show most public methods in a java file
 >> :command! Me g/\\^ *public.*) *\{*\\$/

INDENTING WITHIN VIM ....

 * a mapping to indent a java fragment within a document using astyle
 >> map ,ji :?\\^ *---?+1,/\\^ *,,,/-1! astyle -s2<cr>

 * a mapping to indent a java fragment and indent the result 2 spaces
 >> map ,ji :?\\^ *---?+1,/\\^ *,,,/-1! astyle -s2 <bar> sed 's/\\^/ /'<cr>

 * indent the whole java file
 >> :\\%! astyle -s2 \\#\\#(2 space indent with open brace on the same line)
 >> :\\%! astyle -bs2 \\#\\#(the same but with open brace on the next line)

 * map ',jii' to indent the whole java file with a 2 space indent
 >> :map ,jii \\%! astyle -s2<cr>

 2 space indent with open brace on the same line

GVIM ....

 If you are developing in java using vim on a microsoft computer, you
 will almost certainly want to use gvim, since the fonts are much nicer.

 In gvim select the font which you like, and then type
 >> :set guifont
 If you have select 'courier new' size 20, you will see something like 
 >> guifont=Courier\\_New:h20:cANSI
 
 Now open the \\_vimrc file (windows) or .vimrc file (unix) and put the 
 following line in the vimrc file
 >> set guifont=Courier\\_New:h20:cANSI
 
 This will ensure that everytime that gvim starts it will use the specified
 font. To do the same for the colorscheme, place the following in the vimrc file
 >> colorscheme elflord
 where you replace 'elflord' with whatever colorscheme you like.

BASH AND JAVA

 The power and flexibility of the bash shell may help us
 in the somewhat clumsy process of developing java applications.

 * a bash alias to start a java application in the users 'java/eg' folder
 >> alias mail="java -cp \\$\\verb|~|/java/eg/ EmailSender"

 * a bash function to show the methods and constructors of a java class
 --------------------------------------------------------------------
 function jcl
 \{
 cat << xxx > JJJ.java 
 import java.lang.reflect.*;
 public class JJJ \{
 public static void main(String args[]) throws Exception \{
 Class c = Class.forName("java.lang.\\$1");
 Constructor cc[] = c.getDeclaredConstructors();
 Method m[] = c.getMethods();
 for (int i = 0; i < cc.length; i++) System.out.println(cc[i]);
 for (int i = 0; i < m.length; i++) System.out.println(m[i]);
 \}
 \}
 xxx
 javac JJJ.java; java JJJ
 \}
 ,,,

INDENTING
 
 * astyle

\section{ view a java file nicely indented with 2 spaces }
 >> cat test.java | astyle -s2 | less

 The indent program was written for the c language but may be
 used with java. astyle may be better.

PEOPLE INFLUENTIAL IN JAVA

 * Bill Joy
 One time head of sunf, programmer.
 * josh bloch
 designed java collections framework, book author, google
 employee
 * chet haase
 a graphics and gui expert. 
 * romain guy
 another gui expert

KNOWLEDGABLE PROGRAMMERS ....
 
 * elliott hughes 
 android developer, writing dalvik explorer etc, also
 evergreen which is a kind of acme (by Rob Pike) a programmers ide
 \url{http://en.wikipedia.org/wiki/Acme\\_(text\\_editor).} Acme is the 
 succesor of sam which was also written by Rob Pike. This is 
 of interest because sam was/is the preferred text editor of 
 Brian Kernighan of awk, pic, nroff, c, unix fame. 
 * chris campbell
 java2d and images expert (sun employee)
 * fred swartz 
 made some good notes, at leepoint.net
 * Vineet Reynolds @ stackoverflow 
 knows about stuff in java
 * Andrew Thompson @ stackoverflow - 
 a contributor to the stack overflow site. Writes very complete code
 examples on a range of java topics
 * Howard @ stackoverflow -
 knows stuff about swing.
 * x4u @ stackoverflow 
 knows about images
 * dkarp @ stack 
 knows about javamail
 * camickr @ stackoverflow 
 irritable but knowledgable
 Probably rob camick who also has an advanced java swing blog
 \url{http://tips4java.wordpress.com/}
 * BalusC @ stackoverflow. seems knowledgable 
 * Dave Ray @ stackoverflow
 Knowledgable about swing at least, documentlisteners etc
 * Jeff Friesen
 knows about java text stuff
 * Peter Boughton @ stackoverflow
 knowledgable chap about regexes
 * Jerry Huxtable
 java image operations person
 * adam paynter@stackoverflow
 comes up with some interesting answers
 * skip head@stackoverflow
 good answer about reflection
 * robert gamble@stackoverflow
 reflection knowledge
 * basszero@stackoverflow
 knows alot about drag and drop
 * david flanagan
 author of some java in a nutshell books, writer of lots of 
 java examples on the net.

APPS AND SMALL PROGRAMS

 This section contains some small programs written in java by me that I
 personally find useful. Some of them wont be useful for anybody except me.

FILESEARCH ....

 This application is a simple file search-utility which searches for 
 files in a folder heirarchy having a particular String in the
 name or path. A SwingWorker is used to search and update the JList
 component without freezing the user interface.

 Using the "WHEN\\_IN\\_FOCUSED\\_WINDOW" InputMap from the JPanel seems to 
 work well. The KeyStrokes are available no matter what component
 in the panel has the focus (including the JTextFields). But the 
 WHEN\\_FOCUSED input map only works when the application starts up, I
 suppose when the JPanel has focus.

 Ideas: 
 - make the search case insensitive.
 - add a on-the-fly search JTextField to search the results returned
 by a search (similar to the technique used in the SearchPage
 example). Use keystrokes to show and hide the search box. This 
 prevents the user having to do another time-consuming search if 
 too many results are returned.
 - add some kind of a help facility to show what keystrokes are 
 available.
 - add a 'search history' list to the filename box. Maybe a JPopupMenu
 or else a JComboBox. write this history to a textfile for future use.
 - improve speed of search
 - determine if unix hidden folders should be searched. etc
 - publish the number of folders searched through the Result class
 so that the user feels like something is being done even when very
 few (or no) files are being found.

 performance: on a netbook eee pc (cpu 800 mhz) searching for 'e' (java 1.6)
 >> files found: 43078, folders searched: 3263, time taken: 3251 ms

 The speed of the search varies widely from time to time, probably
 depending on the operating system. Making the FileFilter an anonymous
 inner class doesnt seem to affect performance.

 Changes:
 7 sept 2012 
 - added an indeterminate progress bar at the bottom of the screen
 - added some search and cancel search keystrokes (escape, control S etc)
 - added paste to system clipboard when the user selects an item in
 the search result list. This at least makes it a bit easier to 
 use the results, you can then paste the file name into a browser 
 for example.

 * enhanced file search with an information label 
 -------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.event.*;
 import java.io.*;
 import java.util.*;
 import java.awt.event.*;
 import java.awt.*;
 import java.util.concurrent.*;
 import java.awt.datatransfer.*;
 public class FileSearch extends JPanel 
 implements ActionListener, ListSelectionListener \{
 JList list;
 JButton button;
 JButton cancelButton;
 JTextField field;
 JTextField rootField;
 JLabel info;
 JProgressBar bar;
 SearchTask search;
 public FileSearch() \{
 super(new BorderLayout());
 Font georgia = new Font("Georgia", Font.ITALIC, 20);
 this.list = new JList(new DefaultListModel());
 this.list.addListSelectionListener(this);
 this.button = new JButton(new StartSearchAction());
 this.button.setFont(georgia);
 this.cancelButton = new JButton(new CancelSearchAction());
 this.cancelButton.setFont(georgia);
 this.field = new JTextField(".mp3", 15);
 this.field.setFont(georgia);
 this.field.addActionListener(new StartSearchAction());
 this.rootField = new JTextField("/home/", 15);
 this.rootField.setFont(georgia);
 this.rootField.addActionListener(new StartSearchAction());
 this.info = new JLabel("info:");
 this.info.setFont(georgia);
 this.bar = new JProgressBar();
 this.bar.setStringPainted(true);
 JPanel infoPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
 infoPanel.add(this.bar); infoPanel.add(this.info);
 JPanel topPanel = new JPanel();
 topPanel.add(this.button); topPanel.add(this.cancelButton); 
 topPanel.add(this.field); topPanel.add(this.rootField); 
 this.add(new JScrollPane(this.list), BorderLayout.CENTER);
 this.add(topPanel, BorderLayout.NORTH);
 this.add(infoPanel, BorderLayout.SOUTH);
 this.setActionKeys();
 \}
 /** paste the item to the clipboard when the user selects an item*/
 public void valueChanged(ListSelectionEvent e) \{
 if (e.getValueIsAdjusting() == false) \{
 if (list.getSelectedIndex() == -1) \{ /* No selection */ \}
 else \{
 System.out.println(list.getSelectedValue());
 Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
 StringSelection text = 
 new StringSelection(list.getSelectedValue().toString());
 c.setContents(text, text);
 \}
 \}
 \}
 public void actionPerformed(ActionEvent e) \{\}
 private void setActionKeys() \{
 ActionMap actionMap = this.getActionMap();
 InputMap inputMap = 
 this.getInputMap(JComponent.WHEN\\_IN\\_FOCUSED\\_WINDOW);
 inputMap.put(KeyStroke.getKeyStroke("ESCAPE"), "cancel-search");
 actionMap.put("cancel-search", new CancelSearchAction());
 inputMap.put(KeyStroke.getKeyStroke("control S"), "start-search");
 inputMap.put(KeyStroke.getKeyStroke("ENTER"), "start-search");
 actionMap.put("start-search", new StartSearchAction());
 \}
 public void cancelSearch() \{
 this.search.cancel(true);
 this.bar.setIndeterminate(false);
 this.bar.setString("Search Cancelled");
 this.info.setText("search cancelled");
 \}
 public void startSearch() \{
 ((DefaultListModel)this.list.getModel()).removeAllElements();
 this.info.setText("");
 this.bar.setIndeterminate(true);
 this.bar.setString("Searching");
 this.search = 
 new SearchTask(this.field.getText(), this.rootField.getText());
 this.search.execute();
 \}
 public static void main(String[] args) \{
 javax.swing.SwingUtilities.invokeLater(new Runnable() \{
 public void run() \{
 JFrame f = new JFrame("Search for Files");
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.add(new FileSearch());
 f.pack(); f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.setVisible(true);
 \}
 \});
 \}
 class StartSearchAction extends AbstractAction \{
 public StartSearchAction() \{
 putValue(Action.NAME, "Start Search");
 putValue(Action.SHORT\\_DESCRIPTION, 
 "Starts a new search for file with matching names");
 putValue(Action.MNEMONIC\\_KEY, new Integer(KeyEvent.VK\\_S));
 \}
 public void actionPerformed(ActionEvent e) \{
 FileSearch.this.startSearch();
 \}
 \}
 class CancelSearchAction extends AbstractAction \{
 public CancelSearchAction() \{
 putValue(Action.NAME, "Cancel search");
 putValue(Action.SHORT\\_DESCRIPTION, 
 "Cancels the current search");
 putValue(Action.MNEMONIC\\_KEY, new Integer(KeyEvent.VK\\_C));
 \}
 public void actionPerformed(ActionEvent e) \{
 FileSearch.this.cancelSearch();
 \}
 \}
 class SearchTask extends SwingWorker<Void, File> 
 implements FileFilter \{
 int filesFound;
 int foldersSearched;
 String text;
 File root;
 long searchTime;

 public SearchTask(String text, String root) \{
 super();
 this.filesFound = 0;
 this.foldersSearched = 0;
 this.text = text;
 this.root = new File(root);
 this.searchTime = -1;
 \}
 public SearchTask(String text) \{
 super();
 this.filesFound = 0;
 this.foldersSearched = 0;
 this.text = text;
 this.root = new File("/home/");
 this.searchTime = -1;
 \}

 protected Void doInBackground() \{
 this.searchTime = System.currentTimeMillis();
 this.list(this.root);
 this.searchTime = System.currentTimeMillis() - this.searchTime;
 return null;
 \}
 protected void done() \{
 FileSearch.this.info.setText(String.format(
 "<html>Files found: <font color='blue'>\\%d</font>, Folders searched: \\%d, Time taken: \\%d ms, " +
 " Root folder: \\%s", this.filesFound, this.foldersSearched, 
 this.searchTime, this.root)); 
 FileSearch.this.bar.setIndeterminate(false);
 FileSearch.this.bar.setString("Search Finished");
 \}
 protected void process(java.util.List<File> results) \{
 FileSearch.this.info.setText(String.format(
 "Files found: \\%d, Folders searched: \\%d", 
 this.filesFound, this.foldersSearched));
 DefaultListModel model = 
 (DefaultListModel) FileSearch.this.list.getModel();
 for (File file: results) \{ model.addElement(file); \}
 \}
 /** the FileFilter for the list() method */
 public boolean accept(File file) \{
 return ((file.getAbsolutePath().indexOf(this.text)>0) ||
 file.isDirectory());
 \}
 /** a case insensitive regex FileFilter for the list() method */
 public boolean xaccept(File file) \{
 String pattern = "(?i).*" + this.text + ".*";
 return ((file.getAbsolutePath().matches(pattern)) ||
 file.isDirectory());
 \}
 /** find files with names matching a certain string */
 public void list(File dir) \{
 if (this.isCancelled()) return;
 this.foldersSearched++;
 for (File f: dir.listFiles(this)) \{
 if (f.isDirectory()) this.list(f);
 else \{
 this.publish(f);
 this.filesFound++;
 \}
 \}
 \}
 \}
 \}
 /** a simple class to hold number of folders searched \\& last file found */
 class Result \{
 File lastFound; int foldersSearched;
 public Result(File lastFound, int foldersSearched) \{
 this.lastFound = lastFound; 
 this.foldersSearched = foldersSearched;
 \}
 public File getFile() \{ return this.lastFound; \}
 public int getFoldersSearched() \{ return this.foldersSearched; \}
 \}
 ,,,

JAVADOCPANEL ....

 The code below is a basic but useful java documentation browser, the
 hyperlinks work, and the user can select a class by typing its name in
 the JTextField. The code also searches for the class name in the rt.jar
 file if an unqualified name (eg JList) is given. The java api docs
 (available from Oracle in zip format) must be unzipped in a local folder.
 The font for the JEditorPane is increased in size using css rules applied
 to the EditorKit. Also package names ending with a star such as
 javax.swing.* will display the 'package-summary.html' page for that
 package. 

 Bugs: sometimes the class search finds a non-standard class first
 (eg String finds some org.apache string class for which there are
 no docs) and throws a file not found exception

 A back button would be useful but is not essential. Other enhancements
 would be to allow keyboard cut and paste, 
 
 I could improve the logic of the searchForClass() method, which was
 hacked together late at night, etc. Also, when a link is clicked, show
 the class name plus reference, not the file name.
 
 More improvements to make: when the user presses enter, select the
 whole class name, to make changes easier, also focus the scrollpane
 so that keyboard navigation doesnt write text into the JTextField.

 This program can be used from the command line with for example
 >> java JavaDocPanel JButton
 We can then integrate this with the Vim text editor with a 
 mapping, for example we can put in the vimrc file something like
 >> nmap ,jd :!java -cp eg JavaDocPanel <cword> \\&<cr>
 which assumes that the JavaDocPanel class is in the 'eg' subfolder.
 All this is surprisingly useful.

 ideas:
 stop exception being thrown when no doc for the class
 Some of the functionality of showClassDoc should actually be
 in searchForClass. 

 changes:
 * Case insensitive classname search, but not regex
 * 28 august 2012
 added the SearchPage component to display the page. This allows
 searching of the html document. Added a history to SearchPage
 The code seems to be working quite well.
 * 31 august 2012
 added a popup menu when more than one class is returned by a search.
 Need to add some kind of menu title. also added regular expression
 matching in the class search.

 * JavaDocPanel a javadoc api doc browser with searching 
 ------------------------------------
 import javax.swing.*;
 import javax.swing.event.*;
 import javax.swing.text.html.*;
 import java.net.*;
 import java.io.File;
 import java.awt.*;
 import java.awt.event.*;
 import java.util.jar.*;
 import java.util.zip.*;
 import java.util.*;
 public class JavaDocPanel extends JPanel implements ActionListener \{
 SearchPage ed;
 JTextField field;
 String className;
 java.util.List history;
 URL page;
 final static String docHome = "/usr/lib/jvm/java-6-sun/docs/api";

 public JavaDocPanel(String className) \{
 super(new BorderLayout());
 this.field = new JTextField(className);
 this.field.setFont(new Font("Monospaced", Font.PLAIN, 18));
 this.field.addActionListener(this);
 this.className = new String("");
 this.ed = new SearchPage();
 this.showClassDoc(className);
 this.history = new ArrayList();
 this.add(this.field, BorderLayout.NORTH);
 this.add(this.ed, BorderLayout.CENTER);
 \}
 /** shows a message in the JTextField and selects all the message */
 private void fieldMessage(String message) \{
 this.field.setText(message);
 this.field.setSelectionStart(0);
 this.field.setSelectionEnd(this.field.getText().length());
 \}

 public String[] searchForClass(String className) \{
 java.util.List<String> list = new ArrayList<String>();
 String pattern = ".*(?i)/" + className + ".class\\$";
 try \{
 JarFile jar = new JarFile(
 new File(System.getProperty("java.home") + "/lib/rt.jar"));
 Enumeration<? extends JarEntry> enumeration = jar.entries();
 while (enumeration.hasMoreElements()) \{
 ZipEntry zipEntry = enumeration.nextElement();
 //System.out.println(zipEntry.getName().replace("/", "."));
 if (zipEntry.getName().matches(pattern)) \{
 list.add(zipEntry.getName()
 .replace("/", ".").replace(".class", "")); 
 \}
 \}
 \} catch (java.io.IOException e) \{
 e.printStackTrace();
 \}
 return list.toArray(new String[list.size()]);
 \}
 
 /** show the api docs for a particular class */
 public void showClassDoc(String searchName) \{
 String[] names = new String[]\{\};
 if (searchName.indexOf(".") < 0) \{
 names = this.searchForClass(searchName);
 if (names.length == 0) \{
 this.fieldMessage("class '" + searchName + "' was not found");
 return;
 \} 
 else if (names.length > 1) \{
 JPopupMenu menu = new JPopupMenu(); 
 for (String className: names) \{ 
 Action a = new ShowClassDocAction(className);
 menu.add(a);
 menu.getComponent(menu.getComponentCount()-1)
 .setFont(new Font("Georgia", Font.ITALIC, 20));
 \}
 this.fieldMessage("Choose a class from the list");
 if (this.isVisible()) menu.show(this, 300, 100);
 \}
 else \{ this.className = names[0]; \}
 \}
 else \{
 if (searchName.endsWith(".*"))
 this.className=searchName.replace(".*","") + ".package-summary";
 else
 this.className = searchName;
 \}
 try \{
 this.page = new URL(String.format("file:\\%s/\\%s.html", 
 this.docHome, this.className.replace(".", "/")));
 this.field.setText(this.className.replace(".class", ""));
 if (!(new File(this.page.toURI()).exists())) \{
 this.fieldMessage("no html document for " + this.page);
 return;
 \}
 this.ed.newPage(page.toString());
 \}
 catch (java.net.MalformedURLException e) \{ e.printStackTrace(); \}
 catch (java.net.URISyntaxException e) \{ e.printStackTrace(); \}
 catch (java.io.IOException e) \{ e.printStackTrace(); \}
 \}

 public void actionPerformed(ActionEvent e) \{
 this.showClassDoc(this.field.getText());
 \}
 public static void main(String[] args) throws Exception \{
 System.setProperty("awt.useSystemAAFontSettings","on");
 String className = "java.util.*";
 if (args.length > 0) className = args[0];
 JavaDocPanel j = new JavaDocPanel(className);
 JFrame f = new JFrame("View java api docs"); f.add(j);
 f.pack(); f.setExtendedState(JFrame.MAXIMIZED\\_BOTH);
 f.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);
 f.setVisible(true);
 \}
 class ShowClassDocAction extends AbstractAction \{
 String className;
 public ShowClassDocAction(String className) \{
 this.className = className;
 putValue(Action.NAME, className);
 putValue(Action.SHORT\\_DESCRIPTION, String.format(
 "Shows the java API document for the '\\%s' class",
 this.className));
 \}
 public void actionPerformed(ActionEvent e) \{
 JavaDocPanel.this.showClassDoc(this.className);
 \}
 \}
 \}
 ,,,

JAVADOCPANEL OLD VERSION

 Below is the old version without searching

 * a simple viewer for (local) java api documentation, with class search
 -------------------------------------------------------------
 import javax.swing.*;
 import javax.swing.event.*;
 import javax.swing.text.html.*;
 import java.net.*;
 import java.io.File;
 import java.util.Enumeration;
 import java.awt.*;
 import java.awt.event.*;
 import java.util.jar.*;
 import java.util.zip.*;
 public class JavaDocPanel extends JPanel 
 implements ActionListener, HyperlinkListener \{
 JEditorPane ed;
 JTextField field;
 String className;
 URL page;
 final static String docHome = "/usr/lib/jvm/java-6-sun/docs/api";

 public JavaDocPanel(String className) \{
 super(new BorderLayout());
 this.field = new JTextField(className);
 this.field.setFont(new Font("Monospaced", Font.PLAIN, 18));
 this.field.addActionListener(this);
 this.className = new String("");
 this.ed = new JEditorPane();
 this.ed.setEditable(false);
 this.showClassDoc(className);
 this.ed.addHyperlinkListener(this);
 StyleSheet styles = 
 ((HTMLEditorKit)this.ed.getEditorKit()).getStyleSheet();
 styles.addRule("body \{font-size: x-large; color:\\#000; font-family:Georgia; margin: 20px; \}");
 styles.addRule("code \{font-size: large; \}");

 this.add(this.field, BorderLayout.NORTH);
 KeyScrollPane scroll = new KeyScrollPane(this.ed);
 /*
 JScrollPane scroll = new JScrollPane(this.ed);
 JScrollBar vertical = scroll.getVerticalScrollBar();
 vertical.setUnitIncrement(20);
 InputMap im = vertical.getInputMap(
 JComponent.WHEN\\_IN\\_FOCUSED\\_WINDOW);
 im.put(KeyStroke.getKeyStroke("G"), "minScroll");
 im.put(KeyStroke.getKeyStroke("shift G"), "maxScroll");
 im.put(KeyStroke.getKeyStroke("J"), "positiveUnitIncrement");
 im.put(KeyStroke.getKeyStroke("DOWN"), "positiveUnitIncrement");
 im.put(KeyStroke.getKeyStroke("shift J"), "positiveBlockIncrement");
 im.put(KeyStroke.getKeyStroke("K"), "negativeUnitIncrement");
 im.put(KeyStroke.getKeyStroke("UP"), "negativeUnitIncrement");
 im.put(KeyStroke.getKeyStroke("shift K"), "negativeBlockIncrement");
 */
 this.add(scroll, BorderLayout.CENTER);
 \}
 public String searchForClass(String className) \{
 try \{
 JarFile jar = new JarFile(
 new File(System.getProperty("java.home") + "/lib/rt.jar"));
 Enumeration<? extends JarEntry> enumeration = jar.entries();
 while (enumeration.hasMoreElements()) \{
 ZipEntry zipEntry = enumeration.nextElement();
 //System.out.println(zipEntry.getName().replace("/", "."));
 if (zipEntry.getName().endsWith("/" + className + ".class")) \{
 return zipEntry.getName().replace("/", ".").replace(".class", ""); 
 \}
 \}
 \} catch (java.io.IOException e) \{
 e.printStackTrace();
 \}
 return "not.found";
 \}
 public void showClassDoc(String searchName) \{
 String name = new String();
 if (searchName.indexOf(".") < 0) \{
 name = this.searchForClass(searchName);
 if (name.equals("not.found")) \{
 this.field.setText("class " + searchName + " not found");
 this.className = name;
 return;
 \} else \{ this.className = name; \}
 \}
 else \{
 if (searchName.endsWith(".*"))
 this.className=searchName.replace(".*","") + ".package-summary";
 else
 this.className = searchName;
 \}
 try \{
 this.page = new URL(String.format("file:\\%s/\\%s.html", 
 this.docHome, this.className.replace(".", "/")));
 this.ed.setPage(page);
 \}
 catch (java.net.MalformedURLException e) \{ e.printStackTrace(); \}
 catch (java.io.IOException e) \{ e.printStackTrace(); \}
 \}
 public void hyperlinkUpdate(HyperlinkEvent e) \{
 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) \{
 if (e.getURL().sameFile(this.page)) \{
 try \{
 this.ed.scrollToReference(e.getURL().getRef());
 \} catch (Throwable t) \{
 t.printStackTrace();
 \}
 \}
 else if (!e.getURL().sameFile(this.page)) \{
 try \{
 this.ed.setPage(e.getURL());
 this.field.setText(e.getURL().toString());
 \} catch (Throwable t) \{
 t.printStackTrace();
 \}
 \}
 \}
 \}
 public void actionPerformed(ActionEvent e) \{
 this.showClassDoc(this.field.getText());
 \}
 public static void main(String[] args) throws Exception
 \{
 System.setProperty("awt.useSystemAAFontSettings","on");
 String className;
 if (args.length > 0) className = args[0];
 else className = "java.util.*";
 JavaDocPanel j = new JavaDocPanel(className);
 JFrame f = new JFrame("JavaDocPanel: view class api docs"); f.add(j);
 f.pack(); f.setExtendedState(JFrame.MAXIMIZED\\_BOTH);
 f.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);
 f.setVisible(true);
 //System.out.println(ed.getText());
 \}
 \}
 ,,,

SEARCHPAGE ....

 The idea of this application is to allow an html document to be quickly
 searched using keystrokes. The only really tricky point about its
 implementation is iterating through the HTMLDocument to then search each
 fragment. The code seems to be working well, and with a few additions and
 polishings should be useful. This component is used by the JavadocPanel
 to display html java api documentation

 The code is based on the example SearchHtmlPane.

 features
 * The 1st or Nth match is displayed about 1/3 of the way down 
 the JScrollPane (see the CaretScroll example for this technique). 
 * case insensitive searching - is this a good idea?
 * The 'n' key goes to and highlights the next match 
 * The 'N' key goes to and highlights the previous match 
 * the current match is highlighted in a different colour.
 * display the number of matches and the current match in a label
 next to the search box.
 * The enter key hides the search box.
 * The '/' key shows and focuses the search box.
 28 aug 2012
 added font bigger and smaller keys (B/b) and shift +/- 
 also added KeyScrollPane. Added a HyperlinkListener.
 Need to remove highlights when search string 2 chars or less.
 Added a history list and keystroke navigation of the list.
 30 aug 2012
 added a basic keystroke help feature when the user presses 'i'
 to display the keystrokes and what they do. Ideas, format the 
 help more nicely- icons of the keys, a better toString method 
 for keystrokes.

 Ideas: a nicer painter for the highlighter.
 
 Add a plain text (not regular expression) search, and see if it is any
 faster for big documents. 
 
 Add a 'big test document' method which creates a large
 html document in order to test searching big documents.

 When the current highlight is over a hyperlink, make 'enter'
 activate the link.

 * A searchable JEditorPane displaying html 
 ----------------------------------------------
 import java.io.*;
 import java.net.*;
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import javax.swing.text.*;
 import javax.swing.event.*;
 import javax.swing.text.html.*;
 import java.util.regex.*;
 import java.util.*;
 public class SearchPage extends JPanel 
 implements DocumentListener, HyperlinkListener \{
 JTextField field;
 JLabel searchInfo;
 JPanel searchPanel;
 JEditorPane area;
 JScrollPane scroll;
 URL page;
 java.util.List<URL> history;
 int historyIndex;
 java.util.List<Match> matches;
 int currentMatch;
 int fontSize;

 public SearchPage() \{
 super(); 
 this.setLayout(new BorderLayout());
 this.currentMatch = 0;
 this.fontSize = 18;
 this.matches = new ArrayList<Match>();
 this.history = new ArrayList<URL>();
 this.field = new JTextField(40);
 this.field.getDocument().addDocumentListener(this);
 this.field.setFont(new Font("Georgia", Font.ITALIC, 24));
 this.field.addActionListener(new HideSearchAction());
 this.searchInfo = new JLabel(); this.searchInfo();
 this.area = new JEditorPane();
 this.area.addHyperlinkListener(this);
 this.setActionKeys();
 this.scroll = new KeyScrollPane(this.area);
 this.searchPanel = new JPanel(new BorderLayout(10, 10));
 this.searchPanel.add(this.field, BorderLayout.WEST); 
 this.searchPanel.add(this.searchInfo, BorderLayout.EAST);
 this.searchPanel.setVisible(false);
 this.add(searchPanel, BorderLayout.NORTH);
 this.add(this.scroll, BorderLayout.CENTER);
 try \{ this.page = new URL("file:/nowhere"); \} 
 catch (MalformedURLException e) \{\}
 this.newPage("file:/usr/lib/jvm/java-6-sun-1.6.0.15/docs/api/" +
 "javax/swing/JTree.html");
 this.historyIndex = this.history.size() - 1;
 this.setFontSize(18);

 //this.state();
 \}

 /** determine which keystrokes will activate which actions */
 private void setActionKeys() \{
 InputMap im = this.area.getInputMap(WHEN\\_FOCUSED);
 ActionMap am = this.area.getActionMap();
 im.put(KeyStroke.getKeyStroke("I"), "x.help");
 im.put(KeyStroke.getKeyStroke("shift SLASH"), "x.help");
 am.put("x.help", new HelpAction());
 im.put(KeyStroke.getKeyStroke("H"), "x.back");
 am.put("x.back", new BackAction());
 im.put(KeyStroke.getKeyStroke("L"), "x.forward");
 am.put("x.forward", new ForwardAction());
 im.put(KeyStroke.getKeyStroke("shift B"), "x.bigger.font");
 im.put(KeyStroke.getKeyStroke("shift EQUALS"), "x.bigger.font");
 am.put("x.bigger.font", new BiggerFontAction());
 im.put(KeyStroke.getKeyStroke("B"), "x.smaller.font");
 im.put(KeyStroke.getKeyStroke("shift MINUS"), "x.smaller.font");
 am.put("x.smaller.font", new SmallerFontAction());
 im.put(KeyStroke.getKeyStroke("N"), "x.next.match");
 am.put("x.next.match", new NextMatchAction());
 im.put(KeyStroke.getKeyStroke("shift N"), "x.prev.match");
 am.put("x.prev.match", new PreviousMatchAction());
 im.put(KeyStroke.getKeyStroke("S"), "x.show.search");
 im.put(KeyStroke.getKeyStroke('/'), "x.show.search");
 am.put("x.show.search", new ShowSearchAction());
 \}
 /** show the internal state of the SearchPage */
 private void state() \{
 System.out.format("this.page: \\%s\\$\\backslash\\$nthis.historyIndex: \\%d\\$\\backslash\\$n",
 this.page, this.historyIndex);
 int ii = 0;
 for (URL u: this.history) \{
 System.out.format("\\%d: \\%s\\$\\backslash\\$n", ii, u.toString());
 ii++;
 \}
 \}

 /** returns an html list of keystrokes and actions */
 public String keyStrokeHelp() \{
 InputMap im = this.area.getInputMap(WHEN\\_FOCUSED);
 ActionMap am = this.area.getActionMap();
 StringBuilder sb = new StringBuilder();
 sb.append("<h3>keystrokes and actions</h3>");
 sb.append("<dl>");
 for (KeyStroke key: im.keys()) \{
 String actionKey = (String)im.get(key); 
 Action action = am.get(actionKey);
 sb.append(String.format("<dt>\\%s<dd>\\%s", 
 key.toString(), action.getValue(Action.SHORT\\_DESCRIPTION)));
 \}
 sb.append("</dl>");
 return sb.toString();
 \}

 /** display the help for what keystrokes do what */
 public void showKeyHelp() \{
 String help = new String(String.format(
 "<html><head>" +
 "<style type='text/css'> dd \{ font-style: italic; \}</style>" +
 "</head><body style='font-family:Georgia;'>\\%s", 
 this.keyStrokeHelp()));
 JLabel label = new JLabel(help);
 JOptionPane.showMessageDialog(null, new JScrollPane(label));
 \}

 /** display some help in the search box */
 public void searchHelpMessage() \{
 this.field.setText("search for text");
 this.field.setSelectionStart(0);
 this.field.setSelectionEnd(this.field.getText().length());
 \}
 /** displays a page and adds it to the history list */
 public void newPage(String page) \{
 this.setPage(page);
 this.history.add(this.page);
 this.historyIndex = this.history.size() - 1;
 \}
 /** clears the stream to force the page to be reloaded */
 public void reloadPage() \{
 try \{
 Document doc = this.area.getDocument();
 doc.putProperty(Document.StreamDescriptionProperty, null);
 this.area.setPage(this.page);
 \} catch (IOException err) \{ err.printStackTrace(); \}
 \}

 /** go to the previous page in the history list */
 private void back() \{
 if (this.history.size() < 2) \{
 System.out.println("1 or no pages in history");
 return;
 \}
 if (this.historyIndex == 0) \{
 System.out.println("At first page in history");
 return;
 \}
 this.historyIndex--;
 URL lastPage = this.history.get(this.historyIndex);
 this.setPage(lastPage.toString());
 this.state();
 \}

 /** go to the next page in the history list */
 private void forward() \{
 if (this.history.size() < 2) \{
 System.out.println("1 or no pages in history");
 return;
 \}
 if (this.historyIndex == (this.history.size()-1)) \{
 System.out.println("At last page in history");
 return;
 \}
 this.historyIndex++;
 this.setPage(this.history.get(this.historyIndex).toString());
 this.state();
 \}
 /** set the display (html) page for the JEditorPane */
 public void setPage(String page) \{
 try \{
 URL newPage = new URL(page);
 if (newPage.sameFile(this.page)) \{
 if (newPage.getRef() == null)
 this.scroll.getVerticalScrollBar().setValue(0);
 //this.area.setCaretPosition(0);
 else
 this.area.scrollToReference(newPage.getRef());
 \}
 else \{
 this.area.setPage(newPage);
 this.field.setText("");
 this.hideSearchPanel();
 \}
 this.page = newPage;
 this.area.setEditable(false);
 \} 
 catch (MalformedURLException e) \{ 
 JOptionPane.showMessageDialog(null, 
 String.format("The url '\\%s' is not in a valid format", page));
 \}
 catch (IOException e) \{ 
 JOptionPane.showMessageDialog(null, String.format(
 "It was not possible to read the file '\\%s'", page));
 e.printStackTrace();
 \}
 \}
 public void insertUpdate(DocumentEvent e) \{ this.search(); \}
 public void removeUpdate(DocumentEvent e) \{ this.search(); \}
 public void changedUpdate(DocumentEvent e) \{ \}

 /** HyperlinkListener method */
 public void hyperlinkUpdate(HyperlinkEvent e) \{
 if (e.getEventType() == HyperlinkEvent.EventType.ACTIVATED) \{
 this.newPage(e.getURL().toString());
 this.state();
 \}
 \}
 /** sets the size of the Font using css styles */
 public void setFontSize(int size) \{
 this.fontSize = size;
 StyleSheet styles = 
 ((HTMLEditorKit) this.area.getEditorKit()).getStyleSheet();
 styles.addRule(String.format(
 "body \{font-size: \\%dpx; color:\\#000; " +
 " font-family:Georgia; margin: 20px; \}", this.fontSize));
 styles.addRule(String.format(
 "code \{font-size: \\%dpx; \}", this.fontSize-1));
 styles.addRule(String.format(
 "font \{font-size: \\%dpx; \}", this.fontSize-1));
 this.reloadPage();
 \}
 private void searchInfo() \{
 String s = String.format("<html><big>\\%d / \\%d</big><html>", 
 this.currentMatch + 1, this.matches.size());
 this.searchInfo.setText(s);
 \}

 /** searches the html document for matching text */
 public void search() \{
 String search = this.field.getText();
 if (search.length() < 2) \{
 this.area.getHighlighter().removeAllHighlights();
 this.searchInfo.setText("");
 return;
 \}
 int matchCount = 0; int matchStart = 0; int matchEnd = 0;
 Pattern pattern = Pattern.compile("(?i)" + search);
 HTMLDocument document = (HTMLDocument) this.area.getDocument();
 HTMLDocument.Iterator it = document.getIterator(HTML.Tag.CONTENT);
 while (it.isValid()) \{
 try \{
 String fragment = document.getText(
 it.getStartOffset(), it.getEndOffset() - it.getStartOffset());
 Matcher matcher = pattern.matcher(fragment);
 while (matcher.find()) \{
 if (matchCount == 0) \{
 this.matches.clear();
 this.currentMatch = 0;
 this.field.setBackground(Color.WHITE);
 \}
 matchStart = it.getStartOffset() + matcher.start();
 matchEnd = it.getStartOffset() + matcher.end();
 this.matches.add(new Match(matchStart, matchEnd));
 if (matchCount == 1) \{ this.goToMatch(); \}
 matchCount++;
 \}
 \} catch (BadLocationException ex) \{ 
 System.out.println("bad location:");
 \}
 it.next();
 \}
 this.highlight(); 
 if (matchCount == 0) \{
 this.area.getHighlighter().removeAllHighlights();
 this.field.setBackground(Color.PINK);
 this.searchInfo.setText("");
 return;
 \}
 \}

 /** highlights matches found by the search() method */
 public void highlight() \{
 int ii = 0;
 this.searchInfo();
 DefaultHighlighter.DefaultHighlightPainter orangepainter = 
 new DefaultHighlighter.DefaultHighlightPainter(Color.orange);
 DefaultHighlighter.DefaultHighlightPainter painter = 
 new DefaultHighlighter.DefaultHighlightPainter(Color.green);
 this.area.getHighlighter().removeAllHighlights();
 try \{
 for (Match m: this.matches) \{
 if (ii == this.currentMatch) \{
 this.area.getHighlighter().addHighlight(
 m.start, m.end, orangepainter);
 \}
 else \{
 this.area.getHighlighter().addHighlight(
 m.start, m.end, painter);
 \}
 ii++;
 \}
 \} catch (BadLocationException e) \{\}
 \}

 /** scrolls the page to the current match and highlights it */
 public void goToMatch() \{
 if (this.matches.isEmpty()) return;
 this.area.setCaretPosition(
 this.matches.get(this.currentMatch).start);
 this.highlight();
 try \{
 Dimension view = this.scroll.getViewport().getExtentSize(); 
 JScrollBar bar = this.scroll.getVerticalScrollBar();
 bar.setValue(this.area.modelToView(
 this.area.getCaretPosition()).y - view.height/3);
 \} catch (BadLocationException ex) \{ 
 System.out.println("bad location:");
 \}
 \}

 public void hideSearchPanel() \{
 this.searchPanel.setVisible(false);
 this.revalidate();
 \}
 public void showSearchPanel() \{
 this.searchPanel.setVisible(true);
 this.revalidate();
 this.field.requestFocusInWindow();
 //if (SearchPage.this.field.getText().length() == 0)
 // SearchPage.this.searchHelpMessage();
 \}
 public static void main(String args[]) \{
 EventQueue.invokeLater(new Runnable() \{
 public void run() \{
 JFrame f = new JFrame("SearchPane: Searchable Html Text");
 f.add(new SearchPage());
 f.pack(); f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.setDefaultCloseOperation(JFrame.DISPOSE\\_ON\\_CLOSE);
 f.setVisible(true);
 \}
 \});
 \}
 /* actions for keystrokes */

 class HelpAction extends AbstractAction \{
 public HelpAction() \{
 putValue(Action.NAME, "show help");
 putValue(Action.SHORT\\_DESCRIPTION, 
 "Displays keystrokes and what functions they perform");
 putValue(Action.MNEMONIC\\_KEY, new Integer(KeyEvent.VK\\_I));
 \}
 public void actionPerformed(ActionEvent e) \{
 SearchPage.this.showKeyHelp();
 \}
 \}

 class ShowSearchAction extends AbstractAction \{
 public ShowSearchAction() \{
 putValue(Action.NAME, "show search");
 putValue(Action.SHORT\\_DESCRIPTION, 
 "Displays the search panel for searching the page");
 putValue(Action.MNEMONIC\\_KEY, new Integer(KeyEvent.VK\\_S));
 \}
 public void actionPerformed(ActionEvent e) \{
 SearchPage.this.showSearchPanel();
 \}
 \}

 class HideSearchAction extends AbstractAction \{
 public HideSearchAction() \{
 putValue(Action.NAME, "hide search ");
 putValue(Action.SHORT\\_DESCRIPTION, 
 "Hides the search panel for searching the page");
 putValue(Action.MNEMONIC\\_KEY, new Integer(KeyEvent.VK\\_H));
 \}
 public void actionPerformed(ActionEvent e) \{
 SearchPage.this.hideSearchPanel();
 \}
 \}

 class NextMatchAction extends AbstractAction \{
 public NextMatchAction() \{
 putValue(Action.NAME, "next match");
 putValue(Action.SHORT\\_DESCRIPTION, 
 "scrolls to and highlights the next search string match");
 putValue(Action.MNEMONIC\\_KEY, new Integer(KeyEvent.VK\\_N));
 \}
 public void actionPerformed(ActionEvent e) \{
 if (matches.isEmpty()) return;
 currentMatch++;
 currentMatch = currentMatch \\% matches.size();
 /*
 System.out.println(
 String.format("currentMatch: \\%d\\$\\backslash\\$nmatches.size:\\%d\\$\\backslash\\$n", 
 currentMatch, matches.size()));
 */
 SearchPage.this.goToMatch();
 \}
 \}

 class PreviousMatchAction extends AbstractAction \{
 public PreviousMatchAction() \{
 putValue(Action.NAME, "previous match");
 putValue(Action.SHORT\\_DESCRIPTION, 
 "scrolls to and highlights the previous search string match");
 putValue(Action.MNEMONIC\\_KEY, new Integer(KeyEvent.VK\\_N));
 \}
 public void actionPerformed(ActionEvent e) \{
 if (matches.isEmpty()) return;
 currentMatch = (currentMatch==0)?matches.size()-1:currentMatch-1;
 SearchPage.this.goToMatch();
 \}
 \}
 class BiggerFontAction extends AbstractAction \{
 public BiggerFontAction() \{
 putValue(Action.NAME, "Make the font bigger");
 putValue(Action.SHORT\\_DESCRIPTION, 
 "Makes the font of the html page bigger");
 putValue(Action.MNEMONIC\\_KEY, new Integer(KeyEvent.VK\\_B));
 \}
 public void actionPerformed(ActionEvent e) \{
 SearchPage.this.setFontSize(SearchPage.this.fontSize+2);
 \}
 \}

 class SmallerFontAction extends AbstractAction \{
 public SmallerFontAction() \{
 putValue(Action.NAME, "Make the font smaller");
 putValue(Action.SHORT\\_DESCRIPTION, 
 "Makes the font of the html page smaller");
 putValue(Action.MNEMONIC\\_KEY, new Integer(KeyEvent.VK\\_S));
 \}
 public void actionPerformed(ActionEvent e) \{
 SearchPage.this.setFontSize(SearchPage.this.fontSize-2);
 \}
 \}

 class BackAction extends AbstractAction \{
 public BackAction() \{
 putValue(Action.NAME, "Previous page");
 putValue(Action.SHORT\\_DESCRIPTION, 
 "Go to the previous page in the history list");
 putValue(Action.MNEMONIC\\_KEY, new Integer(KeyEvent.VK\\_H));
 \}
 public void actionPerformed(ActionEvent e) \{
 SearchPage.this.back();
 \}
 \}
 class ForwardAction extends AbstractAction \{
 public ForwardAction() \{
 putValue(Action.NAME, "Next page");
 putValue(Action.SHORT\\_DESCRIPTION, 
 "Go to the next page (if any) in the history list");
 putValue(Action.MNEMONIC\\_KEY, new Integer(KeyEvent.VK\\_L));
 \}
 public void actionPerformed(ActionEvent e) \{
 SearchPage.this.forward();
 \}
 \}


 \}

 /** just hold the start and end indexes of a match */
 class Match \{
 public int start;
 public int end;
 public Match(int start, int end) \{
 this.start = start; this.end = end;
 \}
 \}
 ,,,

SOURCEFORGE TEXT EDITOR ....

 This program is designed to edit a text file on the sourceforge
 server in conjunction with a cgi script. I would like to write this
 as an applet. It is for taking notes and mainly for adding to the 
 java-book.txt

 In the example below, when the user presses the 'enter' key in 
 the JTextField the text in the JTextArea is submitted (posted, sent,
 uploaded) to the webserver. 
 
 Things to do: font resize- add an input/action map to save text
 with control S. make enter in text field load the file named there.
 control B to save the file with a backup name (timestamped). 
 Also save the file locally, to usb etc.

 * post text from a JTextArea to a sf cgi script
 ----------------------------------------------------
 import java.net.*;
 import java.io.*;
 import javax.swing.*;
 import java.awt.event.*;
 import java.awt.*;
 public class ForgeNote extends JPanel implements ActionListener \{
 JTextField field;
 JTextArea area;
 JLabel label;
 String fileName;
 String fullName;
 String savePath;
 String localSavePath;
 final static String cgiPage = 
 "http://bumble.sourceforge.net/cgi-bin/save.x.cgi";
 public ForgeNote() \{
 super(new BorderLayout());
 Font f = new Font(Font.MONOSPACED, Font.PLAIN, 20);
 /*
 this.fileName = new String("");
 this.fullName = new String("");
 this.savePath = new String("");
 */
 this.setFileName("books/java/test.txt");
 this.field = new JTextField("books/java/test.txt");
 this.field.addActionListener(this);
 this.field.setFont(f);
 this.area = new JTextArea(20, 75);
 this.area.setFont(f);
 this.label = new JLabel("info");
 this.label.setFont(f);
 this.add(this.field, BorderLayout.NORTH);
 this.add(new JScrollPane(this.area), BorderLayout.CENTER);
 this.add(this.label, BorderLayout.SOUTH);
 this.getFile();
 \}
 public void setFileName(String fileName) \{
 this.fileName = fileName;
 this.fullName = "http://bumble.sourceforge.net/" + fileName;
 this.savePath = "../htdocs/" + fileName;
 System.out.format("fileName:\\%s\\$\\backslash\\$nfullName:\\%s\\$\\backslash\\$nsavePath:\\%s\\$\\backslash\\$n",
 this.fileName, this.fullName, this.savePath);
 \}
 public void getFile() \{
 try \{
 URL url = new URL(this.fullName);
 BufferedReader in = new BufferedReader(
 new InputStreamReader(url.openStream()));
 String line;
 //InputStreamReader in = new InputStreamReader(fis, "UTF-8");
 this.area.read(in, null);
 in.close();
 \}
 catch (Exception e) \{ e.printStackTrace(); \}
 \}
 public void postText() \{
 System.out.println("posting ...");
 Authenticator.setDefault(new Auth());
 // String page = "http://bumble.sourceforge.net/cgi-bin/save.x.cgi";
 this.setFileName(this.field.getText());
 String filecontents = this.area.getText();
 try \{
 URL siteUrl = new URL(this.cgiPage);
 HttpURLConnection conn = 
 (HttpURLConnection) siteUrl.openConnection();
 conn.setDoOutput(true);
 conn.setRequestMethod("POST");
 conn.setRequestProperty(
 "Content-Type", "application/x-www-form-urlencoded"); 

 DataOutputStream out =
 new DataOutputStream(conn.getOutputStream());
 String content = String.format(
 "filename=\\%s\\&filecontents=\\%s",
 URLEncoder.encode(this.savePath, "UTF-8"),
 URLEncoder.encode(filecontents, "UTF-8"));

 System.out.println(content);
 out.writeBytes(content);
 out.flush(); out.close();
 BufferedReader in = 
 new BufferedReader(new InputStreamReader(conn.getInputStream()));
 String line = "";
 while ((line=in.readLine())!=null) \{
 System.out.println(line);
 \}
 in.close();
 \}
 catch (UnsupportedEncodingException e) \{
 e.printStackTrace();
 \}
 catch (FileNotFoundException e) \{
 //could find the url
 e.printStackTrace();
 \}
 catch (IOException e) \{
 // couldnt connect to the internet
 e.printStackTrace();
 \}
 \}

 public void actionPerformed(ActionEvent e) \{
 this.postText();
 \}
 public static void main(String[] args) \{
 JFrame f = new JFrame("submit text to a webserver");
 f.getContentPane().add(new ForgeNote());
 f.pack(); f.setExtendedState(JFrame.MAXIMIZED\\_BOTH);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.setVisible(true);
 \}
 \}
 class Auth extends Authenticator \{
 protected PasswordAuthentication getPasswordAuthentication() \{
 String prompt = String.format(
 "The host '\\%s' replied '\\%s'\\$\\backslash\\$nplease enter 'name:password'",
 this.getRequestingHost(), this.getRequestingPrompt());
 String namepass = JOptionPane.showInputDialog(
 prompt, "<name:password>");
 String[] info = namepass.split(":", 2);
 System.out.format("name:\\%s,pass:\\%s", info[0], info[1]);
 return new PasswordAuthentication(info[0], info[1].toCharArray());
 \}
 \}
 ,,,


IMAGEPANEL ....

 This section may contain some useful but hopefully small, image
 manipulation applications.

 The following app uses keystrokes to scale and save an image. I should
 change this.imageName to a java.io.File variable. Also change the
 constructor to a File (not string). Also change how new files are loaded
 (since the JFileChooser is annoying)

 Bug: if the first image doesnt load well, then we get null
 pointer exceptions on subsequent loads

 Ideas: change the KeyListener to a set of Actions and modify the 
 ActionMap and InputMap to set up the KeyStrokes that activate the actions.

 * an app which can scale and save an image 
 ----------------------------------
 import java.awt.*;
 import java.awt.image.*;
 import java.awt.event.*;
 import java.io.*;
 import javax.imageio.*;
 import javax.swing.*;

 public class ImagePanel extends JPanel implements KeyListener \{ 
 BufferedImage original;
 BufferedImage image;
 String imageName;
 File saveFile;
 ImageComponent imageDisplay;
 JLabel info;
 String lastOperation;
 long opTime; // how many milliseconds for the last operation 
 public ImagePanel(String imageName) \{
 super(new BorderLayout());
 this.opTime = 0;
 this.lastOperation = new String("");
 this.imageName = new String(imageName);
 this.saveFile = new File("test.save.jpg");
 try \{ 
 this.image = ImageIO.read(new File(imageName)); 
 this.imageDisplay = new ImageComponent(this.image);
 this.info = new JLabel(String.format(
 "Image: \\%s, Dimensions: \\%dx\\%d", 
 imageName, this.image.getWidth(), this.image.getHeight()));
 this.add(this.imageDisplay, BorderLayout.CENTER);
 this.add(this.info, BorderLayout.SOUTH);
 \}
 catch (IOException e) \{
 this.add(new JLabel("Image file couldnt be read"));
 \} 
 \}

 /** executes actions depending on what key is typed */
 public void keyTyped(KeyEvent e) \{
 switch (e.getKeyChar()) \{
 case 'l': 
 JFileChooser chooser = new JFileChooser();
 int result = chooser.showOpenDialog(this);
 File file = chooser.getSelectedFile();
 this.loadImage(file);
 break;
 case 'f':
 String saveFile = 
 JOptionPane.showInputDialog("Save File?");
 this.saveFile = new File(saveFile);
 break;
 case 's': 
 this.scale(0.8f); break;
 case 'S': 
 this.scale(0.5f); break;
 case 'b': 
 this.scale(1.2f); break;
 case 'B': 
 this.scale(2.0f); break;
 case 'w': 
 this.write(); break;
 case 'x': 
 System.exit(0); break;
 default:
 break;
 \}
 this.setInfo();
 //repaint();
 \} 
 public void keyPressed(KeyEvent e) \{\} 
 public void keyReleased(KeyEvent e) \{\}
 public void loadImage(File imageFile) \{
 long start = System.currentTimeMillis(); 
 System.out.println(imageFile.getAbsolutePath());
 BufferedImage test;
 try \{ 
 test = ImageIO.read(imageFile); 
 if (test != null) \{
 this.image = test; 
 this.imageDisplay.setImage(this.image);
 this.imageName = imageFile.getName();
 this.opTime = System.currentTimeMillis() - start;
 this.lastOperation = "load " + this.imageName;
 \}
 else
 this.info.setText(imageFile.getName() + " is not an image"); 
 \}
 catch (IOException e) \{
 this.info.setText(String.format(
 "Image File \\%s could not be read", 
 imageFile.getAbsolutePath()));
 \} 
 this.repaint();
 \}
 
 /** displays information about the last operation in a JLabel */
 private void setInfo() \{
 String s = String.format(
 "<html><em>Image:</em> \\%s, <em>Dimensions:</em> \\%dx\\%d," +
 " Time taken to \\%s: \\%d ms", 
 this.imageName, this.image.getWidth(), this.image.getHeight(),
 this.lastOperation, this.opTime);
 this.info.setText(s);
 \}
 private void scale(float factor) \{
 long start = System.currentTimeMillis(); 
 int newWidth = (int) (this.image.getWidth() * factor);
 int newHeight = (int) (this.image.getHeight() * factor);
 int type = (this.image.getTransparency() == Transparency.OPAQUE) ?
 BufferedImage.TYPE\\_INT\\_RGB : BufferedImage.TYPE\\_INT\\_ARGB;
 BufferedImage tmp = new BufferedImage(newWidth, newHeight, type);
 Graphics2D g2 = tmp.createGraphics();
 g2.setRenderingHint(RenderingHints.KEY\\_INTERPOLATION,
 RenderingHints.VALUE\\_INTERPOLATION\\_BICUBIC);
 g2.drawImage(this.image, 0, 0, newWidth, newHeight, null);
 g2.dispose();
 this.opTime = System.currentTimeMillis() - start;
 this.lastOperation = "scale";
 this.image = tmp;
 this.imageDisplay.setImage(this.image);
 //this.revalidate();
 this.repaint();
 \}
 private void write() \{
 long start = System.currentTimeMillis(); 
 try \{
 ImageIO.write(this.image, "jpeg", this.saveFile);
 \} catch (Exception e) \{ e.printStackTrace(); \}
 this.opTime = System.currentTimeMillis() - start;
 this.lastOperation = String.format(
 "write to \\%s (file size: \\%d bytes)", 
 this.saveFile.getName(), this.saveFile.length());
 \}
 public static void main(String[] args) \{ 
 try \{
 UIManager.setLookAndFeel(
 UIManager.getSystemLookAndFeelClassName());
 \} catch (Exception useDefault) \{\}

 ImagePanel p = new ImagePanel("test.jpg"); 
 JFrame f = new JFrame("Image App");
 f.addKeyListener(p);
 f.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 f.add(p); f.pack(); f.setExtendedState(Frame.MAXIMIZED\\_BOTH);
 f.setVisible(true);
 \}
 \}
 class ImageComponent extends JComponent \{ 
 BufferedImage image;
 public ImageComponent(BufferedImage image) \{
 this.image = image;
 \}
 public BufferedImage getImage() \{
 return this.image;
 \}
 public void setImage(BufferedImage image) \{
 this.image = image; 
 \}
 public void paintComponent(Graphics g) \{ 
 super.paintComponent(g);
 int x = 0; int y = 0;
 // draw the image in the center of the component
 if (this.getSize().getWidth() > this.image.getWidth()) 
 x = (int)(this.getSize().getWidth() - this.image.getWidth())/2; 
 if (this.getSize().getHeight() > this.image.getHeight()) 
 y = (int)(this.getSize().getHeight() - this.image.getHeight())/2; 
 g.drawImage(this.image, x, y, null);
 \}
 public Dimension getPreferredSize() \{
 //return new Dimension(400, 400); 
 Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
 if (this.image.getWidth() >= screen.getWidth() ||
 this.image.getHeight() >= screen.getHeight())
 return this.getParent().getSize(); 
 else
 return new Dimension(this.image.getWidth(), this.image.getHeight());
 \}
 \}

 ,,,


SOME JAVA APPLICATIONS

 This section will contain references to important applications 
 written in the Java language, preferably open source.

 JLatexEditor
 is an editor for the LaTeX markup language 
 JEdit
 A text and java code editor 
 \url{http://lobobrowser.org/java-browser.jsp}
 A webbrowser written in java.

DESIGN PATTERNS

 Design patterns are a way of talking about object oriented design.
 This section will contain very brief notes on a small selection of 
 patterns.

 * Flyweight pattern 
 used in wordprocessors (wysiwyg). Shared state of objects stored in
 external class to minimize memory usage. Eg: class for a glyph in a
 document. 
 * Builder pattern set state of object using methods
 eg: Search s = new Search().recursive()...
 * Factory (method)
 used instead of constructors to create instances of objects 
 with the aim to cache and share
 immutable objects (which would otherwise drain memory resources)
 * Proxy or Surrogate 
 An object which appears to be performing a task but is really handing
 the task to another object. An example is a local RMI stub object
 * 

GLOSSARY

 Tooltip - 
 A little (usually yellow) that pops up when you move your mouse over
 an element in a Java Gui Application. The box is supposed to contain 
 explanatory or helpful text relation to how to use the element highlighted.
 Data hiding:
 Garbage collection
 Memory Management:
 Decoupling
 Patterns:
 JVM:

TESTING 

 * initialization 
 ---------------
 public class Test \{
 public int x;
 public double d;
 public static void main(String[] args) \{
 Test t = new Test();
 System.out.println("x=" + t.d); 
 \}
 \}
 ,,,

 * infinite recursion 
 ---------------
 public class RecursionTest \{
 public static void while()
 \{ Test.while(); \}
 public static void main(String[] args) \{
 Test.while();
 System.out.println("="); 
 \}
 \}
 ,,,

 * testing char casts 
 ---------------
 public class Test \{
 public static void main(String[] args) \{
 char c = 'e';
 int i = (int)'A';
 if ((c >= 'a') \\&\\& (c <= 'z'))
 \{
 System.out.println("c=" + (int)c); 
 System.out.println("i=" + i); 
 \}
 \}
 \}
 ,,,

 * parseint 
 ---------------
 public class Test \{
 public static void main(String[] args) \{
 String s = "-123"; 
 int i = Integer.parseInt(s);
 System.out.println("i=" + i); 
 \}
 \}
 ,,,

 * testing char casts 
 ---------------
 public class Test \{

 public static void main(String[] args) \{
 char c = 'e';
 int i = (int)'A';
 if ((c >= 'a') \\&\\& (c <= 'z'))
 \{
 System.out.println("c=" + (int)c); 
 System.out.println("i=" + i); 
 \}
 \}
 \}
 ,,,

 * testing char casts 
 ---------------
 public class Test \{
 public static void main(String[] args) \{
 char c = 'a' + 4; 
 System.out.println("c=" + c); 
 \}
 \}
 ,,,

NOTES

 This section contains notes which havent been placed in
 their appropriate chapter or section yet.
 * load an application resource from a jar (not a user resource)
 >> URL iconUrl = this.getClass().getResource("/icons/copy.jpg");

 The code above has the disadvantage of downloading the images from
 the internet each time they are used.

 * display a (buffered) image in a message box
 >> JOptionPane.showMessageDialog(parent, new JLabel(new ImageIcon(theImage)));

 * a logger which publishes to the console
 -----------------------------
 import java.util.logging.*;
 
 class LoggingLevels \{
 
 public static void main(String[] args) \{
 Logger logger = Logger.getAnonymousLogger();
 // LOG this level to the log
 logger.setLevel(Level.FINER);
 
 ConsoleHandler handler = new ConsoleHandler();
 // PUBLISH this level
 handler.setLevel(Level.FINER);
 logger.addHandler(handler);
 
 System.out.println("Logging level is: " + logger.getLevel());
 for (int ii=0; ii<3; ii++) \{
 logger.log(Level.FINE, ii + " " + (ii*ii));
 logger.log(Level.INFO, ii + " " + (ii*ii));
 \}
 \}
 \}
,,,
 
* produces output like
--------------
Logging level is: FINER
Jun 11, 2011 9:39:23 PM LoggingLevels main
INFO: 0 0
Jun 11, 2011 9:39:24 PM LoggingLevels main
INFO: 1 1
Jun 11, 2011 9:39:24 PM LoggingLevels main
INFO: 2 4
,,,

 * to investigate, writing log files with the logging package
 --------------------
 import java.util.logging.*;
 private Logger logger = Logger.getAnonymousLogger();
 logger.log(Level.FINER, "Get column styles");
 ,,,

 * update look and feel after gui has been displayed
 -----------------
 try \{
 UIManager.setLookAndFeel(plafInfos[index].getClassName() );
 SwingUtilities.updateComponentTreeUI(frame);
 // not necessary to pack but good
 frame.pack();
 frame.setMinimumSize(frame.getSize());
 \} catch(Exception e) \{
 e.printStackTrace();
 \}
 ,,,

* get a screen shot of a jframe component (using BufferedImage)
 >> \url{http://stackoverflow.com/questions/5853879/java-swing-obtain-image-of-jframe/5853992\\#5853992}

* set a window location depending on os 
>> jframe.setLocationByPlatform(true);

TODO
 
 \url{http://www.daniweb.com/software-development/java/threads/94567/writing-string-to-a-file}
 a nice visual effect of highlighted words with shadows

 * use the built in javascript engine in java 1.6 to evaluate a sum
 -------------------------------
 import javax.script.ScriptEngineManager;
 import javax.script.ScriptEngine;

 public class Test \{
 public static void main(String[] args) throws Exception\{
 ScriptEngineManager mgr = new ScriptEngineManager();
 ScriptEngine engine = mgr.getEngineByName("JavaScript");
 String foo = "40+2";
 System.out.println(engine.eval(foo));
 \} 
 \}
 ,,,

 @@ \url{http://stackoverflow.com/questions/4458982/repaint-swing-button-with-different-gradient/5845007\\#5845007}
 set the colour gradient on abutton

 * (com.sun.awt.AWTUtilities) to make your JFrame really transparent. 
 --------------------------------
 import com.sun.awt.AWTUtilities;
 /* "this" is the JFrame */
 this.setUndecorated(true);
 AWTUtilities.setWindowOpaque(this, true);
 AWTUtilities.setWindowOpacity(this, 0.5f);
 AWTUtilities.setWindowShape(this, new RoundRectangle2D.Float(0f, 0f, (float) getWidth(), (float) getHeight(), 15f, 15f));
 ,,,

 \url{http://oreilly.com/catalog/java2d/chapter/ch04.html}
 a chapter on painting from an oreilly book

 idea: to create an angled stripy effect with two colours, use
 a gradient paint in cycle mode with the gradient very small, or tight.
 Then you could animate the gradient paint to create moving stripes.
 This technique can fill a shape with lots of stripes. 

 * make an italic font in the same family
 >> Font f = g.deriveFont(Font.ITALIC);

 * make a text box with an image in it
 >> use CompoundBorder and MatteBorder

* get a buffered image of a jframe and write it to a png file
---------------------------------------------
 Component c = f.getContentPane();
 BufferedImage i = getScreenShot(c);
 try \{
 ImageIO.write(img, "png", new File("screenshot.png"));
 \} catch (Exception e) \{ e.printStackTrace(); \}
 
 public static BufferedImage getScreenShot(Component component) \{
 BufferedImage image = new BufferedImage(
 component.getWidth(), component.getHeight(), 
 BufferedImage.TYPE\\_INT\\_RGB
 );
 component.paint(image.getGraphics());
 return image;
 \}
,,,

 * create a jlabel with icon from a scaled buffered image
 ----------------------------
 BufferedImage img = ...;
 JLable l = new JLabel(
 new ImageIcon(img.getScaledInstance(
 img.getWidth(null)/2, img.getHeight(null)/2, Image.SCALE\\_SMOOTH))); 
 ,,,

* get a screen shot of a jframe component (using BufferedImage)
 >> \url{http://stackoverflow.com/questions/5853879/java-swing-obtain-image-of-jframe/5853992\\#5853992}

 * set a window location depending on os 
 >> jframe.setLocationByPlatform(true);

* set the native system look and feel. 
------------------------
 public static void main(String[] args) \{
 SwingUtilities.invokeLater( new Runnable() \{
 public void run() \{
 try \{
 UIManager.setLookAndFeel(
 UIManager.getSystemLookAndFeelClassName());
 \} catch (Exception useDefault) \{\}
 initGui();
 \}
 \});
 \}
,,,

 * read a file into a string buffer
 ----
 BufferedReader br = new BufferedReader(fr);
 String buffer; 
 StringBuffer result = new StringBuffer(); 
 while ((buffer = br.readLine()) != null) \{
 result.append(buffer);
\} 
,,,

It would probably be faster to read into a larger buffer (8k ?) rather than
just one line.

* jlist with a list model
 ----
 import java.awt.*;
 import javax.swing.*;

 public class List extends JFrame \{
 public static void main(String[] args) \{
 List t = new List();
 ListModel bigData = new AbstractListModel() \{
 public int getSize() \{ return Short.MAX\\_VALUE; \}
 public Object getElementAt(int index) \{ return "Index " +
 index; \}
 \};

 JList bigDataList = new JList(bigData);

 //use the following method for performance reasons
 bigDataList.setPrototypeCellValue("Index 1234567890");
 JScrollPane js = new JScrollPane(bigDataList);
 t.getContentPane().add(js);
 t.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 t.setVisible(true);
 \}
 \}
 ,,,

 * displays a file list in the center of the screen
 ------
 import java.awt.*;
 import javax.swing.*;
 import java.io.*;

 public class List extends JFrame \{
 public static void main(String[] args) \{
 List t = new List();
 JList bigDataList = new JList((new File(".")).listFiles()); 
 JScrollPane js = new JScrollPane(bigDataList);
 JPanel pl = new JPanel(); pl.add(js);
 t.getContentPane().add(pl);
 t.setSize(new Dimension(300, 300));
 t.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 t.setLocationRelativeTo(null);
 t.setVisible(true);
 \}
 \}
 ,,,

 * display list of files in the current folder in a list box
 ------
 import java.awt.*;
 import javax.swing.*;
 import java.io.*;

 public class List extends JFrame \{
 public static void main(String[] args) \{
 List t = new List();
 
 File dir = new File(".");
 File[] files = dir.listFiles();
 JList bigDataList = new JList(files);
 JScrollPane js = new JScrollPane(bigDataList);
 JPanel pl = new JPanel(); pl.add(js);
 t.getContentPane().add(pl);
 t.setSize(new Dimension(300, 300));
 t.setDefaultCloseOperation(JFrame.EXIT\\_ON\\_CLOSE);
 t.setVisible(true);
 \}
 \}
 ,,,

* a simple file directory TreeModel for use with a JTree element
---------

import javax.swing.*;
import javax.swing.tree.*;
import javax.swing.event.*;
import java.io.*;

public class FileSystemModel implements TreeModel \{

 String root;
 public FileSystemModel() \{
 this( System.getProperty( "user.home" ) );
 \}

 public FileSystemModel( String startPath ) 
 \{ root = startPath; \}

 public Object getRoot() 
 \{ return new File( root ); \}

 public Object getChild( Object parent, int index ) \{
 File directory = (File)parent;
 String[] children = directory.list();
 return new File( directory, children[index] );
 \}

 public int getChildCount( Object parent ) \{
 File fileSysEntity = (File)parent;
 if ( fileSysEntity.isDirectory() ) \{
 String[] children = fileSysEntity.list();
 if (children == null) return 0;
 return children.length;
 \}
 return 0;
 \}

 public boolean isLeaf( Object node )
 \{ return ((File)node).isFile(); \}

 public void valueForPathChanged( TreePath path, Object newValue ) \{\}
 public void removeTreeModelListener(TreeModelListener l) \{\}
 public void addTreeModelListener(TreeModelListener l) \{\}

 public int getIndexOfChild( Object parent, Object child ) \{
 File directory = (File)parent;
 File fileSysEntity = (File)child;
 String[] children = directory.list();
 int result = -1;

 for ( int i = 0; i < children.length; ++i ) \{
 if ( fileSysEntity.getName().equals( children[i] ) ) \{
 result = i; break;
 \}
 \}

 return result;
 \}

 public static void main(String[] args)
 \{
 JFrame f = new JFrame();
 JTree t = new JTree(new FileSystemModel());
 f.getContentPane().add(t);
 f.setVisible(true);
 \}
\}
,,,

DEBUGGING

 

\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents debugging tools: 
 * sscce (sscce.org)
 This is a technique to create all required files needed to 
 reproduce a bug in a java application
 *

BUGS IN JAVA APIS

 Like all big pieces of software the Java apis have bugs, many
 many bugs. 

 \url{http://bugs.sun.com/bugdatabase/}
 View all the known java api bugs (including ones that have been
 fixed)

HISTORY OF JAVA 

 Bill Joy was an influential figure in the elaboration of the
 Berkeley Standard Distribution (BSD) of the Unix operating system at
 the University of California, Berkeley in the late 1960s / 1970s. He
 was also involved in writing one of the first implementations of the
 tcp/ip protocol while still a student as well as creating the 'vi'
 text editor.

 He then went on to co-found Sun Microsystems, where he sponsored the
 development of the Java language. James Gosling, who had previously
 worked on the development of the emacs text editor worked on Java.

VERSIONS OF JAVA

 * choose which version to use of the jre or jdk on a Linux Debian system
 >> sudo update-alternatives --config java
 
VERSION HISTORY ....

 It is often important to know when a particular feature was 
 introduced into java when one is targeting a particular version
 of the java virtual machine

JDK 1.0 ....

 (January 23, 1996)

 The first stable version was the JDK 1.0.2. is called Java 1

JDK 1.1 ....

 (February 19, 1997)


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents major changes 
 .. an extensive retooling of the AWT event model
 .. inner classes added to the language
 .. JavaBeans
 .. JDBC
 .. RMI
 .. reflection - Introspection only, no modification at runtime 
 ..

J2SE 1.2 ....

 (December 8, 1998)

 rebranded Java 2 and the version name "J2SE" (Java 2 Platform, Standard
 Edition) replaced JDK to distinguish the base platform from J2EE (Java 2
 Platform, Enterprise Edition) and J2ME (Java 2 Platform, Micro Edition). 


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents major changes 
 .. strictfp keyword
 .. the Swing graphical API was integrated into the core classes
 .. Just in Time compiler - 
 .. Java Plug-in
 .. Java IDL, an IDL implementation for CORBA interoperability
 .. Collections framework
 ..

J2SE 1.3 ....

 (May 8, 2000)



\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents major changes 
 .. HotSpot JVM included (first released in April, 1999 for J2SE 1.2 JVM)
 .. RMI was modified to support optional compatibility with CORBA
 .. JavaSound
 .. Java Naming and Directory Interface (JNDI) in core libraries 
 .. Java Platform Debugger Architecture (JPDA)
 .. Synthetic proxy classes
 .. javax.swing.InputMaps
 ..

J2SE 1.4 ....

 (February 6, 2002)

 This was the first release of the Java platform developed under the Java
 Community Process as JSR 59. 


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents major changes 
 .. assert keyword 
 .. regular expressions modeled after Perl regular expressions
 .. exception chaining - exceptions can encapsulate lower-level exception
 .. Internet Protocol version 6 (IPv6) support
 .. non-blocking IO (named NIO) (New Input/Output) 
 .. logging API 
 .. image IO - reading and writing images in formats eg JPEG and PNG
 .. integrated XML parser and XSLT processor (JAXP)
 .. integrated security and cryptography extensions (JCE, JSSE, JAAS)
 .. Java Web Start - first released in March, 2001 for J2SE 1.3
 .. Preferences API (java.util.prefs)
 .. Drag-and-drop api reworked
 ..

J2SE 5.0 

 (September 30, 2004)
 Also numbered as java 1.5 

 J2SE 5.0 entered its end-of-life on April 8, 2008 and is no longer
 supported by Sun as of November 3, 2009.

 Java 5 is the last release of Java to officially support the Microsoft
 Windows 9x line (Windows 95, Windows 98, Windows ME). Unofficially,
 Java SE 6 Update 7 (1.6.0.7) is the last version of Java to be shown
 working on this family of operating systems. 

 Java 5 is the default version of Java installed on Apple Mac OS X 10.5
 (Leopard). Java 6 can be installed and set as the default to be used on
 64-bit (Core 2 Duo and higher) processor machines. Java 6 is also
 supported by 32-bit machines running Mac OS X 10.6 (Snow Leopard).


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents language changes:
 .. Generics - compile-time type checking for collections, less typecasts
 .. annotations - tag classes/methods with metadata eg @override
 .. auto conversions between primitives and wrapper classes
 .. enum type - an enumerated data type
 .. varargs - variable number of arguments eg void drawText(String... s)
 .. foreach loop - loop over any iterable with a simple syntax
 .. fix java memory model - improves threads
 .. static imports -
 .. synth - a new look and feel for swing
 .. Automatic stub generation for RMI objects.
 .. concurrency utilities in package java.util.concurrent
 .. Scanner class - parse data from streams and buffers
 ..

JAVA SE 6 ....

 (December 11, 2006)

 The name "J2SE" replace with "Java SE"
 developers numbering remains 1.6.0.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents important changes
 .. Java compiler api - allows programatic compilition
 .. swing performance improvements -
 .. pluggable annotations
 .. SwingWorker included in api - a swing worker thread
 .. Drag and Drop api changes - TransferHandler.TransferSupport class
 .. table sorting and filtering,
 .. Swing double-buffering - eliminates gray-area effect
 .. JAXB 2.0 - integration of a StAX parser.
 .. Scripting Language Support -integration with scripting languages
 .. Mozilla JavaScript Rhino integration
 .. Improved Web Service support through JAX-WS
 .. JDBC 4.0 support 
 ..

 Support for older Win9x versions dropped. Unofficially Java 6 Update 7
 is the last release of Java shown to work on these versions of Windows.

 JVM improvements: synchronization and compiler performance
 optimizations, new algorithms and upgrades to existing garbage
 collection algorithms, and application start-up performance.

JAVA 6 UPDATE 10

 15 oct 2010


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents major changes
 .. Java Deployment Toolkit - JavaScript functions for applets, Web Start
 .. Java Kernel - small installer with only commonly used JRE classes
 .. Enhanced updater.
 .. Enhanced versioning and pack200 support
 .. Java Quick Starter - improve cold start-up time.
 .. Improved performance of Java2D graphics primitives on Windows
 .. A new Swing look and feel called Nimbus and based on synth
 .. new Java Plug-In - applets in a separate process with features of Web Start 
 ..

JAVA SE 7 ....

 released: july 28, 2011

 see the OpenJDK 7 project feature lists for many changes.
 Small language changes were grouped under a project named Coin

 Lambda (Java's implementation of lambda functions), Jigsaw (Java's
 implementation of modules), and parts of Coin were dropped from Java 7.
 Java 8 will be released with the remaining features in summer 2013.


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents major changes
 .. JVM support for dynamic languages
 .. Compressed 64-bit pointers - in Java 6 with -XX:+UseCompressedOops
 .. cast from an Object type to a primitive type directly
 .. Strings in switch statements
 .. Automatic resource management in try-statement
 .. Improved type inference for generic instance creation
 .. Simplified varargs method declaration
 .. Binary integer literals
 .. Allowing underscores in numeric literals
 .. Catching multiple exception types, rethrowing exceptions
 .. Concurrency utilities 
 .. file I/O library for platform independence, metadata, symbolic links.
 .. new packages are java.nio.file and java.nio.file.attribute
 .. Elliptic curve cryptography algorithms
 .. An XRender pipeline for Java 2D
 .. New platform APIs for new graphics features 
 .. Enhanced library-level support for new network protocols, including SCTP and Sockets Direct Protocol
 .. Upstream updates to XML and Unicode

INVESTIGATE AND NONCATEGORISED

 This section contains subjects and code snippets in java to
 investigate

 * what does this mean, a raster is a kind of pixel map
 >> WritableRaster wr = screen.getRaster();

 * investigate Maps 
 >> Map<?, ?> properties = ((TAudioFileFormat) fileFormat).properties();

 * xml parsing code, zip extracting, logging code, by A. Thompson
 >> \url{http://stackoverflow.com/questions/8509302/is-this-ods-reader-functional}

 * investigate using JWindows for pop up dialogs or tool tips
 >> JWindow

 * transfer a file via scp, Jsch has a reputation for being tricky to use
 >> use JSch

 * an alternative to jsch is sshj
 >> https://github.com/shikhar/sshj

JAVA RUNTIME ENGINE

 The compiled classes for the JRE are contained in the file 'rt.jar'
 or 'classes.jar' on an Apple system.

CRASHES OF THE RUNTIME ENGINE ....

 This almost always indicates a bug in a java api. Eg doing a 
 RescaleOp on certain types of images. It may be possible catch these
 crashes with a Throwable?
 
JAVA VIRTUAL MACHINE

 Java is based on a virtual machine. The Sun/oracle implementation is
 called 'Hotspot' ... The Android java machine is called Dalvik. The Sun
 machine is a stack machine, where as Dalvik is a register based machine

 The virtual machine can be thought of, simplistically as consisting 
 of a heap and a stack. The heap is a memory area where objects are 
 created. The stack is used for method calls and local variables.

HEAP IN THE VIRTUAL MACHINE ....

STACK IN THE VIRTUAL MACHINE ....

 The jvm is considered to be a 'stack machine' as opposed to a register
 machine. The stack is used, among other things to store information about
 method calls. Since method calls can, and almost always are, nested, the
 stack is ideally suited to this purpose. It is possible to inspect this
 stack from within a running java program.

 * print the stack for the current Thread 
 -------------------------------------------------------------
 public class StackTrace \{
 public static void main(String[] args) \{
 StackTraceElement[] stack = Thread.currentThread().getStackTrace();
 for (StackTraceElement e: stack) \{
 System.out.println(e.toString());
 \}
 \}
 \}
 ,,,

 * get the name of the last method executed in the current thread
 -------------------------------------------------------------
 public class StackTrace \{
 public static void main(String[] args) \{
 StackTraceElement[] stack = Thread.currentThread().getStackTrace();
 StackTraceElement main = stack[stack.length - 1];
 String mainClass = main.getClassName();
 System.out.println(mainClass);
 \}
 \}
 ,,,

JAVAP

 javap is a utility which forms part of the jdk which displays 
 java bytecode (extracted from .class files) in a disassembled format
 (displays mnemonics instead of instruction numbers). This is useful
 if one needs to analyse the bytecode for performance or debugging 
 reasons.

 * use javap to display compiled bytecode or java assembly for a class
 ----------------------
 3: dup
 4: ldc \\#3; //String bu
 6: invokespecial \\#4; //Method StringBuilder."<init>":(String;)V
 9: astore\\_1
 10: ldc \\#5; //String b
 12: astore\\_2
 13: ldc \\#6; //String u
 ,,,

IMPLEMENTATIONS OF JAVA


\title{} 
\author{bumble.sourceforge.net} 
\maketitle 
\tableofcontents jvm and api implementations 
 .. sun - the primary one
 .. Openjdk - the open source version of the Sun platform
 .. gcj - the gnu version
 .. 

ANDROID JAVA

 This is another big topic and maybe should be a separate booklet but I
 would have to repeat lots of java info.

 Android java api is based on 'Harmony' and uses a different 
 virtual machine (Dalvik).

ANDROID GLOSSARY ....

 Android uses a different terminology when referring to applications
 and their components.

 activity
 similar to a 'window', but can be used by other applications
 service
 a non-visual background task (thread)
 content provider
 an abstraction of a storage medium (database, filesystem)
 intent
 The way that applications use activities from other applications.
 A form of communication between two applications


NOTES 

notes from the file java-notes.txt

 * create a hashmap of actions and their names, but why? 
 --------------
 HashMap<Object, Action> actions = new HashMap<Object, Action>();
 Action[] actionsArray = textComponent.getActions();
 for (int i = 0; i < actionsArray.length; i++) \{
 Action a = actionsArray[i];
 actions.put(a.getValue(Action.NAME), a);
 \}
 ,,,

 * another bizarre hashtable action example, the web proliferates with these.
 -----------------
 public static Action findAction(Action actions[], String key) \{
 Hashtable<Object, Action> commands = new Hashtable<Object, Action>();
 for (int i = 0; i < actions.length; i++) \{
 Action action = actions[i];
 commands.put(action.getValue(Action.NAME), action);
 \}
 return commands.get(key);
 \}
 ,,,

VI IMPLEMENTATION
 
 In order to implement a vi style escape from insert mode while typing in
 a textcomponent we can use the technique in the example below. When the
 user types say >> we can go to normal mode as its called in vi. This cant
 be done with a documentlistener because we cant alter the document from a
 doc listener.

DOCUMENT-NOTES:
 
 \\# this section contains information about the document and
 \\# will not normally be printed.

 \\# a small icon to represent this book
 document-icon: \texttt{/img/icon/coffee-cup-grey.png}

 \\# a larger image
 document-image:

 \\# what sort of document is this
 document-type: book

 \\# in what kind of state (good or bad) is this document 
 document-quality: not too bad

 \\# work carried out on this document
 document-history:
 @@ 2009
 The document was begun sometime in 2009 in colombia
 @@ 28 feb 2010
 added some information about using vim with java.
 @@ 23 march 2010
 some information about playing sound files, and tree
 models, list models and table models
 @@ 28 april 2010
 added some information about the JOptionPane dialog boxes and
 extended the 'gui' section of the booklet. Various things about
 gui interfaces, tabbed panes, labels, borders etc. 
 The problem is that java examples tend to be long and bulky.
 @@ 30 april 2010
 A few notes about arrays and reflection
 @@ 2 may 2010
 a few corrections in the reflection section, and a bash 
 documentation look-up function
 @@ 12 may 2012
 trying to expand and improve the book, but just lost a lot
 of work because of a save error. Want to add sections on images
 sound. Trying to write an image edit app in java
 @@ 14 may 2012
 Continuing work on this. Looking at the UIManager, CellRenderers
 for changing the appearance of components. Created a set of batch
 files for working on ms windows
 @@ 17 may 2012
 more work. notes about drag and drop
 @@ 21 may 2012
 incorporating some code from stackoverflow and A. Thompson
 who writes very complete code examples. Added notes about
 playing sounds. Finally a working mp3 play example.
 @@ 26 june 2012
 in the process of incorporating the java-notes file into the java 
 book.
 @@ 23 july 2012
 Working on some image scaling info.
 @@ 27 july 2012
 Notes about http. Discovered the javarichclient site which
 is a mine of good info.
 @@ 30 july 2012
 Writing the java version history about when features were added
 to the java language. Investigating swingworker threads. 
 Incorporating some collection information and tidying some java 
 notes from a utas course.
 @@ 31 july 2012
 Add some notes about jar files, class loaders, reflection invoke
 method, good javamail info. Things still to do: 
 comprehensive collections chapter, jdbc, jaxp, 
 xml, sockets and networks, and the list goes on.
 @@ 1 August 2012
 Tidying some javamail information. Beginning a section on 
 javadoc and java documentation.
 @@ 2 august 2012
 Some database info about javadb.
 @@ 4 august 2012
 Tidying some image scaling code. Wrote a possibly using image
 scaling app included in the 'image apps' section. Ideas for 
 images: draw an image on a JPanel, then add components, eg
 progress bar for loading, save file name chooser, etc on a 
 card layout. Then hide and show the components as needed.
 Make a multi-image displayer panel, then modify to allow editing
 of images.
 @@ 5 august 2012
 Realized why the multiline gradient paint on a text component
 is not working- the gradient only applies to the first line
 since the coordinates are absolute not relative to the line.
 Put the examples into the 'eg' folder. Adjusted the vim mappings
 @@ 6 august 2012
 Added info about JComboBoxes and their models, events and 
 listeners. Tried to write a general filtering combobox but
 ran into problems with the DocumentListener and a multitude of 
 Events being fired.
 @@ 7th august 2012
 Sunny. Would like to make a TreeModel which reads a DocumentModel
 Adding some information about styled text with the AttributedString
 class. Investigating antialiasing of text. 
 @@ 10 august 2012
 Some jar api examples. A slightly better image load with progress
 bar example.
 @@ 12 august 2012
 Investigating the JEditorPane and associated css stylesheets. 
 Wrote a local java api doc browser JavaDocPanel and attached it 
 to vim with a mapping ',jd' to look up the word under the 
 cursor with the browser. This could be useful
 @@ 14 august 2012
 displaying glyphs from the miscelaneous unicode blocks, having
 problems finding a good font to display them all. Trying to 
 create a nice rounded border but having Insets problems or 
 painting of the border is cut off.
 @@ 15 august 2012 
 Added some JLabel info. Fixed the thick stroke painting problem for 
 classes extending AbstractBorder (shrink the painting rectangle by
 half the stroke width). Looking at the BasicStroke. Looking at
 shapes, areas, translucency, java2d.
 @@ 16 august 2012
 Writing some examples for BufferedImageOps such as ConvolveOp
 RescaleOp. Realised that image filtering is not as mathematically
 complicated as I thought. Ran into some bugs in the Sun implementation
 of these operations, and found workarounds. Need to look more 
 at keybindings, and their default string names in Swing (see 
 camickr)
 @@ 17 august 2012
 would like to look at clipping (g2d.clip), cryptography, java
 printing, public/private keys, signing applets. In bogota. Tidying
 up some text imported from a utas note sheet. Added arrow key
 and vi key scrolling to the JavaDocPanel which is nice. Should
 add page scrolling (J/K), and left arrow key goes to previous page.
 @@ 18 august 2012
 Highlighting and searching JEditorPanes, tackling the doc index
 problem with html text. All so that I can search
 a few javadocs. a bit silly.
 @@ 19 august 2012
 Investigating HTMLDocuments and what they can do. Some notes 
 about public/private key pairs and signing. A basic java.awt.print
 example.
 @@ 20 august 2012
 Looking at viewport positions, scrollbar values etc. Wrote an
 example ScrollBarTest which demonstrates modelToView positions etc.
 Writing SearchHtmlPane to allow 'n' to go to the next match. A lot
 of work and not much results.
 @@ 22 august 2012
 Wrote an example to post data to an authenticated webserver page.
 Started an app ForgeNote to take notes on the sf server. Not
 really useful yet, can only save one file.
 @@ 24 august 2012
 Got some http and network examples from rgagnon. Incorporated more
 notes, about adding text to styled text components. Had some ideas
 for a simple vi style editor using JTextArea and input maps. But
 its more complicated that it first looks.
 @@ 25 august 2012
 Working on the SearchPane example which allows searching an
 html document. A good working version has been created. I would like
 to integrate this with the JavaDocPanel to improve the javadoc
 browser. 
 @@ 27 august 2012
 Wrote an example for java named colors and added some other colour
 information.
 @@ 28 august 2012 
 Improved the javadoc browser, with a history list.
 @@ 29 august 2012
 Some information about JPopupMenus, and using them with Actions.
 They seem to have the potential to be a useful gui interface
 element.
 @@ 31 august 2012
 some work on the JavadocPanel component. starting to look at how
 to write a SwingWorker to search for files. Created a quite nice
 file search utility in the SwingWorker section. Understood the 
 publish() process() done() and get() methods of the SwingWorker
 and also how to cancel the thread.
 @@ 1 september 2012
 Some work on the FileSearch app, looking at its performance. also got
 a JPanel to display an image after loading it. Doesnt sound like much
 but it works. Would like to experiment with setting the image directly
 from the ProgressListener, rather than the SwingWorker. Maybe the
 SwingWorker is only necessary for updating gui components.
 @@ 2 september 2012
 Some work on BoxLayouts and Box parameters. Reading zip files.
 @@ 4 sept 2012
 Wrote a nice little app GlyphApp which copies unicode glyphs 
 to the clipboard, dingbats etc. Like a unicode block explorer. 
 know why. Wrote a very basic email sending app. Could add inbox 
 functionality. 
 @@ 5 sept 2012 
 writing more drag and drop examples. have a better understanding
 now. imported some image data. writing a import to text area example
 which displays information about the dnd data transfer.
 @@ 7 sept 2012
 some more work on drag-and-drop, including using 
 new TransferHandler("property") to easily create DnD behaviors.
 worked on the FileSearch example. Looking at the JToolTip and 
 customizing. Found a good multi-component tooltip example by 
 rcforte.
 @@ 8 sept 2012
 Some notes about the subclassing the DefaultListCellRenderer.
 paintComponent method for JLabels
 @@ 11 sept 2012
 An example to paint glyphs in the background of a JLabel
 @@ 14 sept 2012
 Some examples for using the java compiler api contained in 
 javax.tools.* (JavaCompiler etc). The start of a text area example
 which compiles java code.

 \\# who wrote this
 authors: mjb \\$\\verb|~| \url{http://bumble.sf.net}

 \\# a short description of the contents, possible used for doc lists
 short-description: Succinct java programming, if thats possible

 \\# what language are the code exampless in;
 code-language: java

 \\# the script which will be used to produce html (a webpage)
 make-html: ./booktohtml.cgi
 \\# the script which will produce 'LaTeX' output (for printing, pdf etc)
 make-latex: ./booktolatex.cgi
 
 
\end{document}
%end generated latex
