/******************************************************************************* * Copyright (c) 2016, 2017 xored software, Inc. 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: * xored software, Inc. - initial API and implementation *******************************************************************************/ package org.eclipse.dltk.tcl.internal.debug.ui; import java.util.Collections; import java.util.Iterator; import java.util.List; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.debug.core.DebugPlugin; import org.eclipse.debug.core.model.IBreakpoint; import org.eclipse.dltk.core.IField; import org.eclipse.dltk.core.ISourceRange; import org.eclipse.dltk.debug.core.model.IScriptVariable; import org.eclipse.dltk.debug.core.model.IScriptWatchpoint; import org.eclipse.dltk.debug.ui.DLTKDebugUIPlugin; import org.eclipse.dltk.debug.ui.actions.ActionMessages; import org.eclipse.dltk.debug.ui.breakpoints.BreakpointUtils; import org.eclipse.dltk.debug.ui.breakpoints.IScriptBreakpointLineValidator; import org.eclipse.dltk.debug.ui.breakpoints.Messages; import org.eclipse.dltk.debug.ui.breakpoints.ScriptBreakpointLineValidatorFactory; import org.eclipse.dltk.debug.ui.breakpoints.ScriptToggleBreakpointAdapter; import org.eclipse.dltk.internal.debug.core.model.ScriptWatchpoint; import org.eclipse.dltk.internal.ui.text.ScriptWordFinder; import org.eclipse.dltk.tcl.internal.debug.TclDebugConstants; import org.eclipse.dltk.tcl.internal.debug.ui.actions.IToggleSpawnpointsTarget; import org.eclipse.jface.text.BadLocationException; import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextSelection; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.window.Window; import org.eclipse.osgi.util.NLS; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.texteditor.IDocumentProvider; import org.eclipse.ui.texteditor.ITextEditor; public class TclToggleBreakpointAdapter extends ScriptToggleBreakpointAdapter implements IToggleSpawnpointsTarget { private static final IScriptBreakpointLineValidator validator = ScriptBreakpointLineValidatorFactory .createNonEmptyNoCommentValidator("#"); //$NON-NLS-1$ @Override protected String getDebugModelId() { return TclDebugConstants.DEBUG_MODEL_ID; } @Override protected IScriptBreakpointLineValidator getValidator() { return validator; } @Override public void toggleMethodBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException { // Not implemented for TCL yet } @Override public boolean canToggleMethodBreakpoints(IWorkbenchPart part, ISelection selection) { return false; } @Override public boolean canToggleWatchpoints(IWorkbenchPart part, ISelection selection) { if (isRemote(part, selection)) { return false; } if (selection instanceof IStructuredSelection) { IStructuredSelection ss = (IStructuredSelection) selection; return isFields(ss); } return selection instanceof ITextSelection; } @Override public void toggleWatchpoints(final IWorkbenchPart part, final ISelection finalSelection) throws CoreException { report(null, part); ISelection selection = finalSelection; int lineNumber = -1; IResource resource = ResourcesPlugin.getWorkspace().getRoot(); IBreakpoint[] breakpoints = DebugPlugin.getDefault().getBreakpointManager().getBreakpoints(getDebugModelId()); if (selection instanceof ITextSelection && part instanceof ITextEditor) { // one based line number lineNumber = ((ITextSelection) selection).getStartLine() + 1; resource = BreakpointUtils.getBreakpointResource((ITextEditor) part); } List<?> fields; if (selection instanceof IStructuredSelection) { fields = getFields((IStructuredSelection) selection); } else { ISelection newSelection = translateToMembers(part, selection); if (newSelection instanceof IStructuredSelection) { fields = getFields((IStructuredSelection) newSelection); } else { fields = Collections.EMPTY_LIST; } } if (fields.isEmpty() && selection instanceof ITextSelection) { ITextEditor textEditor = getTextEditor(part); if (textEditor != null) { IEditorInput editorInput = textEditor.getEditorInput(); IDocumentProvider documentProvider = textEditor.getDocumentProvider(); if (documentProvider != null) { IDocument document = documentProvider.getDocument(editorInput); IRegion reg = ScriptWordFinder.findWord(document, ((ITextSelection) selection).getOffset()); final TclAddWatchpointDialog dialog = new TclAddWatchpointDialog(part.getSite().getShell()); try { dialog.setExpression(document.get(reg.getOffset(), reg.getLength())); } catch (BadLocationException e) { // ignore } if (dialog.open() != Window.OK) { return; } fields = Collections.singletonList(dialog.getExpression()); } } } if (fields.isEmpty()) { report(ActionMessages.ToggleBreakpointAdapter_10, part); return; } for (Iterator<?> i = fields.iterator(); i.hasNext();) { final Object element = i.next(); int start = -1; int end = -1; final String watchExpression; if (element instanceof IField) { final IField field = (IField) element; final ISourceRange range = field.getNameRange(); start = range.getOffset(); end = range.getOffset() + range.getLength(); watchExpression = field.getElementName(); } else if (element instanceof IScriptVariable) { watchExpression = ((IScriptVariable) element).getName(); } else if (element instanceof String) { watchExpression = element.toString(); } else { continue; } boolean found = false; for (int j = 0; j < breakpoints.length; j++) { final IBreakpoint breakpoint = breakpoints[j]; if (breakpoint instanceof IScriptWatchpoint && breakpoint.getMarker() != null && resource.equals(breakpoint.getMarker().getResource())) { IScriptWatchpoint wp = (IScriptWatchpoint) breakpoint; if (wp.getLineNumber() == lineNumber && watchExpression.equals(wp.getFieldName())) { // delete existing breakpoint breakpoint.delete(); found = true; } } } if (!found) { new ScriptWatchpoint(getDebugModelId(), resource, resource.getType() == IResource.FILE ? resource.getLocation() : null, lineNumber, start, end, watchExpression); } } } @Override public void toggleBreakpoints(IWorkbenchPart part, ISelection selection) throws CoreException { toggleLineBreakpoints(part, selection); } @Override public boolean canToggleBreakpoints(IWorkbenchPart part, ISelection selection) { return canToggleLineBreakpoints(part, selection); } @Override public boolean canToggleSpawnpoints(IWorkbenchPart part, ITextSelection selection) { if (isRemote(part, selection)) { return false; } return true; } @Override public void toggleSpawnpoints(final IWorkbenchPart part, final ITextSelection selection) throws CoreException { Job job = new Job("Script Toggle Spawnpoint") { //$NON-NLS-1$ @Override protected IStatus run(IProgressMonitor monitor) { final ITextEditor editor = getTextEditor(part); if (editor != null) { if (monitor.isCanceled()) { return Status.CANCEL_STATUS; } try { report(null, part); int lineNumber = selection.getStartLine() + 1; final IBreakpoint breakpoint = BreakpointUtils.findLineBreakpoint(editor, lineNumber); if (breakpoint != null) { // if breakpoint already exists, delete it breakpoint.delete(); } else { final IDocumentProvider documentProvider = editor.getDocumentProvider(); if (documentProvider == null) { return Status.CANCEL_STATUS; } final IDocument document = documentProvider.getDocument(editor.getEditorInput()); lineNumber = findBreakpointLine(document, lineNumber - 1, getValidator()) + 1; if (lineNumber != BREAKPOINT_LINE_NOT_FOUND) { // Check if already breakpoint set to the same // location if (BreakpointUtils.findLineBreakpoint(editor, lineNumber) == null) { BreakpointUtils.addSpawnpoint(editor, lineNumber); } else { final String template = Messages.ScriptToggleBreakpointAdapter_breakpointAlreadySetAtLine; report(NLS.bind(template, Integer.toString(lineNumber)), part); } } else { report(Messages.ScriptToggleBreakpointAdapter_invalidBreakpointPosition, part); } } } catch (CoreException e) { DLTKDebugUIPlugin.log(e); } } return Status.OK_STATUS; } }; job.setSystem(true); job.schedule(); } }