Package com.eteks.furniturelibraryeditor.swing

Source Code of com.eteks.furniturelibraryeditor.swing.FurnitureLibraryTable

/*
* FurnitureLibraryTable.java 18 d�c. 2009
*
* Furniture Library Editor, Copyright (c) 2009 Emmanuel PUYBARET / eTeks <info@eteks.com>
*
* This program 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 2 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
package com.eteks.furniturelibraryeditor.swing;

import java.awt.Component;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Rectangle;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.datatransfer.UnsupportedFlavorException;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;
import java.lang.ref.WeakReference;
import java.math.BigDecimal;
import java.text.Collator;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Currency;
import java.util.List;

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.TransferHandler;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.table.AbstractTableModel;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableColumnModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;

import com.eteks.furniturelibraryeditor.model.FurnitureLibraryUserPreferences;
import com.eteks.furniturelibraryeditor.model.FurnitureLibrary;
import com.eteks.furniturelibraryeditor.viewcontroller.FurnitureLanguageController;
import com.eteks.furniturelibraryeditor.viewcontroller.FurnitureLibraryController;
import com.eteks.sweethome3d.model.CatalogPieceOfFurniture;
import com.eteks.sweethome3d.model.CollectionEvent;
import com.eteks.sweethome3d.model.CollectionListener;
import com.eteks.sweethome3d.model.Content;
import com.eteks.sweethome3d.model.SelectionEvent;
import com.eteks.sweethome3d.model.SelectionListener;
import com.eteks.sweethome3d.model.UserPreferences;
import com.eteks.sweethome3d.swing.IconManager;
import com.eteks.sweethome3d.tools.URLContent;
import com.eteks.sweethome3d.viewcontroller.View;

/**
* A table used to edit furniture library.
* @author Emmanuel Puybaret
*/
public class FurnitureLibraryTable extends JTable implements View {
  private ListSelectionListener tableSelectionListener;

  public FurnitureLibraryTable(FurnitureLibrary furnitureLibrary,
                               FurnitureLibraryUserPreferences preferences,
                               FurnitureLibraryController furnitureLibraryController,
                               FurnitureLanguageController furnitureLanguageController) {
    super(new FurnitureLibraryTableModel(furnitureLibrary, furnitureLanguageController),
        new FurnitureLibraryTableColumnModel(furnitureLibrary, preferences, furnitureLanguageController));
    addTableHeaderListener();
    setAutoResizeMode(AUTO_RESIZE_OFF);
    updateTableColumnsWidth();
    if (furnitureLibraryController != null) {
      addSelectionListeners(furnitureLibraryController);
      addMouseListener(furnitureLibraryController);
      addFurnitureLanguageListener(furnitureLanguageController);
      setTransferHandler(new TableTransferHandler(furnitureLibraryController));
    }
    addUserPreferencesListener(preferences);
  }
 
  /**
   * Adds a listener to <code>preferences</code> to repaint this table
   * and its header when unit changes. 
   */
  private void addUserPreferencesListener(UserPreferences preferences) {
    preferences.addPropertyChangeListener(
        UserPreferences.Property.UNIT, new UserPreferencesChangeListener(this));
  }

  /**
   * Preferences property listener bound to this table with a weak reference to avoid
   * strong link between user preferences and this table. 
   */
  private static class UserPreferencesChangeListener implements PropertyChangeListener {
    private WeakReference<FurnitureLibraryTable>  furnitureLibraryTable;

    public UserPreferencesChangeListener(FurnitureLibraryTable furnitureTable) {
      this.furnitureLibraryTable = new WeakReference<FurnitureLibraryTable>(furnitureTable);
    }
   
    public void propertyChange(PropertyChangeEvent ev) {
      // If furniture table was garbage collected, remove this listener from preferences
      FurnitureLibraryTable furnitureLibraryTable = this.furnitureLibraryTable.get();
      if (furnitureLibraryTable == null) {
        ((UserPreferences)ev.getSource()).removePropertyChangeListener(
            UserPreferences.Property.valueOf(ev.getPropertyName()), this);
      } else {
        furnitureLibraryTable.repaint();
        furnitureLibraryTable.getTableHeader().repaint();
      }
    }
  }

  /**
   * Adds selection listeners to this table.
   */
  private void addSelectionListeners(final FurnitureLibraryController controller) {  
    final SelectionListener controllerSelectionListener = new SelectionListener() {
        public void selectionChanged(SelectionEvent ev) {
          setSelectedFurniture(controller.getSelectedFurniture());       
        }
      };
    this.tableSelectionListener = new ListSelectionListener () {
        public void valueChanged(ListSelectionEvent ev) {
          if (!ev.getValueIsAdjusting()) {
            controller.removeSelectionListener(controllerSelectionListener);
            int [] selectedRows = getSelectedRows();
            // Build the list of selected furniture
            List<CatalogPieceOfFurniture> selectedFurniture =
                new ArrayList<CatalogPieceOfFurniture>(selectedRows.length);
            TableModel tableModel = getModel();
            for (int index : selectedRows) {
              // Add to selectedFurniture table model value that stores piece
              selectedFurniture.add((CatalogPieceOfFurniture)tableModel.getValueAt(index, 0));
            }
            // Set the new selection in controller
            controller.setSelectedFurniture(selectedFurniture);
            controller.addSelectionListener(controllerSelectionListener);
          }
        }
      };
    getSelectionModel().addListSelectionListener(this.tableSelectionListener);
    controller.addSelectionListener(controllerSelectionListener);
  }

  /**
   * Adds a double click mouse listener to modify selected furniture.
   */
  private void addMouseListener(final FurnitureLibraryController controller) {
    addMouseListener(new MouseAdapter () {
        @Override
        public void mouseClicked(MouseEvent ev) {
          if (ev.getClickCount() == 2) {
            controller.modifySelectedFurniture();
          }
        }
      });
  }

  /**
   * Adds a mouse listener on table header that will sort furniture.
   */
  private void addTableHeaderListener() {
    // Sort on click in column header
    getTableHeader().addMouseListener(new MouseAdapter() {
        @Override
        public void mouseClicked(MouseEvent ev) {
          FurnitureLibraryTableModel tableModel = (FurnitureLibraryTableModel)getModel();
          List<CatalogPieceOfFurniture> selectedFurniture = new ArrayList<CatalogPieceOfFurniture>();
          for (int index : getSelectedRows()) {
            selectedFurniture.add((CatalogPieceOfFurniture)tableModel.getValueAt(index, 0));
          }
          int columnIndex = getTableHeader().columnAtPoint(ev.getPoint());
          Object columnIdentifier = getColumnModel().getColumn(columnIndex).getIdentifier();
          if (columnIdentifier instanceof String) {
            String propertyKey = (String)columnIdentifier;
            if (columnIdentifier.equals(tableModel.getSortProperty())) {
              if (tableModel.isDescendingOrder()) {
                tableModel.setSortProperty(null);
              } else {
                tableModel.setDescendingOrder(true);
              }
            } else if (tableModel.getFurnitureComparator(propertyKey) != null) {
              tableModel.setSortProperty(propertyKey);
              tableModel.setDescendingOrder(false);
            }
          }
          getTableHeader().repaint();
          setSelectedFurniture(selectedFurniture);
        }
      });
  }

