Package com.google.gdt.eclipse.designer.model.widgets.support

Source Code of com.google.gdt.eclipse.designer.model.widgets.support.CssSupport

/*******************************************************************************
* Copyright 2011 Google Inc. All Rights Reserved.
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* 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.google.gdt.eclipse.designer.model.widgets.support;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gdt.eclipse.designer.Activator;
import com.google.gdt.eclipse.designer.util.DefaultModuleDescription;
import com.google.gdt.eclipse.designer.util.ModuleDescription;
import com.google.gdt.eclipse.designer.util.Utils;

import org.eclipse.wb.internal.core.utils.IOUtils2;
import org.eclipse.wb.internal.core.utils.execution.ExecutionUtils;
import org.eclipse.wb.internal.core.utils.execution.RunnableEx;
import org.eclipse.wb.internal.core.utils.execution.RunnableObjectEx;

import org.eclipse.core.resources.IFile;
import org.eclipse.jface.text.Document;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;

import java.text.MessageFormat;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
* Support for CSS resources in {@link GwtState}.
*
* @author scheglov_ke
* @author mitin_aa
* @coverage gwt.model
*/
public final class CssSupport {
  private final GwtState state;
  private List<String> resources;
  private List<IFile> files;
  private long nextRequestId;
  private final Map<IFile, Long> filesStampMap = Maps.newHashMap();
  private final Set<String> waitRequestSet = Sets.newHashSet();
  private final Set<String> waitApplySet = Sets.newHashSet();

