<?xml version="1.0" encoding="utf-8"?>
<feed version="0.3" xmlns="http://purl.org/atom/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="en">
<title>Shannon Hickey&apos;s Blog</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/shan_man/" />
<modified>2007-10-19T21:10:43Z</modified>
<tagline></tagline>
<id>tag:weblogs.java.net,2008:/blog/shan_man/255</id>
<generator url="http://www.movabletype.org/" version="3.01D">Movable Type</generator>
<copyright>Copyright (c) 2007, shan_man</copyright>
<entry>
<title>Beans Binding 1.1.1 Beats 1.0&apos;s Butt, Bigtime</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/shan_man/archive/2007/10/beans_binding_1_1.html" />
<modified>2007-10-19T21:10:43Z</modified>
<issued>2007-10-19T21:08:13Z</issued>
<id>tag:weblogs.java.net,2007:/blog/shan_man/255.8458</id>
<created>2007-10-19T21:08:13Z</created>
<summary type="text/plain">Shannon Hickey announces the 1.1.1 release of Beans Binding, with a drastic increase in performance.</summary>
<author>
<name>shan_man</name>

<email>Shannon.Hickey@Sun.COM</email>
</author>
<dc:subject>Community: JavaDesktop</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/shan_man/">
<![CDATA[<p>
I'm pleased to announced that version 1.1.1 of Beans Binding has just been released
at <a href="http://beansbinding.dev.java.net/">http://beansbinding.dev.java.net/</a>.
This release provides a drastic increase in performance over 1.0,
the addition of support for binding to a <code>JSpinner's</code>
<code>value</code> property, and a small set of bug fixes.
</p>
<p>
Extreme performance gains in this release are the result of a fix made to
the <code>BeanProperty</code> and <code>ELProperty</code> classes. As these
classes are central to Beans Binding, most things now perform <b>many orders
of magnitude faster</b>. Consider the following simple test case, that fetches
the value of a property 100,000 times for the same object:
</p>
<p>
<code><pre>

    Person person = new Person("John", "Smith");
    Property p = BeanProperty.create("firstName");
    p.addPropertyStateListener(person, new PSL());

    long start = System.currentTimeMillis();

    for (int i = 0; i < 100000; i++) {
        p.getValue(person);
    }

    System.out.println(System.currentTimeMillis() - start);

</pre></code>
</p>
<p>
In 1.0, this test takes approximately 13,000 milliseconds on my machine.
On the contrary, it takes approximately 8 milliseconds in 1.1.1.
How's that for <i>bigtime</i>?! You can imagine how applications with many
bindings, or components like <code>JTable</code> and <code>JList</code> with
large data sets, will perform much better with this version.
</p>
<p>
I imagine some of you are curious as to how this incredible change in performance
was possible. As described in the JavaDoc for <code>BeanProperty</code> and
<code>ELProperty</code>, once a listener is installed on the property, values
along the paths are cached, and only updated in respose to property change
notifications. Knowing that developers are likely to encounter beans
that don't fire the correct notifications, and that resulting problems
may pose tricky to debug, I began work on allowing developers to turn on a debug
option that would have <code>BeanProperty</code> and <code>ELProperty</code> log
a message when they detect such a change without notification. They would do this
by re-evaluating the entire path on every method call and comparing each object
to what they have in their cache. This would, of course, remove any performance
gains accomplished by the caching; but only when the debug option is on.
</p>
<p>
While the toggle for this debug option hasn't yet been added, it turns out that
in 1.0 the logic itself was left turned on, only without the messaging&mdash;a code path
that served only to remove all caching benefits. In 1.1.1 this code path has been
turned off pending completion of the debugging feature.
</p>
<p>
And since we're talking about performance, I'd like to share something else
with those of you looking to get every last drop of speed from the current
implementation. Naturally you'd expect <code>BeanProperty</code> to perform better
than <code>ELProperty</code> for simple paths, since the former avoids the overhead of EL
parsing. This <i>will</i>, of course, be true once the implementation has been
further optimized. In the current release, however, <code>ELProperty</code> actually
performs better in many cases. Consider the following test case that creates
a <i>new</i> <code>BeanProperty</code> 100,000 times, and uses each instance to fetch
the value for a <i>new</i> object:
</p>
<p>
<code><pre>

    long start = System.currentTimeMillis();

    for (int i = 0; i < 100000; i++) {
    	Property p = BeanProperty.create("firstName");
        p.getValue(new Person("John", "Smith"));
    }

    System.out.println(System.currentTimeMillis() - start);

</pre></code>
</p>
<p>
This test dramatizes the case of an application that creates and binds a large set
of bindings, with similar properties, perhaps on the first initializion of a GUI
form. In 1.1.1, this code takes approximately 7000 milliseconds on my machine. But
replacing <code>BeanProperty</code> with <code>ELProperty</code> reduces it to 330
milliseconds.
</p>
<p>
Consider this similar test case that uses a <i>single</i> <code>BeanProperty</code> and
fetches its value for 100,000 <i>new</i> objects:
</p>
<p>
<code><pre>

    long start = System.currentTimeMillis();
    
    Property p = BeanProperty.create("firstName");
    
    for (int i = 0; i < 100000; i++) {
        p.getValue(new Person("John", "Smith"));
    }
    
    System.out.println(System.currentTimeMillis() - start);

</pre></code>
</p>
<p>
This test dramatizes what <code>JTable</code> or <code>JList</code> might have to do while
scrolling, to fetch the value of a single property for a large set of objects. In 1.1.1,
this test takes approximately 6900 milliseconds on my machine. Replacing
<code>BeanProperty</code> with <code>ELProperty</code> reduces it to 260 milliseconds.
</p>
<p>
I raise this discussion as a point of interest, not to encourage you to switch to
<code>ELProperty</code> (unless your application demands the performance increase that it
currently brings). As I mentioned, <code>BeanProperty</code> will be optimized to be the
better choice for simple paths. Profiling indicates that the source of <code>ELProperty's</code>
higher performance lies with EL's built-in caching of JavaBean <code>BeanInfos</code>&mdash;something
that can easily be added to <code>BeanProperty</code>.
</p>
<p>
One final note before I sign off for the weekend: Some of you might ask why the release number
has jumped from 1.0 to 1.1.1. The answer is that I actually first released a 1.1, and before I had
finished writing up an announcement, internal testing revealed an existing, but previously
unknown bug that I thought was worth fixing quickly. Hence 1.1.1. Enjoy!
</p>]]>

</content>
</entry>
<entry>
<title>Beans Binding 1.0 Released</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/shan_man/archive/2007/09/beans_binding_1.html" />
<modified>2007-10-10T23:35:10Z</modified>
<issued>2007-09-06T00:53:57Z</issued>
<id>tag:weblogs.java.net,2007:/blog/shan_man/255.8188</id>
<created>2007-09-06T00:53:57Z</created>
<summary type="text/plain">After months of re-architecture, based on feedback from the expert group and community members, Shannon Hickey announces a 1.0 release of Beans Binding.</summary>
<author>
<name>shan_man</name>

<email>Shannon.Hickey@Sun.COM</email>
</author>
<dc:subject>Community: JavaDesktop</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/shan_man/">
<![CDATA[<p>
<i>-- From Saint Petersburg, Russia @ 3:30 AM local time</i>
</p>
<p>
It's finally time! After months of eating, sleeping and drinking
Beans Binding, I'm thrilled to finally announce that version 1.0 has been released at
<a href="http://beansbinding.dev.java.net">http://beansbinding.dev.java.net</a>
for your binding pleasure!
</p>
<p>
1.0 represents a major re-architecture of the Beans Binding API, based on the
extremely valuable feedback from members of the expert group and the community.
I'd like to say thank you to all of you who have discussed ideas with me and
contributed your own. I've tried to combine and build on these ideas and create
an API that is powerful, flexible, extensible and easy to use. I hope you'll keep
the feedback coming so we can continue this rewarding process.
</p>
<p>
While the work on this project continues through the JCP process,
with feature additions and possible API changes to come, the current
state represents the core API that is expected, for the most part, to
persist. As such, we're calling it 1.0 and releasing!
</p>
<p>
Some of the major points of interest in this release:
</p>
<p>
<ul>
  <li>The concept of a property has been factored out into an abstract <code>Property</code> class,
      with two concrete implementations of interest: <code>BeanProperty</code> and <code>ELProperty</code>.

  <li><code>Binding</code> is now an abstract class representing a binding between two <code>Property</code>
      instances (typically associated with two objects).

  <li>Binding with automatic syncing is implemented by a new concrete <code>AutoBinding</code> subclass.

  <li>Bindings to complex Swing components (such as <code>JTable</code>, <code>JList</code> and <code>JComboBox</code>) are
      now handled by custom <code>Binding</code> subclasses.

  <li>The synthetic Swing properties that offer multiple possible behaviors are now exposed
      via multiple versions of the property.
      For example: <code>"text"</code>, <code>"text_ON_FOCUS_LOST"</code> and <code>"text_ON_ACTION_OR_FOCUS_LOST"</code>
      for <code>JTextField</code>; <code>"selectedElement"</code> and <code>"selectedElement_IGNORE_ADJUSTING"</code> for
      <code>JList</code> and <code>JTable</code>.

  <li>Everything has been repackaged into <code>org.jdesktop</code> packages.
</ul>
</p>
<p>
It is my hope that the JavaDoc provided with this release will have you well on your way to binding with the new API
very quickly. While I would love to take you on a tour through the entire API here, composing such a tutorial would delay
this announcement. As such, I'll present a few examples to get you started, let you get going with the new API, and then follow up
with additional blog entries, as time allows, on particulars deserving more attention. As always, please feel free to send
me your questions and/or feedback at any time.
</p>
<p>
<h3>Examples</h3>
</p>
<p>
<i>For the purposes of these examples, we'll work on <code>Person</code> beans, and assume that <code>Person</code>
has the following properties: <code>firstName</code>, <code>lastName</code>, <code>age</code> and <code>mother</code>.</i>
</p>
<p>
<b>Creating and using <code>BeanProperty</code> and <code>ELProperty</code>:</b>
</p>
<p>
<code><pre>

  // create a BeanProperty representing a bean's firstName
  Property firstP = BeanProperty.create("firstName");

  // create a BeanProperty representing a bean's lastName
  Property lastP = BeanProperty.create("lastName");

  // create a BeanProperty representing the firstName of
  // a bean's mother
  Property motherFirstP = BeanProperty.create("mother.firstName");

  // creata an ELProperty representing a bean's mother's full name:
  Property motherFullP =
      ELProperty.create("${mother.firstName} ${mother.lastName}");

  // create an ELProperty representing whether or not a bean's
  // mother's age is greater than 65
  Property motherOlderP = ELProperty.create("${mother.age > 65}");


  // print Duke's first name
  System.out.println(firstP.getValue(duke));

  // print John's first name, reusing the same property
  System.out.println(firstP.getValue(john));

  // print Duke's mother's full name
  System.out.println(motherFullP.getValue(duke));

  // set Duke's mother's first name
  motherFirstP.setValue(duke, "Jennifer");

  // set John's mother's first name, reusing the same property
  motherFirstP.setValue(john, "Melanie");

  // listen for changes to motherOlderP for Duke
  motherOlderP.addPropertyStateListener(duke, listener);

</pre></code>
</p>
<p>
<b>Creating <code>AutoBindings</code> between two properties:</b>
</p>
<p>
<code><pre>

  // Bind Duke's first name to the text property of a Swing JTextField
  BeanProperty textP = BeanProperty.create("text");
  Binding binding =
      Bindings.createAutoBinding(READ_WRITE, duke, firstP, textfield, textP);
  binding.bind();

  // Bind Duke's mother's first name to the text property of a Swing JTextField,
  // specifying that the JTextField's text property only reports change
  // (thereby updating the source of the READ_WRITE binding) on focus lost
  BeanProperty textP = BeanProperty.create("text_ON_FOCUS_LOST");
  Binding binding =
      Bindings.createAutoBinding(READ_WRITE, duke, motherFirstP, textfield, textP);
  binding.bind();

  // Bind the motherOlderP for Duke to the selection of a display-only Swing JCheckBox
  BeanProperty selectedP = BeanProperty.create("selected");
  Binding binding =
      Bindings.createAutoBinding(READ, duke, motherOlderP, checkBox, selectedP);
  binding.bind();

</pre></code>
</p>
<p>
<b>Using Swing Binding subclasses:</b>
</p>
<p>
<code><pre>

  // Bind a List of Person objects as the elements of a JTable and specify
  // that columns should be shown for the beans' first name, mother's full
  // name and whether or not the mother is older than 65
  JTableBinding tb = SwingBindings.createJTableBinding(READ, personList, personJTable);
  tb.addColumnBinding(firstP)
      .setColumnName("First Name").setColumnClass(String.class);
  tb.addColumnBinding(motherFullP)
      .setColumnName("Mother's Full Name").setColumnClass(String.class);
  tb.addColumnBinding(motherOlderP)
      .setColumnName("Mother older than 65").setColumnClass(Boolean.class);
  tb.bind();

  // Bind the last name of the table's selected element to a JTextField
  Property selectedLastP = BeanProperty.create("selectedElement.lastName");
  Property textP = BeanProperty.create("text");
  Binding selBinding =
      Bindings.createAutoBinding(READ_WRITE, personJTable, selectedLastP,
                                             textfield, textP);
  selBinding.bind();

  // Bind a List of Person objects as the elements of a JList
  // and specify that the list should display the first name of the beans
  JListBinding lb = SwingBindings.createJListBinding(personList, personJList);
  lb.setDetailBinding(firstP);

  // Bind the last name of the list's selected element to a JTextField,
  // specifying that changes to the selected element are ignored while
  // it is adjusting
  Property selectedLastP =
      BeanProperty.create("selectedElement_IGNORE_ADJUSTING.lastName");
  Property textP = BeanProperty.create("text");
  Binding selBinding =
      Bindings.createAutoBinding(READ_WRITE, personJList, selectedLastP,
                                             textfield, textP);
  selBinding.bind();

</pre></code>
</p>]]>

