summaryrefslogtreecommitdiffstats
path: root/server/src/com/vaadin/ui
diff options
context:
space:
mode:
authorArtur Signell <artur@vaadin.com>2013-04-04 19:56:15 +0300
committerVaadin Code Review <review@vaadin.com>2013-04-05 07:10:48 +0000
commit874c76e4a51f07067a2351fe54d9cfa03f70e968 (patch)
treee8fd662ca26181e367a3dd6d26fcca5bcee8ea82 /server/src/com/vaadin/ui
parent8466d23c5e3d6ca16c27262bf83869e4e4a79ec6 (diff)
downloadvaadin-framework-874c76e4a51f07067a2351fe54d9cfa03f70e968.tar.gz
vaadin-framework-874c76e4a51f07067a2351fe54d9cfa03f70e968.zip
Do not push only meta data to the client (#11490)
Change-Id: I589ede89583be90e99fbed6fe5c0c6c1ac4d7c0a
Diffstat (limited to 'server/src/com/vaadin/ui')
-rw-r--r--server/src/com/vaadin/ui/ConnectorTracker.java11
-rw-r--r--server/src/com/vaadin/ui/UI.java5
2 files changed, 15 insertions, 1 deletions
diff --git a/server/src/com/vaadin/ui/ConnectorTracker.java b/server/src/com/vaadin/ui/ConnectorTracker.java
index bd66f3b368..85cdcdf65c 100644
--- a/server/src/com/vaadin/ui/ConnectorTracker.java
+++ b/server/src/com/vaadin/ui/ConnectorTracker.java
@@ -32,9 +32,9 @@ import org.json.JSONException;
import org.json.JSONObject;
import com.vaadin.server.AbstractClientConnector;
-import com.vaadin.server.LegacyCommunicationManager;
import com.vaadin.server.ClientConnector;
import com.vaadin.server.GlobalResourceHandler;
+import com.vaadin.server.LegacyCommunicationManager;
import com.vaadin.server.StreamVariable;
/**
@@ -465,6 +465,15 @@ public class ConnectorTracker implements Serializable {
}
/**
+ * Checks if there a dirty connectors.
+ *
+ * @return true if there are dirty connectors, false otherwise
+ */
+ public boolean hasDirtyConnectors() {
+ return !getDirtyConnectors().isEmpty();
+ }
+
+ /**
* Returns a collection of those {@link #getDirtyConnectors() dirty
* connectors} that are actually visible to the client.
*
diff --git a/server/src/com/vaadin/ui/UI.java b/server/src/com/vaadin/ui/UI.java
index 162d072222..6b906b8eab 100644
--- a/server/src/com/vaadin/ui/UI.java
+++ b/server/src/com/vaadin/ui/UI.java
@@ -1141,6 +1141,11 @@ public abstract class UI extends AbstractSingleComponentContainer implements
public void push() {
VaadinSession session = getSession();
if (session != null) {
+ if (getConnectorTracker().hasDirtyConnectors()) {
+ // Do not push if there is nothing to push
+ return;
+ }
+
if (session.getPushMode() == PushMode.DISABLED) {
throw new IllegalStateException("Push not enabled");
}
ref='#n256'>256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391
/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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.
 */

/* $Id$ */

package org.apache.fop.fo;

import java.util.List;
import java.util.Stack;
import org.apache.fop.fo.flow.Block;
import org.apache.fop.util.CharUtilities;

/**
 * Class encapsulating the functionality for white-space-handling
 * during refinement stage.
 * The <code>handleWhiteSpace()</code> methods are called during 
 * FOTree-building and marker-cloning:
 * <br>
 * <ul>
 * <li> from <code>FObjMixed.addChildNode()</code></li>
 * <li> from <code>FObjMixed.endOfNode()</code></li>
 * <li> from <code>FObjMixed.handleWhiteSpaceFor()</code></li>
 * </ul>
 * <br>
 * Each time one of the variants is called, white-space is handled
 * for all <code>FOText</code> or <code>Character</code> nodes that
 * were added:
 * <br>
 * <ul>
 * <li> either prior to <code>newChild</code> (and after the previous
 *      non-text child node)</li>
 * <li> or, if <code>newChild</code> is <code>null</code>,
 *      after the previous non-text child</li>
 * </ul>
 * <br>
 * The iteration always starts at <code>firstTextNode</code>, 
 * goes on until the last text-node is reached, and deals only 
 * with <code>FOText</code> or <code>Character</code> nodes.
 * <br>
 * <em>Note</em>: if the method is called from an inline's endOfNode(),
 *   there is too little context to decide whether trailing
 *   white-space may be removed, so the pending inline is stored
 *   in a List, together with an iterator for which the next()
 *   method returns the first in the trailing sequence of white-
 *   space characters. This List is processed again at the end
 *   of the ancestor block.
 */
public class XMLWhiteSpaceHandler {
    
    /** True if we are in a run of white space */
    private boolean inWhiteSpace = false;
    /** True if the last char was a linefeed */
    private boolean afterLinefeed = true;
    /** Counter, increased every time a non-white-space is encountered */
    private int nonWhiteSpaceCount;
    
    private Block currentBlock;
    private FObj currentFO;
    private int linefeedTreatment;
    private int whiteSpaceTreatment;
    private int whiteSpaceCollapse;
    private FONode nextChild;
    private boolean endOfBlock;
    private boolean nextChildIsBlockLevel;
    private RecursiveCharIterator charIter;
    
    private List pendingInlines;
    private Stack nestedBlockStack = new java.util.Stack();
    private CharIterator firstWhiteSpaceInSeq;
    
    /**
     * Handle white-space for the fo that is passed in, starting at
     * firstTextNode
     * @param fo    the FO for which to handle white-space
     * @param firstTextNode the node at which to start
     */
    public void handleWhiteSpace(FObjMixed fo, FONode firstTextNode) {
        
        int foId = fo.getNameId();
        
        if (foId == Constants.FO_BLOCK) {
            if (nextChild != null && currentBlock != null) {
                /* if already in a block, push the current block 
                 * onto the stack of nested blocks
                 */
                nestedBlockStack.push(currentBlock);
            }
            currentBlock = (Block) fo;
        } else if (foId == Constants.FO_RETRIEVE_MARKER) {
            /* look for the nearest block ancestor, if any */
            FONode ancestor = fo;
            do {
                ancestor = ancestor.getParent();
            } while (ancestor.getNameId() != Constants.FO_BLOCK
                    && ancestor.getNameId() != Constants.FO_STATIC_CONTENT);
            
            if (ancestor.getNameId() == Constants.FO_BLOCK) {
                currentBlock = (Block) ancestor;
            }
        }
        
        if (currentBlock != null) {
            linefeedTreatment = currentBlock.getLinefeedTreatment();
            whiteSpaceCollapse = currentBlock.getWhitespaceCollapse();
            whiteSpaceTreatment = currentBlock.getWhitespaceTreatment();
        } else {
            linefeedTreatment = Constants.EN_TREAT_AS_SPACE;
            whiteSpaceCollapse = Constants.EN_TRUE;
            whiteSpaceTreatment = Constants.EN_IGNORE_IF_SURROUNDING_LINEFEED;
        }
        
        currentFO = fo;

        if (firstTextNode == null) {
            //nothing to do but initialize related properties
            return;
        }
        
        charIter = new RecursiveCharIterator(fo, firstTextNode);
        inWhiteSpace = false;
        
        if (currentFO == currentBlock
                || currentBlock == null
                || (foId == Constants.FO_RETRIEVE_MARKER
                        && currentFO.getParent() == currentBlock)) {
            afterLinefeed = (
                    (firstTextNode == fo.firstChild)
                        || (firstTextNode.siblings[0].getNameId()
                                == Constants.FO_BLOCK));
        }
        
        endOfBlock = (nextChild == null && currentFO == currentBlock);
        
        if (nextChild != null) {
            int nextChildId = this.nextChild.getNameId();
            nextChildIsBlockLevel = (
                    nextChildId == Constants.FO_BLOCK
                    || nextChildId == Constants.FO_TABLE_AND_CAPTION
                    || nextChildId == Constants.FO_TABLE
                    || nextChildId == Constants.FO_LIST_BLOCK
                    || nextChildId == Constants.FO_BLOCK_CONTAINER);
        } else {
            nextChildIsBlockLevel = false;
        }
        
        handleWhiteSpace();
        
        if (currentFO == currentBlock 
                && pendingInlines != null 
                && !pendingInlines.isEmpty()) {
            /* current FO is a block, and has pending inlines */
            if (endOfBlock || nextChildIsBlockLevel) {
                if (nonWhiteSpaceCount == 0) {
                    /* handle white-space for all pending inlines*/
                    PendingInline p;
                    for (int i = pendingInlines.size(); --i >= 0;) {
                        p = (PendingInline)pendingInlines.get(i);
                        charIter = (RecursiveCharIterator)p.firstTrailingWhiteSpace;
                        handleWhiteSpace();
                        pendingInlines.remove(p);
                    }
                } else {
                    /* there is non-white-space text between the pending
                     * inline(s) and the end of the block;
                     * clear list of pending inlines */
                    pendingInlines.clear();
                }
            }
        }
        
        if (nextChild == null) {
            if (currentFO != currentBlock) {
                /* current FO is not a block, and is about to end */
                if (nonWhiteSpaceCount > 0 && pendingInlines != null) {
                    /* there is non-white-space text between the pending 
                     * inline(s) and the end of the non-block node; 
                     * clear list of pending inlines */
                    pendingInlines.clear();
                }
                if (inWhiteSpace) {
                    /* means there is at least one trailing space in the
                       inline FO that is about to end */
                    addPendingInline(fo);
                }
            } else {
                /* end of block: clear the references and pop the 
                 * nested block stack */
                if (!nestedBlockStack.empty()) {
                    currentBlock = (Block) nestedBlockStack.pop();
                } else {
                    currentBlock = null;
                }
                currentFO = null;
                charIter = null;
            }
        }
    }
    
    /**
     * Handle white-space for the fo that is passed in, starting at
     * firstTextNode (when a nested FO is encountered)
     * @param fo    the FO for which to handle white-space
     * @param firstTextNode the node at which to start
     * @param nextChild the child-node that will be added to the list after
     *                  the last text-node
     */
    public void handleWhiteSpace(FObjMixed fo, FONode firstTextNode, FONode nextChild) {
        this.nextChild = nextChild;
        handleWhiteSpace(fo, firstTextNode);
        this.nextChild = null;
    }
    
    private void handleWhiteSpace() {
        
        EOLchecker lfCheck = new EOLchecker(charIter);
        
        nonWhiteSpaceCount = 0;
        
        while (charIter.hasNext()) {
            if (!inWhiteSpace) {
                firstWhiteSpaceInSeq = charIter.mark();
            }
            char currentChar = charIter.nextChar();
            int currentCharClass = CharUtilities.classOf(currentChar);
            if (currentCharClass == CharUtilities.LINEFEED
                && linefeedTreatment == Constants.EN_TREAT_AS_SPACE) {
                // if we have a linefeed and it is supposed to be treated
                // like a space, that's what we do and continue
                currentChar = '\u0020';
                charIter.replaceChar('\u0020');
                currentCharClass = CharUtilities.classOf(currentChar);
            }
            switch (CharUtilities.classOf(currentChar)) {
                case CharUtilities.XMLWHITESPACE:
                    // Some kind of whitespace character, except linefeed.
                    if (inWhiteSpace 
                            && whiteSpaceCollapse == Constants.EN_TRUE) {
                        // We are in a run of whitespace and should collapse
                        // Just delete the char
                        charIter.remove();
                    } else {
                        // Do the white space treatment here
                        boolean bIgnore = false;

                        switch (whiteSpaceTreatment) {
                            case Constants.EN_IGNORE:
                                bIgnore = true;
                                break;
                            case Constants.EN_IGNORE_IF_BEFORE_LINEFEED:
                                bIgnore = lfCheck.beforeLinefeed();
                                break;
                            case Constants.EN_IGNORE_IF_SURROUNDING_LINEFEED:
                                bIgnore = afterLinefeed
                                           || lfCheck.beforeLinefeed();
                                break;
                            case Constants.EN_IGNORE_IF_AFTER_LINEFEED:
                                bIgnore = afterLinefeed;
                                break;
                            case Constants.EN_PRESERVE:
                                //nothing to do now, replacement takes place later
                                break;
                            default:
                                //nop
                        }
                        // Handle ignore and replacement
                        if (bIgnore) {
                            charIter.remove();
                        } else {
                            // this is to retain a single space between words
                            inWhiteSpace = true;
                            if (currentChar != '\u0020') {
                                charIter.replaceChar('\u0020');
                            }
                        }
                    }
                    break;

                case CharUtilities.LINEFEED:
                    // A linefeed
                    switch (linefeedTreatment) {
                        case Constants.EN_IGNORE:
                            charIter.remove();
                            break;
                        case Constants.EN_TREAT_AS_ZERO_WIDTH_SPACE:
                            charIter.replaceChar(CharUtilities.ZERO_WIDTH_SPACE);
                            inWhiteSpace = false;
                            break;
                        case Constants.EN_PRESERVE:
                            lfCheck.reset();
                            inWhiteSpace = false;
                            afterLinefeed = true; // for following whitespace
                            break;
                        default:
                            //nop
                    }
                    break;

                case CharUtilities.EOT:
                    // A "boundary" objects such as non-character inline
                    // or nested block object was encountered. (? can't happen)
                    // If any whitespace run in progress, finish it.
                    // FALL THROUGH

                default:
                    // Any other character
                    inWhiteSpace = false;
                    afterLinefeed = false;
                    nonWhiteSpaceCount++;
                    lfCheck.reset();
                    break;
            }
        }
    }
    
    private void addPendingInline(FObjMixed fo) {
        if (pendingInlines == null) {
            pendingInlines = new java.util.ArrayList(5);
        }
        pendingInlines.add(new PendingInline(fo, firstWhiteSpaceInSeq));
    }
    
    /**
     * Helper class, used during white-space handling to look ahead, and
     * see if the next character is a linefeed (or if there will be
     * an equivalent effect during layout, i.e. end-of-block or
     * the following child is a block-level FO)
     */
    private class EOLchecker {
        private boolean nextIsEOL = false;
        private RecursiveCharIterator charIter;

        EOLchecker(CharIterator charIter) {
            this.charIter = (RecursiveCharIterator) charIter;
        }

        boolean beforeLinefeed() {
            if (!nextIsEOL) {
                CharIterator lfIter = charIter.mark();
                while (lfIter.hasNext()) {
                    int charClass = CharUtilities.classOf(lfIter.nextChar());
                    if (charClass == CharUtilities.LINEFEED) {
                        if (linefeedTreatment == Constants.EN_PRESERVE) {
                            nextIsEOL = true;
                            return nextIsEOL;
                        }
                    } else if (charClass != CharUtilities.XMLWHITESPACE) {
                        return nextIsEOL;
                    }
                }
                // No more characters == end of text run
                // means EOL if there either is a nested block to be added,
                // or if this is the last text node in the current block   
                nextIsEOL = nextChildIsBlockLevel || endOfBlock;
            }
            return nextIsEOL;
        }

        void reset() {
            nextIsEOL = false;
        }
    }
    
    /**
     * Helper class to store unfinished inline nodes together 
     * with an iterator that starts at the first white-space
     * character in the sequence of trailing white-space
     */
    private class PendingInline {
        protected FObjMixed fo;
        protected CharIterator firstTrailingWhiteSpace;
        
        PendingInline(FObjMixed fo, CharIterator firstTrailingWhiteSpace) {
            this.fo = fo;
            this.firstTrailingWhiteSpace = firstTrailingWhiteSpace;
        }
    }
}