/* This file belongs to the Servoy development and deployment environment, Copyright (C) 1997-2010 Servoy BV This program is free software; you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. You should have received a copy of the GNU Affero General Public License along with this program; if not, see http://www.gnu.org/licenses or write to the Free Software Foundation,Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 */ package com.servoy.j2db.smart.scripting; import java.awt.Component; import java.util.HashMap; import javax.swing.JComponent; import javax.swing.SwingUtilities; import javax.swing.table.TableCellEditor; import javax.swing.table.TableModel; import org.mozilla.javascript.Function; import org.mozilla.javascript.JavaMembers; import org.mozilla.javascript.NativeJavaObject; import org.mozilla.javascript.Scriptable; import org.mozilla.javascript.Wrapper; import com.servoy.j2db.scripting.TwoNativeJavaMethod; import com.servoy.j2db.smart.ListView; import com.servoy.j2db.smart.TableView; import com.servoy.j2db.smart.dataui.CellAdapter; import com.servoy.j2db.smart.dataui.PortalComponent; /** * This object is made for the FormPanel elements so that both the Renderer object and the Editor object will be called for there requests. * * Also the list view should be repainted. So that setEnabled/Color will be seen by the listview. * * @author jcompagner */ public class TwoNativeJavaObject extends NativeJavaObject { private final NativeJavaObject javaObject2; private final Component listView; private final HashMap methodWrappers; private String executingFunction; /** * @param scope * @param javaObject * @param members */ public TwoNativeJavaObject(Scriptable scope, Object javaObject, NativeJavaObject javaObject2, JavaMembers members, Component listView) { super(scope, javaObject, members); this.javaObject2 = javaObject2; this.listView = listView; this.methodWrappers = new HashMap(); } /* * (non-Javadoc) * * @see org.mozilla.javascript.NativeJavaObject#get(java.lang.String, org.mozilla.javascript.Scriptable) */ @Override public Object get(String name, Scriptable start) { Object returnObject = null; try { returnObject = super.get(name, start); } finally { if (returnObject instanceof Function) { if ("replaceSelectedText".equals(name)) return returnObject; //$NON-NLS-1$ if (!"requestFocus".equals(name)) //$NON-NLS-1$ { executingFunction = name; TwoNativeJavaMethod methodWrapper = (TwoNativeJavaMethod)methodWrappers.get(returnObject); if (methodWrapper == null) { methodWrapper = new TwoNativeJavaMethod(javaObject2, (Function)returnObject, listView); methodWrappers.put(returnObject, methodWrapper); } returnObject = methodWrapper; } else { final JComponent uiComponent = (JComponent)((javaObject instanceof Wrapper) ? ((Wrapper)javaObject).unwrap() : javaObject); if (listView instanceof TableView) { final TableView tv = (TableView)listView; tv.requestFocus(); SwingUtilities.invokeLater(new Runnable() { public void run() { final int selectedRow = tv.getSelectedRow(); for (int i = 0; i < tv.getColumnCount(); i++) { if (((CellAdapter)tv.getCellEditor(selectedRow, i)).getEditor() == uiComponent) { final int currentColumn = i; tv.setColumnSelectionInterval(currentColumn, currentColumn); tv.editCellAt(selectedRow, currentColumn); break; } } } }); } else if (listView instanceof ListView) { ((ListView)listView).editCellAt((((ListView)listView).getSelectedIndex())); uiComponent.requestFocus(); SwingUtilities.invokeLater(new Runnable() { public void run() { if (!((ListView)listView).isEditing()) ((ListView)listView).editCellAt((((ListView)listView).getSelectedIndex())); } }); } else if (listView instanceof PortalComponent) { ((PortalComponent)listView).editCellFor(uiComponent); } } } else { javaObject2.get(name, start); } } return returnObject; } @Override public Object unwrap() { // only go into edit if this is the event dispatch thread. // else debugger can block. If scripts will get its own thread this has to be invokeLater() if (SwingUtilities.isEventDispatchThread()) { // when this component is unwrapped, NOT due to a function call on it, (the reference is given to the java world) // or the location or width is requested we should make sure that it goes in editmode so that the component is in a valid // state. For example popupmenu tries to show an popup on the components location. if (executingFunction == null || executingFunction.startsWith("getLocation") || executingFunction.startsWith("getWidth")) //$NON-NLS-1$ //$NON-NLS-2$ { final JComponent uiComponent = (JComponent)((javaObject instanceof Wrapper) ? ((Wrapper)javaObject).unwrap() : javaObject); if (listView instanceof TableView) { TableView tv = (TableView)listView; TableCellEditor cellEditor = tv.getCellEditor(); if (!(cellEditor instanceof CellAdapter && ((CellAdapter)cellEditor).getEditor() == uiComponent)) { int selectedRow = tv.getSelectedRow(); for (int i = 0; i < tv.getColumnCount(); i++) { if (((CellAdapter)tv.getCellEditor(selectedRow, i)).getEditor() == uiComponent) { TableModel tm = tv.getModel(); if (tm != null && tm.getRowCount() > 0) { if (tv.isCellEditable(selectedRow, i)) { tv.setColumnSelectionInterval(i, i); tv.editCellAt(selectedRow, i); } else { // bounds can be modified even if readonly when moving columns ((Component)uiComponent).setBounds(tv.getCellRect(selectedRow, i, false)); } } break; } } } } else if (listView instanceof ListView) { ((ListView)listView).editCellAt((((ListView)listView).getSelectedIndex())); } else if (listView instanceof PortalComponent) { ((PortalComponent)listView).editCellFor(uiComponent); } } else executingFunction = null; } return super.unwrap(); } /* * (non-Javadoc) * * @see org.mozilla.javascript.NativeJavaObject#put(java.lang.String, org.mozilla.javascript.Scriptable, java.lang.Object) */ @Override public void put(String name, Scriptable start, Object value) { try { super.put(name, start, value); listView.repaint(); } catch (RuntimeException e) { throw e; } finally { javaObject2.put(name, start, value); } } }