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.ade.publish.client; 029 030import org.opencms.ade.publish.shared.CmsPublishResource; 031import org.opencms.ade.publish.shared.CmsWorkflowAction; 032import org.opencms.gwt.client.CmsCoreProvider; 033import org.opencms.gwt.client.rpc.CmsRpcAction; 034import org.opencms.gwt.client.ui.CmsList; 035import org.opencms.gwt.client.ui.CmsListItemWidget; 036import org.opencms.gwt.client.ui.CmsPushButton; 037import org.opencms.gwt.client.ui.CmsScrollPanel; 038import org.opencms.gwt.client.ui.contextmenu.A_CmsContextMenuItem; 039import org.opencms.gwt.client.ui.contextmenu.CmsContextMenuButton; 040import org.opencms.gwt.client.ui.contextmenu.CmsContextMenuHandler; 041import org.opencms.gwt.client.ui.contextmenu.CmsContextMenuItem; 042import org.opencms.gwt.client.ui.contextmenu.I_CmsContextMenuEntry; 043import org.opencms.gwt.client.ui.tree.CmsTreeItem; 044import org.opencms.gwt.client.util.CmsDomUtil; 045import org.opencms.gwt.shared.CmsCoreData.AdeContext; 046import org.opencms.util.CmsUUID; 047 048import java.util.ArrayList; 049import java.util.Collection; 050import java.util.List; 051 052import com.google.gwt.core.client.GWT; 053import com.google.gwt.event.dom.client.ClickEvent; 054import com.google.gwt.event.dom.client.ClickHandler; 055import com.google.gwt.uibinder.client.UiBinder; 056import com.google.gwt.uibinder.client.UiField; 057import com.google.gwt.uibinder.client.UiHandler; 058import com.google.gwt.user.client.Timer; 059import com.google.gwt.user.client.Window; 060import com.google.gwt.user.client.ui.Composite; 061import com.google.gwt.user.client.ui.Label; 062import com.google.gwt.user.client.ui.Widget; 063 064/** 065 * The panel for showing links which would be broken by publishing.<p> 066 * 067 * @since 8.0.0 068 */ 069public class CmsBrokenLinksPanel extends Composite { 070 071 /** The UiBinder interface. */ 072 protected interface I_CmsBrokenLinksPanelUiBinder extends UiBinder<Widget, CmsBrokenLinksPanel> { 073 // empty 074 } 075 076 /** Text metrics key. */ 077 private static final String TM_PUBLISH_BROKEN = "PublishBroken"; 078 079 /** The UiBinder instance for this widget. */ 080 private static final I_CmsBrokenLinksPanelUiBinder UI_BINDER = GWT.create(I_CmsBrokenLinksPanelUiBinder.class); 081 082 /** Button slot mapping for showing broken links. */ 083 public static int[] SLOT_MAPPING; 084 085 static { 086 SLOT_MAPPING = new int[4]; 087 SLOT_MAPPING[CmsPublishGroupPanel.SLOT_WARNING] = 0; 088 SLOT_MAPPING[CmsPublishGroupPanel.SLOT_EDIT] = -1; 089 SLOT_MAPPING[CmsPublishGroupPanel.SLOT_REMOVE] = -1; 090 SLOT_MAPPING[CmsPublishGroupPanel.SLOT_MENU] = 1; 091 } 092 093 /** The button which makes the publish dialog go back to the "resource selection" state. */ 094 @UiField 095 protected CmsPushButton m_backButton; 096 097 /** The button which cancels the publish dialog. */ 098 @UiField 099 protected CmsPushButton m_cancelButton; 100 101 /** The text shown above the resource panel. */ 102 @UiField 103 protected Label m_label; 104 105 /** The list containing the resource widgets representing broken links. */ 106 @UiField 107 protected CmsList<CmsTreeItem> m_list; 108 109 /** The scroll panel containing the group panel. */ 110 @UiField 111 protected CmsScrollPanel m_scrollPanel; 112 113 /** The action buttons. */ 114 private List<CmsPushButton> m_actionButtons; 115 116 /** The available work flow actions. */ 117 private List<CmsWorkflowAction> m_actions; 118 119 /** The publish dialog containing this widget. */ 120 private CmsPublishDialog m_publishDialog; 121 122 /** 123 * Creates a new instance.<p> 124 * 125 * @param publishDialog the publish dialog to which this broken links panel belongs. 126 * @param scrollPanelHeight the available scroll panel height 127 */ 128 public CmsBrokenLinksPanel(CmsPublishDialog publishDialog, int scrollPanelHeight) { 129 130 initWidget(UI_BINDER.createAndBindUi(this)); 131 m_scrollPanel.getElement().getStyle().setPropertyPx(CmsDomUtil.Style.maxHeight.toString(), scrollPanelHeight); 132 prepareButton(m_cancelButton, Messages.get().key(Messages.GUI_PUBLISH_DIALOG_CANCEL_BUTTON_0)); 133 prepareButton(m_backButton, Messages.get().key(Messages.GUI_PUBLISH_DIALOG_BACK_0)); 134 m_label.setText(Messages.get().key(Messages.GUI_PUBLISH_DIALOG_BROKEN_LINKS_0)); 135 m_publishDialog = publishDialog; 136 m_list.truncate(TM_PUBLISH_BROKEN, CmsPublishDialog.DIALOG_WIDTH); 137 m_actionButtons = new ArrayList<CmsPushButton>(); 138 } 139 140 /** 141 * Adds a resource bean to be displayed.<p> 142 * 143 * @param res a resource bean 144 * @return the list item widget of the created entry 145 */ 146 public CmsListItemWidget addEntry(CmsPublishResource res) { 147 148 final CmsListItemWidget itemWidget = CmsPublishGroupPanel.createListItemWidget(res, SLOT_MAPPING); 149 CmsTreeItem item = new CmsTreeItem(false, itemWidget); 150 addContextMenu(item, res); 151 152 item.setOpen(true); 153 for (CmsPublishResource subRes : res.getRelated()) { 154 final CmsListItemWidget subWidget = CmsPublishGroupPanel.createListItemWidget(subRes, SLOT_MAPPING); 155 CmsTreeItem subItem = new CmsTreeItem(false, subWidget); 156 addContextMenu(subItem, subRes); 157 item.addChild(subItem); 158 } 159 m_list.addItem(item); 160 m_scrollPanel.onResizeDescendant(); 161 return itemWidget; 162 } 163 164 /** 165 * Returns the buttons which should be shown in the publish dialog's button panel.<p> 166 * 167 * @return a list of buttons 168 */ 169 public List<CmsPushButton> getButtons() { 170 171 List<CmsPushButton> result = new ArrayList<CmsPushButton>(); 172 result.add(m_backButton); 173 result.add(m_cancelButton); 174 m_actionButtons.clear(); 175 if (m_actions != null) { 176 for (final CmsWorkflowAction action : m_actions) { 177 CmsPushButton actionButton = new CmsPushButton(); 178 actionButton.setText(action.getLabel()); 179 actionButton.setUseMinWidth(true); 180 actionButton.addClickHandler(new ClickHandler() { 181 182 public void onClick(ClickEvent event) { 183 184 executeAction(action); 185 } 186 }); 187 m_actionButtons.add(actionButton); 188 } 189 } 190 result.addAll(m_actionButtons); 191 return result; 192 } 193 194 /** 195 * Sets the resources to be displayed.<p> 196 * 197 * @param resourceBeans the resource beans to be displayed 198 * @param actions the available actions 199 */ 200 public void setEntries(Collection<CmsPublishResource> resourceBeans, List<CmsWorkflowAction> actions) { 201 202 m_list.clear(); 203 CmsListItemWidget listItemWidget = null; 204 for (CmsPublishResource res : resourceBeans) { 205 listItemWidget = addEntry(res); 206 } 207 if (listItemWidget != null) { 208 final CmsListItemWidget lastListItemWidget = listItemWidget; 209 Timer timer = new Timer() { 210 211 @Override 212 public void run() { 213 214 CmsDomUtil.resizeAncestor(lastListItemWidget); 215 } 216 }; 217 timer.schedule(10); 218 } 219 m_actions = actions; 220 } 221 222 /** 223 * Updates the dialog title.<p> 224 **/ 225 public void updateTitle() { 226 227 m_publishDialog.setCaption( 228 Messages.get().key( 229 Messages.GUI_PUBLISH_DIALOG_PROBLEMS_2, 230 m_publishDialog.getSelectedWorkflow().getNiceName(), 231 String.valueOf(m_list.getWidgetCount()))); 232 } 233 234 /** 235 * The event handler for the back button.<p> 236 * 237 * @param e the click event 238 */ 239 @UiHandler("m_backButton") 240 protected void doClickBack(ClickEvent e) { 241 242 m_publishDialog.onGoBack(); 243 } 244 245 /** 246 * The event handler for the cancel button.<p> 247 * 248 * @param e the click event 249 */ 250 @UiHandler("m_cancelButton") 251 protected void doClickCancel(ClickEvent e) { 252 253 m_publishDialog.onCancel(); 254 } 255 256 /** 257 * Executes the given action.<p> 258 * 259 * @param action the action to execute on the selected resources 260 */ 261 protected void executeAction(CmsWorkflowAction action) { 262 263 m_publishDialog.executeAction(action); 264 } 265 266 /** 267 * Adds a context menu button to the resource box, unless the structure id is null (this can happen with already broken relations). 268 * 269 * @param item the item to add the button to 270 * @param res the publish resource data 271 */ 272 private void addContextMenu(CmsTreeItem item, CmsPublishResource res) { 273 274 if (!res.getId().isNullUUID()) { 275 CmsContextMenuButton button = new CmsContextMenuButton( 276 res.getId(), 277 m_publishDialog.getContextMenuHandler(), 278 AdeContext.resourceinfo); 279 CmsPublishGroupPanel.fillButtonSlot( 280 item.getListItemWidget(), 281 CmsPublishGroupPanel.SLOT_MENU, 282 button, 283 SLOT_MAPPING); 284 } else if (CmsCoreProvider.get().getUserInfo().isWorkplaceUser()) { 285 // Null UUID, so resource probably doesn't exist. 286 // We can't use the normal context menu handler, since it uses the structure id for loading the context menu entries, 287 // so we create an individual context menu handler instance for each broken link item. 288 CmsContextMenuButton button = new CmsContextMenuButton(res.getId(), new CmsContextMenuHandler() { 289 290 @Override 291 public void loadContextMenu(CmsUUID structureId, AdeContext context, CmsContextMenuButton menuButton) { 292 293 List<I_CmsContextMenuEntry> menuEntries = new ArrayList<>(); 294 I_CmsContextMenuEntry entry = new I_CmsContextMenuEntry() { 295 296 public void execute() { 297 298 CmsRpcAction<String> rpcAction = new CmsRpcAction<String>() { 299 300 @Override 301 public void execute() { 302 303 start(0, false); 304 CmsCoreProvider.getService().getWorkplaceLinkForPath(res.getSubTitle(), this); 305 } 306 307 @Override 308 protected void onResponse(String result) { 309 310 stop(false); 311 if (result != null) { 312 Window.Location.assign(result); 313 // In case we already are in the workplace, setting the URL does not necessarily update the state. 314 // Schedule a timer to trigger a reload, which only fires in that scenario. 315 Timer timer = new Timer() { 316 317 @Override 318 public void run() { 319 320 Window.Location.reload(); 321 } 322 323 }; 324 timer.schedule(50); 325 } 326 } 327 }; 328 rpcAction.execute(); 329 } 330 331 public A_CmsContextMenuItem generateMenuItem() { 332 333 return new CmsContextMenuItem(this); 334 335 } 336 337 public String getIconClass() { 338 339 return null; 340 } 341 342 public String getJspPath() { 343 344 return null; 345 } 346 347 public String getLabel() { 348 349 return Messages.get().key(Messages.GUI_BROKEN_LINK_SHOW_IN_EXPLORER_0); 350 } 351 352 public String getName() { 353 354 return ""; 355 } 356 357 public String getReason() { 358 359 return null; 360 } 361 362 public List<I_CmsContextMenuEntry> getSubMenu() { 363 364 return null; 365 } 366 367 public boolean hasSubMenu() { 368 369 return false; 370 } 371 372 public boolean isActive() { 373 374 return true; 375 } 376 377 public boolean isSeparator() { 378 379 return false; 380 } 381 382 public boolean isVisible() { 383 384 return true; 385 } 386 }; 387 menuEntries.add(entry); 388 menuButton.showMenu(menuEntries); 389 390 } 391 392 @Override 393 public void refreshResource(CmsUUID structureId) { 394 395 m_publishDialog.getContextMenuHandler().refreshResource(structureId); 396 } 397 398 }, AdeContext.resourceinfo); 399 CmsPublishGroupPanel.fillButtonSlot( 400 item.getListItemWidget(), 401 CmsPublishGroupPanel.SLOT_MENU, 402 button, 403 SLOT_MAPPING); 404 } 405 } 406 407 /** 408 * Sets the text on a button and formats the button.<p> 409 * 410 * @param button the button 411 * @param text the text to put on the button 412 */ 413 private void prepareButton(CmsPushButton button, String text) { 414 415 button.setText(text); 416 button.setUseMinWidth(true); 417 } 418}