Source Code Cross Referenced for DisjointLists.java in  » GIS » GeoTools-2.4.1 » org » geotools » gui » swing » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » GIS » GeoTools 2.4.1 » org.geotools.gui.swing 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *    GeoTools - OpenSource mapping toolkit
003:         *    http://geotools.org
004:         *    (C) 2003-2006, Geotools Project Managment Committee (PMC)
005:         *    (C) 2002, Institut de Recherche pour le Développement
006:         *
007:         *    This library is free software; you can redistribute it and/or
008:         *    modify it under the terms of the GNU Lesser General Public
009:         *    License as published by the Free Software Foundation; either
010:         *    version 2.1 of the License, or (at your option) any later version.
011:         *
012:         *    This library is distributed in the hope that it will be useful,
013:         *    but WITHOUT ANY WARRANTY; without even the implied warranty of
014:         *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
015:         *    Lesser General Public License for more details.
016:         */
017:        package org.geotools.gui.swing;
018:
019:        // Swing and AWT dependencies
020:        import java.awt.Font;
021:        import javax.swing.JList;
022:        import javax.swing.JPanel;
023:        import javax.swing.JButton;
024:        import javax.swing.JScrollPane;
025:        import javax.swing.AbstractListModel;
026:        import java.awt.IllegalComponentStateException;
027:
028:        // Events
029:        import java.awt.event.ActionEvent;
030:        import java.awt.event.ActionListener;
031:
032:        // Layout
033:        import java.awt.Dimension;
034:        import java.awt.Component;
035:        import java.awt.GridBagLayout;
036:        import java.awt.GridBagConstraints;
037:        import java.util.List;
038:        import java.util.Iterator;
039:        import java.util.ArrayList;
040:        import java.util.Collection;
041:        import java.util.Collections;
042:        import java.util.Arrays;
043:        import java.util.Locale;
044:
045:        // Geotools dependencies
046:        import org.geotools.resources.XArray;
047:        import org.geotools.resources.Utilities;
048:        import org.geotools.resources.SwingUtilities;
049:
050:        /**
051:         * A widget showing selected and unselected items in two disjoint list. The list on the left
052:         * side shows items available for selection. The list on the right side shows items already
053:         * selected. User can move items from one list to the other using buttons in the middle.
054:         *
055:         * @since 2.0
056:         * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/extension/widgets-swing/src/main/java/org/geotools/gui/swing/DisjointLists.java $
057:         * @version $Id: DisjointLists.java 22112 2006-10-13 19:43:34Z desruisseaux $
058:         * @author Martin Desruisseaux
059:         */
060:        public class DisjointLists extends JPanel {
061:            /**
062:             * The list model. Each {@link DisjointLists} object will use two instances
063:             * of this class.  Both instances share the same list of elements, but have
064:             * their own list of index of visibles elements.
065:             */
066:            private static final class Model extends AbstractListModel {
067:                /**
068:                 * The list of elements shared by both lists. Not all elements in this list will be
069:                 * displayed. The index of elements to shown are enumerated in the {@link #visibles}
070:                 * array.
071:                 * <p>
072:                 * Note: this list is read by {@link DisjointLists#selectElements}. The content
073:                 *       of this list should never be modified from any method outside this class.
074:                 */
075:                final List choices;
076:
077:                /**
078:                 * The index of valids elements in the {@link #choice} list. This array will growth
079:                 * as needed. Elements in this array should always be in strictly increasing order.
080:                 */
081:                private int[] visibles = new int[12];
082:
083:                /**
084:                 * The number of valid elements in the {@link #visibles} array.
085:                 */
086:                private int size;
087:
088:                /**
089:                 * Constructs a model for the specified list of elements.
090:                 */
091:                public Model(final List choices) {
092:                    this .choices = choices;
093:                }
094:
095:                /**
096:                 * Returns {@code true} if all elements in the {@link #visible} array
097:                 * are in strictly increasing order. This is used for assertions.
098:                 */
099:                private boolean isSorted() {
100:                    for (int i = 1; i < size; i++) {
101:                        if (visibles[i] <= visibles[i - 1]) {
102:                            return false;
103:                        }
104:                    }
105:                    return true;
106:                }
107:
108:                /**
109:                 * Searchs the insertion point. We should use Arrays.binarySearch(...), but
110:                 * unfortunatly J2SE 1.4 do not provides an API for searching in a subarray.
111:                 */
112:                private static int search(final int[] array, int lower,
113:                        final int upper, final int value) {
114:                    while (lower < upper && value > array[lower]) {
115:                        lower++;
116:                    }
117:                    return lower;
118:                }
119:
120:                /**
121:                 * Returns the number of valid elements.
122:                 */
123:                public int getSize() {
124:                    assert size >= 0 && size <= choices.size() : size;
125:                    return size;
126:                }
127:
128:                /**
129:                 * Returns all elements in this list.
130:                 */
131:                public Collection getElements() {
132:                    final Object[] list = new Object[getSize()];
133:                    for (int i = 0; i < list.length; i++) {
134:                        list[i] = ListElement.unwrap(getElementAt(i));
135:                    }
136:                    return Arrays.asList(list);
137:                }
138:
139:                /**
140:                 * Returns the element at the specified index.
141:                 */
142:                public Object getElementAt(final int index) {
143:                    assert index >= 0 && index < size : index;
144:                    return choices.get(visibles[index]);
145:                }
146:
147:                /**
148:                 * Makes sure that the {@link #visibles} array has the specified capacity.
149:                 */
150:                private void ensureCapacity(final int capacity) {
151:                    if (visibles.length < capacity) {
152:                        visibles = XArray.resize(visibles, Math.max(size * 2,
153:                                capacity));
154:                    }
155:                }
156:
157:                /**
158:                 * Removes a range of visible elements. The {@code lower} and {@code upper}
159:                 * indices are index (not values) in the {@link #visibles} array.
160:                 */
161:                private void hide(final int lower, final int upper) {
162:                    if (lower != upper) {
163:                        System.arraycopy(visibles, upper, visibles, lower, size
164:                                - upper);
165:                        size -= (upper - lower);
166:                        fireIntervalRemoved(this , lower, upper - 1);
167:                    }
168:                    assert isSorted();
169:                }
170:
171:                /**
172:                 * Moves elements in the specified range from the specified model to this model.
173:                 *
174:                 * @param source The source model.
175:                 * @param lower  Lower index (inclusive) in the source model.
176:                 * @param upper  Upper index (exclusive) in the source model.
177:                 */
178:                public void move(final Model source, final int lower,
179:                        final int upper) {
180:                    assert lower >= 0 && upper <= source.size;
181:                    ensureCapacity(size + (upper - lower));
182:                    int insertAt = 0;
183:                    int subUpper = lower;
184:                    while (subUpper < upper) {
185:                        final int subLower = subUpper;
186:                        assert isSorted();
187:                        insertAt = search(visibles, insertAt, size,
188:                                source.visibles[subLower]);
189:                        if (insertAt == size) {
190:                            subUpper = upper;
191:                        } else {
192:                            subUpper = search(source.visibles, subLower, upper,
193:                                    visibles[insertAt]);
194:                        }
195:                        final int length = subUpper - subLower;
196:                        System.arraycopy(visibles, insertAt, visibles, insertAt
197:                                + length, size - insertAt);
198:                        System.arraycopy(source.visibles, subLower, visibles,
199:                                insertAt, length);
200:                        size += length;
201:                        assert isSorted();
202:                        fireIntervalAdded(this , insertAt, insertAt + length - 1);
203:                    }
204:                    source.hide(lower, upper);
205:                }
206:
207:                /**
208:                 * Moves elements at the specified indices from the specified model to this model.
209:                 * Note: the indice array will be overwritten.
210:                 *
211:                 * @param source  The source model.
212:                 * @param indices Indices of elements in the source model to move.
213:                 */
214:                public void move(final Model source, final int[] indices) {
215:                    Arrays.sort(indices);
216:                    for (int i = 0; i < indices.length;) {
217:                        int lower = indices[i];
218:                        int upper = lower + 1;
219:                        while (++i < indices.length && indices[i] == upper) {
220:                            // Collapses consecutive indices in a single move operation.
221:                            upper++;
222:                        }
223:                        move(source, lower, upper);
224:                        final int length = (upper - lower);
225:                        for (int j = i; j < indices.length; j++) {
226:                            // Adjusts the remaining indices. Since we just moved previous
227:                            // elements, the indices of remaining elements are shifted.
228:                            indices[j] -= length;
229:                        }
230:                    }
231:                }
232:
233:                /**
234:                 * Adds all elements from the specified collection.
235:                 */
236:                public void addAll(final Collection items) {
237:                    if (!items.isEmpty()) {
238:                        choices.addAll(items);
239:                        final int length = items.size();
240:                        ensureCapacity(size + length);
241:                        final int max = choices.size();
242:                        for (int i = max - length; i < max; i++) {
243:                            visibles[size++] = i;
244:                        }
245:                        assert isSorted();
246:                        fireIntervalAdded(this , size - length, size - 1);
247:                    }
248:                }
249:
250:                /**
251:                 * Removes all elements from this model.
252:                 */
253:                public void clear() {
254:                    choices.clear();
255:                    if (size != 0) {
256:                        final int oldSize = size;
257:                        size = 0;
258:                        fireIntervalRemoved(this , 0, oldSize - 1);
259:                    }
260:                }
261:            }
262:
263:            /**
264:             * Action invoked when the user pressed a button. This action
265:             * invokes {@link Model#move} with selected indices.
266:             */
267:            private static final class Action implements  ActionListener {
268:                /**
269:                 * The source and target lists.
270:                 */
271:                private final JList source, target;
272:
273:                /**
274:                 * {@code true} if we should move all items on action.
275:                 */
276:                private final boolean all;
277:
278:                /**
279:                 * Constructs a new "move" action.
280:                 */
281:                public Action(final JList source, final JList target,
282:                        final boolean all) {
283:                    this .source = source;
284:                    this .target = target;
285:                    this .all = all;
286:                }
287:
288:                /**
289:                 * Invoked when the user pressed a "move" button.
290:                 */
291:                public void actionPerformed(final ActionEvent event) {
292:                    final Model source = (Model) this .source.getModel();
293:                    final Model target = (Model) this .target.getModel();
294:                    if (all) {
295:                        target.move(source, 0, source.getSize());
296:                        return;
297:                    }
298:                    final int[] indices = this .source.getSelectedIndices();
299:                    target.move(source, indices);
300:                }
301:            }
302:
303:            /**
304:             * The list on the left side. This is the list that contains
305:             * the element selectable by the user.
306:             */
307:            private final JList left;
308:
309:            /**
310:             * The list on the right side. This list is initially empty.
311:             */
312:            private final JList right;
313:
314:            /**
315:             * {@code true} if elements should be automatically sorted.
316:             */
317:            private boolean autoSort = true;
318:
319:            /**
320:             * Construct a new list.
321:             */
322:            public DisjointLists() {
323:                super (new GridBagLayout());
324:                /*
325:                 * Setup lists
326:                 */
327:                final List choices = new ArrayList();
328:                left = new JList(new Model(choices));
329:                right = new JList(new Model(choices));
330:                final JScrollPane leftPane = new JScrollPane(left);
331:                final JScrollPane rightPane = new JScrollPane(right);
332:                final Dimension size = new Dimension(160, 200);
333:                leftPane.setPreferredSize(size);
334:                rightPane.setPreferredSize(size);
335:                /*
336:                 * Setup buttons
337:                 */
338:                final JButton add = getButton("StepForward", ">",
339:                        "Add selected elements");
340:                final JButton remove = getButton("StepBack", "<",
341:                        "Remove selected elements");
342:                final JButton addAll = getButton("FastForward", ">>", "Add all");
343:                final JButton removeAll = getButton("Rewind", "<<",
344:                        "Remove all");
345:                add.addActionListener(new Action(left, right, false));
346:                remove.addActionListener(new Action(right, left, false));
347:                addAll.addActionListener(new Action(left, right, true));
348:                removeAll.addActionListener(new Action(right, left, true));
349:                /*
350:                 * Build UI
351:                 */
352:                final GridBagConstraints c = new GridBagConstraints();
353:                c.gridy = 0;
354:                c.gridwidth = 1;
355:                c.gridheight = 4;
356:                c.weightx = c.weighty = 1;
357:                c.fill = c.BOTH;
358:                c.gridx = 0;
359:                add(leftPane, c);
360:                c.gridx = 2;
361:                add(rightPane, c);
362:
363:                c.insets.left = c.insets.right = 9;
364:                c.gridx = 1;
365:                c.gridheight = 1;
366:                c.weightx = 0;
367:                c.fill = c.HORIZONTAL;
368:                c.gridy = 0;
369:                c.anchor = c.SOUTH;
370:                add(add, c);
371:                c.gridy = 3;
372:                c.anchor = c.NORTH;
373:                add(removeAll, c);
374:                c.gridy = 2;
375:                c.weighty = 0;
376:                add(addAll, c);
377:                c.gridy = 1;
378:                c.insets.bottom = 9;
379:                add(remove, c);
380:            }
381:
382:            /**
383:             * Returns a button.
384:             *
385:             * @param loader The class loader for loading the button's image.
386:             * @param image  The image name to load in the "media" category from the
387:             *               <A HREF="http://developer.java.sun.com/developer/techDocs/hi/repository/">Swing
388:             *               graphics repository</A>.
389:             * @param fallback The fallback to use if the image is not found.
390:             * @param description a brief description to use for tooltips.
391:             * @return The button.
392:             */
393:            private static JButton getButton(String image,
394:                    final String fallback, final String description) {
395:                image = "toolbarButtonGraphics/media/" + image + "16.gif";
396:                return IconFactory.DEFAULT.getButton(image, description,
397:                        fallback);
398:            }
399:
400:            /**
401:             * Returns {@code true} if elements are automatically sorted when added to this list.
402:             * The default value is {@code true}.
403:             *
404:             * @since 2.2
405:             */
406:            public boolean isAutoSortEnabled() {
407:                return autoSort;
408:            }
409:
410:            /**
411:             * Sets to {@code true} if elements should be automatically sorted when added to this list.
412:             *
413:             * @since 2.2
414:             */
415:            public void setAutoSortEnabled(final boolean autoSort) {
416:                if (autoSort != this .autoSort) {
417:                    this .autoSort = autoSort;
418:                    if (autoSort) {
419:                        final List elements = new ArrayList(((Model) left
420:                                .getModel()).choices);
421:                        clear();
422:                        addElements(elements);
423:                    }
424:                    firePropertyChange("autoSort", !autoSort, autoSort);
425:                }
426:            }
427:
428:            /**
429:             * Removes all elements from this list.
430:             *
431:             * @since 2.2
432:             */
433:            public void clear() {
434:                ((Model) left.getModel()).clear();
435:                ((Model) right.getModel()).clear();
436:            }
437:
438:            /**
439:             * Add all elements from the specified collection into the list on the left side.
440:             * Elements are sorted if {@link #isAutoSortEnabled} returns {@code true}.
441:             *
442:             * @param items Items to add.
443:             */
444:            public void addElements(final Collection items) {
445:                addElements(items.toArray());
446:            }
447:
448:            /**
449:             * Add all elements from the specified array into the list on the left side.
450:             * Elements are sorted if {@link #isAutoSortEnabled} returns {@code true}.
451:             *
452:             * @param items Items to add.
453:             *
454:             * @since 2.2
455:             */
456:            public void addElements(final Object[] items) {
457:                Locale locale;
458:                try {
459:                    locale = getLocale();
460:                } catch (IllegalComponentStateException e) {
461:                    locale = getDefaultLocale();
462:                }
463:                final List list = new ArrayList(items.length);
464:                for (int i = 0; i < items.length; i++) {
465:                    Object candidate = items[i];
466:                    if (!(candidate instanceof  String)) {
467:                        candidate = new ListElement(candidate, locale);
468:                    }
469:                    list.add(candidate);
470:                }
471:                final Model left = (Model) this .left.getModel();
472:                final Model right = (Model) this .right.getModel();
473:                if (autoSort) {
474:                    list.addAll(left.choices);
475:                    Collections.sort(list);
476:                    left.clear();
477:                    right.clear();
478:                }
479:                left.addAll(list);
480:            }
481:
482:            /**
483:             * Returns all elements with the specified selection state. If {@code selected} is {@code true},
484:             * then this method returns the selected elements on the right side. If {@code selected} is
485:             * {@code false}, then this method returns the unselected elements on the left side.
486:             *
487:             * @since 2.3
488:             */
489:            public Collection getElements(final boolean selected) {
490:                return ((Model) (selected ? right : left).getModel())
491:                        .getElements();
492:            }
493:
494:            /**
495:             * Add the specified elements to the selection list (the one to appears on the right side). If
496:             * an element specified in the {@code selected} collection has not been previously {@linkplain
497:             * #addElements(Collection) added}, it will be ignored.
498:             *
499:             * @since 2.3
500:             */
501:            public void selectElements(final Collection selected) {
502:                final Model source = (Model) left.getModel();
503:                final Model target = (Model) right.getModel();
504:                int[] indices = new int[Math.min(selected.size(),
505:                        source.choices.size())];
506:                int indice = 0, count = 0;
507:                for (final Iterator it = source.choices.iterator(); it
508:                        .hasNext(); indice++) {
509:                    if (selected.contains(ListElement.unwrap(it.next()))) {
510:                        indices[count++] = indice;
511:                    }
512:                }
513:                indices = XArray.resize(indices, count);
514:                target.move(source, indices);
515:            }
516:
517:            /**
518:             * Set the font for both lists on the left and right side.
519:             */
520:            public void setFont(final Font font) {
521:                // Note: 'left' and 'right' may be null during JComponent initialisation.
522:                if (left != null)
523:                    left.setFont(font);
524:                if (right != null)
525:                    right.setFont(font);
526:                super .setFont(font);
527:            }
528:
529:            /**
530:             * Display this component in a dialog box and wait for the user to press "Ok".
531:             * This method can be invoked from any thread.
532:             *
533:             * @param  owner The owner (may be null).
534:             * @param  title The title to write in the window bar.
535:             * @return {@code true} if the user pressed "okay", or {@code false} otherwise.
536:             *
537:             * @since 2.2
538:             */
539:            public boolean showDialog(final Component owner, final String title) {
540:                return SwingUtilities.showOptionDialog(owner, this , title);
541:            }
542:
543:            /**
544:             * Show the dialog box. This method is provided only as an easy
545:             * way to test the dialog appearance from the command line.
546:             *
547:             * @since 2.2
548:             */
549:            public static void main(final String[] args) {
550:                final DisjointLists list = new DisjointLists();
551:                list.addElements(Locale.getAvailableLocales());
552:                list.showDialog(null, Utilities.getShortClassName(list));
553:                System.out.println(list.getElements(true));
554:            }
555:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.