  /**
   * Selects furniture in table.
   */
  private void setSelectedFurniture(List<CatalogPieceOfFurniture> selectedFurniture) {
    getSelectionModel().removeListSelectionListener(this.tableSelectionListener);
    clearSelection();
    FurnitureLibraryTableModel tableModel = (FurnitureLibraryTableModel)getModel();
    int minIndex = Integer.MAX_VALUE;
    int maxIndex = Integer.MIN_VALUE;
    for (CatalogPieceOfFurniture piece : selectedFurniture) {
      if (piece instanceof CatalogPieceOfFurniture) {
        // Search index of piece in sorted table model
        int index = tableModel.getPieceOfFurnitureIndex((CatalogPieceOfFurniture)piece);
        // If the piece was found (during the addition of a piece to library, the model may not be updated yet)
        if (index != -1) {
          addRowSelectionInterval(index, index);
          minIndex = Math.min(minIndex, index);
          maxIndex = Math.max(maxIndex, index);
        }
      }
    }
    if (minIndex != Integer.MIN_VALUE) {
      makeRowsVisible(minIndex, maxIndex);
    }
    getSelectionModel().addListSelectionListener(this.tableSelectionListener);
  }
 
  /**
   * Ensures the rectangle which displays rows from <code>minIndex</code> to <code>maxIndex</code> is visible.
   */
  private void makeRowsVisible(int minRow, int maxRow) {   
    // Compute the rectangle that includes a row
    Rectangle includingRectangle = getCellRect(minRow, 0, true);
    if (minRow != maxRow) {
      includingRectangle = includingRectangle.
          union(getCellRect(maxRow, 0, true));     
    }
    if (getAutoResizeMode() == AUTO_RESIZE_OFF) {
      int lastColumn = getColumnCount() - 1;
      includingRectangle = includingRectangle.
          union(getCellRect(minRow, lastColumn, true));
      if (minRow != maxRow) {
        includingRectangle = includingRectangle.
            union(getCellRect(maxRow, lastColumn, true));     
      }
    }
    scrollRectToVisible(includingRectangle);
  }

  /**
   * Adds a listener on furniture language change to resort furniture.
   */
  private void addFurnitureLanguageListener(FurnitureLanguageController controller) {
    controller.addPropertyChangeListener(FurnitureLanguageController.Property.FURNITURE_LANGUAGE,
        new PropertyChangeListener() {
          public void propertyChange(PropertyChangeEvent ev) {
            FurnitureLibraryTableModel tableModel = (FurnitureLibraryTableModel)getModel();
            List<CatalogPieceOfFurniture> selectedFurniture = new ArrayList<CatalogPieceOfFurniture>();
            for (int index : getSelectedRows()) {
              selectedFurniture.add((CatalogPieceOfFurniture)tableModel.getValueAt(index, 0));
            }
            tableModel.sortFurniture();
            setSelectedFurniture(selectedFurniture);
          }
        });
  }

  /**
   * Updates table columns width from the content of its cells.
   */
  private void updateTableColumnsWidth() {
    int intercellWidth = getIntercellSpacing().width;
    TableColumnModel columnModel = getColumnModel();
    TableModel tableModel = getModel();
    for (int columnIndex = 0, n = columnModel.getColumnCount(); columnIndex < n; columnIndex++) {
      TableColumn column = columnModel.getColumn(columnIndex);
      int modelColumnIndex = convertColumnIndexToModel(columnIndex);
      int preferredWidth = column.getPreferredWidth();
      preferredWidth = Math.max(preferredWidth, column.getHeaderRenderer().getTableCellRendererComponent(
          this, column.getHeaderValue(), false, false, -1, columnIndex).getPreferredSize().width);
      for (int rowIndex = 0, m = tableModel.getRowCount(); rowIndex < m; rowIndex++) {
        preferredWidth = Math.max(preferredWidth,
            column.getCellRenderer().getTableCellRendererComponent(
                this, tableModel.getValueAt(rowIndex, modelColumnIndex), false, false, -1, columnIndex).
                    getPreferredSize().width);
      }
      column.setPreferredWidth(preferredWidth + intercellWidth);
      column.setWidth(preferredWidth + intercellWidth);
    }
  }

  /**
   * Returns a tooltip for furniture pieces described in this table.
   */
  @Override
  public String getToolTipText(MouseEvent ev) {
    int column = columnAtPoint(ev.getPoint());
    if (column != -1
        && FurnitureLibrary.FURNITURE_ICON_PROPERTY.equals(getColumnModel().getColumn(column).getIdentifier())) {
      int row = rowAtPoint(ev.getPoint());
      if (row != -1) {
        CatalogPieceOfFurniture piece = (CatalogPieceOfFurniture)getModel().getValueAt(row, 0);
        if (piece.getIcon() instanceof URLContent) {
          String tooltip = "<html><center><img width='128' height='128' src='"
              + ((URLContent)piece.getIcon()).getURL() + "'>";
          return tooltip;
        }
      }
    }
    return null;
  }

  @Override
  public Dimension getPreferredScrollableViewportSize() {
    return new Dimension(getPreferredSize().width, 400);
  }
 
 
  /**
   * Model used by furniture table.
   */
  private static class FurnitureLibraryTableModel extends AbstractTableModel {
    private final FurnitureLibrary              furnitureLibrary;
    private final FurnitureLanguageController   controller;
    private List<CatalogPieceOfFurniture>       sortedFurniture;
    private String                              sortProperty;
    private boolean                             descendingOrder;
   
    public FurnitureLibraryTableModel(FurnitureLibrary furnitureLibrary,
                                      FurnitureLanguageController controller) {
      this.furnitureLibrary = furnitureLibrary;
      this.controller = controller;
      addFurnitureLibraryListener(furnitureLibrary);
      sortFurniture();
    }

