Java tutorial
/* * 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 com.alkacon.acacia.client.ui; import com.alkacon.geranium.client.util.ClientStringUtil; import com.alkacon.geranium.client.util.DomUtil; import com.alkacon.geranium.client.util.PositionBean; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import com.google.gwt.core.client.GWT; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.Style; import com.google.gwt.dom.client.Style.Display; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.dom.client.HasClickHandlers; 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.user.client.Window; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HTMLPanel; import com.google.gwt.user.client.ui.RootPanel; import com.google.gwt.user.client.ui.Widget; /** * In-line edit overlay covering rest of the page.<p> */ public class InlineEditOverlay extends Composite implements HasClickHandlers { /** The ui binder. */ interface I_CmsInlineEditOverlayUiBinder extends UiBinder<HTMLPanel, InlineEditOverlay> { // nothing to do } /** The width rquired by the button bar. */ private static final int BUTTON_BAR_WIDTH = 28; /** List of present overlays. */ private static List<InlineEditOverlay> m_overlays = new ArrayList<InlineEditOverlay>(); /** The ui binder instance. */ private static I_CmsInlineEditOverlayUiBinder uiBinder = GWT.create(I_CmsInlineEditOverlayUiBinder.class); /** Bottom border. */ @UiField protected Element m_borderBottom; /** Left border. */ @UiField protected Element m_borderLeft; /** Right border. */ @UiField protected Element m_borderRight; /** Top border. */ @UiField protected Element m_borderTop; /** The button bar element. */ @UiField protected Element m_buttonBar; /** Edit overlay. */ @UiField protected Element m_overlayBottom; /** Edit overlay. */ @UiField protected Element m_overlayLeft; /** Edit overlay. */ @UiField protected Element m_overlayRight; /** Edit overlay. */ @UiField protected Element m_overlayTop; /** The edit button panel. */ @UiField FlowPanel m_buttonPanel; /** Style of border. */ private Style m_borderBottomStyle; /** Style of border. */ private Style m_borderLeftStyle; /** Style of border. */ private Style m_borderRightStyle; /** Style of border. */ private Style m_borderTopStyle; /** Map of attached edit buttons and their absolute top positions. */ private Map<InlineEntityWidget, Integer> m_buttons; /** The current overlay position. */ private PositionBean m_currentPosition; /** The element to surround with the overlay. */ private Element m_element; /** Flag indicating this overlay has a button bar. */ private boolean m_hasButtonBar; /** The main panel. */ private HTMLPanel m_main; /** The overlay offset. */ private int m_offset = 3; /** Style of overlay. */ private Style m_overlayBottomStyle; /** Style of overlay. */ private Style m_overlayLeftStyle; /** Style of overlay. */ private Style m_overlayRightStyle; /** Style of overlay. */ private Style m_overlayTopStyle; /** * Constructor.<p> * * @param element the element to surround with the overlay */ public InlineEditOverlay(Element element) { m_main = uiBinder.createAndBindUi(this); initWidget(m_main); m_element = element; m_overlayLeftStyle = m_overlayLeft.getStyle(); m_overlayBottomStyle = m_overlayBottom.getStyle(); m_overlayRightStyle = m_overlayRight.getStyle(); m_overlayTopStyle = m_overlayTop.getStyle(); m_borderBottomStyle = m_borderBottom.getStyle(); m_borderLeftStyle = m_borderLeft.getStyle(); m_borderRightStyle = m_borderRight.getStyle(); m_borderTopStyle = m_borderTop.getStyle(); m_buttonBar.getStyle().setDisplay(Display.NONE); m_buttonPanel.addDomHandler(new ClickHandler() { public void onClick(ClickEvent event) { // prevent the click event to propagated from the button panel to the main widget event.stopPropagation(); } }, ClickEvent.getType()); m_buttons = new HashMap<InlineEntityWidget, Integer>(); } /** * Adds an overlay surrounding the given DOM element.<p> * * @param element the element * * @return the overlay widget */ public static InlineEditOverlay addOverlayForElement(Element element) { InlineEditOverlay overlay = new InlineEditOverlay(element); if (!m_overlays.isEmpty()) { m_overlays.get(m_overlays.size() - 1).setVisible(false); } m_overlays.add(overlay); RootPanel.get().add(overlay); overlay.updatePosition(); overlay.checkZIndex(); return overlay; } /** * Returns the root overlay if available.<p> * * @return the root overlay */ public static InlineEditOverlay getRootOverlay() { return m_overlays.isEmpty() ? null : m_overlays.get(0); } /** * Removes all present overlays.<p> */ public static void removeAll() { for (InlineEditOverlay overlay : m_overlays) { overlay.removeFromParent(); } m_overlays.clear(); } /** * Removes the last overlay to display the previous or none.<p> */ public static void removeLastOverlay() { if (!m_overlays.isEmpty()) { InlineEditOverlay last = m_overlays.remove(m_overlays.size() - 1); last.removeFromParent(); } if (!m_overlays.isEmpty()) { m_overlays.get(m_overlays.size() - 1).setVisible(true); } } /** * Updates the current overlay's position.<p> */ public static void updateCurrentOverlayPosition() { if (!m_overlays.isEmpty()) { m_overlays.get(m_overlays.size() - 1).updatePosition(); } } /** * Adds a button widget to the button panel.<p> * * @param widget the button widget * @param absoluteTop the absolute top position */ public void addButton(InlineEntityWidget widget, int absoluteTop) { setButtonBarVisible(true); m_buttonPanel.add(widget); setButtonPosition(widget, absoluteTop); } /** * @see com.google.gwt.event.dom.client.HasClickHandlers#addClickHandler(com.google.gwt.event.dom.client.ClickHandler) */ public HandlerRegistration addClickHandler(ClickHandler handler) { return addDomHandler(handler, ClickEvent.getType()); } /** * Increases the overlay z-index if necessary.<p> */ public void checkZIndex() { int zIndex = 100000; Element parent = m_element.getParentElement(); while (parent != null) { int parentIndex = DomUtil.getCurrentStyleInt(parent, DomUtil.Style.zIndex); if (parentIndex > zIndex) { zIndex = parentIndex; } parent = parent.getParentElement(); } if (zIndex > 100000) { getElement().getStyle().setZIndex(zIndex); } } /** * Clears and hides the button panel.<p> */ public void clearButtonPanel() { m_buttonPanel.clear(); m_buttons.clear(); setButtonBarVisible(false); } /** * Updates the position of the given button widget.<p> * * @param widget the button widget * @param absoluteTop the top absolute top position */ public void setButtonPosition(InlineEntityWidget widget, int absoluteTop) { if (m_buttonPanel.getWidgetIndex(widget) > -1) { int positionTop = getAvailablePosition(widget, absoluteTop) - ClientStringUtil.parseInt(m_buttonBar.getStyle().getTop()); widget.getElement().getStyle().setTop(positionTop, Unit.PX); if (ClientStringUtil.parseInt(m_buttonBar.getStyle().getHeight()) < (positionTop + 20)) { increaseOverlayHeight(positionTop + 20); } } } /** * Sets the overlay offset.<p> * * @param offset the offset */ public void setOffset(int offset) { m_offset = offset; } /** * @see com.google.gwt.user.client.ui.UIObject#setVisible(boolean) */ @Override public void setVisible(boolean visible) { super.setVisible(visible); if (!visible && m_hasButtonBar) { for (Widget widget : m_buttonPanel) { if (widget instanceof InlineEntityWidget) { ((InlineEntityWidget) widget).setContentHighlightingVisible(false); } } } } /** * Updates the overlay position.<p> */ public void updatePosition() { setPosition(PositionBean.getInnerDimensions(m_element)); for (Widget widget : m_buttonPanel) { if (widget instanceof InlineEntityWidget) { ((InlineEntityWidget) widget).positionWidget(); } } } /** * Returns the available absolute top position for the given button.<p> * * @param widget the button widget * @param absoluteTop the proposed position * * @return the available position */ private int getAvailablePosition(InlineEntityWidget widget, int absoluteTop) { m_buttons.remove(widget); boolean positionBlocked = true; while (positionBlocked) { positionBlocked = false; for (int pos : m_buttons.values()) { if (((pos - 24) < absoluteTop) && (absoluteTop < (pos + 24))) { positionBlocked = true; absoluteTop = pos + 25; break; } } } m_buttons.put(widget, new Integer(absoluteTop)); return absoluteTop; } /** * Increases the overlay height to make space for edit buttons.<p> * * @param height the height to set */ private void increaseOverlayHeight(int height) { if (m_currentPosition != null) { m_currentPosition.setHeight(height); setPosition(m_currentPosition); } } /** * Sets button bar visibility.<p> * * @param visible <code>true</code> to set the button bar visible */ private void setButtonBarVisible(boolean visible) { if (m_hasButtonBar != visible) { m_hasButtonBar = visible; if (m_hasButtonBar) { m_buttonBar.getStyle().clearDisplay(); int width = ClientStringUtil.parseInt(m_borderTopStyle.getWidth()) + BUTTON_BAR_WIDTH; m_borderTopStyle.setWidth(width, Unit.PX); m_borderBottomStyle.setWidth(width, Unit.PX); m_borderRightStyle.setLeft( ClientStringUtil.parseInt(m_borderRightStyle.getLeft()) + BUTTON_BAR_WIDTH, Unit.PX); } else { m_buttonBar.getStyle().setDisplay(Display.NONE); int width = ClientStringUtil.parseInt(m_borderTopStyle.getWidth()) - BUTTON_BAR_WIDTH; m_borderTopStyle.setWidth(width, Unit.PX); m_borderBottomStyle.setWidth(width, Unit.PX); m_borderRightStyle.setLeft( ClientStringUtil.parseInt(m_borderRightStyle.getLeft()) - BUTTON_BAR_WIDTH, Unit.PX); } } } /** * Sets position and size of the overlay area.<p> * * @param position the position of highlighted area */ private void setPosition(PositionBean position) { m_currentPosition = position; setSelectPosition(position.getLeft(), position.getTop(), position.getHeight(), position.getWidth()); } /** * Sets position and size of the overlay area.<p> * * @param posX the new X position * @param posY the new Y position * @param height the new height * @param width the new width */ private void setSelectPosition(int posX, int posY, int height, int width) { int useWidth = Window.getClientWidth(); int bodyWidth = RootPanel.getBodyElement().getClientWidth() + RootPanel.getBodyElement().getOffsetLeft(); if (bodyWidth > useWidth) { useWidth = bodyWidth; } int useHeight = Window.getClientHeight(); int bodyHeight = RootPanel.getBodyElement().getClientHeight() + RootPanel.getBodyElement().getOffsetTop(); if (bodyHeight > useHeight) { useHeight = bodyHeight; } m_overlayLeftStyle.setWidth(posX - m_offset, Unit.PX); m_overlayLeftStyle.setHeight(useHeight, Unit.PX); m_borderLeftStyle.setHeight(height + (2 * m_offset), Unit.PX); m_borderLeftStyle.setTop(posY - (2 * m_offset), Unit.PX); m_borderLeftStyle.setLeft(posX - (2 * m_offset), Unit.PX); m_overlayTopStyle.setLeft(posX - m_offset, Unit.PX); m_overlayTopStyle.setWidth(width + (2 * m_offset), Unit.PX); m_overlayTopStyle.setHeight(posY - m_offset, Unit.PX); m_borderTopStyle.setLeft(posX - m_offset, Unit.PX); m_borderTopStyle.setTop(posY - (2 * m_offset), Unit.PX); if (m_hasButtonBar) { m_borderTopStyle.setWidth(width + (2 * m_offset) + BUTTON_BAR_WIDTH, Unit.PX); } else { m_borderTopStyle.setWidth(width + (2 * m_offset), Unit.PX); } m_overlayBottomStyle.setLeft(posX - m_offset, Unit.PX); m_overlayBottomStyle.setWidth(width + m_offset + m_offset, Unit.PX); m_overlayBottomStyle.setHeight(useHeight - posY - height - m_offset, Unit.PX); m_overlayBottomStyle.setTop(posY + height + m_offset, Unit.PX); m_borderBottomStyle.setLeft(posX - m_offset, Unit.PX); m_borderBottomStyle.setTop((posY + height) + m_offset, Unit.PX); if (m_hasButtonBar) { m_borderBottomStyle.setWidth(width + (2 * m_offset) + BUTTON_BAR_WIDTH, Unit.PX); } else { m_borderBottomStyle.setWidth(width + (2 * m_offset), Unit.PX); } m_overlayRightStyle.setLeft(posX + width + m_offset, Unit.PX); m_overlayRightStyle.setWidth(useWidth - posX - width - m_offset, Unit.PX); m_overlayRightStyle.setHeight(useHeight, Unit.PX); m_borderRightStyle.setHeight(height + (2 * m_offset), Unit.PX); m_borderRightStyle.setTop(posY - (2 * m_offset), Unit.PX); if (m_hasButtonBar) { m_borderRightStyle.setLeft(posX + width + m_offset + BUTTON_BAR_WIDTH, Unit.PX); } else { m_borderRightStyle.setLeft(posX + width + m_offset, Unit.PX); } m_buttonBar.getStyle().setTop(posY - m_offset, Unit.PX); m_buttonBar.getStyle().setHeight(height + (2 * m_offset), Unit.PX); m_buttonBar.getStyle().setLeft(posX + width + m_offset + 1, Unit.PX); } }