Source Code Cross Referenced for ColumnLayout.java in  » Portal » jetspeed-2.1.3 » org » apache » jetspeed » portlets » layout » 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 » Portal » jetspeed 2.1.3 » org.apache.jetspeed.portlets.layout 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Licensed to the Apache Software Foundation (ASF) under one or more
003:         * contributor license agreements.  See the NOTICE file distributed with
004:         * this work for additional information regarding copyright ownership.
005:         * The ASF licenses this file to You under the Apache License, Version 2.0
006:         * (the "License"); you may not use this file except in compliance with
007:         * the License.  You may obtain a copy of the License at
008:         * 
009:         *      http://www.apache.org/licenses/LICENSE-2.0
010:         * 
011:         * Unless required by applicable law or agreed to in writing, software
012:         * distributed under the License is distributed on an "AS IS" BASIS,
013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014:         * See the License for the specific language governing permissions and
015:         * limitations under the License.
016:         */
017:        package org.apache.jetspeed.portlets.layout;
018:
019:        import java.io.Serializable;
020:        import java.text.DecimalFormat;
021:        import java.text.DecimalFormatSymbols;
022:        import java.util.ArrayList;
023:        import java.util.Collection;
024:        import java.util.Collections;
025:        import java.util.HashMap;
026:        import java.util.Iterator;
027:        import java.util.List;
028:        import java.util.Locale;
029:        import java.util.Map;
030:        import java.util.SortedMap;
031:        import java.util.TreeMap;
032:
033:        import org.apache.jetspeed.om.page.Fragment;
034:
035:        /**
036:         * <h2>Basics</h2>
037:         * <p>
038:         * <code>ColumnLayout</code> is the model used to support any 1 to <i>n</i>
039:         * column-based layout. <code>ColumnLayout</code> is constrained by a number
040:         * columns that will not be exceeded, even if a fragment specifies a column
041:         * outside of this constraint. Any fragment exceeded the specified column
042:         * constraint will be deposited into the right-most column.
043:         * </p>
044:         * 
045:         * <h2>Characteristics:</h2>
046:         * <ul>
047:         *   <li>Columns and rows always start at 0.</li>
048:         *   <li>Unless otherwise noted, assume all Collections returned are immutable.</li>
049:         *   <li>Unless otherwise noted, assume that no public method will ever return <code>null</code>.</li>
050:         * </ul>
051:         *  
052:         * 
053:         * <h2>Layout Events</h2>
054:         * <p>
055:         * When any move*() method is invoked and a portlet is actually moved (see indvidual
056:         * methods for what causes these circumstances), an initial LayoutEvent is dispatched.  
057:         * This may cause a cascade of LayoutEvents to be fired in turn if the movement of the
058:         * target fragment cause other fragments to be repositioned.  In this case a LayoutEvent
059:         * is dispatched for each portlet moved, which in turn may our may not cause another
060:         * LayoutEvent to be fired. 
061:         * </p>
062:         * @see org.apache.jetspeed.portlets.layout.LayoutEvent
063:         * @see org.apache.jetspeed.portlets.layout.LayoutEventListener
064:         * @see org.apache.jetspeed.portlets.layout.LayoutCoordinate
065:         * @see org.apache.jetspeed.om.page.Fragment
066:         * 
067:         * @author <href a="mailto:weaver@apache.org">Scott T. Weaver</a>
068:         * 
069:         */
070:        public class ColumnLayout implements  Serializable {
071:            /** Percentage widths gutter width */
072:            private final static double PERCENTAGE_WIDTH_GUTTER = 0.01;
073:
074:            /** Percentage widths format */
075:            private final static DecimalFormat PERCENTAGE_WIDTH_FORMAT = new DecimalFormat(
076:                    "0.00'%'", new DecimalFormatSymbols(Locale.ENGLISH));
077:
078:            /** Constrains the columns for this layout */
079:            private final int numberOfColumns;
080:
081:            /** SortedMap of Columns (which are also sorted maps */
082:            private final SortedMap columns;
083:
084:            /** Width settings for eacah column */
085:            private final String[] columnWidths;
086:
087:            /** Efficent way to always be aware of the next available row in a column */
088:            private final int[] nextRowNumber;
089:
090:            /** maps Fragments (key) to it's current LayoutCoordinate (value) in this layout */
091:            private final Map coordinates;
092:
093:            /** All of the LayoutEventListeners registered to this layout */
094:            private final List eventListeners;
095:
096:            /**
097:             * 
098:             * @param numberOfColumns
099:             *            the maximum number of columns this layout will have.
100:             * @param layoutType
101:             *            this value corresponds to the property settings of the
102:             *            fragments within your psml. Layout type allows segration of
103:             *            property settings based on the type of layout in use. This
104:             *            effectively allows for the interchange of multiple layout
105:             *            formats without one format effecting the settings of another.
106:             * @param columnWidths
107:             *            widths for each column that accumulate to 100% if percentages
108:             *            are used.
109:             * @see org.apache.jetspeed.om.page.Fragment#getType()
110:             */
111:            public ColumnLayout(int numberOfColumns, String layoutType,
112:                    String[] columnWidths) {
113:                this .numberOfColumns = numberOfColumns;
114:                this .columnWidths = columnWidths;
115:                eventListeners = new ArrayList();
116:
117:                columns = new TreeMap();
118:                coordinates = new HashMap();
119:
120:                for (int i = 0; i < numberOfColumns; i++) {
121:                    columns.put(new Integer(i), new TreeMap());
122:                }
123:
124:                nextRowNumber = new int[numberOfColumns];
125:
126:                for (int i = 0; i < numberOfColumns; i++) {
127:                    nextRowNumber[i] = 0;
128:                }
129:            }
130:
131:            /**
132:             * Same as ColumnLayout(int numberOfColumns, String layoutType) but also
133:             * supplies a Collection of fragmetns to initially populate the layout
134:             * with.  Adding these fragments <strong>WILL NOT</strong> cause
135:             * a LayoutEvent to be dispatched.
136:             * 
137:             * @see ColumnLayout(int numberOfColumns, String layoutType)
138:             * @param numberOfColumns
139:             *            the maximum number of columns this layout will have.
140:             * @param layoutType
141:             *            this value corresponds to the property settings of the
142:             *            fragments within your psml. Layout type allows segration of
143:             *            property settings based on the type of layout in use. This
144:             *            effectively allows for the interchange of multiple layout
145:             *            formats without one format effecting the settings of another.
146:             * @param fragments Initial set of fragments to add to this layout.
147:             * @param columnWidths
148:             *            widths for each column that accumulate to 100% if percentages
149:             *            are used.
150:             * @throws LayoutEventException
151:             */
152:            public ColumnLayout(int numberOfColumns, String layoutType,
153:                    Collection fragments, String[] columnWidths)
154:                    throws LayoutEventException {
155:                this (numberOfColumns, layoutType, columnWidths);
156:                Iterator fragmentsItr = fragments.iterator();
157:                try {
158:                    while (fragmentsItr.hasNext()) {
159:                        Fragment fragment = (Fragment) fragmentsItr.next();
160:                        doAdd(getColumn(fragment), getRow(getColumn(fragment),
161:                                fragment), fragment);
162:                    }
163:                } catch (InvalidLayoutLocationException e) {
164:                    // This should NEVER happen as getColumn() should
165:                    // automatically constrain any fragments who's column
166:                    // setting would cause this exception.
167:                    throw new LayoutError(
168:                            "A malformed fragment could not be adjusted.", e);
169:                }
170:            }
171:
172:            /**
173:             * <p>
174:             * Adds a fragment to the layout using fragment properties of
175:             * <code> row  </code> and <code> column  </code> as hints on where to put
176:             * this fragment. The following rules apply to malformed fragment
177:             * definitions:
178:             * </p>
179:             * <ul>
180:             * <li>Fragments without a row defined are placed at the bottom of their
181:             * respective column </li>
182:             * <li>Fragments without a column are placed in the right-most column.
183:             * </li>
184:             * <li> Fragments with overlapping row numbers. The last fragment has
185:             * priority pushing the fragment in that row down one row. </li>
186:             * </ul>
187:             * 
188:             * @param fragment
189:             *            Fragment to add to this layout.
190:             * @throws LayoutEventException 
191:             * @see org.apache.jetspeed.om.page.Fragment
192:             * 
193:             */
194:            public void addFragment(Fragment fragment)
195:                    throws LayoutEventException {
196:                try {
197:                    doAdd(getColumn(fragment), getRow(getColumn(fragment),
198:                            fragment), fragment);
199:                    LayoutCoordinate coordinate = getCoordinate(fragment);
200:                    processEvent(new LayoutEvent(LayoutEvent.ADDED, fragment,
201:                            coordinate, coordinate));
202:                } catch (InvalidLayoutLocationException e) {
203:                    // This should NEVER happen as getColumn() should
204:                    // automatically constrain any fragments who's column
205:                    // setting would cause this exception.
206:                    throw new LayoutError(
207:                            "A malformed fragment could not be adjusted.", e);
208:                } catch (FragmentNotInLayoutException e) {
209:                    throw new LayoutError(
210:                            "Failed to add coordinate to this ColumnLayout.", e);
211:                }
212:            }
213:
214:            /**
215:             * Adds a LayoutEventListener to this layout that will be fired any time
216:             * a LayoutEvent is disaptched.
217:             * 
218:             * @param eventListener
219:             * @see LayoutEventListener
220:             * @see LayoutEventListener
221:             */
222:            public void addLayoutEventListener(LayoutEventListener eventListener) {
223:                eventListeners.add(eventListener);
224:            }
225:
226:            /**
227:             * 
228:             * @param columnNumber
229:             *            Number of column to retreive
230:             * @return requested column (as a immutable Collection). Never returns
231:             *         <code>null.</code>
232:             * @throws InvalidLayoutLocationException
233:             *             if the column is outisde of the constraints of this layout
234:             */
235:            public Collection getColumn(int columnNumber)
236:                    throws InvalidLayoutLocationException {
237:                return Collections.unmodifiableCollection(getColumnMap(
238:                        columnNumber).values());
239:            }
240:
241:            /**
242:             * returns the width to be used with the specified column.  If
243:             * there is no specific column setting sfor the specified column
244:             * 0 is returned.
245:             * 
246:             * @param columnNumber whose width has been requested.
247:             * @return the width to be used with the specified column.  Or 0 if no value
248:             * has been specified.
249:             */
250:            public String getColumnWidth(int columnNumber) {
251:                if ((columnWidths != null) && (columnNumber < numberOfColumns)) {
252:                    String columnWidth = columnWidths[columnNumber];
253:
254:                    // subtract "gutter" width from last percentage
255:                    // column to prevent wrapping on rounding errors
256:                    // of column widths when rendered in the browser
257:                    if ((numberOfColumns > 1)
258:                            && (columnNumber == (numberOfColumns - 1))) {
259:                        int percentIndex = columnWidth.lastIndexOf('%');
260:                        if (percentIndex > 0) {
261:                            try {
262:                                double width = Double.parseDouble(columnWidth
263:                                        .substring(0, percentIndex).trim());
264:                                synchronized (PERCENTAGE_WIDTH_FORMAT) {
265:                                    columnWidth = PERCENTAGE_WIDTH_FORMAT
266:                                            .format(width
267:                                                    - PERCENTAGE_WIDTH_GUTTER);
268:                                }
269:                            } catch (NumberFormatException nfe) {
270:                            }
271:                        }
272:                    }
273:                    return columnWidth;
274:                }
275:                return "0";
276:            }
277:
278:            /**
279:             * returns the float to be used with the specified column.
280:             * 
281:             * @param columnNumber whose width has been requested.
282:             * @return "right" for the last column, "left" if more than one
283:             *         column, or "none" otherwise.
284:             */
285:            public String getColumnFloat(int columnNumber) {
286:                if ((numberOfColumns > 1) && (columnNumber < numberOfColumns)) {
287:                    if (columnNumber == (numberOfColumns - 1)) {
288:                        return "right";
289:                    } else {
290:                        return "left";
291:                    }
292:                }
293:                return "none";
294:            }
295:
296:            /**
297:             * @return <code>java.util.Collection</code> all of columns (also
298:             *         Collection objects) in order within this layout. All Collections
299:             *         are immutable.
300:             */
301:            public Collection getColumns() {
302:                ArrayList columnList = new ArrayList(getNumberOfColumns());
303:                Iterator itr = columns.values().iterator();
304:                while (itr.hasNext()) {
305:                    columnList
306:                            .add(Collections.unmodifiableCollection(((Map) itr
307:                                    .next()).values()));
308:                }
309:
310:                return Collections.unmodifiableCollection(columnList);
311:            }
312:
313:            /**
314:             * 
315:             * Returns the index of the last row in the specified column.
316:             * 
317:             * @param columnNumber column form whom we ant to identify the
318:             * last row.
319:             * @return the index of the last row in the specified column.
320:             */
321:            public int getLastRowNumber(int columnNumber) {
322:                return nextRowNumber[columnNumber] - 1;
323:            }
324:
325:            /**
326:             * Returns an immutable Collection of all the Fragments contained within
327:             * this ColumnLayout in no sepcific order.
328:             * @return Immutable Collection of Fragments.
329:             */
330:            public Collection getFragments() {
331:                return Collections.unmodifiableCollection(coordinates.keySet());
332:            }
333:
334:            /**
335:             * Retrieves the fragment at the specified loaction.
336:             * 
337:             * @param columnNumber Column coordinate (first column starts at 0)
338:             * @param rowNumber Row coordinate (first row starts at 0)
339:             * @return Fragment at the specified coordinate.  Never returns <code>null</code>.
340:             * @throws EmptyLayoutLocationException if there is no fragment currently located at the specified coordinate.
341:             * @throws InvalidLayoutLocationException if the coordinate lies outside the confines of this layout, i.e., the
342:             * <code>columnNumber</code> exceeds the max columns setting for this layout.
343:             */
344:            public Fragment getFragmentAt(int columnNumber, int rowNumber)
345:                    throws EmptyLayoutLocationException,
346:                    InvalidLayoutLocationException {
347:                SortedMap column = getColumnMap(columnNumber);
348:                Integer rowInteger = new Integer(rowNumber);
349:                if (column.containsKey(rowInteger)) {
350:                    return (Fragment) column.get(rowInteger);
351:                } else {
352:                    throw new EmptyLayoutLocationException(columnNumber,
353:                            rowNumber);
354:                }
355:            }
356:
357:            /**
358:             * 
359:             * Retrieves the fragment at the specified loaction.
360:             * 
361:             * @param coodinate LayoutCoordinate object that will be used to located a fragment in this
362:             * layout.
363:             * @see LayoutCoordinate
364:             * @return Fragment at the specified coordinate.  Never returns <code>null</code>.
365:             * @throws EmptyLayoutLocationException if there is no fragment currently located at the specified coordinate.
366:             * @throws InvalidLayoutLocationException if the coordinate lies outside the confines of this layout, i.e., the
367:             * <code>columnNumber</code> exceeds the max columns setting for this layout.
368:             * @see LayoutCoordinate
369:             */
370:            public Fragment getFragmentAt(LayoutCoordinate coodinate)
371:                    throws EmptyLayoutLocationException,
372:                    InvalidLayoutLocationException {
373:                return getFragmentAt(coodinate.getX(), coodinate.getY());
374:            }
375:
376:            /**
377:             * 
378:             * @return The total number of columns in this layout.
379:             */
380:            public int getNumberOfColumns() {
381:                return numberOfColumns;
382:            }
383:
384:            /**
385:             * 
386:             * @return The last column in this layout.  The Collection is immutable.
387:             */
388:            public Collection getLastColumn() {
389:                try {
390:                    return Collections.unmodifiableCollection(getColumnMap(
391:                            numberOfColumns - 1).values());
392:                } catch (InvalidLayoutLocationException e) {
393:                    // This should NEVER happen as getLastColumn() is
394:                    // always correctly constrained and should always exists.
395:                    throw new LayoutError(
396:                            "It appears this layout is corrupt and cannot correctly identify its last column.",
397:                            e);
398:                }
399:            }
400:
401:            /**
402:             * 
403:             * @return The last column in this layout.  The Collection is immutable.
404:             */
405:            public Collection getFirstColumn() {
406:                try {
407:                    return Collections.unmodifiableCollection(getColumnMap(0)
408:                            .values());
409:                } catch (InvalidLayoutLocationException e) {
410:                    // This should NEVER happen as getLastColumn() is
411:                    // always correctly constrained and should always exists.
412:                    throw new LayoutError(
413:                            "It appears this layout is corrupt and cannot correctly identify its first column.",
414:                            e);
415:                }
416:            }
417:
418:            /**
419:             * 
420:             * Moves a fragment one column to the right.  A LayoutEvent is triggered by
421:             * this action.
422:             * 
423:             * <p>
424:             * If the fragment currently
425:             * resides in right-most column, no action is taking and no event LayoutEvent
426:             * is fired.
427:             * </p>
428:             * 
429:             * @param fragment fragment to move.
430:             * @throws FragmentNotInLayoutException if the specified fragment is not currently in the layout.
431:             * @throws LayoutEventException If a triggered LayoutEvent fails.
432:             */
433:            public void moveRight(Fragment fragment)
434:                    throws FragmentNotInLayoutException, LayoutEventException {
435:                LayoutCoordinate coordinate = getCoordinate(fragment);
436:                LayoutCoordinate newCoordinate = new LayoutCoordinate(
437:                        coordinate.getX() + 1, coordinate.getY());
438:
439:                if (newCoordinate.getX() < numberOfColumns) {
440:
441:                    try {
442:                        doMove(fragment, coordinate, newCoordinate);
443:                        processEvent(new LayoutEvent(LayoutEvent.MOVED_RIGHT,
444:                                fragment, coordinate, newCoordinate));
445:                        // now move the fragment below up one level.
446:                        try {
447:                            Fragment fragmentBelow = getFragmentAt(new LayoutCoordinate(
448:                                    coordinate.getX(), coordinate.getY() + 1));
449:                            moveUp(fragmentBelow);
450:                        } catch (EmptyLayoutLocationException e) {
451:                            // indicates no fragment below
452:                        }
453:                    } catch (InvalidLayoutLocationException e) {
454:                        // This should NEVER happen as the location has already been verfied to be valid
455:                        throw new LayoutError(
456:                                "It appears this layout is corrupt and cannot correctly identify valid column locations.",
457:                                e);
458:                    }
459:                }
460:            }
461:
462:            /**
463:             * Moves a fragment one column to the left.  A LayoutEvent is triggered by
464:             * this action.
465:             * 
466:             * <p>
467:             * If the fragment currently
468:             * resides in left-most column, no action is taking and no event LayoutEvent
469:             * is fired.
470:             * </p>
471:             * 
472:             * @param fragment
473:             * @throws FragmentNotInLayoutException if the specified fragment is not currently in the layout.
474:             * @throws LayoutEventException If a triggered LayoutEvent fails.
475:             */
476:            public void moveLeft(Fragment fragment)
477:                    throws FragmentNotInLayoutException, LayoutEventException {
478:                LayoutCoordinate coordinate = getCoordinate(fragment);
479:                LayoutCoordinate newCoordinate = new LayoutCoordinate(
480:                        coordinate.getX() - 1, coordinate.getY());
481:
482:                if (newCoordinate.getX() >= 0) {
483:                    try {
484:                        doMove(fragment, coordinate, newCoordinate);
485:                        processEvent(new LayoutEvent(LayoutEvent.MOVED_LEFT,
486:                                fragment, coordinate, newCoordinate));
487:                        // now move the fragment below up one level.
488:                        try {
489:                            Fragment fragmentBelow = getFragmentAt(new LayoutCoordinate(
490:                                    coordinate.getX(), coordinate.getY() + 1));
491:                            moveUp(fragmentBelow);
492:                        } catch (EmptyLayoutLocationException e) {
493:                            // indicates no fragment below
494:                        }
495:                    } catch (InvalidLayoutLocationException e) {
496:                        // This should NEVER happen as the location has already been verfied to be valid
497:                        throw new LayoutError(
498:                                "It appears this layout is corrupt and cannot correctly identify valid column locations.",
499:                                e);
500:                    }
501:
502:                }
503:
504:            }
505:
506:            /**
507:             * Moves a fragment one row to the up.  A LayoutEvent is triggered by
508:             * this action.
509:             * 
510:             * <p>
511:             * If the fragment currently
512:             * resides in top-most row, no action is taking and no event LayoutEvent
513:             * is fired.
514:             * </p>
515:             * @param fragment
516:             * @throws FragmentNotInLayoutException if the specified fragment is not currently in the layout.
517:             * @throws LayoutEventException If a triggered LayoutEvent fails.
518:             */
519:            public void moveUp(Fragment fragment)
520:                    throws FragmentNotInLayoutException, LayoutEventException {
521:                LayoutCoordinate coordinate = getCoordinate(fragment);
522:                LayoutCoordinate aboveLayoutCoordinate = new LayoutCoordinate(
523:                        coordinate.getX(), coordinate.getY() - 1);
524:                LayoutCoordinate newCoordinate = aboveLayoutCoordinate;
525:
526:                // never go "above" 0.
527:                if (newCoordinate.getY() >= 0) {
528:                    try {
529:                        try {
530:                            // now move the fragment above down one level.
531:                            /*Fragment fragmentAbove =*/getFragmentAt(aboveLayoutCoordinate);
532:                            doMove(fragment, coordinate, newCoordinate);
533:                            processEvent(new LayoutEvent(LayoutEvent.MOVED_UP,
534:                                    fragment, coordinate, newCoordinate));
535:                        } catch (EmptyLayoutLocationException e) {
536:                            // Nothing above??? Then scoot all elements below up one level.
537:                            doMove(fragment, coordinate, newCoordinate);
538:                            processEvent(new LayoutEvent(LayoutEvent.MOVED_UP,
539:                                    fragment, coordinate, newCoordinate));
540:
541:                            // If this the last row, make sure to update the next row pointer accordingly.
542:                            if (coordinate.getY() == (nextRowNumber[coordinate
543:                                    .getX()] - 1)) {
544:                                nextRowNumber[coordinate.getX()] = coordinate
545:                                        .getX();
546:                            }
547:
548:                            try {
549:                                Fragment fragmentBelow = getFragmentAt(new LayoutCoordinate(
550:                                        coordinate.getX(),
551:                                        coordinate.getY() + 1));
552:                                moveUp(fragmentBelow);
553:                            } catch (EmptyLayoutLocationException e1) {
554:
555:                            }
556:                        }
557:                    } catch (InvalidLayoutLocationException e) {
558:                        // This should NEVER happen as the location has already been verfied to be valid
559:                        throw new LayoutError(
560:                                "It appears this layout is corrupt and cannot correctly identify valid column locations.",
561:                                e);
562:                    }
563:                }
564:            }
565:
566:            /**
567:             * 
568:             * @param fragment
569:             * @throws FragmentNotInLayoutException if the specified fragment is not currently in the layout.
570:             * @throws LayoutEventException If a triggered LayoutEvent fails.
571:             */
572:            public void moveDown(Fragment fragment)
573:                    throws FragmentNotInLayoutException, LayoutEventException {
574:                LayoutCoordinate coordinate = getCoordinate(fragment);
575:                LayoutCoordinate newCoordinate = new LayoutCoordinate(
576:                        coordinate.getX(), coordinate.getY() + 1);
577:
578:                // never move past the current bottom row
579:                if (newCoordinate.getY() < nextRowNumber[coordinate.getX()]) {
580:                    try {
581:                        try {
582:                            // the best approach to move a fragment down is to actually move
583:                            // its neighbor underneath up
584:                            LayoutCoordinate aboveCoord = new LayoutCoordinate(
585:                                    coordinate.getX(), coordinate.getY() + 1);
586:                            Fragment fragmentBelow = getFragmentAt(aboveCoord);
587:                            doMove(fragmentBelow, aboveCoord, coordinate);
588:                            processEvent(new LayoutEvent(LayoutEvent.MOVED_UP,
589:                                    fragmentBelow, aboveCoord, coordinate));
590:                            // Since this logic path is a somewhat special case, the processing of the  MOVED_DOWN
591:                            // event happens within the doAdd() method.
592:                        } catch (EmptyLayoutLocationException e) {
593:                            doMove(fragment, coordinate, newCoordinate);
594:                            processEvent(new LayoutEvent(
595:                                    LayoutEvent.MOVED_DOWN, fragment,
596:                                    coordinate, newCoordinate));
597:                        }
598:                    } catch (InvalidLayoutLocationException e) {
599:                        // This should NEVER happen as the location has already been verfied to be valid
600:                        throw new LayoutError(
601:                                "It appears this layout is corrupt and cannot correctly identify valid column locations.",
602:                                e);
603:                    }
604:
605:                }
606:            }
607:
608:            /**
609:             * Performs the actual movement of a fragment.
610:             * 
611:             * 
612:             * @param fragment
613:             * @param oldCoordinate
614:             * @param newCoordinate
615:             * @throws InvalidLayoutLocationException
616:             * @throws LayoutEventException 
617:             */
618:            protected void doMove(Fragment fragment,
619:                    LayoutCoordinate oldCoordinate,
620:                    LayoutCoordinate newCoordinate)
621:                    throws InvalidLayoutLocationException, LayoutEventException {
622:                SortedMap oldColumn = getColumnMap(oldCoordinate.getX());
623:                oldColumn.remove(new Integer(oldCoordinate.getY()));
624:                coordinates.remove(fragment);
625:
626:                doAdd(newCoordinate.getX(), newCoordinate.getY(), fragment);
627:            }
628:
629:            /**
630:             *
631:             * 
632:             * @param fragment fragment whose LayoutCoordinate we ant.
633:             * @return LayoutCoordinate representing the current location of this
634:             * Fragment within this layout.
635:             * @throws FragmentNotInLayoutException if the Fragment is not present in this layout.
636:             * @see LayoutCoordinate
637:             */
638:            public LayoutCoordinate getCoordinate(Fragment fragment)
639:                    throws FragmentNotInLayoutException {
640:                if (coordinates.containsKey(fragment)) {
641:                    return (LayoutCoordinate) coordinates.get(fragment);
642:                } else {
643:                    throw new FragmentNotInLayoutException(fragment);
644:                }
645:            }
646:
647:            /**
648:             * Adds a fragment at the indicated <code>columnNumber</code>
649:             * and <code>rowNumber</code>.
650:             * 
651:             * @param columnNumber
652:             * @param rowNumber
653:             * @param fragment
654:             * @throws InvalidLayoutLocationException if the coordinates are outside the bounds of this layout.
655:             * @throws LayoutEventException id a LayoutEvent fails
656:             */
657:            protected void doAdd(int columnNumber, int rowNumber,
658:                    Fragment fragment) throws InvalidLayoutLocationException,
659:                    LayoutEventException {
660:                SortedMap column = getColumnMap(columnNumber);
661:
662:                Integer rowInteger = new Integer(rowNumber);
663:                LayoutCoordinate targetCoordinate = new LayoutCoordinate(
664:                        columnNumber, rowNumber);
665:                if (column.containsKey(rowInteger)) {
666:                    // If the row has something in it, push everythin down 1
667:                    Fragment existingFragment = (Fragment) column
668:                            .get(rowInteger);
669:                    column.put(rowInteger, fragment);
670:                    coordinates.put(fragment, targetCoordinate);
671:                    doAdd(columnNumber, ++rowNumber, existingFragment);
672:
673:                    LayoutCoordinate oneDownCoordinate = new LayoutCoordinate(
674:                            targetCoordinate.getX(),
675:                            targetCoordinate.getY() + 1);
676:                    processEvent(new LayoutEvent(LayoutEvent.MOVED_DOWN,
677:                            existingFragment, targetCoordinate,
678:                            oneDownCoordinate));
679:                } else {
680:                    column.put(rowInteger, fragment);
681:                    coordinates.put(fragment, targetCoordinate);
682:                    rowNumber++;
683:                    if (rowNumber > nextRowNumber[columnNumber]) {
684:                        nextRowNumber[columnNumber] = rowNumber;
685:                    }
686:                }
687:
688:            }
689:
690:            /**
691:             * Retrieves this specified <code>columnNumber</code> as a
692:             * SortedMap.
693:             * 
694:             * @param columnNumber
695:             * @return
696:             * @throws InvalidLayoutLocationException if the <code>columnNumber</code> resides
697:             * outside the bounds of this layout.
698:             */
699:            protected final SortedMap getColumnMap(int columnNumber)
700:                    throws InvalidLayoutLocationException {
701:                Integer columnNumberIneteger = new Integer(columnNumber);
702:
703:                if (columns.containsKey(columnNumberIneteger)) {
704:                    return ((SortedMap) columns.get(columnNumberIneteger));
705:                } else {
706:                    throw new InvalidLayoutLocationException(columnNumber);
707:                }
708:
709:            }
710:
711:            /**
712:             * Gets the row number of this fragment to looking the <code>layoutType</code>
713:             * property <i>row</i>.  If this property is undefined, the bottom-most row
714:             * number of <code>currentColumn</code> is returned.
715:             * 
716:             * @param currentColumn
717:             * @param fragment
718:             * @return valid row for this fragment within this layout.
719:             */
720:            protected final int getRow(int currentColumn, Fragment fragment) {
721:                String propertyValue = fragment
722:                        .getProperty(Fragment.ROW_PROPERTY_NAME);
723:                if (propertyValue != null) {
724:                    return Integer.parseInt(propertyValue);
725:                } else {
726:                    return nextRowNumber[currentColumn];
727:                }
728:
729:            }
730:
731:            /**
732:             * Gets the row number of this fragment to looking the <code>layoutType</code>
733:             * property <i>column</i>. 
734:             * 
735:             * If the <i>column</i> is undefined or exceeds the constriants of this
736:             * layout, the value returned is <code>numberOfColumns - 1</code>.  If the
737:             * value is less than 0, 0 is returned.
738:             * 
739:             * 
740:             * @param fragment
741:             * @return
742:             */
743:            protected final int getColumn(Fragment fragment) {
744:                String propertyValue = fragment
745:                        .getProperty(Fragment.COLUMN_PROPERTY_NAME);
746:                if (propertyValue != null) {
747:                    int columnNumber = Integer.parseInt(propertyValue);
748:
749:                    // Exceeded columns get put into the last column
750:                    if (columnNumber >= numberOfColumns) {
751:                        columnNumber = (numberOfColumns - 1);
752:                    }
753:                    // Columns less than 1 go in the first column
754:                    else if (columnNumber < 0) {
755:                        columnNumber = 0;
756:                    }
757:
758:                    return columnNumber;
759:                } else {
760:                    return (numberOfColumns - 1);
761:                }
762:            }
763:
764:            /**
765:             * Dispatches a LayoutEvent to all LayoutEventListeners registered to this layout.
766:             * 
767:             * @param event
768:             * @throws LayoutEventException if an error occurs while processing a the LayoutEvent.
769:             */
770:            protected final void processEvent(LayoutEvent event)
771:                    throws LayoutEventException {
772:                Iterator itr = eventListeners.iterator();
773:                while (itr.hasNext()) {
774:                    LayoutEventListener eventListener = (LayoutEventListener) itr
775:                            .next();
776:                    eventListener.handleEvent(event);
777:                }
778:
779:            }
780:
781:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.