/* * This library is part of OpenCms - * the Open Source Content Management System * * Copyright (c) Alkacon Software GmbH (http://www.alkacon.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * For further information about Alkacon Software, please see the * company website: http://www.alkacon.com * * For further information about OpenCms, please see the * project website: http://www.opencms.org * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.opencms.ade.galleries.client.preview; import org.opencms.ade.galleries.client.Messages; import org.opencms.ade.galleries.client.preview.ui.CmsCroppingDialog; import org.opencms.ade.galleries.client.preview.ui.CmsImageFormatsForm; import org.opencms.ade.galleries.shared.I_CmsGalleryProviderConstants.GalleryMode; import org.opencms.gwt.client.util.CmsClientStringUtil; import org.opencms.util.CmsStringUtil; import java.util.Collections; import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import com.google.gwt.event.logical.shared.HasValueChangeHandlers; import com.google.gwt.event.logical.shared.ValueChangeEvent; import com.google.gwt.event.logical.shared.ValueChangeHandler; import com.google.gwt.event.shared.EventHandler; import com.google.gwt.event.shared.GwtEvent; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.event.shared.SimpleEventBus; /** * Image format form handler.<p> * * @since 8.0.0 */ public class CmsImageFormatHandler implements HasValueChangeHandlers<CmsCroppingParamBean> { /** Default image formats. */ private enum DefaultRestriction { big, free, original, small, user } /** Default format configuration. */ private static final String[] DEFAULT_FORMAT_NAMES = { DefaultRestriction.original.name() + ":" + Messages.get().key(Messages.GUI_IMAGE_ORIGINAL_FORMAT_LABEL_0), DefaultRestriction.user.name() + ":" + Messages.get().key(Messages.GUI_IMAGE_USER_FORMAT_LABEL_0), DefaultRestriction.free.name() + ":" + Messages.get().key(Messages.GUI_IMAGE_FREE_FORMAT_LABEL_0), DefaultRestriction.small.name() + ":" + Messages.get().key(Messages.GUI_IMAGE_SMALL_FORMAT_LABEL_0), DefaultRestriction.big.name() + ":" + Messages.get().key(Messages.GUI_IMAGE_BIG_FORMAT_LABEL_0)}; /** Default format configuration. */ private static final String[] DEFAULT_FORMAT_VALUES = { DefaultRestriction.original.name(), DefaultRestriction.user.name(), DefaultRestriction.free.name(), DefaultRestriction.small.name(), DefaultRestriction.big.name()}; private CmsCroppingDialog m_croppingDialog; /** The current cropping parameter. */ private CmsCroppingParamBean m_croppingParam; /** The current image format restriction. */ private I_CmsFormatRestriction m_currentFormat; /** The event bus. */ private SimpleEventBus m_eventBus; /** The format form. */ private CmsImageFormatsForm m_formatForm; /** The format names and labels configuration. */ private String[] m_formatNames; /** The map of available format restrictions. */ private Map<String, I_CmsFormatRestriction> m_formats = Collections.emptyMap(); /** The Format configuration. */ private String[] m_formatValues; /** Flag to indicate the handler has been initialized. */ private boolean m_initialized; /** The image height. */ private int m_originalHeight = -1; /** The image width. */ private int m_originalWidth = -1; /** Flag indicating if the height / width ratio is locked. */ private boolean m_ratioLocked; /** Flag to indicate if image format may be changed. */ private boolean m_useFormats; /** The user format key, if available. */ private String m_userFormatKey; /** * Constructor.<p> * * @param galleryMode the gallery mode * @param selectedPath the selected gallery path * @param imageHeight the image height * @param imageWidth the image width */ public CmsImageFormatHandler(GalleryMode galleryMode, String selectedPath, int imageHeight, int imageWidth) { m_originalHeight = imageHeight; m_originalWidth = imageWidth; m_croppingParam = CmsCroppingParamBean.parseImagePath(selectedPath); m_croppingParam.setOrgHeight(imageHeight); m_croppingParam.setOrgWidth(imageWidth); m_ratioLocked = true; readFormatsConfig(galleryMode); if (m_useFormats) { generateFormats(); } } /** * @see com.google.gwt.event.logical.shared.HasValueChangeHandlers#addValueChangeHandler(com.google.gwt.event.logical.shared.ValueChangeHandler) */ public HandlerRegistration addValueChangeHandler(ValueChangeHandler<CmsCroppingParamBean> handler) { return addHandler(handler, ValueChangeEvent.getType()); } /** * @see com.google.gwt.event.shared.HasHandlers#fireEvent(com.google.gwt.event.shared.GwtEvent) */ public void fireEvent(GwtEvent<?> event) { ensureHandlers().fireEventFromSource(event, this); } /** * Returns the current cropping parameter.<p> * * @return the current cropping parameter */ public CmsCroppingParamBean getCroppingParam() { return m_croppingParam; } /** * Returns the current format.<p> * * @return the current format */ public I_CmsFormatRestriction getCurrentFormat() { return m_currentFormat; } /** * Returns the formats.<p> * * @return the formats */ public Map<String, I_CmsFormatRestriction> getFormats() { return m_formats; } /** * Adds necessary attributes to the map.<p> * * @param attributes the attribute map * @return the attribute map */ public Map<String, String> getImageAttributes(Map<String, String> attributes) { attributes.put("height", String.valueOf(m_croppingParam.getResultingHeight())); attributes.put("width", String.valueOf(m_croppingParam.getResultingWidth())); return attributes; } /** * Returns the original height.<p> * * @return the original height */ public int getOriginalHeight() { return m_originalHeight; } /** * Returns the original width.<p> * * @return the original width */ public int getOriginalWidth() { return m_originalWidth; } /** * Initializes the format form handler.<p> * * @param formatForm the format form * @param croppingDialog the cropping dialog */ public void init(CmsImageFormatsForm formatForm, CmsCroppingDialog croppingDialog) { m_croppingDialog = croppingDialog; m_formatForm = formatForm; if (m_useFormats) { for (Entry<String, I_CmsFormatRestriction> entry : m_formats.entrySet()) { m_formatForm.addFormatSelectOption(entry.getKey(), entry.getValue().getLabel()); } I_CmsFormatRestriction match = getMatchingFormat(m_croppingParam, true); if (match != null) { m_currentFormat = match; m_formatForm.setFormatSelectValue(match.getName()); adjustToCurrentFormat(); } else { onResetSize(); } } else { m_formatForm.addFormatSelectOption("--", "--"); m_formatForm.setFormEnabled(m_useFormats); } if (m_croppingParam.isCropped()) { setCropping(m_croppingParam); } m_croppingDialog.addValueChangeHandler(new ValueChangeHandler<CmsCroppingParamBean>() { /** * Executed on value change. Sets the returned cropping parameters.<p> * * @param event the value change event */ public void onValueChange(ValueChangeEvent<CmsCroppingParamBean> event) { setCropping(event.getValue()); } }); m_initialized = true; } /** * Returns if scaling formats may be selected for the image.<p> * * @return <code>true</code> if scaling formats may be selected for the image */ public boolean isUseFormats() { return m_useFormats; } /** * Execute on format change.<p> * * @param formatKey the new format value */ public void onFormatChange(String formatKey) { // setting the selected format restriction m_currentFormat = m_formats.get(formatKey); m_currentFormat.adjustCroppingParam(m_croppingParam); adjustToCurrentFormat(); if (m_initialized) { // fire change only if initialized fireValueChangedEvent(); } } /** * Execute on height change.<p> * * @param height the new height */ public void onHeightChange(String height) { int value = CmsClientStringUtil.parseInt(height); if ((m_croppingParam.getTargetHeight() == value) || (value == 0)) { // the value has not changed, ignore'0' return; } m_croppingParam.setTargetHeight(value); if (m_ratioLocked) { m_croppingParam.setTargetWidth((value * m_originalWidth) / m_originalHeight); m_formatForm.setWidthInput(m_croppingParam.getTargetWidth()); } if (!m_currentFormat.isHeightEditable() && hasUserFormatRestriction()) { m_formatForm.setFormatSelectValue(m_userFormatKey); } else { fireValueChangedEvent(); } } /** * Execute when the lock image ratio is clicked.<p> * * @param locked <code>true</code> if ratio is locked */ public void onLockRatio(boolean locked) { m_ratioLocked = locked; } /** * Execute when cropping is removed.<p> */ public void onRemoveCropping() { m_formatForm.setCropped(false); onResetSize(); } /** * Execute to reset image format and size input.<p> */ public void onResetSize() { String restrictionKey; if (m_formats.containsKey(DefaultRestriction.original.name())) { restrictionKey = DefaultRestriction.original.name(); } else { restrictionKey = m_formats.keySet().iterator().next(); } m_formatForm.setFormatSelectValue(restrictionKey); m_croppingParam.reset(); onFormatChange(restrictionKey); } /** * Execute on width change.<p> * * @param width the new width */ public void onWidthChange(String width) { int value = CmsClientStringUtil.parseInt(width); if ((m_croppingParam.getTargetWidth() == value) || (value == 0)) { // the value has not changed, ignore'0' return; } m_croppingParam.setTargetWidth(value); if (m_ratioLocked) { m_croppingParam.setTargetHeight((value * m_originalHeight) / m_originalWidth); m_formatForm.setHeightInput(m_croppingParam.getTargetHeight()); } if (!m_currentFormat.isWidthEditable() && hasUserFormatRestriction()) { m_formatForm.setFormatSelectValue(m_userFormatKey); } else { fireValueChangedEvent(); } } /** * Shows the image cropping dialog.<p> */ public void openCropping() { CmsCroppingParamBean param = new CmsCroppingParamBean(m_croppingParam); m_currentFormat.adjustCroppingParam(param); m_croppingDialog.show(param); } /** * Sets the given cropping parameter.<p> * * @param croppingParam the cropping parameter */ public void setCropping(CmsCroppingParamBean croppingParam) { m_croppingParam = croppingParam; m_formatForm.setHeightInput(m_croppingParam.getTargetHeight()); m_formatForm.setWidthInput(m_croppingParam.getTargetWidth()); // only in case of the original-format-restriction, the cropping dialog may be opened to override the selected format if (m_currentFormat instanceof CmsOriginalFormatRestriction) { I_CmsFormatRestriction format = getMatchingFormat(m_croppingParam, false); if (format != null) { m_currentFormat = format; m_formatForm.setFormatSelectValue(format.getName()); } } m_formatForm.setCropped(true); fireValueChangedEvent(); } /** * Sets the original width.<p> * * @param originalWidth the original width to set */ public void setOriginalWidth(int originalWidth) { m_originalWidth = originalWidth; } /** * Adds this handler to the widget. * * @param <H> the type of handler to add * @param type the event type * @param handler the handler * @return {@link HandlerRegistration} used to remove the handler */ protected final <H extends EventHandler> HandlerRegistration addHandler(final H handler, GwtEvent.Type<H> type) { return ensureHandlers().addHandlerToSource(type, this, handler); } /** * Helper method for firing a 'value changed' event.<p> */ protected void fireValueChangedEvent() { ValueChangeEvent.fire(this, m_croppingParam); } /** * Lazy initializing the handler manager.<p> * * @return the handler manager */ private SimpleEventBus ensureHandlers() { if (m_eventBus == null) { m_eventBus = new SimpleEventBus(); } return m_eventBus; } /** * Generates the format restriction objects.<p> */ private void generateFormats() { m_formats = new LinkedHashMap<String, I_CmsFormatRestriction>(); for (int i = 0; i < m_formatValues.length; i++) { String value = m_formatValues[i].trim(); if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(value)) { String label = value; String key = value; if ((m_formatNames != null) && (m_formatNames.length > i) && CmsStringUtil.isNotEmptyOrWhitespaceOnly(m_formatNames[i])) { int pos = m_formatNames[i].indexOf(":"); if (pos > 0) { label = m_formatNames[i].substring(pos + 1, m_formatNames[i].length()); key = m_formatNames[i].substring(0, pos); } else { label = m_formatNames[i]; key = m_formatNames[i]; } } DefaultRestriction restrictionType = null; try { restrictionType = DefaultRestriction.valueOf(value); } catch (Exception e) { // happens with user defined restriction settings } if (restrictionType != null) { switch (restrictionType) { case original: m_formats.put(key, new CmsOriginalFormatRestriction(key, label)); break; case user: m_userFormatKey = key; m_formats.put(key, new CmsUserFormatRestriction(key, label)); break; case free: m_formats.put(key, new CmsFreeFormatRestriction(key, label)); break; case small: m_formats.put(key, new CmsImageFormatRestriction(key, label, "200x?")); break; case big: m_formats.put(key, new CmsImageFormatRestriction(key, label, "500x?")); break; default: } } else { if (CmsImageFormatRestriction.isValidConfig(value)) { m_formats.put(key, new CmsImageFormatRestriction(key, label, value)); } } } } } /** * Checks the format restrictions if the match the giving cropping parameter.<p> * * @param croppingParam the cropping parameter * @param forceByName force format match by name within cropping parameter * * @return the matching format restriction */ private I_CmsFormatRestriction getMatchingFormat(CmsCroppingParamBean croppingParam, boolean forceByName) { I_CmsFormatRestriction result = null; if (forceByName && m_formats.containsKey(croppingParam.getFormatName())) { result = m_formats.get(croppingParam.getFormatName()); if (!result.matchesCroppingParam(croppingParam)) { result.adjustCroppingParam(croppingParam); } return result; } for (I_CmsFormatRestriction format : m_formats.values()) { if (format.matchesCroppingParam(croppingParam)) { result = format; if (format.getName().equals(croppingParam.getFormatName())) { break; } } } return result; } /** * Returns if the user defined format restriction is available.<p> * * @return <code>true</code> if the user defined format restriction is available */ private boolean hasUserFormatRestriction() { return m_userFormatKey != null; } /** * Reads the format configuration for the given gallery mode.<p> * * @param mode the gallery mode */ private void readFormatsConfig(GalleryMode mode) { switch (mode) { case editor: m_useFormats = true; m_formatNames = DEFAULT_FORMAT_NAMES; m_formatValues = DEFAULT_FORMAT_VALUES; break; case widget: m_useFormats = CmsPreviewUtil.isShowFormats(); if (m_useFormats) { m_formatValues = CmsPreviewUtil.getFormats(); if (m_formatValues == null) { m_formatNames = DEFAULT_FORMAT_NAMES; m_formatValues = DEFAULT_FORMAT_VALUES; } else { m_formatNames = CmsPreviewUtil.getFormatNames(); } } break; case ade: case view: m_useFormats = false; break; default: } } private void adjustToCurrentFormat() { // in case of a locked or fixed image ratio height and width need to be reset int height = m_croppingParam.getOrgHeight(); int width = m_croppingParam.getOrgWidth(); if (m_croppingParam.isScaled()) { if (m_croppingParam.getTargetHeight() == -1) { height = (int)Math.floor(((1.00 * m_croppingParam.getOrgHeight()) / m_croppingParam.getOrgWidth()) * m_croppingParam.getTargetWidth()); } else { height = m_croppingParam.getTargetHeight(); } if (m_croppingParam.getTargetWidth() == -1) { width = (int)Math.floor(((1.00 * m_croppingParam.getOrgWidth()) / m_croppingParam.getOrgHeight()) * m_croppingParam.getTargetHeight()); } else { width = m_croppingParam.getTargetWidth(); } } m_formatForm.setHeightInput(height); m_formatForm.setWidthInput(width); // enabling/disabling ratio lock button if (m_currentFormat.isFixedRatio()) { m_formatForm.setRatioButton(false, false, Messages.get().key(Messages.GUI_PRIVIEW_BUTTON_RATIO_FIXED_0)); m_ratioLocked = true; } else { if (!m_currentFormat.isHeightEditable() && !m_currentFormat.isWidthEditable()) { // neither height nor width are editable, disable ratio lock button m_formatForm.setRatioButton( false, false, Messages.get().key(Messages.GUI_PRIVIEW_BUTTON_NOT_EDITABLE_0)); } else { m_formatForm.setRatioButton(false, true, null); } m_ratioLocked = true; } // enabling/disabling height and width input m_formatForm.setHeightInputEnabled(m_currentFormat.isHeightEditable() || hasUserFormatRestriction()); m_formatForm.setWidthInputEnabled(m_currentFormat.isWidthEditable() || hasUserFormatRestriction()); } }