Java tutorial
/******************************************************************************* * 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(); } } }