KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > de > loskutov > bco > editors > BytecodeClassFileEditor


1 /* $Id: BytecodeClassFileEditor.java,v 1.6 2006/11/24 10:14:51 andrei Exp $ */
2
3 package de.loskutov.bco.editors;
4
5 import java.lang.reflect.Constructor JavaDoc;
6 import java.util.BitSet JavaDoc;
7
8 import org.eclipse.core.resources.IFile;
9 import org.eclipse.core.runtime.CoreException;
10 import org.eclipse.core.runtime.IStatus;
11 import org.eclipse.debug.core.DebugException;
12 import org.eclipse.debug.ui.actions.IToggleBreakpointsTarget;
13 import org.eclipse.jdt.core.IBuffer;
14 import org.eclipse.jdt.core.IBufferChangedListener;
15 import org.eclipse.jdt.core.IClassFile;
16 import org.eclipse.jdt.core.IInitializer;
17 import org.eclipse.jdt.core.IJavaElement;
18 import org.eclipse.jdt.core.IJavaModelStatusConstants;
19 import org.eclipse.jdt.core.IMember;
20 import org.eclipse.jdt.core.IMethod;
21 import org.eclipse.jdt.core.ISourceRange;
22 import org.eclipse.jdt.core.ISourceReference;
23 import org.eclipse.jdt.core.IType;
24 import org.eclipse.jdt.core.JavaModelException;
25 import org.eclipse.jdt.core.dom.CompilationUnit;
26 import org.eclipse.jdt.debug.core.IJavaReferenceType;
27 import org.eclipse.jdt.internal.ui.JavaPlugin;
28 import org.eclipse.jdt.internal.ui.JavaUIStatus;
29 import org.eclipse.jdt.internal.ui.javaeditor.ClassFileDocumentProvider;
30 import org.eclipse.jdt.internal.ui.javaeditor.ExternalClassFileEditorInput;
31 import org.eclipse.jdt.internal.ui.javaeditor.IClassFileEditorInput;
32 import org.eclipse.jdt.internal.ui.javaeditor.InternalClassFileEditorInput;
33 import org.eclipse.jdt.internal.ui.javaeditor.JavaEditor;
34 import org.eclipse.jface.preference.IPreferenceStore;
35 import org.eclipse.jface.text.BadLocationException;
36 import org.eclipse.jface.text.IDocument;
37 import org.eclipse.jface.text.IRegion;
38 import org.eclipse.jface.text.ITextSelection;
39 import org.eclipse.jface.text.ITextViewerExtension5;
40 import org.eclipse.jface.text.Region;
41 import org.eclipse.jface.text.TextSelection;
42 import org.eclipse.jface.text.source.IOverviewRuler;
43 import org.eclipse.jface.text.source.ISourceViewer;
44 import org.eclipse.jface.text.source.IVerticalRuler;
45 import org.eclipse.jface.viewers.ISelection;
46 import org.eclipse.jface.viewers.ISelectionProvider;
47 import org.eclipse.jface.viewers.SelectionChangedEvent;
48 import org.eclipse.swt.SWT;
49 import org.eclipse.swt.custom.StackLayout;
50 import org.eclipse.swt.custom.StyledText;
51 import org.eclipse.swt.layout.FillLayout;
52 import org.eclipse.swt.widgets.Composite;
53 import org.eclipse.ui.IEditorInput;
54 import org.eclipse.ui.IEditorPart;
55 import org.eclipse.ui.IEditorReference;
56 import org.eclipse.ui.IEditorSite;
57 import org.eclipse.ui.IFileEditorInput;
58 import org.eclipse.ui.PartInitException;
59 import org.eclipse.ui.PlatformUI;
60 import org.eclipse.ui.part.FileEditorInput;
61 import org.eclipse.ui.texteditor.IDocumentProvider;
62
63 import de.loskutov.bco.BytecodeOutlinePlugin;
64 import de.loskutov.bco.preferences.BCOConstants;
65 import de.loskutov.bco.ui.JdtUtils;
66
67 /**
68  * A "better" way to hook into JDT...
69  * @author Eugene Kuleshov, V. Grishchenko, Jochen Klein, Andrei Loskutov
70  */