    private void addFurnitureLibraryListener(final FurnitureLibrary furnitureLibrary) {
      furnitureLibrary.addListener(new CollectionListener<CatalogPieceOfFurniture>() {
        public void collectionChanged(CollectionEvent<CatalogPieceOfFurniture> ev) {
          CatalogPieceOfFurniture piece = ev.getItem();
          int pieceIndex = ev.getIndex();
          switch (ev.getType()) {
            case ADD :
              int insertionIndex = getPieceOfFurnitureInsertionIndex(piece, furnitureLibrary, pieceIndex);
              if (insertionIndex != -1) {
                sortedFurniture.add(insertionIndex, piece);
                fireTableRowsInserted(insertionIndex, insertionIndex);
              }
              break;
            case DELETE :
              int deletionIndex = getPieceOfFurnitureDeletionIndex(piece, furnitureLibrary, pieceIndex);
              if (deletionIndex != -1) {
                sortedFurniture.remove(deletionIndex);
                fireTableRowsDeleted(deletionIndex, deletionIndex);
              }
              break;
          }
        }

        /**
         * Returns the index of an added <code>piece</code> in furniture table, with a default index
         * of <code>pieceIndex</code> if furniture library isn't sorted.
         * If <code>piece</code> isn't added to furniture table, the returned value is
         * equals to the insertion index where piece should be added.
         */
        private int getPieceOfFurnitureInsertionIndex(CatalogPieceOfFurniture piece,
                                                      FurnitureLibrary furnitureLibrary,
                                                      int pieceIndex) {
          if (sortProperty == null) {
            return pieceIndex;
          }
          // Default case when piece is included and furniture is  sorted
          int sortedIndex = Collections.binarySearch(sortedFurniture, piece, getFurnitureComparator(sortProperty));
          if (sortedIndex >= 0) {
            return sortedIndex;
          } else {
            return -(sortedIndex + 1);
          }             
        }

        /**
         * Returns the index of an existing <code>piece</code> in furniture table, with a default index
         * of <code>pieceIndex</code> if furniture isn't sorted.
         */
        private int getPieceOfFurnitureDeletionIndex(CatalogPieceOfFurniture piece,
                                                     FurnitureLibrary furnitureLibrary,
                                                     int pieceIndex) {
          if (sortProperty == null) {
            return pieceIndex;
          }
          return getPieceOfFurnitureIndex(piece);             
        }
      });
    }

    @Override
    public String getColumnName(int columnIndex) {
      // Column name is set by TableColumn instances themselves
      return null;
    }

    public int getColumnCount() {
      // Column count is set by TableColumnModel itself
      return 0;
    }

    public int getRowCount() {
      return this.sortedFurniture.size();
    }

    public Object getValueAt(int rowIndex, int columnIndex) {
      // Always return piece itself, the real property displayed at screen is chosen by renderer
      return this.sortedFurniture.get(rowIndex);
    }

    /**
     * Returns the index of <code>piece</code> in furniture table, or -1.
     */
    public int getPieceOfFurnitureIndex(CatalogPieceOfFurniture searchedPiece) {
      for (int i = 0, n = this.sortedFurniture.size(); i < n; i++) {
        CatalogPieceOfFurniture piece = this.sortedFurniture.get(i);
        if (searchedPiece == piece) {
          return i;
        }
      }
      return -1;
    }

    /**
     * Sorts furniture.
     */
    public void sortFurniture() {
      int previousRowCount = this.sortedFurniture != null
          ? this.sortedFurniture.size()
          : 0;
      List<CatalogPieceOfFurniture> libraryFurniture = this.furnitureLibrary.getFurniture();
      this.sortedFurniture = new ArrayList<CatalogPieceOfFurniture>(libraryFurniture);
      // Sort it if necessary
      if (this.sortProperty != null) {
        Comparator<CatalogPieceOfFurniture> furnitureComparator = getFurnitureComparator(this.sortProperty);
        Collections.sort(this.sortedFurniture, furnitureComparator);        
      }
     
      if (previousRowCount != this.sortedFurniture.size()) {
        fireTableDataChanged();
      } else {
        fireTableRowsUpdated(0, getRowCount() - 1);
      }
    }

