/******************************************************************************* * Copyright (c) 2015 Zend Technologies 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: * Zend Technologies - initial API and implementation *******************************************************************************/ package org.eclipse.php.internal.debug.ui.actions; import java.text.MessageFormat; import java.util.*; import java.util.List; import java.util.regex.Pattern; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.dltk.core.IType; import org.eclipse.dltk.core.ITypeHierarchy; import org.eclipse.dltk.core.ModelException; import org.eclipse.dltk.core.index2.search.ISearchEngine.MatchRule; import org.eclipse.dltk.core.search.IDLTKSearchScope; import org.eclipse.dltk.core.search.SearchEngine; import org.eclipse.dltk.internal.core.hierarchy.FakeType; import org.eclipse.dltk.ui.util.PixelConverter; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.DialogSettings; import org.eclipse.jface.dialogs.IDialogSettings; import org.eclipse.jface.viewers.*; import org.eclipse.php.internal.core.PHPLanguageToolkit; import org.eclipse.php.internal.core.model.PHPModelAccess; import org.eclipse.php.internal.debug.ui.Logger; import org.eclipse.php.internal.debug.ui.PHPDebugUIImages; import org.eclipse.php.internal.debug.ui.PHPDebugUIPlugin; import org.eclipse.php.internal.ui.util.SWTUtil; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.custom.CLabel; import org.eclipse.swt.custom.StyleRange; import org.eclipse.swt.events.*; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.*; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.dialogs.SelectionDialog; /** * Dialog for adding PHP exception breakpoints. * * @author Bartlomiej Laczkowski */ @SuppressWarnings("restriction") public class AddPHPExceptionBreakpointDialog extends SelectionDialog { private class LabelProvider extends StyledCellLabelProvider { @Override public void update(ViewerCell cell) { Object element = cell.getElement(); cell.setImage(getImage(element)); String text = getText(element); cell.setText(text); int separatorIndex = text.indexOf('-'); StyleRange greyRange = new StyleRange(separatorIndex, text.length() - separatorIndex, Display.getDefault().getSystemColor(SWT.COLOR_DARK_GRAY), null); cell.setStyleRanges(new StyleRange[] { greyRange }); super.update(cell); } private String getText(Object element) { IType exception = (IType) element; if (exception instanceof ErrorType) { return MessageFormat.format(Messages.AddPHPExceptionBreakpointDialog_Exception_description, exception.getElementName(), ((ErrorType) exception).getDescription()); } return MessageFormat.format(Messages.AddPHPExceptionBreakpointDialog_Exception_description, exception.getElementName(), exception.getSourceModule().getElementName()); } private Image getImage(Object element) { IType exception = (IType) element; if (exception instanceof ErrorType) { return PHPDebugUIImages.get(PHPDebugUIImages.IMG_ELCL_ERROR_BREAKPOINT); } return PHPDebugUIImages.get(PHPDebugUIImages.IMG_ELCL_EXCEPTION_BREAKPOINT); } }; static class ErrorType extends FakeType { private String description; /** * @param sourceModule * @param name */ public ErrorType(String name, String description) { super(null, name); this.description = description; } /** * @return the description */ public String getDescription() { return description; } } public static final IType[] ERROR_TYPES = { new ErrorType("Notice", Messages.AddPHPExceptionBreakpointDialog_Suspend_on_notice), //$NON-NLS-1$ new ErrorType("Warning", Messages.AddPHPExceptionBreakpointDialog_Suspend_on_error), //$NON-NLS-1$ new ErrorType("Deprecated", Messages.AddPHPExceptionBreakpointDialog_Suspend_on_deprecated) }; //$NON-NLS-1$ private static final String EXCEPTION_BASE_CLASS_NAME = "Exception"; //$NON-NLS-1$ private static final String DIALOG_SETTINGS = "org.eclipse.php.debug.ui.dialogs.AddPHPExceptionDialog"; //$NON-NLS-1$ private static final String WIDTH = "width"; //$NON-NLS-1$ private static final String HEIGHT = "height"; //$NON-NLS-1$ private Set<IType> fExceptionTypesCache; private Text fExceptionFilter; private TableViewer fExceptionViewer; private IDialogSettings fSettings; private Point fLocation; private Point fSize; /** * Creates new selection dialog. * * @param parent * parent shell */ public AddPHPExceptionBreakpointDialog() { super(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell()); initializeSettings(); BusyIndicator.showWhile(PlatformUI.getWorkbench().getDisplay(), new Runnable() { @Override public void run() { fetchExceptionTypes(); } }); } /* * (non-Javadoc) * * @see org.eclipse.jface.dialogs.Dialog#close() */ @Override public boolean close() { writeSettings(); return super.close(); } /* * (non-Javadoc) * * @see org.eclipse.jface.dialogs.Dialog#getInitialSize() */ protected Point getInitialSize() { Point result = super.getInitialSize(); if (fSize != null) { result.x = Math.max(result.x, fSize.x); result.y = Math.max(result.y, fSize.y); Rectangle display = getShell().getDisplay().getClientArea(); result.x = Math.min(result.x, display.width); result.y = Math.min(result.y, display.height); } return result; } /* * (non-Javadoc) * * @see org.eclipse.jface.dialogs.Dialog#getInitialLocation(org.eclipse.swt. * graphics.Point) */ protected Point getInitialLocation(Point initialSize) { Point result = super.getInitialLocation(initialSize); if (fLocation != null) { result.x = fLocation.x; result.y = fLocation.y; Rectangle display = getShell().getDisplay().getClientArea(); int xe = result.x + initialSize.x; if (xe > display.width) { result.x -= xe - display.width; } int ye = result.y + initialSize.y; if (ye > display.height) { result.y -= ye - display.height; } } return result; } /* * (non-Javadoc) * * @see * org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets * .Composite) */ @Override protected Control createDialogArea(Composite parent) { readSettings(); Composite area = (Composite) super.createDialogArea(parent); Label filterLabel = new Label(area, SWT.NONE); filterLabel.setText(Messages.AddPHPExceptionBreakpointDialog_Choose_an_exception_filter_message); fExceptionFilter = new Text(area, SWT.BORDER); GridData gridData = new GridData(GridData.FILL_HORIZONTAL); fExceptionFilter.setLayoutData(gridData); fExceptionFilter.addModifyListener(new ModifyListener() { @Override public void modifyText(ModifyEvent e) { filterExceptionTypes(fExceptionFilter.getText()); } }); fExceptionFilter.addKeyListener(new KeyAdapter() { public void keyPressed(KeyEvent e) { if (e.keyCode == SWT.ARROW_DOWN) { fExceptionViewer.getTable().setFocus(); } } }); Label itemsLabel = new Label(area, SWT.NONE); itemsLabel.setText(Messages.AddPHPExceptionBreakpointDialog_Matching_items); fExceptionViewer = new TableViewer(area, SWT.BORDER | SWT.MULTI); gridData = new GridData(SWT.FILL, SWT.FILL, true, true); PixelConverter converter = new PixelConverter(fExceptionViewer.getTable()); gridData.widthHint = converter.convertWidthInCharsToPixels(60); gridData.heightHint = SWTUtil.getTableHeightHint(fExceptionViewer.getTable(), 10); fExceptionViewer.getTable().setLayoutData(gridData); fExceptionViewer.getTable().setFont(parent.getFont()); fExceptionViewer.getTable().addMouseListener(new MouseAdapter() { @Override public void mouseDoubleClick(MouseEvent e) { okPressed(); } }); fExceptionViewer.setContentProvider(new ArrayContentProvider()); fExceptionViewer.setLabelProvider(new LabelProvider()); Collection<IType> input = fExceptionTypesCache; fExceptionViewer.setInput(fExceptionTypesCache); if (!input.isEmpty()) { fExceptionViewer.setSelection(new StructuredSelection(input.iterator().next())); } CLabel noteIcon = new CLabel(area, SWT.NONE); noteIcon.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1)); noteIcon.setImage(Dialog.getImage(Dialog.DLG_IMG_MESSAGE_INFO)); noteIcon.setText(Messages.AddPHPExceptionBreakpointDialog_Note); return area; } /* * @see Dialog#okPressed() */ @Override protected void okPressed() { computeResult(); super.okPressed(); } private void computeResult() { List<Object> results = new ArrayList<Object>(); IStructuredSelection selection = fExceptionViewer.getStructuredSelection(); for (Object element : selection.toArray()) { results.add(element); } setResult(results); } private void initializeSettings() { IDialogSettings settings = PHPDebugUIPlugin.getDefault().getDialogSettings(); fSettings = settings.getSection(DIALOG_SETTINGS); if (fSettings == null) { fSettings = new DialogSettings(DIALOG_SETTINGS); settings.addSection(fSettings); fSettings.put(WIDTH, 480); fSettings.put(HEIGHT, 320); } } private void readSettings() { try { int x = fSettings.getInt("x"); //$NON-NLS-1$ int y = fSettings.getInt("y"); //$NON-NLS-1$ fLocation = new Point(x, y); } catch (NumberFormatException e) { fLocation = null; } try { int width = fSettings.getInt("width"); //$NON-NLS-1$ int height = fSettings.getInt("height"); //$NON-NLS-1$ fSize = new Point(width, height); } catch (NumberFormatException e) { fSize = null; } } private void writeSettings() { Point location = getShell().getLocation(); fSettings.put("x", location.x); //$NON-NLS-1$ fSettings.put("y", location.y); //$NON-NLS-1$ Point size = getShell().getSize(); fSettings.put("width", size.x); //$NON-NLS-1$ fSettings.put("height", size.y); //$NON-NLS-1$ } private void filterExceptionTypes(String text) { String patternBase = text.replaceAll("\\*", ".*").replaceAll("\\?", ".").concat(".*"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ Pattern pattern = Pattern.compile(patternBase, Pattern.CASE_INSENSITIVE); List<IType> filtered = new LinkedList<IType>(); for (IType type : fExceptionTypesCache) { if (pattern.matcher(type.getElementName()).matches()) { filtered.add(type); } } fExceptionViewer.setInput(filtered); if (!filtered.isEmpty()) { fExceptionViewer.setSelection(new StructuredSelection(filtered.iterator().next())); } } private void fetchExceptionTypes() { if (fExceptionTypesCache == null) { fExceptionTypesCache = new TreeSet<IType>(new Comparator<IType>() { public int compare(IType o1, IType o2) { if (o1 instanceof ErrorType && !(o2 instanceof ErrorType)) return -1; return o1.getElementName().toLowerCase().compareTo(o2.getElementName().toLowerCase()); } }); final PHPModelAccess modelAccess = PHPModelAccess.getDefault(); final IDLTKSearchScope scope = SearchEngine.createWorkspaceScope(PHPLanguageToolkit.getDefault()); // Make sure that scope is up-to-date scope.enclosingProjectsAndZips(); IType[] exceptionBaseTypes = modelAccess.findTypes(EXCEPTION_BASE_CLASS_NAME, MatchRule.EXACT, 0, 0, scope, null); for (IType exceptionBaseType : exceptionBaseTypes) { try { fExceptionTypesCache.add(exceptionBaseType); ITypeHierarchy hierarchy = exceptionBaseType.newTypeHierarchy(new NullProgressMonitor()); IType[] subtypes = hierarchy.getAllSubtypes(exceptionBaseType); for (IType subType : subtypes) { fExceptionTypesCache.add(subType); } } catch (ModelException e) { Logger.logException(e); } } for (IType mockType : ERROR_TYPES) { fExceptionTypesCache.add(mockType); } } } }