org.chromium.debug.ui/src/org/chromium/debug/ui/actions/JsInspectSnippetAction.java
changeset 2 e4420d2515f1
child 52 f577ea64429e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/org.chromium.debug.ui/src/org/chromium/debug/ui/actions/JsInspectSnippetAction.java	Wed Dec 23 17:13:18 2009 -0800
@@ -0,0 +1,283 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.debug.ui.actions;
+
+import org.chromium.debug.core.model.StackFrame;
+import org.chromium.debug.ui.ChromiumDebugUIPlugin;
+import org.chromium.debug.ui.JsEvalContextManager;
+import org.chromium.debug.ui.editors.JavascriptUtil;
+import org.chromium.sdk.CallFrame;
+import org.chromium.sdk.JsVariable;
+import org.eclipse.debug.core.model.IExpression;
+import org.eclipse.debug.ui.DebugPopup;
+import org.eclipse.debug.ui.InspectPopupDialog;
+import org.eclipse.jface.action.IAction;
+import org.eclipse.jface.text.ITextSelection;
+import org.eclipse.jface.text.ITextViewer;
+import org.eclipse.jface.viewers.ISelection;
+import org.eclipse.jface.viewers.ISelectionProvider;
+import org.eclipse.swt.custom.StyledText;
+import org.eclipse.swt.graphics.GC;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Control;
+import org.eclipse.swt.widgets.Shell;
+import org.eclipse.ui.IEditorActionDelegate;
+import org.eclipse.ui.IEditorPart;
+import org.eclipse.ui.IPartListener;
+import org.eclipse.ui.IViewActionDelegate;
+import org.eclipse.ui.IViewPart;
+import org.eclipse.ui.IWorkbenchPage;
+import org.eclipse.ui.IWorkbenchPart;
+import org.eclipse.ui.IWorkbenchWindow;
+import org.eclipse.ui.IWorkbenchWindowActionDelegate;
+import org.eclipse.ui.texteditor.ITextEditor;
+
+/**
+ * Action for inspecting a JavaScript snippet.
+ */
+public class JsInspectSnippetAction implements IEditorActionDelegate,
+    IWorkbenchWindowActionDelegate, IPartListener, IViewActionDelegate, CallFrame.EvaluateCallback {
+
+  private static final String ACTION_DEFINITION_ID = "org.chromium.debug.ui.commands.Inspect"; //$NON-NLS-1$
+
+  private IWorkbenchWindow window;
+
+  private IWorkbenchPart targetPart;
+
+  private IAction action;
+
+  private String selectedText;
+
+  private IExpression expression;
+
+  private ITextEditor textEditor;
+
+  private ISelection originalSelection;
+
+  public void setActiveEditor(IAction action, IEditorPart targetEditor) {
+    this.action = action;
+    setTargetPart(targetEditor);
+  }
+
+  public void run(IAction action) {
+    updateAction();
+    run();
+  }
+
+  public void selectionChanged(IAction action, ISelection selection) {
+    this.action = action;
+  }
+
+  public void dispose() {
+    IWorkbenchWindow win = getWindow();
+    if (win != null) {
+      win.getPartService().removePartListener(this);
+    }
+  }
+
+  private IWorkbenchWindow getWindow() {
+    return window;
+  }
+
+  public void init(IWorkbenchWindow window) {
+    this.window = window;
+    IWorkbenchPage page = window.getActivePage();
+    if (page != null) {
+      setTargetPart(page.getActivePart());
+    }
+    window.getPartService().addPartListener(this);
+  }
+
+  public void partActivated(IWorkbenchPart part) {
+    setTargetPart(part);
+  }
+
+  public void partBroughtToTop(IWorkbenchPart part) {
+
+  }
+
+  public void partClosed(IWorkbenchPart part) {
+    if (part == getTargetPart()) {
+      setTargetPart(null);
+    }
+  }
+
+  private IWorkbenchPart getTargetPart() {
+    return targetPart;
+  }
+
+  public void partDeactivated(IWorkbenchPart part) {
+  }
+
+  public void partOpened(IWorkbenchPart part) {
+  }
+
+  private void setTargetPart(IWorkbenchPart part) {
+    this.targetPart = part;
+  }
+
+  public void init(IViewPart view) {
+    setTargetPart(view);
+  }
+
+  private void updateAction() {
+    if (action != null) {
+      retrieveSelection();
+    }
+  }
+
+  protected ISelection getTargetSelection() {
+    IWorkbenchPart part = getTargetPart();
+    if (part != null) {
+      ISelectionProvider provider = part.getSite().getSelectionProvider();
+      if (provider != null) {
+        return provider.getSelection();
+      }
+    }
+    return null;
+  }
+
+  private StackFrame getStackFrameContext() {
+    IWorkbenchPart part = getTargetPart();
+    return getStackFrameForPart(part);
+  }
+
+  private StackFrame getStackFrameForPart(IWorkbenchPart part) {
+    StackFrame frame = part == null
+        ? JsEvalContextManager.getStackFrameFor(getWindow())
+        : JsEvalContextManager.getStackFrameFor(part);
+    return frame;
+  }
+
+  private void run() {
+    getStackFrameContext().getCallFrame().evaluateAsync(getSelectedText(), this, null);
+  }
+
+  protected String getSelectedText() {
+    return selectedText;
+  }
+
+  protected Shell getShell() {
+    if (getTargetPart() != null) {
+      return getTargetPart().getSite().getShell();
+    }
+    return ChromiumDebugUIPlugin.getActiveWorkbenchShell();
+  }
+
+  private void retrieveSelection() {
+    ISelection targetSelection = getTargetSelection();
+    if (targetSelection instanceof ITextSelection) {
+      ITextSelection ts = (ITextSelection) targetSelection;
+      String text = ts.getText();
+      if (textHasContent(text)) {
+        selectedText = text;
+      } else if (getTargetPart() instanceof IEditorPart) {
+        IEditorPart editor = (IEditorPart) getTargetPart();
+        if (editor instanceof ITextEditor) {
+          selectedText = extractSurroundingWord(ts, (ITextEditor) editor);
+        }
+      }
+    }
+  }
+
+  private String extractSurroundingWord(ITextSelection targetSelection, ITextEditor editor) {
+    return JavascriptUtil.extractSurroundingJsIdentifier(
+        editor.getDocumentProvider().getDocument(editor.getEditorInput()),
+        targetSelection.getOffset());
+  }
+
+  private boolean textHasContent(String text) {
+    return text != null && JavascriptUtil.ID_PATTERN.matcher(text).find();
+  }
+
+  public void success(JsVariable var) {
+    if (ChromiumDebugUIPlugin.getDefault() == null) {
+      return;
+    }
+    if (var != null) {
+      if (ChromiumDebugUIPlugin.getDisplay().isDisposed()) {
+        return;
+      }
+      displayResult(var, null);
+    }
+  }
+
+  public void failure(String errorMessage) {
+    displayResult(null, errorMessage);
+  }
+
+  protected void displayResult(final JsVariable var, String errorMessage) {
+    IWorkbenchPart part = getTargetPart();
+    final StyledText styledText = getStyledText(part);
+    if (styledText == null) {
+      return; // TODO(apavlov): fix this when adding inspected variables
+    } else {
+      expression = new JsInspectExpression(getStackFrameContext(), selectedText, var, errorMessage);
+      ChromiumDebugUIPlugin.getDisplay().asyncExec(new Runnable() {
+        public void run() {
+          showPopup(styledText);
+        }
+      });
+    }
+  }
+
+  protected void showPopup(StyledText textWidget) {
+    IWorkbenchPart part = getTargetPart();
+    if (part instanceof ITextEditor) {
+      textEditor = (ITextEditor) part;
+      originalSelection = getTargetSelection();
+    }
+    DebugPopup displayPopup =
+        new InspectPopupDialog(getShell(), getPopupAnchor(textWidget), ACTION_DEFINITION_ID,
+            expression) {
+          @Override
+          public boolean close() {
+            boolean returnValue = super.close();
+            if (textEditor != null && originalSelection != null) {
+              textEditor.getSelectionProvider().setSelection(originalSelection);
+              textEditor = null;
+              originalSelection = null;
+            }
+            return returnValue;
+          }
+        };
+    displayPopup.open();
+  }
+
+  private StyledText getStyledText(IWorkbenchPart part) {
+    ITextViewer viewer = (ITextViewer) part.getAdapter(ITextViewer.class);
+    StyledText textWidget = null;
+    if (viewer == null) {
+      Control control = (Control) part.getAdapter(Control.class);
+      if (control instanceof StyledText) {
+        textWidget = (StyledText) control;
+      }
+    } else {
+      textWidget = viewer.getTextWidget();
+    }
+    return textWidget;
+  }
+
+  private static Point getPopupAnchor(StyledText textWidget) {
+    if (textWidget != null) {
+      Point docRange = textWidget.getSelectionRange();
+      int midOffset = docRange.x + (docRange.y / 2);
+      Point point = textWidget.getLocationAtOffset(midOffset);
+      point = textWidget.toDisplay(point);
+      point.y += getFontHeight(textWidget);
+      return point;
+    }
+    return null;
+  }
+
+  private static int getFontHeight(StyledText textWidget) {
+    GC gc = new GC(textWidget);
+    gc.setFont(textWidget.getFont());
+    int height = gc.getFontMetrics().getHeight();
+    gc.dispose();
+    return height;
+  }
+
+}