/****************************************************************************** * Copyright (c) 2007 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): * PSNC: * - Katarzyna Bylec (katis@man.poznan.pl) * *****************************************************************************/ package eu.geclipse.servicejob.ui.views; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.DataOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.List; import org.eclipse.core.filesystem.EFS; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.resources.IStorage; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.PlatformObject; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.TreeSelection; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.graphics.Region; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; 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.Tree; import org.eclipse.swt.widgets.TreeColumn; import org.eclipse.swt.widgets.TreeItem; import org.eclipse.ui.IEditorDescriptor; import org.eclipse.ui.IPersistableElement; import org.eclipse.ui.ISelectionListener; import org.eclipse.ui.IStorageEditorInput; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.ide.IDE; import org.eclipse.ui.part.ViewPart; import eu.geclipse.core.model.GridModel; import eu.geclipse.core.model.IGridElement; import eu.geclipse.core.model.IGridModelEvent; import eu.geclipse.core.model.IGridModelListener; import eu.geclipse.core.model.IServiceJob; import eu.geclipse.core.model.IServiceJobResult; import eu.geclipse.servicejob.ui.Activator; import eu.geclipse.servicejob.ui.providers.DetailsContentProvider; import eu.geclipse.servicejob.ui.providers.DetailsLabelProvider; /** * View that is called "Operator's Job History". It displays detailed information * about single service job, such as: list of resources on which this service * job was run, sub-jobs list and results for each sub-job and each resource. */ public class ServiceJobDetailsView extends ViewPart implements ISelectionListener, SelectionListener, IGridModelListener { /** * Name of folder (in state location of this plug-in) where service jobs's * result data is being serialized to files when needed (e.g. when this data * can be opened only with external - system - editor). */ public static final String SERVICE_JOB_FILES_FOLDER = "./serviceJobFiles"; //$NON-NLS-1$ protected Point pt = new Point( 0, 0 ); int selectedColumnIndex; String selectedColumnText; TreeViewer viewer; IServiceJob rootElement; private DetailsContentProvider contentProvider; private DetailsLabelProvider labelProvider; private Composite parent; /** * Constructs instance of this view. */ public ServiceJobDetailsView() { GridModel.addGridModelListener( this ); this.contentProvider = new DetailsContentProvider( null ); this.labelProvider = new DetailsLabelProvider(); } @Override public void createPartControl( final Composite parent1 ) { this.parent = parent1; this.rootElement = findSelectedServiceJob(); if( this.rootElement != null ) { updateViewer( this.rootElement ); } else { Composite mainComp = new Composite( parent1, SWT.NONE ); mainComp.setLayout( new GridLayout( 1, false ) ); Label label = new Label( mainComp, SWT.LEAD ); label.setText( Messages.getString( "ServiceJobsDetailsView.no_service_job_selected" ) ); //$NON-NLS-1$ label.setLayoutData( new GridData() ); } getSite().getPage().addSelectionListener( this ); } private void updateViewer( final IServiceJob newInput ) { createViewer( this.parent ); List<TreeColumn> columns = new ArrayList<TreeColumn>(); TreeColumn nameColumn = new TreeColumn( this.viewer.getTree(), SWT.NONE ); nameColumn.setText( "Resource" ); //$NON-NLS-1$ nameColumn.setAlignment( SWT.LEFT ); nameColumn.setWidth( 200 ); if( newInput != null ) { String[] properties = new String[ newInput.getSingleServiceJobNames().size() + 1 ]; properties[ 0 ] = Messages.getString( "ServiceJobsDetailsView.name" ); //$NON-NLS-1$ int i = 0; for( String subServiceJob : newInput.getSingleServiceJobNames() ) { columns.add( new TreeColumn( this.viewer.getTree(), SWT.NONE ) ); columns.get( i ).setText( subServiceJob ); columns.get( i ).setAlignment( SWT.LEFT ); columns.get( i ).setWidth( newInput.getColumnWidth( subServiceJob ) ); properties[ i ] = subServiceJob; i++; } } ( ( DetailsContentProvider )this.viewer.getContentProvider() ).changeRoot( newInput ); ( ( DetailsLabelProvider )this.viewer.getLabelProvider() ).changeRoot( newInput ); this.viewer.setInput( newInput ); this.viewer.refresh(); this.parent.redraw(); this.parent.update(); addSelectionListenerForEditor(); this.parent.layout(); } private void addSelectionListenerForEditor() { this.viewer.addDoubleClickListener( new IDoubleClickListener() { @SuppressWarnings("unchecked") public void doubleClick( final DoubleClickEvent event ) { ISelection sel = event.getSelection(); if( sel instanceof TreeSelection ) { TreeSelection structured = ( TreeSelection )sel; if( structured.getFirstElement() instanceof List && ServiceJobDetailsView.this.selectedColumnIndex != 0 ) { List<IServiceJobResult> list = ( List<IServiceJobResult> )structured.getFirstElement(); for( IServiceJobResult result : list ) { if( result.getSubServiceJobName() .equals( ServiceJobDetailsView.this.selectedColumnText ) && ServiceJobDetailsView.this.rootElement.getInputStreamForResult( result ) != null ) { String extension = result.getResultType(); if( extension == null || extension.equals( "" ) ) { //$NON-NLS-1$ extension = "txt"; //$NON-NLS-1$ } IWorkbenchWindow window = PlatformUI.getWorkbench() .getActiveWorkbenchWindow(); IWorkbenchPage page = window.getActivePage(); if( page != null ) { try { IEditorDescriptor desc = PlatformUI.getWorkbench() .getEditorRegistry() .getDefaultEditor( "name." + extension ); //$NON-NLS-1$ if( desc != null ) { IStorage storage = new StreamStorage( ServiceJobDetailsView.this.rootElement.getInputStreamForResult( result ), result.getSubServiceJobName() + " - " //$NON-NLS-1$ + result.getResourceName() ); IStorageEditorInput editorInput = new StreamInput( storage, result ); page.openEditor( editorInput, desc.getId() ); } else { File fileForEditor = null; if( ( fileForEditor = Activator.getFileForServiceJobResult( result ) ) == null ) { fileForEditor = serializeInputStream( ServiceJobDetailsView.this.rootElement.getInputStreamForResult( result ), extension ); Activator.addFileForServiceJobResult( result, fileForEditor ); } IFileStore fileStore = EFS.getLocalFileSystem() .getStore( fileForEditor.toURI() ); IDE.openEditorOnFileStore( page, fileStore ); } } catch( PartInitException e ) { // TODO katis Activator.logException( e ); } } break; } } } } } } ); this.viewer.getTree().addListener( SWT.EraseItem, new Listener() { public void handleEvent( final Event event ) { event.detail &= ~SWT.HOT; if( ( event.detail & SWT.SELECTED ) != 0 ) { GC gc = event.gc; Rectangle area = ServiceJobDetailsView.this.viewer.getTree() .getClientArea(); int columnCount = ServiceJobDetailsView.this.viewer.getTree() .getColumnCount(); if( event.index == columnCount - 1 || columnCount == 0 ) { int width = area.x + area.width - event.x; if( width > 0 ) { Region region = new Region(); gc.getClipping( region ); region.add( event.x, event.y, width, event.height ); gc.setClipping( region ); region.dispose(); } } gc.setAdvanced( true ); if( gc.getAdvanced() ) { gc.setAlpha( 127 ); } Rectangle rect = event.getBounds(); TreeItem item = ServiceJobDetailsView.this.viewer.getTree() .getItem( ServiceJobDetailsView.this.pt ); for( int i = 0; i < ServiceJobDetailsView.this.viewer.getTree() .getColumnCount(); i++ ) { if( item != null ) { Rectangle rect1 = item.getBounds( i ); if( rect1.contains( ServiceJobDetailsView.this.pt ) ) { rect = rect1; } } } gc.setForeground( Display.getCurrent() .getSystemColor( SWT.COLOR_LIST_SELECTION ) ); gc.setBackground( Display.getCurrent() .getSystemColor( SWT.COLOR_LIST_SELECTION ) ); gc.fillGradientRectangle( rect.x, rect.y, rect.width, rect.height, false ); gc.setForeground( Display.getCurrent() .getSystemColor( SWT.COLOR_LIST_FOREGROUND ) ); gc.setBackground( Display.getCurrent() .getSystemColor( SWT.COLOR_LIST_BACKGROUND ) ); event.detail &= ~SWT.SELECTED; } } } ); } class StringStorage extends PlatformObject implements IStorage { private String string; StringStorage( final String input ) { this.string = input; } public InputStream getContents() throws CoreException { return new ByteArrayInputStream( this.string.getBytes() ); } public IPath getFullPath() { return null; } public String getName() { int len = Math.min( 5, this.string.length() ); return this.string.substring( 0, len ).concat( "..." ); //$NON-NLS-1$ } public boolean isReadOnly() { return true; } } class StringInput extends PlatformObject implements IStorageEditorInput { private IStorage storage; StringInput( final IStorage storage ) { this.storage = storage; } public boolean exists() { return true; } public ImageDescriptor getImageDescriptor() { return null; } public String getName() { return this.storage.getName(); } public IPersistableElement getPersistable() { return null; } public IStorage getStorage() { return this.storage; } public String getToolTipText() { return Messages.getString( "ServiceJobsDetailsView.string_based_file" ) + ": " + this.storage.getName(); //$NON-NLS-1$ //$NON-NLS-2$ } } private void createViewer( final Composite parent1 ) { TreeViewer tViewer = null; for( Control comp : parent1.getChildren() ) { comp.dispose(); } tViewer = new TreeViewer( parent1, SWT.VIRTUAL | SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION ); Tree tree = tViewer.getTree(); tree.setHeaderVisible( true ); this.viewer = tViewer; this.viewer.setContentProvider( this.contentProvider ); this.viewer.setLabelProvider( this.labelProvider ); this.viewer.getTree().addListener( SWT.MouseDoubleClick, new Listener() { public void handleEvent( final Event event ) { Point point = new Point( event.x, event.y ); TreeItem item = ServiceJobDetailsView.this.viewer.getTree().getItem( point ); if( item != null ) { for( int i = 0; i < ServiceJobDetailsView.this.viewer.getTree() .getColumnCount(); i++ ) { Rectangle rect = item.getBounds( i ); if( rect.contains( point ) ) { if( !ServiceJobDetailsView.this.viewer.getTree() .getItem( point ) .getText( i ) .equals( "" ) ) //$NON-NLS-1$ { ServiceJobDetailsView.this.selectedColumnIndex = i; ServiceJobDetailsView.this.selectedColumnText = ServiceJobDetailsView.this.viewer.getTree() .getColumn( i ) .getText(); break; } else { // TODO katis // do nothing } } else { ServiceJobDetailsView.this.selectedColumnText = ""; //$NON-NLS-1$ ServiceJobDetailsView.this.selectedColumnIndex = -1; } } } } } ); } File serializeInputStream( final InputStream inputStream, final String type ) { File res = null; File serviceJobFolder = Activator.getDefault() .getStateLocation() .append( SERVICE_JOB_FILES_FOLDER ) .toFile(); if( !serviceJobFolder.exists() ) { serviceJobFolder.mkdir(); } boolean fileCreated = false; String fileNameBase = "file"; //$NON-NLS-1$ String fileNameSufix = ""; //$NON-NLS-1$ int i = 0; while( !fileCreated ) { String fileName = fileNameBase + fileNameSufix + "." + type; //$NON-NLS-1$ Path filePath = new Path( serviceJobFolder.getAbsolutePath() ); if( filePath.append( fileName ).toFile().exists() ) { fileNameSufix = Integer.toString( i ); i++; if( i == 100 ) { break; } } else { DataOutputStream out = null; try { File newFile = filePath.append( fileName ).toFile(); fileCreated = true; if( newFile.createNewFile() ) { out = new DataOutputStream( new BufferedOutputStream( new FileOutputStream( newFile ) ) ); int c; while( ( c = inputStream.read() ) != -1 ) { out.writeByte( c ); } res = newFile; } } catch( IOException e ) { // TODO Auto-generated catch block Activator.logException( e ); } finally { try { inputStream.close(); if( out != null ) { out.close(); } } catch( IOException e ) { //Ignore } } } } return res; } protected IServiceJob findSelectedServiceJob() { IServiceJob result = null; ISelection selection = getSite().getPage().getSelection(); if( selection != null && selection instanceof IStructuredSelection ) { Object obj = ( ( IStructuredSelection )selection ).getFirstElement(); if( obj != null && obj instanceof IServiceJob ) { result = ( IServiceJob )obj; } } return result; } @Override public void setFocus() { // TODO Auto-generated method stub } public void selectionChanged( final IWorkbenchPart part, final ISelection selection ) { if( selection instanceof IStructuredSelection ) { Object obj = ( ( IStructuredSelection )selection ).getFirstElement(); if( obj != null && obj instanceof IServiceJob ) { this.rootElement = ( IServiceJob )obj; updateViewer( ( IServiceJob )obj ); this.viewer.getTree().update(); this.viewer.getTree().redraw(); this.viewer.getTree().layout(); this.parent.redraw(); this.parent.update(); this.parent.layout(); } } } @Override public void dispose() { getSite().getPage().removeSelectionListener( this ); super.dispose(); } public void widgetDefaultSelected( final SelectionEvent e ) { // empty } public void widgetSelected( final SelectionEvent e ) { // empty } public void gridModelChanged( final IGridModelEvent event ) { if( event.getType() == IGridModelEvent.ELEMENTS_CHANGED ) { IGridElement[] removedElements = event.getElements(); if( this.viewer != null ) { Control control = this.viewer.getControl(); for( IGridElement elem : removedElements ) { if( elem instanceof IServiceJob ) { if( !control.isDisposed() ) { Display display = control.getDisplay(); display.asyncExec( new Runnable() { public void run() { ServiceJobDetailsView.this.viewer.refresh( true ); } } ); } } } } } } class StreamStorage extends PlatformObject implements IStorage { private InputStream stream; private String name; StreamStorage( final InputStream input, final String name ) { this.stream = input; this.name = name; } public InputStream getContents() throws CoreException { return this.stream; } public IPath getFullPath() { return null; } public String getName() { return this.name; } public boolean isReadOnly() { return true; } } class StreamInput extends PlatformObject implements IStorageEditorInput { private IStorage storage; private IServiceJobResult result; StreamInput( final IStorage sto, final IServiceJobResult result ) { this.storage = sto; this.result = result; } public boolean exists() { return true; } public ImageDescriptor getImageDescriptor() { return null; } public String getName() { return this.storage.getName(); } public IPersistableElement getPersistable() { return null; } public IStorage getStorage() { return this.storage; } public String getToolTipText() { return Messages.getString( "ServiceJobsDetailsView.results" ) + ":" + this.storage.getName(); //$NON-NLS-1$ //$NON-NLS-2$ } @Override public boolean equals( final Object obj ) { boolean res = super.equals( obj ); if( !res && obj instanceof StreamInput ) { res = this.result.equals( ( ( StreamInput )obj ).result ); } return res; } @Override public int hashCode() { return this.result.hashCode(); } } }