blob: 35b3ed547850348d6aa73c98a1acb622374741e7 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009, 2019 IBM Corporation and others.
*
* This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* 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.JDIContentAssistPreference;
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(JDIContentAssistPreference.getContentAssistDescription());
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();
StringBuilder dashes= new StringBuilder();
int chars= (((width - fMessageLength) / fSeparatorWidth) / 2) - 2;
for (int i= 0; i < chars; i++) {
dashes.append('-');
}
StringBuilder result= new StringBuilder();
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);
}
}
}
}