001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (C) Alkacon Software (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.resourceinfo;
029
030import org.opencms.gwt.client.CmsCoreProvider;
031import org.opencms.gwt.client.CmsEditableData;
032import org.opencms.gwt.client.I_CmsDescendantResizeHandler;
033import org.opencms.gwt.client.Messages;
034import org.opencms.gwt.client.ui.CmsFieldSet;
035import org.opencms.gwt.client.ui.CmsList;
036import org.opencms.gwt.client.ui.CmsListItem;
037import org.opencms.gwt.client.ui.CmsListItemWidget;
038import org.opencms.gwt.client.ui.CmsPopup;
039import org.opencms.gwt.client.ui.CmsPushButton;
040import org.opencms.gwt.client.ui.CmsScrollPanel;
041import org.opencms.gwt.client.ui.CmsSimpleListItem;
042import org.opencms.gwt.client.ui.I_CmsButton;
043import org.opencms.gwt.client.ui.I_CmsButton.ButtonStyle;
044import org.opencms.gwt.client.ui.contenteditor.CmsContentEditorDialog;
045import org.opencms.gwt.client.ui.contenteditor.CmsContentEditorDialog.DialogOptions;
046import org.opencms.gwt.client.ui.contenteditor.I_CmsContentEditorHandler;
047import org.opencms.gwt.client.ui.contextmenu.CmsContextMenuButton;
048import org.opencms.gwt.client.ui.contextmenu.CmsContextMenuHandler;
049import org.opencms.gwt.client.ui.contextmenu.CmsLogout;
050import org.opencms.gwt.client.ui.css.I_CmsLayoutBundle;
051import org.opencms.gwt.client.util.CmsDomUtil;
052import org.opencms.gwt.shared.CmsCoreData.AdeContext;
053import org.opencms.gwt.shared.CmsGwtConstants;
054import org.opencms.gwt.shared.CmsResourceStatusBean;
055import org.opencms.gwt.shared.CmsResourceStatusRelationBean;
056import org.opencms.util.CmsStringUtil;
057import org.opencms.util.CmsUUID;
058
059import java.util.ArrayList;
060import java.util.HashSet;
061import java.util.List;
062import java.util.Set;
063
064import com.google.gwt.core.client.GWT;
065import com.google.gwt.dom.client.Style;
066import com.google.gwt.dom.client.Style.Cursor;
067import com.google.gwt.event.dom.client.ClickEvent;
068import com.google.gwt.event.dom.client.ClickHandler;
069import com.google.gwt.event.logical.shared.CloseEvent;
070import com.google.gwt.event.logical.shared.CloseHandler;
071import com.google.gwt.event.logical.shared.OpenEvent;
072import com.google.gwt.event.logical.shared.OpenHandler;
073import com.google.gwt.user.client.Timer;
074import com.google.gwt.user.client.Window;
075import com.google.gwt.user.client.ui.Composite;
076import com.google.gwt.user.client.ui.FlowPanel;
077import com.google.gwt.user.client.ui.Label;
078import com.google.gwt.user.client.ui.SimplePanel;
079
080/**
081 * Widget which shows which contents refer to a resource. <p>
082 */
083public class CmsResourceRelationView extends Composite implements I_CmsDescendantResizeHandler {
084
085    /** Enum for the display mode. */
086    public enum Mode {
087        /** Display siblings. */
088        siblings,
089        /** Display relation sources. */
090        sources,
091
092        /** Display relation targets. */
093        targets
094    }
095
096    /** Set of context menu actions which we do not want to appear in the context menu for the relation source items. */
097    protected static Set<String> m_filteredActions = new HashSet<String>();
098
099    /** The detail container path pattern. */
100    private static final String DETAIL_CONTAINER_PATTERN = ".*\\/\\.detailContainers\\/.*";
101
102    static {
103        m_filteredActions.add(CmsGwtConstants.ACTION_TEMPLATECONTEXTS);
104        m_filteredActions.add(CmsGwtConstants.ACTION_EDITSMALLELEMENTS);
105        m_filteredActions.add(CmsGwtConstants.ACTION_SELECTELEMENTVIEW);
106        m_filteredActions.add(CmsLogout.class.getName());
107    }
108
109    /** The panel containing the resource boxes. */
110    protected CmsList<CmsListItem> m_list;
111
112    /** List for relations from other sites. */
113    protected CmsList<CmsListItem> m_otherSitesList;
114
115    /** Main panel. */
116    protected FlowPanel m_panel = new FlowPanel();
117
118    /** The popup which contains this widget. */
119    protected CmsPopup m_popup;
120
121    /** The dialog scroll panels. */
122    List<CmsScrollPanel> m_scrollPanels;
123
124    /** The edit button. */
125    private CmsPushButton m_editButton;
126
127    /** The context menu handler. */
128    private CmsContextMenuHandler m_menuHandler;
129
130    /** The display mode. */
131    private Mode m_mode;
132
133    /** The resource status from which we get the related resources to display. */
134    private CmsResourceStatusBean m_statusBean;
135
136    /**
137     * Creates a new widget instance.<p>
138     *
139     * @param status the resource status from which we get the related resources to display.
140     * @param mode the display mode (display relation sources or targets)
141     * @param menuHandler the context menu handler
142     */
143    public CmsResourceRelationView(CmsResourceStatusBean status, Mode mode, CmsContextMenuHandler menuHandler) {
144
145        initWidget(m_panel);
146        m_menuHandler = menuHandler;
147        m_scrollPanels = new ArrayList<CmsScrollPanel>();
148        m_statusBean = status;
149        m_mode = mode;
150        initContent(status);
151    }
152
153    /**
154     * Initializes the content.<p>
155     *
156     * @param status the status data
157     */
158    public void initContent(CmsResourceStatusBean status) {
159
160        m_statusBean = status;
161        m_panel.clear();
162        m_scrollPanels.clear();
163
164        // wrap list info item in another panel to achieve layout uniformity with other similar widgets
165        SimplePanel infoBoxPanel = new SimplePanel();
166        infoBoxPanel.getElement().getStyle().setMarginTop(2, Style.Unit.PX);
167        CmsListItemWidget infoWidget = new CmsListItemWidget(status.getListInfo());
168        infoWidget.addOpenHandler(new OpenHandler<CmsListItemWidget>() {
169
170            public void onOpen(OpenEvent<CmsListItemWidget> event) {
171
172                CmsDomUtil.resizeAncestor(getParent());
173            }
174        });
175        infoWidget.addCloseHandler(new CloseHandler<CmsListItemWidget>() {
176
177            public void onClose(CloseEvent<CmsListItemWidget> event) {
178
179                CmsDomUtil.resizeAncestor(getParent());
180            }
181        });
182        CmsContextMenuButton menuButton = new CmsContextMenuButton(
183            status.getStructureId(),
184            m_menuHandler,
185            AdeContext.resourceinfo);
186        menuButton.addStyleName(I_CmsLayoutBundle.INSTANCE.listItemWidgetCss().permaVisible());
187        infoWidget.addButton(menuButton);
188        m_panel.add(infoBoxPanel);
189        infoBoxPanel.add(infoWidget);
190        m_list = createList(getLegend());
191        fill();
192    }
193
194    /**
195     * @see org.opencms.gwt.client.I_CmsDescendantResizeHandler#onResizeDescendant()
196     */
197    public void onResizeDescendant() {
198
199        Timer timer = new Timer() {
200
201            @Override
202            public void run() {
203
204                for (CmsScrollPanel panel : m_scrollPanels) {
205                    panel.onResizeDescendant();
206                }
207
208            }
209        };
210        timer.schedule(100);
211    }
212
213    /**
214     * Sets the popup which contains this widget.<p>
215     *
216     * @param popup the popup
217     */
218    public void setPopup(CmsPopup popup) {
219
220        m_popup = popup;
221    }
222
223    /**
224     * Creates and renders the resource boxes for the related resources.<p>
225     */
226    protected void fill() {
227
228        m_list.clear();
229        List<CmsResourceStatusRelationBean> relationBeans = getRelationBeans();
230        if (relationBeans.isEmpty()) {
231            CmsSimpleListItem item = new CmsSimpleListItem();
232            item.add(new Label(getEmptyMessage()));
233            m_list.add(item);
234        } else {
235            for (CmsResourceStatusRelationBean relationBean : relationBeans) {
236                CmsListItemWidget itemWidget = new CmsListItemWidget(relationBean.getInfoBean());
237                CmsListItem item = new CmsListItem(itemWidget);
238                CmsContextMenuButton button = new CmsContextMenuButton(
239                    relationBean.getStructureId(),
240                    m_menuHandler,
241                    AdeContext.resourceinfo);
242                item.getListItemWidget().addButton(button);
243                final CmsResourceStatusRelationBean currentRelationBean = relationBean;
244                final boolean isContainerpage = CmsGwtConstants.TYPE_CONTAINERPAGE.equals(
245                    relationBean.getInfoBean().getResourceType());
246                final boolean isXmlContent = relationBean.isXmlContent();
247                final boolean isEditable = (isXmlContent || isContainerpage)
248                    && relationBean.getPermissionInfo().hasWritePermission()
249                    && !currentRelationBean.getSitePath().matches(DETAIL_CONTAINER_PATTERN);
250                if (isEditable) {
251
252                    m_editButton = new CmsPushButton();
253                    m_editButton.setImageClass(I_CmsButton.PEN_SMALL);
254                    m_editButton.setButtonStyle(ButtonStyle.FONT_ICON, null);
255                    m_editButton.setTitle(
256                        org.opencms.gwt.client.Messages.get().key(
257                            org.opencms.gwt.client.Messages.GUI_BUTTON_ELEMENT_EDIT_0));
258                    if (CmsStringUtil.isNotEmptyOrWhitespaceOnly(relationBean.getPermissionInfo().getNoEditReason())) {
259                        m_editButton.disable(relationBean.getPermissionInfo().getNoEditReason());
260                    } else {
261                        m_editButton.setEnabled(true);
262                    }
263                    item.getListItemWidget().addButton(m_editButton);
264                    m_editButton.addClickHandler(new ClickHandler() {
265
266                        public void onClick(ClickEvent event) {
267
268                            if (isContainerpage) {
269                                Window.open(currentRelationBean.getLink(), "_self", "");
270                            } else {
271                                CmsEditableData editableData = new CmsEditableData();
272                                editableData.setElementLanguage(CmsCoreProvider.get().getLocale());
273                                editableData.setStructureId(currentRelationBean.getStructureId());
274                                editableData.setSitePath(currentRelationBean.getSitePath());
275                                CmsContentEditorDialog.get().openEditDialog(
276                                    editableData,
277                                    false,
278                                    null,
279                                    new DialogOptions(),
280                                    new I_CmsContentEditorHandler() {
281
282                                        public void onClose(
283                                            String sitePath,
284                                            CmsUUID structureId,
285                                            boolean isNew,
286                                            boolean hasChangedSettings,
287                                            boolean usedPublishDialog) {
288
289                                            if (m_popup != null) {
290                                                m_popup.hide();
291                                            }
292                                        }
293                                    });
294                                ((CmsPushButton)event.getSource()).clearHoverState();
295                            }
296                        }
297                    });
298                }
299
300                if (isContainerpage) {
301                    if (relationBean.getLink() != null) {
302                        final String link = relationBean.getLink();
303                        itemWidget.setIconCursor(Cursor.POINTER);
304                        itemWidget.addIconClickHandler(new ClickHandler() {
305
306                            public void onClick(ClickEvent e) {
307
308                                Window.open(link, "_blank", "");
309                            }
310                        });
311                    }
312                }
313                m_list.add(item);
314            }
315        }
316        if ((m_mode == Mode.sources) && !m_statusBean.getOtherSiteRelationSources().isEmpty()) {
317            m_otherSitesList = createList(Messages.get().key(Messages.GUI_RESOURCEINFO_OTHERSITES_LEGEND_0));
318            for (CmsResourceStatusRelationBean relationBean : m_statusBean.getOtherSiteRelationSources()) {
319                CmsListItemWidget itemWidget = new CmsListItemWidget(relationBean.getInfoBean());
320                CmsListItem item = new CmsListItem(itemWidget);
321                m_otherSitesList.add(item);
322            }
323        }
324
325        m_list.truncate("RES_INFO", CmsPopup.DEFAULT_WIDTH - 5);
326        if (m_otherSitesList != null) {
327            m_otherSitesList.truncate("RES_INFO", CmsPopup.DEFAULT_WIDTH - 5);
328        }
329
330    }
331
332    /**
333     * Creates a relation item list wrapped in a field set and appends it to the dialog panel.<p>
334     *
335     * @param label the list label
336     *
337     * @return the list
338     */
339    private CmsList<CmsListItem> createList(String label) {
340
341        CmsFieldSet fieldset = new CmsFieldSet();
342        CmsScrollPanel scrollPanel = GWT.create(CmsScrollPanel.class);
343        CmsList<CmsListItem> list = new CmsList<CmsListItem>();
344        scrollPanel.add(list);
345        m_scrollPanels.add(scrollPanel);
346        fieldset.getElement().getStyle().setMarginTop(10, Style.Unit.PX);
347        scrollPanel.getElement().getStyle().setHeight(CmsResourceInfoDialog.SCROLLPANEL_HEIGHT, Style.Unit.PX);
348        fieldset.setLegend(label);
349        fieldset.add(scrollPanel);
350        m_panel.add(fieldset);
351        return list;
352    }
353
354    /**
355     * Gets the message to use for an empty relation list.<p>
356     *
357     * @return the message to display for an empty relation list
358     */
359    private String getEmptyMessage() {
360
361        switch (m_mode) {
362            case sources:
363                if (m_statusBean.getSourcesError() != null) {
364                    return m_statusBean.getSourcesError();
365                }
366                return org.opencms.gwt.client.Messages.get().key(org.opencms.gwt.client.Messages.GUI_USAGE_EMPTY_0);
367            case targets:
368                if (m_statusBean.getTargetsError() != null) {
369                    return m_statusBean.getTargetsError();
370                }
371                //$FALL-THROUGH$
372            default:
373                return org.opencms.gwt.client.Messages.get().key(org.opencms.gwt.client.Messages.GUI_TARGETS_EMPTY_0);
374        }
375
376    }
377
378    /**
379     * Gets the label to use for the fieldset.<p>
380     *
381     * @return the label for the fieldset
382     */
383    private String getLegend() {
384
385        switch (m_mode) {
386            case sources:
387                return org.opencms.gwt.client.Messages.get().key(
388                    org.opencms.gwt.client.Messages.GUI_RESOURCE_INFO_TAB_USAGE_0);
389            case targets:
390
391                return org.opencms.gwt.client.Messages.get().key(
392                    org.opencms.gwt.client.Messages.GUI_RESOURCE_INFO_TAB_TARGETS_0);
393            case siblings:
394            default:
395                return org.opencms.gwt.client.Messages.get().key(
396                    org.opencms.gwt.client.Messages.GUI_RESOURCE_INFO_TAB_SIBLINGS_0);
397
398        }
399
400    }
401
402    /**
403     * Gets the relation beans to display.<p>
404     *
405     * @return the list of relation beans to display
406     */
407    private ArrayList<CmsResourceStatusRelationBean> getRelationBeans() {
408
409        switch (m_mode) {
410            case targets:
411                return m_statusBean.getRelationTargets();
412            case sources:
413                return m_statusBean.getRelationSources();
414            case siblings:
415            default:
416                return m_statusBean.getSiblings();
417        }
418    }
419}