  ////////////////////////////////////////////////////////////////////////////
  //
  // Constructor
  //
  ////////////////////////////////////////////////////////////////////////////
  public CssSupport(GwtState state) {
    this.state = state;
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Access
  //
  ////////////////////////////////////////////////////////////////////////////
  /**
   * @return the CSS resources.
   */
  public List<String> getResources() {
    return resources;
  }

  /**
   * @return the {@link IFile}s for CSS resources.
   */
  public List<IFile> getFiles() {
    return files;
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Private access
  //
  ////////////////////////////////////////////////////////////////////////////
  /**
   * Prepares CSS resources and files.
   */
  void prepareResources() throws Exception {
    ModuleDescription moduleDescription = state.getModuleDescription();
    resources = Utils.getCssResources(moduleDescription);
    if (moduleDescription instanceof DefaultModuleDescription) {
      files =
          Utils.getFilesForResources(
              ((DefaultModuleDescription) moduleDescription).getFile(),
              resources);
      for (IFile file : files) {
        filesStampMap.put(file, file.getModificationStamp());
      }
    }
  }

  /**
   * Adds links to the CSS resources.
   */
  void addLinkDeclarations(List<String> declarations) {
    for (String cssResource : resources) {
      declarations.add(MessageFormat.format(
          "<link rel=''stylesheet'' type=''text/css'' href=''{0}''/>",
          cssResource));
    }
  }

  /**
   * Adds DIVs for CSS "apply wait", see {@link #waitFor()} JavaDoc.
   */
  String addReloadingFeature(String html) {
    StringBuilder declarations = new StringBuilder();
    for (String resource : resources) {
      String name = getWaitRequestName(resource);
      declarations.append("<div class='");
      declarations.append(name);
      declarations.append("'></div>\n");
    }
    return StringUtils.replace(html, "%CSS_WAIT_DECLARATIONS%", declarations.toString());
  }

  /**
   * @return <code>true</code> if one or more CSS files were modified (and schedules them for
   *         reloading with next refresh).
   */
  boolean isModified() {
    waitRequestSet.clear();
    waitApplySet.clear();
    boolean modified = false;
    // check CSS files
    boolean hasModifiedCSSFiles = false;
    for (Map.Entry<IFile, Long> entry : filesStampMap.entrySet()) {
      IFile file = entry.getKey();
      long storedStamp = entry.getValue();
      long fileStamp = file.getModificationStamp();
      if (fileStamp != storedStamp) {
        modified = true;
        filesStampMap.put(file, fileStamp);
        hasModifiedCSSFiles = true;
      }
    }
    // schedule CSS load waiting
    if (hasModifiedCSSFiles) {
      synchronized (waitRequestSet) {
        for (String resource : resources) {
          String waitRequestName = getWaitRequestName(resource);
          waitRequestSet.add(waitRequestName);
        }
      }
    }
    // if has modified CSS files, ask Browser for reload
    if (modified) {
      ExecutionUtils.runLog(new RunnableEx() {
        public void run() throws Exception {
          state.getHostModeSupport().invokeNativeVoid(
              "__reload_css",
              ArrayUtils.EMPTY_CLASS_ARRAY,
              ArrayUtils.EMPTY_OBJECT_ARRAY);
        }
      });
      waitFor();
    }
    // return final modification state
    return modified;
  }

  /**
   * Provides wait operation for CSS files to be applied.
   *
   * CSS files waiting works as following:
   * <p>
   * When HTTP-server recognizes request for CSS resource it added into requested CSS-file fake CSS
   * class with style which applying caused browser to request some resource from HTTP-server, e.g.
   * HTTP-server adds something like that:
   *
   * <pre>
   * .gwt__wait_stylesheetXXXX {
   *   visibility: hidden;
   *   background: url("cssFileName_cssFileTimestamp");
   * }
   * </pre>
   * Where: XXXX is some unique identifier (hashCode for CSS file name), cssFileName is the name of
   * requested CSS file cssFileTimestamp is the timestamp of requested CSS file. So, when the
   * browser applies received CSS file with fake CSS class it requests
   * "cssFileName_cssFileTimestamp" resource from HTTP-server.
   * <p>
   * Note: browser would not request "cssFileName_cssFileTimestamp" resource without any
   * HTML-element with fake CSS class applied, thats why its needed to dynamically generate the HTML
   * element with fake CSS class for every CSS file in project (see set CSS wait declarations in
   * constructor).
   */
  void waitFor() {
    long startWait = System.currentTimeMillis();
    while (true) {
      // may be done
      boolean done = true;
      synchronized (waitRequestSet) {
        done &= waitRequestSet.isEmpty();
      }
      synchronized (waitApplySet) {
        done &= waitApplySet.isEmpty();
      }
      if (done) {
        break;
      }
      // do not wait more than 500ms
      if (System.currentTimeMillis() - startWait > 500) {
        break;
      }
      // wait more
      state.runMessagesLoop();
    }
  }

  /**
   * @return the name of CSS class to use for waiting given CSS file which is referred by
   *         {@link IFile} or public resource path.
   */
  private static String getWaitRequestName(String path) {
    String name = path;
    name = StringUtils.replace(name, "/", "_");
    name = StringUtils.removeEndIgnoreCase(name, ".css");
    return "wbp__wait_stylesheet_" + name;
  }

  ////////////////////////////////////////////////////////////////////////////
  //
  // Content access
  //
  ////////////////////////////////////////////////////////////////////////////
  /**
   * @return the empty PNG image bytes, if this resource path is "wait for CSS" marker, or
   *         <code>null</code> if some other resource for requested.
   */
  byte[] getResourceWait(String publicResourcePath) {
    synchronized (waitApplySet) {
      if (waitApplySet.remove(publicResourcePath)) {
        // IE requires the content, otherwise 'image.complete' is always false.
        // This doesn't affect other browsers though, but returning some content is the right way.
        return ExecutionUtils.runObjectIgnore(new RunnableObjectEx<byte[]>() {
          public byte[] runObject() throws Exception {
            return IOUtils2.readBytes(Activator.getFile("icons/empty.png"));
          }
        }, null);
      }
    }
    return null;
  }

  /**
   * @param result
   *          the bytes of CSS file.
   * @return the updates bytes of CSS file, with "wait for loading" markers added.
   */
  byte[] getResource(String publicResourcePath, byte[] result) throws Exception {
    if (publicResourcePath.toLowerCase().endsWith(".css")) {
      if (resources.contains(publicResourcePath)) {
        // prepare "wait apply" resource, should be image
        String waitRequestName = getWaitRequestName(publicResourcePath);
        String waitApplyName = waitRequestName + "_" + nextRequestId++ + ".png";
        // prepare content
        String cssContent = new String(result, "UTF-8");
        cssContent = addRulesMarkers(publicResourcePath, cssContent);
        // add "wait apply" class to the end of CSS content
        {
          cssContent += "\n." + waitRequestName + "{";
          cssContent += "visibility: hidden; ";
          cssContent += "background-image: url('";
          cssContent += state.m_moduleBaseURL + waitApplyName;
          cssContent += "'); }\n";
          result = cssContent.getBytes("UTF-8");
        }
        // update request/apply sets
        synchronized (waitApplySet) {
          waitApplySet.add(waitApplyName);
        }
        synchronized (waitRequestSet) {
          waitRequestSet.remove(waitRequestName);
        }
      }
    }
    return result;
  }

  private String addRulesMarkers(String publicResourcePath, String content) throws Exception {
    Document sourceDocument = new Document(content);
    /*CssEditContext editContext = new CssEditContext(sourceDocument);
    CssDocument document = editContext.getCssDocument();
    for (CssRuleNode rule : document.getRules()) {
      int ruleId = m_lastTrackedRule++;
      rule.addDeclaration(CssFactory.newDeclaration("wbp-css-rule-" + ruleId, "0"));
    }
    System.out.println(sourceDocument.get());*/
    return sourceDocument.get();
  }
}
TOP

Related Classes of com.google.gdt.eclipse.designer.model.widgets.support.CssSupport

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.