package com.gorillalogic.monkeyconsole.componentview.ui;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeViewerListener;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TreeExpansionEvent;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerFilter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.part.ViewPart;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import com.gorillalogic.monkeyconsole.componentview.model.Model;
import com.gorillalogic.monkeyconsole.componentview.model.UIComponent;
import com.gorillalogic.monkeyconsole.componentview.model.UIContainer;
import com.gorillalogic.monkeyconsole.editors.utils.MonkeyTalkImagesEnum;
import com.gorillalogic.monkeyconsole.plugin.FoneMonkeyPlugin;
/**
* Insert the type's description here.
* @see ViewPart
*/
public class UIContainerView extends ViewPart implements ITreeViewerListener {
protected TreeViewer treeViewer;
protected Text searchBox;
protected UIContainerLabelProvider labelProvider;
protected UIContainerContentProvider contentProvider;
protected boolean showHidden = true;
protected List<UIComponent> searchMatches = new ArrayList<UIComponent>();
protected UIContainer root;
/**
* The constructor.
*/
public UIContainerView() {
}
/*
* @see IWorkbenchPart#createPartControl(Composite)
*/
public void createPartControl(Composite parent) {
/* Create a grid layout object so the text and treeviewer
* are layed out the way I want. */
GridLayout layout = new GridLayout();
layout.numColumns = 1;
layout.verticalSpacing = 2;
layout.marginWidth = 0;
layout.marginHeight = 2;
parent.setLayout(layout);
createSearchBox(parent);
createTreeViewer(parent);
// Create menu, toolbars, filters, sorters.
createActions();
createMenus();
createToolbar();
hookListeners();
treeViewer.setInput(getInitalContainer());
int ops = DND.DROP_COPY | DND.DROP_MOVE;
Transfer[] transfers = new Transfer[] { TextTransfer.getInstance()};
treeViewer.addDragSupport(ops, transfers, new GadgetDragListener(treeViewer));
}
private void createTreeViewer(Composite parent) {
// Create the tree viewer as a child of the composite parent
treeViewer = new TreeViewer(parent);
treeViewer.setAutoExpandLevel(TreeViewer.ALL_LEVELS);
contentProvider=new UIContainerContentProvider();
treeViewer.setContentProvider(contentProvider);
labelProvider = new UIContainerLabelProvider();
treeViewer.setLabelProvider(labelProvider);
// search filter
treeViewer.addFilter(new ViewerFilter(){
@Override
public boolean select(Viewer arg0, Object parentElement, Object element) {
if(element instanceof UIComponent){
UIComponent u = (UIComponent) element;
if(!searchMatches(u,searchBox.getText().toLowerCase())) {
return false;
}
}
return true;
}});
// visible filter
treeViewer.addFilter(new ViewerFilter(){
@Override
public boolean select(Viewer arg0, Object parentElement, Object element) {
if(element instanceof UIComponent){
UIComponent u = (UIComponent) element;
if(!u.isVisible() && !showHidden) {
return false;
}
}
return true;
}});
treeViewer.setUseHashlookup(true);
// tree viewer is greedy for space
GridData layoutData = new GridData();
layoutData.grabExcessHorizontalSpace = true;
layoutData.grabExcessVerticalSpace = true;
layoutData.horizontalAlignment = GridData.FILL;
layoutData.verticalAlignment = GridData.FILL;
treeViewer.getControl().setLayoutData(layoutData);
}
private void createSearchBox(Composite parent) {
Canvas searchBoxCanvas = new Canvas(parent, SWT.CENTER);
GridData layoutData = new GridData();
layoutData.grabExcessHorizontalSpace = true;
layoutData.horizontalAlignment = GridData.FILL;
searchBoxCanvas.setLayoutData(layoutData);
/* Create a grid layout object so the text and treeviewer
* are layed out the way I want. */
GridLayout layout = new GridLayout();
layout.numColumns = 2;
layout.marginWidth = 2;
layout.marginHeight = 2;
searchBoxCanvas.setLayout(layout);
Label searchLabel = new Label(searchBoxCanvas, SWT.RIGHT);
searchLabel.setText("Search:");
layoutData = new GridData();
layoutData.grabExcessHorizontalSpace = false;
layoutData.horizontalAlignment = GridData.FILL;
searchLabel.setLayoutData(layoutData);
searchBox = new Text(searchBoxCanvas, SWT.SINGLE | SWT.BORDER);
searchBox.setToolTipText("Search the tree for any text");
searchBox.addModifyListener(new ModifyListener(){
@Override
public void modifyText(ModifyEvent arg0) {
searchMatches.clear();
treeViewer.refresh();
treeViewer.expandAll();
}
});
layoutData = new GridData();
layoutData.grabExcessHorizontalSpace = true;
layoutData.horizontalAlignment = GridData.FILL;
searchBox.setLayoutData(layoutData);
}
private boolean searchMatches(UIComponent u, String searchString) {
if (searchMatches.contains(u)) {
return true;
}
if (u.getLabelString().toLowerCase().contains(searchString)) {
searchMatches.add(u);
if (u instanceof UIContainer) {
// keep all descendants of a matching node
addDescendantsToSearchMatches((UIContainer)u);
}
return true;
} else if (u instanceof UIContainer) {
for (UIComponent child : ((UIContainer)u).getChildren()) {
if (searchMatches(child, searchString)) {
return true;
}
}
}
return false;
}
private void addDescendantsToSearchMatches(UIContainer u) {
for (UIComponent c : u.getChildren()) {
if (!searchMatches.contains(c)) {
searchMatches.add(c);
}
if (c instanceof UIContainer) {
addDescendantsToSearchMatches((UIContainer)c);
}
}
}
protected void hookListeners() {
treeViewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(SelectionChangedEvent event) {
// if the selection is empty clear the label
// if(event.getSelection().isEmpty()) {
// text.setText("");
// return;
// }
if(event.getSelection() instanceof IStructuredSelection) {
IStructuredSelection selection = (IStructuredSelection)event.getSelection();
StringBuffer toShow = new StringBuffer();
for (Iterator iterator = selection.iterator(); iterator.hasNext();) {
Object domain = (Model) iterator.next();
String value = labelProvider.getText(domain);
toShow.append(value);
toShow.append(", ");
}
// remove the trailing comma space pair
if(toShow.length() > 0) {
toShow.setLength(toShow.length() - 2);
}
//text.setText(toShow.toString());
}
}
});
}
Action expandAll = null;
Action collapseAll = null;
Action toggleVisible = null;
Action treeRefresh = null;
protected void createActions() {
expandAll = new Action() {
public void run() {
treeViewer.expandAll();
}
};
expandAll.setText("Expand all");
expandAll.setToolTipText("Expand all items in this tree");
expandAll.setImageDescriptor(MonkeyTalkImagesEnum.EXPANDALL.image);
expandAll.setId("expandall");
collapseAll = new Action() {
public void run() {
treeViewer.collapseAll();
}
};
collapseAll.setText("Collapse all");
collapseAll.setToolTipText("Collapse all items in this tree");
collapseAll.setImageDescriptor(MonkeyTalkImagesEnum.COLLAPSEALL.image);
collapseAll.setId("collapseall");
toggleVisible = new Action() {
public void run() {
toggleVisible.setChecked(!toggleVisible.isChecked());
showHidden = !showHidden;
treeViewer.refresh();
treeViewer.expandAll();
setToggleVisibleState();
}
};
toggleVisible.setId("toggleVis");
setToggleVisibleState();
treeRefresh = new Action() {
public void run() {
FoneMonkeyPlugin.getDefault().getController().fetchAndShowComponentTree();
treeViewer.refresh();
treeViewer.expandAll();
}
};
treeRefresh.setText("Tree Refresh");
treeRefresh.setToolTipText("Refresh the component tree from the app");
treeRefresh.setImageDescriptor(MonkeyTalkImagesEnum.TREEREFRESH.image);
treeRefresh.setId("treeRefresh");
}
protected void setToggleVisibleState() {
if (showHidden) {
toggleVisible.setText("Hide Hidden Components");
toggleVisible.setToolTipText("Hide hidden components");
toggleVisible.setImageDescriptor(MonkeyTalkImagesEnum.EYE.image);
} else {
toggleVisible.setText("Show Hidden Components");
toggleVisible.setToolTipText("Show hidden components");
toggleVisible.setImageDescriptor(MonkeyTalkImagesEnum.EYENO.image);
}
}
protected void createMenus() {
IMenuManager rootMenuManager = getViewSite().getActionBars().getMenuManager();
rootMenuManager.setRemoveAllWhenShown(true);
}
protected void createToolbar() {
IToolBarManager toolbarManager = getViewSite().getActionBars().getToolBarManager();
toolbarManager.add(expandAll);
toolbarManager.add(collapseAll);
toolbarManager.add(toggleVisible);
toolbarManager.add(treeRefresh);
}
public void setInput(JSONObject jasonData) throws JSONException{
if(jasonData == null) return;
root = this.getInitalContainer();
JSONArray ja = new JSONArray();
ja.put(jasonData.getJSONObject("message"));
root = convertJsonArrayToBoxes(ja, root);
treeViewer.setInput(root);
}
public UIContainer convertJsonArrayToBoxes(JSONArray jsonArray, UIContainer root) throws JSONException{
for(int i = 0; i < jsonArray.length(); i++){
JSONObject rootNode = jsonArray.getJSONObject(i);
String title=formatTitle(rootNode);
boolean isVisible=isVisible(rootNode);
if(rootNode.has("children") && rootNode.getJSONArray("children").length() > 0) {
// String title=rootNode.getString("ComponentType") + "(" +rootNode.getString("monkeyId")+")";
UIContainer parent = new UIContainer(title, isVisible);
root.add(parent);
convertJsonArrayToBoxes(rootNode.getJSONArray("children"),parent);
} else {
root.add(new UIComponent(title, isVisible));
}
}
return root;
}
protected boolean isVisible(JSONObject json) throws JSONException {
boolean isVisible=true;
if(json.has("visible")) {
String viz=json.getString("visible");
isVisible = (viz!=null && viz.contains("t"));
}
return isVisible;
}
private String formatTitle(JSONObject rootNode) throws JSONException {
String componentType = rootNode.has("ComponentType") ? rootNode.getString("ComponentType") : "View";
String monkeyId = "";
if (rootNode.has("monkeyId")) {
String mid = rootNode.getString("monkeyId");
if (!mid.toCharArray().equals("null")) {
monkeyId = mid.replace("\n", "\\n");
}
}
String vizability = "";
if(rootNode.has("visible")) {
String viz=rootNode.getString("visible");
vizability = (viz!=null && viz.contains("t")) ? "visible" : "hidden";
}
String identifiers = "";
if (rootNode.has("identifiers")) {
identifiers=formatIdentifiers(rootNode.getJSONArray("identifiers"), monkeyId);
}
String ordinal = "";
if (rootNode.has("ordinal")) {
Object o = rootNode.get("ordinal");
if (o instanceof String) {
ordinal = (String)o;
} else if (o instanceof Integer) {
Integer ord = (Integer)o;
if (ord > 0) {
ordinal = " #" + (Integer)o;
}
}
}
String title=componentType
+ ordinal
+ " ("
+ monkeyId
+ ") "
+ identifiers
+ " " + rootNode.getString("className")
+ " " + vizability;
return title;
}
private String formatIdentifiers(JSONArray identifiersJson, String monkeyId) throws JSONException {
StringBuilder sb=new StringBuilder();
for (int j=0; j<identifiersJson.length(); j++) {
String identifier = identifiersJson.getString(j);
if (identifier!=null && identifier.length()>0 && !identifier.equals(monkeyId)) {
if (sb.indexOf(identifier)==-1) {
if (sb.length()==0) {
sb.append("[");
} else {
sb.append(", ");
}
sb.append(identifier.replace("\n","\\n"));
}
}
}
if (sb.length()>0) {
sb.append("]");
}
return sb.toString();
}
private UIContainer getInitalContainer() {
root = new UIContainer("root", true);
return root;
}
/*
* @see IWorkbenchPart#setFocus()
*/
public void setFocus() {}
@Override
public void treeCollapsed(TreeExpansionEvent arg0) {
}
@Override
public void treeExpanded(TreeExpansionEvent arg0) {
}
}