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.containerpage.client.ui;
029
030import org.opencms.ade.containerpage.client.CmsContainerpageController;
031import org.opencms.ade.containerpage.shared.CmsContainerElement;
032import org.opencms.ade.containerpage.shared.CmsElementLockInfo;
033import org.opencms.gwt.client.dnd.CmsDNDHandler.Orientation;
034import org.opencms.gwt.client.dnd.I_CmsDraggable;
035import org.opencms.gwt.client.dnd.I_CmsDropTarget;
036import org.opencms.gwt.client.ui.CmsHighlightingBorder;
037import org.opencms.gwt.client.util.CmsDomUtil;
038import org.opencms.gwt.client.util.CmsPositionBean;
039import org.opencms.util.CmsUUID;
040
041import java.util.ArrayList;
042import java.util.Collections;
043import java.util.Iterator;
044import java.util.List;
045
046import com.google.gwt.dom.client.Element;
047import com.google.gwt.dom.client.Style.Display;
048import com.google.gwt.dom.client.Style.Unit;
049import com.google.gwt.user.client.ui.RootPanel;
050import com.google.gwt.user.client.ui.Widget;
051
052/**
053 * Group-container element. To be used for content elements within a container-page.<p>
054 * The group-container acts as a draggable element and if edited as a container.<p>
055 *
056 * @since 8.0.0
057 */
058public class CmsGroupContainerElementPanel extends CmsContainerPageElementPanel implements I_CmsDropContainer {
059
060    /** Processed children of the group. */
061    private List<CmsContainerPageElementPanel> m_children;
062
063    /** The container type. */
064    private String m_containerId;
065
066    /** The editing marker. Used to highlight the container background while editing. */
067    private Element m_editingMarker;
068
069    /** The editing placeholder. Used within group-container editing. */
070    private Element m_editingPlaceholder;
071
072    /** The cached highlighting position. */
073    private CmsPositionBean m_ownPosition;
074
075    /** The placeholder element. */
076    private Element m_placeholder;
077
078    /** The index of the current placeholder position. */
079    private int m_placeholderIndex = -1;
080
081    /** The resource type name. */
082    private String m_resourceType;
083
084    /**
085     * Constructor.<p>
086     *
087     * @param element the DOM element
088     * @param parent the drag parent
089     * @param clientId the client id
090     * @param sitePath the element site-path
091     * @param resourceType the resource type name
092     * @param noEditReason the no edit reason, if empty, editing is allowed
093     * @param title the resource title
094     * @param subTitle the sub title
095     * @param hasSettings should be true if the element has settings which can be edited
096     * @param hasViewPermission indicates if the current user has view permissions on the element resource
097     * @param hasWritePermission indicates if the current user has write permissions on the element resource
098     * @param releasedAndNotExpired <code>true</code> if the element resource is currently released and not expired
099     * @param elementView the element view of the element
100     * @param iconClasses the resource type icon CSS classes
101     */
102    public CmsGroupContainerElementPanel(
103        Element element,
104        I_CmsDropContainer parent,
105        String clientId,
106        String sitePath,
107        String resourceType,
108        String noEditReason,
109        String title,
110        String subTitle,
111        boolean hasSettings,
112        boolean hasViewPermission,
113        boolean hasWritePermission,
114        boolean releasedAndNotExpired,
115        CmsUUID elementView,
116        String iconClasses) {
117
118        super(
119            element,
120            parent,
121            clientId,
122            sitePath,
123            noEditReason,
124            new CmsElementLockInfo(null, false),
125            title,
126            subTitle,
127            resourceType,
128            hasSettings,
129            hasViewPermission,
130            hasWritePermission,
131            releasedAndNotExpired,
132            true,
133            false,
134            null,
135            false,
136            elementView,
137            iconClasses,
138            false);
139        m_resourceType = resourceType;
140    }
141
142    /**
143     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#addDndChild(org.opencms.gwt.client.dnd.I_CmsDropTarget)
144     */
145    public void addDndChild(I_CmsDropTarget child) {
146
147        throw new UnsupportedOperationException("Element groups do not support nested containers");
148    }
149
150    /**
151     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#adoptElement(org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel)
152     */
153    public void adoptElement(CmsContainerPageElementPanel containerElement) {
154
155        assert getElement().equals(containerElement.getElement().getParentElement());
156        getChildren().add(containerElement);
157        adopt(containerElement);
158    }
159
160    /**
161     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#checkMaxElementsOnEnter()
162     */
163    public void checkMaxElementsOnEnter() {
164
165        // TODO: implement
166
167    }
168
169    /**
170     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#checkMaxElementsOnLeave()
171     */
172    public void checkMaxElementsOnLeave() {
173
174        // TODO: implement
175
176    }
177
178    /**
179     * @see org.opencms.gwt.client.dnd.I_CmsDropTarget#checkPosition(int, int, Orientation)
180     */
181    public boolean checkPosition(int x, int y, Orientation orientation) {
182
183        // ignore orientation
184        int scrollTop = getElement().getOwnerDocument().getScrollTop();
185        // use cached position
186        int relativeTop = (y + scrollTop) - m_ownPosition.getTop();
187        if ((relativeTop > 0) && (m_ownPosition.getHeight() > relativeTop)) {
188            // cursor is inside the height of the element, check horizontal position
189            int scrollLeft = getElement().getOwnerDocument().getScrollLeft();
190            int relativeLeft = (x + scrollLeft) - m_ownPosition.getLeft();
191            return (relativeLeft > 0) && (m_ownPosition.getWidth() > relativeLeft);
192        }
193        return false;
194    }
195
196    /**
197     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#clearDnDChildren()
198     */
199    public void clearDnDChildren() {
200
201        // nothing todo
202    }
203
204    /**
205     * Clears the editing placeholder reference.<p>
206     */
207    public void clearEditingPlaceholder() {
208
209        m_editingPlaceholder = null;
210        m_editingMarker = null;
211    }
212
213    /**
214     * Returns the container id.<p>
215     *
216     * @return the container id
217     */
218    public String getContainerId() {
219
220        return m_containerId;
221    }
222
223    /**
224     * @see org.opencms.gwt.client.dnd.I_CmsNestedDropTarget#getDnDChildren()
225     */
226    public List<I_CmsDropTarget> getDnDChildren() {
227
228        return null;
229    }
230
231    /**
232     * Gets the consumed group elements.<p>
233     *
234     * @return the list of children
235     */
236    public List<CmsContainerPageElementPanel> getGroupChildren() {
237
238        if (m_children == null) {
239            // can happen when saving element groups
240            return Collections.emptyList();
241        }
242        return m_children;
243    }
244
245    /**
246     * @see org.opencms.gwt.client.dnd.I_CmsDropTarget#getPlaceholderIndex()
247     */
248    public int getPlaceholderIndex() {
249
250        return m_placeholderIndex;
251    }
252
253    /**
254     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#getPositionInfo()
255     */
256    public CmsPositionBean getPositionInfo() {
257
258        return m_ownPosition;
259    }
260
261    /**
262     * @see org.opencms.gwt.client.dnd.I_CmsNestedDropTarget#hasDnDChildren()
263     */
264    public boolean hasDnDChildren() {
265
266        return false;
267    }
268
269    /**
270     * @see org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel#hideEditableListButtons()
271     */
272    @Override
273    public void hideEditableListButtons() {
274
275        Iterator<Widget> it = iterator();
276        while (it.hasNext()) {
277            Widget child = it.next();
278            if (child instanceof CmsContainerPageElementPanel) {
279                ((CmsContainerPageElementPanel)child).hideEditableListButtons();
280            }
281        }
282    }
283
284    /**
285     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#highlightContainer()
286     */
287    public void highlightContainer(boolean addSeparators) {
288
289        // separators neither needed nor implemented
290        highlightContainer(CmsPositionBean.getBoundingClientRect(getElement()), addSeparators);
291    }
292
293    /**
294     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#highlightContainer(org.opencms.gwt.client.util.CmsPositionBean)
295     */
296    public void highlightContainer(CmsPositionBean positionInfo, boolean separators) {
297        // separators neither needed nor implemented
298
299        // remove any remaining highlighting
300        if (m_highlighting != null) {
301            m_highlighting.removeFromParent();
302        }
303        // cache the position info, to be used during drag and drop
304        m_ownPosition = positionInfo;
305        if (m_editingPlaceholder != null) {
306            m_editingPlaceholder.getStyle().setHeight(m_ownPosition.getHeight() + 10, Unit.PX);
307        }
308        if (m_editingMarker != null) {
309            m_editingMarker.getStyle().setHeight(m_ownPosition.getHeight() + 4, Unit.PX);
310            m_editingMarker.getStyle().setWidth(m_ownPosition.getWidth() + 4, Unit.PX);
311        }
312        m_highlighting = new CmsHighlightingBorder(m_ownPosition, CmsHighlightingBorder.BorderColor.red);
313        RootPanel.get().add(m_highlighting);
314    }
315
316    /**
317     * @see org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel#initInlineEditor(org.opencms.ade.containerpage.client.CmsContainerpageController)
318     */
319    @Override
320    public void initInlineEditor(CmsContainerpageController controller) {
321
322        // don to anything
323    }
324
325    /**
326     * @see org.opencms.gwt.client.dnd.I_CmsDropTarget#insertPlaceholder(com.google.gwt.dom.client.Element, int, int, Orientation)
327     */
328    public void insertPlaceholder(Element placeholder, int x, int y, Orientation orientation) {
329
330        m_placeholderIndex = -1;
331        m_placeholder = placeholder;
332        m_placeholder.getStyle().setDisplay(Display.NONE);
333        repositionPlaceholder(x, y, orientation);
334    }
335
336    /**
337     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#isDetailOnly()
338     */
339    public boolean isDetailOnly() {
340
341        return false;
342    }
343
344    /**
345     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#isDetailView()
346     */
347    public boolean isDetailView() {
348
349        return false;
350    }
351
352    /**
353     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#isEditable()
354     */
355    public boolean isEditable() {
356
357        return hasWritePermission();
358    }
359
360    /**
361     * Returns if this element represents a group container.<p>
362     *
363     * @return <code>true</code> if this element represents a group container
364     */
365    public boolean isGroupContainer() {
366
367        return CmsContainerElement.GROUP_CONTAINER_TYPE_NAME.equals(m_resourceType);
368    }
369
370    /**
371     * Returns if this element represents an inherit container.<p>
372     *
373     * @return <code>true</code> if this element represents an inherit container
374     */
375    public boolean isInheritContainer() {
376
377        return CmsContainerElement.INHERIT_CONTAINER_TYPE_NAME.equals(m_resourceType);
378    }
379
380    /**
381     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#onConsumeChildren(java.util.List)
382     */
383    public void onConsumeChildren(List<CmsContainerPageElementPanel> children) {
384
385        m_children = new ArrayList<CmsContainerPageElementPanel>(children);
386    }
387
388    /**
389     * @see org.opencms.gwt.client.dnd.I_CmsDropTarget#onDrop(org.opencms.gwt.client.dnd.I_CmsDraggable)
390     */
391    public void onDrop(I_CmsDraggable draggable) {
392
393        // nothing to do
394
395    }
396
397    /**
398     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#refreshHighlighting()
399     */
400    public void refreshHighlighting() {
401
402        refreshHighlighting(CmsPositionBean.getBoundingClientRect(getElement()));
403    }
404
405    /**
406     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#refreshHighlighting(org.opencms.gwt.client.util.CmsPositionBean)
407     */
408    public void refreshHighlighting(CmsPositionBean positionInfo) {
409
410        m_ownPosition = positionInfo;
411        if (m_editingPlaceholder != null) {
412            m_editingPlaceholder.getStyle().setHeight(m_ownPosition.getHeight() + 10, Unit.PX);
413        }
414        if (m_editingMarker != null) {
415            m_editingMarker.getStyle().setHeight(m_ownPosition.getHeight() + 4, Unit.PX);
416            m_editingMarker.getStyle().setWidth(m_ownPosition.getWidth() + 4, Unit.PX);
417        }
418        if (m_highlighting != null) {
419            m_highlighting.setPosition(m_ownPosition);
420        }
421    }
422
423    /**
424     * @see org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel#removeHighlighting()
425     */
426    @Override
427    public void removeHighlighting() {
428
429        if (m_highlighting != null) {
430            m_highlighting.removeFromParent();
431            m_highlighting = null;
432        }
433    }
434
435    /**
436     * @see org.opencms.gwt.client.dnd.I_CmsDropTarget#removePlaceholder()
437     */
438    public void removePlaceholder() {
439
440        if (m_placeholder != null) {
441            m_placeholder.removeFromParent();
442            m_placeholder = null;
443        }
444        m_placeholderIndex = -1;
445    }
446
447    /**
448     * @see org.opencms.gwt.client.dnd.I_CmsDropTarget#repositionPlaceholder(int, int, Orientation)
449     */
450    public void repositionPlaceholder(int x, int y, Orientation orientation) {
451
452        int oldIndex = m_placeholderIndex;
453        switch (orientation) {
454            case HORIZONTAL:
455                m_placeholderIndex = CmsDomUtil.positionElementInside(
456                    m_placeholder,
457                    getElement(),
458                    m_placeholderIndex,
459                    x,
460                    -1);
461                break;
462            case VERTICAL:
463                m_placeholderIndex = CmsDomUtil.positionElementInside(
464                    m_placeholder,
465                    getElement(),
466                    m_placeholderIndex,
467                    -1,
468                    y);
469                break;
470            case ALL:
471            default:
472                m_placeholderIndex = CmsDomUtil.positionElementInside(
473                    m_placeholder,
474                    getElement(),
475                    m_placeholderIndex,
476                    x,
477                    y);
478                break;
479        }
480        if (oldIndex != m_placeholderIndex) {
481            m_ownPosition = CmsPositionBean.getBoundingClientRect(getElement());
482        }
483    }
484
485    /**
486     * Sets the container id.<p>
487     *
488     * @param containerId the container id to set
489     */
490    public void setContainerId(String containerId) {
491
492        m_containerId = containerId;
493    }
494
495    /**
496     * Sets the editing marker. Used to highlight the container background while editing.<p>
497     *
498     * @param editingMarker the editing marker element
499     */
500    public void setEditingMarker(Element editingMarker) {
501
502        m_editingMarker = editingMarker;
503    }
504
505    /**
506     * Sets the editing placeholder.<p>
507     *
508     * @param editingPlaceholder the editing placeholder element
509     */
510    public void setEditingPlaceholder(Element editingPlaceholder) {
511
512        m_editingPlaceholder = editingPlaceholder;
513    }
514
515    /**
516     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#setPlaceholderVisibility(boolean)
517     */
518    public void setPlaceholderVisibility(boolean visible) {
519
520        if (visible) {
521            m_placeholder.getStyle().clearDisplay();
522        } else {
523            m_placeholder.getStyle().setDisplay(Display.NONE);
524        }
525    }
526
527    /**
528     * @see org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel#showEditableListButtons()
529     */
530    @Override
531    public void showEditableListButtons() {
532
533        Iterator<Widget> it = iterator();
534        while (it.hasNext()) {
535            Widget child = it.next();
536            if (child instanceof CmsContainerPageElementPanel) {
537                ((CmsContainerPageElementPanel)child).showEditableListButtons();
538            }
539        }
540    }
541
542    /**
543     * @see org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel#updateOptionBarPosition()
544     */
545    @Override
546    public void updateOptionBarPosition() {
547
548        for (Widget widget : this) {
549            if (widget instanceof CmsContainerPageElementPanel) {
550                ((CmsContainerPageElementPanel)widget).updateOptionBarPosition();
551            }
552        }
553    }
554
555    /**
556     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#updatePositionInfo()
557     */
558    public void updatePositionInfo() {
559
560        m_ownPosition = CmsPositionBean.getBoundingClientRect(getElement());
561    }
562}