    public Comparator<CatalogPieceOfFurniture> getFurnitureComparator(final String propertyKey) {
      final Collator collator = Collator.getInstance();
      Comparator<CatalogPieceOfFurniture> furnitureComparator = null;
      if (FurnitureLibrary.FURNITURE_ID_PROPERTY.equals(propertyKey)) {
        furnitureComparator = new Comparator<CatalogPieceOfFurniture>() {
            public int compare(CatalogPieceOfFurniture piece1, CatalogPieceOfFurniture piece2) {
              if (piece1.getId() == null) {
                return -1;
              } else if (piece2.getId() == null) {
                return 1;
              } else {
                return collator.compare(piece1.getId(), piece2.getId());
              }
            }
          };
      } else if (FurnitureLibrary.FURNITURE_NAME_PROPERTY.equals(propertyKey)) {
         furnitureComparator = new Comparator<CatalogPieceOfFurniture>() {
             public int compare(CatalogPieceOfFurniture piece1, CatalogPieceOfFurniture piece2) {
               String piece1Name = (String)furnitureLibrary.getPieceOfFurnitureLocalizedData(
                   piece1, controller.getFurnitureLangauge(), propertyKey, piece1.getName());
               String piece2Name = (String)furnitureLibrary.getPieceOfFurnitureLocalizedData(
                   piece2, controller.getFurnitureLangauge(), propertyKey, piece2.getName());
               return collator.compare(piece1Name, piece2Name);
             }
           };
      } else if (FurnitureLibrary.FURNITURE_DESCRIPTION_PROPERTY.equals(propertyKey)) {
        furnitureComparator = new Comparator<CatalogPieceOfFurniture>() {
            public int compare(CatalogPieceOfFurniture piece1, CatalogPieceOfFurniture piece2) {
              String piece1Description = (String)furnitureLibrary.getPieceOfFurnitureLocalizedData(
                  piece1, controller.getFurnitureLangauge(), propertyKey, piece1.getDescription());
              if (piece1Description == null) {
                return -1;
              } else {
                String piece2Description = (String)furnitureLibrary.getPieceOfFurnitureLocalizedData(
                    piece2, controller.getFurnitureLangauge(), propertyKey, piece2.getDescription());
                if (piece2Description == null) {
                  return 1;
                } else {
                  return collator.compare(piece1Description, piece2Description);
                }
              }
            }
          };
      } else if (FurnitureLibrary.FURNITURE_CREATOR_PROPERTY.equals(propertyKey)) {
        furnitureComparator = new Comparator<CatalogPieceOfFurniture>() {
            public int compare(CatalogPieceOfFurniture piece1, CatalogPieceOfFurniture piece2) {
              return collator.compare(piece1.getCreator(), piece2.getCreator());
            }
          };
      } else if (FurnitureLibrary.FURNITURE_CATEGORY_PROPERTY.equals(propertyKey)) {
        furnitureComparator = new Comparator<CatalogPieceOfFurniture>() {
            public int compare(CatalogPieceOfFurniture piece1, CatalogPieceOfFurniture piece2) {
              String piece1Category = (String)furnitureLibrary.getPieceOfFurnitureLocalizedData(
                  piece1, controller.getFurnitureLangauge(), propertyKey, piece1.getCategory().getName());
              String piece2Category = (String)furnitureLibrary.getPieceOfFurnitureLocalizedData(
                  piece2, controller.getFurnitureLangauge(), propertyKey, piece2.getCategory().getName());
              return collator.compare(piece1Category, piece2Category);
            }
          };
      } else if (FurnitureLibrary.FURNITURE_PRICE_PROPERTY.equals(propertyKey)) {
        furnitureComparator = new Comparator<CatalogPieceOfFurniture>() {
            public int compare(CatalogPieceOfFurniture piece1, CatalogPieceOfFurniture piece2) {
              if (piece1.getPrice() == null) {
                return -1;
              } else if (piece2.getPrice() == null) {
                return 1;
              } else {
                return piece1.getPrice().compareTo(piece2.getPrice());
              }
            }
          };
      } else if (FurnitureLibrary.FURNITURE_VALUE_ADDED_TAX_PERCENTAGE_PROPERTY.equals(propertyKey)) {
        furnitureComparator = new Comparator<CatalogPieceOfFurniture>() {
            public int compare(CatalogPieceOfFurniture piece1, CatalogPieceOfFurniture piece2) {
              if (piece1.getValueAddedTaxPercentage() == null) {
                return -1;
              } else if (piece2.getValueAddedTaxPercentage() == null) {
                return 1;
              } else {
                return piece1.getValueAddedTaxPercentage().compareTo(piece2.getValueAddedTaxPercentage());
              }
            }
          };
      } else if (FurnitureLibrary.FURNITURE_WIDTH_PROPERTY.equals(propertyKey)) {
        furnitureComparator = new Comparator<CatalogPieceOfFurniture>() {
            public int compare(CatalogPieceOfFurniture piece1, CatalogPieceOfFurniture piece2) {
              return piece1.getWidth() < piece2.getWidth() 
                  ? -1
                  : (piece1.getWidth() == piece2.getWidth()
                      ? 0 : 1);
            }
          };
      } else if (FurnitureLibrary.FURNITURE_DEPTH_PROPERTY.equals(propertyKey)) {
        furnitureComparator = new Comparator<CatalogPieceOfFurniture>() {
            public int compare(CatalogPieceOfFurniture piece1, CatalogPieceOfFurniture piece2) {
              return piece1.getDepth() < piece2.getDepth() 
                  ? -1
                  : (piece1.getDepth() == piece2.getDepth()
                      ? 0 : 1);
            }
          };
      } else if (FurnitureLibrary.FURNITURE_HEIGHT_PROPERTY.equals(propertyKey)) {
        furnitureComparator = new Comparator<CatalogPieceOfFurniture>() {
            public int compare(CatalogPieceOfFurniture piece1, CatalogPieceOfFurniture piece2) {
              return piece1.getHeight() < piece2.getHeight() 
                  ? -1
                  : (piece1.getHeight() == piece2.getHeight()
                      ? 0 : 1);
            }
          };
      } else if (FurnitureLibrary.FURNITURE_MOVABLE_PROPERTY.equals(propertyKey)) {
        furnitureComparator = new Comparator<CatalogPieceOfFurniture>() {
            public int compare(CatalogPieceOfFurniture piece1, CatalogPieceOfFurniture piece2) {
              return piece1.isMovable() == piece2.isMovable() 
                  ? 0
                  : (piece1.isMovable()
                      ? -1 : 1);
            }
          };
      } else if (FurnitureLibrary.FURNITURE_DOOR_OR_WINDOW_PROPERTY.equals(propertyKey)) {
        furnitureComparator = new Comparator<CatalogPieceOfFurniture>() {
            public int compare(CatalogPieceOfFurniture piece1, CatalogPieceOfFurniture piece2) {
              return piece1.isDoorOrWindow() == piece2.isDoorOrWindow() 
                  ? 0
                  : (piece1.isDoorOrWindow()
                      ? -1 : 1);
            }
          };
      } else if (FurnitureLibrary.FURNITURE_ELEVATION_PROPERTY.equals(propertyKey)) {
        furnitureComparator = new Comparator<CatalogPieceOfFurniture>() {
            public int compare(CatalogPieceOfFurniture piece1, CatalogPieceOfFurniture piece2) {
              return piece1.getElevation() < piece2.getElevation() 
                  ? -1
                  : (piece1.getElevation() == piece2.getElevation()
                      ? 0 : 1);
            }
          };
      } else if (FurnitureLibrary.FURNITURE_RESIZABLE_PROPERTY.equals(propertyKey)) {
        furnitureComparator = new Comparator<CatalogPieceOfFurniture>() {
            public int compare(CatalogPieceOfFurniture piece1, CatalogPieceOfFurniture piece2) {
              return piece1.isResizable() == piece2.isResizable() 
                  ? 0
                  : (piece1.isResizable()
                      ? -1 : 1);
            }
          };
      } else if (FurnitureLibrary.FURNITURE_DEFORMABLE_PROPERTY.equals(propertyKey)) {
        furnitureComparator = new Comparator<CatalogPieceOfFurniture>() {
          public int compare(CatalogPieceOfFurniture piece1, CatalogPieceOfFurniture piece2) {
            return piece1.isDeformable() == piece2.isDeformable() 
                ? 0
                : (piece1.isDeformable()
                    ? -1 : 1);
          }
        };
    } else {
        furnitureComparator = new Comparator<CatalogPieceOfFurniture>() {
          @SuppressWarnings("unchecked")
          public int compare(CatalogPieceOfFurniture piece1, CatalogPieceOfFurniture piece2) {
            Object piece1Property = furnitureLibrary.getPieceOfFurnitureLocalizedData(
                piece1, controller.getFurnitureLangauge(), propertyKey);
            if (piece1Property == null
                || !(piece1Property instanceof Comparable)) {
              return -1;
            } else {
              Object piece2Property = furnitureLibrary.getPieceOfFurnitureLocalizedData(
                  piece2, controller.getFurnitureLangauge(), propertyKey, piece2.getDescription());
              return ((Comparable)piece1Property).compareTo(piece2Property);
            }
          }
        };
      }
      if (this.descendingOrder) {
        furnitureComparator = Collections.reverseOrder(furnitureComparator);
      }
      return furnitureComparator;
    }

    public String getSortProperty() {
      return this.sortProperty;
    }

    public void setSortProperty(String sortProperty) {
      this.sortProperty = sortProperty;
      sortFurniture();
    }
   
    public boolean isDescendingOrder() {
      return this.descendingOrder;
    }
   
    public void setDescendingOrder(boolean descendingOrder) {
      this.descendingOrder = descendingOrder;
      sortFurniture();
    }
  }

 
  /**
   * Column table model used by furniture library table.
   */
  private static class FurnitureLibraryTableColumnModel extends DefaultTableColumnModel {
    public FurnitureLibraryTableColumnModel(FurnitureLibrary furnitureLibrary,
                                            FurnitureLibraryUserPreferences preferences,
                                            FurnitureLanguageController controller) {
      createColumns(furnitureLibrary, preferences, controller);
      addLanguageListener(preferences);
    }

