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