/***************************************************************************** * Copyright (c) 2010 CEA LIST. * * 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: * Remi Schnekenburger (CEA LIST) remi.schnekenburger@cea.fr - Initial API and implementation * Camille Letavernier (CEA LIST) camille.letavernier@cea.fr - Bug fix *****************************************************************************/ package org.eclipse.papyrus.customization.palette.dialog; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Enumeration; import java.util.List; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Status; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.papyrus.customization.palette.Messages; import org.eclipse.papyrus.uml.diagram.common.Activator; import org.eclipse.pde.core.plugin.IPluginModel; import org.eclipse.pde.core.plugin.PluginRegistry; import org.eclipse.swt.SWT; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; 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.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.dialogs.FilteredList; import org.eclipse.ui.dialogs.SelectionStatusDialog; import org.osgi.framework.Bundle; /** * Selection dialog for icons in bundles */ public class BundleIconExplorerDialog extends SelectionStatusDialog { /** gif file extension */ protected static final String GIF_EXTENSION = ".gif"; //$NON-NLS-1$ /** length of the extension */ public static final int GIF_EXTENSION_LENGTH = GIF_EXTENSION.length(); /** protocol for platform plugin URLs */ protected static final String PLUGIN_PROTOCOL = "platform:/plugin/"; //$NON-NLS-1$ /** indicates if several icons can be selected at the same time */ protected final boolean allowMultiple; /** list that displays icons */ protected FilteredList filteredList; /** text where a filter can be entered for the icon names */ protected Text filterText; /** current filter string */ protected String filter = null; /** initial value */ protected String initialValue; /** current displayed bundle name */ protected String currentBundleName = "org.eclipse.uml2.uml.edit"; //$NON-NLS-1$ private Text text; /** * Creates a new Icon Bundle Explorer Dialog * * @param parentShell * the parent shell for the dialog */ public BundleIconExplorerDialog(Shell parentShell, boolean allowMultiple, String initialValue, String bundle) { super(parentShell); this.allowMultiple = allowMultiple; this.initialValue = initialValue; this.currentBundleName = bundle; setTitle(Messages.BundleIconExplorerDialog_Title); setMessage(Messages.BundleIconExplorerDialog_Message); } /** * Creates a new Icon Bundle Explorer Dialog * * @param parentShell * the parent shell for the dialog */ public BundleIconExplorerDialog(Shell parentShell, String initialValue) { this(parentShell, false, initialValue, retrieveBundleId(initialValue)); } /** * Retrieves the bundle from which the * * @param initialValue * the initial value from which the bundle has to be retrieved * @return the bundle id */ protected static String retrieveBundleId(String initialValue) { if(initialValue.startsWith(PLUGIN_PROTOCOL)) { String tmp = initialValue.substring(PLUGIN_PROTOCOL.length()); int bundleIdEndIndex = tmp.indexOf("/"); return tmp.substring(0, bundleIdEndIndex); } return "org.eclipse.uml2.uml.edit"; } /** * {@inheritDoc} */ @Override protected Control createDialogArea(Composite parent) { Composite composite = (Composite)super.createDialogArea(parent); initializeDialogUnits(composite); // creates the message area, as defined in the super class createMessageArea(composite); createComboArea(composite); createFilterText(composite); createFilteredList(composite); refreshList(); return composite; } /** * Refresh the content of the */ @SuppressWarnings("unchecked") protected void refreshList() { // check selection currentBundleName = text.getText().trim(); Bundle bundle = Platform.getBundle(currentBundleName); if(bundle == null) { Activator.getDefault().getLog().log(new Status(IStatus.ERROR, Activator.ID, "impossible to find bundle with id: " + currentBundleName)); return; } Enumeration<URL> e = bundle.findEntries("", "*" + GIF_EXTENSION, true); //$NON-NLS-1$ //$NON-NLS-2$ List<ImageProxy> selectedProxy = new ArrayList<ImageProxy>(); List<ImageProxy> images = new ArrayList<ImageProxy>(); if(e == null) { return; } while(e.hasMoreElements()) { ImageProxy proxy = new ImageProxy(e.nextElement()); if(proxy.isDisplayed()) { images.add(proxy); // check if the proxy corresponds to the initialValue if(proxy.isInitial()) { selectedProxy.add(proxy); } } } filteredList.setElements(images.toArray()); // select objects if(!selectedProxy.isEmpty()) { filteredList.setSelection(selectedProxy.toArray()); } } /** * Creates an area where users can select bundles where icons should be selected * * @param composite * the parent composite of the controls created in this area */ protected void createComboArea(Composite composite) { Composite parent = new Composite(composite, SWT.NONE); GridData data = new GridData(); data.grabExcessVerticalSpace = false; data.grabExcessHorizontalSpace = true; data.horizontalAlignment = GridData.FILL; data.verticalAlignment = GridData.BEGINNING; parent.setLayoutData(data); parent.setFont(parent.getFont()); GridLayout layout = new GridLayout(3, false); parent.setLayout(layout); Label label = new Label(parent, SWT.NONE); label.setText("Bundle"); text = new Text(parent, SWT.READ_ONLY | SWT.BORDER); data = new GridData(); data.grabExcessVerticalSpace = false; data.grabExcessHorizontalSpace = true; data.horizontalAlignment = GridData.FILL; data.verticalAlignment = GridData.BEGINNING; text.setLayoutData(data); text.setText(currentBundleName); Button selectBundleButton = new Button(parent, SWT.NONE); selectBundleButton.setText("..."); selectBundleButton.addMouseListener(new MouseListener() { /** * @{inheritDoc */ public void mouseUp(MouseEvent e) { handleManageBundlesButtonPressed(); } /** * @{inheritDoc */ public void mouseDown(MouseEvent e) { } /** * @{inheritDoc */ public void mouseDoubleClick(MouseEvent e) { } }); } /** * Handles action when user press the Manage bundle button in the combo area */ protected void handleManageBundlesButtonPressed() { // open a dialog BundleExplorerDialog dialog = new BundleExplorerDialog(getParentShell(), false, PluginRegistry.getActiveModels(true)); if(Dialog.OK == dialog.open()) { text.setText(((IPluginModel)dialog.getFirstResult()).getPlugin().getId()); refreshList(); } } /** * {@inheritDoc} */ @Override protected void computeResult() { List<Object> proxies = Arrays.asList(getSelectedElements()); List<String> results = new ArrayList<String>(proxies.size()); for(Object proxy : proxies) { results.add(((ImageProxy)proxy).getPluginPath()); } setResult(results); } /** * Returns an array of the currently selected elements. * To be called within or after open(). * * @return returns an array of the currently selected elements. */ protected Object[] getSelectedElements() { Assert.isNotNull(filteredList); return filteredList.getSelection(); } /** * Creates an area where a filter can be entered. This filter will restrict the list of available icons. * * @param parent * the parent composite where to create the filter text * @return the created text area */ protected Text createFilterText(Composite parent) { Text text = new Text(parent, SWT.BORDER); GridData data = new GridData(); data.grabExcessVerticalSpace = false; data.grabExcessHorizontalSpace = true; data.horizontalAlignment = GridData.FILL; data.verticalAlignment = GridData.BEGINNING; text.setLayoutData(data); text.setFont(parent.getFont()); text.setText((filter == null ? "" : filter)); //$NON-NLS-1$ Listener listener = new Listener() { public void handleEvent(Event e) { filteredList.setFilter("*" + filterText.getText()); //$NON-NLS-1$ } }; text.addListener(SWT.Modify, listener); text.addKeyListener(new KeyListener() { public void keyPressed(KeyEvent e) { if(e.keyCode == SWT.ARROW_DOWN) { filteredList.setFocus(); } } public void keyReleased(KeyEvent e) { } }); filterText = text; return text; } /** * Creates a filtered list. * * @param parent * the parent composite. * @return returns the filtered list widget. */ protected FilteredList createFilteredList(Composite parent) { int flags = SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL | (allowMultiple ? SWT.MULTI : SWT.SINGLE); FilteredList list = new FilteredList(parent, flags, new BundleIconLabelProvider(), true, true, true); GridData data = new GridData(); data.widthHint = convertWidthInCharsToPixels(60); data.heightHint = convertHeightInCharsToPixels(18); data.grabExcessVerticalSpace = true; data.grabExcessHorizontalSpace = true; data.horizontalAlignment = GridData.FILL; data.verticalAlignment = GridData.FILL; list.setLayoutData(data); list.setFont(parent.getFont()); list.setFilter((filter == null ? "" : filter)); //$NON-NLS-1$ filteredList = list; return list; } /** * Returns the bundle identifier for the current image * * @return the bundle identifier for the current image */ public String getCurrentBundleName() { return currentBundleName; } /** * Returns the path to the icon in the bundle * * @return the path to the icon in the bundle */ public String getIconPath() { List<Object> proxies = Arrays.asList(getSelectedElements()); if(proxies.size() == 1) { return ((ImageProxy)proxies.get(0)).getLocalPath(); } return ""; } /** * label provider for the icons in Bundle */ public class BundleIconLabelProvider extends LabelProvider { /** * Creates a new BundleIconLabelProvider. */ public BundleIconLabelProvider() { } /** * {@inheritDoc} */ @Override public Image getImage(Object element) { if(element instanceof ImageProxy) { // int index = ((String)element).indexOf(currentBundleName); // String path = ((String)element).substring(index+currentBundleName.length()); // return Activator.getImage(currentBundleName, path); return ((ImageProxy)element).getImage(); } return super.getImage(element); } /** * {@inheritDoc} */ @Override public String getText(Object element) { if(element instanceof ImageProxy) { return ((ImageProxy)element).getText(); } return super.getText(element); } } /** * Proxy for images */ protected class ImageProxy { /** proxied image */ private final Image image; /** full plugin path */ private String path; /** local path inside the plugin */ private String localPath; /** local path inside the plugin */ private String fileName; /** * Creates an Image Proxy * * @param url * the url of the image to proxy */ public ImageProxy(URL url) { localPath = url.getPath(); path = PLUGIN_PROTOCOL + getCurrentBundleName() + localPath; image = org.eclipse.papyrus.uml.diagram.common.Activator.getImage(path, ""); //$NON-NLS-1$ int index = localPath.lastIndexOf('/'); if(index > 0 && index < localPath.length()) { fileName = localPath.substring(index + 1, localPath.length() - GIF_EXTENSION_LENGTH); } else { fileName = Messages.BundleIconExplorerDialog_UnknownFileName; } } /** * Checks if this proxy corresponds to the initial value * * @return <code>true</code> if this is the initial value proxy */ public boolean isInitial() { return initialValue.equals(path); } /** * Returns the real image * * @return the real image */ public Image getImage() { return image; } /** * Returns <code>true</code> if this image is correct * * @return <code>true</code> if this image is correct */ public boolean isDisplayed() { Rectangle bounds = image.getBounds(); if(bounds.height == 16 && bounds.width == 16) { return true; } return false; } /** * Returns the text to display * * @return the text to display */ public String getText() { return fileName; } public String getPluginPath() { return path; } /** * Returns the path to the icon in the bundle * * @return the path to the icon in the bundle */ public String getLocalPath() { return localPath; } } }