    /**
     * Creates the list of available columns from furniture sortable properties.
     */
    private void createColumns(FurnitureLibrary furnitureLibrary,
                               FurnitureLibraryUserPreferences preferences,
                               FurnitureLanguageController controller) {
        // Create the list of custom columns
      TableCellRenderer headerRenderer = getHeaderRenderer();
      for (String columnProperty : preferences.getEditedProperties()) {
        if (columnProperty != "MODEL_ROTATION"
            && columnProperty != "MODEL") {
          TableColumn tableColumn = new TableColumn();
          tableColumn.setIdentifier(columnProperty);
          tableColumn.setHeaderValue(getColumnName(columnProperty, preferences));
          tableColumn.setPreferredWidth(getColumnPreferredWidth(columnProperty));
          tableColumn.setCellRenderer(getColumnRenderer(columnProperty, furnitureLibrary, preferences, controller));
          tableColumn.setHeaderRenderer(headerRenderer);
          addColumn(tableColumn);
        }
      }
    }

    /**
     * Adds a property change listener to <code>preferences</code> to update
     * column names when preferred language changes.
     */
    private void addLanguageListener(UserPreferences preferences) {
      preferences.addPropertyChangeListener(UserPreferences.Property.LANGUAGE,
          new LanguageChangeListener(this));
    }

    /**
     * Preferences property listener bound to this component with a weak reference to avoid
     * strong link between preferences and this component. 
     */
    private static class LanguageChangeListener implements PropertyChangeListener {
      private WeakReference<FurnitureLibraryTableColumnModel> furnitureTableColumnModel;

      public LanguageChangeListener(FurnitureLibraryTableColumnModel furnitureTable) {
        this.furnitureTableColumnModel = new WeakReference<FurnitureLibraryTableColumnModel>(furnitureTable);
      }
     
      public void propertyChange(PropertyChangeEvent ev) {
        // If furniture table column model was garbage collected, remove this listener from preferences
        FurnitureLibraryTableColumnModel furnitureTableColumnModel = this.furnitureTableColumnModel.get();
        UserPreferences preferences = (UserPreferences)ev.getSource();
        if (furnitureTableColumnModel == null) {
          preferences.removePropertyChangeListener(UserPreferences.Property.LANGUAGE, this);
        } else {         
          // Change column name and renderer from current locale
          for (int i = 0; i < furnitureTableColumnModel.getColumnCount(); i++) {
            TableColumn tableColumn = furnitureTableColumnModel.getColumn(i);
            Object columnIdentifier = tableColumn.getIdentifier();
            if (columnIdentifier instanceof String) {
              try {
                tableColumn.setHeaderValue(furnitureTableColumnModel.getColumnName(
                    (String)columnIdentifier, preferences));
              } catch (IllegalArgumentException ex) {
                // Don't change unknown columns
              }
            }
          }
        }
      }
    }
   
    /**
     * Returns localized column names.
     */
    private String getColumnName(String propertyKey,
                                 UserPreferences preferences) {
      if (FurnitureLibrary.FURNITURE_ID_PROPERTY.equals(propertyKey)) {
        return preferences.getLocalizedString(FurnitureLibraryTable.class, "idColumn");
      } else if (FurnitureLibrary.FURNITURE_NAME_PROPERTY.equals(propertyKey)) {
        return preferences.getLocalizedString(FurnitureLibraryTable.class, "nameColumn");
      } else if (FurnitureLibrary.FURNITURE_DESCRIPTION_PROPERTY.equals(propertyKey)) {
        return preferences.getLocalizedString(FurnitureLibraryTable.class, "descriptionColumn");
      } else if (FurnitureLibrary.FURNITURE_CREATOR_PROPERTY.equals(propertyKey)) {
        return preferences.getLocalizedString(FurnitureLibraryTable.class, "creatorColumn");
      } else if (FurnitureLibrary.FURNITURE_CATEGORY_PROPERTY.equals(propertyKey)) {
        return preferences.getLocalizedString(FurnitureLibraryTable.class, "categoryColumn");
      } else if (FurnitureLibrary.FURNITURE_PRICE_PROPERTY.equals(propertyKey)) {
        return preferences.getLocalizedString(FurnitureLibraryTable.class, "priceColumn");
      } else if (FurnitureLibrary.FURNITURE_VALUE_ADDED_TAX_PERCENTAGE_PROPERTY.equals(propertyKey)) {
        return preferences.getLocalizedString(FurnitureLibraryTable.class, "valueAddedTaxPercentageColumn");
      } else if (FurnitureLibrary.FURNITURE_ICON_PROPERTY.equals(propertyKey)) {
        return preferences.getLocalizedString(FurnitureLibraryTable.class, "iconColumn");
      } else if (FurnitureLibrary.FURNITURE_PLAN_ICON_PROPERTY.equals(propertyKey)) {
        return preferences.getLocalizedString(FurnitureLibraryTable.class, "planIconColumn");
      } else if (FurnitureLibrary.FURNITURE_MODEL_PROPERTY.equals(propertyKey)) {
        return preferences.getLocalizedString(FurnitureLibraryTable.class, "modelColumn");
      } else if (FurnitureLibrary.FURNITURE_WIDTH_PROPERTY.equals(propertyKey)) {
        return preferences.getLocalizedString(FurnitureLibraryTable.class, "widthColumn");
      } else if (FurnitureLibrary.FURNITURE_DEPTH_PROPERTY.equals(propertyKey)) {
        return preferences.getLocalizedString(FurnitureLibraryTable.class, "depthColumn");
      } else if (FurnitureLibrary.FURNITURE_HEIGHT_PROPERTY.equals(propertyKey)) {
        return preferences.getLocalizedString(FurnitureLibraryTable.class, "heightColumn");
      } else if (FurnitureLibrary.FURNITURE_MOVABLE_PROPERTY.equals(propertyKey)) {
        return preferences.getLocalizedString(FurnitureLibraryTable.class, "movableColumn");
      } else if (FurnitureLibrary.FURNITURE_DOOR_OR_WINDOW_PROPERTY.equals(propertyKey)) {
        return preferences.getLocalizedString(FurnitureLibraryTable.class, "doorOrWindowColumn");
      } else if (FurnitureLibrary.FURNITURE_ELEVATION_PROPERTY.equals(propertyKey)) {
        return preferences.getLocalizedString(FurnitureLibraryTable.class, "elevationColumn");
      } else if (FurnitureLibrary.FURNITURE_MODEL_ROTATION_PROPERTY.equals(propertyKey)) {
        return preferences.getLocalizedString(FurnitureLibraryTable.class, "modelRotationColumn");
      } else if (FurnitureLibrary.FURNITURE_RESIZABLE_PROPERTY.equals(propertyKey)) {
        return preferences.getLocalizedString(FurnitureLibraryTable.class, "resizableColumn");
      } else if (FurnitureLibrary.FURNITURE_DEFORMABLE_PROPERTY.equals(propertyKey)) {
        return preferences.getLocalizedString(FurnitureLibraryTable.class, "deformableColumn");
      } else {
        throw new IllegalArgumentException("Unknown key " + propertyKey);
      }
    }
   
