/* * This library is part of OpenCms - * the Open Source Content Management System * * Copyright (c) Alkacon Software GmbH (http://www.alkacon.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * For further information about Alkacon Software, please see the * company website: http://www.alkacon.com * * For further information about OpenCms, please see the * project website: http://www.opencms.org * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.opencms.ade.publish.client; import org.opencms.ade.publish.client.CmsPublishItemStatus.Signal; import org.opencms.ade.publish.shared.CmsPublishResource; import org.opencms.gwt.client.ui.CmsList; import org.opencms.gwt.client.ui.CmsListItemWidget; import org.opencms.gwt.client.ui.CmsPushButton; import org.opencms.gwt.client.ui.CmsSimpleListItem; import org.opencms.gwt.client.ui.I_CmsButton; import org.opencms.gwt.client.ui.css.I_CmsImageBundle; import org.opencms.gwt.client.ui.css.I_CmsInputLayoutBundle; import org.opencms.gwt.client.ui.css.I_CmsLayoutBundle; import org.opencms.gwt.client.ui.input.CmsCheckBox; import org.opencms.gwt.client.ui.tree.CmsTreeItem; import org.opencms.gwt.client.util.CmsResourceStateUtil; import org.opencms.gwt.client.util.CmsStyleVariable; import org.opencms.gwt.shared.CmsIconUtil; import org.opencms.gwt.shared.CmsListInfoBean; import org.opencms.util.CmsUUID; import java.util.List; import java.util.Map; import com.google.gwt.dom.client.Style.Visibility; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.user.client.ui.Composite; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.Image; /** * A panel representing a single publish group.<p> * * @since 8.0.0 */ public class CmsPublishGroupPanel extends Composite { /** The CSS bundle used for this widget. */ protected static final I_CmsPublishCss CSS = I_CmsPublishLayoutBundle.INSTANCE.publishCss(); /** Text metrics key. */ private static final String TM_PUBLISH_LIST = "PublishList"; /** The handler which is called when the publish item selection changes. */ protected I_CmsPublishSelectionChangeHandler m_selectionChangeHandler; /** The group header (containing the label and add/remove buttons). */ private CmsSimpleListItem m_header = new CmsSimpleListItem(); /** The data model for the publish dialog. */ protected CmsPublishDataModel m_model; /** The root panel of this widget. */ private CmsList<CmsTreeItem> m_panel = new CmsList<CmsTreeItem>(); /** The button for selecting all resources in the group. */ private CmsPushButton m_selectAll; /** The group index for this panel's corresponding group. */ protected int m_groupIndex; /** The number of loaded publish item widgets for this group (used for scrolling).<p> */ private int m_itemIndex; /** The publish resources of the current group.<p>*/ private List<CmsPublishResource> m_publishResources; /** The global map of selection controllers of *ALL* groups (to which this group's selection controllers are added). */ private Map<CmsUUID, CmsPublishItemSelectionController> m_controllersById; /** The button for deselecting all resources in the group. */ private CmsPushButton m_selectNone; /** A flag which indicates whether only resources with problems should be shown. */ private boolean m_showProblemsOnly; /** * Constructs a new instance.<p> * * @param title the title of the group * @param groupIndex the index of the group which this panel should render * @param selectionChangeHandler the handler for selection changes for publish resources * @param model the data model for the publish resources * @param controllersById the map of selection controllers to which this panel's selection controllers should be added * @param showProblemsOnly if true, sets this panel into "show resources with problems only" mode */ public CmsPublishGroupPanel( String title, int groupIndex, I_CmsPublishSelectionChangeHandler selectionChangeHandler, CmsPublishDataModel model, Map<CmsUUID, CmsPublishItemSelectionController> controllersById, boolean showProblemsOnly) { initWidget(m_panel); m_panel.add(m_header); m_model = model; m_groupIndex = groupIndex; m_publishResources = model.getGroups().get(groupIndex).getResources(); m_controllersById = controllersById; m_panel.truncate(TM_PUBLISH_LIST, CmsPublishDialog.DIALOG_WIDTH); initSelectButtons(); if (hasOnlyProblemResources()) { m_selectAll.setEnabled(false); m_selectNone.setEnabled(false); } m_showProblemsOnly = showProblemsOnly; if (hasNoProblemResources() && showProblemsOnly) { this.setVisible(false); } HTML label = new HTML(); label.setHTML(title + CmsPublishSelectPanel.formatResourceCount(m_publishResources.size())); label.addStyleName(CSS.groupHeader()); m_header.add(label); FlowPanel clear = new FlowPanel(); clear.setStyleName(CSS.clear()); m_header.add(clear); m_selectionChangeHandler = selectionChangeHandler; } /** * Creates a basic list item widget for a given publish resource bean.<p> * * @param resourceBean the publish resource bean * * @return the list item widget representing the publish resource bean */ public static CmsListItemWidget createListItemWidget(CmsPublishResource resourceBean) { CmsListInfoBean info = new CmsListInfoBean(); info.setTitle(getTitle(resourceBean)); info.setSubTitle(resourceBean.getName()); String stateLabel = org.opencms.gwt.client.Messages.get().key( org.opencms.gwt.client.Messages.GUI_RESOURCE_STATE_0); String stateName = CmsResourceStateUtil.getStateName(resourceBean.getState()); // this can be null for the source resources of broken relations in the 'broken links' // panel since these resources don't have to be new or deleted or changed if (stateName != null) { info.addAdditionalInfo(stateLabel, stateName, CmsResourceStateUtil.getStateStyle(resourceBean.getState())); } CmsListItemWidget itemWidget = new CmsListItemWidget(info); if (resourceBean.getInfo() != null) { Image warningImage = new Image(I_CmsImageBundle.INSTANCE.warningSmallImage()); warningImage.setTitle(resourceBean.getInfo().getValue()); String permaVisible = I_CmsLayoutBundle.INSTANCE.listItemWidgetCss().permaVisible(); warningImage.addStyleName(permaVisible); itemWidget.addButton(warningImage); } itemWidget.setIcon(CmsIconUtil.getResourceIconClasses(resourceBean.getResourceType(), false)); return itemWidget; } /** * Utility method for getting the title of a publish resource bean, or a default title * if the bean has no title.<p> * * @param resourceBean the resource bean for which the title should be retrieved * * @return the bean's title, or a default title */ private static String getTitle(CmsPublishResource resourceBean) { String title = resourceBean.getTitle(); if ((title == null) || title.equals("")) { title = Messages.get().key(Messages.GUI_NO_TITLE_0); } return title; } /** * Adds the list item for the next publish resource and returns true on success, while * also incrementing the internal item index.<p> * * @return true if an item was added */ public boolean addNextItem() { if (m_itemIndex >= m_publishResources.size()) { return false; } CmsPublishResource res = m_publishResources.get(m_itemIndex); m_itemIndex += 1; if ((res.getInfo() == null) && m_showProblemsOnly) { return false; } else { addItem(res); return true; } } /** * Returns true if there are more potential items to add.<p> * * @return true if there are possibly more items */ public boolean hasMoreItems() { return m_itemIndex < m_publishResources.size(); } /** * Returns true if the corresponding group has no resources with problems.<p> * * @return true if the group for this panel has no resources with problems */ protected boolean hasNoProblemResources() { return 0 == m_model.countResourcesInGroup(new CmsPublishDataModel.HasProblems(), m_model.getGroups().get( m_groupIndex).getResources()); } /** * Returns true if the corresponding group has only resources with problems.<p> * * @return true if the group for this panel has only resources with problems. */ protected boolean hasOnlyProblemResources() { return m_model.getGroups().get(m_groupIndex).getResources().size() == m_model.countResourcesInGroup( new CmsPublishDataModel.HasProblems(), m_model.getGroups().get(m_groupIndex).getResources()); } /** * Adds a resource bean to this group.<p> * * @param resourceBean the resource bean which should be added */ private void addItem(CmsPublishResource resourceBean) { CmsTreeItem row = buildItem(resourceBean, m_model.getStatus(resourceBean.getId()), false); m_panel.add(row); for (CmsPublishResource related : resourceBean.getRelated()) { row.addChild(buildItem(related, m_model.getStatus(related.getId()), true)); } } /** * Creates a widget from resource bean data.<p> * * @param resourceBean the resource bean for which a widget should be constructed * @param status the publish item status * @param isSubItem true if this is not a top-level publish item * * @return a widget representing the resource bean */ private CmsTreeItem buildItem(final CmsPublishResource resourceBean, CmsPublishItemStatus status, boolean isSubItem) { CmsListItemWidget itemWidget = createListItemWidget(resourceBean); final CmsStyleVariable styleVar = new CmsStyleVariable(itemWidget); styleVar.setValue(CSS.itemToKeep()); final CmsCheckBox checkbox = new CmsCheckBox(); CmsTreeItem row; row = new CmsTreeItem(false, checkbox, itemWidget); if (isSubItem) { checkbox.getElement().getStyle().setVisibility(Visibility.HIDDEN); } row.setOpen(true); row.addStyleName(CSS.publishRow()); // we do not need most of the interactive elements for the sub-items if (!isSubItem) { ClickHandler checkboxHandler = new ClickHandler() { /** * @see com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event.dom.client.ClickEvent) */ public void onClick(ClickEvent event) { boolean checked = checkbox.isChecked(); m_model.signal(checked ? Signal.publish : Signal.unpublish, resourceBean.getId()); m_selectionChangeHandler.onChangePublishSelection(); } }; checkbox.addClickHandler(checkboxHandler); final boolean hasProblem = (resourceBean.getInfo() != null); if (hasProblem) { // can't select resource with problems checkbox.setChecked(false); checkbox.setEnabled(false); } final CmsCheckBox remover = new CmsCheckBox(); final CmsPublishItemSelectionController controller = new CmsPublishItemSelectionController( resourceBean.getId(), checkbox, remover, styleVar, hasProblem); m_controllersById.put(resourceBean.getId(), controller); remover.setTitle(Messages.get().key(Messages.GUI_PUBLISH_REMOVE_BUTTON_0)); remover.addClickHandler(new ClickHandler() { /** * @see com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event.dom.client.ClickEvent) */ public void onClick(ClickEvent e) { boolean remove = remover.isChecked(); m_model.signal(remove ? Signal.remove : Signal.unremove, resourceBean.getId()); m_selectionChangeHandler.onChangePublishSelection(); } }); itemWidget.addButtonToFront(remover); controller.update(status); } return row; } /** * Initializes the "select all/none" buttons, adds them to the group header and * attaches event handlers to them.<p> */ private void initSelectButtons() { m_selectAll = new CmsPushButton(); m_selectAll.setText(Messages.get().key(Messages.GUI_PUBLISH_TOP_PANEL_ALL_BUTTON_0)); m_selectAll.setImageClass(I_CmsInputLayoutBundle.INSTANCE.inputCss().checkBoxImageChecked()); m_selectAll.setSize(I_CmsButton.Size.small); m_selectAll.setUseMinWidth(true); m_selectAll.addClickHandler(new ClickHandler() { /** * @see com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event.dom.client.ClickEvent) */ public void onClick(ClickEvent event) { m_model.signalGroup(Signal.publish, m_groupIndex); CmsPublishGroupPanel.this.m_selectionChangeHandler.onChangePublishSelection(); } }); m_selectNone = new CmsPushButton(); m_selectNone.setText(Messages.get().key(Messages.GUI_PUBLISH_TOP_PANEL_NONE_BUTTON_0)); m_selectNone.setImageClass(I_CmsInputLayoutBundle.INSTANCE.inputCss().checkBoxImageUnchecked()); m_selectNone.setSize(I_CmsButton.Size.small); m_selectNone.setUseMinWidth(true); m_selectNone.addClickHandler(new ClickHandler() { /** * @see com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event.dom.client.ClickEvent) */ public void onClick(ClickEvent event) { m_model.signalGroup(Signal.unpublish, m_groupIndex); CmsPublishGroupPanel.this.m_selectionChangeHandler.onChangePublishSelection(); } }); FlowPanel selectButtons = new FlowPanel(); selectButtons.add(m_selectAll); selectButtons.add(m_selectNone); selectButtons.setStyleName(CSS.selectButtons()); m_header.add(selectButtons); } }