/* $Id: TabTaggedValuesModel.java 17881 2010-01-12 21:09:28Z linus $
*****************************************************************************
* Copyright (c) 2009 Contributors - see below
* 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:
* tfmorris
*****************************************************************************
*
* Some portions of this file was previously release using the BSD License:
*/
// Copyright (c) 2005-2008 The Regents of the University of California. All
// Rights Reserved. Permission to use, copy, modify, and distribute this
// software and its documentation without fee, and without a written
// agreement is hereby granted, provided that the above copyright notice
// and this paragraph appear in all copies. This software program and
// documentation are copyrighted by The Regents of the University of
// California. The software program and documentation are supplied "AS
// IS", without any accompanying services from The Regents. The Regents
// does not warrant that the operation of the program will be
// uninterrupted or error-free. The end-user understands that the program
// was developed for research purposes and is advised not to rely
// exclusively on the program for any reason. IN NO EVENT SHALL THE
// UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
// SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS,
// ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
// THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE. THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY
// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
// PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
// CALIFORNIA HAS NO OBLIGATIONS TO PROVIDE MAINTENANCE, SUPPORT,
// UPDATES, ENHANCEMENTS, OR MODIFICATIONS.
package org.argouml.uml.ui;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.VetoableChangeListener;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import javax.swing.SwingUtilities;
import javax.swing.event.TableModelEvent;
import javax.swing.table.AbstractTableModel;
import org.apache.log4j.Logger;
import org.argouml.i18n.Translator;
import org.argouml.kernel.DelayedChangeNotify;
import org.argouml.kernel.DelayedVChangeListener;
import org.argouml.model.DeleteInstanceEvent;
import org.argouml.model.InvalidElementException;
import org.argouml.model.Model;
/**
* The model for the table with the tagged values. Implementation for UML 1.4
* and TagDefinitions.
*
* TODO: This currently only supports TaggedValues with a TagDefinition which
* has a type of String.
*/
public class TabTaggedValuesModel extends AbstractTableModel implements
VetoableChangeListener, DelayedVChangeListener, PropertyChangeListener {
private static final Logger LOG =
Logger.getLogger(TabTaggedValuesModel.class);
/**
* The ModelElement that is the current target.
*/
private Object target;
/**
* Construct a model to be used by a JTable containing TaggedValues.
*/
public TabTaggedValuesModel() {
}
/**
* Set the current target to the given model element.
*
* @param t
* the target modelelement
*/
public void setTarget(Object t) {
if (LOG.isDebugEnabled()) {
LOG.debug("Set target to " + t);
}
if (t != null && !Model.getFacade().isAModelElement(t)) {
throw new IllegalArgumentException();
}
if (target != t) {
if (target != null) {
Model.getPump().removeModelEventListener(this, target);
}
target = t;
if (t != null) {
Model.getPump().addModelEventListener(this, t,
new String[] {"taggedValue", "referenceTag"});
}
}
// always fire changes in the case something has changed in the
// composition of the taggedValues collection.
fireTableDataChanged();
}
/*
* @see javax.swing.table.TableModel#getColumnCount()
*/
public int getColumnCount() {
return 2;
}
/*
* @see javax.swing.table.TableModel#getColumnName(int)
*/
@Override
public String getColumnName(int c) {
if (c == 0) {
return Translator.localize("label.taggedvaluespane.tag");
}
if (c == 1) {
return Translator.localize("label.taggedvaluespane.value");
}
return "XXX";
}
/*
* @see javax.swing.table.TableModel#getColumnClass(int)
*/
@Override
public Class getColumnClass(int c) {
if (c == 0) {
return (Class) Model.getMetaTypes().getTagDefinition();
}
if (c == 1) {
// TODO: This will vary based on the type of the TagDefinition
return String.class;
}
return null;
}
/*
* @see javax.swing.table.TableModel#isCellEditable(int, int)
*/
@Override
public boolean isCellEditable(int row, int col) {
return true;
}
/*
* @see javax.swing.table.TableModel#getRowCount()
*/
public int getRowCount() {
if (target == null) {
return 0;
}
try {
Collection tvs =
Model.getFacade().getTaggedValuesCollection(target);
// if (tvs == null) return 1;
return tvs.size() + 1;
} catch (InvalidElementException e) {
// Target has been deleted
return 0;
}
}
/*
* @see javax.swing.table.TableModel#getValueAt(int, int)
*/
public Object getValueAt(int row, int col) {
Collection tvs = Model.getFacade().getTaggedValuesCollection(target);
if (row > tvs.size() || col > 1) {
throw new IllegalArgumentException();
}
// If the row is past the end of our current collection,
// return an empty string so they can add a new value
if (row == tvs.size()) {
return "";
}
Object tv = tvs.toArray()[row];
if (col == 0) {
Object n = Model.getFacade().getTagDefinition(tv);
if (n == null) {
return "";
}
return n;
}
if (col == 1) {
String be = Model.getFacade().getValueOfTag(tv);
if (be == null) {
return "";
}
return be;
}
return "TV-" + row * 2 + col; // for debugging
}
/*
* @see javax.swing.table.TableModel#setValueAt(java.lang.Object, int, int)
*/
@Override
public void setValueAt(Object aValue, int rowIndex, int columnIndex) {
if (columnIndex != 0 && columnIndex != 1) {
return;
}
if (columnIndex == 1 && aValue == null) {
// TODO: Use default value of appropriate type here
aValue = "";
}
if ((aValue == null || "".equals(aValue)) && columnIndex == 0) {
removeRow(rowIndex);
return;
}
Collection tvs = Model.getFacade().getTaggedValuesCollection(target);
if (tvs.size() <= rowIndex) {
if (columnIndex == 0) {
addRow(new Object[] {aValue, null});
}
if (columnIndex == 1) {
addRow(new Object[] {null, aValue});
}
} else {
Object tv = getFromCollection(tvs, rowIndex);
if (columnIndex == 0) {
Model.getExtensionMechanismsHelper().setType(tv, aValue);
} else if (columnIndex == 1) {
Model.getExtensionMechanismsHelper().setDataValues(tv,
new String[] {(String) aValue });
}
fireTableChanged(
new TableModelEvent(this, rowIndex, rowIndex, columnIndex));
}
}
/**
* Add a tagged value to the model with the given type and value.
*
* @param values values for the columns:
* values[0] contains type for new TaggedValue
* values[1] contains value for new TaggedValue
*/
public void addRow(Object[] values) {
Object tagType = values[0];
String tagValue = (String) values[1];
if (tagType == null) {
tagType = "";
}
if (tagValue == null) {
// TODO: Use default value of appropriate type for TD
tagValue = "";
// tagValue = true;
}
Object tv = Model.getExtensionMechanismsFactory().createTaggedValue();
// We really shouldn't add it until after it is set up, but we
// need it to have an owner for the following method calls
Model.getExtensionMechanismsHelper().addTaggedValue(target, tv);
Model.getExtensionMechanismsHelper().setType(tv, tagType);
Model.getExtensionMechanismsHelper().setDataValues(tv,
new String[] {tagValue});
// Since we aren't sure of ordering, fire event for whole table
fireTableChanged(new TableModelEvent(this));
}
/**
* Remove the TaggedValue at the given row from the ModelElement.
*
* @param row row containing TaggedValue to be removed.
*/
public void removeRow(int row) {
Collection c = Model.getFacade().getTaggedValuesCollection(target);
if ((row >= 0) && (row < c.size())) {
Object element = getFromCollection(c, row);
Model.getUmlFactory().delete(element);
fireTableChanged(new TableModelEvent(this));
}
}
/*
* Return the ith element from a Collection.
*
* @param collection collection to get element from
* @param index index of the element to be returned
* @return the object
*/
static Object getFromCollection(Collection collection, int index) {
if (collection instanceof List) {
return ((List) collection).get(index);
}
if (index >= collection.size() || index < 0) {
throw new IndexOutOfBoundsException();
}
Iterator it = collection.iterator();
for (int i = 0; i < index; i++ ) {
it.next();
}
return it.next();
}
/*
* @see java.beans.PropertyChangeListener#propertyChange(java.beans.PropertyChangeEvent)
*/
public void propertyChange(PropertyChangeEvent evt) {
if ("taggedValue".equals(evt.getPropertyName())
|| "referenceTag".equals(evt.getPropertyName())) {
fireTableChanged(new TableModelEvent(this));
}
if (evt instanceof DeleteInstanceEvent
&& evt.getSource() == target) {
setTarget(null);
}
}
/*
* @see java.beans.VetoableChangeListener#vetoableChange(java.beans.PropertyChangeEvent)
*/
public void vetoableChange(PropertyChangeEvent pce) {
DelayedChangeNotify delayedNotify = new DelayedChangeNotify(this, pce);
SwingUtilities.invokeLater(delayedNotify);
}
/*
* @see org.argouml.kernel.DelayedVChangeListener#delayedVetoableChange(java.beans.PropertyChangeEvent)
*/
public void delayedVetoableChange(PropertyChangeEvent pce) {
fireTableDataChanged();
}
/**
* The UID.
*/
private static final long serialVersionUID = -5711005901444956345L;
}