| /******************************************************************************* |
| * Copyright (c) 2009, 2017 IBM Corporation 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: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| package org.eclipse.jdt.debug.ui.breakpoints; |
| |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.Stack; |
| import java.util.regex.Pattern; |
| |
| import org.eclipse.core.commands.AbstractHandler; |
| import org.eclipse.core.commands.ExecutionEvent; |
| import org.eclipse.core.commands.IHandler; |
| import org.eclipse.core.commands.operations.IUndoContext; |
| import org.eclipse.core.resources.IMarker; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Status; |
| import org.eclipse.debug.internal.ui.SWTFactory; |
| import org.eclipse.jdt.core.IClassFile; |
| import org.eclipse.jdt.core.ICompilationUnit; |
| import org.eclipse.jdt.core.IField; |
| import org.eclipse.jdt.core.ISourceRange; |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.debug.core.IJavaLineBreakpoint; |
| import org.eclipse.jdt.debug.core.IJavaWatchpoint; |
| import org.eclipse.jdt.internal.debug.ui.BreakpointUtils; |
| import org.eclipse.jdt.internal.debug.ui.JDIDebugUIPlugin; |
| import org.eclipse.jdt.internal.debug.ui.JDISourceViewer; |
| import org.eclipse.jdt.internal.debug.ui.breakpoints.AbstractJavaBreakpointEditor; |
| import org.eclipse.jdt.internal.debug.ui.contentassist.IJavaDebugContentAssistContext; |
| import org.eclipse.jdt.internal.debug.ui.contentassist.JavaDebugContentAssistProcessor; |
| import org.eclipse.jdt.internal.debug.ui.contentassist.TypeContext; |
| import org.eclipse.jdt.internal.debug.ui.display.DisplayViewerConfiguration; |
| import org.eclipse.jdt.internal.debug.ui.propertypages.PropertyPageMessages; |
| import org.eclipse.jdt.ui.text.IJavaPartitions; |
| import org.eclipse.jface.action.IAction; |
| import org.eclipse.jface.dialogs.Dialog; |
| import org.eclipse.jface.dialogs.DialogSettings; |
| import org.eclipse.jface.dialogs.IDialogSettings; |
| import org.eclipse.jface.fieldassist.ControlDecoration; |
| import org.eclipse.jface.fieldassist.FieldDecoration; |
| import org.eclipse.jface.fieldassist.FieldDecorationRegistry; |
| import org.eclipse.jface.text.BadLocationException; |
| import org.eclipse.jface.text.Document; |
| import org.eclipse.jface.text.DocumentEvent; |
| import org.eclipse.jface.text.IDocument; |
| import org.eclipse.jface.text.IDocumentListener; |
| import org.eclipse.jface.text.ITextOperationTarget; |
| import org.eclipse.jface.text.ITextViewerExtension6; |
| import org.eclipse.jface.text.IUndoManager; |
| import org.eclipse.jface.text.IUndoManagerExtension; |
| import org.eclipse.jface.text.contentassist.IContentAssistProcessor; |
| import org.eclipse.jface.text.source.ISourceViewer; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.DisposeEvent; |
| import org.eclipse.swt.events.DisposeListener; |
| import org.eclipse.swt.events.FocusAdapter; |
| import org.eclipse.swt.events.FocusEvent; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.graphics.Color; |
| import org.eclipse.swt.graphics.FontMetrics; |
| import org.eclipse.swt.graphics.GC; |
| import org.eclipse.swt.graphics.Rectangle; |
| import org.eclipse.swt.layout.GridData; |
| import org.eclipse.swt.widgets.Button; |
| import org.eclipse.swt.widgets.Combo; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.ui.IPropertyListener; |
| import org.eclipse.ui.IViewSite; |
| import org.eclipse.ui.IWorkbenchCommandConstants; |
| import org.eclipse.ui.IWorkbenchPartSite; |
| import org.eclipse.ui.IWorkbenchWindow; |
| import org.eclipse.ui.PlatformUI; |
| import org.eclipse.ui.handlers.IHandlerActivation; |
| import org.eclipse.ui.handlers.IHandlerService; |
| import org.eclipse.ui.operations.OperationHistoryActionHandler; |
| import org.eclipse.ui.operations.RedoActionHandler; |
| import org.eclipse.ui.operations.UndoActionHandler; |
| import org.eclipse.ui.texteditor.IAbstractTextEditorHelpContextIds; |
| import org.eclipse.ui.texteditor.ITextEditorActionConstants; |
| import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; |
| |
| /** |
| * Controls to edit a breakpoint's conditional expression, condition enabled state, |
| * and suspend policy (suspend when condition is <code>true</code> or when the value of the |
| * conditional expression changes). |
| * <p> |
| * The controls are intended to be embedded in a composite provided by the client - for |
| * example, in a dialog. Clients must call {@link #createControl(Composite)} as the first |
| * life cycle method after instantiation. Clients may then call {@link #setInput(Object)} |
| * with the breakpoint object to be displayed/edited. Changes are not applied to the |
| * breakpoint until {@link #doSave()} is called. The method {@link #isDirty()} may be used |
| * to determine if any changes have been made in the editor, and {@link #getStatus()} may |
| * be used to determine if the editor settings are valid. Clients can register for |
| * property change notification ({@link #addPropertyListener(IPropertyListener)}). The editor |
| * will fire a property change each time a setting is modified. The same editor can be |
| * used to display different breakpoints by calling {@link #setInput(Object)} with different |
| * breakpoint objects. |
| * </p> |
| * |
| * @since 3.5 |
| */ |
| public final class JavaBreakpointConditionEditor extends AbstractJavaBreakpointEditor { |
| |
| private Button fConditional; |
| private Button fWhenTrue; |
| private Button fWhenChange; |
| |
| private JDISourceViewer fViewer; |
| private IContentAssistProcessor fCompletionProcessor; |
| private IJavaLineBreakpoint fBreakpoint; |
| private IHandlerService fHandlerService; |
| private IHandler fContentAssistHandler; |
| private IHandlerActivation fContentAssistActivation; |
| private IHandler fUndoHandler; |
| private IHandlerActivation fUndoActivation; |
| private IHandler fRedoHandler; |
| private IHandlerActivation fRedoActivation; |
| |
| private IDocumentListener fDocumentListener; |
| |
| private Combo fConditionHistory; |
| private IDialogSettings fConditionHistoryDialogSettings; |
| private boolean fReplaceConditionInHistory; |
| private Map<IJavaLineBreakpoint, Stack<String>> fLocalConditionHistory; |
| private int fSeparatorIndex; |
| |
| private IViewSite fBreakpointsViewSite; |
| private IAction fViewUndoAction; |
| private IAction fViewRedoAction; |
| private OperationHistoryActionHandler fViewerUndoAction; |
| private OperationHistoryActionHandler fViewerRedoAction; |
| |
| |
| /** |
| * Property id for breakpoint condition expression. |
| */ |
| public static final int PROP_CONDITION= 0x1001; |
| |
| /** |
| * Property id for breakpoint condition enabled state. |
| */ |
| public static final int PROP_CONDITION_ENABLED= 0x1002; |
| |
| /** |
| * Property id for breakpoint condition suspend policy. |
| */ |
| public static final int PROP_CONDITION_SUSPEND_POLICY= 0x1003; |
| |
| private static final int MAX_HISTORY_SIZE= 10; |
| private static final String DS_SECTION_CONDITION_HISTORY= "conditionHistory"; //$NON-NLS-1$ |
| private static final String DS_KEY_HISTORY_ENTRY_COUNT= "conditionHistoryEntryCount"; //$NON-NLS-1$ |
| private static final String DS_KEY_HISTORY_ENTRY_PREFIX= "conditionHistoryEntry_"; //$NON-NLS-1$ |
| private static final Pattern NEWLINE_PATTERN= Pattern.compile("\r\n|\r|\n"); //$NON-NLS-1$; |
| |
| |
| /** |
| * Creates a new Java breakpoint condition editor. |
| */ |
| public JavaBreakpointConditionEditor() { |
| } |
| |
| /** |
| * Creates a new Java breakpoint condition editor with a history drop-down list. |
| * |
| * @param dialogSettings the dialog settings for the condition history or <code>null</code> to |
| * use the default settings (i.e. those used by JDT Debug) |
| * @since 3.6 |
| */ |
| public JavaBreakpointConditionEditor(IDialogSettings dialogSettings) { |
| fConditionHistoryDialogSettings= dialogSettings != null ? dialogSettings : DialogSettings.getOrCreateSection(JDIDebugUIPlugin.getDefault().getDialogSettings(), DS_SECTION_CONDITION_HISTORY); |
| } |
| |
| /** |
| * Adds the given property listener to this editor. Property changes |
| * are reported on the breakpoint being edited. Property identifiers |
| * are breakpoint attribute keys. |
| * |
| * @param listener listener |
| */ |
| @Override |
| public void addPropertyListener(IPropertyListener listener) { |
| super.addPropertyListener(listener); |
| } |
| |
| /** |
| * Removes the property listener from this editor. |
| * |
| * @param listener listener |
| */ |
| @Override |
| public void removePropertyListener(IPropertyListener listener) { |
| super.removePropertyListener(listener); |
| } |
| |
| /** |
| * Sets the breakpoint to editor or <code>null</code> if none. |
| * |
| * @param input breakpoint or <code>null</code> |
| * @throws CoreException if unable to access breakpoint attributes |
| */ |
| @Override |
| public void setInput(Object input) throws CoreException { |
| try { |
| boolean sameBreakpoint= fBreakpoint == input; |
| suppressPropertyChanges(true); |
| if (input instanceof IJavaLineBreakpoint) { |
| setBreakpoint((IJavaLineBreakpoint)input); |
| } else if (input instanceof IJavaWatchpoint) { |
| setBreakpoint((IJavaWatchpoint) input); |
| } else { |
| setBreakpoint(null); |
| } |
| if (hasConditionHistory()) { |
| if (!sameBreakpoint) { |
| fReplaceConditionInHistory= false; |
| } |
| initializeConditionHistoryDropDown(); |
| } |
| } finally { |
| suppressPropertyChanges(false); |
| } |
| } |
| |
| |
| /** |
| * Sets the breakpoint to edit. Has no effect if the breakpoint responds |
| * <code>false</code> to {@link IJavaLineBreakpoint#supportsCondition()}. |
| * The same editor can be used iteratively for different breakpoints. |
| * |
| * @param breakpoint the breakpoint to edit or <code>null</code> if none |
| * @exception CoreException if unable to access breakpoint attributes |
| */ |
| private void setBreakpoint(IJavaLineBreakpoint breakpoint) throws CoreException { |
| fBreakpoint = breakpoint; |
| if (fDocumentListener != null) { |
| fViewer.getDocument().removeDocumentListener(fDocumentListener); |
| fDocumentListener = null; |
| } |
| fViewer.unconfigure(); |
| IDocument document = new Document(); |
| JDIDebugUIPlugin.getDefault().getJavaTextTools().setupJavaDocumentPartitioner(document, IJavaPartitions.JAVA_PARTITIONING); |
| fViewer.setInput(document); |
| String condition = null; |
| IType type = null; |
| boolean controlsEnabled = false; |
| boolean conditionEnabled = false; |
| boolean whenTrue = true; |
| if (breakpoint != null) { |
| controlsEnabled = true; |
| if (breakpoint.supportsCondition()) { |
| condition = breakpoint.getCondition(); |
| conditionEnabled = breakpoint.isConditionEnabled(); |
| whenTrue = breakpoint.isConditionSuspendOnTrue(); |
| type = BreakpointUtils.getType(breakpoint); |
| } |
| } |
| IJavaDebugContentAssistContext context = null; |
| if (type == null || breakpoint == null) { |
| context = new TypeContext(null, -1); |
| } else { |
| String source = null; |
| ICompilationUnit compilationUnit = type.getCompilationUnit(); |
| if (compilationUnit != null && compilationUnit.getJavaProject().getProject().exists()) { |
| source = compilationUnit.getSource(); |
| } |
| else { |
| IClassFile classFile = type.getClassFile(); |
| if (classFile != null) { |
| source = classFile.getSource(); |
| } |
| } |
| int position= -1; |
| if (breakpoint instanceof IJavaWatchpoint) { |
| IField[] fields = type.getFields(); |
| // Taking first field |
| ISourceRange sourceRange = fields[0].getNameRange(); |
| position = sourceRange.getOffset(); |
| if (source != null && position != -1) { |
| try { |
| // to get offset of the first character of line in which field is defined |
| int lineNumber = new Document(source).getLineOfOffset(position); |
| position = new Document(source).getLineOffset(lineNumber); |
| } |
| catch (BadLocationException e) { |
| // ignore, breakpoint line is out-of-date with the document |
| } |
| } |
| |
| } else { |
| int lineNumber = breakpoint.getMarker().getAttribute(IMarker.LINE_NUMBER, -1); |
| if (source != null && lineNumber != -1) { |
| try { |
| position = new Document(source).getLineOffset(lineNumber - 1); |
| } |
| catch (BadLocationException e) { |
| // ignore, breakpoint line is out-of-date with the document |
| } |
| } |
| } |
| context = new TypeContext(type, position); |
| } |
| fCompletionProcessor = new JavaDebugContentAssistProcessor(context); |
| document.set((condition == null ? "" : condition)); //$NON-NLS-1$ |
| fViewer.configure(new DisplayViewerConfiguration() { |
| @Override |
| public IContentAssistProcessor getContentAssistantProcessor() { |
| return fCompletionProcessor; |
| } |
| }); |
| fDocumentListener = new IDocumentListener() { |
| @Override |
| public void documentAboutToBeChanged(DocumentEvent event) { |
| } |
| @Override |
| public void documentChanged(DocumentEvent event) { |
| setDirty(PROP_CONDITION); |
| } |
| }; |
| fViewer.getDocument().addDocumentListener(fDocumentListener); |
| fConditional.setEnabled(controlsEnabled); |
| fConditional.setSelection(conditionEnabled); |
| fWhenTrue.setSelection(whenTrue); |
| fWhenChange.setSelection(!whenTrue); |
| setEnabled(conditionEnabled && breakpoint != null && breakpoint.supportsCondition(), false); |
| setDirty(false); |
| checkIfUsedInBreakpointsView(); |
| registerViewerUndoRedoActions(); |
| } |
| |
| /** |
| * Creates the condition editor widgets and returns the top level |
| * control. |
| * |
| * @param parent composite to embed the editor controls in |
| * @return top level control |
| */ |
| @Override |
| public Control createControl(Composite parent) { |
| Composite controls = SWTFactory.createComposite(parent, parent.getFont(), 2, 1, GridData.FILL_HORIZONTAL, 0, 0); |
| fConditional = SWTFactory.createCheckButton(controls, |
| processMnemonics(PropertyPageMessages.JavaBreakpointConditionEditor_0), |
| null, |
| false, |
| 1); |
| fConditional.setLayoutData(new GridData(SWT.BEGINNING, SWT.CENTER, false, false)); |
| fConditional.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| boolean checked = fConditional.getSelection(); |
| setEnabled(checked, true); |
| setDirty(PROP_CONDITION_ENABLED); |
| } |
| }); |
| Composite radios = SWTFactory.createComposite(controls, controls.getFont(), 2, 1, GridData.FILL_HORIZONTAL, 0, 0); |
| fWhenTrue = SWTFactory.createRadioButton(radios, processMnemonics(PropertyPageMessages.JavaBreakpointConditionEditor_1)); |
| fWhenTrue.setLayoutData(new GridData()); |
| fWhenChange = SWTFactory.createRadioButton(radios, processMnemonics(PropertyPageMessages.JavaBreakpointConditionEditor_2)); |
| fWhenChange.setLayoutData(new GridData()); |
| fWhenTrue.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| setDirty(PROP_CONDITION_SUSPEND_POLICY); |
| } |
| }); |
| fWhenChange.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| setDirty(PROP_CONDITION_SUSPEND_POLICY); |
| } |
| }); |
| |
| if (fConditionHistoryDialogSettings != null) { |
| fLocalConditionHistory= new HashMap<>(); |
| fConditionHistory= SWTFactory.createCombo(parent, SWT.DROP_DOWN | SWT.READ_ONLY, 1, null); |
| initializeConditionHistoryDropDown(); |
| fConditionHistory.addSelectionListener(new SelectionAdapter() { |
| @Override |
| public void widgetSelected(SelectionEvent e) { |
| int historyIndex= fConditionHistory.getSelectionIndex() - 1; |
| if (historyIndex >= 0 && historyIndex != fSeparatorIndex) { |
| fViewer.getDocument().set(getConditionHistory()[historyIndex]); |
| } |
| } |
| }); |
| GridData data= new GridData(GridData.FILL_HORIZONTAL); |
| data.widthHint= 10; |
| fConditionHistory.setLayoutData(data); |
| fLocalConditionHistory= new HashMap<>(10); |
| } |
| |
| fViewer = new JDISourceViewer(parent, null, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL | SWT.LEFT_TO_RIGHT); |
| fViewer.setEditable(false); |
| ControlDecoration decoration = new ControlDecoration(fViewer.getControl(), SWT.TOP | SWT.LEFT); |
| decoration.setShowOnlyOnFocus(true); |
| FieldDecoration dec = FieldDecorationRegistry.getDefault().getFieldDecoration(FieldDecorationRegistry.DEC_CONTENT_PROPOSAL); |
| decoration.setImage(dec.getImage()); |
| decoration.setDescriptionText(dec.getDescription()); |
| GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true); |
| // set height/width hints based on font |
| GC gc = new GC(fViewer.getTextWidget()); |
| gc.setFont(fViewer.getTextWidget().getFont()); |
| FontMetrics fontMetrics = gc.getFontMetrics(); |
| gd.heightHint = Dialog.convertHeightInCharsToPixels(fontMetrics, 17); |
| gd.widthHint = Dialog.convertWidthInCharsToPixels(fontMetrics, 40); |
| gc.dispose(); |
| fViewer.getControl().setLayoutData(gd); |
| fContentAssistHandler= new AbstractHandler() { |
| @Override |
| public Object execute(ExecutionEvent event) throws org.eclipse.core.commands.ExecutionException { |
| fViewer.doOperation(ISourceViewer.CONTENTASSIST_PROPOSALS); |
| return null; |
| } |
| }; |
| fUndoHandler= new AbstractHandler() { |
| @Override |
| public Object execute(ExecutionEvent event) throws org.eclipse.core.commands.ExecutionException { |
| fViewer.doOperation(ITextOperationTarget.UNDO); |
| return null; |
| } |
| }; |
| fRedoHandler= new AbstractHandler() { |
| @Override |
| public Object execute(ExecutionEvent event) throws org.eclipse.core.commands.ExecutionException { |
| fViewer.doOperation(ITextOperationTarget.REDO); |
| return null; |
| } |
| }; |
| fHandlerService = PlatformUI.getWorkbench().getAdapter(IHandlerService.class); |
| fViewer.getControl().addFocusListener(new FocusAdapter() { |
| @Override |
| public void focusGained(FocusEvent e) { |
| activateHandlers(); |
| } |
| @Override |
| public void focusLost(FocusEvent e) { |
| deactivateHandlers(); |
| } |
| }); |
| parent.addDisposeListener(new DisposeListener() { |
| @Override |
| public void widgetDisposed(DisposeEvent e) { |
| dispose(); |
| } |
| }); |
| return parent; |
| } |
| |
| /** |
| * Disposes this editor and its controls. Once disposed, the editor can no |
| * longer be used. |
| */ |
| @Override |
| protected void dispose() { |
| super.dispose(); |
| deactivateHandlers(); |
| if (fDocumentListener != null) { |
| fViewer.getDocument().removeDocumentListener(fDocumentListener); |
| } |
| fViewer.dispose(); |
| } |
| |
| /** |
| * Gives focus to an appropriate control in the editor. |
| */ |
| @Override |
| public void setFocus() { |
| fViewer.getControl().setFocus(); |
| } |
| |
| /** |
| * Saves current settings to the breakpoint being edited. Has no |
| * effect if a breakpoint is not currently being edited or if this |
| * editor is not dirty. |
| * |
| * @exception CoreException if unable to update the breakpoint. |
| */ |
| @Override |
| public void doSave() throws CoreException { |
| if (fBreakpoint != null && isDirty()) { |
| fBreakpoint.setCondition(fViewer.getDocument().get().trim()); |
| fBreakpoint.setConditionEnabled(fConditional.getSelection()); |
| fBreakpoint.setConditionSuspendOnTrue(fWhenTrue.getSelection()); |
| setDirty(false); |
| if (hasConditionHistory()) { |
| updateConditionHistories(); |
| } |
| } |
| } |
| |
| /** |
| * Returns a status describing whether the condition editor is in |
| * a valid state. Returns an OK status when all is good. For example, an error |
| * status is returned when the conditional expression is empty but enabled. |
| * |
| * @return editor status. |
| */ |
| @Override |
| public IStatus getStatus() { |
| if (fBreakpoint != null && fBreakpoint.supportsCondition()) { |
| if (fConditional.getSelection()) { |
| if (fViewer.getDocument().get().trim().length() == 0) { |
| return new Status(IStatus.ERROR, JDIDebugUIPlugin.getUniqueIdentifier(), PropertyPageMessages.BreakpointConditionEditor_1); |
| } |
| } |
| } |
| return Status.OK_STATUS; |
| } |
| |
| /** |
| * Returns whether the editor needs saving. |
| * |
| * @return whether the editor needs saving |
| */ |
| @Override |
| public boolean isDirty() { |
| return super.isDirty(); |
| } |
| |
| /** |
| * Sets whether mnemonics should be displayed in editor controls. |
| * Only has an effect if set before {@link #createControl(Composite)} |
| * is called. By default, mnemonics are displayed. |
| * |
| * @param mnemonics whether to display mnemonics |
| */ |
| @Override |
| public void setMnemonics(boolean mnemonics) { |
| super.setMnemonics(mnemonics); |
| } |
| |
| private void activateHandlers() { |
| fContentAssistActivation= fHandlerService.activateHandler(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS, fContentAssistHandler); |
| checkIfUsedInBreakpointsView(); |
| if (fBreakpointsViewSite == null) { |
| fUndoActivation= fHandlerService.activateHandler(IWorkbenchCommandConstants.EDIT_UNDO, fUndoHandler); |
| fRedoActivation= fHandlerService.activateHandler(IWorkbenchCommandConstants.EDIT_REDO, fRedoHandler); |
| } else { |
| registerViewerUndoRedoActions(); |
| } |
| } |
| |
| private void deactivateHandlers() { |
| if (fContentAssistActivation != null) { |
| fHandlerService.deactivateHandler(fContentAssistActivation); |
| fContentAssistActivation= null; |
| } |
| if (fUndoActivation != null) { |
| fHandlerService.deactivateHandler(fUndoActivation); |
| fUndoActivation= null; |
| } |
| if (fRedoActivation != null) { |
| fHandlerService.deactivateHandler(fRedoActivation); |
| fRedoActivation= null; |
| } |
| |
| if (fBreakpointsViewSite != null) { |
| fBreakpointsViewSite.getActionBars().setGlobalActionHandler(ITextEditorActionConstants.UNDO, fViewUndoAction); |
| fBreakpointsViewSite.getActionBars().setGlobalActionHandler(ITextEditorActionConstants.REDO, fViewRedoAction); |
| fBreakpointsViewSite.getActionBars().updateActionBars(); |
| disposeViewerUndoRedoActions(); |
| } |
| } |
| |
| private void disposeViewerUndoRedoActions() { |
| if (fViewerUndoAction != null) { |
| fViewerUndoAction.dispose(); |
| fViewerUndoAction= null; |
| } |
| if (fViewerRedoAction != null) { |
| fViewerRedoAction.dispose(); |
| fViewerRedoAction= null; |
| } |
| } |
| |
| /** |
| * Enables controls based on whether the breakpoint's condition is enabled. |
| * |
| * @param enabled <code>true</code> if enabled, <code>false</code> otherwise |
| * @param focus <code>true</code> if focus should be set, <code>false</code> otherwise |
| */ |
| private void setEnabled(boolean enabled, boolean focus) { |
| fViewer.setEditable(enabled); |
| fViewer.getTextWidget().setEnabled(enabled); |
| fWhenChange.setEnabled(enabled); |
| fWhenTrue.setEnabled(enabled); |
| if (enabled) { |
| fViewer.updateViewerColors(); |
| if (focus) { |
| setFocus(); |
| } |
| } else { |
| Color color = fViewer.getControl().getDisplay().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); |
| fViewer.getTextWidget().setBackground(color); |
| } |
| if (hasConditionHistory()) { |
| fConditionHistory.setEnabled(enabled); |
| } |
| } |
| |
| /** |
| * Returns the breakpoint being edited or <code>null</code> if none. |
| * |
| * @return breakpoint or <code>null</code> |
| */ |
| @Override |
| public Object getInput() { |
| return fBreakpoint; |
| } |
| |
| |
| /** |
| * Tells whether this editor shows a condition history drop-down list. |
| * |
| * @return <code>true</code> if this editor shows a condition history drop-down list, |
| * <code>false</code> otherwise |
| */ |
| private boolean hasConditionHistory() { |
| return fConditionHistory != null; |
| } |
| |
| /** |
| * Initializes the condition history drop-down with values. |
| */ |
| private void initializeConditionHistoryDropDown() { |
| fConditionHistory.setItems(getConditionHistoryLabels()); |
| String userHint= PropertyPageMessages.JavaBreakpointConditionEditor_choosePreviousCondition; |
| fConditionHistory.add(userHint, 0); |
| fConditionHistory.setText(userHint); |
| } |
| |
| /** |
| * Returns the condition history labels for the current breakpoint. |
| * |
| * @return an array of strings containing the condition history labels |
| */ |
| private String[] getConditionHistoryLabels() { |
| String[] conditions= getConditionHistory(); |
| String[] labels= new String[conditions.length]; |
| for (int i= 0; i < conditions.length; i++) { |
| labels[i]= NEWLINE_PATTERN.matcher(conditions[i]).replaceAll(" "); //$NON-NLS-1$ |
| } |
| return labels; |
| } |
| |
| /** |
| * Returns the condition history entries for the current breakpoint. |
| * |
| * @return an array of strings containing the history of conditions |
| */ |
| private String[] getConditionHistory() { |
| fSeparatorIndex= -1; |
| |
| // Get global history |
| String[] globalItems= readConditionHistory(fConditionHistoryDialogSettings); |
| |
| // Get local history |
| Stack<String> localHistory= fLocalConditionHistory.get(fBreakpoint); |
| if (localHistory == null) { |
| return globalItems; |
| } |
| |
| // Create combined history |
| int localHistorySize= Math.min(localHistory.size(), MAX_HISTORY_SIZE); |
| String[] historyItems= new String[localHistorySize + globalItems.length + 1]; |
| for (int i= 0; i < localHistorySize; i++) { |
| historyItems[i]= localHistory.get(localHistory.size() - i - 1); |
| } |
| fSeparatorIndex= localHistorySize; |
| historyItems[localHistorySize]= getSeparatorLabel(); |
| System.arraycopy(globalItems, 0, historyItems, localHistorySize + 1, globalItems.length); |
| return historyItems; |
| } |
| |
| /** |
| * Updates the local and global condition histories. |
| */ |
| private void updateConditionHistories() { |
| String newItem= fViewer.getDocument().get(); |
| if (newItem.length() == 0) { |
| return; |
| } |
| |
| // Update local history |
| Stack<String> localHistory= fLocalConditionHistory.get(fBreakpoint); |
| if (localHistory == null) { |
| localHistory= new Stack<>(); |
| fLocalConditionHistory.put(fBreakpoint, localHistory); |
| } |
| |
| localHistory.remove(newItem); |
| localHistory.push(newItem); |
| |
| // Update global history |
| String[] globalItems= readConditionHistory(fConditionHistoryDialogSettings); |
| if (globalItems.length > 0 && newItem.equals(globalItems[0])) { |
| return; |
| } |
| |
| if (!fReplaceConditionInHistory) { |
| String[] tempItems= new String[globalItems.length + 1]; |
| System.arraycopy(globalItems, 0, tempItems, 1, globalItems.length); |
| globalItems= tempItems; |
| } else if (globalItems.length == 0) { |
| globalItems= new String[1]; |
| } |
| fReplaceConditionInHistory= true; |
| globalItems[0]= newItem; |
| storeConditionHistory(globalItems, fConditionHistoryDialogSettings); |
| } |
| |
| /** |
| * Reads the condition history from the given dialog settings. |
| * |
| * @param dialogSettings the dialog settings |
| * @return the condition history |
| */ |
| private static String[] readConditionHistory(IDialogSettings dialogSettings) { |
| int count= 0; |
| try { |
| count= dialogSettings.getInt(DS_KEY_HISTORY_ENTRY_COUNT); |
| } catch (NumberFormatException ex) { |
| // No history yet |
| } |
| count= Math.min(count, MAX_HISTORY_SIZE); |
| String[] conditions= new String[count]; |
| for (int i= 0; i < count; i++) { |
| conditions[i]= dialogSettings.get(DS_KEY_HISTORY_ENTRY_PREFIX + i); |
| } |
| return conditions; |
| } |
| |
| /** |
| * Writes the given conditions into the given dialog settings. |
| * |
| * @param conditions an array of strings containing the conditions |
| * @param dialogSettings the dialog settings |
| */ |
| private static void storeConditionHistory(String[] conditions, IDialogSettings dialogSettings) { |
| int length= Math.min(conditions.length, MAX_HISTORY_SIZE); |
| int count= 0; |
| outer: for (int i= 0; i < length; i++) { |
| for (int j= 0; j < i; j++) { |
| if (conditions[i].equals(conditions[j])) { |
| break outer; |
| } |
| } |
| dialogSettings.put(DS_KEY_HISTORY_ENTRY_PREFIX + count, conditions[i]); |
| count= count + 1; |
| } |
| dialogSettings.put(DS_KEY_HISTORY_ENTRY_COUNT, count); |
| } |
| |
| /** |
| * Returns the label for the history separator. |
| * |
| * @return the label for the history separator |
| */ |
| private String getSeparatorLabel() { |
| int borderWidth= fConditionHistory.computeTrim(0, 0, 0, 0).width; |
| Rectangle rect= fConditionHistory.getBounds(); |
| int width= rect.width - borderWidth; |
| |
| GC gc= new GC(fConditionHistory); |
| gc.setFont(fConditionHistory.getFont()); |
| |
| int fSeparatorWidth= gc.getAdvanceWidth('-'); |
| String separatorLabel= PropertyPageMessages.JavaBreakpointConditionEditor_historySeparator; |
| int fMessageLength= gc.textExtent(separatorLabel).x; |
| |
| gc.dispose(); |
| |
| StringBuffer dashes= new StringBuffer(); |
| int chars= (((width - fMessageLength) / fSeparatorWidth) / 2) - 2; |
| for (int i= 0; i < chars; i++) { |
| dashes.append('-'); |
| } |
| |
| StringBuffer result= new StringBuffer(); |
| result.append(dashes); |
| result.append(" " + separatorLabel + " "); //$NON-NLS-1$//$NON-NLS-2$ |
| result.append(dashes); |
| return result.toString().trim(); |
| } |
| |
| private void registerViewerUndoRedoActions() { |
| if (!fViewer.getTextWidget().isFocusControl()) { |
| return; |
| } |
| |
| disposeViewerUndoRedoActions(); |
| IUndoContext undoContext= getUndoContext(); |
| if (undoContext != null) { |
| fViewerUndoAction= new UndoActionHandler(fBreakpointsViewSite, getUndoContext()); |
| PlatformUI.getWorkbench().getHelpSystem().setHelp(fViewerUndoAction, IAbstractTextEditorHelpContextIds.UNDO_ACTION); |
| fViewerUndoAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_UNDO); |
| |
| fViewerRedoAction= new RedoActionHandler(fBreakpointsViewSite, getUndoContext()); |
| PlatformUI.getWorkbench().getHelpSystem().setHelp(fViewerRedoAction, IAbstractTextEditorHelpContextIds.REDO_ACTION); |
| fViewerRedoAction.setActionDefinitionId(IWorkbenchCommandConstants.EDIT_REDO); |
| } |
| fBreakpointsViewSite.getActionBars().setGlobalActionHandler(ITextEditorActionConstants.UNDO, fViewerUndoAction); |
| fBreakpointsViewSite.getActionBars().setGlobalActionHandler(ITextEditorActionConstants.REDO, fViewerRedoAction); |
| fBreakpointsViewSite.getActionBars().updateActionBars(); |
| } |
| |
| /** |
| * Returns this editor's viewer's undo manager undo context. |
| * |
| * @return the undo context or <code>null</code> if not available |
| * @since 3.1 |
| */ |
| private IUndoContext getUndoContext() { |
| IUndoManager undoManager= ((ITextViewerExtension6)fViewer).getUndoManager(); |
| if (undoManager instanceof IUndoManagerExtension) { |
| return ((IUndoManagerExtension)undoManager).getUndoContext(); |
| } |
| return null; |
| } |
| |
| private void checkIfUsedInBreakpointsView() { |
| if (fBreakpointsViewSite != null) { |
| return; |
| } |
| |
| IWorkbenchWindow activeWorkbenchWindow= PlatformUI.getWorkbench().getActiveWorkbenchWindow(); |
| if (activeWorkbenchWindow != null && activeWorkbenchWindow.getActivePage() != null && activeWorkbenchWindow.getActivePage().getActivePart() != null) { |
| IWorkbenchPartSite site= activeWorkbenchWindow.getActivePage().getActivePart().getSite(); |
| if ("org.eclipse.debug.ui.BreakpointView".equals(site.getId())) { //$NON-NLS-1$ |
| fBreakpointsViewSite= (IViewSite)site; |
| fViewUndoAction= fBreakpointsViewSite.getActionBars().getGlobalActionHandler(ITextEditorActionConstants.UNDO); |
| fViewRedoAction= fBreakpointsViewSite.getActionBars().getGlobalActionHandler(ITextEditorActionConstants.REDO); |
| } |
| } |
| } |
| |
| } |