/* * Copyright (c) 2010, SQL Power Group Inc. * * This file is part of SQL Power Library. * * SQL Power Library is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * SQL Power Library 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package ca.sqlpower.swingui; import java.awt.Color; import java.beans.PropertyChangeEvent; import java.util.Enumeration; import javax.swing.AbstractButton; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.JCheckBox; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JSpinner; import javax.swing.JTable; import javax.swing.JTree; import javax.swing.text.JTextComponent; import ca.sqlpower.sqlobject.SQLType; import ca.sqlpower.sqlobject.UserDefinedSQLType; /** * This class has several methods for JComponents of different types * to check for conflicts and change the UI in an appropriate way. * * It is not meant to be used by all DataEntryPanels, just ChangeListeningDataEntryPanels. */ public class DataEntryPanelChangeUtil { public final static String ERROR_MESSAGE = "<html>This object has been changed by another user.<br>" + "You must re-open this window before making changes.</html>"; public final static Color NONCONFLICTING_COLOR = new Color(255, 255, 200); public final static Color DARK_NONCONFLICTING_COLOR = new Color(255, 200, 0); public final static Color CONFLICTING_COLOR = new Color(255, 200, 200); public final static Color DARK_CONFLICTING_COLOR = new Color(255, 100, 100); /** * Sets the background color of the text field in case of an incoming change/conflict. */ public static boolean incomingChange(JTextComponent field, PropertyChangeEvent e) { return changeBackground(field, field.getText(), e); } /** * Sets the background color and creates a colored border in case of an incoming change/conflict. */ public static boolean incomingChange(JComboBox field, PropertyChangeEvent e) { Object fieldValue = field.getSelectedItem(); if (field.getSelectedItem() instanceof String) { changeBackground(field, (String) fieldValue, e); } else if (field.getSelectedItem() instanceof SQLType) { SQLType type = (SQLType) field.getSelectedItem(); fieldValue = type.getType(); changeBackground(field, fieldValue, e); } return changeBorder(field, fieldValue, e); } /** * Sets the background color of the text field in case of an incoming change/conflict. */ public static boolean incomingChange(JSpinner field, PropertyChangeEvent e) { return changeBackground( ((JSpinner.DefaultEditor) field.getEditor()).getTextField(), field.getValue(), e); } /** * Creates a colored border around the given component in case of incoming change/conflict. */ public static boolean incomingChange(JCheckBox field, PropertyChangeEvent e) { return changeBorder(field, field.isSelected(), e); } /** * Creates a colored border around the given component in case of incoming change/conflict. */ public static boolean incomingChange(ButtonGroup field, Object fieldValue, PropertyChangeEvent e) { return changeBorder(getSelectedButton(field), fieldValue, e); } /** * Sets the background colour of the JTree in case of an incoming change/conflict. */ public static boolean incomingChange(JTree field, PropertyChangeEvent e) { Object selection = field.getLastSelectedPathComponent(); if (selection instanceof UserDefinedSQLType) { return changeBackground(field, ((UserDefinedSQLType) selection).getType(), e); } else { return false; } } /** * Sets the background colour of the {@link JTable} in case of an incoming * change/conflict. * * @param table * The JTable to which the background colour should change on. * @param evt * The {@link PropertyChangeEvent} that is the cause of the * incoming change or conflict. * @return true if the background colour was set. */ public static boolean incomingChange(JTable table, PropertyChangeEvent evt) { return changeBackground(table, null, evt); } /** * Sets the background color of the given component in case of incoming change/conflict. * @param field Any JComponent * @param fieldValue The value in the field that is of the same type as the values in e * @param e The old and new values will be checked against the fieldValue * @return True if the color was set due to an incoming change/conflict. */ public static boolean changeBackground(JComponent field, Object fieldValue, PropertyChangeEvent e) { Object oldValue = e.getOldValue(); Object incomingValue = e.getNewValue(); if (fieldValue instanceof String) { oldValue = (oldValue != null) ? ((String) oldValue).trim() : ""; incomingValue = (incomingValue != null) ? ((String) incomingValue).trim() : ""; fieldValue = (fieldValue != null) ? ((String) fieldValue).trim() : ""; } if (incomingValue.equals(fieldValue)) return false; if (oldValue.equals(fieldValue)) { field.setBackground(NONCONFLICTING_COLOR); } else { field.setBackground(CONFLICTING_COLOR); } return true; } /** * Creates a colored border around the given component in case of incoming change/conflict. * @param field Any JComponent * @param fieldValue The value in the field that is of the same type as the values in e * @param e The old and new values will be checked against the fieldValue * @return True if the border was made due to an incoming change/conflict. */ public static boolean changeBorder(JComponent field, Object fieldValue, PropertyChangeEvent e) { Object oldValue = e.getOldValue(); Object incomingValue = e.getNewValue(); if (fieldValue instanceof String) { oldValue = (oldValue != null) ? ((String) oldValue).trim() : ""; incomingValue = (incomingValue != null) ? ((String) incomingValue).trim() : ""; fieldValue = (fieldValue != null) ? ((String) fieldValue).trim() : ""; } if (incomingValue.equals(fieldValue)) return false; if (oldValue.equals(fieldValue)) { field.setBorder(BorderFactory.createLineBorder(DARK_NONCONFLICTING_COLOR, 3)); } else { field.setBorder(BorderFactory.createLineBorder(DARK_CONFLICTING_COLOR, 3)); } if (field instanceof AbstractButton) { ((AbstractButton) field).setBorderPainted(true); } return true; } private static AbstractButton getSelectedButton(ButtonGroup field) { Enumeration<AbstractButton> buttons = field.getElements(); while (buttons.hasMoreElements()) { AbstractButton b = buttons.nextElement(); if (b.isSelected()) return b; } throw new IllegalStateException("No button is selected"); } }