/* * Copyright (C) 2010 Jan Pokorsky * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package cz.incad.kramerius.editor.client.view; import com.allen_sauer.gwt.dnd.client.HasDragHandle; import com.google.gwt.core.client.GWT; 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.shared.HandlerRegistration; 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.ui.Anchor; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.Image; import com.google.gwt.user.client.ui.Label; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.Widget; import java.util.ArrayList; import java.util.List; /** * XXX implement proper handling of inaccessible thumbnails * * @author Jan Pokorsky */ public final class ElementViewImpl extends Composite implements ElementView, HasDragHandle { public interface ElementViewUiBinder extends UiBinder<Widget, ElementViewImpl> {} private static ElementViewUiBinder uiBinder = GWT.create(ElementViewUiBinder.class); private Callback callback; private PopupPanel popupPanel; @UiField Image elmImage; @UiField Label elmLabel; @UiField Label elmModelLabel; @UiField Label elmRootLabel; @UiField Label elmDetail; @UiField Anchor elmPreview; @UiField Anchor elmOpen; public ElementViewImpl() { initWidget(uiBinder.createAndBindUi(this)); } @Override public void setLocation(String url) { elmImage.setUrl(url); // XXX ImageConsumerQueue needs more investigation // ImageConsumerQueue.addConsumer(elmImage, url); } @Override public void showPreview(String url) { if (popupPanel == null) { initPopupUI(url); } // menuPopup.hide(); popupPanel.center(); } @Override public void setRootTitle(String s) { this.elmRootLabel.setText(s); } @Override public void setDetail(String d) { this.elmDetail.setText(d);; } @Override public void setLabel(String s) { elmLabel.setText(s); } @Override public void setModel(String d) { elmModelLabel.setText(d); } @Override public void setTooltip(String s) { //elmLabel.setTitle(s); this.elmImage.setTitle(s); } @Override public Widget asWidget() { return this; } @Override public Widget getDragHandle() { return elmImage; } @Override public void setCallback(Callback c) { this.callback = c; } @Override public void setOpenEnabled(boolean b) { elmOpen.setVisible(b); } @UiHandler("elmPreview") void onPreviewClick(ClickEvent ce) { callback.onPreviewClick(); } @UiHandler("elmOpen") void onOpenClick(ClickEvent ce) { callback.onOpenClick(); } private void initPopupUI(final String url) { popupPanel = new PopupPanel(true, true); popupPanel.setAnimationEnabled(true); final Image preview = new Image(); final Label status = new Label("Loading..."); FlowPanel flowPanel = new FlowPanel(); flowPanel.add(status); flowPanel.add(preview); popupPanel.setWidget(flowPanel); preview.setVisible(false); preview.addLoadHandler(new LoadHandler() { @Override public void onLoad(LoadEvent event) { preview.setVisible(true); status.setVisible(false); centerUpdatedPopupWorkaround(popupPanel); } }); preview.addErrorHandler(new ErrorHandler() { @Override public void onError(ErrorEvent event) { status.setText("Cannot load image " + url); centerUpdatedPopupWorkaround(popupPanel); } }); preview.setUrl(url); } /** * @see http://code.google.com/p/google-web-toolkit/issues/detail?id=4221 */ private static void centerUpdatedPopupWorkaround(PopupPanel pp) { pp.center(); // pp.center(); // pp.center(); } @Override public String toString() { String objectToString = getClass().getName() + "@" + Integer.toHexString(hashCode()); return objectToString + "[" + (elmLabel == null ? "not initialized" : elmLabel.getText()) + "]"; } public interface ImageConsumer { void consumeImage(Image im); } /** * The class should help not to overload browser and web server * with multiple concurrent requests to load images. The browser seems to be * more responsive then. * XXX try to load 4 images at once */ private static final class ImageConsumerQueue implements LoadHandler, ErrorHandler { private static ImageConsumerQueue INSTANCE = new ImageConsumerQueue(); private List<String> locations = new ArrayList<String>(); private List<Image> iconsumers = new ArrayList<Image>(); private HandlerRegistration imageLoadHandler; private HandlerRegistration imageErrorHandler; public static void addConsumer(Image consumer, String location) { boolean isRunning = !INSTANCE.locations.isEmpty(); INSTANCE.locations.add(location); INSTANCE.iconsumers.add(consumer); if (!isRunning) { INSTANCE.runTask(); } } private void prepareNextTask() { String location = locations.remove(0); iconsumers.remove(0); imageLoadHandler.removeHandler(); imageErrorHandler.removeHandler(); // System.out.println("##runTask.loaded: " + location); runTask(); } private void runTask() { if (locations.isEmpty()) { return; } String location = locations.get(0); Image image = iconsumers.get(0); imageLoadHandler = image.addLoadHandler(this); imageErrorHandler = image.addErrorHandler(this); image.setUrl(location); // System.out.println("##runTask.location: " + location); } @Override public void onLoad(LoadEvent event) { prepareNextTask(); } @Override public void onError(ErrorEvent event) { prepareNextTask(); } } }