001/*
002 * (C) Copyright 2006-2008 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     troger
018 *
019 * $Id$
020 */
021
022package org.nuxeo.ecm.platform.pictures.tiles.gwt.client.view;
023
024import java.util.HashMap;
025import java.util.Map;
026
027import org.nuxeo.ecm.platform.pictures.tiles.gwt.client.controller.TilingController;
028import org.nuxeo.ecm.platform.pictures.tiles.gwt.client.model.TilingModel;
029import org.nuxeo.ecm.platform.pictures.tiles.gwt.client.model.TilingModelListener;
030import org.nuxeo.ecm.platform.pictures.tiles.gwt.client.model.TilingModel.TilingModelEvent;
031import org.nuxeo.ecm.platform.pictures.tiles.gwt.client.util.Point;
032import org.nuxeo.ecm.platform.pictures.tiles.gwt.client.util.Rectangle;
033import org.nuxeo.ecm.platform.pictures.tiles.gwt.client.view.i18n.TranslationConstants;
034
035import com.allen_sauer.gwt.log.client.Log;
036import com.google.gwt.core.client.GWT;
037import com.google.gwt.user.client.Window;
038import com.google.gwt.user.client.ui.AbsolutePanel;
039import com.google.gwt.user.client.ui.Button;
040import com.google.gwt.user.client.ui.ClickListener;
041import com.google.gwt.user.client.ui.Composite;
042import com.google.gwt.user.client.ui.HorizontalPanel;
043import com.google.gwt.user.client.ui.Image;
044import com.google.gwt.user.client.ui.Widget;
045
046/**
047 * @author <a href="mailto:troger@nuxeo.com">Thomas Roger</a>
048 */
049public class TilingPreviewPanel extends Composite implements TilingModelListener {
050
051    private static final String DEFAULT_CLASS_NAME = "tilingPreviewPanel";
052
053    private AbsolutePanel tilingViewPanel;
054
055    private AbsolutePanel tilingView;
056
057    private final TilingController controller;
058
059    private final TilingModel model;
060
061    private final Map<String, Image> images = new HashMap<String, Image>();
062
063    public TilingPreviewPanel(TilingController tilingController, TilingModel tilingModel) {
064        controller = tilingController;
065        model = tilingModel;
066        model.addListener(this);
067
068        // create the panel to show the part of the image
069        tilingViewPanel = new AbsolutePanel();
070        tilingViewPanel.setPixelSize(model.getViewAreaWidth(), model.getViewAreaHeight());
071        tilingView = new AbsolutePanel();
072        tilingViewPanel.add(tilingView);
073
074        tilingViewPanel.addStyleName("tilingViewPanel");
075
076        AbsolutePanel rootPanel = new AbsolutePanel();
077        rootPanel.setPixelSize(model.getViewAreaWidth(), model.getViewAreaHeight());
078        rootPanel.addStyleName("tilingMasterContainer");
079        rootPanel.add(tilingViewPanel, 0, 0);
080
081        HorizontalPanel hPanel = createZoomButtons();
082        rootPanel.add(hPanel, 20, 20);
083
084        initWidget(rootPanel);
085
086        setStyleName(DEFAULT_CLASS_NAME);
087    }
088
089    private HorizontalPanel createZoomButtons() {
090        HorizontalPanel buttons = new HorizontalPanel();
091
092        TranslationConstants translationContants = GWT.create(TranslationConstants.class);
093
094        Button resetZoomButton = new Button();
095        resetZoomButton.addClickListener(new ClickListener() {
096            public void onClick(Widget arg0) {
097                Window.Location.assign(Window.Location.getHref());
098                decorate();
099            }
100        });
101        resetZoomButton.addStyleName("resetZoomButton");
102        resetZoomButton.setTitle(translationContants.zoom());
103        buttons.add(resetZoomButton);
104
105        Button zoomInButton = new Button();
106        zoomInButton.addClickListener(new ClickListener() {
107            public void onClick(Widget arg0) {
108                model.zoomIn();
109            }
110        });
111        zoomInButton.addStyleName("zoomInButton");
112        zoomInButton.setTitle(translationContants.zoomIn());
113        buttons.add(zoomInButton);
114
115        Button zoomOutButton = new Button();
116        zoomOutButton.addClickListener(new ClickListener() {
117            public void onClick(Widget arg0) {
118                model.zoomOut();
119            }
120        });
121        zoomOutButton.addStyleName("zoomOutButton");
122        zoomOutButton.setTitle(translationContants.zoomOut());
123        buttons.add(zoomOutButton);
124
125        return buttons;
126    }
127
128    public void onModelChange(TilingModelEvent event, TilingModel model) {
129        switch (event) {
130        case MOVE_EVENT:
131            // update the view (move)
132            renderView();
133            break;
134        case TILING_INFO_UPDATED:
135            // clean and reload the view
136            resetView();
137            renderView();
138            break;
139        }
140    }
141
142    private void renderView() {
143        int widthInTiles = model.getWidthInTiles();
144        int heightInTiles = model.getHeightInTiles();
145
146        int top = model.getViewAreaTop();
147        int left = model.getViewAreaLeft();
148        int width = model.getViewAreaWidth();
149        int height = model.getViewAreaHeight();
150
151        Rectangle viewableArea = new Rectangle(new Point(left, top), width, height);
152
153        tilingView.clear();
154        for (int y = 0; y < heightInTiles; ++y) {
155            for (int x = 0; x < widthInTiles; ++x) {
156                String imageUrl = model.getBaseUrl() + "?x=" + x + "&y=" + y;
157                imageUrl += "&date=" + model.getLastModificationDate();
158
159                int imageLeft = x * model.getTileWidth();
160                int imageTop = y * model.getTileHeight();
161                int imageRight = imageLeft + model.getTileWidth();
162                int imageBottom = imageTop + model.getTileHeight();
163
164                Point imageTopLeft = new Point(imageLeft, imageTop);
165                Point imageTopRight = new Point(imageRight, imageTop);
166                Point imageBottomLeft = new Point(imageLeft, imageBottom);
167                Point imageBottomRight = new Point(imageRight, imageBottom);
168
169                if (!viewableArea.containsAny(imageTopLeft, imageBottomLeft, imageTopRight, imageBottomRight)) {
170                    // Always draw the first image. It's used to display the
171                    // annotations
172                    if (!(x == 0 && y == 0)) {
173                        continue;
174                    }
175                }
176
177                Log.debug("Getting image: " + imageUrl);
178                Image image = getImage(imageUrl);
179
180                if (x == 0 && y == 0) {
181                    image.getElement().setId("annotationRootImage");
182                }
183
184                tilingView.add(image, imageLeft, imageTop);
185            }
186        }
187        tilingViewPanel.add(tilingView, -left, -top);
188
189        decorate();
190    }
191
192    private Image getImage(String imageUrl) {
193        Image image = images.get(imageUrl);
194        if (image == null) {
195            image = new Image(imageUrl);
196            images.put(imageUrl, image);
197        }
198        return image;
199    }
200
201    private void decorate() {
202        controller.updateAnnotationDecoration();
203    }
204
205    private void resetView() {
206        images.clear();
207        tilingView.clear();
208        tilingView.setPixelSize(model.getTotalWidth(), model.getTotalHeight());
209    }
210
211}