1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810 |
- /*
- * Copyright 2000-2014 Vaadin Ltd.
- *
- * Licensed under the Apache License, Version 2.0 (the "License"); you may not
- * use this file except in compliance with the License. You may obtain a copy of
- * the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
- * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
- * License for the specific language governing permissions and limitations under
- * the License.
- */
- package com.vaadin.client;
-
- import java.util.Collection;
- import java.util.HashMap;
- import java.util.HashSet;
- import java.util.Map;
- import java.util.Set;
- import java.util.logging.Level;
- import java.util.logging.Logger;
-
- import com.google.gwt.core.client.Duration;
- import com.google.gwt.core.client.JsArrayString;
- import com.google.gwt.dom.client.Element;
- import com.google.gwt.dom.client.Style;
- import com.google.gwt.dom.client.Style.Overflow;
- import com.google.gwt.user.client.Timer;
- import com.vaadin.client.MeasuredSize.MeasureResult;
- import com.vaadin.client.ui.ManagedLayout;
- import com.vaadin.client.ui.PostLayoutListener;
- import com.vaadin.client.ui.SimpleManagedLayout;
- import com.vaadin.client.ui.VNotification;
- import com.vaadin.client.ui.layout.ElementResizeEvent;
- import com.vaadin.client.ui.layout.ElementResizeListener;
- import com.vaadin.client.ui.layout.LayoutDependencyTree;
-
- public class LayoutManager {
- private static final String STATE_CHANGE_MESSAGE = "Cannot run layout while processing state change from the server.";
-
- private static final String LOOP_ABORT_MESSAGE = "Aborting layout after 100 passes. This would probably be an infinite loop.";
-
- private static final boolean debugLogging = false;
-
- private ApplicationConnection connection;
- private final Set<Element> measuredNonConnectorElements = new HashSet<Element>();
- private final MeasuredSize nullSize = new MeasuredSize();
-
- private LayoutDependencyTree currentDependencyTree;
-
- private FastStringSet needsHorizontalLayout = FastStringSet.create();
- private FastStringSet needsVerticalLayout = FastStringSet.create();
-
- private FastStringSet needsMeasure = FastStringSet.create();
-
- private FastStringSet pendingOverflowFixes = FastStringSet.create();
-
- private final Map<Element, Collection<ElementResizeListener>> elementResizeListeners = new HashMap<Element, Collection<ElementResizeListener>>();
- private final Set<Element> listenersToFire = new HashSet<Element>();
-
- private boolean layoutPending = false;
- private Timer layoutTimer = new Timer() {
- @Override
- public void run() {
- layoutNow();
- }
- };
- private boolean everythingNeedsMeasure = false;
-
- /**
- * Sets the application connection this instance is connected to. Called
- * internally by the framework.
- *
- * @param connection
- * the application connection this instance is connected to
- */
- public void setConnection(ApplicationConnection connection) {
- if (this.connection != null) {
- throw new RuntimeException(
- "LayoutManager connection can never be changed");
- }
- this.connection = connection;
- }
-
- /**
- * Returns the application connection for this layout manager.
- *
- * @return connection
- */
- protected ApplicationConnection getConnection() {
- return connection;
- }
-
- /**
- * Gets the layout manager associated with the given
- * {@link ApplicationConnection}.
- *
- * @param connection
- * the application connection to get a layout manager for
- * @return the layout manager associated with the provided application
- * connection
- */
- public static LayoutManager get(ApplicationConnection connection) {
- return connection.getLayoutManager();
- }
-
- /**
- * Registers that a ManagedLayout is depending on the size of an Element.
- * This causes this layout manager to measure the element in the beginning
- * of every layout phase and call the appropriate layout method of the
- * managed layout if the size of the element has changed.
- *
- * @param owner
- * the ManagedLayout that depends on an element
- * @param element
- * the Element that should be measured
- */
- public void registerDependency(ManagedLayout owner, Element element) {
- MeasuredSize measuredSize = ensureMeasured(element);
- setNeedsLayout(owner);
- measuredSize.addDependent(owner.getConnectorId());
- }
-
- private MeasuredSize ensureMeasured(Element element) {
- MeasuredSize measuredSize = getMeasuredSize(element, null);
- if (measuredSize == null) {
- measuredSize = new MeasuredSize();
-
- if (ConnectorMap.get(connection).getConnector(element) == null) {
- measuredNonConnectorElements.add(element);
- }
- setMeasuredSize(element, measuredSize);
- }
- return measuredSize;
- }
-
- private boolean needsMeasure(Element e) {
- ComponentConnector connector = connection.getConnectorMap()
- .getConnector(e);
- if (connector != null && needsMeasureForManagedLayout(connector)) {
- return true;
- } else if (elementResizeListeners.containsKey(e)) {
- return true;
- } else if (getMeasuredSize(e, nullSize).hasDependents()) {
- return true;
- } else {
- return false;
- }
- }
-
- private boolean needsMeasureForManagedLayout(ComponentConnector connector) {
- if (connector instanceof ManagedLayout) {
- return true;
- } else if (connector.getParent() instanceof ManagedLayout) {
- return true;
- } else {
- return false;
- }
- }
-
- /**
- * Assigns a measured size to an element. Method defined as protected to
- * allow separate implementation for IE8.
- *
- * @param element
- * the dom element to attach the measured size to
- * @param measuredSize
- * the measured size to attach to the element. If
- * <code>null</code>, any previous measured size is removed.
- */
- protected native void setMeasuredSize(Element element,
- MeasuredSize measuredSize)
- /*-{
- if (measuredSize) {
- element.vMeasuredSize = measuredSize;
- } else {
- delete element.vMeasuredSize;
- }
- }-*/;
-
- /**
- * Gets the measured size for an element. Method defined as protected to
- * allow separate implementation for IE8.
- *
- * @param element
- * The element to get measured size for
- * @param defaultSize
- * The size to return if no measured size could be found
- * @return The measured size for the element or {@literal defaultSize}
- */
- protected native MeasuredSize getMeasuredSize(Element element,
- MeasuredSize defaultSize)
- /*-{
- return element.vMeasuredSize || defaultSize;
- }-*/;
-
- private final MeasuredSize getMeasuredSize(Element element) {
- MeasuredSize measuredSize = getMeasuredSize(element, null);
- if (measuredSize == null) {
- measuredSize = new MeasuredSize();
- setMeasuredSize(element, measuredSize);
- }
- return measuredSize;
- }
-
- /**
- * Registers that a ManagedLayout is no longer depending on the size of an
- * Element.
- *
- * @see #registerDependency(ManagedLayout, Element)
- *
- * @param owner
- * the ManagedLayout no longer depends on an element
- * @param element
- * the Element that that no longer needs to be measured
- */
- public void unregisterDependency(ManagedLayout owner, Element element) {
- MeasuredSize measuredSize = getMeasuredSize(element, null);
- if (measuredSize == null) {
- return;
- }
- measuredSize.removeDependent(owner.getConnectorId());
- stopMeasuringIfUnecessary(element);
- }
-
- public boolean isLayoutRunning() {
- return currentDependencyTree != null;
- }
-
- private void countLayout(FastStringMap<Integer> layoutCounts,
- ManagedLayout layout) {
- Integer count = layoutCounts.get(layout.getConnectorId());
- if (count == null) {
- count = Integer.valueOf(0);
- } else {
- count = Integer.valueOf(count.intValue() + 1);
- }
- layoutCounts.put(layout.getConnectorId(), count);
- if (count.intValue() > 2) {
- getLogger().severe(
- Util.getConnectorString(layout) + " has been layouted "
- + count.intValue() + " times");
- }
- }
-
- public void layoutLater() {
- if (!layoutPending) {
- layoutPending = true;
- layoutTimer.schedule(100);
- }
- }
-
- public void layoutNow() {
- if (isLayoutRunning()) {
- throw new IllegalStateException(
- "Can't start a new layout phase before the previous layout phase ends.");
- }
-
- if (connection.getMessageHandler().isUpdatingState()) {
- // If assertions are enabled, throw an exception
- assert false : STATE_CHANGE_MESSAGE;
-
- // Else just log a warning and postpone the layout
- getLogger().warning(STATE_CHANGE_MESSAGE);
-
- // Framework will call layoutNow when the state update is completed
- return;
- }
-
- layoutPending = false;
- layoutTimer.cancel();
- try {
- currentDependencyTree = new LayoutDependencyTree(connection);
- doLayout();
- } finally {
- currentDependencyTree = null;
- }
- }
-
- /**
- * Called once per iteration in the layout loop before size calculations so
- * different browsers quirks can be handled. Mainly this is currently for
- * the IE8 permutation.
- */
- protected void performBrowserLayoutHacks() {
- // Permutations implement this
- }
-
- private void doLayout() {
- getLogger().info("Starting layout phase");
- Profiler.enter("LayoutManager phase init");
-
- FastStringMap<Integer> layoutCounts = FastStringMap.create();
-
- int passes = 0;
- Duration totalDuration = new Duration();
-
- ConnectorMap connectorMap = ConnectorMap.get(connection);
-
- JsArrayString dump = needsHorizontalLayout.dump();
- int dumpLength = dump.length();
- for (int i = 0; i < dumpLength; i++) {
- String layoutId = dump.get(i);
- currentDependencyTree.setNeedsHorizontalLayout(layoutId, true);
- }
-
- dump = needsVerticalLayout.dump();
- dumpLength = dump.length();
- for (int i = 0; i < dumpLength; i++) {
- String layoutId = dump.get(i);
- currentDependencyTree.setNeedsVerticalLayout(layoutId, true);
- }
- needsHorizontalLayout = FastStringSet.create();
- needsVerticalLayout = FastStringSet.create();
-
- dump = needsMeasure.dump();
- dumpLength = dump.length();
- for (int i = 0; i < dumpLength; i++) {
- ServerConnector connector = connectorMap.getConnector(dump.get(i));
- if (connector != null) {
- currentDependencyTree.setNeedsMeasure(
- (ComponentConnector) connector, true);
- }
- }
- needsMeasure = FastStringSet.create();
-
- measureNonConnectors();
-
- Profiler.leave("LayoutManager phase init");
-
- while (true) {
- Profiler.enter("Layout pass");
- passes++;
-
- performBrowserLayoutHacks();
-
- Profiler.enter("Layout measure connectors");
- int measuredConnectorCount = measureConnectors(
- currentDependencyTree, everythingNeedsMeasure);
- Profiler.leave("Layout measure connectors");
-
- everythingNeedsMeasure = false;
- if (measuredConnectorCount == 0) {
- getLogger().info("No more changes in pass " + passes);
- Profiler.leave("Layout pass");
- break;
- }
-
- int firedListeners = 0;
- if (!listenersToFire.isEmpty()) {
- firedListeners = listenersToFire.size();
- Profiler.enter("Layout fire resize events");
- for (Element element : listenersToFire) {
- Collection<ElementResizeListener> listeners = elementResizeListeners
- .get(element);
- if (listeners != null) {
- Profiler.enter("Layout fire resize events - listeners not null");
- Profiler.enter("ElementResizeListener.onElementResize copy list");
- ElementResizeListener[] array = listeners
- .toArray(new ElementResizeListener[listeners
- .size()]);
- Profiler.leave("ElementResizeListener.onElementResize copy list");
- ElementResizeEvent event = new ElementResizeEvent(this,
- element);
- for (ElementResizeListener listener : array) {
- try {
- String key = null;
- if (Profiler.isEnabled()) {
- Profiler.enter("ElementResizeListener.onElementResize construct profiler key");
- key = "ElementResizeListener.onElementResize for "
- + listener.getClass()
- .getSimpleName();
- Profiler.leave("ElementResizeListener.onElementResize construct profiler key");
- Profiler.enter(key);
- }
-
- listener.onElementResize(event);
- if (Profiler.isEnabled()) {
- Profiler.leave(key);
- }
- } catch (RuntimeException e) {
- getLogger().log(Level.SEVERE,
- "Error in resize listener", e);
- }
- }
- Profiler.leave("Layout fire resize events - listeners not null");
- }
- }
- listenersToFire.clear();
-
- Profiler.leave("Layout fire resize events");
- }
-
- Profiler.enter("LayoutManager handle ManagedLayout");
-
- FastStringSet updatedSet = FastStringSet.create();
-
- int layoutCount = 0;
- while (currentDependencyTree.hasHorizontalConnectorToLayout()
- || currentDependencyTree.hasVerticaConnectorToLayout()) {
-
- JsArrayString layoutTargets = currentDependencyTree
- .getHorizontalLayoutTargetsJsArray();
- int length = layoutTargets.length();
- for (int i = 0; i < length; i++) {
- ManagedLayout layout = (ManagedLayout) connectorMap
- .getConnector(layoutTargets.get(i));
- if (layout instanceof DirectionalManagedLayout) {
- currentDependencyTree
- .markAsHorizontallyLayouted(layout);
- DirectionalManagedLayout cl = (DirectionalManagedLayout) layout;
- try {
- String key = null;
- if (Profiler.isEnabled()) {
- key = "layoutHorizontally() for "
- + cl.getClass().getSimpleName();
- Profiler.enter(key);
- }
-
- cl.layoutHorizontally();
- layoutCount++;
-
- if (Profiler.isEnabled()) {
- Profiler.leave(key);
- }
- } catch (RuntimeException e) {
- getLogger().log(Level.SEVERE,
- "Error in ManagedLayout handling", e);
- }
- countLayout(layoutCounts, cl);
- } else {
- currentDependencyTree
- .markAsHorizontallyLayouted(layout);
- currentDependencyTree.markAsVerticallyLayouted(layout);
- SimpleManagedLayout rr = (SimpleManagedLayout) layout;
- try {
- String key = null;
- if (Profiler.isEnabled()) {
- key = "layout() for "
- + rr.getClass().getSimpleName();
- Profiler.enter(key);
- }
-
- rr.layout();
- layoutCount++;
-
- if (Profiler.isEnabled()) {
- Profiler.leave(key);
- }
- } catch (RuntimeException e) {
- getLogger()
- .log(Level.SEVERE,
- "Error in SimpleManagedLayout (horizontal) handling",
- e);
-
- }
- countLayout(layoutCounts, rr);
- }
- if (debugLogging) {
- updatedSet.add(layout.getConnectorId());
- }
- }
-
- layoutTargets = currentDependencyTree
- .getVerticalLayoutTargetsJsArray();
- length = layoutTargets.length();
- for (int i = 0; i < length; i++) {
- ManagedLayout layout = (ManagedLayout) connectorMap
- .getConnector(layoutTargets.get(i));
- if (layout instanceof DirectionalManagedLayout) {
- currentDependencyTree.markAsVerticallyLayouted(layout);
- DirectionalManagedLayout cl = (DirectionalManagedLayout) layout;
- try {
- String key = null;
- if (Profiler.isEnabled()) {
- key = "layoutVertically() for "
- + cl.getClass().getSimpleName();
- Profiler.enter(key);
- }
-
- cl.layoutVertically();
- layoutCount++;
-
- if (Profiler.isEnabled()) {
- Profiler.leave(key);
- }
- } catch (RuntimeException e) {
- getLogger()
- .log(Level.SEVERE,
- "Error in DirectionalManagedLayout handling",
- e);
- }
- countLayout(layoutCounts, cl);
- } else {
- currentDependencyTree
- .markAsHorizontallyLayouted(layout);
- currentDependencyTree.markAsVerticallyLayouted(layout);
- SimpleManagedLayout rr = (SimpleManagedLayout) layout;
- try {
- String key = null;
- if (Profiler.isEnabled()) {
- key = "layout() for "
- + rr.getClass().getSimpleName();
- Profiler.enter(key);
- }
-
- rr.layout();
- layoutCount++;
-
- if (Profiler.isEnabled()) {
- Profiler.leave(key);
- }
- } catch (RuntimeException e) {
- getLogger()
- .log(Level.SEVERE,
- "Error in SimpleManagedLayout (vertical) handling",
- e);
- }
- countLayout(layoutCounts, rr);
- }
- if (debugLogging) {
- updatedSet.add(layout.getConnectorId());
- }
- }
- }
-
- Profiler.leave("LayoutManager handle ManagedLayout");
-
- if (debugLogging) {
- JsArrayString changedCids = updatedSet.dump();
-
- StringBuilder b = new StringBuilder(" ");
- b.append(changedCids.length());
- b.append(" requestLayout invocations ");
- if (changedCids.length() < 30) {
- for (int i = 0; i < changedCids.length(); i++) {
- if (i != 0) {
- b.append(", ");
- } else {
- b.append(": ");
- }
- String connectorString = changedCids.get(i);
- if (changedCids.length() < 10) {
- ServerConnector connector = ConnectorMap.get(
- connection).getConnector(connectorString);
- connectorString = Util
- .getConnectorString(connector);
- }
- b.append(connectorString);
- }
- }
- getLogger().info(b.toString());
- }
-
- Profiler.leave("Layout pass");
-
- getLogger()
- .info("Pass " + passes + " measured "
- + measuredConnectorCount + " elements, fired "
- + firedListeners + " listeners and did "
- + layoutCount + " layouts.");
-
- if (passes > 100) {
- getLogger().severe(LOOP_ABORT_MESSAGE);
- if (ApplicationConfiguration.isDebugMode()) {
- VNotification.createNotification(
- VNotification.DELAY_FOREVER,
- connection.getUIConnector().getWidget())
- .show(LOOP_ABORT_MESSAGE, VNotification.CENTERED,
- "error");
- }
- break;
- }
- }
-
- Profiler.enter("layout PostLayoutListener");
- JsArrayObject<ComponentConnector> componentConnectors = connectorMap
- .getComponentConnectorsAsJsArray();
- int size = componentConnectors.size();
- for (int i = 0; i < size; i++) {
- ComponentConnector connector = componentConnectors.get(i);
- if (connector instanceof PostLayoutListener) {
- String key = null;
- if (Profiler.isEnabled()) {
- key = "layout PostLayoutListener for "
- + connector.getClass().getSimpleName();
- Profiler.enter(key);
- }
-
- ((PostLayoutListener) connector).postLayout();
-
- if (Profiler.isEnabled()) {
- Profiler.leave(key);
- }
- }
- }
- Profiler.leave("layout PostLayoutListener");
-
- cleanMeasuredSizes();
-
- getLogger().info(
- "Total layout phase time: " + totalDuration.elapsedMillis()
- + "ms");
- }
-
- private void logConnectorStatus(int connectorId) {
- currentDependencyTree
- .logDependencyStatus((ComponentConnector) ConnectorMap.get(
- connection).getConnector(Integer.toString(connectorId)));
- }
-
- private int measureConnectors(LayoutDependencyTree layoutDependencyTree,
- boolean measureAll) {
- Profiler.enter("Layout overflow fix handling");
- JsArrayString pendingOverflowConnectorsIds = pendingOverflowFixes
- .dump();
- int pendingOverflowCount = pendingOverflowConnectorsIds.length();
- ConnectorMap connectorMap = ConnectorMap.get(connection);
- if (pendingOverflowCount > 0) {
- HashMap<Element, String> originalOverflows = new HashMap<Element, String>();
-
- FastStringSet delayedOverflowFixes = FastStringSet.create();
-
- // First set overflow to hidden (and save previous value so it can
- // be restored later)
- for (int i = 0; i < pendingOverflowCount; i++) {
- String connectorId = pendingOverflowConnectorsIds.get(i);
- ComponentConnector componentConnector = (ComponentConnector) connectorMap
- .getConnector(connectorId);
-
- if (delayOverflowFix(componentConnector)) {
- delayedOverflowFixes.add(connectorId);
- continue;
- }
-
- if (debugLogging) {
- getLogger()
- .info("Doing overflow fix for "
- + Util.getConnectorString(componentConnector)
- + " in "
- + Util.getConnectorString(componentConnector
- .getParent()));
- }
- Profiler.enter("Overflow fix apply");
-
- Element parentElement = componentConnector.getWidget()
- .getElement().getParentElement();
- Style style = parentElement.getStyle();
- String originalOverflow = style.getOverflow();
-
- if (originalOverflow != null
- && !originalOverflows.containsKey(parentElement)) {
- // Store original value for restore, but only the first time
- // the value is changed
- originalOverflows.put(parentElement, originalOverflow);
- }
-
- style.setOverflow(Overflow.HIDDEN);
- Profiler.leave("Overflow fix apply");
- }
-
- pendingOverflowFixes.removeAll(delayedOverflowFixes);
-
- JsArrayString remainingOverflowFixIds = pendingOverflowFixes.dump();
- int remainingCount = remainingOverflowFixIds.length();
-
- Profiler.enter("Overflow fix reflow");
- // Then ensure all scrolling elements are reflowed by measuring
- for (int i = 0; i < remainingCount; i++) {
- ComponentConnector componentConnector = (ComponentConnector) connectorMap
- .getConnector(remainingOverflowFixIds.get(i));
- componentConnector.getWidget().getElement().getParentElement()
- .getOffsetHeight();
- }
- Profiler.leave("Overflow fix reflow");
-
- Profiler.enter("Overflow fix restore");
- // Finally restore old overflow value and update bookkeeping
- for (int i = 0; i < remainingCount; i++) {
- String connectorId = remainingOverflowFixIds.get(i);
- ComponentConnector componentConnector = (ComponentConnector) connectorMap
- .getConnector(connectorId);
- Element parentElement = componentConnector.getWidget()
- .getElement().getParentElement();
- parentElement.getStyle().setProperty("overflow",
- originalOverflows.get(parentElement));
-
- layoutDependencyTree.setNeedsMeasure(componentConnector, true);
- }
- Profiler.leave("Overflow fix restore");
-
- if (!pendingOverflowFixes.isEmpty()) {
- getLogger().info(
- "Did overflow fix for " + remainingCount + " elements");
- }
- pendingOverflowFixes = delayedOverflowFixes;
- }
- Profiler.leave("Layout overflow fix handling");
-
- int measureCount = 0;
- if (measureAll) {
- Profiler.enter("Layout measureAll");
- JsArrayObject<ComponentConnector> allConnectors = connectorMap
- .getComponentConnectorsAsJsArray();
- int size = allConnectors.size();
-
- // Find connectors that should actually be measured
- JsArrayObject<ComponentConnector> connectors = JsArrayObject
- .createArray().cast();
- for (int i = 0; i < size; i++) {
- ComponentConnector candidate = allConnectors.get(i);
- if (needsMeasure(candidate.getWidget().getElement())) {
- connectors.add(candidate);
- }
- }
-
- int connectorCount = connectors.size();
- for (int i = 0; i < connectorCount; i++) {
- measureConnector(connectors.get(i));
- }
- for (int i = 0; i < connectorCount; i++) {
- layoutDependencyTree.setNeedsMeasure(connectors.get(i), false);
- }
- measureCount += connectorCount;
-
- Profiler.leave("Layout measureAll");
- }
-
- Profiler.enter("Layout measure from tree");
- while (layoutDependencyTree.hasConnectorsToMeasure()) {
- JsArrayString measureTargets = layoutDependencyTree
- .getMeasureTargetsJsArray();
- int length = measureTargets.length();
- for (int i = 0; i < length; i++) {
- ComponentConnector connector = (ComponentConnector) connectorMap
- .getConnector(measureTargets.get(i));
- measureConnector(connector);
- measureCount++;
- }
- for (int i = 0; i < length; i++) {
- ComponentConnector connector = (ComponentConnector) connectorMap
- .getConnector(measureTargets.get(i));
- layoutDependencyTree.setNeedsMeasure(connector, false);
- }
- }
- Profiler.leave("Layout measure from tree");
-
- return measureCount;
- }
-
- /*
- * Delay the overflow fix if the involved connectors might still change
- */
- private boolean delayOverflowFix(ComponentConnector componentConnector) {
- if (!currentDependencyTree.noMoreChangesExpected(componentConnector)) {
- return true;
- }
- ServerConnector parent = componentConnector.getParent();
- if (parent instanceof ComponentConnector
- && !currentDependencyTree
- .noMoreChangesExpected((ComponentConnector) parent)) {
- return true;
- }
-
- return false;
- }
-
- private void measureConnector(ComponentConnector connector) {
- Profiler.enter("LayoutManager.measureConnector");
- Element element = connector.getWidget().getElement();
- MeasuredSize measuredSize = getMeasuredSize(element);
- MeasureResult measureResult = measuredAndUpdate(element, measuredSize);
-
- if (measureResult.isChanged()) {
- onConnectorChange(connector, measureResult.isWidthChanged(),
- measureResult.isHeightChanged());
- }
- Profiler.leave("LayoutManager.measureConnector");
- }
-
- private void onConnectorChange(ComponentConnector connector,
- boolean widthChanged, boolean heightChanged) {
- Profiler.enter("LayoutManager.onConnectorChange");
- Profiler.enter("LayoutManager.onConnectorChange setNeedsOverflowFix");
- setNeedsOverflowFix(connector);
- Profiler.leave("LayoutManager.onConnectorChange setNeedsOverflowFix");
- Profiler.enter("LayoutManager.onConnectorChange heightChanged");
- if (heightChanged) {
- currentDependencyTree.markHeightAsChanged(connector);
- }
- Profiler.leave("LayoutManager.onConnectorChange heightChanged");
- Profiler.enter("LayoutManager.onConnectorChange widthChanged");
- if (widthChanged) {
- currentDependencyTree.markWidthAsChanged(connector);
- }
- Profiler.leave("LayoutManager.onConnectorChange widthChanged");
- Profiler.leave("LayoutManager.onConnectorChange");
- }
-
- private void setNeedsOverflowFix(ComponentConnector connector) {
- // IE9 doesn't need the original fix, but for some reason it needs this
- if (BrowserInfo.get().requiresOverflowAutoFix()
- || BrowserInfo.get().isIE9()) {
- ComponentConnector scrollingBoundary = currentDependencyTree
- .getScrollingBoundary(connector);
- if (scrollingBoundary != null) {
- pendingOverflowFixes.add(scrollingBoundary.getConnectorId());
- }
- }
- }
-
- private void measureNonConnectors() {
- Profiler.enter("LayoutManager.measureNonConenctors");
- for (Element element : measuredNonConnectorElements) {
- measuredAndUpdate(element, getMeasuredSize(element, null));
- }
- Profiler.leave("LayoutManager.measureNonConenctors");
- getLogger().info(
- "Measured " + measuredNonConnectorElements.size()
- + " non connector elements");
- }
-
- private MeasureResult measuredAndUpdate(Element element,
- MeasuredSize measuredSize) {
- MeasureResult measureResult = measuredSize.measure(element);
- if (measureResult.isChanged()) {
- notifyListenersAndDepdendents(element,
- measureResult.isWidthChanged(),
- measureResult.isHeightChanged());
- }
- return measureResult;
- }
-
- private void notifyListenersAndDepdendents(Element element,
- boolean widthChanged, boolean heightChanged) {
- assert widthChanged || heightChanged;
-
- Profiler.enter("LayoutManager.notifyListenersAndDepdendents");
-
- MeasuredSize measuredSize = getMeasuredSize(element, nullSize);
- JsArrayString dependents = measuredSize.getDependents();
- for (int i = 0; i < dependents.length(); i++) {
- String pid = dependents.get(i);
- if (pid != null) {
- if (heightChanged) {
- currentDependencyTree.setNeedsVerticalLayout(pid, true);
- }
- if (widthChanged) {
- currentDependencyTree.setNeedsHorizontalLayout(pid, true);
- }
- }
- }
- if (elementResizeListeners.containsKey(element)) {
- listenersToFire.add(element);
- }
- Profiler.leave("LayoutManager.notifyListenersAndDepdendents");
- }
-
- private static boolean isManagedLayout(ComponentConnector connector) {
- return connector instanceof ManagedLayout;
- }
-
- public void forceLayout() {
- ConnectorMap connectorMap = connection.getConnectorMap();
- JsArrayObject<ComponentConnector> componentConnectors = connectorMap
- .getComponentConnectorsAsJsArray();
- int size = componentConnectors.size();
- for (int i = 0; i < size; i++) {
- ComponentConnector connector = componentConnectors.get(i);
- if (connector instanceof ManagedLayout) {
- setNeedsLayout((ManagedLayout) connector);
- }
- }
- setEverythingNeedsMeasure();
- layoutNow();
- }
-
- /**
- * Marks that a ManagedLayout should be layouted in the next layout phase
- * even if none of the elements managed by the layout have been resized.
- * <p>
- * This method should not be invoked during a layout phase since it only
- * controls what will happen in the beginning of the next phase. If you want
- * to explicitly cause some layout to be considered in an ongoing layout
- * phase, you should use {@link #setNeedsMeasure(ComponentConnector)}
- * instead.
- *
- * @param layout
- * the managed layout that should be layouted
- */
- public final void setNeedsLayout(ManagedLayout layout) {
- setNeedsHorizontalLayout(layout);
- setNeedsVerticalLayout(layout);
- }
-
- /**
- * Marks that a ManagedLayout should be layouted horizontally in the next
- * layout phase even if none of the elements managed by the layout have been
- * resized horizontally.
- * <p>
- * For SimpleManagedLayout which is always layouted in both directions, this
- * has the same effect as {@link #setNeedsLayout(ManagedLayout)}.
- * <p>
- * This method should not be invoked during a layout phase since it only
- * controls what will happen in the beginning of the next phase. If you want
- * to explicitly cause some layout to be considered in an ongoing layout
- * phase, you should use {@link #setNeedsMeasure(ComponentConnector)}
- * instead.
- *
- * @param layout
- * the managed layout that should be layouted
- */
- public final void setNeedsHorizontalLayout(ManagedLayout layout) {
- if (isLayoutRunning()) {
- getLogger()
- .warning(
- "setNeedsHorizontalLayout should not be run while a layout phase is in progress.");
- }
- needsHorizontalLayout.add(layout.getConnectorId());
- }
-
- /**
- * Marks that a ManagedLayout should be layouted vertically in the next
- * layout phase even if none of the elements managed by the layout have been
- * resized vertically.
- * <p>
- * For SimpleManagedLayout which is always layouted in both directions, this
- * has the same effect as {@link #setNeedsLayout(ManagedLayout)}.
- * <p>
- * This method should not be invoked during a layout phase since it only
- * controls what will happen in the beginning of the next phase. If you want
- * to explicitly cause some layout to be considered in an ongoing layout
- * phase, you should use {@link #setNeedsMeasure(ComponentConnector)}
- * instead.
- *
- * @param layout
- * the managed layout that should be layouted
- */
- public final void setNeedsVerticalLayout(ManagedLayout layout) {
- if (isLayoutRunning()) {
- getLogger()
- .warning(
- "setNeedsVerticalLayout should not be run while a layout phase is in progress.");
- }
- needsVerticalLayout.add(layout.getConnectorId());
- }
-
- /**
- * Gets the outer height (including margins, paddings and borders) of the
- * given element, provided that it has been measured. These elements are
- * guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * -1 is returned if the element has not been measured. If 0 is returned, it
- * might indicate that the element is not attached to the DOM.
- * <p>
- * The value returned by this method is always rounded up. To get the exact
- * outer width, use {@link #getOuterHeightDouble(Element)}
- *
- * @param element
- * the element to get the measured size for
- * @return the measured outer height (including margins, paddings and
- * borders) of the element in pixels.
- */
- public final int getOuterHeight(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return (int) Math.ceil(getMeasuredSize(element, nullSize)
- .getOuterHeight());
- }
-
- /**
- * Gets the outer height (including margins, paddings and borders) of the
- * given element, provided that it has been measured. These elements are
- * guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * -1 is returned if the element has not been measured. If 0 is returned, it
- * might indicate that the element is not attached to the DOM.
- *
- * @param element
- * the element to get the measured size for
- * @return the measured outer height (including margins, paddings and
- * borders) of the element in pixels.
- */
- public final double getOuterHeightDouble(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return getMeasuredSize(element, nullSize).getOuterHeight();
- }
-
- /**
- * Gets the outer width (including margins, paddings and borders) of the
- * given element, provided that it has been measured. These elements are
- * guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * -1 is returned if the element has not been measured. If 0 is returned, it
- * might indicate that the element is not attached to the DOM.
- * <p>
- * The value returned by this method is always rounded up. To get the exact
- * outer width, use {@link #getOuterWidthDouble(Element)}
- *
- * @param element
- * the element to get the measured size for
- * @return the measured outer width (including margins, paddings and
- * borders) of the element in pixels.
- */
- public final int getOuterWidth(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return (int) Math.ceil(getMeasuredSize(element, nullSize)
- .getOuterWidth());
- }
-
- /**
- * Gets the outer width (including margins, paddings and borders) of the
- * given element, provided that it has been measured. These elements are
- * guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * -1 is returned if the element has not been measured. If 0 is returned, it
- * might indicate that the element is not attached to the DOM.
- *
- * @param element
- * the element to get the measured size for
- * @return the measured outer width (including margins, paddings and
- * borders) of the element in pixels.
- */
- public final double getOuterWidthDouble(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return getMeasuredSize(element, nullSize).getOuterWidth();
- }
-
- /**
- * Gets the inner height (excluding margins, paddings and borders) of the
- * given element, provided that it has been measured. These elements are
- * guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * -1 is returned if the element has not been measured. If 0 is returned, it
- * might indicate that the element is not attached to the DOM.
- * <p>
- * The value returned by this method is always rounded up. To get the exact
- * outer width, use {@link #getInnerHeightDouble(Element)}
- *
- * @param element
- * the element to get the measured size for
- * @return the measured inner height (excluding margins, paddings and
- * borders) of the element in pixels.
- */
- public final int getInnerHeight(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return (int) Math.ceil(getMeasuredSize(element, nullSize)
- .getInnerHeight());
- }
-
- /**
- * Gets the inner height (excluding margins, paddings and borders) of the
- * given element, provided that it has been measured. These elements are
- * guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * -1 is returned if the element has not been measured. If 0 is returned, it
- * might indicate that the element is not attached to the DOM.
- *
- * @param element
- * the element to get the measured size for
- * @return the measured inner height (excluding margins, paddings and
- * borders) of the element in pixels.
- */
- public final double getInnerHeightDouble(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return getMeasuredSize(element, nullSize).getInnerHeight();
- }
-
- /**
- * Gets the inner width (excluding margins, paddings and borders) of the
- * given element, provided that it has been measured. These elements are
- * guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * -1 is returned if the element has not been measured. If 0 is returned, it
- * might indicate that the element is not attached to the DOM.
- * <p>
- * The value returned by this method is always rounded up. To get the exact
- * outer width, use {@link #getOuterHeightDouble(Element)}
- *
- * @param element
- * the element to get the measured size for
- * @return the measured inner width (excluding margins, paddings and
- * borders) of the element in pixels.
- */
- public final int getInnerWidth(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return (int) Math.ceil(getMeasuredSize(element, nullSize)
- .getInnerWidth());
- }
-
- /**
- * Gets the inner width (excluding margins, paddings and borders) of the
- * given element, provided that it has been measured. These elements are
- * guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * -1 is returned if the element has not been measured. If 0 is returned, it
- * might indicate that the element is not attached to the DOM.
- *
- * @param element
- * the element to get the measured size for
- * @return the measured inner width (excluding margins, paddings and
- * borders) of the element in pixels.
- */
- public final double getInnerWidthDouble(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return getMeasuredSize(element, nullSize).getInnerWidth();
- }
-
- /**
- * Gets the border height (top border + bottom border) of the given element,
- * provided that it has been measured. These elements are guaranteed to be
- * measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * A negative number is returned if the element has not been measured. If 0
- * is returned, it might indicate that the element is not attached to the
- * DOM.
- *
- * @param element
- * the element to get the measured size for
- * @return the measured border height (top border + bottom border) of the
- * element in pixels.
- */
- public final int getBorderHeight(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return getMeasuredSize(element, nullSize).getBorderHeight();
- }
-
- /**
- * Gets the padding height (top padding + bottom padding) of the given
- * element, provided that it has been measured. These elements are
- * guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * A negative number is returned if the element has not been measured. If 0
- * is returned, it might indicate that the element is not attached to the
- * DOM.
- *
- * @param element
- * the element to get the measured size for
- * @return the measured padding height (top padding + bottom padding) of the
- * element in pixels.
- */
- public int getPaddingHeight(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return getMeasuredSize(element, nullSize).getPaddingHeight();
- }
-
- /**
- * Gets the border width (left border + right border) of the given element,
- * provided that it has been measured. These elements are guaranteed to be
- * measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * A negative number is returned if the element has not been measured. If 0
- * is returned, it might indicate that the element is not attached to the
- * DOM.
- *
- * @param element
- * the element to get the measured size for
- * @return the measured border width (left border + right border) of the
- * element in pixels.
- */
- public int getBorderWidth(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return getMeasuredSize(element, nullSize).getBorderWidth();
- }
-
- /**
- * Gets the top border of the given element, provided that it has been
- * measured. These elements are guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * A negative number is returned if the element has not been measured. If 0
- * is returned, it might indicate that the element is not attached to the
- * DOM.
- *
- * @param element
- * the element to get the measured size for
- * @return the measured top border of the element in pixels.
- */
- public int getBorderTop(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return getMeasuredSize(element, nullSize).getBorderTop();
- }
-
- /**
- * Gets the left border of the given element, provided that it has been
- * measured. These elements are guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * A negative number is returned if the element has not been measured. If 0
- * is returned, it might indicate that the element is not attached to the
- * DOM.
- *
- * @param element
- * the element to get the measured size for
- * @return the measured left border of the element in pixels.
- */
- public int getBorderLeft(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return getMeasuredSize(element, nullSize).getBorderLeft();
- }
-
- /**
- * Gets the bottom border of the given element, provided that it has been
- * measured. These elements are guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * A negative number is returned if the element has not been measured. If 0
- * is returned, it might indicate that the element is not attached to the
- * DOM.
- *
- * @param element
- * the element to get the measured size for
- * @return the measured bottom border of the element in pixels.
- */
- public int getBorderBottom(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return getMeasuredSize(element, nullSize).getBorderBottom();
- }
-
- /**
- * Gets the right border of the given element, provided that it has been
- * measured. These elements are guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * A negative number is returned if the element has not been measured. If 0
- * is returned, it might indicate that the element is not attached to the
- * DOM.
- *
- * @param element
- * the element to get the measured size for
- * @return the measured right border of the element in pixels.
- */
- public int getBorderRight(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return getMeasuredSize(element, nullSize).getBorderRight();
- }
-
- /**
- * Gets the padding width (left padding + right padding) of the given
- * element, provided that it has been measured. These elements are
- * guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * A negative number is returned if the element has not been measured. If 0
- * is returned, it might indicate that the element is not attached to the
- * DOM.
- *
- * @param element
- * the element to get the measured size for
- * @return the measured padding width (left padding + right padding) of the
- * element in pixels.
- */
- public int getPaddingWidth(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return getMeasuredSize(element, nullSize).getPaddingWidth();
- }
-
- /**
- * Gets the top padding of the given element, provided that it has been
- * measured. These elements are guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * A negative number is returned if the element has not been measured. If 0
- * is returned, it might indicate that the element is not attached to the
- * DOM.
- *
- * @param element
- * the element to get the measured size for
- * @return the measured top padding of the element in pixels.
- */
- public int getPaddingTop(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return getMeasuredSize(element, nullSize).getPaddingTop();
- }
-
- /**
- * Gets the left padding of the given element, provided that it has been
- * measured. These elements are guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * A negative number is returned if the element has not been measured. If 0
- * is returned, it might indicate that the element is not attached to the
- * DOM.
- *
- * @param element
- * the element to get the measured size for
- * @return the measured left padding of the element in pixels.
- */
- public int getPaddingLeft(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return getMeasuredSize(element, nullSize).getPaddingLeft();
- }
-
- /**
- * Gets the bottom padding of the given element, provided that it has been
- * measured. These elements are guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * A negative number is returned if the element has not been measured. If 0
- * is returned, it might indicate that the element is not attached to the
- * DOM.
- *
- * @param element
- * the element to get the measured size for
- * @return the measured bottom padding of the element in pixels.
- */
- public int getPaddingBottom(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return getMeasuredSize(element, nullSize).getPaddingBottom();
- }
-
- /**
- * Gets the right padding of the given element, provided that it has been
- * measured. These elements are guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * A negative number is returned if the element has not been measured. If 0
- * is returned, it might indicate that the element is not attached to the
- * DOM.
- *
- * @param element
- * the element to get the measured size for
- * @return the measured right padding of the element in pixels.
- */
- public int getPaddingRight(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return getMeasuredSize(element, nullSize).getPaddingRight();
- }
-
- /**
- * Gets the top margin of the given element, provided that it has been
- * measured. These elements are guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * A negative number is returned if the element has not been measured. If 0
- * is returned, it might indicate that the element is not attached to the
- * DOM.
- *
- * @param element
- * the element to get the measured size for
- * @return the measured top margin of the element in pixels.
- */
- public int getMarginTop(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return getMeasuredSize(element, nullSize).getMarginTop();
- }
-
- /**
- * Gets the right margin of the given element, provided that it has been
- * measured. These elements are guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * A negative number is returned if the element has not been measured. If 0
- * is returned, it might indicate that the element is not attached to the
- * DOM.
- *
- * @param element
- * the element to get the measured size for
- * @return the measured right margin of the element in pixels.
- */
- public int getMarginRight(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return getMeasuredSize(element, nullSize).getMarginRight();
- }
-
- /**
- * Gets the bottom margin of the given element, provided that it has been
- * measured. These elements are guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * A negative number is returned if the element has not been measured. If 0
- * is returned, it might indicate that the element is not attached to the
- * DOM.
- *
- * @param element
- * the element to get the measured size for
- * @return the measured bottom margin of the element in pixels.
- */
- public int getMarginBottom(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return getMeasuredSize(element, nullSize).getMarginBottom();
- }
-
- /**
- * Gets the left margin of the given element, provided that it has been
- * measured. These elements are guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * A negative number is returned if the element has not been measured. If 0
- * is returned, it might indicate that the element is not attached to the
- * DOM.
- *
- * @param element
- * the element to get the measured size for
- * @return the measured left margin of the element in pixels.
- */
- public int getMarginLeft(Element element) {
- assert needsMeasure(element) : "Getting measurement for element that is not measured";
- return getMeasuredSize(element, nullSize).getMarginLeft();
- }
-
- /**
- * Gets the combined top & bottom margin of the given element, provided that
- * they have been measured. These elements are guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * A negative number is returned if the element has not been measured. If 0
- * is returned, it might indicate that the element is not attached to the
- * DOM.
- *
- * @param element
- * the element to get the measured margin for
- * @return the measured top+bottom margin of the element in pixels.
- */
- public int getMarginHeight(Element element) {
- return getMarginTop(element) + getMarginBottom(element);
- }
-
- /**
- * Gets the combined left & right margin of the given element, provided that
- * they have been measured. These elements are guaranteed to be measured:
- * <ul>
- * <li>ManagedLayouts and their child Connectors
- * <li>Elements for which there is at least one ElementResizeListener
- * <li>Elements for which at least one ManagedLayout has registered a
- * dependency
- * </ul>
- *
- * A negative number is returned if the element has not been measured. If 0
- * is returned, it might indicate that the element is not attached to the
- * DOM.
- *
- * @param element
- * the element to get the measured margin for
- * @return the measured left+right margin of the element in pixels.
- */
- public int getMarginWidth(Element element) {
- return getMarginLeft(element) + getMarginRight(element);
- }
-
- /**
- * Registers the outer height (including margins, borders and paddings) of a
- * component. This can be used as an optimization by ManagedLayouts; by
- * informing the LayoutManager about what size a component will have, the
- * layout propagation can continue directly without first measuring the
- * potentially resized elements.
- *
- * @param component
- * the component for which the size is reported
- * @param outerHeight
- * the new outer height (including margins, borders and paddings)
- * of the component in pixels
- */
- public void reportOuterHeight(ComponentConnector component, int outerHeight) {
- Element element = component.getWidget().getElement();
- MeasuredSize measuredSize = getMeasuredSize(element);
- if (isLayoutRunning()) {
- boolean heightChanged = measuredSize.setOuterHeight(outerHeight);
-
- if (heightChanged) {
- onConnectorChange(component, false, true);
- notifyListenersAndDepdendents(element, false, true);
- }
- currentDependencyTree.setNeedsVerticalMeasure(component, false);
- } else if (measuredSize.getOuterHeight() != outerHeight) {
- setNeedsMeasure(component);
- }
- }
-
- /**
- * Registers the height reserved for a relatively sized component. This can
- * be used as an optimization by ManagedLayouts; by informing the
- * LayoutManager about what size a component will have, the layout
- * propagation can continue directly without first measuring the potentially
- * resized elements.
- *
- * @param component
- * the relatively sized component for which the size is reported
- * @param assignedHeight
- * the inner height of the relatively sized component's parent
- * element in pixels
- */
- public void reportHeightAssignedToRelative(ComponentConnector component,
- int assignedHeight) {
- assert component.isRelativeHeight();
-
- float percentSize = parsePercent(component.getState().height == null ? ""
- : component.getState().height);
- int effectiveHeight = Math.round(assignedHeight * (percentSize / 100));
-
- reportOuterHeight(component, effectiveHeight);
- }
-
- /**
- * Registers the width reserved for a relatively sized component. This can
- * be used as an optimization by ManagedLayouts; by informing the
- * LayoutManager about what size a component will have, the layout
- * propagation can continue directly without first measuring the potentially
- * resized elements.
- *
- * @param component
- * the relatively sized component for which the size is reported
- * @param assignedWidth
- * the inner width of the relatively sized component's parent
- * element in pixels
- */
- public void reportWidthAssignedToRelative(ComponentConnector component,
- int assignedWidth) {
- assert component.isRelativeWidth();
-
- float percentSize = parsePercent(component.getState().width == null ? ""
- : component.getState().width);
- int effectiveWidth = Math.round(assignedWidth * (percentSize / 100));
-
- reportOuterWidth(component, effectiveWidth);
- }
-
- private static float parsePercent(String size) {
- return Float.parseFloat(size.substring(0, size.length() - 1));
- }
-
- /**
- * Registers the outer width (including margins, borders and paddings) of a
- * component. This can be used as an optimization by ManagedLayouts; by
- * informing the LayoutManager about what size a component will have, the
- * layout propagation can continue directly without first measuring the
- * potentially resized elements.
- *
- * @param component
- * the component for which the size is reported
- * @param outerWidth
- * the new outer width (including margins, borders and paddings)
- * of the component in pixels
- */
- public void reportOuterWidth(ComponentConnector component, int outerWidth) {
- Element element = component.getWidget().getElement();
- MeasuredSize measuredSize = getMeasuredSize(element);
- if (isLayoutRunning()) {
- boolean widthChanged = measuredSize.setOuterWidth(outerWidth);
-
- if (widthChanged) {
- onConnectorChange(component, true, false);
- notifyListenersAndDepdendents(element, true, false);
- }
- currentDependencyTree.setNeedsHorizontalMeasure(component, false);
- } else if (measuredSize.getOuterWidth() != outerWidth) {
- setNeedsMeasure(component);
- }
- }
-
- /**
- * Adds a listener that will be notified whenever the size of a specific
- * element changes. Adding a listener to an element also ensures that all
- * sizes for that element will be available starting from the next layout
- * phase.
- *
- * @param element
- * the element that should be checked for size changes
- * @param listener
- * an ElementResizeListener that will be informed whenever the
- * size of the target element has changed
- */
- public void addElementResizeListener(Element element,
- ElementResizeListener listener) {
- Collection<ElementResizeListener> listeners = elementResizeListeners
- .get(element);
- if (listeners == null) {
- listeners = new HashSet<ElementResizeListener>();
- elementResizeListeners.put(element, listeners);
- ensureMeasured(element);
- }
- listeners.add(listener);
- }
-
- /**
- * Removes an element resize listener from the provided element. This might
- * cause this LayoutManager to stop tracking the size of the element if no
- * other sources are interested in the size.
- *
- * @param element
- * the element to which the element resize listener was
- * previously added
- * @param listener
- * the ElementResizeListener that should no longer get informed
- * about size changes to the target element.
- */
- public void removeElementResizeListener(Element element,
- ElementResizeListener listener) {
- Collection<ElementResizeListener> listeners = elementResizeListeners
- .get(element);
- if (listeners != null) {
- listeners.remove(listener);
- if (listeners.isEmpty()) {
- elementResizeListeners.remove(element);
- stopMeasuringIfUnecessary(element);
- }
- }
- }
-
- private void stopMeasuringIfUnecessary(Element element) {
- if (!needsMeasure(element)) {
- measuredNonConnectorElements.remove(element);
- setMeasuredSize(element, null);
- }
- }
-
- /**
- * Informs this LayoutManager that the size of a component might have
- * changed. This method should be used whenever the size of an individual
- * component might have changed from outside of Vaadin's normal update
- * phase, e.g. when an icon has been loaded or when the user resizes some
- * part of the UI using the mouse.
- * <p>
- * To set an entire component hierarchy to be measured, use
- * {@link #setNeedsMeasureRecursively(ComponentConnector)} instead.
- * <p>
- * If there is no upcoming layout phase, a new layout phase is scheduled.
- *
- * @param component
- * the component whose size might have changed.
- */
- public void setNeedsMeasure(ComponentConnector component) {
- if (isLayoutRunning()) {
- currentDependencyTree.setNeedsMeasure(component, true);
- } else {
- needsMeasure.add(component.getConnectorId());
- layoutLater();
- }
- }
-
- /**
- * Informs this LayoutManager that some sizes in a component hierarchy might
- * have changed. This method should be used whenever the size of any child
- * component might have changed from outside of Vaadin's normal update
- * phase, e.g. when a CSS class name related to sizing has been changed.
- * <p>
- * To set a single component to be measured, use
- * {@link #setNeedsMeasure(ComponentConnector)} instead.
- * <p>
- * If there is no upcoming layout phase, a new layout phase is scheduled.
- *
- * @since 7.2
- * @param component
- * the component at the root of the component hierarchy to
- * measure
- */
- public void setNeedsMeasureRecursively(ComponentConnector component) {
- setNeedsMeasure(component);
-
- if (component instanceof HasComponentsConnector) {
- HasComponentsConnector hasComponents = (HasComponentsConnector) component;
- for (ComponentConnector child : hasComponents.getChildComponents()) {
- setNeedsMeasureRecursively(child);
- }
- }
- }
-
- public void setEverythingNeedsMeasure() {
- everythingNeedsMeasure = true;
- }
-
- /**
- * Clean measured sizes which are no longer needed. Only for IE8.
- */
- public void cleanMeasuredSizes() {
- }
-
- private static Logger getLogger() {
- return Logger.getLogger(LayoutManager.class.getName());
- }
-
- }
|