/******************************************************************************* * Copyright (c) 2013 EclipseSource 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: * EclipseSource - initial API and implementation ******************************************************************************/ package com.eclipsesource.tabris.internal.ui.web; import static com.eclipsesource.tabris.internal.Clauses.whenNull; import static com.eclipsesource.tabris.internal.Constants.CUSTOM_VARIANT_TABRIS_UI; import java.util.List; import org.eclipse.rap.rwt.Adaptable; import org.eclipse.rap.rwt.RWT; import org.eclipse.rap.rwt.service.ServerPushSession; import org.eclipse.swt.SWT; import org.eclipse.swt.events.FocusEvent; import org.eclipse.swt.events.FocusListener; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.MenuItem; import org.eclipse.swt.widgets.Text; import com.eclipsesource.tabris.internal.ui.ActionDescriptor; import com.eclipsesource.tabris.internal.ui.PropertyChangeHandler; import com.eclipsesource.tabris.internal.ui.PropertyChangeNotifier; import com.eclipsesource.tabris.internal.ui.UIDescriptor; import com.eclipsesource.tabris.ui.Action; import com.eclipsesource.tabris.ui.ActionListener; import com.eclipsesource.tabris.ui.UI; import com.eclipsesource.tabris.ui.action.ProposalHandler; import com.eclipsesource.tabris.ui.action.SearchAction; import com.eclipsesource.tabris.ui.action.SearchActionListener; public class WebSearchAction extends WebAction implements PropertyChangeHandler { private static final int TEXT_WIDTH = 200; private Text text; private Menu proposalsMenu; private final Listener textModifyListener; public WebSearchAction( UI ui, WebUI uiRenderer, ActionDescriptor descriptor ) { super( ui, uiRenderer, descriptor ); textModifyListener = new TextModifyListener( this ); Action action = descriptor.getAction(); ( ( Adaptable )action ).getAdapter( PropertyChangeNotifier.class ).setPropertyChangeHandler( this ); } @Override public void createUi( Composite uiParent ) { super.createUi( uiParent ); createText( uiParent ); createProposalsMenu(); } @Override public void destroy() { super.destroy(); if( text != null ) { text.dispose(); text = null; } if( proposalsMenu != null ) { proposalsMenu.dispose(); proposalsMenu = null; } } @Override public void propertyChanged( String key, Object value ) { if( key.equals( "open" ) ) { open(); } else if( key.equals( "query" ) ) { setQuery( ( String )value ); } else if( key.equals( "message" ) ) { setMessage( ( String )value ); } } public void open() { whenNull( text ).throwIllegalState( "UI is not created" ); getDescriptor().getAction().execute( getUI() ); actionExecuted(); } public void setQuery( String query ) { whenNull( text ).throwIllegalState( "UI is not created" ); text.setText( query ); } public void setMessage( String message ) { whenNull( text ).throwIllegalState( "UI is not created" ); text.setMessage( message ); } @Override protected void actionExecuted() { activateText( true ); } private void createText( Composite uiParent ) { if( text == null ) { text = new Text( uiParent, SWT.SEARCH | SWT.ICON_SEARCH | SWT.ICON_CANCEL ); text.setData( RWT.CUSTOM_VARIANT, CUSTOM_VARIANT_TABRIS_UI ); text.setLayoutData( createRowData( TEXT_WIDTH, SWT.DEFAULT, false ) ); text.setVisible( false ); text.addListener( SWT.DefaultSelection, new TextDefaultSelectionListener() ); text.addFocusListener( new TextFocusListener() ); } } private void createProposalsMenu() { if( proposalsMenu == null ) { proposalsMenu = new Menu( getControl().getShell(), SWT.POP_UP ); proposalsMenu.setData( RWT.CUSTOM_VARIANT, CUSTOM_VARIANT_TABRIS_UI ); } } Text getText() { return text; } Menu getProposalsMenu() { return proposalsMenu; } void showProposals( List<String> proposals ) { if( !proposalsMenu.isDisposed() ) { updateMenuItems( proposals ); if( !proposals.isEmpty() ) { showProposalsMenu(); } } } private void showProposalsMenu() { Control control = getControl(); Rectangle bounds = control.getBounds(); bounds.y += bounds.height + 5; Point point = control.toDisplay( bounds.x, bounds.y ); proposalsMenu.setLocation( point ); proposalsMenu.setVisible( true ); } private void doSearch( String query ) { ActionDescriptor descriptor = getDescriptor(); SearchAction action = ( SearchAction )descriptor.getAction(); action.search( query ); activateText( false ); text.setText( "" ); clearMenuItems(); } private void updateMenuItems( List<String> proposals ) { clearMenuItems(); for( String proposal : proposals ) { if( proposal != null ) { createMenuItem( proposal ); } } } private void clearMenuItems() { for( MenuItem item : proposalsMenu.getItems() ) { item.dispose(); } } private void createMenuItem( String proposal ) { MenuItem item = new MenuItem( proposalsMenu, SWT.PUSH ); item.setData( RWT.CUSTOM_VARIANT, CUSTOM_VARIANT_TABRIS_UI ); item.setText( proposal ); item.addListener( SWT.Selection, new MenuItemSelectionListener() ); } private void activateText( boolean active ) { Button button = getControl(); button.setLayoutData( createRowData( SWT.DEFAULT, SWT.DEFAULT, !active ) ); button.setVisible( !active ); text.setLayoutData( createRowData( TEXT_WIDTH, SWT.DEFAULT, active ) ); text.setVisible( active ); if( active ) { if( !text.isListening( SWT.Modify ) ) { text.addListener( SWT.Modify, textModifyListener ); } text.setFocus(); } else { text.removeListener( SWT.Modify, textModifyListener ); } layoutWebUI(); } private final class TextDefaultSelectionListener implements Listener { @Override public void handleEvent( Event event ) { if( event.detail != SWT.ICON_CANCEL ) { Text text = ( Text )event.widget; String query = text.getText(); doSearch( query ); notifyListenersAboutSearch( getDescriptor().getAction(), query ); } } private void notifyListenersAboutSearch( Action action, String query ) { UIDescriptor uiDescriptor = getUI().getConfiguration().getAdapter( UIDescriptor.class ); for( ActionListener listener : uiDescriptor.getActionListeners() ) { if( listener instanceof SearchActionListener ) { ( ( SearchActionListener )listener ).searched( getUI(), action, query ); } } } } private final class TextModifyListener implements Listener { private final ProposalHandler proposalHandler; public TextModifyListener( WebSearchAction actionRenderer ) { proposalHandler = new WebProposalHandlerImpl( actionRenderer ) ; } @Override public void handleEvent( Event event ) { Text text = ( Text )event.widget; SearchAction action = ( SearchAction )getDescriptor().getAction(); String query = text.getText(); action.modified( query, proposalHandler ); notifyListenersAboutModify( action, query ); } private void notifyListenersAboutModify( Action action, String query ) { UIDescriptor uiDescriptor = getUI().getConfiguration().getAdapter( UIDescriptor.class ); for( ActionListener listener : uiDescriptor.getActionListeners() ) { if( listener instanceof SearchActionListener ) { ( ( SearchActionListener )listener ).modified( getUI(), action, query ); } } } } private final class TextFocusListener implements FocusListener { private final ServerPushSession pushSession; public TextFocusListener() { pushSession = new ServerPushSession(); } @Override public void focusGained( FocusEvent event ) { pushSession.start(); } @Override public void focusLost( FocusEvent event ) { pushSession.stop(); activateText( false ); } } private final class MenuItemSelectionListener implements Listener { @Override public void handleEvent( Event event ) { MenuItem item = ( MenuItem )event.widget; doSearch( item.getText() ); } } }