001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.ade.galleries.client.preview.ui;
029
030import org.opencms.ade.galleries.client.Messages;
031import org.opencms.ade.galleries.client.preview.CmsCroppingParamBean;
032import org.opencms.gwt.client.ui.CmsAreaSelectPanel;
033import org.opencms.gwt.client.ui.CmsPushButton;
034import org.opencms.gwt.client.util.CmsPositionBean;
035
036import com.google.gwt.core.client.GWT;
037import com.google.gwt.dom.client.Element;
038import com.google.gwt.dom.client.Style.Display;
039import com.google.gwt.dom.client.Style.Unit;
040import com.google.gwt.event.dom.client.ClickEvent;
041import com.google.gwt.event.logical.shared.HasValueChangeHandlers;
042import com.google.gwt.event.logical.shared.ValueChangeEvent;
043import com.google.gwt.event.logical.shared.ValueChangeHandler;
044import com.google.gwt.event.shared.HandlerRegistration;
045import com.google.gwt.uibinder.client.UiBinder;
046import com.google.gwt.uibinder.client.UiField;
047import com.google.gwt.uibinder.client.UiHandler;
048import com.google.gwt.user.client.ui.Composite;
049import com.google.gwt.user.client.ui.Image;
050import com.google.gwt.user.client.ui.Label;
051import com.google.gwt.user.client.ui.Widget;
052
053/**
054 * Image cropping dialog.<p>
055 *
056 * @since 8.0.0
057 */
058public class CmsCroppingDialog extends Composite
059implements ValueChangeHandler<CmsPositionBean>, HasValueChangeHandlers<CmsCroppingParamBean> {
060
061    /** The ui-binder for this widget. */
062    interface I_CmsCroppingDialogUiBinder extends UiBinder<Widget, CmsCroppingDialog> {
063        // GWT interface, nothing to do
064    }
065
066    /** The empty field string. */
067    private static final String EMPTY_FIELD = "---";
068
069    /** The ui-binder interface. */
070    private static I_CmsCroppingDialogUiBinder m_uiBinder = GWT.create(I_CmsCroppingDialogUiBinder.class);
071
072    /** The cancel button. */
073    @UiField
074    protected CmsPushButton m_cancelButton;
075
076    /** The cropping panel. */
077    @UiField
078    protected CmsAreaSelectPanel m_croppingPanel;
079
080    /** The height label. */
081    @UiField
082    protected Label m_heightDisplay;
083
084    /** The height label. */
085    @UiField
086    protected Label m_heightLabel;
087
088    /** The image. */
089    @UiField
090    protected Image m_image;
091
092    /** The OK button. */
093    @UiField
094    protected CmsPushButton m_okButton;
095
096    /** The height label. */
097    @UiField
098    protected Label m_scaleDisplay;
099
100    /** The height label. */
101    @UiField
102    protected Label m_scaleLabel;
103
104    /** The top panel holding the cropping area. */
105    @UiField
106    protected Element m_topPanel;
107    /** The height label. */
108    @UiField
109    protected Label m_widthDisplay;
110
111    /** The height label. */
112    @UiField
113    protected Label m_widthLabel;
114
115    /** The cropping parameters. */
116    private CmsCroppingParamBean m_croppingParam;
117
118    /** The cropping parameters of the displayed image. */
119    private CmsCroppingParamBean m_displayCropping;
120
121    /** The ratio from original image height to display height. */
122    private double m_heightRatio;
123
124    /** The image path. */
125    private String m_imagePath;
126
127    /** The ratio from original image width to display width. */
128    private double m_widthRatio;
129
130    /**
131     * Constructor.<p>
132     *
133     * @param imagePath the image path
134     */
135    public CmsCroppingDialog(String imagePath) {
136
137        initWidget(m_uiBinder.createAndBindUi(this));
138
139        m_imagePath = imagePath;
140
141        m_croppingPanel.addValueChangeHandler(this);
142        m_croppingPanel.setFireAll(true);
143
144        m_widthLabel.setText(Messages.get().key(Messages.GUI_PREVIEW_LABEL_WIDTH_0));
145        m_widthDisplay.setText(EMPTY_FIELD);
146        m_heightLabel.setText(Messages.get().key(Messages.GUI_PREVIEW_LABEL_HEIGHT_0));
147        m_heightDisplay.setText(EMPTY_FIELD);
148        m_scaleLabel.setText(Messages.get().key(Messages.GUI_IMAGE_SCALE_0));
149        m_scaleDisplay.setText(EMPTY_FIELD);
150        m_okButton.setText(org.opencms.gwt.client.Messages.get().key(org.opencms.gwt.client.Messages.GUI_OK_0));
151        m_okButton.setUseMinWidth(true);
152        m_cancelButton.setText(org.opencms.gwt.client.Messages.get().key(org.opencms.gwt.client.Messages.GUI_CANCEL_0));
153        m_cancelButton.setUseMinWidth(true);
154    }
155
156    /**
157     * @see com.google.gwt.event.logical.shared.HasValueChangeHandlers#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler)
158     */
159    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<CmsCroppingParamBean> handler) {
160
161        return addHandler(handler, ValueChangeEvent.getType());
162    }
163
164    /**
165     * @see com.google.gwt.event.logical.shared.ValueChangeHandler#onValueChange(com.google.gwt.event.logical.shared.ValueChangeEvent)
166     */
167    public void onValueChange(ValueChangeEvent<CmsPositionBean> event) {
168
169        CmsPositionBean pos = event.getValue();
170        if (pos != null) {
171            calculateCropping(pos);
172            if (m_croppingParam.getTargetWidth() > 0) {
173                if (m_croppingParam.getTargetHeight() > 0) {
174                    m_heightDisplay.setText(String.valueOf(m_croppingParam.getTargetHeight()));
175                    m_widthDisplay.setText(String.valueOf(m_croppingParam.getTargetWidth()));
176                } else {
177                    m_widthDisplay.setText(String.valueOf(m_croppingParam.getTargetWidth()));
178                    m_heightDisplay.setText(
179                        String.valueOf(
180                            (int)Math.floor(
181                                (1.00 * m_croppingParam.getTargetWidth() * m_croppingParam.getCropHeight())
182                                    / m_croppingParam.getCropWidth())));
183                }
184            } else if (m_croppingParam.getTargetHeight() > 0) {
185                m_heightDisplay.setText(String.valueOf(m_croppingParam.getTargetHeight()));
186                m_widthDisplay.setText(
187                    String.valueOf(
188                        (int)Math.floor(
189                            (1.00 * m_croppingParam.getTargetHeight() * m_croppingParam.getCropWidth())
190                                / m_croppingParam.getCropHeight())));
191            } else {
192                m_heightDisplay.setText(String.valueOf(m_croppingParam.getCropHeight()));
193                m_widthDisplay.setText(String.valueOf(m_croppingParam.getCropWidth()));
194            }
195
196            String scale = "100%";
197            if (m_croppingParam.getTargetHeight() > 0) {
198                scale = String.valueOf(
199                    (int)Math.floor((100.00 * m_croppingParam.getCropHeight()) / m_croppingParam.getTargetHeight()))
200                    + "%";
201            } else if (m_croppingParam.getTargetWidth() > 0) {
202                scale = String.valueOf(
203                    (int)Math.floor((100.00 * m_croppingParam.getCropWidth()) / m_croppingParam.getTargetWidth()))
204                    + "%";
205            }
206            m_scaleDisplay.setText(scale);
207            m_okButton.enable();
208        } else {
209            m_okButton.disable(Messages.get().key(Messages.GUI_IMAGE_NO_AREA_SELECTED_0));
210            m_heightDisplay.setText(EMPTY_FIELD);
211            m_widthDisplay.setText(EMPTY_FIELD);
212            m_scaleDisplay.setText(EMPTY_FIELD);
213        }
214
215    }
216
217    /**
218     * Shows the dialog.<p>
219     *
220     * @param targetParam the target cropping parameter, containing the target size restriction
221     */
222    public void show(CmsCroppingParamBean targetParam) {
223
224        getElement().getStyle().setDisplay(Display.BLOCK);
225        m_topPanel.getStyle().setHeight(getElement().getOffsetHeight() - 33, Unit.PX);
226        m_croppingParam = targetParam;
227        m_displayCropping = new CmsCroppingParamBean();
228        m_displayCropping.setTargetHeight(m_croppingParam.getOrgHeight());
229        m_displayCropping.setTargetWidth(m_croppingParam.getOrgWidth());
230        m_displayCropping = m_displayCropping.getRestrictedSizeParam(
231            getElement().getOffsetHeight() - 35,
232            getElement().getOffsetWidth() - 4);
233        m_image.setUrl(m_imagePath + "?" + m_displayCropping.toString());
234        m_croppingPanel.getElement().getStyle().setWidth(m_displayCropping.getTargetWidth(), Unit.PX);
235        if ((targetParam.getTargetHeight() > 0) && (targetParam.getTargetWidth() > 0)) {
236            m_croppingPanel.setRatio((1.00 * targetParam.getTargetHeight()) / targetParam.getTargetWidth());
237        } else {
238            m_croppingPanel.resetRatio();
239        }
240
241        m_heightRatio = (1.00 * m_croppingParam.getOrgHeight()) / m_displayCropping.getTargetHeight();
242        m_widthRatio = (1.00 * m_croppingParam.getOrgWidth()) / m_displayCropping.getTargetWidth();
243        if (m_croppingParam.isCropped()) {
244            m_croppingPanel.setAreaPosition(true, calculateSelectPosition());
245        } else {
246            m_croppingPanel.clearSelection();
247        }
248    }
249
250    /**
251     * Handles the click event for cancel button. Hides the cropping dialog.<p>
252     *
253     * @param event the click event
254     */
255    @UiHandler("m_cancelButton")
256    protected void onCancel(ClickEvent event) {
257
258        hide();
259    }
260
261    /**
262     * Handles the click event for ok button. Sets the selected cropping parameters.<p>
263     *
264     * @param event the click event
265     */
266    @UiHandler("m_okButton")
267    protected void onOk(ClickEvent event) {
268
269        if (!((m_croppingParam.getTargetWidth() > 0) && (m_croppingParam.getTargetHeight() > 0))) {
270            if (m_croppingParam.getTargetWidth() > 0) {
271                m_croppingParam.setTargetHeight(
272                    (int)Math.floor(
273                        (1.00 * m_croppingParam.getTargetWidth() * m_croppingParam.getCropHeight())
274                            / m_croppingParam.getCropWidth()));
275            } else if (m_croppingParam.getTargetHeight() > 0) {
276                m_croppingParam.setTargetWidth(
277                    (int)Math.floor(
278                        (1.00 * m_croppingParam.getTargetHeight() * m_croppingParam.getCropWidth())
279                            / m_croppingParam.getCropHeight()));
280            } else {
281                m_croppingParam.setTargetHeight(m_croppingParam.getCropHeight());
282                m_croppingParam.setTargetWidth(m_croppingParam.getCropWidth());
283            }
284        }
285        ValueChangeEvent.fire(this, m_croppingParam);
286        hide();
287    }
288
289    /**
290     * Calculates the resulting cropping parameter from the supplied selection position.<p>
291     *
292     * @param position the selection position
293     */
294    private void calculateCropping(CmsPositionBean position) {
295
296        m_croppingParam.setCropHeight((int)Math.round(m_heightRatio * position.getHeight()));
297        m_croppingParam.setCropWidth((int)Math.round(m_widthRatio * position.getWidth()));
298        m_croppingParam.setCropY((int)Math.round(m_heightRatio * position.getTop()));
299        m_croppingParam.setCropX((int)Math.round(m_widthRatio * position.getLeft()));
300    }
301
302    /**
303     * Calculates the select area position for the current cropping parameter.<p>
304     *
305     * @return the select area position
306     */
307    private CmsPositionBean calculateSelectPosition() {
308
309        CmsPositionBean result = new CmsPositionBean();
310        result.setHeight((int)Math.round(m_croppingParam.getCropHeight() / m_heightRatio));
311        result.setWidth((int)Math.round(m_croppingParam.getCropWidth() / m_widthRatio));
312        result.setTop((int)Math.round(m_croppingParam.getCropY() / m_heightRatio));
313        result.setLeft((int)Math.round(m_croppingParam.getCropX() / m_widthRatio));
314        return result;
315    }
316
317    /**
318     * Hides the cropping dialog.<p>
319     */
320    private void hide() {
321
322        getElement().getStyle().setDisplay(Display.NONE);
323    }
324
325}