Source Code Cross Referenced for JXList.java in  » Swing-Library » swingx » org » jdesktop » swingx » 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 » swingx » org.jdesktop.swingx 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*
0002:         * $Id: JXList.java,v 1.51 2007/01/25 13:19:00 kleopatra Exp $
0003:         *
0004:         * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
0005:         * Santa Clara, California 95054, U.S.A. All rights reserved.
0006:         *
0007:         * This library is free software; you can redistribute it and/or
0008:         * modify it under the terms of the GNU Lesser General Public
0009:         * License as published by the Free Software Foundation; either
0010:         * version 2.1 of the License, or (at your option) any later version.
0011:         * 
0012:         * This library is distributed in the hope that it will be useful,
0013:         * but WITHOUT ANY WARRANTY; without even the implied warranty of
0014:         * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0015:         * Lesser General Public License for more details.
0016:         * 
0017:         * You should have received a copy of the GNU Lesser General Public
0018:         * License along with this library; if not, write to the Free Software
0019:         * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
0020:         */
0021:
0022:        package org.jdesktop.swingx;
0023:
0024:        import java.awt.Component;
0025:        import java.awt.Cursor;
0026:        import java.awt.Point;
0027:        import java.awt.Rectangle;
0028:        import java.awt.event.ActionEvent;
0029:        import java.util.Collections;
0030:        import java.util.Comparator;
0031:        import java.util.List;
0032:        import java.util.Vector;
0033:        import java.util.regex.Matcher;
0034:        import java.util.regex.Pattern;
0035:
0036:        import javax.swing.AbstractListModel;
0037:        import javax.swing.Action;
0038:        import javax.swing.DefaultListCellRenderer;
0039:        import javax.swing.JComponent;
0040:        import javax.swing.JList;
0041:        import javax.swing.KeyStroke;
0042:        import javax.swing.ListCellRenderer;
0043:        import javax.swing.ListModel;
0044:        import javax.swing.ListSelectionModel;
0045:        import javax.swing.event.ChangeEvent;
0046:        import javax.swing.event.ChangeListener;
0047:        import javax.swing.event.ListDataEvent;
0048:        import javax.swing.event.ListDataListener;
0049:
0050:        import org.jdesktop.swingx.decorator.ComponentAdapter;
0051:        import org.jdesktop.swingx.decorator.DefaultSelectionMapper;
0052:        import org.jdesktop.swingx.decorator.FilterPipeline;
0053:        import org.jdesktop.swingx.decorator.Highlighter;
0054:        import org.jdesktop.swingx.decorator.HighlighterPipeline;
0055:        import org.jdesktop.swingx.decorator.PipelineEvent;
0056:        import org.jdesktop.swingx.decorator.PipelineListener;
0057:        import org.jdesktop.swingx.decorator.SelectionMapper;
0058:        import org.jdesktop.swingx.decorator.SortController;
0059:        import org.jdesktop.swingx.decorator.SortKey;
0060:        import org.jdesktop.swingx.decorator.SortOrder;
0061:        import org.jdesktop.swingx.renderer.DefaultListRenderer;
0062:
0063:        /**
0064:         * JXList
0065:         * 
0066:         * Enabled Rollover/LinkModel handling. Enabled Highlighter support.
0067:         * 
0068:         * Added experimental support for filtering/sorting. This feature is disabled by
0069:         * default because it has side-effects which might break "normal" expectations
0070:         * when using a JList: if enabled all row coordinates (including those returned
0071:         * by the selection) are in view coordinates. Furthermore, the model returned
0072:         * from getModel() is a wrapper around the actual data.
0073:         * 
0074:         * 
0075:         * 
0076:         * @author Ramesh Gupta
0077:         * @author Jeanette Winzenburg
0078:         */
0079:        public class JXList extends JList {
0080:            public static final String EXECUTE_BUTTON_ACTIONCOMMAND = "executeButtonAction";
0081:
0082:            /** The pipeline holding the filters. */
0083:            protected FilterPipeline filters;
0084:
0085:            /**
0086:             * The pipeline holding the highlighters.
0087:             */
0088:            protected HighlighterPipeline highlighters;
0089:
0090:            /** listening to changeEvents from highlighterPipeline. */
0091:            private ChangeListener highlighterChangeListener;
0092:
0093:            /** The ComponentAdapter for model data access. */
0094:            protected ComponentAdapter dataAdapter;
0095:
0096:            /**
0097:             * Mouse/Motion/Listener keeping track of mouse moved in cell coordinates.
0098:             */
0099:            private RolloverProducer rolloverProducer;
0100:
0101:            /**
0102:             * RolloverController: listens to cell over events and repaints
0103:             * entered/exited rows.
0104:             */
0105:            private ListRolloverController linkController;
0106:
0107:            /** A wrapper around the default renderer enabling decoration. */
0108:            private DelegatingRenderer delegatingRenderer;
0109:
0110:            private WrappingListModel wrappingModel;
0111:
0112:            private PipelineListener pipelineListener;
0113:
0114:            private boolean filterEnabled;
0115:
0116:            private SelectionMapper selectionMapper;
0117:
0118:            private Searchable searchable;
0119:
0120:            private Comparator comparator;
0121:
0122:            /**
0123:             * Constructs a <code>JXList</code> with an empty model and filters disabled.
0124:             *
0125:             */
0126:            public JXList() {
0127:                this (false);
0128:            }
0129:
0130:            /**
0131:             * Constructs a <code>JXList</code> that displays the elements in the
0132:             * specified, non-<code>null</code> model and filters disabled.
0133:             *
0134:             * @param dataModel   the data model for this list
0135:             * @exception IllegalArgumentException   if <code>dataModel</code>
0136:             *                                           is <code>null</code>
0137:             */
0138:            public JXList(ListModel dataModel) {
0139:                this (dataModel, false);
0140:            }
0141:
0142:            /**
0143:             * Constructs a <code>JXList</code> that displays the elements in
0144:             * the specified array and filters disabled.
0145:             *
0146:             * @param  listData  the array of Objects to be loaded into the data model
0147:             * @throws IllegalArgumentException   if <code>listData</code>
0148:             *                                          is <code>null</code>
0149:             */
0150:            public JXList(Object[] listData) {
0151:                this (listData, false);
0152:            }
0153:
0154:            /**
0155:             * Constructs a <code>JXList</code> that displays the elements in
0156:             * the specified <code>Vector</code> and filtes disabled.
0157:             *
0158:             * @param  listData  the <code>Vector</code> to be loaded into the
0159:             *          data model
0160:             * @throws IllegalArgumentException   if <code>listData</code>
0161:             *                                          is <code>null</code>
0162:             */
0163:            public JXList(Vector<?> listData) {
0164:                this (listData, false);
0165:            }
0166:
0167:            /**
0168:             * Constructs a <code>JXList</code> with an empty model and
0169:             * filterEnabled property.
0170:             * 
0171:             * @param filterEnabled <code>boolean</code> to determine if 
0172:             *  filtering/sorting is enabled
0173:             */
0174:            public JXList(boolean filterEnabled) {
0175:                init(filterEnabled);
0176:            }
0177:
0178:            /**
0179:             * Constructs a <code>JXList</code> with the specified model and
0180:             * filterEnabled property.
0181:             * 
0182:             * @param dataModel   the data model for this list
0183:             * @param filterEnabled <code>boolean</code> to determine if 
0184:             *          filtering/sorting is enabled
0185:             * @throws IllegalArgumentException   if <code>dataModel</code>
0186:             *                                          is <code>null</code>
0187:             */
0188:            public JXList(ListModel dataModel, boolean filterEnabled) {
0189:                super (dataModel);
0190:                init(filterEnabled);
0191:            }
0192:
0193:            /**
0194:             * Constructs a <code>JXList</code> that displays the elements in
0195:             * the specified array and filterEnabled property.
0196:             *
0197:             * @param  listData  the array of Objects to be loaded into the data model
0198:             * @param filterEnabled <code>boolean</code> to determine if filtering/sorting
0199:             *   is enabled
0200:             * @throws IllegalArgumentException   if <code>listData</code>
0201:             *                                          is <code>null</code>
0202:             */
0203:            public JXList(Object[] listData, boolean filterEnabled) {
0204:                super (listData);
0205:                if (listData == null)
0206:                    throw new IllegalArgumentException(
0207:                            "listData must not be null");
0208:                init(filterEnabled);
0209:            }
0210:
0211:            /**
0212:             * Constructs a <code>JXList</code> that displays the elements in
0213:             * the specified <code>Vector</code> and filtersEnabled property.
0214:             *
0215:             * @param  listData  the <code>Vector</code> to be loaded into the
0216:             *          data model
0217:             * @param filterEnabled <code>boolean</code> to determine if filtering/sorting
0218:             *   is enabled
0219:             * @throws IllegalArgumentException if <code>listData</code> is <code>null</code>
0220:             */
0221:            public JXList(Vector<?> listData, boolean filterEnabled) {
0222:                super (listData);
0223:                if (listData == null)
0224:                    throw new IllegalArgumentException(
0225:                            "listData must not be null");
0226:                init(filterEnabled);
0227:            }
0228:
0229:            private void init(boolean filterEnabled) {
0230:                setFilterEnabled(filterEnabled);
0231:
0232:                Action findAction = createFindAction();
0233:                getActionMap().put("find", findAction);
0234:
0235:                KeyStroke findStroke = SearchFactory.getInstance()
0236:                        .getSearchAccelerator();
0237:                getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
0238:                        findStroke, "find");
0239:
0240:            }
0241:
0242:            private Action createFindAction() {
0243:                Action findAction = new UIAction("find") {
0244:
0245:                    public void actionPerformed(ActionEvent e) {
0246:                        doFind();
0247:
0248:                    }
0249:
0250:                };
0251:                return findAction;
0252:            }
0253:
0254:            protected void doFind() {
0255:                SearchFactory.getInstance()
0256:                        .showFindInput(this , getSearchable());
0257:
0258:            }
0259:
0260:            /**
0261:             * 
0262:             * @return a not-null Searchable for this editor.
0263:             */
0264:            public Searchable getSearchable() {
0265:                if (searchable == null) {
0266:                    searchable = new ListSearchable();
0267:                }
0268:                return searchable;
0269:            }
0270:
0271:            /**
0272:             * sets the Searchable for this editor. If null, a default 
0273:             * searchable will be used.
0274:             * 
0275:             * @param searchable
0276:             */
0277:            public void setSearchable(Searchable searchable) {
0278:                this .searchable = searchable;
0279:            }
0280:
0281:            public class ListSearchable extends AbstractSearchable {
0282:
0283:                @Override
0284:                protected void findMatchAndUpdateState(Pattern pattern,
0285:                        int startRow, boolean backwards) {
0286:                    SearchResult searchResult = null;
0287:                    if (backwards) {
0288:                        for (int index = startRow; index >= 0
0289:                                && searchResult == null; index--) {
0290:                            searchResult = findMatchAt(pattern, index);
0291:                        }
0292:                    } else {
0293:                        for (int index = startRow; index < getSize()
0294:                                && searchResult == null; index++) {
0295:                            searchResult = findMatchAt(pattern, index);
0296:                        }
0297:                    }
0298:                    updateState(searchResult);
0299:                }
0300:
0301:                @Override
0302:                protected SearchResult findExtendedMatch(Pattern pattern,
0303:                        int row) {
0304:
0305:                    return findMatchAt(pattern, row);
0306:                }
0307:
0308:                /**
0309:                 * Matches the cell content at row/col against the given Pattern.
0310:                 * Returns an appropriate SearchResult if matching or null if no
0311:                 * matching
0312:                 * 
0313:                 * @param pattern 
0314:                 * @param row a valid row index in view coordinates
0315:                 * @return <code>SearchResult</code> if matched otherwise null
0316:                 */
0317:                protected SearchResult findMatchAt(Pattern pattern, int row) {
0318:                    Object value = getElementAt(row);
0319:                    if (value != null) {
0320:                        Matcher matcher = pattern.matcher(value.toString());
0321:                        if (matcher.find()) {
0322:                            return createSearchResult(matcher, row, -1);
0323:                        }
0324:                    }
0325:                    return null;
0326:                }
0327:
0328:                @Override
0329:                protected int getSize() {
0330:                    return getElementCount();
0331:                }
0332:
0333:                @Override
0334:                protected void moveMatchMarker() {
0335:                    setSelectedIndex(lastSearchResult.foundRow);
0336:                    if (lastSearchResult.foundRow >= 0) {
0337:                        ensureIndexIsVisible(lastSearchResult.foundRow);
0338:                    }
0339:
0340:                }
0341:
0342:            }
0343:
0344:            /**
0345:             * Property to enable/disable rollover support. This can be enabled to show
0346:             * "live" rollover behaviour, f.i. the cursor over LinkModel cells. Default
0347:             * is disabled.
0348:             * 
0349:             * @param rolloverEnabled
0350:             */
0351:            public void setRolloverEnabled(boolean rolloverEnabled) {
0352:                boolean old = isRolloverEnabled();
0353:                if (rolloverEnabled == old)
0354:                    return;
0355:                if (rolloverEnabled) {
0356:                    rolloverProducer = createRolloverProducer();
0357:                    addMouseListener(rolloverProducer);
0358:                    addMouseMotionListener(rolloverProducer);
0359:                    getLinkController().install(this );
0360:                } else {
0361:                    removeMouseListener(rolloverProducer);
0362:                    removeMouseMotionListener(rolloverProducer);
0363:                    rolloverProducer = null;
0364:                    getLinkController().release();
0365:                }
0366:                firePropertyChange("rolloverEnabled", old, isRolloverEnabled());
0367:            }
0368:
0369:            protected ListRolloverController getLinkController() {
0370:                if (linkController == null) {
0371:                    linkController = createLinkController();
0372:                }
0373:                return linkController;
0374:            }
0375:
0376:            protected ListRolloverController createLinkController() {
0377:                return new ListRolloverController();
0378:            }
0379:
0380:            /**
0381:             * creates and returns the RolloverProducer to use with this tree.
0382:             * 
0383:             * @return <code>RolloverProducer</code> to use with this tree
0384:             */
0385:            protected RolloverProducer createRolloverProducer() {
0386:                RolloverProducer r = new RolloverProducer() {
0387:                    protected void updateRolloverPoint(JComponent component,
0388:                            Point mousePoint) {
0389:                        JList list = (JList) component;
0390:                        int row = list.locationToIndex(mousePoint);
0391:                        if (row >= 0) {
0392:                            Rectangle cellBounds = list.getCellBounds(row, row);
0393:                            if (!cellBounds.contains(mousePoint)) {
0394:                                row = -1;
0395:                            }
0396:                        }
0397:                        int col = row < 0 ? -1 : 0;
0398:                        rollover.x = col;
0399:                        rollover.y = row;
0400:                    }
0401:
0402:                };
0403:                return r;
0404:            }
0405:
0406:            /**
0407:             * returns the rolloverEnabled property.
0408:             *
0409:             * TODO: why doesn't this just return rolloverEnabled???
0410:             *
0411:             * @return true if rollover is enabled
0412:             */
0413:            public boolean isRolloverEnabled() {
0414:                return rolloverProducer != null;
0415:            }
0416:
0417:            /**
0418:             * listens to rollover properties. Repaints effected component regions.
0419:             * Updates link cursor.
0420:             * 
0421:             * @author Jeanette Winzenburg
0422:             */
0423:            public static class ListRolloverController<T extends JList> extends
0424:                    RolloverController<T> {
0425:
0426:                private Cursor oldCursor;
0427:
0428:                // --------------------------------- JList rollover
0429:
0430:                protected void rollover(Point oldLocation, Point newLocation) {
0431:                    setRolloverCursor(newLocation);
0432:                    // JW: partial repaints incomplete
0433:                    component.repaint();
0434:                }
0435:
0436:                /**
0437:                 * something weird: cursor in JList behaves different from JTable?
0438:                 * 
0439:                 * @param location
0440:                 */
0441:                private void setRolloverCursor(Point location) {
0442:                    if (hasRollover(location)) {
0443:                        oldCursor = component.getCursor();
0444:                        component.setCursor(Cursor
0445:                                .getPredefinedCursor(Cursor.HAND_CURSOR));
0446:                    } else {
0447:                        component.setCursor(oldCursor);
0448:                        oldCursor = null;
0449:                    }
0450:
0451:                }
0452:
0453:                protected RolloverRenderer getRolloverRenderer(Point location,
0454:                        boolean prepare) {
0455:                    ListCellRenderer renderer = component.getCellRenderer();
0456:                    RolloverRenderer rollover = renderer instanceof  RolloverRenderer ? (RolloverRenderer) renderer
0457:                            : null;
0458:                    if ((rollover != null) && !rollover.isEnabled()) {
0459:                        rollover = null;
0460:                    }
0461:                    if ((rollover != null) && prepare) {
0462:                        Object element = component.getModel().getElementAt(
0463:                                location.y);
0464:                        renderer.getListCellRendererComponent(component,
0465:                                element, location.y, false, true);
0466:                    }
0467:                    return rollover;
0468:                }
0469:
0470:                @Override
0471:                protected Point getFocusedCell() {
0472:                    int leadRow = component.getLeadSelectionIndex();
0473:                    if (leadRow < 0)
0474:                        return null;
0475:                    return new Point(0, leadRow);
0476:                }
0477:
0478:            }
0479:
0480:            //--------------------- public sort api
0481:            //    /** 
0482:            //     * Returns the sortable property.
0483:            //     * Here: same as filterEnabled.
0484:            //     * @return true if the table is sortable. 
0485:            //     */
0486:            //    public boolean isSortable() {
0487:            //        return isFilterEnabled();
0488:            //    }
0489:            /**
0490:             * Removes the interactive sorter.
0491:             * 
0492:             */
0493:            public void resetSortOrder() {
0494:                SortController controller = getSortController();
0495:                if (controller != null) {
0496:                    controller.setSortKeys(null);
0497:                }
0498:            }
0499:
0500:            /**
0501:             * 
0502:             * Toggles the sort order of the items.
0503:             * <p>
0504:             * The exact behaviour is defined by the SortController's
0505:             * toggleSortOrder implementation. Typically a unsorted 
0506:             * column is sorted in ascending order, a sorted column's
0507:             * order is reversed. 
0508:             * <p>
0509:             * PENDING: where to get the comparator from?
0510:             * <p>
0511:             * 
0512:             * 
0513:             */
0514:            public void toggleSortOrder() {
0515:                SortController controller = getSortController();
0516:                if (controller != null) {
0517:                    controller.toggleSortOrder(0, getComparator());
0518:                }
0519:            }
0520:
0521:            /**
0522:             * Sorts the list using SortOrder. 
0523:             * 
0524:             * 
0525:             * Respects the JXList's sortable and comparator 
0526:             * properties: routes the comparator to the SortController
0527:             * and does nothing if !isFilterEnabled(). 
0528:             * <p>
0529:             * 
0530:             * @param sortOrder the sort order to use. If null or SortOrder.UNSORTED, 
0531:             *   this method has the same effect as resetSortOrder();
0532:             *    
0533:             */
0534:            public void setSortOrder(SortOrder sortOrder) {
0535:                if ((sortOrder == null) || !sortOrder.isSorted()) {
0536:                    resetSortOrder();
0537:                    return;
0538:                }
0539:                SortController sortController = getSortController();
0540:                if (sortController != null) {
0541:                    SortKey sortKey = new SortKey(sortOrder, 0, getComparator());
0542:                    sortController.setSortKeys(Collections
0543:                            .singletonList(sortKey));
0544:                }
0545:            }
0546:
0547:            /**
0548:             * Returns the SortOrder. 
0549:             * 
0550:             * @return the interactive sorter's SortOrder  
0551:             *  or SortOrder.UNSORTED 
0552:             */
0553:            public SortOrder getSortOrder() {
0554:                SortController sortController = getSortController();
0555:                if (sortController == null)
0556:                    return SortOrder.UNSORTED;
0557:                SortKey sortKey = SortKey.getFirstSortKeyForColumn(
0558:                        sortController.getSortKeys(), 0);
0559:                return sortKey != null ? sortKey.getSortOrder()
0560:                        : SortOrder.UNSORTED;
0561:            }
0562:
0563:            /**
0564:             * 
0565:             * @return the comparator used.
0566:             * @see #setComparator(Comparator)
0567:             */
0568:            public Comparator getComparator() {
0569:                return comparator;
0570:            }
0571:
0572:            /**
0573:             * Sets the comparator used. As a side-effect, the 
0574:             * current sort might be updated. The exact behaviour
0575:             * is defined in #updateSortAfterComparatorChange. 
0576:             * 
0577:             * @param comparator the comparator to use.
0578:             */
0579:            public void setComparator(Comparator comparator) {
0580:                Comparator old = getComparator();
0581:                this .comparator = comparator;
0582:                updateSortAfterComparatorChange();
0583:                firePropertyChange("comparator", old, getComparator());
0584:            }
0585:
0586:            /**
0587:             * Updates sort after comparator has changed. 
0588:             * Here: sets the current sortOrder with the new comparator.
0589:             *
0590:             */
0591:            protected void updateSortAfterComparatorChange() {
0592:                setSortOrder(getSortOrder());
0593:
0594:            }
0595:
0596:            /**
0597:             * returns the currently active SortController. Will be null if
0598:             * !isFilterEnabled().
0599:             * @return the currently active <code>SortController</code> may be null
0600:             */
0601:            protected SortController getSortController() {
0602:                //      // this check is for the sake of the very first call after instantiation
0603:                // doesn't apply for JXList? need to test for filterEnabled?
0604:                //if (filters == null) return null;
0605:                if (!isFilterEnabled())
0606:                    return null;
0607:                return getFilters().getSortController();
0608:            }
0609:
0610:            // ---------------------------- filters
0611:
0612:            /**
0613:             * returns the element at the given index. The index is in view coordinates
0614:             * which might differ from model coordinates if filtering is enabled and
0615:             * filters/sorters are active.
0616:             * 
0617:             * @param viewIndex the index in view coordinates
0618:             * @return the element at the index
0619:             * @throws IndexOutOfBoundsException if viewIndex < 0 or viewIndex >=
0620:             *         getElementCount()
0621:             */
0622:            public Object getElementAt(int viewIndex) {
0623:                return getModel().getElementAt(viewIndex);
0624:            }
0625:
0626:            /**
0627:             * Returns the number of elements in this list in view 
0628:             * coordinates. If filters are active this number might be
0629:             * less than the number of elements in the underlying model.
0630:             * 
0631:             * @return number of elements in this list in view coordinates
0632:             */
0633:            public int getElementCount() {
0634:                return getModel().getSize();
0635:            }
0636:
0637:            /**
0638:             * Convert row index from view coordinates to model coordinates accounting
0639:             * for the presence of sorters and filters.
0640:             * 
0641:             * @param viewIndex index in view coordinates
0642:             * @return index in model coordinates
0643:             * @throws IndexOutOfBoundsException if viewIndex < 0 or viewIndex >= getElementCount() 
0644:             */
0645:            public int convertIndexToModel(int viewIndex) {
0646:                return isFilterEnabled() ? getFilters().convertRowIndexToModel(
0647:                        viewIndex) : viewIndex;
0648:            }
0649:
0650:            /**
0651:             * Convert index from model coordinates to view coordinates accounting
0652:             * for the presence of sorters and filters.
0653:             * 
0654:             * PENDING Filter guards against out of range - should not? 
0655:             * 
0656:             * @param modelIndex index in model coordinates
0657:             * @return index in view coordinates if the model index maps to a view coordinate
0658:             *          or -1 if not contained in the view.
0659:             * 
0660:             */
0661:            public int convertIndexToView(int modelIndex) {
0662:                return isFilterEnabled() ? getFilters().convertRowIndexToView(
0663:                        modelIndex) : modelIndex;
0664:            }
0665:
0666:            /**
0667:             * returns the underlying model. If !isFilterEnabled this will be the same
0668:             * as getModel().
0669:             * 
0670:             * @return the underlying model
0671:             */
0672:            public ListModel getWrappedModel() {
0673:                return isFilterEnabled() ? wrappingModel.getModel()
0674:                        : getModel();
0675:            }
0676:
0677:            /**
0678:             * Enables/disables filtering support. If enabled all row indices -
0679:             * including the selection - are in view coordinates and getModel returns a
0680:             * wrapper around the underlying model.
0681:             * 
0682:             * Note: as an implementation side-effect calling this method clears the
0683:             * selection (done in super.setModel).
0684:             * 
0685:             * PENDING: cleanup state transitions!! - currently this can be safely
0686:             * applied once only to enable. Internal state is inconsistent if trying to
0687:             * disable again. As a temporary emergency measure, this will throw a 
0688:             * IllegalStateException. 
0689:             * 
0690:             * see Issue #2-swinglabs.
0691:             * 
0692:             * @param enabled
0693:             * @throws IllegalStateException if trying to disable again.
0694:             */
0695:            public void setFilterEnabled(boolean enabled) {
0696:                boolean old = isFilterEnabled();
0697:                if (old == enabled)
0698:                    return;
0699:                if (old == true)
0700:                    throw new IllegalStateException(
0701:                            "must not reset filterEnabled");
0702:                // JW: filterEnabled must be set before calling super.setModel!
0703:                filterEnabled = enabled;
0704:                if (!old) {
0705:                    wrappingModel = new WrappingListModel(getModel());
0706:                    super .setModel(wrappingModel);
0707:                } else {
0708:                    ListModel model = wrappingModel.getModel();
0709:                    wrappingModel = null;
0710:                    super .setModel(model);
0711:                }
0712:
0713:            }
0714:
0715:            /**
0716:             * 
0717:             * @return a <boolean> indicating if filtering is enabled.
0718:             * @see #setFilterEnabled(boolean)
0719:             */
0720:            public boolean isFilterEnabled() {
0721:                return filterEnabled;
0722:            }
0723:
0724:            /**
0725:             * Overridden to update selectionMapper
0726:             */
0727:            @Override
0728:            public void setSelectionModel(ListSelectionModel newModel) {
0729:                super .setSelectionModel(newModel);
0730:                getSelectionMapper().setViewSelectionModel(getSelectionModel());
0731:            }
0732:
0733:            /**
0734:             * set's the underlying data model. Note that if isFilterEnabled you must
0735:             * call getWrappedModel to access the model given here. In this case
0736:             * getModel returns a wrapper around the data!
0737:             * 
0738:             * 
0739:             * 
0740:             */
0741:            @Override
0742:            public void setModel(ListModel model) {
0743:                if (isFilterEnabled()) {
0744:                    wrappingModel.setModel(model);
0745:                } else {
0746:                    super .setModel(model);
0747:                }
0748:            }
0749:
0750:            /**
0751:             * widened access for testing...
0752:             * @return the selection mapper
0753:             */
0754:            protected SelectionMapper getSelectionMapper() {
0755:                if (selectionMapper == null) {
0756:                    selectionMapper = new DefaultSelectionMapper(filters,
0757:                            getSelectionModel());
0758:                }
0759:                return selectionMapper;
0760:            }
0761:
0762:            /**
0763:             * 
0764:             * @return the <code>FilterPipeline</code> assigned to this list, or
0765:             *   null if !isFiltersEnabled().
0766:             */
0767:            public FilterPipeline getFilters() {
0768:                if ((filters == null) && isFilterEnabled()) {
0769:                    setFilters(null);
0770:                }
0771:                return filters;
0772:            }
0773:
0774:            /** Sets the FilterPipeline for filtering the items of this list, maybe null
0775:             *  to remove all previously applied filters. 
0776:             *  
0777:             *  Note: the current "interactive" sortState is preserved (by 
0778:             *  internally copying the old sortKeys to the new pipeline, if any). 
0779:             *  
0780:             *  PRE: isFilterEnabled()
0781:             * 
0782:             * @param pipeline the <code>FilterPipeline</code> to use, null removes
0783:             *   all filters.
0784:             * @throws IllegalStateException if !isFilterEnabled()
0785:             */
0786:            public void setFilters(FilterPipeline pipeline) {
0787:                if (!isFilterEnabled())
0788:                    throw new IllegalStateException(
0789:                            "filters not enabled - not allowed to set filters");
0790:
0791:                FilterPipeline old = filters;
0792:                List<? extends SortKey> sortKeys = null;
0793:                if (old != null) {
0794:                    old.removePipelineListener(pipelineListener);
0795:                    sortKeys = old.getSortController().getSortKeys();
0796:                }
0797:                if (pipeline == null) {
0798:                    pipeline = new FilterPipeline();
0799:                }
0800:                filters = pipeline;
0801:                filters.getSortController().setSortKeys(sortKeys);
0802:                // JW: first assign to prevent (short?) illegal internal state
0803:                // #173-swingx
0804:                use(filters);
0805:                getSelectionMapper().setFilters(filters);
0806:
0807:            }
0808:
0809:            /**
0810:             * setModel() and setFilters() may be called in either order.
0811:             * 
0812:             * @param pipeline
0813:             */
0814:            private void use(FilterPipeline pipeline) {
0815:                if (pipeline != null) {
0816:                    // check JW: adding listener multiple times (after setModel)?
0817:                    if (initialUse(pipeline)) {
0818:                        pipeline
0819:                                .addPipelineListener(getFilterPipelineListener());
0820:                        pipeline.assign(getComponentAdapter());
0821:                    } else {
0822:                        pipeline.flush();
0823:                    }
0824:                }
0825:            }
0826:
0827:            /**
0828:             * @return true is not yet used in this JXTable, false otherwise
0829:             */
0830:            private boolean initialUse(FilterPipeline pipeline) {
0831:                if (pipelineListener == null)
0832:                    return true;
0833:                PipelineListener[] l = pipeline.getPipelineListeners();
0834:                for (int i = 0; i < l.length; i++) {
0835:                    if (pipelineListener.equals(l[i]))
0836:                        return false;
0837:                }
0838:                return true;
0839:            }
0840:
0841:            /** returns the listener for changes in filters. */
0842:            protected PipelineListener getFilterPipelineListener() {
0843:                if (pipelineListener == null) {
0844:                    pipelineListener = createPipelineListener();
0845:                }
0846:                return pipelineListener;
0847:            }
0848:
0849:            /** creates the listener for changes in filters. */
0850:            protected PipelineListener createPipelineListener() {
0851:                PipelineListener l = new PipelineListener() {
0852:                    public void contentsChanged(PipelineEvent e) {
0853:                        updateOnFilterContentChanged();
0854:                    }
0855:                };
0856:                return l;
0857:            }
0858:
0859:            /**
0860:             * method called on change notification from filterpipeline.
0861:             */
0862:            protected void updateOnFilterContentChanged() {
0863:                // make the wrapper listen to the pipeline?
0864:                if (wrappingModel != null) {
0865:                    wrappingModel.updateOnFilterContentChanged();
0866:                }
0867:                revalidate();
0868:                repaint();
0869:            }
0870:
0871:            private class WrappingListModel extends AbstractListModel {
0872:
0873:                private ListModel delegate;
0874:
0875:                private ListDataListener listDataListener;
0876:
0877:                public WrappingListModel(ListModel model) {
0878:                    setModel(model);
0879:                }
0880:
0881:                public void updateOnFilterContentChanged() {
0882:                    fireContentsChanged(this , -1, -1);
0883:
0884:                }
0885:
0886:                public void setModel(ListModel model) {
0887:                    ListModel old = this .getModel();
0888:                    if (old != null) {
0889:                        old.removeListDataListener(listDataListener);
0890:                    }
0891:                    this .delegate = model;
0892:                    delegate.addListDataListener(getListDataListener());
0893:                    fireContentsChanged(this , -1, -1);
0894:                }
0895:
0896:                private ListDataListener getListDataListener() {
0897:                    if (listDataListener == null) {
0898:                        listDataListener = createListDataListener();
0899:                    }
0900:                    return listDataListener;
0901:                }
0902:
0903:                private ListDataListener createListDataListener() {
0904:                    ListDataListener l = new ListDataListener() {
0905:
0906:                        public void intervalAdded(ListDataEvent e) {
0907:                            contentsChanged(e);
0908:
0909:                        }
0910:
0911:                        public void intervalRemoved(ListDataEvent e) {
0912:                            contentsChanged(e);
0913:
0914:                        }
0915:
0916:                        public void contentsChanged(ListDataEvent e) {
0917:                            boolean wasEnabled = getSelectionMapper()
0918:                                    .isEnabled();
0919:                            getSelectionMapper().setEnabled(false);
0920:                            try {
0921:                                fireContentsChanged(this , -1, -1);
0922:                                updateSelection(e);
0923:                            } finally {
0924:                                getSelectionMapper().setEnabled(wasEnabled);
0925:                            }
0926:                            getFilters().flush();
0927:                        }
0928:
0929:                    };
0930:                    return l;
0931:                }
0932:
0933:                protected void updateSelection(ListDataEvent e) {
0934:                    if (e.getType() == ListDataEvent.INTERVAL_REMOVED) {
0935:                        getSelectionMapper().removeIndexInterval(e.getIndex0(),
0936:                                e.getIndex1());
0937:                    } else if (e.getType() == ListDataEvent.INTERVAL_ADDED) {
0938:
0939:                        int minIndex = Math.min(e.getIndex0(), e.getIndex1());
0940:                        int maxIndex = Math.max(e.getIndex0(), e.getIndex1());
0941:                        int length = maxIndex - minIndex + 1;
0942:                        getSelectionMapper().insertIndexInterval(minIndex,
0943:                                length, true);
0944:                    } else {
0945:                        getSelectionMapper().clearModelSelection();
0946:                    }
0947:
0948:                }
0949:
0950:                public ListModel getModel() {
0951:                    return delegate;
0952:                }
0953:
0954:                public int getSize() {
0955:                    return getFilters().getOutputSize();
0956:                }
0957:
0958:                public Object getElementAt(int index) {
0959:                    return getFilters().getValueAt(index, 0);
0960:                }
0961:
0962:            }
0963:
0964:            // ---------------------------- uniform data model
0965:
0966:            protected ComponentAdapter getComponentAdapter() {
0967:                if (dataAdapter == null) {
0968:                    dataAdapter = new ListAdapter(this );
0969:                }
0970:                return dataAdapter;
0971:            }
0972:
0973:            protected static class ListAdapter extends ComponentAdapter {
0974:                private final JXList list;
0975:
0976:                /**
0977:                 * Constructs a <code>ListDataAdapter</code> for the specified target
0978:                 * component.
0979:                 * 
0980:                 * @param component
0981:                 *            the target component
0982:                 */
0983:                public ListAdapter(JXList component) {
0984:                    super (component);
0985:                    list = component;
0986:                }
0987:
0988:                /**
0989:                 * Typesafe accessor for the target component.
0990:                 * 
0991:                 * @return the target component as a {@link org.jdesktop.swingx.JXList}
0992:                 */
0993:                public JXList getList() {
0994:                    return list;
0995:                }
0996:
0997:                /**
0998:                 * {@inheritDoc}
0999:                 */
1000:                public boolean hasFocus() {
1001:                    /** TODO: Think through printing implications */
1002:                    return list.isFocusOwner()
1003:                            && (row == list.getLeadSelectionIndex());
1004:                }
1005:
1006:                @Override
1007:                public int getRowCount() {
1008:                    return list.getWrappedModel().getSize();
1009:                }
1010:
1011:                /**
1012:                 * {@inheritDoc} <p>
1013:                 * Overridden to return value at implicit view coordinates.
1014:                 */
1015:                @Override
1016:                public Object getValue() {
1017:                    return list.getElementAt(row);
1018:                }
1019:
1020:                /**
1021:                 * {@inheritDoc}
1022:                 */
1023:                public Object getValueAt(int row, int column) {
1024:                    return list.getWrappedModel().getElementAt(row);
1025:                }
1026:
1027:                public Object getFilteredValueAt(int row, int column) {
1028:                    return list.getElementAt(row);
1029:                }
1030:
1031:                public void setValueAt(Object aValue, int row, int column) {
1032:                    throw new UnsupportedOperationException(
1033:                            "Method getFilteredValueAt() not yet implemented.");
1034:                }
1035:
1036:                public boolean isCellEditable(int row, int column) {
1037:                    return false;
1038:                }
1039:
1040:                /**
1041:                 * {@inheritDoc}
1042:                 */
1043:                public boolean isSelected() {
1044:                    /** TODO: Think through printing implications */
1045:                    return list.isSelectedIndex(row);
1046:                }
1047:
1048:                public String getColumnName(int columnIndex) {
1049:                    return "Column_" + columnIndex;
1050:                }
1051:
1052:                public String getColumnIdentifier(int columnIndex) {
1053:                    return null;
1054:                }
1055:
1056:            }
1057:
1058:            // ------------------------------ renderers
1059:
1060:            /**
1061:             * @return the HighlighterPipeline assigned to the list.
1062:             * @see #setHighlighters(HighlighterPipeline)
1063:             */
1064:            public HighlighterPipeline getHighlighters() {
1065:                return highlighters;
1066:            }
1067:
1068:            /**
1069:             * Assigns a HighlighterPipeline to the list. This is a bound property.
1070:             * 
1071:             * @param pipeline the HighlighterPipeline to use for renderer
1072:             *   decoration, maybe null to remove all Highlighters.
1073:             */
1074:            public void setHighlighters(HighlighterPipeline pipeline) {
1075:                HighlighterPipeline old = getHighlighters();
1076:                if (old != null) {
1077:                    old.removeChangeListener(getHighlighterChangeListener());
1078:                }
1079:                highlighters = pipeline;
1080:                if (highlighters != null) {
1081:                    highlighters
1082:                            .addChangeListener(getHighlighterChangeListener());
1083:                }
1084:                firePropertyChange("highlighters", old, getHighlighters());
1085:            }
1086:
1087:            /**
1088:             * Sets the <code>Highlighter</code>s to the list, replacing any old settings.
1089:             * May be null to remove all highlighters.<p>
1090:             * 
1091:             * 
1092:             * @param highlighters the highlighters to use for renderer decoration. 
1093:             * @see #getHighlighters()
1094:             * @see #addHighlighter(Highlighter)
1095:             * @see #removeHighlighter(Highlighter)
1096:             * 
1097:             */
1098:            public void setHighlighters(Highlighter... highlighters) {
1099:                HighlighterPipeline pipeline = null;
1100:                if ((highlighters != null) && (highlighters.length > 0)
1101:                        && (highlighters[0] != null)) {
1102:                    pipeline = new HighlighterPipeline(highlighters);
1103:                }
1104:                setHighlighters(pipeline);
1105:            }
1106:
1107:            /**
1108:             * Adds a Highlighter.
1109:             * 
1110:             * If the HighlighterPipeline returned from getHighlighters() is null, creates
1111:             * and sets a new pipeline containing the given Highlighter. Else, appends
1112:             * the Highlighter to the end of the pipeline.
1113:             * 
1114:             * @param highlighter the Highlighter to add - must not be null.
1115:             * @throws NullPointerException if highlighter is null.
1116:             */
1117:            public void addHighlighter(Highlighter highlighter) {
1118:                HighlighterPipeline pipeline = getHighlighters();
1119:                if (pipeline == null) {
1120:                    setHighlighters(new HighlighterPipeline(
1121:                            new Highlighter[] { highlighter }));
1122:                } else {
1123:                    pipeline.addHighlighter(highlighter);
1124:                }
1125:            }
1126:
1127:            /**
1128:             * Removes the Highlighter.
1129:             * 
1130:             * Does nothing if the HighlighterPipeline is null or does not contain
1131:             * the given Highlighter.
1132:             * 
1133:             * @param highlighter the Highlighter to remove.
1134:             */
1135:            public void removeHighlighter(Highlighter highlighter) {
1136:                if ((getHighlighters() == null))
1137:                    return;
1138:                getHighlighters().removeHighlighter(highlighter);
1139:            }
1140:
1141:            /**
1142:             * returns the ChangeListener to use with highlighters. Creates one if
1143:             * necessary.
1144:             * 
1145:             * @return != null
1146:             */
1147:            protected ChangeListener getHighlighterChangeListener() {
1148:                if (highlighterChangeListener == null) {
1149:                    highlighterChangeListener = new ChangeListener() {
1150:
1151:                        public void stateChanged(ChangeEvent e) {
1152:                            repaint();
1153:                        }
1154:
1155:                    };
1156:                }
1157:                return highlighterChangeListener;
1158:            }
1159:
1160:            private DelegatingRenderer getDelegatingRenderer() {
1161:                if (delegatingRenderer == null) {
1162:                    // only called once... to get hold of the default?
1163:                    delegatingRenderer = new DelegatingRenderer(
1164:                            createDefaultCellRenderer());
1165:                }
1166:                return delegatingRenderer;
1167:            }
1168:
1169:            /**
1170:             * Creates and returns the default cell renderer to use. Subclasses
1171:             * may override to use a different type. Here: returns a <code>DefaultListRenderer</code>.
1172:             * 
1173:             * @return the default cell renderer to use with this list.
1174:             */
1175:            protected ListCellRenderer createDefaultCellRenderer() {
1176:                return new DefaultListRenderer();
1177:            }
1178:
1179:            @Override
1180:            public ListCellRenderer getCellRenderer() {
1181:                return getDelegatingRenderer();
1182:            }
1183:
1184:            @Override
1185:            public void setCellRenderer(ListCellRenderer renderer) {
1186:                // JW: Pending - probably fires propertyChangeEvent with wrong newValue?
1187:                // how about fixedCellWidths?
1188:                // need to test!!
1189:                getDelegatingRenderer().setDelegateRenderer(renderer);
1190:                super .setCellRenderer(delegatingRenderer);
1191:            }
1192:
1193:            public class DelegatingRenderer implements  ListCellRenderer,
1194:                    RolloverRenderer {
1195:
1196:                private ListCellRenderer delegateRenderer;
1197:
1198:                public DelegatingRenderer(ListCellRenderer delegate) {
1199:                    setDelegateRenderer(delegate);
1200:                }
1201:
1202:                public void setDelegateRenderer(ListCellRenderer delegate) {
1203:                    if (delegate == null) {
1204:                        delegate = new DefaultListCellRenderer();
1205:                    }
1206:                    delegateRenderer = delegate;
1207:                }
1208:
1209:                public ListCellRenderer getDelegateRenderer() {
1210:                    return delegateRenderer;
1211:                }
1212:
1213:                public boolean isEnabled() {
1214:                    return (delegateRenderer instanceof  RolloverRenderer)
1215:                            && ((RolloverRenderer) delegateRenderer)
1216:                                    .isEnabled();
1217:                }
1218:
1219:                public void doClick() {
1220:                    if (isEnabled()) {
1221:                        ((RolloverRenderer) delegateRenderer).doClick();
1222:                    }
1223:                }
1224:
1225:                public Component getListCellRendererComponent(JList list,
1226:                        Object value, int index, boolean isSelected,
1227:                        boolean cellHasFocus) {
1228:                    Component comp = null;
1229:
1230:                    comp = delegateRenderer.getListCellRendererComponent(list,
1231:                            value, index, isSelected, cellHasFocus);
1232:                    if (highlighters != null) {
1233:                        ComponentAdapter adapter = getComponentAdapter();
1234:                        adapter.column = 0;
1235:                        adapter.row = index;
1236:                        comp = highlighters.apply(comp, adapter);
1237:                    }
1238:                    return comp;
1239:                }
1240:
1241:                public void updateUI() {
1242:                    updateRendererUI(delegateRenderer);
1243:                }
1244:
1245:                private void updateRendererUI(ListCellRenderer renderer) {
1246:                    if (renderer instanceof  JComponent) {
1247:                        ((JComponent) renderer).updateUI();
1248:                    } else if (renderer != null) {
1249:                        Component comp = renderer.getListCellRendererComponent(
1250:                                JXList.this , null, -1, false, false);
1251:                        if (comp instanceof  JComponent) {
1252:                            ((JComponent) comp).updateUI();
1253:                        }
1254:                    }
1255:
1256:                }
1257:
1258:            }
1259:
1260:            // --------------------------- updateUI
1261:
1262:            @Override
1263:            public void updateUI() {
1264:                super .updateUI();
1265:                updateRendererUI();
1266:            }
1267:
1268:            private void updateRendererUI() {
1269:                if (delegatingRenderer != null) {
1270:                    delegatingRenderer.updateUI();
1271:                } else {
1272:                    ListCellRenderer renderer = getCellRenderer();
1273:                    if (renderer instanceof  JComponent) {
1274:                        ((JComponent) renderer).updateUI();
1275:                    }
1276:                }
1277:            }
1278:
1279:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.