package com.codeaffine.extras.launch.internal.dialog; import static com.codeaffine.extras.launch.internal.LaunchExtrasPlugin.PLUGIN_ID; import static com.codeaffine.extras.launch.internal.dialog.LaunchConfigLabelProvider.LabelMode.DETAIL; import static com.codeaffine.extras.launch.internal.dialog.LaunchConfigLabelProvider.LabelMode.LIST; import static java.util.Arrays.stream; import static org.eclipse.jface.action.IAction.ENABLED; import static org.eclipse.jface.dialogs.IDialogConstants.CANCEL_ID; import static org.eclipse.jface.dialogs.IDialogConstants.CANCEL_LABEL; import static org.eclipse.jface.dialogs.IDialogConstants.OK_ID; import static org.eclipse.jface.dialogs.IDialogConstants.OK_LABEL; import java.util.Comparator; import java.util.stream.Stream; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.ILaunch; import org.eclipse.debug.core.ILaunchConfiguration; import org.eclipse.debug.core.ILaunchManager; import org.eclipse.debug.core.ILaunchMode; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.dialogs.DialogSettings; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.util.IPropertyChangeListener; import org.eclipse.jface.util.PropertyChangeEvent; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.swt.SWT; 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.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.dialogs.FilteredItemsSelectionDialog; import com.codeaffine.eclipse.swt.util.UIThreadSynchronizer; import com.codeaffine.extras.launch.internal.LaunchExtrasPlugin; import com.codeaffine.extras.launch.internal.dialog.LaunchConfigLabelProvider.LabelMode; import com.codeaffine.extras.launch.internal.util.LaunchAdapter; public class LaunchSelectionDialog extends FilteredItemsSelectionDialog implements DuplicatesDetector { static final int EDIT_BUTTON_ID = IDialogConstants.CLIENT_ID + 2; private final ILaunchManager launchManager; private final EditLaunchConfigAction editLaunchConfigAction; private final TerminateLaunchesAction terminateLaunchesAction; private final LaunchConfigSelectionHistory launchConfigHistory; public LaunchSelectionDialog( Shell shell ) { super( shell, true ); launchManager = DebugPlugin.getDefault().getLaunchManager(); editLaunchConfigAction = new EditLaunchConfigAction( this ); editLaunchConfigAction.addPropertyChangeListener( new EditLaunchConfigActionListener() ); terminateLaunchesAction = new TerminateLaunchesAction(); launchConfigHistory = new LaunchConfigSelectionHistory(); setTitle( "Start Launch Configuration" ); setMessage( "Enter a &name pattern (? = any character, * = any string, CamelCase)" ); setListLabelProvider( createLaunchConfigLabelProvider( shell.getDisplay(), LIST ) ); setDetailsLabelProvider( createLaunchConfigLabelProvider( shell.getDisplay(), DETAIL ) ); setSelectionHistory( launchConfigHistory ); setSeparatorLabel( "Launch Configuration matches" ); } public ILaunchConfiguration[] getSelectedLaunchConfigurations() { return Stream.of( getResult() ) .map( element -> ( ILaunchConfiguration )element ) .toArray( ILaunchConfiguration[]::new ); } public String getLaunchModeId() { return new LaunchModeSetting( launchManager, getDialogSettings() ).getLaunchModeId(); } public ILaunchMode getLaunchMode() { return new LaunchModeSetting( launchManager, getDialogSettings() ).getLaunchMode(); } @Override public String getElementName( Object item ) { ILaunchConfiguration configuration = ( ILaunchConfiguration )item; return configuration.getName(); } @Override public void create() { super.create(); registerLaunchConfigDecorationUpdater(); } public void close( int returnCode ) { setReturnCode( returnCode ); close(); } @Override protected void fillViewMenu( IMenuManager menuManager ) { super.fillViewMenu( menuManager ); menuManager.add( new Separator() ); menuManager.add( new ToggleTerminateBeforeRelaunchAction() ); menuManager.add( createLaunchModeDropDownAction() ); } @Override protected void fillContextMenu( IMenuManager menuManager ) { menuManager.add( editLaunchConfigAction ); menuManager.add( new Separator() ); menuManager.add( terminateLaunchesAction ); menuManager.add( new Separator() ); super.fillContextMenu( menuManager ); } @Override protected void createButtonsForButtonBar( Composite parent ) { GridLayout parentLayout = ( GridLayout )parent.getLayout(); parentLayout.makeColumnsEqualWidth = false; parentLayout.numColumns++; Button editButton = createButton( parent, EDIT_BUTTON_ID, "&Edit...", false ); editButton.setEnabled( false ); setButtonLayoutData( editButton ); new Label( parent, SWT.NONE ).setLayoutData( new GridData( 5, 0 ) ); createButton( parent, OK_ID, OK_LABEL, true ); createButton( parent, CANCEL_ID, CANCEL_LABEL, false ); updateOkButtonLabel(); } @Override protected void buttonPressed( int buttonId ) { if( buttonId == EDIT_BUTTON_ID ) { editLaunchConfigAction.run(); } else { super.buttonPressed( buttonId ); } } @Override protected Control createExtendedContentArea( Composite parent ) { return null; } @Override protected IDialogSettings getDialogSettings() { IDialogSettings dialogSettings = LaunchExtrasPlugin.getInstance().getDialogSettings(); return DialogSettings.getOrCreateSection( dialogSettings, "LaunchSelectionDialog" ); } @Override protected void handleSelected( StructuredSelection selection ) { super.handleSelected( selection ); editLaunchConfigAction.setSelection( selection ); terminateLaunchesAction.setSelection( selection ); } @Override protected IStatus validateItem( Object item ) { ILaunchMode preferredLaunchMode = getLaunchMode(); ILaunchConfiguration launchConfig = ( ILaunchConfiguration )item; return new LaunchConfigValidator( launchConfig, preferredLaunchMode ).validate(); } @Override protected ItemsFilter createFilter() { return new LaunchConfigItemsFilter(); } @Override protected Comparator<ILaunchConfiguration> getItemsComparator() { return new LaunchConfigComparator( launchConfigHistory, getLaunchMode() ); } @Override protected void fillContentProvider( AbstractContentProvider contentProvider, ItemsFilter itemsFilter, IProgressMonitor progressMonitor ) throws CoreException { LaunchConfigProvider launchConfigProvider = new LaunchConfigProvider( launchManager ); stream( launchConfigProvider.getLaunchConfigurations() ) .forEach( launchConfig -> contentProvider.add( launchConfig, itemsFilter ) ); } private void registerLaunchConfigDecorationUpdater() { LaunchAdapter launchListener = new LaunchConfigDecorationUpdater(); launchManager.addLaunchListener( launchListener ); getShell().addListener( SWT.Dispose, event -> launchManager.removeLaunchListener( launchListener ) ); } private ILabelProvider createLaunchConfigLabelProvider( Display display, LabelMode labelMode ) { return new LaunchConfigLabelProvider( display, this, labelMode ); } private LaunchModeDropDownAction createLaunchModeDropDownAction() { LaunchModeSetting launchModeSetting = new LaunchModeSetting( launchManager, getDialogSettings() ); LaunchModeDropDownAction result = new LaunchModeDropDownAction( launchModeSetting ); result.addPropertyChangeListener( event -> { updateOkButtonLabel(); updateStatus(); } ); return result; } private void updateOkButtonLabel() { Button okButton = getButton( OK_ID ); LaunchModeSetting launchModeSetting = new LaunchModeSetting( launchManager, getDialogSettings() ); ILaunchMode launchMode = launchModeSetting.getLaunchMode(); if( okButton != null && launchMode != null ) { okButton.setText( launchMode.getLabel() ); okButton.getParent().layout(); } } void updateStatus() { IStatus totalStatus = ( IStatus )getSelectedItems().toList().stream() .map( item -> validateItem( item ) ) .filter( status -> !( ( IStatus )status ).isOK() ) .findFirst() .orElse( okStatus() ); updateStatus( totalStatus ); } private static Status okStatus() { return new Status( OK, PLUGIN_ID, "" ); } public abstract static class AccessibleSelectionHistory extends SelectionHistory { } private class LaunchConfigItemsFilter extends ItemsFilter { LaunchConfigItemsFilter() { super( new LaunchConfigSearchPattern() ); } @Override public boolean matchItem( Object item ) { boolean result = false; if( item instanceof ILaunchConfiguration ) { result = matchLaunchConfig( ( ILaunchConfiguration )item ); } return result; } @Override public boolean isConsistentItem( Object item ) { boolean result = true; if( item instanceof ILaunchConfiguration && !( ( ILaunchConfiguration )item ).exists() ) { result = false; } return result; } private boolean matchLaunchConfig( ILaunchConfiguration launchConfig ) { return matches( launchConfig.getName() ); } } private class LaunchConfigDecorationUpdater extends LaunchAdapter { @Override public void launchesAdded( ILaunch[] launches ) { update(); } @Override public void launchesTerminated( ILaunch[] launches ) { update(); } private void update() { new UIThreadSynchronizer().asyncExec( getShell(), LaunchSelectionDialog.this::refresh ); } } private class EditLaunchConfigActionListener implements IPropertyChangeListener { @Override public void propertyChange( PropertyChangeEvent event ) { if( ENABLED.equals( event.getProperty() ) ) { updateEditButtonEnablement( ( IAction )event.getSource() ); } } private void updateEditButtonEnablement( IAction action ) { Button button = getButton( EDIT_BUTTON_ID ); if( button != null && !button.isDisposed() ) { button.setEnabled( action.isEnabled() ); } } } }