de.blizzy.backup.settings.SettingsDialog.java Source code

Java tutorial

Introduction

Here is the source code for de.blizzy.backup.settings.SettingsDialog.java

Source

/*
blizzy's Backup - Easy to use personal file backup application
Copyright (C) 2011-2012 Maik Schreiber
    
This program 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.
    
This program 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 de.blizzy.backup.settings;

import java.io.File;
import java.text.DateFormat;
import java.util.Calendar;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ListViewer;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.DropTargetListener;
import org.eclipse.swt.dnd.FileTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.DateTime;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Spinner;
import org.eclipse.swt.widgets.Text;

import de.blizzy.backup.BackupApplication;
import de.blizzy.backup.BackupPlugin;
import de.blizzy.backup.Messages;
import de.blizzy.backup.Utils;
import de.blizzy.backup.vfs.ILocation;
import de.blizzy.backup.vfs.ILocationProvider;
import de.blizzy.backup.vfs.LocationProviderDescriptor;
import de.blizzy.backup.vfs.filesystem.FileSystemFileOrFolder;
import de.blizzy.backup.vfs.filesystem.FileSystemLocationProvider;

public class SettingsDialog extends Dialog {
    private ListViewer foldersViewer;
    private Text outputFolderText;
    private Button runHourlyRadio;
    private DateTime dailyTime;
    private Button fileCompareMetadataRadio;
    private Button fileCompareChecksumRadio;
    private Label scheduleExplanationLabel;
    private Button maxAgeDaysRadio;
    private Spinner maxAgeDaysSpinner;
    private Spinner maxDiskFillRateSpinner;

    public SettingsDialog(Shell parentShell) {
        super(parentShell);
    }

    @Override
    protected void configureShell(Shell newShell) {
        super.configureShell(newShell);
        newShell.setImages(BackupApplication.getWindowImages());
        newShell.setText(Messages.Title_Settings);
    }

    @Override
    protected boolean isResizable() {
        return true;
    }

    @Override
    protected Control createDialogArea(Composite parent) {
        Settings settings = BackupApplication.getSettingsManager().getSettings();

        Composite composite = (Composite) super.createDialogArea(parent);
        ((GridLayout) composite.getLayout()).numColumns = 1;
        ((GridLayout) composite.getLayout()).verticalSpacing = 10;

        Group foldersComposite = new Group(composite, SWT.NONE);
        foldersComposite.setText(Messages.Title_FoldersToBackup);
        foldersComposite.setLayout(new GridLayout(2, false));
        foldersComposite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));

        foldersViewer = new ListViewer(foldersComposite, SWT.MULTI | SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
        foldersViewer.setContentProvider(new ArrayContentProvider());
        foldersViewer.setLabelProvider(new FoldersLabelProvider());
        foldersViewer.setSorter(new ViewerSorter() {
            @Override
            public int compare(Viewer viewer, Object e1, Object e2) {
                return ((ILocation) e1).getDisplayName().compareToIgnoreCase(((ILocation) e2).getDisplayName());
            }
        });
        GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
        gd.widthHint = convertWidthInCharsToPixels(60);
        gd.heightHint = convertHeightInCharsToPixels(10);
        foldersViewer.getControl().setLayoutData(gd);
        foldersViewer.setInput(new HashSet<>(settings.getLocations()));

        Composite folderButtonsComposite = new Composite(foldersComposite, SWT.NONE);
        GridLayout layout = new GridLayout(1, false);
        layout.marginWidth = 0;
        layout.marginHeight = 0;
        folderButtonsComposite.setLayout(layout);
        folderButtonsComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, false, false));

        for (final LocationProviderDescriptor descriptor : BackupPlugin.getDefault().getLocationProviders()) {
            Button button = new Button(folderButtonsComposite, SWT.PUSH);
            button.setText(NLS.bind(Messages.Button_AddX, descriptor.getName()));
            button.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
            button.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {
                    addFolder(descriptor.getLocationProvider());
                }
            });
        }

        final Button removeFolderButton = new Button(folderButtonsComposite, SWT.PUSH);
        removeFolderButton.setText(Messages.Button_Remove);
        removeFolderButton.setEnabled(false);
        removeFolderButton.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

        Label label = new Label(foldersComposite, SWT.NONE);
        label.setText(Messages.DropFoldersHelp);
        gd = new GridData(SWT.LEFT, SWT.CENTER, false, false);
        gd.horizontalSpan = 2;
        label.setLayoutData(gd);

        Group outputFolderComposite = new Group(composite, SWT.NONE);
        outputFolderComposite.setText(Messages.Title_OutputFolder);
        outputFolderComposite.setLayout(new GridLayout(3, false));
        outputFolderComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));

        label = new Label(outputFolderComposite, SWT.NONE);
        label.setText(Messages.Label_BackupOutputFolder + ":"); //$NON-NLS-1$
        label.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));

        outputFolderText = new Text(outputFolderComposite, SWT.BORDER | SWT.READ_ONLY);
        outputFolderText.setText(StringUtils.defaultString(settings.getOutputFolder()));
        outputFolderText.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

        Button browseOutputFolderButton = new Button(outputFolderComposite, SWT.PUSH);
        browseOutputFolderButton.setText(Messages.Button_Browse + "..."); //$NON-NLS-1$
        browseOutputFolderButton.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));

        Group scheduleComposite = new Group(composite, SWT.NONE);
        scheduleComposite.setText(Messages.Title_WhenToBackup);
        scheduleComposite.setLayout(new GridLayout(2, false));
        scheduleComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));

        runHourlyRadio = new Button(scheduleComposite, SWT.RADIO);
        runHourlyRadio.setText(Messages.Label_RunHourly);
        gd = new GridData(SWT.LEFT, SWT.CENTER, false, false);
        gd.horizontalSpan = 2;
        runHourlyRadio.setLayoutData(gd);

        final Button runDailyRadio = new Button(scheduleComposite, SWT.RADIO);
        runDailyRadio.setText(Messages.Label_RunDaily + ":"); //$NON-NLS-1$
        runDailyRadio.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));

        dailyTime = new DateTime(scheduleComposite, SWT.TIME | SWT.SHORT);

        runHourlyRadio.setSelection(settings.isRunHourly());
        runDailyRadio.setSelection(!settings.isRunHourly());
        dailyTime.setHours(settings.getDailyHours());
        dailyTime.setMinutes(settings.getDailyMinutes());
        dailyTime.setEnabled(!settings.isRunHourly());

        Group fileComparisonComposite = new Group(composite, SWT.NONE);
        fileComparisonComposite.setText(Messages.Title_FileComparison);
        fileComparisonComposite.setLayout(new GridLayout(1, false));
        fileComparisonComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));

        fileCompareMetadataRadio = new Button(fileComparisonComposite, SWT.RADIO);
        fileCompareMetadataRadio.setText(Messages.CompareFilesMetadata);
        fileCompareMetadataRadio.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));

        fileCompareChecksumRadio = new Button(fileComparisonComposite, SWT.RADIO);
        fileCompareChecksumRadio.setText(Messages.CompareFilesChecksum);
        fileCompareChecksumRadio.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));

        fileCompareMetadataRadio.setSelection(!settings.isUseChecksums());
        fileCompareChecksumRadio.setSelection(settings.isUseChecksums());

        Group maxAgeComposite = new Group(composite, SWT.NONE);
        maxAgeComposite.setText(Messages.Title_MaximumBackupAge);
        maxAgeComposite.setLayout(new GridLayout(2, false));
        maxAgeComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));

        Button maxAgeUnlimitedRadio = new Button(maxAgeComposite, SWT.RADIO);
        maxAgeUnlimitedRadio.setText(Messages.Label_KeepAll);
        gd = new GridData(SWT.LEFT, SWT.CENTER, false, false);
        gd.horizontalSpan = 2;
        maxAgeUnlimitedRadio.setLayoutData(gd);

        maxAgeDaysRadio = new Button(maxAgeComposite, SWT.RADIO);
        maxAgeDaysRadio.setText(Messages.Label_DeleteAfterDays + ":"); //$NON-NLS-1$
        maxAgeDaysRadio.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));

        maxAgeDaysSpinner = new Spinner(maxAgeComposite, SWT.BORDER);
        maxAgeDaysSpinner.setMinimum(14);
        maxAgeDaysSpinner.setMaximum(365);

        maxAgeUnlimitedRadio.setSelection(settings.getMaxAgeDays() < 0);
        maxAgeDaysRadio.setSelection(settings.getMaxAgeDays() > 0);
        maxAgeDaysSpinner.setEnabled(settings.getMaxAgeDays() > 0);
        maxAgeDaysSpinner.setSelection(settings.getMaxAgeDays() > 0 ? settings.getMaxAgeDays() : 90);

        Group maxDiskFillRateComposite = new Group(composite, SWT.NONE);
        maxDiskFillRateComposite.setText(Messages.Title_MaximumDiskFillRate);
        maxDiskFillRateComposite.setLayout(new GridLayout(3, false));
        maxDiskFillRateComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));

        label = new Label(maxDiskFillRateComposite, SWT.NONE);
        label.setText(Messages.Label_DiskFillRate + ":"); //$NON-NLS-1$
        label.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));

        maxDiskFillRateSpinner = new Spinner(maxDiskFillRateComposite, SWT.BORDER);
        maxDiskFillRateSpinner.setMinimum(5);
        maxDiskFillRateSpinner.setMaximum(95);
        maxDiskFillRateSpinner.setSelection(settings.getMaxDiskFillRate());

        label = new Label(maxDiskFillRateComposite, SWT.NONE);
        label.setText("%"); //$NON-NLS-1$
        label.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));

        Group scheduleExplanationComposite = new Group(composite, SWT.NONE);
        scheduleExplanationComposite.setText(Messages.Title_ScheduleExplanation);
        scheduleExplanationComposite.setLayout(new GridLayout(1, false));
        scheduleExplanationComposite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false));

        scheduleExplanationLabel = new Label(scheduleExplanationComposite, SWT.NONE);
        scheduleExplanationLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
        updateExplanationLabel();

        foldersViewer.addSelectionChangedListener(new ISelectionChangedListener() {
            @Override
            public void selectionChanged(SelectionChangedEvent e) {
                removeFolderButton.setEnabled(!e.getSelection().isEmpty());
            }
        });

        removeFolderButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                removeFolder();
            }
        });

        browseOutputFolderButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                browseOutputFolder();
            }
        });

        runDailyRadio.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                dailyTime.setEnabled(runDailyRadio.getSelection());
                updateExplanationLabel();
            }
        });

        dailyTime.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                updateExplanationLabel();
            }
        });

        fileCompareChecksumRadio.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                showWarnings(fileCompareChecksumRadio);
            }
        });

        maxAgeDaysRadio.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                maxAgeDaysSpinner.setEnabled(maxAgeDaysRadio.getSelection());
                updateExplanationLabel();
            }
        });

        maxAgeDaysSpinner.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                maxAgeDaysSpinner.setEnabled(maxAgeDaysRadio.getSelection());
                updateExplanationLabel();
            }
        });

        maxDiskFillRateSpinner.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                updateExplanationLabel();
            }
        });

        DropTarget dropTarget = new DropTarget(foldersViewer.getControl(), DND.DROP_LINK);
        dropTarget.setTransfer(new Transfer[] { FileTransfer.getInstance() });
        dropTarget.addDropListener(new DropTargetListener() {
            @Override
            public void dragEnter(DropTargetEvent event) {
                if (FileTransfer.getInstance().isSupportedType(event.currentDataType)) {
                    event.detail = DND.DROP_LINK;
                    event.feedback = DND.FEEDBACK_SCROLL;
                } else {
                    event.detail = DND.DROP_NONE;
                }
            }

            @Override
            public void dragLeave(DropTargetEvent event) {
            }

            @Override
            public void dragOver(DropTargetEvent event) {
                if (FileTransfer.getInstance().isSupportedType(event.currentDataType)) {
                    event.detail = DND.DROP_LINK;
                    event.feedback = DND.FEEDBACK_SCROLL;
                } else {
                    event.detail = DND.DROP_NONE;
                }
            }

            @Override
            public void dropAccept(DropTargetEvent event) {
                if (FileTransfer.getInstance().isSupportedType(event.currentDataType)) {
                    event.detail = DND.DROP_LINK;
                    event.feedback = DND.FEEDBACK_SCROLL;
                } else {
                    event.detail = DND.DROP_NONE;
                }
            }

            @Override
            public void drop(DropTargetEvent event) {
                if (FileTransfer.getInstance().isSupportedType(event.currentDataType)) {
                    if (event.data != null) {
                        for (String file : (String[]) event.data) {
                            if (new File(file).isDirectory()) {
                                addFolder(
                                        FileSystemLocationProvider.location(Utils.toCanonicalFile(new File(file))));
                            }
                        }
                    } else {
                        event.detail = DND.DROP_NONE;
                    }
                } else {
                    event.detail = DND.DROP_NONE;
                }
            }

            @Override
            public void dragOperationChanged(DropTargetEvent event) {
                if (FileTransfer.getInstance().isSupportedType(event.currentDataType)) {
                    event.detail = DND.DROP_LINK;
                    event.feedback = DND.FEEDBACK_SCROLL;
                } else {
                    event.detail = DND.DROP_NONE;
                }
            }
        });

        return composite;
    }

    private void showWarnings(Control selectedControl) {
        if ((selectedControl == fileCompareChecksumRadio) && fileCompareChecksumRadio.getSelection()) {
            MessageDialog.openInformation(getShell(), Messages.Title_Information, Messages.Warning_CompareChecksum);
        }
    }

    private void addFolder(ILocationProvider provider) {
        ILocation newLocation = provider.promptLocation(getShell());
        if (newLocation != null) {
            addFolder(newLocation);
        }
    }

    private void addFolder(ILocation location) {
        @SuppressWarnings("unchecked")
        Set<ILocation> locations = (Set<ILocation>) foldersViewer.getInput();

        // is the new folder a child of any folder in the backup? if so, display error message
        for (ILocation oldLocation : locations) {
            if (Utils.isParent(oldLocation.getRootFolder(), location.getRootFolder())) {
                MessageDialog.openError(getShell(), Messages.Title_FolderCannotBeAdded,
                        NLS.bind(Messages.ParentFolderInBackup, Utils.getSimpleName(location.getRootFolder())));
                return;
            }
        }

        // is the new folder the parent of the output folder? if so, display error message
        String outputFolder = StringUtils.defaultString(outputFolderText.getText());
        if (StringUtils.isNotBlank(outputFolder)
                && Utils.isParent(location.getRootFolder(), new FileSystemFileOrFolder(new File(outputFolder)))) {

            MessageDialog.openError(getShell(), Messages.Title_FolderCannotBeAdded,
                    NLS.bind(Messages.FolderIsParentOfBackupFolder, Utils.getSimpleName(location.getRootFolder())));
            return;
        }

        // is the new folder the same as the output folder? if so, display error message
        if (StringUtils.isNotBlank(outputFolder)
                && location.getRootFolder().equals(new FileSystemFileOrFolder(new File(outputFolder)))) {

            MessageDialog.openError(getShell(), Messages.Title_FolderCannotBeAdded,
                    NLS.bind(Messages.FolderIsOutputFolder, Utils.getSimpleName(location.getRootFolder())));
            return;
        }

        // is the new folder a child of the output folder? if so, display error message
        if (StringUtils.isNotBlank(outputFolder)
                && Utils.isParent(new FileSystemFileOrFolder(new File(outputFolder)), location.getRootFolder())) {

            MessageDialog.openError(getShell(), Messages.Title_FolderCannotBeAdded,
                    NLS.bind(Messages.FolderIsChildOfOutputFolder, Utils.getSimpleName(location.getRootFolder())));
            return;
        }

        // is the new folder the parent of any folder in the backup? if so, remove those folders
        for (ILocation oldLocation : new HashSet<>(locations)) {
            if (Utils.isParent(location.getRootFolder(), oldLocation.getRootFolder())) {
                locations.remove(oldLocation);
                foldersViewer.remove(oldLocation);
            }
        }

        if (locations.add(location)) {
            foldersViewer.add(location);
        }
    }

    private void removeFolder() {
        @SuppressWarnings("unchecked")
        List<String> selectedFolders = ((IStructuredSelection) foldersViewer.getSelection()).toList();
        @SuppressWarnings("unchecked")
        Set<ILocation> folders = (Set<ILocation>) foldersViewer.getInput();
        folders.removeAll(selectedFolders);
        foldersViewer.remove(selectedFolders.toArray(new ILocation[0]));
    }

    private void browseOutputFolder() {
        @SuppressWarnings("unchecked")
        Set<ILocation> locations = (Set<ILocation>) foldersViewer.getInput();
        String folder = outputFolderText.getText();
        if (StringUtils.isEmpty(folder)) {
            folder = null;
        }
        dialogLoop: for (;;) {
            DirectoryDialog dlg = new DirectoryDialog(getShell(), SWT.SAVE);
            dlg.setText(Messages.Title_SelectOutputFolder);
            dlg.setFilterPath(folder);
            folder = dlg.open();
            if (folder == null) {
                break;
            }

            if (Utils.isBackupFolder(folder)) {
                if (MessageDialog.openConfirm(getShell(), Messages.Title_ExistingBackup,
                        NLS.bind(Messages.FolderContainsExistingBackup,
                                Utils.getSimpleName(new FileSystemFileOrFolder(new File(folder)))))) {

                    break;
                } else {
                    continue;
                }
            }

            // does folder contain files? if so, display error message
            if (new File(folder).list().length > 0) {
                MessageDialog.openError(getShell(), Messages.Title_InvalidFolder, NLS.bind(Messages.FolderNotEmpty,
                        Utils.getSimpleName(new FileSystemFileOrFolder(new File(folder)))));
                continue;
            }

            // display error message if:
            // - folder is the same as any folder in the backup
            // - folder is a child of any folder in the backup
            for (ILocation oldLocation : locations) {
                if (new FileSystemFileOrFolder(new File(folder)).equals(oldLocation.getRootFolder()) || Utils
                        .isParent(oldLocation.getRootFolder(), new FileSystemFileOrFolder(new File(folder)))) {

                    MessageDialog.openError(getShell(), Messages.Title_InvalidFolder,
                            NLS.bind(Messages.OutputFolderIsInBackup,
                                    Utils.getSimpleName(new FileSystemFileOrFolder(new File(folder)))));
                    continue dialogLoop;
                }
            }

            break;
        }
        if (folder != null) {
            outputFolderText.setText(folder);
        }
    }

    private void updateExplanationLabel() {
        DateFormat timeFormat = DateFormat.getTimeInstance(DateFormat.SHORT);
        Calendar c = Calendar.getInstance();
        c.set(Calendar.HOUR_OF_DAY, dailyTime.getHours());
        c.set(Calendar.MINUTE, dailyTime.getMinutes());
        scheduleExplanationLabel.setText("- " + (runHourlyRadio.getSelection() ? //$NON-NLS-1$
                Messages.ScheduleExplanation_HourlyBackups
                : NLS.bind(Messages.ScheduleExplanation_DailyBackups, timeFormat.format(c.getTime()))) + "\n" + //$NON-NLS-1$
                (runHourlyRadio.getSelection() ? "- " + //$NON-NLS-1$
                        NLS.bind(Messages.ScheduleExplanation_HourlyBackupsKeepTime,
                                Integer.valueOf(BackupPlugin.KEEP_HOURLIES_DAYS))
                        + "\n" : //$NON-NLS-1$
                        "") //$NON-NLS-1$
                + "- " + NLS.bind(Messages.ScheduleExplanation_DailyBackupsKeepTime,
                        Integer.valueOf(BackupPlugin.KEEP_DAILIES_DAYS))
                + "\n" + //$NON-NLS-1$
                "- " + (maxAgeDaysRadio.getSelection() ? //$NON-NLS-1$
                        NLS.bind(Messages.ScheduleExplanation_WeeklyBackupsKeepDays,
                                Integer.valueOf(maxAgeDaysSpinner.getSelection()))
                        : Messages.ScheduleExplanation_WeeklyBackupsNoAge)
                + "\n" + //$NON-NLS-1$
                "- " + //$NON-NLS-1$
                NLS.bind(Messages.ScheduleExplanation_WeeklyBackupsKeepDisk,
                        Integer.valueOf(maxDiskFillRateSpinner.getSelection()))
                +
                // compensate for missing line
                (!runHourlyRadio.getSelection() ? "\n " : "")); //$NON-NLS-1$ //$NON-NLS-2$
    }

    @Override
    protected void buttonPressed(int buttonId) {
        if (buttonId == IDialogConstants.OK_ID) {
            @SuppressWarnings("unchecked")
            Set<ILocation> folders = (Set<ILocation>) foldersViewer.getInput();
            String outputFolder = outputFolderText.getText();
            if (StringUtils.isBlank(outputFolder)) {
                outputFolder = null;
            }
            Settings settings = new Settings(folders, outputFolder, runHourlyRadio.getSelection(),
                    dailyTime.getHours(), dailyTime.getMinutes(), fileCompareChecksumRadio.getSelection(),
                    maxAgeDaysRadio.getSelection() ? maxAgeDaysSpinner.getSelection() : -1,
                    maxDiskFillRateSpinner.getSelection());
            BackupApplication.getSettingsManager().setSettings(settings);
        }

        super.buttonPressed(buttonId);
    }
}