/***************************************************************************** * Copyright (c) 2008 g-Eclipse Consortium * 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 * * Initial development of the original code was made for the * g-Eclipse project founded by European Union * project number: FP6-IST-034327 http://www.geclipse.eu/ * * Contributors: * Mathias Stuempert - initial API and implementation *****************************************************************************/ package eu.geclipse.ui.widgets; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerFilter; 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.layout.GridData; import org.eclipse.swt.layout.GridLayout; 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.Group; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Link; import org.eclipse.swt.widgets.Tree; import eu.geclipse.core.filesystem.GEclipseURI; import eu.geclipse.core.model.GridModel; import eu.geclipse.core.model.IGridConnection; import eu.geclipse.core.model.IGridConnectionElement; import eu.geclipse.core.model.IGridContainer; import eu.geclipse.core.model.IGridElement; import eu.geclipse.core.model.IGridModelEvent; import eu.geclipse.core.model.IGridModelListener; import eu.geclipse.core.model.IGridPreferences; import eu.geclipse.core.reporting.ProblemException; import eu.geclipse.ui.Extensions; import eu.geclipse.ui.dialogs.ProblemDialog; import eu.geclipse.ui.internal.Activator; import eu.geclipse.ui.providers.ConnectionViewContentProvider; import eu.geclipse.ui.providers.GridModelLabelProvider; import eu.geclipse.ui.wizards.IConnectionTokenValidator; import eu.geclipse.ui.wizards.IConnectionUriProcessor; /** * A composite for specifying the settings of a new connection. In fact * it holds all necessary widgets to create an {@link URI} with any of * the available constructors. It may be contextualized with the * eu.geclipse.ui.efs extension point. */ public class GridConnectionDefinitionComposite extends Composite { private static class EditorFieldModifyListener implements ModifyListener { private GridConnectionDefinitionComposite parent; private boolean active; public EditorFieldModifyListener( final GridConnectionDefinitionComposite parent ) { this.parent = parent; } public boolean isActive() { return this.active; } public void setActive( final boolean b ) { this.active = b; } public void modifyText( final ModifyEvent e ) { if ( isActive() ) { this.parent.updateUI(); } } } private static final String FS_GECL = "gecl"; //$NON-NLS-1$ private static final String FS_NULL = EFS.getNullFileSystem().getScheme(); private static final String KEY_FIELD_ACTIVE = "field_enablement"; //$NON-NLS-1$ /** * Hard-coded separator used for preferences. */ private static final String SEPARATOR = ":"; //$NON-NLS-1$ /** * Tree viewer used for the temporary connection. */ protected TreeViewer viewer; /** * Cached error message. */ protected String errorMessage; /** * Link for creating a temporary connection. */ protected Link pathLink; /** * Type of the currently edited URI. */ private String currentURIType; /** * Label of the scheme combo. */ private Label schemeLabel; /** * Label of the uri combo. */ private Label uriLabel; /** * Label of the scheme spec part combo. */ private Label schemeSpecificPartLabel; /** * Label of the authority combo. */ private Label authorityLabel; /** * Label of the user info combo. */ private Label userInfoLabel; /** * Label of the host combo. */ private Label hostLabel; /** * Label of the port combo. */ private Label portLabel; /** * Label of the path combo. */ private Label pathLabel; /** * Label of the query combo. */ private Label queryLabel; /** * Label of the fragment combo. */ private Label fragmentLabel; /** * Combo for editing the URI's scheme. */ private Combo schemeCombo; /** * Combo for editing the URI itself. */ private StoredCombo uriCombo; /** * Combo for editing the URI's scheme spec part. */ private StoredCombo schemeSpecificPartCombo; /** * Combo for editing the URI's authority. */ private StoredCombo authorityCombo; /** * Combo for editing the URI's user info. */ private StoredCombo userInfoCombo; /** * Combo for editing the URI's host. */ private StoredCombo hostCombo; /** * Combo for editing the URI's port. */ private StoredCombo portCombo; /** * Combo for editing the URI's path. */ private StoredCombo pathCombo; /** * Combo for editing the URI's query. */ private StoredCombo queryCombo; /** * Combo for editing the URI's fragment. */ private StoredCombo fragmentCombo; /** * Validator used to validate the tokens or the URI. */ private IConnectionTokenValidator validator; /** * Prozessor used to process the final URI. */ private IConnectionUriProcessor processor; /** * List of registered ModifyListeners. */ private List< ModifyListener > listeners; private EditorFieldModifyListener modifyListener; private IGridContainer mountPoint; /** * Create a new connection definition composite. * * @param parent The parent of the composite. * @param style The composite's style. */ public GridConnectionDefinitionComposite( final IGridContainer mountPoint, final Composite parent, final int style ) { super(parent, style); this.mountPoint = mountPoint; GridData gData; this.modifyListener = new EditorFieldModifyListener( this ); setLayout( new GridLayout( 2, false ) ); gData = new GridData( GridData.FILL_HORIZONTAL ); gData.grabExcessHorizontalSpace = true; setLayoutData( gData ); this.schemeLabel = new Label( this, SWT.NONE ); this.schemeLabel.setText( eu.geclipse.ui.widgets.Messages.getString("GridConnectionDefinitionComposite.scheme_label") ); //$NON-NLS-1$ gData = new GridData(); gData.minimumHeight = 0; this.schemeLabel.setLayoutData( gData ); this.schemeCombo = new Combo( this, SWT.READ_ONLY ); gData = new GridData( GridData.FILL_HORIZONTAL ); gData.grabExcessHorizontalSpace = true; gData.minimumHeight = 0; this.schemeCombo.setLayoutData( gData ); this.uriLabel = new Label( this, SWT.NONE ); this.uriCombo = createEditorField( this, this.uriLabel, eu.geclipse.ui.widgets.Messages.getString("GridConnectionDefinitionComposite.uri_label"), //$NON-NLS-1$ this.modifyListener ); this.schemeSpecificPartLabel = new Label( this, SWT.NONE ); this.schemeSpecificPartCombo = createEditorField( this, this.schemeSpecificPartLabel, eu.geclipse.ui.widgets.Messages.getString("GridConnectionDefinitionComposite.scheme_spec_part_label"), //$NON-NLS-1$ this.modifyListener ); this.authorityLabel = new Label( this, SWT.NONE ); this.authorityCombo = createEditorField( this, this.authorityLabel, eu.geclipse.ui.widgets.Messages.getString("GridConnectionDefinitionComposite.authority_label"), //$NON-NLS-1$ this.modifyListener ); this.userInfoLabel = new Label( this, SWT.NONE ); this.userInfoCombo = createEditorField( this, this.userInfoLabel, eu.geclipse.ui.widgets.Messages.getString("GridConnectionDefinitionComposite.user_info_label"), //$NON-NLS-1$ this.modifyListener ); this.hostLabel = new Label( this, SWT.NONE ); this.hostCombo = createEditorField( this, this.hostLabel, eu.geclipse.ui.widgets.Messages.getString("GridConnectionDefinitionComposite.host_label"), //$NON-NLS-1$ this.modifyListener ); this.portLabel = new Label( this, SWT.NONE ); this.portCombo = createEditorField( this, this.portLabel, eu.geclipse.ui.widgets.Messages.getString("GridConnectionDefinitionComposite.port_label"), //$NON-NLS-1$ this.modifyListener ); this.pathLabel = new Label( this, SWT.NONE ); this.pathCombo = createEditorField( this, this.pathLabel, eu.geclipse.ui.widgets.Messages.getString("GridConnectionDefinitionComposite.path_label"), //$NON-NLS-1$ this.modifyListener ); this.queryLabel = new Label( this, SWT.NONE ); this.queryCombo = createEditorField( this, this.queryLabel, eu.geclipse.ui.widgets.Messages.getString("GridConnectionDefinitionComposite.query_label"), //$NON-NLS-1$ this.modifyListener ); this.fragmentLabel = new Label( this, SWT.NONE ); this.fragmentCombo = createEditorField( this, this.fragmentLabel, eu.geclipse.ui.widgets.Messages.getString("GridConnectionDefinitionComposite.fragment_label"), //$NON-NLS-1$ this.modifyListener ); Group browseGroup = new Group( this, SWT.NONE ); browseGroup.setLayout( new GridLayout( 1, false ) ); browseGroup.setText( eu.geclipse.ui.widgets.Messages.getString("GridConnectionDefinitionComposite.browser_group_title") ); //$NON-NLS-1$ gData = new GridData( GridData.FILL_BOTH ); gData.horizontalSpan = 4; gData.grabExcessHorizontalSpace = true; gData.grabExcessVerticalSpace = true; browseGroup.setLayoutData( gData ); this.pathLink = new Link( browseGroup, SWT.NONE ); this.pathLink.setText( eu.geclipse.ui.widgets.Messages.getString("GridConnectionDefinitionComposite.browser_link") ); //$NON-NLS-1$ gData = new GridData(); this.pathLink.setLayoutData( gData ); this.viewer = new TreeViewer( browseGroup, SWT.BORDER | SWT.H_SCROLL | SWT.V_SCROLL | SWT.SINGLE ); ConnectionViewContentProvider cProvider = new ConnectionViewContentProvider(); this.viewer.setContentProvider( cProvider ); GridModelLabelProvider lProvider = new GridModelLabelProvider(); this.viewer.setLabelProvider( lProvider ); this.viewer.addFilter( new ViewerFilter() { @Override public boolean select( final Viewer view, final Object parentElement, final Object element ) { boolean result = true; if ( element instanceof IGridConnectionElement ) { result = ( ( IGridConnectionElement ) element ).isFolder(); } return result; } } ); Tree tree = this.viewer.getTree(); gData = new GridData( GridData.FILL_BOTH ); gData.grabExcessHorizontalSpace = true; gData.grabExcessVerticalSpace = true; tree.setLayoutData( gData ); initializeSchemeCombo( this.schemeCombo ); this.schemeCombo.addModifyListener( new ModifyListener() { public void modifyText( final ModifyEvent e ) { setupFields(); } } ); this.pathLink.addSelectionListener( new SelectionAdapter() { @Override public void widgetSelected( final SelectionEvent e ) { initializeBrowser(); } } ); this.viewer.addDoubleClickListener( new IDoubleClickListener() { public void doubleClick( final DoubleClickEvent event ) { handleDoubleClick(); } } ); this.viewer.addSelectionChangedListener( new ISelectionChangedListener() { public void selectionChanged( final SelectionChangedEvent event ) { handleSelectionChanged( event.getSelection() ); } } ); GridModel.getRoot().addGridModelListener( new IGridModelListener() { public void gridModelChanged( final IGridModelEvent event ) { handleGridModelChanged( event ); } } ); setupFields(); this.modifyListener.setActive( true ); } /** * Add a {@link ModifyListener} to the list of listeners. Modify * listeners are informed whenever a URI specific token was edited. * * @param l The listener to be added. */ public void addModifyListener( final ModifyListener l ) { if ( this.listeners == null ) { this.listeners = new ArrayList< ModifyListener >(); } if ( ! this.listeners.contains( l ) ) { this.listeners.add( l ); } } /** * Get the cached error message if any or <code>null</code> otherwise. * * @return The error message of the last critical operation or * <code>null</code> if this operation did not cause an error. */ public String getErrorMessage() { return this.errorMessage; } /** * Construct a URI from the currently specified parameters. If this * method fails to construct a URI it returns <code>null</code>. In * this case {@link #getErrorMessage()} will return an * appropriate error message. * * @return A URI from the currently specified parameters or * <code>null</code> in the case of an error. */ public URI getURI() { String oldErrorMessage = getErrorMessage(); String newErrorMessage = null; URI uri = null; String scheme = this.schemeCombo.getText(); try { if ( isActive( this.uriCombo ) ) { uri = new URI( this.uriCombo.getText() ); } else if ( isActive( this.schemeSpecificPartCombo ) ) { String schemeSpecificPart = this.schemeSpecificPartCombo.getText(); String fragment = isActive( this.fragmentCombo ) ? this.fragmentCombo.getText() : null; uri = new URI( scheme, schemeSpecificPart, fragment ); } else if ( ! isActive( this.hostCombo ) ) { String authority = this.authorityCombo.getText(); String path = isActive( this.pathCombo ) ? this.pathCombo.getText() : null; String query = isActive( this.queryCombo ) ? this.queryCombo.getText() : null; String fragment = isActive( this.fragmentCombo ) ? this.fragmentCombo.getText() : null; uri = new URI( scheme, authority, path, query, fragment ); } else { String userInfo = isActive( this.userInfoCombo ) ? this.userInfoCombo.getText() : null; String host = this.hostCombo.getText(); int port = isActive( this.portCombo ) ? Integer.parseInt( this.portCombo.getText() ) : -1; String path = isActive( this.pathCombo ) ? this.pathCombo.getText() : null; String query = isActive( this.queryCombo ) ? this.queryCombo.getText() : null; String fragment = isActive( this.fragmentCombo ) ? this.fragmentCombo.getText() : null; uri = new URI( scheme, userInfo, host, port, path, query, fragment ); } } catch ( URISyntaxException uriExc ) { newErrorMessage = eu.geclipse.ui.widgets.Messages.getString("GridConnectionDefinitionComposite.invalid_uri_error") //$NON-NLS-1$ + uriExc.getMessage(); } catch ( NumberFormatException nfExc ) { newErrorMessage = eu.geclipse.ui.widgets.Messages.getString("GridConnectionDefinitionComposite.invalid_uri_error") //$NON-NLS-1$ + nfExc.getMessage(); } if ( ( ( newErrorMessage != null ) && ! newErrorMessage.equals( oldErrorMessage ) ) || ( ( oldErrorMessage != null ) && ! oldErrorMessage.equals( newErrorMessage ) ) ) { this.errorMessage = newErrorMessage; fireModifyEvent(); } if ( this.processor != null ) { uri = this.processor.processURI( this.mountPoint, uri ); } return uri; } /** * Validates the current settings of the composite controls. If * any setting turns out to be invalid <code>false</code> will be * returned. In this case {@link #getErrorMessage()} will contain * an appropriate error message. * * @return <code>True</code> if all settings are valid, * <code>false</code> otherwise. */ public boolean isValid() { String oldErrorMessage = getErrorMessage(); String newErrorMessage = null; if ( this.validator != null ) { if ( isActive( this.uriCombo ) ) { newErrorMessage = this.validator.validateToken( IConnectionTokenValidator.URI_TOKEN, this.uriCombo.getText() ); } if ( ( newErrorMessage == null ) && isActive( this.schemeSpecificPartCombo ) ) { newErrorMessage = this.validator.validateToken( IConnectionTokenValidator.SCHEME_SPEC_TOKEN, this.schemeSpecificPartCombo.getText() ); } if ( ( newErrorMessage == null ) && isActive( this.authorityCombo ) ) { newErrorMessage = this.validator.validateToken( IConnectionTokenValidator.AUTHORITY_TOKEN, this.authorityCombo.getText() ); } if ( ( newErrorMessage == null ) && isActive( this.userInfoCombo ) ) { newErrorMessage = this.validator.validateToken( IConnectionTokenValidator.USER_INFO_TOKEN, this.userInfoCombo.getText() ); } if ( ( newErrorMessage == null ) && isActive( this.hostCombo ) ) { newErrorMessage = this.validator.validateToken( IConnectionTokenValidator.HOST_TOKEN, this.hostCombo.getText() ); } if ( ( newErrorMessage == null ) && isActive( this.portCombo ) ) { newErrorMessage = this.validator.validateToken( IConnectionTokenValidator.PORT_TOKEN, this.portCombo.getText() ); } if ( ( newErrorMessage == null ) && isActive( this.pathCombo ) ) { newErrorMessage = this.validator.validateToken( IConnectionTokenValidator.PATH_TOKEN, this.pathCombo.getText() ); } if ( ( newErrorMessage == null ) && isActive( this.queryCombo ) ) { newErrorMessage = this.validator.validateToken( IConnectionTokenValidator.QUERY_TOKEN, this.queryCombo.getText() ); } if ( ( newErrorMessage == null ) && isActive( this.fragmentCombo ) ) { newErrorMessage = this.validator.validateToken( IConnectionTokenValidator.FRAGMENT_TOKEN, this.fragmentCombo.getText() ); } } if ( ( ( newErrorMessage != null ) && ! newErrorMessage.equals( oldErrorMessage ) ) || ( ( oldErrorMessage != null ) && ! oldErrorMessage.equals( newErrorMessage ) ) ) { this.errorMessage = newErrorMessage; } return this.errorMessage == null; } /** * Removes the specified listener from the list of listeners. * * @param l The {@link ModifyListener} to be removed. */ public void removeModifyListener( final ModifyListener l ) { if ( this.listeners != null ) { this.listeners.remove( l ); } } /** * Set the {@link URI} represented by the controls of this * composite. No validation is done by this method. * * @param uri The {@link URI} to be set. */ public void setURI( final URI uri ) { this.modifyListener.setActive( false ); String scheme = uri.getScheme(); this.schemeCombo.setText( scheme ); String uris = uri.toString(); String schemeSpecificPart = uri.getSchemeSpecificPart(); String authority = uri.getAuthority(); String userInfo = uri.getUserInfo(); String host = uri.getHost(); int port = uri.getPort(); String path = uri.getPath(); String query = uri.getQuery(); String fragment = uri.getFragment(); this.uriCombo.setDefaultItem( uris != null ? uris : "" ); //$NON-NLS-1$ this.schemeSpecificPartCombo.setDefaultItem( schemeSpecificPart != null ? schemeSpecificPart : "" ); //$NON-NLS-1$ this.authorityCombo.setDefaultItem( authority != null ? authority : "" ); //$NON-NLS-1$ this.userInfoCombo.setDefaultItem( userInfo != null ? userInfo : "" ); //$NON-NLS-1$ this.hostCombo.setDefaultItem( host != null ? host : "" ); //$NON-NLS-1$ this.portCombo.setDefaultItem( port != -1 ? String.valueOf( uri.getPort() ) : "" ); //$NON-NLS-1$ this.pathCombo.setDefaultItem( path != null ? path : "" ); //$NON-NLS-1$ this.queryCombo.setDefaultItem( query != null ? query : "" ); //$NON-NLS-1$ this.fragmentCombo.setDefaultItem( fragment != null ? fragment : "" ); //$NON-NLS-1$ this.modifyListener.setActive( true ); updateUI(); } /** * Notify all {@link ModifyListener}s of a change. */ protected void fireModifyEvent() { if ( this.listeners != null ) { Event event = new Event(); event.widget = this; ModifyEvent mEvent = new ModifyEvent( event ); for ( ModifyListener l : this.listeners ) { l.modifyText( mEvent ); } } } /** * Handle a double click event in the tree viewer. */ protected void handleDoubleClick() { IStructuredSelection selection = ( IStructuredSelection )this.viewer.getSelection(); Object object = selection.getFirstElement(); if( this.viewer.isExpandable( object ) ) { boolean state = this.viewer.getExpandedState( object ); this.viewer.setExpandedState( object, !state ); } } /** * Handle a grid model event. * * @param event The event to be handled. */ protected void handleGridModelChanged( final IGridModelEvent event ) { if ( ( event.getType() == IGridModelEvent.ELEMENTS_ADDED ) || ( event.getType() == IGridModelEvent.ELEMENTS_REMOVED ) ) { refreshViewer( event.getSource() ); } } /** * Handle the change of a selection within the tree viewer. * * @param selection The new selection. */ protected void handleSelectionChanged( final ISelection selection ) { if ( selection instanceof IStructuredSelection ) { IStructuredSelection sSelection = ( IStructuredSelection ) selection; Object object = sSelection.getFirstElement(); if ( ( object != null ) && ( object instanceof IGridConnectionElement ) ) { IGridConnectionElement element = ( ( IGridConnectionElement ) object ); try { IFileStore fileStore = element.getConnectionFileStore(); GEclipseURI geclURI = new GEclipseURI( fileStore.toURI() ); URI uri = geclURI.toSlaveURI(); if ( this.currentURIType.equals( Extensions.EFS_URI_RAW ) ) { this.uriCombo.setText( uri.toString() ); } else if ( this.currentURIType.equals( Extensions.EFS_URI_OPAQUE ) ) { this.schemeSpecificPartCombo.setText( uri.getSchemeSpecificPart() ); } else if ( this.currentURIType.equals( Extensions.EFS_URI_HIERARCHICAL ) || this.currentURIType.equals( Extensions.EFS_URI_SERVER ) ) { this.pathCombo.setText( uri.getPath() ); } } catch ( CoreException cExc ) { this.errorMessage = eu.geclipse.ui.widgets.Messages.getString("GridConnectionDefinitionComposite.invalid_path_error"); //$NON-NLS-1$ fireModifyEvent(); } } } } /** * Initialize the tree viewer in order to browse the specified {@link URI}. */ protected void initializeBrowser() { getDisplay().asyncExec( new Runnable() { public void run() { GridConnectionDefinitionComposite.this.pathLink.setEnabled( false ); URI slaveURI = getURI(); if ( slaveURI != null ) { try { GEclipseURI geclURI = new GEclipseURI( slaveURI ); URI masterURI = geclURI.toMasterURI(); IGridPreferences preferences = GridModel.getPreferences(); IGridConnection connection = preferences.createTemporaryConnection( masterURI ); GridConnectionDefinitionComposite.this.viewer.setInput( connection ); } catch ( ProblemException pExc ) { GridConnectionDefinitionComposite.this.errorMessage = eu.geclipse.ui.widgets.Messages.getString("GridConnectionDefinitionComposite.invalid_temp_conn_error"); //$NON-NLS-1$ fireModifyEvent(); ProblemDialog.openProblem( getShell(), eu.geclipse.ui.widgets.Messages.getString("GridConnectionDefinitionComposite.conn_error"), //$NON-NLS-1$ eu.geclipse.ui.widgets.Messages.getString("GridConnectionDefinitionComposite.invalid_temp_conn_error"), //$NON-NLS-1$ pExc ); } finally { GridConnectionDefinitionComposite.this.pathLink.setEnabled( true ); } } } } ); } /** * Reset all controls. */ protected void resetFields() { setActive( this.uriCombo, this.uriLabel, eu.geclipse.ui.widgets.Messages.getString("GridConnectionDefinitionComposite.uri_label") ); //$NON-NLS-1$ setActive( this.schemeSpecificPartCombo, this.schemeSpecificPartLabel, null ); setActive( this.authorityCombo, this.authorityLabel, null ); setActive( this.userInfoCombo, this.userInfoLabel, null ); setActive( this.hostCombo, this.hostLabel, null ); setActive( this.portCombo, this.portLabel, null ); setActive( this.pathCombo, this.pathLabel, null ); setActive( this.queryCombo, this.queryLabel, null ); setActive( this.fragmentCombo, this.fragmentLabel, null ); String scheme = this.schemeCombo.getText(); if ( ! isEmpty( scheme ) ) { this.uriCombo.setText( scheme + SEPARATOR ); } this.currentURIType = Extensions.EFS_URI_RAW; this.validator = null; } /** * Setup all controls according to the scheme specified in the scheme combo. */ protected void setupFields() { resetFields(); String scheme = this.schemeCombo.getText(); IConfigurationElement extension = Extensions.getRegisteredEFSExtension( scheme ); if ( extension != null ) { IConfigurationElement[] children = extension.getChildren(); if ( ( children != null ) && ( children.length == 1 ) ) { setActive( this.uriCombo, this.uriLabel, null ); processURIScheme( children[ 0 ] ); } try { this.validator = ( IConnectionTokenValidator ) extension.createExecutableExtension( Extensions.EFS_VALIDATOR_ATT ); } catch ( CoreException cExc ) { // Since the validator is optional this may fail and // may throw an exception that we would not like // to handle here } try { this.processor = ( IConnectionUriProcessor ) extension.createExecutableExtension( Extensions.EFS_PROCESSOR_ATT ); } catch ( CoreException cExc ) { // Since the processor is optional this may fail and // may throw an exception that we would not like // to handle here } } layout(); updateUI(); } /** * Update the UI and notify all {@link ModifyListener}s. */ protected void updateUI() { URI uri = getURI(); this.viewer.getTree().setEnabled( uri != null ); this.pathLink.setEnabled( uri != null ); fireModifyEvent(); } /** * Helper method to create a field editor for a specific part of a {@link URI}. * * @param parent The parent of the created controls. * @param label The label of the created combo. * @param text The text of the label. * @return The combo used as editor. */ private StoredCombo createEditorField( final Composite parent, final Label label, final String text, final ModifyListener listener ) { label.setText( text + SEPARATOR ); GridData lData = new GridData(); lData.minimumHeight = 0; label.setLayoutData( lData ); StoredCombo editor = new StoredCombo( parent, SWT.NONE ); GridData eData = new GridData( GridData.FILL_HORIZONTAL ); eData.grabExcessHorizontalSpace = true; eData.minimumHeight = 0; editor.setLayoutData( eData ); editor.addModifyListener( listener ); return editor; } /** * Load all available schemes from the org.eclipse.core.filesystem.filesystems * extension point and initialize the scheme combo with these schemes. * @param combo */ private void initializeSchemeCombo( final Combo combo ) { combo.removeAll(); List< String > schemes = eu.geclipse.core.Extensions.getRegisteredFilesystemSchemes(); Collections.sort( schemes, new Comparator< String >() { public int compare( final String s1, final String s2 ) { return s1.compareToIgnoreCase( s2 ); } } ); for ( String scheme : schemes ) { if ( ! scheme.equalsIgnoreCase( FS_GECL ) && ! scheme.equalsIgnoreCase( FS_NULL ) ) { combo.add( scheme ); } } } private boolean isActive( final StoredCombo editor ) { boolean result = false; Boolean active = ( Boolean ) editor.getData( KEY_FIELD_ACTIVE ); if ( active != null ) { result = active.booleanValue(); } return result; } /** * Helper method to test if the specified String is empty. * * @param s The String to be tested. * @return True if the String is <code>null</code> or its length is 0. */ private boolean isEmpty( final String s ) { return ( s == null ) || ( s.length() == 0 ); } private void processURIScheme( final IConfigurationElement element ) { this.currentURIType = element.getName(); if ( this.currentURIType.equals( Extensions.EFS_URI_RAW ) ) { processRawURIScheme( element ); } else if ( this.currentURIType.equals( Extensions.EFS_URI_OPAQUE ) ) { processOpaqueURIScheme( element ); } else if ( this.currentURIType.equals( Extensions.EFS_URI_HIERARCHICAL ) ) { processHierarchicalURIScheme( element ); } else if ( this.currentURIType.equals( Extensions.EFS_URI_SERVER ) ) { processServerURIScheme( element ); } } private void processServerURIScheme( final IConfigurationElement element ) { String userInfo = element.getAttribute( Extensions.EFS_USER_INFO_ATT ); String host = element.getAttribute( Extensions.EFS_HOST_ATT ); String port = element.getAttribute( Extensions.EFS_PORT_ATT ); String path = element.getAttribute( Extensions.EFS_PATH_ATT ); String query = element.getAttribute( Extensions.EFS_QUERY_ATT ); String fragment = element.getAttribute( Extensions.EFS_FRAGMENT_ATT ); setActive( this.userInfoCombo, this.userInfoLabel, userInfo ); setActive( this.hostCombo, this.hostLabel, host ); setActive( this.portCombo, this.portLabel, port ); setActive( this.pathCombo, this.pathLabel, path ); setActive( this.queryCombo, this.queryLabel, query ); setActive( this.fragmentCombo, this.fragmentLabel, fragment ); String scheme = this.schemeCombo.getText(); IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore(); this.userInfoCombo.setPreferences( preferenceStore, scheme + SEPARATOR + Extensions.EFS_USER_INFO_ATT ); this.hostCombo.setPreferences( preferenceStore, scheme + SEPARATOR + Extensions.EFS_HOST_ATT ); this.portCombo.setPreferences( preferenceStore, scheme + SEPARATOR + Extensions.EFS_PORT_ATT ); this.pathCombo.setPreferences( preferenceStore, scheme + SEPARATOR + Extensions.EFS_PATH_ATT ); this.queryCombo.setPreferences( preferenceStore, scheme + SEPARATOR + Extensions.EFS_QUERY_ATT ); this.fragmentCombo.setPreferences( preferenceStore, scheme + SEPARATOR + Extensions.EFS_FRAGMENT_ATT ); } private void processHierarchicalURIScheme( final IConfigurationElement element ) { String authority = element.getAttribute( Extensions.EFS_AUTHORITY_ATT ); String path = element.getAttribute( Extensions.EFS_PATH_ATT ); String query = element.getAttribute( Extensions.EFS_QUERY_ATT ); String fragment = element.getAttribute( Extensions.EFS_FRAGMENT_ATT ); setActive( this.authorityCombo, this.authorityLabel, authority ); setActive( this.pathCombo, this.pathLabel, path ); setActive( this.queryCombo, this.queryLabel, query ); setActive( this.fragmentCombo, this.fragmentLabel, fragment ); String scheme = this.schemeCombo.getText(); IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore(); this.authorityCombo.setPreferences( preferenceStore, scheme + SEPARATOR + Extensions.EFS_AUTHORITY_ATT ); this.pathCombo.setPreferences( preferenceStore, scheme + SEPARATOR + Extensions.EFS_PATH_ATT ); this.queryCombo.setPreferences( preferenceStore, scheme + SEPARATOR + Extensions.EFS_QUERY_ATT ); this.fragmentCombo.setPreferences( preferenceStore, scheme + SEPARATOR + Extensions.EFS_FRAGMENT_ATT ); } private void processOpaqueURIScheme( final IConfigurationElement element ) { String schemeSpecificPart = element.getAttribute( Extensions.EFS_SCHEME_SPEC_PART_ATT ); String fragment = element.getAttribute( Extensions.EFS_FRAGMENT_ATT ); setActive( this.schemeSpecificPartCombo, this.schemeSpecificPartLabel, schemeSpecificPart ); setActive( this.fragmentCombo, this.fragmentLabel, fragment ); String scheme = this.schemeCombo.getText(); IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore(); this.schemeSpecificPartCombo.setPreferences( preferenceStore, scheme + SEPARATOR + Extensions.EFS_SCHEME_SPEC_PART_ATT ); this.fragmentCombo.setPreferences( preferenceStore, scheme + SEPARATOR + Extensions.EFS_FRAGMENT_ATT ); } private void processRawURIScheme( final IConfigurationElement element ) { String uri = element.getAttribute( Extensions.EFS_URI_ATT ); setActive( this.uriCombo, this.uriLabel, uri ); String scheme = this.schemeCombo.getText(); IPreferenceStore preferenceStore = Activator.getDefault().getPreferenceStore(); this.uriCombo.setPreferences( preferenceStore, scheme + SEPARATOR + Extensions.EFS_URI_ATT ); } /** * Refreshes the {@link TreeViewer} starting with the specified element. If * the element is <code>null</code> the whole {@link TreeViewer} will be * refreshed. * * @param element The {@link IGridElement} that will be refreshed. This also * includes the element's children. */ private void refreshViewer( final IGridElement element ) { Control control = this.viewer.getControl(); if ( ! control.isDisposed() ) { Display display = control.getDisplay(); display.asyncExec( new Runnable() { public void run() { if ( ! GridConnectionDefinitionComposite.this.viewer.getControl().isDisposed() ) { if ( element == null ) { GridConnectionDefinitionComposite.this.viewer.refresh( false ); } else { if ( element instanceof IGridContainer ) { IGridContainer container = ( IGridContainer ) element; if ( container.isLazy() && container.isDirty() ) { GridConnectionDefinitionComposite.this.viewer.setChildCount( container, container.getChildCount() ); } } GridConnectionDefinitionComposite.this.viewer.refresh( element, false ); } } } } ); } } private void setActive( final StoredCombo editor, final Label label, final String text ) { if ( ! isEmpty( text ) ) { label.setText( text + SEPARATOR ); } label.setVisible( ! isEmpty( text ) ); editor.setVisible( ! isEmpty( text ) ); editor.setData( KEY_FIELD_ACTIVE, Boolean.valueOf( ! isEmpty( text ) ) ); ( ( GridData ) label.getLayoutData() ).exclude = isEmpty( text ); ( ( GridData ) editor.getLayoutData() ).exclude = isEmpty( text ); } }