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