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.ui.dialogs;
029
030import org.opencms.file.CmsObject;
031import org.opencms.file.CmsResource;
032import org.opencms.file.CmsResource.CmsResourceCopyMode;
033import org.opencms.file.CmsResourceFilter;
034import org.opencms.file.CmsVfsException;
035import org.opencms.file.types.CmsResourceTypeFolderSubSitemap;
036import org.opencms.file.types.CmsResourceTypeXmlContainerPage;
037import org.opencms.i18n.tools.CmsContainerPageCopier;
038import org.opencms.i18n.tools.CmsContainerPageCopier.NoCustomReplacementException;
039import org.opencms.lock.CmsLockActionRecord;
040import org.opencms.lock.CmsLockUtil;
041import org.opencms.main.CmsException;
042import org.opencms.main.CmsIllegalArgumentException;
043import org.opencms.main.CmsLog;
044import org.opencms.main.OpenCms;
045import org.opencms.security.CmsSecurityException;
046import org.opencms.staticexport.CmsLinkManager;
047import org.opencms.ui.A_CmsUI;
048import org.opencms.ui.CmsVaadinUtils;
049import org.opencms.ui.I_CmsDialogContext;
050import org.opencms.ui.apps.sitemanager.CmsSiteManager;
051import org.opencms.ui.components.CmsBasicDialog;
052import org.opencms.ui.components.CmsConfirmationDialog;
053import org.opencms.ui.components.CmsErrorDialog;
054import org.opencms.ui.components.CmsMacroResolverDialog;
055import org.opencms.ui.components.CmsOkCancelActionHandler;
056import org.opencms.ui.components.fileselect.CmsPathSelectField;
057import org.opencms.util.CmsMacroResolver;
058import org.opencms.util.CmsStringUtil;
059import org.opencms.util.CmsUUID;
060
061import java.util.ArrayList;
062import java.util.Arrays;
063import java.util.Collections;
064import java.util.HashMap;
065import java.util.HashSet;
066import java.util.List;
067import java.util.Map;
068import java.util.Set;
069
070import org.apache.commons.logging.Log;
071
072import com.vaadin.ui.Button;
073import com.vaadin.ui.Button.ClickEvent;
074import com.vaadin.ui.Button.ClickListener;
075import com.vaadin.ui.FormLayout;
076import com.vaadin.ui.UI;
077import com.vaadin.ui.Window;
078import com.vaadin.v7.ui.CheckBox;
079import com.vaadin.v7.ui.ComboBox;
080import com.vaadin.v7.ui.ComboBox.ItemStyleGenerator;
081
082/**
083 * The copy move dialog.<p>
084 */
085@SuppressWarnings("deprecation")
086public class CmsCopyMoveDialog extends CmsBasicDialog {
087
088    /** The copy/move actions. */
089    public static enum Action {
090
091        /** Copy container page automatic mode. */
092        container_page_automatic,
093        /** Copy container page including referenced elements. */
094        container_page_copy,
095        /** Copy container page reuse referenced elements. */
096        container_page_reuse,
097        /** Copy resources as new. */
098        copy_all,
099        /** Create siblings. */
100        copy_sibling_all,
101        /** Copy and preserve siblings. */
102        copy_sibling_mixed,
103        /** Move resources. */
104        move,
105        /** Copy sub sitemap, adjust internal links. */
106        sub_sitemap;
107    }
108
109    /** The dialog mode. */
110    public static enum DialogMode {
111        /** Allow copy only. */
112        copy,
113        /** Allow copy and move. */
114        copy_and_move,
115        /** Allow move only. */
116        move
117    }
118
119    /** Logger instance for this class. */
120    static final Log LOG = CmsLog.getLog(CmsCopyMoveDialog.class);
121
122    /** The serial version id. */
123    private static final long serialVersionUID = 1L;
124
125    /** The default actions. */
126    List<Action> m_defaultActions;
127
128    /** The action radio buttons. */
129    private ComboBox m_actionCombo;
130
131    /** The cancel button. */
132    private Button m_cancelButton;
133
134    /** The cms context. */
135    private CmsObject m_cms;
136
137    /** The dialog context. */
138    private I_CmsDialogContext m_context;
139
140    /** Flag indicating the move option is allowed. */
141    private DialogMode m_dialogMode;
142
143    /** Indicates the copy folder has a default file of the type container page. */
144    private boolean m_hasContainerPageDefaultFile;
145
146    /**Dialog for editing key value pairs used as macros. Only used for sitemap folder*/
147    private CmsMacroResolverDialog m_macroDialog;
148
149    /** The OK button. */
150    private Button m_okButton;
151
152    /** The overwrite existing resources checkbox. */
153    private CheckBox m_overwriteExisting;
154
155    /** The root cms context. */
156    private CmsObject m_rootCms;
157
158    /** The target path select field. */
159    private CmsPathSelectField m_targetPath;
160
161    /** The resources to update after dialog close. */
162    private Set<CmsUUID> m_updateResources;
163
164    /**
165     * Constructor.<p>
166     *
167     * @param context the dialog context
168     * @param mode the dialog mode
169     */
170    public CmsCopyMoveDialog(final I_CmsDialogContext context, DialogMode mode) {
171
172        m_dialogMode = mode;
173        m_updateResources = new HashSet<CmsUUID>();
174        m_context = context;
175        m_defaultActions = new ArrayList<Action>();
176        displayResourceInfo(context.getResources());
177        FormLayout form = initForm();
178        setContent(form);
179        updateDefaultActions(null);
180        m_okButton = new Button(CmsVaadinUtils.getMessageText(org.opencms.workplace.Messages.GUI_DIALOG_BUTTON_OK_0));
181        m_okButton.addClickListener(new ClickListener() {
182
183            private static final long serialVersionUID = 1L;
184
185            public void buttonClick(ClickEvent event) {
186
187                submit(false, null);
188            }
189        });
190        addButton(m_okButton);
191        m_cancelButton = new Button(
192            CmsVaadinUtils.getMessageText(org.opencms.workplace.Messages.GUI_DIALOG_BUTTON_CANCEL_0));
193        m_cancelButton.addClickListener(new ClickListener() {
194
195            private static final long serialVersionUID = 1L;
196
197            public void buttonClick(ClickEvent event) {
198
199                cancel();
200            }
201        });
202        addButton(m_cancelButton);
203        setActionHandler(new CmsOkCancelActionHandler() {
204
205            private static final long serialVersionUID = 1L;
206
207            @Override
208            protected void cancel() {
209
210                CmsCopyMoveDialog.this.cancel();
211            }
212
213            @Override
214            protected void ok() {
215
216                submit(false, null);
217            }
218        });
219    }
220
221    /**
222     * Preselects the target folder.<p>
223     *
224     * @param structureId the target structure id
225     *
226     * @throws CmsException in case the target can not be read or is not a folder
227     */
228    public void setTargetFolder(CmsUUID structureId) throws CmsException {
229
230        CmsObject cms = A_CmsUI.getCmsObject();
231        CmsResource res = cms.readResource(structureId);
232        setTargetForlder(res);
233    }
234
235    /**
236     * Preselects the target folder.<p>
237     *
238     * @param resource the target resource
239     */
240    public void setTargetForlder(CmsResource resource) {
241
242        if (resource.isFolder()) {
243            if (m_context.getResources().size() == 1) {
244                try {
245                    if (m_dialogMode.equals(DialogMode.copy)
246                        | (m_dialogMode.equals(DialogMode.copy_and_move)
247                            && CmsResource.getParentFolder(m_context.getResources().get(0).getRootPath()).equals(
248                                resource.getRootPath()))) {
249                        m_targetPath.setValue(getTargetName(m_context.getResources().get(0), resource));
250                    } else {
251
252                        m_targetPath.setValue(
253                            getCms().getSitePath(resource) + getTargetName(m_context.getResources().get(0), resource));
254                    }
255                } catch (CmsException e) {
256                    m_targetPath.setValue(getCms().getSitePath(resource));
257                }
258            } else {
259                m_targetPath.setValue(getCms().getSitePath(resource));
260            }
261
262            updateDefaultActions(resource.getRootPath());
263        } else {
264            throw new CmsIllegalArgumentException(
265                org.opencms.workplace.commons.Messages.get().container(
266                    org.opencms.workplace.commons.Messages.ERR_COPY_MULTI_TARGET_NOFOLDER_1,
267                    A_CmsUI.getCmsObject().getSitePath(resource)));
268        }
269    }
270
271    /**
272     * Get bunle values from dialog.<p>
273     *
274     * @return map of key-value pairs to be resolved as macro. if null or empty, then ignored
275     */
276    protected Map<String, String> getMacroMap() {
277
278        return m_macroDialog.getMacroMap();
279    }
280
281    /**
282     * Performs the single resource operation.<p>
283     *
284     * @param source the source
285     * @param target the target
286     * @param action the action
287     * @param overwrite if existing resources should be overwritten
288     * @param makroMap map of key-value pairs to be resolved as macro. if null or empty, then ignored
289     *
290     * @throws CmsException in case the operation fails
291     */
292    protected void performSingleOperation(
293        CmsResource source,
294        CmsResource target,
295        Action action,
296        boolean overwrite,
297        Map<String, String> makroMap)
298    throws CmsException {
299
300        performSingleOperation(source, target, getTargetName(source, target), action, overwrite, makroMap);
301    }
302
303    /**
304     * Performs the single resource operation.<p>
305     *
306     * @param source the source
307     * @param target the target folder
308     * @param name the target resource name
309     * @param action the action
310     * @param overwrite if existing resources should be overwritten
311     * @param macroMap map of key-value pairs to be resolved as macro. if null or empty, then ignored
312     *
313     * @throws CmsException in case the operation fails
314     */
315    protected void performSingleOperation(
316        CmsResource source,
317        CmsResource target,
318        String name,
319        Action action,
320        boolean overwrite,
321        Map<String, String> macroMap)
322    throws CmsException {
323
324        // add new parent and source to the update resources
325        m_updateResources.add(target.getStructureId());
326        m_updateResources.add(source.getStructureId());
327
328        String finalTarget = target.getRootPath();
329        if (finalTarget.equals(source.getRootPath()) || finalTarget.startsWith(source.getRootPath())) {
330            throw new CmsVfsException(
331                org.opencms.workplace.commons.Messages.get().container(
332                    org.opencms.workplace.commons.Messages.ERR_COPY_ONTO_ITSELF_1,
333                    finalTarget));
334        }
335        finalTarget = CmsStringUtil.joinPaths(finalTarget, name);
336        // delete existing target resource if selected or confirmed by the user
337        if (overwrite && getRootCms().existsResource(finalTarget, CmsResourceFilter.ONLY_VISIBLE)) {
338            CmsLockUtil.ensureLock(
339                getRootCms(),
340                getRootCms().readResource(finalTarget, CmsResourceFilter.ONLY_VISIBLE));
341            if (getRootCms().existsResource(finalTarget, CmsResourceFilter.ONLY_VISIBLE_NO_DELETED)) {
342                if ((action != Action.container_page_automatic)
343                    && (action != Action.container_page_copy)
344                    && (action != Action.container_page_reuse)) {
345                    // container page copy modes don't just call copyResource(), they need special handling for the overwrite case
346                    getRootCms().deleteResource(finalTarget, CmsResource.DELETE_PRESERVE_SIBLINGS);
347                }
348            }
349        }
350        // copy the resource
351        if (action == Action.move) {
352            // add former parent to the update resources
353            CmsResource parent = getRootCms().readParentFolder(source.getStructureId());
354            m_updateResources.add(parent.getStructureId());
355            CmsLockActionRecord lockRecord = CmsLockUtil.ensureLock(getRootCms(), source);
356            getRootCms().moveResource(source.getRootPath(), finalTarget);
357            if (lockRecord.getChange() == CmsLockActionRecord.LockChange.locked) {
358                getRootCms().unlockResource(finalTarget);
359            }
360        } else if ((action == Action.container_page_automatic)
361            || (action == Action.container_page_copy)
362            || (action == Action.container_page_reuse)) {
363                CmsContainerPageCopier copier = new CmsContainerPageCopier(m_context.getCms());
364                try {
365
366                    CmsContainerPageCopier.CopyMode mode = action == Action.container_page_automatic
367                    ? CmsContainerPageCopier.CopyMode.automatic
368                    : (action == Action.container_page_copy
369                    ? CmsContainerPageCopier.CopyMode.smartCopyAndChangeLocale
370                    : CmsContainerPageCopier.CopyMode.reuse);
371                    copier.setCopyMode(mode);
372                    copier.run(m_context.getResources().get(0), target, name);
373                    m_context.finish(
374                        Arrays.asList(
375                            copier.getTargetFolder().getStructureId(),
376                            copier.getCopiedFolderOrPage().getStructureId()));
377                } catch (CmsException e) {
378                    m_context.error(e);
379                } catch (NoCustomReplacementException e) {
380                    String errorMessage = CmsVaadinUtils.getMessageText(
381                        org.opencms.ui.Messages.GUI_COPYPAGE_NO_REPLACEMENT_FOUND_1,
382                        e.getResource().getRootPath());
383                    CmsErrorDialog.showErrorDialog(errorMessage, e);
384                }
385            } else {
386
387                CmsResourceCopyMode copyMode = null;
388                switch ((Action)m_actionCombo.getValue()) {
389                    case copy_all:
390                        copyMode = CmsResource.COPY_AS_NEW;
391                        break;
392                    case copy_sibling_all:
393                        copyMode = CmsResource.COPY_AS_SIBLING;
394                        break;
395                    case copy_sibling_mixed:
396                    case sub_sitemap:
397                    default:
398                        copyMode = CmsResource.COPY_PRESERVE_SIBLING;
399                }
400
401                //Copies resources. Adjust links if action==Action.sub_sitemap, resolves macro if marcoMap if not null or empty
402                CmsMacroResolver.copyAndResolveMacro(
403                    getRootCms(),
404                    source.getRootPath(),
405                    finalTarget,
406                    macroMap,
407                    action == Action.sub_sitemap,
408                    copyMode);
409
410                getRootCms().unlockResource(finalTarget);
411
412                CmsResource copyResource = getRootCms().readResource(finalTarget, CmsResourceFilter.IGNORE_EXPIRATION);
413                m_updateResources.add(copyResource.getStructureId());
414            }
415    }
416
417    /**
418     * Updates the 'overwrite existing' checkbox state depending on the currently selected mode.<p>
419     */
420    protected void updateOverwriteExisting() {
421
422        if (m_overwriteExisting != null) {
423            boolean move = (m_dialogMode == DialogMode.move) || (m_actionCombo.getValue() == Action.move);
424            if (move) {
425                m_overwriteExisting.setValue(Boolean.FALSE);
426                m_overwriteExisting.setVisible(false);
427            } else {
428                m_overwriteExisting.setVisible(true);
429            }
430        }
431    }
432
433    /**
434     * Cancels the dialog action.<p>
435     */
436    void cancel() {
437
438        m_context.finish(Collections.<CmsUUID> emptyList());
439    }
440
441    /**
442     * Submits the dialog action.<p>
443     *
444     * @param overwrite to forcefully overwrite existing files
445     * @param makroMap map of key-value pairs to be resolved as macro. if null or empty, then ignored
446     */
447    void submit(boolean overwrite, Map<String, String> makroMap) {
448
449        try {
450            CmsResource targetFolder = null;
451            String targetName = null;
452            String target = m_targetPath.getValue();
453            boolean isSingleResource = m_context.getResources().size() == 1;
454            // resolve relative paths
455            target = CmsLinkManager.getAbsoluteUri(
456                target,
457                CmsResource.getParentFolder(getCms().getSitePath(m_context.getResources().get(0))));
458
459            // check if the given path is a root path
460            CmsObject cms = OpenCms.getSiteManager().getSiteForRootPath(target) != null ? getRootCms() : getCms();
461
462            if (cms.existsResource(target, CmsResourceFilter.ALL.addRequireFolder())) {
463                // The target is an existing folder
464                // always copy files into that folder
465                targetFolder = cms.readResource(target);
466            } else if (cms.existsResource(target, CmsResourceFilter.ALL.addRequireFile())) {
467                // The target is an existing file
468                if (isSingleResource) {
469                    // Replace the file with the resource copied, if it is just a single resource
470                    if (target.equals(m_context.getResources().get(0).getRootPath())) {
471                        throw new CmsVfsException(
472                            org.opencms.workplace.commons.Messages.get().container(
473                                org.opencms.workplace.commons.Messages.ERR_COPY_ONTO_ITSELF_1,
474                                target));
475                    }
476                    targetName = CmsResource.getName(target);
477                    targetFolder = cms.readResource(CmsResource.getParentFolder(target));
478                } else {
479                    // Throw an error if a single file should be replaced with multiple resources
480                    // since we cannot copy multiple resources to a single file
481                    throw new CmsVfsException(
482                        org.opencms.workplace.commons.Messages.get().container(
483                            org.opencms.workplace.commons.Messages.ERR_COPY_MULTI_TARGET_NOFOLDER_1,
484                            target));
485                }
486            } else {
487                // The target does not exist
488                if (isSingleResource) {
489                    // If we have a single resource, we could possible create the target as copy of that resource
490                    if (cms.existsResource(
491                        CmsResource.getParentFolder(target),
492                        CmsResourceFilter.ALL.addRequireFolder())) {
493                        targetName = CmsResource.getName(target);
494                        targetFolder = cms.readResource(CmsResource.getParentFolder(target));
495                    } else {
496                        // If the parent folder of the resource does not exist, we will not create it automatically.
497                        // Thus we need to throw an exception.
498                        throw new CmsVfsException(
499                            org.opencms.workplace.commons.Messages.get().container(
500                                org.opencms.workplace.commons.Messages.ERR_COPY_TARGET_PARENT_FOLDER_MISSING_1,
501                                target));
502                    }
503                } else {
504                    // We cannot copy multiple resources to a single resource
505                    throw new CmsVfsException(
506                        org.opencms.workplace.commons.Messages.get().container(
507                            org.opencms.workplace.commons.Messages.ERR_COPY_MULTI_TARGET_NOFOLDER_1,
508                            target));
509                }
510            }
511
512            Action action = m_actionCombo != null ? (Action)m_actionCombo.getValue() : Action.move;
513
514            overwrite = overwrite || isOverwriteExisting();
515            if (!overwrite || action.equals(Action.move)) {
516                List<CmsResource> collidingResources = getExistingFileCollisions(targetFolder, targetName);
517                if (collidingResources != null) {
518                    if (action.equals(Action.move)) {
519                        throw new CmsVfsException(
520                            org.opencms.workplace.commons.Messages.get().container(
521                                org.opencms.workplace.commons.Messages.ERR_MOVE_FORCES_OVERWRITE_EXISTING_RESOURCE_0));
522                    } else {
523                        showConfirmOverwrite(collidingResources);
524                        return;
525                    }
526                }
527            }
528            Map<CmsResource, CmsException> errors = new HashMap<CmsResource, CmsException>();
529
530            //Check if dialog for macro resolver has to be shown: action correct?, makroMap==null (default, not set by dialog yet)
531            if ((action == Action.sub_sitemap) & (makroMap == null)) {
532                if (CmsSiteManager.isFolderWithMacros(getRootCms(), m_context.getResources().get(0).getRootPath())) {
533                    showMacroResolverDialog(m_context.getResources().get(0));
534                    return;
535                }
536            }
537            if (targetName == null) {
538                for (CmsResource source : m_context.getResources()) {
539                    try {
540                        performSingleOperation(source, targetFolder, action, overwrite, makroMap);
541                    } catch (CmsException e) {
542                        errors.put(source, e);
543                        LOG.error(
544                            "Error while executing "
545                                + action
546                                + " on resource "
547                                + source.getRootPath(),
548                            e);
549                    }
550                }
551            } else {
552                // this will only be the case in a single resource scenario
553                CmsResource source = m_context.getResources().get(0);
554                try {
555                    performSingleOperation(source, targetFolder, targetName, action, overwrite, makroMap);
556                } catch (CmsException e) {
557                    errors.put(source, e);
558                    LOG.error(
559                        "Error while executing "
560                            + m_actionCombo.getValue().toString()
561                            + " on resource "
562                            + source.getRootPath(),
563                        e);
564                }
565            }
566
567            if (!errors.isEmpty()) {
568                if (m_context instanceof CmsEmbeddedDialogContext) {
569                    // In ADE, finish() would trigger a reload and cause the error message to not be displayed,
570                    // and we can only trigger the dialog for a single resource there anyway
571                    m_context.error(errors.values().iterator().next());
572                } else {
573                    m_context.finish(m_updateResources);
574                    m_context.error(errors.values().iterator().next());
575                }
576            } else {
577                m_context.finish(m_updateResources);
578            }
579
580        } catch (CmsException e) {
581            m_context.error(e);
582        }
583    }
584
585    /**
586     * Returns the cms context.<p>
587     *
588     * @return the cms context
589     */
590    private CmsObject getCms() {
591
592        if (m_cms == null) {
593            m_cms = A_CmsUI.getCmsObject();
594        }
595        return m_cms;
596    }
597
598    /**
599     * Returns the resources that collide with already existing resources.<p>
600     *
601     * @param targetFolder the target folder
602     * @param targetName name of the target if a single file's copy should be named differently
603     *
604     * @return the colliding resources or <code>null</code> if no collisions found
605     *
606     * @throws CmsException in case the checking the resources fails
607     */
608    private List<CmsResource> getExistingFileCollisions(CmsResource targetFolder, String targetName)
609    throws CmsException {
610
611        List<CmsResource> collidingResources = new ArrayList<CmsResource>();
612
613        String finalTarget = targetFolder.getRootPath();
614        if (!finalTarget.endsWith("/")) {
615            finalTarget += "/";
616        }
617        if (targetName == null) {
618            for (CmsResource source : m_context.getResources()) {
619                if (finalTarget.equals(CmsResource.getParentFolder(source.getRootPath()))) {
620                    // copying to the same folder, a new name will be generated
621                    return null;
622                }
623                String fileName = finalTarget + source.getName();
624                if (getRootCms().existsResource(fileName, CmsResourceFilter.ALL)) {
625                    collidingResources.add(source);
626                }
627            }
628        } else {
629            String fileName = finalTarget + targetName;
630            if (getRootCms().existsResource(fileName, CmsResourceFilter.ALL)) {
631                collidingResources.add(getRootCms().readResource(fileName, CmsResourceFilter.ALL));
632            }
633        }
634        return collidingResources.isEmpty() ? null : collidingResources;
635    }
636
637    /**
638     * Returns the root cms context.<p>
639     *
640     * @return the root cms context
641     *
642     * @throws CmsException in case initializing the context fails
643     */
644    private CmsObject getRootCms() throws CmsException {
645
646        if (m_rootCms == null) {
647            m_rootCms = OpenCms.initCmsObject(getCms());
648            m_rootCms.getRequestContext().setSiteRoot("/");
649        }
650        return m_rootCms;
651    }
652
653    /**
654     * Gets a name for the target resource.<p>
655     *
656     * @param source Source
657     * @param target Target
658     * @return Name
659     * @throws CmsException exception
660     */
661    private String getTargetName(CmsResource source, CmsResource target) throws CmsException {
662
663        String name;
664        String folderRootPath = target.getRootPath();
665        if (!folderRootPath.endsWith("/")) {
666            folderRootPath += "/";
667        }
668        if (folderRootPath.equals(CmsResource.getParentFolder(source.getRootPath()))) {
669            name = OpenCms.getResourceManager().getNameGenerator().getCopyFileName(
670                getRootCms(),
671                folderRootPath,
672                source.getName());
673        } else {
674            name = source.getName();
675        }
676        return name;
677    }
678
679    /**
680     * Checks whether the folder has a default file of the type container page.<p>
681     *
682     * @param folder the folder to check
683     *
684     * @return <code>true</code> if the folder has a default file of the type container page
685     */
686    private boolean hasContainerPageDefaultFile(CmsResource folder) {
687
688        try {
689            CmsResource defaultFile = A_CmsUI.getCmsObject().readDefaultFile(
690                folder,
691                CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
692            return (defaultFile != null) && CmsResourceTypeXmlContainerPage.isContainerPage(defaultFile);
693        } catch (CmsSecurityException e) {
694            return false;
695        }
696    }
697
698    /**
699     * Initializes the form fields.<p>
700     *
701     * @return the form component
702     */
703    private FormLayout initForm() {
704
705        FormLayout form = new FormLayout();
706        form.setWidth("100%");
707        m_targetPath = new CmsPathSelectField();
708        m_targetPath.setCaption(
709            CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_COPY_MOVE_TARGET_0));
710        m_targetPath.setFileSelectCaption(
711            CmsVaadinUtils.getMessageText(Messages.GUI_COPY_MOVE_SELECT_TARGET_CAPTION_0));
712        m_targetPath.setResourceFilter(CmsResourceFilter.ONLY_VISIBLE_NO_DELETED.addRequireFolder());
713        m_targetPath.setWidth("100%");
714        form.addComponent(m_targetPath);
715
716        if (m_dialogMode != DialogMode.move) {
717            m_actionCombo = new ComboBox();
718            m_actionCombo.setCaption(CmsVaadinUtils.getMessageText(org.opencms.ui.Messages.GUI_COPYPAGE_COPY_MODE_0));
719            m_actionCombo.setNullSelectionAllowed(false);
720            m_actionCombo.setNewItemsAllowed(false);
721            m_actionCombo.setWidth("100%");
722            if (m_context.getResources().size() == 1) {
723                if (m_context.getResources().get(0).isFile()) {
724                    m_actionCombo.addItem(Action.copy_all);
725                    m_actionCombo.setItemCaption(
726                        Action.copy_all,
727                        CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_COPY_AS_NEW_0));
728                    m_actionCombo.addItem(Action.copy_sibling_all);
729                    m_actionCombo.setItemCaption(
730                        Action.copy_sibling_all,
731                        CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_CREATE_SIBLING_0));
732                    if (m_dialogMode == DialogMode.copy_and_move) {
733                        m_actionCombo.addItem(Action.move);
734                        m_actionCombo.setItemCaption(
735                            Action.move,
736                            CmsVaadinUtils.getMessageText(
737                                org.opencms.workplace.commons.Messages.GUI_COPY_MOVE_MOVE_FILE_0));
738                    }
739                } else {
740                    CmsResource folder = m_context.getResources().get(0);
741                    m_hasContainerPageDefaultFile = hasContainerPageDefaultFile(folder);
742                    if (m_hasContainerPageDefaultFile) {
743                        m_actionCombo.addItem(Action.container_page_automatic);
744                        m_actionCombo.setItemCaption(
745                            Action.container_page_automatic,
746                            CmsVaadinUtils.getMessageText(Messages.GUI_COPY_MOVE_AUTOMATIC_0));
747                        m_actionCombo.addItem(Action.container_page_copy);
748                        m_actionCombo.setItemCaption(
749                            Action.container_page_copy,
750                            CmsVaadinUtils.getMessageText(Messages.GUI_COPY_MOVE_CONTAINERPAGE_COPY_0));
751                        m_actionCombo.addItem(Action.container_page_reuse);
752                        m_actionCombo.setItemCaption(
753                            Action.container_page_reuse,
754                            CmsVaadinUtils.getMessageText(Messages.GUI_COPY_MOVE_CONTAINERPAGE_REUSE_0));
755                    }
756                    if (CmsResourceTypeFolderSubSitemap.isSubSitemap(folder)) {
757                        m_actionCombo.addItem(Action.sub_sitemap);
758                        m_actionCombo.setItemCaption(
759                            Action.sub_sitemap,
760                            CmsVaadinUtils.getMessageText(Messages.GUI_COPY_MOVE_SUBSITEMAP_0));
761                    }
762                    m_actionCombo.addItem(Action.copy_sibling_mixed);
763                    m_actionCombo.setItemCaption(
764                        Action.copy_sibling_mixed,
765                        CmsVaadinUtils.getMessageText(
766                            org.opencms.workplace.commons.Messages.GUI_COPY_ALL_NO_SIBLINGS_0));
767                    m_actionCombo.addItem(Action.copy_all);
768                    m_actionCombo.setItemCaption(
769                        Action.copy_all,
770                        CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_COPY_ALL_0));
771                    m_actionCombo.addItem(Action.copy_sibling_all);
772                    m_actionCombo.setItemCaption(
773                        Action.copy_sibling_all,
774                        CmsVaadinUtils.getMessageText(
775                            org.opencms.workplace.commons.Messages.GUI_COPY_MULTI_CREATE_SIBLINGS_0));
776                    if (m_dialogMode == DialogMode.copy_and_move) {
777                        m_actionCombo.addItem(Action.move);
778                        m_actionCombo.setItemCaption(
779                            Action.move,
780                            CmsVaadinUtils.getMessageText(
781                                org.opencms.workplace.commons.Messages.GUI_COPY_MOVE_MOVE_FOLDER_0));
782                    }
783                }
784            } else {
785                m_actionCombo.addItem(Action.copy_sibling_mixed);
786                m_actionCombo.setItemCaption(
787                    Action.copy_sibling_mixed,
788                    CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_COPY_ALL_NO_SIBLINGS_0));
789                m_actionCombo.addItem(Action.copy_all);
790                m_actionCombo.setItemCaption(
791                    Action.copy_all,
792                    CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_COPY_ALL_0));
793                m_actionCombo.addItem(Action.copy_sibling_all);
794                m_actionCombo.setItemCaption(
795                    Action.copy_sibling_all,
796                    CmsVaadinUtils.getMessageText(
797                        org.opencms.workplace.commons.Messages.GUI_COPY_MULTI_CREATE_SIBLINGS_0));
798                if (m_dialogMode == DialogMode.copy_and_move) {
799                    m_actionCombo.addItem(Action.move);
800                    m_actionCombo.setItemCaption(
801                        Action.move,
802                        CmsVaadinUtils.getMessageText(
803                            org.opencms.workplace.commons.Messages.GUI_COPY_MOVE_MOVE_RESOURCES_0));
804                }
805            }
806            m_actionCombo.setItemStyleGenerator(new ItemStyleGenerator() {
807
808                private static final long serialVersionUID = 1L;
809
810                public String getStyle(ComboBox source, Object itemId) {
811
812                    String style = null;
813                    if (m_defaultActions.contains(itemId)) {
814                        style = "bold";
815                    }
816                    return style;
817                }
818            });
819            form.addComponent(m_actionCombo);
820            m_actionCombo.addValueChangeListener(event -> updateOverwriteExisting());
821        }
822
823        if (m_context.getResources().size() > 1) {
824            m_overwriteExisting = new CheckBox(
825                CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_COPY_MULTI_OVERWRITE_0));
826            m_overwriteExisting.setValue(Boolean.FALSE);
827            form.addComponent(m_overwriteExisting);
828
829            updateOverwriteExisting();
830        }
831
832        return form;
833    }
834
835    /**
836     * Checks the overwrite existing setting.<p>
837     *
838     * @return <code>true</code> if overwrite existing is set
839     */
840    private boolean isOverwriteExisting() {
841
842        return (m_overwriteExisting != null) && m_overwriteExisting.getValue().booleanValue();
843    }
844
845    /**
846     * Displays the confirm overwrite dialog.<p>
847     *
848     * @param collidingResources the colliding resources
849     */
850    private void showConfirmOverwrite(List<CmsResource> collidingResources) {
851
852        final Window window = CmsBasicDialog.prepareWindow();
853        window.setCaption(CmsVaadinUtils.getMessageText(Messages.GUI_COPY_MOVE_CONFIRM_OVERWRITE_TITLE_0));
854        final CmsConfirmationDialog dialog = new CmsConfirmationDialog(
855            CmsVaadinUtils.getMessageText(Messages.GUI_COPY_MOVE_CONFIRM_OVERWRITE_MESSAGE_0),
856            new Runnable() {
857
858                public void run() {
859
860                    window.close();
861                    submit(true, null);
862                }
863            },
864            new Runnable() {
865
866                public void run() {
867
868                    window.close();
869                    cancel();
870                }
871            });
872        dialog.displayResourceInfo(collidingResources);
873        window.setContent(dialog);
874        UI.getCurrent().addWindow(window);
875    }
876
877    /**
878     * Displays the resolve macro dialog.<p>
879     *
880     * @param resource to be copied.
881     */
882    private void showMacroResolverDialog(CmsResource resource) {
883
884        final Window window = CmsBasicDialog.prepareWindow(DialogWidth.wide);
885        window.setCaption(CmsVaadinUtils.getMessageText(Messages.GUI_COPY_MOVE_SET_MACRO_VALUES_TITLE_0));
886        m_macroDialog = new CmsMacroResolverDialog(new Runnable() {
887
888            public void run() {
889
890                Map<String, String> map = getMacroMap();
891                window.close();
892                submit(true, map); //Overwrite true because this was checked first. If no overwrite, window is closed and this code isn't called
893            }
894        }, new Runnable() {
895
896            public void run() {
897
898                window.close();
899                cancel();
900            }
901        }, resource);
902        m_macroDialog.displayResourceInfo(Collections.singletonList(resource));
903        window.setContent(m_macroDialog);
904        UI.getCurrent().addWindow(window);
905    }
906
907    /**
908     * Updates the default dialog actions.<p>
909     *
910     * @param targetRootPath the target root path
911     */
912    private void updateDefaultActions(String targetRootPath) {
913
914        if (m_actionCombo != null) {
915            m_defaultActions.clear();
916            String resPath = m_context.getResources().get(0).getRootPath();
917            String parentFolder = CmsResource.getParentFolder(resPath);
918            if ((DialogMode.copy_and_move == m_dialogMode) && !parentFolder.equals(targetRootPath)) {
919                m_defaultActions.clear();
920                m_defaultActions.add(Action.move);
921            } else if (m_context.getResources().size() == 1) {
922                if (m_context.getResources().get(0).isFile()) {
923                    m_defaultActions.add(Action.copy_all);
924                } else {
925                    m_defaultActions.add(Action.copy_sibling_mixed);
926                    if (m_hasContainerPageDefaultFile) {
927                        m_defaultActions.clear();
928                        m_defaultActions.add(Action.container_page_automatic);
929                        m_defaultActions.add(Action.container_page_copy);
930                        m_defaultActions.add(Action.container_page_reuse);
931                    }
932                    CmsResource folder = m_context.getResources().get(0);
933                    if (CmsResourceTypeFolderSubSitemap.isSubSitemap(folder)) {
934                        m_defaultActions.clear();
935                        m_defaultActions.add(Action.sub_sitemap);
936                    }
937                }
938            } else {
939                m_defaultActions.add(Action.copy_sibling_mixed);
940            }
941            if (!m_defaultActions.isEmpty()) {
942                m_actionCombo.setValue(m_defaultActions.get(0));
943            }
944            m_actionCombo.markAsDirty();
945        }
946    }
947}