com.google.gdt.eclipse.designer.util.ui.ResourceSelectionDialog.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gdt.eclipse.designer.util.ui.ResourceSelectionDialog.java

Source

/*******************************************************************************
 * Copyright 2011 Google Inc. All Rights Reserved.
 *
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *******************************************************************************/
package com.google.gdt.eclipse.designer.util.ui;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.gdt.eclipse.designer.Activator;
import com.google.gdt.eclipse.designer.model.module.ModuleElement;
import com.google.gdt.eclipse.designer.model.web.WebUtils;
import com.google.gdt.eclipse.designer.util.ModuleDescription;
import com.google.gdt.eclipse.designer.util.ModuleVisitor;
import com.google.gdt.eclipse.designer.util.resources.IResourcesProvider;

import org.eclipse.wb.internal.core.DesignerPlugin;
import org.eclipse.wb.internal.core.utils.ui.GridDataFactory;
import org.eclipse.wb.internal.core.utils.ui.GridLayoutFactory;
import org.eclipse.wb.internal.core.utils.ui.UiUtils;
import org.eclipse.wb.internal.core.utils.ui.dialogs.ResizableDialog;

import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.Path;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.ui.dialogs.SearchPattern;

import org.apache.commons.lang.ArrayUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Dialog for selecting resource from public folder of given module and inherited modules.
 * 
 * @author scheglov_ke
 * @coverage gwt.util.ui
 */
public class ResourceSelectionDialog extends ResizableDialog {
    private final IResourcesProvider m_provider;
    private final String m_title;
    private final ResourceFolder m_root;
    ////////////////////////////////////////////////////////////////////////////
    //
    // UI objects
    //
    ////////////////////////////////////////////////////////////////////////////
    private Text m_namePatternText;
    private Button m_allFilesButton;
    private SearchPattern m_namePattern;
    private TreeViewer m_viewer;
    private Tree m_tree;

