Source Code Cross Referenced for Table.java in  » Web-Framework » Millstone » org » millstone » base » ui » 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 » Web Framework » Millstone » org.millstone.base.ui 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /*******************************************************************************
0002:         * 
0003:         * Millstone(TM) Open Sourced User Interface Library for Internet Development
0004:         * with Java
0005:         * 
0006:         * Millstone is a registered trademark of IT Mill Ltd Copyright (C)
0007:         * 2000-2005 IT Mill Ltd
0008:         * 
0009:         * ************************************************************************
0010:         * 
0011:         * This library is free software; you can redistribute it and/or
0012:         * modify it under the terms of the GNU Lesser General Public
0013:         * license version 2.1 as published by the Free Software Foundation.
0014:         * 
0015:         * This library is distributed in the hope that it will be useful, but WITHOUT
0016:         * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
0017:         * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
0018:         * details.
0019:         * 
0020:         * You should have received a copy of the GNU Lesser General Public License
0021:         * along with this library; if not, write to the Free Software Foundation, Inc.,
0022:         * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
0023:         * 
0024:         * ************************************************************************
0025:         * 
0026:         * For more information, contact:
0027:         * 
0028:         * IT Mill Ltd phone: +358 2 4802 7180 Ruukinkatu 2-4 fax: +358 2 4802 7181
0029:         * 20540, Turku email: info@itmill.com Finland company www: www.itmill.com
0030:         * 
0031:         * Primary source for MillStone information and releases: www.millstone.org
0032:         *  */package org.millstone.base.ui;
0033:
0034:        import java.util.Collection;
0035:        import java.util.HashMap;
0036:        import java.util.HashSet;
0037:        import java.util.Iterator;
0038:        import java.util.LinkedHashSet;
0039:        import java.util.LinkedList;
0040:        import java.util.Map;
0041:        import java.util.Set;
0042:        import java.util.StringTokenizer;
0043:
0044:        import org.millstone.base.data.Container;
0045:        import org.millstone.base.data.Item;
0046:        import org.millstone.base.data.Property;
0047:        import org.millstone.base.data.util.ContainerOrderedWrapper;
0048:        import org.millstone.base.data.util.IndexedContainer;
0049:        import org.millstone.base.event.Action;
0050:        import org.millstone.base.terminal.KeyMapper;
0051:        import org.millstone.base.terminal.PaintException;
0052:        import org.millstone.base.terminal.PaintTarget;
0053:        import org.millstone.base.terminal.Resource;
0054:
0055:        /**
0056:         * Table component is used for representing data or components in pageable and
0057:         * selectable table.
0058:         * 
0059:         * @author IT Mill Ltd.
0060:         * @version 3.1.1 @since 3.0
0061:         */
0062:        public class Table extends Select implements  Action.Container,
0063:                Container.Ordered, Container.Sortable {
0064:
0065:            private static final int CELL_KEY = 0;
0066:
0067:            private static final int CELL_HEADER = 1;
0068:
0069:            private static final int CELL_ICON = 2;
0070:
0071:            private static final int CELL_ITEMID = 3;
0072:
0073:            private static final int CELL_FIRSTCOL = 4;
0074:
0075:            /**
0076:             * Left column alignment. <b>This is the default behaviour. </b>
0077:             */
0078:            public static final String ALIGN_LEFT = "b";
0079:
0080:            /** Center column alignment. */
0081:            public static final String ALIGN_CENTER = "c";
0082:
0083:            /** Right column alignment. */
0084:            public static final String ALIGN_RIGHT = "e";
0085:
0086:            /**
0087:             * Column header mode: Column headers are hidden. <b>This is the default
0088:             * behaviour. </b>
0089:             */
0090:            public static final int COLUMN_HEADER_MODE_HIDDEN = -1;
0091:
0092:            /**
0093:             * Column header mode: Property ID:s are used as column headers.
0094:             */
0095:            public static final int COLUMN_HEADER_MODE_ID = 0;
0096:
0097:            /**
0098:             * Column header mode: Column headers are explicitly specified with
0099:             * <code>setColumnHeaders()</code>
0100:             */
0101:            public static final int COLUMN_HEADER_MODE_EXPLICIT = 1;
0102:
0103:            /**
0104:             * Column header mode: Column headers are explicitly specified with
0105:             * <code>setColumnHeaders()</code>
0106:             */
0107:            public static final int COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID = 2;
0108:
0109:            /**
0110:             * Row caption mode: The row headers are hidden. <b>This is the default
0111:             * mode. </b>
0112:             */
0113:            public static final int ROW_HEADER_MODE_HIDDEN = -1;
0114:
0115:            /**
0116:             * Row caption mode: Items Id-objects toString() is used as row caption.
0117:             */
0118:            public static final int ROW_HEADER_MODE_ID = Select.ITEM_CAPTION_MODE_ID;
0119:
0120:            /**
0121:             * Row caption mode: Item-objects toString() is used as row caption.
0122:             */
0123:            public static final int ROW_HEADER_MODE_ITEM = Select.ITEM_CAPTION_MODE_ITEM;
0124:
0125:            /**
0126:             * Row caption mode: Index of the item is used as item caption. * The index
0127:             * mode can only be used with the containers implementing Container.Indexed
0128:             * interface.
0129:             */
0130:            public static final int ROW_HEADER_MODE_INDEX = Select.ITEM_CAPTION_MODE_INDEX;
0131:
0132:            /**
0133:             * Row caption mode: Item captions are explicitly specified.
0134:             */
0135:            public static final int ROW_HEADER_MODE_EXPLICIT = Select.ITEM_CAPTION_MODE_EXPLICIT;
0136:
0137:            /**
0138:             * Row caption mode: Item captions are read from property specified with
0139:             * <code>setItemCaptionPropertyId</code>.
0140:             */
0141:            public static final int ROW_HEADER_MODE_PROPERTY = Select.ITEM_CAPTION_MODE_PROPERTY;
0142:
0143:            /**
0144:             * Row caption mode: Only icons are shown, the captions are hidden.
0145:             */
0146:            public static final int ROW_HEADER_MODE_ICON_ONLY = Select.ITEM_CAPTION_MODE_ICON_ONLY;
0147:
0148:            /**
0149:             * Row caption mode: Item captions are explicitly specified, but if the
0150:             * caption is missing, the item id objects <code>toString()</code> is used
0151:             * instead.
0152:             */
0153:            public static final int ROW_HEADER_MODE_EXPLICIT_DEFAULTS_ID = Select.ITEM_CAPTION_MODE_EXPLICIT_DEFAULTS_ID;
0154:
0155:            /* Private table extensions to Select *********************************** */
0156:
0157:            /** True if column collapsing is allowed */
0158:            private boolean columnCollapsingAllowed = false;
0159:
0160:            /** True if reordering of columns is allowed on the client side */
0161:            private boolean columnReorderingAllowed = false;
0162:
0163:            /** Keymapper for column ids */
0164:            private KeyMapper columnIdMap = new KeyMapper();
0165:
0166:            /** Holds visible column propertyIds - in order */
0167:            private LinkedList visibleColumns = new LinkedList();
0168:
0169:            /** Holds propertyIds of currently collapsed columns */
0170:            private HashSet collapsedColumns = new HashSet();
0171:
0172:            /** Holds headers for visible columns (by propertyId) */
0173:            private HashMap columnHeaders = new HashMap();
0174:
0175:            /** Holds icons for visible columns (by propertyId) */
0176:            private HashMap columnIcons = new HashMap();
0177:
0178:            /** Holds alignments for visible columns (by propertyId) */
0179:            private HashMap columnAlignments = new HashMap();
0180:
0181:            /** Holds value of property pageLength. 0 disables paging. */
0182:            private int pageLength = 0;
0183:
0184:            /** Id the first item on the current page. */
0185:            private Object currentPageFirstItemId = null;
0186:
0187:            /** Index of the first item on the current page. */
0188:            private int currentPageFirstItemIndex = 0;
0189:
0190:            /** Holds value of property pageBuffering. */
0191:            private boolean pageBuffering = false;
0192:
0193:            /** Holds value of property selectable. */
0194:            private boolean selectable = false;
0195:
0196:            /** Holds value of property columnHeaderMode. */
0197:            private int columnHeaderMode = COLUMN_HEADER_MODE_HIDDEN;
0198:
0199:            /** True iff the row captions are hidden. */
0200:            private boolean rowCaptionsAreHidden = true;
0201:
0202:            /** Page contents buffer used in buffered mode */
0203:            private Object[][] pageBuffer = null;
0204:
0205:            /**
0206:             * List of properties listened - the list is kept to release the listeners
0207:             * later.
0208:             */
0209:            private LinkedList listenedProperties = null;
0210:
0211:            /** List of visible components - the is used for needsRepaint calculation. */
0212:            private LinkedList visibleComponents = null;
0213:
0214:            /** List of action handlers */
0215:            private LinkedList actionHandlers = null;
0216:
0217:            /** Action mapper */
0218:            private KeyMapper actionMapper = null;
0219:
0220:            /** Table cell editor factory */
0221:            private FieldFactory fieldFactory = new BaseFieldFactory();
0222:
0223:            /** Is table editable */
0224:            private boolean editable = false;
0225:
0226:            /** Current sorting direction */
0227:            private boolean sortAscending = true;
0228:
0229:            /** Currently table is sorted on this propertyId */
0230:            private Object sortContainerPropertyId = null;
0231:
0232:            /** Is table sorting disabled alltogether; even if some of the properties would be 
0233:             * sortable. */
0234:            private boolean sortDisabled = false;
0235:
0236:            /* Table constructors *************************************************** */
0237:
0238:            /** Create new empty table */
0239:            public Table() {
0240:                setRowHeaderMode(ROW_HEADER_MODE_HIDDEN);
0241:            }
0242:
0243:            /** Create new empty table with caption. */
0244:            public Table(String caption) {
0245:                this ();
0246:                setCaption(caption);
0247:            }
0248:
0249:            /** Create new table with caption and connect it to a Container. */
0250:            public Table(String caption, Container dataSource) {
0251:                this ();
0252:                setCaption(caption);
0253:                setContainerDataSource(dataSource);
0254:            }
0255:
0256:            /* Table functionality ************************************************** */
0257:
0258:            /**
0259:             * Get the array of visible column property id:s.
0260:             * 
0261:             * <p>
0262:             * The columns are show in the order of their appearance in this array
0263:             * </p>
0264:             * 
0265:             * @return Value of property availableColumns.
0266:             */
0267:            public Object[] getVisibleColumns() {
0268:                if (this .visibleColumns == null) {
0269:                    return null;
0270:                }
0271:                return this .visibleColumns.toArray();
0272:            }
0273:
0274:            /**
0275:             * Set the array of visible column property id:s.
0276:             * 
0277:             * <p>
0278:             * The columns are show in the order of their appearance in this array
0279:             * </p>
0280:             * 
0281:             * @param availableColumns
0282:             *            Array of shown property id:s.
0283:             */
0284:            public void setVisibleColumns(Object[] visibleColumns) {
0285:
0286:                // Visible columns must exist
0287:                if (visibleColumns == null)
0288:                    throw new NullPointerException(
0289:                            "Can not set visible columns to null value");
0290:
0291:                // Check that the new visible columns contains no nulls and properties
0292:                // exist
0293:                Collection properties = getContainerPropertyIds();
0294:                for (int i = 0; i < visibleColumns.length; i++) {
0295:                    if (visibleColumns[i] == null)
0296:                        throw new NullPointerException(
0297:                                "Properties must be non-nulls");
0298:                    else if (!properties.contains(visibleColumns[i]))
0299:                        throw new IllegalArgumentException(
0300:                                "Properties must exist in the Container, missing property: "
0301:                                        + visibleColumns[i]);
0302:                }
0303:
0304:                // If this is called befor the constructor is finished, it might be
0305:                // uninitialized
0306:                LinkedList newVC = new LinkedList();
0307:                for (int i = 0; i < visibleColumns.length; i++) {
0308:                    newVC.add(visibleColumns[i]);
0309:                }
0310:
0311:                // Remove alignments, icons and headers from hidden columns
0312:                if (this .visibleColumns != null)
0313:                    for (Iterator i = this .visibleColumns.iterator(); i
0314:                            .hasNext();) {
0315:                        Object col = i.next();
0316:                        if (!newVC.contains(col)) {
0317:                            setColumnHeader(col, null);
0318:                            setColumnAlignment(col, null);
0319:                            setColumnIcon(col, null);
0320:                        }
0321:                    }
0322:
0323:                this .visibleColumns = newVC;
0324:
0325:                // Assure visual refresh
0326:                refreshCurrentPage();
0327:            }
0328:
0329:            /**
0330:             * Get the headers of the columns.
0331:             * 
0332:             * <p>
0333:             * The headers match the property id:s given my the set visible column
0334:             * headers. The table must be set in either
0335:             * <code>ROW_HEADER_MODE_EXPLICIT</code> or
0336:             * <code>ROW_HEADER_MODE_EXPLICIT_DEFAULTS_ID</code> mode to show the
0337:             * headers. In the defaults mode any nulls in the headers array are replaced
0338:             * with id.toString() outputs when rendering.
0339:             * </p>
0340:             * 
0341:             * @return Array of column headers.
0342:             */
0343:            public String[] getColumnHeaders() {
0344:                if (this .columnHeaders == null) {
0345:                    return null;
0346:                }
0347:                String[] headers = new String[this .visibleColumns.size()];
0348:                int i = 0;
0349:                for (Iterator it = this .visibleColumns.iterator(); it.hasNext(); i++) {
0350:                    headers[i] = (String) this .columnHeaders.get(it.next());
0351:                }
0352:                return headers;
0353:            }
0354:
0355:            /**
0356:             * Set the headers of the columns.
0357:             * 
0358:             * <p>
0359:             * The headers match the property id:s given my the set visible column
0360:             * headers. The table must be set in either
0361:             * <code>ROW_HEADER_MODE_EXPLICIT</code> or
0362:             * <code>ROW_HEADER_MODE_EXPLICIT_DEFAULTS_ID</code> mode to show the
0363:             * headers. In the defaults mode any nulls in the headers array are replaced
0364:             * with id.toString() outputs when rendering.
0365:             * </p>
0366:             * 
0367:             * @param columnHeaders
0368:             *            Array of column headers that match the
0369:             *            <code>getVisibleColumns()</code>.
0370:             */
0371:            public void setColumnHeaders(String[] columnHeaders) {
0372:
0373:                if (columnHeaders.length != this .visibleColumns.size())
0374:                    throw new IllegalArgumentException(
0375:                            "The length of the headers array must match the number of visible columns");
0376:
0377:                this .columnHeaders.clear();
0378:                int i = 0;
0379:                for (Iterator it = this .visibleColumns.iterator(); it.hasNext()
0380:                        && i < columnHeaders.length; i++) {
0381:                    this .columnHeaders.put(it.next(), columnHeaders[i]);
0382:                }
0383:
0384:                // Assure visual refresh
0385:                refreshCurrentPage();
0386:            }
0387:
0388:            /**
0389:             * Get the icons of the columns.
0390:             * 
0391:             * <p>
0392:             * The icons in headers match the property id:s given my the set visible
0393:             * column headers. The table must be set in either
0394:             * <code>ROW_HEADER_MODE_EXPLICIT</code> or
0395:             * <code>ROW_HEADER_MODE_EXPLICIT_DEFAULTS_ID</code> mode to show the
0396:             * headers with icons.
0397:             * </p>
0398:             * 
0399:             * @return Array of icons that match the <code>getVisibleColumns()</code>.
0400:             */
0401:            public Resource[] getColumnIcons() {
0402:                if (this .columnIcons == null) {
0403:                    return null;
0404:                }
0405:                Resource[] icons = new Resource[this .visibleColumns.size()];
0406:                int i = 0;
0407:                for (Iterator it = this .visibleColumns.iterator(); it.hasNext(); i++) {
0408:                    icons[i] = (Resource) this .columnIcons.get(it.next());
0409:                }
0410:
0411:                return icons;
0412:            }
0413:
0414:            /**
0415:             * Set the icons of the columns.
0416:             * 
0417:             * <p>
0418:             * The icons in headers match the property id:s given my the set visible
0419:             * column headers. The table must be set in either
0420:             * <code>ROW_HEADER_MODE_EXPLICIT</code> or
0421:             * <code>ROW_HEADER_MODE_EXPLICIT_DEFAULTS_ID</code> mode to show the
0422:             * headers with icons.
0423:             * </p>
0424:             * 
0425:             * @param columnIcons
0426:             *            Array of icons that match the <code>getVisibleColumns()</code>.
0427:             */
0428:            public void setColumnIcons(Resource[] columnIcons) {
0429:
0430:                if (columnIcons.length != this .visibleColumns.size())
0431:                    throw new IllegalArgumentException(
0432:                            "The length of the icons array must match the number of visible columns");
0433:
0434:                this .columnIcons.clear();
0435:                int i = 0;
0436:                for (Iterator it = this .visibleColumns.iterator(); it.hasNext()
0437:                        && i < columnIcons.length; i++) {
0438:                    this .columnIcons.put(it.next(), columnIcons[i]);
0439:                }
0440:
0441:                // Assure visual refresh
0442:                refreshCurrentPage();
0443:            }
0444:
0445:            /**
0446:             * Get array of column alignments.
0447:             * 
0448:             * <p>
0449:             * The items in the array must match the properties identified by
0450:             * <code>getVisibleColumns()</code>. The possible values for the
0451:             * alignments include:
0452:             * <ul>
0453:             * <li><code>ALIGN_LEFT</code>: Left alignment</li>
0454:             * <li><code>ALIGN_CENTER</code>: Centered</li>
0455:             * <li><code>ALIGN_RIGHT</code>: Right alignment</li>
0456:             * </ul>
0457:             * The alignments default to <code>ALIGN_LEFT</code>: any null values are
0458:             * rendered as align lefts.
0459:             * </p>
0460:             * 
0461:             * @return Column alignments array.
0462:             */
0463:            public String[] getColumnAlignments() {
0464:                if (this .columnAlignments == null) {
0465:                    return null;
0466:                }
0467:                String[] alignments = new String[this .visibleColumns.size()];
0468:                int i = 0;
0469:                for (Iterator it = this .visibleColumns.iterator(); it.hasNext(); i++) {
0470:                    alignments[i++] = getColumnAlignment(it.next());
0471:                }
0472:
0473:                return alignments;
0474:            }
0475:
0476:            /**
0477:             * Set the column alignments.
0478:             * 
0479:             * <p>
0480:             * The items in the array must match the properties identified by
0481:             * <code>getVisibleColumns()</code>. The possible values for the
0482:             * alignments include:
0483:             * <ul>
0484:             * <li><code>ALIGN_LEFT</code>: Left alignment</li>
0485:             * <li><code>ALIGN_CENTER</code>: Centered</li>
0486:             * <li><code>ALIGN_RIGHT</code>: Right alignment</li>
0487:             * </ul>
0488:             * The alignments default to <code>ALIGN_LEFT</code>
0489:             * </p>
0490:             * 
0491:             * @param columnAlignments
0492:             *            Column alignments array.
0493:             */
0494:            public void setColumnAlignments(String[] columnAlignments) {
0495:
0496:                if (columnAlignments.length != this .visibleColumns.size())
0497:                    throw new IllegalArgumentException(
0498:                            "The length of the alignments array must match the number of visible columns");
0499:
0500:                // Check all alignments
0501:                for (int i = 0; i < columnAlignments.length; i++) {
0502:                    String a = columnAlignments[i];
0503:                    if (a != null && !a.equals(ALIGN_LEFT)
0504:                            && !a.equals(ALIGN_CENTER)
0505:                            && !a.equals(ALIGN_RIGHT))
0506:                        throw new IllegalArgumentException("Column " + i
0507:                                + " aligment '" + a + "' is invalid");
0508:                }
0509:
0510:                // Reset alignments
0511:                HashMap newCA = new HashMap();
0512:                int i = 0;
0513:                for (Iterator it = this .visibleColumns.iterator(); it.hasNext()
0514:                        && i < columnAlignments.length; i++) {
0515:                    newCA.put(it.next(), columnAlignments[i]);
0516:                }
0517:                this .columnAlignments = newCA;
0518:
0519:                // Assure visual refresh
0520:                refreshCurrentPage();
0521:            }
0522:
0523:            /**
0524:             * Get the page length.
0525:             * 
0526:             * <p>
0527:             * Setting page length 0 disables paging.
0528:             * </p>
0529:             * 
0530:             * @return Lenght of one page.
0531:             */
0532:            public int getPageLength() {
0533:                return this .pageLength;
0534:            }
0535:
0536:            /**
0537:             * Set the page length.
0538:             * 
0539:             * <p>
0540:             * Setting page length 0 disables paging. The page length defaults to 0 (no
0541:             * paging).
0542:             * </p>
0543:             * 
0544:             * @param Lenght
0545:             *            of one page.
0546:             */
0547:            public void setPageLength(int pageLength) {
0548:                if (pageLength >= 0 && this .pageLength != pageLength) {
0549:                    this .pageLength = pageLength;
0550:
0551:                    // Assure visual refresh
0552:                    refreshCurrentPage();
0553:                }
0554:            }
0555:
0556:            /**
0557:             * Getter for property currentPageFirstItem.
0558:             * 
0559:             * @return Value of property currentPageFirstItem.
0560:             */
0561:            public Object getCurrentPageFirstItemId() {
0562:
0563:                // Priorise index over id if indexes are supported
0564:                if (items instanceof  Container.Indexed) {
0565:                    int index = getCurrentPageFirstItemIndex();
0566:                    Object id = null;
0567:                    if (index >= 0 && index < size())
0568:                        id = ((Container.Indexed) items).getIdByIndex(index);
0569:                    if (id != null && !id.equals(currentPageFirstItemId))
0570:                        currentPageFirstItemId = id;
0571:                }
0572:
0573:                // If there is no item id at all, use the first one
0574:                if (currentPageFirstItemId == null)
0575:                    currentPageFirstItemId = ((Container.Ordered) items)
0576:                            .firstItemId();
0577:
0578:                return currentPageFirstItemId;
0579:            }
0580:
0581:            /**
0582:             * Setter for property currentPageFirstItem.
0583:             * 
0584:             * @param currentPageFirstItem
0585:             *            New value of property currentPageFirstItem.
0586:             */
0587:            public void setCurrentPageFirstItemId(Object currentPageFirstItemId) {
0588:
0589:                // Get the corresponding index
0590:                int index = -1;
0591:                try {
0592:                    index = ((Container.Indexed) items)
0593:                            .indexOfId(currentPageFirstItemId);
0594:                } catch (ClassCastException e) {
0595:
0596:                    // If the table item container does not have index, we have to
0597:                    // calculate the index by hand
0598:                    Object id = ((Container.Ordered) items).firstItemId();
0599:                    while (id != null && !id.equals(currentPageFirstItemId)) {
0600:                        index++;
0601:                        id = ((Container.Ordered) items).nextItemId(id);
0602:                    }
0603:                    if (id == null)
0604:                        index = -1;
0605:                }
0606:
0607:                // If the search for item index was successfull
0608:                if (index >= 0) {
0609:                    this .currentPageFirstItemId = currentPageFirstItemId;
0610:                    this .currentPageFirstItemIndex = index;
0611:                }
0612:
0613:                // Assure visual refresh
0614:                refreshCurrentPage();
0615:
0616:            }
0617:
0618:            /**
0619:             * Gets the icon Resource for the specified column.
0620:             * 
0621:             * @param propertyId
0622:             *            the propertyId indentifying the column.
0623:             * @return the icon for the specified column; null if the column has no icon
0624:             *         set, or if the column is not visible.
0625:             */
0626:            public Resource getColumnIcon(Object propertyId) {
0627:                return (Resource) this .columnIcons.get(propertyId);
0628:            }
0629:
0630:            /**
0631:             * Sets the icon Resource for the specified column.
0632:             * <p>
0633:             * Throws IllegalArgumentException if the specified column is not visible.
0634:             * </p>
0635:             * 
0636:             * @param propertyId
0637:             *            the propertyId identifying the column.
0638:             * @param icon
0639:             *            the icon Resource to set.
0640:             */
0641:            public void setColumnIcon(Object propertyId, Resource icon) {
0642:
0643:                if (icon == null)
0644:                    this .columnIcons.remove(propertyId);
0645:                else
0646:                    this .columnIcons.put(propertyId, icon);
0647:
0648:                // Assure visual refresh
0649:                refreshCurrentPage();
0650:            }
0651:
0652:            /**
0653:             * Gets the header for the specified column.
0654:             * 
0655:             * @param propertyId
0656:             *            the propertyId indentifying the column.
0657:             * @return the header for the specifed column if it has one.
0658:             */
0659:            public String getColumnHeader(Object propertyId) {
0660:                if (getColumnHeaderMode() == COLUMN_HEADER_MODE_HIDDEN)
0661:                    return null;
0662:
0663:                String header = (String) this .columnHeaders.get(propertyId);
0664:                if ((header == null && this .getColumnHeaderMode() == COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID)
0665:                        || this .getColumnHeaderMode() == COLUMN_HEADER_MODE_ID) {
0666:                    header = propertyId.toString();
0667:                }
0668:
0669:                return header;
0670:            }
0671:
0672:            /**
0673:             * Sets column header for the specified column;
0674:             * 
0675:             * @param propertyId
0676:             *            the propertyId indentifying the column.
0677:             * @param header
0678:             *            the header to set.
0679:             */
0680:            public void setColumnHeader(Object propertyId, String header) {
0681:
0682:                if (header == null) {
0683:                    this .columnHeaders.remove(propertyId);
0684:                    return;
0685:                }
0686:                this .columnHeaders.put(propertyId, header);
0687:
0688:                // Assure visual refresh
0689:                refreshCurrentPage();
0690:            }
0691:
0692:            /**
0693:             * Gets the specified column's alignment.
0694:             * 
0695:             * @param propertyId
0696:             *            the propertyID identifying the column.
0697:             * @return the specified column's alignment if it as one; null otherwise.
0698:             */
0699:            public String getColumnAlignment(Object propertyId) {
0700:                String a = (String) this .columnAlignments.get(propertyId);
0701:                return a == null ? ALIGN_LEFT : a;
0702:            }
0703:
0704:            /**
0705:             * Sets the specified column's alignment.
0706:             * 
0707:             * <p>
0708:             * Throws IllegalArgumentException if the alignment is not one of the
0709:             * following: ALIGN_LEFT, ALIGN_CENTER or ALIGN_RIGHT
0710:             * </p>
0711:             * 
0712:             * @param propertyId
0713:             *            the propertyID identifying the column.
0714:             * @param alignment
0715:             *            the desired alignment.
0716:             */
0717:            public void setColumnAlignment(Object propertyId, String alignment) {
0718:
0719:                // Check for valid alignments
0720:                if (alignment != null && !alignment.equals(ALIGN_LEFT)
0721:                        && !alignment.equals(ALIGN_CENTER)
0722:                        && !alignment.equals(ALIGN_RIGHT))
0723:                    throw new IllegalArgumentException("Column alignment '"
0724:                            + alignment + "' is not supported.");
0725:
0726:                if (alignment == null || alignment.equals(ALIGN_LEFT)) {
0727:                    this .columnAlignments.remove(propertyId);
0728:                    return;
0729:                }
0730:
0731:                this .columnAlignments.put(propertyId, alignment);
0732:
0733:                // Assure visual refresh
0734:                refreshCurrentPage();
0735:            }
0736:
0737:            /**
0738:             * Checks if the specified column is collapsed.
0739:             * 
0740:             * @param propertyId
0741:             *            the propertyID identifying the column.
0742:             * @return true if the column is collapsed; false otherwise;
0743:             */
0744:            public boolean isColumnCollapsed(Object propertyId) {
0745:                return collapsedColumns != null
0746:                        && collapsedColumns.contains(propertyId);
0747:            }
0748:
0749:            /**
0750:             * Sets whether the specified column is collapsed or not.
0751:             * 
0752:             * 
0753:             * @param propertyId
0754:             *            the propertyID identifying the column.
0755:             * @param collapsed
0756:             *            the desired collapsedness.
0757:             */
0758:            public void setColumnCollapsed(Object propertyId, boolean collapsed)
0759:                    throws IllegalAccessException {
0760:                if (!this .isColumnCollapsingAllowed()) {
0761:                    throw new IllegalAccessException(
0762:                            "Column collapsing not allowed!");
0763:                }
0764:
0765:                if (collapsed)
0766:                    this .collapsedColumns.add(propertyId);
0767:                else
0768:                    this .collapsedColumns.remove(propertyId);
0769:
0770:                // Assure visual refresh
0771:                refreshCurrentPage();
0772:            }
0773:
0774:            /**
0775:             * Check if column collapsing is allowed.
0776:             * 
0777:             * @return true if columns can be collapsed; false otherwise.
0778:             */
0779:            public boolean isColumnCollapsingAllowed() {
0780:                return this .columnCollapsingAllowed;
0781:            }
0782:
0783:            /**
0784:             * Sets whether column collapsing is allowed or not.
0785:             * 
0786:             * @param collapsingAllowed
0787:             *            specifies whether column collapsing is allowed.
0788:             */
0789:            public void setColumnCollapsingAllowed(boolean collapsingAllowed) {
0790:                this .columnCollapsingAllowed = collapsingAllowed;
0791:
0792:                if (!collapsingAllowed)
0793:                    collapsedColumns.clear();
0794:
0795:                // Assure visual refresh
0796:                refreshCurrentPage();
0797:            }
0798:
0799:            /**
0800:             * Check if column reordering is allowed.
0801:             * 
0802:             * @return true if columns can be reordered; false otherwise.
0803:             */
0804:            public boolean isColumnReorderingAllowed() {
0805:                return this .columnReorderingAllowed;
0806:            }
0807:
0808:            /**
0809:             * Sets whether column reordering is allowed or not.
0810:             * 
0811:             * @param reorderingAllowed
0812:             *            specifies whether column reordering is allowed.
0813:             */
0814:            public void setColumnReorderingAllowed(boolean reorderingAllowed) {
0815:                this .columnReorderingAllowed = reorderingAllowed;
0816:
0817:                // Assure visual refresh
0818:                refreshCurrentPage();
0819:            }
0820:
0821:            /*
0822:             * Arranges visible columns according to given columnOrder. Silently ignores
0823:             * colimnId:s that are not visible columns, and keeps the internal order of
0824:             * visible columns left out of the ordering (trailing). Silently does
0825:             * nothing if columnReordering is not allowed.
0826:             */
0827:            private void setColumnOrder(Object[] columnOrder) {
0828:                if (columnOrder == null || !this .isColumnReorderingAllowed()) {
0829:                    return;
0830:                }
0831:                LinkedList newOrder = new LinkedList();
0832:                for (int i = 0; i < columnOrder.length; i++) {
0833:                    if (columnOrder[i] != null
0834:                            && this .visibleColumns.contains(columnOrder[i])) {
0835:                        this .visibleColumns.remove(columnOrder[i]);
0836:                        newOrder.add(columnOrder[i]);
0837:                    }
0838:                }
0839:                for (Iterator it = this .visibleColumns.iterator(); it.hasNext();) {
0840:                    Object columnId = it.next();
0841:                    if (!newOrder.contains(columnId))
0842:                        newOrder.add(columnId);
0843:                }
0844:                this .visibleColumns = newOrder;
0845:
0846:                // Assure visual refresh
0847:                refreshCurrentPage();
0848:            }
0849:
0850:            /**
0851:             * Getter for property currentPageFirstItem.
0852:             * 
0853:             * @return Value of property currentPageFirstItem.
0854:             */
0855:            public int getCurrentPageFirstItemIndex() {
0856:                return this .currentPageFirstItemIndex;
0857:            }
0858:
0859:            /**
0860:             * Setter for property currentPageFirstItem.
0861:             * 
0862:             * @param newIndex
0863:             *            New value of property currentPageFirstItem.
0864:             */
0865:            public void setCurrentPageFirstItemIndex(int newIndex) {
0866:
0867:                // Ensure that the new value is valid
0868:                if (newIndex < 0)
0869:                    newIndex = 0;
0870:                if (newIndex >= size())
0871:                    newIndex = size() - 1;
0872:
0873:                // Refresh first item id
0874:                if (items instanceof  Container.Indexed) {
0875:                    try {
0876:                        currentPageFirstItemId = ((Container.Indexed) items)
0877:                                .getIdByIndex(newIndex);
0878:                    } catch (IndexOutOfBoundsException e) {
0879:                        currentPageFirstItemId = null;
0880:                    }
0881:                    this .currentPageFirstItemIndex = newIndex;
0882:                } else {
0883:
0884:                    // For containers not supporting indexes, we must iterate the
0885:                    // container forwards / backwards
0886:                    // next available item forward or backward
0887:
0888:                    this .currentPageFirstItemId = ((Container.Ordered) items)
0889:                            .firstItemId();
0890:
0891:                    // Go forwards in the middle of the list (respect borders)
0892:                    while (this .currentPageFirstItemIndex < newIndex
0893:                            && !((Container.Ordered) items)
0894:                                    .isLastId(currentPageFirstItemId)) {
0895:                        this .currentPageFirstItemIndex++;
0896:                        currentPageFirstItemId = ((Container.Ordered) items)
0897:                                .nextItemId(currentPageFirstItemId);
0898:                    }
0899:
0900:                    // If we did hit the border
0901:                    if (((Container.Ordered) items)
0902:                            .isLastId(currentPageFirstItemId)) {
0903:                        this .currentPageFirstItemIndex = size() - 1;
0904:                    }
0905:
0906:                    // Go backwards in the middle of the list (respect borders)
0907:                    while (this .currentPageFirstItemIndex > newIndex
0908:                            && !((Container.Ordered) items)
0909:                                    .isFirstId(currentPageFirstItemId)) {
0910:                        this .currentPageFirstItemIndex--;
0911:                        currentPageFirstItemId = ((Container.Ordered) items)
0912:                                .prevItemId(currentPageFirstItemId);
0913:                    }
0914:
0915:                    // If we did hit the border
0916:                    if (((Container.Ordered) items)
0917:                            .isFirstId(currentPageFirstItemId)) {
0918:                        this .currentPageFirstItemIndex = 0;
0919:                    }
0920:
0921:                    // Go forwards once more
0922:                    while (this .currentPageFirstItemIndex < newIndex
0923:                            && !((Container.Ordered) items)
0924:                                    .isLastId(currentPageFirstItemId)) {
0925:                        this .currentPageFirstItemIndex++;
0926:                        currentPageFirstItemId = ((Container.Ordered) items)
0927:                                .nextItemId(currentPageFirstItemId);
0928:                    }
0929:
0930:                    // If for some reason we do hit border again, override
0931:                    // the user index request
0932:                    if (((Container.Ordered) items)
0933:                            .isLastId(currentPageFirstItemId)) {
0934:                        newIndex = this .currentPageFirstItemIndex = size() - 1;
0935:                    }
0936:                }
0937:
0938:                // Assure visual refresh
0939:                refreshCurrentPage();
0940:            }
0941:
0942:            /**
0943:             * Getter for property pageBuffering.
0944:             * 
0945:             * @return Value of property pageBuffering.
0946:             */
0947:            public boolean isPageBufferingEnabled() {
0948:                return this .pageBuffering;
0949:            }
0950:
0951:            /**
0952:             * Setter for property pageBuffering.
0953:             * 
0954:             * @param pageBuffering
0955:             *            New value of property pageBuffering.
0956:             */
0957:            public void setPageBufferingEnabled(boolean pageBuffering) {
0958:
0959:                this .pageBuffering = pageBuffering;
0960:
0961:                // If page buffering is disabled, clear the buffer
0962:                if (!pageBuffering)
0963:                    pageBuffer = null;
0964:            }
0965:
0966:            /**
0967:             * Getter for property selectable.
0968:             * 
0969:             * <p>
0970:             * The table is not selectable by default.
0971:             * </p>
0972:             * 
0973:             * @return Value of property selectable.
0974:             */
0975:            public boolean isSelectable() {
0976:                return this .selectable;
0977:            }
0978:
0979:            /**
0980:             * Setter for property selectable.
0981:             * 
0982:             * <p>
0983:             * The table is not selectable by default.
0984:             * </p>
0985:             * 
0986:             * @param selectable
0987:             *            New value of property selectable.
0988:             */
0989:            public void setSelectable(boolean selectable) {
0990:                if (this .selectable != selectable) {
0991:                    this .selectable = selectable;
0992:                    requestRepaint();
0993:                }
0994:            }
0995:
0996:            /**
0997:             * Getter for property columnHeaderMode.
0998:             * 
0999:             * @return Value of property columnHeaderMode.
1000:             */
1001:            public int getColumnHeaderMode() {
1002:                return this .columnHeaderMode;
1003:            }
1004:
1005:            /**
1006:             * Setter for property columnHeaderMode.
1007:             * 
1008:             * @param columnHeaderMode
1009:             *            New value of property columnHeaderMode.
1010:             */
1011:            public void setColumnHeaderMode(int columnHeaderMode) {
1012:                if (columnHeaderMode >= COLUMN_HEADER_MODE_HIDDEN
1013:                        && columnHeaderMode <= COLUMN_HEADER_MODE_EXPLICIT_DEFAULTS_ID)
1014:                    this .columnHeaderMode = columnHeaderMode;
1015:
1016:                // Assure visual refresh
1017:                refreshCurrentPage();
1018:            }
1019:
1020:            /**
1021:             * Refresh the current page contents. If the page buffering is turned off,
1022:             * it is not necessary to call this explicitely.
1023:             */
1024:            public void refreshCurrentPage() {
1025:
1026:                // Clear page buffer and notify about the change
1027:                pageBuffer = null;
1028:                requestRepaint();
1029:            }
1030:
1031:            /**
1032:             * Set the row header mode.
1033:             * <p>
1034:             * The mode can be one of the following ones:
1035:             * <ul>
1036:             * <li><code>ROW_HEADER_MODE_HIDDEN</code>: The row captions are hidden.
1037:             * </li>
1038:             * <li><code>ROW_HEADER_MODE_ID</code>: Items Id-objects
1039:             * <code>toString()</code> is used as row caption.
1040:             * <li><code>ROW_HEADER_MODE_ITEM</code>: Item-objects
1041:             * <code>toString()</code> is used as row caption.
1042:             * <li><code>ROW_HEADER_MODE_PROPERTY</code>: Property set with
1043:             * <code>setItemCaptionPropertyId()</code> is used as row header.
1044:             * <li><code>ROW_HEADER_MODE_EXPLICIT_DEFAULTS_ID</code>: Items
1045:             * Id-objects <code>toString()</code> is used as row header. If caption is
1046:             * explicitly specified, it overrides the id-caption.
1047:             * <li><code>ROW_HEADER_MODE_EXPLICIT</code>: The row headers must be
1048:             * explicitly specified.</li>
1049:             * <li><code>ROW_HEADER_MODE_INDEX</code>: The index of the item is used
1050:             * as row caption. The index mode can only be used with the containers
1051:             * implementing <code>Container.Indexed</code> interface.</li>
1052:             * </ul>
1053:             * The default value is <code>ROW_HEADER_MODE_HIDDEN</code>
1054:             * </p>
1055:             * 
1056:             * @param mode
1057:             *            One of the modes listed above.
1058:             */
1059:            public void setRowHeaderMode(int mode) {
1060:                if (ROW_HEADER_MODE_HIDDEN == mode)
1061:                    rowCaptionsAreHidden = true;
1062:                else {
1063:                    rowCaptionsAreHidden = false;
1064:                    setItemCaptionMode(mode);
1065:                }
1066:
1067:                // Assure visual refresh
1068:                refreshCurrentPage();
1069:            }
1070:
1071:            /**
1072:             * Get the row header mode.
1073:             * 
1074:             * @return Row header mode.
1075:             * @see #setRowHeaderMode(int)
1076:             */
1077:            public int getRowHeaderMode() {
1078:                return rowCaptionsAreHidden ? ROW_HEADER_MODE_HIDDEN
1079:                        : getItemCaptionMode();
1080:            }
1081:
1082:            /**
1083:             * Add new row to table and fill the visible cells with given values.
1084:             * 
1085:             * @param cells
1086:             *            Object array that is used for filling the visible cells new
1087:             *            row. The types must be settable to visible column property
1088:             *            types.
1089:             * @param itemId
1090:             *            Id the new row. If null, a new id is automatically assigned.
1091:             *            If given, the table cant already have a item with given id.
1092:             * @return Returns item id for the new row. Returns null if operation fails.
1093:             */
1094:            public Object addItem(Object[] cells, Object itemId)
1095:                    throws UnsupportedOperationException {
1096:
1097:                Object[] cols = getVisibleColumns();
1098:
1099:                // Check that a correct number of cells are given
1100:                if (cells.length != cols.length)
1101:                    return null;
1102:
1103:                // Create new item
1104:                Item item;
1105:                if (itemId == null) {
1106:                    itemId = items.addItem();
1107:                    if (itemId == null)
1108:                        return null;
1109:                    item = items.getItem(itemId);
1110:                } else
1111:                    item = items.addItem(itemId);
1112:                if (item == null)
1113:                    return null;
1114:
1115:                // Fill the item properties
1116:                for (int i = 0; i < cols.length; i++)
1117:                    item.getItemProperty(cols[i]).setValue(cells[i]);
1118:
1119:                return itemId;
1120:            }
1121:
1122:            /* Overriding select behavior******************************************** */
1123:
1124:            /**
1125:             * @see org.millstone.base.data.Container.Viewer#setContainerDataSource(Container)
1126:             */
1127:            public void setContainerDataSource(Container newDataSource) {
1128:
1129:                if (newDataSource == null)
1130:                    newDataSource = new IndexedContainer();
1131:
1132:                // Assure that the data source is ordered by making unordered
1133:                // containers ordered by wrapping them
1134:                if (newDataSource instanceof  Container.Ordered)
1135:                    super .setContainerDataSource(newDataSource);
1136:                else
1137:                    super .setContainerDataSource(new ContainerOrderedWrapper(
1138:                            newDataSource));
1139:
1140:                // Reset page position
1141:                currentPageFirstItemId = null;
1142:                currentPageFirstItemIndex = 0;
1143:
1144:                // Reset column properties
1145:                if (this .collapsedColumns != null)
1146:                    this .collapsedColumns.clear();
1147:                setVisibleColumns(getContainerPropertyIds().toArray());
1148:
1149:                // Assure visual refresh
1150:                refreshCurrentPage();
1151:            }
1152:
1153:            /* Component basics ***************************************************** */
1154:
1155:            /**
1156:             * Invoked when the value of a variable has changed.
1157:             * 
1158:             * @param event
1159:             *            Variable change event containing the information about the
1160:             *            changed variable.
1161:             */
1162:            public void changeVariables(Object source, Map variables) {
1163:
1164:                super .changeVariables(source, variables);
1165:
1166:                // Page start index
1167:                if (variables.containsKey("firstvisible")) {
1168:                    Integer value = (Integer) variables.get("firstvisible");
1169:                    if (value != null)
1170:                        setCurrentPageFirstItemIndex(value.intValue() - 1);
1171:                }
1172:
1173:                // Actions
1174:                if (variables.containsKey("action")) {
1175:                    StringTokenizer st = new StringTokenizer((String) variables
1176:                            .get("action"), ",");
1177:                    if (st.countTokens() == 2) {
1178:                        Object itemId = itemIdMapper.get(st.nextToken());
1179:                        Action action = (Action) actionMapper.get(st
1180:                                .nextToken());
1181:                        if (action != null && containsId(itemId)
1182:                                && actionHandlers != null)
1183:                            for (Iterator i = actionHandlers.iterator(); i
1184:                                    .hasNext();)
1185:                                ((Action.Handler) i.next()).handleAction(
1186:                                        action, this , itemId);
1187:                    }
1188:                }
1189:
1190:                // Sorting
1191:                boolean doSort = false;
1192:                if (variables.containsKey("sortcolumn")) {
1193:                    String colId = (String) variables.get("sortcolumn");
1194:                    if (colId != null && !"".equals(colId)
1195:                            && !"null".equals(colId)) {
1196:                        Object id = this .columnIdMap.get(colId);
1197:                        setSortContainerPropertyId(id);
1198:                        doSort = true;
1199:                    }
1200:                }
1201:                if (variables.containsKey("sortascending")) {
1202:                    boolean state = ((Boolean) variables.get("sortascending"))
1203:                            .booleanValue();
1204:                    if (state != this .sortAscending) {
1205:                        setSortAscending(state);
1206:                        doSort = true;
1207:                    }
1208:                }
1209:                if (doSort)
1210:                    this .sort();
1211:
1212:                // Dynamic column hide/show and order
1213:                // Update visible columns
1214:                if (this .isColumnCollapsingAllowed()) {
1215:                    if (variables.containsKey("collapsedcolumns")) {
1216:                        try {
1217:                            Object[] ids = (Object[]) variables
1218:                                    .get("collapsedcolumns");
1219:                            for (Iterator it = this .visibleColumns.iterator(); it
1220:                                    .hasNext();) {
1221:                                this .setColumnCollapsed(it.next(), false);
1222:                            }
1223:                            for (int i = 0; i < ids.length; i++) {
1224:                                this .setColumnCollapsed(columnIdMap.get(ids[i]
1225:                                        .toString()), true);
1226:                            }
1227:                        } catch (Exception ignored) {
1228:                        }
1229:                    }
1230:                }
1231:                if (this .isColumnReorderingAllowed()) {
1232:                    if (variables.containsKey("columnorder")) {
1233:                        try {
1234:                            Object[] ids = (Object[]) variables
1235:                                    .get("columnorder");
1236:                            for (int i = 0; i < ids.length; i++) {
1237:                                ids[i] = columnIdMap.get(ids[i].toString());
1238:                            }
1239:                            this .setColumnOrder(ids);
1240:                        } catch (Exception ignored) {
1241:                        }
1242:                    }
1243:                }
1244:            }
1245:
1246:            /**
1247:             * Paint the content of this component.
1248:             * 
1249:             * @param target
1250:             *            Paint target.
1251:             * @throws PaintException
1252:             *             The paint operation failed.
1253:             */
1254:            public void paintContent(PaintTarget target) throws PaintException {
1255:
1256:                // Focus control id
1257:                if (this .getFocusableId() > 0) {
1258:                    target.addAttribute("focusid", this .getFocusableId());
1259:                }
1260:
1261:                // The tab ordering number
1262:                if (this .getTabIndex() > 0)
1263:                    target.addAttribute("tabindex", this .getTabIndex());
1264:
1265:                // Initialize temps
1266:                Object[] colids = getVisibleColumns();
1267:                int cols = colids.length;
1268:                int first = getCurrentPageFirstItemIndex();
1269:                int total = size();
1270:                int pagelen = getPageLength();
1271:                int colHeadMode = getColumnHeaderMode();
1272:                boolean colheads = colHeadMode != COLUMN_HEADER_MODE_HIDDEN;
1273:                boolean rowheads = getRowHeaderMode() != ROW_HEADER_MODE_HIDDEN;
1274:                Object[][] cells = getVisibleCells();
1275:                boolean iseditable = this .isEditable();
1276:
1277:                // selection support
1278:                String[] selectedKeys;
1279:                if (isMultiSelect())
1280:                    selectedKeys = new String[((Set) getValue()).size()];
1281:                else
1282:                    selectedKeys = new String[(getValue() == null
1283:                            && getNullSelectionItemId() == null ? 0 : 1)];
1284:                int keyIndex = 0;
1285:
1286:                // Table attributes
1287:                if (isSelectable())
1288:                    target.addAttribute("selectmode",
1289:                            (isMultiSelect() ? "multi" : "single"));
1290:                else
1291:                    target.addAttribute("selectmode", "none");
1292:                target.addAttribute("cols", cols);
1293:                target.addAttribute("rows", cells[0].length);
1294:                target.addAttribute("totalrows", total);
1295:                if (pagelen != 0)
1296:                    target.addAttribute("pagelength", pagelen);
1297:                if (colheads)
1298:                    target.addAttribute("colheaders", true);
1299:                if (rowheads)
1300:                    target.addAttribute("rowheaders", true);
1301:
1302:                // Columns
1303:                target.startTag("cols");
1304:                Collection sortables = getSortableContainerPropertyIds();
1305:                for (Iterator it = this .visibleColumns.iterator(); it.hasNext();) {
1306:                    Object columnId = it.next();
1307:                    if (!isColumnCollapsed(columnId)) {
1308:                        target.startTag("ch");
1309:                        if (colheads) {
1310:                            if (this .getColumnIcon(columnId) != null)
1311:                                target.addAttribute("icon", this 
1312:                                        .getColumnIcon(columnId));
1313:                            if (sortables.contains(columnId))
1314:                                target.addAttribute("sortable", true);
1315:                            String header = (String) this 
1316:                                    .getColumnHeader(columnId);
1317:                            target.addAttribute("caption",
1318:                                    (header != null ? header : ""));
1319:                        }
1320:                        target.addAttribute("cid", this .columnIdMap
1321:                                .key(columnId));
1322:                        if (!ALIGN_LEFT.equals(this 
1323:                                .getColumnAlignment(columnId)))
1324:                            target.addAttribute("align", this 
1325:                                    .getColumnAlignment(columnId));
1326:                        target.endTag("ch");
1327:                    }
1328:                }
1329:                target.endTag("cols");
1330:
1331:                // Rows
1332:                Set actionSet = new LinkedHashSet();
1333:                boolean selectable = isSelectable();
1334:                boolean[] iscomponent = new boolean[this .visibleColumns.size()];
1335:                int iscomponentIndex = 0;
1336:                for (Iterator it = this .visibleColumns.iterator(); it.hasNext()
1337:                        && iscomponentIndex < iscomponent.length;) {
1338:                    Object columnId = it.next();
1339:                    Class colType = getType(columnId);
1340:                    iscomponent[iscomponentIndex++] = colType != null
1341:                            && Component.class.isAssignableFrom(colType);
1342:                }
1343:                target.startTag("rows");
1344:                for (int i = 0; i < cells[0].length; i++) {
1345:                    target.startTag("tr");
1346:                    Object itemId = cells[CELL_ITEMID][i];
1347:
1348:                    // tr attributes
1349:                    if (rowheads) {
1350:                        if (cells[CELL_ICON][i] != null)
1351:                            target.addAttribute("icon",
1352:                                    (Resource) cells[CELL_ICON][i]);
1353:                        if (cells[CELL_HEADER][i] != null)
1354:                            target.addAttribute("caption",
1355:                                    (String) cells[CELL_HEADER][i]);
1356:                    }
1357:                    if (actionHandlers != null || isSelectable()) {
1358:                        target.addAttribute("key", (String) cells[CELL_KEY][i]);
1359:                        if (isSelected(itemId)
1360:                                && keyIndex < selectedKeys.length) {
1361:                            target.addAttribute("selected", true);
1362:                            selectedKeys[keyIndex++] = (String) cells[CELL_KEY][i];
1363:                        }
1364:                    }
1365:
1366:                    // Actions
1367:                    if (actionHandlers != null) {
1368:                        target.startTag("al");
1369:                        for (Iterator ahi = actionHandlers.iterator(); ahi
1370:                                .hasNext();) {
1371:                            Action[] aa = ((Action.Handler) ahi.next())
1372:                                    .getActions(itemId, this );
1373:                            if (aa != null)
1374:                                for (int ai = 0; ai < aa.length; ai++) {
1375:                                    String key = actionMapper.key(aa[ai]);
1376:                                    actionSet.add(aa[ai]);
1377:                                    target.addSection("ak", key);
1378:                                }
1379:                        }
1380:                        target.endTag("al");
1381:                    }
1382:
1383:                    // cells
1384:                    int currentColumn = 0;
1385:                    for (Iterator it = this .visibleColumns.iterator(); it
1386:                            .hasNext(); currentColumn++) {
1387:                        Object columnId = it.next();
1388:                        if (columnId == null
1389:                                || this .isColumnCollapsed(columnId))
1390:                            continue;
1391:                        if ((iscomponent[currentColumn] || iseditable)
1392:                                && Component.class
1393:                                        .isInstance(cells[CELL_FIRSTCOL
1394:                                                + currentColumn][i])) {
1395:                            Component c = (Component) cells[CELL_FIRSTCOL
1396:                                    + currentColumn][i];
1397:                            if (c == null)
1398:                                target.addSection("label", "");
1399:                            else
1400:                                c.paint(target);
1401:                        } else
1402:                            target.addSection("label",
1403:                                    (String) cells[CELL_FIRSTCOL
1404:                                            + currentColumn][i]);
1405:                    }
1406:
1407:                    target.endTag("tr");
1408:                }
1409:                target.endTag("rows");
1410:
1411:                // The select variable is only enabled if selectable
1412:                if (selectable)
1413:                    target.addVariable(this , "selected", selectedKeys);
1414:
1415:                // The cursors are only shown on pageable table
1416:                if (first != 0 || getPageLength() > 0)
1417:                    target.addVariable(this , "firstvisible", first + 1);
1418:
1419:                // Sorting
1420:                if (getContainerDataSource() instanceof  Container.Sortable) {
1421:                    target.addVariable(this , "sortcolumn", this .columnIdMap
1422:                            .key(this .sortContainerPropertyId));
1423:                    target.addVariable(this , "sortascending",
1424:                            this .sortAscending);
1425:                }
1426:
1427:                // Actions
1428:                if (!actionSet.isEmpty()) {
1429:                    target.startTag("actions");
1430:                    target.addVariable(this , "action", "");
1431:                    for (Iterator it = actionSet.iterator(); it.hasNext();) {
1432:                        Action a = (Action) it.next();
1433:                        target.startTag("action");
1434:                        if (a.getCaption() != null)
1435:                            target.addAttribute("caption", a.getCaption());
1436:                        if (a.getIcon() != null)
1437:                            target.addAttribute("icon", a.getIcon());
1438:                        target.addAttribute("key", actionMapper.key(a));
1439:                        target.endTag("action");
1440:                    }
1441:                    target.endTag("actions");
1442:                }
1443:                if (this .columnReorderingAllowed) {
1444:                    String[] colorder = new String[this .visibleColumns.size()];
1445:                    int i = 0;
1446:                    for (Iterator it = this .visibleColumns.iterator(); it
1447:                            .hasNext()
1448:                            && i < colorder.length;) {
1449:                        colorder[i++] = this .columnIdMap.key(it.next());
1450:                    }
1451:                    target.addVariable(this , "columnorder", colorder);
1452:                }
1453:                // Available columns
1454:                if (this .columnCollapsingAllowed) {
1455:                    HashSet ccs = new HashSet();
1456:                    for (Iterator i = visibleColumns.iterator(); i.hasNext();) {
1457:                        Object o = i.next();
1458:                        if (isColumnCollapsed(o))
1459:                            ccs.add(o);
1460:                    }
1461:                    String[] collapsedkeys = new String[ccs.size()];
1462:                    int nextColumn = 0;
1463:                    for (Iterator it = this .visibleColumns.iterator(); it
1464:                            .hasNext()
1465:                            && nextColumn < collapsedkeys.length;) {
1466:                        Object columnId = it.next();
1467:                        if (this .isColumnCollapsed(columnId)) {
1468:                            collapsedkeys[nextColumn++] = this .columnIdMap
1469:                                    .key(columnId);
1470:                        }
1471:                    }
1472:                    target.addVariable(this , "collapsedcolumns", collapsedkeys);
1473:                    target.startTag("visiblecolumns");
1474:                    int i = 0;
1475:                    for (Iterator it = this .visibleColumns.iterator(); it
1476:                            .hasNext(); i++) {
1477:                        Object columnId = it.next();
1478:                        if (columnId != null) {
1479:                            target.startTag("column");
1480:                            target.addAttribute("cid", this .columnIdMap
1481:                                    .key(columnId));
1482:                            String head = getColumnHeader(columnId);
1483:                            target.addAttribute("caption", (head != null ? head
1484:                                    : ""));
1485:                            if (this .isColumnCollapsed(columnId)) {
1486:                                target.addAttribute("collapsed", true);
1487:                            }
1488:                            target.endTag("column");
1489:                        }
1490:                    }
1491:                    target.endTag("visiblecolumns");
1492:                }
1493:            }
1494:
1495:            /**
1496:             * Get UIDL tag corresponding to component.
1497:             * 
1498:             * @return UIDL tag as string.
1499:             */
1500:            public String getTag() {
1501:                return "table";
1502:            }
1503:
1504:            /** Return cached visible table contents */
1505:            private Object[][] getVisibleCells() {
1506:
1507:                // Return a buffered value if possible
1508:                if (pageBuffer != null && isPageBufferingEnabled())
1509:                    return pageBuffer;
1510:
1511:                // Stop listening the old properties and initialise the list
1512:                if (listenedProperties == null)
1513:                    listenedProperties = new LinkedList();
1514:                else
1515:                    for (Iterator i = listenedProperties.iterator(); i
1516:                            .hasNext();) {
1517:                        ((Property.ValueChangeNotifier) i.next())
1518:                                .removeListener(this );
1519:                    }
1520:
1521:                // Detach old visible component from the table
1522:                if (visibleComponents == null)
1523:                    visibleComponents = new LinkedList();
1524:                else
1525:                    for (Iterator i = visibleComponents.iterator(); i.hasNext();) {
1526:                        ((Component) i.next()).setParent(null);
1527:                    }
1528:
1529:                // Collect basic facts about the table page
1530:                Object[] colids = getVisibleColumns();
1531:                int cols = colids.length;
1532:                int pagelen = getPageLength();
1533:                int firstIndex = getCurrentPageFirstItemIndex();
1534:                int rows = size();
1535:                if (rows > 0 && firstIndex >= 0)
1536:                    rows -= firstIndex;
1537:
1538:                if (pagelen > 0 && pagelen < rows)
1539:                    rows = pagelen;
1540:                Object[][] cells = new Object[cols + CELL_FIRSTCOL][rows];
1541:                if (rows == 0)
1542:                    return cells;
1543:                Object id = getCurrentPageFirstItemId();
1544:                int headmode = getRowHeaderMode();
1545:                boolean[] iscomponent = new boolean[cols];
1546:                for (int i = 0; i < cols; i++)
1547:                    iscomponent[i] = Component.class
1548:                            .isAssignableFrom(getType(colids[i]));
1549:
1550:                // Create page contents
1551:                int filledRows = 0;
1552:                for (int i = 0; i < rows && id != null; i++) {
1553:                    cells[CELL_ITEMID][i] = id;
1554:                    cells[CELL_KEY][i] = itemIdMapper.key(id);
1555:                    if (headmode != ROW_HEADER_MODE_HIDDEN) {
1556:                        switch (headmode) {
1557:                        case ROW_HEADER_MODE_INDEX:
1558:                            cells[CELL_HEADER][i] = String.valueOf(i
1559:                                    + firstIndex + 1);
1560:                            break;
1561:                        default:
1562:                            cells[CELL_HEADER][i] = getItemCaption(id);
1563:                        }
1564:                        cells[CELL_ICON][i] = getItemIcon(id);
1565:                    }
1566:                    if (cols > 0) {
1567:                        for (int j = 0; j < cols; j++) {
1568:                            Object value = null;
1569:                            Property p = getContainerProperty(id, colids[j]);
1570:                            if (p != null) {
1571:                                if (p instanceof  Property.ValueChangeNotifier) {
1572:                                    ((Property.ValueChangeNotifier) p)
1573:                                            .addListener(this );
1574:                                    listenedProperties.add(p);
1575:                                }
1576:                                if (iscomponent[j]) {
1577:                                    value = p.getValue();
1578:                                } else if (p != null) {
1579:                                    value = getPropertyValue(id, colids[j], p);
1580:                                } else {
1581:                                    value = getPropertyValue(id, colids[j],
1582:                                            null);
1583:                                }
1584:                            } else {
1585:                                value = "";
1586:                            }
1587:
1588:                            if (value instanceof  Component) {
1589:                                ((Component) value).setParent(this );
1590:                                visibleComponents.add((Component) value);
1591:                            }
1592:                            cells[CELL_FIRSTCOL + j][i] = value;
1593:
1594:                        }
1595:                    }
1596:                    id = ((Container.Ordered) items).nextItemId(id);
1597:
1598:                    filledRows++;
1599:                }
1600:
1601:                // Assure that all the rows of the cell-buffer are valid
1602:                if (filledRows != cells[0].length) {
1603:                    Object[][] temp = new Object[cells.length][filledRows];
1604:                    for (int i = 0; i < cells.length; i++)
1605:                        for (int j = 0; j < filledRows; j++)
1606:                            temp[i][j] = cells[i][j];
1607:                    cells = temp;
1608:                }
1609:
1610:                // Save the results to internal buffer iff in buffering mode
1611:                // to possible conserve memory from large non-buffered pages
1612:                if (isPageBufferingEnabled())
1613:                    pageBuffer = cells;
1614:
1615:                return cells;
1616:            }
1617:
1618:            /**
1619:             * Get value of property.
1620:             * 
1621:             * By default if the table is editable the fieldFactory is used to create
1622:             * editors for table cells. Otherwise formatPropertyValue is used to format
1623:             * the value representation.
1624:             * 
1625:             * @see #setFieldFactory(FieldFactory)
1626:             * @param rowId
1627:             *            Id of the row (same as item Id)
1628:             * @param colId
1629:             *            Id of the column
1630:             * @param property
1631:             *            Property to be presented
1632:             * @return Object Either formatted value or Component for field.
1633:             */
1634:            protected Object getPropertyValue(Object rowId, Object colId,
1635:                    Property property) {
1636:                if (this .isEditable() && this .fieldFactory != null) {
1637:                    Field f = this .fieldFactory.createField(
1638:                            getContainerDataSource(), rowId, colId, this );
1639:                    if (f != null) {
1640:                        f.setPropertyDataSource(property);
1641:                        return f;
1642:                    }
1643:                }
1644:
1645:                return formatPropertyValue(rowId, colId, property);
1646:            }
1647:
1648:            /**
1649:             * Formats table cell property values. By default the property.toString()
1650:             * and return a empty string for null properties.
1651:             * 
1652:             * @param itemId
1653:             * @param property
1654:             *            Property to be formatted
1655:             * @return String representation of property and its value.
1656:             * @since 3.1
1657:             */
1658:            protected String formatPropertyValue(Object rowId, Object colId,
1659:                    Property property) {
1660:                if (property == null) {
1661:                    return "";
1662:                }
1663:                return property.toString();
1664:            }
1665:
1666:            /* Action container *************************************************** */
1667:
1668:            /**
1669:             * @see org.millstone.base.event.Action.Container#addActionHandler(Action.Handler)
1670:             */
1671:            public void addActionHandler(Action.Handler actionHandler) {
1672:
1673:                if (actionHandler != null) {
1674:
1675:                    if (actionHandlers == null) {
1676:                        actionHandlers = new LinkedList();
1677:                        actionMapper = new KeyMapper();
1678:                    }
1679:
1680:                    if (!actionHandlers.contains(actionHandler)) {
1681:                        actionHandlers.add(actionHandler);
1682:                        requestRepaint();
1683:                    }
1684:
1685:                }
1686:            }
1687:
1688:            /**
1689:             * @see org.millstone.base.event.Action.Container#removeActionHandler(Action.Handler)
1690:             */
1691:            public void removeActionHandler(Action.Handler actionHandler) {
1692:
1693:                if (actionHandlers != null
1694:                        && actionHandlers.contains(actionHandler)) {
1695:
1696:                    actionHandlers.remove(actionHandler);
1697:
1698:                    if (actionHandlers.isEmpty()) {
1699:                        actionHandlers = null;
1700:                        actionMapper = null;
1701:                    }
1702:
1703:                    requestRepaint();
1704:                }
1705:            }
1706:
1707:            /* Property value change listening support **************************** */
1708:
1709:            /**
1710:             * @see org.millstone.base.data.Property.ValueChangeListener#valueChange(Property.ValueChangeEvent)
1711:             */
1712:            public void valueChange(Property.ValueChangeEvent event) {
1713:                super .valueChange(event);
1714:                requestRepaint();
1715:            }
1716:
1717:            /**
1718:             * @see org.millstone.base.ui.Component#attach()
1719:             */
1720:            public void attach() {
1721:                super .attach();
1722:
1723:                if (visibleComponents != null)
1724:                    for (Iterator i = visibleComponents.iterator(); i.hasNext();)
1725:                        ((Component) i.next()).attach();
1726:            }
1727:
1728:            /**
1729:             * @see org.millstone.base.ui.Component#attach()
1730:             */
1731:            public void detach() {
1732:                super .detach();
1733:
1734:                if (visibleComponents != null)
1735:                    for (Iterator i = visibleComponents.iterator(); i.hasNext();)
1736:                        ((Component) i.next()).detach();
1737:            }
1738:
1739:            /**
1740:             * @see org.millstone.base.data.Container#removeAllItems()
1741:             */
1742:            public boolean removeAllItems() {
1743:                this .currentPageFirstItemId = null;
1744:                this .currentPageFirstItemIndex = 0;
1745:                return super .removeAllItems();
1746:            }
1747:
1748:            /**
1749:             * @see org.millstone.base.data.Container#removeItem(Object)
1750:             */
1751:            public boolean removeItem(Object itemId) {
1752:                Object nextItemId = ((Container.Ordered) items)
1753:                        .nextItemId(itemId);
1754:                boolean ret = super .removeItem(itemId);
1755:                if (ret && (itemId != null)
1756:                        && (itemId.equals(this .currentPageFirstItemId))) {
1757:                    this .currentPageFirstItemId = nextItemId;
1758:                }
1759:                return ret;
1760:            }
1761:
1762:            /**
1763:             * @see org.millstone.base.data.Container#removeContainerProperty(Object)
1764:             */
1765:            public boolean removeContainerProperty(Object propertyId)
1766:                    throws UnsupportedOperationException {
1767:
1768:                // If a visible property is removed, remove the corresponding column
1769:                this .visibleColumns.remove(propertyId);
1770:                this .columnAlignments.remove(propertyId);
1771:                this .columnIcons.remove(propertyId);
1772:                this .columnHeaders.remove(propertyId);
1773:
1774:                return super .removeContainerProperty(propertyId);
1775:            }
1776:
1777:            /**
1778:             * Adds a new property to the table and show it as a visible column.
1779:             * 
1780:             * @see org.millstone.base.data.Container#addContainerProperty(Object,
1781:             *      Class, Object)
1782:             * 
1783:             * @param propertyId
1784:             *            Id of the proprty
1785:             * @param type
1786:             *            The class of the property
1787:             * @param defaultValue
1788:             *            The default value given for all existing items
1789:             */
1790:            public boolean addContainerProperty(Object propertyId, Class type,
1791:                    Object defaultValue) throws UnsupportedOperationException {
1792:                if (!super .addContainerProperty(propertyId, type, defaultValue))
1793:                    return false;
1794:                if (!this .visibleColumns.contains(propertyId))
1795:                    this .visibleColumns.add(propertyId);
1796:                return true;
1797:            }
1798:
1799:            /**
1800:             * Adds a new property to the table and show it as a visible column.
1801:             * 
1802:             * @see org.millstone.base.data.Container#addContainerProperty(Object,
1803:             *      Class, Object)
1804:             * 
1805:             * @param propertyId
1806:             *            Id of the proprty
1807:             * @param type
1808:             *            The class of the property
1809:             * @param defaultValue
1810:             *            The default value given for all existing items
1811:             * @param columnHeader
1812:             *            Explicit header of the column. If explicit header is not
1813:             *            needed, this should be set null.
1814:             * @param columnIcon
1815:             *            Icon of the column. If icon is not needed, this should be set
1816:             *            null.
1817:             * @param columnAlignment
1818:             *            Alignment of the column. Null implies align left.
1819:             */
1820:            public boolean addContainerProperty(Object propertyId, Class type,
1821:                    Object defaultValue, String columnHeader,
1822:                    Resource columnIcon, String columnAlignment)
1823:                    throws UnsupportedOperationException {
1824:                if (!this .addContainerProperty(propertyId, type, defaultValue))
1825:                    return false;
1826:                this .setColumnAlignment(propertyId, columnAlignment);
1827:                this .setColumnHeader(propertyId, columnHeader);
1828:                this .setColumnIcon(propertyId, columnIcon);
1829:                return true;
1830:            }
1831:
1832:            /**
1833:             * Return list of items on the current page
1834:             * 
1835:             * @see org.millstone.base.ui.Select#getVisibleItemIds()
1836:             */
1837:            public Collection getVisibleItemIds() {
1838:
1839:                LinkedList visible = new LinkedList();
1840:
1841:                Object[][] cells = getVisibleCells();
1842:                for (int i = 0; i < cells[CELL_ITEMID].length; i++)
1843:                    visible.add(cells[CELL_ITEMID][i]);
1844:
1845:                return visible;
1846:            }
1847:
1848:            /**
1849:             * Container datasource item set change. Table must flush its buffers on
1850:             * change.
1851:             * 
1852:             * @see org.millstone.base.data.Container.ItemSetChangeListener#containerItemSetChange(org.millstone.base.data.Container.ItemSetChangeEvent)
1853:             */
1854:            public void containerItemSetChange(
1855:                    Container.ItemSetChangeEvent event) {
1856:                pageBuffer = null;
1857:                super .containerItemSetChange(event);
1858:                setCurrentPageFirstItemIndex(this 
1859:                        .getCurrentPageFirstItemIndex());
1860:            }
1861:
1862:            /**
1863:             * Container datasource property set change. Table must flush its buffers on
1864:             * change.
1865:             * 
1866:             * @see org.millstone.base.data.Container.PropertySetChangeListener#containerPropertySetChange(org.millstone.base.data.Container.PropertySetChangeEvent)
1867:             */
1868:            public void containerPropertySetChange(
1869:                    Container.PropertySetChangeEvent event) {
1870:                pageBuffer = null;
1871:                super .containerPropertySetChange(event);
1872:            }
1873:
1874:            /**
1875:             * Adding new items is not supported.
1876:             * 
1877:             * @see org.millstone.base.ui.Select#setNewItemsAllowed(boolean)
1878:             * @throws UnsupportedOperationException
1879:             *             if set to true.
1880:             */
1881:            public void setNewItemsAllowed(boolean allowNewOptions)
1882:                    throws UnsupportedOperationException {
1883:                if (allowNewOptions)
1884:                    throw new UnsupportedOperationException();
1885:            }
1886:
1887:            /**
1888:             * Focusing to this component is not supported.
1889:             * 
1890:             * @see org.millstone.base.ui.AbstractField#focus()
1891:             * @throws UnsupportedOperationException
1892:             *             if invoked.
1893:             */
1894:            public void focus() throws UnsupportedOperationException {
1895:                throw new UnsupportedOperationException();
1896:            }
1897:
1898:            /**
1899:             * @see org.millstone.base.data.Container.Ordered#nextItemId(java.lang.Object)
1900:             */
1901:            public Object nextItemId(Object itemId) {
1902:                return ((Container.Ordered) items).nextItemId(itemId);
1903:            }
1904:
1905:            /**
1906:             * @see org.millstone.base.data.Container.Ordered#prevItemId(java.lang.Object)
1907:             */
1908:            public Object prevItemId(Object itemId) {
1909:                return ((Container.Ordered) items).prevItemId(itemId);
1910:            }
1911:
1912:            /**
1913:             * @see org.millstone.base.data.Container.Ordered#firstItemId()
1914:             */
1915:            public Object firstItemId() {
1916:                return ((Container.Ordered) items).firstItemId();
1917:            }
1918:
1919:            /**
1920:             * @see org.millstone.base.data.Container.Ordered#lastItemId()
1921:             */
1922:            public Object lastItemId() {
1923:                return ((Container.Ordered) items).lastItemId();
1924:            }
1925:
1926:            /**
1927:             * @see org.millstone.base.data.Container.Ordered#isFirstId(java.lang.Object)
1928:             */
1929:            public boolean isFirstId(Object itemId) {
1930:                return ((Container.Ordered) items).isFirstId(itemId);
1931:            }
1932:
1933:            /**
1934:             * @see org.millstone.base.data.Container.Ordered#isLastId(java.lang.Object)
1935:             */
1936:            public boolean isLastId(Object itemId) {
1937:                return ((Container.Ordered) items).isLastId(itemId);
1938:            }
1939:
1940:            /**
1941:             * @see org.millstone.base.data.Container.Ordered#addItemAfter(java.lang.Object)
1942:             */
1943:            public Object addItemAfter(Object previousItemId)
1944:                    throws UnsupportedOperationException {
1945:                return ((Container.Ordered) items).addItemAfter(previousItemId);
1946:            }
1947:
1948:            /**
1949:             * @see org.millstone.base.data.Container.Ordered#addItemAfter(java.lang.Object,
1950:             *      java.lang.Object)
1951:             */
1952:            public Item addItemAfter(Object previousItemId, Object newItemId)
1953:                    throws UnsupportedOperationException {
1954:                return ((Container.Ordered) items).addItemAfter(previousItemId,
1955:                        newItemId);
1956:            }
1957:
1958:            /**
1959:             * Get the FieldFactory that is used to create editor for table cells.
1960:             * 
1961:             * The FieldFactory is only used if the Table is editable.
1962:             * 
1963:             * @see #isEditable
1964:             * @return FieldFactory used to create the Field instances.
1965:             */
1966:            public FieldFactory getFieldFactory() {
1967:                return fieldFactory;
1968:            }
1969:
1970:            /**
1971:             * Set the FieldFactory that is used to create editor for table cells.
1972:             * 
1973:             * The FieldFactory is only used if the Table is editable. By default the
1974:             * BaseFieldFactory is used.
1975:             * 
1976:             * @see #isEditable
1977:             * @see BaseFieldFactory
1978:             * @param fieldFactory
1979:             *            The field factory to set
1980:             */
1981:            public void setFieldFactory(FieldFactory fieldFactory) {
1982:                this .fieldFactory = fieldFactory;
1983:
1984:                // Assure visual refresh
1985:                refreshCurrentPage();
1986:            }
1987:
1988:            /**
1989:             * Is table editable.
1990:             * 
1991:             * If table is editable a editor of type Field is created for each table
1992:             * cell. The assigned FieldFactory is used to create the instances.
1993:             * 
1994:             * To provide custom editors for table cells create a class implementins the
1995:             * FieldFactory interface, and assign it to table, and set the editable
1996:             * property to true.
1997:             * 
1998:             * @see Field
1999:             * @see FieldFactory
2000:             * @return true if table is editable, false oterwise.
2001:             */
2002:            public boolean isEditable() {
2003:                return editable;
2004:            }
2005:
2006:            /**
2007:             * Set the editable property.
2008:             * 
2009:             * If table is editable a editor of type Field is created for each table
2010:             * cell. The assigned FieldFactory is used to create the instances.
2011:             * 
2012:             * To provide custom editors for table cells create a class implementins the
2013:             * FieldFactory interface, and assign it to table, and set the editable
2014:             * property to true.
2015:             * 
2016:             * @see Field
2017:             * @see FieldFactory
2018:             * @param editable
2019:             *            true if table should be editable by user.
2020:             */
2021:            public void setEditable(boolean editable) {
2022:                this .editable = editable;
2023:
2024:                // Assure visual refresh
2025:                refreshCurrentPage();
2026:            }
2027:
2028:            /**
2029:             * Sort table.
2030:             * 
2031:             * @see org.millstone.base.data.Container.Sortable#sort(java.lang.Object[],
2032:             *      boolean[])
2033:             * 
2034:             * @throws UnsupportedOperationException
2035:             *             if the container data source does not implement
2036:             *             Container.Sortable
2037:             */
2038:            public void sort(Object[] propertyId, boolean[] ascending)
2039:                    throws UnsupportedOperationException {
2040:                Container c = getContainerDataSource();
2041:                if (c instanceof  Container.Sortable) {
2042:                    int pageIndex = this .getCurrentPageFirstItemIndex();
2043:                    ((Container.Sortable) c).sort(propertyId, ascending);
2044:                    setCurrentPageFirstItemIndex(pageIndex);
2045:                } else if (c != null) {
2046:                    throw new UnsupportedOperationException(
2047:                            "Underlying Data does not allow sorting");
2048:                }
2049:            }
2050:
2051:            /**
2052:             * Sort table by currently selected sorting column.
2053:             * 
2054:             * @throws UnsupportedOperationException
2055:             *             if the container data source does not implement
2056:             *             Container.Sortable
2057:             */
2058:            public void sort() {
2059:                if (getSortContainerPropertyId() == null)
2060:                    return;
2061:                sort(new Object[] { this .sortContainerPropertyId },
2062:                        new boolean[] { this .sortAscending });
2063:            }
2064:
2065:            /*
2066:             * (non-Javadoc)
2067:             * 
2068:             * @see org.millstone.base.data.Container.Sortable#getSortableContainerPropertyIds()
2069:             */
2070:            public Collection getSortableContainerPropertyIds() {
2071:                Container c = getContainerDataSource();
2072:                if (c instanceof  Container.Sortable && !isSortDisabled()) {
2073:                    return ((Container.Sortable) c)
2074:                            .getSortableContainerPropertyIds();
2075:                } else {
2076:                    return new LinkedList();
2077:                }
2078:            }
2079:
2080:            /**
2081:             * Get the currently sorted column property ID.
2082:             * 
2083:             * @return Container property id of the currently sorted column.
2084:             */
2085:            public Object getSortContainerPropertyId() {
2086:                return this .sortContainerPropertyId;
2087:            }
2088:
2089:            /**
2090:             * Set the currently sorted column property id.
2091:             * 
2092:             * @param propertyId
2093:             *            Container property id of the currently sorted column.
2094:             */
2095:            public void setSortContainerPropertyId(Object propertyId) {
2096:                if ((this .sortContainerPropertyId != null && !this .sortContainerPropertyId
2097:                        .equals(propertyId))
2098:                        || (this .sortContainerPropertyId == null && propertyId != null)) {
2099:                    this .sortContainerPropertyId = propertyId;
2100:                    sort();
2101:                }
2102:
2103:                // Assure visual refresh
2104:                refreshCurrentPage();
2105:            }
2106:
2107:            /**
2108:             * Is the table currently sorted in ascending order.
2109:             * 
2110:             * @return <code>true</code> if ascending, <code>false</code> if
2111:             *         descending
2112:             */
2113:            public boolean isSortAscending() {
2114:                return this .sortAscending;
2115:            }
2116:
2117:            /**
2118:             * Set the table in ascending order.
2119:             * 
2120:             * @param ascending
2121:             *            <code>true</code> if ascending, <code>false</code> if
2122:             *            descending
2123:             */
2124:            public void setSortAscending(boolean ascending) {
2125:                if (this .sortAscending != ascending) {
2126:                    this .sortAscending = ascending;
2127:                    sort();
2128:                }
2129:
2130:                // Assure visual refresh
2131:                refreshCurrentPage();
2132:            }
2133:
2134:            /** Is sorting disabled alltogether.
2135:             * 
2136:             * True iff no sortable columns are given even in the case where datasource would support this.
2137:             * 
2138:             * @return True iff sorting is disabled.
2139:             */
2140:            public boolean isSortDisabled() {
2141:                return sortDisabled;
2142:            }
2143:
2144:            /** Disable sorting alltogether.
2145:             * 
2146:             * To disable sorting alltogether, set to true. In this case no 
2147:             * sortable columns are given even in the case where datasource would support this.
2148:             * 
2149:             * @param sortDisabled True iff sorting is disabled
2150:             */
2151:            public void setSortDisabled(boolean sortDisabled) {
2152:                if (this.sortDisabled != sortDisabled) {
2153:                    this.sortDisabled = sortDisabled;
2154:                    refreshCurrentPage();
2155:                }
2156:            }
2157:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.