71 public class BytecodeClassFileEditor extends JavaEditor
72     implements
73         ClassFileDocumentProvider.InputChangeListener {
74
75     private StackLayout fStackLayout;
76     private Composite fParent;
77     private Composite fViewerComposite;
78     private InputUpdater fInputUpdater;
79     public static final String JavaDoc ID = "de.loskutov.bco.editors.BytecodeClassFileEditor";
80     public static final String JavaDoc MARK = "// class version ";
81     /** the modes (flags) for the decompiler */
82     private BitSet JavaDoc decompilerFlags;
83     /** is not null only on class files with decompiled source */
84     private static BytecodeSourceMapper sourceMapper;
85     private static BytecodeDocumentProvider fClassFileDocumentProvider;
86     private boolean hasMappedSource;
87     private boolean decompiled;
88     private boolean initDone;
89
90     /**
91      * Constructor for JadclipseClassFileEditor.
92      */

93     public BytecodeClassFileEditor() {
94         super();
95         if (sourceMapper == null) {
96             sourceMapper = new BytecodeSourceMapper();
97         }
98         fInputUpdater = new InputUpdater();
99         setDocumentProvider(getClassFileDocumentProvider());
100         setEditorContextMenuId("#ClassFileEditorContext"); //$NON-NLS-1$
101
setRulerContextMenuId("#ClassFileRulerContext"); //$NON-NLS-1$
102
setOutlinerContextMenuId("#ClassFileOutlinerContext"); //$NON-NLS-1$
103
// don't set help contextId, we install our own help context
104

105         decompilerFlags = new BitSet JavaDoc();
106         // TODO take from preferences and/or last editor memento
107
decompilerFlags.set(BCOConstants.F_SHOW_LINE_INFO, true);
108         decompilerFlags.set(BCOConstants.F_SHOW_VARIABLES, true);
109         decompilerFlags.set(BCOConstants.F_SHOW_RAW_BYTECODE, false);
110     }
111
112     /**
113      * @return the hasMappedSource
114      */

115     protected boolean hasMappedSource() {
116         return hasMappedSource;
117     }
118
119     /**
120      * @param hasMappedSource the hasMappedSource to set
121      */

122     protected void setHasMappedSource(boolean hasMappedSource) {
123         this.hasMappedSource = hasMappedSource;
124     }
125
126     private static ClassFileDocumentProvider getClassFileDocumentProvider() {
127         if (fClassFileDocumentProvider == null) {
128             fClassFileDocumentProvider = new BytecodeDocumentProvider();
129         }
130         return fClassFileDocumentProvider;
131     }
132
133     public void setDecompilerFlag(int flag, boolean value) {
134         decompilerFlags.set(flag, value);
135     }
136
137     public boolean getDecompilerFlag(int flag) {
138         return decompilerFlags.get(flag);
139     }
140
141     /*
142      * @see IEditorPart#init(IEditorSite, IEditorInput)
143      */

144     public void init(IEditorSite site, IEditorInput input)
145         throws PartInitException {
146         input = doOpenBuffer(input, false, true);
147         super.init(site, input);
148     }
149
150     /**
151      * Sets editor input only if buffer was actually opened.
152      * @param force if <code>true</code> initialize no matter what
153      * @param reuseSource true to show source code if available
154      */

155     public void doSetInput(boolean force, boolean reuseSource) {
156         IEditorInput input = getEditorInput();
157         input = doOpenBuffer(input, force, reuseSource);
158         if (input != null) {
159             try {
160                 doSetInput(input);
161             } catch (Exception JavaDoc e) {
162                 BytecodeOutlinePlugin.log(e, IStatus.ERROR);
163             }
164         }
165     }
166
167     /*
168      * @see AbstractTextEditor#doSetInput(IEditorInput)
169      * ClassFileDocumentProvider.setDocumentContent(IDocument, IEditorInput, String) line:
170      * 202 ClassFileDocumentProvider(StorageDocumentProvider).createDocument(Object) line:
171      * 228 ClassFileDocumentProvider.createDocument(Object) line: 247
172      * ClassFileDocumentProvider.createElementInfo(Object) line: 275
173      * ClassFileDocumentProvider(AbstractDocumentProvider).connect(Object) line: 398
174      * BytecodeClassFileEditor(AbstractTextEditor).doSetInput(IEditorInput) line: 3063
175      * BytecodeClassFileEditor(StatusTextEditor).doSetInput(IEditorInput) line: 173
176      * BytecodeClassFileEditor(AbstractDecoratedTextEditor).doSetInput(IEditorInput) line:
177      * 1511 BytecodeClassFileEditor(JavaEditor).internalDoSetInput(IEditorInput) line:
178      * 2370 BytecodeClassFileEditor(JavaEditor).doSetInput(IEditorInput) line: 2343
179      * BytecodeClassFileEditor.doSetInput(IEditorInput) line: 201
180      * AbstractTextEditor$17.run(IProgressMonitor) line: 2396
181      */

182     protected void doSetInput(IEditorInput input) throws CoreException {
183
184         input = transformEditorInput(input);
185         if (!(input instanceof IClassFileEditorInput))
186             throw new CoreException(JavaUIStatus.createError(
187                 IJavaModelStatusConstants.INVALID_RESOURCE_TYPE,
188                 "invalid input", // JavaEditorMessages.ClassFileEditor_error_invalid_input_message,
189
null));
190
191         IDocumentProvider documentProvider = getDocumentProvider();
192         if (documentProvider instanceof ClassFileDocumentProvider) {
193             ((ClassFileDocumentProvider) documentProvider)
194                 .removeInputChangeListener(this);
195         }
196
197         super.doSetInput(input);
198
199         documentProvider = getDocumentProvider();
200         if (documentProvider instanceof ClassFileDocumentProvider) {
201             ((ClassFileDocumentProvider) documentProvider)
202                 .addInputChangeListener(this);
203         }
204     }
205
206     /**
207      * @return <code>true</code> if this editor displays decompiled source,
208      * <code>false</code> otherwise
209      */

210     public boolean isDecompiled() {
211         return decompiled;
212     }
213
214     private IEditorInput doOpenBuffer(IJavaReferenceType type,
215         IClassFile parent, boolean externalClass) {
216         IClassFile classFile = null;
217         try {
218             classFile = JdtUtils.getInnerType(parent, getSourceMapper()
219                 .getDecompiledClass(parent), type.getSignature());
220         } catch (DebugException e) {
221             BytecodeOutlinePlugin.log(e, IStatus.ERROR);
222         }
223         return doOpenBuffer(classFile, externalClass);
224     }
225
226     private IEditorInput doOpenBuffer(IClassFile classFile, boolean externalClass) {
227         IEditorInput input = null;
228         if (classFile == null) {
229             return null;
230         }
231         if (externalClass) {
232             // TODO create external input, but we need a file object here...
233
} else {
234             input = transformEditorInput(classFile);
235         }
236         return doOpenBuffer(input, false, true);
237     }
238
239     private IEditorInput doOpenBuffer(IEditorInput input, boolean force,
240         boolean reuseSource) {
241         if (input instanceof IClassFileEditorInput) {
242             IClassFile cf = ((IClassFileEditorInput) input).getClassFile();
243             String JavaDoc origSrc = getAttachedJavaSource(cf, force);
244             if (origSrc != null && !hasMappedSource) {
245                 // remember, that the JDT knows where the real source is and can show it
246
setHasMappedSource(true);
247             }
248
249             if (origSrc == null || (force && !reuseSource)) {
250                 setDecompiled(true);
251                 char[] src;
252                 if (input instanceof ExternalClassFileEditorInput) {
253                     ExternalClassFileEditorInput extInput = (ExternalClassFileEditorInput) input;
254                     src = getSourceMapper().getSource(
255                         extInput.getFile(), cf, decompilerFlags);
256                 } else {
257                     src = getSourceMapper().getSource(cf, decompilerFlags);
258                 }
259                 changeBufferContent(cf, src);
260             } else {
261                 setDecompiled(false);
262             }
263         } else if (input instanceof FileEditorInput) {
264             FileEditorInput fileEditorInput = (FileEditorInput) input;
265             // make class file from that
266
IClassFileEditorInput cfi = transformEditorInput(input);
267             // return changed reference
268
input = cfi;
269             setDecompiled(true);
270             IClassFile cf = cfi.getClassFile();
271             char[] src = getSourceMapper().getSource(
272                 fileEditorInput.getFile(), cf, decompilerFlags);
273             changeBufferContent(cf, src);
274         }
275         return input;
276     }
277
278     private void setDecompiled(boolean decompiled) {
279         boolean oldDecompiled = this.decompiled;
280         this.decompiled = decompiled;
281         if(initDone && oldDecompiled != decompiled) {
282             if(decompiled) {
283                 // prevent multiple errors in ASTProvider which fails to work without source
284
uninstallOccurrencesFinder();
285             } else {
286                 // install again if source is available
287
installOccurrencesFinder(true);
288             }
289         }
290     }
291
292     private String JavaDoc getAttachedJavaSource(IClassFile cf, boolean force) {
293         String JavaDoc origSrc = null;
294         if (force) {
295             IBuffer buffer = BytecodeBufferManager.getBuffer(cf);
296             if (buffer != null) {
297                 BytecodeBufferManager.removeBuffer(buffer);
298             }
299         }
300         try {
301             origSrc = cf.getSource();
302             if (origSrc != null && origSrc.startsWith(MARK)) {
303                 // this is NOT orig. sourse, but cached content
304
origSrc = null;
305             }
306         } catch (JavaModelException e) {
307             BytecodeOutlinePlugin.log(e, IStatus.ERROR);
308         }
309         return origSrc;
310     }
311
312     private void changeBufferContent(IClassFile cf, char[] src) {
313         IBuffer buffer = BytecodeBufferManager.getBuffer(cf);
314
315         // i'm not sure if we need to create buffer each time -
316
// couldn't we reuse existing one (if any)?
317
// - seems that without "create" some listener didn't get notifications about
318
// changed content
319
boolean addBuffer = false;
320
321         // if(buffer == null) {
322
buffer = BytecodeBufferManager.createBuffer(cf);
323         addBuffer = true;
324         // }
325
if (src == null) {
326             src = new char[]{'\n', '/', '/', 'E', 'r', 'r', 'o', 'r'};
327         }
328         buffer.setContents(src);
329         if (addBuffer) {
330             BytecodeBufferManager.addBuffer(buffer);
331             buffer.addBufferChangedListener((IBufferChangedListener) cf);
332         }
333     }
334
335     /*
336      * @see JavaEditor#getElementAt(int)
337      */

338     protected IJavaElement getElementAt(int offset) {
339
340         IClassFile classFile = getClassFile();
341         if (classFile == null) {
342             return null;
343         }
344         IJavaElement result = null;
345         if (isDecompiled()) {
346             IDocument document = getDocumentProvider().getDocument(
347                 getEditorInput());
348             try {
349                 int lineAtOffset = document.getLineOfOffset(offset);
350                 // get DecompiledMethod from line, then get JavaElement with same
351
// signature, because we do not have offsets or lines in the class file,
352
// only java elements...
353
result = getSourceMapper().findElement(classFile, lineAtOffset);
354             } catch (BadLocationException e) {
355                 BytecodeOutlinePlugin.log(e, IStatus.ERROR);
356             }
357         } else {
358             try {
359                 result = classFile.getElementAt(offset);
360             } catch (JavaModelException e) {
361                 BytecodeOutlinePlugin.log(e, IStatus.ERROR);
362             }
363         }
364
365         return result;
366     }
367
368     public IClassFile getClassFile() {
369         IEditorInput editorInput = getEditorInput();
370         if (!(editorInput instanceof IClassFileEditorInput)) {
371             return null;
372         }
373         return ((IClassFileEditorInput) editorInput).getClassFile();
374     }
375
376     protected void setSelection(ISourceReference reference, boolean moveCursor) {
377         if (reference == null) {
378             if (moveCursor) {
379                 resetHighlightRange();
380             }
381             return;
382         }
383         try {
384             ISourceRange range = null;
385             int offset;
386             int length;
387             if (isDecompiled() && isSupportedMember(reference)) {
388
389                 // document lines count starts with 1 and not with 0
390
int decompLine = -1
391                     + getSourceMapper().getDecompiledLine(
392                         (IMember) reference, getClassFile());
393                 if(decompLine < 0){
394                     return;
395                 }
396                 IRegion region = ((BytecodeDocumentProvider) getDocumentProvider())
397                     .getDecompiledLineInfo(getEditorInput(), decompLine);
398                 if (region == null) {
399                     return;
400                 }
401                 offset = region.getOffset();
402                 length = region.getLength();
403             } else if (!isDecompiled()) {
404                 range = reference.getSourceRange();
405                 if (range == null) {
406                     return;
407                 }
408                 offset = range.getOffset();
409                 length = range.getLength();
410             } else {
411                 return;
412             }
413
414             if (offset > -1 && length > 0) {
415                 setHighlightRange(offset, length, moveCursor);
416             }
417
418             if ((reference instanceof IMember) && !isDecompiled()) {
419                 IMember member = (IMember) reference;
420                 range = member.getNameRange();
421                 if (range != null) {
422                     offset = range.getOffset();
423                     length = range.getLength();
424                 }
425             }
426             if (moveCursor && offset > -1 && length > 0) {
427                 ISourceViewer sourceViewer = getSourceViewer();
428                 if (sourceViewer != null) {
429                     sourceViewer.revealRange(offset, length);
430                     sourceViewer.setSelectedRange(offset, length);
431                 }
432             }
433             return;
434         } catch (Exception JavaDoc e) {
435             BytecodeOutlinePlugin.log(e, IStatus.ERROR);
436         }
437
438         if (moveCursor) {
439             resetHighlightRange();
440         }
441     }
442
443     private boolean isSupportedMember(ISourceReference reference) {
444         // TODO this condition is not enough. We could have inner/anon. classes
445
// as selection source (they are displayed in the outline),
446
// but they are not in the decompiled class,
447
// so we need to filter "external" elements too, even if they are methods...
448

449         // we could also later point to the IField's, but currently it is not supported
450
return reference instanceof IMethod
451             || reference instanceof IInitializer;
452     }
453
454     public Object JavaDoc getAdapter(Class JavaDoc required) {
455         if (IToggleBreakpointsTarget.class == required) {
456
457             // TODO implement own adapter for toggle breakpoints, because the default one
458
// could not find java elements in our document and therefore could not
459
// create a Java breakpoint.
460
// see org.eclipse.jdt.internal.debug.ui.actions.ToggleBreakpointAdapter
461
// IMember member =
462
// ActionDelegateHelper.getDefault().getCurrentMember(selection);
463
// and the ActionDelegateHelper looks with the given offset at classfile or
464
// compilation unit, but our offset is completely different to Java source
465
// code
466
super.getAdapter(required);
467         }
468
469         return super.getAdapter(required);
470     }
471
472     /*
473      * Overriden to prevent NPE on SourceReference objects without associated source
474      * ranges, see https://bugs.eclipse.org/bugs/show_bug.cgi?id=142936
475      * @see JavaEditor#adjustHighlightRange(int, int)
476      */

477     protected void adjustHighlightRange(int offset, int length) {
478         try {
479
480             IJavaElement element = getElementAt(offset);
481             while (element instanceof ISourceReference) {
482                 ISourceRange range = ((ISourceReference) element)
483                     .getSourceRange();
484                 // range != null is the only one change we need here
485
if (range != null
486                     && (offset < range.getOffset() + range.getLength() && range
487                         .getOffset() < offset + length)) {
488
489                     ISourceViewer viewer = getSourceViewer();
490                     if (viewer instanceof ITextViewerExtension5) {
491                         ITextViewerExtension5 extension = (ITextViewerExtension5) viewer;
492                         extension.exposeModelRange(new Region(
493                             range.getOffset(), range.getLength()));
494                     }
495
496                     setHighlightRange(
497                         range.getOffset(), range.getLength(), true);
498                     if (fOutlinePage != null) {
499                         fOutlineSelectionChangedListener
500                             .uninstall(fOutlinePage);
501                         fOutlinePage.select((ISourceReference) element);
502                         fOutlineSelectionChangedListener.install(fOutlinePage);
503                     }
504
505                     return;
506                 }
507                 element = element.getParent();
508             }
509
510         } catch (JavaModelException x) {
511             JavaPlugin.log(x.getStatus());
512         }
513
514         ISourceViewer viewer = getSourceViewer();
515         if (viewer instanceof ITextViewerExtension5) {
516             ITextViewerExtension5 extension = (ITextViewerExtension5) viewer;
517             extension.exposeModelRange(new Region(offset, length));
518         } else {
519             resetHighlightRange();
520         }
521
522     }
523
524     /*
525      * (non-Javadoc)
526      * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor#computeHighlightRangeSourceReference()
527      */

528     protected ISourceReference computeHighlightRangeSourceReference() {
529         if (!isDecompiled()) {
530             return super.computeHighlightRangeSourceReference();
531         }
532
533         ISourceViewer sourceViewer = getSourceViewer();
534         if (sourceViewer == null) {
535             return null;
536         }
537         StyledText styledText = sourceViewer.getTextWidget();
538         if (styledText == null) {
539             return null;
540         }
541
542         int caret = 0;
543         if (sourceViewer instanceof ITextViewerExtension5) {
544             ITextViewerExtension5 extension = (ITextViewerExtension5) sourceViewer;
545             caret = extension.widgetOffset2ModelOffset(styledText
546                 .getCaretOffset());
547         } else {
548             int offset = sourceViewer.getVisibleRegion().getOffset();
549             caret = offset + styledText.getCaretOffset();
550         }
551
552         IJavaElement element = getElementAt(caret);
553
554         if (!(element instanceof ISourceReference)) {
555             return null;
556         }
557         return (ISourceReference) element;
558     }
559
560     /*
561      * (non-Javadoc)
562      * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor#createJavaSourceViewer(org.eclipse.swt.widgets.Composite,
563      * org.eclipse.jface.text.source.IVerticalRuler,
564      * org.eclipse.jface.text.source.IOverviewRuler, boolean, int,
565      * org.eclipse.jface.preference.IPreferenceStore)
566      */

567     protected ISourceViewer createJavaSourceViewer(Composite parent,
568         IVerticalRuler verticalRuler, IOverviewRuler overviewRuler,
569         boolean isOverviewRulerVisible, int styles, IPreferenceStore store) {
570
571         return super.createJavaSourceViewer(
572             parent, verticalRuler, overviewRuler, isOverviewRulerVisible,
573             styles, store);
574     }
575
576     /*
577      * (non-Javadoc)
578      * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor#doSelectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
579      */

580     protected void doSelectionChanged(SelectionChangedEvent event) {
581
582         super.doSelectionChanged(event);
583     }
584
585     /*
586      * (non-Javadoc)
587      * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor#doSetSelection(org.eclipse.jface.viewers.ISelection)
588      */

589     protected void doSetSelection(ISelection selection) {
590
591         super.doSetSelection(selection);
592     }
593
594     /*
595      * (non-Javadoc)
596      * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor#getSignedSelection(org.eclipse.jface.text.source.ISourceViewer)
597      */

598     protected IRegion getSignedSelection(ISourceViewer sourceViewer) {
599
600         return super.getSignedSelection(sourceViewer);
601     }
602
603     /*
604      * (non-Javadoc)
605      * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor#synchronizeOutlinePage(org.eclipse.jdt.core.ISourceReference,
606      * boolean)
607      */

608     protected void synchronizeOutlinePage(ISourceReference element,
609         boolean checkIfOutlinePageActive) {
610
611         super.synchronizeOutlinePage(element, checkIfOutlinePageActive);
612     }
613
614     /*
615      * (non-Javadoc)
616      * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor#synchronizeOutlinePage(org.eclipse.jdt.core.ISourceReference)
617      */

618     protected void synchronizeOutlinePage(ISourceReference element) {
619
620         super.synchronizeOutlinePage(element);
621     }
622
623     /*
624      * (non-Javadoc)
625      * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor#synchronizeOutlinePageSelection()
626      */

627     public void synchronizeOutlinePageSelection() {
628
629         super.synchronizeOutlinePageSelection();
630     }
631
632     /*
633      * (non-Javadoc)
634      * @see org.eclipse.ui.texteditor.AbstractTextEditor#getSelectionProvider()
635      */

636     public ISelectionProvider getSelectionProvider() {
637
638         return super.getSelectionProvider();
639     }
640
641     /*
642      * (non-Javadoc)
643      * @see org.eclipse.ui.texteditor.AbstractTextEditor#selectAndReveal(int, int, int,
644      * int)
645      */

646     protected void selectAndReveal(int selectionStart, int selectionLength,
647         int revealStart, int revealLength) {
648
649         super.selectAndReveal(
650             selectionStart, selectionLength, revealStart, revealLength);
651     }
652
653     /*
654      * (non-Javadoc)
655      * @see org.eclipse.ui.texteditor.AbstractTextEditor#selectAndReveal(int, int)
656      */

657     public void selectAndReveal(int start, int length) {
658
659         super.selectAndReveal(start, length);
660     }
661
662     /*
663      * (non-Javadoc)
664      * @see org.eclipse.ui.texteditor.AbstractTextEditor#setHighlightRange(int, int,
665      * boolean)
666      */

667     public void setHighlightRange(int offset, int length, boolean moveCursor) {
668         super.setHighlightRange(offset, length, moveCursor);
669
670     }
671
672     public void showHighlightRangeOnly(boolean showHighlightRangeOnly) {
673         // disabled as we currently do not support "partial" view on selected
674
// elements
675
// super.showHighlightRangeOnly(showHighlightRangeOnly);
676
}
677
678     protected void updateOccurrenceAnnotations(ITextSelection selection,
679         CompilationUnit astRoot) {
680         // disabled for bytecode as we currently do not support "occurencies" highlighting
681
if(hasMappedSource()) {
682             super.updateOccurrenceAnnotations(selection, astRoot);
683         }
684     }
685
686     /**
687      * Updater that takes care of minimizing changes of the editor input.
688      */

689     private class InputUpdater implements Runnable JavaDoc {
690
691         /** Has the runnable already been posted? */
692         private boolean fPosted = false;
693         /** Editor input */
694         private IClassFileEditorInput fClassFileEditorInput;
695
696         public InputUpdater() {
697             //
698
}
699
700         /*
701          * @see Runnable#run()
702          */

703         public void run() {
704
705             IClassFileEditorInput input;
706             synchronized (this) {
707                 input = fClassFileEditorInput;
708             }
709
710             try {
711                 if (getSourceViewer() != null) {
712                     setInput(input);
713                 }
714             } finally {
715                 synchronized (this) {
716                     fPosted = false;
717                 }
718             }
719         }
720
721         /**
722          * Posts this runnable into the event queue if not already there.
723          * @param input the input to be set when executed
724          */

725         public void post(IClassFileEditorInput input) {
726
727             synchronized (this) {
728                 if (fPosted) {
729                     if (input != null && input.equals(fClassFileEditorInput))
730                         fClassFileEditorInput = input;
731                     return;
732                 }
733             }
734
735             if (input != null && input.equals(getEditorInput())) {
736                 ISourceViewer viewer = getSourceViewer();
737                 if (viewer != null) {
738                     StyledText textWidget = viewer.getTextWidget();
739                     if (textWidget != null && !textWidget.isDisposed()) {
740                         synchronized (this) {
741                             fPosted = true;
742                             fClassFileEditorInput = input;
743                         }
744                         textWidget.getDisplay().asyncExec(this);
745                     }
746                 }
747             }
748         }
749     }
750
751     /*
752      * @see AbstractTextEditor#createActions()
753      */

754     protected void createActions() {
755         super.createActions();
756
757         // setAction(ITextEditorActionConstants.SAVE, null);
758
// setAction(ITextEditorActionConstants.REVERT_TO_SAVED, null);
759

760         /*
761          * 1GF82PL: ITPJUI:ALL - Need to be able to add bookmark to classfile // replace
762          * default action with class file specific ones
763          * setAction(ITextEditorActionConstants.BOOKMARK, new
764          * AddClassFileMarkerAction("AddBookmark.", this, IMarker.BOOKMARK, true));
765          * //$NON-NLS-1$ setAction(ITextEditorActionConstants.ADD_TASK, new
766          * AddClassFileMarkerAction("AddTask.", this, IMarker.TASK, false)); //$NON-NLS-1$
767          * setAction(ITextEditorActionConstants.RULER_MANAGE_BOOKMARKS, new
768          * ClassFileMarkerRulerAction("ManageBookmarks.", getVerticalRuler(), this,
769          * IMarker.BOOKMARK, true)); //$NON-NLS-1$
770          * setAction(ITextEditorActionConstants.RULER_MANAGE_TASKS, new
771          * ClassFileMarkerRulerAction("ManageTasks.", getVerticalRuler(), this,
772          * IMarker.TASK, true)); //$NON-NLS-1$
773          */

774     }
775
776     /*
777      * @see JavaEditor#getCorrespondingElement(IJavaElement)
778      */

779     protected IJavaElement getCorrespondingElement(IJavaElement element) {
780         IClassFile classFile = getClassFile();
781         if (classFile == null) {
782             return null;
783         }
784         if (classFile.equals(element.getAncestor(IJavaElement.CLASS_FILE))) {
785             return element;
786         }
787         return null;
788     }
789
790     /*
791      * 1GEPKT5: ITPJUI:Linux - Source in editor for external classes is editable Removed
792      * methods isSaveOnClosedNeeded and isDirty. Added method isEditable.
793      */

794     /*
795      * @see org.eclipse.ui.texteditor.AbstractTextEditor#isEditable()
796      */

797     public boolean isEditable() {
798         return isDecompiled();
799     }
800
801     /*
802      * @see org.eclipse.ui.texteditor.AbstractTextEditor#isEditorInputReadOnly()
803      * @since 3.2
804      */

805     public boolean isEditorInputReadOnly() {
806         return !isDecompiled();
807     }
808
809     /*
810      * @see ITextEditorExtension2#isEditorInputModifiable()
811      * @since 2.1
812      */

813     public boolean isEditorInputModifiable() {
814         return isDecompiled();
815     }
816
817     public boolean isSaveAsAllowed() {
818         return isDecompiled();
819     }
820
821     /**
822      * Translates the given object into an <code>IClassFileEditorInput</code>
823      * @param input the object to be transformed if necessary
824      * @return the transformed editor input
825      */

826     protected IClassFileEditorInput transformEditorInput(Object JavaDoc input) {
827
828         if (input instanceof IFileEditorInput) {
829             IFile file = ((IFileEditorInput) input).getFile();
830             Constructor JavaDoc cons;
831             try {
832                 cons = ExternalClassFileEditorInput.class
833                     .getDeclaredConstructor(new Class JavaDoc[]{IFile.class});
834                 cons.setAccessible(true);
835                 IClassFileEditorInput classFileInput = (IClassFileEditorInput) cons
836                     .newInstance(new Object JavaDoc[]{file});
837                 return classFileInput;
838             } catch (Exception JavaDoc e) {
839                 BytecodeOutlinePlugin.log(e, IStatus.ERROR);
840             }
841         } else if (input instanceof IClassFileEditorInput) {
842             return (IClassFileEditorInput) input;
843         } else if (input instanceof IClassFile) {
844             return new InternalClassFileEditorInput((IClassFile) input);
845         }
846
847         return null;
848     }
849
850     /*
851      * @see IWorkbenchPart#createPartControl(Composite)
852      */

853     public void createPartControl(Composite parent) {
854
855         fParent = new Composite(parent, SWT.NONE);
856         fStackLayout = new StackLayout();
857         fParent.setLayout(fStackLayout);
858
859         fViewerComposite = new Composite(fParent, SWT.NONE);
860         fViewerComposite.setLayout(new FillLayout());
861
862         super.createPartControl(fViewerComposite);
863
864         fStackLayout.topControl = fViewerComposite;
865         fParent.layout();
866         initDone = true;
867     }
868
869     /*
870      * @see ClassFileDocumentProvider.InputChangeListener#inputChanged(IClassFileEditorInput)
871      */

872     public void inputChanged(IClassFileEditorInput input) {
873         fInputUpdater.post(input);
874         IClassFile cf = input.getClassFile();
875         String JavaDoc source;
876         try {
877             source = cf.getSource();
878             setDecompiled(source != null && source.startsWith(MARK));
879         } catch (JavaModelException e) {
880             BytecodeOutlinePlugin.log(e, IStatus.ERROR);
881         }
882
883     }
884
885     /*
886      * @see org.eclipse.ui.IWorkbenchPart#dispose()
887      */

888     public void dispose() {
889         // http://bugs.eclipse.org/bugs/show_bug.cgi?id=18510
890
IDocumentProvider documentProvider = getDocumentProvider();
891         if (documentProvider instanceof ClassFileDocumentProvider) {
892             ((ClassFileDocumentProvider) documentProvider)
893                 .removeInputChangeListener(this);
894         }
895
896         IClassFile classFile = getClassFile();
897         BytecodeBufferManager.removeBuffer(BytecodeBufferManager
898             .getBuffer(classFile));
899         super.dispose();
900     }
901
902     public static BytecodeSourceMapper getSourceMapper() {
903         return sourceMapper;
904     }
905
906     /**
907      * Check if we can show an inner class, which was declared in the source code of the
908      * given parent class and which could have the bytecode for the given source line.
909      *
910      * If both are true, then this method changes the input of the bytecode editor
911      * with the given class file (if any) to the inner class, or opens a new editor with
912      * the inner class.
913      *
914      * @param sourceLine requested source line (from debugger)
915      * @param parent expected parent class file
916      * @return The region in the inner class (if inner class could be found), or an empty
917      * zero-based region.
918      */

919     public static IRegion checkForInnerClass(int sourceLine, IClassFile parent) {
920         IRegion region = new Region(0, 0);
921
922         // get the editor with given class file, if any
923
BytecodeClassFileEditor editor = getBytecodeEditor(parent);
924         if (editor == null) {
925             return region;
926         }
927
928         // get the inner class type according to the debugger stack frame, if any
929
IJavaReferenceType debugType = sourceMapper.getLastTypeInDebugger();
930         if (debugType == null) {
931             return region;
932         }
933
934         boolean externalClass = editor.getEditorInput() instanceof ExternalClassFileEditorInput;
935         IEditorInput input = null;
936         // check if it is a inner class from the class in editor
937
if (!hasInnerClass(debugType, parent)) {
938             // not only inner classes could be defined in the same source file, but also
939
// local types (non public non inner classes in the same source file)
940
IClassFile classFile = getLocalTypeClass(debugType, parent);
941             if(classFile != null){
942                 input = editor.doOpenBuffer(classFile, externalClass);
943             }
944         } else {
945             // if both exists, replace the input to the inner class
946
input = editor.doOpenBuffer(debugType, parent, externalClass);
947         }
948
949         if (input == null) {
950             return region;
951         }
952
953         /*
954          * Now we change editor input from parent class to child class.
955          * It will change editor title too, so the user will see a new class.
956          * After this change, we could finally compute right source line for current stack
957          */

958         try {
959             editor.doSetInput(input);
960         } catch (CoreException e) {
961             BytecodeOutlinePlugin.log(e, IStatus.ERROR);
962             return region;
963         }
964
965         // and then map given source line to the decompiled code
966
int decompiledLine = sourceMapper.mapToDecompiled(
967             sourceLine + 1, editor.getClassFile());
968
969         if (decompiledLine >= 0) {
970             // and get the requested line information
971
try {
972                 region = editor.getDocumentProvider().getDocument(input)
973                     .getLineInformation(decompiledLine);
974             } catch (BadLocationException e) {
975                 BytecodeOutlinePlugin.log(e, IStatus.ERROR);
976             }
977         }
978         return region;
979     }
980
981     /**
982      * @param debugType
983      * @param parent
984      * @return non public class (local type class) with the name from "debugType" and
985      * which source was in the "parent" class. Null if no class file could be found.
986      */

987     private static IClassFile getLocalTypeClass(IJavaReferenceType debugType, IClassFile parent) {
988         try {
989             IType type = parent.getType();
990             if((type.isLocal()) || (type.isMember())) {
991                 // local type could not be defined in local or inner classes
992
return null;
993             }
994             // debugType.getSignature() == Lpackage/name/with/slashes/className;
995
String JavaDoc binarySignature = debugType.getSignature();
996             // get only type name from binary signature
997
int idx = binarySignature.lastIndexOf('/');
998             if(idx > 0 && idx < binarySignature.length() - 1){
999                 String JavaDoc name = binarySignature.substring(idx + 1);
1000                if(name.charAt(name.length() - 1) == ';'){
1001                    name = name.substring(0, name.length() - 1);
1002                }
1003                return type.getPackageFragment().getClassFile(name + ".class");
1004            }
1005        } catch (Exception JavaDoc e) {
1006            BytecodeOutlinePlugin.log(e, IStatus.ERROR);
1007        }
1008        return null;
1009    }
1010
1011    private static boolean hasInnerClass(IJavaReferenceType debugType,
1012        IClassFile parent) {
1013        try {
1014            String JavaDoc parentName = parent.getType().getFullyQualifiedName();
1015            String JavaDoc childName = debugType.getName();
1016            return childName != null && childName.startsWith(parentName + "$");
1017        } catch (Exception JavaDoc e) {
1018            BytecodeOutlinePlugin.log(e, IStatus.ERROR);
1019        }
1020        return false;
1021    }
1022
1023    private static BytecodeClassFileEditor getBytecodeEditor(IClassFile parent) {
1024        IEditorReference[] editorReferences = PlatformUI.getWorkbench()
1025            .getActiveWorkbenchWindow().getActivePage().getEditorReferences();
1026        for (int i = 0; i < editorReferences.length; i++) {
1027            IEditorPart editor = editorReferences[i].getEditor(false);
1028            if (editor instanceof BytecodeClassFileEditor) {
1029                BytecodeClassFileEditor bytecodeEditor = (BytecodeClassFileEditor) editor;
1030                if (parent.equals((bytecodeEditor).getClassFile())) {
1031                    return bytecodeEditor;
1032                }
1033            }
1034        }
1035        return null;
1036    }
1037
1038    public ITextSelection convertSelection(ITextSelection textSelection,
1039        boolean toDecompiled) {
1040        int startLine = textSelection.getStartLine();
1041        int newLine;
1042        if (toDecompiled) {
1043            newLine = sourceMapper.mapToDecompiled(
1044                startLine + 1, getClassFile()) + 1;
1045        } else {
1046            newLine = sourceMapper.mapToSource(startLine, getClassFile()) - 1;
1047        }
1048        IDocument document = getDocumentProvider()
1049            .getDocument(getEditorInput());
1050        try {
1051            int lineOffset = document.getLineOffset(newLine);
1052            return new TextSelection(lineOffset, 0);
1053        } catch (BadLocationException e) {
1054            BytecodeOutlinePlugin.log(e, IStatus.ERROR);
1055        }
1056        return null;
1057    }
1058
1059    public int getSourceLine(ITextSelection bytecodeSelection) {
1060        int startLine = bytecodeSelection.getStartLine();
1061        return sourceMapper.mapToSource(startLine, getClassFile()) - 1;
1062    }
1063
1064    public ITextSelection convertLine(int sourceLine) {
1065        int newLine = sourceMapper.mapToDecompiled(
1066            sourceLine + 1, getClassFile()) + 1;
1067        IDocument document = getDocumentProvider()
1068            .getDocument(getEditorInput());
1069        try {
1070            int lineOffset = document.getLineOffset(newLine);
1071            return new TextSelection(lineOffset, 0);
1072        } catch (BadLocationException e) {
1073            BytecodeOutlinePlugin.log(e, IStatus.ERROR);
1074        }
1075        return null;
1076    }
1077
1078    /*
1079     * @see org.eclipse.jdt.internal.ui.javaeditor.JavaEditor#installOverrideIndicator(boolean)
1080     * @since 3.0
1081     */

1082    protected void installOverrideIndicator(boolean provideAST) {
1083        super.installOverrideIndicator(true);
1084    }
1085
1086}
1087
Popular Tags