</content>
</entry>
<entry>
<title>Beans Binding 0.6.1 Release Available</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/shan_man/archive/2007/06/beans_binding_0_1.html" />
<modified>2007-06-22T22:43:58Z</modified>
<issued>2007-06-22T22:41:40Z</issued>
<id>tag:weblogs.java.net,2007:/blog/shan_man/255.7718</id>
<created>2007-06-22T22:41:40Z</created>
<summary type="text/plain">Two days after the 0.6 release of Beans Binding, the 0.6.1 release is out with simpler and more intuitive method names and constants.</summary>
<author>
<name>shan_man</name>

<email>Shannon.Hickey@Sun.COM</email>
</author>
<dc:subject>Community: JavaDesktop</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/shan_man/">
<![CDATA[<p>
Taking into consideration the feedback that I've received since yesterday's blog on the 0.6 release of Beans Binding,
I've just released 0.6.1 with simpler and more intuitive method names and constants. It's available at
<a href="http://beansbinding.dev.java.net">http://beansbinding.dev.java.net</a>
</p>
<p>
<h3>Full details, straight from the release notes:</h3>
</p>
<p>
<h5>API Changes/Additions</h5>
</p>
<p>
<ul>
<li><p><code>UpdateStrategy.READ_FROM_SOURCE</code> has been renamed to the shorter
    <code>UpdateStrategy.READ</code></p>

<li><p><code>TextChangeStategy</code> is now a top-level enum. In addition, the values
     <code>CHANGE_ON_TYPE</code>, <code>CHANGE_ON_ACTION_OR_FOCUS_LOST</code>
     and <code>CHANGE_ON_FOCUS_LOST</code>
     have been shortened to <code>ON_TYPE</code>,
     <code>ON_ACTION_OR_FOCUS_LOST</code>, <code>ON_FOCUS_LOST</code>.</p>

<li><p><code>Binding.Parameter</code> has been renamed to <code>Binding.ParameterKey</code> and
    <code>Binding.setValue/getValue</code> have been given the more appropriate names
    <code>Binding.putParameter/getParameter</code>.</p>

<li><p>All Swing <code>ParameterKey</code>s are now in a top-level <code>ParameterKeys</code> class.
   They've been renamed as appropriate to reflect the fact that they are constants.
   A few have also been shortened.</p>

<li><p><code>SwingBindingSupport</code> has been removed. Documentation for Swing binding
     is now in the package-level documentation.</p>
</ul>
</p>
<p>
To see how some of these changes affect you, let's look at two examples:
</p>
<p>
Before:
</p>
<p>
<code><pre>

  Binding b = new Binding(list, null, table, "elements");
  b.addChildBinding("${firstName}, null)
     .setValue(SwingBindingSupport.TableColumnParameter, 0)
     .setValue(SwingBindingSupport.TableColumnClassParameter, String.class);

</pre></code>
</p>
<p>
After:
</p>
<p>
<code><pre>

  Binding b = new Binding(list, null, table, "elements");
  b.addChildBinding("${firstName}, null)
     .putParameter(ParameterKeys.COLUMN, 0)
     .putParameter(ParameterKeys.COLUMN_CLASS, String.class);

</pre></code>
</p>
<p>
Likewise, before:
</p>
<p>
<code><pre>

  Binding b = new Binding(object, "${property}", textField, "text");
  b.setValue(SwingBindingSupport.TextChangeStrategyParameter,
             SwingBindingSupport.TextChangeStrategy.CHANGE_ON_TYPE);

</pre></code>
</p>
<p>
After:
</p>
<code><pre>

  Binding b = new Binding(object, "${property}", textField, "text");
  binding.putParameter(ParameterKeys.TEXT_CHANGE_STRATEGY,
                       TextChangeStrategy.ON_TYPE);

</pre></code>
</p>]]>

</content>
</entry>
<entry>
<title>Beans Binding 0.6 Release Available</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/shan_man/archive/2007/06/beans_binding_0.html" />
<modified>2007-06-22T20:57:45Z</modified>
<issued>2007-06-21T17:04:46Z</issued>
<id>tag:weblogs.java.net,2007:/blog/shan_man/255.7704</id>
<created>2007-06-21T17:04:46Z</created>
<summary type="text/plain">Shannon Hickey announces the Beans Binding 0.6 release.</summary>
<author>
<name>shan_man</name>

<email>Shannon.Hickey@Sun.COM</email>
</author>
<dc:subject>Community: JavaDesktop</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/shan_man/">
<![CDATA[<p>
Just a short note to announce that I've posted the 0.6 release of
the Beans Binding project at <a href="http://beansbinding.dev.java.net">http://beansbinding.dev.java.net</a>
</p>
<p>
<h3>In this release:</h3>
</p>
<p>
<ul>
  <li>Improved <code>JTable</code> support
  <li>More default converters
  <li>Name your <code>Bindings</code>
  <li>Compile-time type safety for setting <code>Parameters</code>
  <li>A handful of method renames
</ul>
</p>
<p>
<h3>Full details, straight from the release notes:</h3>
</p>
<p>
<h5>API Changes/Additions</h5>
</p>
<p>
<ul>
<li><p><code>Binding.addBinding/removeBinding/getBindings</code> have been renamed to the more
     descriptive <code>Binding.addChildBinding/removeChildBinding/getChildBindings</code></p>

<li><p><code>Binding.setSourcePath/getSourcePath</code> have been renamed to the more
     appropriate <code>Binding.setSourceExpression/getSourceExpression</code></p>

<li><p>To enforce compile-time type safety, the <code>Object</code> varargs parameter has been
     removed from all constructors and methods in <codE>Binding</code> and <code>BindingContext</code>.
     You must now call <code>setValue</code> directly. To allow for method chaining, <code>setValue</code>
     now returns the <code>Binding</code>. As an example, replace this binding:</p>
     <p>
     <code><pre>

  Binding b = new Binding(source, "${property}", target, "property",
                          Parameter1, param1Value, Parameter2, param2Value);

</pre></code>
     </p>
     <p>
     with this:
     </p>
     <p>
     <code><pre>

  Binding b = new Binding(source, "${property}", target, "property");
  b.setValue(Parameter1, param1Value).setValue(Parameter2, param2Value);

</pre></code>
     </p>
<li><p>Some <code>Binding</code> and <code>BindingContext</code> methods were updated to throw the more
     appropriate <code>IllegalArgumentException</code> (rather than <code>IllegalStateException</code>)
     for certain conditions.</p>

<li><p><code>Binding</code> now has a name property. The ability to name a binding assists in
     debugging. Its main goal, however, is to make it possible to fetch
     bindings by name. This will show its full utility with future changes
     making it easier to validate and then commit or revert bindings as a group.</p>
     <p>
     To support naming a binding, the following API additions have been
     made to <code>Binding</code>:
     </p>
     <p>
     <ul>
       <li>Constructors that take a <code>String</code> name parameter
       <li><code>void setName(String name)</code>
       <li><code>String getName()</code>
       <li><code>addChildBinding</code> methods that take a <code>String</code> name parameter
       <li><code>Binding getChildBinding(String name)</code>
     </ul>
     </p>
     <p></p>
     <p>
     In addition, the following additions have been made to <code>BindingContext</code>:
     </p>
     <p>
     <ul>
       <li><code>addBinding</code> methods that take a <code>String</code> name parameter
       <li><code>Binding getBinding(String name)</code>
     </ul>
     </p>
     <p></p>
<li><p>Added a <code>Parameter</code> to control the editability of a <code>JTable</code> when it is the
     target of a binding. A new <code>EditableParameter</code> has been added to
     <code>SwingBindingSupport</code> to control this. It can be used on a top-level
     binding to control the editability of the entire JTable, and/or on the
     binding's individual child bindings to control editability of individual
     columns. For example, to make all columns non-editable, except for
     the first:</p>
     <p>
     <code><pre>

  Binding b = new Binding(list, null, table, "elements");
  <font color="green">// whole table is non-editable</font>
  b.setValue(SwingBindingSupport.EditableParameter, false);
  b.addChildBinding("${firstName}, null)
      .setValue(SwingBindingSupport.TableColumnParameter, 0)
      <font color="green">// this column IS editable</font>
      .setValue(SwingBindingSupport.EditableParameter, true);
  b.addChildBinding("${lastName}, null)
      .setValue(SwingBindingSupport.TableColumnParameter, 1);

</pre></code>
     </p>
</ul>
</p>
<p>
<h5>Issues Resolved</h5>
</p>
<p>
<ul>
  <li>2: Need converters between various types and String
  <li>5: JTable binding support doesn't support sorting and filtering
</ul>
</p>
<p>
<h5>Other</h5>
</p>
<p></p>
<p>
  The JavaDoc in <code>Binding</code> and <code>SwingBindingSupport</code> has been updated to reflect the
  change to use EL for the source "property".
</p>]]>

</content>
</entry>
<entry>
<title>Top-Level Drop with Swing and Java SE 6</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/shan_man/archive/2006/09/toplevel_drop_w.html" />
<modified>2006-11-22T18:51:52Z</modified>
<issued>2006-09-15T21:06:34Z</issued>
<id>tag:weblogs.java.net,2006:/blog/shan_man/255.5567</id>
<created>2006-09-15T21:06:34Z</created>
<summary type="text/plain">Shannon Hickey demonstrates support in Java SE 6 for dropping into top-level containers such as JFrame and JDialog.</summary>
<author>
<name>shan_man</name>

<email>Shannon.Hickey@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/shan_man/">
<![CDATA[<p>
Although my blog has been quiet for the last few months, it's certainly not for
lack of content to share. In reality, this blog that you're reading now is one
of three that have been living in various stages of completion in my unposted
blogs folder. For many bloggers, I suspect it doesn't work like this. They have
something worthwhile to say (we can hope) and they post it. In my case, however,
I like to use this space both to keep in touch with you, and also to present
technical content that (we can hope) teaches you something new. As such,
it takes me a bit longer while I construct a demo, grab screenshots, and prepare the
technical discussion. These items I work on in parallel with other blogs and
responsibilities. And then, when they're finally ready, I initiate contact.
</p>
<p>
This brings me to today's installment. I'd like to present details on
a Swing Drag and Drop RFE that we implemented back in build 53 of
<a href="http://jdk6.dev.java.net" target="_blank">JDK 6</a>. This addition to the
platform, tracked under RFE
<a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4519484" target="_blank">4519484</a>,
provides support for dropping onto top-level containers, such as <code>JFrame</code> and
<code>JDialog</code>, by allowing you to set a <code>TransferHandler</code> directly on the
container. I'll walk you through this new feature with a demo showing an application type
where this support is particularly useful.
</p>
<p>
The type of application I'm referring to is what I call an "editor"&mdash;an application
designed for editing one or more documents. These applications include IDEs, image manipulation
programs, and editors for many other types of documents. Such an application typically includes,
at a minimum: a menu, a toolbar, an area for editing documents, and perhaps a list or other
mechanism for switching between open documents. For this demonstration, I've put together just
such an arrangement in the form of a simple text editor. Please ensure that you have a recent build
of <a href="http://jdk6.dev.java.net" target="_blank">JDK 6</a> (build 76 or later) installed,
and then click
<a href="http://www.java.net/download/javadesktop/blogs/shan_man/2006.09.15/TopLevelTransferHandlerDemo.jnlp">here</a>
to launch the demo. Note that you'll need to accept a security dialog upon launch, as an editor
application just isn't useful without permission to read files. Rest assured that the demo opens
only the files you tell it to, and only for reading; it has no write capability.
</p>
<p>
The following screen shot shows what the application looks like when it's launched:
</p>
<center>
<p>
<img src="http://weblogs.java.net/blog/shan_man/archive/2006.09.15/initial.PNG">
</p>
</center>
<p>
As you can see, this demo application contains all of the components that I've mentioned above.
In addition, it also adds something that is particularly useful in this type of
application&mdash;drop support for opening files! By allowing drops of files, the user is saved
from having to navigate through a file dialog to open files and instead they can drag files from
their native file system directly to the application for editing. Go ahead and try it now:
drag a file (or a few) from your native desktop or file system, and drop into the document area
at the right. The <nobr>file(s)</nobr> will be opened and you'll see something like the following screen-shot:
</p>
<center>
<p>
<img src="http://weblogs.java.net/blog/shan_man/archive/2006.09.15/dropped.PNG">
</p>
</center>
<p>
Supporting drops of files like this is extremely easy. It requires only that you create
a simple <code>TransferHandler</code> to handle the details of importing files,
and that you set the <code>TransferHandler</code> (via the <code>setTransferHandler</code>
method) on the component that you wish to handle the drops.
Here's the source code for the <code>TransferHandler</code> used in this demo:
</p>
<p>
<blockquote><code><pre style="border: 1px solid darkgray; padding: 4px; color: darkblue;">
class FileDropHandler extends TransferHandler {

    public boolean canImport(TransferSupport supp) {
        /* for the demo, we'll only support drops (not clipboard paste) */
        if (!supp.isDrop()) {
            return false;
        }

        /* return true if and only if the drop contains a list of files */
        return supp.isDataFlavorSupported(DataFlavor.javaFileListFlavor);
    }

    public boolean importData(TransferSupport supp) {
        if (!canImport(supp)) {
            return false;
        }

        /* fetch the Transferable */
        Transferable t = support.getTransferable();

        try {
            /* fetch the data from the Transferable */
            Object data = t.getTransferData(DataFlavor.javaFileListFlavor);

            /* data of type javaFileListFlavor is a list of files */
            java.util.List<File> fileList = (java.util.List<File>)data;

            /* loop through the files in the file list */
            for (File file : fileList) {
                /* This is where you place your code for opening the
                 * document represented by the "file" variable.
                 * For example:
                 * - create a new internal frame with a text area to
                 *   represent the document
                 * - use a BufferedReader to read lines of the document
                 *   and append to the text area
                 * - add the internal frame to the desktop pane,
                 *   set its bounds and make it visible
                 */
            }
        } catch (UnsupportedFlavorException e) {
            return false;
        } catch (IOException e) {
            return false;
        }

        return true;
    }
}
</pre></code></blockquote>
</p>
<p>
Once you have this <code>TransferHandler</code>, you just need to decide which component
to set it on. With this demo, it's <i>initially</i> set it on the <code>JDesktopPane</code>,
which represents the area where documents are edited. While this approach is a decent start,
it has a limitation. Try dragging again over the demo and notice which areas
accept drops. The following screen shot illustrates what you'd see when dragging over
different parts of the demo:
</p>
<center>
<p>
<img src="http://weblogs.java.net/blog/shan_man/archive/2006.09.15/spots0.PNG">
</p>
</center>
<p>
Notice that the only location that accepts drops is the document area. This makes sense,
of course, since the <code>JDesktopPane</code> is the component to which our new
<code>TransferHandler</code> was added. As I mentioned, this is a great start. But
in Java SE 6 we can do better for the user.
</p>
<p>
Also notice that it's actually only a subset
of the document area that accepts file drops; those areas that are covered by an
editor component do not. The reason for this is that the text area component that we're
using as an editor has it's own default <code>TransferHandler</code>, to deal with
the transfer of text content. The text component's <code>TransferHandler</code>,
which knows nothing of file drops, controls the handling of drag and drop within its
component's bounds. But this is all technical details. Let's take a step towards a
better user experience.
</p>
<p>
For starters, let's take advantage of the new Java SE 6 support, change one line of code,
and simply change our <code>setTransferHandler</code> call from the <code>JDesktopPane</code> to
the <code>JFrame</code> itself. <code>JFrame</code>&mdash;along with <code>JDialog</code>,
<code>JWindow</code> and <code>JApplet</code>&mdash;benefits from the addition of a
<code>setTransferHandler</code> method in Java SE 6. By taking advantage of this in the
demo, the user experience is significantly improved. From our demo application's "Demo"
menu, please select "Use Top-Level TransferHandler" to make this change. Try dragging
over the demo again and see how the number of areas that accept drop has increased,
as illustrated by the screen shot below:
</p>
<center>
<p>
<img src="http://weblogs.java.net/blog/shan_man/archive/2006.09.15/spots1.PNG">
</p>
</center>
<p>
Drops are now accepted on almost every area of the application, including the menu bar,
toolbar, and even the frame's title bar! In fact, drops are accepted on any area that isn't
covered by a component with its own <code>TransferHandler</code>. Note that prior to Java
SE 6, similar support can be implemented by setting the <code>TransferHandler</code> on a frame's
<code>JRootPane</code>&mdash;<code>frame.getRootPane().setTransferHandler(th)&mdash;</code>the
difference being that drop can not be supported on the frame's title bar.
</p>
<p>
Like the text area component, the document selector at the left (a <code>JList</code>) also comes
with a default <code>TransferHandler</code>, and therefore does not accept drops of files. Here the
solution is easy: In this context, the default <code>TransferHandler</code> on the list
isn't benefiting us, so we can simply remove it (replace it with <code>null</code>). In fact,
for the purposes of our demo, let's remove the <code>TransferHandlers</code> from the text areas
too and look at the results. From the demo application's "Demo" menu, please select
"Remove TransferHandler from List and Text" and then try dragging over the application once
again. You'll see that file drops are now accepted everywhere! This is shown in the following
screen shot:
</p>
<center>
<p>
<img src="http://weblogs.java.net/blog/shan_man/archive/2006.09.15/spots2.PNG">
</p>
</center>
<p>
Fantastic! There's a caveat here, however. While we've decided that it's acceptable to
remove the default <code>TransferHandler</code> from the list component, the story is somewhat
different with the text components. In removing a text component's <code>TransferHandler</code>
you also remove its default support for cut/copy/paste and drag and drop of text.
</p>
<p>
The correct
solution, for the time being, is to instead provide the text components with their own
custom <code>TransferHandler</code> that supports file drops, and also re-implements the missing
support for handling text transfers. In the future, however, we hope to rememedy the situation
by providing support for <i>adding</i> import support <i>on top of</i> existing
<code>TransferHandlers</code>. This is covered under RFE
<a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4830695" target="_blank">4830695</a>
which has the synopsis "Require ability to add data import ability on top of existing TransferHandler."
</p>
<p>
Before we conclude, I'd like to take you one step further into providing a better user experience
for file drops. If you haven't noticed yet, I'd like to point out that when you drag over the
demo, the mouse cursor changes to the drag and drop "move" cursor. This doesn't exactly make sense,
since you're not really moving the file into the editor. In playing with native applications that
support file drops, I've discovered that they all tend to use "copy" as a better representation
of this situation. That is, when a file is dragged from the file system, where both the "move" and
"copy" actions are supported, the applications I've inspected typically chose "copy".
While, in Java, the results of the drop are identical, it seems worthwhile to provide user
feedback consistent with what users expect. To do so requires that only a few additional
lines be added to the <code>TransferHandler's</code> <code>canImport</code> method to explicitly
chose the action. Let's replace the previous version of <code>canImport</code> with the following:
</p>
<p>
<blockquote><code><pre style="border: 1px solid darkgray; padding: 4px; color: darkblue;">
public boolean canImport(TransferSupport supp) {
    /* for the demo, we'll only support drops (not clipboard paste) */
    if (!supp.isDrop()) {
        return false;
    }

    /* return false if the drop doesn't contain a list of files */
    if (!supp.isDataFlavorSupported(DataFlavor.javaFileListFlavor)) {
        return false;
    }

    /* check to see if the source actions (a bitwise-OR of supported
     * actions) contains the COPY action
     */
    boolean copySupported = (COPY & supp.getSourceDropActions()) == COPY;

    /* if COPY is supported, choose COPY and accept the transfer */
    if (copySupported) {
        support.setDropAction(COPY);
        return true;
    }

    /* COPY isn't supported, so reject the transfer.
     *
     * Note: If you want to accept the transfer with the default
     *       action anyway, you could instead return true.
     */
    return false;
}
</pre></code></blockquote>
</p>
<p>
You can try this out with the demo now. From the "Demo" menu, please select "Use COPY Action",
and then try dragging over the application again. You'll now see, as illustrated in the
following screen shot, that the drag and drop "copy" cursor is used.
<center>
<p>
<img src="http://weblogs.java.net/blog/shan_man/archive/2006.09.15/spots_copy.PNG">
</p>
</center>
<p>
And there you have it&mdash;top-level drop support with Java SE 6. So what am I planning next?
Well, I'm right on the heels of another visit to St. Petersburg, Russia</a> and I hope to come
home with more
<a href="http://weblogs.java.net/blog/shan_man/archive/2006/01/first_class_dra.html">pictures</a>
and stories to share. And I'm definitely in for many hours of flight time, which gives me the chance
to stop <i>dragging</i> my feet and finish some of my other blogs. Until then, please take care,
and feel free to share your questions and comments.
</p>]]>

</content>
</entry>
<entry>
<title>Choosing the Drop Action, and Further Changes to Swing Drag and Drop</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/shan_man/archive/2006/02/choosing_the_dr.html" />
<modified>2006-11-22T18:52:38Z</modified>
<issued>2006-02-15T16:25:11Z</issued>
<id>tag:weblogs.java.net,2006:/blog/shan_man/255.4121</id>
<created>2006-02-15T16:25:11Z</created>
<summary type="text/plain">Shannon Hickey explains the upcoming support for choosing the drop action during Swing Drag and Drop, and how the implementation prompted simplification and further changes to those enhancements already made in Mustang.</summary>
<author>
<name>shan_man</name>

<email>Shannon.Hickey@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/shan_man/">
<![CDATA[<p>
Greetings Gentle Reader; I'm thrilled that you've come back to visit!
As you might imagine, we're still working very hard on Mustang,
aiming to make it the best Java SE release in history. And now with the
<a href="http://java.sun.com/javase/6/" target="_blank">Mustang Beta</a> release
live on the web, we eagerly await your questions, feedback and more of the excellent
<a href="https://mustang.dev.java.net/collaborate.html" target="_blank">code contributions</a>
you've been sending in. While we wait, of course, we're still deeply involved in resolving our
own bug lists and polishing off the features we've released, and we're already fixing things in post-beta
builds. With all of this going on, I'm truly happy for the opportunity to bring you up to date
with one of my little corners of Java SE.
</p>
<p>
In this new world, where you can read <a href="http://weblogs.java.net/" target="_blank">blogs</a>
about and <a href="http://mustang.dev.java.net/" target="_blank">download</a> Java SE changes
as fast as we can make them, an interesting scenario arises: You have access
to code that is evolving; stuff that has the potential to change (for the better). This is an extremely
positive thing! We <i>want</i> the code in your hands as quickly as possible, allowing you to test
drive it, provide feedback, and to help us improve. But this implies a certain obligation for
those of us who blog about our evolving technology - we need to keep you current
with any changes to what we've already shared. It's only fair <nobr>:-)</nobr>
</p>
<p>
Which brings me to the purpose of this particular blog entry. I'd like to introduce you to the
new support for choosing the drop action with Swing Drag and Drop, and narrate how the addition
of this support prompted positive change to one aspect of the API I've already spoken of.
The story begins with drop actions...
</p>
<p>
Every drag source (Java based or otherwise) advertises the set of actions it supports
when exporting data. If it supports data being copied, it advertises the copy action;
if it supports data being moved from it, then it advertises the move action; etc.
(With Swing components, source actions are advertised via the <code>TransferHandler</code>'s
<code>getSourceActions</code> method.)
When a drag is initiated, the user has some control over which of the source actions
is chosen for the transfer, by way of keyboard modifiers used in conjunction with
their drag gesture. Typically, an ordinary drag indicates a preference for moving, holding
<code>control</code> while dragging indicates a preference for copying, and holding both
<code>shift</code> and <code>control</code> gives a preference to linking. The so-called
<i>user action</i> is determined by the system by choosing an appropriate value from the
source actions based on this preference.
</p>
<p>
Prior to Mustang, this nifty little system could only get you so far with Swing Drag and
Drop. When accepting a transfer, <code>TransferHandler</code> would always choose the
user action as the action for the transfer. This would result in a copy being performed
for a user copy action, a move of the data for a move action, and so on.
But two things were missing. The first was a way to accept or reject transfers
based on the drop action. As I explained in my previous blog entry on
<a href="http://weblogs.java.net/blog/shan_man/archive/2006/01/first_class_dra.html">First Class Drag and Drop Support in Mustang</a>,
this ability was added with the introduction of the <code>TransferInfo</code> class in Mustang.
Excellent! The second thing missing was the ability for the developer to explicitly choose
an action; for why should the developer be limited to importing solely with the action chosen by the user?
</p>
<p>
Consider a component that wants to accept copied data, but doesn't want the
responsibility that goes with allowing data to be moved to it. And consider a drag source
that advertises supporting copy as one of its actions. Shouldn't the developer be able to
support dragging from this source to our copy-to-only component, regardless of what the user
prefers with their drag gesture? Of course they should! I discovered this limitation
while composing an upcoming blog entry, and immediately filed bug number
<a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6379813" target="_blank">6379813</a> (<i>TransferHandler should allow the developer to choose the drop action</i>)
on the issue. With the fix for this bug comes the changes I'm about to share with you.
</p>
<p>
In order to support choosing the drop action, we determined that the following were needed:
</p>
<p>
<ul>
  <li>A method to query the source's drop actions, so you know which actions are supported
  <li>A method to query the user drop action, which may be of interest when choosing an action
  <li>A method to query the actual drop action that <code>TransferHandler</code> will use
     (the explicitly chosen action, if applicable; otherwise the user action)
  <li>A way to explicitly choose the actual drop action
</ul>
</p>
<p>
Where to add the first three methods was immediately obvious - we already had <code>TransferInfo</code> to hold
this kind of information. So we added <code>getSourceDropActions</code> and <code>getUserDropAction</code> for
the first two items respectively, and then updated the existing
<code>getDropAction</code> to reflect the actual drop action.
Now, where to add the ability to <i>choose</i> the drop action required some
thinking. An initial thought was to provide a new protected method on <code>TransferHandler</code> that
developers could override to return their choice of drop action. But when a use case was considered, this
seemed less than ideal: Developer overrides <code>canImport</code> to determine the suitability of a
transfer; inspecting the source actions for the action they want, and returning <code>true</code> only
if that action is supported. Developer <i>also</i> must override our new method to choose and return the action they want,
possibly inspecting the source actions again. Yuck! Not very tidy: A need to override two separate methods, and potentially
write the same logic twice. No, it became clear that the right solution would allow the developer to
do everything in one place.
</p>
<p>
Knowing that every <code>TransferHandler</code> supporting drop must implement the
workhorse <code>canImport</code> method, and that it's the place where developers are already
inspecting details of the transfer, it made sense to us that it is also the ideal place for any
logic dealing with configuring the drop action.
As such, providing support for choosing the drop action became as simple as adding one additional method
to <code>TransferInfo</code>, to be called by the developer from <code>canImport</code>.
Gentle Reader, it was the addition of this new <code>setDropAction</code> method that began the chain
of events leading to the API changes I'm here to update you on.
</p>
<p>
You see, with this one tiny change, it came about that <code>TransferInfo</code> was no longer
just an informational class - it had suddenly gained behavior. As such, referring to it as an
"Info" no longer felt appropriate. And so the name <b><code>TransferSupport</code></b> was born. With a quick
search and replace in our source base, the <code>TransferInfo</code> name has gone to the recycling bin,
and the apt <code>TransferSupport</code> name has taken its place. Same little helper, just a little
more power and three extra letters to type <nobr>;-)</nobr>
</p>
<p>
Considering what I've discussed so far, let's see how one implementation of <code>canImport</code> might
look in terms of the updated API. This implementation, which uses the new <code>TransferSupport</code> name,
accepts drops of <code>String</code>s and explicitly chooses the COPY action if it's supported
by the source; it rejects the transfer otherwise:
</p>
<p>
<blockquote><code><pre style="border: 1px solid darkgray; padding: 4px; color: darkblue;">
public boolean canImport(TransferSupport support) {
    // for the demo, we'll only support drops (not clipboard paste)
    if (!support.isDrop()) {
        return false;
    }

    // we only import Strings
    if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)) {
        return false;
    }

    // check if the source actions (a bitwise-OR of supported actions)
    // contains the COPY action
    boolean copySupported =
        (COPY & support.getSourceDropActions()) == COPY;

    // if COPY is supported, choose COPY and accept the transfer
    if (copySupported) {
        support.setDropAction(COPY);
        return true;
    }

    // COPY isn't supported, so reject the transfer
    return false;
}
</pre></code></blockquote>
</p>
<p>
As I mentioned, this implementation rejects the transfer if COPY isn't a supported action of the drag source.
Alternatively, the last line could instead return <code>true</code>, in which case the drop is accepted
with the user drop action (the default if an action isn't explicitly chosen) if the COPY action isn't available.
Let's try this out with a demo. As these are up to the minute changes that I'm discussing, you'll need
to wait until build 76 or later of <a href="http://mustang.dev.java.net/" target="_blank">Mustang</a> is
available to run the demo. At the time of this writing, the current weekly build available for download
is 71. Once you have the correct build, click
<a href="http://www.java.net/download/javadesktop/blogs/shan_man/2006.02.15/ChooseDropActionDemo.jnlp">here</a>
to launch the demo.
</p>
<p>
When it launches, you're presented with a frame containing three <code>JList</code> components.
The larger list on the left, labelled "Drag from here" acts as a drag source for the demo,
supporting both copying and moving of its data, and advertising this via its <code>TransferHandler</code>'s
<code>getSourceActions</code> method. On the right side are two smaller lists that act as targets for drops.
The top one, labelled "Drop to COPY here", has a <code>TransferHandler</code> that always chooses
a copy action, with a <code>canImport</code> implementation exactly the same as the code snippet
I've shown above. Similarly, the bottom one, labelled "Drop to MOVE here", always chooses a move action,
with the same code, but using MOVE in place of COPY.
</p>
<p>
Go ahead and initiate a drag from the source list and drag into the upper target list. Notice while you're
dragging over the target that the use of the copy action is indicated by the copy-drop mouse cursor, which shows
a little plus sign. This can be seen in <b>Screen Shot 1</b> below. <b>Screen Shot 2</b> illustrates the
effect of dropping into this list: The dragged item is inserted into the target, but not removed from
the source - a perfect copy drop.
</p>
<center>
<table border="0">
  <tr>
    <td align="center"><b>Screen Shot 1</b></td><td width=50>&nbsp;</td><td align="center"><b>Screen Shot 2</b></td>
  </tr>
  <tr>
    <td><img src="http://weblogs.java.net/blog/shan_man/archive/2006.02.15/copy.PNG"></td>
    <td>&nbsp;</td>
    <td><img src="http://weblogs.java.net/blog/shan_man/archive/2006.02.15/copy_after.PNG"></td>
</tr>
</table>
</center>
<p></p>
<p>
Now drag again from the source list, and into the lower target list. While you're dragging over
this target, notice that the mouse cursor indicates a drag action without the plus
sign - indicating that the move action is in use (see <a href="#NOTE"><b>Note</b></a> below - a known,
and soon to be fixed, bug may cause a no-drop cursor to be shown instead).
This is shown in <b>Screen Shot 3</b> below. When you drop into this list, notice that the
dragged item is inserted, <i>and removed</i> from the source - the effect of a move drop. The result is
illustrated in <b>Screen Shot 4</b> below.
</p>
<center>
<table border="0">
  <tr>
    <td align="center"><b>Screen Shot 3</b></td><td width=50>&nbsp;</td><td align="center"><b>Screen Shot 4</b></td>
  </tr>
  <tr>
    <td><img src="http://weblogs.java.net/blog/shan_man/archive/2006.02.15/move.PNG"></td>
    <td>&nbsp;</td>
    <td><img src="http://weblogs.java.net/blog/shan_man/archive/2006.02.15/move_after.PNG"></td>
</tr>
</table>
</center>
<p></p>
<p>
For a little bit of added fun, try dragging a snippet of text from your favorite native text editor into the target
lists to see the same results. Most text editors support dragging text as both copy and move,
and the support I've discussed works for both Java and non-Java components alike!
</p>
<p>
<a name="NOTE"></a>
<b>Note:</b> Before we move on, one final note on behavior you may encounter while trying out this demo, depending on what build
you are using to run it. I've just discovered a small bug in the underlying drag and drop subsystem, such that
explicitly choosing an action other than the user action causes the no-drop mouse cursor to be shown when the drag
source is Java based. Until this bug is fixed, you'll unfortunately see the no-drop cursor instead of the
copy-drop cursor when dragging into the bottom target list. This does not affect the functionality of the demo,
or the ability to actually drop into the component. I've filed this as a high priority bug and expect to see it
fixed shortly. For your reference, the bug number is
<a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6385534" target="_blank">6385534</a>
(For Java drag source, choosing an action other than the user action shows a no-drop cursor).
</p>
<p>
Okay, so now you've learned about choosing the drop action, and the name change from <code>TransferInfo</code>
to <code>TransferSupport</code>. Recalling what I mentioned earlier about upcoming changes to API that has
already been released, you may be wondering if I've already covered it - and if a search and replace of
the term <code>TransferInfo</code> in your code will bring you up to date. Well, the answer is "it depends".
If you happen to have read my blog entry on
<a href="http://weblogs.java.net/blog/shan_man/archive/2006/01/location_sensit.html">Location-Sensitive Drag and Drop in Mustang</a>,
and have already started taking advantage of the new <code>shouldIndicate</code> method in <code>TransferHandler</code>,
to specify whether or not the drop location should be indicated by the target of a transfer, you'll need to prepare
for another small change.
</p>
<p>
You see, the line of thought that saw <code>setDropAction</code> added to <code>TransferSupport</code>,
rather than providing another overridable method to <code>TransferHandler</code> for choosing the drop action,
led to a re-evaluation of our placement of the recently added <code>shouldIndicate</code> method.
Like choosing a drop action, deciding whether or not to show the drop
location likely involves inspecting many of the same things that a developer would already be looking at in
<code>canImport</code>. With a fresh look, it now seemed silly to force the developer to override
a separate method for the purpose of changing the drop location indication. Do you see where I'm going?
</p>
<p>
<code>TransferHandler.shouldIndicate</code> has been removed and in its place a new method,
<nobr><b><code>setShowDropLocation(boolean)</code></b></nobr>, has been added to <code>TransferSupport</code>. This new method is to be called
from <code>TransferHandler.canImport</code> any time the developer wishes to change the default
displayability of the drop location. Let's look at an example of how this simplifies things by contrasting
the code for a <code>TransferHandler</code> under the old API and the new API. Consider a <code>TransferHandler</code>
implemented to accept drops into a <code>JList</code> only when the data is a <code>String</code> and the
drop location is on top of items 0 through 5. Furthermore, let's say that it also wishes to always indicate the drop
location, regardless of whether or not it accepts the transfer. Here's the code with the old API:
</p>
<p>
<blockquote><code><pre style="border: 1px solid darkgray; padding: 4px; color: darkblue;">
public boolean canImport(TransferInfo info) {
    // for the demo, we'll only support drops (not clipboard paste)
    if (!info.isDrop()) {
        return false;
    }

    // we only import Strings
    if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
        return false;
    }

    // fetch the drop location (it's a JList.DropLocation for JList)
    JList.DropLocation dl = (JList.DropLocation)info.getDropLocation();

    // return true for index 0 through 5, and false otherwise
    return (dl.getIndex() >= 0 && dl.getIndex() <= 5) {
}

public boolean shouldIndicate(TransferInfo info, boolean canImport) {
    // always show the drop location
    return true;
}
</pre></code></blockquote>
</p>
<p>
It's not too bad in this case, but remember that in reality <code>shouldIndicate</code> and <code>canImport</code>
will likely have more in common, such as conditionalizing on the drop location or the data flavors available.
This makes the following new approach much more appealing:
</p>
<p>
<blockquote><code><pre style="border: 1px solid darkgray; padding: 4px; color: darkblue;">
public boolean canImport(TransferSupport support) {
    // for the demo, we'll only support drops (not clipboard paste)
    if (!support.isDrop()) {
        return false;
    }

    // always show the drop location
    support.setShowDropLocation(true);

    // we only import Strings
    if (!support.isDataFlavorSupported(DataFlavor.stringFlavor)) {
        return false;
    }

    // fetch the drop location (it's a JList.DropLocation for JList)
    JList.DropLocation dl = (JList.DropLocation)support.getDropLocation();

    // return true for index 0 through, 5 and false otherwise
    return (dl.getIndex() >= 0 && dl.getIndex() <= 5) {
}
</pre></code></blockquote>
</p>
<p>
Simplicity - removing an override and keeping associated logic together. I like it and I like it a lot!
One of the benefits to regular blogging about ongoing Java SE development is that it keeps me
constantly re-evaluating and using our new features. Hopefully, it also keeps you excited,
so you can help do the same. The end result being a more feature-complete, bug free API.
And of course, the best release in history.
</p>
<hr width="200" align="left">
<p>
For your reference, the updated <code>TransferSupport</code> API:
</p>
<table align="center" cellpadding="3px" style="border-collapse: collapse; border-color: darkgray; border-style: solid; border-width: 1px;">
  <tr>
    <th style="border-width: 1px; border-style: solid;">Method</th>
    <th style="border-width: 1px; border-style: solid;">Description</th>
  </tr>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>Component <nobr>getComponent()</nobr></code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">Returns the target component for the transfer.</code></td>
  </tr>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code><nobr>DataFlavor[]</nobr> <nobr>getDataFlavors()</nobr></code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">Returns the data flavors for the transfer.</td>
  </tr>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>boolean <nobr>isDataFlavorSupported(DataFlavor)</nobr></code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">Returns whether or not the given data flavor is supported.</td>
  </tr>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>Transferable <nobr>getTransferable()</nobr></code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">Returns the <code>Transferable</code> associated with the transfer.</td>
  </tr>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>boolean <nobr>isDrop()</nobr></code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">Returns whether or not the transfer represents a drop operation.</td>
  </tr>
  <tr>
    <td colspan="2" align="left" style="border-width: 1px; border-style: solid;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Note: The following methods throw <code>IllegalStateException</code> if the transfer is not a drop.</td>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code><nobr>TransferHandler.DropLocation</nobr> <nobr>getDropLocation()</nobr></code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">Returns the current drop location for the component</td>
  </tr>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>void <nobr>setShowDropLocation(boolean)</nobr></code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">Sets whether or not the drop location should be visually indicated for the transfer.</td>
  </tr>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>int <nobr>getUserDropAction()</nobr></code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">Returns the user action for the drop.</td>
  </tr>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>int <nobr>getSourceDropActions()</nobr></code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">Returns the drag source's supported actions.</td>
  </tr>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>int <nobr>getDropAction()</nobr></code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">Returns the action chosen for the drop (the user action unless explicitly set).</td>
  </tr>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>void <nobr>setDropAction(int)</nobr></code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">Sets the drop action for the transfer to the given action. Throws <code>IllegalArgumentException</code> if the action isn't supported.</td>
  </tr>
</table>]]>

</content>
</entry>
<entry>
<title>Enable Dropping into Empty JTables</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/shan_man/archive/2006/01/enable_dropping.html" />
<modified>2006-11-22T18:49:20Z</modified>
<issued>2006-01-19T21:46:24Z</issued>
<id>tag:weblogs.java.net,2006:/blog/shan_man/255.3975</id>
<created>2006-01-19T21:46:24Z</created>
<summary type="text/plain">Shannon Hickey shows how to enable dropping into empty JTables with a single method call in Mustang, or a simple override in earlier versions of J2SE.</summary>
<author>
<name>shan_man</name>

<email>Shannon.Hickey@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/shan_man/">
<![CDATA[<p>
So you've created an empty <code>JTable</code>, you've given it a <code>TransferHandler</code> to accept drops,
and you've added it to a <code>JScrollPane</code>. But when you launch your application and drag some completely valid
data into the table, it rejects you! I'm not kidding; go ahead and try it yourself with this <a href="http://www.java.net/download/javadesktop/blogs/shan_man/2006.01.19/FillViewportHeightDemo.jnlp">demo</a>
(requires build 76 or greater of <a href="http://mustang.dev.java.net/" target="_blank">Mustang</a>). Drag from the component
labelled "Drag from here" into the <code>JTable</code>, and you'll see the following:
</p>
<center>
<p>
<img src="http://weblogs.java.net/blog/shan_man/archive/2006.01.19/unfilled_empty.PNG">
</p>
</center>
<p>
What's going on? <i>Without</i> peeking at the demo's "Options" menu (which would likely give it away), can you
figure it out? How about a hint: The background color of a <code>JTable</code> in the Ocean Look and Feel
is supposed to be white. In this demo, I haven't changed it, and yet you aren't seeing that white color. Perhaps
there's a connection...Are you ready for a second hint? Using the demo, double click a couple of times on the
drag source to have some rows added to the table. Now try dragging again and you'll see that this time you
can indeed drop into the table. <b>But</b>, the drop line is only shown when the mouse is over an existing row; if
you drag <i>below</i> the existing rows, you'll see something like the following:
</p>
<center>
<p>
<img src="http://weblogs.java.net/blog/shan_man/archive/2006.01.19/unfilled_two_rows.PNG">
</p>
</center>
<p>
After seeing this, have you yet started to wonder if maybe that gray "no-drop" area is not actually a part of the table?
If so, you've figured out what's going on! You see, unlike <code>JList</code> and <code>JTree</code>, for some reason
<code>JTable</code> is not implemented to be automatically stretched to fill the height of a <code>JScrollPane</code>'s viewport;
it only takes up as much vertical room as needed for the rows that it contains. As such, when you're dragging
over that gray area, you're actually not over the table. This issue has been known for some time under
bug number <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4310721" target="_blank">4310721</a>
(JTable is not stretched to fill a viewport's height). Let's have a look at how this has been resolved in Mustang,
and how you can easily work around it in earlier releases.
</p>
<p>
The behavior of a component in this capacity is controlled by the component's implementation
of the <code>getScrollableTracksViewportHeight</code> method, declared in the <code>Scrollable</code> interface.
This method tells the viewport whether or not it should force the height of the contained component to
match the height of the viewport. <code>JList</code> and <code>JTree</code>, which implement <code>Scrollable</code>,
do something intelligent in this method and tell the viewport that they want to be stretched any time their preferred
height is smaller than the viewport height. <code>JTable</code> on the other hand, prior to Mustang,
always returns <code>false</code>.
</p>
<p>
Determining this to be something that developers often want to change,
we've made it easier to do so in Mustang; it is now very simple to configure <code>JTable</code> to
act like the other two components in this regard. Striving to maintain backward compatibility and
to not break the previous clearly specified behavior (however poor), we've added a new property to <code>JTable</code>
to enable solving this problem: "fillsViewportHeight". By default the property is <code>false</code>,
so that <code>JTable</code> acts exactly as it did previously. By setting the property to <code>true</code>,
with the method <nobr><b><code>JTable.setFillsViewportHeight(boolean)</code></b></nobr>, <code>JTable</code> behaves
like lists and trees and is stretched to fill the viewport height when appropriate.
</p>
<p>
Using the demo again, let's see what this looks like. If you've closed the demo, please launch it
<a href="http://www.java.net/download/javadesktop/blogs/shan_man/2006.01.19/FillViewportHeightDemo.jnlp">again</a>. If you still have it running, please select the "Reset"
item from the "Options" menu to reset the state. In the demo, the new "fillsViewportHeight" property can
be changed via the "Fill Viewport Height" item in the "Options" menu. Please enable this option now. As you'll
see, and as indicated in the following screen shots, the table is now stretched to fill the viewport. This
results in two positive things: 1) The white background is now visible; 2) You can now drop anywhere within the viewport.
</p>
<center>
<table border="0">
  <tr>
    <td><img src="http://weblogs.java.net/blog/shan_man/archive/2006.01.19/filled_empty.PNG"></td>
    <td width=50>&nbsp;</td>
    <td><img src="http://weblogs.java.net/blog/shan_man/archive/2006.01.19/filled_two_rows.PNG"></td>
</tr>
</table>
</center>
<p></p>
<p>
Incidentally, since it's already apparent in the demo and screen shots, let me quickly draw your attention to
the solid line indicating the drop location in the <code>JTable</code>. This is also new in Mustang, and the result of using
<code>JTable</code> in the <code>INSERT_ROWS</code> drop mode, a subject which I began talking about in my earlier
<a href="http://weblogs.java.net/blog/shan_man/archive/2006/01/first_class_dra.html">blog entry</a>. There's
actually a lot more to say about the new drop modes with respect to <code>JTable</code>, and for that reason
I'll leave further discussion on the subject to a future blog entry.
</p>
<p>
For now, let's conclude with me fulfilling my promise of demonstrating how to make <code>JTable</code> stretch to
fill the viewport in pre-Mustang releases. It's extremely simple, with a variation of the following override in a
<code>JTable</code> subclass being all that is needed :
</p>
<p>
<blockquote><code><pre style="border: 1px solid darkgray; padding: 4px; color: darkblue;">
public boolean getScrollableTracksViewportHeight() {
    // fetch the table's parent
    Container viewport = getParent();

    // if the parent is not a viewport, calling this isn't useful
    if (!viewport instanceof JViewport) {
        return false;
    }

    // return true if the table's preferred height is smaller
    // than the viewport height, else false
    return getPreferredSize().height < viewport.getHeight();
}
</pre></code></blockquote>
</p>
<p>
With this code you'll acheive identical results to turning the new property on in Mustang. And there's no need
to wait since it's most likely the behavior you want, is extremely easy, and will not interfere when you upgrade
in the future. That's the best kind of work-around in my opinion!
</p>
<p>
That's all I have for today, but please stay tuned.
I'm finding it extremely rewarding to communicate with you via this blog and I'm on a roll, with the words just flowing.
Potential upcoming topics include the new drop modes as they pertain to JTable, and fancy customization of drop mode
indication in <code>JTree</code> - something that was a big hit, and received audience applause at the last JavaOne conference.
In fact, I may just have to write that one first, as I'm getting quite excited about it. Until next time, take care!
</p>]]>

</content>
</entry>
<entry>
<title>Location-Sensitive Drag and Drop in Mustang</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/shan_man/archive/2006/01/location_sensit.html" />
<modified>2006-11-22T19:25:46Z</modified>
<issued>2006-01-17T20:19:32Z</issued>
<id>tag:weblogs.java.net,2006:/blog/shan_man/255.3958</id>
<created>2006-01-17T20:19:32Z</created>
<summary type="text/plain">Prompted by a question on his recent Swing Drag and Drop blog entry, Shannon Hickey talks about location-sensitive Drag and Drop in Mustang.</summary>
<author>
<name>shan_man</name>

<email>Shannon.Hickey@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/shan_man/">
<![CDATA[<p>
Hello again friends!
</p>
<p>
Prompted by an excellent question from <b>wrandelshofer</b> in the comments section of my recent
Swing Drag and Drop
<a href="http://weblogs.java.net/blog/shan_man/archive/2006/01/first_class_dra.html">blog entry</a>,
I'm jumping on the opportunity to tell you more about the enhancements made in Mustang. In particular,
I'd like to talk about how these changes have enabled location-sensitive Drag and Drop.
</p>
<p>
In order to clarify the concept, I'll paraphrase the question that
I've just referred to: <i>Is it possible to allow the user to drop into some locations of a JTree and not others, and have Swing indicate this by only showing the drop location when the mouse is over acceptable
drop locations?</i> The answer is a resounding YES; this is the default behavior in Mustang!
Let's take a look at how this has been enabled.
</p>
<p>
Prior to Mustang, developers could not implement this very important behavior due to oversights in the
Swing implementation. The first problem, as I discussed in my previous blog entry, was that the drop location
wasn't easily available to the <code>TransferHandler</code> during a drag operation. The astute developer could
often overcome this limitation, however, after discovering that Swing changed the selection instead.
But it was actually a second more subtle and hidden problem in the implementation that was the limiting factor:
a problem with when <code>TransferHandler</code> called the <code>canImport</code> method. As you know,
the <code>canImport</code> method gives you control over whether or not a component should
accept a particular drag operation. Prior to Mustang, though, <code>canImport</code> was only called when
a drag operation entered a component, and the returned value was then used for the duration of the mouse's visit
to that component. This gave the developer absolutely no mechanism to return different values based
on the drop location, or any other factors that might change throughout the operation.
</p>
<p>
Enter Mustang! With the recent enhancements made to Swing Drag and Drop, <code>canImport</code> is
now called <i>continuously</i> by a component's <code>TransferHandler</code> while a drag and drop
operation is occuring over it. As such, the acceptability of a transfer can change as many
times, and based on whatever criteria (including the drop location), you choose. You need only
return a different value from <code>canImport</code> and Swing will respond. I'll elaborate on
what that response is. When <code>canImport</code> returns <code>true</code> to accept a transfer,
Swing shows the normal drag and drop mouse cursor and visually indicates the drop location, as discussed
in my previous blog entry. When <code>canImport</code> rejects a drag, on the other hand,
the "no-drag" mouse cursor is shown and no drop location is indicated. Let's see this in action -
click <a href="http://www.java.net/download/javadesktop/blogs/shan_man/2006.01.17/LocationSensitiveTreeDnDDemo.jnlp">here</a> to launch a Java Webstart demo
(requires build 76 or greater of <a href="http://mustang.dev.java.net/" target="_blank">Mustang</a>).
</p>
<p>
Below you'll see two screen shots of how the demo appears. At the very
top is a drag source, with the label "Drag from here:". You'll use this component to initiate
drags when playing with the demo. The middle component is a <code>JTree</code> that's been
configured to accept drops <i>on any node except for "names" and its descendants</i>.
At the bottom is a <code>JComboBox</code> that we'll talk about a bit later, when I introduce
another new method in Mustang to allow further customization of when drop locations
are shown. For now, simply note that it is set to "Default", meaning that nothing has been changed
from the default behavior of showing drop locations when accepted, and not showing them when
rejected.
</p>
<p>
Initiate a drag by pressing on top of the drag source and dragging the mouse a short distance.
Drag into the tree and start moving down on top of the nodes. As you hover the mouse over
most of the nodes, the drag acceptibility is indicated by both the mouse cursor and by
the node becoming highlighted. This is portrayed in <b>Screen Shot 1</b>, which shows
an acceptable drag over the "yellow" node. Likewise, <b>Screen Shot 2</b> shows what
happens when you drag over the "names" node or any descendant, which I've mentioned have
been configured to reject the drag. The "no-drop" cursor is shown, and the drop location isn't indicated.
</p>
<center>
<table border="0">
  <tr>
    <td align="center"><b>Screen Shot 1</b></td><td width=50>&nbsp;</td><td align="center"><b>Screen Shot 2</b></td>
  </tr>
  <tr>
    <td><img src="http://weblogs.java.net/blog/shan_man/archive/2006.01.17/default_yellow.PNG"></td>
    <td>&nbsp;</td>
    <td><img src="http://weblogs.java.net/blog/shan_man/archive/2006.01.17/default_men.PNG"></td>
</tr>
</table>
</center>
<p></p>
<p>
Here's the implementation of <code>canImport</code> from the demo, showing how
drops on top of "names" and descendants has been prevented:
</p>
<p>
<blockquote>
<hr>
<b>Important Note</b>: This blog was published before finalization of the Swing drag and drop API for Java SE 6.
As such, there have since been minor modifications.
In particular, <code>TransferInfo</code>, as shown in the following code snippet, has been renamed to <code>TransferSupport</code>.
For full details on these changes, please see my later blog entitled
<a href="http://weblogs.java.net/blog/shan_man/archive/2006/02/choosing_the_dr.html">Choosing the Drop Action, and Further Changes to Swing Drag and Drop<a>.
<hr>
</blockquote>
</p>
<p>
<blockquote><code><pre style="border: 1px solid darkgray; padding: 4px; color: darkblue;">
public boolean canImport(TransferHandler.TransferInfo info) {
    // for the demo, we'll only support drops (not clipboard paste)
    if (!info.isDrop()) {
        return false;
    }

    // we only support importing Strings
    if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
        return false;
    }

    // fetch the drop location (it's a JTree.DropLocation for JTree)
    JTree.DropLocation dl = (JTree.DropLocation)info.getDropLocation();

    // fetch the path from the drop location
    TreePath dropPath = dl.getPath();

    // we'll reject invalid paths, and descendants of the "names" node
    if (dropPath == null || NAMESPATH.isDescendant(dropPath)) {
        return false;
    }

    return true;
}
</pre></code></blockquote>
</p>
<p>
So what if you want to change an aspect of this behavior from the default?
What if you want to <i>always</i> show the potential drop location,
regardless of the acceptability of the transfer, so that the user can
see what item they're hovering over? Or say for some reason you prefer <i>not</i>
to indicate the drop location for some items, even though you want to accept the
transfer itself?
</p>
<p>
<blockquote>
<hr>
<b>Important Note</b>: This blog was published before finalization of the Swing drag and drop API for Java SE 6.
As such, there have since been minor modifications.
In particular, <code>shouldIndicate</code>, as mentioned in the remainder of this document, has been removed in favor
of a new <code>setShowDropLocation</code> method on <code>TransferSupport</code>. For full details on these changes,
please see my later blog entitled
<a href="http://weblogs.java.net/blog/shan_man/archive/2006/02/choosing_the_dr.html">Choosing the Drop Action, and Further Changes to Swing Drag and Drop<a>.
<hr>
</blockquote>
</p>
<p>
<code>TransferHandler</code> now calls a new method, allowing you to
control this too:
</p>
<p>
<nobr><b><code>boolean shouldIndicate(TransferInfo info, boolean canImport)</code></b></nobr>
</p>
<p>
This method returns whether or not the drop location should be indicated for the
given transfer, and is called after the <code>canImport</code> method.
The arguments are the <code>TransferInfo</code> for the transfer in question,
and the return value from the preceding call to <code>canImport</code>.
The default implementation simply returns the value of the <code>canImport</code>
argument, causing the drop location to be shown if and only if the
<code>TransferHandler</code> has already said that it can accept the
import; the behavior that I've described above. By simply overriding this
method, you can customize the drop location indication as it works for your application.
For example, the following simple override will cause the drop location to always
be shown, even if the <code>canImport</code> method rejects the transfer:
</p>
<p>
<blockquote><code><pre style="border: 1px solid darkgray; padding: 4px; color: darkblue;">
public boolean shouldIndicate(TransferInfo info, boolean canImport) {
    return true;
}
</pre></code></blockquote>
</p>
<p>
Likewise, returning <code>false</code> causes the drop location to never be shown.
Of course, the implementation can be more involved, possibly inspecting the
<code>TransferInfo</code>, depending on how specific your logic needs to be.
An important thing to note is that this method is designed specifically
for configuring the drop location indication, and it does not
affect how the mouse cursor appears. The mouse cursor needs to tell the user
whether or not the drag is acceptable and, as such, needs to stay true
to the return value of <code>canImport</code>. Let's have a look at this
in practice, by bringing up the <a href="http://www.java.net/download/javadesktop/blogs/shan_man/2006.01.17/LocationSensitiveTreeDnDDemo.jnlp">demo</a> again.
</p>
<p>
This time we will play with the <code>JComboBox</code> at the bottom, which has
been set up to dictate how <code>shouldIndicate</code> will return. Switch
the option to "Always" to have <code>shouldIndicate</code> always return <code>true</code>.
Dragging over the <code>JTree</code> you'll see that the drop location is shown for
all nodes, including "names" and its descendants which won't actually accept the transfer. This
can be seen in <b>Screen Shot 3</b> below. Switching the <code>JComboBox</code> to "Never"
configures <code>shouldIndicate</code> to always return <code>false</code>. This causes
the drop location to <i>not</i> be indicated for any node, regardless of whether or not the
transfer is acceptable. <b>Screen Shot 4</b> shows this case, where the "yellow"
node is not highlighted even though the mouse cursor is showing an acceptable transfer.
</p>
<center>
<table border="0">
  <tr>
    <td align="center"><b>Screen Shot 3</b></td><td width=50>&nbsp;</td><td align="center"><b>Screen Shot 4</b></td>
  </tr>
  <tr>
    <td><img src="http://weblogs.java.net/blog/shan_man/archive/2006.01.17/always.PNG"></td>
    <td>&nbsp;</td>
    <td><img src="http://weblogs.java.net/blog/shan_man/archive/2006.01.17/never.PNG"></td>
</tr>
</table>
</center>
<p></p>
<p>
Pretty neat! Location-sensitive Drag and Drop for Swing, new in Mustang. I encourage you to keep those questions
and comments coming. You may just prompt my next blog entry! All the best :)
</p>]]>

