blob: a1e4f139b0f22b890262a8f2a149fff11a6e7efb [file] [log] [blame]
/*
* Copyright (c) 2007-2013 Eike Stepper (Berlin, Germany) 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:
* Eike Stepper - initial API and implementation
*/
package org.eclipse.net4j.util.internal.ui.views;
import org.eclipse.net4j.ui.shared.SharedIcons;
import org.eclipse.net4j.util.ReflectUtil;
import org.eclipse.net4j.util.WrappedException;
import org.eclipse.net4j.util.collection.Pair;
import org.eclipse.net4j.util.container.IPluginContainer;
import org.eclipse.net4j.util.event.EventUtil;
import org.eclipse.net4j.util.event.IEvent;
import org.eclipse.net4j.util.event.IListener;
import org.eclipse.net4j.util.internal.ui.bundle.OM;
import org.eclipse.net4j.util.internal.ui.messages.Messages;
import org.eclipse.net4j.util.ui.UIUtil;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StackLayout;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IPartListener;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Stack;
/**
* @author Eike Stepper
*/
public class Net4jIntrospectorView extends ViewPart
implements IPartListener, ISelectionListener, IDoubleClickListener, IListener
{
public static final String VIEW_ID = "org.eclipse.net4j.util.Net4jIntrospectorView"; //$NON-NLS-1$
private static final Object[] NO_ELEMENTS = {};
private static Net4jIntrospectorView instance;
private TableViewer currentViewer;
private TableViewer objectViewer;
private TableViewer iterableViewer;
private TableViewer arrayViewer;
private TableViewer mapViewer;
private Stack<Object> elements = new Stack<Object>();
private Text classLabel;
private Text objectLabel;
private IAction backAction = new BackAction();
private IAction modeAction = new ModeAction();
private IAction containerAction = new ContainerAction();
private IAction refreshAction = new RefreshAction();
private StackLayout stackLayout;
private Composite stacked;
private IWorkbenchPart activePart;
public Net4jIntrospectorView()
{
}
@Override
public void dispose()
{
IWorkbenchPage page = getSite().getPage();
page.removePartListener(this);
page.removeSelectionListener(this);
super.dispose();
}
public static Net4jIntrospectorView getInstance()
{
return instance;
}
public static synchronized Net4jIntrospectorView getInstance(boolean show)
{
if (instance == null)
{
try
{
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
page.showView(VIEW_ID);
}
catch (Exception ex)
{
throw WrappedException.wrap(ex);
}
}
return instance;
}
@Override
public void createPartControl(Composite parent)
{
Color bg = parent.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND);
Color gray = parent.getDisplay().getSystemColor(SWT.COLOR_DARK_BLUE);
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayout(UIUtil.createGridLayout(1));
Composite c = new Composite(composite, SWT.BORDER);
c.setLayout(UIUtil.createGridLayout(2));
c.setLayoutData(UIUtil.createGridData(true, false));
classLabel = new Text(c, SWT.READ_ONLY);
classLabel.setLayoutData(UIUtil.createGridData(false, false));
classLabel.setBackground(bg);
classLabel.setForeground(gray);
objectLabel = new Text(c, SWT.READ_ONLY);
objectLabel.setLayoutData(UIUtil.createGridData(true, false));
objectLabel.setBackground(bg);
stackLayout = new StackLayout();
stacked = new Composite(composite, SWT.NONE);
stacked.setLayoutData(UIUtil.createGridData());
stacked.setLayout(stackLayout);
objectViewer = createViewer(stacked);
createObjectColmuns();
objectViewer.addDoubleClickListener(this);
objectViewer.setContentProvider(new ObjectContentProvider());
objectViewer.setLabelProvider(new ObjectLabelProvider());
objectViewer.setSorter(new NameSorter());
objectViewer.setInput(getViewSite());
iterableViewer = createViewer(stacked);
createIterableColmuns();
iterableViewer.addDoubleClickListener(this);
iterableViewer.setContentProvider(new IterableContentProvider());
iterableViewer.setLabelProvider(new IterableLabelProvider());
iterableViewer.setInput(getViewSite());
arrayViewer = createViewer(stacked);
createArrayColmuns();
arrayViewer.addDoubleClickListener(this);
arrayViewer.setContentProvider(new ArrayContentProvider());
arrayViewer.setLabelProvider(new ArrayLabelProvider());
arrayViewer.setInput(getViewSite());
mapViewer = createViewer(stacked);
createMapColmuns();
mapViewer.addDoubleClickListener(this);
mapViewer.setContentProvider(new MapContentProvider());
mapViewer.setLabelProvider(new MapLabelProvider());
mapViewer.setSorter(new NameSorter());
mapViewer.setInput(getViewSite());
IActionBars bars = getViewSite().getActionBars();
fillLocalPullDown(bars.getMenuManager());
fillLocalToolBar(bars.getToolBarManager());
IWorkbenchPage page = getSite().getPage();
page.addPartListener(this);
page.addSelectionListener(this);
setCurrentViewer(objectViewer);
instance = this;
}
private void setCurrentViewer(TableViewer viewer)
{
currentViewer = viewer;
stackLayout.topControl = currentViewer.getControl();
stacked.layout();
}
private TableViewer createViewer(Composite parent)
{
TableViewer viewer = new TableViewer(parent, SWT.FULL_SELECTION | SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
viewer.getTable().setLayoutData(UIUtil.createGridData());
viewer.getTable().setHeaderVisible(true);
viewer.getTable().setLinesVisible(true);
return viewer;
}
public void refreshViewer()
{
UIUtil.refreshViewer(currentViewer);
}
public void partActivated(IWorkbenchPart part)
{
if (part == this)
{
return;
}
activePart = part;
if (modeAction.isChecked())
{
elements.clear();
setObject(activePart);
}
}
public void partBroughtToTop(IWorkbenchPart part)
{
}
public void partClosed(IWorkbenchPart part)
{
}
public void partDeactivated(IWorkbenchPart part)
{
if (modeAction.isChecked())
{
if (part == activePart)
{
activePart = null;
setObject(null);
}
}
}
public void partOpened(IWorkbenchPart part)
{
}
public void selectionChanged(IWorkbenchPart part, ISelection sel)
{
if (part == this)
{
return;
}
if (modeAction.isChecked())
{
return;
}
if (sel instanceof IStructuredSelection)
{
IStructuredSelection ssel = (IStructuredSelection)sel;
elements.clear();
setObject(ssel.getFirstElement());
}
else
{
setObject(null);
}
}
public void doubleClick(DoubleClickEvent event)
{
ISelection sel = event.getSelection();
if (sel instanceof IStructuredSelection)
{
IStructuredSelection ssel = (IStructuredSelection)sel;
Object element = ssel.getFirstElement();
if (currentViewer == objectViewer && element instanceof Pair<?, ?>)
{
@SuppressWarnings("unchecked")
Pair<Field, Object> pair = (Pair<Field, Object>)element;
Field field = pair.getElement1();
if (!field.getType().isPrimitive())
{
setObject(pair.getElement2());
}
}
else if (currentViewer == mapViewer && element instanceof Map.Entry<?, ?>)
{
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)element;
setObject(entry.getValue());
}
else if (currentViewer == iterableViewer)
{
setObject(element);
}
else if (currentViewer == arrayViewer && element instanceof Pair<?, ?>)
{
@SuppressWarnings("unchecked")
Pair<Integer, Object> pair = (Pair<Integer, Object>)element;
setObject(pair.getElement2());
}
}
}
/**
* Passing the focus request to the viewer's control.
*/
@Override
public void setFocus()
{
try
{
currentViewer.getControl().setFocus();
}
catch (RuntimeException ignore)
{
}
}
public void notifyEvent(IEvent event)
{
refreshViewer();
}
public void setObject(Object object)
{
EventUtil.removeListener(object, this);
if (object != null)
{
if (!elements.isEmpty())
{
Object element = elements.peek();
if (element != object)
{
EventUtil.removeListener(element, this);
elements.push(object);
}
}
else
{
elements.push(object);
}
}
if (object == null)
{
classLabel.setText(""); //$NON-NLS-1$
objectLabel.setText(""); //$NON-NLS-1$
currentViewer = objectViewer;
}
else
{
EventUtil.addListener(object, this);
String className = object.getClass().getName();
classLabel.setText(className);
String value = object.toString();
if (value.startsWith(className + "@")) //$NON-NLS-1$
{
objectLabel.setText(value.substring(className.length()));
}
else
{
objectLabel.setText(value);
}
}
classLabel.getParent().layout();
backAction.setEnabled(elements.size() >= 2);
if (object instanceof Map<?, ?>)
{
setCurrentViewer(mapViewer);
}
else if (object instanceof Iterable<?>)
{
setCurrentViewer(iterableViewer);
}
else if (object != null && object.getClass().isArray())
{
setCurrentViewer(arrayViewer);
}
else
{
setCurrentViewer(objectViewer);
}
refreshViewer();
}
private void createObjectColmuns()
{
Table table = objectViewer.getTable();
String[] columnNames = { Messages.getString("Net4jIntrospectorView_4"), //$NON-NLS-1$
Messages.getString("Net4jIntrospectorView_5"), Messages.getString("Net4jIntrospectorView_6"), //$NON-NLS-1$ //$NON-NLS-2$
Messages.getString("Net4jIntrospectorView_7") }; //$NON-NLS-1$
int[] columnWidths = { 200, 400, 300, 300 };
createColumns(table, columnNames, columnWidths);
}
private void createMapColmuns()
{
Table table = mapViewer.getTable();
String[] columnNames = { Messages.getString("Net4jIntrospectorView_8"), //$NON-NLS-1$
Messages.getString("Net4jIntrospectorView_9"), Messages.getString("Net4jIntrospectorView_10") }; //$NON-NLS-1$ //$NON-NLS-2$
int[] columnWidths = { 200, 400, 300 };
createColumns(table, columnNames, columnWidths);
}
private void createIterableColmuns()
{
Table table = iterableViewer.getTable();
String[] columnNames = { Messages.getString("Net4jIntrospectorView_11"), //$NON-NLS-1$
Messages.getString("Net4jIntrospectorView_12") }; //$NON-NLS-1$
int[] columnWidths = { 400, 300 };
createColumns(table, columnNames, columnWidths);
}
private void createArrayColmuns()
{
Table table = arrayViewer.getTable();
String[] columnNames = { Messages.getString("Net4jIntrospectorView_13"), //$NON-NLS-1$
Messages.getString("Net4jIntrospectorView_14"), Messages.getString("Net4jIntrospectorView_15") }; //$NON-NLS-1$ //$NON-NLS-2$
int[] columnWidths = { 50, 400, 300 };
createColumns(table, columnNames, columnWidths);
}
private void createColumns(Table table, String[] columnNames, int[] columnWidths)
{
TableColumn[] columns = new TableColumn[columnNames.length];
for (int i = 0; i < columns.length; i++)
{
TableColumn column = new TableColumn(table, SWT.LEFT, i);
column.setText(columnNames[i]);
column.setWidth(columnWidths[i]);
column.setMoveable(true);
column.setResizable(true);
}
}
private void fillLocalPullDown(IMenuManager manager)
{
}
private void fillLocalToolBar(IToolBarManager manager)
{
manager.add(backAction);
manager.add(containerAction);
manager.add(new Separator());
manager.add(modeAction);
manager.add(new Separator());
manager.add(refreshAction);
}
/**
* @author Eike Stepper
*/
class BackAction extends Action
{
private BackAction()
{
super(Messages.getString("Net4jIntrospectorView_16")); //$NON-NLS-1$
ISharedImages sharedImages = PlatformUI.getWorkbench().getSharedImages();
setImageDescriptor(sharedImages.getImageDescriptor(ISharedImages.IMG_TOOL_BACK));
setDisabledImageDescriptor(sharedImages.getImageDescriptor(ISharedImages.IMG_TOOL_BACK_DISABLED));
}
@Override
public void run()
{
if (!elements.isEmpty())
{
elements.pop();
if (!elements.isEmpty())
{
setObject(elements.peek());
}
}
}
}
/**
* @author Eike Stepper
*/
class ModeAction extends Action
{
private ModeAction()
{
super(Messages.getString("Net4jIntrospectorView_17b"), AS_CHECK_BOX); //$NON-NLS-1$
setImageDescriptor(SharedIcons.getDescriptor(SharedIcons.ETOOL_PART_MODE));
}
@Override
public void run()
{
if (isChecked())
{
elements.clear();
setObject(activePart);
}
else
{
setObject(null);
}
}
}
/**
* @author Eike Stepper
*/
class ContainerAction extends Action
{
private ContainerAction()
{
super(Messages.getString("Net4jIntrospectorView_17")); //$NON-NLS-1$
setImageDescriptor(SharedIcons.getDescriptor(SharedIcons.VIEW_CONTAINER));
}
@Override
public void run()
{
setObject(IPluginContainer.INSTANCE);
}
}
/**
* @author Eike Stepper
*/
class RefreshAction extends Action
{
private RefreshAction()
{
super("Refresh"); //$NON-NLS-1$
setImageDescriptor(SharedIcons.getDescriptor(SharedIcons.ETOOL_REFRESH));
}
@Override
public void run()
{
refreshViewer();
}
}
/**
* @author Eike Stepper
*/
abstract class AbstractContentProvider implements IStructuredContentProvider
{
public void inputChanged(Viewer v, Object oldInput, Object newInput)
{
}
public void dispose()
{
}
}
/**
* @author Eike Stepper
*/
abstract class AbstractLabelProvider extends LabelProvider implements ITableLabelProvider
{
@Override
public String getText(Object element)
{
return getColumnText(element, 0);
}
public Image getColumnImage(Object obj, int index)
{
return null;
}
@Override
public Image getImage(Object obj)
{
return null;
}
}
/**
* @author Eike Stepper
*/
class ObjectContentProvider extends AbstractContentProvider
{
public Object[] getElements(Object parent)
{
if (!elements.isEmpty())
{
try
{
return ReflectUtil.dumpToArray(elements.peek());
}
catch (RuntimeException ex)
{
OM.LOG.error(ex);
}
}
return NO_ELEMENTS;
}
}
/**
* @author Eike Stepper
*/
class ObjectLabelProvider extends AbstractLabelProvider
{
public String getColumnText(Object obj, int index)
{
if (obj instanceof Pair<?, ?>)
{
try
{
@SuppressWarnings("unchecked")
Pair<Field, Object> pair = (Pair<Field, Object>)obj;
Field field = pair.getElement1();
Object value = pair.getElement2();
switch (index)
{
case 0:
return field.getName();
case 1:
return value == null ? Messages.getString("Net4jIntrospectorView_18") : value.toString(); //$NON-NLS-1$
case 2:
return field.getType().getName();
case 3:
return value == null ? Messages.getString("Net4jIntrospectorView_1") : value.getClass().getName(); //$NON-NLS-1$
}
}
catch (RuntimeException ex)
{
OM.LOG.error(ex);
}
}
return ""; //$NON-NLS-1$
}
}
/**
* @author Eike Stepper
*/
class IterableContentProvider extends AbstractContentProvider
{
public Object[] getElements(Object parent)
{
if (!elements.isEmpty())
{
Object element = elements.peek();
if (element instanceof Iterable<?>)
{
List<Object> result = new ArrayList<Object>();
for (Object object : (Iterable<?>)element)
{
result.add(object);
}
return result.toArray();
}
}
return NO_ELEMENTS;
}
}
/**
* @author Eike Stepper
*/
class IterableLabelProvider extends AbstractLabelProvider
{
public String getColumnText(Object obj, int index)
{
switch (index)
{
case 0:
return obj == null ? Messages.getString("Net4jIntrospectorView_21") : obj.toString(); //$NON-NLS-1$
case 1:
return obj == null ? Messages.getString("Net4jIntrospectorView_22") : obj.getClass().getName(); //$NON-NLS-1$
}
return ""; //$NON-NLS-1$
}
}
/**
* @author Eike Stepper
*/
class ArrayContentProvider extends AbstractContentProvider
{
@SuppressWarnings("unchecked")
public Object[] getElements(Object parent)
{
if (!elements.isEmpty())
{
Object element = elements.peek();
if (element.getClass().isArray())
{
Object[] array = (Object[])element;
Pair<Integer, Object>[] result = new Pair[array.length];
for (int i = 0; i < array.length; i++)
{
result[i] = Pair.create(i, array[i]);
}
return result;
}
}
return NO_ELEMENTS;
}
}
/**
* @author Eike Stepper
*/
class ArrayLabelProvider extends AbstractLabelProvider
{
public String getColumnText(Object obj, int index)
{
if (obj instanceof Pair<?, ?>)
{
try
{
@SuppressWarnings("unchecked")
Pair<Integer, Object> pair = (Pair<Integer, Object>)obj;
int i = pair.getElement1();
Object value = pair.getElement2();
switch (index)
{
case 0:
return String.valueOf(i);
case 1:
return value == null ? Messages.getString("Net4jIntrospectorView_24") : value.toString(); //$NON-NLS-1$
case 2:
return value == null ? Messages.getString("Net4jIntrospectorView_25") : value.getClass().getName(); //$NON-NLS-1$
}
}
catch (RuntimeException ex)
{
OM.LOG.error(ex);
}
}
return ""; //$NON-NLS-1$
}
}
/**
* @author Eike Stepper
*/
class MapContentProvider extends AbstractContentProvider
{
public Object[] getElements(Object parent)
{
if (!elements.isEmpty())
{
Object element = elements.peek();
if (element instanceof Map<?, ?>)
{
return ((Map<?, ?>)element).entrySet().toArray();
}
}
return NO_ELEMENTS;
}
}
/**
* @author Eike Stepper
*/
class MapLabelProvider extends AbstractLabelProvider
{
public String getColumnText(Object obj, int index)
{
if (obj instanceof Map.Entry<?, ?>)
{
Map.Entry<?, ?> entry = (Map.Entry<?, ?>)obj;
Object key = entry.getKey();
Object value = entry.getValue();
switch (index)
{
case 0:
return key == null ? Messages.getString("Net4jIntrospectorView_27") : key.toString(); //$NON-NLS-1$
case 1:
return value == null ? Messages.getString("Net4jIntrospectorView_28") : value.toString(); //$NON-NLS-1$
case 2:
return value == null ? Messages.getString("Net4jIntrospectorView_29") : value.getClass().getName(); //$NON-NLS-1$
}
}
return ""; //$NON-NLS-1$
}
}
/**
* @author Eike Stepper
*/
class NameSorter extends ViewerSorter
{
}
}