001/*
002 * This library is part of OpenCms -
003 * the Open Source Content Management System
004 *
005 * Copyright (c) Alkacon Software GmbH & Co. KG (http://www.alkacon.com)
006 *
007 * This library is free software; you can redistribute it and/or
008 * modify it under the terms of the GNU Lesser General Public
009 * License as published by the Free Software Foundation; either
010 * version 2.1 of the License, or (at your option) any later version.
011 *
012 * This library is distributed in the hope that it will be useful,
013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015 * Lesser General Public License for more details.
016 *
017 * For further information about Alkacon Software, please see the
018 * company website: http://www.alkacon.com
019 *
020 * For further information about OpenCms, please see the
021 * project website: http://www.opencms.org
022 *
023 * You should have received a copy of the GNU Lesser General Public
024 * License along with this library; if not, write to the Free Software
025 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
026 */
027
028package org.opencms.ade.upload.client.ui;
029
030import org.opencms.ade.upload.client.I_CmsUploadContext;
031import org.opencms.ade.upload.client.Messages;
032import org.opencms.ade.upload.client.ui.css.I_CmsLayoutBundle;
033import org.opencms.ade.upload.client.ui.css.I_CmsLayoutBundle.I_CmsUploadCss;
034import org.opencms.gwt.client.CmsCoreProvider;
035import org.opencms.gwt.client.rpc.CmsRpcAction;
036import org.opencms.gwt.client.ui.CmsErrorDialog;
037import org.opencms.gwt.client.ui.CmsList;
038import org.opencms.gwt.client.ui.CmsListItem;
039import org.opencms.gwt.client.ui.CmsListItemWidget;
040import org.opencms.gwt.client.ui.CmsListItemWidget.Background;
041import org.opencms.gwt.client.ui.CmsLoadingAnimation;
042import org.opencms.gwt.client.ui.CmsNotification;
043import org.opencms.gwt.client.ui.CmsNotification.Type;
044import org.opencms.gwt.client.ui.CmsPopup;
045import org.opencms.gwt.client.ui.CmsPushButton;
046import org.opencms.gwt.client.ui.CmsScrollPanel;
047import org.opencms.gwt.client.ui.CmsToggleButton;
048import org.opencms.gwt.client.ui.FontOpenCms;
049import org.opencms.gwt.client.ui.I_CmsButton;
050import org.opencms.gwt.client.ui.I_CmsListItem;
051import org.opencms.gwt.client.ui.css.I_CmsConstantsBundle;
052import org.opencms.gwt.client.ui.input.CmsCheckBox;
053import org.opencms.gwt.client.ui.input.upload.CmsFileInfo;
054import org.opencms.gwt.client.ui.input.upload.CmsFileInput;
055import org.opencms.gwt.client.ui.input.upload.CmsUploadButton;
056import org.opencms.gwt.client.ui.input.upload.CmsUploadProgressInfo;
057import org.opencms.gwt.client.ui.input.upload.CmsUploader;
058import org.opencms.gwt.client.ui.input.upload.I_CmsUploadButton;
059import org.opencms.gwt.client.ui.input.upload.I_CmsUploadDialog;
060import org.opencms.gwt.client.util.CmsChangeHeightAnimation;
061import org.opencms.gwt.client.util.CmsDomUtil;
062import org.opencms.gwt.shared.CmsListInfoBean;
063import org.opencms.gwt.shared.CmsUploadFileBean;
064import org.opencms.gwt.shared.CmsUploadProgessInfo;
065import org.opencms.gwt.shared.CmsUploadRestrictionInfo;
066import org.opencms.gwt.shared.I_CmsUploadConstants;
067import org.opencms.gwt.shared.rpc.I_CmsUploadService;
068import org.opencms.gwt.shared.rpc.I_CmsUploadServiceAsync;
069import org.opencms.util.CmsStringUtil;
070
071import java.util.ArrayList;
072import java.util.Arrays;
073import java.util.Collections;
074import java.util.HashMap;
075import java.util.HashSet;
076import java.util.List;
077import java.util.Map;
078import java.util.Set;
079
080import com.google.common.base.Supplier;
081import com.google.gwt.core.client.GWT;
082import com.google.gwt.core.client.Scheduler;
083import com.google.gwt.core.client.Scheduler.ScheduledCommand;
084import com.google.gwt.dom.client.Style.Display;
085import com.google.gwt.dom.client.Style.Unit;
086import com.google.gwt.event.dom.client.ClickEvent;
087import com.google.gwt.event.dom.client.ClickHandler;
088import com.google.gwt.event.logical.shared.CloseEvent;
089import com.google.gwt.event.logical.shared.CloseHandler;
090import com.google.gwt.event.shared.HandlerRegistration;
091import com.google.gwt.json.client.JSONArray;
092import com.google.gwt.json.client.JSONObject;
093import com.google.gwt.json.client.JSONParser;
094import com.google.gwt.json.client.JSONString;
095import com.google.gwt.json.client.JSONValue;
096import com.google.gwt.user.client.Command;
097import com.google.gwt.user.client.Timer;
098import com.google.gwt.user.client.rpc.ServiceDefTarget;
099import com.google.gwt.user.client.ui.FlowPanel;
100import com.google.gwt.user.client.ui.FormPanel;
101import com.google.gwt.user.client.ui.HTML;
102import com.google.gwt.user.client.ui.PopupPanel;
103import com.google.gwt.user.client.ui.UIObject;
104import com.google.gwt.user.client.ui.Widget;
105
106/**
107 * Provides an upload dialog.<p>
108 *
109 * @since 8.0.0
110 */
111public abstract class A_CmsUploadDialog extends CmsPopup implements I_CmsUploadDialog {
112
113    /** The minimal height of the content wrapper. */
114    private static final int MIN_CONTENT_HEIGHT = 110;
115
116    /** Text metrics key. */
117    private static final String TM_FILE_UPLOAD_LIST = "FileUploadList";
118
119    /** The interval for updating the progress information in milliseconds. */
120    private static final int UPDATE_PROGRESS_INTERVALL = 1000;
121
122    /** The upload context. */
123    protected I_CmsUploadContext m_context;
124
125    /** The drag and drop message. */
126    protected HTML m_dragAndDropMessage;
127
128    /** The scroll panel. */
129    protected CmsScrollPanel m_scrollPanel;
130
131    /** The uploaded file names. */
132    protected List<String> m_uploadedFiles;
133
134    /** Signals that the upload dialog was canceled. */
135    boolean m_canceled;
136
137    /** True if the target folder is given as a root path. */
138    boolean m_isTargetRootPath;
139
140    /** Stores all files that were added. */
141    private Map<String, CmsFileInfo> m_allFiles;
142
143    /** Signals that the client currently loading. */
144    private boolean m_clientLoading;
145
146    /** The close handler. */
147    private CloseHandler<PopupPanel> m_closeHandler;
148
149    /** The sum of all file sizes. */
150    private long m_contentLength;
151
152    /** A flow panel with a dynamic height. */
153    private FlowPanel m_contentWrapper;
154
155    /** The user information text widget. */
156    private HTML m_dialogInfo;
157
158    /** The list of file item widgets. */
159    private CmsList<I_CmsListItem> m_fileList;
160
161    /** The list of filenames that should be unziped on the server. */
162    private List<String> m_filesToUnzip;
163
164    /** The Map of files to upload. */
165    private Map<String, CmsFileInfo> m_filesToUpload;
166
167    /** Stores the content height of the selection dialog. */
168    private int m_firstContentHeight;
169
170    /** Stores the height of the user information text widget of the selection dialog. */
171    private int m_firstInfoHeight;
172
173    /** Stores the height of the summary. */
174    private int m_firstSummaryHeight;
175
176    /** A local reference to the default gwt CSS. */
177    private org.opencms.gwt.client.ui.css.I_CmsLayoutBundle m_gwtCss = org.opencms.gwt.client.ui.css.I_CmsLayoutBundle.INSTANCE;
178
179    /** The close handler registration. */
180    private HandlerRegistration m_handlerReg;
181
182    /** Stores the list items of all added files. */
183    private Map<String, CmsListItem> m_listItems;
184
185    /** A panel for showing client loading. */
186    private FlowPanel m_loadingPanel;
187
188    /** A timer to delay the loading animation. */
189    private Timer m_loadingTimer;
190
191    /** The main panel. */
192    private FlowPanel m_mainPanel;
193
194    /** The OK button. */
195    private CmsPushButton m_okButton;
196
197    /** The post-create handler. */
198    private String m_postCreateHandler;
199
200    /** The progress bar for the upload process. */
201    private CmsUploadProgressInfo m_progressInfo;
202
203    /** The names of restricted upload files. */
204    private Set<String> m_restricted = new HashSet<>();
205
206    /** Signals whether the selection is done or not. */
207    private boolean m_selectionDone;
208
209    /** The user information text widget. */
210    private HTML m_selectionSummary;
211
212    /** The target folder to upload the selected files. */
213    private String m_targetFolder;
214
215    /** The timer for updating the progress. */
216    private Timer m_updateProgressTimer = new Timer() {
217
218        /**
219         * @see com.google.gwt.user.client.Timer#run()
220         */
221        @Override
222        public void run() {
223
224            updateProgress();
225        }
226    };
227
228    /** The upload button of this dialog. */
229    private I_CmsUploadButton m_uploadButton;
230
231    /** The upload service instance. */
232    private I_CmsUploadServiceAsync m_uploadService;
233
234    /**
235     * Default constructor.<p>
236     */
237    public A_CmsUploadDialog() {
238
239        super(Messages.get().key(Messages.GUI_UPLOAD_DIALOG_TITLE_1));
240
241        I_CmsLayoutBundle.INSTANCE.uploadCss().ensureInjected();
242        setModal(true);
243        setGlassEnabled(true);
244        catchNotifications();
245        setWidth(CmsPopup.DEFAULT_WIDTH);
246
247        // create a map that stores all files (upload, existing, invalid)
248        m_allFiles = new HashMap<String, CmsFileInfo>();
249        // create a map the holds all the list items for the selection dialog
250        m_listItems = new HashMap<String, CmsListItem>();
251        m_filesToUnzip = new ArrayList<String>();
252        m_fileList = new CmsList<I_CmsListItem>();
253        m_fileList.truncate(TM_FILE_UPLOAD_LIST, CmsPopup.DEFAULT_WIDTH - 50);
254
255        // initialize a map that stores all the files that should be uploaded
256        m_filesToUpload = new HashMap<String, CmsFileInfo>();
257
258        // create the main panel
259        m_mainPanel = new FlowPanel();
260
261        // add the user info to the main panel
262        m_dialogInfo = new HTML();
263        m_dialogInfo.addStyleName(I_CmsLayoutBundle.INSTANCE.uploadCss().dialogInfo());
264        m_mainPanel.add(m_dialogInfo);
265        m_scrollPanel = GWT.create(CmsScrollPanel.class);
266        m_scrollPanel.getElement().getStyle().setPropertyPx("minHeight", MIN_CONTENT_HEIGHT);
267        m_scrollPanel.addStyleName(I_CmsLayoutBundle.INSTANCE.uploadCss().mainContentWidget());
268        m_scrollPanel.addStyleName(m_gwtCss.generalCss().cornerAll());
269        m_mainPanel.add(m_scrollPanel);
270        // add the content wrapper
271        m_contentWrapper = new FlowPanel();
272        m_contentWrapper.add(m_fileList);
273        m_scrollPanel.add(m_contentWrapper);
274
275        m_selectionSummary = new HTML();
276        m_selectionSummary.addStyleName(I_CmsLayoutBundle.INSTANCE.uploadCss().summary());
277        m_mainPanel.add(m_selectionSummary);
278
279        // set the main panel as content of the popup
280        setMainContent(m_mainPanel);
281
282        addCloseHandler(new CloseHandler<PopupPanel>() {
283
284            /**
285             * @see com.google.gwt.event.logical.shared.CloseHandler#onClose(com.google.gwt.event.logical.shared.CloseEvent)
286             */
287            public void onClose(CloseEvent<PopupPanel> e) {
288
289                if (m_context != null) {
290                    m_context.onUploadFinished(m_uploadedFiles);
291                }
292            }
293        });
294
295        // create and add the "OK", "Cancel" and upload button
296        createButtons();
297    }
298
299    /**
300     * @see org.opencms.gwt.client.ui.CmsPopup#addCloseHandler(com.google.gwt.event.logical.shared.CloseHandler)
301     */
302    @Override
303    public HandlerRegistration addCloseHandler(CloseHandler<PopupPanel> handler) {
304
305        m_closeHandler = handler;
306        m_handlerReg = super.addCloseHandler(handler);
307        return m_handlerReg;
308    }
309
310    /**
311     * Creates a bean that can be used for the list item widget.<p>
312     *
313     * @param file the info to create the bean for
314     *
315     * @return a list info bean
316     */
317    public abstract CmsListInfoBean createInfoBean(CmsFileInfo file);
318
319    /**
320     * Returns the massage for too large files.<p>
321     *
322     * @param file the file
323     *
324     * @return the message
325     */
326    public abstract String getFileSizeTooLargeMessage(CmsFileInfo file);
327
328    /**
329     * Returns <code>true</code> if the file is too large, <code>false</code> otherwise.<p>
330     *
331     * @param cmsFileInfo the file to check
332     *
333     * @return <code>true</code> if the file is too large, <code>false</code> otherwise
334     */
335    public abstract boolean isTooLarge(CmsFileInfo cmsFileInfo);
336
337    /**
338     * Loads and shows this dialog.<p>
339     */
340    public void loadAndShow() {
341
342        // enable or disable the OK button
343        if (getFilesToUpload().isEmpty()) {
344            disableOKButton(Messages.get().key(Messages.GUI_UPLOAD_NOTIFICATION_NO_FILES_0));
345            setDragAndDropMessage();
346        } else {
347            enableOKButton();
348            removeDragAndDropMessage();
349        }
350        m_uploadedFiles = null;
351        // set the user info
352        displayDialogInfo(Messages.get().key(Messages.GUI_UPLOAD_INFO_SELECTION_0), false);
353        // set the selection summary
354        updateSummary();
355
356        // add a upload button
357        m_uploadButton.createFileInput();
358
359        // show the popup
360        if (!isShowing()) {
361            Scheduler.get().scheduleDeferred(new ScheduledCommand() {
362
363                /**
364                 * @see com.google.gwt.core.client.Scheduler.ScheduledCommand#execute()
365                 */
366                public void execute() {
367
368                    setContentWrapperHeight();
369                    center();
370                }
371            });
372        }
373        center();
374    }
375
376    /**
377     * Parses the upload response of the server and decides what to do.<p>
378     *
379     * @param results a JSON Object
380     */
381    public void parseResponse(String results) {
382
383        cancelUpdateProgress();
384        stopLoadingAnimation();
385
386        if ((!m_canceled) && CmsStringUtil.isNotEmptyOrWhitespaceOnly(results)) {
387            JSONObject jsonObject = JSONParser.parseStrict(results).isObject();
388            boolean success = jsonObject.get(I_CmsUploadConstants.KEY_SUCCESS).isBoolean().booleanValue();
389            // If the upload is done so fast that we did not receive any progress information, then
390            // the content length is unknown. For that reason take the request size to show how
391            // much bytes were uploaded.
392            double size = jsonObject.get(I_CmsUploadConstants.KEY_REQUEST_SIZE).isNumber().doubleValue();
393            long requestSize = Double.valueOf(size).longValue();
394            if (m_contentLength == 0) {
395                m_contentLength = requestSize;
396            }
397            if (success) {
398                m_uploadedFiles = new ArrayList<String>();
399                List<String> uploadedFileIds = new ArrayList<String>();
400                displayDialogInfo(
401                    org.opencms.gwt.client.Messages.get().key(
402                        org.opencms.gwt.client.Messages.GUI_UPLOAD_INFO_FINISHING_0),
403                    false);
404                JSONValue uploadedFilesVal = jsonObject.get(I_CmsUploadConstants.KEY_UPLOADED_FILE_NAMES);
405                JSONValue uploadHook = jsonObject.get(I_CmsUploadConstants.KEY_UPLOAD_HOOK);
406                String hookUri = null;
407                if ((uploadHook != null) && (uploadHook.isString() != null)) {
408                    hookUri = uploadHook.isString().stringValue();
409                    JSONValue uploadedFileIdsVal = jsonObject.get(I_CmsUploadConstants.KEY_UPLOADED_FILES);
410                    JSONArray uploadedFileIdsArray = uploadedFileIdsVal.isArray();
411                    if (uploadedFileIdsArray != null) {
412                        for (int i = 0; i < uploadedFileIdsArray.size(); i++) {
413                            JSONString entry = uploadedFileIdsArray.get(i).isString();
414                            if (entry != null) {
415                                uploadedFileIds.add(entry.stringValue());
416                            }
417                        }
418                    }
419                }
420                JSONArray uploadedFilesArray = uploadedFilesVal.isArray();
421                if (uploadedFilesArray != null) {
422                    for (int i = 0; i < uploadedFilesArray.size(); i++) {
423                        JSONString entry = uploadedFilesArray.get(i).isString();
424                        if (entry != null) {
425                            m_uploadedFiles.add(entry.stringValue());
426                        }
427                    }
428                }
429                m_progressInfo.finish();
430                final I_CmsUploadContext context = m_context;
431                closeOnSuccess();
432                if (hookUri != null) {
433                    // Set the context to be null so that it isn't called when the upload dialog closed;
434                    // we want it to be called when the upload property dialog is closed instead.<p>
435                    m_context = null;
436                    CloseHandler<PopupPanel> closeHandler;
437                    closeHandler = new CloseHandler<PopupPanel>() {
438
439                        public void onClose(CloseEvent<PopupPanel> event) {
440
441                            if (context != null) {
442                                context.onUploadFinished(m_uploadedFiles);
443                            }
444                        }
445                    };
446
447                    String title = Messages.get().key(Messages.GUI_UPLOAD_HOOK_DIALOG_TITLE_0);
448                    CmsUploadHookDialog.openDialog(title, hookUri, uploadedFileIds, closeHandler);
449                }
450            } else {
451                String message = jsonObject.get(I_CmsUploadConstants.KEY_MESSAGE).isString().stringValue();
452                String stacktrace = jsonObject.get(I_CmsUploadConstants.KEY_STACKTRACE).isString().stringValue();
453                showErrorReport(message, stacktrace);
454            }
455        }
456    }
457
458    /**
459     * Sets the upload context.<p>
460     *
461     * @param context the new upload context
462     */
463    public void setContext(I_CmsUploadContext context) {
464
465        m_context = context;
466    }
467
468    /**
469     * Sets the boolean flag to control whether the target folder is interpreted as a root path.<p>
470     *
471     * @param isTargetRootPath true if the target folder should be treated as a root path
472     */
473    public void setIsTargetRootPath(boolean isTargetRootPath) {
474
475        m_isTargetRootPath = isTargetRootPath;
476    }
477
478    /**
479     * Sets the post-create handler.
480     *
481     * @param postCreateHandler the post-create handler
482     */
483    public void setPostCreateHandler(String postCreateHandler) {
484
485        m_postCreateHandler = postCreateHandler;
486    }
487
488    /**
489     * Sets the target folder.<p>
490     *
491     * @param target the target folder to set
492     */
493    public void setTargetFolder(String target) {
494
495        m_targetFolder = target;
496        setCaption(Messages.get().key(Messages.GUI_UPLOAD_DIALOG_TITLE_1, m_targetFolder));
497    }
498
499    /**
500     * Shows the error report.<p>
501     *
502     * @param message the message to show
503     * @param stacktrace the stacktrace to show
504     */
505    public void showErrorReport(final String message, final String stacktrace) {
506
507        if (!m_canceled) {
508            CmsErrorDialog errDialog = new CmsErrorDialog(message, stacktrace);
509            if (m_handlerReg != null) {
510                m_handlerReg.removeHandler();
511            }
512            if (m_closeHandler != null) {
513                errDialog.addCloseHandler(m_closeHandler);
514            }
515            hide();
516            errDialog.center();
517        }
518    }
519
520    /**
521     * Executes the submit action.<p>
522     */
523    public void submit() {
524
525        // create a JsArray containing the files to upload
526        List<CmsFileInfo> filesToUpload = new ArrayList<CmsFileInfo>(getFilesToUpload().values());
527        Collections.sort(filesToUpload, CmsFileInfo.INFO_COMPARATOR);
528
529        CmsUploader uploader = new CmsUploader();
530        uploader.uploadFiles(
531            getUploadUri(),
532            getTargetFolder(),
533            m_isTargetRootPath,
534            getPostCreateHandler(),
535            filesToUpload,
536            getFilesToUnzip(false),
537            false,
538            this);
539    }
540
541    /**
542     * Updates the button handler.
543     */
544    public void updateHandler() {
545
546        CmsDialogUploadButtonHandler handler = new CmsDialogUploadButtonHandler(
547            () -> m_context,
548            m_targetFolder,
549            m_isTargetRootPath);
550        handler.setUploadDialog(this);
551        m_uploadButton.reinitButton(handler);
552    }
553
554    /**
555     * Updates the file summary.<p>
556     */
557    public abstract void updateSummary();
558
559    /**
560     * Adds the given file input field to this dialog.<p>
561     *
562     * @param fileInput the file input field to add
563     */
564    protected void addFileInput(CmsFileInput fileInput) {
565
566        // add the files selected by the user to the list of files to upload
567        if (fileInput != null) {
568            addFiles(Arrays.asList(fileInput.getFiles()));
569        } else {
570            loadAndShow();
571        }
572    }
573
574    /**
575     * Adds the given file input field to this dialog.<p>
576     *
577     * @param fileInfos the file info objects
578     */
579    protected void addFiles(List<CmsFileInfo> fileInfos) {
580
581        if (fileInfos != null) {
582            for (CmsFileInfo file : fileInfos) {
583
584                // store all files
585                m_allFiles.put(file.getFileName(), file);
586                CmsUploadRestrictionInfo restriction = CmsCoreProvider.get().getUploadRestriction();
587
588                String targetRootPath = getTargetRootPath();
589                boolean restricted = !restriction.isUploadEnabled(targetRootPath)
590                    || !restriction.checkTypeAllowed(targetRootPath, file.getFileSuffix());
591                if (restricted) {
592                    m_restricted.add(file.getFileName());
593                }
594
595                // add those files to the list of files to upload that potential candidates
596                if (!isTooLarge(file) && (file.getFileSize() != 0) && !restricted) {
597                    m_filesToUpload.put(file.getFileName(), file);
598                }
599
600                // remove those files from the list to upload that were previously unchecked by the user
601                if ((m_listItems.get(file.getFileName()) != null)
602                    && (m_listItems.get(file.getFileName()).getCheckBox() != null)
603                    && !m_listItems.get(file.getFileName()).getCheckBox().isChecked()) {
604                    m_filesToUpload.remove(file.getFileName());
605                }
606            }
607
608            // now rebuild the list: handle all files
609            m_fileList.clearList();
610            List<String> sortedFileNames = new ArrayList<String>(m_allFiles.keySet());
611            Collections.sort(sortedFileNames, String.CASE_INSENSITIVE_ORDER);
612            for (String filename : sortedFileNames) {
613                CmsFileInfo file = m_allFiles.get(filename);
614                addFileToList(file, false, false, isTooLarge(file), m_restricted.contains(file.getFileName()));
615            }
616            doResize();
617        }
618        loadAndShow();
619    }
620
621    /**
622     * Cancels the upload progress timer.<p>
623     */
624    protected void cancelUpdateProgress() {
625
626        m_updateProgressTimer.cancel();
627    }
628
629    /**
630     * Cancels the upload.<p>
631     */
632    protected void cancelUpload() {
633
634        m_canceled = true;
635        cancelUpdateProgress();
636
637        CmsRpcAction<Boolean> callback = new CmsRpcAction<Boolean>() {
638
639            /**
640             * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
641             */
642            @Override
643            public void execute() {
644
645                getUploadService().cancelUpload(this);
646            }
647
648            /**
649             * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
650             */
651            @Override
652            protected void onResponse(Boolean result) {
653
654                hide();
655            }
656        };
657        callback.execute();
658    }
659
660    /**
661     * Creates the loading animation HTML and adds is to the content wrapper.<p>
662     *
663     * @param msg the message to display below the animation
664     */
665    protected void createLoadingAnimation(String msg) {
666
667        m_clientLoading = true;
668        if (m_loadingPanel != null) {
669            m_loadingPanel.removeFromParent();
670        }
671        m_loadingPanel = new FlowPanel();
672        m_loadingPanel.addStyleName(
673            org.opencms.gwt.client.ui.css.I_CmsLayoutBundle.INSTANCE.uploadButton().loadingPanel());
674        m_loadingPanel.addStyleName(m_gwtCss.generalCss().cornerAll());
675
676        CmsLoadingAnimation animationDiv = new CmsLoadingAnimation();
677        animationDiv.addStyleName(
678            org.opencms.gwt.client.ui.css.I_CmsLayoutBundle.INSTANCE.uploadButton().loadingAnimation());
679        m_loadingPanel.add(animationDiv);
680
681        HTML messageDiv = new HTML();
682        messageDiv.addStyleName(org.opencms.gwt.client.ui.css.I_CmsLayoutBundle.INSTANCE.uploadButton().loadingText());
683        messageDiv.setHTML(msg);
684        m_loadingPanel.add(messageDiv);
685
686        m_contentWrapper.add(m_loadingPanel);
687        doResize();
688    }
689
690    /**
691     * Disables the OK button.<p>
692     *
693     * @param disabledReason the reason for disabling the OK button
694     */
695    protected void disableOKButton(String disabledReason) {
696
697        m_okButton.disable(disabledReason);
698    }
699
700    /**
701     * Required to be called when the content has changed.<p>
702     */
703    protected void doResize() {
704
705        m_scrollPanel.onResizeDescendant();
706    }
707
708    /**
709     * Enables the OK button.<p>
710     */
711    protected void enableOKButton() {
712
713        m_okButton.enable();
714    }
715
716    /**
717     * Returns the contentLength.<p>
718     *
719     * @return the contentLength
720     */
721    protected long getContentLength() {
722
723        return m_contentLength;
724    }
725
726    /**
727     * Returns the contentWrapper.<p>
728     *
729     * @return the contentWrapper
730     */
731    protected FlowPanel getContentWrapper() {
732
733        return m_contentWrapper;
734    }
735
736    /**
737     * Returns the list of file names that have to unziped.<p>
738     *
739     * @param all <code>true</code> if the returned list should contain those filenames that
740     * are not inside the map of files to upload. <code>false</code> only those filenames are
741     * returned that are also inside the map of files to upload
742     *
743     * @return the list of file names that have to unziped
744     */
745    protected List<String> getFilesToUnzip(boolean all) {
746
747        if (!all) {
748            List<String> result = new ArrayList<String>();
749            for (String fileName : m_filesToUnzip) {
750                if (m_filesToUpload.keySet().contains(fileName)) {
751                    result.add(fileName);
752                }
753            }
754            return result;
755        }
756        return m_filesToUnzip;
757    }
758
759    /**
760     * Returns the filesToUpload.<p>
761     *
762     * @return the filesToUpload
763     */
764    protected Map<String, CmsFileInfo> getFilesToUpload() {
765
766        return m_filesToUpload;
767    }
768
769    /**
770     * Returns "files" or "file" depending on the files to upload.<p>
771     *
772     * @return "files" or "file" depending on the files to upload
773     */
774    protected String getFileText() {
775
776        if (m_filesToUpload.size() == 1) {
777            return org.opencms.gwt.client.Messages.get().key(
778                org.opencms.gwt.client.Messages.GUI_UPLOAD_FILES_SINGULAR_0);
779        }
780        return org.opencms.gwt.client.Messages.get().key(org.opencms.gwt.client.Messages.GUI_UPLOAD_FILES_PLURAL_0);
781    }
782
783    /**
784     * Gets the post-create handler.
785     *
786     * @return the post-create handler
787     */
788    protected String getPostCreateHandler() {
789
790        return m_postCreateHandler;
791    }
792
793    /**
794     * Returns the resource type name for a given filename.<p>
795     *
796     * @param file the file info
797     *
798     * @return the resource type name
799     */
800    protected String getResourceType(CmsFileInfo file) {
801
802        return CmsCoreProvider.get().getResourceType(file);
803    }
804
805    /**
806     * Returns the targetFolder.<p>
807     *
808     * @return the targetFolder
809     */
810    protected String getTargetFolder() {
811
812        return m_targetFolder;
813    }
814
815    /**
816     * Returns the upload service instance.<p>
817     *
818     * @return the upload service instance
819     */
820    protected I_CmsUploadServiceAsync getUploadService() {
821
822        if (m_uploadService == null) {
823            m_uploadService = GWT.create(I_CmsUploadService.class);
824            String serviceUrl = CmsCoreProvider.get().link("org.opencms.ade.upload.CmsUploadService.gwt");
825            ((ServiceDefTarget)m_uploadService).setServiceEntryPoint(serviceUrl);
826        }
827        return m_uploadService;
828    }
829
830    /**
831     * Returns the upload JSP uri.<p>
832     *
833     * @return the upload JSP uri
834     */
835    protected String getUploadUri() {
836
837        return CmsCoreProvider.get().link(I_CmsUploadConstants.UPLOAD_ACTION_JSP_URI);
838    }
839
840    /**
841     * Inserts a hidden form into.<p>
842     *
843     * @param form the form to insert
844     */
845    protected void insertUploadForm(FormPanel form) {
846
847        form.getElement().getStyle().setDisplay(Display.NONE);
848        m_contentWrapper.add(form);
849    }
850
851    /**
852     * The action that is executed if the user clicks on the OK button.<p>
853     *
854     * If the selection dialog is currently shown the selected files are checked
855     * otherwise the upload is triggered.<p>
856     */
857    protected void onOkClick() {
858
859        if (!m_selectionDone) {
860            checkSelection();
861        } else {
862            commit();
863        }
864    }
865
866    /**
867     * Required to be called when the content has changed.<p>
868     */
869    protected void onResize() {
870
871        m_scrollPanel.onResize();
872    }
873
874    /**
875     * Decides how to go on depending on the information of the server response.<p>
876     *
877     * Shows a warning if there is another upload process active (inside the same session).<p>
878     *
879     * Otherwise if the list of files to upload contains already existent resources on the VFS or if there
880     * are files selected that have invalid file names the overwrite dialog is shown.<p>
881     *
882     * Only if there is no other upload process running and none of the selected files
883     * is already existent on the VFS the upload is triggered.<p>
884     *
885     * @param result the bean that contains the information to evaluate
886     */
887    protected void proceedWorkflow(CmsUploadFileBean result) {
888
889        if (result.isActive()) {
890            m_okButton.enable();
891            CmsNotification.get().send(Type.WARNING, Messages.get().key(Messages.GUI_UPLOAD_NOTIFICATION_RUNNING_0));
892        } else {
893            if (!result.getExistingResourceNames().isEmpty()
894                || !result.getInvalidFileNames().isEmpty()
895                || !result.getExistingDeletedFileNames().isEmpty()) {
896                showOverwriteDialog(result);
897            } else {
898                commit();
899            }
900        }
901    }
902
903    /**
904     * Removes the drag and drop message.<p>
905     */
906    protected void removeDragAndDropMessage() {
907
908        if (m_dragAndDropMessage != null) {
909            m_dragAndDropMessage.removeFromParent();
910            m_dragAndDropMessage = null;
911            getContentWrapper().getElement().getStyle().clearBackgroundColor();
912        }
913    }
914
915    /**
916     * Sets the contentLength.<p>
917     *
918     * @param contentLength the contentLength to set
919     */
920    protected void setContentLength(long contentLength) {
921
922        m_contentLength = contentLength;
923    }
924
925    /**
926     * Execute to set the content wrapper height.<p>
927     */
928    protected void setContentWrapperHeight() {
929
930        // set the max height of the content panel
931        int fixedContent = 0;
932        if (m_dialogInfo.isVisible()) {
933            fixedContent += m_dialogInfo.getOffsetHeight();
934        }
935        if (m_selectionSummary.isVisible()) {
936            fixedContent += m_selectionSummary.getOffsetHeight();
937        }
938        m_scrollPanel.getElement().getStyle().setPropertyPx("maxHeight", getAvailableHeight(fixedContent));
939        doResize();
940    }
941
942    /**
943     * Displays the 'use drag and drop' / 'no drag and drop available' message.<p>
944     */
945    protected void setDragAndDropMessage() {
946
947        if (m_dragAndDropMessage == null) {
948            m_dragAndDropMessage = new HTML();
949            m_dragAndDropMessage.setStyleName(I_CmsLayoutBundle.INSTANCE.uploadCss().dragAndDropMessage());
950            m_dragAndDropMessage.setText(Messages.get().key(Messages.GUI_UPLOAD_DRAG_AND_DROP_DISABLED_0));
951        }
952        getContentWrapper().add(m_dragAndDropMessage);
953        getContentWrapper().getElement().getStyle().setBackgroundColor(
954            I_CmsConstantsBundle.INSTANCE.css().notificationErrorBg());
955        doResize();
956    }
957
958    /**
959     * Sets the HTML of the selection summary.<p>
960     *
961     * @param html the HTML to set as String
962     */
963    protected void setSummaryHTML(String html) {
964
965        m_selectionSummary.setHTML(html);
966    }
967
968    /**
969     * Retrieves the progress information from the server.<p>
970     */
971    protected void updateProgress() {
972
973        CmsRpcAction<CmsUploadProgessInfo> callback = new CmsRpcAction<CmsUploadProgessInfo>() {
974
975            /**
976             * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
977             */
978            @Override
979            public void execute() {
980
981                getUploadService().getUploadProgressInfo(this);
982            }
983
984            /**
985             * @see org.opencms.gwt.client.rpc.CmsRpcAction#onFailure(java.lang.Throwable)
986             */
987            @Override
988            public void onFailure(Throwable t) {
989
990                super.onFailure(t);
991                cancelUpdateProgress();
992            }
993
994            /**
995             * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
996             */
997            @Override
998            protected void onResponse(CmsUploadProgessInfo result) {
999
1000                updateProgressBar(result);
1001            }
1002        };
1003        callback.execute();
1004    }
1005
1006    /**
1007     * Updates the progress bar.<p>
1008     *
1009     * @param info the progress info
1010     */
1011    protected void updateProgressBar(CmsUploadProgessInfo info) {
1012
1013        switch (info.getState()) {
1014            case notStarted:
1015                break;
1016            case running:
1017                m_progressInfo.setProgress(info);
1018                stopLoadingAnimation();
1019                break;
1020            case finished:
1021                m_progressInfo.finish();
1022                displayDialogInfo(
1023                    org.opencms.gwt.client.Messages.get().key(
1024                        org.opencms.gwt.client.Messages.GUI_UPLOAD_INFO_FINISHING_0),
1025                    false);
1026                startLoadingAnimation(
1027                    org.opencms.gwt.client.Messages.get().key(
1028                        org.opencms.gwt.client.Messages.GUI_UPLOAD_INFO_CREATING_RESOURCES_0),
1029                    1500);
1030                break;
1031            default:
1032                break;
1033        }
1034    }
1035
1036    /**
1037     * Adds a click handler for the given check box.<p>
1038     *
1039     * @param check the check box
1040     * @param unzipWidget the un-zip check box
1041     * @param file the file
1042     */
1043    private void addClickHandlerToCheckBox(final CmsCheckBox check, final Widget unzipWidget, final CmsFileInfo file) {
1044
1045        check.addClickHandler(new ClickHandler() {
1046
1047            /**
1048             * @see com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event.dom.client.ClickEvent)
1049             */
1050            public void onClick(ClickEvent event) {
1051
1052                // add or remove the file from the list of files to upload
1053                if (check.isChecked()) {
1054                    getFilesToUpload().put(file.getFileName(), file);
1055                    if (unzipWidget != null) {
1056                        enableUnzip(unzipWidget);
1057                    }
1058                } else {
1059                    getFilesToUpload().remove(file.getFileName());
1060                    if (unzipWidget != null) {
1061                        disableUnzip(unzipWidget);
1062                    }
1063                }
1064
1065                // disable or enable the OK button
1066                if (getFilesToUpload().isEmpty()) {
1067                    disableOKButton(Messages.get().key(Messages.GUI_UPLOAD_NOTIFICATION_NO_FILES_0));
1068                } else {
1069                    enableOKButton();
1070                }
1071
1072                // update summary
1073                updateSummary();
1074
1075            }
1076
1077            /**
1078             * Disables the 'unzip' button
1079             *
1080             * @param unzip the unzip button
1081             */
1082            private void disableUnzip(Widget unzip) {
1083
1084                ((CmsToggleButton)unzip).setEnabled(false);
1085            }
1086
1087            /**
1088             * Enables the 'unzip' button
1089             *
1090             * @param unzip the unzip button
1091             */
1092            private void enableUnzip(Widget unzip) {
1093
1094                ((CmsToggleButton)unzip).setEnabled(true);
1095            }
1096        });
1097    }
1098
1099    /**
1100     * Adds a file to the list.<p>
1101     *
1102     * @param file the file to add
1103     * @param invalid signals if the filename is invalid
1104     * @param existingDeleted in case of existing files marked as deleted
1105     * @param isTooLarge signals if the file size limit is exceeded
1106     * @param forbiddenType true if the file has a forbidden type
1107     */
1108    private void addFileToList(
1109        final CmsFileInfo file,
1110        boolean invalid,
1111        boolean existingDeleted,
1112        boolean isTooLarge,
1113        boolean forbiddenType) {
1114
1115        CmsListInfoBean infoBean = createInfoBean(file);
1116        CmsListItemWidget listItemWidget = new CmsListItemWidget(infoBean);
1117        listItemWidget.setIcon(CmsCoreProvider.get().getResourceTypeIcon(file));
1118        CmsCheckBox check = new CmsCheckBox();
1119        check.setChecked(false);
1120        if (!invalid && !isTooLarge && !existingDeleted && !forbiddenType) {
1121            if (file.getFileSize() == 0) {
1122                check.setChecked(false);
1123            }
1124            check.setChecked(m_filesToUpload.containsKey(file.getFileName()));
1125            check.setTitle(file.getFileName());
1126            if (!m_selectionDone && file.getFileName().toLowerCase().endsWith(".zip")) {
1127                final Widget unzip = createUnzipCheckBox(file);
1128                addClickHandlerToCheckBox(check, unzip, file);
1129                listItemWidget.addButton(unzip);
1130            } else {
1131                addClickHandlerToCheckBox(check, null, file);
1132            }
1133        } else if (forbiddenType) {
1134            String message = Messages.get().key(Messages.GUI_UPLOAD_RESTRICTED_0);
1135            check.disable(message);
1136            listItemWidget.setBackground(Background.RED);
1137            listItemWidget.setSubtitleLabel(message);
1138        } else if (existingDeleted) {
1139            // is invalid
1140            String message = Messages.get().key(Messages.GUI_UPLOAD_FILE_EXISTING_DELETED_1, file.getFileName());
1141            check.disable(message);
1142            listItemWidget.setBackground(Background.RED);
1143            listItemWidget.setSubtitleLabel(message);
1144        } else if (isTooLarge) {
1145            String message = getFileSizeTooLargeMessage(file);
1146            check.disable(message);
1147            listItemWidget.setBackground(Background.RED);
1148            listItemWidget.setSubtitleLabel(message);
1149        } else {
1150            // is invalid
1151            String message = Messages.get().key(
1152                Messages.GUI_UPLOAD_FILE_INVALID_NAME_2,
1153                file.getFileName(),
1154                CmsUploadButton.formatBytes(file.getFileSize()));
1155            check.disable(message);
1156            listItemWidget.setBackground(Background.RED);
1157            listItemWidget.setSubtitleLabel(message);
1158        }
1159
1160        CmsListItem listItem = new CmsListItem(check, listItemWidget);
1161        m_fileList.addItem(listItem);
1162        m_listItems.put(file.getFileName(), listItem);
1163        doResize();
1164    }
1165
1166    /**
1167     * Changes the height of the content wrapper so that the dialog finally has the
1168     * same height that the dialog has when the min height is set on the selection screen.<p>
1169     */
1170    private void changeHeight() {
1171
1172        int firstHeight = MIN_CONTENT_HEIGHT + m_firstInfoHeight + m_firstSummaryHeight + 2;
1173        int currentHeight = CmsDomUtil.getCurrentStyleInt(m_mainPanel.getElement(), CmsDomUtil.Style.height);
1174        int targetHeight = firstHeight - m_dialogInfo.getOffsetHeight() - m_selectionSummary.getOffsetHeight();
1175        if (currentHeight > firstHeight) {
1176            CmsChangeHeightAnimation.change(m_scrollPanel.getElement(), targetHeight, new Command() {
1177
1178                public void execute() {
1179
1180                    doResize();
1181                }
1182            }, 750);
1183        }
1184    }
1185
1186    /**
1187     * Before the upload data is effectively submited we have to check
1188     * for already existent resources in the VFS.<p>
1189     *
1190     * Executes the RPC call that checks the VFS for existing resources.
1191     * Passes the response object to a method that evaluates the result.<p>
1192     */
1193    private void checkSelection() {
1194
1195        m_okButton.disable(Messages.get().key(Messages.GUI_UPLOAD_BUTTON_OK_DISABLE_CHECKING_0));
1196
1197        if (!m_selectionDone) {
1198            m_firstContentHeight = CmsDomUtil.getCurrentStyleInt(m_scrollPanel.getElement(), CmsDomUtil.Style.height);
1199            m_firstInfoHeight = m_dialogInfo.getOffsetHeight();
1200            m_firstSummaryHeight = m_selectionSummary.getOffsetHeight();
1201        }
1202
1203        CmsRpcAction<CmsUploadFileBean> callback = new CmsRpcAction<CmsUploadFileBean>() {
1204
1205            /**
1206             * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute()
1207             */
1208            @Override
1209            public void execute() {
1210
1211                List<String> filesToCheck = new ArrayList<String>(getFilesToUpload().keySet());
1212                filesToCheck.removeAll(getFilesToUnzip(false));
1213                getUploadService().checkUploadFiles(filesToCheck, getTargetFolder(), m_isTargetRootPath, this);
1214            }
1215
1216            /**
1217             * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object)
1218             */
1219            @Override
1220            protected void onResponse(CmsUploadFileBean result) {
1221
1222                proceedWorkflow(result);
1223            }
1224        };
1225        callback.execute();
1226    }
1227
1228    /**
1229     * Closes the dialog after a delay.<p>
1230     */
1231    private void closeOnSuccess() {
1232
1233        Timer closeTimer = new Timer() {
1234
1235            /**
1236             * @see com.google.gwt.user.client.Timer#run()
1237             */
1238            @Override
1239            public void run() {
1240
1241                A_CmsUploadDialog.this.hide();
1242            }
1243        };
1244        closeTimer.schedule(1500);
1245    }
1246
1247    /**
1248     * Calls the submit action if there are any files selected for upload.<p>
1249     */
1250    private void commit() {
1251
1252        m_selectionDone = true;
1253        if (!m_filesToUpload.isEmpty()) {
1254            m_okButton.disable(Messages.get().key(Messages.GUI_UPLOAD_BUTTON_OK_DISABLE_UPLOADING_0));
1255            if (m_uploadButton instanceof UIObject) {
1256                ((UIObject)m_uploadButton).getElement().getStyle().setDisplay(Display.NONE);
1257            }
1258            showProgress();
1259            submit();
1260        }
1261    }
1262
1263    /**
1264     * Creates the "OK", the "Cancel" and the "Upload" button.<p>
1265     */
1266    private void createButtons() {
1267
1268        addDialogClose(new Command() {
1269
1270            public void execute() {
1271
1272                cancelUpload();
1273            }
1274        });
1275
1276        CmsPushButton cancelButton = new CmsPushButton();
1277        cancelButton.setTitle(org.opencms.gwt.client.Messages.get().key(org.opencms.gwt.client.Messages.GUI_CANCEL_0));
1278        cancelButton.setText(org.opencms.gwt.client.Messages.get().key(org.opencms.gwt.client.Messages.GUI_CANCEL_0));
1279        cancelButton.setSize(I_CmsButton.Size.medium);
1280        cancelButton.setUseMinWidth(true);
1281        cancelButton.addClickHandler(new ClickHandler() {
1282
1283            /**
1284             * @see com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event.dom.client.ClickEvent)
1285             */
1286            public void onClick(ClickEvent event) {
1287
1288                cancelUpload();
1289            }
1290        });
1291        addButton(cancelButton);
1292
1293        m_okButton = new CmsPushButton();
1294        m_okButton.setTitle(org.opencms.gwt.client.Messages.get().key(org.opencms.gwt.client.Messages.GUI_OK_0));
1295        m_okButton.setText(org.opencms.gwt.client.Messages.get().key(org.opencms.gwt.client.Messages.GUI_OK_0));
1296        m_okButton.setSize(I_CmsButton.Size.medium);
1297        m_okButton.setUseMinWidth(true);
1298        m_okButton.addClickHandler(new ClickHandler() {
1299
1300            /**
1301             * @see com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event.dom.client.ClickEvent)
1302             */
1303            public void onClick(ClickEvent event) {
1304
1305                onOkClick();
1306            }
1307        });
1308        addButton(m_okButton);
1309
1310        CmsDialogUploadButtonHandler buttonHandler = new CmsDialogUploadButtonHandler(
1311            new Supplier<I_CmsUploadContext>() {
1312
1313                public I_CmsUploadContext get() {
1314
1315                    return m_context;
1316                }
1317            });
1318        buttonHandler.setUploadDialog(this);
1319        // add a new upload button
1320        CmsUploadButton uploadButton = new CmsUploadButton(buttonHandler);
1321        uploadButton.addStyleName(I_CmsLayoutBundle.INSTANCE.uploadCss().uploadDialogButton());
1322        uploadButton.setText(Messages.get().key(Messages.GUI_UPLOAD_BUTTON_ADD_FILES_0));
1323        addButton(uploadButton);
1324        m_uploadButton = uploadButton;
1325    }
1326
1327    /**
1328     * Creates the unzip checkbox.<p>
1329     *
1330     * @param file the file to create the checkbox for
1331     *
1332     * @return the unzip checkbox
1333     */
1334    private Widget createUnzipCheckBox(final CmsFileInfo file) {
1335
1336        final CmsToggleButton unzip = new CmsToggleButton();
1337        I_CmsUploadCss uploadCss = I_CmsLayoutBundle.INSTANCE.uploadCss();
1338        String caption = Messages.get().key(Messages.GUI_UNZIP_BUTTON_TEXT_0);
1339        unzip.setUpFace(caption, uploadCss.unzipButtonUpFace());
1340        unzip.setDownFace(caption, uploadCss.unzipButtonDownFace());
1341        unzip.addStyleName(uploadCss.unzipButton());
1342        unzip.addStyleName(org.opencms.gwt.client.ui.css.I_CmsLayoutBundle.INSTANCE.listItemWidgetCss().permaVisible());
1343        unzip.setDown(getFilesToUnzip(true).contains(file.getFileName()));
1344        if (!m_filesToUpload.containsKey(file.getFileName())) {
1345            unzip.disable(Messages.get().key(Messages.GUI_UPLOAD_FILE_NOT_SELECTED_0));
1346        }
1347        unzip.addClickHandler(new ClickHandler() {
1348
1349            /**
1350             * @see com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event.dom.client.ClickEvent)
1351             */
1352            public void onClick(ClickEvent event) {
1353
1354                // add or remove the file from the list of files to upload
1355                if (unzip.isDown()) {
1356                    getFilesToUnzip(true).add(file.getFileName());
1357                } else {
1358                    getFilesToUnzip(true).remove(file.getFileName());
1359                }
1360            }
1361        });
1362        return unzip;
1363    }
1364
1365    /**
1366     * Sets the user info.<p>
1367     *
1368     * @param msg the message to display
1369     * @param warning signals whether the message should be a warning or nor
1370     */
1371    private void displayDialogInfo(String msg, boolean warning) {
1372
1373        StringBuffer buffer = new StringBuffer(64);
1374        if (!warning) {
1375            buffer.append("<p class=\"");
1376            buffer.append(org.opencms.gwt.client.ui.css.I_CmsLayoutBundle.INSTANCE.uploadButton().dialogMessage());
1377            buffer.append("\">");
1378            buffer.append(msg);
1379            buffer.append("</p>");
1380        } else {
1381            buffer.append(FontOpenCms.WARNING.getHtml(32, I_CmsConstantsBundle.INSTANCE.css().colorWarning()));
1382            buffer.append("<p class=\"");
1383            buffer.append(org.opencms.gwt.client.ui.css.I_CmsLayoutBundle.INSTANCE.uploadButton().warningMessage());
1384            buffer.append("\">");
1385            buffer.append(msg);
1386            buffer.append("</p>");
1387        }
1388        m_dialogInfo.setHTML(buffer.toString());
1389    }
1390
1391    /**
1392     * Gets the target root path.
1393     *
1394     * @return the target root path
1395     */
1396    private String getTargetRootPath() {
1397
1398        if (m_isTargetRootPath) {
1399            return m_targetFolder;
1400        } else {
1401            return CmsCoreProvider.get().addSiteRoot(m_targetFolder);
1402        }
1403    }
1404
1405    /**
1406     * Removes all widgets from the content wrapper.<p>
1407     */
1408    private void removeContent() {
1409
1410        m_contentWrapper.clear();
1411        doResize();
1412    }
1413
1414    /**
1415     * Sets the height for the content so that the dialog finally has the same height
1416     * as the dialog has on the selection screen.<p>
1417     */
1418    private void setHeight() {
1419
1420        int infoDiff = m_firstInfoHeight - m_dialogInfo.getOffsetHeight();
1421        int summaryDiff = m_firstSummaryHeight - m_selectionSummary.getOffsetHeight();
1422        int height = m_firstContentHeight + infoDiff + summaryDiff;
1423        m_scrollPanel.getElement().getStyle().setHeight(height, Unit.PX);
1424        m_scrollPanel.getElement().getStyle().clearProperty("minHeight");
1425        m_scrollPanel.getElement().getStyle().clearProperty("maxHeight");
1426        doResize();
1427    }
1428
1429    /**
1430     * Shows the overwrite dialog.<p>
1431     *
1432     * @param infoBean the info bean containing the existing and invalid file names
1433     */
1434    private void showOverwriteDialog(CmsUploadFileBean infoBean) {
1435
1436        // update the dialog
1437        m_selectionDone = true;
1438        m_okButton.enable();
1439        if (infoBean.getInvalidFileNames().isEmpty() && infoBean.getExistingDeletedFileNames().isEmpty()) {
1440            displayDialogInfo(Messages.get().key(Messages.GUI_UPLOAD_INFO_OVERWRITE_0), true);
1441        } else {
1442            displayDialogInfo(Messages.get().key(Messages.GUI_UPLOAD_INFO_INVALID_0), true);
1443        }
1444        if (m_uploadButton instanceof UIObject) {
1445            ((UIObject)m_uploadButton).getElement().getStyle().setDisplay(Display.NONE);
1446        }
1447        // clear the list
1448        m_fileList.clearList();
1449
1450        // handle existing files
1451        List<String> existings = new ArrayList<String>(infoBean.getExistingResourceNames());
1452        Collections.sort(existings, String.CASE_INSENSITIVE_ORDER);
1453        for (String filename : existings) {
1454            addFileToList(m_filesToUpload.get(filename), false, false, false, false);
1455        }
1456
1457        // handle the invalid files
1458        List<String> invalids = new ArrayList<String>(infoBean.getInvalidFileNames());
1459        Collections.sort(invalids, String.CASE_INSENSITIVE_ORDER);
1460        for (String filename : invalids) {
1461            addFileToList(m_filesToUpload.get(filename), true, false, false, false);
1462            m_filesToUpload.remove(filename);
1463        }
1464
1465        // handle the invalid files
1466        List<String> existingDeleted = new ArrayList<String>(infoBean.getExistingDeletedFileNames());
1467        Collections.sort(existingDeleted, String.CASE_INSENSITIVE_ORDER);
1468        for (String filename : existingDeleted) {
1469            addFileToList(m_filesToUpload.get(filename), false, true, false, false);
1470            m_filesToUpload.remove(filename);
1471        }
1472
1473        // set the height of the content
1474        setHeight();
1475    }
1476
1477    /**
1478     * Starts the upload progress bar.<p>
1479     */
1480    private void showProgress() {
1481
1482        removeContent();
1483        displayDialogInfo(
1484            org.opencms.gwt.client.Messages.get().key(org.opencms.gwt.client.Messages.GUI_UPLOAD_INFO_UPLOADING_0),
1485            false);
1486        m_selectionSummary.removeFromParent();
1487        List<String> files = new ArrayList<String>(getFilesToUpload().keySet());
1488        Collections.sort(files, String.CASE_INSENSITIVE_ORDER);
1489        m_progressInfo = new CmsUploadProgressInfo(files);
1490        m_progressInfo.setContentLength(m_contentLength);
1491        m_contentWrapper.add(m_progressInfo);
1492        m_updateProgressTimer.scheduleRepeating(UPDATE_PROGRESS_INTERVALL);
1493        startLoadingAnimation(Messages.get().key(Messages.GUI_UPLOAD_CLIENT_LOADING_0), 0);
1494        setHeight();
1495        changeHeight();
1496    }
1497
1498    /**
1499     * Starts the loading animation.<p>
1500     *
1501     * Used while client is loading files from hard disk into memory.<p>
1502     *
1503     * @param msg the message that should be displayed below the loading animation (can also be HTML as String)
1504     * @param delayMillis the delay to start the animation with
1505     */
1506    private void startLoadingAnimation(final String msg, int delayMillis) {
1507
1508        m_loadingTimer = new Timer() {
1509
1510            @Override
1511            public void run() {
1512
1513                createLoadingAnimation(msg);
1514            }
1515        };
1516        if (delayMillis > 0) {
1517            m_loadingTimer.schedule(delayMillis);
1518        } else {
1519            m_loadingTimer.run();
1520        }
1521    }
1522
1523    /**
1524     * Stops the client loading animation.<p>
1525     */
1526    private void stopLoadingAnimation() {
1527
1528        if (m_loadingTimer != null) {
1529            m_loadingTimer.cancel();
1530        }
1531        if (m_clientLoading) {
1532            m_contentWrapper.remove(m_loadingPanel);
1533            doResize();
1534            m_clientLoading = false;
1535        }
1536    }
1537}