1 package prefuse.data; 2 3 import java.util.ArrayList ; 4 import java.util.Iterator ; 5 6 import javax.swing.event.TableModelEvent ; 7 8 import prefuse.data.column.Column; 9 import prefuse.data.column.ColumnMetadata; 10 import prefuse.data.event.EventConstants; 11 import prefuse.data.event.ExpressionListener; 12 import prefuse.data.event.ProjectionListener; 13 import prefuse.data.event.TableListener; 14 import prefuse.data.expression.BooleanLiteral; 15 import prefuse.data.expression.Expression; 16 import prefuse.data.expression.Predicate; 17 import prefuse.data.tuple.TableTuple; 18 import prefuse.data.util.AcceptAllColumnProjection; 19 import prefuse.data.util.CascadedRowManager; 20 import prefuse.data.util.ColumnProjection; 21 import prefuse.util.collections.CompositeIterator; 22 import prefuse.util.collections.IntIterator; 23 24 25 45 public class CascadedTable extends Table { 46 47 48 protected Table m_parent; 49 50 protected ArrayList m_pnames; 51 52 54 protected ColumnProjection m_colFilter; 55 57 protected Predicate m_rowFilter; 58 59 60 protected Listener m_listener; 61 62 65 70 public CascadedTable(Table parent) { 71 this(parent, null, null); 72 } 73 74 81 public CascadedTable(Table parent, Predicate rowFilter) { 82 this(parent, rowFilter, null); 83 } 84 85 92 public CascadedTable(Table parent, ColumnProjection colFilter) { 93 this(parent, null, colFilter); 94 } 95 96 104 public CascadedTable(Table parent, Predicate rowFilter, 105 ColumnProjection colFilter) 106 { 107 this(parent, rowFilter, colFilter, TableTuple.class); 108 } 109 110 119 protected CascadedTable(Table parent, Predicate rowFilter, 120 ColumnProjection colFilter, Class tupleType) 121 { 122 super(0, 0, tupleType); 123 m_parent = parent; 124 m_pnames = new ArrayList (); 125 m_rows = new CascadedRowManager(this); 126 m_listener = new Listener(); 127 128 setColumnProjection(colFilter); 129 setRowFilter(rowFilter); 130 m_parent.addTableListener(m_listener); 131 } 132 133 135 138 protected CascadedTable() { 139 this(TableTuple.class); 140 } 141 142 146 protected CascadedTable(Class tupleType) { 147 super(0, 0, tupleType); 148 m_pnames = new ArrayList (); 149 } 150 151 154 157 protected void filterColumns() { 158 if ( m_parent == null ) return; 159 160 for ( int i=0; i<m_pnames.size(); ++i ) { 161 String name = (String )m_pnames.get(i); 162 Column col = m_parent.getColumn(i); 163 boolean contained = m_names.contains(name); 164 if ( !m_colFilter.include(col, name) || contained ) { 165 m_pnames.remove(i--); 166 if ( !contained ) { 167 ((ColumnEntry)m_entries.get(name)).dispose(); 168 m_entries.remove(name); 169 } 170 171 fireTableEvent(m_rows.getMinimumRow(), 173 m_rows.getMaximumRow(), 174 i, EventConstants.DELETE); 175 } 176 } 177 178 m_pnames.clear(); 179 180 Iterator pcols = m_parent.getColumnNames(); 181 for ( int i=0, j=m_columns.size(); pcols.hasNext(); ++i ) { 182 String name = (String )pcols.next(); 183 Column col = m_parent.getColumn(i); 184 185 if ( m_colFilter.include(col, name) && !m_names.contains(name) ) { 186 m_pnames.add(name); 187 ColumnEntry entry = (ColumnEntry)m_entries.get(name); 188 if ( entry == null ) { 189 entry = new ColumnEntry(j++, col, 190 new ColumnMetadata(this, name)); 191 m_entries.put(name, entry); 192 fireTableEvent(m_rows.getMinimumRow(), 194 m_rows.getMaximumRow(), 195 i, EventConstants.INSERT); 196 } else { 197 entry.colnum = j++; 198 } 199 m_lastCol = m_columns.size()-1; 200 } 201 } 202 203 } 204 205 215 public void filterRows() { 216 if ( m_parent == null ) return; 217 218 CascadedRowManager rowman = (CascadedRowManager)m_rows; 219 IntIterator crows = m_rows.rows(); 220 while ( crows.hasNext() ) { 221 int crow = crows.nextInt(); 222 if ( !m_rowFilter.getBoolean( 223 m_parent.getTuple(rowman.getParentRow(crow))) ) 224 { 225 removeCascadedRow(crow); 226 } 227 } 228 229 Iterator ptuples = m_parent.tuples(m_rowFilter); 230 while ( ptuples.hasNext() ) { 231 Tuple pt = (Tuple)ptuples.next(); 232 int prow = pt.getRow(); 233 if ( rowman.getChildRow(prow) == -1 ) 234 addCascadedRow(prow); 235 } 236 } 237 238 243 public ColumnProjection getColumnProjection() { 244 return m_colFilter; 245 } 246 247 253 public void setColumnProjection(ColumnProjection colFilter) { 254 if ( m_colFilter != null ) { 255 m_colFilter.removeProjectionListener(m_listener); 256 } 257 m_colFilter = colFilter==null ? new AcceptAllColumnProjection() : colFilter; 258 m_colFilter.addProjectionListener(m_listener); 259 filterColumns(); 260 } 261 262 267 public Predicate getRowFilter() { 268 return m_rowFilter; 269 } 270 271 277 public void setRowFilter(Predicate rowFilter) { 278 if ( m_rowFilter != null ) { 279 m_rowFilter.removeExpressionListener(m_listener); 280 } 281 m_rowFilter = rowFilter==null ? BooleanLiteral.TRUE : rowFilter; 282 if ( m_rowFilter != BooleanLiteral.TRUE ) 283 m_rowFilter.addExpressionListener(m_listener); 284 filterRows(); 285 } 286 287 290 293 public int getColumnCount() { 294 return m_columns.size() + m_pnames.size(); 295 } 296 297 302 public int getLocalColumnCount() { 303 return m_columns.size(); 304 } 305 306 309 313 public Table getParentTable() { 314 return m_parent; 315 } 316 317 323 public int getParentRow(int row) { 324 return ((CascadedRowManager)m_rows).getParentRow(row); 325 } 326 327 334 public int getChildRow(int prow) { 335 return ((CascadedRowManager)m_rows).getChildRow(prow); 336 } 337 338 341 344 public int addRow() { 345 if ( m_parent != null ) { 346 throw new IllegalStateException ( 347 "Add row not supported for CascadedTable."); 348 } else { 349 return super.addRow(); 350 } 351 } 352 353 356 public void addRows(int nrows) { 357 if ( m_parent != null ) { 358 throw new IllegalStateException ( 359 "Add rows not supported for CascadedTable."); 360 } else { 361 super.addRows(nrows); 362 } 363 } 364 365 368 public boolean removeRow(int row) { 369 if ( m_parent != null ) { 370 throw new IllegalStateException ( 371 "Remove row not supported for CascadedTable."); 372 } else { 373 return super.removeRow(row); 374 } 375 } 376 377 383 protected int addCascadedRow(int prow) { 384 int r = m_rows.addRow(); 385 ((CascadedRowManager)m_rows).put(r, prow); 386 updateRowCount(); 387 388 fireTableEvent(r, r, TableModelEvent.ALL_COLUMNS, 389 TableModelEvent.INSERT); 390 return r; 391 } 392 393 398 protected boolean removeCascadedRow(int row) { 399 boolean rv = super.removeRow(row); 400 if ( rv ) 401 ((CascadedRowManager)m_rows).remove(row); 402 return rv; 403 } 404 405 408 411 public String getColumnName(int col) { 412 int local = m_names.size(); 413 if ( col >= local ) { 414 return (String )m_pnames.get(col-local); 415 } else { 416 return (String )m_names.get(col); 417 } 418 } 419 420 423 public int getColumnNumber(Column col) { 424 int idx = m_columns.indexOf(col); 425 if ( idx == -1 && m_parent != null ) { 426 idx = m_parent.getColumnNumber(col); 427 if ( idx == -1 ) return idx; 428 String name = m_parent.getColumnName(idx); 429 idx = m_pnames.indexOf(name); 430 if ( idx != -1 ) idx += m_columns.size(); 431 } 432 return idx; 433 } 434 435 438 public Column getColumn(int col) { 439 m_lastCol = col; 440 int local = m_names.size(); 441 if ( col >= local && m_parent != null ) { 442 return m_parent.getColumn((String )m_pnames.get(col-local)); 443 } else { 444 return (Column)m_columns.get(col); 445 } 446 } 447 448 451 protected boolean hasColumn(String name) { 452 int idx = getColumnNumber(name); 453 return idx >= 0 && idx < getLocalColumnCount(); 454 } 455 456 459 protected Iterator getColumnNames() { 460 if ( m_parent == null ) { 461 return m_names.iterator(); 462 } else { 463 return new CompositeIterator(m_names.iterator(), 464 m_pnames.iterator()); 465 } 466 } 467 468 472 protected void invalidateSchema() { 473 super.invalidateSchema(); 474 this.filterColumns(); 475 } 476 477 480 484 private class Listener 485 implements TableListener, ProjectionListener, ExpressionListener 486 { 487 public void tableChanged(Table t, int start, int end, int col, int type) { 488 if ( t != m_parent ) 490 return; 491 492 CascadedRowManager rowman = (CascadedRowManager)m_rows; 493 494 switch ( type ) { 496 case EventConstants.UPDATE: 497 { 498 if ( col == EventConstants.ALL_COLUMNS ) { 501 break; 502 } 503 504 for ( int r=start, cr=-1; r<=end; ++r ) { 506 if ( (cr=rowman.getChildRow(r)) != -1 ) { 507 if ( m_rowFilter.getBoolean(m_parent.getTuple(r)) ) { 509 int idx = getColumnNumber(m_parent.getColumnName(col)); 511 if ( idx >= getLocalColumnCount() ) 512 fireTableEvent(cr, cr, idx, EventConstants.UPDATE); 513 } else { 514 removeCascadedRow(cr); 516 } 517 } else { 518 if ( m_rowFilter.getBoolean(m_parent.getTuple(r)) ) { 520 if ( (cr=rowman.getChildRow(r)) < 0 ) 521 addCascadedRow(r); 522 } 523 } 524 } 525 break; 526 } 527 case EventConstants.DELETE: 528 { 529 if ( col == EventConstants.ALL_COLUMNS ) { 530 for ( int r=start, cr=-1; r<=end; ++r ) { 532 if ( (cr=rowman.getChildRow(r)) != -1 ) 533 removeCascadedRow(cr); 534 } 535 } else { 536 filterColumns(); 538 } 539 break; 540 } 541 case EventConstants.INSERT: 542 if ( col == EventConstants.ALL_COLUMNS ) { 543 for ( int r=start; r<=end; ++r ) { 545 if ( m_rowFilter.getBoolean(m_parent.getTuple(r)) ) { 546 if ( rowman.getChildRow(r) < 0 ) 547 addCascadedRow(r); 548 } 549 } 550 } else { 551 filterColumns(); 553 } 554 break; 555 } 556 } 557 558 public void projectionChanged(ColumnProjection projection) { 559 if ( projection == m_colFilter ) 560 filterColumns(); 561 } 562 563 public void expressionChanged(Expression expr) { 564 if ( expr == m_rowFilter ) 565 filterRows(); 566 } 567 } 568 569 } | Popular Tags |