001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://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: https://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: https://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            null,
133            true,
134            false,
135            null,
136            false,
137            elementView,
138            iconClasses,
139            false);
140        m_resourceType = resourceType;
141    }
142
143    /**
144     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#addDndChild(org.opencms.gwt.client.dnd.I_CmsDropTarget)
145     */
146    public void addDndChild(I_CmsDropTarget child) {
147
148        throw new UnsupportedOperationException("Element groups do not support nested containers");
149    }
150
151    /**
152     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#adoptElement(org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel)
153     */
154    public void adoptElement(CmsContainerPageElementPanel containerElement) {
155
156        assert getElement().equals(containerElement.getElement().getParentElement());
157        getChildren().add(containerElement);
158        adopt(containerElement);
159    }
160
161    /**
162     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#checkMaxElementsOnEnter()
163     */
164    public void checkMaxElementsOnEnter() {
165
166        // TODO: implement
167
168    }
169
170    /**
171     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#checkMaxElementsOnLeave()
172     */
173    public void checkMaxElementsOnLeave() {
174
175        // TODO: implement
176
177    }
178
179    /**
180     * @see org.opencms.gwt.client.dnd.I_CmsDropTarget#checkPosition(int, int, Orientation)
181     */
182    public boolean checkPosition(int x, int y, Orientation orientation) {
183
184        // ignore orientation
185        int scrollTop = getElement().getOwnerDocument().getScrollTop();
186        // use cached position
187        int relativeTop = (y + scrollTop) - m_ownPosition.getTop();
188        if ((relativeTop > 0) && (m_ownPosition.getHeight() > relativeTop)) {
189            // cursor is inside the height of the element, check horizontal position
190            int scrollLeft = getElement().getOwnerDocument().getScrollLeft();
191            int relativeLeft = (x + scrollLeft) - m_ownPosition.getLeft();
192            return (relativeLeft > 0) && (m_ownPosition.getWidth() > relativeLeft);
193        }
194        return false;
195    }
196
197    /**
198     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#clearDnDChildren()
199     */
200    public void clearDnDChildren() {
201
202        // nothing todo
203    }
204
205    /**
206     * Clears the editing placeholder reference.<p>
207     */
208    public void clearEditingPlaceholder() {
209
210        m_editingPlaceholder = null;
211        m_editingMarker = null;
212    }
213
214    /**
215     * Returns the container id.<p>
216     *
217     * @return the container id
218     */
219    public String getContainerId() {
220
221        return m_containerId;
222    }
223
224    /**
225     * @see org.opencms.gwt.client.dnd.I_CmsNestedDropTarget#getDnDChildren()
226     */
227    public List<I_CmsDropTarget> getDnDChildren() {
228
229        return null;
230    }
231
232    /**
233     * Gets the consumed group elements.<p>
234     *
235     * @return the list of children
236     */
237    public List<CmsContainerPageElementPanel> getGroupChildren() {
238
239        if (m_children == null) {
240            // can happen when saving element groups
241            return Collections.emptyList();
242        }
243        return m_children;
244    }
245
246    /**
247     * @see org.opencms.gwt.client.dnd.I_CmsDropTarget#getPlaceholderIndex()
248     */
249    public int getPlaceholderIndex() {
250
251        return m_placeholderIndex;
252    }
253
254    /**
255     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#getPositionInfo()
256     */
257    public CmsPositionBean getPositionInfo() {
258
259        return m_ownPosition;
260    }
261
262    /**
263     * @see org.opencms.gwt.client.dnd.I_CmsNestedDropTarget#hasDnDChildren()
264     */
265    public boolean hasDnDChildren() {
266
267        return false;
268    }
269
270    /**
271     * @see org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel#hideEditableListButtons()
272     */
273    @Override
274    public void hideEditableListButtons() {
275
276        Iterator<Widget> it = iterator();
277        while (it.hasNext()) {
278            Widget child = it.next();
279            if (child instanceof CmsContainerPageElementPanel) {
280                ((CmsContainerPageElementPanel)child).hideEditableListButtons();
281            }
282        }
283    }
284
285    /**
286     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#highlightContainer(boolean)
287     */
288    public void highlightContainer(boolean addSeparators) {
289
290        // separators neither needed nor implemented
291        highlightContainer(CmsPositionBean.getBoundingClientRect(getElement()), addSeparators);
292    }
293
294    /**
295     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#highlightContainer(org.opencms.gwt.client.util.CmsPositionBean, boolean)
296     */
297    public void highlightContainer(CmsPositionBean positionInfo, boolean separators) {
298        // separators neither needed nor implemented
299
300        // remove any remaining highlighting
301        if (m_highlighting != null) {
302            m_highlighting.removeFromParent();
303        }
304        // cache the position info, to be used during drag and drop
305        m_ownPosition = positionInfo;
306        if (m_editingPlaceholder != null) {
307            m_editingPlaceholder.getStyle().setHeight(m_ownPosition.getHeight() + 10, Unit.PX);
308        }
309        if (m_editingMarker != null) {
310            m_editingMarker.getStyle().setHeight(m_ownPosition.getHeight() + 4, Unit.PX);
311            m_editingMarker.getStyle().setWidth(m_ownPosition.getWidth() + 4, Unit.PX);
312        }
313        m_highlighting = new CmsHighlightingBorder(m_ownPosition, CmsHighlightingBorder.BorderColor.red);
314        RootPanel.get().add(m_highlighting);
315    }
316
317    /**
318     * @see org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel#initInlineEditor(org.opencms.ade.containerpage.client.CmsContainerpageController)
319     */
320    @Override
321    public void initInlineEditor(CmsContainerpageController controller) {
322
323        // don to anything
324    }
325
326    /**
327     * @see org.opencms.gwt.client.dnd.I_CmsDropTarget#insertPlaceholder(com.google.gwt.dom.client.Element, int, int, Orientation)
328     */
329    public void insertPlaceholder(Element placeholder, int x, int y, Orientation orientation) {
330
331        m_placeholderIndex = -1;
332        m_placeholder = placeholder;
333        m_placeholder.getStyle().setDisplay(Display.NONE);
334        repositionPlaceholder(x, y, orientation);
335    }
336
337    /**
338     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#isDetailOnly()
339     */
340    public boolean isDetailOnly() {
341
342        return false;
343    }
344
345    /**
346     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#isDetailView()
347     */
348    public boolean isDetailView() {
349
350        return false;
351    }
352
353    /**
354     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#isEditable()
355     */
356    public boolean isEditable() {
357
358        return hasWritePermission();
359    }
360
361    /**
362     * Returns if this element represents a group container.<p>
363     *
364     * @return <code>true</code> if this element represents a group container
365     */
366    public boolean isGroupContainer() {
367
368        return CmsContainerElement.GROUP_CONTAINER_TYPE_NAME.equals(m_resourceType);
369    }
370
371    /**
372     * Returns if this element represents an inherit container.<p>
373     *
374     * @return <code>true</code> if this element represents an inherit container
375     */
376    public boolean isInheritContainer() {
377
378        return CmsContainerElement.INHERIT_CONTAINER_TYPE_NAME.equals(m_resourceType);
379    }
380
381    /**
382     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#onConsumeChildren(java.util.List)
383     */
384    public void onConsumeChildren(List<CmsContainerPageElementPanel> children) {
385
386        m_children = new ArrayList<CmsContainerPageElementPanel>(children);
387    }
388
389    /**
390     * @see org.opencms.gwt.client.dnd.I_CmsDropTarget#onDrop(org.opencms.gwt.client.dnd.I_CmsDraggable)
391     */
392    public void onDrop(I_CmsDraggable draggable) {
393
394        // nothing to do
395
396    }
397
398    /**
399     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#refreshHighlighting()
400     */
401    public void refreshHighlighting() {
402
403        refreshHighlighting(CmsPositionBean.getBoundingClientRect(getElement()));
404    }
405
406    /**
407     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#refreshHighlighting(org.opencms.gwt.client.util.CmsPositionBean)
408     */
409    public void refreshHighlighting(CmsPositionBean positionInfo) {
410
411        m_ownPosition = positionInfo;
412        if (m_editingPlaceholder != null) {
413            m_editingPlaceholder.getStyle().setHeight(m_ownPosition.getHeight() + 10, Unit.PX);
414        }
415        if (m_editingMarker != null) {
416            m_editingMarker.getStyle().setHeight(m_ownPosition.getHeight() + 4, Unit.PX);
417            m_editingMarker.getStyle().setWidth(m_ownPosition.getWidth() + 4, Unit.PX);
418        }
419        if (m_highlighting != null) {
420            m_highlighting.setPosition(m_ownPosition);
421        }
422    }
423
424    /**
425     * @see org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel#removeHighlighting()
426     */
427    @Override
428    public void removeHighlighting() {
429
430        if (m_highlighting != null) {
431            m_highlighting.removeFromParent();
432            m_highlighting = null;
433        }
434    }
435
436    /**
437     * @see org.opencms.gwt.client.dnd.I_CmsDropTarget#removePlaceholder()
438     */
439    public void removePlaceholder() {
440
441        if (m_placeholder != null) {
442            m_placeholder.removeFromParent();
443            m_placeholder = null;
444        }
445        m_placeholderIndex = -1;
446    }
447
448    /**
449     * @see org.opencms.gwt.client.dnd.I_CmsDropTarget#repositionPlaceholder(int, int, Orientation)
450     */
451    public void repositionPlaceholder(int x, int y, Orientation orientation) {
452
453        int oldIndex = m_placeholderIndex;
454        switch (orientation) {
455            case HORIZONTAL:
456                m_placeholderIndex = CmsDomUtil.positionElementInside(
457                    m_placeholder,
458                    getElement(),
459                    m_placeholderIndex,
460                    x,
461                    -1);
462                break;
463            case VERTICAL:
464                m_placeholderIndex = CmsDomUtil.positionElementInside(
465                    m_placeholder,
466                    getElement(),
467                    m_placeholderIndex,
468                    -1,
469                    y);
470                break;
471            case ALL:
472            default:
473                m_placeholderIndex = CmsDomUtil.positionElementInside(
474                    m_placeholder,
475                    getElement(),
476                    m_placeholderIndex,
477                    x,
478                    y);
479                break;
480        }
481        if (oldIndex != m_placeholderIndex) {
482            m_ownPosition = CmsPositionBean.getBoundingClientRect(getElement());
483        }
484    }
485
486    /**
487     * Sets the container id.<p>
488     *
489     * @param containerId the container id to set
490     */
491    public void setContainerId(String containerId) {
492
493        m_containerId = containerId;
494    }
495
496    /**
497     * Sets the editing marker. Used to highlight the container background while editing.<p>
498     *
499     * @param editingMarker the editing marker element
500     */
501    public void setEditingMarker(Element editingMarker) {
502
503        m_editingMarker = editingMarker;
504    }
505
506    /**
507     * Sets the editing placeholder.<p>
508     *
509     * @param editingPlaceholder the editing placeholder element
510     */
511    public void setEditingPlaceholder(Element editingPlaceholder) {
512
513        m_editingPlaceholder = editingPlaceholder;
514    }
515
516    /**
517     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#setPlaceholderVisibility(boolean)
518     */
519    public void setPlaceholderVisibility(boolean visible) {
520
521        if (visible) {
522            m_placeholder.getStyle().clearDisplay();
523        } else {
524            m_placeholder.getStyle().setDisplay(Display.NONE);
525        }
526    }
527
528    /**
529     * @see org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel#showEditableListButtons()
530     */
531    @Override
532    public void showEditableListButtons() {
533
534        Iterator<Widget> it = iterator();
535        while (it.hasNext()) {
536            Widget child = it.next();
537            if (child instanceof CmsContainerPageElementPanel) {
538                ((CmsContainerPageElementPanel)child).showEditableListButtons();
539            }
540        }
541    }
542
543    /**
544     * @see org.opencms.ade.containerpage.client.ui.CmsContainerPageElementPanel#updateOptionBarPosition()
545     */
546    @Override
547    public void updateOptionBarPosition() {
548
549        for (Widget widget : this) {
550            if (widget instanceof CmsContainerPageElementPanel) {
551                ((CmsContainerPageElementPanel)widget).updateOptionBarPosition();
552            }
553        }
554    }
555
556    /**
557     * @see org.opencms.ade.containerpage.client.ui.I_CmsDropContainer#updatePositionInfo()
558     */
559    public void updatePositionInfo() {
560
561        m_ownPosition = CmsPositionBean.getBoundingClientRect(getElement());
562    }
563}