/******************************************************************************* * Copyright (C) 2003-2007, 2013, Guillaume Brocker * Copyright (C) 2015-2017, Andre Bossert * * 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: * Guillaume Brocker - Initial API and implementation * Andre Bossert - #171: added sorting column in advanced tab * ******************************************************************************/ package eclox.ui.editor.advanced; import java.text.Collator; import java.util.HashSet; import java.util.Iterator; import java.util.Locale; import java.util.Set; import org.eclipse.jface.viewers.DoubleClickEvent; import org.eclipse.jface.viewers.IDoubleClickListener; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.ITableLabelProvider; import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.LabelProviderChangedEvent; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.jface.viewers.Viewer; import org.eclipse.swt.SWT; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.FillLayout; import org.eclipse.swt.layout.FormAttachment; import org.eclipse.swt.layout.FormData; import org.eclipse.swt.layout.FormLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.ui.ISharedImages; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.forms.DetailsPart; import org.eclipse.ui.forms.IFormPart; import org.eclipse.ui.forms.IManagedForm; import org.eclipse.ui.forms.IPartSelectionListener; import org.eclipse.ui.forms.SectionPart; import org.eclipse.ui.forms.widgets.FormToolkit; import org.eclipse.ui.forms.widgets.Section; import eclox.core.doxyfiles.Doxyfile; import eclox.core.doxyfiles.ISettingPropertyListener; import eclox.core.doxyfiles.Setting; import eclox.ui.editor.Editor; import eclox.ui.editor.advanced.filters.All; import eclox.ui.editor.advanced.filters.ByGroup; import eclox.ui.editor.advanced.filters.Custom; import eclox.ui.editor.advanced.filters.IFilter; import eclox.ui.editor.advanced.filters.Modified; /** * Implements the master part's user interface. * * @author gbrocker */ public class MasterPart extends SectionPart implements IPartSelectionListener { /** * Implements the master content provider. */ private class MyContentProvider implements IStructuredContentProvider { /** * @see org.eclipse.jface.viewers.IContentProvider#dispose() */ public void dispose() { } /** * @see org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java.lang.Object) */ public Object[] getElements(Object inputElement) { Doxyfile doxyfile = (Doxyfile) inputElement; return doxyfile.getSettings(); } /** * @see org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface.viewers.Viewer, java.lang.Object, java.lang.Object) */ public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { } } /** * Implements the mouse listener attached to the table. * * This listener will search for a DetailsPart in the managed form given * at construction time and will set the focus on that part. */ private class MyDoubleClickListener implements IDoubleClickListener { /** * @see org.eclipse.jface.viewers.IDoubleClickListener#doubleClick(org.eclipse.jface.viewers.DoubleClickEvent) */ public void doubleClick(DoubleClickEvent event) { IManagedForm managedForm = getManagedForm(); // Searchs for the details part in the managed form and set the focus on it. IFormPart parts[] = managedForm.getParts(); for (int i = 0; i < parts.length; ++i) { IFormPart currentPart = parts[i]; if (currentPart instanceof DetailsPart) { currentPart.setFocus(); break; } } } } /** * Implements a filter button listener */ private class MyFilterButtonListener implements SelectionListener { /** * @see org.eclipse.swt.events.SelectionListener#widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent) */ public void widgetDefaultSelected(SelectionEvent e) { Object data = e.widget.getData(); IFilter filter = (IFilter) data; activateFilter(filter); } /** * @see org.eclipse.swt.events.SelectionListener#widgetSelected(org.eclipse.swt.events.SelectionEvent) */ public void widgetSelected(SelectionEvent e) { Object data = e.widget.getData(); IFilter filter = (IFilter) data; activateFilter(filter); } } /** * Implements the label provider. */ private class MyLabelProvider extends LabelProvider implements ITableLabelProvider, ISettingPropertyListener { /** * the set of all settings the label provider has registered to */ private Set<Setting> settings = new HashSet<Setting>(); /** * @see org.eclipse.jface.viewers.IBaseLabelProvider#dispose() */ public void dispose() { // Walks through all settings and unregisters from the listeners Iterator<Setting> i = settings.iterator(); while (i.hasNext() == true) { Object object = i.next(); Setting setting = (Setting) object; setting.removeSettingListener(this); } settings.clear(); super.dispose(); } /** * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang.Object, int) */ public Image getColumnImage(Object element, int columnIndex) { // We don't have any image to return. return null; } /** * @see org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang.Object, int) */ public String getColumnText(Object element, int columnIndex) { // Pre-condition assert element instanceof Setting; // Retrieves the setting's text. Setting setting = (Setting) element; // Registers as an observer of the setting setting.addSettingListener(this); settings.add(setting); // Determine the text to return according to the given column index. if (columnIndex == TEXT_COLUMN) { return setting.getTextLabel(Editor.PROP_SETTING_DIRTY); } else if (columnIndex == VALUE_COLUMN) { return setting.getValueLabel(); } return null; } public void settingPropertyChanged(Setting setting, String property) { if (property.equals(Editor.PROP_SETTING_DIRTY)) { fireLabelProviderChanged(new LabelProviderChangedEvent(this, setting)); } } public void settingPropertyRemoved(Setting setting, String property) { if (property.equals(Editor.PROP_SETTING_DIRTY)) { fireLabelProviderChanged(new LabelProviderChangedEvent(this, setting)); } } } /** * Implements a tree viewer selection listener. */ private class MyTableSelectionListener implements ISelectionChangedListener { /** * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent) */ public void selectionChanged(SelectionChangedEvent event) { ISelection selection = event.getSelection(); if (selection.isEmpty() == false) { assert selection instanceof StructuredSelection; // Updates the selection StructuredSelection structuredSelection = (StructuredSelection) selection; setSelection(currentSelection.select(structuredSelection.getFirstElement()), false); } } } /** the text column index */ private final static int TEXT_COLUMN = 0; /** the value column index */ private final static int VALUE_COLUMN = 1; /** the doxyfile being edited */ private Doxyfile doxyfile; /** the active filter */ private IFilter activeFilter; /** the default filter */ private IFilter defaultFilter = new All(); /** the parent composite for filter buttons */ private Composite filterButtons; /** the parent composite for filter controls */ private Composite filterControls; /** the list viewer */ private TableViewer tableViewer; /** the table viewer selection listener */ private MyTableSelectionListener tableViewerSelectionListener; /** the go backward history action */ private HistoryAction goBack = new HistoryAction(HistoryAction.BACK, this); /** the go foreward history action */ private HistoryAction goForward = new HistoryAction(HistoryAction.FORWARD, this); /** the current selection */ private NavigableSelection currentSelection = new NavigableSelection(); /** * Constructor * * @param parent a composite that is the parent of all part controls * @param toolkit a toolkit used to create the part controls. * @param doxyfile a doxyfile to edit */ public MasterPart(Composite parent, FormToolkit toolkit, Doxyfile doxyfile) { super(parent, toolkit, Section.TITLE_BAR | Section.COMPACT); this.doxyfile = doxyfile; // Initializes the managed section. Section section = getSection(); section.setText("Settings"); section.marginHeight = 5; section.marginWidth = 10; toolkit.paintBordersFor(section); // Creates the main section container. Composite rootContainer = toolkit.createComposite(section); section.setClient(rootContainer); rootContainer.setLayout(new FormLayout()); // Continues with other initializations. createFilterButtons(toolkit, rootContainer); createSubControls(toolkit, rootContainer); // Adds some filters. addFilter(toolkit, defaultFilter); addFilter(toolkit, new ByGroup()); addFilter(toolkit, new Custom()); addFilter(toolkit, new Modified()); // Activates the default filter. activateFilter(defaultFilter); } /** * Activates the specified filter. * * @param filter a filter that must be activated */ private void activateFilter(IFilter filter) { Section section = getSection(); // Freezes the section widget. section.setRedraw(false); // Updates the filter button's state. Control[] controls = filterButtons.getChildren(); for (int i = 0; i < controls.length; ++i) { Control control = controls[i]; Button button = (Button) control; button.setSelection(control.getData() == filter); } // If there is a new filter to activate, do the activation job. if (filter != activeFilter) { // Deactivates the previous filter. if (activeFilter != null) { activeFilter.disposeViewerFilers(tableViewer); activeFilter.disposeControls(); activeFilter.setDoxyfile(null); activeFilter = null; } // Activates the new filter. activeFilter = filter; activeFilter.setDoxyfile(doxyfile); activeFilter.createControls(getManagedForm(), filterControls); activeFilter.createViewerFilters(tableViewer); tableViewer.refresh(); // Adapts the size of the filter control container & relayout the section content. Object tableLayoutData = tableViewer.getTable().getLayoutData(); FormData tableFormData = (FormData) tableLayoutData; if (filterControls.getChildren().length == 0) { filterControls.setVisible(false); tableFormData.top = new FormAttachment(0, 0); } else { filterControls.setVisible(true); tableFormData.top = new FormAttachment(filterControls, 6, SWT.BOTTOM); } // Reactivates section widget. section.layout(true, true); } // Reactivates the redrawing. section.setRedraw(true); } /** * Adds a new filter to the master part. * * @param toolkit a toolkit to use for the widget creation * @param filter a new filter to add */ private void addFilter(FormToolkit toolkit, IFilter filter) { Button button = toolkit.createButton(filterButtons, filter.getName(), SWT.FLAT | SWT.TOGGLE); button.setData(filter); button.addSelectionListener(new MyFilterButtonListener()); } /** * Creates all buttons for setting filters. * * @param toolkit the form tool to use for the control creation * @param parent a composite that will be the parent of all controls */ private void createFilterButtons(FormToolkit toolkit, Composite parent) { // Pre-condition assert filterButtons == null; assert filterControls == null; // Creates the filter button container. FillLayout buttonContainerLayout = new FillLayout(SWT.HORIZONTAL); filterButtons = toolkit.createComposite(parent); buttonContainerLayout.marginWidth = 0; buttonContainerLayout.marginHeight = 0; buttonContainerLayout.spacing = 3; filterButtons.setLayout(buttonContainerLayout); // Assignes layout data fo the filter button container. FormData buttonFormData = new FormData(); buttonFormData.top = new FormAttachment(0, 0); buttonFormData.right = new FormAttachment(100, 0); buttonFormData.left = new FormAttachment(0, 0); filterButtons.setLayoutData(buttonFormData); // Post-condition assert filterButtons != null; } private TableViewerColumn createColumnFor(TableViewer viewer, String label) { TableViewerColumn column = new TableViewerColumn(viewer, SWT.NONE); column.getColumn().setWidth(200); column.getColumn().setText(label); column.getColumn().setMoveable(true); return column; } /** * Creates controls subordinated to the filter buttons. */ private void createSubControls(FormToolkit toolkit, Composite parent) { // Pre-condition assert filterButtons != null; assert filterControls == null; assert tableViewer == null; toolkit.paintBordersFor(parent); // Creates the sub parent control container. Composite subParent = toolkit.createComposite(parent); FormData subParentFormData = new FormData(); subParentFormData.top = new FormAttachment(filterButtons, 6, SWT.BOTTOM); subParentFormData.right = new FormAttachment(100, -2); subParentFormData.bottom = new FormAttachment(100, -2); subParentFormData.left = new FormAttachment(0, 1); subParentFormData.height = 50; subParent.setLayoutData(subParentFormData); subParent.setLayout(new FormLayout()); subParent.setData(FormToolkit.KEY_DRAW_BORDER, FormToolkit.TEXT_BORDER); // Creates the filter control container. FormData controlFormData = new FormData(); controlFormData.top = new FormAttachment(0, 5); controlFormData.right = new FormAttachment(100, -5); controlFormData.left = new FormAttachment(0, 5); filterControls = toolkit.createComposite(subParent); filterControls.setLayoutData(controlFormData); // Creates the table widget that will display all settings. Table table = new Table(subParent, SWT.V_SCROLL | SWT.FULL_SELECTION); FormData formData = new FormData(); formData.top = new FormAttachment(filterControls, 5, SWT.BOTTOM); formData.right = new FormAttachment(100, 0); formData.bottom = new FormAttachment(100, 0); formData.left = new FormAttachment(0, 0); formData.height = 10; formData.width = 10; table.setLayoutData(formData); table.setHeaderVisible(true); // Adds some columns to the table /* TableColumn tableColumn; tableColumn = new TableColumn( table, SWT.LEFT, TEXT_COLUMN ); tableColumn.setText( "Name" ); tableColumn = new TableColumn( table, SWT.LEFT, VALUE_COLUMN ); tableColumn.setText( "Value" ); */ // Creates the table viewer. tableViewer = new TableViewer(table); // create columns final Collator collator = Collator.getInstance(Locale.getDefault()); TableViewerColumn nameColumn = createColumnFor(tableViewer, "Name"); ColumnViewerComparator nameSorter = new ColumnViewerComparator(tableViewer, nameColumn) { @Override protected int doCompare(Viewer viewer, Object e1, Object e2) { //String string1 = ((Setting) e1).getIdentifier(); String string1 = ((Setting) e1).getTextLabel(Editor.PROP_SETTING_DIRTY); //String string2 = ((Setting) e2).getIdentifier(); String string2 = ((Setting) e2).getTextLabel(Editor.PROP_SETTING_DIRTY); return collator.compare(string1, string2); } }; TableViewerColumn valueColumn = createColumnFor(tableViewer, "Value"); /*ColumnViewerComparator valueSorter = */new ColumnViewerComparator(tableViewer, valueColumn) { @Override protected int doCompare(Viewer viewer, Object e1, Object e2) { //String string1 = ((Setting) e1).getValue(); String string1 = ((Setting) e1).getValueLabel(); //String string2 = ((Setting) e2).getValue(); String string2 = ((Setting) e2).getValueLabel(); return collator.compare(string1, string2); } }; nameSorter.setSorter(nameSorter, ColumnViewerComparator.NONE); tableViewer.setContentProvider(new MyContentProvider()); tableViewer.setLabelProvider(new MyLabelProvider()); tableViewer.setInput(doxyfile); // Updates the column widths. TableColumn columns[] = table.getColumns(); columns[TEXT_COLUMN].pack(); columns[VALUE_COLUMN].pack(); // Post-condition assert filterControls != null; assert tableViewer != null; } /** * @see org.eclipse.ui.forms.AbstractFormPart#initialize(org.eclipse.ui.forms.IManagedForm) */ public void initialize(IManagedForm form) { // Pre-condition assert tableViewer != null; // Installs several listeners. tableViewerSelectionListener = new MyTableSelectionListener(); tableViewer.addPostSelectionChangedListener(tableViewerSelectionListener); tableViewer.addDoubleClickListener(new MyDoubleClickListener()); // Installs the actions goBack.setImageDescriptor( PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_TOOL_BACK)); goForward.setImageDescriptor( PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_TOOL_FORWARD)); form.getForm().getToolBarManager().add(goBack); form.getForm().getToolBarManager().add(goForward); goBack.selectionChanged(new NavigableSelection()); goForward.selectionChanged(new NavigableSelection()); // Default job done by super class. super.initialize(form); } /** * @see org.eclipse.ui.forms.AbstractFormPart#isStale() */ public boolean isStale() { // We always answer yes because it is currently not trivial // to know if the data model has changed since last refresh. return true; } /** * @see org.eclipse.ui.forms.AbstractFormPart#refresh() */ public void refresh() { tableViewer.refresh(); super.refresh(); } /** * @see org.eclipse.ui.forms.IPartSelectionListener#selectionChanged(org.eclipse.ui.forms.IFormPart, org.eclipse.jface.viewers.ISelection) */ public void selectionChanged(IFormPart part, ISelection selection) { assert selection instanceof NavigableSelection; currentSelection = (NavigableSelection) selection; // Activates the default filter. activateFilter(defaultFilter); revealObject(currentSelection.getFirstElement()); // Updates the navigation actions. goBack.selectionChanged(selection); goForward.selectionChanged(selection); } /** * Set the new selection of the part. This will forward the selection to the form * so other parts will be notified about the selection change. * * @param selection the new selection * @param reveal tells if the selection should be revealed in the controls */ public void setSelection(NavigableSelection selection, boolean reveal) { currentSelection = selection; // If requested, reveals the selection's first element if (reveal == true) { revealObject(selection.getFirstElement()); } // Updates the actions goBack.selectionChanged(currentSelection); goForward.selectionChanged(currentSelection); // Notifies other parts. getManagedForm().fireSelectionChanged(this, selection); } /** * Reveals the given object into the managed table viewer by selecting it. * * @param object the object to reveal */ private void revealObject(Object object) { StructuredSelection selection = (object != null) ? new StructuredSelection(object) : new StructuredSelection(); tableViewer.removePostSelectionChangedListener(tableViewerSelectionListener); tableViewer.setSelection(selection, true); tableViewer.addPostSelectionChangedListener(tableViewerSelectionListener); } }