package org.erlide.debug.ui.properties; import java.text.MessageFormat; import java.util.ArrayList; import java.util.List; import org.eclipse.core.resources.IWorkspaceRunnable; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ShellEvent; import org.eclipse.swt.events.ShellListener; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; 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.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.dialogs.PropertyPage; import org.eclipse.ui.model.IWorkbenchAdapter; import org.erlide.backend.debug.IErlangBreakpoint; import org.erlide.ui.editors.erl.IErlangHelpContextIds; import org.erlide.ui.internal.ErlideUIPlugin; import org.erlide.ui.util.PixelConverter; import org.erlide.util.ErlLogger; public class ErlangBreakpointPropertyPage extends PropertyPage { protected Button fEnabledButton; protected Button fHitCountButton; // protected Text fHitCountText; protected Combo fBreakActionCombo; protected List<String> fErrorMessages = new ArrayList<>(); /** * Attribute used to indicate that a breakpoint should be deleted when cancel is * pressed. */ public static final String ATTR_DELETE_ON_CANCEL = ErlideUIPlugin.PLUGIN_ID + ".ATTR_DELETE_ON_CANCEL"; //$NON-NLS-1$ /** * Constant for the empty string */ protected static final String EMPTY_STRING = ""; //$NON-NLS-1$ /** * the hit count error message */ // private static final String fgHitCountErrorMessage = // "Hit count must be a positive integer"; /** * Store the breakpoint properties. * * @see org.eclipse.jface.preference.IPreferencePage#performOk() */ @Override public boolean performOk() { final IWorkspaceRunnable wr = new IWorkspaceRunnable() { @Override public void run(final IProgressMonitor monitor) throws CoreException { final IErlangBreakpoint breakpoint = getBreakpoint(); final boolean delOnCancel = breakpoint.getMarker() .getAttribute(ATTR_DELETE_ON_CANCEL) != null; if (delOnCancel) { // if this breakpoint is being created, remove the // "delete on cancel" attribute // and register with the breakpoint manager breakpoint.getMarker().setAttribute(ATTR_DELETE_ON_CANCEL, (String) null); breakpoint.setRegistered(true); } doStore(); } }; try { ResourcesPlugin.getWorkspace().run(wr, null, 0, null); } catch (final CoreException e) { ErlLogger.error(e); } return super.performOk(); } /** * Adds the given error message to the errors currently displayed on this page. The * page displays the most recently added error message. Clients should retain messages * that are passed into this method as the message should later be passed into * removeErrorMessage(String) to clear the error. This method should be used instead * of setErrorMessage(String). * * @param message * the error message to display on this page. */ protected void addErrorMessage(final String message) { fErrorMessages.remove(message); fErrorMessages.add(message); setErrorMessage(message); setValid(message == null); } /** * Removes the given error message from the errors currently displayed on this page. * When an error message is removed, the page displays the error that was added before * the given message. This is akin to popping the message from a stack. Clients should * call this method instead of setErrorMessage(null). * * @param message * the error message to clear */ protected void removeErrorMessage(final String message) { fErrorMessages.remove(message); if (fErrorMessages.isEmpty()) { addErrorMessage(null); } else { addErrorMessage(fErrorMessages.get(fErrorMessages.size() - 1)); } } /** * Stores the values configured in this page. This method should be called from within * a workspace runnable to reduce the number of resource deltas. */ protected void doStore() throws CoreException { final IErlangBreakpoint breakpoint = getBreakpoint(); // storeHitCount(breakpoint); storeEnabled(breakpoint); storeBreakAction(breakpoint); } /** * Stores the value of the enabled state in the breakpoint. * * @param breakpoint * the breakpoint to update * @throws CoreException * if an exception occurs while setting the enabled state */ private void storeEnabled(final IErlangBreakpoint breakpoint) throws CoreException { breakpoint.setEnabled(fEnabledButton.getSelection()); } /** * Stores the value of the suspend policy in the breakpoint. * * @param breakpoint * the breakpoint to update * @throws CoreException * if an exception occurs while setting the suspend policy */ private void storeBreakAction(final IErlangBreakpoint breakpoint) throws CoreException { breakpoint.setBreakAction(fBreakActionCombo.getSelectionIndex()); } /** * Stores the value of the hit count in the breakpoint. * * @param breakpoint * the breakpoint to update * @throws CoreException * if an exception occurs while setting the hit count */ // private void storeHitCount(final IErlangBreakpoint breakpoint) // throws CoreException { // int hitCount = -1; // if (fHitCountButton.getSelection()) { // try { // hitCount = Integer.parseInt(fHitCountText.getText()); // } catch (final NumberFormatException e) { // ErlLogger.warn(e); // // JDIDebugUIPlugin // // .log(new Status( // // IStatus.ERROR, // // JDIDebugUIPlugin.getUniqueIdentifier(), // // IStatus.ERROR, // // MessageFormat // // .format( // // "ErlangBreakpointPage allowed input of invalid string for hit count value: // {0}.", new String[] { fHitCountText.getText() }), e)); //$NON-NLS-1$ // } // } // breakpoint.setHitCount(hitCount); // } /** * Creates the labels and editors displayed for the breakpoint. * * @see org.eclipse.jface.preference.PreferencePage#createContents(org.eclipse.swt.widgets.Composite) */ @Override protected Control createContents(final Composite parent) { setTitle("<erlang breakpoint page, should be overridden>"); noDefaultAndApplyButton(); final Composite mainComposite = createComposite(parent, 1); createLabels(mainComposite); try { createEnabledButton(mainComposite); // createHitCountEditor(mainComposite); createTypeSpecificEditors(mainComposite); createActionCombo(mainComposite); // considered uncommon. // Add it last. } catch (final CoreException e) { ErlLogger.error(e); } setValid(true); // if this breakpoint is being created, change the shell title to // indicate 'creation' try { if (getBreakpoint().getMarker().getAttribute(ATTR_DELETE_ON_CANCEL) != null) { getShell().addShellListener(new ShellListener() { @Override public void shellActivated(final ShellEvent e) { final Shell shell = (Shell) e.getSource(); shell.setText(MessageFormat.format("Create Breakpoint for {0}", new Object[] { getName(getBreakpoint()) })); shell.removeShellListener(this); } @Override public void shellClosed(final ShellEvent e) { } @Override public void shellDeactivated(final ShellEvent e) { } @Override public void shellDeiconified(final ShellEvent e) { } @Override public void shellIconified(final ShellEvent e) { } }); } } catch (final CoreException e) { } return mainComposite; } private void createActionCombo(final Composite parent) { final Composite comp = createComposite(parent, 2); createLabel(comp, "Break Action"); fBreakActionCombo = new Combo(comp, SWT.BORDER | SWT.READ_ONLY); fBreakActionCombo.add("Break"); fBreakActionCombo.add("Trace And Continue"); fBreakActionCombo.select(getBreakpoint().getBreakAction()); } /** * Returns the name of the given element. * * @param element * the element * @return the name of the element */ String getName(final IAdaptable element) { final IWorkbenchAdapter adapter = (IWorkbenchAdapter) element .getAdapter(IWorkbenchAdapter.class); if (adapter != null) { return adapter.getLabel(element); } return EMPTY_STRING; } /** * Creates the labels displayed for the breakpoint. * * @param parent */ protected void createLabels(final Composite parent) { final Composite labelComposite = createComposite(parent, 2); // final String typeName = getBreakpoint().getTypeName(); // if (typeName != null) { // createLabel(labelComposite, "&Type:"); // final Text t = new Text(labelComposite, SWT.READ_ONLY); // t.setFont(labelComposite.getFont()); // final GridData gd = new GridData(GridData.FILL_HORIZONTAL); // gd.horizontalSpan = 1; // t.setLayoutData(gd); // t.setText(typeName); // t.setBackground(parent.getBackground()); // } createTypeSpecificLabels(labelComposite); } // /** // * @param parent // * the composite in which the hit count editor will be created // */ // private void createHitCountEditor(final Composite parent) // throws CoreException { // final Composite hitCountComposite = createComposite(parent, 2); // fHitCountButton = createCheckButton(hitCountComposite, "&Hit Count:"); // fHitCountButton.addSelectionListener(new SelectionAdapter() { // @Override // public void widgetSelected(final SelectionEvent event) { // fHitCountText.setEnabled(fHitCountButton.getSelection()); // hitCountChanged(); // } // }); // final int hitCount = getBreakpoint().getHitCount(); // String hitCountString = EMPTY_STRING; // if (hitCount > 0) { // hitCountString = new Integer(hitCount).toString(); // fHitCountButton.setSelection(true); // } else { // fHitCountButton.setSelection(false); // } // fHitCountText = createText(hitCountComposite, hitCountString); // if (hitCount <= 0) { // fHitCountText.setEnabled(false); // } // fHitCountText.addModifyListener(new ModifyListener() { // public void modifyText(final ModifyEvent e) { // hitCountChanged(); // } // }); // } // /** // * Validates the current state of the hit count editor. Hit count value // must // * be a positive integer. // */ // private void hitCountChanged() { // if (!fHitCountButton.getSelection()) { // removeErrorMessage(fgHitCountErrorMessage); // return; // } // final String hitCountText = fHitCountText.getText(); // int hitCount = -1; // try { // hitCount = Integer.parseInt(hitCountText); // } catch (final NumberFormatException e1) { // addErrorMessage(fgHitCountErrorMessage); // return; // } // if (hitCount < 1) { // addErrorMessage(fgHitCountErrorMessage); // } else { // removeErrorMessage(fgHitCountErrorMessage); // } // } /** * Creates the button to toggle enablement of the breakpoint * * @param parent * @throws CoreException */ protected void createEnabledButton(final Composite parent) throws CoreException { fEnabledButton = createCheckButton(parent, "&Enabled"); fEnabledButton.setSelection(getBreakpoint().isEnabled()); } /** * Returns the breakpoint that this preference page configures * * @return the breakpoint this page configures */ protected IErlangBreakpoint getBreakpoint() { return (IErlangBreakpoint) getElement(); } /** * Allows subclasses to add type specific labels to the common Erlang breakpoint page. * * @param parent */ protected void createTypeSpecificLabels(final Composite parent) { } /** * Allows subclasses to add type specific editors to the common Erlang breakpoint * page. * * @param parent * @throws CoreException */ protected void createTypeSpecificEditors(final Composite parent) throws CoreException { } /** * Creates a fully configured text editor with the given initial value * * @param parent * @param initialValue * @return the configured text editor */ protected Text createText(final Composite parent, final String initialValue) { return createText(parent, SWT.BORDER | SWT.SINGLE, initialValue); } protected Text createText(final Composite parent, final int style, final String initialValue) { final Text t = new Text(parent, style); t.setFont(parent.getFont()); final GridData gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 1; t.setLayoutData(gd); t.setText(initialValue); return t; } /** * Creates a fully configured composite with the given number of columns * * @param parent * @param numColumns * @return the configured composite */ protected Composite createComposite(final Composite parent, final int numColumns) { final Composite g = new Composite(parent, SWT.NONE); final GridLayout layout = new GridLayout(numColumns, false); layout.marginWidth = 0; layout.marginHeight = 0; g.setLayout(layout); g.setFont(parent.getFont()); final GridData gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 1; g.setLayoutData(gd); return g; } /** * Creates a fully configured check button with the given text. * * @param parent * the parent composite * @param text * the label of the returned check button * @return a fully configured check button */ protected Button createCheckButton(final Composite parent, final String text) { final Button button = new Button(parent, SWT.CHECK); button.setFont(parent.getFont()); button.setSelection(false); button.setText(text); final GridData gd = new GridData(); gd.horizontalSpan = 1; button.setLayoutData(gd); setButtonDimensionHint(button); return button; } private void setButtonDimensionHint(final Button button) { final Object o = button.getLayoutData(); if (o instanceof GridData) { final GridData gd = (GridData) o; button.setFont(JFaceResources.getDialogFont()); final PixelConverter converter = new PixelConverter(button); final int widthHint1 = converter .convertHorizontalDLUsToPixels(IDialogConstants.BUTTON_WIDTH); gd.widthHint = Math.max(widthHint1, button.computeSize(SWT.DEFAULT, SWT.DEFAULT, true).x); gd.horizontalAlignment = GridData.FILL; } } /** * Creates a fully configured label with the given text. * * @param parent * the parent composite * @param text * the test of the returned label * @return a fully configured label */ protected Label createLabel(final Composite parent, final String text) { final Label l = new Label(parent, SWT.NONE); l.setFont(parent.getFont()); l.setText(text); final GridData gd = new GridData(GridData.FILL_HORIZONTAL); gd.horizontalSpan = 1; gd.grabExcessHorizontalSpace = false; l.setLayoutData(gd); return l; } /** * Creates a fully configured radio button with the given text. * * @param parent * the parent composite * @param text * the label of the returned radio button * @return a fully configured radio button */ protected Button createRadioButton(final Composite parent, final String text) { final Button button = new Button(parent, SWT.RADIO); button.setFont(parent.getFont()); button.setText(text); final GridData gd = new GridData(); button.setLayoutData(gd); setButtonDimensionHint(button); return button; } /** * Check to see if the breakpoint should be deleted. */ @Override public boolean performCancel() { try { if (getBreakpoint().getMarker().getAttribute(ATTR_DELETE_ON_CANCEL) != null) { // if this breakpoint is being created, delete on cancel getBreakpoint().delete(); } } catch (final CoreException e) { ErlLogger.error(e); // JDIDebugUIPlugin.statusDialog( // PropertyPageMessages.ErlangBreakpointPage_9, e.getStatus()); } return super.performCancel(); } @Override public void createControl(final Composite parent) { super.createControl(parent); PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), IErlangHelpContextIds.ERLANG_BREAKPOINT_PROPERTY_PAGE); } }