Showing posts with label gui. Show all posts
Showing posts with label gui. Show all posts

Tuesday, July 3, 2012

Lists: An Observable List for UIs

This article discusses combining the java.util.List interface with the javax.swing.ListModel interface. That is: suppose you want a list that you can easily interact with, but also that plugs into UI elements.

The Simple Solution

The simplest solution is to implement these two interfaces in one object:

public class MyList implements java.util.List, javax.swing.ListModel {
...
}

Several years ago I wrote the WatchableVector with this approach in mind: this class extends the java.util.Stack, so all the data structure logic is built-in. All this class has to do is add support for the listeners.

This list can be plugged directly into a JList, and at the same time you can treat it like it a traditional java.util.List. For example, now if you call java.util.Collections.sort( myList ), the UI will automatically update.

Shortcomings

After working with this class for several years, I started to identify shortcomings in this implementation:

  • Recursive Listeners. In theory a a observable/observer contract is simple: when a change occurs, then notify the listeners. But in the world of UI: it is my experience that listeners spiral out of control very quickly. Here is a simplified/approximated stack trace diagram of a potential listener problem:

    Here the list is represented in blue, and two separate listeners are represented in orange and green. The first listener (orange) is notified that a new file is added to a list, but it knows the list needs to always be alphabetized: so it resorts the list. This ends up triggering the first (orange) listener a second time before the second (green) listener ever hears about the first event. If the second listener actually listens to the described event: it will be confused that elements are being reordered that it doesn't even know exist yet.

    This is a contrived example showing a simplified chain reaction. In the real world the first listener might have interacted with a separate data structure, and that structure interacted with another, and another, and as a result: a series of listeners that seemed minimally simple (even elegant?) on paper turn into a nightmare of events. I refer to this as "cascading listeners", but a coworker refers to it as "listener hell".

  • The Event Dispatch Thread. My ListModel is plugged into a Swing component: so it needs to only ever be updated on the event dispatch thread. But my List is the same as my ListModel: so complex (potentially time-consuming) operations on my list now need to occur on the EDT, or ambiguous "bad things" may happen (in a hard-to-pin-down kind of way).
  • Multithreading. Consider the illustrated example above: all this is occurring in the event dispatch thread. What happens if another thread wants to access this list? It has to wait, because the call to WatchableVector.add(..) is synchronized, as is the call the WatchableVector.get(index). The operation itself may be relatively fast, but the synchronization lock isn't released until all the listeners have been notified. (Including the potentially recursive listener chain reactions...). If you think of this as an IO-model: there's no reason other threads have to wait to read data from this list while other listeners spin their wheels -- but we should prevent them from write operations.
  • This weekend I wrote a new class to address these issues: the ObservableList.

    Addressing Listener Recursion

    The ObservableList continues to support the ListDataListener, but it separates listeners into two categories: synchronized and unsynchronized.

  • Synchronized Listeners. These listeners are not allowed to modify the list. Because of this contract: it is guaranteed that the ListDataEvent each synchronized listener receives reflects the current state of the list. If both listeners in the previous example were added as synchronized listeners, then the flow of execution will look like the diagram on the right.

    Even if the first listener doesn't catch the RecursiveListenerModificationException: the loop that iterates over the listeners will catch it and call e.printStackTrace(), so all the subsequent listeners are guaranteed to carry on as usual.

    The downside of this approach is: in a complex environment calls that modify this list should be wrapped with a try/catch clause to catch potential RecursiveListenerModificationExceptions. This will be easy to forget. Hopefully violations will be consistent and easy to identify early in testing. But the positive side is: all the other listeners are protected.

  • Unsynchronized Listeners. These listeners are allowed to modify the source list, so when you use an unsynchronized listener: you have to accept that the ListDataEvent you receive may be inaccurate. (For example: you may be notified that an element was removed, but in fact a previous listener re-added it! You'll receive that event, too, but probably not in the order you would expect.)
  • You have the option when adding an unsynchronized listener to also prohibit modification from within that thread. This is intended largely as a safeguard for developers to detect unintended chain reactions.

    Addressing Synchronization

    My original data structure relied on the synchronized keyword to protect the integrity of the list. But it also kept listener notification inside the synchronization block, so if one thread made a call to modify the list and a second thread later wanted to read from the list: then the second thread could not obtain the synchronization lock until all the listeners had completed.

    Here is a crude sequence diagram of what that would look like:

    When working with complicated UI elements: sometimes listeners (especially a chain reaction of listeners) can involve very expensive operations. We're blocking thread #2 for no real reason: the actual doAdd() operation is complete, so the list is stable again.

    The ObservableList uses Semaphores and not the synchronized keyword. The basic format for all operations that modify the list resemble this:

    public Object execute(...) {
    readSemaphore.acquireUninterruptibly( 1 );
    try {
    [ evaluate if this is a null-op, if so: return ]
    readSemaphore.acquireUninterruptibly( MAX-1 );
    try {
    [ do operation ]
    } finally {
    readSemaphore.release( MAX-1 );
    }
    fireSynchronizedEvent(...);
    } finally {
    readSemaphore.release();
    }
    fireUnsynchronizedEvent(...);
    return returnValue;
    }

    And the format for all operations that retrieve (but do not modify) data from this list resemble:

    public Object getSomething() {
    readSemaphore.acquireUninterruptibly();
    try {
    return returnValue;
    } finally {
    readSemaphore.release();
    }
    }

    Since we already (separately) established that a synchronized listener is forbidden to further modify this list: this provides a safe model for concurrent read operations on this list (including while listeners are being notified). The sequence diagram for the previous example now looks like this:

    Now suppose thread #2 is the event dispatch thread, and one of the listeners in thread #1 called: SwingUtilities.invokeAndWait(..). (That is: thread #1 is forcing something to run on the EDT.) In the first model using the synchronized keyword: you will have a deadlock. The EDT is waiting to synchronize against the list, and the thread with that lock is waiting for the EDT. In the second model: there is no deadlock.

    Addressing The Event Dispatch Thread

    There's probably a reason the java.util.List and javax.swing.ListModel were kept separate: when one class implements both, it's very tempting to forget that object (which may have been pledged to the UI) should never be modified on different threads.

    So the ObservableList is designated only as List and not a ListModel. But it has two methods to help UI development:

  • getListModelEDTMirror(): this returns a separate object that mirrors this list. This object will only be updated in the EDT.

    As a result: it may (briefly) be the case that the UI mirror has outdated information, so just because you remove an element from this list doesn't mean it's safe to completely dispose of it. Also if the original list is several thousand elements long: maintaining a copy may be expensive.

  • getListModelView(): this returns a ListModel with direct access to the parent ObservableList. This is basically the "old-fashioned" solution I previously described. If you use this method: it is your responsibility to only ever modify the ObservableList in the EDT. In most cases: you should not rely on this method, but in some (simple) cases it may be safe.
  • Other Convenient Features

    Here are a few additional features the ObservableList list offers:

  • Detailed events. The ListDataEvent involves specific list indices to describe operations that occurred.

    However sometimes calculating a precise event to describe an operation is as expensive as the operation itself, and sometimes your listener really doesn't care about specific indices.

    When you add a listener: you pass an argument indicating whether you want a high level of detail or not. If none of the registered listeners have asked for a high level of detail (or if there simply are no listeners): then an oversimplified CONTENTS_CHANGED events may be used to save time.

  • ChangeListeners. If you aren't really interested in specifics about ListDataEvents, then it can be cumbersome to add the 3 methods of a ListDataListener. You can instead add a ChangeListener: it has only one method to implement.
  • The setAll( List ) Method. This is equivalent to calling list.clear() followed by list.addAll( otherList ). However those calls will trigger 2 listener notifications indicating that everything has changed, when it might be the case that a single ListDataEvent.INTERVAL_ADDED event is needed because only 1 element was added. In short: this method can streamline the notifications the listeners receive.
  • Supplemental Methods with Argument Arrays. Every method that takes a java.util.Collection or java.util.List as an argument now has a supplemental method that accepts an array of elements.
  • Delegating to an Abstract List. The ObservableList wraps around another java.util.List object. The default constructor creates an ArrayList underneath, but you're welcome to use any other list you prefer.
  • Conclusion

    Usually I try to include an applet with my blog articles to keep your attention, but that really isn't possible with this project. Instead all I can link to this time is the ObservableList itself and the related unit tests.

    After years of dealing with (self-inflicted) lessons learned from UI development: I think this list implementation satisfies the need for listeners with safety and efficiency.

    Of course I'm not the first person to work on an observable list. Here are some other related efforts that might suit your needs better:

  • There is an Apache version of the ObservableList, but as far as I can tell it's not optimized for multithreading/safety.
  • JavaFX has its own ObservableList. They also have a setAll(..) method. (In fact my original implementation named this method "replaceAll(..)", and I changed it based on their example.) But I don't have access to the source for this implementation, so I don't know how optimized it is. Also I don't want to start bundling parts of JavaFX in my apps yet.
  • The JDesktop project has a static method: ObservableCollections.observableList(java.util.List list). But this implementation does not have a setAll(..) method, and I'm unclear how this is implemented under the hood.
  • One thing all these approaches do that I appreciate is: they use their own (new) type of listener. The ListDataListener can be a little bit constraining sometimes. (For example: try to describe a List.retainAll( Collection ) operation in terms of a ListDataEvent.) But this listener is how the javax.swing.JList wants to be communicated with, so it's acceptable for my usage.

    Tuesday, June 26, 2012

    ListUIs: Adding Decorations to Cells

    This is a follow-up to my previous article: TreeUI's: Adding Decorations to Cells.

    What is a "Decoration" again?

    A decoration is a UI component overlayed inside or on top of another component.

    Muted-color minimal buttons/decorations are becoming increasingly common in modern UIs. This is great way to add extra functionality for power users without adding too much visual clutter.

    Here is a screenshot of part of my current Firefox window. There are 6 decorations showing:

  • The star bookmarks a page.
  • The down arrow presents a list of recent URLs.
  • The circular arrow refreshes the page.
  • The left side of the search field lets me change search engines.
  • The word "Google" is also a decoration indicating what search engine is being used.
  • The right side of the search field commits my search.
  • ... but there are only 3 non-decorative UI elements showing: the URL field, the history button, and the search field. The decorations add a lot of subtle controls in a small space.

    As an accessibility side-note: it's worth mentioning that decorations usually do not receive keyboard focus as you navigate the interface with the tab key. They are second-class citizens when it comes to your window hierarchy. You probably need to provide alternate ways to access these features (menu shortcuts, for example) to help reach a wider target audience.

    List Decorations

    The section above talked about decorations in general, but what are some examples of decorations for list elements?

    Above are search results in a recent youtube query: when you mouse over a thumbnail there is an optional button to add a video to your queue.

    Also you could provide buttons to delete list elements, reload, or show progress indicators.

    On the right is a new-ish decoration for sound files observed on Mac OS 10.7. When you mouse over the graphic: a play button fades in. When you click the play button: the outer ring appears, and the gray arc proceeds clockwise representing the playback of your sound.

    The same playback controls are used for movies, however for movies the controls fade away as soon as you mouse out of the preview area.

    (Traditionally these controls have been presented with a thin horizontal row of controls along the bottom of a sound/movie. I'm not trying to argue that Apple's new circular timeline is any better than a horizontal timeline: both could be presented with overlayed controls.)

    Implementation

    In Swing, JLists (and JTrees) use renderers, where one component is rubber stamped for every element in the list/tree.

    This is a great scalable model (because tens of thousands of elements can safely be rendered without too much overhead), but it lacks mouse input. To implement decorations on a list, I developed the DecoratedListUI. This UI manages multiple ListDecorations, which are rubber-stamp overlays to your existing ListCellRenderers.

    All you have to do is invoke the following:


    ListDecoration[] arrayOfDecorations;
    ...
    myList.setUI( new DecoratedListUI() );
    myList.putClientProperty( DecoratedListUI.KEY_DECORATIONS, arrayOfDecorations);

    Example

    Here is an example that emulates the Mac playback controls with a list of 5 sounds:

    You can download this jar (source included) here.

    (Note: usually I make an effort to keep my jars small in file size so you can easily plug them in to other projects, but in this case: I ended up bundling several megabytes of wav files inside the jar. So while this jar is nearly 2 MB, the code you need is probably less than 100 KB. Sorry for the inconvenience.)

    In this applet: each sound file is an element of a JList. When you select a sound file: decorations appears to play/pause and delete the sound.

    In theory you could make some decorations always visible (this might be especially useful for a loading indicator, or a warning indicator?), but personally I want actionable buttons to be limited in number to keep the interface simple.

    Also, in case you were wondering: the music file icon is a scalable javax.swing.Icon. I noticed in some contexts on my Mac the background had a sort of plastic glazed look and not a radial gradient, but I decided not to fixate on that level of detail. My replicas are never intended to be pixel-perfect copies, just reasonable likenesses.

    And if anyone knows how to reduce the flickering observed in this (and other) applets: please let me know! This does not reproduce when launched as a desktop application, so I'm not sure exactly how to debug this.

    Sunday, May 27, 2012

    TreeUIs: Adding Decorations to Cells

    This article discusses a modified TreeUI that lets you add decorations on the right side of your tree. (See this other article for a similar discussion focusing on JLists.)

    What do I mean by "Decoration"?

    The short answer is, "I'm not exactly sure." It's similar to a button or a label (depending on which one you want), and that's how most users will perceive it, but it is not actually a JComponent, and it does not exist in the Swing hierarchy of your window.

    In a JTree: every cell is rendered via a TreeCellRenderer. The same renderer is consulted for every row in the tree, so the intended usage is for one component to be used to display potentially thousands of different values. This is referred to as "stamping", because the renderer is repeatedly painting to the tree without actually belonging to it.

    This is a wonderful design regarding memory use, but it becomes difficult to add functionality to trees the same way you can add functionality to text fields and other Swing components -- because you don't have a solid grasp on the hierarchy of elements involved.

    The decoration model partially addresses this issue. Swing components are (usually) very well suited to this kind of augmentation. There is nothing sacred about the current implementation of the JTree and how it renders: these components are designed to flexible and, when possible, improved to meet your needs.

    Examples

    To help paint a better picture of what I'm describing, here is an applet demonstrating tree decorations:

    This applet (source code included) is available here. Here is a summary of each decoration:

  • Progress Indicator: the root node takes a few seconds to load. While it is loading: a progress indicator appears on the right side of the tree. As soon as the tree is fully loaded: the indicator is hidden.
  • Refresh Button: Once the progress indicator is dismissed, the root node will show a refresh button when it is selected. (When clicked, the node re-loads like it did before.)
  • Play/Pause Buttons: when the "Playable" node is selected a play/pause toggle is present. (In this demo nothing actually plays, but this was designed with audio playback in mind.)
  • Warning Indicator: this node shows a pulsing warning icon when selected. (Thanks to the Silk icon set for the image!)
  • Rating Stars: this node shows 5 rating stars when selected. This is a good demonstration of the current limits of the decoration implementation: clicking and dragging does not work like I would want it to.
  • Delete Button: this removes the selected node from the list.
  • The delete button is actually the original motivation for this project: I didn't want the user to have to click a tree node and then navigate somewhere else in the UI to the delete button. In my case this saved several pixels, cleaned up the layout, and made the user's task more efficient. Also because the button is adjacent to what it modifies: there is little room for confusion about which object the user is acting on.

    However I am also worried that this model can introduce too much visual clutter (aka "over-stimulation"). To limit the amount of controls the user needs to process I made most of the decorations only appear in a row when that row is selected. Also this helps guard against accidentally clicking the wrong button, which becomes increasingly important when your controls become smaller. Restraining the number of decorations is just a suggestion, though: you can make all your decorations visible all the time if you want to. (For example: if you're always dealing with very advanced users, or if your tree is usually going to be relatively small.)

    And lastly: as a personal preference I added an option to highlight the width of the entire row. By default the BasicTreeUI only highlights the text of the tree node when it is selected, but this tree is a kind of hybrid between a tree and a list (or a tree and a table?): so highlighting the entire row seemed like a good idea.

    Implementation

    The DecoratedTreeUI is an extension of the BasicTreeUI, so it inherits most of the standard tree functionality.

    It takes the existing TreeCellRenderer (that the JTree stores) and places it inside its own renderer. On the right side of that renderer it adds all the appropriate decorations as JLabels. As the demo above shows: different tree nodes can have different decorations.

    The decoration object you need to supply is represented with three methods:

    public abstract static class TreeDecoration {
    public abstract Icon getIcon(JTree tree, Object value, boolean selected, boolean expanded,
    boolean leaf, int row, boolean isRollover,boolean isPressed);

    public abstract boolean isVisible(JTree tree, Object value, boolean selected, boolean expanded,
    boolean leaf, int row, boolean hasFocus);

    public abstract ActionListener getActionListener(JTree tree, Object value, boolean selected, boolean expanded,
    boolean leaf, int row, boolean hasFocus);
    }

    These are the only methods you need to implement to add decorations to your tree. And there is also built-in support for the BasicTreeDecoration (for simple labels/buttons) and RepaintingTreeDecoration (for decorations that continually need to repaint).

    To install decorations, call:

    myTree.setUI(new DecoratedTreeUI());
    myTree.putClientProperty( DecoratedTreeUI.KEY_DECORATIONS, myArrayOfDecorations );

    Also to give you complete control over how the icons are positioned: there is no padding between decorations. That's not because I think zero padding is a good idea (it's not), but this lets you pad your icons with however many pixels you think is appropriate (instead of an arbitrary amount I made up).

    The rest of the implementation is probably relatively boring: the hard parts included identifying the simplest methods I needed to override to add the functionality I wanted, and adding a simple model to arm/disarm the decorations so they really behaved like buttons. As of this writing: the final implementation is about 500 lines of code (not counting comments), so it's not that daunting in the end.

    Thursday, January 14, 2010

    Colors: A Good GUI for Selecting Colors

    This article explores the question: what is a good GUI for picking a color?

    Dialogs


    The first instinct of many developers will be to use a dialog. And there is a dialog that comes standard with Java that does the trick. It takes one line to invoke:

    Color newColor = JColorChooser.showDialog(component, title, initialColor)



    I have several complaints about this dialog:
    • The default tab is poorly designed. Look at all that wasted vertical space! And I don't like the strong shadows that surrounds each cell.
    • The colorful components are not keyboard accessible. You can navigate the dialog using the keyboard if you eventually tab to a text field or spinner: but then you have to choose your color by numbers. Do you like choosing a color by numbers? It seems more natural to choose a color from a set of colors.
    • The dialog uses tabs. This is perhaps acceptable on the grounds that this is intended to be a universal component. But a better design would only present one suitable model. The user's goal here is to select a color. In this dialog they can get distracted with all the different components. Depending on how you count them, I see at least 23 different components the user can click here: this is overdoing it.

    This prompted me to create a new dialog. It's default view features a color wheel. You can navigate it with the keyboard. There are no tabs, but it does offer subtle controls to change the view. This is modeled after what Photoshop uses, and they must know a thing or two about how professional artists want to choose a color, right?

    However most users are not professional artists, so this is still overkill. Also when possible it is better to avoid dialogs. The book About Face makes these comments about dialogs:

    "A dialog box is another room; have a good reason to go there.

    ... Build functions into the window where they are used.

    ... Putting functions in a dialog box emphasizes their separateness from the main task."

    Palettes


    Instead I would like to focus on palettes. A grid of colors. This could be presented in a small JWindow, or it could be presented in a JPopupMenu.

    Here size is everything. The key difference in this concept and the dialogs mentioned before is that this is small. In nuanced jargon: this is a "transient", and the previous two dialogs are more "sovereign". This is one component - not several.

    Here is an applet that provides several consecutive drafts of different palettes:


    This applet (source included) is available here.

    Here is a brief history of each draft:

    1. This was my first reaction to the words "pick a color". Every pixel counts. You have thousands of colors here to choose from. Not every color is represented, but you get light and dark shades that really stand out. (Compared to less saturated, muddy shades.)
    2. But quickly someone pointed out: this doesn't have black and white! Those are very important colors. As are shades of gray. So the second draft included a special column for white/black/gray.
    3. We had this model deployed in a desktop application for a while. Eventually the feedback came back to us: it's too many options. It was nearly impossible to ever pick the same color.

      The previous models were based on my instincts as a developer: if I give you more choices, that gives you more control. More control is better, right? But in fact people don't usually like too many choices. Here is a quote from The Power of Persuasion:

      "The greater the number of choices, the happier the consumer - so it's assumed.

      In a recent series of experiments ... a group of Columbia University chocolate lovers were given a choice between six different flavors of Godiva chocolates. A second group was asked to select between thirty different flavors. Subjects given the extensive flavor choices rated their selection as less tasty, less satisfying and less enjoyable than did the limited-choice group. The thirty-flavor subjects expressed more regrets about their selection and were less likely to choose chocolate as payment for participating in the experiment."

      In other words: suppose a user goes off in search of the color green. But then they quickly see that there are 300 different shades to choose from! This is a source of stress to the user. Give them a few tasteful options and they'll actually be happier.
    4. Then we designed a product for a younger audience. We wanted to thin the color pool down even more. Also a common complaint was that users needed brown. So we added a second special column for brown.
    5. But for graphic designers and other artists: they really might want more than 60 colors. This model uses keyboard modifiers to let the user get thousands of more choices. There are modifiers for "flesh tones" and "earth tones", as well as to toggle to a continuous spectrum of colors.
    6. Another way to give more options is to add scrollbars. A color is generally considered to have three dimensions (RGB, HSB, RYB, HSL, etc.). A rectangle will only present two of these dimensions. If you add a scrollbar, though: you can represent another dimension. Also you can add a scrollbar for opacity. And because I still like the modifier idea: you can press a modifier key to toggle between a continuous spectrum and a grid. In theory this model offers every color conceivable to the user. (In practice it is subject to rounding, though.)
    7. But the HSB model is not very aesthetic. Rob Camick has a nice article about using the hue-saturation-luminance model instead. Isn't it just all-around better looking?
    8. Lastly: yellow. In HSB or HSL: the hue is still abstractly based on an RGB model (that is: the primary colors of light). The problem here is if you split the RGB model into 6ths, you'll get: red, yellow, green, cyan, blue, purple. What about orange? You'll have to split the model into 12ths to see orange: it's a tiny sliver in an RGB-based spectrum. Instead I added a special class called HueDistribution, and I use it to give each of these colors equal weight: red, orange, yellow, green, cyan, blue, purple.

    You'll notice in the applet these drafts all have funny names: the list presents them as ColorPaletteUIs. The component shown is a com.bric.swing.ColorPalette, and it can be configured with several different look-and-feels.

    Also the controls at the top of the applet are client properties that affect the look of the UI. They are purely aesthetic - they make no functional difference. Personally I hate selecting a color from uniform cells due to the contrast effect of placing the cells side-by-side. These options provide a stylized way to break up that effect.

    I'd like to add this sidenote: these were intended for (and tested against) use in desktop apps: not applets. I'd recommend downloading and running these jars as applications to really observe their behavior. So far my limited testing shows these bugs:

    • On Vista in IE the alt modifier doesn't work. (Well, it toggles IE's menu bar... so it is technically working...)
    • On OpenSUSE in Firefox the popup color well (shown below) doesn't work.


    ... there are probably many more. But if these bugs only reproduce in applet form: I'm not too worried about them.

    Integrating Into A Window


    Almost done. But not quite. Where should the ColorPalette component live? It is possible to put in in your main window, but you would only want to do that if your user constantly needed to select a color. In a painting program, for example.

    Or I'm developing a graphics application where I put two ColorPalettes side-by-side: one contains the usual spectrum of colors, and the other contains translucent shades of white/black. You might also want to provide a separate set of themed colors (if you were working on, say, a PowerPoint-like program). Or a set of recently-used colors.

    However in several applications you can't devote that much window space to the act of choosing a color. Consider iWeb, for example: for your text, shadows, and other effects you need to choose a color, but the inspector is already crammed full of useful odds and ends

    In this case what I'd want is a ColorWell. This is about the height of a JLabel (and the width is arbitrary). I gave it an Aqua-ish border to blend in on my Mac.

    In order to keep it abstract I defined 4 client properties that are associated with an ActionListener. By default these are what these actions do:

    1. downKeyAction: displays a ColorPalette below the ColorWell.
    2. spaceKeyAction: provides a ColorPicker dialog for your advanced user.
    3. singleClickAction: same as downKeyAction
    4. doubleClickAction: same as spaceKeyAction

    So in conclusion: here is applet that contains everything: the ColorWell, the ColorPalette, and the ColorPicker:



    This applet (source included) is available here.

    Sunday, December 6, 2009

    Text: Searching JTextComponents

    This entry has to do with searching for a phrase in JTextComponents. There's a lot of ground to cover, so I'll start you off with the demo and then go into details. (Give this applet a few seconds to load... it has a lot of text to read.)


    This jar (source included) is available here.

    Text Search Bars


    What is the point of a search bar? This is an interface decision more than a technical one. A search bar has several advantages over a search dialog:
    1. A dialog will physically be in the wrong location. It will start out centered, which probably covers part of the text the user wants to search.
    2. Providing a search bar in a fixed location will help users visually scan the interface more easily. They'll know where to look. It's a matter of identifying a fixed point vs searching for it.
    3. Dialogs are usually (and perhaps originally) designed for the convenience of programmers. You can cram a program full of thousands of dialogs... but the screen real estate is unlimited. It is much harder to create a well-balanced window with just the right amount of essential interface controls without becoming too cluttered. It takes more work, and we usually don't bother.
    4. Of course a modal search dialog is worse. Modal dialogs are discouraged here, among other places.

    I modeled these search bars after the ones I saw in Firefox and Safari. They include:

    • a search field
    • next/previous buttons
    • a checkbox for matching case
    • a dismiss button
    • a label including the occurrences of the search phrase
    • a toggle button for "Highlight All"

    The order (and presence) varies, but those are the basics. Safari automatically highlights all, and Firefox uses a toggle button. The anchor varies in both toolbars, but the components are still listed in about that order.

    Text Search Dialog


    Of course sometimes a dialog might be appropriate: that's up to you to decide. If searching is a feature so rarely used that it doesn't make sense to keep it in the main interface: that's justifiable. Or if your software is so versatile that searching is nothing but an auxiliary function? That's OK too.

    So I included a minimal dialog. It automatically performs case insensitive, wrap-around searches. It's not modal, but it does dismiss itself when the user hits the return key.

    No matter which model you use (a search dialog or a search bar), you probably want to also include typical menu shortcuts for find, find again, and find previous.

    Searching Text


    Most of the rest of this project was GUI work: so I was in my prime. The actual methods that do the searching/counting, though... I admit I'm pretty clueless about.

    My first instinct was to convert the document into a String, and then use .indexOf() and .lastIndexOf() to search for everything. Now I have absolutely no proof for what I'm about to say, but that sure feels like a horrible approach. Especially when we have to convert the entire string to a specific case to avoid case sensitivity.

    So instead I went spelunking around, and tried using the Segment class. Now the method is much hairier, but it walks through chunks of characters at a time to find the search phrase: at no time do I have an extra copy of the whole document floating around.

    (Remember when we count the occurrences of the search phrase: we perform a bajillion searches, so this method needs to be relatively light.)

    If anyone has any experience/suggestions on this subject, here is the code in question.

    The Visuals


    When you use the Safari-style search bar you're introducing two extra layers of visual effects into your JFrame:

    The middle layer is known as the TextHighlightSheet. The topmost layer is a SearchHighlight. These layers have a few of things in common:
    1. They are both added to the JLayeredPane.
    2. They both are tied to their "parent" JTextComponent. (It's not technically their parent component as far as the Swing hierarchy is concerned, but it's useful to think of them as bound to that text component.) When AncestorListeners or ComponentListeners are notified that the TextComponent has moved around: these other layers have to immediately respond.
    3. They're both animated. Or at least they can be. The middle sheet may fade in/out, and the highlight can have any number of customized animations.

    Now I'll discuss each in a little more detail.

    The TextHighlightSheet


    This is the more clever component: it has to highlight all the occurrences of the search phrase, without looking at irrelevant hits. So it will first calculate the index that is mapped to the point (0, 0) of the viewport, and then the index that is mapped to (width, height). Then search only within those indices, and calculate the shapes of all the hits.

    The hits are outlined in rectangles, and Area objects are used to join overlapping rectangles. Usually I avoid the Area class like the plague, but combined rectangles shouldn't be a hassle: they're small, and they contain only lines. Paint those rectangles white, and then paint everything around them in a translucent black (to add the overall shadow).

    Finally a combination of the right clipping, translation, and a TextOnlyGraphics2D let us call parentTextComponent.paint(g) to render the text.

    The Firefox search bar uses the same component as the Safari search bar. (Although in the Firefox bar you have to explicitly turn it on with the "Highlight All" button.) The Firefox sheet, however, doesn't have a translucent shadow. Also it uses different padding and colors. All of this is covered in the javadocs if you really want to customize it.

    The sheet has isActive() and setActive() methods to control whether it is visible. The TextSearchBar automatically follows one of two behaviors:

    1. If the "Highlight All" button is visible: then that button is the only factor controlling whether the sheet is active. This is how Firefox behaves.
    2. If the "Highlight All" button is invisible: then the sheet is made active only when the search field has the keyboard focus. This is how Safari behaves.

    SearchHighlight


    This is a very different component, and is subclassed directly into the look you're aiming for. The AbstractSearchHighlight subclasses into the AquaSearchHighlight, the FirefoxSearchHighlight, and the NudgeSearchHighlight.

    When constructed this component creates a BufferedImage of one particular hit of the search phrase. Then a javax.swing.Timer is activated, and this component is ready for action.

    The subclasses can animate the transform and opacity of the image over the duration of the animation.

    It is important that the sheet and the effect be designed to visually complement each other. For example: the highlight sheet for the Safari search bar is designed to work with the Aqua or the Nudge effects, but the Firefox effect uses smaller padding around the hit phrases.

    Also the Firefox effect cheats and uses an infinite duration, so the effect never really goes away. I'm not sure exactly what should happen in this scenario if the JTextComponent is editable? (Any thoughts?) I guess the effect should go away as soon you modify the document such that that particular hit phrase is changed? This is not an issue in the Safari/Nudge models, simply because the animation will quickly dispose of itself. So this is a bug in the Firefox effect, but I'm not sure what the ideal behavior is.

    Each effect is created by calling TextSearch.highlight(). This looks up the value for UIManager.get("textSearchHighlightEffect"), and instantiates the class name provided. I won't go into detail here, but the point is: you can customize this if you want. (You don't even have to extend the com.bric.plaf.AbstractSearchHighlight if you don't want to.)

    Conclusion


    In v1.0 of this project I just included the search bars and the effects. In v2.0 I added the middle sheet. If I get around to a v3.0: what next? (Aside from existing bugs.)

    Speaking of bugs: I suppose you also need to be able to perform a revised search with every key stroke in the search field. This is how Firefox behaves. This is slightly different from hitting the enter key in the text field, because that will search for the next occurrence starting at the end of the current selection... but continuous typing really needs a search that starts at the beginning of the current selection. Another day, maybe...