/* * 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$ */ package de.dal33t.powerfolder.ui.panel; import java.awt.Component; import java.awt.event.ActionEvent; import java.awt.event.ItemEvent; import java.awt.event.ItemListener; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.ArrayList; import java.util.List; import javax.swing.JComboBox; import javax.swing.JPanel; import com.jgoodies.binding.value.ValueHolder; import com.jgoodies.binding.value.ValueModel; import com.jgoodies.forms.layout.CellConstraints; import com.jgoodies.forms.layout.FormLayout; import de.dal33t.powerfolder.Controller; import de.dal33t.powerfolder.disk.Folder; import de.dal33t.powerfolder.disk.SyncProfile; import de.dal33t.powerfolder.security.ChangeTransferModePermission; import de.dal33t.powerfolder.ui.WikiLinks; import de.dal33t.powerfolder.ui.action.BaseAction; import de.dal33t.powerfolder.ui.dialog.CreateEditSyncProfileDialog; import de.dal33t.powerfolder.ui.dialog.DeleteSyncProfileDialog; import de.dal33t.powerfolder.ui.dialog.DialogFactory; import de.dal33t.powerfolder.ui.dialog.GenericDialogType; import de.dal33t.powerfolder.ui.model.BoundPermission; import de.dal33t.powerfolder.ui.widget.JButtonMini; import de.dal33t.powerfolder.ui.PFUIComponent; import de.dal33t.powerfolder.ui.util.Help; import de.dal33t.powerfolder.util.Translation; /** * Panel for displaying selected sync profile and opening the * CustomSyncProfileDialog. * * @author <a href="mailto:hglasgow@powerfolder.com">Harry Glasgow</a> * @version $Revision: 2.01 $ */ public class SyncProfileSelectorPanel extends PFUIComponent { private JComboBox syncProfilesCombo; private JPanel panel; private ValueModel valueModel; private Folder updateableFolder; private boolean ignoreChanges; private JButtonMini configureButton; private JButtonMini deleteButton; @SuppressWarnings("unused") // Held to prevent gc from collecting it. private BoundPermission changeModePermission; public SyncProfileSelectorPanel(Controller controller, SyncProfile syncProfile) { super(controller); initComponents(syncProfile); } public SyncProfileSelectorPanel(Controller controller) { this(controller, SyncProfile.getDefault(controller)); } /** * Builds panel and returns the component. * * @return the component. */ public Component getUIComponent() { if (panel == null) { buildPanel(); changeModePermission = new BoundPermission(getController(), ChangeTransferModePermission.INSTANCE) { @Override public void hasPermission(boolean hasPermission) { setEnabled(hasPermission); } }; } return panel; } /** * Sets a Folder that will have its syncProfile updated if the syncProfile * is changed on this panel. * * @param folder * the Folder to update. */ public void setUpdateableFolder(Folder folder) { updateableFolder = folder; configureCombo(folder.getSyncProfile()); } /** * Initialize the visual components. * * @param syncProfile */ private void initComponents(SyncProfile syncProfile) { syncProfilesCombo = new JComboBox(); syncProfilesCombo.addItemListener(new ItemListener() { public void itemStateChanged(ItemEvent e) { udateSyncProfile(); } }); valueModel = new ValueHolder(); valueModel.setValue(syncProfile); configureButton = new JButtonMini( new MyConfigureAction(getController())); deleteButton = new JButtonMini(new MyDeleteAction(getController())); configureCombo(syncProfile); // Warn if changing to delete type profiles addModelValueChangeListener(new PropertyChangeListener() { public void propertyChange(PropertyChangeEvent evt) { if (!isOkToSwitchToProfile((SyncProfile) evt.getNewValue())) { setSyncProfile((SyncProfile) evt.getOldValue(), false); } } }); enableButtons(); } private void udateSyncProfile() { // Don't update if the combo items are being re-entered. if (!ignoreChanges) { int i = syncProfilesCombo.getSelectedIndex(); if (i >= 0) { SyncProfile profile = SyncProfile.getSyncProfilesCopy().get(i); valueModel.setValue(profile); if (updateableFolder != null) { updateableFolder.setSyncProfile(profile); } // Configure delete for selection. enableButtons(); } } } private void enableButtons() { int i = syncProfilesCombo.getSelectedIndex(); if (i >= 0) { SyncProfile profile = SyncProfile.getSyncProfilesCopy().get(i); valueModel.setValue(profile); if (updateableFolder != null) { updateableFolder.setSyncProfile(profile); } } SyncProfile profile = (SyncProfile) valueModel.getValue(); deleteButton.setEnabled(profile != null && profile.isCustom()); configureButton.setEnabled(profile != null); } public void configureCombo(SyncProfile syncProfile) { // Don't process itemStateChange events. ignoreChanges = true; syncProfilesCombo.removeAllItems(); for (SyncProfile aSyncProfile : SyncProfile.getSyncProfilesCopy()) { syncProfilesCombo.addItem(aSyncProfile.getName()); if (syncProfile.equals(aSyncProfile)) { syncProfilesCombo.setSelectedItem(aSyncProfile.getName()); } } // Configure edit / delete for initial selection. enableButtons(); // Begin processing itemStateChange events again. ignoreChanges = false; } /** * Builds the visible panel. */ private void buildPanel() { int iconHeight = configureButton.getIcon().getIconHeight(); FormLayout layout = new FormLayout( "140dlu, 3dlu, pref, pref, pref, pref:grow", "max(pref;" + iconHeight + ')'); panel = new JPanel(layout); CellConstraints cc = new CellConstraints(); panel.add(syncProfilesCombo, cc.xy(1, 1)); panel.add(configureButton, cc.xy(3, 1)); panel.add(deleteButton, cc.xy(4, 1)); panel.add(Help.createWikiLinkButton(getController(), WikiLinks.TRANSFER_MODES), cc.xy(5, 1)); } /** * Shows a warning if the syncProfile will sync deletions. * * @param syncProfile * the syncProfile selected * @return true only if the profile doesn't sync deletion or the user * approved it */ public boolean isOkToSwitchToProfile(SyncProfile syncProfile) { // Don't hassel the user with too many warnings. It's ok! We got an // archive! return true; } /** * Sets the syncProfile on the panel. * * @param syncProfile * the SyncProfile * @param updateFolder * whether to update the folder. Should be true only when the * profile is changed by the CustomSyncProfileDialog */ public void setSyncProfile(SyncProfile syncProfile, boolean updateFolder) { valueModel.setValue(syncProfile); if (updateFolder) { if (updateableFolder != null) { updateableFolder.setSyncProfile(syncProfile); // Also need to persist for any other folders that have this // profile. This ensures that any minor changes are persisted // for all affected folders. for (Folder folder : getController().getFolderRepository() .getFolders()) { if (folder.getSyncProfile().equals(syncProfile) && !updateableFolder.equals(folder)) { folder.setSyncProfile(syncProfile); } } } } // Always reconfigure combo after setSyncProfile. // Cannot use a change listener becaue the sync profile name may have // changed, which is not a listen-able 'event' :-( configureCombo(syncProfile); } /** * Gets the SyncProfile * * @return the sync profile */ public SyncProfile getSyncProfile() { return (SyncProfile) valueModel.getValue(); } /** * Adds a value change listener for the sync profile model. This allows * things to react to changes. * * @param propertyChangeListener */ public void addModelValueChangeListener( PropertyChangeListener propertyChangeListener) { valueModel.addValueChangeListener(propertyChangeListener); } /** * Enable the components of the panel. * * @param enable */ public void setEnabled(boolean enable) { enableButtons(); syncProfilesCombo.setEnabled(enable); configureButton.setVisible(enable); deleteButton.setVisible(enable); } /** * Opens a CustomSyncProfileDialog to change the profile configuration. */ private void openCustomSyncProfileDialog(boolean create) { // If edit, count the number of folders that use this profile, // and warn if more than one. int response = 0; // Default to dialog OK if (!create) { List<Folder> folders = usedFolders(); if (folders.size() >= 2) { response = showDuplicates(folders, "dialog.synchronization.duplicate.edit"); } } if (response == 0) { // OK CreateEditSyncProfileDialog createEditSyncProfileDialog = new CreateEditSyncProfileDialog( getController(), this, create); createEditSyncProfileDialog.open(); } } public void deleteProfile() { List<Folder> folders = usedFolders(); int response = 0; // Default to dialog OK if (folders.size() >= 2) { response = showDuplicates(folders, "dialog.synchronization.duplicate.delete"); } if (response == 0) { // OK DeleteSyncProfileDialog deleteProfileDialog = new DeleteSyncProfileDialog( getController(), this); deleteProfileDialog.open(); } } /** * Show duplicate folders to user, warning. * * @param folders * @param messageKey * @return */ private int showDuplicates(List<Folder> folders, String messageKey) { String title = Translation .getTranslation("dialog.synchronization.duplicate.title"); StringBuilder sb = new StringBuilder(); int local = 0; for (Folder folder : folders) { sb.append(" "); if (local++ >= 10) { // Too many folders - enough!!! sb.append(Translation.getTranslation("general.more.lower_case") + "...\n"); break; } sb.append(folder.getName() + '\n'); } String message = Translation .getTranslation("dialog.synchronization.duplicate.use") + "\n\n" + sb.toString() + '\n' + Translation.getTranslation(messageKey); return DialogFactory.genericDialog( getController(), title, message, new String[]{"OK", "Cancel"}, 0, GenericDialogType.WARN); } private List<Folder> usedFolders() { List<Folder> folders = new ArrayList<Folder>(); SyncProfile syncProfile = getSyncProfile(); for (Folder folder : getController().getFolderRepository().getFolders()) { if (folder.getSyncProfile().equals(syncProfile)) { folders.add(folder); } } return folders; } private class MyConfigureAction extends BaseAction { private MyConfigureAction(Controller controller) { super("action_configure_transfer_mode", controller); } public void actionPerformed(ActionEvent e) { SyncProfile syncProfile = getSyncProfile(); if (syncProfile != null) { openCustomSyncProfileDialog(!syncProfile.isCustom()); } } } private class MyDeleteAction extends BaseAction { private MyDeleteAction(Controller controller) { super("action_delete_transfer_mode", controller); } public void actionPerformed(ActionEvent e) { SyncProfile syncProfile = getSyncProfile(); if (syncProfile != null) { deleteProfile(); } } } }