/* * Copyright 2012 Red Hat, Inc. and/or its affiliates. * * Licensed 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.kie.workbench.common.widgets.decoratedgrid.client.widget.cells; import com.google.gwt.cell.client.AbstractEditableCell; import com.google.gwt.cell.client.ValueUpdater; import com.google.gwt.dom.client.Element; import com.google.gwt.dom.client.NativeEvent; import com.google.gwt.dom.client.TableCellElement; import com.google.gwt.dom.client.TableSectionElement; import com.google.gwt.event.dom.client.KeyCodes; import com.google.gwt.event.logical.shared.CloseEvent; import com.google.gwt.event.logical.shared.CloseHandler; import com.google.gwt.text.shared.SafeHtmlRenderer; import com.google.gwt.text.shared.SimpleSafeHtmlRenderer; import com.google.gwt.user.client.Event; import com.google.gwt.user.client.Event.NativePreviewEvent; import com.google.gwt.user.client.ui.PopupPanel; import com.google.gwt.user.client.ui.VerticalPanel; import static com.google.gwt.dom.client.BrowserEvents.*; /** * A Popup Editor. */ public abstract class AbstractPopupEditCell<C, V> extends AbstractEditableCell<C, V> { protected int offsetX = 5; protected int offsetY = 5; protected Context lastContext; protected Element lastParent; protected C lastValue; protected final PopupPanel panel; protected final VerticalPanel vPanel; protected final SafeHtmlRenderer<String> renderer; protected final boolean isReadOnly; protected ValueUpdater<C> valueUpdater; /** * Boiler-plate and scaffolding for a general "Popup". Subclasses should * call this default constructor and append their specific child controls * for the "Popup" to <code>vPanel</code>. */ public AbstractPopupEditCell( boolean isReadOnly ) { super( DBLCLICK, KEYDOWN ); this.renderer = SimpleSafeHtmlRenderer.getInstance(); this.vPanel = new VerticalPanel(); this.isReadOnly = isReadOnly; // Pressing ESCAPE dismisses the pop-up loosing any changes this.panel = new PopupPanel( true, true ) { @Override protected void onPreviewNativeEvent( NativePreviewEvent event ) { if ( Event.ONKEYUP == event.getTypeInt() ) { if ( event.getNativeEvent().getKeyCode() == KeyCodes.KEY_ESCAPE ) { panel.hide(); } } } }; // Closing the pop-up commits the change panel.addCloseHandler( new CloseHandler<PopupPanel>() { public void onClose( CloseEvent<PopupPanel> event ) { if ( lastParent != null && !event.isAutoClosed() ) { getTableCellElementAncestor( lastParent ).focus(); } else if ( event.isAutoClosed() ) { commit(); } lastContext = null; lastParent = null; lastValue = null; } } ); panel.add( vPanel ); } @Override public boolean isEditing( Context context, Element parent, C value ) { return lastContext != null && lastContext.equals( context ); } @Override public void onBrowserEvent( Context context, Element parent, C value, NativeEvent event, ValueUpdater<C> valueUpdater ) { //If read-only ignore editing events if ( isReadOnly ) { return; } // KeyDown and "Enter" key-press is handled here super.onBrowserEvent( context, parent, value, event, valueUpdater ); if ( event.getType().equals( "dblclick" ) ) { this.lastContext = context; this.lastParent = parent; this.lastValue = value; this.valueUpdater = valueUpdater; startEditing( context, parent, value ); } } // Find the nearest TableCellElement ancestor private Element getTableCellElementAncestor( Element e ) { Element parent = e.getParentElement(); while ( !TableSectionElement.is( parent ) && !TableCellElement.is( parent ) ) { parent = parent.getParentElement(); } return parent; } /** * Commit the change to the underlying model. Implementations should use the * protected <code>valueUpdater</code> initialised in onBrowseEvent to pass * new values to the model. Implementations should also invoke * <code>setValue</code> to write the new value back to the Cell's HTML */ protected abstract void commit(); @Override protected void onEnterKeyDown( Context context, Element parent, C value, NativeEvent event, ValueUpdater<C> valueUpdater ) { this.lastContext = context; this.lastParent = parent; this.lastValue = value; this.valueUpdater = valueUpdater; startEditing( context, parent, value ); } /** * Initiate editing within the "Popup". Implementations should populate the * child controls within the "Popup" before showing the Popup * <code>panel</code> * @param parent * @param value */ protected abstract void startEditing( final Context context, final Element parent, final C value ); }