de.blizzy.backup.BackupShell.java Source code

Java tutorial

Introduction

Here is the source code for de.blizzy.backup.BackupShell.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;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.ToolBarManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.ShellAdapter;
import org.eclipse.swt.events.ShellEvent;
import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.FontData;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Link;
import org.eclipse.swt.widgets.ProgressBar;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolBar;

import de.blizzy.backup.backup.BackupEndedEvent;
import de.blizzy.backup.backup.BackupErrorEvent;
import de.blizzy.backup.backup.BackupRun;
import de.blizzy.backup.backup.BackupStatus;
import de.blizzy.backup.backup.BackupStatusEvent;
import de.blizzy.backup.backup.IBackupRunListener;
import de.blizzy.backup.restore.RestoreDialog;
import de.blizzy.backup.settings.ISettingsListener;
import de.blizzy.backup.settings.Settings;
import de.blizzy.backup.settings.SettingsDialog;

class BackupShell {
    private Shell shell;
    private Button restoreButton;
    private Button backupNowButton;
    private Button checkButton;
    private Composite progressComposite;
    private ProgressBar progressBar;
    private Link statusLabel;
    private BackupRun backupRun;
    private IBackupRunListener backupRunListener = new IBackupRunListener() {
        @Override
        public void backupStatusChanged(BackupStatusEvent e) {
            BackupStatus status = e.getStatus();
            updateStatusLabel(status);
            if (status.isCleanup() || status.isFinalize()) {
                pauseAction.setEnabled(false);
                stopAction.setEnabled(false);
            }
        }

        @Override
        public void backupEnded(BackupEndedEvent e) {
            backupRun.removeListener(this);
            backupRun = null;
            updateStatusLabel(null);
            updateRestoreButton();
            updateBackupNowButton();
            updateCheckButton();
            updateProgressVisibility();
            pauseAction.setChecked(false);
            pauseAction.setEnabled(true);
            stopAction.setEnabled(true);
        }

        @Override
        public void backupErrorOccurred(BackupErrorEvent e) {
            synchronized (backupErrors) {
                backupErrors.add(new BackupError(e));
            }
        }
    };
    private ISettingsListener settingsListener = new ISettingsListener() {
        @Override
        public void settingsChanged() {
            updateStatusLabel(null);
            updateRestoreButton();
            updateBackupNowButton();
            updateCheckButton();
        }
    };
    private IAction pauseAction;
    private IAction stopAction;
    private List<BackupError> backupErrors = new ArrayList<>();

