blob: 9dc4f271d466e4d4e9ecea368f779699c4880cf6 [file] [log] [blame]
/******************************************************************************
* Copyright (c) 2010, 2014 Oracle 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:
* Konstantin Komissarchik - initial implementation and ongoing maintenance
* Rastislav Wagner - [444850] FacetsSelectionPanel wont disable menu when it should
******************************************************************************/
package org.eclipse.wst.common.project.facet.ui.internal;
import static java.lang.Math.max;
import static org.eclipse.wst.common.project.facet.ui.internal.util.GridLayoutUtil.gdfill;
import static org.eclipse.wst.common.project.facet.ui.internal.util.GridLayoutUtil.gdhfill;
import static org.eclipse.wst.common.project.facet.ui.internal.util.GridLayoutUtil.gdhhint;
import static org.eclipse.wst.common.project.facet.ui.internal.util.GridLayoutUtil.gdhspan;
import static org.eclipse.wst.common.project.facet.ui.internal.util.GridLayoutUtil.gdwhint;
import static org.eclipse.wst.common.project.facet.ui.internal.util.GridLayoutUtil.gl;
import static org.eclipse.wst.common.project.facet.ui.internal.util.GridLayoutUtil.glmargins;
import static org.eclipse.wst.common.project.facet.ui.internal.util.SwtUtil.getPreferredWidth;
import static org.eclipse.wst.common.project.facet.ui.internal.util.SwtUtil.runOnDisplayThread;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.layout.GridDataFactory;
import org.eclipse.jface.resource.CompositeImageDescriptor;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.ImageRegistry;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.CheckboxTreeViewer;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.EditingSupport;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.ILabelProviderListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.jface.window.ToolTip;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.MenuDetectEvent;
import org.eclipse.swt.events.MenuDetectListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.TabFolder;
import org.eclipse.swt.widgets.TabItem;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.wst.common.project.facet.core.ICategory;
import org.eclipse.wst.common.project.facet.core.IFacetedProjectWorkingCopy;
import org.eclipse.wst.common.project.facet.core.IPreset;
import org.eclipse.wst.common.project.facet.core.IProjectFacet;
import org.eclipse.wst.common.project.facet.core.IProjectFacetVersion;
import org.eclipse.wst.common.project.facet.core.ProjectFacetsManager;
import org.eclipse.wst.common.project.facet.core.events.IFacetedProjectEvent;
import org.eclipse.wst.common.project.facet.core.events.IFacetedProjectListener;
import org.eclipse.wst.common.project.facet.core.events.IProjectFacetsChangedEvent;
import org.eclipse.wst.common.project.facet.core.internal.ProjectFacet;
import org.eclipse.wst.common.project.facet.core.runtime.RuntimeManager;
import org.eclipse.wst.common.project.facet.core.runtime.events.IRuntimeLifecycleEvent;
import org.eclipse.wst.common.project.facet.core.runtime.events.IRuntimeLifecycleListener;
import org.eclipse.wst.common.project.facet.ui.IDecorationsProvider;
import org.eclipse.wst.common.project.facet.ui.ModifyFacetedProjectWizard;
import org.eclipse.wst.common.project.facet.ui.internal.util.BasicToolTip;
import org.eclipse.wst.common.project.facet.ui.internal.util.HeaderToolTip;
import org.eclipse.wst.common.project.facet.ui.internal.util.ReadOnlyComboBoxCellEditor;
import org.osgi.framework.Bundle;
/**
* @author <a href="mailto:konstantin.komissarchik@oracle.com">Konstantin Komissarchik</a>
*/
public final class FacetsSelectionPanel
extends Composite
implements ISelectionProvider
{
private static final String IMG_DOWN_ARROW = "##down-arrow##"; //$NON-NLS-1$
private final Composite topComposite;
private final SashForm sform1;
private final SashForm sform2;
private final Label presetsLabel;
private final Combo presetsCombo;
private final Button savePresetButton;
private final Button deletePresetButton;
private final CheckboxTreeViewer treeViewer;
private final Tree tree;
private final TreeViewerColumn colFacet;
private final TreeViewerColumn colVersion;
private final FixedFacetToolTip fixedFacetToolTip;
private final Menu popupMenu;
private final MenuItem popupMenuLockUnlock;
private final MenuItem popupMenuChangeVersion;
private final TableViewer problemsView;
private final TabItem detailsTabItem;
private final DetailsPanel detailsPanel;
private final TabItem runtimesTabItem;
private final RuntimesPanel runtimesPanel;
private boolean showToolTips;
private final IFacetedProjectWorkingCopy fpjwc;
private final List<IFacetedProjectListener> registeredWorkingCopyListeners;
private final Map<IProjectFacet,IProjectFacetVersion> selectedVersions;
private final List<ISelectionChangedListener> selectionListeners;
private Object selection;
/**
* Holds images used throughout the panel.
*/
private final ImageRegistry imageRegistry;
private final IRuntimeLifecycleListener runtimeLifecycleListener;
public interface IFilter
{
boolean check( IProjectFacetVersion fv );
}
public FacetsSelectionPanel( final Composite parent,
final IFacetedProjectWorkingCopy fpjwc )
{
super( parent, SWT.NONE );
this.fpjwc = fpjwc;
this.registeredWorkingCopyListeners = new ArrayList<IFacetedProjectListener>();
this.selectedVersions = new HashMap<IProjectFacet,IProjectFacetVersion>();
this.selection = null;
this.selectionListeners = new ArrayList<ISelectionChangedListener>();
this.showToolTips = false;
// Initialize the image registry.
this.imageRegistry = new ImageRegistry();
final Bundle bundle = Platform.getBundle( FacetUiPlugin.PLUGIN_ID );
URL url = bundle.getEntry( "images/down-arrow.gif" ); //$NON-NLS-1$
this.imageRegistry.put( IMG_DOWN_ARROW, ImageDescriptor.createFromURL( url ) );
// Layout the panel.
setLayout( glmargins( gl( 1 ), 0, 0 ) );
this.topComposite = new Composite( this, SWT.NONE );
this.topComposite.setLayout( glmargins( gl( 4 ), 0, 0 ) );
this.presetsLabel = new Label( this.topComposite, SWT.NONE );
this.presetsLabel.setText( Resources.presetsLabel );
this.presetsCombo = new Combo( this.topComposite, SWT.READ_ONLY );
this.presetsCombo.setLayoutData( gdhfill() );
this.savePresetButton = new Button( this.topComposite, SWT.PUSH );
this.savePresetButton.setText( Resources.saveButtonLabel );
GridDataFactory.defaultsFor( this.savePresetButton ).applyTo( this.savePresetButton );
this.savePresetButton.addSelectionListener
(
new SelectionAdapter()
{
public void widgetSelected( final SelectionEvent e )
{
handleSavePreset();
}
}
);
this.deletePresetButton = new Button( this.topComposite, SWT.PUSH );
this.deletePresetButton.setText( Resources.deleteButtonLabel );
GridDataFactory.defaultsFor( this.deletePresetButton ).applyTo( this.deletePresetButton );
this.deletePresetButton.addSelectionListener
(
new SelectionAdapter()
{
public void widgetSelected( final SelectionEvent e )
{
handleDeletePreset();
}
}
);
this.sform1 = new SashForm( this.topComposite, SWT.VERTICAL | SWT.SMOOTH );
this.sform1.setLayoutData( gdhspan( gdfill(), 4 ) );
this.sform2 = new SashForm( this.sform1, SWT.HORIZONTAL | SWT.SMOOTH );
this.sform2.setLayoutData( gdhspan( gdfill(), 4 ) );
this.treeViewer = new CheckboxTreeViewer( this.sform2, SWT.BORDER );
this.tree = this.treeViewer.getTree();
this.tree.setHeaderVisible( true );
this.treeViewer.setContentProvider( new ContentProvider() );
this.treeViewer.setSorter( new Sorter() );
this.colFacet = new TreeViewerColumn( this.treeViewer, SWT.NONE );
this.colFacet.getColumn().setText( Resources.facetColumnLabel );
this.colFacet.getColumn().setResizable( true );
this.colFacet.setLabelProvider( new FacetColumnLabelProvider() );
this.colFacet.getColumn().setWidth( computeDefaultFacetColumnWidth() );
this.colVersion = new TreeViewerColumn( this.treeViewer, SWT.NONE );
this.colVersion.getColumn().setText( Resources.versionColumnLabel );
this.colVersion.getColumn().setResizable( true );
this.colVersion.setLabelProvider( new FacetVersionColumnLabelProvider() );
this.colVersion.setEditingSupport( new FacetVersionColumnEditingSupport( this.treeViewer ) );
this.colVersion.getColumn().setWidth( computeDefaultVersionColumnWidth() );
this.popupMenu = new Menu( getShell(), SWT.POP_UP );
this.popupMenuChangeVersion = new MenuItem( this.popupMenu, SWT.PUSH );
this.popupMenuChangeVersion.setText( Resources.changeVersionMenuItem );
this.popupMenuChangeVersion.addSelectionListener
(
new SelectionAdapter()
{
public void widgetSelected( final SelectionEvent e )
{
handleChangeVersionMenuSelected();
}
}
);
this.popupMenuLockUnlock = new MenuItem( this.popupMenu, SWT.PUSH );
this.popupMenuLockUnlock.addSelectionListener
(
new SelectionAdapter()
{
public void widgetSelected( final SelectionEvent e )
{
handleFacetLockUnlock();
}
}
);
new FacetToolTip( this.tree );
new CategoryToolTip( this.tree );
this.fixedFacetToolTip = new FixedFacetToolTip( this.tree );
this.treeViewer.setInput( new Object() );
this.treeViewer.addSelectionChangedListener
(
new ISelectionChangedListener()
{
public void selectionChanged( final SelectionChangedEvent e )
{
FacetsSelectionPanel.this.handleSelectionChangedEvent();
}
}
);
this.treeViewer.addCheckStateListener
(
new ICheckStateListener()
{
public void checkStateChanged( final CheckStateChangedEvent e )
{
FacetsSelectionPanel.this.handleCheckStateChanged( e );
}
}
);
this.tree.addListener
(
SWT.PaintItem,
new Listener()
{
public void handleEvent( final Event event )
{
handlePaintItemEvent( event );
}
}
);
this.tree.addListener
(
SWT.MouseDown,
new Listener()
{
public void handleEvent( final Event event )
{
handleMouseDownEvent( event );
}
}
);
this.tree.addMenuDetectListener(new MenuDetectListener() {
public void menuDetected(MenuDetectEvent arg0) {
updatePopupMenu();
}
});
final TabFolder tabFolder = new TabFolder( this.sform2, SWT.NONE );
tabFolder.setLayoutData( gdhhint( gdhfill(), 80 ) );
this.detailsPanel = new DetailsPanel( tabFolder, this );
this.detailsTabItem = new TabItem( tabFolder, SWT.NULL );
this.detailsTabItem.setControl( this.detailsPanel );
this.detailsTabItem.setText( Resources.detailsTabLabel );
this.runtimesPanel = new RuntimesPanel( tabFolder, this.fpjwc );
this.runtimesTabItem = new TabItem( tabFolder, SWT.NULL );
this.runtimesTabItem.setControl( this.runtimesPanel );
this.runtimesTabItem.setText( Resources.runtimesTabLabel );
this.problemsView = new TableViewer( this.sform1, SWT.BORDER );
this.problemsView.setContentProvider( new ProblemsContentProvider() );
this.problemsView.setLabelProvider( new ProblemsLabelProvider() );
this.problemsView.setInput( new Object() );
addDisposeListener
(
new DisposeListener()
{
public void widgetDisposed( final DisposeEvent e )
{
handleDisposeEvent();
}
}
);
Dialog.applyDialogFont( parent );
// Setup runtime lifecycle listener.
this.runtimeLifecycleListener = new IRuntimeLifecycleListener()
{
public void handleEvent( final IRuntimeLifecycleEvent event )
{
handleValidationProblemsChangedEvent();
}
};
RuntimeManager.addListener( this.runtimeLifecycleListener,
IRuntimeLifecycleEvent.Type.VALIDATION_STATUS_CHANGED );
// Bind to the model.
addWorkingCopyListener
(
new IFacetedProjectListener()
{
public void handleEvent( final IFacetedProjectEvent event )
{
handleProjectFacetsChangedEvent( event );
}
},
IFacetedProjectEvent.Type.PROJECT_FACETS_CHANGED
);
handleProjectFacetsChangedEvent( null );
addWorkingCopyListener
(
new IFacetedProjectListener()
{
public void handleEvent( final IFacetedProjectEvent event )
{
handleValidationProblemsChangedEvent();
}
},
IFacetedProjectEvent.Type.VALIDATION_PROBLEMS_CHANGED,
IFacetedProjectEvent.Type.PROJECT_MODIFIED
);
handleValidationProblemsChangedEvent();
addWorkingCopyListener
(
new IFacetedProjectListener()
{
public void handleEvent( final IFacetedProjectEvent event )
{
handleSelectedPresetChangedEvent();
}
},
IFacetedProjectEvent.Type.SELECTED_PRESET_CHANGED
);
ModifyFacetedProjectWizard.syncWithPresetsModel( this.fpjwc, this.presetsCombo );
addWorkingCopyListener
(
new IFacetedProjectListener()
{
public void handleEvent( final IFacetedProjectEvent event )
{
handleModelChangedEvent( event );
}
},
IFacetedProjectEvent.Type.FIXED_FACETS_CHANGED,
IFacetedProjectEvent.Type.SELECTED_PRESET_CHANGED,
IFacetedProjectEvent.Type.TARGETED_RUNTIMES_CHANGED
);
// Set the preferred dimensions of the panel.
final int prefWidthTree = getPreferredWidth( this.tree );
int prefWidthRuntimesPanel = getPreferredWidth( this.runtimesPanel );
prefWidthRuntimesPanel = max( prefWidthRuntimesPanel, 300 );
final int prefWidth = prefWidthTree + prefWidthRuntimesPanel + 80;
this.topComposite.setLayoutData( gdwhint( gdhhint( gdfill(), 500 ), prefWidth ) );
this.sform1.setWeights( new int[] { 70, 30 } );
this.sform2.setWeights( new int[] { prefWidthTree, prefWidthRuntimesPanel } );
// Select the first item in the table.
if( this.tree.getItemCount() > 0 )
{
final TreeItem firstItem = this.tree.getItem( 0 );
this.treeViewer.setSelection( new StructuredSelection( firstItem.getData() ) );
}
handleSelectionChangedEvent();
}
public IFacetedProjectWorkingCopy getFacetedProjectWorkingCopy()
{
return this.fpjwc;
}
public boolean isSelectionValid()
{
return ( this.fpjwc.validate().getSeverity() != IStatus.ERROR );
}
public boolean setFocus()
{
return this.tree.setFocus();
}
public void addSelectionChangedListener( final ISelectionChangedListener listener )
{
this.selectionListeners.add( listener );
}
public void removeSelectionChangedListener( final ISelectionChangedListener listener )
{
this.selectionListeners.remove( listener );
}
public ISelection getSelection()
{
if( this.selection != null )
{
return new StructuredSelection( this.selection );
}
else
{
return new StructuredSelection( new Object[ 0 ] );
}
}
public void setSelection( final ISelection selection )
{
throw new UnsupportedOperationException();
}
private void notifySelectionChangedListeners()
{
final SelectionChangedEvent event = new SelectionChangedEvent( this, getSelection() );
for( ISelectionChangedListener listener : this.selectionListeners )
{
listener.selectionChanged( event );
}
}
private ImageRegistry getImageRegistry()
{
return this.imageRegistry;
}
public Image getImage( final IProjectFacet facet,
final boolean showDecorations )
{
final boolean isFixed = getFacetedProjectWorkingCopy().isFixedProjectFacet( facet );
final String id = ( isFixed && showDecorations ? "F:" : "f:" ) + facet.getId(); //$NON-NLS-1$ //$NON-NLS-2$
Image image = getImageRegistry().get( id );
if( image == null )
{
final IDecorationsProvider decprov
= facet.getAdapter( IDecorationsProvider.class );
ImageDescriptor imgdesc = decprov.getIcon();
if( isFixed && showDecorations )
{
imgdesc = new FixedFacetImageDescriptor( imgdesc );
}
getImageRegistry().put( id, imgdesc );
image = getImageRegistry().get( id );
}
return image;
}
public Image getImage( final ICategory category )
{
final String id = "c:" + category.getId(); //$NON-NLS-1$
Image image = getImageRegistry().get( id );
if( image == null )
{
final IDecorationsProvider decprov
= category.getAdapter( IDecorationsProvider.class );
final ImageDescriptor imgdesc = decprov.getIcon();
getImageRegistry().put( id, imgdesc );
image = getImageRegistry().get( id );
}
return image;
}
private void refresh()
{
// Somehow the checked state of nested items gets lost when a refresh
// is performed, so we have to do this workaround.
final Object[] checked = this.treeViewer.getCheckedElements();
this.treeViewer.refresh();
this.treeViewer.setCheckedElements( checked );
}
public void setCategoryExpandedState( final ICategory category,
final boolean expanded )
{
this.treeViewer.setExpandedState( category, expanded );
}
public boolean getShowToolTips()
{
return this.showToolTips;
}
public void setShowToolTips( final boolean showToolTips )
{
this.showToolTips = showToolTips;
}
private void refreshCategoryState( final ICategory category )
{
if( category == null )
{
return;
}
int available = 0;
int selected = 0;
for( IProjectFacet f : category.getProjectFacets() )
{
if( this.fpjwc.isFacetAvailable( f ) )
{
available++;
}
if( this.fpjwc.hasProjectFacet( f ) )
{
selected++;
}
}
if( selected == 0 )
{
this.treeViewer.setChecked( category, false );
this.treeViewer.setGrayed( category, false );
}
else if( selected == available )
{
this.treeViewer.setChecked( category, true );
this.treeViewer.setGrayed( category, false );
}
else
{
this.treeViewer.setGrayChecked( category, true );
}
}
private void addWorkingCopyListener( final IFacetedProjectListener listener,
final IFacetedProjectEvent.Type... types )
{
this.fpjwc.addListener( listener, types );
this.registeredWorkingCopyListeners.add( listener );
}
public IProjectFacet getSelectedProjectFacet()
{
final IProjectFacetVersion fv = getSelectedProjectFacetVersion();
if( fv != null )
{
return fv.getProjectFacet();
}
return null;
}
public IProjectFacetVersion getSelectedProjectFacetVersion()
{
if( this.selection != null && this.selection instanceof IProjectFacetVersion )
{
return (IProjectFacetVersion) this.selection;
}
return null;
}
private IProjectFacetVersion getSelectedVersion( final IProjectFacet f )
{
final Set<IProjectFacetVersion> availableVersions = this.fpjwc.getAvailableVersions( f );
if( availableVersions.isEmpty() )
{
throw new IllegalStateException();
}
IProjectFacetVersion selectedVersion = this.fpjwc.getProjectFacetVersion( f );
if( selectedVersion == null )
{
selectedVersion = this.selectedVersions.get( f );
if( selectedVersion == null )
{
selectedVersion = f.getDefaultVersion();
}
if( ! availableVersions.contains( selectedVersion ) )
{
selectedVersion = this.fpjwc.getHighestAvailableVersion( f );
}
}
this.selectedVersions.put( f, selectedVersion );
return selectedVersion;
}
private void setSelectedVersion( final IProjectFacet f,
final IProjectFacetVersion fv )
{
if( this.fpjwc.getProjectFacetVersion( f ) != null )
{
this.fpjwc.changeProjectFacetVersion( fv );
}
this.selectedVersions.put( f, fv );
if( f == this.getSelectedProjectFacet() )
{
this.selection = fv;
notifySelectionChangedListeners();
}
}
private void handleSelectionChangedEvent()
{
Object selection = getCurrentSelection();
if( selection != this.selection )
{
this.selection = selection;
notifySelectionChangedListeners();
}
}
private void handleCheckStateChanged( final CheckStateChangedEvent event )
{
final Object el = event.getElement();
final boolean checked = event.getChecked();
if( el instanceof IProjectFacet )
{
final IProjectFacet f = (IProjectFacet) el;
if( this.fpjwc.getFixedProjectFacets().contains( f ) )
{
if( ! checked )
{
this.treeViewer.setChecked( el, true );
final String msg
= NLS.bind( Resources.couldNotDeselectFixedFacetMessage, f.getLabel() );
this.fixedFacetToolTip.setMessage( msg );
final Point cursorLocation = getDisplay().getCursorLocation();
this.fixedFacetToolTip.show( this.tree.toControl( cursorLocation ) );
}
return;
}
if( checked )
{
this.fpjwc.addProjectFacet( getSelectedVersion( f ) );
}
else
{
this.fpjwc.removeProjectFacet( f );
}
refreshCategoryState( f.getCategory() );
}
else
{
final ContentProvider cp
= (ContentProvider) this.treeViewer.getContentProvider();
final Set<IProjectFacetVersion> facets
= new HashSet<IProjectFacetVersion>( this.fpjwc.getProjectFacets() );
final Object[] children = cp.getChildren( el );
int selected = 0;
for( Object child : children )
{
final IProjectFacet f = (IProjectFacet) child;
if( ! this.fpjwc.getFixedProjectFacets().contains( f ) )
{
final IProjectFacetVersion fv = getSelectedVersion( f );
if( checked )
{
facets.add( fv );
}
else
{
facets.remove( fv );
}
this.treeViewer.setChecked( f, checked );
}
if( this.fpjwc.hasProjectFacet( f ) )
{
selected++;
}
}
if( selected == 0 || selected == children.length )
{
this.treeViewer.setGrayed( el, false );
}
else
{
this.treeViewer.setGrayChecked( el, true );
}
this.fpjwc.setProjectFacets( facets );
}
this.fpjwc.setSelectedPreset( null );
}
private void handleMouseDownEvent( final Event event )
{
handleMouseDownEventHelper( event, this.tree.getItems() );
}
private boolean handleMouseDownEventHelper( final Event event,
final TreeItem[] items )
{
for( TreeItem item : items )
{
if( item.getBounds( 1 ).contains( event.x, event.y ) )
{
final TreeItem[] newSelection = new TreeItem[] { item };
if( ! Arrays.equals( this.tree.getSelection(), newSelection ) )
{
this.tree.setSelection( new TreeItem[] { item } );
this.treeViewer.editElement( item.getData(), 1 );
}
return true;
}
else if( handleMouseDownEventHelper( event, item.getItems() ) )
{
return true;
}
}
return false;
}
private void handlePaintItemEvent( final Event event )
{
final TreeItem item = (TreeItem) event.item;
final Object itemData = item.getData();
if( itemData instanceof IProjectFacet && event.index == 1 )
{
final IProjectFacet f = (IProjectFacet) itemData;
if( this.fpjwc.getAvailableVersions( f ).size() > 1 )
{
final Image arrowImage = getImageRegistry().get( IMG_DOWN_ARROW );
final Rectangle arrowImageBounds = arrowImage.getBounds();
final int columnWidth = this.colVersion.getColumn().getWidth();
final int itemHeight = this.tree.getItemHeight();
int x, y;
x = event.x + columnWidth - arrowImageBounds.width - 10;
y = event.y;
event.gc.fillRectangle( x, y, arrowImageBounds.width + 10, itemHeight );
y = event.y + ( itemHeight - arrowImageBounds.height ) / 2;
event.gc.drawImage( arrowImage, x, y );
}
}
}
private void handleDisposeEvent()
{
this.imageRegistry.dispose();
for( IFacetedProjectListener listener : this.registeredWorkingCopyListeners )
{
this.fpjwc.removeListener( listener );
}
RuntimeManager.removeListener( this.runtimeLifecycleListener );
}
private void handleSavePreset()
{
final Set<IProjectFacetVersion> facets = this.fpjwc.getProjectFacets();
final IPreset preset = SavePresetDialog.showDialog( getShell(), facets );
if( preset != null )
{
this.fpjwc.setSelectedPreset( preset.getId() );
}
}
private void handleDeletePreset()
{
final IPreset preset = this.fpjwc.getSelectedPreset();
this.fpjwc.setSelectedPreset( null );
ProjectFacetsManager.deletePreset( preset );
}
private void handleProjectFacetsChangedEvent( final IFacetedProjectEvent event )
{
if( ! Thread.currentThread().equals( getDisplay().getThread() ) )
{
final Runnable uiRunnable = new Runnable()
{
public void run()
{
handleProjectFacetsChangedEvent( event );
}
};
getDisplay().asyncExec( uiRunnable );
return;
}
final Set<ICategory> affectedCategories = new HashSet<ICategory>();
if( event != null )
{
final IFacetedProjectWorkingCopy fpjwc = event.getWorkingCopy();
final IProjectFacetsChangedEvent evt
= (IProjectFacetsChangedEvent) event;
for( IProjectFacetVersion fv : evt.getAllAffectedFacets())
{
final IProjectFacet f = fv.getProjectFacet();
final boolean checked = fpjwc.hasProjectFacet( fv );
this.treeViewer.setChecked( f, checked );
this.treeViewer.update( f, null );
final ICategory category = f.getCategory();
if( category != null )
{
affectedCategories.add( category );
}
}
}
else
{
final List<IProjectFacet> facets = new ArrayList<IProjectFacet>();
for( IProjectFacetVersion fv : this.fpjwc.getProjectFacets() )
{
facets.add( fv.getProjectFacet() );
}
this.treeViewer.setCheckedElements( facets.toArray() );
for( IProjectFacet facet : this.fpjwc.getAvailableFacets().keySet() )
{
final ICategory category = facet.getCategory();
if( category != null )
{
affectedCategories.add( category );
}
}
this.treeViewer.update( this.fpjwc.getAvailableFacets().keySet().toArray(), null );
}
for( ICategory category : affectedCategories )
{
refreshCategoryState( category );
}
}
private void handleValidationProblemsChangedEvent()
{
if( ! Thread.currentThread().equals( getDisplay().getThread() ) )
{
final Runnable uiRunnable = new Runnable()
{
public void run()
{
handleValidationProblemsChangedEvent();
}
};
getDisplay().asyncExec( uiRunnable );
return;
}
this.problemsView.refresh();
if( getFilteredProblems().length == 0 )
{
if( this.sform1.getMaximizedControl() == null )
{
this.sform1.setMaximizedControl( this.sform2 );
}
}
else
{
if( this.sform1.getMaximizedControl() != null )
{
this.sform1.setMaximizedControl( null );
}
}
}
private void handleSelectedPresetChangedEvent()
{
final IPreset preset = this.fpjwc.getSelectedPreset();
if( preset == null )
{
this.savePresetButton.setEnabled( true );
this.deletePresetButton.setEnabled( false );
}
else
{
this.savePresetButton.setEnabled( false );
this.deletePresetButton.setEnabled( preset.getType() == IPreset.Type.USER_DEFINED );
}
}
private void handleModelChangedEvent( final IFacetedProjectEvent event )
{
switch( event.getType() )
{
case FIXED_FACETS_CHANGED:
case TARGETED_RUNTIMES_CHANGED:
{
final Runnable runnable = new Runnable()
{
public void run()
{
refresh();
}
};
runOnDisplayThread( getDisplay(), runnable );
break;
}
}
}
private void handleChangeVersionMenuSelected()
{
final IProjectFacet f = getSelectedProjectFacet();
final IProjectFacetVersion fv = getSelectedVersion( f );
final SortedSet<IProjectFacetVersion> versions = this.fpjwc.getAvailableVersions( f );
final IProjectFacetVersion newVersion
= ChangeFacetVersionDialog.showDialog( getShell(), f, fv, versions );
if( newVersion != null )
{
this.fpjwc.changeProjectFacetVersion( newVersion );
}
}
private void handleFacetLockUnlock()
{
final IProjectFacet f = getSelectedProjectFacet();
final Set<IProjectFacet> fixedFacets
= new HashSet<IProjectFacet>( this.fpjwc.getFixedProjectFacets() );
if( fixedFacets.contains( f ) )
{
fixedFacets.remove( f );
}
else
{
fixedFacets.add( f );
}
this.fpjwc.setFixedProjectFacets( fixedFacets );
}
private void updatePopupMenu()
{
Object selection = getCurrentSelection();
if(selection instanceof IProjectFacetVersion )
{
this.tree.setMenu( this.popupMenu );
final IProjectFacet f = ( (IProjectFacetVersion) selection ).getProjectFacet();
if( this.fpjwc.isFixedProjectFacet( f ) )
{
this.popupMenuLockUnlock.setText( Resources.unlockMenuItem );
}
else
{
this.popupMenuLockUnlock.setText( Resources.lockMenuItem );
}
this.popupMenuLockUnlock.setEnabled( this.fpjwc.hasProjectFacet( f ) );
final int numAvailableVersions = this.fpjwc.getAvailableVersions( f ).size();
this.popupMenuChangeVersion.setEnabled( numAvailableVersions > 1 );
}
else
{
this.tree.setMenu( null );
}
}
private Object getCurrentSelection(){
Object selection = ( (IStructuredSelection) this.treeViewer.getSelection() ).getFirstElement();
if( selection != null && selection instanceof IProjectFacet )
{
return getSelectedVersion( (IProjectFacet ) selection );
}
return null;
}
private TreeItem getTreeItem( final int x,
final int y )
{
return getTreeItemHelper( x, y, this.tree.getItems() );
}
private static TreeItem getTreeItemHelper( final int x,
final int y,
final TreeItem[] items )
{
for( TreeItem item : items )
{
if( item.getBounds().contains( x, y ) )
{
return item;
}
final TreeItem res = getTreeItemHelper( x, y, item.getItems() );
if( res != null )
{
return res;
}
}
return null;
}
private int computeDefaultFacetColumnWidth()
{
final GC gc = new GC( this.getDisplay() );
int maxFacetLabelWidth = 0;
try
{
gc.setFont( this.tree.getFont() );
for( IProjectFacet f : ProjectFacetsManager.getProjectFacets() )
{
maxFacetLabelWidth = max( maxFacetLabelWidth, gc.textExtent( f.getLabel() ).x );
}
}
finally
{
gc.dispose();
}
return max( maxFacetLabelWidth + 100, 200 );
}
private int computeDefaultVersionColumnWidth()
{
final GC gc = new GC( this.getDisplay() );
int maxVersionStringWidth = 0;
final int columnLabelWidth;
try
{
gc.setFont( this.tree.getFont() );
for( IProjectFacet f : ProjectFacetsManager.getProjectFacets() )
{
for( IProjectFacetVersion fv : f.getVersions() )
{
final int textExtent = gc.textExtent( fv.getVersionString() ).x;
maxVersionStringWidth = max( maxVersionStringWidth, textExtent + 30 );
}
}
columnLabelWidth = gc.textExtent( Resources.versionColumnLabel ).x + 30;
}
finally
{
gc.dispose();
}
return max( maxVersionStringWidth, columnLabelWidth );
}
private IStatus[] getFilteredProblems()
{
final IStatus[] unfiltered = this.fpjwc.validate().getChildren();
boolean somethingToRemove = false;
for( IStatus st : unfiltered )
{
if( st.getCode() == IFacetedProjectWorkingCopy.PROBLEM_PROJECT_NAME )
{
somethingToRemove = true;
break;
}
}
if( ! somethingToRemove )
{
return unfiltered;
}
final List<IStatus> filtered = new ArrayList<IStatus>();
for( IStatus st : unfiltered )
{
if( st.getCode() != IFacetedProjectWorkingCopy.PROBLEM_PROJECT_NAME )
{
filtered.add( st );
}
}
return filtered.toArray( new IStatus[ filtered.size() ] );
}
private final class ContentProvider
implements ITreeContentProvider
{
public Object[] getElements( final Object element )
{
final IFacetedProjectWorkingCopy fpjwc = getFacetedProjectWorkingCopy();
final List<Object> list = new ArrayList<Object>();
final Set<ICategory> categories = ProjectFacetsManager.getCategories();
for( ICategory cat : categories )
{
boolean visible = false;
for( IProjectFacet f : cat.getProjectFacets() )
{
if( ! fpjwc.getAvailableVersions( f ).isEmpty() )
{
visible = true;
break;
}
}
if( visible )
{
list.add( cat );
}
}
for( Map.Entry<IProjectFacet,SortedSet<IProjectFacetVersion>> entry
: fpjwc.getAvailableFacets().entrySet() )
{
final IProjectFacet f = entry.getKey();
final SortedSet<IProjectFacetVersion> availableVersions = entry.getValue();
if( f.getCategory() == null && ! availableVersions.isEmpty() )
{
list.add( f );
}
}
return list.toArray();
}
public Object[] getChildren( final Object parent )
{
if( parent instanceof ICategory )
{
final IFacetedProjectWorkingCopy fpjwc = getFacetedProjectWorkingCopy();
final ICategory category = (ICategory) parent;
final List<IProjectFacet> facets = new ArrayList<IProjectFacet>();
for( IProjectFacet f : category.getProjectFacets() )
{
if( ! fpjwc.getAvailableVersions( f ).isEmpty() )
{
facets.add( f );
}
}
return facets.toArray();
}
else
{
return new Object[ 0 ];
}
}
public Object getParent( final Object element )
{
if( element instanceof IProjectFacet )
{
final IProjectFacet f = (IProjectFacet) element;
return f.getCategory();
}
else
{
return null;
}
}
public boolean hasChildren( final Object element )
{
return ( element instanceof ICategory ) &&
! ( (ICategory) element ).getProjectFacets().isEmpty();
}
public void dispose() { }
public void inputChanged( final Viewer viewer,
final Object oldObject,
final Object newObject ) {}
}
private final class FacetColumnLabelProvider
extends ColumnLabelProvider
{
@Override
public String getText( final Object element )
{
if( element instanceof ICategory )
{
return ( (ICategory) element ).getLabel();
}
else
{
return ( (IProjectFacet) element ).getLabel();
}
}
@Override
public Image getImage( final Object element )
{
if( element instanceof IProjectFacet )
{
return FacetsSelectionPanel.this.getImage( (IProjectFacet) element, true );
}
else
{
return FacetsSelectionPanel.this.getImage( (ICategory) element );
}
}
}
private final class FacetVersionColumnLabelProvider
extends ColumnLabelProvider
{
@Override
public String getText( final Object element )
{
if( element instanceof IProjectFacet )
{
final ProjectFacet f = (ProjectFacet) element;
if( ! f.isVersionHidden() )
{
return getSelectedVersion( f ).getVersionString();
}
}
return null;
}
}
private final class FacetVersionColumnEditingSupport
extends EditingSupport
{
private final ReadOnlyComboBoxCellEditor ceditor;
private final IFacetedProjectWorkingCopy fpjwc;
public FacetVersionColumnEditingSupport( final TreeViewer treeViewer )
{
super( treeViewer );
this.ceditor = new ReadOnlyComboBoxCellEditor( treeViewer.getTree(), new String[ 0 ], SWT.DROP_DOWN | SWT.READ_ONLY );
this.fpjwc = getFacetedProjectWorkingCopy();
}
@Override
public boolean canEdit( final Object element )
{
return element instanceof IProjectFacet &&
this.fpjwc.getAvailableVersions( (IProjectFacet ) element ).size() > 1;
}
@Override
protected CellEditor getCellEditor( final Object element )
{
final IProjectFacet f = (IProjectFacet) element;
if( f == null )
{
throw new IllegalStateException();
}
final SortedSet<IProjectFacetVersion> versions = this.fpjwc.getAvailableVersions( f );
final String[] verstrs = new String[ versions.size() ];
Integer value = null;
int i = 0;
for( IProjectFacetVersion fv : versions )
{
verstrs[ i ] = fv.getVersionString();
if( fv == getSelectedVersion( f ) )
{
value = new Integer( i );
}
i++;
}
this.ceditor.setItems( verstrs );
this.ceditor.setValue( value );
return this.ceditor;
}
@Override
public Object getValue( final Object element )
{
final IProjectFacet f = (IProjectFacet) element;
int i = 0;
for( IProjectFacetVersion fv : this.fpjwc.getAvailableVersions( f ) )
{
if( fv == getSelectedVersion( f ) )
{
return new Integer( i );
}
i++;
}
return new IllegalStateException();
}
@Override
public void setValue( final Object element,
final Object value )
{
final IProjectFacet f = (IProjectFacet) element;
final int index = ( (Integer) value ).intValue();
if( index != -1 )
{
int i = 0;
for( IProjectFacetVersion fv : this.fpjwc.getAvailableVersions( f ) )
{
if( i == index )
{
setSelectedVersion( f, fv );
FacetsSelectionPanel.this.treeViewer.update( f, null );
break;
}
i++;
}
}
}
}
private static final class FixedFacetImageDescriptor
extends CompositeImageDescriptor
{
private static final String OVERLAY_IMG_LOCATION
= "images/lock.gif"; //$NON-NLS-1$
private static final ImageData OVERLAY
= FacetUiPlugin.getImageDescriptor( OVERLAY_IMG_LOCATION ).getImageData();
private final ImageData base;
private final Point size;
public FixedFacetImageDescriptor( final ImageDescriptor base )
{
this.base = base.getImageData();
this.size = new Point( this.base.width, this.base.height );
}
protected void drawCompositeImage( final int width,
final int height )
{
drawImage( this.base, 0, 0 );
drawImage( OVERLAY, 0, height - OVERLAY.height );
}
protected Point getSize()
{
return this.size;
}
}
private static final class Sorter
extends ViewerSorter
{
public int compare( final Viewer viewer,
final Object a,
final Object b )
{
return getLabel( a ).compareToIgnoreCase( getLabel( b ) );
}
private static String getLabel( final Object obj )
{
if( obj instanceof IProjectFacet )
{
return ( (IProjectFacet) obj ).getLabel();
}
else
{
return ( (ICategory) obj ).getLabel();
}
}
}
private final class FacetToolTip
extends HeaderToolTip
{
public FacetToolTip( final Control control )
{
super( control );
}
@Override
protected final boolean shouldCreateToolTip( final Event event )
{
if( getShowToolTips() == false )
{
return false;
}
final TreeItem treeItem = getTreeItem( event.x, event.y );
String description = null;
if( treeItem != null && treeItem.getBounds( 0 ).contains( event.x, event.y ) )
{
final Object treeItemData = treeItem.getData();
if( treeItemData instanceof IProjectFacet )
{
description = ( (IProjectFacet) treeItemData ).getDescription();
}
}
return ( description != null && description.trim().length() > 0 );
}
@Override
protected String getToolTipTitle( final Event event )
{
final IProjectFacet f = (IProjectFacet) getTreeItem( event.x, event.y ).getData();
return getSelectedVersion( f ).toString();
}
@Override
protected Composite createContentArea( final Event event,
final Composite parent )
{
final Display display = parent.getDisplay();
final Composite composite = new Composite( parent, SWT.NONE );
composite.setLayout( gl( 1 ) );
composite.setBackground( display.getSystemColor( SWT.COLOR_INFO_BACKGROUND ) );
final Label label = new Label( composite, SWT.WRAP );
label.setLayoutData( gdfill() );
label.setBackground( display.getSystemColor( SWT.COLOR_INFO_BACKGROUND ) );
final IProjectFacet f = (IProjectFacet) getTreeItem( event.x, event.y ).getData();
label.setText( f.getDescription() );
return composite;
}
}
private final class CategoryToolTip
extends HeaderToolTip
{
public CategoryToolTip( final Control control )
{
super( control );
}
@Override
protected final boolean shouldCreateToolTip( final Event event )
{
if( getShowToolTips() == false )
{
return false;
}
final TreeItem treeItem = getTreeItem( event.x, event.y );
String description = null;
if( treeItem != null && treeItem.getBounds( 0 ).contains( event.x, event.y ) )
{
final Object treeItemData = treeItem.getData();
if( treeItemData instanceof ICategory )
{
description = ( (ICategory) treeItemData ).getDescription();
}
}
return ( description != null && description.trim().length() > 0 );
}
@Override
protected String getToolTipTitle( final Event event )
{
return ( (ICategory) getTreeItem( event.x, event.y ).getData() ).getLabel();
}
@Override
protected Composite createContentArea( final Event event,
final Composite parent )
{
final Display display = parent.getDisplay();
final Composite composite = new Composite( parent, SWT.NONE );
composite.setLayout( gl( 1 ) );
composite.setBackground( display.getSystemColor( SWT.COLOR_INFO_BACKGROUND ) );
final Label label = new Label( composite, SWT.WRAP );
label.setLayoutData( gdfill() );
label.setBackground( display.getSystemColor( SWT.COLOR_INFO_BACKGROUND ) );
final ICategory category = (ICategory) getTreeItem( event.x, event.y ).getData();
label.setText( category.getDescription() );
return composite;
}
}
private final class FixedFacetToolTip
extends BasicToolTip
{
private static final int FAKE_EVENT_TYPE = -9999;
public FixedFacetToolTip( final Control control )
{
super( control );
setPopupDelay( 0 );
}
public void show( final Point location )
{
// The JFace ToolTip class does not support alternative methods of tool tip activation.
// An enhancement request https://bugs.eclipse.org/bugs/show_bug.cgi?id=174844 tracks
// this issue. When that enhancement request has been resolved, this hacky
// implementation should be replaced with something more sensible.
final Event fakeEvent = new Event();
fakeEvent.type = FAKE_EVENT_TYPE;
fakeEvent.x = location.x;
fakeEvent.y = location.y;
try
{
final Method method
= ToolTip.class.getDeclaredMethod( "toolTipCreate", Event.class ); //$NON-NLS-1$
method.setAccessible( true );
method.invoke( this, fakeEvent );
}
catch( Exception e )
{
FacetUiPlugin.log( e );
}
}
@Override
protected final boolean shouldCreateToolTip( final Event event )
{
return ( event.type == FAKE_EVENT_TYPE );
}
}
private final class ProblemsContentProvider
implements IStructuredContentProvider
{
public Object[] getElements( final Object element )
{
return getFilteredProblems();
}
public void inputChanged( final Viewer viewer,
final Object oldObject,
final Object newObject ) {}
public void dispose() {}
}
private final class ProblemsLabelProvider
implements ITableLabelProvider
{
public String getColumnText( final Object element,
final int column )
{
return ( (IStatus) element ).getMessage();
}
public Image getColumnImage( final Object element,
final int column )
{
final ISharedImages sharedImages = PlatformUI.getWorkbench().getSharedImages();
final String imageType;
if( ( (IStatus) element ).getSeverity() == IStatus.ERROR )
{
imageType = ISharedImages.IMG_OBJS_ERROR_TSK;
}
else
{
imageType = ISharedImages.IMG_OBJS_WARN_TSK;
}
return sharedImages.getImage( imageType );
}
public boolean isLabelProperty( final Object obj,
final String s )
{
return false;
}
public void dispose() {}
public void addListener( final ILabelProviderListener listener ) {}
public void removeListener( ILabelProviderListener listener ) {}
}
private static final class Resources
extends NLS
{
public static String presetsLabel;
public static String saveButtonLabel;
public static String deleteButtonLabel;
public static String facetColumnLabel;
public static String versionColumnLabel;
public static String couldNotDeselectFixedFacetMessage;
public static String detailsTabLabel;
public static String runtimesTabLabel;
public static String lockMenuItem;
public static String unlockMenuItem;
public static String changeVersionMenuItem;
static
{
initializeMessages( FacetsSelectionPanel.class.getName(),
Resources.class );
}
}
}