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}