    BackupShell(Display display) {
        shell = new Shell(display, SWT.SHELL_TRIM ^ SWT.MAX);
        shell.setText(Messages.Title_BlizzysBackup);
        shell.setImages(BackupApplication.getWindowImages());

        GridLayout layout = new GridLayout(1, false);
        layout.marginWidth = 20;
        layout.marginHeight = 20;
        layout.verticalSpacing = 15;
        shell.setLayout(layout);

        Composite logoAndHeaderComposite = new Composite(shell, SWT.NONE);
        layout = new GridLayout(2, false);
        layout.marginWidth = 0;
        layout.marginHeight = 0;
        layout.horizontalSpacing = 15;
        logoAndHeaderComposite.setLayout(layout);

        Canvas logoCanvas = new Canvas(logoAndHeaderComposite, SWT.DOUBLE_BUFFERED);
        logoCanvas.addPaintListener(new PaintListener() {
            @Override
            public void paintControl(PaintEvent e) {
                Image image = BackupPlugin.getDefault().getImageDescriptor("etc/logo/logo_48.png") //$NON-NLS-1$
                        .createImage(e.display);
                e.gc.drawImage(image, 0, 0);
                image.dispose();
            }
        });
        GridData gd = new GridData(SWT.CENTER, SWT.CENTER, false, false);
        gd.widthHint = 48;
        gd.heightHint = 48;
        logoCanvas.setLayoutData(gd);

        Link headerText = new Link(logoAndHeaderComposite, SWT.NONE);
        headerText.setText(NLS.bind(Messages.Version, BackupPlugin.VERSION, BackupPlugin.COPYRIGHT_YEARS));

        Composite buttonsComposite = new Composite(shell, SWT.NONE);
        layout = new GridLayout(2, false);
        layout.marginWidth = 0;
        layout.marginHeight = 0;
        layout.horizontalSpacing = 10;
        layout.verticalSpacing = 15;
        buttonsComposite.setLayout(layout);
        buttonsComposite.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));

        FontData[] fontDatas = buttonsComposite.getFont().getFontData();
        for (FontData fontData : fontDatas) {
            fontData.setHeight((int) (fontData.getHeight() * 1.5d));
        }
        final Font bigFont = new Font(display, fontDatas);

        Point extent = getMaxTextExtent(display, bigFont, Messages.Button_Settings, Messages.Button_Restore,
                Messages.Button_BackupNow);

        Button settingsButton = new Button(buttonsComposite, SWT.PUSH);
        settingsButton.setText(Messages.Button_Settings);
        settingsButton.setFont(bigFont);
        gd = new GridData(SWT.FILL, SWT.FILL, false, true);
        gd.widthHint = (int) (extent.x * 1.6d);
        gd.heightHint = extent.y * 2;
        settingsButton.setLayoutData(gd);

        Label label = new Label(buttonsComposite, SWT.NONE);
        label.setText(Messages.ModifyBackupSettings);
        label.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));

        restoreButton = new Button(buttonsComposite, SWT.PUSH);
        restoreButton.setText(Messages.Button_Restore);
        restoreButton.setFont(bigFont);
        gd = new GridData(SWT.FILL, SWT.FILL, false, true);
        gd.widthHint = (int) (extent.x * 1.6d);
        gd.heightHint = extent.y * 2;
        restoreButton.setLayoutData(gd);
        updateRestoreButton();

        label = new Label(buttonsComposite, SWT.NONE);
        label.setText(Messages.RestoreFromBackup);
        label.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));

        backupNowButton = new Button(buttonsComposite, SWT.PUSH);
        backupNowButton.setText(Messages.Button_BackupNow);
        backupNowButton.setFont(bigFont);
        gd = new GridData(SWT.FILL, SWT.FILL, false, true);
        gd.widthHint = (int) (extent.x * 1.6d);
        gd.heightHint = extent.y * 2;
        backupNowButton.setLayoutData(gd);
        updateBackupNowButton();

        label = new Label(buttonsComposite, SWT.NONE);
        label.setText(Messages.RunBackupNow);
        label.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));

        if (BackupPlugin.getDefault().isCheckGui()) {
            checkButton = new Button(buttonsComposite, SWT.PUSH);
            checkButton.setText(Messages.Button_Check);
            checkButton.setFont(bigFont);
            gd = new GridData(SWT.FILL, SWT.FILL, false, true);
            gd.widthHint = (int) (extent.x * 1.6d);
            gd.heightHint = extent.y * 2;
            checkButton.setLayoutData(gd);
            updateCheckButton();

            label = new Label(buttonsComposite, SWT.NONE);
            label.setText(Messages.CheckBackup);
            label.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));
        }

        Composite progressStatusComposite = new Composite(shell, SWT.NONE);
        layout = new GridLayout(1, false);
        layout.marginWidth = 0;
        layout.marginHeight = 0;
        progressStatusComposite.setLayout(layout);
        progressStatusComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

        progressComposite = new Composite(progressStatusComposite, SWT.NONE);
        layout = new GridLayout(3, false);
        layout.marginWidth = 0;
        layout.marginHeight = 0;
        progressComposite.setLayout(layout);
        progressComposite.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));

        progressBar = new ProgressBar(progressComposite, SWT.HORIZONTAL | SWT.SMOOTH);
        progressBar.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
        progressBar.setMinimum(0);
        updateProgressVisibility();

        ToolBarManager toolBarManager = new ToolBarManager(SWT.FLAT);

        pauseAction = new Action(Messages.Button_PauseBackup, IAction.AS_CHECK_BOX) {
            @Override
            public void run() {
                if (backupRun != null) {
                    backupRun.setPaused(pauseAction.isChecked());
                }
            }
        };
        ImageDescriptor imgDesc = BackupPlugin.getDefault().getImageDescriptor("etc/icons/pause.gif"); //$NON-NLS-1$
        pauseAction.setImageDescriptor(imgDesc);
        pauseAction.setToolTipText(Messages.Button_PauseBackup);
        toolBarManager.add(pauseAction);

        stopAction = new Action() {
            @Override
            public void run() {
                if (backupRun != null) {
                    pauseAction.setChecked(false);
                    pauseAction.setEnabled(false);
                    stopAction.setEnabled(false);
                    backupRun.stopBackup();
                }
            }
        };
        imgDesc = BackupPlugin.getDefault().getImageDescriptor("etc/icons/stop.gif"); //$NON-NLS-1$
        stopAction.setImageDescriptor(imgDesc);
        stopAction.setToolTipText(Messages.Button_StopBackup);
        toolBarManager.add(stopAction);

        ToolBar toolBar = toolBarManager.createControl(progressComposite);
        toolBar.setLayoutData(new GridData(SWT.CENTER, SWT.CENTER, false, false));

        statusLabel = new Link(progressStatusComposite, SWT.NONE);
        statusLabel.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
        updateStatusLabel(null);

        shell.pack();

        headerText.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                new LicenseDialog(shell).open();
            }
        });

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

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

        backupNowButton.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                BackupApplication.scheduleBackupRun(true);
            }
        });

        if (checkButton != null) {
            checkButton.addSelectionListener(new SelectionAdapter() {
                @Override
                public void widgetSelected(SelectionEvent e) {
                    BackupApplication.runCheck();
                }
            });
        }

        statusLabel.addSelectionListener(new SelectionAdapter() {
            @Override
            public void widgetSelected(SelectionEvent e) {
                if (e.text.equals("errors")) { //$NON-NLS-1$
                    showErrors();
                }
            }
        });

        shell.addDisposeListener(new DisposeListener() {
            @Override
            public void widgetDisposed(DisposeEvent e) {
                bigFont.dispose();
            }
        });

        shell.addShellListener(new ShellAdapter() {
            @Override
            public void shellClosed(ShellEvent e) {
                MessageDialog dlg = new MessageDialog(shell, Messages.Title_ExitApplication, null,
                        Messages.ExitApplication, MessageDialog.CONFIRM,
                        new String[] { Messages.Button_Exit, Messages.Button_MinimizeOnly }, 1);
                if (dlg.open() == 0) {
                    BackupApplication.quit();
                } else {
                    e.doit = false;
                    BackupApplication.hideShell();
                }
            }

            @Override
            public void shellIconified(ShellEvent e) {
                e.doit = false;
                BackupApplication.hideShell();
            }
        });

        shell.addDisposeListener(new DisposeListener() {
            @Override
            public void widgetDisposed(DisposeEvent e) {
                handleDispose();
            }
        });

        BackupApplication.getSettingsManager().addListener(settingsListener);

        settingsButton.forceFocus();
    }

    private void handleDispose() {
        if (backupRun != null) {
            backupRun.removeListener(backupRunListener);
        }
        BackupApplication.getSettingsManager().removeListener(settingsListener);
    }

    private void updateStatusLabel(final BackupStatus status) {
        Utils.runAsync(shell.getDisplay(), new Runnable() {
            @Override
            public void run() {
                if (!statusLabel.isDisposed()) {
                    String text;
                    if (status != null) {
                        int numEntries = status.getNumEntries();
                        int totalEntries = status.getTotalEntries();
                        synchronized (backupErrors) {
                            text = Messages.Label_Status + ": " + Messages.Running + " " + //$NON-NLS-1$ //$NON-NLS-2$
                            (((numEntries >= 0) && (totalEntries >= 0))
                                    ? ("(" + (int) Math.round(numEntries * 100d / totalEntries) + "%) ") //$NON-NLS-1$//$NON-NLS-2$
                                    : "") + //$NON-NLS-1$
                            (!backupErrors.isEmpty() ? "(<a href=\"errors\">" + Messages.Errors + "</a>) " : "") + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
                            "- " + //$NON-NLS-1$
                            status.getText();
                        }
                        if ((numEntries >= 0) && (totalEntries >= 0)) {
                            progressBar.setMaximum(totalEntries);
                            progressBar.setSelection(numEntries);
                        }
                    } else {
                        Date nextRunDate = new Date(BackupApplication.getNextScheduledBackupRunTime());
                        synchronized (backupErrors) {
                            text = Messages.Label_Status + ": " + Messages.Idle + " " + //$NON-NLS-1$ //$NON-NLS-2$
                            (!backupErrors.isEmpty() ? "(<a href=\"errors\">" + Messages.Errors + "</a>) " : "") + //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
                            "- " + Messages.Label_NextRun + ": " + //$NON-NLS-1$ //$NON-NLS-2$
                            DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.SHORT).format(nextRunDate);
                        }
                        progressBar.setMaximum(0);
                        progressBar.setSelection(0);
                    }
                    statusLabel.setText(text);
                }
            }
        });
    }

    private void updateRestoreButton() {
        Utils.runAsync(shell.getDisplay(), new Runnable() {
            @Override
            public void run() {
                if (!restoreButton.isDisposed()) {
                    Settings settings = BackupApplication.getSettingsManager().getSettings();
                    restoreButton
                            .setEnabled((backupRun == null) && Utils.isBackupFolder(settings.getOutputFolder()));
                }
            }
        });
    }

    private void updateBackupNowButton() {
        Utils.runAsync(shell.getDisplay(), new Runnable() {
            @Override
            public void run() {
                if (!backupNowButton.isDisposed()) {
                    backupNowButton
                            .setEnabled((backupRun == null) && BackupApplication.areSettingsOkayToRunBackup());
                }
            }
        });
    }

    private void updateCheckButton() {
        if (checkButton != null) {
            Utils.runAsync(shell.getDisplay(), new Runnable() {
                @Override
                public void run() {
                    if (!checkButton.isDisposed()) {
                        checkButton
                                .setEnabled((backupRun == null) && BackupApplication.areSettingsOkayToRunBackup());
                    }
                }
            });
        }
    }

    private void editSettings() {
        new SettingsDialog(shell).open();
    }

    private void restore() {
        new RestoreDialog(shell).open();
    }

    private Point getMaxTextExtent(Device device, Font font, String... strings) {
        Image buf = new Image(device, 1, 1);
        GC gc = new GC(buf);
        gc.setFont(font);
        Point result = new Point(0, 0);
        for (String string : strings) {
            Point extent = gc.textExtent(string);
            result.x = Math.max(result.x, extent.x);
            result.y = Math.max(result.y, extent.y);
        }
        gc.dispose();
        buf.dispose();
        return result;
    }

    void open() {
        shell.open();
    }

    void forceActive() {
        shell.setMinimized(false);
        shell.setActive();
    }

    void setVisible(boolean visible) {
        shell.setVisible(visible);
    }

    void setBackupRun(BackupRun backupRun) {
        this.backupRun = backupRun;
        backupRun.addListener(backupRunListener);
        updateRestoreButton();
        updateBackupNowButton();
        updateCheckButton();
        updateProgressVisibility();
    }

    private void updateProgressVisibility() {
        Utils.runAsync(shell.getDisplay(), new Runnable() {
            @Override
            public void run() {
                if (!progressComposite.isDisposed()) {
                    progressComposite.setVisible(backupRun != null);
                }
            }
        });
    }

    private void showErrors() {
        List<BackupError> errors;
        synchronized (backupErrors) {
            errors = new ArrayList<>(backupErrors);
        }
        ErrorsDialog dlg = new ErrorsDialog(shell, errors);
        dlg.open();
        if (dlg.isClearErrors()) {
            synchronized (backupErrors) {
                backupErrors.clear();
            }
            BackupApplication.resetTrayIconErrors();
            if (backupRun == null) {
                updateStatusLabel(null);
            }
        }
    }

    Shell getShell() {
        return shell;
    }
}