    ////////////////////////////////////////////////////////////////////////////
    //
    // Constructors
    //
    ////////////////////////////////////////////////////////////////////////////
    public ResourceSelectionDialog(Shell parentShell, IResourcesProvider provider,
            ModuleDescription moduleDescription, String title) throws Exception {
        super(parentShell, Activator.getDefault());
        m_provider = provider;
        m_title = title;
        // prepare resources
        m_root = new ResourceFolder(null, null);
        {
            addWarFolder(moduleDescription);
        }
        {
            final Set<String> visitedModules = Sets.newTreeSet();
            final Set<String> visitedPackages = Sets.newTreeSet();
            ModuleVisitor.accept(moduleDescription, new ModuleVisitor() {
                private ResourceFolder m_moduleFolder;

                @Override
                public boolean visitModule(ModuleElement module) {
                    String moduleName = module.getName();
                    if (visitedModules.contains(moduleName)) {
                        return false;
                    }
                    //
                    m_moduleFolder = new ResourceFolder(m_root, moduleName);
                    m_root.add(m_moduleFolder);
                    //
                    visitedModules.add(moduleName);
                    return true;
                }

                @Override
                public void visitPublicPackage(ModuleElement module, String packageName) throws Exception {
                    if (!visitedPackages.contains(packageName)) {
                        visitedPackages.add(packageName);
                        String path = packageName.replace('.', '/');
                        for (String file : m_provider.listFiles(path)) {
                            m_moduleFolder.add(file, path + "/" + file);
                        }
                    }
                }
            });
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // GWT 1.6 'war' folder resources
    //
    ////////////////////////////////////////////////////////////////////////////
    private void addWarFolder(ModuleDescription moduleDescription) {
        IProject project = moduleDescription.getProject();
        String webFolderName = WebUtils.getWebFolderName(project);
        IFolder webFolder = project.getFolder(webFolderName);
        if (webFolder != null && webFolder.exists()) {
            ResourceFolder resourceFolder = new ResourceFolder(m_root, webFolderName);
            m_root.add(resourceFolder);
            listWarFolder(resourceFolder, "", webFolder.getLocation().toFile());
        }
    }

    private void listWarFolder(ResourceFolder resFolder, String folderPublicPath, File folder) {
        for (File file : folder.listFiles()) {
            // prepare file path
            String filePublicPath;
            if (folderPublicPath.length() == 0) {
                filePublicPath = file.getName();
            } else {
                filePublicPath = folderPublicPath + "/" + file.getName();
            }
            // visit new folder or add file
            if (file.isDirectory()) {
                listWarFolder(resFolder, filePublicPath, file);
            } else {
                resFolder.add(filePublicPath, file.getAbsolutePath());
            }
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Access
    //
    ////////////////////////////////////////////////////////////////////////////
    /**
     * @return the {@link InputStream} for contents of given {@link ResourceFile}.
     */
    protected final InputStream getResourceAsStream(ResourceFile file) throws Exception {
        InputStream stream = m_provider.getResourceAsStream(file.getFullPath());
        if (stream == null) {
            // try absolute path
            File resourceFile = new File(file.getFullPath());
            if (resourceFile.exists() && resourceFile.isFile()) {
                return new FileInputStream(resourceFile);
            }
            return null;
        }
        return stream;
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // GUI
    //
    ////////////////////////////////////////////////////////////////////////////
    @Override
    protected Control createDialogArea(Composite parent) {
        Composite container = (Composite) super.createDialogArea(parent);
        GridLayoutFactory.create(container).columns(2).equalColumns();
        // create name pattern
        {
            {
                Label label = new Label(container, SWT.NONE);
                GridDataFactory.create(label).spanH(2);
                label.setText("Select a resource (? = any character, * = any string):");
            }
            {
                m_namePatternText = new Text(container, SWT.BORDER);
                GridDataFactory.create(m_namePatternText).spanH(2).grabH().fillH();
                m_namePatternText.addModifyListener(new ModifyListener() {
                    public void modifyText(ModifyEvent e) {
                        // prepare name pattern matcher
                        String pattern = m_namePatternText.getText();
                        if (pattern.length() != 0) {
                            pattern = adjustPattern(pattern);
                            m_namePattern = new SearchPattern();
                            m_namePattern.setPattern(pattern);
                        } else {
                            m_namePattern = null;
                        }
                        // refresh viewer
                        refreshViewer();
                    }

                    private String adjustPattern(String pattern) {
                        pattern = pattern.trim();
                        if (pattern.endsWith("<")) {
                            // the < character indicates an exact match search
                            return pattern.substring(0, pattern.length() - 1);
                        }
                        if (!pattern.equals("") && !pattern.endsWith("*")) {
                            return pattern + "*";
                        }
                        return pattern;
                    }
                });
            }
        }
        // create tree viewer group
        {
            Group treeGroup = new Group(container, SWT.NONE);
            GridDataFactory.create(treeGroup).spanV(2).grab().fill().hintHC(55).hintVC(25);
            GridLayoutFactory.create(treeGroup);
            treeGroup.setText("Matching resources");
            // create tree viewer
            {
                m_viewer = new TreeViewer(treeGroup, SWT.BORDER);
                m_viewer.setContentProvider(new ResourceContentProvider());
                m_viewer.setLabelProvider(new ResourceLabelProvider());
                m_viewer.setSorter(new ResourceSorter());
                m_viewer.addFilter(new ResourceViewerFilter());
                //
                m_tree = m_viewer.getTree();
                GridDataFactory.create(m_tree).grab().fill();
                // all listeners
                m_viewer.addSelectionChangedListener(new ISelectionChangedListener() {
                    public void selectionChanged(SelectionChangedEvent event) {
                        clearPreviewGroup();
                        //
                        IStructuredSelection selection = (IStructuredSelection) m_viewer.getSelection();
                        AbstractResource resource = (AbstractResource) selection.getFirstElement();
                        if (resource instanceof ResourceFile) {
                            ResourceFile file = (ResourceFile) resource;
                            previewFile(m_previewGroup, file);
                            m_selectedResourcePath = file.getPublicPath();
                        } else {
                            m_selectedResourcePath = null;
                        }
                        // update OK button
                        getButton(IDialogConstants.OK_ID).setEnabled(m_selectedResourcePath != null);
                    }
                });
                m_viewer.addDoubleClickListener(new IDoubleClickListener() {
                    public void doubleClick(DoubleClickEvent event) {
                        if (m_selectedResourcePath != null) {
                            okPressed();
                        }
                    }
                });
            }
        }
        // filters group
        {
            Group filtersGroup = new Group(container, SWT.NONE);
            GridDataFactory.create(filtersGroup).fill();
            GridLayoutFactory.create(filtersGroup);
            filtersGroup.setText("Filters");
            // add "all files" button
            {
                m_allFilesButton = new Button(filtersGroup, SWT.CHECK);
                m_allFilesButton.setText("All Files");
                m_allFilesButton.addSelectionListener(new SelectionAdapter() {
                    @Override
                    public void widgetSelected(SelectionEvent e) {
                        refreshViewer();
                    }
                });
            }
            // add filters
            for (final ResourceFilter filter : m_filters) {
                // create check box
                final Button filterButton = new Button(filtersGroup, SWT.CHECK);
                filterButton.setText(filter.m_title);
                filterButton.setSelection(true);
                m_activeFilters.add(filter);
                // add listener
                filterButton.addSelectionListener(new SelectionAdapter() {
                    @Override
                    public void widgetSelected(SelectionEvent e) {
                        if (filterButton.getSelection()) {
                            m_activeFilters.add(filter);
                        } else {
                            m_activeFilters.remove(filter);
                        }
                        refreshViewer();
                    }
                });
            }
        }
        //
        createPreviewGroup(container);
        // initialize viewer
        {
            m_viewer.setInput(m_root);
            m_viewer.expandAll();
        }
        //
        return container;
    }

    private void refreshViewer() {
        m_viewer.refresh();
        m_viewer.expandAll();
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Preview
    //
    ////////////////////////////////////////////////////////////////////////////
    private Group m_previewGroup;

    private void createPreviewGroup(Composite parent) {
        m_previewGroup = new Group(parent, SWT.NONE);
        m_previewGroup.setText("Preview");
        GridDataFactory.create(m_previewGroup).fill();
    }

    /**
     * Removes all children of preview group that subclasses could create in
     * {@link #previewFile(Composite, ResourceFile)}
     */
    private void clearPreviewGroup() {
        for (Control child : m_previewGroup.getChildren()) {
            child.dispose();
        }
    }

    /**
     * This methods allows subclasses add some control on given parent that will show preview of given
     * file.
     */
    protected void previewFile(Composite parent, ResourceFile file) {
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Dialog: shell
    //
    ////////////////////////////////////////////////////////////////////////////
    @Override
    protected void configureShell(Shell newShell) {
        super.configureShell(newShell);
        newShell.setText(m_title);
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Dialog: buttons
    //
    ////////////////////////////////////////////////////////////////////////////
    @Override
    protected void createButtonsForButtonBar(Composite parent) {
        createButton(parent, IDialogConstants.OK_ID, IDialogConstants.OK_LABEL, true);
        createButton(parent, IDialogConstants.CANCEL_ID, IDialogConstants.CANCEL_LABEL, false);
        getButton(IDialogConstants.OK_ID).setEnabled(false);
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Access
    //
    ////////////////////////////////////////////////////////////////////////////
    private String m_selectedResourcePath;

    /**
     * @return the public path of selected resource.
     */
    public String getSelectedResourcePath() {
        return m_selectedResourcePath;
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Filters
    //
    ////////////////////////////////////////////////////////////////////////////
    private final List<ResourceFilter> m_filters = Lists.newArrayList();
    private final List<ResourceFilter> m_activeFilters = Lists.newArrayList();

    /**
     * Adds new filter for resource files.
     */
    public void addFilter(String title, String pattern) {
        m_filters.add(new ResourceFilter(title, pattern));
    }

    private boolean matchFilters(String resourceName) {
        // check, may be we should match all files
        if (m_allFilesButton.getSelection()) {
            return true;
        }
        // check active filters
        for (ResourceFilter filter : m_activeFilters) {
            if (filter.match(resourceName)) {
                return true;
            }
        }
        // no, given resource name does not match any filter
        return false;
    }

    /**
     * Filter for resources in {@link ResourceSelectionDialog}.
     * 
     * @author scheglov_ke
     */
    private static final class ResourceFilter {
        private final String m_title;
        private final SearchPattern m_pattern;

        public ResourceFilter(String title, String pattern) {
            m_title = title;
            m_pattern = new SearchPattern();
            m_pattern.setPattern(pattern);
        }

        public boolean match(String s) {
            return m_pattern.matches(s);
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Resource content provider
    //
    ////////////////////////////////////////////////////////////////////////////
    private static class ResourceContentProvider implements ITreeContentProvider {
        public Object[] getElements(Object inputElement) {
            return ((ResourceFolder) inputElement).getChildren().toArray();
        }

        public Object[] getChildren(Object parentElement) {
            if (parentElement instanceof ResourceFolder) {
                ResourceFolder folder = (ResourceFolder) parentElement;
                return folder.getChildren().toArray();
            }
            return ArrayUtils.EMPTY_OBJECT_ARRAY;
        }

        public Object getParent(Object element) {
            return ((AbstractResource) element).getParent();
        }

        public boolean hasChildren(Object element) {
            return getChildren(element).length != 0;
        }

        public void dispose() {
        }

        public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Resource label provider
    //
    ////////////////////////////////////////////////////////////////////////////
    private final class ResourceLabelProvider extends LabelProvider {
        @Override
        public String getText(Object element) {
            return ((AbstractResource) element).getName();
        }

        @Override
        public Image getImage(Object element) {
            if (element instanceof ResourceFolder) {
                return DesignerPlugin.getImage("folder_open.gif");
            }
            if (element instanceof ResourceFile) {
                ResourceFile file = (ResourceFile) element;
                return getIcon(file);
            }
            return null;
        }
    }

    protected Image getIcon(ResourceFile file) {
        String extension = file.getExtension();
        if (extension != null) {
            return UiUtils.getIcon(extension);
        }
        return null;
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // ResourceFilter
    //
    ////////////////////////////////////////////////////////////////////////////
    private final class ResourceViewerFilter extends ViewerFilter {
        @Override
        public boolean select(Viewer viewer, Object parentElement, Object element) {
            return select(element);
        }

        private boolean select(Object element) {
            if (element instanceof ResourceFile) {
                ResourceFile file = (ResourceFile) element;
                String fileName = file.getName();
                // check for filters
                if (!matchFilters(fileName)) {
                    return false;
                }
                // check for name filter
                if (m_namePattern != null) {
                    return m_namePattern.matches(fileName);
                }
                // OK, accept this file
                return true;
            }
            if (element instanceof ResourceFolder) {
                ResourceFolder folder = (ResourceFolder) element;
                for (AbstractResource resource : folder.getChildren()) {
                    if (select(resource)) {
                        return true;
                    }
                }
            }
            return false;
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // Resource sorter
    //
    ////////////////////////////////////////////////////////////////////////////
    private static final class ResourceSorter extends ViewerSorter {
        @Override
        public int category(Object element) {
            if (element instanceof ResourceFolder) {
                return 0;
            }
            return 1;
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // AbstractResource
    //
    ////////////////////////////////////////////////////////////////////////////
    /**
     * Abstract resource.
     */
    private static class AbstractResource {
        private final ResourceFolder m_parent;
        private final String m_name;

        ////////////////////////////////////////////////////////////////////////////
        //
        // Constructor
        //
        ////////////////////////////////////////////////////////////////////////////
        public AbstractResource(ResourceFolder parent, String name) {
            m_parent = parent;
            m_name = name;
        }

        ////////////////////////////////////////////////////////////////////////////
        //
        // Access
        //
        ////////////////////////////////////////////////////////////////////////////
        public ResourceFolder getParent() {
            return m_parent;
        }

        public String getName() {
            return m_name;
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // ResourceFolder
    //
    ////////////////////////////////////////////////////////////////////////////
    /**
     * Folder with resources.
     */
    private static final class ResourceFolder extends AbstractResource {
        private final List<AbstractResource> m_children = Lists.newArrayList();
        private final Map<String, AbstractResource> m_nameToChild = Maps.newTreeMap();

        ////////////////////////////////////////////////////////////////////////////
        //
        // Constructor
        //
        ////////////////////////////////////////////////////////////////////////////
        public ResourceFolder(ResourceFolder parent, String name) {
            super(parent, name);
        }

        ////////////////////////////////////////////////////////////////////////////
        //
        // Access
        //
        ////////////////////////////////////////////////////////////////////////////
        public Collection<AbstractResource> getChildren() {
            return m_children;
        }

        public AbstractResource getChild(String name) {
            return m_nameToChild.get(name);
        }

        public void add(AbstractResource resource) {
            m_children.add(resource);
            m_nameToChild.put(resource.getName(), resource);
        }

        public void add(String publicPath, String fullPath) {
            IPath name = new Path(publicPath);
            add(name, publicPath, fullPath);
        }

        ////////////////////////////////////////////////////////////////////////////
        //
        // Internal
        //
        ////////////////////////////////////////////////////////////////////////////
        private void add(IPath name, String publicPath, String fullPath) {
            if (name.segmentCount() == 1) {
                if (!publicPath.endsWith("/")) {
                    ResourceFile file = new ResourceFile(this, name.toPortableString(), publicPath, fullPath);
                    add(file);
                }
            } else {
                String folderName = name.segments()[0];
                ResourceFolder folder = (ResourceFolder) getChild(folderName);
                if (folder == null) {
                    folder = new ResourceFolder(this, folderName);
                    add(folder);
                }
                folder.add(name.removeFirstSegments(1), publicPath, fullPath);
            }
        }
    }

    ////////////////////////////////////////////////////////////////////////////
    //
    // ResourceFile
    //
    ////////////////////////////////////////////////////////////////////////////
    /**
     * File with some name and path.
     */
    protected static final class ResourceFile extends AbstractResource {
        private final String m_publicPath;
        private final String m_fullPath;

        ////////////////////////////////////////////////////////////////////////////
        //
        // Constructor
        //
        ////////////////////////////////////////////////////////////////////////////
        public ResourceFile(ResourceFolder parent, String name, String publicPath, String fullPath) {
            super(parent, name);
            m_publicPath = publicPath;
            m_fullPath = fullPath;
        }

        ////////////////////////////////////////////////////////////////////////////
        //
        // Access
        //
        ////////////////////////////////////////////////////////////////////////////
        public String getPublicPath() {
            return m_publicPath;
        }

        public String getFullPath() {
            return m_fullPath;
        }

        public String getExtension() {
            return new Path(m_fullPath).getFileExtension();
        }
    }
}