/******************************************************************************* * Copyright (c) 2000, 2015 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.internal.debug.ui; import java.util.List; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.IHandler; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.debug.internal.ui.SWTFactory; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.search.IJavaSearchConstants; import org.eclipse.jdt.core.search.IJavaSearchScope; import org.eclipse.jdt.core.search.SearchEngine; import org.eclipse.jdt.core.search.SearchMatch; import org.eclipse.jdt.core.search.SearchParticipant; import org.eclipse.jdt.core.search.SearchPattern; import org.eclipse.jdt.core.search.SearchRequestor; import org.eclipse.jdt.internal.debug.ui.contentassist.DynamicTypeContext; import org.eclipse.jdt.internal.debug.ui.contentassist.DynamicTypeContext.ITypeProvider; import org.eclipse.jdt.internal.debug.ui.contentassist.JavaDebugContentAssistProcessor; import org.eclipse.jdt.internal.debug.ui.display.DisplayViewerConfiguration; import org.eclipse.jdt.ui.IJavaElementSearchConstants; import org.eclipse.jdt.ui.JavaUI; import org.eclipse.jdt.ui.text.IJavaPartitions; import org.eclipse.jdt.ui.text.JavaTextTools; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.StatusDialog; 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.contentassist.IContentAssistProcessor; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.events.ModifyEvent; import org.eclipse.swt.events.ModifyListener; import org.eclipse.swt.graphics.Font; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchCommandConstants; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.dialogs.SelectionDialog; import org.eclipse.ui.handlers.IHandlerActivation; import org.eclipse.ui.handlers.IHandlerService; import org.eclipse.ui.keys.IBindingService; import org.eclipse.ui.texteditor.ITextEditorActionDefinitionIds; /** * Dialog for edit detail formatter. */ public class DetailFormatterDialog extends StatusDialog implements ITypeProvider { /** * The detail formatter to edit. */ private DetailFormatter fDetailFormatter; // widgets private Text fTypeNameText; private JDISourceViewer fSnippetViewer; private Button fCheckBox; /** * Indicate if a search for a type with the given name * have been already performed. */ private boolean fTypeSearched; /** * Indicate if the type can be modified. */ private boolean fEditTypeName; /** * The type object which corresponds to the given name. * If this field is <code>null</code> and <code>fTypeSearched</code> is * <code>true</code>, that means there is no type with the given name in * the workspace. */ private IType fType; /** * List of types that have detail formatters already defined. */ private List<?> fDefinedTypes; /** * Activation handler for content assist, must be deactivated on disposal. */ private IHandlerActivation fHandlerActivation; /** * DetailFormatterDialog constructor. Creates a new dialog to create/edit a detail formatter. * * @param parent parent shell * @param detailFormatter detail formatter to edit, not <code>null</code> * @param definedTypes list of types with detail formatters already defined, or <code>null</code> * @param editDialog whether the dialog is being used to edit a detail formatter */ public DetailFormatterDialog(Shell parent, DetailFormatter detailFormatter, List<?> definedTypes, boolean editDialog) { this(parent, detailFormatter, definedTypes, true, editDialog); } /** * DetailFormatterDialog constructor. Creates a new dialog to create/edit a detail formatter. * * @param parent parent shell * @param detailFormatter detail formatter to edit, not <code>null</code> * @param definedTypes list of types with detail formatters already defined, or <code>null</code> * @param editTypeName whether the user should be able to modify the type * @param editDialog whether the dialog is being used to edit a detail formatter */ public DetailFormatterDialog(Shell parent, DetailFormatter detailFormatter, List<?> definedTypes, boolean editTypeName, boolean editDialog) { super(parent); fDetailFormatter= detailFormatter; fTypeSearched= false; setShellStyle(getShellStyle() | SWT.MAX | SWT.RESIZE); if (editDialog) { setTitle(DebugUIMessages.DetailFormatterDialog_Edit_Detail_Formatter_1); } else { setTitle(DebugUIMessages.DetailFormatterDialog_Add_Detail_Formatter_2); } fEditTypeName= editTypeName; fDefinedTypes= definedTypes; } /** * Create the dialog area. * * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(Composite) */ @Override protected Control createDialogArea(Composite parent) { IWorkbench workbench = PlatformUI.getWorkbench(); workbench.getHelpSystem().setHelp( parent, IJavaDebugHelpContextIds.EDIT_DETAIL_FORMATTER_DIALOG); Font font = parent.getFont(); Composite container = (Composite)super.createDialogArea(parent); SWTFactory.createLabel(container, DebugUIMessages.DetailFormatterDialog_Qualified_type__name__2, 1); Composite innerContainer = SWTFactory.createComposite(container, font, 2, 1, GridData.FILL_HORIZONTAL); fTypeNameText = SWTFactory.createSingleText(innerContainer, 1); fTypeNameText.setEditable(fEditTypeName); fTypeNameText.setText(fDetailFormatter.getTypeName()); fTypeNameText.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { fTypeSearched= false; checkValues(); } }); Button typeSearchButton = SWTFactory.createPushButton(innerContainer, DebugUIMessages.DetailFormatterDialog_Select__type_4, null); typeSearchButton.setEnabled(fEditTypeName); typeSearchButton.addListener(SWT.Selection, new Listener() { @Override public void handleEvent(Event e) { selectType(); } }); String labelText = null; IBindingService bindingService = workbench.getAdapter(IBindingService.class); String binding = bindingService.getBestActiveBindingFormattedFor(IWorkbenchCommandConstants.EDIT_CONTENT_ASSIST); if (binding != null) { labelText = NLS.bind(DebugUIMessages.DetailFormatterDialog_17, new String[] { binding }); } if (labelText == null) { labelText = DebugUIMessages.DetailFormatterDialog_Detail_formatter__code_snippet__1; } SWTFactory.createLabel(container, labelText, 1); createSnippetViewer(container); fCheckBox = SWTFactory.createCheckButton(container, DebugUIMessages.DetailFormatterDialog__Enable_1, null, fDetailFormatter.isEnabled(), 1); // Set up content assist in the viewer IHandler handler = new AbstractHandler() { @Override public Object execute(ExecutionEvent event) throws ExecutionException { if (fSnippetViewer.canDoOperation(ISourceViewer.CONTENTASSIST_PROPOSALS) && fSnippetViewer.getControl().isFocusControl()){ findCorrespondingType(); fSnippetViewer.doOperation(ISourceViewer.CONTENTASSIST_PROPOSALS); } return null; } }; IHandlerService handlerService = workbench.getAdapter(IHandlerService.class); fHandlerActivation = handlerService.activateHandler(ITextEditorActionDefinitionIds.CONTENT_ASSIST_PROPOSALS, handler); checkValues(); return container; } /** * Creates the JDISourceViewer that displays the code snippet to the user. * * @param parent parent composite */ private void createSnippetViewer(Composite parent) { fSnippetViewer= new JDISourceViewer(parent, null, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL | SWT.LEFT_TO_RIGHT); fSnippetViewer.setInput(this); JavaTextTools tools= JDIDebugUIPlugin.getDefault().getJavaTextTools(); IDocument document= new Document(); tools.setupJavaDocumentPartitioner(document, IJavaPartitions.JAVA_PARTITIONING); fSnippetViewer.configure(new DisplayViewerConfiguration() { @Override public IContentAssistProcessor getContentAssistantProcessor() { return new JavaDebugContentAssistProcessor(new DynamicTypeContext(DetailFormatterDialog.this)); } }); fSnippetViewer.setEditable(true); fSnippetViewer.setDocument(document); Control control= fSnippetViewer.getControl(); GridData gd= new GridData(GridData.FILL_BOTH); gd.heightHint= convertHeightInCharsToPixels(10); gd.widthHint= convertWidthInCharsToPixels(80); control.setLayoutData(gd); document.set(fDetailFormatter.getSnippet()); fSnippetViewer.getDocument().addDocumentListener(new IDocumentListener() { @Override public void documentAboutToBeChanged(DocumentEvent event) { } @Override public void documentChanged(DocumentEvent event) { checkValues(); } }); if (fDetailFormatter.getTypeName().length() > 0) { fSnippetViewer.getControl().setFocus(); } } /** * Check the field values and display a message in the status if needed. */ private void checkValues() { StatusInfo status= new StatusInfo(); String typeName= fTypeNameText.getText().trim(); if (typeName.length() == 0) { status.setError(DebugUIMessages.DetailFormatterDialog_Qualified_type_name_must_not_be_empty__3); } else if (fDefinedTypes != null && fDefinedTypes.contains(typeName)) { status.setError(DebugUIMessages.DetailFormatterDialog_A_detail_formatter_is_already_defined_for_this_type_2); } else if (fSnippetViewer.getDocument().get().trim().length() == 0) { status.setError(DebugUIMessages.DetailFormatterDialog_Associated_code_must_not_be_empty_3); } else if (fType == null && fTypeSearched) { status.setWarning(DebugUIMessages.No_type_with_the_given_name_found_in_the_workspace__1); } updateStatus(status); } /** * @see org.eclipse.jface.dialogs.Dialog#okPressed() */ @Override protected void okPressed() { fDetailFormatter.setEnabled(fCheckBox.getSelection()); fDetailFormatter.setTypeName(fTypeNameText.getText().trim()); fDetailFormatter.setSnippet(fSnippetViewer.getDocument().get()); super.okPressed(); } /** * Open the 'select type' dialog, and set the user choice into the formatter. */ private void selectType() { Shell shell= getShell(); SelectionDialog dialog= null; try { dialog= JavaUI.createTypeDialog(shell, PlatformUI.getWorkbench().getProgressService(), SearchEngine.createWorkspaceScope(), IJavaElementSearchConstants.CONSIDER_ALL_TYPES, false, fTypeNameText.getText()); } catch (JavaModelException jme) { String title= DebugUIMessages.DetailFormatterDialog_Select_type_6; String message= DebugUIMessages.DetailFormatterDialog_Could_not_open_type_selection_dialog_for_detail_formatters_7; ExceptionHandler.handle(jme, title, message); return; } dialog.setTitle(DebugUIMessages.DetailFormatterDialog_Select_type_8); dialog.setMessage(DebugUIMessages.DetailFormatterDialog_Select_a_type_to_format_when_displaying_its_detail_9); if (dialog.open() == IDialogConstants.CANCEL_ID) { return; } Object[] types= dialog.getResult(); if (types != null && types.length > 0) { fType = (IType)types[0]; fTypeNameText.setText(fType.getFullyQualifiedName()); fTypeSearched = true; } } /** * Use the Java search engine to find the type which corresponds * to the given name. */ private void findCorrespondingType() { if (fTypeSearched) { return; } fType= null; fTypeSearched= true; final String pattern= fTypeNameText.getText().trim().replace('$', '.'); if (pattern == null || "".equals(pattern)) { //$NON-NLS-1$ return; } final IProgressMonitor monitor = new NullProgressMonitor(); final SearchRequestor collector = new SearchRequestor() { private boolean fFirst= true; @Override public void endReporting() { checkValues(); } @Override public void acceptSearchMatch(SearchMatch match) throws CoreException { Object enclosingElement = match.getElement(); if (!fFirst) { return; } fFirst= false; if (enclosingElement instanceof IType) { fType= (IType) enclosingElement; } // cancel once we have one match monitor.setCanceled(true); } }; SearchEngine engine= new SearchEngine(JavaCore.getWorkingCopies(null)); SearchPattern searchPattern = SearchPattern.createPattern(pattern, IJavaSearchConstants.TYPE, IJavaSearchConstants.DECLARATIONS, SearchPattern.R_EXACT_MATCH | SearchPattern.R_CASE_SENSITIVE); IJavaSearchScope scope= SearchEngine.createWorkspaceScope(); SearchParticipant[] participants = new SearchParticipant[] {SearchEngine.getDefaultSearchParticipant()}; try { engine.search(searchPattern, participants, scope, collector, monitor); } catch (CoreException e) { JDIDebugUIPlugin.log(e); } catch (OperationCanceledException e) { } } /** * Return the type object which corresponds to the given name. */ @Override public IType getType() { if (!fTypeSearched) { findCorrespondingType(); } return fType; } /* (non-Javadoc) * @see org.eclipse.jface.window.Window#close() */ @Override public boolean close() { IWorkbench workbench = PlatformUI.getWorkbench(); IHandlerService handlerService = workbench.getAdapter(IHandlerService.class); handlerService.deactivateHandler(fHandlerActivation); fSnippetViewer.dispose(); return super.close(); } }