]> source.dussan.org Git - vaadin-framework.git/commitdiff
Refactored layout size checking method, related to #2139
authorArtur Signell <artur.signell@itmill.com>
Thu, 18 Dec 2008 10:05:37 +0000 (10:05 +0000)
committerArtur Signell <artur.signell@itmill.com>
Thu, 18 Dec 2008 10:05:37 +0000 (10:05 +0000)
svn changeset:6264/svn branch:trunk

src/com/itmill/toolkit/terminal/gwt/server/CommunicationManager.java
src/com/itmill/toolkit/terminal/gwt/server/ComponentSizeValidator.java [new file with mode: 0644]
src/com/itmill/toolkit/terminal/gwt/server/DebugUtilities.java [deleted file]
src/com/itmill/toolkit/ui/AbstractComponent.java

index acdc8665d1f4a0921fdc779572265c8a89245eff..270ea42cc7caed8cff813ee6197210bef83495c9 100644 (file)
@@ -54,7 +54,7 @@ import com.itmill.toolkit.terminal.VariableOwner;
 import com.itmill.toolkit.terminal.Paintable.RepaintRequestEvent;
 import com.itmill.toolkit.terminal.Terminal.ErrorEvent;
 import com.itmill.toolkit.terminal.gwt.client.ApplicationConnection;
-import com.itmill.toolkit.terminal.gwt.server.DebugUtilities.InvalidLayout;
+import com.itmill.toolkit.terminal.gwt.server.ComponentSizeValidator.InvalidLayout;
 import com.itmill.toolkit.ui.AbstractField;
 import com.itmill.toolkit.ui.Component;
 import com.itmill.toolkit.ui.Upload;
