/* * Geotoolkit.org - An Open Source Java GIS Toolkit * http://www.geotoolkit.org * * (C) 2009-2012, Open Source Geospatial Foundation (OSGeo) * (C) 2009-2012, Geomatys * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This 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 * Lesser General Public License for more details. */ package org.geotoolkit.internal.swing.table; import java.util.List; import java.util.Arrays; import java.util.Comparator; import javax.swing.JLabel; import javax.swing.JTable; import javax.swing.table.TableColumn; import javax.swing.table.TableColumnModel; import javax.swing.table.TableCellRenderer; import org.jdesktop.swingx.table.TableColumnExt; import org.jdesktop.swingx.table.TableColumnModelExt; import org.geotoolkit.lang.Static; import org.geotoolkit.lang.Workaround; import org.geotoolkit.resources.Errors; /** * Utilities that apply to {@link JTable} and related classes. * * @author Martin Desruisseaux (Geomatys) * @version 3.13 * * @since 3.05 * @module */ public final class JTables extends Static { /** * Do not allow instantiation of this class. */ private JTables() { } /** * Sets the alignments of header labels to {@link JLabel#CENTER}, if possible. * * @param table The table for which to set the alignment of header label. * * @since 3.13 */ public static void setHeaderCenterAlignment(final JTable table) { final TableCellRenderer renderer = table.getTableHeader().getDefaultRenderer(); if (renderer instanceof JLabel) { ((JLabel) renderer).setHorizontalAlignment(JLabel.CENTER); } } /** * Sets the identifiers of every visible columns in the given model, in the order * they are shown in the {@link JTable}. Hidden column, if any, are not included. * <p> * Because the affected columns depend on user actions (he may have moved the * columns around), this method is more useful immediately after the creation * of a {@link JTable}, when we still known the column order. * * @param model The columns on which to set the identifiers. * @param identifiers The identifiers to set. */ public static void setIdentifiers(final TableColumnModel model, final Object... identifiers) { for (int i=0; i<identifiers.length; i++) { model.getColumn(i).setIdentifier(identifiers[i]); } } /** * Returns every columns in the given model, in the order they are shown in the {@link JTable}. * <p> * <b>HACK:</b> This method contains a workaround for a {@link TableColumnModelExt} * behavior, which returns the columns in a different order depending on the value * of {@code includeHidden}. This hack may be removed in a future version if Swingx * change this behavior (see {@link TableColumnModelExt#getColumns(boolean)} javadoc). * * @param model The model from which to get the columns. * @param includeHidden {@code true} if invisible columns should be included. * @return The columns (never {@code null}). */ public static TableColumn[] getColumns(final TableColumnModel model, final boolean includeHidden) { TableColumn[] columns = null; if (model instanceof TableColumnModelExt) { final TableColumnModelExt ext = (TableColumnModelExt) model; final List<TableColumn> list = ext.getColumns(includeHidden); columns = list.toArray(new TableColumn[list.size()]); /* * Swingx documentation said that we have the view order if hidden columns * are not included. This is the order that we want. */ if (!includeHidden) { return columns; } } final TableColumn[] visibleColumns = new TableColumn[model.getColumnCount()]; for (int i=0; i<visibleColumns.length; i++) { visibleColumns[i] = model.getColumn(i); } if (columns == null) { return visibleColumns; } /* * The columns are in insertion order, will we wanted view order. * Re-order them now with visible columns first in the same order * then 'visibleColumns', and hidden columns last. */ Arrays.sort(columns, new Comparator<TableColumn>() { @Workaround(library="Swingx", version="1.6") @Override public int compare(final TableColumn c1, final TableColumn c2) { if (c1 != c2) { for (int i=0; i<visibleColumns.length; i++) { final TableColumn c = visibleColumns[i]; if (c == c1) return -1; if (c == c2) return +1; } } return 0; } }); return columns; } /** * Copies the configuration of the given source model to the given target model. * Every columns declared in the source model, including invisible ones, must be * present in the target model. Extra columns in the target model are ignored. * <p> * All target columns shall be visible before the call to this method. * The identifiers in the source and target models must match. * <p> * See the documentation in {@link #copyConfiguration(TableColumn, TableColumn)} * for more information on the property that are copied (not all of them are copied). * * @param source The source model. This model will not be modified. * @param target The model to modify. * @throws IllegalArgumentException If a column in {@code target} has not been found * in {@code source}. */ public static void copyConfiguration(final TableColumnModel source, final TableColumnModel target) { final TableColumn[] sourceColumns = getColumns(source, true); /* * We move the target columns before we copy the configuration, * because the later may turn some columns into invisible ones * and thus make them inacessible from the getColumn(int) method. */ for (int i=0; i<sourceColumns.length; i++) { final TableColumn sourceColumn = sourceColumns[i]; final Object identifier = sourceColumn.getIdentifier(); final int position = target.getColumnIndex(identifier); if (position < i) { throw new IllegalArgumentException(Errors.format( Errors.Keys.DuplicatedValuesForKey_1, identifier)); } target.moveColumn(position, i); } /* * Configures the columns in reverse order for avoiding the * change in index numbers caused by the column visibility changes. */ for (int i=sourceColumns.length; --i>=0;) { final TableColumn src = sourceColumns[i]; final TableColumn tgt = target.getColumn(i); assert tgt.getIdentifier().equals(src.getIdentifier()); copyConfiguration(src, tgt); } } /** * Copies the configuration of the given source column to the given target column. * Current implementation copies only the configuration which is typically modified * by the user, like the column width and the visibility status. Future versions * may expand on that. * * @param source The source column. This column will not be modified. * @param target The column to modify. */ public static void copyConfiguration(final TableColumn source, final TableColumn target) { /* * Note on set order: we set "max" first on the assumption that "min == 0", in * which case setting "max" should never fail. Next we set the "min" with the * confidence that 0 <= min <= max. Finally we set the preferred width which * shall be between min and max. The width must be last, because setting the * preferred width invalidate it. */ target.setMaxWidth(source.getMaxWidth()); target.setMinWidth(source.getMinWidth()); target.setPreferredWidth(source.getPreferredWidth()); target.setWidth(source.getWidth()); if (source instanceof TableColumnExt && target instanceof TableColumnExt) { final TableColumnExt se = (TableColumnExt) source; final TableColumnExt te = (TableColumnExt) target; te.setVisible(se.isVisible()); } } }