Changeset 5093

Show
Ignore:
Timestamp:
07/11/08 14:13:14 (2 months ago)
Author:
joonas.lehtinen@…
Message:

Fixes lot of alignment issues in IOrderedLayout.

- Fixes #1909 IOrderedLayout : Horzontal components with empty caption, but validation errors sometimes stack on top of each other
- Fixes #1916 IOrderedLayout misalign components with no caption, but with validation errors in horizontal mode
- Fixes #1935 OrderedLayout?-horizontal fixed height broken

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • trunk/src/com/itmill/toolkit/terminal/gwt/client/ui/IOrderedLayout.java

    r5079 r5093  
    126126     * @param newOrientationMode 
    127127     */ 
    128     private void rebuildRootDomStructure(boolean forceUpdate) { 
     128    private void rebuildRootDomStructure(int oldOrientationMode) { 
    129129 
    130130        // Should we have table as a root element? 
     
    132132 
    133133        // Already in correct mode? 
    134         if (!forceUpdate && newTableMode == tableMode) { 
     134        if (oldOrientationMode == orientationMode && newTableMode == tableMode) { 
    135135            return; 
    136136        } 
     
    141141        if (tableMode) { 
    142142            Element tmp = DOM.createDiv(); 
    143             final String structure = "<table cellspacing=\"0\" cellpadding=\"0\"><tbody><tr></tr></tbody></table>"; 
     143            final String structure = "<table cellspacing=\"0\" cellpadding=\"0\"><tbody>" 
     144                    + (orientationMode == ORIENTATION_HORIZONTAL ? "<tr></tr>" 
     145                            : "") + "</tbody></table>"; 
    144146            DOM.setInnerHTML(tmp, structure); 
    145147            root = DOM.getFirstChild(tmp); 
    146148            DOM.removeChild(tmp, root); 
    147             wrappedChildContainer = DOM.getFirstChild(DOM.getFirstChild(root)); 
     149            // set TBODY to be the wrappedChildContainer 
     150            wrappedChildContainer = DOM.getFirstChild(root); 
     151            // In case of horizontal layouts, we must user TR instead of TBODY 
     152            if (orientationMode == ORIENTATION_HORIZONTAL) { 
     153                wrappedChildContainer = DOM 
     154                        .getFirstChild(wrappedChildContainer); 
     155            } 
    148156        } else { 
    149157            wrappedChildContainer = root = DOM.createDiv(); 
     
    164172 
    165173        // Reinsert all widget wrappers to this container 
     174        final int currentOrientationMode = orientationMode; 
    166175        for (int i = 0; i < childWidgetWrappers.size(); i++) { 
    167176            WidgetWrapper wr = (WidgetWrapper) childWidgetWrappers.get(i); 
    168             Element oldWrElement = wr.getWrappingElement(); 
     177            orientationMode = oldOrientationMode; 
     178            Element oldWrElement = wr.getElementWrappingWidgetAndCaption(); 
     179            orientationMode = currentOrientationMode; 
    169180            wr.resetRootElement(); 
    170             Element newWrElement = wr.getWrappingElement(); 
     181            Element newWrElement = wr.getElementWrappingWidgetAndCaption(); 
    171182            while (DOM.getChildCount(oldWrElement) > 0) { 
    172183                Element c = DOM.getFirstChild(oldWrElement); 
     
    204215                .getStringAttribute("orientation")) ? ORIENTATION_HORIZONTAL 
    205216                : ORIENTATION_VERTICAL; 
    206         rebuildRootDomStructure(oldO != orientationMode); 
     217        rebuildRootDomStructure(oldO); 
    207218 
    208219        // Handle component spacing later in handleAlignments() method 
     
    306317 
    307318        // Update child layouts 
    308         // TODO This is most probably unnedessary and should be done within 
     319        // TODO This is most probably unnecessary and should be done within 
    309320        // update Child H/W 
    310321        if (childLayoutsHaveChanged) { 
     
    367378            int size; 
    368379            if (tableMode) { 
    369                 size = rootOffsetMeasure("offsetHeight"); 
     380 
     381                // If we know explicitly set pixel-size, use that 
     382                if (height != null && height.endsWith("px")) { 
     383                    try { 
     384                        size = Integer.parseInt(height.substring(0, height 
     385                                .length() - 2)); 
     386 
     387                        // For negative sizes, use measurements 
     388                        if (size < 0) { 
     389                            size = rootOffsetMeasure("offsetHeight"); 
     390                        } 
     391                    } catch (NumberFormatException e) { 
     392 
     393                        // In case of invalid number, try to measure the size; 
     394                        size = rootOffsetMeasure("offsetHeight"); 
     395                    } 
     396                } 
     397                // If not, try to measure the size 
     398                else { 
     399                    size = rootOffsetMeasure("offsetHeight"); 
     400                } 
     401 
    370402            } else { 
    371403                size = DOM.getElementPropertyInt(root, "offsetHeight"); 
     
    418450        DOM.setStyleAttribute(measure, "height", "100%"); 
    419451        Element parent = DOM.getParent(root); 
    420         DOM.insertBefore(parent, measure, getElement()); 
     452        DOM.insertBefore(parent, measure, root); 
    421453        DOM.removeChild(parent, root); 
    422454        int size = DOM.getElementPropertyInt(measure, offset); 
    423455        DOM.insertBefore(parent, root, measure); 
    424456        DOM.removeChild(parent, measure); 
     457        // In case the no space would be given for this element 
     458        // without pushing, use the current side of the root 
    425459        return size; 
    426460    } 
     
    432466 
    433467            // Calculate the space for fixed contents minus marginals 
    434             int size = rootOffsetMeasure("offsetWidth"); 
     468            int size; 
     469            // If we know explicitly set pixel-size, use that 
     470            if (width != null && width.endsWith("px")) { 
     471                try { 
     472                    size = Integer.parseInt(width.substring(0, 
     473                            width.length() - 2)); 
     474 
     475                    // For negative sizes, use measurements 
     476                    if (size < 0) { 
     477                        size = rootOffsetMeasure("offsetWidth"); 
     478                    } 
     479 
     480                } catch (NumberFormatException e) { 
     481 
     482                    // In case of invalid number, try to measure the size; 
     483                    size = rootOffsetMeasure("offsetWidth"); 
     484                } 
     485            } 
     486            // If not, try to measure the size 
     487            else { 
     488                size = rootOffsetMeasure("offsetWidth"); 
     489            } 
    435490 
    436491            size -= margins.hasLeft() ? marginLeft : 0; 
     
    500555 
    501556    /** 
    502      * Cell contained in the orderedlayout. This helper also manages for spacing 
    503      * and alignment for individual cells handling. 
     557     * Wrapper around single child in the layout. 
    504558     *  
     559     * This helper also manages spacing, margins and alignment for individual 
     560     * cells handling. It also can put hard size limits for its contens by 
     561     * clipping the content to given pixel size. 
     562     *  
    505563     */ 
    506564    class WidgetWrapper extends UIObject { 
    507565 
    508         Element td; 
     566        /** 
     567         * When alignment table structure is used, these elements correspond to 
     568         * the TD elements within the structure. If alignment is not used, these 
     569         * are null. 
     570         */ 
     571        Element alignmentTD, innermostTDinAlignmnetStructure; 
     572 
     573        /** 
     574         * When clipping must be done and the element wrapping clipped content 
     575         * would be TD instead of DIV, this element points to additional DIV 
     576         * that is used for clipping. 
     577         */ 
    509578        Element clipperDiv; 
     579 
     580        /** Caption element when used. */ 
    510581        Caption caption = null; 
     582 
     583        /** 
     584         * Last set pixel height for the wrapper. -1 if vertical clipping is not 
     585         * used. 
     586         */ 
    511587        int lastForcedPixelHeight = -1; 
     588 
     589        /** 
     590         * Last set pidel width for the wrapper. -1 if horizontal clipping is 
     591         * not used. 
     592         */ 
    512593        int lastForcedPixelWidth = -1; 
    513594 
     
    541622                } 
    542623            } 
    543             Element e = clipperDiv != null ? clipperDiv : getWrappingElement(); 
     624            Element e = clipperDiv != null ? clipperDiv 
     625                    : getElementWrappingAlignmentStructures(); 
    544626 
    545627            // Overflow 
     
    579661                } 
    580662            } 
    581             Element e = clipperDiv != null ? clipperDiv : getWrappingElement(); 
     663            Element e = clipperDiv != null ? clipperDiv 
     664                    : getElementWrappingAlignmentStructures(); 
    582665 
    583666            // Overflow 
     
    592675        } 
    593676 
    594         /** Create a DIV inside TD for clipping child */ 
     677        /** Create a DIV for clipping the child */ 
    595678        private void createClipperDiv() { 
    596679            clipperDiv = DOM.createDiv(); 
    597             final Element e = getWrappingElement(); 
     680            final Element e = getElementWrappingClipperDiv(); 
    598681            while (DOM.getChildCount(e) > 0) { 
    599682                final Element c = DOM.getFirstChild(e); 
     
    606689        /** Undo createClipperDiv() */ 
    607690        private void removeClipperDiv() { 
    608             final Element e = getWrappingElement(); 
     691            final Element e = getElementWrappingClipperDiv(); 
    609692            while (DOM.getChildCount(clipperDiv) > 0) { 
    610693                final Element c = DOM.getFirstChild(clipperDiv); 
     
    616699        } 
    617700 
    618         /** Get the element containing the caption and the wrapped widget. */ 
    619         private Element getWrappingElement() { 
     701        /** 
     702         * Get the element containing the caption and the wrapped widget. 
     703         * Returned element can one of the following: 
     704         * <ul> 
     705         * <li>(a) Root DIV of the WrapperElement when not in tableMode</li> 
     706         * <li>(b) TD in just below the root TR of the WrapperElement when in 
     707         * tableMode</li> 
     708         * <li>(c) clipperDiv inside the (a) or (b)</li> 
     709         * <li>(d) The innermost TD within alignment structures located in (a), 
     710         * (b) or (c)</li> 
     711         * </ul> 
     712         *  
     713         * @return Element described above 
     714         */ 
     715        private Element getElementWrappingWidgetAndCaption() { 
     716 
     717            // When alignment is used, we will can safely return the innermost 
     718            // TD 
     719            if (innermostTDinAlignmnetStructure != null) { 
     720                return innermostTDinAlignmnetStructure; 
     721            } 
     722 
     723            // In all other cases element wrapping the potential alignment 
     724            // structures is the correct one 
     725            return getElementWrappingAlignmentStructures(); 
     726        } 
     727 
     728        /** 
     729         * Get the element where alignment structures should be placed in if 
     730         * they are in use. 
     731         *  
     732         * Returned element can one of the following: 
     733         * <ul> 
     734         * <li>(a) Root DIV of the WrapperElement when not in tableMode</li> 
     735         * <li>(b) TD in just below the root TR of the WrapperElement when in 
     736         * tableMode</li> 
     737         * <li>(c) clipperDiv inside the (a) or (b)</li> 
     738         * </ul> 
     739         *  
     740         * @return Element described above 
     741         */ 
     742        private Element getElementWrappingAlignmentStructures() { 
     743 
     744            // Clipper DIV wraps the alignment structures if present 
     745            if (clipperDiv != null) { 
     746                return clipperDiv; 
     747            } 
     748 
     749            // When Clipper DIV is not used, we just give the element 
     750            // that would wrap it if it would be used 
     751            return getElementWrappingClipperDiv(); 
     752        } 
     753 
     754        /** 
     755         * Get the element where clipperDiv should be placed in if they it is in 
     756         * use. 
     757         *  
     758         * Returned element can one of the following: 
     759         * <ul> 
     760         * <li>(a) Root DIV of the WrapperElement when not in tableMode</li> 
     761         * <li>(b) TD in just below the root TR of the WrapperElement when in 
     762         * tableMode</li> 
     763         * </ul> 
     764         *  
     765         * @return Element described above 
     766         */ 
     767        private Element getElementWrappingClipperDiv() { 
     768 
     769            // Only vertical layouts in non-table mode use TR as root, for the 
     770            // rest we can safely give root element 
    620771            if (!tableMode || orientationMode == ORIENTATION_HORIZONTAL) { 
    621772                return getElement(); 
    622773            } 
     774 
     775            // The root is TR, we'll thus give the TD that is immediately within 
     776            // the root 
    623777            return DOM.getFirstChild(getElement()); 
    624778        } 
     
    627781         * Create tr, td or div - depending on the orientation of the layout and 
    628782         * set it as root. 
     783         *  
     784         * All contents of the wrapper are cleared. Caller is responsible for 
     785         * preserving the contents and moving them into new root. 
    629786         *  
    630787         * @return Previous root element. 
     
    647804                } 
    648805            } 
     806 
     807            // Clear any references to intermediate elements 
     808            clipperDiv = alignmentTD = innermostTDinAlignmnetStructure = null; 
    649809        } 
    650810 
     
    653813 
    654814            final Widget widget = (Widget) paintable; 
     815            final Element captionWrapper = getElementWrappingWidgetAndCaption(); 
    655816 
    656817            // The widget needs caption 
     
    675836                    // As the caption has just been created, insert it to DOM 
    676837                    if (after) { 
    677                         DOM.appendChild(getWrappingElement(), captionElement); 
    678                         DOM.setElementAttribute(getWrappingElement(), "class", 
     838                        DOM.appendChild(captionWrapper, captionElement); 
     839                        DOM.setElementAttribute(captionWrapper, "class", 
    679840                                "i-orderedlayout-w"); 
    680841                        caption.addStyleName("i-orderedlayout-c"); 
    681842                        widget.addStyleName("i-orderedlayout-w-e"); 
    682843                    } else { 
    683                         DOM 
    684                                 .insertChild(getWrappingElement(), 
    685                                         captionElement, 0); 
     844                        DOM.insertChild(captionWrapper, captionElement, 0); 
    686845                    } 
    687846 
     
    689848 
    690849                // Caption exists. Move it to correct position if needed 
    691                 if (after == (DOM.getChildIndex(getWrappingElement(), 
    692                         widgetElement) > DOM.getChildIndex( 
    693                         getWrappingElement(), captionElement))) { 
    694                     Element firstElement = DOM.getChild(getWrappingElement(), 
    695                             DOM.getChildCount(getWrappingElement()) - 2); 
     850                if (after == (DOM.getChildIndex(captionWrapper, widgetElement) > DOM 
     851                        .getChildIndex(captionWrapper, captionElement))) { 
     852                    Element firstElement = DOM.getChild(captionWrapper, DOM 
     853                            .getChildCount(captionWrapper) - 2); 
    696854                    if (firstElement != null) { 
    697                         DOM.removeChild(getWrappingElement(), firstElement); 
    698                         DOM.appendChild(getWrappingElement(), firstElement); 
    699                     } 
    700                     DOM.setElementAttribute(getWrappingElement(), "class", 
     855                        DOM.removeChild(captionWrapper, firstElement); 
     856                        DOM.appendChild(captionWrapper, firstElement); 
     857                    } 
     858                    DOM.setElementAttribute(captionWrapper, "class", 
    701859                            after ? "i-orderedlayout-w" : ""); 
    702860                    if (after) { 
     
    716874                // Remove existing caption from DOM 
    717875                if (caption != null) { 
    718                     DOM.removeChild(getWrappingElement(), caption.getElement()); 
     876                    DOM.removeChild(captionWrapper, caption.getElement()); 
    719877                    caption = null; 
    720                     DOM.setElementAttribute(getWrappingElement(), "class", ""); 
     878                    DOM.setElementAttribute(captionWrapper, "class", ""); 
    721879                    widget.removeStyleName("i-orderedlayout-w-e"); 
    722880                    caption.removeStyleName("i-orderedlayout-w-c"); 
     
    730888        void setAlignment(String verticalAlignment, String horizontalAlignment) { 
    731889 
    732             // Set vertical alignment 
    733             if (BrowserInfo.get().isIE()) { 
    734                 DOM.setElementAttribute(getWrappingElement(), "vAlign", 
    735                         verticalAlignment); 
    736             } else { 
    737                 if (orientationMode == ORIENTATION_VERTICAL) { 
    738                     if (verticalAlignment == null 
    739                             || verticalAlignment.equals("top")) { 
    740                         DOM.setStyleAttribute(getWrappingElement(), "display", 
    741                                 "block"); 
    742                         DOM 
    743                                 .setStyleAttribute(getWrappingElement(), 
    744                                         "width", ""); 
    745                     } else { 
    746                         DOM.setStyleAttribute(getWrappingElement(), "display", 
    747                                 "table-cell"); 
    748                         DOM.setStyleAttribute(getWrappingElement(), "width", 
    749                                 "1000000px"); 
    750                     } 
    751                 } 
    752                 DOM.setStyleAttribute(getWrappingElement(), "verticalAlign", 
    753                         verticalAlignment); 
    754             } 
    755  
    756             // Set horizontal alignment 
    757  
    758890            // use one-cell table to implement horizontal alignments, only 
    759             // for values other than "left" (which is default) 
    760             // build one cell table 
    761             if (!horizontalAlignment.equals("left")) { 
     891            // for values other than top-left (which is default) 
     892            if (!horizontalAlignment.equals("left") 
     893                    || !verticalAlignment.equals("top")) { 
    762894 
    763895                // The previous positioning has been left (or unspecified). 
    764896                // Thus we need to create a one-cell-table to position 
    765897                // this element. 
    766                 if (td == null) { 
     898                if (alignmentTD == null) { 
    767899 
    768900                    // Store and remove the current childs (widget and caption) 
    769                     Element c1 = DOM.getFirstChild(getWrappingElement()); 
     901                    Element c1 = DOM 
     902                            .getFirstChild(getElementWrappingWidgetAndCaption()); 
    770903                    if (c1 != null) { 
    771                         DOM.removeChild(getWrappingElement(), c1); 
    772                     } 
    773                     Element c2 = DOM.getFirstChild(getWrappingElement()); 
     904                        DOM.removeChild(getElementWrappingWidgetAndCaption(), 
     905                                c1); 
     906                    } 
     907                    Element c2 = DOM 
     908                            .getFirstChild(getElementWrappingWidgetAndCaption()); 
    774909                    if (c2 != null) { 
    775                         DOM.removeChild(getWrappingElement(), c2); 
     910                        DOM.removeChild(getElementWrappingWidgetAndCaption(), 
     911                                c2); 
    776912                    } 
    777913 
    778914                    // Construct table structure to align children 
    779                     final String t = "<table cellpadding='0' cellspacing='0' width='100%'><tbody><tr><td>" 
     915                    final String t = "<table cellpadding='0' cellspacing='0' width='100%' height='100%'><tbody><tr><td>" 
    780916                            + "<table cellpadding='0' cellspacing='0' ><tbody><tr><td align='left'>" 
    781917                            + "</td></tr></tbody></table></td></tr></tbody></table>"; 
    782                     DOM.setInnerHTML(getWrappingElement(), t); 
    783                     td = DOM.getFirstChild(DOM.getFirstChild(DOM 
     918                    DOM.setInnerHTML(getElementWrappingWidgetAndCaption(), t); 
     919                    alignmentTD = DOM 
    784920                            .getFirstChild(DOM 
    785                                     .getFirstChild(getWrappingElement())))); 
    786                     Element itd = DOM.getFirstChild(DOM.getFirstChild(DOM 
    787                             .getFirstChild(DOM.getFirstChild(td)))); 
     921                                    .getFirstChild(DOM 
     922                                            .getFirstChild(DOM 
     923                                                    .getFirstChild(getElementWrappingWidgetAndCaption())))); 
     924                    innermostTDinAlignmnetStructure = DOM.getFirstChild(DOM 
     925                            .getFirstChild(DOM.getFirstChild(DOM 
     926                                    .getFirstChild(alignmentTD)))); 
    788927 
    789928                    // Restore children inside the 
    790929                    if (c1 != null) { 
    791                         DOM.appendChild(itd, c1); 
     930                        DOM.appendChild(innermostTDinAlignmnetStructure, c1); 
    792931                        if (c2 != null) { 
    793                             DOM.appendChild(itd, c2); 
     932                            DOM 
     933                                    .appendChild( 
     934                                            innermostTDinAlignmnetStructure, c2); 
    794935                        } 
    795936                    } 
     
    799940                    // Go around optimization bug in WebKit and ensure repaint 
    800941                    if (BrowserInfo.get().isSafari()) { 
    801                         String prevValue = DOM.getElementAttribute(td, "align"); 
     942                        String prevValue = DOM.getElementAttribute(alignmentTD, 
     943                                "align"); 
    802944                        if (!horizontalAlignment.equals(prevValue)) { 
    803                             Element parent = DOM.getParent(td); 
    804                             DOM.removeChild(parent, td); 
    805                             DOM.appendChild(parent, td); 
     945                            Element parent = DOM.getParent(alignmentTD); 
     946                            DOM.removeChild(parent, alignmentTD); 
     947                            DOM.appendChild(parent, alignmentTD); 
    806948                        } 
    807949                    } 
     
    809951                } 
    810952 
    811                 // Seth the alignment in td 
    812                 DOM.setElementAttribute(td, "align", horizontalAlignment); 
    813  
    814             } else 
    815  
    816             // In this case we are requested to position this left 
    817             // while as it has had some other position in the past. 
    818             // Thus the one-cell wrapper table must be removed. 
    819             if (td != null) { 
    820  
    821                 // Move content to main container 
    822                 Element itd = DOM.getFirstChild(DOM.getFirstChild(DOM 
    823                         .getFirstChild(DOM.getFirstChild(td)))); 
    824                 while (DOM.getChildCount(itd) > 0) { 
    825                     Element content = DOM.getFirstChild(itd); 
    826                     if (content != null) { 
    827                         DOM.removeChild(itd, content); 
    828                         DOM.appendChild(getWrappingElement(), content); 
    829                     } 
    830                 } 
    831  
    832                 // Remove unneeded table element 
    833                 DOM.removeChild(getWrappingElement(), DOM 
    834                         .getFirstChild(getWrappingElement())); 
    835  
    836                 td = null; 
     953                // Set the alignment in td 
     954                DOM.setElementAttribute(alignmentTD, "align", 
     955                        horizontalAlignment); 
     956                DOM.setElementAttribute(alignmentTD, "valign", 
     957                        verticalAlignment); 
     958 
     959            } else { 
     960 
     961                // In this case we are requested to position this left 
     962                // while as it has had some other position in the past. 
     963                // Thus the one-cell wrapper table must be removed. 
     964                if (alignmentTD != null) { 
     965 
     966                    // Move content to main container 
     967                    final Element itd = innermostTDinAlignmnetStructure; 
     968                    final Element alignmentTable = DOM.getParent(DOM 
     969                            .getParent(DOM.getParent(alignmentTD))); 
     970                    final Element target = DOM.getParent(alignmentTable); 
     971                    while (DOM.getChildCount(itd) > 0) { 
     972                        Element content = DOM.getFirstChild(itd); 
     973                        if (content != null) { 
     974                            DOM.removeChild(itd, content); 
     975                            DOM.appendChild(target, content); 
     976                        } 
     977                    } 
     978 
     979                    // Remove unneeded table element 
     980                    DOM.removeChild(target, alignmentTable); 
     981 
     982                    alignmentTD = innermostTDinAlignmnetStructure = null; 
     983                } 
    837984            } 
    838985        } 
     
    841988        void setSpacingAndMargins(boolean first, boolean last) { 
    842989 
     990            final Element e = getElementWrappingWidgetAndCaption(); 
     991 
    843992            if (orientationMode == ORIENTATION_HORIZONTAL) { 
    844                 DOM 
    845                         .setStyleAttribute(getWrappingElement(), "paddingLeft", 
    846                                 first ? (margins.hasLeft() ? marginLeft + "px" 
    847                                         : "0") 
    848                                         : (hasComponentSpacing ? hSpacing 
    849                                                 + "px" : "0")); 
    850   &nbs