/* 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; import java.awt.Component; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.KeyEvent; import java.awt.event.MouseEvent; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import javax.swing.DefaultListModel; import javax.swing.DefaultListSelectionModel; import javax.swing.JButton; import javax.swing.KeyStroke; import javax.swing.ListCellRenderer; import javax.swing.SwingUtilities; import com.servoy.j2db.IApplication; import com.servoy.j2db.IView; import com.servoy.j2db.dataprocessing.IFoundSetInternal; import com.servoy.j2db.dataprocessing.ISwingFoundSet; import com.servoy.j2db.scripting.IScriptableProvider; import com.servoy.j2db.smart.dataui.DataCalendar; import com.servoy.j2db.smart.dataui.DataRenderer; import com.servoy.j2db.smart.dataui.FormBodyEditor; import com.servoy.j2db.ui.ISupportRowStyling; import com.servoy.j2db.ui.runtime.HasRuntimeReadOnly; import com.servoy.j2db.util.IStyleRule; import com.servoy.j2db.util.IStyleSheet; import com.servoy.j2db.util.editlist.EmptyEditListModel; import com.servoy.j2db.util.editlist.IEditListEditor; import com.servoy.j2db.util.editlist.JEditList; import com.servoy.j2db.util.model.IEditListModel; /** * The listview controller from mvc architecture * * @author jblok */ public class ListView extends JEditList implements IView, ISupportRowStyling, ISupportEditStateTracking { private IApplication application; private String rowBGColorScript; private List<Object> rowBGColorArgs; private int keyReleaseToBeIgnored; private IStyleSheet styleSheet; private IStyleRule oddStyle, evenStyle, selectedStyle, headerStyle; public ListView() { super(); setAutoscrolls(true); } /* * (non-Javadoc) * * @see java.awt.Component#processMouseEvent(java.awt.event.MouseEvent) */ @Override protected void processMouseEvent(MouseEvent e) { if (e.getID() == MouseEvent.MOUSE_PRESSED) { //search on which component is clicked becouse we do not want to save if clicked on field for example int row = getSelectedIndex(); if (row != -1) { Point p = (e).getPoint(); Component comp = getEditorComponent(); if (comp != null) { Point p2 = SwingUtilities.convertPoint(this, p, comp); Component dispatchComponent = SwingUtilities.getDeepestComponentAt(comp, p2.x, p2.y); if (dispatchComponent == this || dispatchComponent == comp) { application.getFoundSetManager().getEditRecordList().stopEditing(false); } } else { comp = getCellEditor().getListCellEditorComponent(this, null, true, row); if (comp != null) { comp.setBounds(getCellBounds(row, row)); add(comp); comp.doLayout(); Point p2 = SwingUtilities.convertPoint(this, p, comp); Component dispatchComponent = SwingUtilities.getDeepestComponentAt(comp, p2.x, p2.y); remove(comp); if (dispatchComponent == this || dispatchComponent == comp) { application.getFoundSetManager().getEditRecordList().stopEditing(false); } } } } } super.processMouseEvent(e); } @Override protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) { // if we are in find mode, no row is being edited and enter is pressed then we should enter edit mode // on selected row rather then perform the search (so the enter release must be marked as consumed/processed); // for example search for something => no results, choose modify last find in the dialog - now you must be able to enter // edit mode in the list to modify find criteria... boolean wasEditingBeforePress = isEditing(); boolean keyEventWasUsed = super.processKeyBinding(ks, e, condition, pressed); if (!wasEditingBeforePress && isEditing() && ks.getKeyEventType() == KeyEvent.KEY_PRESSED) { keyReleaseToBeIgnored = ks.getKeyCode(); } else if (keyReleaseToBeIgnored == ks.getKeyCode() && ks.getKeyEventType() == KeyEvent.KEY_RELEASED) { keyReleaseToBeIgnored = -1; return true; } else if (ks.getKeyEventType() != KeyEvent.KEY_TYPED) { keyReleaseToBeIgnored = -1; // get rid of this value, because this in only implemented for simple scenarios // and it shouldn't cause trouble } return keyEventWasUsed; } private final DefaultListSelectionModel EMPTY_SELECTION = new DefaultListSelectionModel(); private final DefaultListModel EMPTY_DATA = new DefaultListModel(); public void destroy() { setSelectionModel(EMPTY_SELECTION); super.setModel(EMPTY_DATA); removeAll(); } /** * @see com.servoy.j2db.IView#setModel(com.servoy.j2db.dataprocessing.IFoundSetInternal) */ public void setModel(IFoundSetInternal fs) { if (fs instanceof IEditListModel) { // Not needed anymore see FoundSet constuctor (selection model is a var of foundset) // ListSelectionModel sm = getSelectionModel(); // if (sm instanceof ListDataListener) // { // getModel().removeListDataListener((ListDataListener)sm); // } // if (sm instanceof ListDataListener) // { // fs.addListDataListener((ListDataListener)sm); // } // JList clears the selection in setModel() if (getModel() != fs) { // stop editing if another foundset removeEditor(); } setSelectionModel(EMPTY_SELECTION); super.setModel((ISwingFoundSet)fs); setSelectionModel(((ISwingFoundSet)fs).getSelectionModel()); } else if (fs == null) { removeEditor();//safety setSelectionModel(EMPTY_SELECTION); super.setModel(EMPTY_DATA); } } /** * @see com.servoy.j2db.IView#start() */ public void start(IApplication app) { application = app; } /** * @see com.servoy.j2db.IView#stop() */ public void stop() { setSelectionModel(new DefaultListSelectionModel()); setModel(new EmptyEditListModel()); } public boolean stopUIEditing(boolean looseFocus) { if (isEditing()) { // just do the same as for recordview, this seems to be desired behavior DataRenderer dr = ((DataRenderer)getEditorComponent()); if (dr != null) { return dr.stopUIEditing(looseFocus); } } return true; } @Override public void removeEditor() { //System.out.println("REMOVING EDITOR"); DataRenderer dr = ((DataRenderer)getEditorComponent()); if (dr != null) { dr.stopUIEditing(true); } super.removeEditor(); } public void setRowBGColorScript(String str, List<Object> args) { rowBGColorScript = str; rowBGColorArgs = args; } public String getRowBGColorScript() { return rowBGColorScript; } public List<Object> getRowBGColorArgs() { return rowBGColorArgs; } public boolean isDisplayingMoreThanOneRecord() { return true; } private final List<HasRuntimeReadOnly> componentsWithEditableStateChanged = new ArrayList<HasRuntimeReadOnly>(); private boolean editable = true; private List<HasRuntimeReadOnly> getReadOnlyAwareComponents() { List<HasRuntimeReadOnly> readOnlyAwareComponents = new ArrayList<HasRuntimeReadOnly>(); ListCellRenderer cellRenderer = getCellRenderer(); if (cellRenderer instanceof DataRenderer) { DataRenderer dr = (DataRenderer)cellRenderer; for (int i = 0; i < dr.getComponentCount(); i++) { Component c = dr.getComponent(i); if (c instanceof IScriptableProvider && ((IScriptableProvider)c).getScriptObject() instanceof HasRuntimeReadOnly) { readOnlyAwareComponents.add((HasRuntimeReadOnly)((IScriptableProvider)c).getScriptObject()); } } } IEditListEditor editorComponent = getCellEditor(); if (editorComponent instanceof FormBodyEditor) { FormBodyEditor formBodyEditor = (FormBodyEditor)editorComponent; DataRenderer dataRenderer = formBodyEditor.getDataRenderer(); for (int i = 0; i < dataRenderer.getComponentCount(); i++) { Component c = dataRenderer.getComponent(i); if (c instanceof IScriptableProvider && ((IScriptableProvider)c).getScriptObject() instanceof HasRuntimeReadOnly) { readOnlyAwareComponents.add((HasRuntimeReadOnly)((IScriptableProvider)c).getScriptObject()); } } } return readOnlyAwareComponents; } @Override public void setEditable(boolean editable) { super.setEditable(editable); this.editable = editable; } @Override public boolean isEditable() { return editable; } @Override protected boolean shouldDispatchClickToButton(JButton button) { return !((button.getParent() != null) && (button.getParent() instanceof DataCalendar)); } /* * @see com.servoy.j2db.ui.ISupportOddEvenStyling#getOddStyle() */ public IStyleRule getRowOddStyle() { return oddStyle; } /* * @see com.servoy.j2db.ui.ISupportOddEvenStyling#getEvenStyle() */ public IStyleRule getRowEvenStyle() { return evenStyle; } /* * @see com.servoy.j2db.ui.ISupportOddEvenStyling#getStyleSheet() */ public IStyleSheet getRowStyleSheet() { return styleSheet; } /* * @see com.servoy.j2db.ui.ISupportRowStyling#setStyles(javax.swing.text.html.StyleSheet, javax.swing.text.Style, javax.swing.text.Style, * javax.swing.text.Style) */ public void setRowStyles(IStyleSheet styleSheet, IStyleRule oddStyle, IStyleRule evenStyle, IStyleRule selectedStyle, IStyleRule headerStyle) { this.styleSheet = styleSheet; this.oddStyle = oddStyle; this.evenStyle = evenStyle; this.selectedStyle = selectedStyle; this.headerStyle = headerStyle; } /* * @see com.servoy.j2db.ui.ISupportRowStyling#getSelectedStyle() */ public IStyleRule getRowSelectedStyle() { return selectedStyle; } public IStyleRule getHeaderStyle() { return headerStyle; } public void setVisibleRect(Rectangle scrollPosition) { if (isVisible()) { scrollRectToVisible(scrollPosition); } } /* * (non-Javadoc) * * @see com.servoy.j2db.smart.ISupportEditStateTracking#setEditableWithStateTracking(boolean) */ @Override public void setEditableWithStateTracking(boolean b) { if (editable != b) { super.setEditable(b); this.editable = b; if (editable == false) { Iterator<HasRuntimeReadOnly> readOnlyAwareComponentsIte = getReadOnlyAwareComponents().iterator(); HasRuntimeReadOnly el; while (readOnlyAwareComponentsIte.hasNext()) { el = readOnlyAwareComponentsIte.next(); if (el.isReadOnly() == false) { el.setReadOnly(true); if (componentsWithEditableStateChanged.contains(el) == false) componentsWithEditableStateChanged.add(el); } } } else { if (componentsWithEditableStateChanged.size() != 0) { for (HasRuntimeReadOnly component : componentsWithEditableStateChanged) { component.setReadOnly(false); } } componentsWithEditableStateChanged.clear(); } invalidate(); repaint(); } } }