blob: 21702c61c10cc62e7b21056de8d90eb5c2acf6d6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2016 ALL4TEC & CEA LIST.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* ALL4TEC & CEA LIST - initial API and implementation
******************************************************************************/
package org.polarsys.esf.core.common.ui.widget;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTarget;
import org.eclipse.swt.dnd.DropTargetAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.ModifyEvent;
import org.eclipse.swt.events.ModifyListener;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.events.MouseTrackAdapter;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.Text;
import org.polarsys.esf.core.common.ui.CommonUIActivator;
import org.polarsys.esf.core.common.ui.CommonUIActivator.Implementation;
import org.polarsys.esf.core.common.ui.actions.FilterPartAction;
import org.polarsys.esf.core.common.ui.constants.ImageConstants;
import org.polarsys.esf.core.common.ui.filter.FilterPartManager;
import org.polarsys.esf.core.common.ui.filter.IFilterPartListener;
/**
* Composite used to display all what is needed for the filter mechanisms.
* This include the field to select the filter value, the menu to apply
* to filter on available parts, etc.
*
* @author $Author: jdumont $
* @version $Revision: 83 $
*/
public class FilterComposite
extends Composite {
/** The preferred width for the composite. */
private static final int CONTROL_WIDTH = 200;
/** The preferred height for the composite. */
private static final int CONTROL_HEIGHT = 17;
/** Reference to the singleton which manages the filter mechanisms. */
private static final FilterPartManager FILTER_PART_MANAGER = FilterPartManager.INSTANCE;
/** The filter text field. */
private Text mFilterTextField = null;
/** The clear label. */
private Label mClearLabel = null;
/** The search label. */
private Label mSearchLabel = null;
/**
* Default constructor.
*
* @param pParent The parent composite
*/
public FilterComposite(final Composite pParent) {
// Call the parent constructor
super(pParent, SWT.FLAT);
// Create its content
createContent(pParent);
}
/**
* Create the content of the composite, with all the needed widgets.
*
* @param pParent The parent composite
*/
private void createContent(final Composite pParent) {
// Initialise the layout of this instance
final GridLayout vMainLayout = new GridLayout();
vMainLayout.marginHeight = 0;
vMainLayout.marginWidth = 1;
setLayout(vMainLayout);
// Create the filter composite
final Composite vFilterComposite = new Composite(this, SWT.BORDER);
vFilterComposite.setBackground(getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
// Initialise the layout of the filter composite to display the widgets on three columns
final GridLayout vFilterLayout = new GridLayout(3, false);
vFilterLayout.marginHeight = 0;
vFilterLayout.marginWidth = 0;
vFilterComposite.setLayout(vFilterLayout);
GridData vGridData = new GridData(SWT.FILL, SWT.BEGINNING, true, false);
vGridData.widthHint = CONTROL_WIDTH;
vFilterComposite.setLayoutData(vGridData);
// Create the search label
createSearchLabel(vFilterComposite);
// Create the menu manager and associate it to the search label
createMenuManager();
// Create the filter text field
createFilterText(vFilterComposite);
// Create the clear label
createClearLabel(vFilterComposite);
// Initialise the widgets value for the initial state, without filter value
mClearLabel.setVisible(false);
}
/**
* Create the filter text field.
*
* @param pParent The parent composite
*/
private void createFilterText(final Composite pParent) {
// Create and initialise the filter text
mFilterTextField = new Text(pParent, SWT.SINGLE | SWT.ICON_CANCEL);
mFilterTextField.setMessage(CommonUIActivator.getMessages().getString("FilterComposite.text.defaulttext")); //$NON-NLS-1$
mFilterTextField.setToolTipText(CommonUIActivator.getMessages().getString("FilterComposite.text.tooltip")); //$NON-NLS-1$
// Add a key listener on the field to be warned that
// the filter value changes dynamically
mFilterTextField.addKeyListener(new KeyAdapter() {
/**
* {@inheritDoc}
*/
@Override
public void keyReleased(final KeyEvent pEvent) {
FILTER_PART_MANAGER.updateFilterText(mFilterTextField.getText());
}
});
// Add a modify listener on the field to react
// when a value is validated
mFilterTextField.addModifyListener(new ModifyListener() {
/**
* {@inheritDoc}
*/
@Override
public void modifyText(final ModifyEvent pEvent) {
mClearLabel.setVisible(StringUtils.isNotEmpty(mFilterTextField.getText()));
}
});
// Build the layout data for the text field
// NB : If the text widget supported cancel then it will have it's own
// integrated button, thus we can take the whole space
final GridData vGridData = new GridData(SWT.FILL, SWT.CENTER, true, false);
vGridData.heightHint = CONTROL_HEIGHT;
if ((mFilterTextField.getStyle() & SWT.ICON_CANCEL) != 0) {
vGridData.horizontalSpan = 2;
}
mFilterTextField.setLayoutData(vGridData);
// Add the drag and drop support on the text field
final DropTarget vDropTarget = new DropTarget(mFilterTextField, DND.DROP_MOVE | DND.DROP_COPY);
vDropTarget.setTransfer(new Transfer[] {TextTransfer.getInstance()});
vDropTarget.addDropListener(new DropTargetAdapter() {
/**
* {@inheritDoc}
*/
@Override
public void drop(final DropTargetEvent pEvent) {
// Try to use the event data as new filter text
mFilterTextField.setText(String.valueOf(pEvent.data));
}
/**
* {@inheritDoc}
*/
@Override
public void dragEnter(final DropTargetEvent pEvent) {
// Force the drag and drop operation to be a copy
pEvent.detail = DND.DROP_COPY;
}
});
}
/**
* Create the search label, displayed as an image, and associate a context menu to it.
*
* @param pParent The parent composite
*/
private void createSearchLabel(final Composite pParent) {
// Create the label and set its layout
mSearchLabel = new Label(pParent, SWT.NONE);
mSearchLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false, 0, 0));
// Set the label display, to show a standard search image
mSearchLabel.setImage(CommonUIActivator.getPlugin().getImageRegistry().get(Implementation.ICON_SEARCH_KEY));
mSearchLabel.setBackground(pParent.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
mSearchLabel.setToolTipText(CommonUIActivator.getMessages().getString("FilterComposite.search.tooltip")); //$NON-NLS-1$
}
/**
* Create the menu manager of the search label.
* Thus, when the user click on the search label, a contextual menu is
* displayed with all the available listeners.
*/
private void createMenuManager() {
// Create the menu manager
final MenuManager vMenuManager = new MenuManager();
// Ensure that when the menu is shown, all the previous elements are removed
vMenuManager.setRemoveAllWhenShown(true);
// Add a custom listener to populate the menu dynamically
vMenuManager.addMenuListener(new IMenuListener() {
/**
* {@inheritDoc}
*/
@Override
public void menuAboutToShow(final IMenuManager pMenuManager) {
// Add an item in the menu for all the active listeners
// This item will be already checked
for (IFilterPartListener vFiltrePartListener : FILTER_PART_MANAGER.getActivePartListenersList()) {
pMenuManager.add(new FilterPartAction(vFiltrePartListener, true));
}
// Add an item in the menu for all the available listeners
// This item won't be checked
for (IFilterPartListener vFiltrePartListener : FILTER_PART_MANAGER.getAvailablePartListenersList()) {
pMenuManager.add(new FilterPartAction(vFiltrePartListener));
}
}
});
// Add a custom listener to the search label, to be able to react on the mouse click,
// and build the contextual menu to the right location
mSearchLabel.addMouseListener(new MouseAdapter() {
/**
* {@inheritDoc}
*/
@Override
public void mouseDown(final MouseEvent pEvent) {
// Ensure that it's a left click
if (pEvent.button == 1) {
// Create the context menu for the search label
final Menu vContextMenu = vMenuManager.createContextMenu(mSearchLabel);
// Build the point, relative to the search label, where the
// contextual menu must appear
final Rectangle vRectangle = mSearchLabel.getBounds();
Point vPoint = new Point(vRectangle.x, vRectangle.y + vRectangle.height);
vPoint = mSearchLabel.toDisplay(vPoint);
// Set the menu location, and display it
vContextMenu.setLocation(vPoint.x, vPoint.y);
vContextMenu.setVisible(true);
}
}
});
}
/**
* Create the clear text label, displayed as an image.
*
* @param pParent The parent composite
*/
private void createClearLabel(final Composite pParent) {
// Create the label only if the text widget doesn't support one natively
if ((mFilterTextField.getStyle() & SWT.ICON_CANCEL) == 0) {
// Create the label and set its layout
mClearLabel = new Label(pParent, SWT.NONE);
mClearLabel.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, false, false));
// Set the label display, to show a standard clear image
mClearLabel.setImage(ImageConstants.ICON_CLEAR_DISABLED);
mClearLabel.setBackground(pParent.getDisplay().getSystemColor(SWT.COLOR_LIST_BACKGROUND));
mClearLabel
.setToolTipText(CommonUIActivator.getMessages().getString("FilterComposite.clearfilter.tooltip")); //$NON-NLS-1$
// Add a custom mouse listener to be able to clear the text on a click
// and to update the label image with the click action
mClearLabel.addMouseListener(new ClearLabelMouseAdapter());
// Add a custom mouse track adapter to update the label image when
// the mouse is over it
mClearLabel.addMouseTrackListener(new MouseTrackAdapter() {
/**
* {@inheritDoc}
*/
@Override
public void mouseEnter(final MouseEvent pEvent) {
mClearLabel.setImage(ImageConstants.ICON_CLEAR);
}
/**
* {@inheritDoc}
*/
@Override
public void mouseExit(final MouseEvent pEvent) {
mClearLabel.setImage(ImageConstants.ICON_CLEAR_DISABLED);
}
});
}
}
/**
* Clear the filter text, by setting the default value.
*/
private void clearFilterText() {
// Reset the text from the text widget, using the default filter
mFilterTextField.setText(FilterPartManager.DEFAULT_FILTER_TEXT);
// Reset the filter text applied by the manager
// NB : This will warn all the listeners
FILTER_PART_MANAGER.resetFilterText();
}
/**
* Mouse adapter linked to the clear label.
*
* The clear label is displayed as an image, and when the user click on it,
* it must clear the filter text.
*
* @author $Author: jdumont $
* @version $Revision: 83 $
*/
private class ClearLabelMouseAdapter
extends MouseAdapter {
/**
* Default constructor.
*/
ClearLabelMouseAdapter() {
super();
}
/**
* {@inheritDoc}
*
* Update the clear label image.
*/
@Override
public void mouseDown(final MouseEvent pEvent) {
mClearLabel.setImage(ImageConstants.ICON_CLEAR_PRESSED);
}
/**
* {@inheritDoc}
*
* Update the clear label image and clear the filter text.
*/
@Override
public void mouseUp(final MouseEvent pEvent) {
// Thus update the label image and clear the text if needed
mClearLabel.setImage(ImageConstants.ICON_CLEAR);
clearFilterText();
mFilterTextField.setFocus();
}
}
}