http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/AttachmentImpl.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/AttachmentImpl.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/AttachmentImpl.java
deleted file mode 100644
index 2b3ef14..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/AttachmentImpl.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/**
- * 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.
- */
-
-package org.waveprotocol.wave.client.doodad.attachment;
-
-import org.waveprotocol.box.attachment.AttachmentMetadata;
-import org.waveprotocol.box.attachment.impl.AttachmentMetadataImpl;
-import org.waveprotocol.wave.media.model.Attachment;
-
-/**
- * @author [email protected] (A. Kaplanov)
- */
-public class AttachmentImpl implements Attachment {
-
-  private AttachmentMetadata metadata;
-  private Status status = Status.NOT_UPLOADING;
-
-  public AttachmentImpl() {
-    metadata = new AttachmentMetadataImpl();
-  }
-
-  public void copyMetadata(AttachmentMetadata metadata) {
-    this.metadata.copyFrom(metadata);
-  }
-
-  @Override
-  public String getAttachmentId() {
-    return metadata.getAttachmentId();
-  }
-
-  @Override
-  public String getCreator() {
-    return metadata.getCreator();
-  }
-
-  @Override
-  public String getAttachmentUrl() {
-    return metadata.getAttachmentUrl();
-  }
-
-  @Override
-  public String getThumbnailUrl() {
-    return metadata.getThumbnailUrl();
-  }
-
-  @Override
-  public String getMimeType() {
-    return metadata.getMimeType();
-  }
-
-  @Override
-  public String getFilename() {
-    return metadata.getFileName();
-  }
-
-  @Override
-  public Long getSize() {
-    return metadata.getSize();
-  }
-
-  @Override
-  public ImageMetadata getContentImageMetadata() {
-    if (metadata.hasImageMetadata()) {
-      return new ImageMetadata() {
-
-        @Override
-        public int getWidth() {
-          return metadata.getImageMetadata().getWidth();
-        }
-
-        @Override
-        public int getHeight() {
-          return metadata.getImageMetadata().getHeight();
-        }
-      };
-    } else {
-      return null;
-    }
-  }
-
-  @Override
-  public ImageMetadata getThumbnailImageMetadata() {
-    if (metadata.hasThumbnailMetadata()) {
-      return new ImageMetadata() {
-
-        @Override
-        public int getWidth() {
-          return metadata.getThumbnailMetadata().getWidth();
-        }
-
-        @Override
-        public int getHeight() {
-          return metadata.getThumbnailMetadata().getHeight();
-        }
-      };
-    } else {
-      return null;
-    }
-  }
-
-  @Override
-  public long getUploadedByteCount() {
-    throw new UnsupportedOperationException("Not supported yet.");
-  }
-
-  @Override
-  public long getUploadRetryCount() {
-    throw new UnsupportedOperationException("Not supported yet.");
-  }
-
-  @Override
-  public boolean isMalware() {
-    if (metadata.hasMalware()) {
-      return metadata.getMalware();
-    }
-    return false;
-  }
-
-  @Override
-  public Status getStatus() {
-    return status;
-  }
-
-  public void setStatus(Status status) {
-    this.status = status;
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/AttachmentManagerImpl.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/AttachmentManagerImpl.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/AttachmentManagerImpl.java
deleted file mode 100644
index b13d528..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/AttachmentManagerImpl.java
+++ /dev/null
@@ -1,208 +0,0 @@
-/**
- * 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.
- */
-
-package org.waveprotocol.wave.client.doodad.attachment;
-
-import com.google.gwt.http.client.Request;
-import com.google.gwt.http.client.RequestBuilder;
-import com.google.gwt.http.client.RequestCallback;
-import com.google.gwt.http.client.RequestException;
-import com.google.gwt.http.client.Response;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import org.waveprotocol.box.attachment.jso.AttachmentsResponseJsoImpl;
-import org.waveprotocol.box.attachment.jso.AttachmentMetadataJsoImpl;
-import org.waveprotocol.wave.client.debug.logger.DomLogger;
-import org.waveprotocol.wave.client.scheduler.Scheduler.Task;
-import org.waveprotocol.wave.client.scheduler.SchedulerInstance;
-import org.waveprotocol.wave.client.scheduler.TimerService;
-import org.waveprotocol.wave.common.logging.LoggerBundle;
-import org.waveprotocol.wave.communication.gwt.JsonMessage;
-import org.waveprotocol.wave.communication.json.JsonException;
-import org.waveprotocol.wave.media.model.Attachment;
-import org.waveprotocol.wave.model.util.CollectionUtils;
-
-/**
- * Gets attachments meta info from server.
- *
- * @author [email protected] (A. Kaplanov)
- */
-public class AttachmentManagerImpl implements SimpleAttachmentManager {
-  interface GetAttachmentsInfoCallback {
-
-    public void onSuccess(List<Attachment> attachments);
-
-    public void onFailure(List<Attachment> attachments, String message);
-  }
-
-  private static final String ATTACHMENTS_INFO_URL_BASE = "/attachmentsInfo";
-
-  private static final LoggerBundle LOG = new 
DomLogger(AttachmentManagerImpl.class.getName());
-
-  private static SimpleAttachmentManager instance;
-
-  private final TimerService scheduler;
-  private final Map<String, AttachmentImpl> attachmentsInfo = new 
HashMap<String, AttachmentImpl>();
-  private final List<String> pendingQueue = new ArrayList<String>();
-  private final List<Listener> listeners = new ArrayList<Listener>();
-
-  public static SimpleAttachmentManager getInstance() {
-    if (instance != null) {
-      return instance;
-    }
-    instance = new AttachmentManagerImpl();
-    return instance;
-  }
-
-  private Task getAttachmentsInfoTask = new Task() {
-    @Override
-    public void execute() {
-      getAttachmentsInfo(new GetAttachmentsInfoCallback() {
-
-        @Override
-        public void onSuccess(List<Attachment> attachments) {
-          for (Attachment attachment : attachments) {
-            notifyImageUpdated(attachment);
-          }
-        }
-
-        @Override
-        public void onFailure(List<Attachment> attachments, String message) {
-          LOG.error().log("Getting of attachments info failed: " + message);
-          for (Attachment attachment : attachments) {
-            notifyImageUpdated(attachment);
-          }
-        }
-      });
-    }
-  };
-
-  private AttachmentManagerImpl() {
-    this.scheduler = SchedulerInstance.getMediumPriorityTimer();
-  }
-
-  @Override
-  public Attachment getAttachment(String attachmentId) {
-    AttachmentImpl attachment = attachmentsInfo.get(attachmentId);
-    if (attachment == null) {
-      attachment = new AttachmentImpl();
-      attachmentsInfo.put(attachmentId, attachment);
-      if (!pendingQueue.contains(attachmentId)) {
-        pendingQueue.add(attachmentId);
-        scheduler.schedule(getAttachmentsInfoTask);
-      }
-    }
-    return attachment;
-  }
-
-  @Override
-  public void addListener(Listener listener) {
-    listeners.add(listener);
-  }
-
-  @Override
-  public void removeListener(Listener listener) {
-    listeners.remove(listener);
-  }
-
-  private void notifyImageUpdated(Attachment attachment) {
-    for (Listener listener : listeners) {
-      listener.onContentUpdated(attachment);
-      listener.onThumbnailUpdated(attachment);
-    }
-  }
-
-  private void getAttachmentsInfo(final GetAttachmentsInfoCallback callback) {
-
-    LOG.trace().log("Getting attachments info");
-
-    String request = ATTACHMENTS_INFO_URL_BASE + "?attachmentIds=";
-
-    for (String attacmentId : pendingQueue) {
-      if (!request.endsWith("=")) {
-        request += ",";
-      }
-      request += attacmentId;
-    }
-    final List<String> requestedAttachments = new 
ArrayList<String>(pendingQueue);
-    pendingQueue.clear();
-
-    RequestBuilder requestBuilder = new RequestBuilder(RequestBuilder.GET, 
request);
-
-    requestBuilder.setCallback(new RequestCallback() {
-      @Override
-      public void onResponseReceived(Request request, Response response) {
-        LOG.trace().log("Attachments info was received: ", response.getText());
-        if (response.getStatusCode() != Response.SC_OK) {
-          callback.onFailure(setFailureStatus(requestedAttachments), "Got back 
status code " + response.getStatusCode());
-        } else if 
(!response.getHeader("Content-Type").startsWith("application/json")) {
-          callback.onFailure(setFailureStatus(requestedAttachments), "Search 
service did not return json");
-        } else {
-          AttachmentsResponseJsoImpl attachmentsProto;
-          try {
-            attachmentsProto = JsonMessage.parse(response.getText());
-          } catch (JsonException e) {
-            callback.onFailure(setFailureStatus(requestedAttachments), 
e.getMessage());
-            return;
-          }
-          List<Attachment> attachments = 
initializeAttachments(attachmentsProto);
-          callback.onSuccess(attachments);
-        }
-      }
-
-      @Override
-      public void onError(Request request, Throwable e) {
-        LOG.error().log("Getting attachments info error: ", e);
-        callback.onFailure(setFailureStatus(requestedAttachments), 
e.getMessage());
-      }
-    });
-
-    try {
-      requestBuilder.send();
-    } catch (RequestException e) {
-      callback.onFailure(setFailureStatus(requestedAttachments), 
e.getMessage());
-    }
-  }
-
-  private List<Attachment> initializeAttachments(AttachmentsResponseJsoImpl 
protoAttachments) {
-    List<Attachment> attachments = CollectionUtils.newArrayList();
-    for (AttachmentMetadataJsoImpl protoAttachment : 
protoAttachments.getAttachment()) {
-      AttachmentImpl attachment = 
attachmentsInfo.get(protoAttachment.getAttachmentId());
-      if (attachment != null) {
-        attachment.copyMetadata(protoAttachment);
-        attachments.add(attachment);
-      }
-    }
-    return attachments;
-  }
-
-  private List<Attachment> setFailureStatus(List<String> attachmentIds) {
-    List<Attachment>  attachments = new ArrayList<Attachment>();
-    for (String attachmentId : attachmentIds) {
-      AttachmentImpl attachment = attachmentsInfo.get(attachmentId);
-      if (attachment != null) {
-        attachment.setStatus(Attachment.Status.FAILED_AND_NOT_RETRYABLE);
-        attachments.add(attachment);
-      }
-    }
-    return attachments;
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/AttachmentManagerProvider.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/AttachmentManagerProvider.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/AttachmentManagerProvider.java
deleted file mode 100644
index ec9ba6c..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/AttachmentManagerProvider.java
+++ /dev/null
@@ -1,34 +0,0 @@
-/**
- * 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.
- */
-
-package org.waveprotocol.wave.client.doodad.attachment;
-
-public class AttachmentManagerProvider {
-
-  private static SimpleAttachmentManager instance;
-
-  public static SimpleAttachmentManager get() {
-    return instance;
-  }
-
-  public static void init(SimpleAttachmentManager manager) {
-    instance = manager;
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/ImageThumbnail.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/ImageThumbnail.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/ImageThumbnail.java
deleted file mode 100644
index e9ad3b3..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/ImageThumbnail.java
+++ /dev/null
@@ -1,144 +0,0 @@
-/**
- * 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.
- */
-
-package org.waveprotocol.wave.client.doodad.attachment;
-
-import 
org.waveprotocol.wave.client.doodad.attachment.render.ImageThumbnailRenderer;
-import 
org.waveprotocol.wave.client.doodad.attachment.render.ImageThumbnailWrapper;
-import org.waveprotocol.wave.client.editor.EditorStaticDeps;
-import org.waveprotocol.wave.client.editor.ElementHandlerRegistry;
-import org.waveprotocol.wave.client.editor.NodeEventHandler;
-import org.waveprotocol.wave.client.editor.content.ContentElement;
-import org.waveprotocol.wave.client.editor.content.ContentNode;
-import org.waveprotocol.wave.client.editor.content.misc.Caption;
-import 
org.waveprotocol.wave.client.editor.selection.content.ValidSelectionStrategy;
-import org.waveprotocol.wave.client.editor.util.EditorDocHelper;
-import org.waveprotocol.wave.model.document.util.FilteredView.Skip;
-import org.waveprotocol.wave.model.document.util.Property;
-import org.waveprotocol.wave.model.document.util.XmlStringBuilder;
-
-/**
- * Editable image thumbnail
- *
- */
-public class ImageThumbnail {
-
-  /**
-   * Allows propagation of image thumbnail events to external hooks.
-   */
-  public interface ThumbnailActionHandler {
-
-    /**
-     * Called when the user clicks the thumbnail.
-     *
-     * @return true if the action was handled in a special manner, false to 
allow default behaviour
-     */
-    boolean onClick(ImageThumbnailWrapper thumbnail);
-  }
-
-  public static final String TAGNAME = "image";
-
-  /**
-   * The attachment id attribute
-   */
-  public static final String ATTACHMENT_ATTR = "attachment";
-
-  /**
-   * Potential attribute names
-   */
-  protected static final String[] ATTRIBUTE_NAMES = new String[] 
{ATTACHMENT_ATTR};
-
-  public static final Property<ContentElement> CAPTION = 
Property.immutable("Caption");
-
-  /**
-   * Render style attribute
-   */
-  public static final String STYLE_ATTR = "style";
-
-  /**
-   * Image displayed full size without thumbnail chrome
-   */
-  public static final String STYLE_FULL = "full";
-
-  /**
-   * Registers subclass with ContentElement
-   *
-   * @param actionHandler May be null. If not, allows external hooks into
-   *        thumbnail events for extended behaviour.
-   */
-  public static void register(ElementHandlerRegistry registry,
-      SimpleAttachmentManager attachmentsManager, ThumbnailActionHandler 
actionHandler) {
-    // TODO(danilatos): Generify
-    ImageThumbnailAttachmentHandler attachmentListener = new 
ImageThumbnailAttachmentHandler();
-    ImageThumbnailRenderer renderer = new 
ImageThumbnailRenderer(attachmentsManager, attachmentListener);
-    NodeEventHandler eventHandler = new ImageThumbnailNodeEventHandler(
-        EditorStaticDeps.logger, renderer, actionHandler);
-    attachmentListener.setRenderer(renderer);
-
-
-    // TODO(danilatos/hearnden): These listeners need to be cleaned up.
-    // E.g. currently they are created in WaveManager?
-    attachmentsManager.addListener(attachmentListener);
-
-    registry.registerEventHandler(TAGNAME, eventHandler);
-    registry.registerRenderingMutationHandler(TAGNAME, renderer);
-
-    // let the editor know image persistent tag can't have selection, but 
contains things that can
-    ValidSelectionStrategy.registerTagForSelections(
-        ImageThumbnail.TAGNAME, true, Skip.SHALLOW);
-  }
-
-  /**
-   * @param attachmentId
-   * @param xmlCaption
-   * @return A content xml string containing an image thumbnail
-   */
-  public static XmlStringBuilder constructXml(
-      String attachmentId, String xmlCaption) {
-    return XmlStringBuilder.createText(xmlCaption).wrap(Caption.TAGNAME).wrap(
-        TAGNAME, ATTACHMENT_ATTR, attachmentId);
-  }
-
-  /**
-   * @param attachmentId
-   * @param full whether it's full size
-   * @param xmlCaption
-   */
-  public static XmlStringBuilder constructXml(
-      String attachmentId, boolean full, String xmlCaption) {
-    if (!full) {
-      return constructXml(attachmentId, xmlCaption);
-    }
-    return XmlStringBuilder.createText(xmlCaption).wrap(Caption.TAGNAME).wrap(
-        TAGNAME, ATTACHMENT_ATTR, attachmentId, STYLE_ATTR, STYLE_FULL);
-  }
-
-  private ImageThumbnail() {}
-
-  /**
-   * Determines whether a node is an image thumbnail.
-   *
-   * @param node the node to be checked.
-   * @return true if the node is an image thumbnail, false otherwise.
-   */
-  public static boolean isThumbnailElement(ContentNode node) {
-    assert node != null;
-    return EditorDocHelper.isNamedElement(node, TAGNAME);
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/ImageThumbnailAttachmentHandler.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/ImageThumbnailAttachmentHandler.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/ImageThumbnailAttachmentHandler.java
deleted file mode 100644
index d79b03d..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/ImageThumbnailAttachmentHandler.java
+++ /dev/null
@@ -1,162 +0,0 @@
-/**
- * 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.
- */
-
-package org.waveprotocol.wave.client.doodad.attachment;
-
-import 
org.waveprotocol.wave.client.doodad.attachment.render.ImageThumbnailRenderer;
-import 
org.waveprotocol.wave.client.doodad.attachment.render.ImageThumbnailView;
-import org.waveprotocol.wave.client.editor.content.ContentElement;
-import org.waveprotocol.wave.media.model.Attachment;
-import org.waveprotocol.wave.media.model.Attachment.ImageMetadata;
-import org.waveprotocol.wave.media.model.Attachment.Status;
-import org.waveprotocol.wave.model.util.CollectionUtils;
-import org.waveprotocol.wave.model.util.IdentityMap;
-import org.waveprotocol.wave.model.util.Preconditions;
-
-/**
- * Handler for the attachment logic for thumbnail doodads.
- *
- * @author [email protected] (Daniel Danilatos)
- */
-public class ImageThumbnailAttachmentHandler implements 
SimpleAttachmentManager.Listener {
-
-  // @NotInternationalized
-  private static final String attachmentLoadingFailedTooltip = "Loading 
attachment failed.";
-  private static final String attachmentMalwareDetected =
-      "The file contains a virus or other malware and has been disabled.";
-
-  // Memory leak? Should be OK if this handler is per-wavelet
-  private final IdentityMap<Attachment, ContentElement> doodads =
-      CollectionUtils.createIdentityMap();
-  private ImageThumbnailRenderer renderer;
-
-  /** NOTE(patcoleman): Not in ctor due to circular dependency. */
-  void setRenderer(ImageThumbnailRenderer renderer) {
-    Preconditions.checkArgument(renderer != null, "can't bind attachment 
handler to a null renderer");
-    Preconditions.checkState(this.renderer == null, "renderer should only be 
set once");
-    this.renderer = renderer;
-  }
-
-  /**
-   * Set up attachment handling for the given element
-   *
-   * @param e the element
-   * @param attachment the attachment
-   */
-  public void init(ContentElement e, Attachment attachment) {
-    doodads.put(attachment, e);
-    onContentUpdated(attachment);
-    onThumbnailUpdated(attachment);
-    onUploadStatusUpdated(attachment);
-  }
-
-  /**
-   * Inverse of {@link #init}.
-   */
-  public void cleanup(ContentElement e, Attachment a) {
-    doodads.remove(a);
-  }
-
-  private ContentElement getElement(Attachment c) {
-    ContentElement e = doodads.get(c);
-    if (e != null) {
-      if (!e.isContentAttached()) {
-        // Lazy removal. Perhaps do it from the node mutation event handler?
-        doodads.remove(c);
-      } else {
-        return e;
-      }
-    }
-    return null;
-  }
-
-  @Override
-  public void onContentUpdated(Attachment c) {
-    ContentElement e = getElement(c);
-    // TODO(nigeltao): can e ever be null?
-    if (e == null) {
-      return;
-    }
-
-    String url = c.getAttachmentUrl();
-    if (url != null) {
-      renderer.getView(e).setAttachmentUrl(url);
-    }
-
-    ImageMetadata metadata = c.getContentImageMetadata();
-    if (metadata != null) {
-      renderer.getView(e).setAttachmentSize(metadata.getWidth(), 
metadata.getHeight());
-    }
-  }
-
-  @Override
-  public void onThumbnailUpdated(Attachment c) {
-    ContentElement e = getElement(c);
-    if (e == null) {
-      return;
-    }
-
-    if (c.isMalware()) {
-      renderer.getView(e).displayDeadImage(attachmentMalwareDetected);
-      return;
-    }
-
-    String url = c.getThumbnailUrl();
-    if (url != null) {
-      renderer.getView(e).setThumbnailUrl(url);
-    }
-
-    ImageMetadata metadata = c.getThumbnailImageMetadata();
-    if (metadata != null) {
-      renderer.getView(e).setThumbnailSize(metadata.getWidth(), 
metadata.getHeight());
-    }
-
-    if (metadata == null && c.getStatus() == Status.FAILED_AND_NOT_RETRYABLE) {
-      renderer.getView(e).displayDeadImage(
-          attachmentLoadingFailedTooltip);
-    }
-  }
-
-  @Override
-  public void onUploadStatusUpdated(Attachment c) {
-    ContentElement e = getElement(c);
-    if (e == null) {
-      return;
-    }
-
-    ImageThumbnailView v = renderer.getView(e);
-    switch (c.getStatus()) {
-      case NOT_UPLOADING:
-      case SUCCEEDED:
-        v.hideUploadProgress();
-        break;
-      case IN_PROGRESS:
-      case FAILED_AND_RETRYABLE:
-        v.setUploadProgress(((double)c.getUploadedByteCount())/c.getSize());
-        v.showUploadProgress();
-        break;
-      case FAILED_AND_NOT_RETRYABLE:
-        v.hideUploadProgress();
-        v.displayDeadImage(attachmentLoadingFailedTooltip);
-        break;
-      default:
-        throw new IllegalStateException();
-    }
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/ImageThumbnailNodeEventHandler.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/ImageThumbnailNodeEventHandler.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/ImageThumbnailNodeEventHandler.java
deleted file mode 100644
index 047871d..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/ImageThumbnailNodeEventHandler.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/**
- * 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.
- */
-
-package org.waveprotocol.wave.client.doodad.attachment;
-
-import com.google.gwt.user.client.Window;
-
-import 
org.waveprotocol.wave.client.doodad.attachment.ImageThumbnail.ThumbnailActionHandler;
-import 
org.waveprotocol.wave.client.doodad.attachment.render.ImageThumbnailRenderer;
-import 
org.waveprotocol.wave.client.doodad.attachment.render.ImageThumbnailView.ImageThumbnailViewListener;
-import 
org.waveprotocol.wave.client.doodad.attachment.render.ImageThumbnailWrapper;
-import org.waveprotocol.wave.client.editor.NodeEventHandlerImpl;
-import org.waveprotocol.wave.client.editor.content.ContentElement;
-import org.waveprotocol.wave.client.editor.content.ContentNode;
-import org.waveprotocol.wave.client.editor.event.EditorEvent;
-import org.waveprotocol.wave.common.logging.LoggerBundle;
-import org.waveprotocol.wave.model.document.util.Point;
-
-/**
- * Node event handler for ImageThumbnail.
- *
- * NOTE(user): We can probably make this more general and use it for different
- * types of doodads.
- *
- */
-final class ImageThumbnailNodeEventHandler extends NodeEventHandlerImpl {
-
-  private final ThumbnailActionHandler actionHandler;
-
-  private final LoggerBundle logger;
-
-  ImageThumbnailRenderer renderer;
-
-  ImageThumbnailNodeEventHandler(LoggerBundle logger,
-      ImageThumbnailRenderer renderer, ThumbnailActionHandler actionHandler) {
-    this.logger = logger;
-    this.renderer = renderer;
-    this.actionHandler = actionHandler;
-  }
-
-  @SuppressWarnings("unchecked") // Limitations of java's type system
-  @Override
-  public void onActivated(final ContentElement element) {
-    renderer.getView(element).setListener(new ImageThumbnailViewListener() {
-      public void onRequestSetFullSizeMode(boolean isOn) {
-        element.getMutableDoc().setElementAttribute(element,
-            ImageThumbnail.STYLE_ATTR, isOn ? ImageThumbnail.STYLE_FULL : 
null);
-      }
-      public void onClickImage() {
-        ImageThumbnailWrapper thumbnail = ImageThumbnailWrapper.of(element);
-        if (!actionHandler.onClick(thumbnail)) {
-          String url = thumbnail.getAttachment().getAttachmentUrl();
-          if (url != null) {
-            // TODO(nigeltao): Is it necessary to open a window here? All 
attachments are set to
-            // content-disposition=attachment which means the browser should 
download them.
-            // The current implementation means we always get a blank tab.
-            Window.open(url, thumbnail.getCaptionText(), "");
-          }
-        }
-      }
-    });
-  }
-
-  /**
-   * Removes the entire thumbnail on backspace after
-   *
-   * {@inheritDoc}
-   */
-  @Override
-  public boolean handleBackspaceAfterNode(ContentElement element, EditorEvent 
event) {
-    logger.trace().log("backspace after", element);
-    element.getMutableDoc().deleteNode(element);
-    return true;
-  }
-
-  /**
-   * Removes the entire thumbnail on delete before
-   *
-   * {@inheritDoc}
-   */
-  @Override
-  public boolean handleDeleteBeforeNode(ContentElement element, EditorEvent 
event) {
-    logger.trace().log("Delete before", element);
-    element.getMutableDoc().deleteNode(element);
-    return true;
-  }
-
-  /**
-   * Handles a left arrow that occurred with the caret immediately
-   * after this node, by moving caret to end of caption
-   *
-   * {@inheritDoc}
-   */
-  @Override
-  public boolean handleLeftAfterNode(ContentElement element, EditorEvent 
event) {
-    element.getSelectionHelper().setCaret(
-        Point.<ContentNode> end(getCaption(element)));
-    return true;
-  }
-
-  /**
-   * Handles a right arrow that occurred with the caret immediately
-   * before this node, by moving caret to beginning of caption
-   *
-   * {@inheritDoc}
-   */
-  @Override
-  public boolean handleRightBeforeNode(ContentElement element, EditorEvent 
event) {
-    element.getSelectionHelper().setCaret(
-        Point.start(element.getRenderedContentView(), getCaption(element)));
-    return true;
-  }
-
-  @Override
-  public boolean handleLeftAtBeginning(ContentElement element, EditorEvent 
event) {
-    // NOTE(danilatos): The use of location mapper will normalise into text 
nodes,
-    // masking a weird firefox selection bug except when there is no adjacent 
text node.
-    
element.getSelectionHelper().setCaret(element.getLocationMapper().getLocation(
-        Point.before(element.getRenderedContentView(), element)));
-    return true;
-  }
-
-  @Override
-  public boolean handleRightAtEnd(ContentElement element, EditorEvent event) {
-    // NOTE(danilatos): The use of location mapper will normalise into text 
nodes,
-    // masking a weird firefox selection bug except when there is no adjacent 
text node.
-    
element.getSelectionHelper().setCaret(element.getLocationMapper().getLocation(
-        Point.after(element.getRenderedContentView(), element)));
-    return true;
-  }
-
-  private ContentElement getCaption(ContentElement element) {
-    // TODO(danilatos): Enforce correctness via schema
-    return (ContentElement) element.getFirstChild();
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/SimpleAttachmentManager.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/SimpleAttachmentManager.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/SimpleAttachmentManager.java
deleted file mode 100644
index d84eea1..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/SimpleAttachmentManager.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/**
- * 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.
- */
-
-
-package org.waveprotocol.wave.client.doodad.attachment;
-
-import org.waveprotocol.wave.media.model.Attachment;
-
-/**
- * @author [email protected] (Daniel Danilatos)
- *
- */
-public interface SimpleAttachmentManager {
-
-  public interface Listener {
-    void onContentUpdated(Attachment attachment);
-    void onThumbnailUpdated(Attachment attachment);
-    void onUploadStatusUpdated(Attachment attachment);
-  }
-
-  Attachment getAttachment(String id);
-
-  public void addListener(Listener l);
-
-  public void removeListener(Listener l);
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/ImageThumbnailRenderer.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/ImageThumbnailRenderer.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/ImageThumbnailRenderer.java
deleted file mode 100644
index e95dec4..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/ImageThumbnailRenderer.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/**
- * 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.
- */
-
-package org.waveprotocol.wave.client.doodad.attachment.render;
-
-import com.google.gwt.dom.client.Element;
-import com.google.gwt.user.client.ui.Widget;
-
-import java.util.logging.Logger;
-import org.waveprotocol.wave.client.doodad.attachment.AttachmentConstants;
-import org.waveprotocol.wave.client.doodad.attachment.ImageThumbnail;
-import 
org.waveprotocol.wave.client.doodad.attachment.ImageThumbnailAttachmentHandler;
-import org.waveprotocol.wave.client.doodad.attachment.SimpleAttachmentManager;
-import org.waveprotocol.wave.client.editor.content.ContentElement;
-import org.waveprotocol.wave.client.editor.gwt.GwtRenderingMutationHandler;
-import org.waveprotocol.wave.media.model.Attachment;
-
-/**
- * Renderer implementation for ImageThumbnails.
- *
- */
-public class ImageThumbnailRenderer extends GwtRenderingMutationHandler {
-
-  private static final Logger LOG = 
Logger.getLogger(ImageThumbnailRenderer.class.getName());
-
-  private final SimpleAttachmentManager manager;
-  private final ImageThumbnailAttachmentHandler attachmentHandler;
-
-  /**
-   * Constructor
-   */
-  public ImageThumbnailRenderer(SimpleAttachmentManager manager,
-      ImageThumbnailAttachmentHandler handler) {
-    super(Flow.USE_WIDGET);
-    this.manager = manager;
-    this.attachmentHandler = handler;
-  }
-
-  @Override
-  protected Widget createGwtWidget(Renderable element) {
-    ImageThumbnailWidget widget = new ImageThumbnailWidget();
-
-    // TODO(danilatos/reuben): Can we remove the dependency on this max size 
constant?
-    int maxSize = AttachmentConstants.MAX_THUMBNAIL_SIZE;
-    widget.setThumbnailSize(maxSize, maxSize * 3 / 4);
-
-    return widget;
-  }
-
-  private ImageThumbnailWidget getWidget(ContentElement e) {
-    return (ImageThumbnailWidget) getGwtWidget(e);
-  }
-
-  @Override
-  public Element getContainerNodelet(Widget w) {
-    return ((ImageThumbnailWidget) w).getCaptionContainer();
-  }
-
-  /**
-   * @param e an element
-   * @return the view for the element
-   */
-  public ImageThumbnailView getView(ContentElement e) {
-    return getWidget(e);
-  }
-
-  @Override
-  public void onActivationStart(ContentElement element) {
-    element.setProperty(ImageThumbnailWrapper.PROPERTY, new 
ImageThumbnailWrapper(element));
-
-    fanoutAttrs(element);
-  }
-
-  @Override
-  public void onDeactivated(ContentElement element) {
-    ImageThumbnailWrapper w = ImageThumbnailWrapper.of(element);
-    if (w.getAttachment() != null) {
-      attachmentHandler.cleanup(element, w.getAttachment());
-    }
-    element.setProperty(ImageThumbnailWrapper.PROPERTY, null);
-  }
-
-  @Override
-  public void onAttributeModified(ContentElement element, String name,
-      String oldValue, String newValue) {
-    if (ImageThumbnail.STYLE_ATTR.equals(name)) {
-      ImageThumbnailView view = getView(element);
-      view.setFullSizeMode(ImageThumbnail.STYLE_FULL.equals(newValue));
-    } else if (ImageThumbnail.ATTACHMENT_ATTR.equals(name)) {
-      ImageThumbnailWrapper w = ImageThumbnailWrapper.of(element);
-      assert w != null;
-
-      Attachment newAttachment = manager.getAttachment(newValue);
-      Attachment oldAttachment = w.getAttachment();
-      if (newAttachment != oldAttachment) {
-        if (oldAttachment != null) {
-          attachmentHandler.cleanup(element, oldAttachment);
-        }
-        if (newAttachment != null) {
-          ImageThumbnailWrapper.of(element).setAttachment(newAttachment);
-          attachmentHandler.init(element, newAttachment);
-        }
-      }
-    }
-    super.onAttributeModified(element, name, oldValue, newValue);
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/ImageThumbnailView.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/ImageThumbnailView.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/ImageThumbnailView.java
deleted file mode 100644
index 5708294..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/ImageThumbnailView.java
+++ /dev/null
@@ -1,111 +0,0 @@
-/**
- * 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.
- */
-
-package org.waveprotocol.wave.client.doodad.attachment.render;
-
-/**
- * Write-only interface for updating the display of an image thumbnail
- *
- * @author [email protected] (Daniel Danilatos)
- */
-public interface ImageThumbnailView {
-
-  /**
-   * Listener to Image Thumbnail UI events
-   */
-  public interface ImageThumbnailViewListener {
-
-    /**
-     * The user requested a change to "full size mode"
-     *
-     * @param isOn if true, show full size, if false, thumbnail mode.
-     */
-    void onRequestSetFullSizeMode(boolean isOn);
-
-    /**
-     * The user clicked on the image.
-     */
-    public void onClickImage();
-  }
-
-  /**
-   * Displays a special image to indicate that an image's upload has failed
-   * and will never complete.
-   *
-   * @param tooltip to be shown when the mouse hovers over the error.
-   */
-  public void displayDeadImage(String tooltip);
-
-  /**
-   * Sets the URL that the attachment file is stored at
-   */
-  public void setAttachmentUrl(String url);
-
-  /**
-   * Sets the size of the attachment image.
-   *
-   * @param width image width (0 if unknown).
-   * @param height image height (0 if unknown).
-   */
-  public void setAttachmentSize(int width, int height);
-
-  /**
-   * Sets the URL for the thumbnail preview image
-   * @param url the non-null url
-   */
-  public void setThumbnailUrl(String url);
-
-  /**
-   * Sets the size of the thumbnail image.
-   *
-   * @param width image width (0 if unknown).
-   * @param height image height (0 if unknown).
-   */
-  public void setThumbnailSize(int width, int height);
-
-  /**
-   * Displays progress information
-   */
-  public void showUploadProgress();
-
-  /**
-   * Stops displaying progress information
-   */
-  public void hideUploadProgress();
-
-  /**
-   * Sets progress
-   * @param progress number between 0 and 1
-   */
-  public void setUploadProgress(double progress);
-
-  /**
-   * Choose displaymode
-   *
-   * @param isOn if true, full size mode, if false, thumbnail mode
-   */
-  void setFullSizeMode(boolean isOn);
-
-  /**
-   * Set listener for thumbnail UI events
-   *
-   * @param listener
-   */
-  void setListener(ImageThumbnailViewListener listener);
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/ImageThumbnailWidget.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/ImageThumbnailWidget.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/ImageThumbnailWidget.java
deleted file mode 100644
index ca6896b..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/ImageThumbnailWidget.java
+++ /dev/null
@@ -1,578 +0,0 @@
-/**
- * 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.
- */
-
-package org.waveprotocol.wave.client.doodad.attachment.render;
-
-import com.google.gwt.core.client.GWT;
-import com.google.gwt.dom.client.Element;
-import com.google.gwt.dom.client.Style;
-import com.google.gwt.dom.client.Style.Display;
-import com.google.gwt.dom.client.Style.Unit;
-import com.google.gwt.dom.client.Style.Visibility;
-import com.google.gwt.dom.client.StyleInjector;
-import com.google.gwt.event.dom.client.ClickEvent;
-import com.google.gwt.event.dom.client.ErrorEvent;
-import com.google.gwt.event.dom.client.ErrorHandler;
-import com.google.gwt.event.dom.client.LoadEvent;
-import com.google.gwt.event.dom.client.LoadHandler;
-import com.google.gwt.event.dom.client.MouseOutEvent;
-import com.google.gwt.event.dom.client.MouseOutHandler;
-import com.google.gwt.event.dom.client.MouseOverEvent;
-import com.google.gwt.event.dom.client.MouseOverHandler;
-import com.google.gwt.event.shared.HandlerRegistration;
-import com.google.gwt.resources.client.ClientBundle;
-import com.google.gwt.resources.client.CssResource;
-import com.google.gwt.resources.client.CssResource.NotStrict;
-import com.google.gwt.resources.client.DataResource;
-import com.google.gwt.resources.client.ImageResource;
-import com.google.gwt.resources.client.ImageResource.ImageOptions;
-import com.google.gwt.resources.client.ImageResource.RepeatStyle;
-import com.google.gwt.uibinder.client.UiBinder;
-import com.google.gwt.uibinder.client.UiField;
-import com.google.gwt.uibinder.client.UiHandler;
-import com.google.gwt.user.client.DOM;
-import com.google.gwt.user.client.Event;
-import com.google.gwt.user.client.ui.Composite;
-import com.google.gwt.user.client.ui.HTMLPanel;
-import com.google.gwt.user.client.ui.Image;
-import com.google.gwt.user.client.ui.Label;
-import com.google.gwt.user.client.ui.RootPanel;
-import com.google.gwt.user.client.ui.SimplePanel;
-import com.google.gwt.user.client.ui.Widget;
-
-import org.waveprotocol.wave.client.common.util.DomHelper;
-import org.waveprotocol.wave.client.common.util.UserAgent;
-import org.waveprotocol.wave.client.common.webdriver.DebugClassHelper;
-import org.waveprotocol.wave.client.scheduler.ScheduleCommand;
-import org.waveprotocol.wave.client.scheduler.Scheduler;
-import org.waveprotocol.wave.client.widget.button.ButtonFactory;
-import 
org.waveprotocol.wave.client.widget.button.ToggleButton.ToggleButtonListener;
-import org.waveprotocol.wave.client.widget.button.ToggleButtonWidget;
-import 
org.waveprotocol.wave.client.widget.button.icon.IconButtonTemplate.IconButtonStyle;
-import org.waveprotocol.wave.client.widget.progress.ProgressWidget;
-
-/**
- * Widget that implements a thumbnail structure.
- * Package-private as used only by ImageThumbnail.
- *
- */
-// TODO(user): replace with no widgets, only lightweight elements
-class ImageThumbnailWidget extends Composite implements ImageThumbnailView {
-
-  /** ClientBundle */
-  interface Resources extends ClientBundle {
-    /** Css */
-    interface Css extends CssResource {
-      /** Class for the thumbnail as a whole */
-      String imageThumbnail();
-      /** Class for the actual image */
-      String image();
-      /** Class applied to the progress widget */
-      String progress();
-      /** Class for the progress button */
-      String thumbSizeButton();
-    }
-
-    /** Css resource */
-    @Source("Thumbnail.css")
-    @NotStrict  // TODO(user): make Strict by including all classes in the 
CssResource
-    public Css css();
-
-    /** Thumbnail images */
-    @Source("thumb-n-2.png")
-    @ImageOptions(repeatStyle = RepeatStyle.Horizontal)
-    ImageResource chromeNorth();
-
-    @Source("thumb-ne-2.png")
-    @ImageOptions(flipRtl = true)
-    ImageResource chromeNorthEast();
-
-    @Source("thumb-e-2.png")
-    @ImageOptions(repeatStyle = RepeatStyle.Vertical, flipRtl = true)
-    ImageResource chromeEast();
-
-    @Source("thumb-se-2.png")
-    @ImageOptions(flipRtl = true)
-    ImageResource chromeSouthEast();
-
-    @Source("thumb-s-2.png")
-    @ImageOptions(repeatStyle = RepeatStyle.Horizontal)
-    ImageResource chromeSouth();
-
-    @Source("thumb-sw-2.png")
-    @ImageOptions(flipRtl = true)
-    ImageResource chromeSouthWest();
-
-    @Source("thumb-w-2.png")
-    @ImageOptions(repeatStyle = RepeatStyle.Vertical, flipRtl = true)
-    ImageResource chromeWest();
-
-    @Source("thumb-nw-2.png")
-    @ImageOptions(flipRtl = true)
-    ImageResource chromeNorthWest();
-
-    @Source("thumb-c-2.png")
-    @ImageOptions(repeatStyle = RepeatStyle.Horizontal)
-    ImageResource chromeCenter();
-
-    @Source("error.png")
-    @ImageOptions(flipRtl = true)
-    ImageResource errorAttachment();
-
-    /** loading images are animated GIF images.
-     *  DataResource is used instead of ImageResource to prevent conversion to 
PNG.
-     */
-    @Source("slow_loading.gif")
-    @ImageOptions(flipRtl = true)
-    DataResource chromeLoadingSlow();
-
-    @Source("slow_loading_fast.gif")
-    @ImageOptions(flipRtl = true)
-    DataResource chromeLoadingFast();
-
-    @Source("att_loading.gif")
-    @ImageOptions(flipRtl = true)
-    DataResource chromeLoadingAttachment();
-  }
-
-  private static class DoubleBufferImage {
-
-    /**
-     * An image object used to preload the thumbnail before we display it
-     */
-    private final Image doubleLoadedImage = new Image();
-    private final Image imageToLoad;
-
-    private final Widget spinner;
-    private final Widget error;
-
-    /**
-     * Create a double buffer loader for a given image widget
-     *
-     * @param spinner
-     * @param imageToLoad
-     */
-    public DoubleBufferImage(Widget spinner, Widget error, Image imageToLoad) {
-      if (UserAgent.isIE()) {
-        DomHelper.makeUnselectable(doubleLoadedImage.getElement());
-      }
-      this.spinner = spinner;
-      this.error = error;
-      this.imageToLoad = imageToLoad;
-    }
-
-    /**
-     * Registration of load handler to monitor the doubleLoadedImage to see if
-     * it has finished.
-     */
-    private HandlerRegistration onLoadHandlerRegistration;
-
-    /**
-     * Registration of error handler to monitor the doubleLoadedImage to see if
-     * it has finished.
-     */
-    private HandlerRegistration onErrorHandlerRegistration;
-
-    /**
-     * Handler for load + error events used by the double buffered image.
-     */
-    private class DoubleLoadHandler implements LoadHandler, ErrorHandler {
-      private final String url;
-      private boolean completed = false;
-
-      /***/
-      public DoubleLoadHandler(String url) {
-        this.url = url;
-      }
-
-      /** {@inheritDoc}) */
-      public void onError(ErrorEvent e) {
-        if (completed) {
-          return;
-        }
-        cleanUp();
-        spinner.setVisible(false);
-        error.setVisible(true);
-      }
-
-      /** {@inheritDoc}) */
-      public void onLoad(LoadEvent e) {
-        if (completed) {
-          return;
-        }
-        cleanUp();
-        spinner.setVisible(false);
-        imageToLoad.getElement().getStyle().clearVisibility();
-        imageToLoad.setUrl(url);
-      }
-
-      private void cleanUp() {
-        RootPanel.get().remove(doubleLoadedImage);
-
-        final HandlerRegistration onLoadReg = onLoadHandlerRegistration;
-        final HandlerRegistration onErrorReg = onErrorHandlerRegistration;
-
-        // HACK(user): There is a bug in GWT which stops us from removing a 
listener in HOSTED
-        // mode inside the invoke context.  Put the remove in a deferred 
command to avoid this
-        // error
-        ScheduleCommand.addCommand(new Scheduler.Task() {
-          public void execute() {
-            onLoadReg.removeHandler();
-            onErrorReg.removeHandler();
-          }
-        });
-
-        onLoadHandlerRegistration = null;
-        onErrorHandlerRegistration = null;
-
-        completed = true;
-      }
-    }
-
-    /**
-     * Get the thumbnail to load its image from the given url.
-     * @param url
-     */
-    public void loadImage(final String url) {
-      // Remove the old double loader to stop the last double buffered load.
-      if (onLoadHandlerRegistration != null) {
-        onLoadHandlerRegistration.removeHandler();
-        onErrorHandlerRegistration.removeHandler();
-
-        // We used to set doubleLoadedImage's url to "" here.
-        // It turns out to be a really bad thing to do.  Setting an url to null
-        // cause Wfe's bootstrap servelet to get called, which overload the 
server.
-        RootPanel.get().remove(doubleLoadedImage);
-      }
-
-      // set up the handler to hide spinning wheel when loading has finished
-      // We need to have the doubleLoadedImage created even if we are loading 
the image directly
-      // in imageToLoad.  This is done because we don't get a event otherwise.
-      DoubleLoadHandler doubleLoadHandler = new DoubleLoadHandler(url);
-      onLoadHandlerRegistration = 
doubleLoadedImage.addLoadHandler(doubleLoadHandler);
-      onErrorHandlerRegistration = 
doubleLoadedImage.addErrorHandler(doubleLoadHandler);
-
-      error.setVisible(false);
-      doubleLoadedImage.setVisible(false);
-      doubleLoadedImage.setUrl(url);
-      RootPanel.get().add(doubleLoadedImage);
-
-      imageToLoad.getElement().getStyle().setVisibility(Visibility.HIDDEN);
-
-      // If image is empty, show the url directly.
-      if (imageToLoad.getUrl().length() == 0) {
-        imageToLoad.setUrl(url);
-      }
-    }
-  }
-
-  /** UiBinder */
-  interface Binder extends UiBinder<HTMLPanel, ImageThumbnailWidget> {}
-  private static final Binder BINDER = GWT.create(Binder.class);
-
-  /**
-   * Singleton instance of resource bundle
-   */
-  static final Resources.Css css = 
GWT.<Resources>create(Resources.class).css();
-  static {
-    StyleInjector.inject(css.getText());
-  }
-
-  /**
-   * Specifies whether or not to set the width of the image container element.
-   */
-  private static final boolean DO_FRAME_WIDTH_UPDATE = UserAgent.isIE();
-
-  public ImageThumbnailWidget() {
-    initWidget(BINDER.createAndBindUi(this));
-
-    // Restore the desired attributes of widget elements in the template (GWT 
rips them out)
-
-    Element element = getElement();
-    addStyleName(css.imageThumbnail());
-    // Make the thumbnail as a whole uneditable and unselectable.
-    element.setAttribute("contentEditable", "false");
-    DomHelper.makeUnselectable(element);
-
-    errorLabel.setVisible(false);
-    spin.setVisible(true);
-
-    Element imageElement = image.getElement();
-    imageElement.addClassName(css.image());
-    imageElement.getStyle().setVisibility(Visibility.HIDDEN);
-
-    button = ButtonFactory.createIconToggleButton(
-        IconButtonStyle.PLUS_MINUS, "Options", new ToggleButtonListener() {
-          public void onOff() {
-            Event.getCurrentEvent().stopPropagation();
-            Event.getCurrentEvent().preventDefault();
-            if (listener != null) {
-              listener.onRequestSetFullSizeMode(false);
-            }
-          }
-
-          public void onOn() {
-            Event.getCurrentEvent().stopPropagation();
-            Event.getCurrentEvent().preventDefault();
-            if (listener != null) {
-              listener.onRequestSetFullSizeMode(true);
-            }
-          }
-        });
-    button.addStyleName(css.thumbSizeButton());
-    DebugClassHelper.addDebugClass(button.getElement(), "image_toggle");
-
-    menuButtonContainer.add(button);
-    final Element buttonContainerElement = menuButtonContainer.getElement();
-
-    buttonContainerElement.getStyle().setDisplay(Display.NONE);
-
-    addDomHandler(new MouseOverHandler() {
-      public void onMouseOver(MouseOverEvent event) {
-        if (isContentImage() && !errorLabel.isVisible()) {
-          resizeButtonVisible = true;
-          updateResizeButton();
-        }
-      }
-    }, MouseOverEvent.getType());
-
-    addDomHandler(new MouseOutHandler() {
-      public void onMouseOut(MouseOutEvent event) {
-        resizeButtonVisible = false;
-        updateResizeButton();
-      }
-    }, MouseOutEvent.getType());
-  }
-
-  @UiHandler("image")
-  void onImageClicked(ClickEvent ignored) {
-    handleImageRegionClicked();
-  }
-
-  @UiHandler("spin")
-  void onSpinClicked(ClickEvent ignored) {
-    handleImageRegionClicked();
-  }
-
-  @UiHandler("errorLabel")
-  void onErrorClicked(ClickEvent ignored) {
-    handleImageRegionClicked();
-  }
-
-  private void handleImageRegionClicked() {
-    if (listener != null) {
-      listener.onClickImage();
-    }
-  }
-
-  /**
-   * The double buffer loaded used to load the thumbnail.
-   */
-  private DoubleBufferImage doubleBufferLoader;
-
-  /**
-   * Image widget representing the thumbnail image.
-   */
-  @UiField Image image;
-
-  /**
-   * The container to which we will add our drop down menu button
-   */
-  @UiField SimplePanel menuButtonContainer;
-
-  /**
-   * Caption panel to put the caption.
-   */
-  @UiField SimplePanel captionPanel;
-
-  /**
-   * The Label that contains the spinning wheel
-   */
-  @UiField Label spin;
-
-  /**
-   * The Label that contains the error image
-   */
-  @UiField Label errorLabel;
-
-  /**
-   * The fancy chrome around the thumbnail
-   */
-  @UiField HTMLPanel chromeContainer;
-
-  /**
-   * The progress widget.
-   */
-  @UiField ProgressWidget progressWidget;
-
-  private String attachmentUrl;
-
-  private String thumbnailUrl;
-
-  private ImageThumbnailViewListener listener;
-
-  private final ToggleButtonWidget button;
-
-  private boolean resizeButtonVisible = false;
-
-  // logical state
-
-  // TODO(danilatos): Move this state out of the display. Ideally displays 
should
-  // be stateless.
-  private boolean isFullSize = false;
-
-  private int thumbnailWidth, thumbnailHeight;
-
-  private int attachmentWidth, attachmentHeight;
-
-  private final Scheduler.Task clearButtonTask = new Scheduler.Task() {
-    public void execute() {
-      Style style = menuButtonContainer.getElement().getStyle();
-      if (resizeButtonVisible) {
-        style.setDisplay(Display.BLOCK);
-      } else {
-        style.setDisplay(Display.NONE);
-      }
-    }
-  };
-
-  @Override
-  public void displayDeadImage(String toolTip) {
-    this.hideUploadProgress();
-    this.spin.setVisible(false);
-    this.errorLabel.setTitle(toolTip);
-    this.errorLabel.setVisible(true);
-  }
-
-  @Override
-  public void setListener(ImageThumbnailViewListener listener) {
-    this.listener = listener;
-  }
-
-  @Override
-  public void setThumbnailUrl(String url) {
-    this.thumbnailUrl = url;
-  }
-
-  @Override
-  public void setAttachmentUrl(String url) {
-    this.attachmentUrl = url;
-  }
-
-  @Override
-  public void setThumbnailSize(int width, int height) {
-    this.thumbnailWidth = width;
-    this.thumbnailHeight = height;
-
-    if (!isFullSize) {
-      setImageSize();
-    }
-  }
-
-  @Override
-  public void setAttachmentSize(int width, int height) {
-    this.attachmentWidth = width;
-    this.attachmentHeight = height;
-
-    if (isFullSize) {
-      setImageSize();
-    }
-  }
-
-  @Override
-  public void setFullSizeMode(boolean isOn) {
-    isFullSize = isOn;
-    button.setOn(isOn);
-    if (isOn) {
-      chromeContainer.getElement().getStyle().setDisplay(Display.NONE);
-    } else {
-      chromeContainer.getElement().getStyle().clearDisplay();
-    }
-    setImageSize();
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public void showUploadProgress() {
-    progressWidget.setVisible(true);
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public void hideUploadProgress() {
-    progressWidget.setVisible(false);
-  }
-
-  /** {@inheritDoc} */
-  @Override
-  public void setUploadProgress(double progress) {
-    progressWidget.setValue(progress);
-  }
-
-  /**
-   * @return element the caption will be appended to
-   */
-  public Element getCaptionContainer() {
-    return captionPanel.getElement();
-  }
-
-  private void updateResizeButton() {
-    ScheduleCommand.addCommand(clearButtonTask);
-  }
-
-  private void setImageSize() {
-    int width = isFullSize?attachmentWidth:thumbnailWidth;
-    int height = isFullSize?attachmentHeight:thumbnailHeight;
-    image.setPixelSize(width, height);
-    //TODO(user,danilatos): Whinge about how declarative UI doesn't let us 
avoid this hack:
-    Style pstyle = 
image.getElement().getParentElement().getParentElement().getStyle();
-    if (width == 0) {
-      image.setWidth("");
-      pstyle.clearWidth();
-    } else {
-      pstyle.setWidth(width, Unit.PX);
-    }
-    if (height == 0) {
-      image.setHeight("");
-      pstyle.clearHeight();
-    } else {
-      pstyle.setHeight(height, Unit.PX);
-    }
-
-    String url = isFullSize?attachmentUrl:thumbnailUrl;
-    if (url != null) {
-      if (doubleBufferLoader == null) {
-        doubleBufferLoader = new DoubleBufferImage(spin, errorLabel, image);
-      }
-      doubleBufferLoader.loadImage(url);
-      DOM.setStyleAttribute(image.getElement(), "visibility", "");
-    }
-
-    // NOTE(user): IE requires that the imageCaptionContainer element has a 
width
-    //   in order to correctly center the caption.
-    if (DO_FRAME_WIDTH_UPDATE) {
-      captionPanel.getElement().getStyle().setWidth(width, Unit.PX);
-    }
-  }
-
-  private boolean isContentImage() {
-    return attachmentWidth != 0 && attachmentHeight != 0;
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/ImageThumbnailWrapper.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/ImageThumbnailWrapper.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/ImageThumbnailWrapper.java
deleted file mode 100644
index 1c4d6be..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/ImageThumbnailWrapper.java
+++ /dev/null
@@ -1,133 +0,0 @@
-/**
- * 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.
- */
-
-package org.waveprotocol.wave.client.doodad.attachment.render;
-
-import org.waveprotocol.wave.client.doodad.attachment.ImageThumbnail;
-import org.waveprotocol.wave.client.editor.content.CMutableDocument;
-import org.waveprotocol.wave.client.editor.content.ContentElement;
-import org.waveprotocol.wave.client.editor.content.ContentNode;
-import org.waveprotocol.wave.client.editor.content.misc.Caption;
-import org.waveprotocol.wave.media.model.Attachment;
-import org.waveprotocol.wave.model.document.util.DocHelper;
-import org.waveprotocol.wave.model.document.util.Point;
-import org.waveprotocol.wave.model.document.util.Property;
-import org.waveprotocol.wave.model.document.util.XmlStringBuilderDoc;
-
-/**
- * A per-instance wrapper to provide an interface over image thumbnail elements
- *
- * TODO(danilatos): Find a nice way to get rid of this?
- *
- * @author [email protected] (Daniel Danilatos)
- */
-public class ImageThumbnailWrapper {
-  /**
-   * Property for storing an instance of this wrapper on a thumbnail element
-   */
-  static final Property<ImageThumbnailWrapper> PROPERTY = 
Property.immutable("wrapper");
-
-  /** Element being wrapped. */
-  private final ContentElement element;
-
-  /** Attachment. */
-  private Attachment attachment;
-
-  /**
-   * @param element the element being wrapped
-   */
-  public ImageThumbnailWrapper(ContentElement element) {
-    this.element = element;
-  }
-
-  /**
-   * Gets the wrapper for an element, if it has one.
-   *
-   * @return wrapper for {@code e}.
-   */
-  public static ImageThumbnailWrapper of(ContentElement e) {
-    return e.getProperty(ImageThumbnailWrapper.PROPERTY);
-  }
-
-  void setAttachment(Attachment a) {
-    attachment = a;
-  }
-
-  /**
-   * @return attachment of the thumbnail.
-   */
-  public Attachment getAttachment() {
-    return attachment;
-  }
-
-  /**
-   * Sets the attachment id of this doodad.
-   */
-  public void setAttachmentId(String id) {
-    element.getMutableDoc().setElementAttribute(element, 
ImageThumbnail.ATTACHMENT_ATTR, id);
-  }
-
-  /**
-   * Sets the caption text of this doodad.
-   */
-  public void setCaptionText(String text) {
-    CMutableDocument doc = element.getMutableDoc();
-    ContentElement caption = DocHelper.getElementWithTagName(doc, 
Caption.TAGNAME, element);
-    if (caption != null) {
-      doc.emptyElement(caption);
-      doc.insertText(Point.<ContentNode> end(caption), text);
-    }
-  }
-
-  /**
-   * Gets the text of the image caption
-   */
-  public String getCaptionText() {
-    CMutableDocument doc = element.getMutableDoc();
-    return DocHelper.getText(doc, doc, doc.getLocation(element),
-        doc.getLocation(Point.end((ContentNode) element)));
-  }
-
-  /**
-   * Deletes this doodad from its document.
-   */
-  public void delete() {
-    element.getMutableDoc().deleteNode(element);
-  }
-
-  /**
-   * Renders this wrapper's element into a string builder.
-   *
-   * @param builder  builder into which this wrapper's element is appended,
-   *                 or null if this wrapper should produce a builder
-   * @return resulting XML builder.
-   */
-  public XmlStringBuilderDoc<? super ContentElement, ContentElement, ?>
-      appendInto(XmlStringBuilderDoc<? super ContentElement, ContentElement, 
?> builder) {
-    if (builder == null) {
-      builder = XmlStringBuilderDoc.createEmpty(element.getMutableDoc());
-    }
-    builder.appendNode(element);
-    return builder;
-  }
-
-  public ContentElement getElement() {
-    return element;
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/att_loading.gif
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/att_loading.gif
 
b/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/att_loading.gif
deleted file mode 100644
index afa3da4..0000000
Binary files 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/att_loading.gif
 and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/slow_loading.gif
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/slow_loading.gif
 
b/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/slow_loading.gif
deleted file mode 100644
index c45d20b..0000000
Binary files 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/slow_loading.gif
 and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/slow_loading_fast.gif
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/slow_loading_fast.gif
 
b/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/slow_loading_fast.gif
deleted file mode 100755
index 8b07f72..0000000
Binary files 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/render/slow_loading_fast.gif
 and /dev/null differ

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/testing/FakeAttachment.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/testing/FakeAttachment.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/testing/FakeAttachment.java
deleted file mode 100644
index 0ab6a1e..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/testing/FakeAttachment.java
+++ /dev/null
@@ -1,130 +0,0 @@
-/**
- * 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.
- */
-
-package org.waveprotocol.wave.client.doodad.attachment.testing;
-
-import org.waveprotocol.wave.media.model.Attachment;
-
-/**
- * Super simple attachment
- *
- */
-// TODO(nigeltao): Replace this Fake by a mockito Mock.
-public class FakeAttachment implements Attachment {
-
-  private final String url;
-  private final int thumbWidth;
-  private final int thumbHeight;
-  private final String mimeType;
-
-  public FakeAttachment(String url, int thumbWidth, int thumbHeight, String 
mimeType) {
-    this.url = url;
-    this.thumbWidth = thumbWidth;
-    this.thumbHeight = thumbHeight;
-    this.mimeType = mimeType;
-  }
-
-  public String getAttachmentId() {
-    return url;
-  }
-
-  public String getCreator() {
-    return "[email protected]";
-  }
-
-  public String getMimeType() {
-    return mimeType;
-  }
-
-  public boolean isMalware() {
-    return false;
-  }
-
-  public ImageMetadata getContentImageMetadata() {
-    // Pretend the image height and width match the thumbnail height and width.
-    if (thumbWidth != 0 && thumbHeight != 0) {
-      return new ImageMetadata() {
-        @Override
-        public int getHeight() {
-          return thumbHeight;
-        }
-
-        @Override
-        public int getWidth() {
-          return thumbWidth;
-        }
-      };
-    }
-    return null;
-  }
-
-  public ImageMetadata getThumbnailImageMetadata() {
-    if (thumbWidth != 0 && thumbHeight != 0) {
-      return new ImageMetadata() {
-        @Override
-        public int getHeight() {
-          return thumbHeight;
-        }
-
-        @Override
-        public int getWidth() {
-          return thumbWidth;
-        }
-      };
-    }
-    return null;
-  }
-
-
-  @Override
-  public Status getStatus() {
-    return Status.NOT_UPLOADING;
-  }
-
-  @Override
-  public String getAttachmentUrl() {
-    return url;
-  }
-
-  @Override
-  public String getFilename() {
-    throw new AssertionError("Not implemented");
-  }
-
-  @Override
-  public Long getSize() {
-    throw new AssertionError("Not implemented");
-  }
-
-  @Override
-  public String getThumbnailUrl() {
-    return url;
-  }
-
-  @Override
-  public long getUploadRetryCount() {
-    return 0;
-  }
-
-  @Override
-  public long getUploadedByteCount() {
-    return 0;
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/testing/FakeAttachmentsManager.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/testing/FakeAttachmentsManager.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/testing/FakeAttachmentsManager.java
deleted file mode 100644
index af18c31..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/attachment/testing/FakeAttachmentsManager.java
+++ /dev/null
@@ -1,69 +0,0 @@
-/**
- * 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.
- */
-
-package org.waveprotocol.wave.client.doodad.attachment.testing;
-
-import org.waveprotocol.wave.client.doodad.attachment.SimpleAttachmentManager;
-import org.waveprotocol.wave.media.model.Attachment;
-import org.waveprotocol.wave.model.util.CollectionUtils;
-import org.waveprotocol.wave.model.util.IdentitySet;
-import org.waveprotocol.wave.model.util.StringMap;
-
-
-/**
- * Super-simple Attachment manager for use with test harness
- *
- * @author [email protected] (Daniel Danilatos)
- */
-// TODO(nigeltao): Replace this Fake by a mockito Mock.
-public class FakeAttachmentsManager implements SimpleAttachmentManager {
-  private final StringMap<FakeAttachment> map = 
CollectionUtils.createStringMap();
-  private final IdentitySet<Listener> listeners = 
CollectionUtils.createIdentitySet();
-
-  public FakeAttachment createFakeAttachment(
-      String url, int thumbnailWidth, int thumbnailHeight) {
-    return createFakeAttachment(url, thumbnailWidth, thumbnailHeight, 
"application/octet-stream");
-  }
-
-  public FakeAttachment createFakeAttachment(
-      String url, int thumbnailWidth, int thumbnailHeight, String mimeType) {
-    FakeAttachment a = new FakeAttachment(url, thumbnailWidth, 
thumbnailHeight, mimeType);
-    map.put(url, a);
-    return a;
-  }
-
-  public FakeAttachmentsManager() {
-  }
-
-  @Override
-  public void addListener(Listener l) {
-    listeners.add(l);
-  }
-
-  @Override
-  public Attachment getAttachment(String id) {
-    return id != null ? map.get(id) : null;
-  }
-
-  @Override
-  public void removeListener(Listener l) {
-    listeners.remove(l);
-  }
-
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/doodad/diff/DiffAnnotationHandler.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/diff/DiffAnnotationHandler.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/doodad/diff/DiffAnnotationHandler.java
deleted file mode 100644
index f47ed82..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/diff/DiffAnnotationHandler.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/**
- * 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.
- */
-
-package org.waveprotocol.wave.client.doodad.diff;
-
-import org.waveprotocol.wave.client.editor.content.AnnotationPainter;
-import 
org.waveprotocol.wave.client.editor.content.AnnotationPainter.BoundaryFunction;
-import 
org.waveprotocol.wave.client.editor.content.AnnotationPainter.PaintFunction;
-import org.waveprotocol.wave.client.editor.content.ContentElement;
-import org.waveprotocol.wave.client.editor.content.DiffHighlightingFilter;
-import 
org.waveprotocol.wave.client.editor.content.DiffHighlightingFilter.DeleteInfo;
-import org.waveprotocol.wave.client.editor.content.PainterRegistry;
-import org.waveprotocol.wave.model.document.AnnotationMutationHandler;
-import org.waveprotocol.wave.model.document.util.AnnotationRegistry;
-import org.waveprotocol.wave.model.document.util.DocumentContext;
-import org.waveprotocol.wave.model.document.util.LocalDocument;
-import org.waveprotocol.wave.model.util.CollectionUtils;
-import org.waveprotocol.wave.model.util.ReadableStringSet;
-
-import java.util.Collections;
-import java.util.Map;
-
-/**
- * Defines behaviour for rendering diffs
- *
- * @author [email protected] (Daniel Danilatos)
- */
-public class DiffAnnotationHandler implements AnnotationMutationHandler {
-  /** Colour used for diff hilights of new content. */
-  private static final String HILIGHT_COLOUR = "yellow";
-
-  /** Annotation key prefix. */
-  public static final String PREFIX = DiffHighlightingFilter.DIFF_KEY;
-
-  /** Set of annotation keys that the paint function is interested in. */
-  private final static ReadableStringSet PAINT_KEYS =
-      CollectionUtils.newStringSet(DiffHighlightingFilter.DIFF_INSERT_KEY);
-
-  /** Set of annotation keys that the boundary function is interested in. */
-  private final static ReadableStringSet BOUNDARY_KEYS =
-    CollectionUtils.newStringSet(DiffHighlightingFilter.DIFF_DELETE_KEY);
-
-  /** Map of annotations for the diff paint renderer. */
-  private final static Map<String, String> PAINT_PROPERTIES =
-      Collections.singletonMap("backgroundColor", HILIGHT_COLOUR);
-
-  /**
-   * Create and register a style annotation handler
-   *
-   * @param annotationRegistry registry to register on
-   * @param painterRegistry painter registry to use for rendering
-   */
-  public static void register(AnnotationRegistry annotationRegistry,
-      PainterRegistry painterRegistry) {
-
-    painterRegistry.registerPaintFunction(PAINT_KEYS, paintFunc);
-    painterRegistry.registerBoundaryFunction(BOUNDARY_KEYS, boundaryFunc);
-
-    annotationRegistry.registerHandler(PREFIX,
-        new DiffAnnotationHandler(painterRegistry.getPainter()));
-  }
-
-  /** Painter to access regional repainting of diff areas. */
-  private final AnnotationPainter painter;
-
-  /**
-   * Paint function for normal diffs, sets the background colour of the new
-   * content .
-   */
-  private static final PaintFunction paintFunc = new PaintFunction() {
-    public Map<String, String> apply(Map<String, Object> from, boolean 
isEditing) {
-      if (from.get(DiffHighlightingFilter.DIFF_INSERT_KEY) != null) {
-        return PAINT_PROPERTIES;
-      } else {
-        return Collections.emptyMap();
-      }
-    }
-  };
-
-  /** Paint function for diff deletions. */
-  private static final BoundaryFunction boundaryFunc = new BoundaryFunction() {
-        public <N, E extends N, T extends N> E apply(LocalDocument<N, E, T> 
localDoc, E parent,
-        N nodeAfter, Map<String, Object> before, Map<String, Object> after, 
boolean isEditing) {
-      Object obj = after.get(DiffHighlightingFilter.DIFF_DELETE_KEY);
-      if (obj != null) {
-        // HACK(danilatos): Assume the elements are of this implementation.
-        assert obj instanceof DeleteInfo : "delete key's value must be a 
DeleteInfo";
-
-        // find the element, then set internal deleted content in the DOM
-        E elt = localDoc.transparentCreate(DiffDeleteRenderer.FULL_TAGNAME,
-            Collections.<String,String>emptyMap(), parent, nodeAfter);
-
-        DiffDeleteRenderer.getInstance().setInnards((ContentElement) elt,
-            ((DeleteInfo) obj).getDeletedHtmlElements());
-        return elt;
-      } else {
-        return null;
-      }
-    }
-  };
-
-  /**
-   * Construct the handler, registering its rendering functions with the 
painter.
-   * @param painter painter to use for rendering
-   */
-  public DiffAnnotationHandler(AnnotationPainter painter) {
-    this.painter = painter;
-  }
-
-  @Override
-  public <N, E extends N, T extends N> void 
handleAnnotationChange(DocumentContext<N, E, T> bundle,
-      int start, int end, String key, Object newValue) {
-    painter.scheduleRepaint(bundle, start, end);
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/doodad/diff/DiffDeleteRenderer.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/diff/DiffDeleteRenderer.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/doodad/diff/DiffDeleteRenderer.java
deleted file mode 100644
index 8436dd9..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/diff/DiffDeleteRenderer.java
+++ /dev/null
@@ -1,78 +0,0 @@
-/**
- * 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.
- */
-
-package org.waveprotocol.wave.client.doodad.diff;
-
-import com.google.gwt.dom.client.Document;
-import com.google.gwt.dom.client.Element;
-
-import org.waveprotocol.wave.client.common.util.DomHelper;
-import org.waveprotocol.wave.client.editor.ElementHandlerRegistry;
-import org.waveprotocol.wave.client.editor.content.ContentElement;
-import org.waveprotocol.wave.client.editor.content.Renderer;
-
-import java.util.List;
-
-/**
- * Renders diff content for things that have been removed since last view.
- *
- * @author [email protected] (Daniel Danilatos)
- * @author [email protected] (Pat Coleman)
- */
-public class DiffDeleteRenderer implements Renderer {
-  /** Singleton instance: */
-  private static DiffDeleteRenderer instance;
-  public static DiffDeleteRenderer getInstance() {
-    if (instance == null) {
-      instance = new DiffDeleteRenderer();
-    }
-    return instance;
-  }
-
-  /** Tag details: */
-  public static final String FULL_TAGNAME = "l:diffdel";
-
-  /**
-   * Registers subclass with ContentElement
-   */
-  public static void register(ElementHandlerRegistry handlerRegistry) {
-    // register the annotation handler:
-    handlerRegistry.registerRenderer(FULL_TAGNAME, getInstance());
-  }
-
-  /** Create a renderer, taking an object to use to manage properties. */
-  private DiffDeleteRenderer() {
-  }
-
-  /** Adds internal html of deleted contents to a diff element. */
-  public void setInnards(ContentElement element, List<Element> deletedStuff) {
-    Element nodelet = element.getContainerNodelet(); // first find DOM element
-    for (Element e : deletedStuff) {
-      nodelet.appendChild(e);
-    }
-  }
-
-  @Override
-  public Element createDomImpl(Renderable element) {
-    Element nodelet = Document.get().createSpanElement();
-    DomHelper.makeUnselectable(nodelet);
-    DomHelper.setContentEditable(nodelet, false, true);
-    return element.setAutoAppendContainer(nodelet);
-  }
-}

http://git-wip-us.apache.org/repos/asf/incubator-wave/blob/051db092/wave/src/main/java/org/waveprotocol/wave/client/doodad/experimental/htmltemplate/CajoleService.java
----------------------------------------------------------------------
diff --git 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/experimental/htmltemplate/CajoleService.java
 
b/wave/src/main/java/org/waveprotocol/wave/client/doodad/experimental/htmltemplate/CajoleService.java
deleted file mode 100644
index 16dd553..0000000
--- 
a/wave/src/main/java/org/waveprotocol/wave/client/doodad/experimental/htmltemplate/CajoleService.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * 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.
- */
-
-package org.waveprotocol.wave.client.doodad.experimental.htmltemplate;
-
-/**
- * A service that "cajoles" an HTML page referenced via a URL.
- */
-public interface CajoleService {
-
-  /** The response from the cajoer. */
-  public interface CajolerResponse {
-    // TODO: Consider using SafeHtml.
-    String getHtml();
-    String getJs();
-  }
-
-  /**
-   * Requests that the content reference by a URL be cajoled.
-   */
-  void cajole(String url, Callback<? super CajolerResponse> callback);
-}
\ No newline at end of file

Reply via email to