From: Artur Signell Date: Thu, 18 Dec 2008 10:05:37 +0000 (+0000) Subject: Refactored layout size checking method, related to #2139 X-Git-Tag: 6.7.0.beta1~3516 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=3058750c7652c229d0beeaf562bc9d4658b62c33;p=vaadin-framework.git Refactored layout size checking method, related to #2139 svn changeset:6264/svn branch:trunk --- diff --git a/src/com/itmill/toolkit/terminal/gwt/server/CommunicationManager.java b/src/com/itmill/toolkit/terminal/gwt/server/CommunicationManager.java index acdc8665d1..270ea42cc7 100644 --- a/src/com/itmill/toolkit/terminal/gwt/server/CommunicationManager.java +++ b/src/com/itmill/toolkit/terminal/gwt/server/CommunicationManager.java @@ -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 index 0000000000..cca56e3034 --- /dev/null +++ b/src/com/itmill/toolkit/terminal/gwt/server/ComponentSizeValidator.java @@ -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 validateComponentRelativeSizes( + Component component, List 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(); + } + 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 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 subErrors = new Vector(); + + 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 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 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 getHeightAttributes(Component component) { + Stack attributes = new Stack(); + 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 getWidthAttributes(Component component) { + Stack attributes = new Stack(); + 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 creationLocations = new HashMap(); + private static Map widthLocations = new HashMap(); + private static Map heightLocations = new HashMap(); + + 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 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 index 01c0c94f74..0000000000 --- a/src/com/itmill/toolkit/terminal/gwt/server/DebugUtilities.java +++ /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 validateComponentRelativeSizes( - Component component, List 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(); - } - 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 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 subErrors = new Vector(); - - 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 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 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 getHeightAttributes(Component component) { - Stack attributes = new Stack(); - 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 getWidthAttributes(Component component) { - Stack attributes = new Stack(); - 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 creationLocations = new HashMap(); - private static Map widthLocations = new HashMap(); - private static Map heightLocations = new HashMap(); - - 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 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(); - } - - } - } - -} diff --git a/src/com/itmill/toolkit/ui/AbstractComponent.java b/src/com/itmill/toolkit/ui/AbstractComponent.java index 94e194d351..0d7f40d5b2 100644 --- a/src/com/itmill/toolkit/ui/AbstractComponent.java +++ b/src/com/itmill/toolkit/ui/AbstractComponent.java @@ -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); } /*