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.CmsPublishData; 031import org.opencms.ade.publish.shared.CmsPublishGroupList; 032import org.opencms.ade.publish.shared.CmsPublishListToken; 033import org.opencms.ade.publish.shared.CmsPublishOptions; 034import org.opencms.ade.publish.shared.CmsWorkflow; 035import org.opencms.ade.publish.shared.CmsWorkflowAction; 036import org.opencms.ade.publish.shared.CmsWorkflowActionParams; 037import org.opencms.ade.publish.shared.CmsWorkflowResponse; 038import org.opencms.ade.publish.shared.rpc.I_CmsPublishService; 039import org.opencms.ade.publish.shared.rpc.I_CmsPublishServiceAsync; 040import org.opencms.gwt.client.CmsCoreProvider; 041import org.opencms.gwt.client.CmsEditableDataJSO; 042import org.opencms.gwt.client.rpc.CmsRpcAction; 043import org.opencms.gwt.client.ui.CmsNotification; 044import org.opencms.gwt.client.ui.CmsPopup; 045import org.opencms.gwt.client.ui.CmsPushButton; 046import org.opencms.gwt.client.ui.contenteditor.I_CmsContentEditorHandler; 047import org.opencms.gwt.client.ui.contextmenu.CmsContextMenuHandler; 048import org.opencms.gwt.client.ui.contextmenu.CmsDialogContextMenuHandler; 049import org.opencms.gwt.client.util.CmsDomUtil; 050import org.opencms.gwt.shared.CmsGwtConstants; 051import org.opencms.util.CmsStringUtil; 052import org.opencms.util.CmsUUID; 053 054import java.util.ArrayList; 055import java.util.HashMap; 056import java.util.List; 057import java.util.Map; 058 059import com.google.common.collect.Lists; 060import com.google.gwt.core.client.GWT; 061import com.google.gwt.dom.client.Element; 062import com.google.gwt.event.logical.shared.CloseHandler; 063import com.google.gwt.user.client.Window; 064import com.google.gwt.user.client.rpc.ServiceDefTarget; 065import com.google.gwt.user.client.ui.DeckPanel; 066import com.google.gwt.user.client.ui.PopupPanel; 067 068/** 069 * 070 * Main class for the publish dialog.<p> 071 * 072 * This class is mostly responsible for the control flow and RPC calls of the publish dialog. 073 * It delegates most of the actual GUI work to the {@link CmsPublishSelectPanel} and {@link CmsBrokenLinksPanel} classes. 074 * 075 * @since 8.0.0 076 * 077 */ 078public class CmsPublishDialog extends CmsPopup { 079 080 /** 081 * A type which represents the state of a publish action.<p> 082 */ 083 public enum State { 084 /** The publish dialog was cancelled. */ 085 cancel, 086 087 /** The publish dialog has failed. */ 088 failure, 089 090 /** The publish dialog has succeeded. */ 091 success; 092 } 093 094 /** 095 * The action for publishing and/or removing resources from the publish list.<p> 096 */ 097 private class CmsPublishAction extends CmsRpcAction<CmsWorkflowResponse> { 098 099 /** If true, try to ignore broken links when publishing. */ 100 private CmsWorkflowAction m_action; 101 102 /** Creates a new instance of this action. 103 * 104 * @param action the workflow action to execute 105 */ 106 public CmsPublishAction(CmsWorkflowAction action) { 107 108 m_action = action; 109 } 110 111 /** 112 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 113 */ 114 @Override 115 public void execute() { 116 117 start(0, true); 118 setLastAction(m_action); 119 CmsWorkflowActionParams actionParams = getWorkflowActionParams(); 120 getService().executeAction(m_action, actionParams, this); 121 122 } 123 124 /** 125 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 126 */ 127 @Override 128 protected void onResponse(CmsWorkflowResponse result) { 129 130 stop(false); 131 onReceiveStatus(result); 132 133 } 134 } 135 136 /** 137 * The action for loading the publish list.<p> 138 */ 139 private class CmsPublishListAction extends CmsRpcAction<CmsPublishGroupList> { 140 141 /** 142 * Constructor.<p> 143 */ 144 protected CmsPublishListAction() { 145 146 // nothing to do 147 } 148 149 /** 150 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 151 */ 152 @Override 153 public void execute() { 154 155 start(0, true); 156 CmsPublishOptions options = getPublishOptions(); 157 boolean projectChanged = m_projectChanged; 158 m_projectChanged = false; 159 160 getService().getResourceGroups(getSelectedWorkflow(), options, projectChanged, this); 161 } 162 163 /** 164 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 165 */ 166 @Override 167 protected void onResponse(CmsPublishGroupList result) { 168 169 stop(false); 170 onReceivePublishList(result); 171 172 } 173 } 174 175 /** The dialog width in pixels. */ 176 public static final int DIALOG_WIDTH = 766; 177 178 /** The project map used by showPublishDialog. */ 179 public static Map<String, String> m_staticProjects; 180 181 /** The index of the "broken links" panel. */ 182 public static final int PANEL_BROKEN_LINKS = 1; 183 184 /** The index of the publish selection panel. */ 185 public static final int PANEL_SELECT = 0; 186 187 /** The CSS bundle used for this widget. */ 188 private static final I_CmsPublishCss CSS = I_CmsPublishLayoutBundle.INSTANCE.publishCss(); 189 /** Flag indicating if the CSS has been initialized. */ 190 private static boolean CSS_INITIALIZED; 191 192 /** The publish service instance. */ 193 private static I_CmsPublishServiceAsync SERVICE; 194 195 /** The panel for selecting the resources to publish or remove from the publish list. */ 196 protected CmsPublishSelectPanel m_publishSelectPanel; 197 198 /** Flag to keep track of whether the user just changed the project. */ 199 boolean m_projectChanged; 200 201 /** The panel for showing the links that would be broken by publishing. */ 202 private CmsBrokenLinksPanel m_brokenLinksPanel; 203 204 /** The content editor handler. */ 205 private I_CmsContentEditorHandler m_editorHandler; 206 207 /** Stores a failure message. */ 208 private String m_failureMessage; 209 210 /** Stores the last workflow action. */ 211 private CmsWorkflowAction m_lastAction; 212 213 /** The context menu handler. */ 214 private CmsContextMenuHandler m_menuHandler; 215 216 /** The root panel of this dialog which contains both the selection panel and the panel for displaying broken links. */ 217 private DeckPanel m_panel = new DeckPanel(); 218 219 /** The current publish list options. */ 220 private CmsPublishOptions m_publishOptions; 221 222 /** Stores the state. */ 223 private State m_state = State.cancel; 224 225 /** The id of the current workflow. */ 226 private String m_workflowId; 227 228 /** The available workflows. */ 229 private Map<String, CmsWorkflow> m_workflows; 230 231 /** 232 * Constructs a new publish dialog.<p> 233 * 234 * @param initData the initial data 235 * @param refreshAction the action to perform on a context menu triggered refresh 236 * @param editorHandler the content editor handler 237 */ 238 public CmsPublishDialog( 239 CmsPublishData initData, 240 final Runnable refreshAction, 241 I_CmsContentEditorHandler editorHandler) { 242 243 super(800); 244 initCss(); 245 setGlassEnabled(true); 246 setPositionFixed(); 247 setAutoHideEnabled(false); 248 setModal(true); 249 addStyleName(CSS.publishDialog()); 250 m_menuHandler = new CmsDialogContextMenuHandler() { 251 252 @Override 253 public void refreshResource(CmsUUID structureId) { 254 255 CmsPublishDialog.this.hide(); 256 refreshAction.run(); 257 } 258 }; 259 m_editorHandler = editorHandler; 260 m_menuHandler.setEditorHandler(editorHandler); 261 m_workflows = initData.getWorkflows(); 262 m_workflowId = initData.getSelectedWorkflowId(); 263 m_publishOptions = initData.getOptions(); 264 int availableHeight = Window.getClientHeight() - 290; 265 m_publishSelectPanel = new CmsPublishSelectPanel( 266 this, 267 initData.getProjects(), 268 initData.getOptions(), 269 initData.getWorkflows(), 270 initData.getSelectedWorkflowId(), 271 availableHeight); 272 m_brokenLinksPanel = new CmsBrokenLinksPanel(this, availableHeight); 273 274 addDialogClose(null); 275 276 m_panel = new DeckPanel(); 277 m_panel.add(m_publishSelectPanel); 278 m_panel.add(m_brokenLinksPanel); 279 setMainContent(m_panel); 280 onReceivePublishList(initData.getGroups()); 281 } 282 283 /** 284 * Shows the publish dialog.<p> 285 * 286 * @param result the publish data 287 * @param handler the dialog close handler (may be null) 288 * @param refreshAction the action to execute on a context menu triggered refresh 289 * @param editorHandler the content editor handler (may be null) 290 */ 291 public static void showPublishDialog( 292 CmsPublishData result, 293 CloseHandler<PopupPanel> handler, 294 Runnable refreshAction, 295 I_CmsContentEditorHandler editorHandler) { 296 297 CmsPublishDialog publishDialog = new CmsPublishDialog(result, refreshAction, editorHandler); 298 if (handler != null) { 299 publishDialog.addCloseHandler(handler); 300 } 301 publishDialog.centerHorizontally(50); 302 // replace current notification widget by overlay 303 publishDialog.catchNotifications(); 304 } 305 306 /** 307 * Convenience method which opens a publish dialog.<p> 308 * 309 * @param handler the close handler 310 * @param params the additional publish dialog parameters 311 * @param refreshAction the action to execute after a context menu triggered refresh 312 * @param editorHandler the content editor handler 313 */ 314 public static void showPublishDialog( 315 final HashMap<String, String> params, 316 final CloseHandler<PopupPanel> handler, 317 final Runnable refreshAction, 318 final I_CmsContentEditorHandler editorHandler) { 319 320 List<String> structureIds = Lists.newArrayList(); 321 for (CmsEditableDataJSO editableData : CmsDomUtil.getAllEditableDataForPage()) { 322 structureIds.add("" + editableData.getStructureId()); 323 } 324 325 List<Element> collectorInfos = CmsDomUtil.getElementsByClass(CmsGwtConstants.CLASS_COLLECTOR_INFO); 326 int j = 1; 327 for (Element elem : collectorInfos) { 328 String infoJson = elem.getAttribute(CmsGwtConstants.ATTR_DATA_COLLECTOR); 329 params.put(CmsPublishOptions.PARAM_COLLECTOR_INFO + "." + j, infoJson); 330 j += 1; 331 } 332 String editableIdList = CmsStringUtil.listAsString(structureIds, ","); 333 params.put(CmsPublishOptions.PARAM_COLLECTOR_ITEMS, editableIdList); 334 335 (new CmsRpcAction<CmsPublishData>() { 336 337 /** 338 * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() 339 */ 340 @Override 341 public void execute() { 342 343 start(0, true); 344 getService().getInitData(params, this); 345 } 346 347 /** 348 * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) 349 */ 350 @Override 351 protected void onResponse(CmsPublishData result) { 352 353 stop(false); 354 showPublishDialog(result, handler, refreshAction, editorHandler); 355 } 356 }).execute(); 357 } 358 359 /** 360 * Convenience method which opens a publish dialog.<p> 361 * 362 * @param refreshAction the action to execute after a context menu triggered refresh 363 */ 364 public static void showPublishDialog(Runnable refreshAction) { 365 366 showPublishDialog(new HashMap<String, String>(), null, refreshAction, null); 367 } 368 369 /** 370 * Returns the publish service instance.<p> 371 * 372 * @return the publish service instance 373 */ 374 protected static I_CmsPublishServiceAsync getService() { 375 376 if (SERVICE == null) { 377 SERVICE = GWT.create(I_CmsPublishService.class); 378 String serviceUrl = CmsCoreProvider.get().link("org.opencms.ade.publish.CmsPublishService.gwt"); 379 ((ServiceDefTarget)SERVICE).setServiceEntryPoint(serviceUrl); 380 } 381 return SERVICE; 382 } 383 384 /** 385 * Executes the specified action for the selected resources.<p> 386 * 387 * @param actionKey the workflow action 388 */ 389 public void executeAction(CmsWorkflowAction actionKey) { 390 391 (new CmsPublishAction(actionKey)).execute(); 392 } 393 394 /** 395 * Gets the context menu handler.<p> 396 * 397 * @return the context menu handler 398 */ 399 public CmsContextMenuHandler getContextMenuHandler() { 400 401 return m_menuHandler; 402 } 403 404 /** 405 * Returns the content editor handler.<p> 406 * 407 * @return the content editor handler 408 */ 409 public I_CmsContentEditorHandler getEditorHandler() { 410 411 return m_editorHandler; 412 } 413 414 /** 415 * Gets the failure message.<p> 416 * 417 * @return the failure message 418 */ 419 public String getFailureMessage() { 420 421 return m_failureMessage; 422 } 423 424 /** 425 * Gets the last workflow action.<p> 426 * 427 * @return the last workflow action 428 */ 429 public CmsWorkflowAction getLastAction() { 430 431 return m_lastAction; 432 } 433 434 /** 435 * Gets the context menu handler. 436 */ 437 public CmsContextMenuHandler getMenuHandler() { 438 439 return m_menuHandler; 440 } 441 442 /** 443 * Returns the current publish options.<p> 444 * 445 * @return a publish options bean 446 */ 447 public CmsPublishOptions getPublishOptions() { 448 449 return m_publishOptions; 450 } 451 452 /** 453 * Gets the publish dialog state.<p> 454 * 455 * @return the publish dialog state 456 */ 457 public State getState() { 458 459 return m_state; 460 } 461 462 /** 463 * Checks whether the publish dialog has failed.<p> 464 * 465 * @return checks whether the publish dialog has succeeded 466 */ 467 public boolean hasFailed() { 468 469 return m_state == State.failure; 470 } 471 472 /** 473 * Checks whether the publish dialog has succeeded.<p> 474 * 475 * @return true if the publish dialog has succeeded 476 */ 477 public boolean hasSucceeded() { 478 479 return m_state == State.success; 480 } 481 482 /** 483 * Method which is called when the cancel button is pressed.<p> 484 */ 485 public void onCancel() { 486 487 if (m_publishSelectPanel.m_model != null) { 488 final List<CmsUUID> toRemove = m_publishSelectPanel.m_model.getIdsOfAlreadyPublishedResources(); 489 if (toRemove.isEmpty()) { 490 hide(); 491 } else { 492 CmsRpcAction<CmsWorkflowResponse> action = new CmsRpcAction<CmsWorkflowResponse>() { 493 494 @Override 495 public void execute() { 496 497 start(0, true); 498 CmsWorkflowActionParams params = getWorkflowActionParams(); 499 getService().executeAction( 500 new CmsWorkflowAction(CmsWorkflowAction.ACTION_CANCEL, "", true), 501 params, 502 this); 503 } 504 505 @Override 506 protected void onResponse(CmsWorkflowResponse result) { 507 508 stop(false); 509 hide(); 510 511 } 512 }; 513 action.execute(); 514 } 515 } else { 516 hide(); 517 } 518 } 519 520 /** 521 * Method which is called when the back button is pressed.<p> 522 */ 523 public void onGoBack() { 524 525 setPanel(PANEL_SELECT); 526 } 527 528 /** 529 * Method which is called after the publish list has been received from the server.<p> 530 * 531 * @param groups the groups of the publish list 532 */ 533 public void onReceivePublishList(CmsPublishGroupList groups) { 534 535 m_publishSelectPanel.setGroupList(groups, true, groups.getOverrideWorkflowId()); 536 setPanel(PANEL_SELECT); 537 if (!isVisible()) { 538 center(); 539 } 540 } 541 542 /** 543 * Method which is called after the status from a publish action has arrived.<p> 544 * 545 * @param brokenResources the list of broken resources 546 */ 547 public void onReceiveStatus(CmsWorkflowResponse brokenResources) { 548 549 if (brokenResources.isSuccess()) { 550 succeed(); 551 hide(); 552 CmsNotification.get().send( 553 CmsNotification.Type.NORMAL, 554 org.opencms.gwt.client.Messages.get().key(org.opencms.gwt.client.Messages.GUI_DONE_0)); 555 556 } else { 557 m_failureMessage = brokenResources.getMessage(); 558 m_state = State.failure; 559 m_brokenLinksPanel.setEntries(brokenResources.getResources(), brokenResources.getAvailableActions()); 560 setPanel(PANEL_BROKEN_LINKS); 561 } 562 } 563 564 /** 565 * Sets the include related resources option.<p> 566 * 567 * @param includeRelated the include related option 568 */ 569 public void setIncludeRelated(boolean includeRelated) { 570 571 m_publishOptions.setIncludeRelated(includeRelated); 572 } 573 574 /** 575 * Sets the include sibling resources option.<p> 576 * 577 * @param includeSiblings the include siblings option 578 */ 579 public void setIncludeSiblings(boolean includeSiblings) { 580 581 m_publishOptions.setIncludeSiblings(includeSiblings); 582 } 583 584 /** 585 * Changes the currently active panel.<p> 586 * 587 * @param panelId the number of the panel to show 588 */ 589 public void setPanel(int panelId) { 590 591 m_panel.showWidget(panelId); 592 removeAllButtons(); 593 if (panelId == PANEL_SELECT) { 594 for (CmsPushButton button : m_publishSelectPanel.getButtons()) { 595 addButton(button); 596 } 597 m_publishSelectPanel.updateDialogTitle(); 598 } else if (panelId == PANEL_BROKEN_LINKS) { 599 for (CmsPushButton button : m_brokenLinksPanel.getButtons()) { 600 addButton(button); 601 } 602 m_brokenLinksPanel.updateTitle(); 603 } 604 } 605 606 /** 607 * This is called when the user just changed the project.<p> 608 */ 609 public void setProjectChanged() { 610 611 m_projectChanged = true; 612 } 613 614 /** 615 * Sets the selected project id.<p> 616 * 617 * @param projectId the project id 618 */ 619 public void setProjectId(CmsUUID projectId) { 620 621 m_publishOptions.setProjectId(projectId); 622 } 623 624 /** 625 * Sets the selected workflow id.<p> 626 * 627 * @param workflowId the workflow id 628 */ 629 public void setWorkflowId(String workflowId) { 630 631 m_workflowId = workflowId; 632 if (!m_workflows.containsKey(workflowId)) { 633 m_workflowId = "WORKFLOW_PUBLISH"; 634 } 635 } 636 637 /** 638 * Sets the publish dialog state to 'success'.<p> 639 */ 640 public void succeed() { 641 642 m_state = State.success; 643 CmsCoreProvider.get().fireEvent(new CmsPublishEvent()); 644 } 645 646 /** 647 * Method which is called when the publish options are changed.<p> 648 */ 649 public void updateResourceList() { 650 651 (new CmsPublishListAction()).execute(); 652 } 653 654 /** 655 * Returns the selected workflow.<p> 656 * 657 * @return the selected workflow 658 */ 659 protected CmsWorkflow getSelectedWorkflow() { 660 661 return m_workflows.get(m_workflowId); 662 } 663 664 /** 665 * Gets the workflow action parameters to which the workflow action should be applied.<p> 666 * 667 * @return the workflow action parameters 668 */ 669 protected CmsWorkflowActionParams getWorkflowActionParams() { 670 671 if (m_publishSelectPanel.isShowResources()) { 672 List<CmsUUID> resourcesToPublish = new ArrayList<CmsUUID>(m_publishSelectPanel.getResourcesToPublish()); 673 List<CmsUUID> resourcesToRemove = new ArrayList<CmsUUID>(m_publishSelectPanel.getResourcesToRemove()); 674 CmsWorkflowActionParams actionParams = new CmsWorkflowActionParams(resourcesToPublish, resourcesToRemove); 675 return actionParams; 676 } else { 677 CmsPublishOptions options = getPublishOptions(); 678 CmsWorkflow workflow = getSelectedWorkflow(); 679 return new CmsWorkflowActionParams(new CmsPublishListToken(workflow, options)); 680 681 } 682 } 683 684 /** 685 * Sets the last workflow action.<p> 686 * 687 * @param action a workflow action 688 */ 689 protected void setLastAction(CmsWorkflowAction action) { 690 691 m_lastAction = action; 692 } 693 694 /** 695 * Ensures all style sheets are loaded.<p> 696 */ 697 private void initCss() { 698 699 if (!CSS_INITIALIZED) { 700 I_CmsPublishLayoutBundle.INSTANCE.publishCss().ensureInjected(); 701 CSS_INITIALIZED = true; 702 } 703 } 704 705}