net.sourceforge.ganttproject.document.webdav.GanttURLChooser.java Source code

Java tutorial

Introduction

Here is the source code for net.sourceforge.ganttproject.document.webdav.GanttURLChooser.java

Source

/*
GanttProject is an opensource project management tool. License: GPL3
Copyright (C) 2003-2012 GanttProject Team
    
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, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

package net.sourceforge.ganttproject.document.webdav;

import io.milton.http.exceptions.NotAuthorizedException;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
import java.util.concurrent.ExecutionException;

import javax.swing.Action;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.SpringLayout;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;

import net.sourceforge.ganttproject.GPLogger;
import net.sourceforge.ganttproject.IGanttProject;
import net.sourceforge.ganttproject.action.CancelAction;
import net.sourceforge.ganttproject.action.GPAction;
import net.sourceforge.ganttproject.action.OkAction;
import net.sourceforge.ganttproject.document.webdav.WebDavResource.WebDavException;
import net.sourceforge.ganttproject.gui.UIFacade;
import net.sourceforge.ganttproject.gui.UIUtil;
import net.sourceforge.ganttproject.gui.options.OptionsPageBuilder;
import net.sourceforge.ganttproject.gui.options.SpringUtilities;
import net.sourceforge.ganttproject.language.GanttLanguage;
import net.sourceforge.ganttproject.util.collect.Pair;

import org.divxdede.swing.busy.JBusyComponent;
import org.jdesktop.swingx.JXHyperlink;
import org.jdesktop.swingx.JXList;

import biz.ganttproject.core.option.BooleanOption;
import biz.ganttproject.core.option.ChangeValueEvent;
import biz.ganttproject.core.option.ChangeValueListener;
import biz.ganttproject.core.option.DefaultStringOption;
import biz.ganttproject.core.option.EnumerationOption;
import biz.ganttproject.core.option.IntegerOption;
import biz.ganttproject.core.option.ListOption;
import biz.ganttproject.core.option.StringOption;

import com.google.common.base.Objects;
import com.google.common.base.Predicate;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;

/**
 * UI component for WebDAV operarions.
 *
 * @author dbarashev (Dmitry Barashev)
 */
class GanttURLChooser {
    private static final GanttLanguage language = GanttLanguage.getInstance();

    private final StringOption myUsername;

    private final StringOption myPassword;

    private final StringOption myPath;

    private final IntegerOption myTimeout;

    private SelectionListener mySelectionListener;

    private final ListOption<WebDavServerDescriptor> myServers;

    private final MiltonResourceFactory myWebDavFactory;

    private final GPAction myReloadAction = new GPAction("fileChooser.reload") {
        @Override
        public void actionPerformed(ActionEvent event) {
            if (!isEnabled()) {
                return;
            }
            reloadFilesTable();
        }
    };

    private final GPAction myUpAction = new GPAction("fileChooser.up") {
        @Override
        public void actionPerformed(ActionEvent event) {
            try {
                WebDavResource collection = tableModel.getCollection();
                WebDavResource parent = collection.getParent();
                if (parent != null && parent.exists() && parent.isCollection()) {
                    new ReloadWorker(parent).execute();
                    myPath.setValue(new URL(parent.getUrl()).getPath());
                }
            } catch (WebDavException e) {
                showError(e);
            } catch (MalformedURLException e) {
                showError(e);
            }
        }
    };

    private final GPAction myLockAction = new GPAction("fileChooser.lock") {
        @Override
        public void actionPerformed(ActionEvent evt) {
            WebDavResource resource = getSelectedResource();
            if (resource == null) {
                return;
            }
            try {
                if (!resource.isLocked()) {
                    resource.lock(myTimeout.getValue() * 60);
                    reloadFilesTable();
                }
            } catch (WebDavException e) {
                showError(e);
            }
        }
    };

    private final GPAction myUnlockAction = new GPAction("fileChooser.unlock") {
        @Override
        public void actionPerformed(ActionEvent evt) {
            WebDavResource resource = getSelectedResource();
            if (resource == null) {
                return;
            }
            try {
                if (resource.isLocked()) {
                    resource.unlock();
                    reloadFilesTable();
                }
            } catch (WebDavException e) {
                showError(e);
            }
        }
    };

    private final GPAction myDeleteAction = new GPAction("fileChooser.delete") {
        @Override
        public void actionPerformed(ActionEvent evt) {
            final WebDavResource resource = getSelectedResource();
            if (resource == null) {
                return;
            }
            myUiFacade.showOptionDialog(JOptionPane.QUESTION_MESSAGE,
                    GanttLanguage.getInstance().getText("fileChooser.delete.question"),
                    new Action[] { new OkAction() {
                        @Override
                        public void actionPerformed(ActionEvent evt) {
                            try {
                                resource.delete();
                            } catch (WebDavException e) {
                                showError(e);
                            }
                        }
                    }, CancelAction.EMPTY });
        }
    };

