/*******************************************************************************
* Copyright (c) 2005, 2012 eBay Inc.
* 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
*
*******************************************************************************/
/**
*
*/
package org.eclipse.vjet.eclipse.internal.ui.view.scriptunit;
import java.lang.reflect.Method;
import java.util.List;
import org.eclipse.dltk.mod.core.IModelElement;
import org.eclipse.dltk.mod.internal.core.NativeVjoSourceModule;
import org.eclipse.dltk.mod.internal.core.VjoSourceModule;
import org.eclipse.dltk.mod.internal.ui.editor.ExternalFileEditorInput;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.text.DocumentEvent;
import org.eclipse.jface.text.IDocumentListener;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.Clipboard;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IPartListener;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IViewSite;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.vjet.dsf.jst.IJstNode;
import org.eclipse.vjet.dsf.jst.IJstType;
import org.eclipse.vjet.dsf.jst.JstSource;
import org.eclipse.vjet.dsf.jst.declaration.JstMethod;
import org.eclipse.vjet.dsf.jst.declaration.JstProperty;
import org.eclipse.vjet.dsf.jst.declaration.JstType;
import org.eclipse.vjet.dsf.jst.term.JstIdentifier;
import org.eclipse.vjet.dsf.jst.term.SimpleLiteral;
import org.eclipse.vjet.dsf.jstojava.translator.JstUtil;
import org.eclipse.vjet.eclipse.core.VjetPlugin;
import org.eclipse.vjet.eclipse.core.parser.VjoParserToJstAndIType;
import org.eclipse.vjet.eclipse.internal.ui.editor.VjoEditor;
import org.eclipse.vjet.eclipse.internal.ui.nodeprinter.INodePrinter;
import org.eclipse.vjet.eclipse.internal.ui.nodeprinter.NodePrinterFactory;
import org.eclipse.vjet.vjo.tool.typespace.TypeSpaceMgr;
/**
* Script Unit View
*
*
*
*/
public class ScriptUnitView extends ViewPart implements ISelectionListener{
private TreeViewer viewer;
private Label offsetLabel;
private VjoEditor vjoEditor; //the editor that provide the content
private IPartListener partListener = new PartListener();
private IDocumentListener documentListener = new DocumentListener();
private IJstType jstType; //last jst type input
@Override
public void init(IViewSite site) throws PartInitException {
super.init(site);
this.getSite().getPage().getWorkbenchWindow().getSelectionService().addPostSelectionListener(this);
this.getSite().getPage().getWorkbenchWindow().getPartService().addPartListener(partListener);
}
/* (non-Javadoc)
* @see org.eclipse.ui.part.WorkbenchPart#createPartControl(org.eclipse.swt.widgets.Composite)
*/
@Override
public void createPartControl(Composite parent) {
parent.setLayout(new GridLayout(1, false));
//create tree viewer
this.viewer = new TreeViewer(parent);
this.viewer.getTree().setLayoutData(new GridData(GridData.FILL_BOTH));
this.viewer.setContentProvider(new ScriptUnitTreeContentProvider());
this.viewer.setLabelProvider(new ScriptUnitTreeLabelProvider());
this.viewer.addDoubleClickListener(new IDoubleClickListener() {
/*
* select source code range in editor
*
* @see org.eclipse.jface.viewers.IDoubleClickListener#doubleClick(org.eclipse.jface.viewers.DoubleClickEvent)
*/
public void doubleClick(DoubleClickEvent event) {
IStructuredSelection structuredSelection = (IStructuredSelection)event.getSelection();
if (!(structuredSelection.getFirstElement() instanceof IJstNode))
return;
IJstNode jstNode = (IJstNode)structuredSelection.getFirstElement();
JstSource jstSource = jstNode.getSource();
if (jstSource == null)
return;
vjoEditor.getScriptSourceViewer().revealRange(jstSource.getStartOffSet(), jstSource.getLength());
vjoEditor.getScriptSourceViewer().setSelectedRange(jstSource.getStartOffSet(), jstSource.getLength());
}
});
//offset label
this.offsetLabel = new Label(parent, SWT.SHADOW_IN);
this.offsetLabel.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
//set selection provider
this.getSite().setSelectionProvider(this.viewer);
//fill action bar
this.fillActionBar();
//context menu
this.initContextMenu();
}
private void fillActionBar() {
IActionBars actionBars = this.getViewSite().getActionBars();
actionBars.getToolBarManager().add(new CheckNodeAction(this.viewer));
}
private void initContextMenu() {
MenuManager popupMenuManager = new MenuManager("#PopupMenu");
popupMenuManager.add(new Action("Copy Structure") {
/* (non-Javadoc)
* @see org.eclipse.jface.action.Action#run()
*/
public void run() {
Object selectedNode = ((IStructuredSelection)viewer.getSelection()).getFirstElement();
String structure = copyStructure(selectedNode, 0);
Clipboard clipboard = new Clipboard(Display.getCurrent());
clipboard.setContents(new Object[] {structure}, new Transfer[] {TextTransfer.getInstance()});
clipboard.dispose();
}
});
popupMenuManager.add(new Action("Copy Properties") {
/* (non-Javadoc)
* @see org.eclipse.jface.action.Action#run()
*/
public void run() {
Object selectedNode = ((IStructuredSelection)viewer.getSelection()).getFirstElement();
String properties = copyProperties(selectedNode);
Clipboard clipboard = new Clipboard(Display.getCurrent());
clipboard.setContents(new Object[] {properties}, new Transfer[] {TextTransfer.getInstance()});
clipboard.dispose();
}
});
popupMenuManager.add(new Action("Copy XPath") {
/* (non-Javadoc)
* @see org.eclipse.jface.action.Action#run()
*/
public void run() {
Object selectedNode = ((IStructuredSelection)viewer.getSelection()).getFirstElement();
String xpath = "";
if (selectedNode instanceof IJstNode){
IJstNode node = (IJstNode)selectedNode;
ITreeContentProvider contentProvider = (ITreeContentProvider)viewer.getContentProvider();
xpath = getXPathTestString(node, contentProvider);
System.out.println("Here is my XPath === : \n" + xpath);
}
Clipboard clipboard = new Clipboard(Display.getCurrent());
clipboard.setContents(new Object[] {xpath}, new Transfer[] {TextTransfer.getInstance()});
clipboard.dispose();
}
});
Menu popupMenu = popupMenuManager.createContextMenu(this.viewer.getTree());
this.viewer.getTree().setMenu(popupMenu);
getSite().registerContextMenu(popupMenuManager, this.viewer);
}
private String getXPathTestString(IJstNode node, ITreeContentProvider contentProvider){
StringBuffer testString = new StringBuffer("<testcase number='1'>\n\t");
node.getOwnerType().getName();
testString.append("<file>" + node.getRootType().getName()+ "</file>\n\t");
testString.append("<jxpath>\n\t\t");
String nodeToPut = "";
if (getNodeName((Object)node).equals("")){
nodeToPut = node.getClass().getSimpleName();
} else {
nodeToPut = node.getClass().getSimpleName()
+ "[@Name='" + getNodeName((Object)node) + "']";
}
String str = getXPath(nodeToPut, node, contentProvider);
testString.append("<pathname>"+str+"</pathname>\n\t\t");
testString.append("<nodecount>1</nodecount>\n\t\t");
testString.append("<node position='1' status='pass'>\n\t\t\t");
if (node instanceof JstIdentifier){
IJstNode bNode = ((JstIdentifier)node).getJstBinding();
String bName = getNodeName(bNode);
String bType = getTypeList(bNode);
String bClass = bNode.getClass().getSimpleName();
String bParent = getTypeList(bNode.getParentNode());
System.out.println(bName + " ; " + bType + " ; " + bClass + " ; " + bParent);
testString.append("<bindingnode>" + getNodeName(bNode) + "</bindingnode>\n\t\t\t");
testString.append("<bindingtype>" + getTypeList(bNode) + "</bindingtype>\n\t\t\t");
testString.append("<bindingclass>" + bNode.getClass().getSimpleName() + "</bindingclass>\n\t\t\t");
testString.append("<bindingparent>" + getTypeList(bNode.getParentNode()) + "</bindingparent>\n\t\t");
} else {
testString.append("<bindingnode>"+ getNodeName(node) +"</bindingnode>\n\t\t\t");
testString.append("<bindingtype>"+ getTypeList(node) +"</bindingtype>\n\t\t");
}
testString.append("</node>\n\t");
testString.append("</jxpath>\n");
testString.append("</testcase>");
return testString.toString();
}
private String getXPath(String str, Object obj,
ITreeContentProvider contentProvider){
String returnStr = "";
if (contentProvider.getParent(obj) != null){
Object parent = contentProvider.getParent(obj);
String addIt = "";
//Add node and name
if (getNodeName(parent).equals("")){
addIt = parent.getClass().getSimpleName();
} else {
addIt = parent.getClass().getSimpleName()
+ "[@Name='" + getNodeName(parent) + "']";
}
if(getNodeName(obj).equals("")){
//Add position if more than 1
if (getPosition((IJstNode)obj, (IJstNode)parent) > 1){
if (str.indexOf("/") == -1) {
str = str + "[@Position='" +
getPosition((IJstNode)obj, (IJstNode)parent) + "']";
} else {
str = str.replaceFirst("/", "[@Position='" +
getPosition((IJstNode)obj, (IJstNode)parent) + "']/");
}
}
}
str = addIt + "/" + str;
if (parent.getClass().getSimpleName().equals(
JstType.class.getSimpleName())){
return str;
}
returnStr = getXPath(str, parent, contentProvider);
}
return returnStr;
}
private int getPosition(IJstNode child, IJstNode parent){
int position = 0;
for (IJstNode node : parent.getChildren()){
if (node.getClass().equals(child.getClass())){
position = position + 1;
if (getNodeName(node).equals(getNodeName(child))){
break;
}
}
}
return position;
}
private static String getNodeName(IJstNode node) {
String value = null;
try {
JstAstInfoVisitor visitor = new JstAstInfoVisitor();
Method method = JstAstInfoVisitor.class.getMethod("visit", node
.getClass());
method.invoke(visitor, node);
value = visitor.getValue();
} catch (Exception e) {
}
return value;
}
private String getNodeName(Object node){
String str = "";
if (node instanceof JstMethod) {
str = ((JstMethod)node).getName().getName();
} else if (node instanceof JstProperty) {
str = ((JstProperty)node).getName().getName();
} else if (node instanceof JstIdentifier){
str = ((JstIdentifier)node).getName();
} else if (node instanceof SimpleLiteral){
str = ((SimpleLiteral)node).getValue();
}
return str;
}
private String getTypeList(IJstNode node){
String retStr = "";
try {
JstAstInfoVisitor visitor = new JstAstInfoVisitor();
Method method = JstAstInfoVisitor.class.getMethod("visit", node
.getClass());
method.invoke(visitor, node);
List<String> actualType = visitor.getType();
for (String s : actualType){
if (retStr.equals(""))
retStr = retStr + s;
else
retStr = retStr + "," +s;
}
} catch (Exception e) {}
return retStr;
}
private String copyStructure(Object node, int tier) {
ILabelProvider labelProvider = (ILabelProvider)this.viewer.getLabelProvider();
StringBuilder structureBuilder = new StringBuilder(labelProvider.getText(node));
ITreeContentProvider contentProvider = (ITreeContentProvider)this.viewer.getContentProvider();
Object[] children = contentProvider.getChildren(node);
++ tier;
for (int i = 0; i < children.length; i++) {
String childrenStructure = copyStructure(children[i], tier);
structureBuilder.append("\n");
for (int j = 0; j < tier; j++) {
structureBuilder.append("\t");
}
structureBuilder.append(childrenStructure);
}
return structureBuilder.toString();
}
private String copyProperties(Object node) {
INodePrinter nodePrinter = NodePrinterFactory.getNodePrinter(node);
if (nodePrinter == null)
return "";
String[] names = nodePrinter.getPropertyNames(node);
if (names.length == 0)
return "";
StringBuilder stringBuilder = new StringBuilder();
Object[] values = nodePrinter.getPropertyValuies(node);
for (int i = 0; i < names.length; i++) {
stringBuilder.append(names[i] + ":" + values[i]);
if (i != names.length - 1)
stringBuilder.append("\n");
}
return stringBuilder.toString();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.part.WorkbenchPart#setFocus()
*/
@Override
public void setFocus() {
}
/* (non-Javadoc)
* @see org.eclipse.ui.ISelectionListener#selectionChanged(org.eclipse.ui.IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
*/
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
if (!(part instanceof IEditorPart))
return;
if (!(part instanceof VjoEditor)) {
this.cleanUp();
return;
}
if (this.vjoEditor != part) {
/**
* fix bug 5832: first time open 'Array', do parsing, so the groupName of native type 'Array' will be set NULL.
* Note: do not use VjoEditor.getInputElement(), for native type, maybe return VjoSourceModule not NativeVjoSourceModule.
* For example, to native type 'Date', VjoSourceModule.getGroupname() return NULL!!!
*/
IModelElement modelElement = null;
IEditorInput editorInput = ((VjoEditor)part).getEditorInput();
if (editorInput instanceof ExternalFileEditorInput) {
modelElement = ((ExternalFileEditorInput)editorInput).getModelElement();
}
else
modelElement = ((VjoEditor)part).getInputModelElement();
if (!(modelElement instanceof VjoSourceModule)) {
this.cleanUp();
return;
}
VjoSourceModule sourceModule = ((VjoSourceModule)modelElement);
IJstType scriptUnit = sourceModule.getJstType();
//add to fix NPE
if (scriptUnit == null)
return;
//record the latest jst type
this.jstType = scriptUnit;
this.vjoEditor = (VjoEditor)part;
this.vjoEditor.getScriptSourceViewer().getDocument().addDocumentListener(this.documentListener);
//update script unit
((ScriptUnitTreeContentProvider)this.viewer.getContentProvider()).setScriptUnit(scriptUnit);
this.viewer.setInput(new Object[]{scriptUnit});
}
if (selection instanceof ITextSelection && jstType != null) {
ITextSelection textSelection = (ITextSelection)selection;
int startOffset = textSelection.getOffset();
int endOffset = startOffset + textSelection.getLength();
if (textSelection.getLength() > 0)
endOffset = startOffset + textSelection.getLength() - 1;
//update offset status label
String offsetInfo = "Offset:" + textSelection.getOffset() + " Length:" + textSelection.getLength();
this.offsetLabel.setText(offsetInfo);
Object node = JstUtil.getLeafNode(jstType, startOffset, endOffset);
if (node != null) {
this.viewer.setSelection(new StructuredSelection(node), true);
}
else
this.viewer.setSelection(null);
}
}
/**
* Note: this method should not be changed, wrong parsing will interrupt jst type in TypespaceMgr
*
* @param sourceModule
* @param vjoEditor
* @return
*/
private IJstType getScriptUnit(VjoSourceModule sourceModule, VjoEditor vjoEditor) {
try {
String groupName = sourceModule.getGroupName();
String fileName = sourceModule.getTypeName().typeName();
// System.out.println(groupName);
if(groupName.equals(".org.eclipse.dltk.mod.core.external.folders")){
return TypeSpaceMgr.getInstance().findType(sourceModule.getTypeName());
}
// if from lib don't parse it get type from typespace
String source = sourceModule.getSource();
VjoParserToJstAndIType m_parser = new VjoParserToJstAndIType();
if(VjetPlugin.TRACE_PARSER){
System.out.println("parsing for " + getClass().getName());
}
return m_parser.parse(groupName, sourceModule.getTypeName().typeName(), source);
} catch (Exception e) {
return null;
}
}
private boolean needUpdate(IJstType jstType) {
return this.jstType != jstType;
}
private void cleanUp() {
this.viewer.setInput(new Object[0]);
if (this.vjoEditor != null)
this.vjoEditor.getScriptSourceViewer().getDocument().removeDocumentListener(this.documentListener);
this.vjoEditor = null;
}
/* (non-Javadoc)
* @see org.eclipse.ui.part.WorkbenchPart#dispose()
*/
public void dispose() {
if (this.vjoEditor != null)
this.vjoEditor.getScriptSourceViewer().getDocument().removeDocumentListener(this.documentListener);
super.dispose();
this.getSite().getPage().getWorkbenchWindow().getSelectionService().removePostSelectionListener(this);
this.getSite().getPage().getWorkbenchWindow().getPartService().removePartListener(partListener);
}
/**
* vjo editor part listener
*
*
*
*/
private class PartListener implements IPartListener {
public void partActivated(IWorkbenchPart part) {
}
public void partBroughtToTop(IWorkbenchPart part) {
}
/*
* clean the content in script view
*
* @see org.eclipse.ui.IPartListener#partClosed(org.eclipse.ui.IWorkbenchPart)
*/
public void partClosed(IWorkbenchPart part) {
if (vjoEditor == part) {
cleanUp();
}
}
public void partDeactivated(IWorkbenchPart part) {
// TODO Auto-generated method stub
}
public void partOpened(IWorkbenchPart part) {
// TODO Auto-generated method stub
}
}
/**
* update script unit view, when script unit changed (document changed)
*
*
*
*/
private class DocumentListener implements IDocumentListener {
public void documentChanged(DocumentEvent event) {
IModelElement element = vjoEditor.getInputModelElement();
if (!(element instanceof VjoSourceModule)) {
return;
}
VjoSourceModule sourceModule = (VjoSourceModule)element;
IJstType scriptUnit = getScriptUnit(sourceModule, vjoEditor);
//record jst type
jstType = scriptUnit;
//reset input
((ScriptUnitTreeContentProvider)viewer.getContentProvider()).setScriptUnit(scriptUnit);
viewer.setInput(new Object[]{scriptUnit});
}
public void documentAboutToBeChanged(DocumentEvent event) {
// nothing to do
}
}
}