</content>
</entry>
<entry>
<title>toto, The Francophone foo</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/shan_man/archive/2006/01/toto_the_franco.html" />
<modified>2006-06-09T00:45:50Z</modified>
<issued>2006-01-16T16:22:40Z</issued>
<id>tag:weblogs.java.net,2006:/blog/shan_man/255.3948</id>
<created>2006-01-16T16:22:40Z</created>
<summary type="text/plain">Where Shannon Hickey learns about metasyntactic variables in other languages, during a recent trip to Montreal, Canada.</summary>
<author>
<name>shan_man</name>

<email>Shannon.Hickey@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/shan_man/">
<![CDATA[<p>
<i>Do the toto!</i>
</p>
<p>
Shortly before the holidays, I had the opportunity to visit a customer site in the
wonderful city of Montreal, Canada. I was an eater of excellent food, a seer of
new sites, and a lucky fan at <a href="http://www.centrebell.ca/" target="_blank">Centre Bell</a>
when the <a href="http://www.canadiens.com/" target="_blank">Montreal Canadians</a> won their first
overtime shootout under the new NHL rules! And that was just in the off hours. I also
truly enjoyed myself during the day in the company of the folks whom I met,
who, by the way, are all very savvy and are doing powerful things with Java and Swing.
I thank them for their friendly hospitality, for switching to English during my visit,
and for encouraging my multiple attempts at expanding my French vocabulary
(<i>Je voudrais des frites, s'il vous plait</i>). I also thank them for introducing me
to <b>toto</b>. The introduction went something like this:
</p>
<p>
We were sitting in a conference room, where it was my turn at the whiteboard to demonstrate
code snippets. So I began: <i><code>boolean foo = ...</code></i> And then
I stopped, for suddenly (and I don't what prompted it) I was unsure if they'd ever met
<b>foo</b>. Feeling it was important to know before continuing, I asked them straight out.
Gesturing over my shoulders with both hands towards the board, I asked them: "Do you foo?"
Well I assume they took my gestures out of context, for the next few seconds were
extremely comical. I watched as they looked at each other, and some non-verbal communication
passsed between them. Then, looking back at me akwardly, they slowly pushed back their chairs
and rose. Beginning a cute little dance, they responded in the negative: "Non...nous ne foo pas. But we toto!"
</p>
<p>
Alright, okay, so the true story is a lot less entertaining. In actuality, I did ask about the
use of <b>foo</b> in French programming and, in fact, these gentlemen had not seen it before.
But, being that these were smart guys, they deduced exactly what it represented.
And that's how it came about that they introduced me to <b>foo's</b> French counterpart
<b>toto</b>. You see, where we'd normally talk using "foo", "bar" or "baz"
in English, as a proper francophone you should correctly use the French "toto", "titi" or "tata".
And while I personally couldn't get Dorothy's little
<a href="http://en.wikipedia.org/wiki/Toto_%28dog%29" target="_blank">puppy</a> out of my head for the first
hour, I eventually became very comfortable with this. Due to their pattern that has you alternating
hands between letters (LEFT: <b>t</b> - RIGHT: <b>o</b> - LEFT: <b>t</b> - RIGHT: <b>o</b>), some of these little guys are exceptionally easy to
type - and can be entered even faster than the three-letter <b>foo</b>! Give it a try.
</p>
<p>
But what about the words themselves? Is "toto" as steeped in culture as the English "foo"? Is "titi" a direct
translation of our "bar", the place where programmers rejuvinate on coffee between late-night coding sessions?
And what about "tata", a word I've actually used myself when speaking with my two-year-old sons; as in
"tata honey, please give Daddy back the digital camera that you're not supposed to be playing with."
Well it turns out that these words are designed to have no inherent meaning at all when we use them to talk
about computer systems. With a little googling, I've discovered that all of these words, English and French alike,
belong to a group with the easy-to-remember name of <b>metasyntactic variables</b>. They are so-called,
according to <a href="http://en.wikipedia.org/wiki/Metasyntactic_variable" target="_blank">Wikipedia</a> and
<a href="http://www.catb.org/~esr/jargon/html/M/metasyntactic-variable.html" target="_blank">The Jargon File</a>,
because (a) "They are variables in the metalanguage used to talk about programs, etc." and (b)
"They are variables whose values are often variables (as in usages like 'the value of f(foo, bar) is the sum of foo and bar')."
</p>
<p>
Nifty - so someone's named some of the nonsense that we programmers instinctively understand!
But what I find particularly interesting, since I'd never considered it before, is that the implementation
of the concept varies across cultures and languages. Again reading from
<a href="http://en.wikipedia.org/wiki/Metasyntactic_variable#Other_languages" target="_blank">Wikipedia</a>,
I've learned that when programming in Estonia you may need to refer to the "<b>kalatehas</b> (fish factory)" or maybe
"<b>oxe</b> (misspelled vomit)". And in Italy, according to
<a href="http://www.catb.org/~esr/jargon/html/M/metasyntactic-variable.html" target="_blank">The Jargon File</a>,
be prepared to be introduced to "<b>pippo</b> (Goofy)" and "<b>paperino</b> (Donald Duck)".
</p>
<p>
Cool! By happening to discover the non-universality of <b>foo</b>, I met his francophone twin <b>toto</b>,
became more cultured, and learned about a universal concept. I'd say my visit to Montreal was quite succesful!
</p>]]>

</content>
</entry>
<entry>
<title>First Class Drag and Drop Support in Mustang</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/shan_man/archive/2006/01/first_class_dra.html" />
<modified>2006-11-22T19:14:31Z</modified>
<issued>2006-01-02T23:41:26Z</issued>
<id>tag:weblogs.java.net,2006:/blog/shan_man/255.3873</id>
<created>2006-01-02T23:41:26Z</created>
<summary type="text/plain">Shannon Hickey introduces major enhancements to Swing Drag and Drop in Mustang, and also recounts his recent once-in-a-lifetime visit to Saint Petersburg, Russia, with pictures from the trip.</summary>
<author>
<name>shan_man</name>

<email>Shannon.Hickey@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/shan_man/">
<![CDATA[<p>
<i>Many Thanks!</i>
</p>
<p>
An expression that my friend and Swing Team colleague in Russia, Michael Knyazev, offers to me;
and one I'd like to extend to you now. It's been seven months since <a href="http://weblogs.java.net/blog/shan_man/archive/2005/06/improved_drag_g.html">my first blog</a>,
with it's goofy play on words, discussion of Swing's improved drag gesture, and my promise that
I'd write about more exciting Drag and Drop enhancements shortly. Seven months is slightly longer than I
intended, and I sincerely apologize for the delay in fulfilling my promise. Even more
importantly, I'd like to offer Many Thanks, for both your patience and your visit here today.
</p>
<p>
In this blog entry I'll introduce some major enhancements that make Swing Drag and Drop
much more powerful, flexible, and easy to use: a first class citizen in Mustang!
The discussion will include a Java Web Start demo displaying this
power in the context of <code>JTree</code>, and source code showing how, with a single
method call, you can finally configure <code>JTree</code> to accept drops between nodes. But
first, to help excuse the seven month delay with some finesse (and yet delay a little
longer), I'll quickly tell you what I've been up to for the last little while.
</p>
<p>
There's been lots of bug fixing and code reviewing, as we work the release into top shape
for beta. I've also been working hard along with my team on implementing and refining
major <a href="http://java.sun.com/developer/technicalArticles/J2SE/Desktop/mustang/" target="_blank">features</a>
for the Mustang release. I travelled to California in September to engage
in early Dolphin planning sessions with my team. And most incredible, I had the opportunity
to visit our team members in Saint Petersburg, Russia. Wow - what an amazing experience!
Our colleagues were outstanding hosts, and their city is very beautiful. I've included a
few thumbnail pictures below, that you can mouse-over for descriptions, and click for full versions:
</p>
<center>
<p>
<a href="http://weblogs.java.net/blog/shan_man/archive/2006.01.02/moika.JPG"><img src="http://weblogs.java.net/blog/shan_man/archive/2006.01.02/tn_moika.PNG" border="none" alt="Buildings along the Moika canal"></a>
<a href="http://weblogs.java.net/blog/shan_man/archive/2006.01.02/moika_night.JPG"><img src="http://weblogs.java.net/blog/shan_man/archive/2006.01.02/tn_moika_night.PNG" border="none" alt="Buildings along the Moika canal at night"></a>
<a href="http://weblogs.java.net/blog/shan_man/archive/2006.01.02/spilled.JPG"><img src="http://weblogs.java.net/blog/shan_man/archive/2006.01.02/tn_spilled.PNG" border="none" alt="Griboedov channel and &quot;Savior on Spilled Blood&quot; Cathedral"></a>
<a href="http://weblogs.java.net/blog/shan_man/archive/2006.01.02/spilled_night.JPG"><img src="http://weblogs.java.net/blog/shan_man/archive/2006.01.02/tn_spilled_night.PNG" border="none" alt="Griboedov channel and &quot;Savior on Spilled Blood&quot; Cathedral at night"></a>
<a href="http://weblogs.java.net/blog/shan_man/archive/2006.01.02/isaacs.JPG"><img src="http://weblogs.java.net/blog/shan_man/archive/2006.01.02/tn_isaacs.PNG" border="none" alt="Saint Isaac's Cathedral"></a>
<a href="http://weblogs.java.net/blog/shan_man/archive/2006.01.02/top_isaacs.JPG"><img src="http://weblogs.java.net/blog/shan_man/archive/2006.01.02/tn_top_isaacs.PNG" border="none" alt="View from the top of Saint Isaac's Cathedral. Peter and Paul fortress in the background, across the Neva River. Hermitage Museum is the green building to the right."></a>
<a href="http://weblogs.java.net/blog/shan_man/archive/2006.01.02/on_canal.JPG"><img src="http://weblogs.java.net/blog/shan_man/archive/2006.01.02/tn_on_canal.PNG" border="none" alt="A bridge over the Fontanka river"></a>
</p>
</center>
<p>
The things I'll remember most about my trip are the wonderful people,
the beautiful architecture, Russian pancakes (Blinis) with strawberry jam, refining humor with
<a href="http://weblogs.java.net/blog/chet/archive/2005/10/two_items_walk.html" target="_blank">Chet Haase</a>,
and the fact that there's smoking everywhere - which was just fine, since I enjoy the occasional
<a href="http://weblogs.java.net/blog/shan_man/archive/2006.01.02/smoke_hermitage.jpg">cigarette myself</a>. It was an experience I'll remember forever,
and I give Many Thanks to our Russian colleagues for making it so.
</p>
<p>
With that, let's continue on to the fun technical stuff. There are two themes addressed
by our Mustang Drag and Drop feature. The first is the ability to tell a component how to
determine drop locations, and to easily and consistently query said locations.
The second is for Swing to provide <i>all relevant</i> information on a transfer when
asking the <code>TransferHandler</code> if it is acceptable, and when telling it to import
data. Together, the enhancements made under these themes open up many doors for Swing Drag and Drop users.
</p>
<p>
The first theme has a single associated bug number,
<a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4468566" target="_blank">4468566</a>,
with a synopsis (Swing DnD should not use selection to show drop location) that very clearly
states the issue to be solved. Since the initial implementation of Swing Drag and Drop,
multiple components (<code>JTree</code>, <code>JTable</code>, <code>JList</code>,
<code>JTextComponent</code>s) have been capable of visually displaying a drop location during a
Drag and Drop operation. Historically this has been done by determining where the mouse is in
the component, and then simply changing the component's selection temporarily to be the item
under the mouse. Likewise, for text components, the caret is moved to the location under the
mouse, temporarily clearing any selection. There is a fundamental problem with this approach
in that clearing the selection affects the user experience. After initiating a drag, the user
immediately loses the context of what data they are dragging.
</p>
<p>
Secondarily, this approach can lead to problems for developers, as they are potentially forced
to ignore selection events that are fired during Drag and Drop. They also have to deal with
the fact that there's no consistent API for fetching the drop location at drop time; and must
learn that they have to ask the component directly for it's selected item or index. Finally, and
possibly most important, the use of selection to show drop location has a very serious limitation:
One cannot drop <b>between</b> items. And so...drum roll please...
</p>
<p>
Introducing <b><code>setDropMode(DropMode)</code></b>! This is a new property on the components mentioned
above, allowing you to decide how drop locations are determined. You want
to drop on top of items - sure; you want to drop between items - no problem; you want a
combination of both - excellent, you can do it. For each of these cases there is a drop mode
that can be set on the component, and the location will be automatically calculated and displayed,
<b>without</b> affecting the component's selection! The following table lists each drop mode
constant, defined in class <code>DropMode</code>, the components that support each mode, and
what each one means:
</p>
<table align="center" cellpadding="3px" style="border-collapse: collapse; border-color: darkgray; border-style: solid; border-width: 1px;">
  <tr>
    <th style="border-width: 1px; border-style: solid;">Mode</th>
    <th style="border-width: 1px; border-style: solid;">Supported By</th>
    <th style="border-width: 1px; border-style: solid;">Description</th>
  </tr>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>ON</code></td>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>JList</code>, <code>JTree</code>, <code>JTable</code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">
    The drop location should be tracked in terms of the position of
    existing items. Useful for dropping on top of items.
    </td>
  </tr>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>INSERT</code></td>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>JList</code>, <code>JTree</code>, <code>JTable</code>, <code>JTextComponent</code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">
    The drop location should be tracked in terms of the position
    where new data should be inserted. Useful for inserting or
    re-arranging content.
    </td>
  </tr>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>ON_OR_INSERT</code></td>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>JList</code>, <code>JTree</code>, <code>JTable</code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">
    A combination of <code>ON</code>
    and <code>INSERT</code>, specifying that data can be
    dropped on top of existing items, or in insert locations
    as specified by <code>INSERT</code>.
    </td>
  </tr>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;">
    <nobr><code>[ON_OR_]INSERT_ROWS&nbsp;&nbsp;</code></nobr><br><nobr><code>[ON_OR_]INSERT_COLS&nbsp;&nbsp;</code></nobr><br>
    </td>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>JTable</code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">
    Drop modes specific to <code>JTable</code>, indicating that drop locations should be calculated
    in terms of rows or columns only.
    </td>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>USE_SELECTION</code></td>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>JList</code>, <code>JTree</code>, <code>JTable</code>, <code>JTextComponent</code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">
    The default, for backward compatibility.
    A component's own internal selection mechanism (or caret for text
    components) should be used to track the drop location.
    </td>
  </tr>
</table>
<p></p>
<p>
At this point, let's take a little break from the technical talk to play.
Because it's one of the more interesting examples, I've included a Java Web Start
enabled demo allowing me to illustrate how you can finally configure a <code>JTree</code>
to accept drops between nodes. Of course, the demo will also let you try each of the
other drop modes supported by <code>JTree</code>. <b><a href="http://www.java.net/download/javadesktop/blogs/shan_man/2006.01.02/TreeDnDDemo.jnlp">Click
here</a></b> to launch the demo (requires
build 76 or greater of Mustang to work correctly, which you can <a href="http://mustang.dev.java.net/" target="_blank">
download now</a> if you don't already have it).
</p>
<p>
<b>Screen Shot 1</b> below shows what the demo looks like when it's launched. At the very
top is a drag source, with the label "Drag from here:". You'll use this component to initiate
drags when playing with the demo. The middle component is a <code>JTree</code> that's been
configured to accept drops, and will allow you to try out the different drop modes in the context
of trees. Notice that by default, the "blue" node is selected. This allows me to demonstrate how
the new drop modes provide drag-over feedback without affecting selection.
Finally, at the bottom is a <code>JComboBox</code> used for setting different drop modes on
the <code>JTree</code>. By default it is set to <code>INSERT</code>, the subject of this discussion.
</p>
<table align="center" border="0">
  <tr>
    <td align="center"><b>Screen Shot 1</b></td>
  </tr>
  <tr>
    <td><img src="http://weblogs.java.net/blog/shan_man/archive/2006.01.02/original.png"></td>
</tr>
</table>
<p></p>
<p>
The <code>INSERT</code> mode was designed by considering exactly what you need when you want to
Drag and Drop to insert new nodes into a tree. That is, the ability to drop on top of existing non-leaf (folder)
nodes to insert a child, and the ability to drop between existing nodes to insert between
them. This is exactly what you'll see in the demo. Initiate a drag by pressing on top
of the drag source and dragging the mouse a short distance. Drag into the tree and start moving
down on top of the nodes. As you drag over folder nodes they become highlighted to indicate
that the drop can be accepted into that folder. This can be seen in <b>Screen Shot 2</b> below,
which illustrates the effect of dragging over the "names" folder node. <b>Screen Shot 3</b>
shows the effect of releasing the mouse and dropping on top of that node: a new item is inserted
as the last child of the "names" node.
</p>
<table align="center" border="0">
  <tr>
    <td align="center"><b>Screen Shot 2</b></td><td width=50>&nbsp;</td><td align="center"><b>Screen Shot 3</b></td>
  </tr>
  <tr>
    <td><img src="http://weblogs.java.net/blog/shan_man/archive/2006.01.02/on_during.png"></td>
    <td>&nbsp;</td>
    <td><img src="http://weblogs.java.net/blog/shan_man/archive/2006.01.02/on_after.png"></td>
</tr>
</table>
<p></p>
<p>
Similarly, as you drag between nodes a horizontal line is displayed to indicate that the drop can be accepted at
that location. The line shows the position and level of the tree where the new node is to be inserted.
<b>Screen Shot 4</b> illustrates this drag-over effect and <b>Screen Shot 5</b> displays the effect of
releasing the mouse at the position indicated: a new node is inserted as a child of "colors" between "red" and "yellow".
</p>
<table align="center" border="0">
  <tr>
    <td align="center"><b>Screen Shot 4</b></td><td width=50>&nbsp;</td><td align="center"><b>Screen Shot 5</b></td>
  </tr>
  <tr>
    <td><img src="http://weblogs.java.net/blog/shan_man/archive/2006.01.02/between_during.png"></td>
    <td>&nbsp;</td>
    <td><img src="http://weblogs.java.net/blog/shan_man/archive/2006.01.02/between_after.png"></td>
</tr>
</table>
<p></p>
<p>
Notice that throughout this demonstration, selection of the "blue" node is not affected at all! As mentioned previously,
all of the new drop modes show the drop location without affecting selection.
And speaking of other drop modes, you may have noticed something that you
were unable to do with the <code>INSERT</code> mode: namely, dropping on top of a <i>leaf</i> node to add a child to it,
effectively converting it to a folder node. This is certainly possible, but a job for <code>ON_OR_INSERT</code>.
The difference is that <code>ON_OR_INSERT</code> allows dropping on top of <i>any</i> node, whereas <code>INSERT</code>
only allows dropping on top of existing folders. Finally, I'd like to draw your attention to one additional ease of
use feature added for <code>JTree</code> Drag and Drop in Mustang: during a drag operation, hovering the mouse over
a collapsed folder node for two seconds causes the folder to be expanded, making it possible to drop within its list
of children.
</p>
<p>
Now that you've taken the demo for a spin and had a chance to see the power of <code>setDropMode</code>, it's time
to dive into the second theme to see how developers have been empowered to write robust drop handling code,
by making the drop location and other important information available to <code>TransferHandler</code>. As you know,
the responsibility for deciding the acceptability of drops, and for performing data import, lies with the
<code>TransferHandler</code> class. Prior to Mustang, however, some common tasks could not be accomplished
due to needed information not being available to <code>TransferHandler</code>'s drop related methods. Multiple
bugs complained about these problems:
</p>
<p>
<ul>
  <li><a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4942851" target="_blank">4942851</a>: canImport should carry Transferable in TransferHandler</li>
  <li><a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5029427" target="_blank">5029427</a>: Location sensitive dropping</li>
  <li><a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=5029432" target="_blank">5029432</a>: Provide a way of getting the action in TransferHandler.importData(...)</li>
</ul>
</p>
<p>
As described in these bug reports, it wasn't possible to customize drop handling based on the <code>Transferable</code>,
drop location, or drop action associated with a particular drop. These limitations have finally been removed in Mustang with
the addition of a new <code>TransferHandler.TransferInfo</code> inner class to encapsulate the details of every transfer. An instance of
this class is provided to new overloaded versions of <code>TransferHandler</code>'s import related methods,
<code>canImport</code> and <code>importData</code>, so that developers can now accept or reject transfers, and customize data import,
based on all information that can be provided about a transfer. As one example of what this enables, developers can now write a
<code>TransferHandler</code> to accepts drops only to particular locations in a component!
</p>
<p>
The following table outlines the API of <code>TransferInfo</code>:
</p>
<table align="center" cellpadding="3px" style="border-collapse: collapse; border-color: darkgray; border-style: solid; border-width: 1px;">
  <tr>
    <th style="border-width: 1px; border-style: solid;">Method</th>
    <th style="border-width: 1px; border-style: solid;">Description</th>
  </tr>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>Component getComponent()</code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">Returns the target component of the transfer.</code></td>
  </tr>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>DataFlavor[] getDataFlavors()</code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">Returns the data flavors for the transfer.</td>
  </tr>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>boolean isDataFlavorSupported(DataFlavor)</code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">Returns whether or not the given data flavor is supported.</td>
  </tr>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>Transferable getTransferable()</code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">Returns the <code>Transferable</code> associated with the transfer.</td>
  </tr>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>boolean isDrop()</code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">Returns whether or not the transfer represents a drop operation.</td>
  </tr>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>int getDropAction()</code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">If the transfer is a drop, returns the action chosen for the drop, otherwise returns <code>-1</code>.</td>
  </tr>
  <tr>
    <td align="left" style="border-width: 1px; border-style: solid;"><code>TransferHandler.DropLocation getDropLocation()</code></td>
    <td align="left" style="border-width: 1px; border-style: solid;">If the transfer is a drop, returns the current drop location for the component,
        otherwise returns <code>null</code>.</td>
  </tr>
</table>
<p></p>
<p>
<blockquote>
<hr>
<b>Important Note</b>: This blog was published before finalization of the Swing drag and drop API for Java SE 6.
As such, there have since been minor modifications. In particular, <code>TransferInfo</code> has been
renamed to <code>TransferSupport</code> and now benefits from additional methods. For full
details on these changes, please see my later blog entitled
<a href="http://weblogs.java.net/blog/shan_man/archive/2006/02/choosing_the_dr.html">Choosing the Drop Action, and Further Changes to Swing Drag and Drop<a>.
<hr>
</blockquote>
</p>
<p>
The last entry is particularly exciting in terms of the first Mustang theme that I discussed earlier.
<code>getDropLocation</code> allows you to query the drop location determined by the component in a consistent manner,
regardless of the component you're working with. And the really neat thing is that the return value from this method,
which is declared to be of the new type <code>TransferHandler.DropLocation</code>, is actually a more informative subtype
when <code>TransferHandler</code> is used with those components having built in drop support.
Specifically, the default <code>TransferHandler.DropLocation</code> contains the single
method <code>getDropPoint</code>, which returns the point in the component over which the operation is occurring.
But when used with <code>JTree</code>, <code>JList</code>, <code>JTable</code> or <code>JTextComponent</code>,
a subclass of <code>DropLocation</code> (<code>JTree.DropLocation</code>, <code>JList.DropLocation</code>,
<code>JTable.DropLocation</code> or <code>JTextComponent.DropLocation</code> respectively) is returned, giving
more information about the drop location in terms of the particular component type; for example, the index for
lists or text components, or the tree path for trees.
</p>
<p>
As we've been doing throughout this blog, let's again take a closer look at this aspect of the new Drag
and Drop support in the context of <code>JTree</code>. For Drag and Drop with <code>JTree</code>, the class
<code>JTree.DropLocation</code> provides details on the drop location by way of the two methods
<nobr><code>getPath</code></nobr> and <nobr><code>getChildIndex</code></nobr>. The former dictates
the path over which dropped data should be inserted. The latter indicates the index where dropped data should
be inserted with respect to the path given. Together these methods make explicit the exact location of the drop in
terms that make sense for <code>JTree</code>!
</p>
<p>
Pulling together the ideas I've discussed in this portion of the blog, I'd like to show things in practice by sharing
the source code of the <code>TransferHandler</code> I wrote for the earlier tree demo. To accomplish the import behavior
shown by the demo, only two methods require overriding. First, the new version of <code>canImport</code> which takes a
<code>TransferInfo</code>, to return the acceptability of transfers:
</p>
<p>
<blockquote><code><pre style="border: 1px solid darkgray; padding: 4px; color: darkblue;">
public boolean canImport(TransferHandler.TransferInfo info) {
    // for demo purposes, we'll only support drops and not clipboard paste
    if (!info.isDrop()) {
        return false;
    }

    // we only support importing Strings
    if (!info.isDataFlavorSupported(DataFlavor.stringFlavor)) {
        return false;
    }

    // fetch the drop location (it's a JTree.DropLocation for JTree)
    JTree.DropLocation dl = (JTree.DropLocation)info.getDropLocation();

    // we only support drops for valid paths in the tree
    return dl.getPath() != null;
}
</pre></code></blockquote>
</p>
<p>
Extremely simple! We accept imports of Strings, only for valid drop locations, and that's it.
Note the use of <code>isDataFlavorSupported</code> for determining whether or not the <code>String</code>
flavor is available. This is much simpler than looping through all of the available flavors to look for the
<code>String</code> flavor - the only available approach prior to Mustang.
</p>
<p>
The second method of interest, with an implementation almost as simple as <code>canImport</code>, is
the new version of <code>importData</code>, responsible for handling data import:
</p>
<p>
<blockquote><code><pre style="border: 1px solid darkgray; padding: 4px; color: darkblue;">
public boolean importData(TransferHandler.TransferInfo info) {
    // if we can't handle the import, return so
    if (!canImport(info)) {
        return false;
    }

    // fetch the drop location (it's a JTree.DropLocation for JTree)
    JTree.DropLocation dl = (JTree.DropLocation)info.getDropLocation();

    // fetch the path and child index from the drop location
    TreePath path = dl.getPath();
    int childIndex = dl.getChildIndex();

    // fetch the Transferable
    Transferable trans = info.getTransferable();

    // fetch the data, and bail if it fails
    String data;
    try {
        data = (String)trans.getTransferData(DataFlavor.stringFlavor);
    } catch (UnsupportedFlavorException e) {
        return false;
    } catch (IOException e) {
        return false;
    }

    // if the child index is -1, the drop was directly on top of the path,
    // which we'll treat as inserting at the end of the path's child list
    if (childIndex == -1) {
        childIndex = treeModel.getChildCount(path.getLastPathComponent());
    }

    // create a new node to represent the data and insert it into the model
    DefaultMutableTreeNode newNode = new DefaultMutableTreeNode(data);
    DefaultMutableTreeNode parentNode =
        (DefaultMutableTreeNode)path.getLastPathComponent();
    treeModel.insertNodeInto(newNode, parentNode, childIndex);

    // expand and scroll so that the new node is visible
    TreePath newPath = path.pathByAddingChild(newNode);
    tree.makeVisible(newPath);
    tree.scrollRectToVisible(tree.getPathBounds(newPath));

    // return success
    return true;
}
</pre></code></blockquote>
</p>
<p>
That's it - the full <code>TransferHandler</code> source for accepting Drag and Drop inserts into a <code>JTree</code>.
Again, it's extremely simple with the additions made in Mustang. I believe you'll find this to be the case
with Mustang Drag and Drop in general - it's been made easier to use, barriers have been eliminated, and new functionality
has been made possible. As you can tell, I'm rather excited about this and have lots of information to share on the subject.
In fact, I have enough for at least three more blog entries. Which is to say that, although I'm about to conclude this
particular lengthy discussion, I think you'll be hearing from me again "shortly", and this time a lot sooner than seven months.
</p>
<p>
Until then, all the best to you. Oh, and one last time - Many Thanks!
</p>]]>

</content>
</entry>
<entry>
<title>Improved Drag Gesture in Swing</title>
<link rel="alternate" type="text/html" href="http://weblogs.java.net/blog/shan_man/archive/2005/06/improved_drag_g.html" />
<modified>2008-01-02T17:42:16Z</modified>
<issued>2005-06-07T20:22:14Z</issued>
<id>tag:weblogs.java.net,2005:/blog/shan_man/255.2550</id>
<created>2005-06-07T20:22:14Z</created>
<summary type="text/plain">Shannon Hickey marks the occasion of his first step into the blogging world by announcing the exciting release of improved Swing drag gesture recognition, one of the most highly requested J2SE bug fixes.</summary>
<author>
<name>shan_man</name>

<email>Shannon.Hickey@Sun.COM</email>
</author>
<dc:subject>Swing</dc:subject>
<content type="text/html" mode="escaped" xml:lang="en" xml:base="http://weblogs.java.net/blog/shan_man/">
<![CDATA[<p>
<i>One small step for Shan, one exciting leap for Swing drag and drop.</i>

<p>
Fantastic! The java.net folks kindly set me up a place to share my thoughts,
I sit down and begin typing, and out comes a play on the monumental
<a href="http://www.answers.com/neil%20armstrong">Neil Armstrong</a> quote.
I consider: "Why would I start my blog space with a goofy play on
words, appearing to compare Swing drag and drop to humankind landing on the moon?" Well,
the answer is twofold: First, as a software engineer, my mind often travels into
odd or complex places, and seems to stick there for extended periods of time
(like the months I disappeared into fixing the drag and drop bug which I'm about
to tell you about). Driving to work this morning, thinking about how to start off this
blog that I've been planning for some time, in popped the "One small step..." jingle.
As I've just described, I got stuck on it. Although I got a kick out of my own [not so]
wittiness, I realized it was rather cheezy. So I tried playing a game with myself to pass the
commute - if I could forget about it by the time I arrived at work, I'd find something else
to start with. You know how successful trying to forget about something can be...

<p>
But the more important reason I started as I did is that it perfectly summarizes this morning
for me. I'm taking my very first step into the world of blogging, and to mark the occasion
I'm announcing a very exciting bug fix to Swing drag and drop. While I wouldn't even think
to seriously compare this to landing on the moon, I know it will mean the world to a rather
large group of Swing drag and drop users.

<p>
Until very recently, the sixth highest vote getter on Sun's list of
<a href="http://bugs.sun.com/bugdatabase/top25_bugs.do">Top 25 Bugs</a> was bug
<a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4521075">4521075</a> with a
total of <b>239</b> votes. This bug reports that the recognition of a drag gesture
in Swing is unlike what is typically expected by users. More specifically, it complains
that Swing requires an item to first be selected with one mouse click,
before pressing on it again and dragging to begin drag and drop. The much more
common paradigm expected by users is that a single mouse press should be able
to select the item and <b>also</b> begin recognition of a drag gesture.

<p>
I am extremely pleased to announce that this important bug <b>has been fixed!</b> In fact,
it has already been released to the public in build 36 of Mustang, which you can
<a href="http://mustang.dev.java.net/">download now</a>. And let me top this with
some even better news: This fix is also targeted to be released in update 5 of
J2SE 5.0, due out in the not too distant future.

<p>
Originally, the fix for this bug was targeted to be the default behavior in FCS of
J2SE 5.0. However, it turns out that the changes involved were larger and had
more potential for backward incompatibility than was orginally expected. It was a
sad thing to do after all of the effort we'd invested, but we finally decided that this
needed more investigation to eliminate the risk of breaking existing
applications, and therefore it couldn't make 5.0. But that's history!
Today, the fix is available in Mustang with very few potential points of
incompatibility, and we'll make the entire fix available in 5.0 update 5
safely by conditionalizing around a system property,
"<code>sun.swing.enableImprovedDragGesture"</code>. So in update 5 you'd launch
your application like this:

<blockquote>
<code>
java -Dsun.swing.enableImprovedDragGesture APPCLASSNAME
</code>
</blockquote>

<p>
(In Mustang the system property disappears and it just works!)

<p>
Most of the details regarding this fix are available in the evaluation of the bug report.
But please let me point out the highlights:

<ul>
<li>
<p>
<b><code>JList</code>, <code>JTree</code>, and <code>JFileChooser</code> have been fixed</b>
such that a selection is no longer required before pressing on an item to begin a drag operation.
More importantly, we've carefully studied this behavior and are confident that the many
different combinations of mouse gestures will work as expected
(ex. ctrl-press, ctrl-press then drag, etc).
</p>
</li>
<li>
<p>
<b><code>JTable</code> has also been fixed</b> to work as described, but (for good reason) only
in <code>SINGLE_SELECTION</code> mode. The reason behind this decision is that <code>JTable</code>
has always allowed the user to select ranges of cells by dragging the mouse.
The new drag gesture would be identical to the existing gesture for selecting a range of
cells, and this conflict prevented the change from being be made in modes supporting
multiple selections. In these modes, users must continue to select a range of cells first,
before clicking on them to start drag and drop. This behavior is consistent with the
spreadsheet applications we compared with during development.
</p>
</li>
</ul>

<p>
Of course, the description of this change wouldn't be complete without a quick summary
of any potential points of incompatibility:

<ul>
<li>
<p>
<b>Consolidation of selection and gesture recognition logic:</b>
Prior to this fix, selection logic and drag gesture recognition logic was separated
into two distinct mouse listeners installed by the UI on each component. The two listeners
knew nothing about each other, and therefore it wasn't possible to make them do the
right thing. In some cases selection needs to happen before considering for a drag
gesture, and in other cases drag and drop should begin without processing selection
changes. Without coordination between the two listeners, this process couldn't work.
<p>
The fix was to put all selection and
drag gesture recognition logic into a single mouse listener to be installed
by the UI on each component. This has worked extremely well and has facilitated the fix of this
bug as desired. It has also introduced the first two very minor points of potential
incompatibility. First, I have seen numerous work-arounds posted to forums for this bug,
and some of them include removing or playing with the private listeners on the components.
It is unknown how these work-arounds will fare under the re-designed drag recognition.
The good news is that any problem can be easily fixed by removing the work-around.
The second potential for incompatibility is for developers that have created custom UI
implementations supplying their own mouse listeners that replace the behavior of Swing's
defaults.
Any such implementation would simply suffer from no longer having built-in drag support. We
don't expect this to be a major issue though, as most UIs replace the look of a component and leave
the listeners alone.
</p>
</li>
<li>
<p>
<b>Handling of cell editors:</b>
The last thing of significance that had to be modified to facilitate this change is the way
that cell editors are handled in <code>JTable</code> and <code>JTree</code> when drag recognition
is turned on. While selection and drag recognition will be considered on mouse press events,
cell editing will now not be considered until after the mouse has been released. This will not affect
most developers at all (after the mouse release, Swing re-processes the press event - and things
will appear to developer code the same as before). The only easily noticeable result of this is
that <code>JComboBoxes</code> in <code>JTables</code> now pop up on the release rather than
the press. This is considered a benefit in that users can now begin drag and drop
or drag to make selections on top of a <code>JComboBox</code> cell without it popping up. Finally,
the value of <code>CellEditor.shouldSelectCell()</code> will now be ignored for table
and tree editors when drag is enabled, on the grounds that cells that aren't selected
can never be dragged.
</p>
</li>
</ul>

<p>
Phew, that covers it! I can't believe I let my mind back into those last couple of points again.
But seriously folks, I absolutely love working on Swing drag and drop and there's some more
exciting changes in the works that I'll be writing about shortly. So please, if you're interested
in Swing drag and drop, Swing in general, or cheesy plays on words, please come back and visit soon.
Otherwise, life would really be a drag. Ha ha h...OK, I think it's about time I drop it.]]>

</content>
</entry>

</feed>