package com.yoursway.swt.inspector;
import static com.google.common.base.Join.join;
import static com.google.common.collect.Lists.newArrayList;
import static com.yoursway.utils.DebugOutputHelper.simpleNameOf;
import static java.lang.String.format;
import java.lang.reflect.Field;
import java.util.List;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Widget;
public class SwtInspectorController implements SwtInspectorViewCallback {
private final SwtInspectorView view;
private final Display display;
private final SwtInspectorModel model;
static final int KEYED_DATA = 1 << 2;
private static final int MASK = SWT.ALT | SWT.SHIFT;
private final Listener controlHighlightListener = new Listener() {
public void handleEvent(Event event) {
switch (event.type) {
case SWT.MouseMove:
if ((event.stateMask & MASK) == MASK) {
turnOffTracking();
event.doit = false;
return;
}
highlightActiveControl(event.widget);
break;
case SWT.MouseExit:
if (event.widget instanceof Control)
controlHightlightView.removeHightlight((Control) event.widget);
break;
case SWT.MouseDown:
if ((event.stateMask & MASK) == MASK && event.button == 1) {
turnOffTracking();
event.doit = false;
}
break;
}
}
};
private final ControlHightlightView controlHightlightView;
private final ControlRegistry controlRegistry;
public SwtInspectorController(Display display, SwtInspectorViewFactory factory,
ControlRegistry controlRegistry) {
if (display == null)
throw new NullPointerException("display is null");
if (controlRegistry == null)
throw new NullPointerException("controlRegistry is null");
this.display = display;
this.controlRegistry = controlRegistry;
model = new SwtInspectorModel();
model.highlightControls = true;
controlHightlightView = new ControlHightlightView(display);
view = factory.createView(this, model);
view.setMessageToWelcome();
turnOnTracking();
}
void highlightActiveControl(Widget widget) {
if (!model.highlightControls)
return;
if (!(widget instanceof Control))
return;
Control control = (Control) widget;
controlHightlightView.highlight(control);
StringBuilder builder = new StringBuilder();
int depth = 0;
while (control != null) {
if (depth > 0)
builder.append("\n--------------------------------------------\n");
describeControl(control, depth, builder);
control = control.getParent();
depth += 1;
}
view.setMessage(builder.toString());
}
private void describeControl(Control control, int depth, StringBuilder result) {
ControlDescriptor descriptor = controlRegistry.lookup(control.getClass());
appendName(control, depth, result, descriptor);
appendStyles(control, result, descriptor);
appendNewLine(result);
if (control instanceof Composite) {
appendLayout(result, ((Composite) control).getLayout());
}
appendLayoutData(control, result);
appendNewLine(result);
result.append(format("Size: %dx%d\n", control.getSize().x, control.getSize().y));
appendUserData(control, result);
}
private void appendUserData(Control control, StringBuilder result) {
String objectDataDescription;
try {
Field dataField = Widget.class.getDeclaredField("data");
Field stateField = Widget.class.getDeclaredField("state");
dataField.setAccessible(true);
stateField.setAccessible(true);
Object data = dataField.get(control);
int state = (Integer) stateField.get(control);
List<String> dataItems = newArrayList();
if ((state & KEYED_DATA) == KEYED_DATA) {
Object[] pairs = (Object[]) data;
for (int i = 1; i < pairs.length; i += 2)
dataItems.add(format("%s (%s)", pairs[i], simpleNameOf(pairs[i + 1])));
data = pairs[0];
}
if (data != null)
dataItems.add(0, format("unnamed (%s)", simpleNameOf(data)));
objectDataDescription = join(", ", dataItems);
} catch (Throwable e) {
e.printStackTrace();
objectDataDescription = "**failed to obtain key/value data**";
Object data = control.getData();
if (data != null)
objectDataDescription = format("unnamed (%s) ", simpleNameOf(data)) + objectDataDescription;
}
if (objectDataDescription.length() != 0) {
appendNewLine(result);
result.append(format("User data keys: %s", objectDataDescription));
}
}
private void appendLayoutData(Control control, StringBuilder result) {
result.append(format("Layout data: %s\n", control.getLayoutData()));
}
private void appendLayout(StringBuilder result, Layout layout) {
result
.append(format("Layout: %s\n",
(layout == null ? "(none)" : layout.getClass().getSimpleName())));
if (layout != null)
result.append(format("Layout.toString: %s\n", layout));
}
private void appendNewLine(StringBuilder result) {
result.append("\n");
}
private void appendName(Control control, int depth, StringBuilder result, ControlDescriptor descriptor) {
String controlDesignator = depth == 0 ? "Control" : "Parent " + depth;
result.append(format("%s: %s\n", controlDesignator, descriptor.name(control)));
}
private void appendStyles(Control control, StringBuilder result, ControlDescriptor descriptor) {
appendStyles(control, descriptor, "Specific styles", true, result);
for (ControlDescriptor d = descriptor.baseDescriptor(); d != null; d = d.baseDescriptor())
appendStyles(control, d, d.className() + " styles", false, result);
}
private void appendStyles(Control control, ControlDescriptor descriptor, String message, boolean force,
StringBuilder result) {
String styles = join(", ", descriptor.stylesOf(control));
if (styles.length() == 0 && !force)
return;
result.append(format("%s: %s\n", message, (styles.length() == 0 ? "(none)" : styles)));
}
public void show() {
view.open();
}
public void viewClosed() {
turnOffTracking();
}
public void setHighlightControls(boolean enable) {
if (enable == model.highlightControls)
return;
if (enable)
turnOnTracking();
else {
turnOffTracking();
view.setMessageToWelcome();
}
}
private void turnOnTracking() {
model.highlightControls = true;
display.addFilter(SWT.MouseMove, controlHighlightListener);
display.addFilter(SWT.MouseExit, controlHighlightListener);
display.addFilter(SWT.MouseDown, controlHighlightListener);
view.update();
}
protected void turnOffTracking() {
model.highlightControls = false;
display.removeFilter(SWT.MouseMove, controlHighlightListener);
display.removeFilter(SWT.MouseExit, controlHighlightListener);
display.removeFilter(SWT.MouseDown, controlHighlightListener);
controlHightlightView.dehighlight();
view.update();
}
}