Java tutorial
/* * Copyright 2004 - 2008 Christian Sprajc. All rights reserved. * * This file is part of PowerFolder. * * PowerFolder 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. * * PowerFolder 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 PowerFolder. If not, see <http://www.gnu.org/licenses/>. * * $Id: SettingsTab.java 5457 2008-10-17 14:25:41Z harry $ */ package de.dal33t.powerfolder.ui.information.folder.settings; import java.awt.Dimension; import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Date; import java.util.List; import javax.swing.AbstractAction; import javax.swing.Action; import javax.swing.DefaultListModel; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JFileChooser; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JOptionPane; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTextField; import javax.swing.SwingUtilities; import javax.swing.SwingWorker; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import com.jgoodies.binding.adapter.BasicComponentFactory; import com.jgoodies.binding.value.ValueHolder; import com.jgoodies.binding.value.ValueModel; import com.jgoodies.forms.builder.DefaultFormBuilder; import com.jgoodies.forms.builder.PanelBuilder; import com.jgoodies.forms.layout.CellConstraints; import com.jgoodies.forms.layout.FormLayout; import de.dal33t.powerfolder.ConfigurationEntry; import de.dal33t.powerfolder.Constants; import de.dal33t.powerfolder.Controller; import de.dal33t.powerfolder.PreferencesEntry; import de.dal33t.powerfolder.clientserver.FolderService; import de.dal33t.powerfolder.clientserver.ServerClient; import de.dal33t.powerfolder.clientserver.ServerClientEvent; import de.dal33t.powerfolder.clientserver.ServerClientListener; import de.dal33t.powerfolder.disk.Folder; import de.dal33t.powerfolder.disk.FolderPreviewHelper; import de.dal33t.powerfolder.disk.FolderRepository; import de.dal33t.powerfolder.disk.FolderSettings; import de.dal33t.powerfolder.event.DiskItemFilterListener; import de.dal33t.powerfolder.event.FolderMembershipEvent; import de.dal33t.powerfolder.event.FolderMembershipListener; import de.dal33t.powerfolder.event.PatternChangedEvent; import de.dal33t.powerfolder.light.FolderInfo; import de.dal33t.powerfolder.message.FolderDBMaintCommando; import de.dal33t.powerfolder.security.FolderPermission; import de.dal33t.powerfolder.security.FolderRemovePermission; import de.dal33t.powerfolder.ui.PFUIComponent; import de.dal33t.powerfolder.ui.WikiLinks; import de.dal33t.powerfolder.ui.action.BaseAction; import de.dal33t.powerfolder.ui.dialog.DialogFactory; import de.dal33t.powerfolder.ui.dialog.FolderRemoveDialog; import de.dal33t.powerfolder.ui.dialog.GenericDialogType; import de.dal33t.powerfolder.ui.dialog.PreviewToJoinDialog; import de.dal33t.powerfolder.ui.event.SelectionChangeEvent; import de.dal33t.powerfolder.ui.event.SelectionChangeListener; import de.dal33t.powerfolder.ui.event.SelectionModel; import de.dal33t.powerfolder.ui.panel.ArchiveModeSelectorPanel; import de.dal33t.powerfolder.ui.panel.SyncProfileSelectorPanel; import de.dal33t.powerfolder.ui.util.Help; import de.dal33t.powerfolder.ui.util.Icons; import de.dal33t.powerfolder.ui.util.UIUtil; import de.dal33t.powerfolder.ui.widget.ActionLabel; import de.dal33t.powerfolder.ui.widget.ActivityVisualizationWorker; import de.dal33t.powerfolder.ui.widget.JButtonMini; import de.dal33t.powerfolder.ui.wizard.PFWizard; import de.dal33t.powerfolder.util.PathUtils; import de.dal33t.powerfolder.util.Reject; import de.dal33t.powerfolder.util.StringUtils; import de.dal33t.powerfolder.util.Translation; import de.dal33t.powerfolder.util.pattern.Pattern; import de.dal33t.powerfolder.util.pattern.PatternFactory; /** * UI component for the information settings tab */ public class SettingsTab extends PFUIComponent { // Model and other stuff private final ServerClient serverClient; private Folder folder; private ValueModel localVersionModel; private ValueModel onlineVersionModel; private final ValueModel scriptModel; private DefaultListModel<String> patternsListModel = new DefaultListModel<>(); private final SelectionModel selectionModel; private FolderMembershipListener membershipListener; private final DiskItemFilterListener patternChangeListener; private volatile boolean updatingOnlineArchiveMode; /** * Folders with this setting will backup files before replacing them with * newer downloaded ones. */ private final RemoveFolderAction removeFolderAction; // UI Components private JPanel uiComponent; private final SyncProfileSelectorPanel transferModeSelectorPanel; private final ArchiveModeSelectorPanel localArchiveModeSelectorPanel; private final ArchiveModeSelectorPanel onlineArchiveModeSelectorPanel; private JList<String> patternsList; private final JTextField localFolderField; private final JButton localFolderButton; private ActionLabel confOSActionLabel; private BaseAction confOSAction; private Action maintainDBAction; private ActionLabel previewFolderActionLabel; private JButtonMini editButton; private JButtonMini removeButton; private boolean settingFolder; private JLabel onlineLabel; private JCheckBox syncPatternsCheckBox; /** * Constructor * * @param controller */ public SettingsTab(Controller controller) { super(controller); serverClient = controller.getOSClient(); transferModeSelectorPanel = new SyncProfileSelectorPanel(getController()); MyActionListener myActionListener = new MyActionListener(); selectionModel = new SelectionModel(); localFolderField = new JTextField(); localFolderField.setEditable(false); localFolderButton = new JButtonMini(Icons.getIconById(Icons.DIRECTORY), Translation.getTranslation("settings_tab.select_directory.text")); localFolderButton.setEnabled(false); localFolderButton.addActionListener(myActionListener); patternChangeListener = new MyPatternChangeListener(); patternsListModel = new DefaultListModel<>(); removeFolderAction = new RemoveFolderAction(getController()); maintainDBAction = new MaintainFolderAction(getController()); serverClient.addListener(new MyServerClientListener()); membershipListener = new MyFolderMembershipListener(); scriptModel = new ValueHolder(null, false); MyLocalValueChangeListener localListener = new MyLocalValueChangeListener(); localVersionModel = new ValueHolder(); // <Integer> localVersionModel.addValueChangeListener(localListener); MyOnlineValueChangeListener onlineListener = new MyOnlineValueChangeListener(); onlineVersionModel = new ValueHolder(); // <Integer> onlineVersionModel.addValueChangeListener(onlineListener); List<ValueModel> localVersionModels = new ArrayList<ValueModel>(); List<ValueModel> onlineVersionModels = new ArrayList<ValueModel>(); if (PreferencesEntry.EXPERT_MODE.getValueBoolean(controller)) { // Expert gets separate archive mode panels - local and online. localVersionModels.add(localVersionModel); onlineVersionModels.add(onlineVersionModel); } else { // Non-expert gets one archive mode panel, // which simultaneously updates both local and online. localVersionModels.add(localVersionModel); localVersionModels.add(onlineVersionModel); } localArchiveModeSelectorPanel = new ArchiveModeSelectorPanel(controller, localVersionModels, new LocalPurgeListener()); onlineArchiveModeSelectorPanel = new ArchiveModeSelectorPanel(controller, onlineVersionModels, new OnlinePurgeListener()); onlineLabel = new JLabel(Translation.getTranslation("general.online_archive_mode")); onlineLabel.setVisible(false); onlineArchiveModeSelectorPanel.getUIComponent().setVisible(false); } /** * Set the tab with details for a folder. * * @param folderInfo */ public void setFolderInfo(FolderInfo folderInfo) { if (folder != null) { folder.getDiskItemFilter().removeListener(patternChangeListener); folder.removeMembershipListener(membershipListener); } settingFolder = true; folder = getController().getFolderRepository().getFolder(folderInfo); folder.getDiskItemFilter().addListener(patternChangeListener); folder.addMembershipListener(membershipListener); transferModeSelectorPanel.setUpdateableFolder(folder); scriptModel.setValue(folder.getDownloadScript()); localArchiveModeSelectorPanel.setArchiveMode(folder.getFileArchiver().getVersionsPerFile()); syncPatternsCheckBox.setSelected(folder.isSyncPatterns()); settingFolder = false; update(); enableConfigOSAction(); enablePreviewFolderAction(); loadOnlineArchiveMode(); } private void loadOnlineArchiveMode() { // Do this offline so it does not slow the main display. FolderInfo fi = folder == null ? null : folder.getInfo(); if (folder.hasMember(serverClient.getServer()) && serverClient.isConnected()) { new MyServerModeSwingWorker(fi).execute(); } else { onlineArchiveModeSelectorPanel.getUIComponent().setVisible(false); onlineLabel.setVisible(false); } } /** * @return the ui component */ public JPanel getUIComponent() { if (uiComponent == null) { buildUIComponent(); } return uiComponent; } /** * Builds the ui component. */ private void buildUIComponent() { // label folder butn padding FormLayout layout = new FormLayout("3dlu, right:pref, 3dlu, 140dlu, 3dlu, pref, pref:grow", "3dlu, pref, 3dlu, pref, 3dlu, pref, 3dlu, pref, 3dlu, pref, 3dlu, pref, 12dlu, pref, 3dlu, pref, 3dlu, pref, 3dlu, pref, 3dlu"); DefaultFormBuilder builder = new DefaultFormBuilder(layout); CellConstraints cc = new CellConstraints(); int row = 2; Boolean expertMode = PreferencesEntry.EXPERT_MODE.getValueBoolean(getController()); if (expertMode) { builder.add(new JLabel(Translation.getTranslation("general.transfer_mode")), cc.xy(2, row)); builder.add(transferModeSelectorPanel.getUIComponent(), cc.xyw(4, row, 4)); } else { transferModeSelectorPanel.getUIComponent(); } row += 2; builder.add(new JLabel(Translation.getTranslation("settings_tab.local_folder_location")), cc.xy(2, row)); builder.add(localFolderField, cc.xy(4, row)); builder.add(localFolderButton, cc.xy(6, row)); row += 2; builder.add(new JLabel(Translation.getTranslation("general.local_archive_mode")), cc.xy(2, row)); builder.add(localArchiveModeSelectorPanel.getUIComponent(), cc.xyw(4, row, 4)); if (expertMode) { row += 2; builder.add(onlineLabel, cc.xy(2, row)); builder.add(onlineArchiveModeSelectorPanel.getUIComponent(), cc.xyw(4, row, 4)); } row += 2; if (expertMode) { builder.addLabel(Translation.getTranslation("exp.settings_tab.download_script"), cc.xy(2, row)); builder.add(createScriptField(), cc.xyw(4, row, 4)); } row += 2; if (expertMode) { builder.add(new JLabel(Translation.getTranslation("exp.settings_tab.ignore_patterns")), cc.xy(2, row, "right, top")); builder.add(createPatternsPanel(), cc.xyw(4, row, 4)); row += 2; builder.add(createConfigurePanel(), cc.xy(4, row)); } else { createPatternsPanel(); createConfigurePanel(); row += 2; } // Disabled. Not used anymore. createPreviewPanel(); // row += 2; // builder.add(createPreviewPanel(), cc.xy(4, row)); row += 2; builder.add(createDeletePanel(), cc.xy(4, row)); if (expertMode) { row += 2; builder.add(createMaintainPanel(), cc.xy(4, row)); } addSelectionListener(); uiComponent = builder.getPanel(); } private void addSelectionListener() { selectionModel.addSelectionChangeListener(new SelectionChangeListener() { public void selectionChanged(SelectionChangeEvent event) { int selectionsLength = selectionModel.getSelections() == null ? 0 : selectionModel.getSelections().length; editButton.setEnabled(selectionsLength > 0); removeButton.setEnabled(selectionsLength > 0); } }); } private JPanel createDeletePanel() { FormLayout layout = new FormLayout("pref", "pref"); PanelBuilder builder = new PanelBuilder(layout); CellConstraints cc = new CellConstraints(); ActionLabel label = new ActionLabel(getController(), removeFolderAction); builder.add(label.getUIComponent(), cc.xy(1, 1)); label.convertToBigLabel(); return builder.getPanel(); } private JPanel createMaintainPanel() { FormLayout layout = new FormLayout("pref", "pref"); PanelBuilder builder = new PanelBuilder(layout); CellConstraints cc = new CellConstraints(); ActionLabel label = new ActionLabel(getController(), maintainDBAction); builder.add(label.getUIComponent(), cc.xy(1, 1)); label.convertToBigLabel(); return builder.getPanel(); } private JPanel createConfigurePanel() { FormLayout layout = new FormLayout("pref", "pref"); PanelBuilder builder = new PanelBuilder(layout); CellConstraints cc = new CellConstraints(); confOSAction = new FolderOnlineStorageAction(getController()); // Permission setting done later enableConfigOSAction. This causes // NPE: // confOSAction.allowWith(FolderPermission.admin(folder.getInfo())); confOSActionLabel = new ActionLabel(getController(), confOSAction); confOSActionLabel.convertToBigLabel(); builder.add(confOSActionLabel.getUIComponent(), cc.xy(1, 1)); return builder.getPanel(); } private JPanel createPreviewPanel() { FormLayout layout = new FormLayout("pref", "pref"); PanelBuilder builder = new PanelBuilder(layout); CellConstraints cc = new CellConstraints(); BaseAction previewAction = new PreviewFolderAction(getController()); previewAction.allowWith(FolderRemovePermission.INSTANCE); previewFolderActionLabel = new ActionLabel(getController(), previewAction); previewFolderActionLabel.convertToBigLabel(); builder.add(previewFolderActionLabel.getUIComponent(), cc.xy(1, 1)); return builder.getPanel(); } private JPanel createPatternsPanel() { patternsList = new JList<>(patternsListModel); patternsList.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { selectionModel.setSelection(patternsList.getSelectedValue()); } }); Dimension size = new Dimension(200, 100); JScrollPane scroller = new JScrollPane(patternsList); scroller.setPreferredSize(size); FormLayout layout = new FormLayout("140dlu", "pref, 3dlu, pref"); PanelBuilder builder = new PanelBuilder(layout); CellConstraints cc = new CellConstraints(); builder.add(scroller, cc.xy(1, 1)); builder.add(createButtonBar(), cc.xy(1, 3)); return builder.getPanel(); } /** * Creates a pair of location text field and button. * * @return */ private JComponent createScriptField() { scriptModel.addValueChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { folder.setDownloadScript((String) evt.getNewValue()); } }); FormLayout layout = new FormLayout("140dlu, 3dlu, pref, pref", "pref"); PanelBuilder builder = new PanelBuilder(layout); CellConstraints cc = new CellConstraints(); JTextField locationTF = BasicComponentFactory.createTextField(scriptModel, false); locationTF.setEditable(true); builder.add(locationTF, cc.xy(1, 1)); JButton locationButton = new JButtonMini(Icons.getIconById(Icons.DIRECTORY), Translation.getTranslation("exp.settings_tab.download_script")); locationButton.addActionListener(new SelectScriptAction()); builder.add(locationButton, cc.xy(3, 1)); builder.add(Help.createWikiLinkButton(getController(), WikiLinks.SCRIPT_EXECUTION), cc.xy(4, 1)); return builder.getPanel(); } /** * refreshes the UI elements with the current data */ private void update() { rebuildPatterns(); localFolderField.setText(folder.getCommitOrLocalDir().toAbsolutePath().toString()); localFolderButton.setEnabled(!folder.isPreviewOnly()); } private void rebuildPatterns() { patternsListModel.clear(); List<String> stringList = folder.getDiskItemFilter().getPatterns(); for (String s : stringList) { patternsListModel.addElement(s); } } private JPanel createButtonBar() { AddAction addAction = new AddAction(getController()); EditAction editAction = new EditAction(getController()); RemoveAction removeAction = new RemoveAction(getController()); FormLayout layout = new FormLayout("pref, pref, pref, pref, pref:grow", "pref"); PanelBuilder bar = new PanelBuilder(layout); CellConstraints cc = new CellConstraints(); editButton = new JButtonMini(editAction); removeButton = new JButtonMini(removeAction); editButton.setEnabled(false); removeButton.setEnabled(false); bar.add(new JButtonMini(addAction), cc.xy(1, 1)); bar.add(editButton, cc.xy(2, 1)); bar.add(removeButton, cc.xy(3, 1)); bar.add(Help.createWikiLinkButton(getController(), WikiLinks.EXCLUDING_FILES_FROM_SYNCHRONIZATION), cc.xy(4, 1)); syncPatternsCheckBox = new JCheckBox(Translation.getTranslation("exp.settings_tab.sync_patterns")); syncPatternsCheckBox.setToolTipText(Translation.getTranslation("exp.settings_tab.sync_patterns.tip")); syncPatternsCheckBox.addActionListener(new MyActionListener()); bar.add(syncPatternsCheckBox, cc.xy(5, 1)); syncPatternsCheckBox.setVisible(true); return bar.getPanel(); } /** * Removes any patterns for this file name. Directories should have "/*" * added to the name. * * @param patterns */ public void removePatterns(String patterns) { String[] options = { Translation.getTranslation("remove_pattern.remove"), Translation.getTranslation("remove_pattern.dont"), Translation.getTranslation("general.cancel") }; String[] patternArray = patterns.split("\\n"); for (String pattern : patternArray) { // Match any patterns for this file. Pattern patternMatch = PatternFactory.createPattern(pattern); for (String blackListPattern : folder.getDiskItemFilter().getPatterns()) { if (patternMatch.isMatch(blackListPattern)) { // Confirm that the user wants to remove this. int result = DialogFactory.genericDialog(getController(), Translation.getTranslation("remove_pattern.title"), Translation.getTranslation("remove_pattern.prompt", pattern), options, 0, GenericDialogType.INFO); // Default is remove. if (result == 0) { // Remove // Remove pattern and update. folder.removePattern(blackListPattern); } else if (result == 2) { // Cancel // Abort for all other patterns. break; } } } } // Trigger resync getController().getFolderRepository().getFileRequestor().triggerFileRequesting(folder.getInfo()); } public void showAddPane(String initialPatterns) { Reject.ifNull(initialPatterns, "Patterns required"); String[] patternArray = initialPatterns.split("\\n"); if (patternArray.length == 1) { String pattern = patternArray[0]; String title = Translation.getTranslation("exp.settings_tab.add_a_pattern.title"); String text = Translation.getTranslation("exp.settings_tab.add_a_pattern.text"); String patternResult = (String) JOptionPane.showInputDialog(getUIController().getActiveFrame(), text, title, JOptionPane.PLAIN_MESSAGE, null, null, pattern); if (!StringUtils.isBlank(patternResult)) { folder.addPattern(patternResult); getController().getTransferManager().checkActiveTranfersForExcludes(); } } else { StringBuilder sb = new StringBuilder(); int count = 0; for (String pattern : patternArray) { sb.append(" "); if (count++ >= 10) { // Too many selections - enough!!! sb.append(Translation.getTranslation("general.more.lower_case") + "...\n"); break; } sb.append(pattern + '\n'); } String message = Translation.getTranslation("exp.settings_tab.add_patterns.text_1") + "\n\n" + sb.toString(); String title = Translation.getTranslation("exp.settings_tab.add_patterns.title"); int result = DialogFactory.genericDialog(getController(), title, message, new String[] { Translation.getTranslation("general.ok"), Translation.getTranslation("general.cancel") }, 0, GenericDialogType.QUESTION); if (result == 0) { for (String pattern : patternArray) { folder.addPattern(pattern); } } } patternsList.getSelectionModel().clearSelection(); } /** * Controls the movement of a folder directory. */ public void moveLocalFolder() { // Lock out the 'new folder' scanner. // Else it's _just_ possible the scanner might see the renamed folder // and autocreate it during the file move. getController().getFolderRepository().setSuspendNewFolderSearch(true); try { Path originalDirectory = folder.getCommitOrLocalDir(); // Select the new folder. List<Path> files = DialogFactory.chooseDirectory(getController().getUIController(), originalDirectory, false); if (!files.isEmpty()) { Path newDirectory = files.get(0); if (!folder.checkIfDeviceDisconnected() && PathUtils.isSubdirectory(originalDirectory, newDirectory)) { // Can't move a folder to one of its subdirectories. DialogFactory.genericDialog(getController(), Translation.getTranslation("general.directory"), Translation.getTranslation("general.subdirectory_error.text"), GenericDialogType.ERROR); return; } Path foldersBaseDir = getController().getFolderRepository().getFoldersBasedir(); if (newDirectory.equals(foldersBaseDir)) { // Can't move a folder to the base directory. DialogFactory.genericDialog(getController(), Translation.getTranslation("general.directory"), Translation.getTranslation("general.basedir_error.text"), GenericDialogType.ERROR); return; } if (ConfigurationEntry.FOLDER_CREATE_IN_BASEDIR_ONLY.getValueBoolean(getController())) { if (!newDirectory.getParent() .equals(getController().getFolderRepository().getFoldersBasedir())) { // Can't move a folder outside the base directory. DialogFactory.genericDialog(getController(), Translation.getTranslation("general.directory"), Translation.getTranslation("general.outside_basedir_error.text", getController().getFolderRepository().getFoldersBasedirString()), GenericDialogType.ERROR); return; } } // Find out if the user wants to move the content of the // current folder // to the new one. int moveContent = shouldMoveContent(); if (moveContent == 2) { // Cancel return; } moveDirectory(originalDirectory, newDirectory, moveContent == 0); } } finally { try { // Unlock the 'new folder' scanner. getController().getFolderRepository().setSuspendNewFolderSearch(false); } catch (Exception e) { logSevere(e); } } } /** * Should the content of the existing folder be moved to the new location? * * @return true if should move. */ private int shouldMoveContent() { return DialogFactory.genericDialog(getController(), Translation.getTranslation("settings_tab.move_content.title"), Translation.getTranslation("settings_tab.move_content"), new String[] { Translation.getTranslation("settings_tab.move_content.move"), Translation.getTranslation("settings_tab.move_content.dont"), Translation.getTranslation("general.cancel"), }, 0, GenericDialogType.INFO); } /** * Move the directory. */ public void moveDirectory(Path originalDirectory, Path newDirectory, boolean moveContent) { if (!newDirectory.equals(originalDirectory)) { // Check for any problems with the new folder. if (checkNewLocalFolder(newDirectory)) { // Confirm move. if (shouldMoveLocal(newDirectory)) { try { // Move contentes selected ActivityVisualizationWorker worker = new MyActivityVisualizationWorker(moveContent, originalDirectory, newDirectory); worker.start(); } catch (Exception e) { // Probably failed to create temp directory. DialogFactory.genericDialog(getController(), Translation.getTranslation("settings_tab.move_error.title"), Translation.getTranslation("settings_tab.move_error.temp"), getController().isVerbose(), e); } } } } } /** * Confirm that the user really does want to go ahead with the move. * * @param newDirectory * @return true if the user wishes to move. */ private boolean shouldMoveLocal(Path newDirectory) { String title = Translation.getTranslation("settings_tab.confirm_local_folder_move.title"); String message = Translation.getTranslation("settings_tab.confirm_local_folder_move.text", folder.getCommitOrLocalDir().toAbsolutePath().toString(), newDirectory.toAbsolutePath().toString()); return DialogFactory.genericDialog(getController(), title, message, new String[] { Translation.getTranslation("general.continue"), Translation.getTranslation("general.cancel") }, 0, GenericDialogType.INFO) == 0; } /** * Do some basic validation. Warn if moving to a folder that has files / * directories in it. * * @param newDirectory * @return */ private boolean checkNewLocalFolder(Path newDirectory) { // Warn if target directory is not empty. if (newDirectory != null && Files.exists(newDirectory) && PathUtils.getNumberOfSiblings(newDirectory) > 0) { int result = DialogFactory.genericDialog(getController(), Translation.getTranslation("exp.settings_tab.folder_not_empty.title"), Translation.getTranslation("exp.settings_tab.folder_not_empty", newDirectory.toAbsolutePath().toString()), new String[] { Translation.getTranslation("general.continue"), Translation.getTranslation("general.cancel") }, 1, GenericDialogType.WARN); // Default is cancel. if (result != 0) { // User does not want to move to new folder. return false; } } // All good. return true; } /** * Moves the contents of a folder to another via a temporary directory. * * @param moveContent * @param originalDirectory * @param newDirectory * @return */ private Object transferFolder(boolean moveContent, Path originalDirectory, Path newDirectory) { try { newDirectory = PathUtils.removeInvalidFilenameChars(newDirectory); // Copy the files to the new local base if (Files.notExists(newDirectory)) { try { Files.createDirectories(newDirectory); } catch (IOException ioe) { throw new IOException("Failed to create directory: " + newDirectory + ". " + ioe); } } // Remove the old folder from the repository. FolderRepository repository = getController().getFolderRepository(); repository.removeFolder(folder, false); // Move it. if (moveContent) { PathUtils.recursiveMove(originalDirectory, newDirectory); } Path commitDir = null; boolean hasCommitDir = folder.getCommitDir() != null; if (hasCommitDir) { commitDir = newDirectory; newDirectory = newDirectory.resolve(Constants.ATOMIC_COMMIT_TEMP_TARGET_DIR); PathUtils.setAttributesOnWindows(newDirectory, true, true); } // Remember patterns if content not moving. List<String> patterns = null; if (!moveContent) { patterns = folder.getDiskItemFilter().getPatterns(); } // Create the new Folder in the repository. FolderInfo fi = new FolderInfo(folder); FolderSettings fs = new FolderSettings(newDirectory, folder.getSyncProfile(), folder.getDownloadScript(), folder.getFileArchiver().getVersionsPerFile(), folder.isSyncPatterns(), commitDir, folder.getSyncWarnSeconds()); folder = repository.createFolder(fi, fs); // Restore patterns if content not moved. if (!moveContent && patterns != null) { for (String pattern : patterns) { folder.addPattern(pattern); } } // Update with new folder info. update(); } catch (Exception e) { return e; } return null; } /** * Displays an error if the folder move failed. * * @param e * the error */ private void displayError(Exception e) { DialogFactory.genericDialog(getController(), Translation.getTranslation("settings_tab.move_error.title"), Translation.getTranslation("settings_tab.move_error.other", e.getMessage()), GenericDialogType.WARN); } /** * Listen to changes in onlineStorage / folder and enable the configOS * button as required. Also config action on whether already joined OS. */ private void enableConfigOSAction() { boolean enabled = false; if (folder != null && serverClient.isConnected() && serverClient.isLoggedIn()) { enabled = true; boolean osConfigured = serverClient.joinedByCloud(folder); if (osConfigured) { confOSActionLabel.setText(Translation.getTranslation("exp.action_stop_online_storage.name")); confOSActionLabel .setToolTipText(Translation.getTranslation("exp.action_stop_online_storage.description")); } else { confOSActionLabel.setText(Translation.getTranslation("exp.action_backup_online_storage.name")); confOSActionLabel .setToolTipText(Translation.getTranslation("exp.action_backup_online_storage.description")); } } confOSAction.allowWith(FolderPermission.admin(folder.getInfo())); confOSActionLabel.getUIComponent().setVisible(enabled); } /** * Listen to changes in onlineStorage / folder and enable the configOS * button as required. Also config action on whether already joined OS. */ private void enablePreviewFolderAction() { boolean enabled = false; if (folder != null) { enabled = true; if (folder.isPreviewOnly()) { previewFolderActionLabel.setText(Translation.getTranslation("exp.action_stop_preview_folder.name")); previewFolderActionLabel .setToolTipText(Translation.getTranslation("exp.action_stop_preview_folder.description")); } else { previewFolderActionLabel.setText(Translation.getTranslation("exp.action_preview_folder.name")); previewFolderActionLabel .setToolTipText(Translation.getTranslation("exp.action_preview_folder.description")); } } previewFolderActionLabel.getUIComponent().setVisible(enabled); } private void updateLocalArchiveMode(Object oldValue, final Object newValue) { Integer versions = (Integer) localVersionModel.getValue(); folder.setArchiveVersions(versions); // If the versions is reduced, offer to delete excess. if (newValue != null && oldValue != null && newValue instanceof Integer && oldValue instanceof Integer && (Integer) newValue < (Integer) oldValue && (Integer) newValue > -1) { SwingUtilities.invokeLater(new Runnable() { public void run() { int i = DialogFactory.genericDialog(getController(), Translation.getTranslation("exp.settings_tab.offer_maintenance.title"), Translation.getTranslation("exp.settings_tab.offer_maintenance.text"), new String[] { Translation.getTranslation("exp.settings_tab.offer_maintenance.cleanup_button"), Translation.getTranslation("general.cancel") }, 0, GenericDialogType.QUESTION); if (i == 0) { SwingWorker worker = new MyMaintainSwingWorker(); worker.execute(); } } }); } } public static void doPreviewChange(Controller controller, Folder fldr) { if (fldr.isPreviewOnly()) { // Join preview folder. PreviewToJoinDialog panel = new PreviewToJoinDialog(controller, fldr); panel.open(); } else { int result = DialogFactory.genericDialog(controller, Translation.getTranslation("exp.settings_tab.preview_warning_title"), Translation.getTranslation("exp.settings_tab.preview_warning_message"), new String[] { Translation.getTranslation("exp.settings_tab.preview_warning_convert"), Translation.getTranslation("general.cancel") }, 0, GenericDialogType.WARN); if (result == 0) { // Convert to preview // Convert folder to preview. FolderPreviewHelper.convertFolderToPreview(controller, fldr); } } } private void purgeLocalArchive() { if (folder == null) { logSevere("Calling purgeArchive with no folder???"); } else { int result = DialogFactory.genericDialog(getController(), Translation.getTranslation("settings_tab.purge_archive_title"), Translation.getTranslation("settings_tab.purge_archive_message"), new String[] { Translation.getTranslation("settings_tab.purge_archive_purge"), Translation.getTranslation("general.cancel") }, 0, GenericDialogType.WARN); if (result == 0) { // Purge try { folder.getFileArchiver().purge(); } catch (IOException e) { logSevere(e); DialogFactory.genericDialog(getController(), Translation.getTranslation("settings_tab.purge_archive_title"), Translation.getTranslation("settings_tab.purge_archive_problem"), GenericDialogType.ERROR); } } } } private void purgeOnlineArchive() { if (folder == null) { logSevere("Calling purgeArchive with no folder???"); } else { int result = DialogFactory.genericDialog(getController(), Translation.getTranslation("settings_tab.purge_archive_title"), Translation.getTranslation("settings_tab.purge_archive_message"), new String[] { Translation.getTranslation("settings_tab.purge_archive_purge"), Translation.getTranslation("general.cancel") }, 0, GenericDialogType.WARN); if (result == 0) { // Purge try { serverClient.getFolderService().purgeArchive(folder.getInfo()); } catch (Exception e) { logSevere(e); DialogFactory.genericDialog(getController(), Translation.getTranslation("settings_tab.purge_archive_title"), Translation.getTranslation("settings_tab.purge_archive_problem"), GenericDialogType.ERROR); } } } } // //////////////// // Inner Classes // // //////////////// /** * Local class to handle action events. */ private class MyActionListener implements ActionListener { public void actionPerformed(ActionEvent e) { if (!settingFolder) { if (e.getSource().equals(localFolderButton)) { moveLocalFolder(); } else if (e.getSource().equals(syncPatternsCheckBox)) { folder.setSyncPatterns(syncPatternsCheckBox.isSelected()); } } } } /** * Visualisation worker for folder move. */ private class MyActivityVisualizationWorker extends ActivityVisualizationWorker { private final boolean moveContent; private final Path originalDirectory; private final Path newDirectory; MyActivityVisualizationWorker(boolean moveContent, Path originalDirectory, Path newDirectory) { super(getUIController()); this.moveContent = moveContent; this.originalDirectory = originalDirectory; this.newDirectory = newDirectory; } @Override public Object construct() { return transferFolder(moveContent, originalDirectory, newDirectory); } @Override protected String getTitle() { return Translation.getTranslation("settings_tab.working.title"); } @Override protected String getWorkingText() { return Translation.getTranslation("settings_tab.working.description"); } @Override public void finished() { if (get() != null) { displayError((Exception) get()); } } } private class RemoveFolderAction extends BaseAction { private RemoveFolderAction(Controller controller) { super("action_remove_folder", controller); } public void actionPerformed(ActionEvent e) { FolderRemoveDialog panel = new FolderRemoveDialog(getController(), folder.getInfo()); panel.open(); } } private class PreviewFolderAction extends BaseAction { private PreviewFolderAction(Controller controller) { super("exp.action_preview_folder", controller); } public void actionPerformed(ActionEvent e) { doPreviewChange(getController(), folder); } } private class FolderOnlineStorageAction extends BaseAction { private FolderOnlineStorageAction(Controller controller) { super("exp.action_backup_online_storage", controller); } public void actionPerformed(ActionEvent e) { // FolderOnlineStoragePanel knows if folder already joined :-) PFWizard.openMirrorFolderWizard(getController(), folder); } } private class MaintainFolderAction extends BaseAction { private MaintainFolderAction(Controller controller) { super("exp.action_maintain_folder_db", controller); } public void actionPerformed(ActionEvent e) { MaintainFolderAction.this.setEnabled(false); getController().getIOProvider().startIO(new Runnable() { public void run() { folder.broadcastMessages(new FolderDBMaintCommando(folder.getInfo(), new Date())); folder.maintainFolderDB(System.currentTimeMillis()); EventQueue.invokeLater(new Runnable() { public void run() { setEnabled(true); //TODO: Add dialog DialogFactory.genericDialog(getController(), "Cleanup Database", Translation.getTranslation("database_cleanup_finished"), GenericDialogType.INFO); } }); } }); } } private class MyPatternChangeListener implements DiskItemFilterListener { public void patternAdded(PatternChangedEvent e) { rebuildPatterns(); } public void patternRemoved(PatternChangedEvent e) { rebuildPatterns(); } public boolean fireInEventDispatchThread() { return true; } } /** * Listener to ServerClient for connection changes. */ private class MyServerClientListener implements ServerClientListener { public void login(ServerClientEvent event) { enableConfigOSAction(); loadOnlineArchiveMode(); } public void accountUpdated(ServerClientEvent event) { enableConfigOSAction(); loadOnlineArchiveMode(); } public void serverConnected(ServerClientEvent event) { enableConfigOSAction(); loadOnlineArchiveMode(); } public void serverDisconnected(ServerClientEvent event) { enableConfigOSAction(); loadOnlineArchiveMode(); } public void nodeServerStatusChanged(ServerClientEvent event) { enableConfigOSAction(); loadOnlineArchiveMode(); } public boolean fireInEventDispatchThread() { return true; } } private class MyFolderMembershipListener implements FolderMembershipListener { public void memberJoined(FolderMembershipEvent folderEvent) { if (getController().getOSClient().isClusterServer(folderEvent.getMember())) { enableConfigOSAction(); } } public void memberLeft(FolderMembershipEvent folderEvent) { if (getController().getOSClient().isClusterServer(folderEvent.getMember())) { enableConfigOSAction(); } } public boolean fireInEventDispatchThread() { return true; } } /** * opens a popup, input dialog to edit the selected pattern */ private class EditAction extends BaseAction { EditAction(Controller controller) { super("action_edit_ignore", controller); } public void actionPerformed(ActionEvent e) { String text = Translation.getTranslation("exp.settings_tab.edit_a_pattern.text"); String title = Translation.getTranslation("exp.settings_tab.edit_a_pattern.title"); String pattern = (String) JOptionPane.showInputDialog(UIUtil.getParentWindow(e), text, title, JOptionPane.PLAIN_MESSAGE, null, null, // the text to edit: selectionModel.getSelection()); if (!StringUtils.isBlank(pattern)) { folder.removePattern((String) selectionModel.getSelection()); folder.addPattern(pattern); getController().getTransferManager().checkActiveTranfersForExcludes(); // Trigger resync getController().getFolderRepository().getFileRequestor().triggerFileRequesting(folder.getInfo()); } patternsList.getSelectionModel().clearSelection(); } } /** * Add a pattern to the backlist, opens a input dialog so user can enter * one. */ private class AddAction extends BaseAction { private AddAction(Controller controller) { super("action_add_ignore", controller); // #2054 setIcon(Icons.getIconById("action_remove_ignore.icon")); } public void actionPerformed(ActionEvent e) { showAddPane(Translation.getTranslation("exp.settings_tab.add_a_pattern.example")); } } /** * removes the selected pattern from the blacklist */ private class RemoveAction extends BaseAction { private RemoveAction(Controller controller) { super("action_remove_ignore", controller); // #2054 setIcon(Icons.getIconById("action_add_ignore.icon")); } public void actionPerformed(ActionEvent e) { for (Object object : selectionModel.getSelections()) { String selection = (String) object; folder.removePattern(selection); // Trigger resync getController().getFolderRepository().getFileRequestor().triggerFileRequesting(folder.getInfo()); } patternsList.getSelectionModel().clearSelection(); } } /** * Action listener for the location button. Opens a choose dir dialog and * sets the location model with the result. */ private class SelectScriptAction extends AbstractAction { public void actionPerformed(ActionEvent e) { String initial = (String) scriptModel.getValue(); JFileChooser chooser = DialogFactory.createFileChooser(); chooser.setSelectedFile(Paths.get(initial).toFile()); int res = chooser.showDialog(getUIController().getMainFrame().getUIComponent(), Translation.getTranslation("general.select")); if (res == JFileChooser.APPROVE_OPTION) { String script = chooser.getSelectedFile().getAbsolutePath(); scriptModel.setValue(script); } } } private class MyLocalValueChangeListener implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent evt) { if (evt.getSource() == localVersionModel) { if (!settingFolder) { updateLocalArchiveMode(evt.getOldValue(), evt.getNewValue()); } } } } private class MyOnlineValueChangeListener implements PropertyChangeListener { public void propertyChange(PropertyChangeEvent evt) { if (evt.getSource() == onlineVersionModel) { if (!updatingOnlineArchiveMode) { SwingWorker worker = new MyUpdaterSwingWorker(); worker.execute(); } } } } /** * Maintain the folder archive. */ private class MyMaintainSwingWorker extends SwingWorker { public Object doInBackground() { try { return folder.getFileArchiver().maintain(); } catch (Exception e) { logSevere(e); return null; } } } /** * Update the online archive version details. */ private class MyUpdaterSwingWorker extends SwingWorker { protected Object doInBackground() throws Exception { try { if (folder == null || settingFolder) { return null; } FolderInfo folderInfo = folder.getInfo(); FolderService folderService = serverClient.isLoggedIn() && serverClient.isConnected() ? serverClient.getFolderService() : null; if (folderService != null && serverClient.joinedByCloud(folder)) { Integer versions = (Integer) onlineVersionModel.getValue(); folderService.setArchiveMode(folderInfo, versions); } } catch (Exception e) { logWarning(e); } return null; } } /** * Update the online archive component with online details. */ private class MyServerModeSwingWorker extends SwingWorker { private final FolderInfo folderInfo; private MyServerModeSwingWorker(FolderInfo folderInfo) { this.folderInfo = folderInfo; } public Object doInBackground() { try { onlineArchiveModeSelectorPanel.getUIComponent().setVisible(false); onlineLabel.setVisible(false); if (folderInfo != null) { FolderService folderService = serverClient.getFolderService(); int perFile = folderService.getVersionsPerFile(folderInfo); updatingOnlineArchiveMode = true; onlineArchiveModeSelectorPanel.setArchiveMode(perFile); onlineArchiveModeSelectorPanel.getUIComponent().setVisible(true); onlineLabel.setVisible(true); } } catch (Exception e) { logWarning(e.toString()); return null; } finally { updatingOnlineArchiveMode = false; } return null; } } private class LocalPurgeListener implements ActionListener { public void actionPerformed(ActionEvent e) { purgeLocalArchive(); } } private class OnlinePurgeListener implements ActionListener { public void actionPerformed(ActionEvent e) { new SwingWorker() { protected Object doInBackground() throws Exception { purgeOnlineArchive(); return null; } }.execute(); } } }