    /**
     * Returns the preferred width of a column.
     */
    private int getColumnPreferredWidth(String propertyKey) {
      if (FurnitureLibrary.FURNITURE_ID_PROPERTY.equals(propertyKey)) {
        return 120;
      } else if (FurnitureLibrary.FURNITURE_NAME_PROPERTY.equals(propertyKey)) {
        return 100;
      } else if (FurnitureLibrary.FURNITURE_DESCRIPTION_PROPERTY.equals(propertyKey)) {
        return 150;
      } else if (FurnitureLibrary.FURNITURE_CREATOR_PROPERTY.equals(propertyKey)) {
        return 100;
      } else if (FurnitureLibrary.FURNITURE_CATEGORY_PROPERTY.equals(propertyKey)) {
        return 70;
      } else if (FurnitureLibrary.FURNITURE_PRICE_PROPERTY.equals(propertyKey)) {
        return 70;
      } else if (FurnitureLibrary.FURNITURE_VALUE_ADDED_TAX_PERCENTAGE_PROPERTY.equals(propertyKey)) {
        return 50;
      } else if (FurnitureLibrary.FURNITURE_ICON_PROPERTY.equals(propertyKey)
          || FurnitureLibrary.FURNITURE_PLAN_ICON_PROPERTY.equals(propertyKey)) {
        return 50;
      } else if (FurnitureLibrary.FURNITURE_MODEL_PROPERTY.equals(propertyKey)) {
        return 70;
      } else if (FurnitureLibrary.FURNITURE_WIDTH_PROPERTY.equals(propertyKey)
          || FurnitureLibrary.FURNITURE_DEPTH_PROPERTY.equals(propertyKey)
          || FurnitureLibrary.FURNITURE_HEIGHT_PROPERTY.equals(propertyKey)
          || FurnitureLibrary.FURNITURE_ELEVATION_PROPERTY.equals(propertyKey)) {
        return 45;
      } else if (FurnitureLibrary.FURNITURE_MOVABLE_PROPERTY.equals(propertyKey)
          || FurnitureLibrary.FURNITURE_DOOR_OR_WINDOW_PROPERTY.equals(propertyKey)
          || FurnitureLibrary.FURNITURE_RESIZABLE_PROPERTY.equals(propertyKey)
          || FurnitureLibrary.FURNITURE_DEFORMABLE_PROPERTY.equals(propertyKey)) {
        return 20;
      } else if (FurnitureLibrary.FURNITURE_MODEL_ROTATION_PROPERTY.equals(propertyKey)) {
        return 70;
      } else {
        throw new IllegalArgumentException("Unknown key " + propertyKey);
      }
    }
   
    /**
     * Returns column renderers.
     */
    private TableCellRenderer getColumnRenderer(String propertyKey,
                                                FurnitureLibrary furnitureLibrary,
                                                UserPreferences preferences,
                                                FurnitureLanguageController controller) {
      if (FurnitureLibrary.FURNITURE_ID_PROPERTY.equals(propertyKey)
          || FurnitureLibrary.FURNITURE_NAME_PROPERTY.equals(propertyKey)
          || FurnitureLibrary.FURNITURE_DESCRIPTION_PROPERTY.equals(propertyKey)
          || FurnitureLibrary.FURNITURE_CATEGORY_PROPERTY.equals(propertyKey)
          || FurnitureLibrary.FURNITURE_CREATOR_PROPERTY.equals(propertyKey)) {
        return getStringRenderer(propertyKey, furnitureLibrary, controller);
      } else if (FurnitureLibrary.FURNITURE_ICON_PROPERTY.equals(propertyKey)
          || FurnitureLibrary.FURNITURE_PLAN_ICON_PROPERTY.equals(propertyKey)) {
        return getIconRenderer(propertyKey);
      } else if (FurnitureLibrary.FURNITURE_MODEL_PROPERTY.equals(propertyKey)) {
        return getButtonRenderer(propertyKey, preferences);
      } else if (FurnitureLibrary.FURNITURE_PRICE_PROPERTY.equals(propertyKey)) {
        return getPriceRenderer(preferences);         
      } else if (FurnitureLibrary.FURNITURE_VALUE_ADDED_TAX_PERCENTAGE_PROPERTY.equals(propertyKey)) {
        return getValueAddedTaxPercentageRenderer();         
      } else if (FurnitureLibrary.FURNITURE_WIDTH_PROPERTY.equals(propertyKey)
          || FurnitureLibrary.FURNITURE_DEPTH_PROPERTY.equals(propertyKey)
          || FurnitureLibrary.FURNITURE_HEIGHT_PROPERTY.equals(propertyKey)
          || FurnitureLibrary.FURNITURE_ELEVATION_PROPERTY.equals(propertyKey)) {
        return getSizeRenderer(propertyKey, preferences);
      } else if (FurnitureLibrary.FURNITURE_MOVABLE_PROPERTY.equals(propertyKey)
          || FurnitureLibrary.FURNITURE_DOOR_OR_WINDOW_PROPERTY.equals(propertyKey)
          || FurnitureLibrary.FURNITURE_RESIZABLE_PROPERTY.equals(propertyKey)
          || FurnitureLibrary.FURNITURE_DEFORMABLE_PROPERTY.equals(propertyKey)) {
        return getBooleanRenderer(propertyKey);
      } else if (FurnitureLibrary.FURNITURE_MODEL_ROTATION_PROPERTY.equals(propertyKey)) {
        return getButtonRenderer(propertyKey, preferences);
      } else {
        throw new IllegalArgumentException("Unknown key " + propertyKey);
      }
    }

