/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ package org.apache.directory.studio.ldapbrowser.ui.editors.searchresult; import org.apache.directory.studio.ldapbrowser.common.BrowserCommonActivator; import org.apache.directory.studio.ldapbrowser.common.BrowserCommonConstants; import org.apache.directory.studio.ldapbrowser.common.actions.BrowserSelectionUtils; import org.apache.directory.studio.ldapbrowser.core.events.EmptyValueAddedEvent; import org.apache.directory.studio.ldapbrowser.core.events.EntryModificationEvent; import org.apache.directory.studio.ldapbrowser.core.events.EntryUpdateListener; import org.apache.directory.studio.ldapbrowser.core.events.EventRegistry; import org.apache.directory.studio.ldapbrowser.core.events.SearchUpdateEvent; import org.apache.directory.studio.ldapbrowser.core.events.SearchUpdateListener; import org.apache.directory.studio.ldapbrowser.core.model.AttributeHierarchy; import org.apache.directory.studio.ldapbrowser.core.model.IAttribute; import org.apache.directory.studio.ldapbrowser.core.model.ISearch; import org.apache.directory.studio.ldapbrowser.core.model.ISearchResult; import org.apache.directory.studio.ldapbrowser.ui.BrowserUIConstants; import org.apache.directory.studio.ldapbrowser.ui.BrowserUIPlugin; import org.apache.directory.studio.ldapbrowser.ui.actions.OpenSearchResultAction; import org.apache.directory.studio.ldapbrowser.ui.views.browser.BrowserView; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TextCellEditor; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.TableEditor; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.MouseAdapter; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseListener; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.events.MouseTrackListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.events.SelectionListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.TableColumn; import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.INullSelectionListener; import org.eclipse.ui.IPartListener2; import org.eclipse.ui.IWorkbenchPart; import org.eclipse.ui.IWorkbenchPartReference; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.contexts.IContextActivation; import org.eclipse.ui.contexts.IContextService; import org.eclipse.ui.forms.events.HyperlinkEvent; import org.eclipse.ui.forms.events.IHyperlinkListener; import org.eclipse.ui.forms.widgets.Hyperlink; /** * The SearchResultEditorUniversalListener manages all events for the search result editor. * * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> */ public class SearchResultEditorUniversalListener implements SearchUpdateListener, EntryUpdateListener { /** The search result editor */ private SearchResultEditor editor; /** The table viewer */ private TableViewer viewer; /** The cursor */ private SearchResultEditorCursor cursor; /** The action used to start the default value editor */ private OpenBestEditorAction startEditAction; /** The selected search that is displayed in the search result editor */ private ISearch selectedSearch; /** The hyperlink used for DNs */ private Hyperlink dnLink; /** The table editor, used to display the hyperlink */ private TableEditor tableEditor; /** Token used to activate and deactivate shortcuts in the editor */ private IContextActivation contextActivation; /** Listener that listens for selections of ISearch objects. */ private INullSelectionListener searchSelectionListener = new INullSelectionListener() { /** * {@inheritDoc} * * This implementation sets the editor's input when a search is selected. */ public void selectionChanged( IWorkbenchPart part, ISelection selection ) { if ( editor != null && part != null ) { if ( editor.getSite().getWorkbenchWindow() == part.getSite().getWorkbenchWindow() ) { ISearch[] searches = BrowserSelectionUtils.getSearches( selection ); Object[] objects = BrowserSelectionUtils.getObjects( selection ); if ( searches.length == 1 && objects.length == 1 ) { editor.setInput( new SearchResultEditorInput( searches[0] ) ); } else { editor.setInput( new SearchResultEditorInput( null ) ); } } } } }; /** The part listener used to activate and deactivate the shortcuts */ private IPartListener2 partListener = new IPartListener2() { /** * {@inheritDoc} * * This implementation deactivates the shortcuts when the part is deactivated. */ public void partDeactivated( IWorkbenchPartReference partRef ) { if ( partRef.getPart( false ) == editor && contextActivation != null ) { editor.getActionGroup().deactivateGlobalActionHandlers(); IContextService contextService = ( IContextService ) PlatformUI.getWorkbench().getAdapter( IContextService.class ); contextService.deactivateContext( contextActivation ); contextActivation = null; } } /** * {@inheritDoc} * * This implementation activates the shortcuts when the part is activated. */ public void partActivated( IWorkbenchPartReference partRef ) { if ( partRef.getPart( false ) == editor ) { IContextService contextService = ( IContextService ) PlatformUI.getWorkbench().getAdapter( IContextService.class ); contextActivation = contextService.activateContext( BrowserCommonConstants.CONTEXT_WINDOWS ); editor.getActionGroup().activateGlobalActionHandlers(); } } /** * {@inheritDoc} */ public void partBroughtToTop( IWorkbenchPartReference partRef ) { } /** * {@inheritDoc} */ public void partClosed( IWorkbenchPartReference partRef ) { } /** * {@inheritDoc} */ public void partOpened( IWorkbenchPartReference partRef ) { } /** * {@inheritDoc} */ public void partHidden( IWorkbenchPartReference partRef ) { } /** * {@inheritDoc} */ public void partVisible( IWorkbenchPartReference partRef ) { } /** * {@inheritDoc} */ public void partInputChanged( IWorkbenchPartReference partRef ) { } }; /** The listener used to handle clicks to the Dn hyper link */ private IHyperlinkListener dnHyperlinkListener = new IHyperlinkListener() { /** * {@inheritDoc} * * This implementation opens the search result when clicking thd Dn link. */ public void linkActivated( HyperlinkEvent e ) { ISearchResult sr = ( ISearchResult ) e.widget.getData(); OpenSearchResultAction action = new OpenSearchResultAction(); action.setSelectedSearchResults( new ISearchResult[] { sr } ); action.run(); } /** * {@inheritDoc} */ public void linkEntered( HyperlinkEvent e ) { } /** * {@inheritDoc} */ public void linkExited( HyperlinkEvent e ) { } }; /** This listener removes the Dn link when then mouse exits the hyperlink control */ private MouseTrackListener dnMouseTrackListener = new MouseTrackListener() { /** * {@inheritDoc} */ public void mouseEnter( MouseEvent e ) { } /** * {@inheritDoc} * * This implementation removed the Dn link. */ public void mouseExit( MouseEvent e ) { if ( !dnLink.isDisposed() ) { dnLink.setVisible( false ); tableEditor.setEditor( null ); } } public void mouseHover( MouseEvent e ) { } }; /** This listener renders the Dn hyperlink when the mouse cursor moves over the Dn */ private MouseMoveListener cursorMouseMoveListener = new MouseMoveListener() { /** * {@inheritDoc} * * This implementation renders the Dn link. */ public void mouseMove( MouseEvent e ) { if ( !cursor.isDisposed() ) { TableItem item = cursor.getRow(); if ( cursor.getColumn() == 0 && "Dn".equalsIgnoreCase( cursor.getRow().getParent().getColumns()[0].getText() ) ) //$NON-NLS-1$ { checkDnLink( item ); } } } }; /** This listener renders the Dn link when the mouse cursor moves over the Dn */ private MouseMoveListener viewerMouseMoveListener = new MouseMoveListener() { /** * {@inheritDoc} * * This implementation renders the Dn link. */ public void mouseMove( MouseEvent e ) { if ( !viewer.getTable().isDisposed() ) { TableItem item = viewer.getTable().getItem( new Point( e.x, e.y ) ); viewer.getTable().getColumns()[0].getWidth(); if ( e.x > 0 && e.x < viewer.getTable().getColumns()[0].getWidth() && "Dn".equalsIgnoreCase( viewer.getTable().getColumns()[0].getText() ) ) //$NON-NLS-1$ { checkDnLink( item ); } } } }; /** This listener starts the value editor and toggles the cursor's background color */ private SelectionListener cursorSelectionListener = new SelectionAdapter() { /** * {@inheritDoc} * * This implementation sets the cursor's background color. */ public void widgetSelected( SelectionEvent e ) { // viewer.setSelection(new StructuredSelection(getRow()), true); // viewer.getTable().setSelection(new TableItem[]{getRow()}); viewer.setSelection( null, true ); viewer.getTable().setSelection( new TableItem[0] ); ISearchResult result = cursor.getSelectedSearchResult(); String property = cursor.getSelectedProperty(); if ( property != null && result != null && viewer.getCellModifier().canModify( result, property ) ) { cursor.setBackground( Display.getDefault().getSystemColor( SWT.COLOR_LIST_SELECTION ) ); } else { cursor.setBackground( Display.getDefault().getSystemColor( SWT.COLOR_TITLE_INACTIVE_FOREGROUND ) ); } // cursor.setForeground(Display.getDefault().getSystemColor(SWT.COLOR_LIST_SELECTION_TEXT)); } /** * {@inheritDoc} * * This implementation starts the value editor when pressing enter. */ public void widgetDefaultSelected( SelectionEvent e ) { viewer.setSelection( null, true ); viewer.getTable().setSelection( new TableItem[0] ); if ( startEditAction.isEnabled() ) startEditAction.run(); } }; /** This listener starts the value editor when double-clicking a cell */ private MouseListener cursorMouseListener = new MouseAdapter() { /** * {@inheritDoc} * * This implementation starts the value editor when double-clicking a cell. */ public void mouseDoubleClick( MouseEvent e ) { viewer.setSelection( null, true ); viewer.getTable().setSelection( new TableItem[0] ); if ( startEditAction.isEnabled() ) startEditAction.run(); } /** * {@inheritDoc} */ public void mouseDown( MouseEvent e ) { } /** * {@inheritDoc} */ public void mouseUp( MouseEvent e ) { } }; /** This listener starts the value editor when typing */ private KeyListener cursorKeyListener = new KeyListener() { /** * {@inheritDoc} * * This implementation starts the value editor when a non-control key is pressed. */ public void keyPressed( KeyEvent e ) { if ( e.character != '\0' && e.character != SWT.CR && e.character != SWT.LF && e.character != SWT.BS && e.character != SWT.DEL && e.character != SWT.TAB && e.character != SWT.ESC && ( e.stateMask == 0 || e.stateMask == SWT.SHIFT ) ) { if ( startEditAction.isEnabled() && startEditAction.getBestValueEditor().getCellEditor() instanceof TextCellEditor ) { startEditAction.run(); CellEditor editor = viewer.getCellEditors()[cursor.getColumn()]; if ( editor instanceof TextCellEditor ) { editor.setValue( String.valueOf( e.character ) ); ( ( Text ) editor.getControl() ).setSelection( 1 ); } } } } /** * {@inheritDoc} */ public void keyReleased( KeyEvent e ) { } }; /** * Creates a new instance of SearchResultEditorUniversalListener. * * @param editor the search result editor */ public SearchResultEditorUniversalListener( SearchResultEditor editor ) { this.editor = editor; startEditAction = editor.getActionGroup().getOpenBestEditorAction(); viewer = editor.getMainWidget().getViewer(); cursor = editor.getConfiguration().getCursor( viewer ); // create dn link control dnLink = new Hyperlink( viewer.getTable(), SWT.NONE ); dnLink.setLayoutData( new GridData( SWT.BOTTOM, SWT.LEFT, true, true ) ); dnLink.setText( "" ); //$NON-NLS-1$ dnLink.setMenu( viewer.getTable().getMenu() ); tableEditor = new TableEditor( viewer.getTable() ); tableEditor.horizontalAlignment = SWT.LEFT; tableEditor.verticalAlignment = SWT.BOTTOM; tableEditor.grabHorizontal = true; tableEditor.grabVertical = true; // init listeners dnLink.addHyperlinkListener( dnHyperlinkListener ); dnLink.addMouseTrackListener( dnMouseTrackListener ); cursor.addMouseMoveListener( cursorMouseMoveListener ); cursor.addSelectionListener( cursorSelectionListener ); cursor.addMouseListener( cursorMouseListener ); cursor.addKeyListener( cursorKeyListener ); viewer.getTable().addMouseMoveListener( viewerMouseMoveListener ); editor.getSite().getPage().addPartListener( partListener ); editor.getSite().getWorkbenchWindow().getSelectionService().addPostSelectionListener( BrowserView.getId(), searchSelectionListener ); EventRegistry.addSearchUpdateListener( this, BrowserCommonActivator.getDefault().getEventRunner() ); EventRegistry.addEntryUpdateListener( this, BrowserCommonActivator.getDefault().getEventRunner() ); } /** * Disposes the listener. */ public void dispose() { if ( editor != null ) { editor.getSite().getPage().removePartListener( partListener ); editor.getSite().getWorkbenchWindow().getSelectionService().removePostSelectionListener( BrowserView.getId(), searchSelectionListener ); EventRegistry.removeSearchUpdateListener( this ); EventRegistry.removeEntryUpdateListener( this ); selectedSearch = null; startEditAction = null; cursor = null; viewer = null; editor = null; } } /** * {@inheritDoc} * * This implementation refreshes the search result editor. */ public void searchUpdated( SearchUpdateEvent searchUpdateEvent ) { if ( selectedSearch == searchUpdateEvent.getSearch() ) { refreshInput(); } } /** * {@inheritDoc} * * This implementation refreshes the search result editor * or starts the value editor if an empty value was added. */ public void entryUpdated( EntryModificationEvent event ) { if ( event instanceof EmptyValueAddedEvent && !editor.getActionGroup().isEditorActive() ) { EmptyValueAddedEvent evae = ( EmptyValueAddedEvent ) event; IAttribute att = evae.getAddedValue().getAttribute(); AttributeHierarchy ah = cursor.getSelectedAttributeHierarchy(); if ( ah != null && ah.contains( att ) ) { viewer.setSelection( null, true ); viewer.getTable().setSelection( new TableItem[0] ); if ( startEditAction.isEnabled() ) { startEditAction.run(); } } } else { viewer.refresh( true ); cursor.notifyListeners( SWT.Selection, new Event() ); } } /** * Sets the input. * * @param search the search */ void setInput( ISearch search ) { selectedSearch = search; refreshInput(); editor.getActionGroup().setInput( search ); } /** * Refreshes the input, makes columns visible or hides columns depending on the number * of returning attributes. */ void refreshInput() { // create at least on column ensureColumnCount( 1 ); // get all columns TableColumn[] columns = viewer.getTable().getColumns(); // number of used columns int usedColumns; if ( selectedSearch != null ) { // get displayed attributes boolean showDn = BrowserUIPlugin.getDefault().getPreferenceStore().getBoolean( BrowserUIConstants.PREFERENCE_SEARCHRESULTEDITOR_SHOW_DN ) || selectedSearch.getReturningAttributes().length == 0; String[] attributes; if ( showDn ) { attributes = new String[selectedSearch.getReturningAttributes().length + 1]; attributes[0] = "Dn"; //$NON-NLS-1$ System.arraycopy( selectedSearch.getReturningAttributes(), 0, attributes, 1, attributes.length - 1 ); } else { attributes = selectedSearch.getReturningAttributes(); } // create missing columns if ( attributes.length > columns.length ) { ensureColumnCount( attributes.length ); columns = viewer.getTable().getColumns(); } // set column headers for ( int i = 0; i < attributes.length; i++ ) { columns[i].setText( attributes[i] ); } viewer.setColumnProperties( attributes ); // set input ( ( SearchResultEditorLabelProvider ) viewer.getLabelProvider() ).inputChanged( selectedSearch, showDn ); viewer.setInput( selectedSearch ); // this.viewer.refresh(); // update cell editors CellEditor[] editors = new CellEditor[attributes.length]; viewer.setCellEditors( editors ); if ( attributes.length > 0 ) { int width = viewer.getTable().getClientArea().width / attributes.length; for ( int i = 0; i < attributes.length; i++ ) { columns[i].setWidth( width ); } } // layout columns // for(int i=0; i<attributes.length; i++) { // columns[i].pack(); // } usedColumns = attributes.length; } else { viewer.setInput( null ); columns[0].setText( "Dn" ); //$NON-NLS-1$ columns[0].pack(); usedColumns = 1; } // make unused columns invisible for ( int i = usedColumns; i < columns.length; i++ ) { columns[i].setWidth( 0 ); columns[i].setText( " " ); //$NON-NLS-1$ } // refresh content provider (sorter and filter) editor.getConfiguration().getContentProvider( editor.getMainWidget() ).refresh(); // this.cursor.setFocus(); } /** * Ensures that the table contains at least the number of * the requested columns. * * @param count the requested number of columns */ private void ensureColumnCount( int count ) { TableColumn[] columns = viewer.getTable().getColumns(); if ( columns.length < count ) { for ( int i = columns.length; i < count; i++ ) { TableColumn column = new TableColumn( viewer.getTable(), SWT.LEFT ); column.setText( "" ); //$NON-NLS-1$ column.setWidth( 0 ); column.setResizable( true ); column.setMoveable( true ); } } } /** * Renders the Dn link. * * @param item the table item */ private void checkDnLink( TableItem item ) { if ( dnLink == null || dnLink.isDisposed() || tableEditor == null || viewer.getTable().isDisposed() || cursor.isDisposed() ) { return; } boolean showLinks = BrowserUIPlugin.getDefault().getPreferenceStore().getBoolean( BrowserUIConstants.PREFERENCE_SEARCHRESULTEDITOR_SHOW_LINKS ); if ( showLinks ) { boolean linkVisible = false; if ( item != null ) { Object data = item.getData(); if ( data instanceof ISearchResult ) { ISearchResult sr = ( ISearchResult ) data; item.getFont(); viewer.getTable().getColumn( 0 ).getWidth(); viewer.getTable().getItemHeight(); // dnLink.setText("<a>"+sr.getDn().toString()+"</a>"); dnLink.setData( sr ); dnLink.setText( sr.getDn().getName() ); dnLink.setUnderlined( true ); dnLink.setFont( item.getFont() ); dnLink.setForeground( item.getForeground() ); dnLink.setBackground( item.getBackground() ); dnLink.setBounds( item.getBounds( 0 ) ); tableEditor.setEditor( dnLink, item, 0 ); linkVisible = true; } } if ( !linkVisible ) { dnLink.setVisible( false ); tableEditor.setEditor( null ); } } } }