001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (https://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: https://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: https://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("Error while executing " + action + " on resource " + source.getRootPath(), e);
544                    }
545                }
546            } else {
547                // this will only be the case in a single resource scenario
548                CmsResource source = m_context.getResources().get(0);
549                try {
550                    performSingleOperation(source, targetFolder, targetName, action, overwrite, makroMap);
551                } catch (CmsException e) {
552                    errors.put(source, e);
553                    LOG.error(
554                        "Error while executing "
555                            + m_actionCombo.getValue().toString()
556                            + " on resource "
557                            + source.getRootPath(),
558                        e);
559                }
560            }
561
562            if (!errors.isEmpty()) {
563                if (m_context instanceof CmsEmbeddedDialogContext) {
564                    // In ADE, finish() would trigger a reload and cause the error message to not be displayed,
565                    // and we can only trigger the dialog for a single resource there anyway
566                    m_context.error(errors.values().iterator().next());
567                } else {
568                    m_context.finish(m_updateResources);
569                    m_context.error(errors.values().iterator().next());
570                }
571            } else {
572                m_context.finish(m_updateResources);
573            }
574
575        } catch (CmsException e) {
576            m_context.error(e);
577        }
578    }
579
580    /**
581     * Returns the cms context.<p>
582     *
583     * @return the cms context
584     */
585    private CmsObject getCms() {
586
587        if (m_cms == null) {
588            m_cms = A_CmsUI.getCmsObject();
589        }
590        return m_cms;
591    }
592
593    /**
594     * Returns the resources that collide with already existing resources.<p>
595     *
596     * @param targetFolder the target folder
597     * @param targetName name of the target if a single file's copy should be named differently
598     *
599     * @return the colliding resources or <code>null</code> if no collisions found
600     *
601     * @throws CmsException in case the checking the resources fails
602     */
603    private List<CmsResource> getExistingFileCollisions(CmsResource targetFolder, String targetName)
604    throws CmsException {
605
606        List<CmsResource> collidingResources = new ArrayList<CmsResource>();
607
608        String finalTarget = targetFolder.getRootPath();
609        if (!finalTarget.endsWith("/")) {
610            finalTarget += "/";
611        }
612        if (targetName == null) {
613            for (CmsResource source : m_context.getResources()) {
614                if (finalTarget.equals(CmsResource.getParentFolder(source.getRootPath()))) {
615                    // copying to the same folder, a new name will be generated
616                    return null;
617                }
618                String fileName = finalTarget + source.getName();
619                if (getRootCms().existsResource(fileName, CmsResourceFilter.ALL)) {
620                    collidingResources.add(source);
621                }
622            }
623        } else {
624            String fileName = finalTarget + targetName;
625            if (getRootCms().existsResource(fileName, CmsResourceFilter.ALL)) {
626                collidingResources.add(getRootCms().readResource(fileName, CmsResourceFilter.ALL));
627            }
628        }
629        return collidingResources.isEmpty() ? null : collidingResources;
630    }
631
632    /**
633     * Returns the root cms context.<p>
634     *
635     * @return the root cms context
636     *
637     * @throws CmsException in case initializing the context fails
638     */
639    private CmsObject getRootCms() throws CmsException {
640
641        if (m_rootCms == null) {
642            m_rootCms = OpenCms.initCmsObject(getCms());
643            m_rootCms.getRequestContext().setSiteRoot("/");
644        }
645        return m_rootCms;
646    }
647
648    /**
649     * Gets a name for the target resource.<p>
650     *
651     * @param source Source
652     * @param target Target
653     * @return Name
654     * @throws CmsException exception
655     */
656    private String getTargetName(CmsResource source, CmsResource target) throws CmsException {
657
658        String name;
659        String folderRootPath = target.getRootPath();
660        if (!folderRootPath.endsWith("/")) {
661            folderRootPath += "/";
662        }
663        if (folderRootPath.equals(CmsResource.getParentFolder(source.getRootPath()))) {
664            name = OpenCms.getResourceManager().getNameGenerator().getCopyFileName(
665                getRootCms(),
666                folderRootPath,
667                source.getName());
668        } else {
669            name = source.getName();
670        }
671        return name;
672    }
673
674    /**
675     * Checks whether the folder has a default file of the type container page.<p>
676     *
677     * @param folder the folder to check
678     *
679     * @return <code>true</code> if the folder has a default file of the type container page
680     */
681    private boolean hasContainerPageDefaultFile(CmsResource folder) {
682
683        try {
684            CmsResource defaultFile = A_CmsUI.getCmsObject().readDefaultFile(
685                folder,
686                CmsResourceFilter.ONLY_VISIBLE_NO_DELETED);
687            return (defaultFile != null) && CmsResourceTypeXmlContainerPage.isContainerPage(defaultFile);
688        } catch (CmsSecurityException e) {
689            return false;
690        }
691    }
692
693    /**
694     * Initializes the form fields.<p>
695     *
696     * @return the form component
697     */
698    private FormLayout initForm() {
699
700        FormLayout form = new FormLayout();
701        form.setWidth("100%");
702        m_targetPath = new CmsPathSelectField();
703        m_targetPath.setCaption(
704            CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_COPY_MOVE_TARGET_0));
705        m_targetPath.setFileSelectCaption(
706            CmsVaadinUtils.getMessageText(Messages.GUI_COPY_MOVE_SELECT_TARGET_CAPTION_0));
707        m_targetPath.setResourceFilter(CmsResourceFilter.ONLY_VISIBLE_NO_DELETED.addRequireFolder());
708        m_targetPath.setWidth("100%");
709        form.addComponent(m_targetPath);
710
711        if (m_dialogMode != DialogMode.move) {
712            m_actionCombo = new ComboBox();
713            m_actionCombo.setCaption(CmsVaadinUtils.getMessageText(org.opencms.ui.Messages.GUI_COPYPAGE_COPY_MODE_0));
714            m_actionCombo.setNullSelectionAllowed(false);
715            m_actionCombo.setNewItemsAllowed(false);
716            m_actionCombo.setWidth("100%");
717            if (m_context.getResources().size() == 1) {
718                if (m_context.getResources().get(0).isFile()) {
719                    m_actionCombo.addItem(Action.copy_all);
720                    m_actionCombo.setItemCaption(
721                        Action.copy_all,
722                        CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_COPY_AS_NEW_0));
723                    m_actionCombo.addItem(Action.copy_sibling_all);
724                    m_actionCombo.setItemCaption(
725                        Action.copy_sibling_all,
726                        CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_CREATE_SIBLING_0));
727                    if (m_dialogMode == DialogMode.copy_and_move) {
728                        m_actionCombo.addItem(Action.move);
729                        m_actionCombo.setItemCaption(
730                            Action.move,
731                            CmsVaadinUtils.getMessageText(
732                                org.opencms.workplace.commons.Messages.GUI_COPY_MOVE_MOVE_FILE_0));
733                    }
734                } else {
735                    CmsResource folder = m_context.getResources().get(0);
736                    m_hasContainerPageDefaultFile = hasContainerPageDefaultFile(folder);
737                    if (m_hasContainerPageDefaultFile) {
738                        m_actionCombo.addItem(Action.container_page_automatic);
739                        m_actionCombo.setItemCaption(
740                            Action.container_page_automatic,
741                            CmsVaadinUtils.getMessageText(Messages.GUI_COPY_MOVE_AUTOMATIC_0));
742                        m_actionCombo.addItem(Action.container_page_copy);
743                        m_actionCombo.setItemCaption(
744                            Action.container_page_copy,
745                            CmsVaadinUtils.getMessageText(Messages.GUI_COPY_MOVE_CONTAINERPAGE_COPY_0));
746                        m_actionCombo.addItem(Action.container_page_reuse);
747                        m_actionCombo.setItemCaption(
748                            Action.container_page_reuse,
749                            CmsVaadinUtils.getMessageText(Messages.GUI_COPY_MOVE_CONTAINERPAGE_REUSE_0));
750                    }
751                    if (CmsResourceTypeFolderSubSitemap.isSubSitemap(folder)) {
752                        m_actionCombo.addItem(Action.sub_sitemap);
753                        m_actionCombo.setItemCaption(
754                            Action.sub_sitemap,
755                            CmsVaadinUtils.getMessageText(Messages.GUI_COPY_MOVE_SUBSITEMAP_0));
756                    }
757                    m_actionCombo.addItem(Action.copy_sibling_mixed);
758                    m_actionCombo.setItemCaption(
759                        Action.copy_sibling_mixed,
760                        CmsVaadinUtils.getMessageText(
761                            org.opencms.workplace.commons.Messages.GUI_COPY_ALL_NO_SIBLINGS_0));
762                    m_actionCombo.addItem(Action.copy_all);
763                    m_actionCombo.setItemCaption(
764                        Action.copy_all,
765                        CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_COPY_ALL_0));
766                    m_actionCombo.addItem(Action.copy_sibling_all);
767                    m_actionCombo.setItemCaption(
768                        Action.copy_sibling_all,
769                        CmsVaadinUtils.getMessageText(
770                            org.opencms.workplace.commons.Messages.GUI_COPY_MULTI_CREATE_SIBLINGS_0));
771                    if (m_dialogMode == DialogMode.copy_and_move) {
772                        m_actionCombo.addItem(Action.move);
773                        m_actionCombo.setItemCaption(
774                            Action.move,
775                            CmsVaadinUtils.getMessageText(
776                                org.opencms.workplace.commons.Messages.GUI_COPY_MOVE_MOVE_FOLDER_0));
777                    }
778                }
779            } else {
780                m_actionCombo.addItem(Action.copy_sibling_mixed);
781                m_actionCombo.setItemCaption(
782                    Action.copy_sibling_mixed,
783                    CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_COPY_ALL_NO_SIBLINGS_0));
784                m_actionCombo.addItem(Action.copy_all);
785                m_actionCombo.setItemCaption(
786                    Action.copy_all,
787                    CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_COPY_ALL_0));
788                m_actionCombo.addItem(Action.copy_sibling_all);
789                m_actionCombo.setItemCaption(
790                    Action.copy_sibling_all,
791                    CmsVaadinUtils.getMessageText(
792                        org.opencms.workplace.commons.Messages.GUI_COPY_MULTI_CREATE_SIBLINGS_0));
793                if (m_dialogMode == DialogMode.copy_and_move) {
794                    m_actionCombo.addItem(Action.move);
795                    m_actionCombo.setItemCaption(
796                        Action.move,
797                        CmsVaadinUtils.getMessageText(
798                            org.opencms.workplace.commons.Messages.GUI_COPY_MOVE_MOVE_RESOURCES_0));
799                }
800            }
801            m_actionCombo.setItemStyleGenerator(new ItemStyleGenerator() {
802
803                private static final long serialVersionUID = 1L;
804
805                public String getStyle(ComboBox source, Object itemId) {
806
807                    String style = null;
808                    if (m_defaultActions.contains(itemId)) {
809                        style = "bold";
810                    }
811                    return style;
812                }
813            });
814            form.addComponent(m_actionCombo);
815            m_actionCombo.addValueChangeListener(event -> updateOverwriteExisting());
816        }
817
818        if (m_context.getResources().size() > 1) {
819            m_overwriteExisting = new CheckBox(
820                CmsVaadinUtils.getMessageText(org.opencms.workplace.commons.Messages.GUI_COPY_MULTI_OVERWRITE_0));
821            m_overwriteExisting.setValue(Boolean.FALSE);
822            form.addComponent(m_overwriteExisting);
823
824            updateOverwriteExisting();
825        }
826
827        return form;
828    }
829
830    /**
831     * Checks the overwrite existing setting.<p>
832     *
833     * @return <code>true</code> if overwrite existing is set
834     */
835    private boolean isOverwriteExisting() {
836
837        return (m_overwriteExisting != null) && m_overwriteExisting.getValue().booleanValue();
838    }
839
840    /**
841     * Displays the confirm overwrite dialog.<p>
842     *
843     * @param collidingResources the colliding resources
844     */
845    private void showConfirmOverwrite(List<CmsResource> collidingResources) {
846
847        final Window window = CmsBasicDialog.prepareWindow();
848        window.setCaption(CmsVaadinUtils.getMessageText(Messages.GUI_COPY_MOVE_CONFIRM_OVERWRITE_TITLE_0));
849        final CmsConfirmationDialog dialog = new CmsConfirmationDialog(
850            CmsVaadinUtils.getMessageText(Messages.GUI_COPY_MOVE_CONFIRM_OVERWRITE_MESSAGE_0),
851            new Runnable() {
852
853                public void run() {
854
855                    window.close();
856                    submit(true, null);
857                }
858            },
859            new Runnable() {
860
861                public void run() {
862
863                    window.close();
864                    cancel();
865                }
866            });
867        dialog.displayResourceInfo(collidingResources);
868        window.setContent(dialog);
869        UI.getCurrent().addWindow(window);
870    }
871
872    /**
873     * Displays the resolve macro dialog.<p>
874     *
875     * @param resource to be copied.
876     */
877    private void showMacroResolverDialog(CmsResource resource) {
878
879        final Window window = CmsBasicDialog.prepareWindow(DialogWidth.wide);
880        window.setCaption(CmsVaadinUtils.getMessageText(Messages.GUI_COPY_MOVE_SET_MACRO_VALUES_TITLE_0));
881        m_macroDialog = new CmsMacroResolverDialog(new Runnable() {
882
883            public void run() {
884
885                Map<String, String> map = getMacroMap();
886                window.close();
887                submit(true, map); //Overwrite true because this was checked first. If no overwrite, window is closed and this code isn't called
888            }
889        }, new Runnable() {
890
891            public void run() {
892
893                window.close();
894                cancel();
895            }
896        }, resource);
897        m_macroDialog.displayResourceInfo(Collections.singletonList(resource));
898        window.setContent(m_macroDialog);
899        UI.getCurrent().addWindow(window);
900    }
901
902    /**
903     * Updates the default dialog actions.<p>
904     *
905     * @param targetRootPath the target root path
906     */
907    private void updateDefaultActions(String targetRootPath) {
908
909        if (m_actionCombo != null) {
910            m_defaultActions.clear();
911            String resPath = m_context.getResources().get(0).getRootPath();
912            String parentFolder = CmsResource.getParentFolder(resPath);
913            if ((DialogMode.copy_and_move == m_dialogMode) && !parentFolder.equals(targetRootPath)) {
914                m_defaultActions.clear();
915                m_defaultActions.add(Action.move);
916            } else if (m_context.getResources().size() == 1) {
917                if (m_context.getResources().get(0).isFile()) {
918                    m_defaultActions.add(Action.copy_all);
919                } else {
920                    m_defaultActions.add(Action.copy_sibling_mixed);
921                    if (m_hasContainerPageDefaultFile) {
922                        m_defaultActions.clear();
923                        m_defaultActions.add(Action.container_page_automatic);
924                        m_defaultActions.add(Action.container_page_copy);
925                        m_defaultActions.add(Action.container_page_reuse);
926                    }
927                    CmsResource folder = m_context.getResources().get(0);
928                    if (CmsResourceTypeFolderSubSitemap.isSubSitemap(folder)) {
929                        m_defaultActions.clear();
930                        m_defaultActions.add(Action.sub_sitemap);
931                    }
932                }
933            } else {
934                m_defaultActions.add(Action.copy_sibling_mixed);
935            }
936            if (!m_defaultActions.isEmpty()) {
937                m_actionCombo.setValue(m_defaultActions.get(0));
938            }
939            m_actionCombo.markAsDirty();
940        }
941    }
942}