/* * This library is part of OpenCms - * the Open Source Content Management System * * Copyright (c) Alkacon Software GmbH (http://www.alkacon.com) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * For further information about Alkacon Software, please see the * company website: http://www.alkacon.com * * For further information about OpenCms, please see the * project website: http://www.opencms.org * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ package org.opencms.ade.upload.client.ui; import org.opencms.ade.upload.client.Messages; import org.opencms.ade.upload.client.ui.css.I_CmsLayoutBundle; import org.opencms.ade.upload.shared.CmsUploadData; import org.opencms.ade.upload.shared.CmsUploadFileBean; import org.opencms.ade.upload.shared.CmsUploadProgessInfo; import org.opencms.ade.upload.shared.I_CmsUploadConstants; import org.opencms.ade.upload.shared.rpc.I_CmsUploadService; import org.opencms.ade.upload.shared.rpc.I_CmsUploadServiceAsync; import org.opencms.gwt.client.CmsCoreProvider; import org.opencms.gwt.client.rpc.CmsRpcAction; import org.opencms.gwt.client.rpc.CmsRpcPrefetcher; import org.opencms.gwt.client.ui.CmsErrorDialog; import org.opencms.gwt.client.ui.CmsList; import org.opencms.gwt.client.ui.CmsListItem; import org.opencms.gwt.client.ui.CmsListItemWidget; import org.opencms.gwt.client.ui.CmsListItemWidget.Background; import org.opencms.gwt.client.ui.CmsNotification; import org.opencms.gwt.client.ui.CmsNotification.Type; import org.opencms.gwt.client.ui.CmsPopup; import org.opencms.gwt.client.ui.CmsProgressBar; import org.opencms.gwt.client.ui.CmsPushButton; import org.opencms.gwt.client.ui.I_CmsButton; import org.opencms.gwt.client.ui.I_CmsListItem; import org.opencms.gwt.client.ui.css.I_CmsConstantsBundle; import org.opencms.gwt.client.ui.input.CmsCheckBox; import org.opencms.gwt.client.ui.input.upload.CmsFileInfo; import org.opencms.gwt.client.ui.input.upload.CmsFileInput; import org.opencms.gwt.client.util.CmsChangeHeightAnimation; import org.opencms.gwt.client.util.CmsDomUtil; import org.opencms.gwt.shared.CmsIconUtil; import org.opencms.gwt.shared.CmsListInfoBean; import org.opencms.util.CmsStringUtil; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import com.google.gwt.core.client.GWT; import com.google.gwt.core.client.Scheduler; import com.google.gwt.core.client.Scheduler.ScheduledCommand; import com.google.gwt.dom.client.Style.Display; import com.google.gwt.dom.client.Style.Unit; import com.google.gwt.event.dom.client.ClickEvent; import com.google.gwt.event.dom.client.ClickHandler; import com.google.gwt.event.logical.shared.CloseHandler; import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.i18n.client.NumberFormat; import com.google.gwt.json.client.JSONObject; import com.google.gwt.json.client.JSONParser; import com.google.gwt.user.client.Command; import com.google.gwt.user.client.Timer; import com.google.gwt.user.client.rpc.ServiceDefTarget; import com.google.gwt.user.client.ui.FlexTable; import com.google.gwt.user.client.ui.FlowPanel; import com.google.gwt.user.client.ui.FormPanel; import com.google.gwt.user.client.ui.HTML; import com.google.gwt.user.client.ui.PopupPanel; /** * Provides an upload dialog.<p> * * @since 8.0.0 */ public abstract class A_CmsUploadDialog extends CmsPopup { /** * Provides the upload progress information.<p> * * Has a progressbar and a table for showing details.<p> */ private class CmsUploadProgressInfo extends FlowPanel { /** The progress bar. */ private CmsProgressBar m_bar; /** The table for showing upload details. */ private FlexTable m_fileinfo; /** A sorted list of the filenames to upload. */ private List<String> m_orderedFilenamesToUpload; /** Signals if the progress was set at least one time. */ private boolean m_started; /** * Default constructor.<p> */ public CmsUploadProgressInfo() { // get a ordered list of filenames m_orderedFilenamesToUpload = new ArrayList<String>(getFilesToUpload().keySet()); Collections.sort(m_orderedFilenamesToUpload, String.CASE_INSENSITIVE_ORDER); // create the progress bar m_bar = new CmsProgressBar(); // create the file info table m_fileinfo = new FlexTable(); m_fileinfo.addStyleName(I_CmsLayoutBundle.INSTANCE.uploadCss().fileInfoTable()); // arrange the progress info addStyleName(I_CmsLayoutBundle.INSTANCE.uploadCss().progressInfo()); add(m_bar); add(m_fileinfo); } /** * Finishes the state of the progress bar.<p> */ public void finish() { String length = formatBytes(getContentLength()); int fileCount = m_orderedFilenamesToUpload.size(); m_bar.setValue(100); m_fileinfo.removeAllRows(); m_fileinfo.setHTML(0, 0, "<b>" + Messages.get().key(Messages.GUI_UPLOAD_FINISH_UPLOADED_0) + "</b>"); m_fileinfo.setText(0, 1, Messages.get().key( Messages.GUI_UPLOAD_FINISH_UPLOADED_VALUE_4, new Integer(fileCount), new Integer(fileCount), getFileText(), length)); } /** * Sets the progress information.<p> * * @param info the progress info bean */ public void setProgress(CmsUploadProgessInfo info) { int currFile = info.getCurrentFile(); int currFileIndex = 0; if (currFile == 0) { // no files read so far } else { currFileIndex = currFile - 1; if (currFileIndex >= m_orderedFilenamesToUpload.size()) { currFileIndex = m_orderedFilenamesToUpload.size() - 1; } } if (getContentLength() == 0) { setContentLength(info.getContentLength()); } String currFilename = m_orderedFilenamesToUpload.get(currFileIndex); String contentLength = formatBytes(getContentLength()); int fileCount = m_orderedFilenamesToUpload.size(); String readBytes = formatBytes(getBytesRead(info.getPercent())); m_bar.setValue(info.getPercent()); if (!m_started) { m_started = true; m_fileinfo.setHTML(0, 0, "<b>" + Messages.get().key(Messages.GUI_UPLOAD_PROGRESS_CURRENT_FILE_0) + "</b>"); m_fileinfo.setHTML(1, 0, "<b>" + Messages.get().key(Messages.GUI_UPLOAD_PROGRESS_UPLOADING_0) + "</b>"); m_fileinfo.setHTML(2, 0, ""); m_fileinfo.setText(0, 1, ""); m_fileinfo.setText(1, 1, ""); m_fileinfo.setText(2, 1, ""); m_fileinfo.getColumnFormatter().setWidth(0, "100px"); } m_fileinfo.setText(0, 1, currFilename); m_fileinfo.setText(1, 1, Messages.get().key( Messages.GUI_UPLOAD_PROGRESS_CURRENT_VALUE_3, new Integer(currFileIndex + 1), new Integer(fileCount), getFileText())); m_fileinfo.setText(2, 1, Messages.get().key( Messages.GUI_UPLOAD_PROGRESS_UPLOADING_VALUE_2, readBytes, contentLength)); } /** * Returns the bytes that are read so far.<p> * * The total request size is larger than the sum of all file sizes that are uploaded. * Because boundaries and the target folder or even some other information than only * the plain file contents are submited to the server.<p> * * This method calculates the bytes that are read with the help of the file sizes.<p> * * @param percent the server side determined percentage * * @return the bytes that are read so far */ private long getBytesRead(long percent) { return percent != 0 ? (getContentLength() * percent) / 100 : 0; } } /** Maximum width for the file item widget list. */ private static final int DIALOG_WIDTH = 600; /** The size for kilobytes in bytes. */ private static final float KILOBYTE = 1024L; /** The minimal height of the content wrapper. */ private static final int MIN_CONTENT_HEIGHT = 110; /** Text metrics key. */ private static final String TM_FILE_UPLOAD_LIST = "FileUploadList"; /** The interval for updating the progress information in milliseconds. */ private static final int UPDATE_PROGRESS_INTERVALL = 1000; /** Stores all files that were added. */ private Map<String, CmsFileInfo> m_allFiles; /** Signals that the upload dialog was canceled. */ private boolean m_canceled; /** Signals that the client currently loading. */ private boolean m_clientLoading; /** The close handler. */ private CloseHandler<PopupPanel> m_closeHandler; /** The sum of all file sizes. */ private long m_contentLength; /** A flow panel with a dynamic height. */ private FlowPanel m_contentWrapper; /** The upload data. */ private CmsUploadData m_data; /** The user information text widget. */ private HTML m_dialogInfo; /** The drag and drop message. */ protected HTML m_dragAndDropMessage; /** The list of file item widgets. */ private CmsList<I_CmsListItem> m_fileList; /** The list of filenames that should be unziped on the server. */ private List<String> m_filesToUnzip; /** The Map of files to upload. */ private Map<String, CmsFileInfo> m_filesToUpload; /** Stores the content height of the selection dialog. */ private int m_firstContentHeight; /** Stores the height of the user information text widget of the selection dialog. */ private int m_firstInfoHeight; /** Stores the height of the summary. */ private int m_firstSummaryHeight; /** A local reference to the default gwt CSS. */ private org.opencms.gwt.client.ui.css.I_CmsLayoutBundle m_gwtCss = org.opencms.gwt.client.ui.css.I_CmsLayoutBundle.INSTANCE; /** The close handler registration. */ private HandlerRegistration m_handlerReg; /** Stores the list items of all added files. */ private Map<String, CmsListItem> m_listItems; /** A panel for showing client loading. */ private FlowPanel m_loadingPanel; /** A timer to delay the loading animation. */ private Timer m_loadingTimer; /** The main panel. */ private FlowPanel m_mainPanel; /** The OK button. */ private CmsPushButton m_okButton; /** The progress bar for the upload process. */ private CmsUploadProgressInfo m_progressInfo; /** Signals whether the selection is done or not. */ private boolean m_selectionDone; /** The user information text widget. */ private HTML m_selectionSummary; /** The target folder to upload the selected files. */ private String m_targetFolder; /** The timer for updating the progress. */ private Timer m_updateProgressTimer = new Timer() { /** * @see com.google.gwt.user.client.Timer#run() */ @Override public void run() { updateProgress(); } }; /** The upload button of this dialog. */ private CmsUploadButton m_uploadButton; /** The upload service instance. */ private I_CmsUploadServiceAsync m_uploadService; /** * Default constructor.<p> */ public A_CmsUploadDialog() { super(Messages.get().key(Messages.GUI_UPLOAD_DIALOG_TITLE_0)); I_CmsLayoutBundle.INSTANCE.uploadCss().ensureInjected(); m_data = (CmsUploadData)CmsRpcPrefetcher.getSerializedObject(getUploadService(), CmsUploadData.DICT_NAME); setModal(true); setGlassEnabled(true); catchNotifications(); setWidth(DIALOG_WIDTH); // create a map that stores all files (upload, existing, invalid) m_allFiles = new HashMap<String, CmsFileInfo>(); // create a map the holds all the list items for the selection dialog m_listItems = new HashMap<String, CmsListItem>(); m_filesToUnzip = new ArrayList<String>(); m_fileList = new CmsList<I_CmsListItem>(); m_fileList.truncate(TM_FILE_UPLOAD_LIST, DIALOG_WIDTH - 50); // initialize a map that stores all the files that should be uploaded m_filesToUpload = new HashMap<String, CmsFileInfo>(); // create the main panel m_mainPanel = new FlowPanel(); // add the user info to the main panel m_dialogInfo = new HTML(); m_dialogInfo.addStyleName(I_CmsLayoutBundle.INSTANCE.uploadCss().dialogInfo()); m_mainPanel.add(m_dialogInfo); // add the content wrapper to the main panel m_contentWrapper = new FlowPanel(); m_contentWrapper.addStyleName(I_CmsLayoutBundle.INSTANCE.uploadCss().mainContentWidget()); m_contentWrapper.addStyleName(m_gwtCss.generalCss().cornerAll()); m_contentWrapper.getElement().getStyle().setPropertyPx("minHeight", MIN_CONTENT_HEIGHT); m_contentWrapper.add(m_fileList); m_mainPanel.add(m_contentWrapper); m_selectionSummary = new HTML(); m_selectionSummary.addStyleName(I_CmsLayoutBundle.INSTANCE.uploadCss().summary()); m_mainPanel.add(m_selectionSummary); // set the main panel as content of the popup setMainContent(m_mainPanel); // create and add the "OK", "Cancel" and upload button createButtons(); } /** * @see org.opencms.gwt.client.ui.CmsPopup#addCloseHandler(com.google.gwt.event.logical.shared.CloseHandler) */ @Override public HandlerRegistration addCloseHandler(CloseHandler<PopupPanel> handler) { m_closeHandler = handler; m_handlerReg = super.addCloseHandler(handler); return m_handlerReg; } /** * Creates a bean that can be used for the list item widget.<p> * * @param file the info to create the bean for * * @return a list info bean */ public abstract CmsListInfoBean createInfoBean(CmsFileInfo file); /** * Returns the massage for too large files.<p> * * @param file the file * * @return the message */ public abstract String getFileSizeTooLargeMessage(CmsFileInfo file); /** * Returns <code>true</code> if the file is too large, <code>false</code> otherwise.<p> * * @param cmsFileInfo the file to check * * @return <code>true</code> if the file is too large, <code>false</code> otherwise */ public abstract boolean isTooLarge(CmsFileInfo cmsFileInfo); /** * Loads and shows this dialog.<p> */ public void loadAndShow() { // enable or disable the OK button if (getFilesToUpload().isEmpty()) { disableOKButton(Messages.get().key(Messages.GUI_UPLOAD_NOTIFICATION_NO_FILES_0)); setDragAndDropMessage(); } else { enableOKButton(); removeDragAndDropMessage(); } // set the user info displayDialogInfo(Messages.get().key(Messages.GUI_UPLOAD_INFO_SELECTION_0), false); // set the selection summary updateSummary(); // add a upload button m_uploadButton.createFileInput(); // show the popup if (!isShowing()) { Scheduler.get().scheduleDeferred(new ScheduledCommand() { /** * @see com.google.gwt.core.client.Scheduler.ScheduledCommand#execute() */ public void execute() { setContentWrapperHeight(); center(); } }); } center(); } /** * Sets the target folder.<p> * * @param target the target folder to set */ public void setTargetFolder(String target) { m_targetFolder = target; } /** * Executes the submit action.<p> */ public abstract void submit(); /** * Updates the file summary.<p> */ public abstract void updateSummary(); /** * Adds the given file input field to this dialog.<p> * * @param fileInput the file input field to add */ protected void addFileInput(CmsFileInput fileInput) { // add the files selected by the user to the list of files to upload if (fileInput != null) { addFiles(Arrays.asList(fileInput.getFiles())); } else { loadAndShow(); } } /** * Adds the given file input field to this dialog.<p> * * @param fileInfos the file info objects */ protected void addFiles(List<CmsFileInfo> fileInfos) { if (fileInfos != null) { for (CmsFileInfo file : fileInfos) { // store all files m_allFiles.put(file.getFileName(), file); // add those files to the list of files to upload that potential candidates if (!isTooLarge(file) && (file.getFileSize() != 0)) { m_filesToUpload.put(file.getFileName(), file); } // remove those files from the list to upload that were previously unchecked by the user if ((m_listItems.get(file.getFileName()) != null) && (m_listItems.get(file.getFileName()).getCheckBox() != null) && !m_listItems.get(file.getFileName()).getCheckBox().isChecked()) { m_filesToUpload.remove(file.getFileName()); } } // now rebuild the list: handle all files m_fileList.clearList(); List<String> sortedFileNames = new ArrayList<String>(m_allFiles.keySet()); Collections.sort(sortedFileNames, String.CASE_INSENSITIVE_ORDER); for (String filename : sortedFileNames) { CmsFileInfo file = m_allFiles.get(filename); addFileToList(file, false, isTooLarge(file)); } } loadAndShow(); } /** * Cancels the upload progress timer.<p> */ protected void cancelUpdateProgress() { m_updateProgressTimer.cancel(); } /** * Cancels the upload.<p> */ protected void cancelUpload() { m_canceled = true; cancelUpdateProgress(); CmsRpcAction<Boolean> callback = new CmsRpcAction<Boolean>() { /** * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() */ @Override public void execute() { getUploadService().cancelUpload(this); } /** * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) */ @Override protected void onResponse(Boolean result) { hide(); } }; callback.execute(); } /** * Creates the loading animation HTML and adds is to the content wrapper.<p> * * @param msg the message to display below the animation */ protected void createLoadingAnimation(String msg) { m_clientLoading = true; m_loadingPanel = new FlowPanel(); m_loadingPanel.addStyleName(I_CmsLayoutBundle.INSTANCE.uploadCss().loadingPanel()); m_loadingPanel.addStyleName(m_gwtCss.generalCss().cornerAll()); HTML animationDiv = new HTML(); animationDiv.addStyleName(I_CmsLayoutBundle.INSTANCE.uploadCss().loadingAnimation()); m_loadingPanel.add(animationDiv); HTML messageDiv = new HTML(); messageDiv.addStyleName(I_CmsLayoutBundle.INSTANCE.uploadCss().loadingText()); messageDiv.setHTML(msg); m_loadingPanel.add(messageDiv); m_contentWrapper.add(m_loadingPanel); } /** * Disables the OK button.<p> * * @param disabledReason the reason for disabling the OK button */ protected void disableOKButton(String disabledReason) { m_okButton.disable(disabledReason); } /** * Enables the OK button.<p> */ protected void enableOKButton() { m_okButton.enable(); } /** * Formats a given bytes value (file size).<p> * * @param filesize the file size to format * * @return the formated file size in KB */ protected String formatBytes(long filesize) { double kByte = Math.ceil(filesize / KILOBYTE); String formated = NumberFormat.getDecimalFormat().format(new Double(kByte)); return formated + " KB"; } /** * Returns the contentLength.<p> * * @return the contentLength */ protected long getContentLength() { return m_contentLength; } /** * Returns the contentWrapper.<p> * * @return the contentWrapper */ protected FlowPanel getContentWrapper() { return m_contentWrapper; } /** * Returns the data.<p> * * @return the data */ protected CmsUploadData getData() { return m_data; } /** * Returns the list of file names that have to unziped.<p> * * @param all <code>true</code> if the returned list should contain those filenames that * are not inside the map of files to upload. <code>false</code> only those filenames are * returned that are also inside the map of files to upload * * @return the list of file names that have to unziped */ protected List<String> getFilesToUnzip(boolean all) { if (!all) { List<String> result = new ArrayList<String>(); for (String fileName : m_filesToUnzip) { if (m_filesToUpload.keySet().contains(fileName)) { result.add(fileName); } } return result; } return m_filesToUnzip; } /** * Returns the filesToUpload.<p> * * @return the filesToUpload */ protected Map<String, CmsFileInfo> getFilesToUpload() { return m_filesToUpload; } /** * Returns "files" or "file" depending on the files to upload.<p> * * @return "files" or "file" depending on the files to upload */ protected String getFileText() { if (m_filesToUpload.size() == 1) { return Messages.get().key(Messages.GUI_UPLOAD_FILES_SINGULAR_0); } return Messages.get().key(Messages.GUI_UPLOAD_FILES_PLURAL_0); } /** * Returns the resource type name for a given filename.<p> * * @param file the file info * * @return the resource type name */ protected String getResourceType(CmsFileInfo file) { String typeName = null; typeName = CmsCoreProvider.get().getExtensionMapping().get(file.getFileSuffix().toLowerCase()); if (typeName == null) { typeName = "plain"; } return typeName; } /** * Returns the targetFolder.<p> * * @return the targetFolder */ protected String getTargetFolder() { return m_targetFolder; } /** * Returns the upload service instance.<p> * * @return the upload service instance */ protected I_CmsUploadServiceAsync getUploadService() { if (m_uploadService == null) { m_uploadService = GWT.create(I_CmsUploadService.class); String serviceUrl = CmsCoreProvider.get().link("org.opencms.ade.upload.CmsUploadService.gwt"); ((ServiceDefTarget)m_uploadService).setServiceEntryPoint(serviceUrl); } return m_uploadService; } /** * Returns the upload JSP uri.<p> * * @return the upload JSP uri */ protected String getUploadUri() { return CmsCoreProvider.get().link(I_CmsUploadConstants.UPLOAD_ACTION_JSP_URI); } /** * Inserts a hidden form into.<p> * * @param form the form to insert */ protected void insertUploadForm(FormPanel form) { form.getElement().getStyle().setDisplay(Display.NONE); m_contentWrapper.add(form); } /** * The action that is executed if the user clicks on the OK button.<p> * * If the selection dialog is currently shown the selected files are checked * otherwise the upload is triggered.<p> */ protected void onOkClick() { if (!m_selectionDone) { checkSelection(); } else { commit(); } } /** * Execute to set the content wrapper height.<p> */ protected void setContentWrapperHeight() { // set the max height of the content panel int fixedContent = 0; if (m_dialogInfo.isVisible()) { fixedContent += m_dialogInfo.getOffsetHeight(); } if (m_selectionSummary.isVisible()) { fixedContent += m_selectionSummary.getOffsetHeight(); } m_contentWrapper.getElement().getStyle().setPropertyPx("maxHeight", getAvailableHeight(fixedContent)); } /** * Parses the upload response of the server and decides what to do.<p> * * @param results a JSON Object */ protected void parseResponse(String results) { cancelUpdateProgress(); stopLoadingAnimation(); if ((!m_canceled) && CmsStringUtil.isNotEmptyOrWhitespaceOnly(results)) { JSONObject jsonObject = JSONParser.parseStrict(results).isObject(); boolean success = jsonObject.get(I_CmsUploadConstants.KEY_SUCCESS).isBoolean().booleanValue(); // If the upload is done so fast that we did not receive any progress information, then // the content length is unknown. For that reason take the request size to show how // much bytes were uploaded. double size = jsonObject.get(I_CmsUploadConstants.KEY_REQUEST_SIZE).isNumber().doubleValue(); long requestSize = new Double(size).longValue(); if (m_contentLength == 0) { m_contentLength = requestSize; } if (success) { displayDialogInfo(Messages.get().key(Messages.GUI_UPLOAD_INFO_FINISHING_0), false); m_progressInfo.finish(); closeOnSuccess(); } else { String message = jsonObject.get(I_CmsUploadConstants.KEY_MESSAGE).isString().stringValue(); String stacktrace = jsonObject.get(I_CmsUploadConstants.KEY_STACKTRACE).isString().stringValue(); showErrorReport(message, stacktrace); } } } /** * Decides how to go on depending on the information of the server response.<p> * * Shows a warning if there is another upload process active (inside the same session).<p> * * Otherwise if the list of files to upload contains already existent resources on the VFS or if there * are files selected that have invalid file names the overwrite dialog is shown.<p> * * Only if there is no other upload process running and none of the selected files * is already existent on the VFS the upload is triggered.<p> * * @param result the bean that contains the information to evaluate */ protected void proceedWorkflow(CmsUploadFileBean result) { if (result.isActive()) { m_okButton.enable(); CmsNotification.get().send(Type.WARNING, Messages.get().key(Messages.GUI_UPLOAD_NOTIFICATION_RUNNING_0)); } else { if (!result.getExistingResourceNames().isEmpty() || !result.getInvalidFileNames().isEmpty()) { showOverwriteDialog(result); } else { commit(); } } } /** * Sets the contentLength.<p> * * @param contentLength the contentLength to set */ protected void setContentLength(long contentLength) { m_contentLength = contentLength; } /** * Sets the HTML of the selection summary.<p> * * @param html the HTML to set as String */ protected void setSummaryHTML(String html) { m_selectionSummary.setHTML(html); } /** * Shows the error report.<p> * * @param message the message to show * @param stacktrace the stacktrace to show */ protected void showErrorReport(final String message, final String stacktrace) { if (!m_canceled) { CmsErrorDialog errDialog = new CmsErrorDialog(message, stacktrace); if (m_handlerReg != null) { m_handlerReg.removeHandler(); } if (m_closeHandler != null) { errDialog.addCloseHandler(m_closeHandler); } hide(); errDialog.center(); } } /** * Retrieves the progress information from the server.<p> */ protected void updateProgress() { CmsRpcAction<CmsUploadProgessInfo> callback = new CmsRpcAction<CmsUploadProgessInfo>() { /** * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() */ @Override public void execute() { getUploadService().getUploadProgressInfo(this); } /** * @see org.opencms.gwt.client.rpc.CmsRpcAction#onFailure(java.lang.Throwable) */ @Override public void onFailure(Throwable t) { super.onFailure(t); cancelUpdateProgress(); } /** * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) */ @Override protected void onResponse(CmsUploadProgessInfo result) { updateProgressBar(result); } }; callback.execute(); } /** * Updates the progress bar.<p> * * @param info the progress info */ protected void updateProgressBar(CmsUploadProgessInfo info) { switch (info.getState()) { case notStarted: break; case running: m_progressInfo.setProgress(info); stopLoadingAnimation(); break; case finished: m_progressInfo.finish(); displayDialogInfo(Messages.get().key(Messages.GUI_UPLOAD_INFO_FINISHING_0), false); startLoadingAnimation(Messages.get().key(Messages.GUI_UPLOAD_INFO_CREATING_RESOURCES_0), 1500); break; default: break; } } /** * Adds a click handler for the given checkbox.<p> * * @param check the checkbox * @param file the file */ private void addClickHandlerToCheckBox(final CmsCheckBox check, final CmsCheckBox unzip, final CmsFileInfo file) { check.addClickHandler(new ClickHandler() { /** * @see com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event.dom.client.ClickEvent) */ public void onClick(ClickEvent event) { // add or remove the file from the list of files to upload if (check.isChecked()) { getFilesToUpload().put(file.getFileName(), file); if (unzip != null) { unzip.enable(); } } else { getFilesToUpload().remove(file.getFileName()); if (unzip != null) { unzip.disable(Messages.get().key(Messages.GUI_UPLOAD_FILE_NOT_SELECTED_0)); } } // disable or enable the OK button if (getFilesToUpload().isEmpty()) { disableOKButton(Messages.get().key(Messages.GUI_UPLOAD_NOTIFICATION_NO_FILES_0)); } else { enableOKButton(); } // update summary updateSummary(); } }); } /** * Adds a file to the list.<p> * * @param file the file to add * @param invalid signals if the filename is invalid * @param isTooLarge signals if the file size limit is exceeded * @param isFolder signals if the file is a folder */ private void addFileToList(final CmsFileInfo file, boolean invalid, boolean isTooLarge) { CmsListInfoBean infoBean = createInfoBean(file); CmsListItemWidget listItemWidget = new CmsListItemWidget(infoBean); String icon = CmsIconUtil.getResourceIconClasses(getResourceType(file), file.getFileName(), false); listItemWidget.setIcon(icon); CmsCheckBox check = new CmsCheckBox(); check.setChecked(false); if (!invalid && !isTooLarge) { if (file.getFileSize() == 0) { check.setChecked(false); } check.setChecked(m_filesToUpload.containsKey(file.getFileName())); check.setTitle(file.getFileName()); if (!m_selectionDone && file.getFileName().toLowerCase().endsWith(".zip")) { final CmsCheckBox unzip = createUnzipCheckBox(file); addClickHandlerToCheckBox(check, unzip, file); listItemWidget.addButton(unzip); } else { addClickHandlerToCheckBox(check, null, file); } } else if (isTooLarge) { String message = getFileSizeTooLargeMessage(file); check.disable(message); listItemWidget.setBackground(Background.RED); listItemWidget.setSubtitleLabel(message); } else { // is invalid String message = Messages.get().key( Messages.GUI_UPLOAD_FILE_INVALID_NAME_2, file.getFileName(), formatBytes(file.getFileSize())); check.disable(message); listItemWidget.setBackground(Background.RED); listItemWidget.setSubtitleLabel(message); } CmsListItem listItem = new CmsListItem(check, listItemWidget); m_fileList.addItem(listItem); m_listItems.put(file.getFileName(), listItem); } /** * Changes the height of the content wrapper so that the dialog finally has the * same height that the dialog has when the min height is set on the selection screen.<p> */ private void changeHeight() { int firstHeight = MIN_CONTENT_HEIGHT + m_firstInfoHeight + m_firstSummaryHeight + 2; int currentHeight = CmsDomUtil.getCurrentStyleInt(m_mainPanel.getElement(), CmsDomUtil.Style.height); int targetHeight = firstHeight - m_dialogInfo.getOffsetHeight() - m_selectionSummary.getOffsetHeight(); if (currentHeight > firstHeight) { CmsChangeHeightAnimation.change(m_contentWrapper.getElement(), targetHeight, null, 750); } } /** * Before the upload data is effectively submited we have to check * for already existent resources in the VFS.<p> * * Executes the RPC call that checks the VFS for existing resources. * Passes the response object to a method that evaluates the result.<p> */ private void checkSelection() { m_okButton.disable(Messages.get().key(Messages.GUI_UPLOAD_BUTTON_OK_DISABLE_CHECKING_0)); if (!m_selectionDone) { m_firstContentHeight = CmsDomUtil.getCurrentStyleInt(m_contentWrapper.getElement(), CmsDomUtil.Style.height); m_firstInfoHeight = m_dialogInfo.getOffsetHeight(); m_firstSummaryHeight = m_selectionSummary.getOffsetHeight(); } CmsRpcAction<CmsUploadFileBean> callback = new CmsRpcAction<CmsUploadFileBean>() { /** * @see org.opencms.gwt.client.rpc.CmsRpcAction#execute() */ @Override public void execute() { List<String> filesToCheck = new ArrayList<String>(getFilesToUpload().keySet()); filesToCheck.removeAll(getFilesToUnzip(false)); getUploadService().checkUploadFiles(filesToCheck, getTargetFolder(), this); } /** * @see org.opencms.gwt.client.rpc.CmsRpcAction#onResponse(java.lang.Object) */ @Override protected void onResponse(CmsUploadFileBean result) { proceedWorkflow(result); } }; callback.execute(); } /** * Closes the dialog after a delay.<p> */ private void closeOnSuccess() { Timer closeTimer = new Timer() { /** * @see com.google.gwt.user.client.Timer#run() */ @Override public void run() { A_CmsUploadDialog.this.hide(); } }; closeTimer.schedule(1500); } /** * Calls the submit action if there are any files selected for upload.<p> */ private void commit() { m_selectionDone = true; if (!m_filesToUpload.isEmpty()) { m_okButton.disable(Messages.get().key(Messages.GUI_UPLOAD_BUTTON_OK_DISABLE_UPLOADING_0)); m_uploadButton.getElement().getStyle().setDisplay(Display.NONE); showProgress(); submit(); } } /** * Creates the "OK", the "Cancel" and the "Upload" button.<p> */ private void createButtons() { addDialogClose(new Command() { public void execute() { cancelUpload(); } }); CmsPushButton cancelButton = new CmsPushButton(); cancelButton.setTitle(org.opencms.gwt.client.Messages.get().key(org.opencms.gwt.client.Messages.GUI_CANCEL_0)); cancelButton.setText(org.opencms.gwt.client.Messages.get().key(org.opencms.gwt.client.Messages.GUI_CANCEL_0)); cancelButton.setSize(I_CmsButton.Size.medium); cancelButton.setUseMinWidth(true); cancelButton.addClickHandler(new ClickHandler() { /** * @see com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event.dom.client.ClickEvent) */ public void onClick(ClickEvent event) { cancelUpload(); } }); addButton(cancelButton); m_okButton = new CmsPushButton(); m_okButton.setTitle(org.opencms.gwt.client.Messages.get().key(org.opencms.gwt.client.Messages.GUI_OK_0)); m_okButton.setText(org.opencms.gwt.client.Messages.get().key(org.opencms.gwt.client.Messages.GUI_OK_0)); m_okButton.setSize(I_CmsButton.Size.medium); m_okButton.setUseMinWidth(true); m_okButton.addClickHandler(new ClickHandler() { /** * @see com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event.dom.client.ClickEvent) */ public void onClick(ClickEvent event) { onOkClick(); } }); addButton(m_okButton); // add a new upload button m_uploadButton = new CmsUploadButton(this); m_uploadButton.addStyleName(I_CmsLayoutBundle.INSTANCE.uploadCss().uploadDialogButton()); m_uploadButton.setText(Messages.get().key(Messages.GUI_UPLOAD_BUTTON_ADD_FILES_0)); addButton(m_uploadButton); } /** * Creates the unzip checkbox.<p> * * @param file the file to create the checkbox for * * @return the unzip checkbox */ private CmsCheckBox createUnzipCheckBox(final CmsFileInfo file) { final CmsCheckBox unzip = new CmsCheckBox(); unzip.addStyleName(org.opencms.gwt.client.ui.css.I_CmsLayoutBundle.INSTANCE.listItemWidgetCss().permaVisible()); unzip.setChecked(getFilesToUnzip(true).contains(file.getFileName())); unzip.setTitle(Messages.get().key(Messages.GUI_UPLOAD_UNZIP_FILE_0)); if (!m_filesToUpload.containsKey(file.getFileName())) { unzip.disable(Messages.get().key(Messages.GUI_UPLOAD_FILE_NOT_SELECTED_0)); } unzip.addClickHandler(new ClickHandler() { /** * @see com.google.gwt.event.dom.client.ClickHandler#onClick(com.google.gwt.event.dom.client.ClickEvent) */ public void onClick(ClickEvent event) { // add or remove the file from the list of files to upload if (unzip.isChecked()) { getFilesToUnzip(true).add(file.getFileName()); } else { getFilesToUnzip(true).remove(file.getFileName()); } } }); return unzip; } /** * Sets the user info.<p> * * @param msg the message to display * @param warning signals whether the message should be a warning or nor */ private void displayDialogInfo(String msg, boolean warning) { StringBuffer buffer = new StringBuffer(64); if (!warning) { buffer.append("<p class=\""); buffer.append(I_CmsLayoutBundle.INSTANCE.uploadCss().dialogMessage()); buffer.append("\">"); buffer.append(msg); buffer.append("</p>"); } else { buffer.append("<div class=\""); buffer.append(I_CmsLayoutBundle.INSTANCE.uploadCss().warningIcon()); buffer.append("\"></div>"); buffer.append("<p class=\""); buffer.append(I_CmsLayoutBundle.INSTANCE.uploadCss().warningMessage()); buffer.append("\">"); buffer.append(msg); buffer.append("</p>"); } m_dialogInfo.setHTML(buffer.toString()); } /** * Removes all widgets from the content wrapper.<p> */ private void removeContent() { int widgetCount = m_contentWrapper.getWidgetCount(); for (int i = 0; i < widgetCount; i++) { m_contentWrapper.remove(0); } } /** * Sets the height for the content so that the dialog finally has the same height * as the dialog has on the selection screen.<p> */ private void setHeight() { int infoDiff = m_firstInfoHeight - m_dialogInfo.getOffsetHeight(); int summaryDiff = m_firstSummaryHeight - m_selectionSummary.getOffsetHeight(); int height = m_firstContentHeight + infoDiff + summaryDiff; m_contentWrapper.getElement().getStyle().setHeight(height, Unit.PX); m_contentWrapper.getElement().getStyle().clearProperty("minHeight"); m_contentWrapper.getElement().getStyle().clearProperty("maxHeight"); } /** * Shows the overwrite dialog.<p> * * @param infoBean the info bean containing the existing and invalid file names */ private void showOverwriteDialog(CmsUploadFileBean infoBean) { // update the dialog m_selectionDone = true; m_okButton.enable(); displayDialogInfo(Messages.get().key(Messages.GUI_UPLOAD_INFO_OVERWRITE_0), true); m_uploadButton.getElement().getStyle().setDisplay(Display.NONE); // clear the list m_fileList.clearList(); // handle existing files List<String> existings = new ArrayList<String>(infoBean.getExistingResourceNames()); Collections.sort(existings, String.CASE_INSENSITIVE_ORDER); for (String filename : existings) { addFileToList(m_filesToUpload.get(filename), false, false); } // handle the invalid files List<String> invalids = new ArrayList<String>(infoBean.getInvalidFileNames()); Collections.sort(invalids, String.CASE_INSENSITIVE_ORDER); for (String filename : invalids) { addFileToList(m_filesToUpload.get(filename), true, false); m_filesToUpload.remove(filename); } // set the height of the content setHeight(); } /** * Starts the upload progress bar.<p> */ private void showProgress() { removeContent(); displayDialogInfo(Messages.get().key(Messages.GUI_UPLOAD_INFO_UPLOADING_0), false); m_selectionSummary.removeFromParent(); m_progressInfo = new CmsUploadProgressInfo(); m_contentWrapper.add(m_progressInfo); m_updateProgressTimer.scheduleRepeating(UPDATE_PROGRESS_INTERVALL); startLoadingAnimation(Messages.get().key(Messages.GUI_UPLOAD_CLIENT_LOADING_0), 0); setHeight(); changeHeight(); } /** * Starts the loading animation.<p> * * Used while client is loading files from hard disk into memory.<p> * * @param msg the message that should be displayed below the loading animation (can also be HTML as String) */ private void startLoadingAnimation(final String msg, int delayMillis) { m_loadingTimer = new Timer() { @Override public void run() { createLoadingAnimation(msg); } }; if (delayMillis > 0) { m_loadingTimer.schedule(delayMillis); } else { m_loadingTimer.run(); } } /** * Stops the client loading animation.<p> */ private void stopLoadingAnimation() { if (m_loadingTimer != null) { m_loadingTimer.cancel(); } if (m_clientLoading) { m_contentWrapper.remove(m_loadingPanel); m_clientLoading = false; } } /** * Displays the 'use drag and drop' / 'no drag and drop available' message.<p> */ protected void setDragAndDropMessage() { if (m_dragAndDropMessage == null) { m_dragAndDropMessage = new HTML(); m_dragAndDropMessage.setStyleName(I_CmsLayoutBundle.INSTANCE.uploadCss().dragAndDropMessage()); m_dragAndDropMessage.setText(Messages.get().key(Messages.GUI_UPLOAD_DRAG_AND_DROP_DISABLED_0)); } getContentWrapper().add(m_dragAndDropMessage); getContentWrapper().getElement().getStyle().setBackgroundColor( I_CmsConstantsBundle.INSTANCE.css().notificationErrorBg()); } /** * Removes the drag and drop message.<p> */ protected void removeDragAndDropMessage() { if (m_dragAndDropMessage != null) { m_dragAndDropMessage.removeFromParent(); m_dragAndDropMessage = null; getContentWrapper().getElement().getStyle().clearBackgroundColor(); } } }