/* * This file is part of muCommander, http://www.mucommander.com * Copyright (C) 2002-2016 Maxence Bernard * * muCommander is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * muCommander 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package com.mucommander.ui.dialog.file; import com.mucommander.commons.file.AbstractFile; import com.mucommander.job.FileCollisionChecker; import com.mucommander.text.CustomDateFormat; import com.mucommander.text.SizeFormat; import com.mucommander.text.Translator; import com.mucommander.ui.dialog.QuestionDialog; import com.mucommander.ui.layout.InformationPane; import com.mucommander.ui.layout.XAlignedComponentPanel; import com.mucommander.ui.layout.YBoxPanel; import com.mucommander.ui.notifier.AbstractNotifier; import com.mucommander.ui.notifier.NotificationType; import com.mucommander.ui.text.FileLabel; import com.mucommander.ui.text.FontUtils; import javax.swing.*; import java.awt.*; import java.util.Date; import java.util.Vector; /** * Dialog used to inform the user that a file collision has been detected and ask him how to resolve the conflict. * Prior to invoking this dialog, {@link com.mucommander.job.FileCollisionChecker} can be used to check for file collisions. * * @see com.mucommander.job.FileCollisionChecker * @author Maxence Bernard */ public class FileCollisionDialog extends QuestionDialog { /** This value is used by some FileJob classes */ public final static int ASK_ACTION = -1; public final static int CANCEL_ACTION = 0; public final static int SKIP_ACTION = 1; public final static int OVERWRITE_ACTION = 2; public final static int OVERWRITE_IF_OLDER_ACTION = 3; public final static int RESUME_ACTION = 4; public final static int RENAME_ACTION = 5; public final static String CANCEL_TEXT = Translator.get("cancel"); public final static String SKIP_TEXT = Translator.get("skip"); public final static String OVERWRITE_TEXT = Translator.get("overwrite"); public final static String OVERWRITE_IF_OLDER_TEXT = Translator.get("overwrite_if_older"); public final static String RESUME_TEXT = Translator.get("resume"); public final static String RENAME_TEXT = Translator.get("rename"); private JCheckBox applyToAllCheckBox; /** * Creates a new FileCollisionDialog. * * @param owner the Frame that owns this dialog * @param locationRelative component the location of this dialog will be based on * @param collisionType the type of collision as returned by {@link com.mucommander.job.FileCollisionChecker} * @param sourceFile the source file that 'conflicts' with the destination file, can be null. * @param destFile the destination file which already exists * @param multipleFilesMode if true, options that apply to multiple files will be displayed (skip, apply to all) * @param allowRename if true, display an option to rename a file */ public FileCollisionDialog(Dialog owner, Component locationRelative, int collisionType, AbstractFile sourceFile, AbstractFile destFile, boolean multipleFilesMode, boolean allowRename) { super(owner, Translator.get("file_collision_dialog.title"), locationRelative); init(collisionType, sourceFile, destFile, multipleFilesMode, allowRename); } /** * Creates a new FileCollisionDialog. * * @param owner the Frame that owns this dialog * @param locationRelative component the location of this dialog will be based on * @param collisionType the type of collision as returned by {@link com.mucommander.job.FileCollisionChecker} * @param sourceFile the source file that 'conflicts' with the destination file, can be null. * @param destFile the destination file which already exists * @param multipleFilesMode if true, options that apply to multiple files will be displayed (skip, apply to all) * @param allowRename if true, display an option to rename a file */ public FileCollisionDialog(Frame owner, Component locationRelative, int collisionType, AbstractFile sourceFile, AbstractFile destFile, boolean multipleFilesMode, boolean allowRename) { super(owner, Translator.get("file_collision_dialog.title"), locationRelative); init(collisionType, sourceFile, destFile, multipleFilesMode, allowRename); } private void init(int collisionType, AbstractFile sourceFile, AbstractFile destFile, boolean multipleFilesMode, boolean allowRename) { // Init choices java.util.List<String> choicesTextV = new Vector<String>(); java.util.List<Integer> choicesActionsV = new Vector<Integer>(); choicesTextV.add(CANCEL_TEXT); choicesActionsV.add(CANCEL_ACTION); if(multipleFilesMode) { choicesTextV.add(SKIP_TEXT); choicesActionsV.add(SKIP_ACTION); } // Add 'overwrite' / 'overwrite if older' / 'resume' actions only for 'destination file already exists' collision type if(collisionType==FileCollisionChecker.DESTINATION_FILE_ALREADY_EXISTS && !destFile.isDirectory()) { choicesTextV.add(OVERWRITE_TEXT); choicesActionsV.add(OVERWRITE_ACTION); if(sourceFile!=null) { choicesTextV.add(OVERWRITE_IF_OLDER_TEXT); choicesActionsV.add(OVERWRITE_IF_OLDER_ACTION); // Give resume option only if destination file is smaller than source file long destSize = destFile.getSize(); long sourceSize = sourceFile.getSize(); if(destSize!=-1 && (sourceSize==-1 || destSize<sourceSize)) { choicesTextV.add(RESUME_TEXT); choicesActionsV.add(RESUME_ACTION); } if (allowRename) { choicesTextV.add(RENAME_TEXT); choicesActionsV.add(RENAME_ACTION); } } } // Convert choice vectors into arrays int nbChoices = choicesActionsV.size(); String choicesText[] = new String[nbChoices]; choicesTextV.toArray(choicesText); int choicesActions[] = new int[nbChoices]; for(int i=0; i<nbChoices; i++) choicesActions[i] = choicesActionsV.get(i); // Init UI String desc; if(collisionType==FileCollisionChecker.DESTINATION_FILE_ALREADY_EXISTS) desc = Translator.get("file_exists_in_destination"); else if(collisionType==FileCollisionChecker.SAME_SOURCE_AND_DESTINATION) desc = Translator.get("same_source_destination"); else if(collisionType==FileCollisionChecker.SOURCE_PARENT_OF_DESTINATION) desc = Translator.get("source_parent_of_destination"); else desc = null; YBoxPanel yPanel = new YBoxPanel(); if(desc!=null) { yPanel.add(new InformationPane(desc, null, Font.PLAIN, InformationPane.QUESTION_ICON)); yPanel.addSpace(10); } // Add a separator before file details yPanel.add(new JSeparator()); XAlignedComponentPanel tfPanel = new XAlignedComponentPanel(10); // If collision type is 'same source and destination' no need to show both source and destination if(collisionType==FileCollisionChecker.SAME_SOURCE_AND_DESTINATION) { addFileDetails(tfPanel, sourceFile, Translator.get("name")); } else { if(sourceFile!=null) addFileDetails(tfPanel, sourceFile, Translator.get("source")); addFileDetails(tfPanel, destFile, Translator.get("destination")); } yPanel.add(tfPanel); // Add a separator after file details yPanel.add(new JSeparator()); init(yPanel, choicesText, choicesActions, 3); // 'Apply to all' is available only for 'destination file already exists' collision type if(multipleFilesMode && collisionType==FileCollisionChecker.DESTINATION_FILE_ALREADY_EXISTS) { applyToAllCheckBox = new JCheckBox(Translator.get("apply_to_all")); addComponent(applyToAllCheckBox); } // Send a system notification if a notifier is available and enabled if(AbstractNotifier.isAvailable() && AbstractNotifier.getNotifier().isEnabled()) AbstractNotifier.getNotifier().displayBackgroundNotification(NotificationType.JOB_ERROR, getTitle(), desc); } private void addFileDetails(XAlignedComponentPanel panel, AbstractFile file, String nameLabel) { addFileDetailsRow(panel, nameLabel+":", new FileLabel(file, false), 0); AbstractFile parent = file.getParent(); addFileDetailsRow(panel, Translator.get("location")+":", new FileLabel((parent==null?file:parent), true), 0); addFileDetailsRow(panel, Translator.get("size")+":", new JLabel(SizeFormat.format(file.getSize(), SizeFormat.DIGITS_FULL| SizeFormat.UNIT_LONG| SizeFormat.INCLUDE_SPACE)), 0); addFileDetailsRow(panel, Translator.get("date")+":", new JLabel(CustomDateFormat.format(new Date(file.getDate()))), 0); addFileDetailsRow(panel, Translator.get("permissions")+":", new JLabel(file.getPermissionsString()), 10); } private void addFileDetailsRow(XAlignedComponentPanel panel, String label, JComponent comp, int ySpaceAfter) { panel.addRow(FontUtils.makeMini(new JLabel(label)), FontUtils.makeMini(comp), ySpaceAfter); } /** * Returns <code>true</code> if the 'apply to all' checkbox has been selected. * * @return <code>true</code> if the 'apply to all' checkbox has been selected. */ public boolean applyToAllSelected() { return applyToAllCheckBox != null && applyToAllCheckBox.isSelected(); } }