| /******************************************************************************* |
| * Copyright (c) 2010, 2017 BestSolution.at and others. |
| * 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 |
| * |
| * Contributors: |
| * Tom Schindl <tom.schindl@bestsolution.at> - initial API and implementation |
| * Steven Spungin <steven@spungin.tv> - Bug 404136, 424730 |
| * Andrej ten Brummelhuis <andrejbrummelhuis@gmail.com> - Bug 395283 |
| ******************************************************************************/ |
| package org.eclipse.e4.tools.emf.ui.internal.common.component.dialogs; |
| |
| import java.io.BufferedReader; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InputStreamReader; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.Timer; |
| import java.util.TimerTask; |
| |
| import org.eclipse.core.databinding.observable.list.IObservableList; |
| import org.eclipse.core.databinding.observable.list.WritableList; |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IProject; |
| import org.eclipse.core.resources.IResource; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.e4.core.contexts.IEclipseContext; |
| import org.eclipse.e4.tools.emf.ui.common.ResourceSearchScope; |
| import org.eclipse.e4.tools.emf.ui.internal.Messages; |
| import org.eclipse.e4.tools.emf.ui.internal.StringMatcher; |
| import org.eclipse.e4.tools.emf.ui.internal.common.component.tabs.empty.E; |
| import org.eclipse.jface.databinding.viewers.ObservableListContentProvider; |
| import org.eclipse.jface.viewers.IStructuredSelection; |
| import org.eclipse.jface.viewers.StyledCellLabelProvider; |
| import org.eclipse.jface.viewers.StyledString; |
| import org.eclipse.jface.viewers.TableViewer; |
| import org.eclipse.jface.viewers.ViewerCell; |
| 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.layout.GridData; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.layout.RowLayout; |
| import org.eclipse.swt.widgets.Button; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.Event; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.Text; |
| |
| /** |
| * Based of of AbstractIconDialog, but passively returns selection instead of |
| * modifying model. |
| * |
| * @author Steven Spungin |
| * |
| */ |
| public abstract class AbstractIconDialogWithHardcodedScope extends SaveDialogBoundsSettingsDialog { |
| private TableViewer viewer; |
| private IProject project; |
| private Map<IFile, Image> icons = Collections.synchronizedMap(new HashMap<IFile, Image>()); |
| private ResourceSearchScope searchScope = ResourceSearchScope.PROJECT; |
| |
| protected Messages Messages; |
| private Text textSearch; |
| private String value; |
| private IEclipseContext context; |
| |
| public AbstractIconDialogWithHardcodedScope(Shell parentShell, IEclipseContext context) { |
| super(parentShell); |
| this.context = context; |
| this.project = context.get(IProject.class); |
| Messages = context.get(Messages.class); |
| } |
| |
| protected IEclipseContext getContext() { |
| return context; |
| } |
| |
| protected abstract String getShellTitle(); |
| |
| protected abstract String getDialogTitle(); |
| |
| protected abstract String getDialogMessage(); |
| |
| @Override |
| protected Control createDialogArea(Composite parent) { |
| Composite comp = (Composite) super.createDialogArea(parent); |
| |
| getShell().setText(getShellTitle()); |
| setTitle(getDialogTitle()); |
| setMessage(getDialogMessage()); |
| String bundleFilter = (String) context.get("bundle"); //$NON-NLS-1$ |
| if (E.notEmpty(bundleFilter)) { |
| setMessage("Filtering by bundle " + bundleFilter); //$NON-NLS-1$ |
| } |
| |
| Composite container = new Composite(comp, SWT.NONE); |
| container.setLayoutData(new GridData(GridData.FILL_BOTH)); |
| container.setLayout(new GridLayout(2, false)); |
| |
| Composite compOptions = new Composite(container, SWT.NONE); |
| compOptions.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1)); |
| compOptions.setLayout(new RowLayout()); |
| |
| if (E.isEmpty(bundleFilter)) { |
| Button btnProject = new Button(compOptions, SWT.RADIO); |
| btnProject.setText(Messages.AbstractIconDialogWithHardcodedScope_Project); |
| btnProject.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| searchScope = ResourceSearchScope.PROJECT; |
| textSearch.notifyListeners(SWT.Modify, new Event()); |
| |
| } |
| }); |
| btnProject.setSelection(true); |
| |
| Button btnWorkspace = new Button(compOptions, SWT.RADIO); |
| btnWorkspace.setText(Messages.AbstractIconDialogWithHardcodedScope_Workspace); |
| btnWorkspace.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| searchScope = ResourceSearchScope.WORKSPACE; |
| textSearch.notifyListeners(SWT.Modify, new Event()); |
| } |
| }); |
| |
| btnWorkspace.setSelection(searchScope == ResourceSearchScope.WORKSPACE); |
| btnProject.setSelection(searchScope == ResourceSearchScope.PROJECT); |
| } else { |
| searchScope = ResourceSearchScope.WORKSPACE; |
| } |
| |
| Label l = new Label(container, SWT.NONE); |
| l.setText(Messages.AbstractIconDialog_IconName); |
| |
| textSearch = new Text(container, SWT.BORDER | SWT.SEARCH | SWT.ICON_SEARCH); |
| textSearch.setLayoutData(new GridData(GridData.FILL_HORIZONTAL)); |
| |
| new Label(container, SWT.NONE); |
| |
| viewer = new TableViewer(container, SWT.FULL_SELECTION | SWT.BORDER); |
| GridData gd = new GridData(GridData.FILL_BOTH); |
| viewer.getControl().setLayoutData(gd); |
| viewer.setContentProvider(new ObservableListContentProvider()); |
| viewer.setLabelProvider(new StyledCellLabelProvider() { |
| @Override |
| public void update(ViewerCell cell) { |
| IFile file = (IFile) cell.getElement(); |
| StyledString styledString = new StyledString(file.getProjectRelativePath().toString(), null); |
| |
| Image img = icons.get(file); |
| if (img == null) { |
| try (InputStream in = file.getContents()) { |
| img = new Image(cell.getControl().getDisplay(), in); |
| icons.put(file, img); |
| } catch (CoreException | IOException e) { |
| // TODO Auto-generated catch block |
| e.printStackTrace(); |
| } |
| } |
| |
| String bundle = getBundle(file); |
| if (bundle != null) { |
| styledString.append(" - " + bundle, StyledString.DECORATIONS_STYLER); //$NON-NLS-1$ |
| } |
| |
| cell.setImage(img); |
| cell.setText(styledString.getString()); |
| cell.setStyleRanges(styledString.getStyleRanges()); |
| } |
| }); |
| |
| final WritableList list = new WritableList(); |
| viewer.setInput(list); |
| viewer.addDoubleClickListener(event -> okPressed()); |
| |
| textSearch.addModifyListener(new ModifyListener() { |
| private IconMatchCallback callback; |
| private Timer timer = new Timer(true); |
| private TimerTask task; |
| |
| @Override |
| public void modifyText(ModifyEvent e) { |
| if (callback != null) { |
| callback.cancel = true; |
| } |
| if (task != null) { |
| task.cancel(); |
| } |
| list.clear(); |
| |
| clearImages(); |
| |
| callback = new IconMatchCallback(list); |
| task = new SearchThread(callback, textSearch.getText(), project, context, searchScope); |
| timer.schedule(task, 500); |
| } |
| }); |
| |
| getShell().addDisposeListener(e -> clearImages()); |
| |
| textSearch.notifyListeners(SWT.Modify, new Event()); |
| |
| return comp; |
| } |
| |
| private void clearImages() { |
| for (Image img : icons.values()) { |
| img.dispose(); |
| } |
| icons.clear(); |
| } |
| |
| @Override |
| protected boolean isResizable() { |
| return true; |
| } |
| |
| @Override |
| protected void okPressed() { |
| value = null; |
| IStructuredSelection s = (IStructuredSelection) viewer.getSelection(); |
| if (!s.isEmpty()) { |
| IFile file = (IFile) s.getFirstElement(); |
| String bundle = getBundle(file); |
| value = "platform:/plugin/" + bundle + "/" + file.getProjectRelativePath().toString(); //$NON-NLS-1$//$NON-NLS-2$ |
| |
| } |
| super.okPressed(); |
| } |
| |
| private String getBundle(IFile file) { |
| IProject project = file.getProject(); |
| IFile f = project.getFile("/META-INF/MANIFEST.MF"); //$NON-NLS-1$ |
| |
| if (f != null && f.exists()) { |
| try (InputStream s = f.getContents(); BufferedReader r = new BufferedReader(new InputStreamReader(s));) { |
| String line; |
| while ((line = r.readLine()) != null) { |
| if (line.startsWith("Bundle-SymbolicName:")) { //$NON-NLS-1$ |
| int start = line.indexOf(':'); |
| int end = line.indexOf(';'); |
| if (end == -1) { |
| end = line.length(); |
| } |
| return line.substring(start + 1, end).trim(); |
| } |
| } |
| } catch (CoreException e) { |
| // TODO Auto-generated catch block |
| e.printStackTrace(); |
| } catch (IOException e) { |
| // TODO Auto-generated catch block |
| e.printStackTrace(); |
| } |
| } |
| return null; |
| } |
| |
| public String getValue() { |
| return value; |
| } |
| |
| private class IconMatchCallback { |
| private volatile boolean cancel; |
| private IObservableList list; |
| |
| private IconMatchCallback(IObservableList list) { |
| this.list = list; |
| } |
| |
| public void match(final IFile file) { |
| if (!cancel) { |
| list.getRealm().exec(() -> list.add(file)); |
| } |
| } |
| } |
| |
| private static class SearchThread extends TimerTask { |
| private final IconMatchCallback callback; |
| private final IProject project; |
| private final StringMatcher matcherGif; |
| private final StringMatcher matcherJpg; |
| private final StringMatcher matcherPng; |
| private IEclipseContext context; |
| private ResourceSearchScope searchScope; |
| |
| public SearchThread(IconMatchCallback callback, String pattern, IProject project, IEclipseContext context, ResourceSearchScope searchScope) { |
| this.context = context; |
| this.matcherGif = new StringMatcher("*" + pattern + "*.gif", true, false); //$NON-NLS-1$//$NON-NLS-2$ |
| this.matcherJpg = new StringMatcher("*" + pattern + "*.jpg", true, false); //$NON-NLS-1$//$NON-NLS-2$ |
| this.matcherPng = new StringMatcher("*" + pattern + "*.png", true, false); //$NON-NLS-1$//$NON-NLS-2$ |
| this.callback = callback; |
| this.project = project; |
| this.searchScope = searchScope; |
| } |
| |
| @Override |
| public void run() { |
| List<IProject> projects; |
| switch (searchScope) { |
| case WORKSPACE: |
| projects = Arrays.asList(project.getWorkspace().getRoot().getProjects()); |
| break; |
| case PROJECT: |
| default: |
| projects = Arrays.asList(project); |
| break; |
| } |
| try { |
| for (IProject project : projects) { |
| // Only search bundles |
| IFile iFile = project.getFile("/META-INF/MANIFEST.MF"); //$NON-NLS-1$ |
| if (iFile.exists() == false) { |
| continue; |
| } |
| // Only search target bundle if specified |
| String bundle = (String) context.get("bundle"); //$NON-NLS-1$ |
| if (E.notEmpty(bundle)) { |
| try (InputStream inputStream = iFile.getContents();) { |
| Properties props = new Properties(); |
| props.load(inputStream); |
| String name = props.getProperty("Bundle-SymbolicName"); //$NON-NLS-1$ |
| String[] parts = name.split(";"); //$NON-NLS-1$ |
| if (parts[0].equals(bundle) == false) { |
| continue; |
| } |
| } catch (IOException e) { |
| // TODO Auto-generated catch block |
| e.printStackTrace(); |
| } |
| } |
| project.accept(resource -> { |
| if (callback.cancel) { |
| return false; |
| } |
| |
| if (resource.getType() == IResource.FOLDER || resource.getType() == IResource.PROJECT) { |
| return true; |
| } else if (resource.getType() == IResource.FILE && !resource.isLinked()) { |
| String path = resource.getProjectRelativePath().toString(); |
| if (matcherGif.match(path) || matcherPng.match(path) || matcherJpg.match(path)) { |
| callback.match((IFile) resource); |
| } |
| } |
| return false; |
| }); |
| } |
| } catch (CoreException e) { |
| // TODO Auto-generated catch block |
| e.printStackTrace(); |
| } |
| } |
| } |
| } |