/******************************************************************************* * Copyright (c) 2004, 2016 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 * Lars Vogel <Lars.Vogel@vogella.com> - Bug 490755 *******************************************************************************/ package org.eclipse.debug.internal.ui.actions.breakpointGroups; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import org.eclipse.debug.internal.ui.IDebugHelpContextIds; import org.eclipse.debug.internal.ui.SWTFactory; import org.eclipse.debug.internal.ui.breakpoints.provisional.IBreakpointOrganizer; import org.eclipse.debug.internal.ui.views.breakpoints.BreakpointOrganizerManager; import org.eclipse.debug.internal.ui.views.breakpoints.BreakpointsView; import org.eclipse.jface.dialogs.Dialog; import org.eclipse.jface.dialogs.TrayDialog; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ILabelProvider; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITreeContentProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TreeViewer; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; 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.Table; import org.eclipse.swt.widgets.Tree; import org.eclipse.ui.PlatformUI; /** * Dialog which presents available breakpoint groupings to * the user and allows them to specify which they'd like * to use and in what order they should be applied. */ public class GroupBreakpointsByDialog extends TrayDialog { private BreakpointsView fView; // Table viewer that presents available containers private TableViewer fAvailableViewer; private AvailableOrganizersProvider fAvailableOrganizersProvider= new AvailableOrganizersProvider(); // Tree viewer that presents selected containers private TreeViewer fSelectedViewer; private SelectedOrganizerProvider fSelectedOrganizersProvider= new SelectedOrganizerProvider(); private List<Object> fResult = new ArrayList<Object>(); private Button fAddButton; private Button fRemoveButton; private Button fMoveUpButton; private Button fMoveDownButton; /** * Selection listener that listens to selection from all buttons in this * dialog. */ private SelectionAdapter fSelectionListener= new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { Object source= e.getSource(); if (source == fAddButton) { handleAddPressed(); } else if (source == fRemoveButton) { handleRemovePressed(); } else if (source == fMoveUpButton) { handleMoveUpPressed(); } else if (source == fMoveDownButton) { handleMoveDownPressed(); } } }; protected GroupBreakpointsByDialog(BreakpointsView view) { super(view.getSite().getShell()); fView= view; setShellStyle(getShellStyle() | SWT.RESIZE); } /* (non-Javadoc) * @see org.eclipse.jface.dialogs.Dialog#createDialogArea(org.eclipse.swt.widgets.Composite) */ @Override protected Control createDialogArea(Composite parent) { ILabelProvider labelProvider= new BreakpointOrganzierLabelProvider(); Composite parentComposite= (Composite) super.createDialogArea(parent); parentComposite.setFont(parent.getFont()); Composite composite= new Composite(parentComposite, SWT.NONE); GridLayout layout = new GridLayout(); layout.numColumns = 3; composite.setLayout(layout); GridData data= new GridData(GridData.FILL_BOTH); data.heightHint= 400; composite.setLayoutData(data); composite.setFont(parent.getFont()); Label label= new Label(composite, SWT.WRAP); label.setText(BreakpointGroupMessages.GroupBreakpointsByDialog_0); GridData gridData = new GridData(GridData.FILL_HORIZONTAL); gridData.horizontalSpan = 3; label.setLayoutData(gridData); createAvailableViewer(composite, labelProvider); createButtons(composite); createSelectedViewer(composite, labelProvider); initializeContent(); updateViewers(); Dialog.applyDialogFont(parentComposite); return parentComposite; } /* (non-Javadoc) * @see org.eclipse.jface.dialogs.Dialog#createContents(org.eclipse.swt.widgets.Composite) */ @Override protected Control createContents(Composite parent) { Control contents = super.createContents(parent); PlatformUI.getWorkbench().getHelpSystem().setHelp(getDialogArea(), IDebugHelpContextIds.GROUP_BREAKPOINTS_DIALOG); return contents; } /** * Divides the available breakpoint container factories into the * appropriate viewers ("available" or "selected"). */ private void initializeContent() { IBreakpointOrganizer[] organizers= BreakpointOrganizerManager.getDefault().getOrganizers(); for (int i = 0; i < organizers.length; i++) { fAvailableOrganizersProvider.addAvailable(organizers[i]); } organizers = fView.getBreakpointOrganizers(); if (organizers != null) { for (int i = 0; i < organizers.length; i++) { fSelectedOrganizersProvider.addSelected(organizers[i]); } } } /** * Creates and configured the viewer that shows the available (not currently selected) * breakpoint container factories. */ private void createAvailableViewer(Composite parent, ILabelProvider labelProvider) { Composite availableComposite= new Composite(parent, SWT.NONE); availableComposite.setFont(parent.getFont()); GridLayout layout = new GridLayout(); layout.marginHeight=0; layout.marginWidth=0; availableComposite.setLayout(layout); GridData gridData= new GridData(GridData.FILL_BOTH); gridData.widthHint= 225; availableComposite.setLayoutData(gridData); Label label= new Label(availableComposite, SWT.WRAP); label.setText(BreakpointGroupMessages.GroupBreakpointsByDialog_1); gridData = new GridData(GridData.FILL_HORIZONTAL); label.setLayoutData(gridData); fAvailableViewer= new TableViewer(availableComposite); fAvailableViewer.setContentProvider(fAvailableOrganizersProvider); fAvailableViewer.setLabelProvider(labelProvider); fAvailableViewer.setInput(new Object()); Table table = fAvailableViewer.getTable(); table.setLayoutData(new GridData(GridData.FILL_BOTH)); table.setFont(parent.getFont()); fAvailableViewer.addDoubleClickListener(new IDoubleClickListener() { @Override public void doubleClick(DoubleClickEvent event) { handleAddPressed(); } }); fAvailableViewer.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { updateAddButton(); } }); } /** * Creates and configures the viewer that shows the currently selected * breakpoint container factories. */ private void createSelectedViewer(Composite parent, ILabelProvider labelProvider) { Composite selectedComposite= new Composite(parent, SWT.NONE); GridLayout layout = new GridLayout(); layout.marginHeight=0; layout.marginWidth=0; layout.numColumns= 2; selectedComposite.setLayout(layout); GridData gridData= new GridData(GridData.FILL_BOTH); gridData.widthHint= 225; selectedComposite.setLayoutData(gridData); selectedComposite.setFont(parent.getFont()); Label label= new Label(selectedComposite, SWT.WRAP); label.setText(BreakpointGroupMessages.GroupBreakpointsByDialog_3); gridData = new GridData(); gridData.horizontalSpan = 2; label.setLayoutData(gridData); fSelectedViewer= new TreeViewer(selectedComposite); fSelectedViewer.setContentProvider(fSelectedOrganizersProvider); fSelectedViewer.setLabelProvider(labelProvider); fSelectedViewer.setInput(new Object()); Tree tree = fSelectedViewer.getTree(); tree.setLayoutData(new GridData(GridData.FILL_BOTH)); tree.setFont(parent.getFont()); fSelectedViewer.addDoubleClickListener(new IDoubleClickListener() { @Override public void doubleClick(DoubleClickEvent event) { handleRemovePressed(); } }); fSelectedViewer.addSelectionChangedListener(new ISelectionChangedListener() { @Override public void selectionChanged(SelectionChangedEvent event) { updateSelectedButtons(); } }); } public void createButtons(Composite parent) { Composite buttonComposite= new Composite(parent, SWT.NONE); buttonComposite.setLayout(new GridLayout()); buttonComposite.setLayoutData(new GridData()); buttonComposite.setFont(parent.getFont()); fAddButton= SWTFactory.createPushButton(buttonComposite, BreakpointGroupMessages.GroupBreakpointsByDialog_2, null); fAddButton.addSelectionListener(fSelectionListener); fRemoveButton= SWTFactory.createPushButton(buttonComposite, BreakpointGroupMessages.GroupBreakpointsByDialog_4, null); fRemoveButton.addSelectionListener(fSelectionListener); fMoveUpButton= SWTFactory.createPushButton(buttonComposite, BreakpointGroupMessages.GroupBreakpointsByDialog_5, null); fMoveUpButton.addSelectionListener(fSelectionListener); fMoveDownButton= SWTFactory.createPushButton(buttonComposite, BreakpointGroupMessages.GroupBreakpointsByDialog_6, null); fMoveDownButton.addSelectionListener(fSelectionListener); } /** * Returns the organizers chosen by the user. The order * of the list is the order that the organizers should be displayed * in the breakpoints view. * @return the breakpoint organizers chosen by the user */ public IBreakpointOrganizer[] getOrganizers() { return fResult.toArray(new IBreakpointOrganizer[fResult.size()]); } /** * When the user presses OK, convert the tree selection into a list. */ @Override protected void okPressed() { Object[] factories= fSelectedOrganizersProvider.getElements(null); while (factories.length > 0) { Object factory= factories[0]; fResult.add(factory); factories= fSelectedOrganizersProvider.getChildren(factory); } super.okPressed(); } /** * Moves the selected item from the list of "available" factories * to the tree of "selected" factories. */ public void handleAddPressed() { IStructuredSelection selection= (IStructuredSelection) fAvailableViewer.getSelection(); if (selection.size() < 1) { return; } Iterator<?> iter = selection.iterator(); while (iter.hasNext()) { fSelectedOrganizersProvider.addSelected((IBreakpointOrganizer) iter.next()); } updateViewers(); } /** * Moves the selected item from the tree of "selected" factories * to the list of "available" factories. */ public void handleRemovePressed() { IStructuredSelection selection= (IStructuredSelection) fSelectedViewer.getSelection(); if (selection.size() < 1) { return; } Iterator<?> iter = selection.iterator(); while (iter.hasNext()) { fAvailableOrganizersProvider.addAvailable((IBreakpointOrganizer) iter.next()); } updateViewers(); } /** * Moves each selected item up in the tree of selected containers */ public void handleMoveUpPressed() { IStructuredSelection selection = (IStructuredSelection) fSelectedViewer.getSelection(); Iterator<?> iter = selection.iterator(); while (iter.hasNext()) { fSelectedOrganizersProvider.moveUp(iter.next()); } updateViewers(); } /** * Moves each selected item down in the tree of selected containers */ public void handleMoveDownPressed() { IStructuredSelection selection = (IStructuredSelection) fSelectedViewer.getSelection(); Object[] elements= selection.toArray(); for (int i= elements.length - 1; i >= 0; i--) { fSelectedOrganizersProvider.moveDown(elements[i]); } updateViewers(); } /** * Fully refreshes and updates all viewers and buttons. */ public void updateViewers() { fAvailableViewer.refresh(); fSelectedViewer.refresh(); fSelectedViewer.expandAll(); updateAddButton(); updateSelectedButtons(); } /** * Updates all buttons associated with the tree of selected containers. */ public void updateSelectedButtons() { updateRemoveButton(); updateMoveUpButton(); updateMoveDownButton(); } public void updateAddButton() { IStructuredSelection selection = (IStructuredSelection) fAvailableViewer.getSelection(); fAddButton.setEnabled(selection.size() > 0); } public void updateRemoveButton() { IStructuredSelection selection = (IStructuredSelection) fSelectedViewer.getSelection(); fRemoveButton.setEnabled(selection.size() > 0); } public void updateMoveUpButton() { boolean enabled= true; IStructuredSelection selection = (IStructuredSelection) fSelectedViewer.getSelection(); if (selection.size() == 0) { enabled= false; } else { Object firstSelected= selection.getFirstElement(); Object parent= fSelectedOrganizersProvider.getParent(firstSelected); if (!(parent instanceof IBreakpointOrganizer)) { enabled= false; } } fMoveUpButton.setEnabled(enabled); } public void updateMoveDownButton() { boolean enabled= true; IStructuredSelection selection = (IStructuredSelection) fSelectedViewer.getSelection(); if (selection.size() == 0) { enabled= false; } else { Object lastSelected= selection.toList().get(selection.size() - 1); Object[] children= fSelectedOrganizersProvider.getChildren(lastSelected); if (children.length < 1) { enabled= false; } } fMoveDownButton.setEnabled(enabled); } /** * Content provider that provides the list of breakpoint organaisers * that are available but not currently selected. */ private class AvailableOrganizersProvider implements IStructuredContentProvider { protected List<IBreakpointOrganizer> availableOrganziers = new ArrayList<IBreakpointOrganizer>(); public void addAvailable(IBreakpointOrganizer organizer) { availableOrganziers.add(organizer); fSelectedOrganizersProvider.selectedOrganizers.remove(organizer); } @Override public Object[] getElements(Object inputElement) { return availableOrganziers.toArray(); } @Override public void dispose() { } @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } } /** * Content provider that returns the selected breakpoint organizers * as a tree. This tree shows the list of organzizers as they will * appear in the breakpoints view. */ private class SelectedOrganizerProvider implements ITreeContentProvider { protected List<Object> selectedOrganizers = new ArrayList<Object>(); public void addSelected(IBreakpointOrganizer organizer) { selectedOrganizers.add(organizer); fAvailableOrganizersProvider.availableOrganziers.remove(organizer); } public void moveUp(Object object) { int index = selectedOrganizers.indexOf(object); if (index > 0) { selectedOrganizers.remove(object); selectedOrganizers.add(index - 1, object); } } public void moveDown(Object object) { int index = selectedOrganizers.indexOf(object); if (index < selectedOrganizers.size() - 1) { selectedOrganizers.remove(object); selectedOrganizers.add(index + 1, object); } } @Override public Object[] getChildren(Object parentElement) { // A factory's "child" is the next factory in the list int index = selectedOrganizers.indexOf(parentElement); if (index < selectedOrganizers.size() - 1) { return new Object[] { selectedOrganizers.get(index + 1) }; } return new Object[0]; } @Override public Object getParent(Object element) { // A factory's "parent" is the factory before it int index = selectedOrganizers.indexOf(element); if (index <= 0 || selectedOrganizers.size() <= 1) { return null; } return selectedOrganizers.get(index - 1); } @Override public boolean hasChildren(Object element) { // A factory has "children" if there are more // factories after it. int index = selectedOrganizers.indexOf(element); return index != -1 && index < selectedOrganizers.size() - 1; } @Override public Object[] getElements(Object inputElement) { if (selectedOrganizers.size() > 0) { return new Object[] { selectedOrganizers.get(0) }; } return new Object[0]; } } /** * Label provider which provides text and images for breakpoint container factories */ private class BreakpointOrganzierLabelProvider extends LabelProvider { private HashMap<ImageDescriptor, Image> fImageCache = new HashMap<ImageDescriptor, Image>(); @Override public String getText(Object element) { if (element instanceof IBreakpointOrganizer) { return ((IBreakpointOrganizer) element).getLabel(); } return super.getText(element); } @Override public Image getImage(Object element) { if (element instanceof IBreakpointOrganizer) { ImageDescriptor imageDescriptor = ((IBreakpointOrganizer) element).getImageDescriptor(); if (imageDescriptor != null) { Image image = fImageCache.get(imageDescriptor); if (image == null) { image= imageDescriptor.createImage(); if (image != null) { fImageCache.put(imageDescriptor, image); } } return image; } } return super.getImage(element); } @Override public void dispose() { for (Image image : fImageCache.values()) { image.dispose(); } super.dispose(); } } /* * (non-Javadoc) * * @see org.eclipse.jface.window.Window#configureShell(org.eclipse.swt.widgets.Shell) */ @Override protected void configureShell(Shell shell) { super.configureShell(shell); shell.setText(BreakpointGroupMessages.GroupBreakpointsByDialog_7); } }