Source Code Cross Referenced for IndirectListModel.java in  » Swing-Library » jgoodies-data-binding » com » jgoodies » binding » list » 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 » Swing Library » jgoodies data binding » com.jgoodies.binding.list 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Copyright (c) 2002-2007 JGoodies Karsten Lentzsch. All Rights Reserved.
003:         *
004:         * Redistribution and use in source and binary forms, with or without
005:         * modification, are permitted provided that the following conditions are met:
006:         *
007:         *  o Redistributions of source code must retain the above copyright notice,
008:         *    this list of conditions and the following disclaimer.
009:         *
010:         *  o Redistributions in binary form must reproduce the above copyright notice,
011:         *    this list of conditions and the following disclaimer in the documentation
012:         *    and/or other materials provided with the distribution.
013:         *
014:         *  o Neither the name of JGoodies Karsten Lentzsch nor the names of
015:         *    its contributors may be used to endorse or promote products derived
016:         *    from this software without specific prior written permission.
017:         *
018:         * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
019:         * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
020:         * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
021:         * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
022:         * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
023:         * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
024:         * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
025:         * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
026:         * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
027:         * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
028:         * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
029:         */
030:
031:        package com.jgoodies.binding.list;
032:
033:        import java.beans.PropertyChangeEvent;
034:        import java.beans.PropertyChangeListener;
035:        import java.io.Serializable;
036:        import java.util.Arrays;
037:        import java.util.Collections;
038:        import java.util.List;
039:
040:        import javax.swing.ListModel;
041:        import javax.swing.event.EventListenerList;
042:        import javax.swing.event.ListDataEvent;
043:        import javax.swing.event.ListDataListener;
044:
045:        import com.jgoodies.binding.PresentationModel;
046:        import com.jgoodies.binding.beans.BeanAdapter;
047:        import com.jgoodies.binding.beans.Model;
048:        import com.jgoodies.binding.value.ValueHolder;
049:        import com.jgoodies.binding.value.ValueModel;
050:
051:        /**
052:         * A ListModel implementation that holds a List or ListModel in a ValueModel.
053:         * If you hold a List, this class can only report that the List has been
054:         * replaced; this is done by firing a PropertyChangeEvent for the <em>list</em>
055:         * property. Also, a <code>ListDataEvent</code> is fired that reports
056:         * a complete change. In contrast, if you use a ListModel it will report
057:         * the same PropertyChangeEvent. But fine grained changes in the ListModel
058:         * will be fired by this class to notify observes about changes in the content,
059:         * added and removed elements.<p>
060:         *
061:         * If the list content doesn't change at all, or if it always changes
062:         * completely, you can work well with both List content and ListModel content.
063:         * But if the list structure or content changes, the ListModel reports more
064:         * fine grained events to registered ListDataListeners, which in turn allows
065:         * list views to chooser better user interface gestures: for example, a table
066:         * with scroll pane may retain the current selection and scroll offset.<p>
067:         *
068:         * If you want to combine List operations and the ListModel change reports,
069:         * you may consider using an implementation that combines these two interfaces,
070:         * for example {@link ArrayListModel} or {@link LinkedListModel}.<p>
071:         *
072:         * <strong>Important Note:</strong> If you change the ListModel instance,
073:         * either by calling <code>#setListModel(ListModel)</code> or by setting
074:         * a new value to the underlying list holder, you must ensure that
075:         * the list holder throws a PropertyChangeEvent whenever the instance changes.
076:         * This event is used to remove a ListDataListener from the old ListModel
077:         * instance and is later used to add it to the new ListModel instance.
078:         * It is easy to violate this constraint, just because Java's standard
079:         * PropertyChangeSupport helper class that is used by many beans, checks
080:         * a changed property value via <code>#equals</code>, not <code>==</code>.
081:         * For example, if you change the IndirectListModel's list model from an empty
082:         * list <code>L1</code> to another empty list instance <code>L2</code>,
083:         * the PropertyChangeSupport won't generate a PropertyChangeEvent,
084:         * and so, the IndirectListModel won't know about the change, which
085:         * may lead to unexpected behavior.<p>
086:         *
087:         * This binding library provides some help for firing PropertyChangeEvents
088:         * if the old ListModel and new ListModel are equal but not the same.
089:         * Class {@link com.jgoodies.binding.beans.ExtendedPropertyChangeSupport}
090:         * allows to permanently or individually check the identity (using
091:         * <code>==</code>) instead of checking the equity (using <code>#equals</code>).
092:         * Class {@link com.jgoodies.binding.beans.Model} uses this extended
093:         * property change support. And class {@link ValueHolder} uses it too
094:         * and can be configured to always test the identity.<p>
095:         *
096:         * This class provides public convenience methods for firing ListDataEvents,
097:         * see the methods <code>#fireContentsChanged</code>,
098:         * <code>#fireIntervalAdded</code>, and <code>#fireIntervalRemoved</code>.
099:         * These are automatically invoked if the list holder holds a ListModel
100:         * that fires these events. If on the other hand the underlying List or
101:         * ListModel does not fire a required ListDataEvent, you can use these
102:         * methods to notify presentations about a change. It is recommended
103:         * to avoid sending duplicate ListDataEvents; hence check if the underlying
104:         * ListModel fires the necessary events or not.<p>
105:         *
106:         * <strong>Constraints:</strong> The list holder holds instances of {@link List}
107:         * or {@link ListModel}. If the ListModel changes, the underlying ValueModel
108:         * must fire a PropertyChangeEvent.
109:         *
110:         * @author  Karsten Lentzsch
111:         * @version $Revision: 1.7 $
112:         *
113:         * @see     List
114:         * @see     ListModel
115:         * @see     SelectionInList
116:         * @see     ValueModel
117:         * @see     com.jgoodies.binding.adapter.ComboBoxAdapter
118:         * @see     com.jgoodies.binding.adapter.AbstractTableAdapter
119:         * @see     com.jgoodies.binding.beans.ExtendedPropertyChangeSupport
120:         * @see     com.jgoodies.binding.beans.Model
121:         * @see     com.jgoodies.binding.value.ValueHolder
122:         *
123:         * @param <E>  the type of the list elements
124:         *
125:         * @since 2.0
126:         */
127:        public class IndirectListModel<E> extends Model implements  ListModel {
128:
129:            // Constant Names for Bound Properties ************************************
130:
131:            /**
132:             * The name of the bound write-only <em>list</em> property.
133:             */
134:            public static final String PROPERTYNAME_LIST = "list";
135:
136:            /**
137:             * The name of the bound read-write <em>listHolder</em> property.
138:             */
139:            public static final String PROPERTYNAME_LIST_HOLDER = "listHolder";
140:
141:            // ************************************************************************
142:
143:            /**
144:             * An empty <code>ListModel</code> that is used if the list holder's
145:             * content is null.
146:             *
147:             * @see #getListModel()
148:             */
149:            private static final ListModel EMPTY_LIST_MODEL = new EmptyListModel();
150:
151:            // Instance Fields ********************************************************
152:
153:            /**
154:             * Holds a <code>List</code> or <code>ListModel</code> that in turn
155:             * holds the elements.
156:             */
157:            private ValueModel listHolder;
158:
159:            /**
160:             * Holds a copy of the listHolder's value. Used as the old list
161:             * when the listHolder's value changes. Required because a ValueModel
162:             * may use {@code null} as old value, but the IndirectListModel
163:             * must know about the old and the new list.
164:             */
165:            private Object list;
166:
167:            /**
168:             * The size of the current list. Used during changes from an old
169:             * to a new list to check for shorter or longer lists, which in turn
170:             * leads to different ListDataEvents.
171:             * Required only if the old and new list are the same instance.
172:             */
173:            private int listSize;
174:
175:            /**
176:             * Handles changes of the list.
177:             */
178:            private final PropertyChangeListener listChangeHandler;
179:
180:            /**
181:             * Handles structural and content changes of the list model.
182:             */
183:            private final ListDataListener listDataChangeHandler;
184:
185:            /**
186:             * Refers to the list of list data listeners that is used
187:             * to notify registered listeners if the ListModel changes.
188:             */
189:            private final EventListenerList listenerList = new EventListenerList();
190:
191:            // Instance creation ****************************************************
192:
193:            /**
194:             * Constructs an IndirectListModel with an empty initial
195:             * {@code ArrayListModel}.
196:             */
197:            public IndirectListModel() {
198:                this ((ListModel) new ArrayListModel<E>());
199:            }
200:
201:            /**
202:             * Constructs an IndirectListModel on the given item array.
203:             * The specified array will be converted to a List.<p>
204:             *
205:             * Changes to the list "write through" to the array, and changes
206:             * to the array contents will be reflected in the list.
207:             *
208:             * @param listItems        the array of initial items
209:             *
210:             * @throws NullPointerException if <code>listItems</code> is {@code null}
211:             */
212:            public IndirectListModel(E[] listItems) {
213:                this (Arrays.asList(listItems));
214:            }
215:
216:            /**
217:             * Constructs an IndirectListModel on the given list.<p>
218:             *
219:             * <strong>Note:</strong> Favor <code>ListModel</code> over
220:             * <code>List</code> when working with an IndirectListModel.
221:             * Why? The IndirectListModel can work with both types. What's the
222:             * difference? ListModel provides all list access features
223:             * required by the IndirectListModel's. In addition it reports more
224:             * fine grained change events, instances of <code>ListDataEvents</code>.
225:             * In contrast developer often create Lists and operate on them
226:             * and the ListModel may be inconvenient for these operations.<p>
227:             *
228:             * A convenient solution for this situation is to use the
229:             * <code>ArrayListModel</code> and <code>LinkedListModel</code> classes.
230:             * These implement both List and ListModel, offer the standard List
231:             * operations and report the fine grained ListDataEvents.
232:             *
233:             * @param list        the initial list
234:             */
235:            public IndirectListModel(List<E> list) {
236:                this (new ValueHolder(list, true));
237:            }
238:
239:            /**
240:             * Constructs an IndirectListModel on the given list model
241:             * using a default list holder.
242:             *
243:             * @param listModel        the initial list model
244:             */
245:            public IndirectListModel(ListModel listModel) {
246:                this (new ValueHolder(listModel, true));
247:            }
248:
249:            /**
250:             * Constructs an IndirectListModel on the given list holder.<p>
251:             *
252:             * <strong>Constraints:</strong>
253:             * 1) The listHolder must hold instances of List or ListModel and
254:             * 2) must report a value change whenever the value's identity changes.
255:             * Note that many bean properties don't fire a PropertyChangeEvent
256:             * if the old and new value are equal - and so would break this constraint.
257:             * If you provide a ValueHolder, enable its identityCheck feature
258:             * during construction. If you provide an adapted bean property from
259:             * a bean that extends the JGoodies <code>Model</code> class,
260:             * you can enable the identity check feature in the methods
261:             * <code>#firePropertyChange</code> by setting the trailing boolean
262:             * parameter to <code>true</code>.
263:             *
264:             * @param listHolder          holds the list or list model
265:             *
266:             * @throws NullPointerException
267:             *     if <code>listHolder</code> is {@code null}
268:             */
269:            public IndirectListModel(ValueModel listHolder) {
270:                if (listHolder == null)
271:                    throw new NullPointerException(
272:                            "The list holder must not be null.");
273:                checkListHolderIdentityCheck(listHolder);
274:
275:                listChangeHandler = new ListChangeHandler();
276:                listDataChangeHandler = createListDataChangeHandler();
277:
278:                this .listHolder = listHolder;
279:
280:                this .listHolder.addValueChangeListener(listChangeHandler);
281:
282:                // If the ValueModel holds a ListModel observe list data changes too.
283:                list = listHolder.getValue();
284:                listSize = getSize(list);
285:                if (list != null) {
286:                    if (list instanceof  ListModel) {
287:                        ((ListModel) list)
288:                                .addListDataListener(listDataChangeHandler);
289:                    } else if (!(list instanceof  List)) {
290:                        throw new ClassCastException(
291:                                "The listHolder's value must be a List or ListModel.");
292:                    }
293:                }
294:            }
295:
296:            // Accessing the List/ListModel *******************************************
297:
298:            /**
299:             * Returns the list holder's List or an empty List, if it
300:             * holds {@code null}. Throws an exception if the list holder holds
301:             * any other type, including ListModels.
302:             *
303:             * @return the List content or an empty List if the content is {@code null}
304:             *
305:             * @throws ClassCastException if the list holder is neither
306:             *     {@code null} nor a List
307:             *
308:             * @see #setList(List)
309:             * @see #getListModel()
310:             * @see #setListModel(ListModel)
311:             *
312:             * @since 2.0
313:             */
314:            public final List<E> getList() {
315:                Object aList = getListHolder().getValue();
316:                if (aList == null)
317:                    return Collections.<E> emptyList();
318:                if (aList instanceof  List)
319:                    return (List<E>) aList;
320:                throw new ClassCastException(
321:                        "#getList assumes that the list holder holds a List");
322:            }
323:
324:            /**
325:             * Sets the given list as value of the list holder.<p>
326:             *
327:             * <strong>Note:</strong> Favor <code>ListModel</code> over
328:             * <code>List</code> when working with an IndirectListModel.
329:             * Why? The IndirectListModel can work with both types. What's the
330:             * difference? ListModel provides all list access features
331:             * required by the IndirectListModel's. In addition it reports more
332:             * fine grained change events, instances of <code>ListDataEvents</code>.
333:             * In contrast developer often create Lists and operate on them
334:             * and the ListModel may be inconvenient for these operations.<p>
335:             *
336:             * A convenient solution for this situation is to use the
337:             * <code>ArrayListModel</code> and <code>LinkedListModel</code> classes.
338:             * These implement both List and ListModel, offer the standard List
339:             * operations and report the fine grained ListDataEvents.
340:             *
341:             * @param newList   the list to be set as new list content
342:             *
343:             * @see #getList()
344:             * @see #getListModel()
345:             * @see #setListModel(ListModel)
346:             */
347:            public final void setList(List<E> newList) {
348:                getListHolder().setValue(newList);
349:            }
350:
351:            /**
352:             * Returns the list holder's ListModel or an empty ListModel, if it
353:             * holds {@code null}. Throws an exception if the list holder holds
354:             * any other type, including Lists.
355:             *
356:             * @return the ListModel content or an empty ListModel
357:             *     if the content is {@code null}
358:             *
359:             * @throws ClassCastException if the list holder is neither
360:             *     {@code null} nor a ListModel
361:             *
362:             * @see #setListModel(ListModel)
363:             * @see #setList(List)
364:             */
365:            public final ListModel getListModel() {
366:                Object aListModel = getListHolder().getValue();
367:                if (aListModel == null)
368:                    return EMPTY_LIST_MODEL;
369:                if (aListModel instanceof  ListModel)
370:                    return (ListModel) aListModel;
371:                throw new ClassCastException(
372:                        "#getListModel assumes that the list holder holds a ListModel");
373:            }
374:
375:            /**
376:             * Sets the given list model as value of the list holder.
377:             *
378:             * @param newListModel   the list model to be set as new list content
379:             *
380:             * @see #getListModel()
381:             * @see #setList(List)
382:             */
383:            public final void setListModel(ListModel newListModel) {
384:                getListHolder().setValue(newListModel);
385:            }
386:
387:            // Accessing the List/ListModel Holder ************************************
388:
389:            /**
390:             * Returns the model that holds the List/ListModel.
391:             *
392:             * @return the model that holds the List/ListModel
393:             */
394:            public final ValueModel getListHolder() {
395:                return listHolder;
396:            }
397:
398:            /**
399:             * Sets a new list holder. Does nothing if old and new holder are equal.
400:             * Removes the list change handler from the old holder and adds
401:             * it to the new one. In case the list holder contents is a ListModel,
402:             * the list data change handler is updated too by invoking
403:             * <code>#updateListDataRegistration</code> in the same way as done in the
404:             * list change handler.<p>
405:             *
406:             * TODO: Check and verify whether the list data registration update
407:             * can be performed in one step <em>after</em> the listHolder has been
408:             * changed - instead of remove the list data change handler, then
409:             * changing the listHolder, and finally adding the list data change handler.
410:             *
411:             * @param newListHolder   the list holder to be set
412:             *
413:             * @throws NullPointerException if the new list holder is {@code null}
414:             * @throws IllegalArgumentException if the listHolder is a ValueHolder
415:             *     that doesn't check the identity when changing its value
416:             */
417:            public final void setListHolder(ValueModel newListHolder) {
418:                if (newListHolder == null)
419:                    throw new NullPointerException(
420:                            "The new list holder must not be null.");
421:                checkListHolderIdentityCheck(newListHolder);
422:
423:                ValueModel oldListHolder = getListHolder();
424:                if (oldListHolder == newListHolder)
425:                    return;
426:
427:                Object oldList = list;
428:                int oldSize = listSize;
429:                Object newList = newListHolder.getValue();
430:
431:                oldListHolder.removeValueChangeListener(listChangeHandler);
432:                listHolder = newListHolder;
433:                newListHolder.addValueChangeListener(listChangeHandler);
434:
435:                updateList(oldList, oldSize, newList);
436:                firePropertyChange(PROPERTYNAME_LIST_HOLDER, oldListHolder,
437:                        newListHolder);
438:            }
439:
440:            // ListModel Implementation ***********************************************
441:
442:            /**
443:             * Checks and answers if the list is empty or {@code null}.
444:             *
445:             * @return true if the list is empty or {@code null}, false otherwise
446:             */
447:            public final boolean isEmpty() {
448:                return getSize() == 0;
449:            }
450:
451:            /**
452:             * Returns the length of the list, <code>0</code> if the list model
453:             * is {@code null}.
454:             *
455:             * @return the size of the list, <code>0</code> if the list model is
456:             *     {@code null}
457:             */
458:            public final int getSize() {
459:                return getSize(getListHolder().getValue());
460:            }
461:
462:            /**
463:             * Returns the value at the specified index, {@code null}
464:             * if the list model is {@code null}.
465:             *
466:             * @param index  the requested index
467:             * @return the value at <code>index</code>, {@code null}
468:             *      if the list model is {@code null}
469:             *
470:             * @throws NullPointerException if the list holder's content is null
471:             */
472:            public final E getElementAt(int index) {
473:                return getElementAt(getListHolder().getValue(), index);
474:            }
475:
476:            /**
477:             * Adds a listener to the list that's notified each time a change
478:             * to the data model occurs.
479:             *
480:             * @param l the <code>ListDataListener</code> to be added
481:             */
482:            public final void addListDataListener(ListDataListener l) {
483:                listenerList.add(ListDataListener.class, l);
484:            }
485:
486:            /**
487:             * Removes a listener from the list that's notified each time a
488:             * change to the data model occurs.
489:             *
490:             * @param l the <code>ListDataListener</code> to be removed
491:             */
492:            public final void removeListDataListener(ListDataListener l) {
493:                listenerList.remove(ListDataListener.class, l);
494:            }
495:
496:            /**
497:             * Returns an array of all the list data listeners
498:             * registered on this <code>IndirectListModel</code>.
499:             *
500:             * @return all of this model's <code>ListDataListener</code>s,
501:             *         or an empty array if no list data listeners
502:             *         are currently registered
503:             *
504:             * @see #addListDataListener(ListDataListener)
505:             * @see #removeListDataListener(ListDataListener)
506:             */
507:            public final ListDataListener[] getListDataListeners() {
508:                return listenerList.getListeners(ListDataListener.class);
509:            }
510:
511:            // ListModel Helper Code **************************************************
512:
513:            /**
514:             * Notifies all registered ListDataListeners that the contents
515:             * of one or more list elements has changed.
516:             * The changed elements are specified by the closed interval index0, index1
517:             * -- the end points are included. Note that index0 need not be less than
518:             * or equal to index1.<p>
519:             *
520:             * If the list holder holds a ListModel, this IndirectListModel listens
521:             * to ListDataEvents fired by that ListModel, and forwards these events
522:             * by invoking the associated <code>#fireXXX</code> method, which in turn
523:             * notifies all registered ListDataListeners. Therefore if you fire
524:             * ListDataEvents in an underlying ListModel, you don't need this method
525:             * and should not use it to avoid sending duplicate ListDataEvents.
526:             *
527:             * @param index0 one end of the new interval
528:             * @param index1 the other end of the new interval
529:             *
530:             * @see ListModel
531:             * @see ListDataListener
532:             * @see ListDataEvent
533:             *
534:             * @since 1.0.2
535:             */
536:            public final void fireContentsChanged(int index0, int index1) {
537:                Object[] listeners = listenerList.getListenerList();
538:                ListDataEvent e = null;
539:
540:                for (int i = listeners.length - 2; i >= 0; i -= 2) {
541:                    if (listeners[i] == ListDataListener.class) {
542:                        if (e == null) {
543:                            e = new ListDataEvent(this ,
544:                                    ListDataEvent.CONTENTS_CHANGED, index0,
545:                                    index1);
546:                        }
547:                        ((ListDataListener) listeners[i + 1])
548:                                .contentsChanged(e);
549:                    }
550:                }
551:            }
552:
553:            /**
554:             * Notifies all registered ListDataListeners that one or more elements
555:             * have been added to this IndirectListModel's List/ListModel.
556:             * The new elements are specified by a closed interval index0, index1
557:             * -- the end points are included. Note that index0 need not be less than
558:             * or equal to index1.<p>
559:             *
560:             * If the list holder holds a ListModel, this IndirectListModel listens
561:             * to ListDataEvents fired by that ListModel, and forwards these events
562:             * by invoking the associated <code>#fireXXX</code> method, which in turn
563:             * notifies all registered ListDataListeners. Therefore if you fire
564:             * ListDataEvents in an underlying ListModel, you don't need this method
565:             * and should not use it to avoid sending duplicate ListDataEvents.
566:             *
567:             * @param index0 one end of the new interval
568:             * @param index1 the other end of the new interval
569:             *
570:             * @see ListModel
571:             * @see ListDataListener
572:             * @see ListDataEvent
573:             *
574:             * @since 1.0.2
575:             */
576:            public final void fireIntervalAdded(int index0, int index1) {
577:                Object[] listeners = listenerList.getListenerList();
578:                ListDataEvent e = null;
579:                listSize = getSize();
580:
581:                for (int i = listeners.length - 2; i >= 0; i -= 2) {
582:                    if (listeners[i] == ListDataListener.class) {
583:                        if (e == null) {
584:                            e = new ListDataEvent(this ,
585:                                    ListDataEvent.INTERVAL_ADDED, index0,
586:                                    index1);
587:                        }
588:                        ((ListDataListener) listeners[i + 1]).intervalAdded(e);
589:                    }
590:                }
591:            }
592:
593:            /**
594:             * Notifies all registered ListDataListeners that one or more elements
595:             * have been removed from this IndirectListModel's List/ListModel.
596:             * <code>index0</code> and <code>index1</code> are the end points
597:             * of the interval that's been removed.  Note that <code>index0</code>
598:             * need not be less than or equal to <code>index1</code>.<p>
599:             *
600:             * If the list holder holds a ListModel, this IndirectListModel listens
601:             * to ListDataEvents fired by that ListModel, and forwards these events
602:             * by invoking the associated <code>#fireXXX</code> method, which in turn
603:             * notifies all registered ListDataListeners. Therefore if you fire
604:             * ListDataEvents in an underlying ListModel, you don't need this method
605:             * and should not use it to avoid sending duplicate ListDataEvents.
606:             *
607:             * @param index0 one end of the removed interval,
608:             *               including <code>index0</code>
609:             * @param index1 the other end of the removed interval,
610:             *               including <code>index1</code>
611:             *
612:             * @see ListModel
613:             * @see ListDataListener
614:             * @see ListDataEvent
615:             *
616:             * @since 1.0.2
617:             */
618:            public final void fireIntervalRemoved(int index0, int index1) {
619:                Object[] listeners = listenerList.getListenerList();
620:                ListDataEvent e = null;
621:                listSize = getSize();
622:
623:                for (int i = listeners.length - 2; i >= 0; i -= 2) {
624:                    if (listeners[i] == ListDataListener.class) {
625:                        if (e == null) {
626:                            e = new ListDataEvent(this ,
627:                                    ListDataEvent.INTERVAL_REMOVED, index0,
628:                                    index1);
629:                        }
630:                        ((ListDataListener) listeners[i + 1])
631:                                .intervalRemoved(e);
632:                    }
633:                }
634:            }
635:
636:            // Misc ******************************************************************
637:
638:            /**
639:             * Removes the internal listeners from the list holder. If the current list
640:             * is a ListModel, the internal ListDataListener is removed from it.
641:             * This IndirectListModel must not be used after calling
642:             * <code>#release</code>.<p>
643:             *
644:             * To avoid memory leaks it is recommended to invoke this method,
645:             * if the list holder, selection holder, or selection index holder
646:             * live much longer than this IndirectListModel.
647:             * Instead of releasing the IndirectListModel, you typically make the
648:             * list holder obsolete by releasing the PresentationModel or BeanAdapter
649:             * that has created them before.<p>
650:             *
651:             * As an alternative you may use ValueModels that in turn use
652:             * event listener lists implemented using <code>WeakReference</code>.<p>
653:             *
654:             * Basically this release method performs the reverse operation
655:             * performed during the IndirectListModel construction.
656:             *
657:             * @see PresentationModel#release()
658:             * @see BeanAdapter#release()
659:             * @see java.lang.ref.WeakReference
660:             *
661:             * @since 1.2
662:             */
663:            public void release() {
664:                listHolder.removeValueChangeListener(listChangeHandler);
665:                if (list != null && (list instanceof  ListModel)) {
666:                    ((ListModel) list)
667:                            .removeListDataListener(listDataChangeHandler);
668:                }
669:                listHolder = null;
670:                list = null;
671:            }
672:
673:            // Default Behavior *******************************************************
674:
675:            /**
676:             * Creates and returns the ListDataListener used to observe
677:             * changes in the underlying ListModel. It is re-registered
678:             * in <code>#updateListModel</code>.
679:             *
680:             * @return the ListDataListener that handles changes
681:             *     in the underlying ListModel
682:             */
683:            protected ListDataListener createListDataChangeHandler() {
684:                return new ListDataChangeHandler();
685:            }
686:
687:            /**
688:             * Removes the list data change handler from the old list in case
689:             * it is a <code>ListModel</code> and adds it to new one in case
690:             * it is a <code>ListModel</code>.
691:             * It then fires a property change for the list and a contents change event
692:             * for the list content.
693:             *
694:             * @param oldList   the old list content
695:             * @param oldSize   the size of the old List content
696:             * @param newList   the new list content
697:             *
698:             * @see javax.swing.JTable#tableChanged(javax.swing.event.TableModelEvent)
699:             */
700:            protected void updateList(Object oldList, int oldSize,
701:                    Object newList) {
702:                if (oldList != null && (oldList instanceof  ListModel)) {
703:                    ((ListModel) oldList)
704:                            .removeListDataListener(listDataChangeHandler);
705:                }
706:                if (newList != null && (newList instanceof  ListModel)) {
707:                    ((ListModel) newList)
708:                            .addListDataListener(listDataChangeHandler);
709:                }
710:                int newSize = getSize(newList);
711:                list = newList;
712:                listSize = getSize(newList);
713:                firePropertyChange(PROPERTYNAME_LIST, oldList, newList);
714:                fireListChanged(oldSize - 1, newSize - 1);
715:            }
716:
717:            /**
718:             * Notifies all registered ListDataListeners that this ListModel
719:             * has changed from an old list to a new list content.
720:             * If the old and new list size differ, a remove or add event for
721:             * the removed or added interval is fired. A content change
722:             * is reported for the interval common to the old and new list.<p>
723:             *
724:             * This method is invoked by #updateList during the transition
725:             * from an old List(Model) to a new List(Model).<p>
726:             *
727:             * <strong>Note:</strong>
728:             * The order of the events fired ensures that after each event
729:             * the size described by the ListDataEvents equals the ListModel size.
730:             *
731:             * @param oldLastIndex   the last index of the old list
732:             * @param newLastIndex   the last index of the new list
733:             */
734:            protected final void fireListChanged(int oldLastIndex,
735:                    int newLastIndex) {
736:                if (newLastIndex < oldLastIndex) {
737:                    fireIntervalRemoved(newLastIndex + 1, oldLastIndex);
738:                } else if (oldLastIndex < newLastIndex) {
739:                    fireIntervalAdded(oldLastIndex + 1, newLastIndex);
740:                }
741:                int lastCommonIndex = Math.min(oldLastIndex, newLastIndex);
742:                if (lastCommonIndex >= 0) {
743:                    fireContentsChanged(0, lastCommonIndex);
744:                }
745:            }
746:
747:            // Helper Code ************************************************************
748:
749:            /**
750:             * Returns the length of the given list, <code>0</code> if the list model
751:             * is {@code null}.
752:             *
753:             * @param aListListModelOrNull  a List, ListModel or null
754:             * @return the size of the given list, <code>0</code> if the list model is
755:             *     {@code null}
756:             */
757:            protected final int getSize(Object aListListModelOrNull) {
758:                if (aListListModelOrNull == null)
759:                    return 0;
760:                else if (aListListModelOrNull instanceof  ListModel)
761:                    return ((ListModel) aListListModelOrNull).getSize();
762:                else
763:                    return ((List<?>) aListListModelOrNull).size();
764:            }
765:
766:            private E getElementAt(Object aList, int index) {
767:                if (aList == null)
768:                    throw new NullPointerException("The list contents is null.");
769:                else if (aList instanceof  ListModel)
770:                    return (E) ((ListModel) aList).getElementAt(index);
771:                else
772:                    return ((List<E>) aList).get(index);
773:            }
774:
775:            /**
776:             * Throws an IllegalArgumentException if the given ValueModel
777:             * is a ValueHolder that has the identityCheck feature disabled.
778:             */
779:            private void checkListHolderIdentityCheck(ValueModel aListHolder) {
780:                if (!(aListHolder instanceof  ValueHolder))
781:                    return;
782:
783:                ValueHolder valueHolder = (ValueHolder) aListHolder;
784:                if (!valueHolder.isIdentityCheckEnabled())
785:                    throw new IllegalArgumentException(
786:                            "The list holder must have the identity check enabled.");
787:            }
788:
789:            // Helper Classes *********************************************************
790:
791:            /**
792:             * A ListModel that has no elements, a size of 0, and never fires an event.
793:             */
794:            private static final class EmptyListModel implements  ListModel,
795:                    Serializable {
796:
797:                /**
798:                 * Returns zero to indicate an empty list.
799:                 */
800:                public int getSize() {
801:                    return 0;
802:                }
803:
804:                /**
805:                 * Returns {@code null} because this model has no elements.
806:                 */
807:                public Object getElementAt(int index) {
808:                    return null;
809:                }
810:
811:                /**
812:                 * Does nothing, because the empty list will never fire an event.
813:                 *
814:                 * @param l the <code>ListDataListener</code> to be ignored
815:                 */
816:                public void addListDataListener(ListDataListener l) {
817:                    // Do nothing.
818:                }
819:
820:                /**
821:                 * Does nothing, because the empty list will never fire an event.
822:                 *
823:                 * @param l the <code>ListDataListener</code> to be ignored
824:                 */
825:                public void removeListDataListener(ListDataListener l) {
826:                    // Do nothing.
827:                }
828:
829:            }
830:
831:            // Event Handlers *********************************************************
832:
833:            /**
834:             * Handles changes of the List or ListModel.
835:             */
836:            private final class ListChangeHandler implements 
837:                    PropertyChangeListener {
838:
839:                /**
840:                 * The list has been changed.
841:                 * Notifies all registered listeners about the change.
842:                 *
843:                 * @param evt   the property change event to be handled
844:                 */
845:                public void propertyChange(PropertyChangeEvent evt) {
846:                    Object oldList = list;
847:                    int oldSize = listSize;
848:                    Object newList = evt.getNewValue();
849:                    updateList(oldList, oldSize, newList);
850:                }
851:            }
852:
853:            /**
854:             * Handles ListDataEvents in the list model.
855:             */
856:            private final class ListDataChangeHandler implements 
857:                    ListDataListener {
858:
859:                /**
860:                 * Sent after the indices in the index0, index1
861:                 * interval have been inserted in the data model.
862:                 * The new interval includes both index0 and index1.
863:                 *
864:                 * @param evt  a <code>ListDataEvent</code> encapsulating the
865:                 *    event information
866:                 */
867:                public void intervalAdded(ListDataEvent evt) {
868:                    int index0 = evt.getIndex0();
869:                    int index1 = evt.getIndex1();
870:                    fireIntervalAdded(index0, index1);
871:                }
872:
873:                /**
874:                 * Sent after the indices in the index0, index1 interval
875:                 * have been removed from the data model.  The interval
876:                 * includes both index0 and index1.
877:                 *
878:                 * @param evt  a <code>ListDataEvent</code> encapsulating the
879:                 *    event information
880:                 */
881:                public void intervalRemoved(ListDataEvent evt) {
882:                    int index0 = evt.getIndex0();
883:                    int index1 = evt.getIndex1();
884:                    fireIntervalRemoved(index0, index1);
885:                }
886:
887:                /**
888:                 * Sent when the contents of the list has changed in a way
889:                 * that's too complex to characterize with the previous
890:                 * methods. For example, this is sent when an item has been
891:                 * replaced. Index0 and index1 bracket the change.
892:                 *
893:                 * @param evt  a <code>ListDataEvent</code> encapsulating the
894:                 *    event information
895:                 */
896:                public void contentsChanged(ListDataEvent evt) {
897:                    fireContentsChanged(evt.getIndex0(), evt.getIndex1());
898:                }
899:
900:            }
901:
902:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.