@@ -446,7 +446,7 @@ public class CommunicationManager implements Paintable.RepaintRequestListener {
                     paintablePainted(p);
 
                     if (analyzeLayouts) {
-                        invalidComponentRelativeSizes = DebugUtilities
+                        invalidComponentRelativeSizes = ComponentSizeValidator
                                 .validateComponentRelativeSizes(((Window) p)
                                         .getLayout(), null, null);
                     }
diff --git a/src/com/itmill/toolkit/terminal/gwt/server/ComponentSizeValidator.java b/src/com/itmill/toolkit/terminal/gwt/server/ComponentSizeValidator.java
new file mode 100644 (file)
index 0000000..cca56e3
--- /dev/null
@@ -0,0 +1,635 @@
+package com.itmill.toolkit.terminal.gwt.server;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Stack;
+import java.util.Vector;
+
+import com.itmill.toolkit.terminal.Sizeable;
+import com.itmill.toolkit.ui.AbstractOrderedLayout;
+import com.itmill.toolkit.ui.Component;
+import com.itmill.toolkit.ui.ComponentContainer;
+import com.itmill.toolkit.ui.CustomComponent;
+import com.itmill.toolkit.ui.GridLayout;
+import com.itmill.toolkit.ui.OrderedLayout;
+import com.itmill.toolkit.ui.Panel;
+import com.itmill.toolkit.ui.SplitPanel;
+import com.itmill.toolkit.ui.TabSheet;
+import com.itmill.toolkit.ui.VerticalLayout;
+import com.itmill.toolkit.ui.Window;
+import com.itmill.toolkit.ui.GridLayout.Area;
+
+public class ComponentSizeValidator {
+
+    private final static int LAYERS_SHOWN = 4;
+
+    /**
+     * Recursively checks given component and its subtree for invalid layout
+     * setups. Prints errors to std err stream.
+     * 
+     * @param component
+     *            component to check
+     * @return set of first level errors found
+     */
+    public static List<InvalidLayout> validateComponentRelativeSizes(
+            Component component, List<InvalidLayout> errors,
+            InvalidLayout parent) {
+
+        boolean invalidHeight = !checkHeights(component);
+        boolean invalidWidth = !checkWidths(component);
+
+        if (invalidHeight || invalidWidth) {
+            InvalidLayout error = new InvalidLayout(component, invalidHeight,
+                    invalidWidth);
+            if (parent != null) {
+                parent.addError(error);
+            } else {
+                if (errors == null) {
+                    errors = new LinkedList<InvalidLayout>();
+                }
+                errors.add(error);
+            }
+            parent = error;
+        }
+
+        if (component instanceof Panel) {
+            Panel panel = (Panel) component;
+            errors = validateComponentRelativeSizes(panel.getLayout(), errors,
+                    parent);
+        } else if (component instanceof ComponentContainer) {
+            ComponentContainer lo = (ComponentContainer) component;
+            Iterator it = lo.getComponentIterator();
+            while (it.hasNext()) {
+                errors = validateComponentRelativeSizes((Component) it.next(),
+                        errors, parent);
+            }
+        }
+
+        return errors;
+    }
+
+    private static void printServerError(String msg,
+            Stack<ComponentInfo> attributes, boolean widthError,
+            PrintStream errorStream) {
+        StringBuffer err = new StringBuffer();
+        err.append("IT MILL Toolkit DEBUG\n");
+
+        StringBuilder indent = new StringBuilder("");
+        ComponentInfo ci;
+        if (attributes != null) {
+            while (attributes.size() > LAYERS_SHOWN) {
+                attributes.pop();
+            }
+            while (!attributes.empty()) {
+                ci = attributes.pop();
+                showComponent(ci.component, ci.info, err, indent, widthError);
+            }
+        }
+
+        err.append("Invalid layout detected. ");
+        err.append(msg);
+        err.append("\n");
+        err
+                .append("Components may be invisible or not render as expected. Relative sizes were replaced by undefined sizes.\n");
+        errorStream.println(err);
+
+    }
+
+    public static boolean checkHeights(Component component) {
+        try {
+            if (!hasRelativeHeight(component)) {
+                return true;
+            }
+            if (component instanceof Window) {
+                return true;
+            }
+            if (component.getParent() == null) {
+                return true;
+            }
+
+            return parentCanDefineHeight(component);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return true;
+        }
+    }
+
+    public static boolean checkWidths(Component component) {
+        try {
+            if (!hasRelativeWidth(component)) {
+                return true;
+            }
+            if (component instanceof Window) {
+                return true;
+            }
+            if (component.getParent() == null) {
+                return true;
+            }
+
+            return parentCanDefineWidth(component);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return true;
+        }
+    }
+
+    public static class InvalidLayout {
+
+        private Component component;
+
+        private boolean invalidHeight;
+        private boolean invalidWidth;
+
+        private Vector<InvalidLayout> subErrors = new Vector<InvalidLayout>();
+
+        public InvalidLayout(Component component, boolean height, boolean width) {
+            this.component = component;
+            invalidHeight = height;
+            invalidWidth = width;
+        }
+
+        public void addError(InvalidLayout error) {
+            subErrors.add(error);
+        }
+
+        public void reportErrors(PrintWriter clientJSON,
+                CommunicationManager communicationManager,
+                PrintStream serverErrorStream) {
+            clientJSON.write("{");
+
+            Component parent = component.getParent();
+            String paintableId = communicationManager.getPaintableId(component);
+
+            clientJSON.print("id:\"" + paintableId + "\"");
+
+            if (invalidHeight) {
+                Stack<ComponentInfo> attributes = null;
+                String msg = "";
+                // set proper error messages
+                if (parent instanceof AbstractOrderedLayout) {
+                    AbstractOrderedLayout ol = (AbstractOrderedLayout) parent;
+                    boolean vertical = false;
+
+                    if (ol instanceof OrderedLayout) {
+                        if (((OrderedLayout) ol).getOrientation() == OrderedLayout.ORIENTATION_VERTICAL) {
+                            vertical = true;
+                        }
+                    } else if (ol instanceof VerticalLayout) {
+                        vertical = true;
+                    }
+
+                    if (vertical) {
+                        msg = "Relative height for component inside non sized vertical ordered layout.";
+                        attributes = getHeightAttributes(component);
+                    } else {
+                        msg = "At least one of horizontal orderedlayout's components must have non relative height if layout has no height defined";
+                        attributes = getHeightAttributes(component);
+                    }
+                } else if (parent instanceof GridLayout) {
+                    msg = "At least one component in each row should have non relative height in GridLayout with undefined height.";
+                    attributes = getHeightAttributes(component);
+                } else {
+                    // default error for non sized parent issue
+                    msg = "Relative height component's parent should not have undefined height.";
+                    attributes = getHeightAttributes(component);
+                }
+                printServerError(msg, attributes, false, serverErrorStream);
+                clientJSON.print(",\"heightMsg\":\"" + msg + "\"");
+            }
+            if (invalidWidth) {
+                Stack<ComponentInfo> attributes = null;
+                String msg = "";
+                if (parent instanceof AbstractOrderedLayout) {
+                    AbstractOrderedLayout ol = (AbstractOrderedLayout) parent;
+                    boolean horizontal = true;
+
+                    if (ol instanceof OrderedLayout) {
+                        if (((OrderedLayout) ol).getOrientation() == OrderedLayout.ORIENTATION_VERTICAL) {
+                            horizontal = false;
+                        }
+                    } else if (ol instanceof VerticalLayout) {
+                        horizontal = false;
+                    }
+
+                    if (horizontal) {
+                        msg = "Relative width for component inside non sized horizontal ordered layout.";
+                        attributes = getWidthAttributes(component);
+                    } else {
+                        msg = "At least one of vertical orderedlayout's components must have non relative width if layout has no width defined";
+                        attributes = getWidthAttributes(component);
+                    }
+                } else if (parent instanceof GridLayout) {
+                    msg = "At least one component in each column should have non relative width in GridLayout with undefined width.";
+                    attributes = getWidthAttributes(component);
+                } else {
+                    // default error for non sized parent issue
+                    msg = "Relative width component's parent should not have undefined width.";
+                    attributes = getWidthAttributes(component);
+                }
+                clientJSON.print(",\"widthMsg\":\"" + msg + "\"");
+                printServerError(msg, attributes, true, serverErrorStream);
+            }
+            if (subErrors.size() > 0) {
+                serverErrorStream.println("Sub errors >>");
+                clientJSON.write(", \"subErrors\" : [");
+                boolean first = true;
+                for (InvalidLayout subError : subErrors) {
+                    if (!first) {
+                        clientJSON.print(",");
+                    } else {
+                        first = false;
+                    }
+                    subError.reportErrors(clientJSON, communicationManager,
+                            serverErrorStream);
+                }
+                clientJSON.write("]");
+                serverErrorStream.println("<< Sub erros");
+            }
+            clientJSON.write("}");
+        }
+    }
+
+    private static class ComponentInfo {
+        Component component;
+        String info;
+
+        public ComponentInfo(Component component, String info) {
+            this.component = component;
+            this.info = info;
+        }
+
+    }
+
+    private static Stack<ComponentInfo> getHeightAttributes(Component component) {
+        Stack<ComponentInfo> attributes = new Stack<ComponentInfo>();
+        attributes
+                .add(new ComponentInfo(component, getHeightString(component)));
+        Component parent = component.getParent();
+        attributes.add(new ComponentInfo(parent, getHeightString(parent)));
+
+        while ((parent = parent.getParent()) != null) {
+            attributes.add(new ComponentInfo(parent, getHeightString(parent)));
+        }
+
+        return attributes;
+    }
+
+    private static Stack<ComponentInfo> getWidthAttributes(Component component) {
+        Stack<ComponentInfo> attributes = new Stack<ComponentInfo>();
+        attributes.add(new ComponentInfo(component, getWidthString(component)));
+        Component parent = component.getParent();
+        attributes.add(new ComponentInfo(parent, getWidthString(parent)));
+
+        while ((parent = parent.getParent()) != null) {
+            attributes.add(new ComponentInfo(parent, getWidthString(parent)));
+        }
+
+        return attributes;
+    }
+
+    private static String getWidthString(Component component) {
+        String width = "width: ";
+        if (hasRelativeWidth(component)) {
+            width += "RELATIVE, " + component.getWidth() + " %";
+        } else if (component instanceof Window && component.getParent() == null) {
+            width += "MAIN WINDOW";
+        } else if (component.getWidth() >= 0) {
+            width += "ABSOLUTE, " + component.getWidth() + " "
+                    + Sizeable.UNIT_SYMBOLS[component.getWidthUnits()];
+        } else {
+            width += "UNDEFINED";
+        }
+
+        return width;
+    }
+
+    private static String getHeightString(Component component) {
+        String height = "height: ";
+        if (hasRelativeHeight(component)) {
+            height += "RELATIVE, " + component.getHeight() + " %";
+        } else if (component instanceof Window && component.getParent() == null) {
+            height += "MAIN WINDOW";
+        } else if (component.getHeight() > 0) {
+            height += "ABSOLUTE, " + component.getHeight() + " "
+                    + Sizeable.UNIT_SYMBOLS[component.getHeightUnits()];
+        } else {
+            height += "UNDEFINED";
+        }
+
+        return height;
+    }
+
+    private static void showComponent(Component component, String attribute,
+            StringBuffer err, StringBuilder indent, boolean widthError) {
+
+        FileLocation createLoc = creationLocations.get(component);
+
+        FileLocation sizeLoc;
+        if (widthError) {
+            sizeLoc = widthLocations.get(component);
+        } else {
+            sizeLoc = heightLocations.get(component);
+        }
+
+        err.append(indent);
+        indent.append("  ");
+        err.append("- ");
+
+        err.append(component.getClass().getSimpleName());
+        err.append("/").append(Integer.toHexString(component.hashCode()));
+
+        if (component.getCaption() != null) {
+            err.append(" \"");
+            err.append(component.getCaption());
+            err.append("\"");
+        }
+
+        if (component.getDebugId() != null) {
+            err.append(" debugId: ");
+            err.append(component.getDebugId());
+        }
+
+        if (createLoc != null) {
+            err.append(", created at (" + createLoc.file + ":"
+                    + createLoc.lineNumber + ")");
+
+        }
+
+        if (attribute != null) {
+            err.append(" (");
+            err.append(attribute);
+            if (sizeLoc != null) {
+                err.append(", set at (" + sizeLoc.file + ":"
+                        + sizeLoc.lineNumber + ")");
+            }
+
+            err.append(")");
+        }
+        err.append("\n");
+
+    }
+
+    private static boolean hasNonRelativeHeightComponent(
+            AbstractOrderedLayout ol) {
+        Iterator it = ol.getComponentIterator();
+        while (it.hasNext()) {
+            if (!hasRelativeHeight((Component) it.next())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static boolean parentCanDefineHeight(Component component) {
+        Component parent = component.getParent();
+        if (parent == null) {
+            // main window, valid situation
+            return true;
+        }
+        if (parent.getHeight() < 0) {
+            // Undefined height
+            if (parent instanceof Window) {
+                Window w = (Window) parent;
+                if (w.getParent() == null) {
+                    // main window is considered to have size
+                    return true;
+                }
+            }
+
+            if (parent instanceof AbstractOrderedLayout) {
+                boolean horizontal = true;
+                if (parent instanceof OrderedLayout) {
+                    horizontal = ((OrderedLayout) parent).getOrientation() == OrderedLayout.ORIENTATION_HORIZONTAL;
+                } else if (parent instanceof VerticalLayout) {
+                    horizontal = false;
+                }
+                if (horizontal
+                        && hasNonRelativeHeightComponent((AbstractOrderedLayout) parent)) {
+                    return true;
+                } else {
+                    return false;
+                }
+
+            } else if (parent instanceof GridLayout) {
+                GridLayout gl = (GridLayout) parent;
+                Area componentArea = gl.getComponentArea(component);
+                boolean rowHasHeight = false;
+                for (int row = componentArea.getRow1(); !rowHasHeight
+                        && row <= componentArea.getRow2(); row++) {
+                    for (int column = 0; !rowHasHeight
+                            && column < gl.getColumns(); column++) {
+                        Component c = gl.getComponent(column, row);
+                        if (c != null) {
+                            rowHasHeight = !hasRelativeHeight(c);
+                        }
+                    }
+                }
+                if (!rowHasHeight) {
+                    return false;
+                } else {
+                    // Other components define row height
+                    return true;
+                }
+            }
+
+            if (parent instanceof Panel || parent instanceof SplitPanel
+                    || parent instanceof TabSheet
+                    || parent instanceof CustomComponent) {
+                // height undefined, we know how how component works and no
+                // exceptions
+                // TODO horiz SplitPanel ??
+                return false;
+            } else {
+                // We cannot generally know if undefined component can serve
+                // space for children (like CustomLayout or component built by
+                // third party) so we assume they can
+                return true;
+            }
+
+        } else if (hasRelativeHeight(parent)) {
+            // Relative height
+            if (parent.getParent() != null) {
+                return parentCanDefineHeight(parent);
+            } else {
+                return true;
+            }
+        } else {
+            // Absolute height
+            return true;
+        }
+    }
+
+    private static boolean hasRelativeHeight(Component component) {
+        return (component.getHeightUnits() == Sizeable.UNITS_PERCENTAGE && component
+                .getHeight() > 0);
+    }
+
+    private static boolean hasNonRelativeWidthComponent(AbstractOrderedLayout ol) {
+        Iterator it = ol.getComponentIterator();
+        while (it.hasNext()) {
+            if (!hasRelativeWidth((Component) it.next())) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private static boolean hasRelativeWidth(Component paintable) {
+        return paintable.getWidth() > 0
+                && paintable.getWidthUnits() == Sizeable.UNITS_PERCENTAGE;
+    }
+
+    public static boolean parentCanDefineWidth(Component component) {
+        Component parent = component.getParent();
+        if (parent == null) {
+            // main window, valid situation
+            return true;
+        }
+        if (parent instanceof Window) {
+            Window w = (Window) parent;
+            if (w.getParent() == null) {
+                // main window is considered to have size
+                return true;
+            }
+
+        }
+
+        if (parent.getWidth() < 0) {
+            // Undefined width
+
+            if (parent instanceof AbstractOrderedLayout) {
+                AbstractOrderedLayout ol = (AbstractOrderedLayout) parent;
+                boolean horizontal = true;
+                if (ol instanceof OrderedLayout) {
+                    if (((OrderedLayout) ol).getOrientation() == OrderedLayout.ORIENTATION_VERTICAL) {
+                        horizontal = false;
+                    }
+                } else if (ol instanceof VerticalLayout) {
+                    horizontal = false;
+                }
+
+                if (!horizontal && hasNonRelativeWidthComponent(ol)) {
+                    // valid situation, other components defined width
+                    return true;
+                } else {
+                    return false;
+                }
+            } else if (parent instanceof GridLayout) {
+                GridLayout gl = (GridLayout) parent;
+                Area componentArea = gl.getComponentArea(component);
+                boolean columnHasWidth = false;
+                for (int col = componentArea.getColumn1(); !columnHasWidth
+                        && col <= componentArea.getColumn2(); col++) {
+                    for (int row = 0; !columnHasWidth && row < gl.getRows(); row++) {
+                        Component c = gl.getComponent(col, row);
+                        if (c != null) {
+                            columnHasWidth = !hasRelativeWidth(c);
+                        }
+                    }
+                }
+                if (!columnHasWidth) {
+                    return false;
+                } else {
+                    // Other components define column width
+                    return true;
+                }
+            } else if (parent instanceof SplitPanel
+                    || parent instanceof TabSheet
+                    || parent instanceof CustomComponent) {
+                // TODO vertical splitpanel with another non relative component?
+                return false;
+            } else if (parent instanceof Panel) {
+                // TODO Panel should be able to define width based on caption
+                return false;
+                // if (parent.getCaption() != null
+                // && !parent.getCaption().equals("")) {
+                // return true;
+                // } else {
+                // return false;
+                // }
+            } else {
+                return true;
+            }
+        } else if (hasRelativeWidth(parent)) {
+            // Relative width
+            if (parent.getParent() == null) {
+                return true;
+            }
+
+            return parentCanDefineWidth(parent);
+        } else {
+            return true;
+        }
+
+    }
+
+    private static Map<Object, FileLocation> creationLocations = new HashMap<Object, FileLocation>();
+    private static Map<Object, FileLocation> widthLocations = new HashMap<Object, FileLocation>();
+    private static Map<Object, FileLocation> heightLocations = new HashMap<Object, FileLocation>();
+
+    public static class FileLocation {
+        public String method;
+        public String file;
+        public String className;
+        public String classNameSimple;
+        public int lineNumber;
+
+        public FileLocation(StackTraceElement traceElement) {
+            file = traceElement.getFileName();
+            className = traceElement.getClassName();
+            classNameSimple = className
+                    .substring(className.lastIndexOf('.') + 1);
+            lineNumber = traceElement.getLineNumber();
+            method = traceElement.getMethodName();
+        }
+    }
+
+    public static void setCreationLocation(Object object) {
+        setLocation(creationLocations, object);
+    }
+
+    public static void setWidthLocation(Object object) {
+        setLocation(widthLocations, object);
+    }
+
+    public static void setHeightLocation(Object object) {
+        setLocation(heightLocations, object);
+    }
+
+    private static void setLocation(Map<Object, FileLocation> map, Object object) {
+        StackTraceElement[] traceLines = Thread.currentThread().getStackTrace();
+        for (StackTraceElement traceElement : traceLines) {
+            Class cls;
+            try {
+                String className = traceElement.getClassName();
+                if (className.startsWith("java.")
+                        || className.startsWith("sun.")) {
+                    continue;
+                }
+
+                cls = Class.forName(className);
+                if (cls == ComponentSizeValidator.class || cls == Thread.class) {
+                    continue;
+                }
+
+                if (Component.class.isAssignableFrom(cls)
+                        && !CustomComponent.class.isAssignableFrom(cls)) {
+                    continue;
+                }
+                FileLocation cl = new FileLocation(traceElement);
+                map.put(object, cl);
+                return;
+            } catch (Exception e) {
+                // TODO Auto-generated catch block
+                e.printStackTrace();
+            }
+
+        }
+    }
+
+}
diff --git a/src/com/itmill/toolkit/terminal/gwt/server/DebugUtilities.java b/src/com/itmill/toolkit/terminal/gwt/server/DebugUtilities.java
deleted file mode 100644 (file)
index 01c0c94..0000000
+++ /dev/null
@@ -1,613 +0,0 @@
-package com.itmill.toolkit.terminal.gwt.server;
-
-import java.io.PrintStream;
-import java.io.PrintWriter;
-import java.util.HashMap;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-import java.util.Stack;
-import java.util.Vector;
-
-import com.itmill.toolkit.terminal.Sizeable;
-import com.itmill.toolkit.ui.AbstractOrderedLayout;
-import com.itmill.toolkit.ui.Component;
-import com.itmill.toolkit.ui.ComponentContainer;
-import com.itmill.toolkit.ui.CustomComponent;
-import com.itmill.toolkit.ui.GridLayout;
-import com.itmill.toolkit.ui.OrderedLayout;
-import com.itmill.toolkit.ui.Panel;
-import com.itmill.toolkit.ui.SplitPanel;
-import com.itmill.toolkit.ui.TabSheet;
-import com.itmill.toolkit.ui.VerticalLayout;
-import com.itmill.toolkit.ui.Window;
-import com.itmill.toolkit.ui.GridLayout.Area;
-
-public class DebugUtilities {
-
-    private final static int LAYERS_SHOWN = 4;
-
-    /**
-     * Recursively checks given component and its subtree for invalid layout
-     * setups. Prints errors to std err stream.
-     * 
-     * @param component
-     *            component to check
-     * @return set of first level errors found
-     */
-    public static List<InvalidLayout> validateComponentRelativeSizes(
-            Component component, List<InvalidLayout> errors,
-            InvalidLayout parent) {
-
-        boolean invalidHeight = !checkHeights(component);
-        boolean invalidWidth = !checkWidths(component);
-
-        if (invalidHeight || invalidWidth) {
-            InvalidLayout error = new InvalidLayout(component, invalidHeight,
-                    invalidWidth);
-            if (parent != null) {
-                parent.addError(error);
-            } else {
-                if (errors == null) {
-                    errors = new LinkedList<InvalidLayout>();
-                }
-                errors.add(error);
-            }
-            parent = error;
-        }
-
-        if (component instanceof Panel) {
-            Panel panel = (Panel) component;
-            errors = validateComponentRelativeSizes(panel.getLayout(), errors,
-                    parent);
-        } else if (component instanceof ComponentContainer) {
-            ComponentContainer lo = (ComponentContainer) component;
-            Iterator it = lo.getComponentIterator();
-            while (it.hasNext()) {
-                errors = validateComponentRelativeSizes((Component) it.next(),
-                        errors, parent);
-            }
-        }
-
-        return errors;
-    }
-
-    private static void printServerError(String msg,
-            Stack<ComponentInfo> attributes, boolean widthError,
-            PrintStream errorStream) {
-        StringBuffer err = new StringBuffer();
-        err.append("IT MILL Toolkit DEBUG\n");
-
-        StringBuilder indent = new StringBuilder("");
-        ComponentInfo ci;
-        if (attributes != null) {
-            while (attributes.size() > LAYERS_SHOWN) {
-                attributes.pop();
-            }
-            while (!attributes.empty()) {
-                ci = attributes.pop();
-                showComponent(ci.component, ci.info, err, indent, widthError);
-            }
-        }
-
-        err.append("Invalid layout detected. ");
-        err.append(msg);
-        err.append("\n");
-        err
-                .append("Components may be invisible or not render as expected. Relative sizes were replaced by undefined sizes.\n");
-        errorStream.println(err);
-
-    }
-
-    public static boolean checkHeights(Component component) {
-        try {
-            if (!hasRelativeHeight(component)) {
-                return true;
-            }
-            if (component instanceof Window) {
-                return true;
-            }
-            return !(component.getParent() != null && parentCannotDefineHeight(component));
-        } catch (Exception e) {
-            e.printStackTrace();
-            return true;
-        }
-    }
-
-    public static boolean checkWidths(Component component) {
-        try {
-            if (!hasRelativeWidth(component)) {
-                return true;
-            }
-            if (component instanceof Window) {
-                return true;
-            }
-            return !(component.getParent() != null && parentCannotDefineWidth(component));
-        } catch (Exception e) {
-            e.printStackTrace();
-            return true;
-        }
-    }
-
-    public static class InvalidLayout {
-
-        private Component component;
-
-        private boolean invalidHeight;
-        private boolean invalidWidth;
-
-        private Vector<InvalidLayout> subErrors = new Vector<InvalidLayout>();
-
-        public InvalidLayout(Component component, boolean height, boolean width) {
-            this.component = component;
-            invalidHeight = height;
-            invalidWidth = width;
-        }
-
-        public void addError(InvalidLayout error) {
-            subErrors.add(error);
-        }
-
-        public void reportErrors(PrintWriter clientJSON,
-                CommunicationManager communicationManager,
-                PrintStream serverErrorStream) {
-            clientJSON.write("{");
-
-            Component parent = component.getParent();
-            String paintableId = communicationManager.getPaintableId(component);
-
-            clientJSON.print("id:\"" + paintableId + "\"");
-
-            if (invalidHeight) {
-                Stack<ComponentInfo> attributes = null;
-                String msg = "";
-                // set proper error messages
-                if (parent instanceof AbstractOrderedLayout) {
-                    AbstractOrderedLayout ol = (AbstractOrderedLayout) parent;
-                    boolean vertical = false;
-
-                    if (ol instanceof OrderedLayout) {
-                        if (((OrderedLayout) ol).getOrientation() == OrderedLayout.ORIENTATION_VERTICAL) {
-                            vertical = true;
-                        }
-                    } else if (ol instanceof VerticalLayout) {
-                        vertical = true;
-                    }
-
-                    if (vertical) {
-                        msg = "Relative height for component inside non sized vertical ordered layout.";
-                        attributes = getHeightAttributes(component);
-                    } else {
-                        msg = "At least one of horizontal orderedlayout's components must have non relative height if layout has no height defined";
-                        attributes = getHeightAttributes(component);
-                    }
-                } else if (parent instanceof GridLayout) {
-                    msg = "At least one component in each row should have non relative height in GridLayout with undefined height.";
-                    attributes = getHeightAttributes(component);
-                } else {
-                    // default error for non sized parent issue
-                    msg = "Relative height component's parent should not have undefined height.";
-                    attributes = getHeightAttributes(component);
-                }
-                printServerError(msg, attributes, false, serverErrorStream);
-                clientJSON.print(",\"heightMsg\":\"" + msg + "\"");
-            }
-            if (invalidWidth) {
-                Stack<ComponentInfo> attributes = null;
-                String msg = "";
-                if (parent instanceof AbstractOrderedLayout) {
-                    AbstractOrderedLayout ol = (AbstractOrderedLayout) parent;
-                    boolean horizontal = true;
-
-                    if (ol instanceof OrderedLayout) {
-                        if (((OrderedLayout) ol).getOrientation() == OrderedLayout.ORIENTATION_VERTICAL) {
-                            horizontal = false;
-                        }
-                    } else if (ol instanceof VerticalLayout) {
-                        horizontal = false;
-                    }
-
-                    if (horizontal) {
-                        msg = "Relative width for component inside non sized horizontal ordered layout.";
-                        attributes = getWidthAttributes(component);
-                    } else {
-                        msg = "At least one of vertical orderedlayout's components must have non relative width if layout has no width defined";
-                        attributes = getWidthAttributes(component);
-                    }
-                } else if (parent instanceof GridLayout) {
-                    msg = "At least one component in each column should have non relative width in GridLayout with undefined width.";
-                    attributes = getWidthAttributes(component);
-                } else {
-                    // default error for non sized parent issue
-                    msg = "Relative width component's parent should not have undefined width.";
-                    attributes = getWidthAttributes(component);
-                }
-                clientJSON.print(",\"widthMsg\":\"" + msg + "\"");
-                printServerError(msg, attributes, true, serverErrorStream);
-            }
-            if (subErrors.size() > 0) {
-                serverErrorStream.println("Sub erros >>");
-                clientJSON.write(", \"subErrors\" : [");
-                boolean first = true;
-                for (InvalidLayout subError : subErrors) {
-                    if (!first) {
-                        clientJSON.print(",");
-                    } else {
-                        first = false;
-                    }
-                    subError.reportErrors(clientJSON, communicationManager,
-                            serverErrorStream);
-                }
-                clientJSON.write("]");
-                serverErrorStream.println("<< Sub erros");
-            }
-            clientJSON.write("}");
-        }
-    }
-
-    private static class ComponentInfo {
-        Component component;
-        String info;
-
-        public ComponentInfo(Component component, String info) {
-            this.component = component;
-            this.info = info;
-        }
-
-    }
-
-    private static Stack<ComponentInfo> getHeightAttributes(Component component) {
-        Stack<ComponentInfo> attributes = new Stack<ComponentInfo>();
-        attributes
-                .add(new ComponentInfo(component, getHeightString(component)));
-        Component parent = component.getParent();
-        attributes.add(new ComponentInfo(parent, getHeightString(parent)));
-
-        while ((parent = parent.getParent()) != null) {
-            attributes.add(new ComponentInfo(parent, getHeightString(parent)));
-        }
-
-        return attributes;
-    }
-
-    private static Stack<ComponentInfo> getWidthAttributes(Component component) {
-        Stack<ComponentInfo> attributes = new Stack<ComponentInfo>();
-        attributes.add(new ComponentInfo(component, getWidthString(component)));
-        Component parent = component.getParent();
-        attributes.add(new ComponentInfo(parent, getWidthString(parent)));
-
-        while ((parent = parent.getParent()) != null) {
-            attributes.add(new ComponentInfo(parent, getWidthString(parent)));
-        }
-
-        return attributes;
-    }
-
-    private static String getWidthString(Component component) {
-        String width = "width: ";
-        if (hasRelativeWidth(component)) {
-            width += "RELATIVE, " + component.getWidth() + " %";
-        } else if (component instanceof Window && component.getParent() == null) {
-            width += "MAIN WINDOW";
-        } else if (component.getWidth() >= 0) {
-            width += "ABSOLUTE, " + component.getWidth() + " "
-                    + Sizeable.UNIT_SYMBOLS[component.getWidthUnits()];
-        } else {
-            width += "UNDEFINED";
-        }
-
-        return width;
-    }
-
-    private static String getHeightString(Component component) {
-        String height = "height: ";
-        if (hasRelativeHeight(component)) {
-            height += "RELATIVE, " + component.getHeight() + " %";
-        } else if (component instanceof Window && component.getParent() == null) {
-            height += "MAIN WINDOW";
-        } else if (component.getHeight() > 0) {
-            height += "ABSOLUTE, " + component.getHeight() + " "
-                    + Sizeable.UNIT_SYMBOLS[component.getHeightUnits()];
-        } else {
-            height += "UNDEFINED";
-        }
-
-        return height;
-    }
-
-    private static void showComponent(Component component, String attribute,
-            StringBuffer err, StringBuilder indent, boolean widthError) {
-
-        FileLocation createLoc = creationLocations.get(component);
-
-        FileLocation sizeLoc;
-        if (widthError) {
-            sizeLoc = widthLocations.get(component);
-        } else {
-            sizeLoc = heightLocations.get(component);
-        }
-
-        err.append(indent);
-        indent.append("  ");
-        err.append("- ");
-
-        err.append(component.getClass().getSimpleName());
-        err.append("/").append(Integer.toHexString(component.hashCode()));
-
-        if (component.getCaption() != null) {
-            err.append(" \"");
-            err.append(component.getCaption());
-            err.append("\"");
-        }
-
-        if (component.getDebugId() != null) {
-            err.append(" debugId: ");
-            err.append(component.getDebugId());
-        }
-
-        if (createLoc != null) {
-            err.append(", created at (" + createLoc.file + ":"
-                    + createLoc.lineNumber + ")");
-
-        }
-
-        if (attribute != null) {
-            err.append(" (");
-            err.append(attribute);
-            if (sizeLoc != null) {
-                err.append(", set at (" + sizeLoc.file + ":"
-                        + sizeLoc.lineNumber + ")");
-            }
-
-            err.append(")");
-        }
-        err.append("\n");
-
-    }
-
-    private static boolean hasNonRelativeHeightComponent(
-            AbstractOrderedLayout ol) {
-        Iterator it = ol.getComponentIterator();
-        while (it.hasNext()) {
-            if (!hasRelativeHeight((Component) it.next())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    public static boolean parentCannotDefineHeight(Component component) {
-        Component parent = component.getParent();
-        if (parent == null) {
-            // main window, valid situation
-            return false;
-        }
-        if (parent.getHeight() < 0) {
-            if (parent instanceof Window) {
-                Window w = (Window) parent;
-                if (w.getParent() == null) {
-                    // main window is considered to have size
-                    return false;
-                }
-            }
-            if (parent instanceof VerticalLayout) {
-                return true;
-            } else if (parent instanceof AbstractOrderedLayout) {
-                boolean horizontal = true;
-                if (parent instanceof OrderedLayout) {
-                    horizontal = ((OrderedLayout) parent).getOrientation() == OrderedLayout.ORIENTATION_HORIZONTAL;
-                }
-                if (horizontal
-                        && hasNonRelativeHeightComponent((AbstractOrderedLayout) parent)) {
-                    return false;
-                } else {
-                    return true;
-                }
-
-            } else if (parent instanceof GridLayout) {
-                GridLayout gl = (GridLayout) parent;
-                Area componentArea = gl.getComponentArea(component);
-                boolean rowHasHeight = false;
-                for (int row = componentArea.getRow1(); !rowHasHeight
-                        && row <= componentArea.getRow2(); row++) {
-                    for (int column = 0; !rowHasHeight
-                            && column < gl.getColumns(); column++) {
-                        Component c = gl.getComponent(column, row);
-                        if (c != null) {
-                            rowHasHeight = !hasRelativeHeight(c);
-                        }
-                    }
-                }
-                if (!rowHasHeight) {
-                    return true;
-                }
-            }
-
-            if (parent instanceof Panel || parent instanceof SplitPanel
-                    || parent instanceof TabSheet
-                    || parent instanceof CustomComponent) {
-                // height undefined, we know how how component works and no
-                // exceptions
-                // TODO horiz SplitPanel ??
-                return true;
-            } else {
-                // we cannot generally know if undefined component can serve
-                // space for children (like CustomLayout or component built by
-                // third party)
-                return false;
-            }
-
-        } else {
-            if (hasRelativeHeight(parent) && parent.getParent() != null) {
-                return parentCannotDefineHeight(parent);
-            } else {
-                return false;
-            }
-        }
-    }
-
-    private static boolean hasRelativeHeight(Component component) {
-        return (component.getHeightUnits() == Sizeable.UNITS_PERCENTAGE && component
-                .getHeight() > 0);
-    }
-
-    private static boolean hasNonRelativeWidthComponent(AbstractOrderedLayout ol) {
-        Iterator it = ol.getComponentIterator();
-        while (it.hasNext()) {
-            if (!hasRelativeWidth((Component) it.next())) {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private static boolean hasRelativeWidth(Component paintable) {
-        return paintable.getWidth() > 0
-                && paintable.getWidthUnits() == Sizeable.UNITS_PERCENTAGE;
-    }
-
-    public static boolean parentCannotDefineWidth(Component component) {
-        Component parent = component.getParent();
-        if (parent == null) {
-            // main window, valid situation
-            return false;
-        }
-        if (parent instanceof Window) {
-            Window w = (Window) parent;
-            if (w.getParent() == null) {
-                // main window is considered to have size
-                return false;
-            }
-
-        }
-
-        if (parent.getWidth() < 0) {
-            if (parent instanceof Panel) {
-                if (parent.getCaption() != null
-                        && !parent.getCaption().equals("")) {
-                    return false;
-                } else {
-                    return true;
-                }
-            } else if (parent instanceof AbstractOrderedLayout) {
-                AbstractOrderedLayout ol = (AbstractOrderedLayout) parent;
-                boolean horizontal = true;
-                if (ol instanceof OrderedLayout) {
-                    if (((OrderedLayout) ol).getOrientation() == OrderedLayout.ORIENTATION_VERTICAL) {
-                        horizontal = false;
-                    }
-                } else if (ol instanceof VerticalLayout) {
-                    horizontal = false;
-                }
-
-                if (horizontal) {
-                    return true;
-                } else if (!hasNonRelativeWidthComponent(ol)) {
-                    return true;
-                } else {
-                    // valid situation, other components defined width
-                    return false;
-                }
-            } else if (parent instanceof GridLayout) {
-                GridLayout gl = (GridLayout) parent;
-                Area componentArea = gl.getComponentArea(component);
-                boolean columnHasWidth = false;
-                for (int col = componentArea.getColumn1(); !columnHasWidth
-                        && col <= componentArea.getColumn2(); col++) {
-                    for (int row = 0; !columnHasWidth && row < gl.getRows(); row++) {
-                        Component c = gl.getComponent(col, row);
-                        if (c != null) {
-                            columnHasWidth = !hasRelativeWidth(c);
-                        }
-                    }
-                }
-                if (!columnHasWidth) {
-                    return true;
-                } else {
-                    // valid situation
-                    return false;
-                }
-            } else if (parent instanceof SplitPanel
-                    || parent instanceof TabSheet
-                    || parent instanceof CustomComponent) {
-                // TODO vertical splitpanel with another non relative component?
-                return true;
-            } else {
-                return false;
-            }
-        } else {
-            if (hasRelativeWidth(parent) && parent.getParent() != null) {
-                return parentCannotDefineWidth(parent);
-            } else {
-                return false;
-            }
-        }
-
-    }
-
-    private static Map<Object, FileLocation> creationLocations = new HashMap<Object, FileLocation>();
-    private static Map<Object, FileLocation> widthLocations = new HashMap<Object, FileLocation>();
-    private static Map<Object, FileLocation> heightLocations = new HashMap<Object, FileLocation>();
-
-    public static class FileLocation {
-        public String method;
-        public String file;
-        public String className;
-        public String classNameSimple;
-        public int lineNumber;
-
-        public FileLocation(StackTraceElement traceElement) {
-            file = traceElement.getFileName();
-            className = traceElement.getClassName();
-            classNameSimple = className
-                    .substring(className.lastIndexOf('.') + 1);
-            lineNumber = traceElement.getLineNumber();
-            method = traceElement.getMethodName();
-        }
-    }
-
-    public static void setCreationLocation(Object object) {
-        setLocation(creationLocations, object);
-    }
-
-    public static void setWidthLocation(Object object) {
-        setLocation(widthLocations, object);
-    }
-
-    public static void setHeightLocation(Object object) {
-        setLocation(heightLocations, object);
-    }
-
-    private static void setLocation(Map<Object, FileLocation> map, Object object) {
-        StackTraceElement[] traceLines = Thread.currentThread().getStackTrace();
-        for (StackTraceElement traceElement : traceLines) {
-            Class cls;
-            try {
-                String className = traceElement.getClassName();
-                if (className.startsWith("java.")
-                        || className.startsWith("sun.")) {
-                    continue;
-                }
-
-                cls = Class.forName(className);
-                if (cls == DebugUtilities.class || cls == Thread.class) {
-                    continue;
-                }
-
-                if (Component.class.isAssignableFrom(cls)
-                        && !CustomComponent.class.isAssignableFrom(cls)) {
-                    continue;
-                }
-                FileLocation cl = new FileLocation(traceElement);
-                map.put(object, cl);
-                return;
-            } catch (Exception e) {
-                // TODO Auto-generated catch block
-                e.printStackTrace();
-            }
-
-        }
-    }
-
-}
index 94e194d3519b35cd25ca03fc36f54755b4594ab2..0d7f40d5b230ac68e3c88603ad6c40695e22b98b 100644 (file)
@@ -22,7 +22,7 @@ import com.itmill.toolkit.terminal.PaintException;
 import com.itmill.toolkit.terminal.PaintTarget;
 import com.itmill.toolkit.terminal.Resource;
 import com.itmill.toolkit.terminal.Terminal;
-import com.itmill.toolkit.terminal.gwt.server.DebugUtilities;
+import com.itmill.toolkit.terminal.gwt.server.ComponentSizeValidator;
 
 /**
  * An abstract class that defines default implementation for the
@@ -135,6 +135,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource
      * Constructs a new Component.
      */
     public AbstractComponent() {
+        // ComponentSizeValidator.setCreationLocation(this);
     }
 
     /* Get/Set component properties */
@@ -610,14 +611,14 @@ public abstract class AbstractComponent implements Component, MethodEventSource
             // Only paint content of visible components.
             if (isVisible()) {
                 if (getHeight() >= 0
-                        && (getHeightUnits() != UNITS_PERCENTAGE || !DebugUtilities
-                                .parentCannotDefineHeight(this))) {
+                        && (getHeightUnits() != UNITS_PERCENTAGE || ComponentSizeValidator
+                                .parentCanDefineHeight(this))) {
                     target.addAttribute("height", "" + getCSSHeight());
                 }
 
                 if (getWidth() >= 0
-                        && (getWidthUnits() != UNITS_PERCENTAGE || !DebugUtilities
-                                .parentCannotDefineWidth(this))) {
+                        && (getWidthUnits() != UNITS_PERCENTAGE || ComponentSizeValidator
+                                .parentCanDefineWidth(this))) {
                     target.addAttribute("width", "" + getCSSWidth());
                 }
                 if (styles != null && styles.size() > 0) {
@@ -1107,6 +1108,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource
         this.height = height;
         heightUnit = unit;
         requestRepaint();
+        // ComponentSizeValidator.setHeightLocation(this);
     }
 
     /*
@@ -1158,6 +1160,7 @@ public abstract class AbstractComponent implements Component, MethodEventSource
         this.width = width;
         widthUnit = unit;
         requestRepaint();
+        // ComponentSizeValidator.setWidthLocation(this);
     }
 
     /*