content: /*******************************************************************************
   * Copyright (c) 2000, 2008 IBM Corporation 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:
   *     IBM Corporation - initial API and implementation
   *******************************************************************************/
  
  package org.eclipse.wst.jsdt.internal.ui.javaeditor;
  
  
  
  import java.lang.reflect.InvocationTargetException;
  import java.util.ArrayList;
  import java.util.Iterator;
  import java.util.List;
  
  import org.eclipse.core.resources.IFile;
  import org.eclipse.core.runtime.CoreException;
  import org.eclipse.core.runtime.IPath;
  import org.eclipse.core.runtime.IProgressMonitor;
  import org.eclipse.core.runtime.IStatus;
  import org.eclipse.core.runtime.Status;
  import org.eclipse.core.runtime.jobs.Job;
  import org.eclipse.jface.action.Action;
  import org.eclipse.jface.action.IAction;
  import org.eclipse.jface.action.IMenuManager;
  import org.eclipse.jface.operation.IRunnableWithProgress;
  import org.eclipse.jface.preference.IPreferenceStore;
  import org.eclipse.jface.resource.JFaceResources;
  import org.eclipse.jface.text.IWidgetTokenKeeper;
  import org.eclipse.jface.text.source.ISourceViewer;
  import org.eclipse.jface.text.source.IVerticalRuler;
  import org.eclipse.jface.util.IPropertyChangeListener;
  import org.eclipse.jface.util.PropertyChangeEvent;
  import org.eclipse.swt.SWT;
  import org.eclipse.swt.custom.StackLayout;
  import org.eclipse.swt.custom.StyledText;
  import org.eclipse.swt.events.DisposeEvent;
  import org.eclipse.swt.events.DisposeListener;
  import org.eclipse.swt.events.SelectionEvent;
  import org.eclipse.swt.events.SelectionListener;
  import org.eclipse.swt.graphics.Color;
  import org.eclipse.swt.graphics.Font;
  import org.eclipse.swt.layout.FillLayout;
  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.IActionBars;
  import org.eclipse.ui.IEditorInput;
  import org.eclipse.ui.IFileEditorInput;
  import org.eclipse.ui.PlatformUI;
  import org.eclipse.ui.actions.ActionContext;
  import org.eclipse.ui.actions.ActionGroup;
  import org.eclipse.ui.texteditor.IDocumentProvider;
  import org.eclipse.ui.texteditor.ITextEditorActionConstants;
  import org.eclipse.ui.texteditor.IWorkbenchActionDefinitionIds;
  import org.eclipse.wst.jsdt.core.IClassFile;
  import org.eclipse.wst.jsdt.core.IIncludePathEntry;
  import org.eclipse.wst.jsdt.core.IJavaScriptElement;
  import org.eclipse.wst.jsdt.core.IJavaScriptModelStatusConstants;
  import org.eclipse.wst.jsdt.core.IJavaScriptProject;
  import org.eclipse.wst.jsdt.core.IPackageFragmentRoot;
  import org.eclipse.wst.jsdt.core.JavaScriptModelException;
  import org.eclipse.wst.jsdt.core.dom.JavaScriptUnit;
  import org.eclipse.wst.jsdt.internal.ui.JavaScriptPlugin;
  import org.eclipse.wst.jsdt.internal.ui.JavaUIStatus;
  import org.eclipse.wst.jsdt.internal.ui.actions.CompositeActionGroup;
  import org.eclipse.wst.jsdt.internal.ui.util.ExceptionHandler;
  import org.eclipse.wst.jsdt.internal.ui.util.PixelConverter;
  import org.eclipse.wst.jsdt.internal.ui.wizards.buildpaths.SourceAttachmentBlock;
  import org.eclipse.wst.jsdt.ui.actions.RefactorActionGroup;
  
  /**
   * Java specific text editor.
   */
  public class ClassFileEditor extends JavaEditor implements ClassFileDocumentProvider.InputChangeListener {
  
  
  	/**
  	 * A form to attach source to a class file.
  	 */
  	private class SourceAttachmentForm implements IPropertyChangeListener {
  
  		private final IClassFile fFile;
  		private Composite fComposite;
  		private Color fBackgroundColor;
  		private Color fForegroundColor;
  		private Color fSeparatorColor;
  		private List fBannerLabels= new ArrayList();
  		private List fHeaderLabels= new ArrayList();
  		private Font fFont;
  
  		/**
  		 * Creates a source attachment form for a class file.
  		 * 
  		 * @param file the class file
  		 */
  		public SourceAttachmentForm(IClassFile file) {
  			fFile= file;
  		}
  
  		/**
  		 * Returns the package fragment root of this file.
  		 * 
  		 * @param file the class file 
  		 * @return the package fragment root of the given class file
  		 */
  		private IPackageFragmentRoot getPackageFragmentRoot(IClassFile file) {
  
  			IJavaScriptElement element= file.getParent();
  			while (element != null && element.getElementType() != IJavaScriptElement.PACKAGE_FRAGMENT_ROOT)
  				element= element.getParent();
  
  			return (IPackageFragmentRoot) element;
  		}
  
  		/**
  		 * Creates the control of the source attachment form.
  		 * 
  		 * @param parent the parent composite 
  		 * @return the creates source attachment form
  		 */
  		public Control createControl(Composite parent) {
  
  			Display display= parent.getDisplay();
  			fBackgroundColor= display.getSystemColor(SWT.COLOR_LIST_BACKGROUND);
  			fForegroundColor= display.getSystemColor(SWT.COLOR_LIST_FOREGROUND);
  			fSeparatorColor= new Color(display, 152, 170, 203);
  
  			JFaceResources.getFontRegistry().addListener(this);
  
  			fComposite= createComposite(parent);
  			fComposite.setLayout(new GridLayout());
  			fComposite.addDisposeListener(new DisposeListener() {
  				public void widgetDisposed(DisposeEvent e) {
  					JFaceResources.getFontRegistry().removeListener(SourceAttachmentForm.this);
  					fComposite= null;
  					fSeparatorColor.dispose();
  					fSeparatorColor= null;
  					fBannerLabels.clear();
  					fHeaderLabels.clear();
  					if (fFont != null) {
  						fFont.dispose();
  						fFont= null;
  					}
  				}
  			});
  
  			createTitleLabel(fComposite, JavaEditorMessages.SourceAttachmentForm_title);
  			createLabel(fComposite, null);
  			createLabel(fComposite, null);
  
  			createHeadingLabel(fComposite, JavaEditorMessages.SourceAttachmentForm_heading);
  
  			Composite separator= createCompositeSeparator(fComposite);
  			GridData data= new GridData(GridData.FILL_HORIZONTAL);
  			data.heightHint= 2;
  			separator.setLayoutData(data);
  
  //			try {
  //				IPackageFragmentRoot root= getPackageFragmentRoot(fFile);
  //				if (root != null) {
  //					createSourceAttachmentControls(fComposite, root);
  //				}
  //			} catch (JavaScriptModelException e) {
  //				String title= JavaEditorMessages.SourceAttachmentForm_error_title;
  //				String message= JavaEditorMessages.SourceAttachmentForm_error_message;
  //				ExceptionHandler.handle(e, fComposite.getShell(), title, message);
  //			}
  
  			separator= createCompositeSeparator(fComposite);
  			data= new GridData(GridData.FILL_HORIZONTAL);
  			data.heightHint= 2;
  			separator.setLayoutData(data);
  
  			fNoSourceTextWidget= createCodeView(fComposite);
  			data= new GridData(GridData.FILL_BOTH);
  			fNoSourceTextWidget.setLayoutData(data);
  			
  //			updateCodeView(fNoSourceTextWidget, fFile);
  			
  			return fComposite;
  		}
  
  //		private void createSourceAttachmentControls(Composite composite, IPackageFragmentRoot root) throws JavaScriptModelException {
  //			IIncludePathEntry entry;
  //			try {
  //				entry= root.getRawIncludepathEntry();
  //			} catch (JavaScriptModelException ex) {
  //				if (ex.isDoesNotExist())
  //					entry= null;
  //				else
  //					throw ex;
  //			}
  //			IPath containerPath= null;
  //
  //			if (entry == null || root.getKind() != IPackageFragmentRoot.K_BINARY) {
  //				createLabel(composite, Messages.format(JavaEditorMessages.SourceAttachmentForm_message_noSource, fFile.getDisplayName()));
  //				return;
  //			}
  //
  //			IJavaScriptProject jproject= root.getJavaScriptProject();
  //			if (entry.getEntryKind() == IIncludePathEntry.CPE_CONTAINER) {
  //				containerPath= entry.getPath();
  //				JsGlobalScopeContainerInitializer initializer= JavaScriptCore.getJsGlobalScopeContainerInitializer(containerPath.segment(0));
  //				IJsGlobalScopeContainer container= JavaScriptCore.getJsGlobalScopeContainer(containerPath, jproject);
  //				if (initializer == null || container == null) {
  //					createLabel(composite, Messages.format(JavaEditorMessages.ClassFileEditor_SourceAttachmentForm_cannotconfigure, containerPath.toString())); 
  //					return;
  //				}
  //				String containerName= container.getDescription();
  //				IStatus status= initializer.getSourceAttachmentStatus(containerPath, jproject);
  //				if (status.getCode() == JsGlobalScopeContainerInitializer.ATTRIBUTE_NOT_SUPPORTED) {
  //					createLabel(composite, Messages.format(JavaEditorMessages.ClassFileEditor_SourceAttachmentForm_notsupported, containerName));  
  //					return;
  //				}
  //				if (status.getCode() == JsGlobalScopeContainerInitializer.ATTRIBUTE_READ_ONLY) {
  //					createLabel(composite, Messages.format(JavaEditorMessages.ClassFileEditor_SourceAttachmentForm_readonly, containerName));  
  //					return;
  //				}
  //				entry= JavaModelUtil.findEntryInContainer(container, root.getPath());
  //				Assert.isNotNull(entry);
  //			}
  //
  //
  //			Button button;
  //
  //			IPath path= entry.getSourceAttachmentPath();
  //			if (path == null || path.isEmpty()) {
  //				createLabel(composite, Messages.format(JavaEditorMessages.SourceAttachmentForm_message_noSourceAttachment, root.getElementName()));
  //				createLabel(composite, JavaEditorMessages.SourceAttachmentForm_message_pressButtonToAttach);
  //				createLabel(composite, null);
  //
  //				button= createButton(composite, JavaEditorMessages.SourceAttachmentForm_button_attachSource);
  //
  //			} else {
  //				createLabel(composite, Messages.format(JavaEditorMessages.SourceAttachmentForm_message_noSourceInAttachment, fFile.getDisplayName()));
  //				createLabel(composite, JavaEditorMessages.SourceAttachmentForm_message_pressButtonToChange);
  //				createLabel(composite, null);
  //
  //				button= createButton(composite, JavaEditorMessages.SourceAttachmentForm_button_changeAttachedSource);
  //			}
  //
  //			button.addSelectionListener(getButtonListener(entry, containerPath, jproject));
  //		}
  //
  //		private SelectionListener getButtonListener(final IIncludePathEntry entry, final IPath containerPath, final IJavaScriptProject jproject) {
  //			return new SelectionListener() {
  //				public void widgetSelected(SelectionEvent event) {
  //					Shell shell= getSite().getShell();
  //					try {
  //						IIncludePathEntry result= BuildPathDialogAccess.configureSourceAttachment(shell, entry);
  //						if (result != null) {
  //							applySourceAttachment(shell, result, jproject, containerPath);
  //							verifyInput(getEditorInput());
  //						}
  //					} catch (CoreException e) {
  //						String title= JavaEditorMessages.SourceAttachmentForm_error_title;
  //						String message= JavaEditorMessages.SourceAttachmentForm_error_message;
  //						ExceptionHandler.handle(e, shell, title, message);
  //					}
  //				}
  //
  //				public void widgetDefaultSelected(SelectionEvent e) {}
  //			};
  //		}
  
  		protected void applySourceAttachment(Shell shell, IIncludePathEntry newEntry, IJavaScriptProject project, IPath containerPath) {
  			try {
  				IRunnableWithProgress runnable= SourceAttachmentBlock.getRunnable(shell, newEntry, project, containerPath);
  				PlatformUI.getWorkbench().getProgressService().run(true, true, runnable);
  
  			} catch (InvocationTargetException e) {
  				String title= JavaEditorMessages.SourceAttachmentForm_attach_error_title;
  				String message= JavaEditorMessages.SourceAttachmentForm_attach_error_message;
  				ExceptionHandler.handle(e, shell, title, message);
  
  			} catch (InterruptedException e) {
  				// cancelled
  			}
  		}
  
  		/*
  		 * @see IPropertyChangeListener#propertyChange(PropertyChangeEvent)
  		 */
  		public void propertyChange(PropertyChangeEvent event) {
  
  			for (Iterator iterator = fBannerLabels.iterator(); iterator.hasNext();) {
  				Label label = (Label) iterator.next();
  				label.setFont(JFaceResources.getBannerFont());
  			}
  
  			for (Iterator iterator = fHeaderLabels.iterator(); iterator.hasNext();) {
  				Label label = (Label) iterator.next();
  				label.setFont(JFaceResources.getHeaderFont());
  			}
  
  			fComposite.layout(true);
  			fComposite.redraw();
  		}
  
  		// --- copied from org.eclipse.update.ui.forms.internal.FormWidgetFactory
  
  		private Composite createComposite(Composite parent) {
  			Composite composite = new Composite(parent, SWT.NONE);
  			composite.setBackground(fBackgroundColor);
  			//		composite.addMouseListener(new MouseAdapter() {
  			//			public void mousePressed(MouseEvent e) {
  			//				((Control) e.widget).setFocus();
  			//			}
  			//		});
  			return composite;
  		}
  
  		private Composite createCompositeSeparator(Composite parent) {
  			Composite composite = new Composite(parent, SWT.NONE);
  			composite.setBackground(fSeparatorColor);
  			return composite;
  		}
  
  		private StyledText createCodeView(Composite parent) {
  			int styles= SWT.V_SCROLL | SWT.H_SCROLL | SWT.MULTI | SWT.FULL_SELECTION;
  			StyledText styledText= new StyledText(parent, styles);
  			styledText.setBackground(fBackgroundColor);
  			styledText.setForeground(fForegroundColor);
  			styledText.setEditable(false);
  			return styledText;
  		}
  
  		private Label createLabel(Composite parent, String text) {
  			Label label= new Label(parent, SWT.WRAP);
  			if (text != null)
  				label.setText(text);
  			label.setBackground(fBackgroundColor);
  			label.setForeground(fForegroundColor);
  			GridData gd= new GridData();
  			gd.widthHint= new PixelConverter(label).convertWidthInCharsToPixels(80);
  			label.setLayoutData(gd);
  			return label;
  		}
  
  		private Label createTitleLabel(Composite parent, String text) {
  			Label label = new Label(parent, SWT.NONE);
  			if (text != null)
  				label.setText(text);
  			label.setBackground(fBackgroundColor);
  			label.setForeground(fForegroundColor);
  			label.setFont(JFaceResources.getHeaderFont());
  			fHeaderLabels.add(label);
  			return label;
  		}
  
  		private Label createHeadingLabel(Composite parent, String text) {
  			Label label = new Label(parent, SWT.NONE);
  			if (text != null)
  				label.setText(text);
  			label.setBackground(fBackgroundColor);
  			label.setForeground(fForegroundColor);
  			label.setFont(JFaceResources.getBannerFont());
  			fBannerLabels.add(label);
  			return label;
  		}
  
  		private Button createButton(Composite parent, String text) {
  			Button button = new Button(parent, SWT.FLAT);
  			button.setBackground(fBackgroundColor);
  			button.setForeground(fForegroundColor);
  			if (text != null)
  				button.setText(text);
  			return button;
  		}
  
  //		private void updateCodeView(StyledText styledText, IClassFile classFile) {
  //			String content= null;
  //			ClassFileBytesDisassembler disassembler= ToolFactory.createDefaultClassFileBytesDisassembler();
  //			try {
  //				content= disassembler.disassemble(classFile.getBytes(), "\n", ClassFileBytesDisassembler.DETAILED); //$NON-NLS-1$
  //			} catch (JavaScriptModelException ex) {
  //				JavaScriptPlugin.log(ex.getStatus());
  //			} catch (ClassFormatException ex) {
  //				JavaScriptPlugin.log(ex);
  //			}
  //			styledText.setText(content == null ? "" : content); //$NON-NLS-1$
  //		}
  	}
  
  	/**
  	 *  Updater that takes care of minimizing changes of the editor input.
  	 */
  	private class InputUpdater implements Runnable {
  
  		/** Has the runnable already been posted? */
  		private boolean fPosted= false;
  		/** Editor input */
  		private IClassFileEditorInput fClassFileEditorInput;
  
  
  		public InputUpdater() {
  		}
  
  		/*
  		 * @see Runnable#run()
  		 */
  		public void run() {
  
  			IClassFileEditorInput input;
  			synchronized (this) {
  				input= fClassFileEditorInput;
  			}
  
  			try {
  
  				if (getSourceViewer() != null)
  					setInput(input);
  
  			} finally {
  				synchronized (this) {
  					fPosted= false;
  				}
  			}
  		}
  
  		/**
  		 * Posts this runnable into the event queue if not already there.
  		 *
  		 * @param input the input to be set when executed
  		 */
  		public void post(IClassFileEditorInput input) {
  
  			synchronized(this) {
  				if (fPosted) {
  					if (input != null && input.equals(fClassFileEditorInput))
  						fClassFileEditorInput= input;
  					return;
  				}
  			}
  
  			if (input != null && input.equals(getEditorInput())) {
  				ISourceViewer viewer= getSourceViewer();
  				if (viewer != null) {
  					StyledText textWidget= viewer.getTextWidget();
  					if (textWidget != null && !textWidget.isDisposed()) {
  						synchronized (this) {
  							fPosted= true;
  							fClassFileEditorInput= input;
  						}
  						textWidget.getDisplay().asyncExec(this);
  					}
  				}
  			}
  		}
  	}
  
  
  	private StackLayout fStackLayout;
  	private Composite fParent;
  
  	private Composite fViewerComposite;
  	private Control fSourceAttachmentForm;
  
  	private CompositeActionGroup fContextMenuGroup;
  
  	private InputUpdater fInputUpdater= new InputUpdater();
  	
  	/**
  	 * The copy action used when there's attached source.
  	 * 
  	 */
  	private IAction fSourceCopyAction;
  	/**
  	 * The Select All action used when there's attached source.
  	 * 
  	 */
  	private IAction fSelectAllAction;
  
  	/**
  	 * StyledText widget used to show the disassembled code.
  	 * if there's no source.
  	 * 
  	 * 
  	 */
  	private StyledText fNoSourceTextWidget;
  
  	
  	/**
  	 * Default constructor.
  	 */
  	public ClassFileEditor() {
  		super();
  		setDocumentProvider(JavaScriptPlugin.getDefault().getClassFileDocumentProvider());
  		setEditorContextMenuId("#ClassFileEditorContext"); //$NON-NLS-1$
  		setRulerContextMenuId("#ReadOnlyJavaScriptRulerContext"); //$NON-NLS-1$
  		setOutlinerContextMenuId("#ClassFileOutlinerContext"); //$NON-NLS-1$
  		// don't set help contextId, we install our own help context
  	}
  
  	/*
  	 * @see AbstractTextEditor#createActions()
  	 */
  	protected void createActions() {
  		super.createActions();
  
  		setAction(ITextEditorActionConstants.SAVE, null);
  		setAction(ITextEditorActionConstants.REVERT_TO_SAVED, null);
  
  		fSourceCopyAction= getAction(ITextEditorActionConstants.COPY);
  		fSelectAllAction= getAction(ITextEditorActionConstants.SELECT_ALL);
  
  		final ActionGroup group= new RefactorActionGroup(this, ITextEditorActionConstants.GROUP_EDIT, true);
  		fActionGroups.addGroup(group);
  		fContextMenuGroup= new CompositeActionGroup(new ActionGroup[] {group});
  
  		/*
  		 * 1GF82PL: ITPJUI:ALL - Need to be able to add bookmark to class file
  		 *
  		 *  // replace default action with class file specific ones
  		 *
  		 *	setAction(ITextEditorActionConstants.BOOKMARK, new AddClassFileMarkerAction("AddBookmark.", this, IMarker.BOOKMARK, true)); //$NON-NLS-1$
  		 *	setAction(ITextEditorActionConstants.ADD_TASK, new AddClassFileMarkerAction("AddTask.", this, IMarker.TASK, false)); //$NON-NLS-1$
  		 *	setAction(ITextEditorActionConstants.RULER_MANAGE_BOOKMARKS, new ClassFileMarkerRulerAction("ManageBookmarks.", getVerticalRuler(), this, IMarker.BOOKMARK, true)); //$NON-NLS-1$
  		 *	setAction(ITextEditorActionConstants.RULER_MANAGE_TASKS, new ClassFileMarkerRulerAction("ManageTasks.", getVerticalRuler(), this, IMarker.TASK, true)); //$NON-NLS-1$
  		 */
  	}
  
  	/*
  	 * @see AbstractTextEditor#editorContextMenuAboutToShow(IMenuManager)
  	 */
  	public void editorContextMenuAboutToShow(IMenuManager menu) {
  		super.editorContextMenuAboutToShow(menu);
  
  		ActionContext context= new ActionContext(getSelectionProvider().getSelection());
  		fContextMenuGroup.setContext(context);
  		fContextMenuGroup.fillContextMenu(menu);
  		fContextMenuGroup.setContext(null);
  	}
  
  	/*
  	 * @see JavaEditor#getElementAt(int)
  	 */
  	protected IJavaScriptElement getElementAt(int offset) {
  		if (getEditorInput() instanceof IClassFileEditorInput) {
  			try {
  				IClassFileEditorInput input= (IClassFileEditorInput) getEditorInput();
  				return input.getClassFile().getElementAt(offset);
  			} catch (JavaScriptModelException x) {
  			}
  		}
  		return null;
  	}
  
  	/*
  	 * @see JavaEditor#getCorrespondingElement(IJavaScriptElement)
  	 */
  	protected IJavaScriptElement getCorrespondingElement(IJavaScriptElement element) {
  		if (getEditorInput() instanceof IClassFileEditorInput) {
  			IClassFileEditorInput input= (IClassFileEditorInput) getEditorInput();
  			IJavaScriptElement parent= element.getAncestor(IJavaScriptElement.CLASS_FILE);
  			if (input.getClassFile().equals(parent))
  				return element;
  		}
  		return null;
  	}
  
  	/*
  	 * 1GEPKT5: ITPJUI:Linux - Source in editor for external classes is editable
  	 * Removed methods isSaveOnClosedNeeded and isDirty.
  	 * Added method isEditable.
  	 */
  	/*
  	 * @see org.eclipse.ui.texteditor.AbstractTextEditor#isEditable()
  	 */
  	public boolean isEditable() {
  		return false;
  	}
  
  	/*
  	 * @see org.eclipse.ui.texteditor.AbstractTextEditor#isEditorInputReadOnly()
  	 * 
  	 */
  	public boolean isEditorInputReadOnly() {
  		return true;
  	}
  
  	/**
  	 * Translates the given editor input into an <code>ExternalClassFileEditorInput</code>
  	 * if it is a file editor input representing an external class file.
  	 *
  	 * @param input the editor input to be transformed if necessary
  	 * @return the transformed editor input
  	 */
  	protected IEditorInput transformEditorInput(IEditorInput input) {
  
  		if (input instanceof IFileEditorInput) {
  			IFile file= ((IFileEditorInput) input).getFile();
  			IClassFileEditorInput classFileInput= new ExternalClassFileEditorInput(file);
  			if (classFileInput.getClassFile() != null)
  				input= classFileInput;
  		}
  
  		return input;
  	}
  
  	/*
  	 * @see AbstractTextEditor#doSetInput(IEditorInput)
  	 */
  	protected void doSetInput(IEditorInput input) throws CoreException {
  		uninstallOccurrencesFinder();
  
  		input= transformEditorInput(input);
  		if (!(input instanceof IClassFileEditorInput))
  			throw new CoreException(JavaUIStatus.createError(
  					IJavaScriptModelStatusConstants.INVALID_RESOURCE_TYPE,
  					JavaEditorMessages.ClassFileEditor_error_invalid_input_message,
  					null)); 
  
  		JavaScriptModelException e= probeInputForSource(input);
  		if (e != null) {
  			IClassFileEditorInput classFileEditorInput= (IClassFileEditorInput) input;
  			IClassFile file= classFileEditorInput.getClassFile();
  			IJavaScriptProject javaProject= file.getJavaScriptProject();
  			if (!javaProject.exists() || !javaProject.isOnIncludepath(file)) {
  				throw new CoreException(JavaUIStatus.createError(
  						IJavaScriptModelStatusConstants.INVALID_RESOURCE,
  						JavaEditorMessages.ClassFileEditor_error_classfile_not_on_classpath,
  						null)); 
  			} else {
  				throw e;
  			}
  		}
  
  		IDocumentProvider documentProvider= getDocumentProvider();
  		if (documentProvider instanceof ClassFileDocumentProvider)
  			((ClassFileDocumentProvider) documentProvider).removeInputChangeListener(this);
  
  		super.doSetInput(input);
  
  		documentProvider= getDocumentProvider();
  		if (documentProvider instanceof ClassFileDocumentProvider)
  			((ClassFileDocumentProvider) documentProvider).addInputChangeListener(this);
  
  		verifyInput(getEditorInput());
  		
  		final IJavaScriptElement inputElement= getInputJavaElement();
  
  		Job job= new Job(JavaEditorMessages.OverrideIndicatorManager_intallJob) {
  			/*
  			 * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor)
  			 * 
  			 */
  			protected IStatus run(IProgressMonitor monitor) {
  				JavaScriptUnit ast= JavaScriptPlugin.getDefault().getASTProvider().getAST(inputElement, ASTProvider.WAIT_YES, null);
  				if (fOverrideIndicatorManager != null)
  					fOverrideIndicatorManager.reconciled(ast, true, monitor);
  				if (fSemanticManager != null) {
  					SemanticHighlightingReconciler reconciler= fSemanticManager.getReconciler();
  					if (reconciler != null)
  						reconciler.reconciled(ast, false, monitor);
  				}
  				if (isMarkingOccurrences())
  					installOccurrencesFinder(false);
  				return Status.OK_STATUS;
  			}
  		};
  		job.setPriority(Job.DECORATE);
  		job.setSystem(true);
  		job.schedule();
  		
  	}
  
  	/*
  	 * @see IWorkbenchPart#createPartControl(Composite)
  	 */
  	public void createPartControl(Composite parent) {
  
  		fParent= new Composite(parent, SWT.NONE);
  		fStackLayout= new StackLayout();
  		fParent.setLayout(fStackLayout);
  
  		fViewerComposite= new Composite(fParent, SWT.NONE);
  		fViewerComposite.setLayout(new FillLayout());
  
  		super.createPartControl(fViewerComposite);
  
  		fStackLayout.topControl= fViewerComposite;
  		fParent.layout();
  
  		try {
  			verifyInput(getEditorInput());
  		} catch (CoreException e) {
  			String title= JavaEditorMessages.ClassFileEditor_error_title;
  			String message= JavaEditorMessages.ClassFileEditor_error_message;
  			ExceptionHandler.handle(e, fParent.getShell(), title, message);
  		}
  	}
  
  	private JavaScriptModelException probeInputForSource(IEditorInput input) {
  		if (input == null)
  			return null;
  
  		IClassFileEditorInput classFileEditorInput= (IClassFileEditorInput) input;
  		IClassFile file= classFileEditorInput.getClassFile();
  
  		try {
  			file.getSourceRange();
  		} catch (JavaScriptModelException e) {
  			return e;
  		}
  
  		return null;
  	}
  
  	/**
  	 * Checks if the class file input has no source attached. If so, a source attachment form is shown.
  	 * 
  	 * @param input the editor input 
  	 * @throws JavaScriptModelException if an exception occurs while accessing its corresponding resource 
  	 */
  	private void verifyInput(IEditorInput input) throws JavaScriptModelException {
  
  		if (fParent == null || input == null)
  			return;
  
  		IClassFileEditorInput classFileEditorInput= (IClassFileEditorInput) input;
  		IClassFile file= classFileEditorInput.getClassFile();
  		
  		IAction copyQualifiedName= getAction(IJavaEditorActionConstants.COPY_QUALIFIED_NAME);
  		
  		boolean wasUsingSourceCopyAction= fSourceCopyAction == getAction(ITextEditorActionConstants.COPY);
  
  		// show source attachment form if no source found
  		if (file.getSourceRange() == null) {
  
  			// dispose old source attachment form
  			if (fSourceAttachmentForm != null)
  				fSourceAttachmentForm.dispose();
  
  			SourceAttachmentForm form= new SourceAttachmentForm(file);
  			fSourceAttachmentForm= form.createControl(fParent);
  
  			fStackLayout.topControl= fSourceAttachmentForm;
  			fParent.layout();
  
  			if (fNoSourceTextWidget != null) {
  				// Copy action for the no attached source case
  				final IAction copyAction= new Action() {
  					public void run() {
  						fNoSourceTextWidget.copy();
  					}
  				};
  				copyAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.COPY);
  				setAction(ITextEditorActionConstants.COPY, copyAction);
  				copyAction.setEnabled(fNoSourceTextWidget.getSelectionText().length() > 0);
  				fNoSourceTextWidget.addSelectionListener(new SelectionListener() {
  					public void widgetSelected(SelectionEvent e) {
  						copyAction.setEnabled(fNoSourceTextWidget.getSelectionText().length() > 0);
  					}
  					public void widgetDefaultSelected(SelectionEvent e) {
  					}
  				});
  				
  				// Select All action for the no attached source case
  				final IAction selectAllAction= new Action() {
  					public void run() {
  						fNoSourceTextWidget.selectAll();
  						copyAction.setEnabled(true);
  					}
  				};
  				selectAllAction.setActionDefinitionId(IWorkbenchActionDefinitionIds.SELECT_ALL);
  				setAction(ITextEditorActionConstants.SELECT_ALL, selectAllAction);
  				copyAction.setEnabled(fNoSourceTextWidget.getSelectionText().length() > 0);
  				copyQualifiedName.setEnabled(false);
  				
  				
  			}
  
  		} else { // show source viewer
  
  			if (fSourceAttachmentForm != null) {
  				fSourceAttachmentForm.dispose();
  				fSourceAttachmentForm= null;
  
  				fStackLayout.topControl= fViewerComposite;
  				fParent.layout();
  			}
  
  			setAction(ITextEditorActionConstants.COPY, fSourceCopyAction);
  			setAction(ITextEditorActionConstants.SELECT_ALL, fSelectAllAction);
  			copyQualifiedName.setEnabled(true);
  
  		}
  		
  		IAction currentCopyAction= getAction(ITextEditorActionConstants.COPY);
  		boolean isUsingSourceCopyAction=  fSourceCopyAction == currentCopyAction;
  		if (wasUsingSourceCopyAction != isUsingSourceCopyAction) {
  			IActionBars actionBars= getEditorSite().getActionBars();
  			
  			if (isUsingSourceCopyAction) {
  				createNavigationActions();
  			} else {
  				for (int i= 0; i < ACTION_MAP.length; i++) {
  					IdMapEntry entry= ACTION_MAP[i];
  					actionBars.setGlobalActionHandler(entry.getActionId(), null);
  					setAction(entry.getActionId(), null);
  				}
  			}
  			
  			actionBars.setGlobalActionHandler(ITextEditorActionConstants.COPY, currentCopyAction);
  			actionBars.setGlobalActionHandler(ITextEditorActionConstants.SELECT_ALL, getAction(ITextEditorActionConstants.SELECT_ALL));
  			actionBars.updateActionBars();
  		}
  		
  	}
  
  	/*
  	 * @see ClassFileDocumentProvider.InputChangeListener#inputChanged(IClassFileEditorInput)
  	 */
  	public void inputChanged(IClassFileEditorInput input) {
  		fInputUpdater.post(input);
  	}
  
  	/*
  	 * @see JavaEditor#createJavaSourceViewer(Composite, IVerticalRuler, int)
  	 */
  	protected ISourceViewer createJavaSourceViewer(Composite parent, IVerticalRuler ruler, int styles, IPreferenceStore store) {
  		return new JavaSourceViewer(parent, ruler, null, false, styles, store) {
  
  			public boolean requestWidgetToken(IWidgetTokenKeeper requester) {
  				if (PlatformUI.getWorkbench().getHelpSystem().isContextHelpDisplayed())
  					return false;
  				return super.requestWidgetToken(requester);
  			}
  
  			public boolean requestWidgetToken(IWidgetTokenKeeper requester, int priority) {
  				if (PlatformUI.getWorkbench().getHelpSystem().isContextHelpDisplayed())
  					return false;
  				return super.requestWidgetToken(requester, priority);
  			}
  		};
  	}
  
  	/*
  	 * @see org.eclipse.ui.IWorkbenchPart#dispose()
  	 */
  	public void dispose() {
  		// http://bugs.eclipse.org/bugs/show_bug.cgi?id=18510
  		IDocumentProvider documentProvider= getDocumentProvider();
  		if (documentProvider instanceof ClassFileDocumentProvider)
  			((ClassFileDocumentProvider) documentProvider).removeInputChangeListener(this);
  		super.dispose();
  	}
  
  	/*
  	 * @see org.eclipse.ui.IWorkbenchPart#setFocus()
  	 */
  	public void setFocus() {
  		super.setFocus();
  
  		if (fSourceAttachmentForm != null && !fSourceAttachmentForm.isDisposed())
  			fSourceAttachmentForm.setFocus();
  	}
  
  }
  