//----------------------------------------------------------------------------//
// //
// U n i t M o d e l //
// //
//----------------------------------------------------------------------------//
// <editor-fold defaultstate="collapsed" desc="hdr"> //
// Copyright © Hervé Bitteur and others 2000-2013. All rights reserved. //
// This software is released under the GNU General Public License. //
// Goto http://kenai.com/projects/audiveris to report bugs or suggestions. //
//----------------------------------------------------------------------------//
// </editor-fold>
package omr.constant;
import omr.sheet.Scale;
import omr.sheet.Sheet;
import omr.sheet.ui.SheetsController;
import omr.ui.treetable.AbstractTreeTableModel;
import omr.ui.treetable.TreeTableModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.swing.JOptionPane;
/**
* Class {@code UnitModel} implements a data model for units suitable
* for use in a JTreeTable.
*
* <p>A row in the UnitModel can be any instance of the 3 following types:
* <ul>
*
* <li><b>PackageNode</b> to represent a package. Its children rows can be
* either (sub) PackageNodes or UnitNodes.</li>
*
* <li><b>UnitNode</b> to represent a class that contains a ConstantSet.
* Its parent node is a PackageNode. Its children rows (if any)
* are the Constants of its ConstantSet.</li>
*
* <li><b>Constant</b> to represent a constant within a ConstantSet. In that
* case, its parent node is a UnitNode. It has no children rows.</li>
* </ul>
*
* @author Hervé Bitteur
*/
public class UnitModel
extends AbstractTreeTableModel
{
//~ Static fields/initializers ---------------------------------------------
/** Usual logger utility */
private static final Logger logger = LoggerFactory.getLogger(
UnitModel.class);
//~ Enumerations -----------------------------------------------------------
/**
* Enumeration type to describe each column of the JTreeTable
*/
public static enum Column
{
//~ Enumeration constant initializers ----------------------------------
/**
* The left column, assigned to tree structure, allows expansion
* and collapsing of sub-tree portions.
*/
TREE("Unit", true, 280, TreeTableModel.class),
/**
* Editable column with modification flag if node is a constant.
* Empty if node is a package.
*/
MODIF("Modif", true, 50, String.class),
/**
* Column that recalls the constant type, and thus the possible
* range of values.
*/
TYPE("Type", false, 70, String.class),
/**
* Column for the units, if any, used for the value.
*/
UNIT("Unit", false, 70, String.class),
/**
* Column relevant only for constants which are fractions of
* interline, as defined by {@link omr.sheet.Scale.Fraction}.
* The equivalent number of pixels is displayed, according to the scale
* of the currently selected Sheet.
* If there is no current Sheet, then just a question mark (?) is shown
*/
PIXEL("Pixels", false, 30, String.class),
/**
* Editable column for constant current value, with related tool
* tip retrieved from the constant declaration.
*/
VALUE("Value", true, 100, String.class),
/**
* Column dedicated to constant description.
*/
DESC("Description", false, 350, String.class);
//~ Instance fields ----------------------------------------------------
/** Java class to handle column content. */
private final Class<?> type;
/** Is this column user editable?. */
private final boolean editable;
/** Header for the column. */
private final String header;
/** Width for column display. */
private final int width;
//~ Constructors -------------------------------------------------------
//--------//
// Column //
//--------//
Column (String header,
boolean editable,
int width,
Class<?> type)
{
this.header = header;
this.editable = editable;
this.width = width;
this.type = type;
}
//~ Methods ------------------------------------------------------------
//----------//
// getWidth //
//----------//
public int getWidth ()
{
return width;
}
}
//~ Constructors -----------------------------------------------------------
//-----------//
// UnitModel //
//-----------//
/**
* Builds the model.
*/
public UnitModel ()
{
super(UnitManager.getInstance().getRoot());
}
//~ Methods ----------------------------------------------------------------
//----------//
// getChild //
//----------//
/**
* Returns the child of {@code parent} at index {@code index} in
* the parent's child array.
*
* @param parent a node in the tree, obtained from this data source
* @param i the child index in parent sequence
* @return the child of {@code parent</code> at index <code>index}
*/
@Override
public Object getChild (Object parent,
int i)
{
if (parent instanceof PackageNode) {
PackageNode pNode = (PackageNode) parent;
return pNode.getChild(i);
}
if (parent instanceof UnitNode) {
UnitNode unit = (UnitNode) parent;
ConstantSet set = unit.getConstantSet();
if (set != null) {
return set.getConstant(i);
}
}
System.err.println(
"*** getChild. Unexpected node " + parent + ", type="
+ parent.getClass().getName());
return null;
}
//---------------//
// getChildCount //
//---------------//
/**
* Returns the number of children of {@code parent}.
*
* @param parent a node in the tree, obtained from this data source
* @return the number of children of the node {@code parent}
*/
@Override
public int getChildCount (Object parent)
{
if (parent instanceof PackageNode) {
return ((PackageNode) parent).getChildCount();
}
if (parent instanceof UnitNode) {
UnitNode unit = (UnitNode) parent;
ConstantSet set = unit.getConstantSet();
return set.size();
}
if (parent instanceof Constant) {
return 0;
}
System.err.println(
"*** getChildCount. Unexpected node " + parent + ", type="
+ parent.getClass().getName());
return 0;
}
//----------------//
// getColumnClass //
//----------------//
/**
* Report the class for instances in the provided column.
*
* @param column the desired column
* @return the class for all cells in this column
*/
@Override
public Class<?> getColumnClass (int column)
{
return Column.values()[column].type;
}
//----------------//
// getColumnCount //
//----------------//
/**
* Report the number of column in the table.
*
* @return the table number of columns
*/
@Override
public int getColumnCount ()
{
return Column.values().length;
}
//---------------//
// getColumnName //
//---------------//
/**
* Report the name of the column at hand.
*
* @param column the desired column
* @return the column name
*/
@Override
public String getColumnName (int column)
{
return Column.values()[column].header;
}
//------------//
// getValueAt //
//------------//
/**
* Report the value of a cell.
*
* @param node the desired node
* @param col the related column
* @return the cell value
*/
@Override
public Object getValueAt (Object node,
int col)
{
Column column = Column.values()[col];
switch (column) {
case MODIF:
if (node instanceof PackageNode) {
return null;
} else if (node instanceof Constant) {
Constant constant = (Constant) node;
return Boolean.valueOf(!constant.isSourceValue());
}
return "";
case VALUE:
if (node instanceof Constant) {
Constant constant = (Constant) node;
if (constant instanceof Constant.Boolean) {
Constant.Boolean cb = (Constant.Boolean) constant;
return cb.getCachedValue();
} else {
return constant.getCurrentString();
}
} else {
return "";
}
case TYPE:
if (node instanceof Constant) {
Constant constant = (Constant) node;
return constant.getShortTypeName();
} else {
return "";
}
case UNIT:
if (node instanceof Constant) {
Constant constant = (Constant) node;
return (constant.getQuantityUnit() != null)
? constant.getQuantityUnit() : "";
} else {
return "";
}
case PIXEL:
if (node instanceof Constant) {
Constant constant = (Constant) node;
if (constant instanceof Scale.Fraction
|| constant instanceof Scale.LineFraction
|| constant instanceof Scale.AreaFraction) {
// Compute the equivalent in pixels of this interline-based
// fraction, line or area fraction, provided that we have a
// current sheet and its scale is available.
Sheet sheet = SheetsController.getCurrentSheet();
if (sheet != null) {
Scale scale = sheet.getScale();
if (scale != null) {
if (constant instanceof Scale.Fraction) {
return Integer.valueOf(
scale.toPixels((Scale.Fraction) constant));
} else if (constant instanceof Scale.LineFraction) {
return Integer.valueOf(
scale.toPixels(
(Scale.LineFraction) constant));
} else if (constant instanceof Scale.AreaFraction) {
return Integer.valueOf(
scale.toPixels(
(Scale.AreaFraction) constant));
}
}
} else {
return "?"; // Cannot compute the value
}
}
}
return "";
case DESC:
if (node instanceof Constant) {
Constant constant = (Constant) node;
return constant.getDescription();
} else {
return null;
}
}
return null; // For the compiler
}
//----------------//
// isCellEditable //
//----------------//
/**
* Predicate on cell being editable
*
* @param node the related tree node
* @param column the related table column
* @return true if editable
*/
@Override
public boolean isCellEditable (Object node,
int column)
{
Column col = Column.values()[column];
if (col == Column.MODIF) {
if (node instanceof Constant) {
Constant constant = (Constant) node;
return Boolean.valueOf(!constant.isSourceValue());
// } else if (node instanceof UnitNode) {
// return true;
} else {
return false;
}
} else {
return col.editable;
}
}
//--------//
// isLeaf //
//--------//
/**
* Returns {@code true} if {@code node} is a leaf.
*
* @param node a node in the tree, obtained from this data source
* @return true if {@code node} is a leaf
*/
@Override
public boolean isLeaf (Object node)
{
if (node instanceof Constant) {
return true;
}
if (node instanceof UnitNode) {
UnitNode unit = (UnitNode) node;
return (unit.getConstantSet() == null);
}
return false; // By default
}
//------------//
// setValueAt //
//------------//
/**
* Assign a value to a cell
*
* @param value the value to assign
* @param node the target node
* @param col the related column
*/
@Override
public void setValueAt (Object value,
Object node,
int col)
{
if (node instanceof Constant) {
Constant constant = (Constant) node;
Column column = Column.values()[col];
switch (column) {
case VALUE:
try {
constant.setValue(value.toString());
// Forward modif to the modif status column and to the pixel
// column (brute force!)
fireTreeNodesChanged(
this,
new Object[]{getRoot()},
null,
null);
} catch (NumberFormatException ex) {
JOptionPane.showMessageDialog(
null,
"Illegal number format");
}
break;
case MODIF:
if (!((Boolean) value).booleanValue()) {
constant.reset();
fireTreeNodesChanged(
this,
new Object[]{getRoot()},
null,
null);
}
break;
default:
}
}
}
}