/******************************************************************************* * Copyright (c) 2000, 2009 IBM Corporation 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: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.wst.jsdt.internal.ui.wizards.buildpaths.newsourcepage; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.SWT; import org.eclipse.swt.events.DisposeEvent; import org.eclipse.swt.events.DisposeListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.forms.events.HyperlinkAdapter; import org.eclipse.ui.forms.events.HyperlinkEvent; import org.eclipse.ui.forms.widgets.FormText; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.TableWrapData; import org.eclipse.ui.forms.widgets.TableWrapLayout; import org.eclipse.wst.jsdt.core.IPackageFragmentRoot; import org.eclipse.wst.jsdt.core.JavaScriptModelException; import org.eclipse.wst.jsdt.internal.corext.util.Messages; import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin; import org.eclipse.wst.jsdt.internal.ui.preferences.ScrolledPageContent; import org.eclipse.wst.jsdt.internal.ui.util.PixelConverter; import org.eclipse.wst.jsdt.internal.ui.wizards.NewWizardMessages; /** * Displays a set of available links to modify or adjust the project. * The links contain a short description about the consequences of * this action. * * The content depends on the selection made on the project. * If selection changes, then the <code>HintTextGroup</code> will be * notified through the <code>IPackageExplorerActionListener</code> interface. */ public final class HintTextGroup implements ISelectionChangedListener { private Composite fTopComposite; private DialogPackageExplorerActionGroup fActionGroup; private List fNewFolders; private HashMap fImageMap; public HintTextGroup() { fNewFolders= new ArrayList(); fImageMap= new HashMap(); } public Composite createControl(Composite parent) { fTopComposite= new Composite(parent, SWT.NONE); fTopComposite.setFont(parent.getFont()); GridData gridData= new GridData(GridData.FILL_BOTH); PixelConverter converter= new PixelConverter(parent); gridData.heightHint= converter.convertHeightInCharsToPixels(12); gridData.widthHint= converter.convertWidthInCharsToPixels(25); GridLayout gridLayout= new GridLayout(); gridLayout.marginWidth= 0;//-converter.convertWidthInCharsToPixels(2); gridLayout.marginHeight= 0;//= -4; fTopComposite.setLayout(gridLayout); fTopComposite.setLayoutData(gridData); fTopComposite.setData(null); fTopComposite.addDisposeListener(new DisposeListener() { public void widgetDisposed(DisposeEvent e) { Collection collection= fImageMap.values(); Iterator iterator= collection.iterator(); while(iterator.hasNext()) { Image image= (Image)iterator.next(); image.dispose(); } } }); return fTopComposite; } private Shell getShell() { return JavaScriptPlugin.getActiveWorkbenchShell(); } /** * An action group managing the actions needed by * the <code>HintTextGroup</code>. * * Note: This method has to be called on initialization. * Calling this method in the constructor is not * possible because the actions might need a reference to * this class. * * @param actionGroup the action group containing the necessary * actions * * @see DialogPackageExplorerActionGroup */ public void setActionGroup(DialogPackageExplorerActionGroup actionGroup) { fActionGroup= actionGroup; } /** * Creates a form text. * * @param parent the parent to put the form text on * @param text the form text to be displayed * @return the created form text * * @see FormToolkit#createFormText(org.eclipse.swt.widgets.Composite, boolean) */ private FormText createFormText(Composite parent, String text) { FormToolkit toolkit= new FormToolkit(getShell().getDisplay()); try { FormText formText= toolkit.createFormText(parent, true); formText.setFont(parent.getFont()); try { formText.setText(text, true, false); } catch (IllegalArgumentException e) { formText.setText(e.getMessage(), false, false); JavaScriptPlugin.log(e); } formText.marginHeight= 2; formText.marginWidth= 0; formText.setBackground(null); formText.setLayoutData(new TableWrapData(TableWrapData.FILL_GRAB)); return formText; } finally { toolkit.dispose(); } } /** * Create a label with a hyperlink and a picture. * * @param parent the parent widget of the label * @param text the text of the label * @param action the action to be executed if the hyperlink is activated */ private void createLabel(Composite parent, String text, final BuildpathModifierAction action) { FormText formText= createFormText(parent, text); Image image= (Image)fImageMap.get(action.getId()); if (image == null) { image= action.getImageDescriptor().createImage(); fImageMap.put(action.getId(), image); } formText.setImage("defaultImage", image); //$NON-NLS-1$ formText.addHyperlinkListener(new HyperlinkAdapter() { public void linkActivated(HyperlinkEvent e) { action.run(); } }); } /** * Handle folder creation. This includes: * <li>Set the selection of the <code>fPackageExplorer</code> * to the result object, unless the result object is <code> * null</code></li> * <li>Add the created folder to the list of new folders</li> * * In this case, the list consists only of one element on which the * new folder has been created * * @param result a list with only one element to be selected by the * <code>fPackageExplorer</code>, or an empty list if creation was * aborted */ void handleFolderCreation(List result) { if (result.size() == 1) { try { fNewFolders.add(((IPackageFragmentRoot)result.get(0)).getCorrespondingResource()); } catch (JavaScriptModelException e) { JavaScriptPlugin.log(e); } } } public List getCreatedResources() { return fNewFolders; } public void resetCreatedResources() { fNewFolders.clear(); } /** * {@inheritDoc} */ public void selectionChanged(SelectionChangedEvent event) { if (event.getSelection() instanceof StructuredSelection) { handlePostSelectionChange((StructuredSelection)event.getSelection()); } else { handlePostSelectionChange(StructuredSelection.EMPTY); } } private void handlePostSelectionChange(StructuredSelection selection) { BuildpathModifierAction[] actions= fActionGroup.getHintTextGroupActions(); String[] descriptions= new String[actions.length]; for (int i= 0; i < actions.length; i++) { descriptions[i]= actions[i].getDetailedDescription(); } // Get the child composite of the top composite Composite childComposite= (Composite)fTopComposite.getData(); // Dispose old composite (if necessary) if (childComposite != null && childComposite.getParent() != null) childComposite.getParent().dispose(); PixelConverter converter= new PixelConverter(fTopComposite); // Create new composite ScrolledPageContent spc= new ScrolledPageContent(fTopComposite, SWT.V_SCROLL); spc.getVerticalBar().setIncrement(5); GridData gridData= new GridData(GridData.FILL_BOTH); gridData.heightHint= converter.convertHeightInCharsToPixels(12); gridData.widthHint= converter.convertWidthInCharsToPixels(25); spc.setLayoutData(gridData); childComposite= spc.getBody(); TableWrapLayout tableWrapLayout= new TableWrapLayout(); tableWrapLayout.leftMargin= 0; tableWrapLayout.rightMargin= 0; childComposite.setLayout(tableWrapLayout); gridData= new GridData(GridData.FILL_BOTH); gridData.heightHint= converter.convertHeightInCharsToPixels(12); gridData.widthHint= converter.convertWidthInCharsToPixels(25); childComposite.setLayoutData(gridData); fTopComposite.setData(childComposite); if (noContextHelpAvailable(actions)) { String noAction= noAction(selection); createFormText(childComposite, Messages.format(NewWizardMessages.HintTextGroup_NoAction, noAction)); fTopComposite.layout(true); return; } for (int i= 0; i < actions.length; i++) { createLabel(childComposite, descriptions[i], actions[i]); } fTopComposite.layout(true); } private String noAction(ISelection selection) { if (selection instanceof StructuredSelection) { return noAction(((StructuredSelection)selection).toList()); } else { return noAction(Collections.EMPTY_LIST); } } private String noAction(List selectedElements) { if (selectedElements.size() == 0) return NewWizardMessages.PackageExplorerActionGroup_NoAction_NullSelection; if (selectedElements.size() == 1) return NewWizardMessages.PackageExplorerActionGroup_NoAction_NoReason; return NewWizardMessages.PackageExplorerActionGroup_NoAction_MultiSelection; } /** * Check if for the current type of selection, no context specific actions can * be applied. Note: this does not mean, that there are NO actions available at all.<p> * * For example: if the default package is selected, there is no specific action for this kind * of selection as no operations are allowed on the default package. Nevertheless, the * <code>PackageExplorerActionEvent</code> will return at least one action that allows to * link to an existing folder in the file system, but this operation is always available * and does not add any supporting information to the current selection. Therefore, * it can be filtered and the correct answer to the user is that there is no specific * action for the default package. * * @param actions an array of provided actions * @return <code>true</code> if there is at least one action that allows context * sensitive operations, <code>false</code> otherwise. */ private boolean noContextHelpAvailable(BuildpathModifierAction[] actions) { if (actions.length == 0) return true; if (actions.length == 1) { int id= Integer.parseInt(actions[0].getId()); if (id == BuildpathModifierAction.CREATE_LINK) return true; } if (actions.length == 2) { int idLink= Integer.parseInt(actions[0].getId()); int idReset= Integer.parseInt(actions[1].getId()); if (idReset == BuildpathModifierAction.RESET_ALL && idLink == BuildpathModifierAction.CREATE_LINK) return true; } return false; } }