    /**
     * Returns a renderer that displays a string property of a piece of furniture.
     */
    private TableCellRenderer getStringRenderer(final String propertyKey,
                                                final FurnitureLibrary furnitureLibrary,
                                                final FurnitureLanguageController controller) {
      if (FurnitureLibrary.FURNITURE_ID_PROPERTY.equals(propertyKey)) {
        return new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value,
                boolean isSelected, boolean hasFocus, int row, int column) {
              return super.getTableCellRendererComponent(
                  table, ((CatalogPieceOfFurniture)value).getId(), isSelected, hasFocus, row, column);
            }
          };
      } else if (FurnitureLibrary.FURNITURE_NAME_PROPERTY.equals(propertyKey)) {
        return new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value,
                boolean isSelected, boolean hasFocus, int row, int column) {
              CatalogPieceOfFurniture piece = (CatalogPieceOfFurniture)value;
              String pieceName = (String)furnitureLibrary.getPieceOfFurnitureLocalizedData(
                    piece, controller.getFurnitureLangauge(), propertyKey, piece.getName());
              return super.getTableCellRendererComponent(
                  table, pieceName, isSelected, hasFocus, row, column);
            }
          };
      } else if (FurnitureLibrary.FURNITURE_DESCRIPTION_PROPERTY.equals(propertyKey)) {
        return new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value,
                boolean isSelected, boolean hasFocus, int row, int column) {
              CatalogPieceOfFurniture piece = (CatalogPieceOfFurniture)value;
              String pieceDescription = (String)furnitureLibrary.getPieceOfFurnitureLocalizedData(
                    piece, controller.getFurnitureLangauge(), propertyKey, piece.getDescription());
              return super.getTableCellRendererComponent(
                  table, pieceDescription, isSelected, hasFocus, row, column);
            }
          };
      } else if (FurnitureLibrary.FURNITURE_CATEGORY_PROPERTY.equals(propertyKey)) {
        return new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value,
                boolean isSelected, boolean hasFocus, int row, int column) {
              CatalogPieceOfFurniture piece = (CatalogPieceOfFurniture)value;
              String pieceCategory = (String)furnitureLibrary.getPieceOfFurnitureLocalizedData(
                    piece, controller.getFurnitureLangauge(), propertyKey, piece.getCategory().getName());
              return super.getTableCellRendererComponent(
                  table, pieceCategory, isSelected, hasFocus, row, column);
            }
          };
      } else if (FurnitureLibrary.FURNITURE_CREATOR_PROPERTY.equals(propertyKey)) {
        return new DefaultTableCellRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table, Object value,
                boolean isSelected, boolean hasFocus, int row, int column) {
              return super.getTableCellRendererComponent(
                  table, ((CatalogPieceOfFurniture)value).getCreator(), isSelected, hasFocus, row, column);
            }
          };
      } else {
          throw new IllegalArgumentException(propertyKey + " column not a string column");
      }
    }

    /**
     * Returns a renderer that displays a button.
     */
    private TableCellRenderer getButtonRenderer(String propertyKey,
                                                final UserPreferences preferences) {
      if (FurnitureLibrary.FURNITURE_MODEL_PROPERTY.equals(propertyKey)
          || FurnitureLibrary.FURNITURE_MODEL_ROTATION_PROPERTY.equals(propertyKey)) {
        return new TableCellRenderer() {
          private JButton component = new JButton();
          public Component getTableCellRendererComponent(JTable table, Object value,
              boolean isSelected, boolean hasFocus, int row, int column) {
            component.setText(preferences.getLocalizedString(FurnitureLibraryTable.class, "modifyButton"));
            return component;
          }
        };
      } else {
        throw new IllegalArgumentException(propertyKey + " column not a button column");
      }
    }

    /**
     * Returns a renderer that displays the icons of a piece of furniture.
     */
    private TableCellRenderer getIconRenderer(final String propertyKey) {
      return new DefaultTableCellRenderer() {
        @Override
        public Component getTableCellRendererComponent(JTable table,
             Object value, boolean isSelected, boolean hasFocus,
             int row, int column) {
          CatalogPieceOfFurniture piece = (CatalogPieceOfFurniture)value;
          JLabel label = (JLabel)super.getTableCellRendererComponent(
            table, "", isSelected, hasFocus, row, column);
          Content iconContent;
          if (FurnitureLibrary.FURNITURE_ICON_PROPERTY.equals(propertyKey)) {
            iconContent = piece.getIcon();
          } else {
            iconContent = piece.getPlanIcon();
          }
          if (iconContent != null) {
            label.setIcon(IconManager.getInstance().getIcon(
                iconContent, table.getRowHeight(), table));
            label.setHorizontalAlignment(JLabel.CENTER);
          } else {
            label.setIcon(null);
          }
          return label;
        }
      };
    }

    /**
     * Returns a renderer that converts the displayed <code>property</code> of a piece of furniture
     * to inch in case preferences unit us equal to INCH.
     */
    private TableCellRenderer getSizeRenderer(String propertyKey,
                                              final UserPreferences preferences) {
      // Renderer super class used to display sizes
      class SizeRenderer extends DefaultTableCellRenderer {
        public Component getTableCellRendererComponent(JTable table,
             Object value, boolean isSelected, boolean hasFocus,
             int row, int column) {
          value = preferences.getLengthUnit().getFormat().format((Float)value);
          setHorizontalAlignment(JLabel.RIGHT);
          return super.getTableCellRendererComponent(
              table, value, isSelected, hasFocus, row, column);
        }
      };
     
      if (FurnitureLibrary.FURNITURE_WIDTH_PROPERTY.equals(propertyKey)) {
        return new SizeRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table,
                Object value, boolean isSelected, boolean hasFocus, int row, int column) {
              return super.getTableCellRendererComponent(table,
                  ((CatalogPieceOfFurniture)value).getWidth(), isSelected, hasFocus, row, column);
            }
          };
      } else if (FurnitureLibrary.FURNITURE_DEPTH_PROPERTY.equals(propertyKey)) {
        return new SizeRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table,
                Object value, boolean isSelected, boolean hasFocus, int row, int column) {
              return super.getTableCellRendererComponent(table,
                  ((CatalogPieceOfFurniture)value).getDepth(), isSelected, hasFocus, row, column);
            }
          };
      } else if (FurnitureLibrary.FURNITURE_HEIGHT_PROPERTY.equals(propertyKey)) {
        return new SizeRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table,
                Object value, boolean isSelected, boolean hasFocus, int row, int column) {
              return super.getTableCellRendererComponent(table,
                  ((CatalogPieceOfFurniture)value).getHeight(), isSelected, hasFocus, row, column);
            }
          };
      } else if (FurnitureLibrary.FURNITURE_ELEVATION_PROPERTY.equals(propertyKey)) {
        return new SizeRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table,
                Object value, boolean isSelected, boolean hasFocus, int row, int column) {
              return super.getTableCellRendererComponent(table,
                  ((CatalogPieceOfFurniture)value).getElevation(), isSelected, hasFocus, row, column);
            }
          };
      } else {
        throw new IllegalArgumentException(propertyKey + " column not a size column");
      }
    }

    /**
     * Returns a renderer that displays the price of a piece of furniture.
     */
    private TableCellRenderer getPriceRenderer(final UserPreferences preferences) {
      return new DefaultTableCellRenderer() {
          public Component getTableCellRendererComponent(JTable table,
               Object value, boolean isSelected, boolean hasFocus,
               int row, int column) {
            value = ((CatalogPieceOfFurniture)value).getPrice();
            if (value != null) {
              String currency = preferences.getCurrency();
              NumberFormat currencyFormat;
              if (currency != null) {
                currencyFormat = DecimalFormat.getCurrencyInstance();
                currencyFormat.setCurrency(Currency.getInstance(currency));
              } else {
                currencyFormat = new DecimalFormat("##0.00");
              }
              value = currencyFormat.format(value);
            } else {
              value = "";
            }
            setHorizontalAlignment(JLabel.RIGHT);
            return super.getTableCellRendererComponent(
                table, value, isSelected, hasFocus, row, column);
          }
        };
    }

    /**
     * Returns a renderer that displays the value added tax percentage property of a piece of furniture.
     */
    private TableCellRenderer getValueAddedTaxPercentageRenderer() {
      return new DefaultTableCellRenderer() {
          @Override
          public Component getTableCellRendererComponent(JTable table,
               Object value, boolean isSelected, boolean hasFocus,
               int row, int column) {
            BigDecimal valueAddedTaxPercentage = ((CatalogPieceOfFurniture)value).getValueAddedTaxPercentage();
            if (valueAddedTaxPercentage != null) {
              NumberFormat percentInstance = DecimalFormat.getPercentInstance();
              percentInstance.setMinimumFractionDigits(valueAddedTaxPercentage.scale() - 2);
              value = percentInstance.format(valueAddedTaxPercentage);
            } else {
              value = "";
            }
            setHorizontalAlignment(JLabel.RIGHT);
            return super.getTableCellRendererComponent(
                table, value, isSelected, hasFocus, row, column);
          }
        };
    }

    /**
     * Returns a renderer that displays a property of a piece of furniture
     * with <code>JTable</code> default boolean renderer.
     */
    private TableCellRenderer getBooleanRenderer(String propertyKey) {
      // Renderer super class used to display booleans
      class BooleanRenderer implements TableCellRenderer {
        private TableCellRenderer booleanRenderer;

        public Component getTableCellRendererComponent(JTable table,
             Object value, boolean isSelected, boolean hasFocus, int row, int column) {
          if (this.booleanRenderer == null) {
            this.booleanRenderer = table.getDefaultRenderer(Boolean.class);
          }
          return this.booleanRenderer.getTableCellRendererComponent(
              table, value, isSelected, hasFocus, row, column);
        }
      };
     
      if (FurnitureLibrary.FURNITURE_MOVABLE_PROPERTY.equals(propertyKey)) {
        return new BooleanRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table,
                Object value, boolean isSelected, boolean hasFocus, int row, int column) {
              return super.getTableCellRendererComponent(table,
                  ((CatalogPieceOfFurniture)value).isMovable(), isSelected, hasFocus, row, column);
            }
          };
      } else if (FurnitureLibrary.FURNITURE_DOOR_OR_WINDOW_PROPERTY.equals(propertyKey)) {
        return new BooleanRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table,
                Object value, boolean isSelected, boolean hasFocus, int row, int column) {
              return super.getTableCellRendererComponent(table,
                  ((CatalogPieceOfFurniture)value).isDoorOrWindow(), isSelected, hasFocus, row, column);
            }
          };
      } else if (FurnitureLibrary.FURNITURE_RESIZABLE_PROPERTY.equals(propertyKey)) {
        return new BooleanRenderer() {
            @Override
            public Component getTableCellRendererComponent(JTable table,
                Object value, boolean isSelected, boolean hasFocus, int row, int column) {
              return super.getTableCellRendererComponent(table,
                  ((CatalogPieceOfFurniture)value).isResizable(), isSelected, hasFocus, row, column);
            }
          };
      } else if (FurnitureLibrary.FURNITURE_DEFORMABLE_PROPERTY.equals(propertyKey)) {
        return new BooleanRenderer() {
          @Override
          public Component getTableCellRendererComponent(JTable table,
              Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            return super.getTableCellRendererComponent(table,
                ((CatalogPieceOfFurniture)value).isDeformable(), isSelected, hasFocus, row, column);
          }
        };
    } else {
        throw new IllegalArgumentException(propertyKey + " column not a boolean column");
      }
    }

    /**
     * Returns column header renderer that displays an ascending or a descending icon
     * when column is sorted, beside column name.
     */
    private TableCellRenderer getHeaderRenderer() {
      // Return a table renderer that displays the icon matching current sort
      return new TableCellRenderer() {
          private TableCellRenderer headerRenderer;       
          private ImageIcon ascendingSortIcon = new ImageIcon(getClass().getResource("resources/ascending.png"));
          private ImageIcon descendingSortIcon = new ImageIcon(getClass().getResource("resources/descending.png"));
         
          public Component getTableCellRendererComponent(JTable table,
               Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            if (this.headerRenderer == null) {
              this.headerRenderer = table.getTableHeader().getDefaultRenderer();
            }
            // Get default label
            JLabel label = (JLabel)this.headerRenderer.getTableCellRendererComponent(
                table, value, isSelected, hasFocus, row, column);
            // Add to column an icon matching sort
            FurnitureLibraryTableModel model = (FurnitureLibraryTableModel)table.getModel();
            if (getColumn(column).getIdentifier().equals(model.getSortProperty())) {
              label.setHorizontalTextPosition(JLabel.LEADING);
              if (model.isDescendingOrder()) {
                label.setIcon(descendingSortIcon);
              } else {
                label.setIcon(ascendingSortIcon);
              }
            } else {
              label.setIcon(null);
            }
            return label;
          }
        };
    }
  }

 
  /**
   * Table transfer handler.
   */
  private class TableTransferHandler extends TransferHandler {
    private final FurnitureLibraryController furnitureController;
   
    /**
     * Creates a handler able to receive furniture files.
     */
    public TableTransferHandler(FurnitureLibraryController furnitureController) {
      this.furnitureController = furnitureController;
    }

    @Override
    public int getSourceActions(JComponent source) {
      return NONE;
    }

    /**
     * Returns <code>true</code> if flavors contains
     * <code>DataFlavor.javaFileListFlavor</code> flavor.
     */
    @Override
    public boolean canImport(JComponent destination, DataFlavor [] flavors) {
      return this.furnitureController != null
          && Arrays.asList(flavors).contains(DataFlavor.javaFileListFlavor);
    }

    /**
     * Add to library the furniture contained in <code>transferable</code>.
     */
    @SuppressWarnings("unchecked")
    @Override
    public boolean importData(JComponent destination, Transferable transferable) {
      if (canImport(destination, transferable.getTransferDataFlavors())) {
        try {
          List<File> files = (List<File>)transferable.getTransferData(DataFlavor.javaFileListFlavor);
          final List<String> importableModels = new ArrayList<String>();       
          for (File file : files) {
            if (!file.isDirectory()) {
              String absolutePath = file.getAbsolutePath();
              importableModels.add(absolutePath);
            }       
          }
          EventQueue.invokeLater(new Runnable() {
              public void run() {
                furnitureController.importFurniture(importableModels.toArray(new String [importableModels.size()]));
              }
            });
          return !importableModels.isEmpty();
        } catch (UnsupportedFlavorException ex) {
          throw new RuntimeException("Can't import", ex);
        } catch (IOException ex) {
          throw new RuntimeException("Can't access to data", ex);
        }
      } else {
        return false;
      }
    }
  }
}

TOP

Related Classes of com.eteks.furniturelibraryeditor.swing.FurnitureLibraryTable

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.