    private final FilesTableModel tableModel = new FilesTableModel();

    private JXList table;

    private JButton myLockButton;

    private final UIFacade myUiFacade;

    private final IGanttProject myProject;

    private JScrollPane myFilesComponent;

    private WebDavUri myInitialUri;

    private JLabel myPasswordLabel;

    private OkAction myOkAction;

    private final List<Runnable> myListenerRemovers = Lists.newArrayList();

    private JBusyComponent<JComponent> myBusyComponent;

    static interface SelectionListener {
        public void setSelection(WebDavResource resource);
    }

    GanttURLChooser(IGanttProject project, UIFacade uiFacade, ListOption<WebDavServerDescriptor> servers,
            WebDavUri currentUri, StringOption username, StringOption password, IntegerOption lockTimeoutOption,
            BooleanOption releaseLockOption, MiltonResourceFactory webDavFactory) {
        myProject = project;
        myUiFacade = uiFacade;
        myWebDavFactory = webDavFactory;
        myPath = new DefaultStringOption("path");
        myServers = servers;
        myUsername = username;
        myPassword = password;
        myTimeout = lockTimeoutOption;
        myInitialUri = currentUri;

        myListenerRemovers.add(myServers.addChangeValueListener(new ChangeValueListener() {
            @Override
            public void changeValue(ChangeValueEvent event) {
                myPath.setValue("");
                updateUsernameAndPassword();
                myReloadAction.actionPerformed(null);
            }
        }));

        myListenerRemovers.add(myUsername.addChangeValueListener(new ChangeValueListener() {
            @Override
            public void changeValue(ChangeValueEvent event) {
                if (myServers.getValue() != null) {
                    myServers.getValue().username = myUsername.getValue();
                }
            }
        }));

        myListenerRemovers.add(myPassword.addChangeValueListener(new ChangeValueListener() {
            @Override
            public void changeValue(ChangeValueEvent event) {
                if (myServers.getValue() != null) {
                    myServers.getValue().password = myPassword.getValue();
                }
            }
        }));
    }

    class ReloadWorker extends SwingWorker<Pair<WebDavResource, List<WebDavResource>>, Object> {
        private WebDavResource myResource;

        public ReloadWorker(WebDavResource resource) {
            myResource = resource;
            setProgressBar(true);
        }

        @Override
        protected Pair<WebDavResource, List<WebDavResource>> doInBackground() throws Exception {
            try {
                WebDavResource resource = myResource;
                if (resource.exists() && resource.isCollection()) {
                    return Pair.create(resource, readChildren(resource));
                }
                WebDavResource parent = resource.getParent();
                if (parent.exists() && parent.isCollection()) {
                    return Pair.create(parent, readChildren(parent));
                }
                return null;
            } catch (WebDavException e) {
                showError(e);
                return null;
            }
        }

        private List<WebDavResource> readChildren(WebDavResource parent) throws WebDavException {
            List<WebDavResource> children = Lists.newArrayList();
            for (WebDavResource child : parent.getChildResources()) {
                try {
                    if (child.exists()) {
                        children.add(child);
                    }
                } catch (WebDavException e) {
                    GPLogger.logToLogger(e);
                }
            }
            return children;
        }

        @Override
        protected void done() {
            try {
                Pair<WebDavResource, List<WebDavResource>> result = get();
                if (result != null) {
                    tableModel.setCollection(result.first(), result.second());
                }
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (ExecutionException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } finally {
                setProgressBar(false);
            }
        }
    };

    protected void reloadFilesTable() {
        myWebDavFactory.clearCache();
        myWebDavFactory.setCredentials(myUsername.getValue(), myPassword.getValue());
        WebDavUri webDavUri = buildUrl();
        if (webDavUri != null) {
            new ReloadWorker(myWebDavFactory.createResource(webDavUri)).execute();
        }
    }

    private boolean tryApplyUrl(WebDavUri currentUri) {
        WebDavServerDescriptor savedServer = findSavedServer(currentUri.buildRootUrl());
        if (savedServer == null) {
            WebDavServerDescriptor server = new WebDavServerDescriptor(
                    Strings.isNullOrEmpty(currentUri.hostName) ? currentUri.hostUrl : currentUri.hostName,
                    currentUri.buildRootUrl(), "");
            myServers.addValue(server);
            myServers.setValue(server);
        } else if (!savedServer.equals(myServers.getValue())) {
            myServers.setValue(savedServer);
        }
        myPath.setValue(currentUri.path);
        return true;
    }

    private WebDavServerDescriptor findSavedServer(String domainUrl) {
        for (WebDavServerDescriptor server : myServers.getValues()) {
            if (server.getRootUrl().equals(domainUrl)) {
                return server;
            }
        }
        return null;
    }

