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.gwt.client.ui;
029
030import org.opencms.gwt.client.dnd.CmsDNDHandler;
031import org.opencms.gwt.client.dnd.CmsDNDHandler.Orientation;
032import org.opencms.gwt.client.dnd.I_CmsDraggable;
033import org.opencms.gwt.client.dnd.I_CmsDropTarget;
034import org.opencms.gwt.client.ui.css.I_CmsLayoutBundle;
035import org.opencms.gwt.client.ui.css.I_CmsLayoutBundle.I_CmsListTreeCss;
036import org.opencms.gwt.client.util.CmsDomUtil;
037
038import java.util.HashMap;
039import java.util.Map;
040
041import com.google.gwt.dom.client.Element;
042import com.google.gwt.user.client.DOM;
043import com.google.gwt.user.client.ui.ComplexPanel;
044import com.google.gwt.user.client.ui.Widget;
045
046/**
047 * A very basic list implementation to hold {@link CmsListItemWidget}.<p>
048 *
049 * @param <I> the specific list item implementation
050 *
051 * @since 8.0.0
052 */
053public class CmsList<I extends I_CmsListItem> extends ComplexPanel implements I_CmsTruncable, I_CmsDropTarget {
054
055    /** The css bundle used for this widget. */
056    private static final I_CmsListTreeCss CSS = I_CmsLayoutBundle.INSTANCE.listTreeCss();
057
058    /** The drag'n drop handler. */
059    protected CmsDNDHandler m_dndHandler;
060
061    /** The current place holder. */
062    protected Element m_placeholder;
063
064    /** The placeholder position index. */
065    protected int m_placeholderIndex = -1;
066
067    /** The child width in px for truncation. */
068    private int m_childWidth;
069
070    /** Flag to indicate if drag'n drop on the root node is allowed. */
071    private boolean m_dropEnabled;
072
073    /** The map of items. */
074    private Map<String, I> m_items;
075
076    /** Flag to indicate if the list will always return <code>true</code> on check target requests within drag and drop. */
077    private boolean m_takeAll;
078
079    /** The text metrics prefix. */
080    private String m_tmPrefix;
081
082    /**
083     * Constructor.<p>
084     */
085    public CmsList() {
086
087        setElement((Element)DOM.createElement(CmsDomUtil.Tag.ul.name()));
088        setStyleName(CSS.list());
089        m_items = new HashMap<String, I>();
090    }
091
092    /**
093     * @see com.google.gwt.user.client.ui.Panel#add(com.google.gwt.user.client.ui.Widget)
094     */
095    @SuppressWarnings("unchecked")
096    @Override
097    public void add(Widget widget) {
098
099        assert widget instanceof I_CmsListItem;
100        add(widget, (Element)getElement());
101        registerItem((I)widget);
102    }
103
104    /**
105     * Adds an item to the list.<p>
106     *
107     * @param item the item to add
108     *
109     * @see #add(Widget)
110     */
111    public void addItem(I item) {
112
113        add((Widget)item);
114    }
115
116    /**
117     * @see org.opencms.gwt.client.dnd.I_CmsDropTarget#checkPosition(int, int, Orientation)
118     */
119    public boolean checkPosition(int x, int y, Orientation orientation) {
120
121        if (!isDropEnabled()) {
122            return false;
123        }
124        if (isDNDTakeAll()) {
125            return true;
126        }
127        switch (orientation) {
128            case HORIZONTAL:
129                return CmsDomUtil.checkPositionInside(getElement(), x, -1);
130            case VERTICAL:
131                return CmsDomUtil.checkPositionInside(getElement(), -1, y);
132            case ALL:
133            default:
134                return CmsDomUtil.checkPositionInside(getElement(), x, y);
135        }
136    }
137
138    /**
139     * Clears the list.<p>
140     */
141    public void clearList() {
142
143        clear();
144        m_items.clear();
145    }
146
147    /**
148     * Returns the drag'n drop handler.<p>
149     *
150     * @return the handler
151     */
152    public CmsDNDHandler getDnDHandler() {
153
154        return m_dndHandler;
155    }
156
157    /**
158     * Returns the list item at the given position.<p>
159     *
160     * @param index the position
161     *
162     * @return the list item
163     *
164     * @see #getWidget(int)
165     */
166    public I getItem(int index) {
167
168        return (I)getWidget(index);
169    }
170
171    /**
172     * Returns the list item with the given id.<p>
173     *
174     * @param itemId the id of the item to retrieve
175     *
176     * @return the list item
177     *
178     * @see #getWidget(int)
179     */
180    public I getItem(String itemId) {
181
182        return m_items.get(itemId);
183    }
184
185    /**
186     * Returns the given item position.<p>
187     *
188     * @param item the item to get the position for
189     *
190     * @return the item position
191     */
192    public int getItemPosition(I item) {
193
194        return getWidgetIndex((Widget)item);
195    }
196
197    /**
198     * @see org.opencms.gwt.client.dnd.I_CmsDropTarget#getPlaceholderIndex()
199     */
200    public int getPlaceholderIndex() {
201
202        return m_placeholderIndex;
203
204    }
205
206    /**
207     * Inserts the given widget at the given position.<p>
208     *
209     * @param widget the widget to insert
210     * @param position the position
211     */
212    @SuppressWarnings("unchecked")
213    public void insert(Widget widget, int position) {
214
215        assert widget instanceof I_CmsListItem;
216        insert(widget, (Element)getElement(), position, true);
217        registerItem((I)widget);
218    }
219
220    /**
221     * Inserts the given item at the given position.<p>
222     *
223     * @param item the item to insert
224     * @param position the position
225     */
226    public void insertItem(I item, int position) {
227
228        insert((Widget)item, position);
229    }
230
231    /**
232     * @see org.opencms.gwt.client.dnd.I_CmsDropTarget#insertPlaceholder(com.google.gwt.dom.client.Element, int, int, Orientation)
233     */
234    public void insertPlaceholder(Element placeholder, int x, int y, Orientation orientation) {
235
236        m_placeholder = placeholder;
237        repositionPlaceholder(x, y, orientation);
238    }
239
240    /**
241     * Returns if the list will always return <code>true</code> on check target requests within drag and drop.<p>
242     *
243     * @return <code>true</code> if take all is enabled for drag and drop
244     */
245    public boolean isDNDTakeAll() {
246
247        return m_takeAll;
248    }
249
250    /**
251     * Checks if dropping is enabled.<p>
252     *
253     * @return <code>true</code> if dropping is enabled
254     */
255    public boolean isDropEnabled() {
256
257        return m_dropEnabled;
258    }
259
260    /**
261     * @see org.opencms.gwt.client.dnd.I_CmsDropTarget#onDrop(org.opencms.gwt.client.dnd.I_CmsDraggable)
262     */
263    public void onDrop(I_CmsDraggable draggable) {
264
265        return;
266    }
267
268    /**
269     * @see com.google.gwt.user.client.ui.ComplexPanel#remove(com.google.gwt.user.client.ui.Widget)
270     */
271    @Override
272    public boolean remove(Widget w) {
273
274        boolean result = super.remove(w);
275        if (result && (w instanceof I_CmsListItem)) {
276            String id = ((I_CmsListItem)w).getId();
277            if (id != null) {
278                m_items.remove(id);
279            }
280        }
281        return result;
282    }
283
284    /**
285     * Removes an item from the list.<p>
286     *
287     * @param item the item to remove
288     *
289     * @return the removed item
290     *
291     * @see #remove(Widget)
292     */
293    public I removeItem(I item) {
294
295        remove((Widget)item);
296        return item;
297    }
298
299    /**
300     * Removes an item from the list.<p>
301     *
302     * @param itemId the id of the item to remove
303     *
304     * @return the removed item
305     *
306     * @see #remove(Widget)
307     */
308    public I removeItem(String itemId) {
309
310        I item = m_items.get(itemId);
311        remove((Widget)item);
312        return item;
313    }
314
315    /**
316     * @see org.opencms.gwt.client.dnd.I_CmsDropTarget#removePlaceholder()
317     */
318    public void removePlaceholder() {
319
320        if (m_placeholder == null) {
321            return;
322        }
323        m_placeholder.removeFromParent();
324        m_placeholder = null;
325        m_placeholderIndex = -1;
326    }
327
328    /**
329     * @see org.opencms.gwt.client.dnd.I_CmsDropTarget#repositionPlaceholder(int, int, Orientation)
330     */
331    public void repositionPlaceholder(int x, int y, Orientation orientation) {
332
333        switch (orientation) {
334            case HORIZONTAL:
335                m_placeholderIndex = CmsDomUtil.positionElementInside(
336                    m_placeholder,
337                    getElement(),
338                    m_placeholderIndex,
339                    x,
340                    -1);
341                break;
342            case VERTICAL:
343                m_placeholderIndex = CmsDomUtil.positionElementInside(
344                    m_placeholder,
345                    getElement(),
346                    m_placeholderIndex,
347                    -1,
348                    y);
349                break;
350            case ALL:
351            default:
352                m_placeholderIndex = CmsDomUtil.positionElementInside(
353                    m_placeholder,
354                    getElement(),
355                    m_placeholderIndex,
356                    x,
357                    y);
358                break;
359        }
360    }
361
362    /**
363     * Sets the drag'n drop handler.<p>
364     *
365     * @param handler the handler to set
366     */
367    public void setDNDHandler(CmsDNDHandler handler) {
368
369        m_dndHandler = handler;
370    }
371
372    /**
373     * Sets if the list will always return <code>true</code> on check target requests within drag and drop.<p>
374     *
375     * @param takeAll <code>true</code> to enable take all for drag and drop
376     */
377    public void setDNDTakeAll(boolean takeAll) {
378
379        m_takeAll = takeAll;
380    }
381
382    /**
383     * Enables/disables dropping.<p>
384     *
385     * @param enabled <code>true</code> to enable, or <code>false</code> to disable
386     */
387    public void setDropEnabled(boolean enabled) {
388
389        m_dropEnabled = enabled;
390    }
391
392    /**
393     * @see org.opencms.gwt.client.ui.I_CmsTruncable#truncate(java.lang.String, int)
394     */
395    public void truncate(String textMetricsPrefix, int widgetWidth) {
396
397        m_childWidth = widgetWidth;
398        for (Widget item : this) {
399            if (item instanceof I_CmsTruncable) {
400                ((I_CmsTruncable)item).truncate(textMetricsPrefix, widgetWidth);
401            }
402        }
403        m_tmPrefix = textMetricsPrefix;
404    }
405
406    /**
407     * Changes the id for the given item.<p>
408     *
409     * @param item the item to change the id for
410     * @param id the new id
411     */
412    protected void changeId(I item, String id) {
413
414        if (m_items.remove(item.getId()) != null) {
415            m_items.put(id, item);
416        }
417    }
418
419    /**
420     * Registers the given item on this list.<p>
421     *
422     * @param item the item to register
423     */
424    protected void registerItem(I item) {
425
426        if (item.getId() != null) {
427            m_items.put(item.getId(), item);
428        }
429        if (m_tmPrefix != null) {
430            item.truncate(m_tmPrefix, m_childWidth);
431        }
432    }
433
434    /**
435     * Sets the current drag'n drop place holder.<p>
436     *
437     * @param placeholder the element to set as place holder
438     */
439    protected void setPlaceholder(Element placeholder) {
440
441        removePlaceholder();
442        m_placeholder = placeholder;
443    }
444}