/*
* Copyright (c) 2012, the Dart project authors.
*
* Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except
* in compliance with the License. You may obtain a copy of the License at
*
* http://www.eclipse.org/legal/epl-v10.html
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package com.google.dart.tools.debug.ui.internal;
import com.google.dart.tools.core.DartCore;
import com.google.dart.tools.core.mobile.MobileUrlConnectionException;
import com.google.dart.tools.debug.core.DartDebugCorePlugin;
import com.google.dart.tools.debug.core.DebugUIHelper;
import com.google.dart.tools.debug.core.dartium.DartiumDebugTarget;
import com.google.dart.tools.debug.ui.internal.dartium.DevToolsDisconnectManager;
import com.google.dart.tools.debug.ui.internal.dialogs.MobilePortForwardDialog;
import com.google.dart.tools.debug.ui.internal.util.LaunchUtils;
import com.google.dart.tools.debug.ui.internal.view.DebuggerView;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IViewPart;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* A helper to allow non-UI code to interact with the UI.
*/
public class DefaultDebugUIHelper extends DebugUIHelper {
@Override
public void activateApplication(File application, String name) {
if (DartCore.isMac()) {
activateApplicationMacOS(application);
} else if (DartCore.isWindows()) {
bringWindowToFrontWin32(".*" + name + "\\z");
} else if (DartCore.isLinux()) {
// This is not necessary on Linux.
}
}
@Override
public void handleDevtoolsDisconnect(DartiumDebugTarget target) {
// Create a new manager for this specific disconnect.
new DevToolsDisconnectManager(target);
}
@Override
public void openBrowserTab(String url) {
try {
LaunchUtils.openBrowser(url);
} catch (CoreException e) {
showError("Open Browser", e.getMessage());
}
}
@Override
public void showError(String title, CoreException e) {
// Detect mobile launch port forwarding problems
// and present user with more specific dialog to help fix them fix the problem
if (e instanceof MobileUrlConnectionException) {
final String pageUrl = ((MobileUrlConnectionException) e).getPageUrl();
final boolean localhostOverUsb = ((MobileUrlConnectionException) e).isLocalhostOverUsb();
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
new MobilePortForwardDialog(shell, pageUrl, localhostOverUsb).open();
}
});
return;
}
showError(title, e.getMessage());
}
@Override
public void showError(final String title, final String message) {
final Display display = Display.getDefault();
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
if (display.isDisposed()) {
return;
}
Shell shell = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell();
MessageDialog.openError(shell, title, message);
}
});
}
@Override
public void showStatusLineMessage(final String message) {
final Display display = Display.getDefault();
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
if (display.isDisposed()) {
return;
}
IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage();
IViewPart part = page.findView(DebuggerView.ID);
if (part != null) {
IStatusLineManager manager = part.getViewSite().getActionBars().getStatusLineManager();
manager.setMessage(message);
}
}
});
}
protected void activateApplicationMacOS(File app) {
String appleScript = "tell application \"" + app.getName() + "\" to activate";
ProcessBuilder builder = new ProcessBuilder("osascript", "-e", appleScript);
try {
builder.start();
} catch (IOException e) {
DartDebugCorePlugin.logError(e);
}
}
protected void bringWindowToFrontWin32(final String regex) {
Display.getDefault().asyncExec(new Runnable() {
@Override
public void run() {
try {
bringWindowToFrontWin32_impl(regex);
} catch (Exception e) {
DartDebugCorePlugin.logError(e);
}
}
});
}
private void bringWindowToFrontWin32_impl(String regex) throws Exception {
final int GW_HWNDNEXT = 0x2;
Pattern pattern = Pattern.compile(regex);
Number window = OS_GetActiveWindow();
while (window.longValue() != 0) {
int textLength = OS_GetWindowTextLength(window);
if (textLength > 0) {
String str = OS_GetWindowText(window, textLength);
Matcher matcher = pattern.matcher(str);
if (matcher.matches()) {
OS_BringWindowToTop(window);
return;
}
}
window = OS_GetWindow(window, GW_HWNDNEXT);
}
}
private Class<?> getOSClass() throws ClassNotFoundException {
return Class.forName("org.eclipse.swt.internal.win32.OS");
}
private void OS_BringWindowToTop(Number window) throws Exception {
if (window instanceof Integer) {
Method method = getOSClass().getMethod("BringWindowToTop", int.class);
method.invoke(null, window.intValue());
} else {
Method method = getOSClass().getMethod("BringWindowToTop", long.class);
method.invoke(null, window.longValue());
}
}
private Number OS_GetActiveWindow() throws Exception {
return (Number) getOSClass().getMethod("GetActiveWindow").invoke(null);
}
private Number OS_GetWindow(Number window, int direction) throws Exception {
if (window instanceof Integer) {
Method method = getOSClass().getMethod("GetWindow", int.class, int.class);
return (Number) method.invoke(null, window.intValue(), direction);
} else {
Method method = getOSClass().getMethod("GetWindow", long.class, int.class);
return (Number) method.invoke(null, window.longValue(), direction);
}
}
private String OS_GetWindowText(Number window, int textLength) throws Exception {
Class<?> tcharClass = Class.forName("org.eclipse.swt.internal.win32.TCHAR");
Constructor<?> tcharCtor = tcharClass.getConstructor(int.class, int.class);
Object tchar = tcharCtor.newInstance(0, textLength + 2);
if (window instanceof Integer) {
Method method = getOSClass().getMethod("GetWindowText", int.class, tcharClass, int.class);
method.invoke(null, window.intValue(), tchar, textLength + 1);
} else {
Method method = getOSClass().getMethod("GetWindowText", long.class, tcharClass, int.class);
method.invoke(null, window.longValue(), tchar, textLength + 1);
}
Method tcharToString = tcharClass.getMethod("toString", int.class, int.class);
return (String) tcharToString.invoke(tchar, 0, textLength);
}
private int OS_GetWindowTextLength(Number window) throws Exception {
if (window instanceof Integer) {
Method method = getOSClass().getMethod("GetWindowTextLength", int.class);
return (Integer) method.invoke(null, window.intValue());
} else {
Method method = getOSClass().getMethod("GetWindowTextLength", long.class);
return (Integer) method.invoke(null, window.longValue());
}
}
}