    public JComponent createOpenDocumentUi(OkAction openAction) {
        myOkAction = openAction;
        return createComponent();
    }

    public JComponent createSaveDocumentUi(OkAction saveAction) {
        myOkAction = saveAction;
        return createComponent();
    }

    private WebDavUri buildUrl() {
        WebDavServerDescriptor server = myServers.getValue();
        if (server == null) {
            return null;
        }
        String host = server.getRootUrl().trim();
        while (host.endsWith("/")) {
            host = host.substring(0, host.length() - 1);
        }
        String path = Objects.firstNonNull(myPath.getValue(), "");
        if (!path.startsWith("/")) {
            path = "/" + path;
        }
        return new WebDavUri(server.name, host, path);
    }

    private WebDavResource getSelectedResource() {
        return (WebDavResource) table.getSelectedValue();
    }

    private JComponent createComponent() {
        OptionsPageBuilder builder = new OptionsPageBuilder();

        JPanel panel = new JPanel(new SpringLayout());
        panel.add(new JLabel(language.getCorrectedLabel("webServer")));
        EnumerationOption serverChoiceOption = myServers.asEnumerationOption();
        panel.add(builder.createOptionComponent(null, serverChoiceOption));
        panel.add(new JLabel());
        panel.add(createUsernamePasswordPanel());

        panel.add(new JLabel(language.getCorrectedLabel("fileFromServer")));
        panel.add(builder.createOptionComponent(null, myPath));
        myPath.addChangeValueListener(new ChangeValueListener() {
            @Override
            public void changeValue(ChangeValueEvent event) {
                String value = (String) event.getNewValue();
                if (value == null) {
                    return;
                }
                String lcValue = value.toLowerCase();
                if (lcValue.startsWith("http://") || lcValue.startsWith("https://")) {
                    if (!tryApplyUrl(new WebDavUri(value))) {
                        myUpAction.setEnabled(value.split("/").length > 1);
                    }
                }
            }
        });

        addEmptyRow(panel);

        {
            JPanel filesTablePanel = new JPanel(new BorderLayout());
            JButton refreshButton = new JButton(myReloadAction);
            JButton upButton = new JButton(myUpAction);
            myLockButton = new JButton(myLockAction);

            panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(myUpAction.getKeyStroke(), myUpAction);
            panel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(myReloadAction.getKeyStroke(), myReloadAction);
            panel.getActionMap().put(myUpAction, myUpAction);
            panel.getActionMap().put(myReloadAction, myReloadAction);
            upButton.setText("");
            refreshButton.setText("");
            Box filesHeaderBox = Box.createVerticalBox();
            filesHeaderBox.add(upButton);
            filesHeaderBox.add(Box.createVerticalStrut(5));
            filesHeaderBox.add(refreshButton);
            filesHeaderBox.add(Box.createVerticalGlue());
            filesHeaderBox.add(new JButton(myDeleteAction));
            filesHeaderBox.add(Box.createVerticalStrut(5));
            filesHeaderBox.add(myLockButton);

            filesTablePanel.add(filesHeaderBox, BorderLayout.EAST);
            filesHeaderBox.setBorder(BorderFactory.createEmptyBorder(0, 3, 0, 0));
            table = new JXList(tableModel);
            table.setHighlighters(UIUtil.ZEBRA_HIGHLIGHTER);
            table.setCellRenderer(new FilesCellRenderer());
            table.addListSelectionListener(new ListSelectionListener() {
                @Override
                public void valueChanged(ListSelectionEvent e) {
                    WebDavResource resource = getSelectedResource();
                    if (resource == null) {
                        return;
                    }
                    onSelectionChanged(resource);
                }
            });
            table.addMouseListener(new MouseAdapter() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    if (e.getClickCount() == 2) {
                        tryEnterCollection(table, tableModel);
                    }
                }
            });
            table.addKeyListener(new KeyAdapter() {
                @Override
                public void keyReleased(KeyEvent e) {
                    if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                        tryEnterCollection(table, tableModel);
                    }
                }
            });

            myFilesComponent = new JScrollPane(table);
            myFilesComponent.setMaximumSize(table.getPreferredScrollableViewportSize());

            filesTablePanel.add(myFilesComponent, BorderLayout.CENTER);

