blob: d7cd439e7de876ba5f5675df429395b685bff602 [file] [log] [blame]
package org.eclipse.photran.internal.ui.views.declaration;
import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.eclipse.core.resources.IFile;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.text.Document;
import org.eclipse.jface.text.IDocumentPartitioner;
import org.eclipse.jface.text.TextSelection;
import org.eclipse.jface.text.TextViewer;
import org.eclipse.jface.text.rules.FastPartitioner;
import org.eclipse.jface.text.rules.ITokenScanner;
import org.eclipse.jface.text.rules.RuleBasedPartitionScanner;
import org.eclipse.jface.text.source.SourceViewer;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.photran.core.IFortranAST;
import org.eclipse.photran.internal.core.analysis.binding.Definition;
import org.eclipse.photran.internal.core.lexer.TokenList;
import org.eclipse.photran.internal.core.parser.ASTExecutableProgramNode;
import org.eclipse.photran.internal.core.properties.SearchPathProperties;
import org.eclipse.photran.internal.core.vpg.PhotranVPG;
import org.eclipse.photran.internal.ui.editor.FortranEditor;
import org.eclipse.photran.internal.ui.editor.FortranKeywordRuleBasedScanner;
import org.eclipse.photran.internal.ui.editor_vpg.DefinitionMap;
import org.eclipse.photran.internal.ui.editor_vpg.FortranEditorTasks;
import org.eclipse.photran.internal.ui.editor_vpg.IFortranEditorASTTask;
import org.eclipse.photran.internal.ui.editor_vpg.IFortranEditorVPGTask;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.IPartListener2;
import org.eclipse.ui.IPartService;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.IWorkbenchPartReference;
import org.eclipse.ui.part.ViewPart;
/**
* Implements Photran's Declaration view
*
* @author Jeff Overbey - modified to use MVC pattern, SourceViewer, caret listener, DefinitionMap; based on code by...
* @author John Goode, Abe Hassan, Sean Kim
* Group: Fennel-Garlic
* University of Illinois at Urbana-Champaign
* CS 427 Fall 2007
*/
public class DeclarationView extends ViewPart
implements ISelectionListener,
ISelectionChangedListener,
IFortranEditorVPGTask,
IFortranEditorASTTask
{
private FortranEditor activeEditor = null;
private HashMap<String, ASTExecutableProgramNode> activeAST = new HashMap<String, ASTExecutableProgramNode>();
private HashMap<String, TokenList> activeTokenList = new HashMap<String, TokenList>();
private HashMap<String, DefinitionMap<String>> activeDefinitions = new HashMap<String, DefinitionMap<String>>();
private SourceViewer viewer = null;
private Document document = new Document();
private Color LIGHT_YELLOW = new Color(null, new RGB(255, 255, 191));
/*
* The content provider class is responsible for
* providing objects to the view. It can wrap
* existing objects in adapters or simply return
* objects as-is. These objects may be sensitive
* to the current input of the view, or ignore
* it and always show the same content
* (like Task List, for example).
*/
/**
* This is a callback that will allow us
* to create the viewer and initialize it.
*/
@Override public void createPartControl(Composite parent)
{
this.viewer = createFortranSourceViewer(parent);
// Add this view as a selection listener to the workbench page
getSite().getPage().addSelectionListener(this);
// Update the selection immediately
try
{
IWorkbenchPage activePage = getSite().getWorkbenchWindow().getActivePage();
if (activePage != null)
selectionChanged(activePage.getActivePart(),
activePage.getSelection());
}
catch (Throwable e) // NullPointerException, etc.
{
;
}
}
private SourceViewer createFortranSourceViewer(Composite parent)
{
final SourceViewer viewer = new SourceViewer(parent, null, SWT.V_SCROLL); //TextViewer(parent, SWT.NONE);
viewer.configure(new FortranEditor.FortranSourceViewerConfiguration(null)
{
@Override protected ITokenScanner getTokenScanner()
{
// Copied from FortranEditor#getTokenScanner
return new FortranKeywordRuleBasedScanner(false, viewer);
}
});
viewer.setDocument(document);
IDocumentPartitioner partitioner = new FastPartitioner(new RuleBasedPartitionScanner(), FortranEditor.PARTITION_TYPES);
partitioner.connect(document);
document.setDocumentPartitioner(partitioner);
viewer.getControl().setBackground(LIGHT_YELLOW);
viewer.setEditable(false);
viewer.getTextWidget().setFont(JFaceResources.getTextFont());
return viewer;
}
/**
* Update document by displaying the new text
*/
public void update(String str)
{
if (str.length() > 0)
str = trimBlankLines(str);
document.set(str);
viewer.refresh();
}
private static Pattern blankLine = Pattern.compile("(([ \\t]*[\\r\\n]+)+)[^\\00]*"); //$NON-NLS-1$
private String trimBlankLines(String str)
{
Matcher m = blankLine.matcher(str);
while (str.length() > 0 && m.matches())
{
str = str.substring(m.end(1));
m = blankLine.matcher(str);
}
return str;
}
/**
* Passing the focus request to the viewer's control.
*/
@Override public void setFocus()
{
viewer.getControl().setFocus();
}
/**
* ISelectionListener - Callback notifying the view that a new workbench part has been selected.
*/
public synchronized void selectionChanged(IWorkbenchPart part, ISelection selection)
{
if (part instanceof FortranEditor)
{
if (activeEditor != part)
{
// Observe new editor
stopObserving(activeEditor);
activeEditor = startObserving((FortranEditor)part);
}
else
{
// Leave everything as-is
}
}
else
{
// Observe nothing
stopObserving(activeEditor);
activeEditor = null;
}
}
/**
* Registers this view to receive notifications of caret movement in <code>editor</code>
*
* See http://dev.eclipse.org/mhonarc/newsLists/news.eclipse.platform/msg44602.html
*/
private FortranEditor startObserving(final FortranEditor editor)
{
if (editor != null)
{
String declViewEnabledProperty = new SearchPathProperties().getProperty(
editor.getIFile(),
SearchPathProperties.ENABLE_DECL_VIEW_PROPERTY_NAME);
if (declViewEnabledProperty != null && declViewEnabledProperty.equals("true")) //$NON-NLS-1$
{
addCaretMovementListenerTo(editor);
FortranEditorTasks tasks = FortranEditorTasks.instance(editor);
tasks.addASTTask(this);
tasks.addVPGTask(this);
((IPartService)getSite().getService(IPartService.class)).addPartListener(new IPartListener2()
{
public void partActivated(IWorkbenchPartReference partRef)
{
}
public void partBroughtToTop(IWorkbenchPartReference partRef)
{
}
public void partClosed(IWorkbenchPartReference partRef)
{
if (partRef.getPart(false) == editor)
{
FortranEditorTasks tasks = FortranEditorTasks.instance(editor);
tasks.removeASTTask(DeclarationView.this);
tasks.removeVPGTask(DeclarationView.this);
IFile ifile = editor.getIFile();
if (ifile != null)
{
String path = ifile.getFullPath().toPortableString();
activeAST.remove(path);
activeDefinitions.remove(path);
activeTokenList.remove(path);
}
}
((IPartService)getSite().getService(IPartService.class)).removePartListener(this);
}
public void partDeactivated(IWorkbenchPartReference partRef)
{
}
public void partHidden(IWorkbenchPartReference partRef)
{
}
public void partInputChanged(IWorkbenchPartReference partRef)
{
}
public void partOpened(IWorkbenchPartReference partRef)
{
}
public void partVisible(IWorkbenchPartReference partRef)
{
}
});
tasks.getRunner().runTasks(true);
return editor;
}
}
return null;
}
private void addCaretMovementListenerTo(FortranEditor editor)
{
TextViewer sourceViewer = (TextViewer)editor.getSourceViewerx();
if (sourceViewer != null)
sourceViewer.addPostSelectionChangedListener(this);
}
/**
* Unregisters this view to receive notifications of caret movement in <code>editor</code>
*/
private void stopObserving(FortranEditor editor)
{
update(""); //$NON-NLS-1$
if (editor != null)
removeCaretMovementListenerFrom(editor);
}
private void removeCaretMovementListenerFrom(FortranEditor editor)
{
TextViewer sourceViewer = (TextViewer)editor.getSourceViewerx();
if (sourceViewer != null)
sourceViewer.removePostSelectionChangedListener(this);
}
/**
* IFortranEditorVPGTask - Callback run when the VPG is more-or-less up-to-date.
* This method is run <i>outside</i> the UI thread.
*/
public void handle(IFile file, IFortranAST ast, DefinitionMap<Definition> defMap)
{
if (defMap == null) return;
long start = System.currentTimeMillis();
DefinitionMap<String> newDefMap = new DefinitionMap<String>(defMap)
{
@Override protected String map(String qualifiedName, Definition def)
{
return def.describe();
}
};
synchronized (this)
{
activeDefinitions.put(file.getFullPath().toPortableString(), newDefMap);
}
PhotranVPG.getInstance().debug(" Decl view IEditorVPGTask handler:\t" + (System.currentTimeMillis()-start) + " ms", PhotranVPG.getFilenameForIFile(file)); //$NON-NLS-1$ //$NON-NLS-2$
}
/**
* IFortranEditorASTTask - Callback run when a fresh AST for the file in the editor
* is available. May be newer than the information available in the VPG.
* This method is run <i>outside</i> the UI thread.
*/
public synchronized boolean handle(ASTExecutableProgramNode ast, TokenList tokenList, DefinitionMap<Definition> defMap)
{
if (activeEditor != null)
{
long start = System.currentTimeMillis();
String path = activeEditor.getIFile().getFullPath().toPortableString();
activeAST.put(path, ast);
activeTokenList.put(path, tokenList);
PhotranVPG.getInstance().debug(" Decl view IEditorASTTask handler:\t" + (System.currentTimeMillis()-start) + " ms", null); //$NON-NLS-1$ //$NON-NLS-2$
}
return true;
}
/**
* ISelectionChangedListener - Callback notifying the view that the editor's caret has moved
*/
public synchronized void selectionChanged(SelectionChangedEvent event)
{
if (activeEditor == null) return;
String path = activeEditor.getIFile().getFullPath().toPortableString();
TokenList tokenList = activeTokenList.get(path);
DefinitionMap<String> defMap = activeDefinitions.get(path);
if (event.getSelection() instanceof TextSelection && tokenList != null && defMap != null)
{
String description = defMap.lookup((TextSelection)event.getSelection(), tokenList);
update(description == null
? "" //$NON-NLS-1$
: description);
}
else
{
update(""); //$NON-NLS-1$
}
}
}