blob: 8d554e6ef01f6351ebd7285b7772a1a1a232ec3b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2007, 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:
* Takashi ITOH - initial API and implementation
*******************************************************************************/
package org.eclipse.actf.visualization.flash.ui.views;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.viewers.AbstractTreeViewer;
import org.eclipse.jface.viewers.IColorProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.actf.accservice.swtbridge.AccessibleObject;
import org.eclipse.actf.model.flash.FlashAdjust;
import org.eclipse.actf.model.flash.FlashDetect;
import org.eclipse.actf.model.flash.FlashNode;
import org.eclipse.actf.model.flash.FlashPlayer;
import org.eclipse.actf.visualization.flash.FlashImages;
import org.eclipse.actf.visualization.flash.Messages;
import org.eclipse.actf.visualization.gui.GuiImages;
import org.eclipse.actf.visualization.gui.GuiPlugin;
import org.eclipse.actf.visualization.gui.flash.FlashFinder;
import org.eclipse.actf.visualization.gui.flash.FlashUtil;
import org.eclipse.actf.visualization.gui.ui.actions.RefreshRootAction;
import org.eclipse.actf.visualization.gui.ui.views.IFlashDOMView;
import org.eclipse.actf.visualization.gui.ui.views.MSAAViewRegistory;
public class FlashDOMView extends ViewPart implements IFlashDOMView {
public static final String ID = FlashDOMView.class.getName();
private TreeViewer viewer;
private Action expandAction;
private Action expandAllAction;
private Action collapseAllAction;
private RefreshRootAction refreshAction;
private Action informativeTreeAction;
private Action visualTreeAction;
private Action debugTreeAction;
private Action scanWindowlessAction;
private Color colorFound = Display.getCurrent().getSystemColor(SWT.COLOR_CYAN);
/**
* The constructor.
*/
public FlashDOMView() {
}
/**
* This is a callback that will allow us
* to create the viewer and initialize it.
*/
public void createPartControl(Composite parent) {
viewer = new FlashTreeViewer(parent, SWT.SINGLE | SWT.H_SCROLL | SWT.V_SCROLL);
viewer.setContentProvider(new FlashDOMContentProvider());
viewer.setLabelProvider(new FlashDOMLabelProvider());
viewer.addSelectionChangedListener(new ISelectionChangedListener(){
public void selectionChanged(SelectionChangedEvent event) {
ISelection selection = event.getSelection();
if (selection instanceof IStructuredSelection) {
Object selectedItem = ((IStructuredSelection) selection).getFirstElement();
if( selectedItem instanceof FlashNode ) {
((FlashNode)selectedItem).setMarker();
}
else if( !(selectedItem instanceof FlashPlayer) ) {
return;
}
MSAAViewRegistory.showProperties(selectedItem);
}
}
});
makeActions();
hookContextMenu();
contributeToActionBars();
MSAAViewRegistory.findView(MSAAViewRegistory.MSAAOutlineView_ID);
refresh();
}
public void adjustID() {
Object[] results = FlashUtil.getFlashElements(MSAAViewRegistory.rootObject);
for( int i=0; i<results.length; i++ ) {
FlashAdjust flashAdjust = new FlashAdjust(results[i]);
flashAdjust.adjust("adesigner_flash_object"+i); //$NON-NLS-1$
flashAdjust.dispose();
}
}
public void refresh() {
AccessibleObject rootObject = MSAAViewRegistory.getRootObject();
if( null != rootObject ) {
adjustID();
viewer.setInput(FlashUtil.getFlashElements(rootObject));
FlashDetect.showDialog();
}
}
public void findRectangle(Rectangle flashRect, Object objUnknown) {
viewer.setInput(new Object[]{objUnknown});
String strMessage = Messages.getString("flash.error_no_element"); //$NON-NLS-1$
RectangleFinder finder = new RectangleFinder(flashRect);
try {
finder.find(viewer.getTree().getItems());
}
catch( Error e ) {
e.printStackTrace();
}
if( finder.foundCount > 0 ) {
strMessage = MessageFormat.format(Messages.getString("flash.element_found"), new Object[]{new Integer(finder.foundCount)}); //$NON-NLS-1$
}
MessageDialog.openInformation(
viewer.getControl().getShell(),
Messages.getString("flash.flash_dom"), //$NON-NLS-1$
strMessage);
}
public void addWindowlessElement(final Object objUnknown) {
if( !scanWindowlessAction.isChecked() ) {
Display.getCurrent().asyncExec(new Runnable(){
public void run() {
Object currentInput = viewer.getInput();
if( currentInput instanceof Object[] ) {
List list = Arrays.asList((Object[])currentInput);
if( !list.contains(objUnknown) ) {
ArrayList newList = new ArrayList(list);
newList.add(objUnknown);
viewer.setInput(newList.toArray());
}
}
}
});
}
}
private class RectangleFinder {
private static final int MARGIN = 10;
public int foundCount = 0;
private int errorCount = 0;
private int flashLeft, flashTop, flashRight, flashBottom;
public RectangleFinder(Rectangle flashRect) {
flashLeft = flashRect.x;
flashTop = flashRect.y;
flashRight = flashRect.x+flashRect.width;
flashBottom = flashRect.y+flashRect.height;
}
public void find(TreeItem[] items) {
for( int i=0; i<items.length; i++ ) {
TreeItem item = items[i];
try {
FlashNode flashNode = (FlashNode)item.getData();
if( flashNode.getLevel()>=40 ) {
throw new Error(MessageFormat.format(Messages.getString("flash.error_target_length"),new Object[]{new Integer(flashNode.getLevel())})+"\n"+flashNode.getTarget()); //$NON-NLS-1$ //$NON-NLS-2$
}
String strX = flashNode.getString("x"); //$NON-NLS-1$
if( null == strX ) continue;
int x = Float.valueOf(strX).intValue(); //$NON-NLS-1$
if( x>=flashRight+MARGIN ) {
continue;
}
int y = Float.valueOf(flashNode.getString("y")).intValue(); //$NON-NLS-1$
if( y>=flashBottom+MARGIN ) {
continue;
}
int w = Float.valueOf(flashNode.getString("w")).intValue(); //$NON-NLS-1$
if( x+w<=flashLeft-MARGIN ) {
continue;
}
int h = Float.valueOf(flashNode.getString("h")).intValue(); //$NON-NLS-1$
if( y+h<=flashTop-MARGIN ) {
continue;
}
if( isMatch(x,y,w,h) ) {
item.setBackground(colorFound);
foundCount++;
viewer.reveal(flashNode);
}
if( Boolean.TRUE.equals(flashNode.getObject("isOpaqueObject")) ) { //$NON-NLS-1$
// System.out.println("Skip Opaque Object "+flashNode.getTarget()); //$NON-NLS-1$
continue;
}
find(((FlashTreeViewer)viewer).getChildItems(item));
}
catch( Exception e ) {
e.printStackTrace();
}
catch( FindError e ) {
throw e;
}
catch( Error e) {
System.err.println(e.getMessage());
if( ++errorCount >= 20 ) {
throw new FindError("Error count reached "+errorCount); //$NON-NLS-1$
}
}
}
}
private class FindError extends Error {
private static final long serialVersionUID = -7707451728015676479L;
public FindError(String message) {
super(message);
}
};
private boolean isMatch(int x, int y, int w, int h) {
return flashLeft-MARGIN<=x && x<flashLeft+MARGIN &&
flashTop-MARGIN<=y && y<flashTop+MARGIN &&
flashRight-MARGIN<=x+w && x+w<=flashRight+MARGIN &&
flashBottom-MARGIN<=y+h && y+h<=flashBottom+MARGIN;
}
}
private void hookContextMenu() {
MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
FlashDOMView.this.fillContextMenu(manager);
}
});
Menu menu = menuMgr.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
getSite().registerContextMenu(menuMgr, viewer);
}
private void contributeToActionBars() {
IActionBars bars = getViewSite().getActionBars();
fillLocalPullDown(bars.getMenuManager());
fillLocalToolBar(bars.getToolBarManager());
}
private void fillLocalPullDown(IMenuManager manager) {
manager.add(informativeTreeAction);
manager.add(visualTreeAction);
manager.add(scanWindowlessAction);
manager.add(debugTreeAction);
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
private void fillContextMenu(IMenuManager manager) {
Object selected = getSelectedItem();
if (null != selected) {
manager.add(expandAction);
}
manager.add(new Separator());
manager.add(refreshAction);
// Other plug-ins can contribute there actions here
manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
private void fillLocalToolBar(IToolBarManager manager) {
manager.add(expandAllAction);
manager.add(collapseAllAction);
manager.add(refreshAction);
}
private void makeActions() {
expandAction = new Action(Messages.getString("msaa.expand")) { //$NON-NLS-1$
public void run() {
try {
Object selected = getSelectedItem();
if (null != selected) {
viewer.expandToLevel(selected, AbstractTreeViewer.ALL_LEVELS);
}
}
catch (Error e) {
e.printStackTrace();
}
}
};
expandAllAction = new Action(Messages.getString("msaa.expand_all")) { //$NON-NLS-1$
public void run() {
try {
viewer.expandAll();
}
catch (Error e) {
System.err.println(e.getMessage());
}
}
};
expandAllAction.setToolTipText(Messages.getString("msaa.expand_all")); //$NON-NLS-1$
expandAllAction.setImageDescriptor(GuiPlugin.IMAGE_EXPAND_ALL);
collapseAllAction = new Action(Messages.getString("msaa.collapse_all")) { //$NON-NLS-1$
public void run() {
try {
viewer.collapseAll();
}
catch (Error e) {
e.printStackTrace();
}
}
};
collapseAllAction.setToolTipText(Messages.getString("msaa.collapse_all")); //$NON-NLS-1$
collapseAllAction.setImageDescriptor(GuiPlugin.IMAGE_COLLAPSE_ALL);
refreshAction = new RefreshRootAction();
informativeTreeAction = new Action(Messages.getString("flash.filter_noninformative"),Action.AS_CHECK_BOX) { //$NON-NLS-1$
public void run() {
FlashDOMContentProvider provider = (FlashDOMContentProvider)viewer.getContentProvider();
provider.informativeTree = informativeTreeAction.isChecked();
MSAAViewRegistory.refreshRootObject();
}
};
visualTreeAction = new Action(Messages.getString("flash.show_visual"),Action.AS_CHECK_BOX) { //$NON-NLS-1$
public void run() {
FlashDOMContentProvider provider = (FlashDOMContentProvider)viewer.getContentProvider();
provider.visualTree = visualTreeAction.isChecked();
MSAAViewRegistory.refreshRootObject();
}
};
debugTreeAction = new Action(Messages.getString("flash.debugMode"),Action.AS_CHECK_BOX) { //$NON-NLS-1$
public void run() {
FlashFinder.debugMode = debugTreeAction.isChecked();
MSAAViewRegistory.refreshRootObject();
}
};
scanWindowlessAction = new Action(Messages.getString("flash.scanWindowless"),Action.AS_CHECK_BOX) { //$NON-NLS-1$
public void run() {
FlashFinder.scanAll = scanWindowlessAction.isChecked();
MSAAViewRegistory.refreshRootObject();
}
};
}
private Object getSelectedItem() {
IStructuredSelection selection = (IStructuredSelection) viewer.getSelection();
if (selection.size() == 1) {
return selection.getFirstElement();
}
return null;
}
/**
* Passing the focus request to the viewer's control.
*/
public void setFocus() {
viewer.getControl().setFocus();
}
private class FlashDOMContentProvider implements ITreeContentProvider {
public boolean visualTree = false;
public boolean informativeTree = false;
public Object[] getChildren(Object parentElement) {
if( parentElement instanceof FlashNode ) {
return ((FlashNode)parentElement).getChildren(visualTree,informativeTree/*,debugMode*/);
}
return new Object[0];
}
public Object getParent(Object element) {
if( element instanceof FlashNode ) {
return ((FlashNode)element).getParent();
}
return null;
}
public boolean hasChildren(Object element) {
if( element instanceof FlashNode ) {
return ((FlashNode)element).hasChild(visualTree);
}
return false;
}
public Object[] getElements(Object inputElement) {
List elements = new ArrayList();
if( inputElement instanceof Object[] ){
Object[] objects = (Object[])inputElement;
for( int i=0; i<objects.length; i++ ) {
if( objects[i] instanceof AccessibleObject ) {
AccessibleObject accObject= (AccessibleObject)objects[i];
FlashPlayer player = FlashPlayer.getPlayerFromObject(accObject);
if( null != player ) {
FlashNode rootNode = player.getRootNode();
if( null != rootNode ) {
if( FlashUtil.isInvisibleFlash(accObject) ) {
player.isVisible = false;
}
elements.add(rootNode);
}
else {
elements.add(player);
}
}
}
}
}
return elements.toArray();
}
public void dispose() {
}
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
}
private static String getNodeImage(Object element) {
String iconType = null;
if( element instanceof FlashNode ) {
FlashNode flashNode = ((FlashNode)element);
String type = flashNode.getType();
if( "movieclip".equals(type) ) { //$NON-NLS-1$
iconType = type;
int accRole = flashNode.getAccInfo().getAccRole();
if( -1 != accRole ) {
return GuiImages.roleIcon(accRole);
}
else if( flashNode.getAccInfo().hasOnRelease() ) {
iconType = FlashImages.TYPE_button;
}
}
else if( "object".equals(type) ) { //$NON-NLS-1$
iconType = type;
String className = flashNode.getClassName();
if( "Button".equals(className) ) { //$NON-NLS-1$
iconType = FlashImages.TYPE_button;
}
else if( className.startsWith("TextField") ) { //$NON-NLS-1$
iconType = FlashImages.TYPE_text;
}
else {
String objectName = flashNode.getObjectName();
if( "_accProps".equals(objectName) || //$NON-NLS-1$
"_accImpl".equals(objectName) ) { //$NON-NLS-1$
iconType = FlashImages.TYPE_accprops;
}
}
}
else if( "function".equals(type) || //$NON-NLS-1$
"string".equals(type) ) { //$NON-NLS-1$
iconType = type;
}
else if( "number".equals(type) || //$NON-NLS-1$
"null".equals(type) || //$NON-NLS-1$
"boolean".equals(type) || //$NON-NLS-1$
"undefined".equals(type) ) { //$NON-NLS-1$
iconType = FlashImages.TYPE_variable;
}
else {
iconType = FlashImages.TYPE_others;
}
}
else if( element instanceof FlashPlayer ) {
iconType = FlashImages.TYPE_flash;
}
return null!=iconType ? FlashImages.flashIcon(iconType) : null;
}
private static String getNodeText(Object element) {
if( element instanceof FlashNode ) {
FlashNode flashNode = (FlashNode)element;
StringBuffer sb = new StringBuffer();
String text = flashNode.getText();
if( null !=text ) {
sb.append(text);
}
String title = flashNode.getTitle();
if( null != title ) {
if( sb.length()>0 ) {
sb.append(" "); //$NON-NLS-1$
}
sb.append(title);
}
String value = flashNode.getValue();
if( null != value ) {
if( sb.length()>0 ) {
sb.append(" "); //$NON-NLS-1$
}
sb.append(value);
}
if( sb.length()==0 ) {
sb.append(Messages.getString("msaa.NAMELESS")); //$NON-NLS-1$
}
String objectName = flashNode.getObjectName();
if( sb.length()>0 ) {
sb.append(" "); //$NON-NLS-1$
}
sb.append(objectName);
String type = flashNode.getType();
if( null != type ) {
sb.append("("); //$NON-NLS-1$
sb.append(type);
sb.append(")"); //$NON-NLS-1$
}
return sb.toString();
}
else if( element instanceof FlashPlayer ) {
return ((FlashPlayer)element).getErrorText();
}
if( null==element ) return "null"; //$NON-NLS-1$
return element.toString();
}
public String getNodeError(Object element) {
if( element instanceof FlashNode ) {
FlashNode flashNode = (FlashNode)element;
if( !flashNode.getPlayer().isVisible ) {
return FlashImages.OVER_BLACK;
}
if( flashNode.isUIComponent() ) {
if( -1 == flashNode.getAccInfo().getAccRole() ) {
return FlashImages.OVER_RED;
}
}
boolean shouldWarn = "movieclip".equals(flashNode.getType()) || //$NON-NLS-1$
"Button".equals(flashNode.getClassName()); //$NON-NLS-1$
if( shouldWarn && flashNode.getAccInfo().isSilent() ) {
return FlashImages.OVER_BLACK;
}
if( null != flashNode.getText() ) {
return FlashImages.OVER_GREEN;
}
if( shouldWarn && null == flashNode.getAccInfo().getAccName() ) {
return FlashImages.OVER_RED;
}
if( "Button".equals(flashNode.getClassName()) ) { //$NON-NLS-1$
return FlashImages.OVER_YELLOW;
}
String objectName = flashNode.getObjectName();
if( "onRelease".equals(objectName) ) { //$NON-NLS-1$
return FlashImages.OVER_YELLOW;
}
if( "_accProps".equals(objectName) || //$NON-NLS-1$
"_accImpl".equals(objectName) ) { //$NON-NLS-1$
return FlashImages.OVER_GREEN;
}
}
else if (element instanceof FlashPlayer) {
return FlashImages.OVER_BLACK;
}
return null;
}
private class FlashDOMLabelProvider extends LabelProvider implements IColorProvider {
public FlashDOMLabelProvider() {
super();
}
public Image getImage(Object element) {
String nodeImage = getNodeImage(element);
String nodeError = getNodeError(element);
if( null != nodeImage ) {
if( null != nodeError ) {
return FlashImages.getImage(nodeImage,nodeError, new Point(16,16)); }
return FlashImages.getImage(nodeImage);
}
else if( null != nodeError) {
return FlashImages.getImage(nodeError);
}
return null;
}
public String getText(Object element) {
return getNodeText(element);
}
public Color getBackground(Object element) {
return null;
}
public Color getForeground(Object element) {
return null;
}
}
private class FlashTreeViewer extends TreeViewer {
public FlashTreeViewer(Composite parent, int style) {
super(new Tree(parent, style));
}
public TreeItem[] getChildItems(TreeItem item) {
super.createChildren(item);
return item.getItems();
}
}
}