            panel.add(new JLabel(language.getText("fileChooser.fileList")));
            panel.add(filesTablePanel);
        }

        addEmptyRow(panel);
        SpringUtilities.makeCompactGrid(panel, 6, 2, 0, 0, 10, 5);
        panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
        panel.setMaximumSize(new Dimension(Integer.MAX_VALUE, panel.getPreferredSize().height));

        Box properties = Box.createVerticalBox();
        properties.add(panel);
        properties.add(Box.createVerticalGlue());

        myBusyComponent = new JBusyComponent<JComponent>(properties);
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                if (myInitialUri != null) {
                    tryApplyUrl(myInitialUri);
                }
                reloadFilesTable();
            }
        });
        return myBusyComponent;
    }

    private void setProgressBar(boolean b) {
        myBusyComponent.setBusy(b);
    }

    private Component createUsernamePasswordPanel() {
        JPanel grid = new JPanel(new GridLayout(3, 2));
        grid.add(new JLabel(language.getText("userName")));
        final JLabel username = new JLabel(myUsername.getValue());
        myUsername.addChangeValueListener(new ChangeValueListener() {
            @Override
            public void changeValue(ChangeValueEvent event) {
                username.setText(myUsername.getValue() == null ? "" : myUsername.getValue());
            }
        });
        grid.add(username);
        grid.add(new JLabel(language.getText("password")));
        myPasswordLabel = new JLabel(
                myPassword.getValue() == null ? "" : Strings.repeat("*", myPassword.getValue().length()));
        myPassword.addChangeValueListener(new ChangeValueListener() {
            @Override
            public void changeValue(ChangeValueEvent event) {
                UIUtil.clearErrorLabel(myPasswordLabel);
                myPasswordLabel.setText(
                        myPassword.getValue() == null ? "" : Strings.repeat("*", myPassword.getValue().length()));
            }
        });
        grid.add(myPasswordLabel);
        grid.add(new JXHyperlink(new GPAction("webdav.configure") {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                WebDavOptionPageProvider optionPage = new WebDavOptionPageProvider();
                optionPage.init(myProject, myUiFacade);
                myUiFacade.createDialog(optionPage.buildPageComponent(), new Action[] { CancelAction.CLOSE }, "")
                        .show();
                updateUsernameAndPassword();
                myReloadAction.actionPerformed(null);
            }
        }));
        UIUtil.walkComponentTree(grid, new Predicate<JComponent>() {
            @Override
            public boolean apply(JComponent input) {
                input.setFont(input.getFont().deriveFont(input.getFont().getSize() * 0.82f));
                return true;
            }
        });

        Box result = Box.createHorizontalBox();
        result.add(grid);
        result.add(Box.createHorizontalGlue());
        return grid;
    }

    private void updateUsernameAndPassword() {
        WebDavServerDescriptor server = myServers.getValue();
        myUsername.setValue(server == null ? "" : server.username);
        myPassword.setValue(server == null ? "" : server.password);
        setWebDavActionsEnabled(
                !Strings.isNullOrEmpty(myUsername.getValue()) && !Strings.isNullOrEmpty(myPassword.getValue()));
    }

    private void setWebDavActionsEnabled(boolean value) {
        myDeleteAction.setEnabled(value);
        myLockAction.setEnabled(value);
        myReloadAction.setEnabled(value);
        myUpAction.setEnabled(value);
        myOkAction.setEnabled(value);
    }

    protected void onSelectionChanged(WebDavResource resource) {
        if (mySelectionListener != null) {
            mySelectionListener.setSelection(resource);
        }
        myPath.setValue(resource.getWebDavUri().path);
        try {
            if (resource.isLocked()) {
                myLockButton.setAction(myUnlockAction);
            } else {
                myLockButton.setAction(myLockAction);
            }
        } catch (WebDavException e) {
            GPLogger.logToLogger(e);
        }
    }

    protected void tryEnterCollection(JXList table, FilesTableModel tableModel) {
        WebDavResource resource = (WebDavResource) table.getSelectedValue();
        try {
            if (resource.isCollection()) {
                new ReloadWorker(resource).execute();
            }
        } catch (WebDavException e) {
            showError(e);
        }
    }

    private static void addEmptyRow(JPanel form) {
        form.add(Box.createRigidArea(new Dimension(1, 10)));
        form.add(Box.createRigidArea(new Dimension(1, 10)));
    }

    WebDavUri getUrl() {
        return buildUrl();
    }

    String getUsername() {
        return myUsername.getValue();
    }

    String getPassword() {
        return myPassword.getValue();
    }

    int getLockTimeout() {
        return myTimeout.getValue();
    }

    void setSelectionListener(SelectionListener selectionListener) {
        mySelectionListener = selectionListener;
    }

    StringOption getPathOption() {
        return myPath;
    }

    void showError(Exception e) {
        if (e.getCause() instanceof NotAuthorizedException) {
            UIUtil.setupErrorLabel(myPasswordLabel, "Access denied");
            setWebDavActionsEnabled(false);
        }
        GPLogger.log(e);
    }

    public void dispose() {
        for (Runnable remover : myListenerRemovers) {
            remover.run();
        }
    }
}