/****************************************************************************** * 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 * project g-Eclipse founded by European Union * project number: FP6-IST-034327 http://www.geclipse.eu/ * * Contributor(s): * UCY (http://www.ucy.cs.ac.cy) * - Nicholas Loulloudes (loulloudes.n@cs.ucy.ac.cy) * *****************************************************************************/ package eu.geclipse.jsdl.ui.internal.pages.sections; import java.util.ArrayList; import java.util.Iterator; import org.eclipse.emf.common.util.BasicEList; import org.eclipse.emf.common.util.EList; import org.eclipse.emf.common.util.TreeIterator; import org.eclipse.emf.ecore.EObject; import org.eclipse.emf.ecore.EStructuralFeature; import org.eclipse.emf.ecore.util.EcoreUtil; import org.eclipse.jface.dialogs.MessageDialog; 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.TableViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.jface.viewers.ViewerFilter; import org.eclipse.jface.window.Window; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.ui.forms.widgets.FormToolkit; import eu.geclipse.jsdl.model.base.DataStagingType; import eu.geclipse.jsdl.model.base.JobDefinitionType; import eu.geclipse.jsdl.model.base.JobDescriptionType; import eu.geclipse.jsdl.model.base.JsdlFactory; import eu.geclipse.jsdl.model.base.JsdlPackage; import eu.geclipse.jsdl.model.posix.POSIXApplicationType; import eu.geclipse.jsdl.ui.internal.Activator; import eu.geclipse.jsdl.ui.internal.dialogs.DataStagingInDialog; import eu.geclipse.jsdl.ui.internal.pages.FormSectionFactory; import eu.geclipse.jsdl.ui.internal.pages.Messages; import eu.geclipse.jsdl.ui.providers.DataStageInLabelProvider; import eu.geclipse.jsdl.ui.providers.FeatureContentProvider; /** * @author nloulloud * * This class is responsible for displaying the Stage-In Files section in the * Data Staging Page of the JSDL editor. It provides widgets to manipulate the * elements specified in the "Data Staging Elements" section of the * Job Submission Description Language (JSDL) Specification, Version 1.0. */ public class DataStageInSection extends JsdlFormPageSection { private static final int WIDGET_HEIGHT = 170; protected Button btnStageInAdd = null; protected Button btnStageInEdit = null; protected Button btnStageInDel = null; protected Table tblStageIn = null; protected TableViewer stageInViewer = null; protected ArrayList<DataStagingType>dataStageList = new ArrayList<DataStagingType>(); private TableColumn column; private Composite containerComposite = null; private DataStagingType dataStagingType = JsdlFactory.eINSTANCE.createDataStagingType(); private JobDescriptionType jobDescriptionType = null; private JobDefinitionType jobDefinitionType = null; private EList<DataStagingType> dataStageInputList = null; /** * Class constructor. Creates the section. * * @param parent The parent composite. * @param toolkit The parent Form Toolkit. */ public DataStageInSection( final Composite parent, final FormToolkit toolkit ){ this.containerComposite = parent; createSection( parent, toolkit ); } /* This function creates the Stage-In Section of the DateStage Page */ private void createSection( final Composite parentComposite, final FormToolkit toolkit ) { String sectionTitle = Messages.getString( "DataStagingPage_StageInSection" ); //$NON-NLS-1$ String sectionDescription = Messages.getString( "DataStagingPage_StageInDescr" ); //$NON-NLS-1$ GridData gd; Composite client = FormSectionFactory.createGridStaticSection( toolkit, parentComposite, sectionTitle, sectionDescription, 3 ); gd = new GridData(); gd.horizontalAlignment = GridData.FILL; gd.verticalAlignment = GridData.FILL; gd.verticalSpan = 3; gd.horizontalSpan = 1; gd.widthHint = 600; gd.heightHint = WIDGET_HEIGHT; this.stageInViewer = new TableViewer( client, SWT.BORDER | SWT.FULL_SELECTION | SWT.MULTI); this.tblStageIn = this.stageInViewer.getTable(); this.tblStageIn .setHeaderVisible( true); this.tblStageIn.setLinesVisible( true ); /* Set the common Content Provider */ this.stageInViewer.setContentProvider( new FeatureContentProvider() ); /* Set the dedicated Label Provider for DataStage-In elements */ this.stageInViewer.setLabelProvider( new DataStageInLabelProvider() ); this.column = new TableColumn( this.tblStageIn, SWT.LEFT ); this.column.setText( Messages.getString( "DataStagingPage_Source" ) ); //$NON-NLS-1$ this.column.setWidth( 200 ); this.column = new TableColumn( this.tblStageIn, SWT.CENTER ); this.column.setText( Messages.getString( "DataStagingPage_FileName") ); //$NON-NLS-1$ this.column.setWidth( 150 ); this.column = new TableColumn( this.tblStageIn, SWT.CENTER ); this.column.setText( Messages.getString( "DataStagingPage_CreationFlag" ) ); //$NON-NLS-1$ this.column.setWidth( 100 ); this.column = new TableColumn( this.tblStageIn, SWT.CENTER ); this.column.setText( Messages.getString( "DataStagingPage_DeleteOnTermination" ) ); //$NON-NLS-1$ this.column.setWidth( 100 ); this.stageInViewer.addFilter( new ViewerFilter() { @Override public boolean select( final Viewer viewer, final Object parent, final Object element ) { return ( ( DataStagingType ) element).getSource()!= null; } }); /* Based on the Table Viewer selection, update the status of the respective * buttons. */ this.stageInViewer .addSelectionChangedListener( new ISelectionChangedListener() { public void selectionChanged( final SelectionChangedEvent event ) { updateButtons( ( TableViewer )event.getSource() ); } } ); this.tblStageIn.setData( FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER ); this.tblStageIn.setLayoutData( gd ); /* Create "Add" Button */ gd = new GridData(); gd.horizontalSpan = 2; gd.verticalSpan = 1; gd.widthHint = 60; this.btnStageInAdd = toolkit.createButton( client, Messages.getString( "JsdlEditor_AddButton" ) //$NON-NLS-1$ , SWT.PUSH); this.btnStageInAdd.addSelectionListener( new SelectionListener() { public void widgetSelected( final SelectionEvent event ) { handleEventDialog( null ); performAdd( DataStageInSection.this.stageInViewer ,DataStageInSection.this.dataStageList ); } public void widgetDefaultSelected( final SelectionEvent event ) { // Do Nothing - Required method } }); this.btnStageInAdd.setLayoutData( gd ); /* Create "Edit..." Button */ gd = new GridData(); gd.horizontalSpan = 2; gd.verticalSpan = 1; gd.widthHint = 60; this.btnStageInEdit = toolkit.createButton( client, Messages.getString("JsdlEditor_EditButton") //$NON-NLS-1$ , SWT.PUSH ); this.btnStageInEdit.addSelectionListener( new SelectionListener() { public void widgetSelected( final SelectionEvent event ) { handleEventDialog( getViewerSelectionObject( DataStageInSection.this.stageInViewer ) ); performEdit( DataStageInSection.this.stageInViewer, DataStageInSection.this.dataStageList ); } public void widgetDefaultSelected( final SelectionEvent event ) { // Do Nothing - Required method } }); this.btnStageInEdit.setLayoutData( gd ); /* Create "Remove" Button */ gd = new GridData(); gd.horizontalSpan = 2; gd.verticalSpan = 1; gd.widthHint = 60; gd.verticalAlignment = GridData.BEGINNING; this.btnStageInDel = toolkit.createButton( client, Messages.getString( "JsdlEditor_RemoveButton" ), //$NON-NLS-1$ SWT.PUSH ); this.btnStageInDel.addSelectionListener( new SelectionListener() { public void widgetSelected( final SelectionEvent event ) { performDelete( DataStageInSection.this.stageInViewer ); } public void widgetDefaultSelected( final SelectionEvent event ) { // Do Nothing - Required method } }); this.btnStageInDel.setLayoutData( gd ); /* Update Buttons so as to reflect the initial status of the TableViewer */ updateButtons( this.stageInViewer ); toolkit.paintBordersFor( client ); } protected DataStagingType getViewerSelectionObject( final TableViewer tableViewer ) { DataStagingType result = null; IStructuredSelection selection = ( IStructuredSelection )tableViewer.getSelection(); Object obj = selection.getFirstElement(); if( obj instanceof DataStagingType ) { result = ( DataStagingType )obj; } return result; } protected void handleEventDialog( final DataStagingType selectedObject ) { DataStagingInDialog dialog; if( selectedObject == null ) { dialog = new DataStagingInDialog( this.containerComposite.getShell(), DataStagingInDialog.ADVANCED_DIALOG); if( dialog.open() == Window.OK ) { this.dataStageList = dialog.getDataStageInList(); } } else { dialog = new DataStagingInDialog( this.containerComposite.getShell(), DataStagingInDialog.ADVANCED_DIALOG, selectedObject ); if( dialog.open() == Window.OK ) { this.dataStageList = dialog.getDataStageInList(); } } } // end void handleEventDialog() /** * Add's a new DataStaging element in the JSDL model. The new DataStaging element * is added as a child of the JobDescription element. The new DataStaging element * is a Stage-In element (containing a Source URI). * * @param tableViewer The {@link TableViewer} to add the new DataStaging element. * If the new DataStaging element is a Stage-In element, then the table viewer * responsible for such elements should be passed here. * * @param innerDataStageList The list containing the new DataStaqe elements which were * retrieved from the respective Stage-In dialog * */ @SuppressWarnings({ "unchecked" }) public void performAdd ( final TableViewer tableViewer, final ArrayList<DataStagingType> innerDataStageList) { /* Check if the values from the dialog are null. */ if (innerDataStageList.isEmpty()) { return; } EList <DataStagingType> newInputList = ( EList<DataStagingType> )tableViewer.getInput(); if ( newInputList == null ) { newInputList = new BasicEList<DataStagingType>(); } /* Check if the new Data Stage element is not already in the table viewer's * input */ for (int i=0; i<innerDataStageList.size(); i++){ boolean exists = doesElementExists( this.dataStagingType, innerDataStageList.get( i ), newInputList ); if ( !exists ) { newInputList.add( innerDataStageList.get( i ) ); /* Get the EStructural Feature of the DataStaging Type */ /* Change the table viewers input. */ try { this.jobDescriptionType.getDataStaging().addAll( newInputList ); tableViewer.setInput(this.jobDescriptionType.getDataStaging()); } catch( Exception e ) { Activator.logException( e ); } /* Refresh the table viewer and notify the editor that * the page content has changed. */ tableViewer.refresh(); contentChanged(); } else { /* * Show the Error Dialog, this means that the new values that are to be added * are already contained in the table viewer Input. */ MessageDialog.openError( tableViewer.getControl().getShell(), Messages.getString( "DataStagingPage_DuplicateEntryDialog_Title"), //$NON-NLS-1$ Messages.getString( "DataStagingPage_New_DuplicateEntryDialog_Message" ) ); //$NON-NLS-1$ } } newInputList = null; } // end void performAdd() /** * Delete the selected Element in the TableViewer. The selected element must * be of type: {@link DataStagingType} * * If the selected DataStage element is a data-staged POSIX Input / Output / Error element, then * the respective element in the POSIX Application section will also be deleted. */ protected void performDelete( final TableViewer viewer ) { /* Get the table viewer selection. */ IStructuredSelection structSelection = ( IStructuredSelection ) viewer.getSelection(); Iterator<?> it = structSelection.iterator(); /* * Get the JSDL Posix Element in order to check if the staged item to be deleted has any association with * it - that is if the staged item to be deleted is reported in one of the Input | Output | Error elements. */ POSIXApplicationType posixApplicationType = null; TreeIterator<EObject> iterator = this.jobDefinitionType.eAllContents(); while ( iterator.hasNext ( ) ) { EObject testType = iterator.next(); if ( testType instanceof POSIXApplicationType ) { posixApplicationType = (POSIXApplicationType) testType; } } /* * Iterate over the selections and delete them from the model. */ while ( it.hasNext() ) { /* Get the First Element of the selection. */ Object feature = it.next(); /* Cast the first element to DataStageingType */ DataStagingType selectedDataStage = ( DataStagingType ) feature; /* Remove the selected DataStage object from it's container (JobDescription) */ try { if ( null != posixApplicationType ){ if ( ( null != posixApplicationType.getOutput() ) && (posixApplicationType.getOutput().getValue().equals( selectedDataStage.getFileName() ) ) ){ posixApplicationType.setOutput( null ); } else if ( ( null != posixApplicationType.getInput() ) && ( posixApplicationType.getInput().getValue().equals( selectedDataStage.getFileName() ) ) ) { posixApplicationType.setInput( null ); } else { if ( null != posixApplicationType.getError() ){ posixApplicationType.setError( null ); } } } EcoreUtil.remove( selectedDataStage ); } catch( Exception e ) { Activator.logException( e ); } // end while /* Refresh the viewer and notify the editor that the page content has * changed. */ viewer.refresh(); contentChanged(); } //end iterator } // End void performDelete() /** * Edit the attribute values of the selected object in the TableViewer. * * @param tableViewer The SWT TableViewer that contains the Structural Features * @param innerDataStageList The list containing the selected DataStage elements. * */ @SuppressWarnings({ "unchecked" }) public void performEdit( final TableViewer tableViewer, final ArrayList<DataStagingType> innerDataStageList) { /* Check if the values from the dialog are null. */ if (innerDataStageList.isEmpty()) { return; } //Get the table viewer's input. EList <DataStagingType> newInputList = ( EList<DataStagingType> )tableViewer.getInput(); EStructuralFeature eStructuralFeature; int featureID = JsdlPackage.JOB_DESCRIPTION_TYPE__DATA_STAGING; /* * Get the TableViewer Selection */ IStructuredSelection structSelection = ( IStructuredSelection ) tableViewer.getSelection(); /* If the selection is not null then Change the selected element */ if (structSelection != null) { for (int i=0; i<innerDataStageList.size(); i++){ eStructuralFeature = this.jobDescriptionType.eClass().getEStructuralFeature( featureID ); Object oldDataStageElement = structSelection.getFirstElement(); /* Get the Index of the Element that needs to be changed */ int index = ( ( java.util.List<Object> ) this.jobDescriptionType.eGet(eStructuralFeature)) .indexOf( oldDataStageElement ); /* Instantiate new DataStage and SourceTarge objects */ this.dataStagingType = JsdlFactory.eINSTANCE.createDataStagingType(); this.dataStagingType = innerDataStageList.get( i ); /* Check if the new Data Stage element is not already in the table viewer's * input */ if (!doesElementExists( ( DataStagingType ) oldDataStageElement, this.dataStagingType, newInputList )) { /* Change the element. The element is located through it's index position * in the list. */ ( ( java.util.List<Object> ) this.jobDescriptionType.eGet( eStructuralFeature ) ) .set( index, this.dataStagingType ); /* Refresh the table viewer and notify the editor that * the page content has changed. */ tableViewer.refresh(); contentChanged(); } // end_if doesElementExits() else { /* * Show the Error Dialog, this means that the new values that are edited * are already contained in the table viewer Input. */ MessageDialog.openError( tableViewer.getControl().getShell(), Messages.getString( "DataStagingPage_DuplicateEntryDialog_Title"), //$NON-NLS-1$ Messages.getString( "DataStagingPage_Edit_DuplicateEntryDialog_Message" ) ); //$NON-NLS-1$ } // End else } } // end_if structSelection } // End void performEdit() /* * Private function that checks whether a specific Data Stage element already * exists in the input of the table viewer. The criteria for an element match * are the equality of Location(either Source or Target) and the FileName. * * Returns TRUE if the new element already exists and FALSE if it doesn't. */ private boolean doesElementExists ( final DataStagingType oldDataStage, final DataStagingType newDataStage, final EList <DataStagingType> inputList ) { boolean result = false; /* * Check if the oldDataStage is not null first. */ /* * Check if the new Element is Stage-In element or if is a Stage-Out Element */ if (newDataStage.getSource() != null) { /* * Iterate over all the table viewer input. * If the the new data-stage element is not the old one and * the FileName and Source are the same, return TRUE because * it means that there is a duplicate data-stage element, * so the new one must not be add. * */ for( DataStagingType data : inputList ) { if( !data.equals( oldDataStage ) && data.getSource() != null && data.getFileName().equals( newDataStage.getFileName() ) && data.getSource().getURI().equals( newDataStage.getSource().getURI() ) ) { result = true; } } } else { /* * Iterate over all the table viewer input. * If the the new data-stage element is not the old one and * the FileName and Target are the same, return TRUE because * it means that there is a duplicate data-stage element, * so the new one must not be add. * */ for( DataStagingType data : inputList ) { if( !data.equals( oldDataStage ) && data.getTarget() != null && data.getFileName().equals( newDataStage.getFileName() ) && data.getTarget().getURI().equals( newDataStage.getTarget().getURI() ) ) { result = true; } } } return result; } // End boolean doesElementExists() /** * @param jobDefinition The JSDL Job Definition element. */ @SuppressWarnings("unchecked") public void setInput( final JobDefinitionType jobDefinition ) { this.adapterRefreshed = true; if( null != jobDefinition ) { this.jobDefinitionType = jobDefinition; this.jobDescriptionType = jobDefinition.getJobDescription(); if (null != this.jobDescriptionType ) { if ( null != this.jobDescriptionType.getDataStaging() ){ this.dataStageInputList = this.jobDescriptionType.getDataStaging(); fillFields(); } } } } private void fillFields() { this.isNotifyAllowed = false; this.stageInViewer.setInput( this.dataStageInputList ); this.isNotifyAllowed = true; if( this.adapterRefreshed ) { this.adapterRefreshed = false; } } /* * This function updates the status of the buttons related to * the Stage-In Table Viewer. The Status of the buttons is adjusted * according to the selection and content of the respective * table viewer. * */ protected void updateButtons( final TableViewer tableViewer ) { ISelection selection = tableViewer.getSelection(); boolean selectionAvailable = !selection.isEmpty(); this.btnStageInAdd.setEnabled( true ); this.btnStageInDel.setEnabled( selectionAvailable ); this.btnStageInEdit.setEnabled( selectionAvailable ); } // End updateButtons }