DataRelationTable.java
上传用户:zhengdagz
上传日期:2014-03-06
资源大小:1956k
文件大小:16k
源码类别:

xml/soap/webservice

开发平台:

Java

  1. /*
  2.  * $Id: DataRelationTable.java,v 1.9 2005/10/15 11:43:19 pdoubleya Exp $
  3.  *
  4.  * Copyright 2005 Sun Microsystems, Inc., 4150 Network Circle,
  5.  * Santa Clara, California 95054, U.S.A. All rights reserved.
  6.  *
  7.  * This library is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  * 
  12.  * This library is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  * 
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with this library; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  20.  */
  21. package org.jdesktop.dataset;
  22. import java.beans.PropertyChangeEvent;
  23. import java.beans.PropertyChangeListener;
  24. import java.util.ArrayList;
  25. import java.util.Collections;
  26. import java.util.HashMap;
  27. import java.util.List;
  28. import java.util.Map;
  29. import java.util.logging.Logger;
  30. import org.jdesktop.dataset.event.DataTableListener;
  31. import org.jdesktop.dataset.event.RowChangeEvent;
  32. import org.jdesktop.dataset.event.TableChangeEvent;
  33. /**
  34.  *
  35.  * @author rbair
  36.  */
  37. public class DataRelationTable extends DataTable {
  38.     /**
  39.      * The Logger
  40.      */
  41.     private static final Logger LOG = Logger.getLogger(DataRelationTable.class.getName());
  42.     /**
  43.      * The relation that is used to populate this DataRelationTable
  44.      */
  45.     private DataRelation relation;
  46.     /**
  47.      * The selector in the parent table that is used to indicate what parent
  48.      * rows to retrieve child rows for
  49.      */
  50.     private DataSelector parentSelector;
  51.     /**
  52.      * The parentTable that is used to indicate what child rows to retrieve. If
  53.      * parentSelector is defined, then parentTable is ignored. Otherwise, all
  54.      * of the contents of the parentTable will be used to retrieve rows in the
  55.      * childTable.
  56.      * <p>
  57.      * This is of particular use when the parentTable is another DataRelationTable,
  58.      * and therefore a subset of the original DataTable.
  59.      */
  60.     private DataTable parentTable;
  61.     /**
  62.      * A selection listener that is affixed to the parentSelector. Whenever the
  63.      * selection changes in the parentSelector, this is notified and refreshes
  64.      * this table
  65.      */
  66.     private SelectionListener listener = new SelectionListener();
  67.     /**
  68.      * Listens to changes on the parentTable, if there IS a parentTable
  69.      */
  70.     private ParentTableListener pListener = new ParentTableListener();
  71.     /**
  72.      * Listens to changes on the childTable, if there IS a childTable
  73.      */
  74.     private ChildTableListener cListener = new ChildTableListener();
  75.     /** 
  76.      * Creates a new instance of DataRelationTable 
  77.      */
  78.     public DataRelationTable(DataSet ds) {
  79.         super(ds);
  80.     }
  81.     
  82.     public DataRelationTable(DataSet ds, String name) {
  83.         super(ds, name);
  84.     }
  85.     
  86.     /**
  87.      * Set the relation that this DataRelationTable uses
  88.      * @param relation the DataRelation to use
  89.      */
  90.     public void setRelation(DataRelation relation) {
  91.         if (this.relation != relation) {
  92.             if (this.relation != null && this.relation.getChildColumn() != null) {
  93.                 this.relation.getChildColumn().getTable().removeDataTableListener(cListener);
  94.             }
  95.             //TODO affix a DataSet listener so that if this relation is removed
  96.             //from the DataSet, I can remove my reference to it as well.
  97.             this.relation = relation;
  98.             addChildListener();
  99.             if (relation != null) {
  100.                 relation.addPropertyChangeListener("childColumn", new PropertyChangeListener() {
  101.                     public void propertyChange(PropertyChangeEvent evt) {
  102.                         addChildListener();
  103.                     }
  104.                 });
  105.             }
  106.         }
  107.     }
  108.     
  109.     private void addChildListener() {
  110.         if (this.relation != null && this.relation.getChildColumn() != null) {
  111.             this.relation.getChildColumn().getTable().removeDataTableListener(cListener);
  112.         }
  113.         if (this.relation != null && this.relation.getChildColumn() != null) {
  114.             this.relation.getChildColumn().getTable().addDataTableListener(cListener);
  115.         }
  116.     }
  117.     
  118.     /**
  119.      * @return the relation used to populate this DataRelationTable
  120.      */
  121.     public DataRelation getRelation() {
  122.         return relation;
  123.     }
  124.     
  125.     /**
  126.      * Sets the selector for this DataRelationTable. This selector is used to
  127.      * retrieve the currently selected rows from the parent table so that the
  128.      * proper child rows can be retrieved from the child table using the
  129.      * relation.
  130.      *
  131.      * @param selector The selector on the parent table. The selector must belong
  132.      * to the same table as the relation's parentColumn
  133.      */
  134.     public void setParentSelector(DataSelector selector) {
  135.         if (this.parentSelector != null) {
  136.             this.parentSelector.removePropertyChangeListener("rowIndices", listener);
  137.         }
  138.         this.parentSelector = selector;
  139.         if (this.parentSelector != null) {
  140.             this.parentSelector.addPropertyChangeListener("rowIndices", listener);
  141.         }
  142.     }
  143.     
  144.     /**
  145.      * @return the DataSelector used to retrieve rows from the DataRelation
  146.      */
  147.     public DataSelector getParentSelector() {
  148.         return parentSelector;
  149.     }
  150.     
  151.     public void setParentTable(DataTable parent) {
  152.         if (this.parentTable != null) {
  153.             this.parentTable.removeDataTableListener(pListener);
  154.         }
  155.         this.parentTable = parent;
  156.         if (this.parentTable != null) {
  157.             this.parentTable.addDataTableListener(pListener);
  158.         }
  159.     }
  160.     
  161.     public DataTable getParentTable() {
  162.         return parentTable;
  163.     }
  164.     
  165.     /**
  166.      * This method makes no sense for a DataRelationTable. A cleaner refactoring
  167.      * might remove the need to override this method. Nothing bad happens if
  168.      * this method is called, it just doesn't make sense. A Warning is logged
  169.      * if this method is called.
  170.      */
  171.     public void setDataProvider(DataProvider dataProvider) {
  172.         LOG.warning("An attempt was made to set the DataProvider for a " +
  173.                 "DataRelationTable. This is not honored because a " +
  174.                 "DataRelationTable, by definition, gets its records " +
  175.                 "by querying a DataSelector from the Parent table, and " +
  176.                 "the DataRelation leading to the Child table.");
  177.     }
  178.     /**
  179.      * This method makes no sense for a DataRelationTable. A cleaner refactoring
  180.      * might remove the need to override this method. Nothing bad happens if
  181.      * this method is called, it just doesn't make sense. A Warning is logged
  182.      * if this method is called
  183.      */
  184.     public void save() {
  185.         LOG.warning("An attempt was made to save a DataRelationTable. " +
  186.                 "This is not honored because a DataRelationTable, " +
  187.                 "by definition, gets its records by querying a DataSelector " +
  188.                 "from the Parent table, and the DataRelation leading to the " +
  189.                 "Child table. Therefore, to save, the child table should be " +
  190.                 "asked to save, not the DataRelationTable.");
  191.     }
  192.     /**
  193.      * Appends a row to the child table, retrieved by
  194.      * <code>relation.getChildColumn().getTable()</code>. If the DataTable
  195.      * doesn't exist, null is returned
  196.      *
  197.      * @return The newly added DataRow, or null if no DataRow was added.
  198.      */
  199.     public DataRow appendRow() {
  200.         //append a row to the child table, and view it here.
  201.         //when the row is added to the child table, the child table
  202.         //will fire an event notification indicating that a new row has
  203.         //been added. When this happens, this child as well as all other
  204.         //relation tables will be notified that they need to refresh themselves.
  205.         if (relation != null && relation.getChildColumn() != null) {
  206.             DataTable t = relation.getChildColumn().getTable();
  207.             DataRow row = t.appendRow();
  208.             if (parentSelector.getRowIndices().size() == 1) {
  209.                 row.setValue(relation.getChildColumn().getName(), 
  210.                              relation.getParentColumn().getTable().getValue(
  211.                                  parentSelector.getRowIndices().get(0), 
  212.                                  relation.getParentColumn().getName()
  213.                              ));
  214.             }
  215.             rows.add(row);
  216.             return row;
  217.         }
  218.         return null;
  219.     }
  220.     /**
  221.      * Removes all of the rows from this DataRelationTable, and reloads it with
  222.      * the proper rows from the DataRelation using the parentSelector
  223.      * DataSelector. When rows are removed from a DataRelationTable, they still
  224.      * exist in the child DataTable, hence it is always safe to call this method
  225.      * without losing any data.<br>
  226.      *
  227.      * This method attempts to reset all of its selectors to the same rows,
  228.      * where possible. It does this by remembering all of the values for the
  229.      * rows key fields, and looking for them again after the refresh. If the
  230.      * row cannot be found, it is no longer selected<br>
  231.      *
  232.      * TODO This code for remembering the selected rows and trying to locate
  233.      * them again after refresh is horrible and needs to be rewritten.
  234.      */
  235.     public void refresh() {
  236.         //for each DataSelector, save its selection state.
  237.         Map<DataSelector,Object[][]> selectorState = new HashMap<DataSelector,Object[][]>();
  238.         List<DataColumn> keyColumns = new ArrayList<DataColumn>();
  239.         for (DataColumn c : columns.values()) {
  240.             if (c.isKeyColumn()) {
  241.                 keyColumns.add(c);
  242.             }
  243.         }
  244.         
  245.         for (DataSelector sel : selectors.values()) {
  246.             List<Integer> indices = sel.getRowIndices();
  247.             Object[][] values = new Object[indices.size()][keyColumns.size()];
  248.             for (int i=0; i<indices.size(); i++) {
  249.                 for (int j=0; j<keyColumns.size(); j++) {
  250.                     DataRow row = rows.get(indices.get(i));
  251.                     values[i][j] = getValue(row, keyColumns.get(j));
  252.                 }
  253.             }
  254.             sel.setRowIndices(new int[0]);
  255.             selectorState.put(sel, values);
  256.         }
  257.         
  258.         //clear out the DataRelationTable, and reload it
  259.         clear();
  260.         if (relation != null && relation.getChildColumn() != null) {
  261.             fireDataTableChanged(TableChangeEvent.newLoadStartEvent(this));
  262.             if (parentSelector != null) {
  263.                 //use the selector and the relation to get the rows
  264. //                assert relation.getParentColumn() != null && relation.getParentColumn().getTable() == selector.getTable();
  265.                 super.rows.addAll(relation.getRows(parentSelector.getRowIndices()));
  266.             } else if (parentTable != null) {
  267.                 //use all of the rows in the parent table to get the children
  268.                 List<DataRow> list = parentTable.getRows();
  269.                 super.rows.addAll(relation.getRows(list.toArray(new DataRow[list.size()])));
  270.             } else {
  271.                 //get all of the rows from the relations child table
  272.                 super.rows.addAll(relation.getChildColumn().getTable().getRows());
  273.             }
  274.             fireDataTableChanged(TableChangeEvent.newLoadCompleteEvent(this));
  275.         }
  276.         
  277.         //try to restore the selection state, where possible
  278.         for (DataSelector sel : selectors.values()) {
  279.             Object[][] values = selectorState.get(sel);
  280.             //for each selector, find its values. Look for a row who's columns
  281.             //values match the specified set, and match it.
  282.             //NOTE: This algorithm is a brute force algorithm, and not very
  283.             //efficient where multiple rows are selected in a large DataTable.
  284.             List<Integer> indices = new ArrayList<Integer>(values.length);
  285.             for (int i=0; i<values.length; i++) {
  286.                 boolean found = true;
  287.                 for (int rowIndex=0; rowIndex<rows.size(); rowIndex++) {
  288.                     found = true; //reset
  289.                     for (int j=0; j<keyColumns.size(); j++) {
  290.                         DataRow row = rows.get(rowIndex);
  291.                         if (found && values[i][j].equals(row.getValue(keyColumns.get(j)))) {
  292.                             //do nothing
  293.                         } else {
  294.                             found = false;
  295.                         }
  296.                     }
  297.                     if (found) {
  298.                         indices.add(rowIndex);
  299.                     }
  300.                 }
  301.             }
  302.             
  303.             //ok, set the selector state
  304.             //reset the selectors
  305.             int[] rows = new int[indices.size()];
  306.             for (int i=0; i<rows.length; i++) {
  307.                 rows[i] = indices.get(i);
  308.             }
  309.             if (super.rows.size() > 0) {
  310.                 if (rows.length == 0) {
  311.                     //reset all of the selectors to 0
  312.                     sel.setRowIndices(new int[]{0});
  313.                 } else {
  314.                     sel.setRowIndices(rows);
  315.                 }
  316.             }
  317.         }
  318.     }
  319.     
  320.     /**
  321.      * Overridden so that it will defer to the child Table first. A
  322.      * DataRelationTable contains all of the columns in the child Table, but
  323.      * may also contain its own set of calculated columns as well. This method
  324.      * must therefore check the child table for a given column before checking
  325.      * its own set of columns.
  326.      *
  327.      * @param colName The String name for the column to retrieve.
  328.      * @return The DataColumn identified by the given name.
  329.      */
  330.     public DataColumn getColumn(String colName) {
  331.         DataColumn col = null;
  332.         if (relation != null && relation.getChildColumn() != null && relation.getChildColumn().getTable() != null) {
  333.             col = relation.getChildColumn().getTable().getColumn(colName);
  334.         }
  335.         
  336.         if (col == null) {
  337.             return super.getColumn(colName);
  338.         } else {
  339.             return col;
  340.         }
  341.     }
  342.     /**
  343.      * @return the set of columns that comprise this DataRelationTable. This is
  344.      * the union of the child tables columns, and any native columns to this
  345.      * DataRelationTable
  346.      */
  347.     public List<DataColumn> getColumns() {
  348.         List<DataColumn> cols = new ArrayList<DataColumn>();
  349.         if (relation != null && relation.getChildColumn() != null && relation.getChildColumn().getTable() != null) {
  350.             cols.addAll(relation.getChildColumn().getTable().getColumns());
  351.         }
  352.         
  353.         cols.addAll(super.getColumns());
  354.         return Collections.unmodifiableList(cols);
  355.     }
  356.     
  357.     /**
  358.      * A listener to the parentSelector. When selection change events occur in
  359.      * the parentSelector, this DataRelationTable is automatically refreshed.
  360.      */
  361.     private final class SelectionListener implements PropertyChangeListener {
  362.         public void propertyChange(PropertyChangeEvent evt) {
  363.             refresh();
  364.         }
  365.     }
  366.     
  367.     private final class ParentTableListener implements DataTableListener {
  368.         public void rowChanged(RowChangeEvent evt) {
  369.         }
  370.         public void tableChanged(TableChangeEvent evt) {
  371.             refresh();
  372.         }
  373.         
  374.     }
  375.     private final class ChildTableListener implements DataTableListener {
  376.         public void rowChanged(RowChangeEvent evt) {
  377.         }
  378.         public void tableChanged(TableChangeEvent evt) {
  379.             refresh();
  380.         }
  381.         
  382.     }
  383. }