1
2
3
4
5
6
7 package net.sourceforge.jsh3modtool.gui.imagetable;
8
9 import net.sourceforge.jsh3modtool.gui.imagetable.cache.ImageLoadingListener;
10 import net.sourceforge.jsh3modtool.gui.imagetable.cellfilters.*;
11 import net.sourceforge.jsh3modtool.gui.imagetable.cellsorters.FilenameCellSorter;
12 import net.sourceforge.jsh3modtool.gui.imagetable.cellsorters.FoldersFirstCellSorter;
13 import net.sourceforge.jsh3modtool.gui.imagetable.utils.JTableUtil;
14
15 import java.util.*;
16 import javax.swing.table.*;
17
18 /***
19 * A model for a JTable oontaining images
20 *
21 * @author erma
22 */
23 public class ImageTableModel extends AbstractTableModel implements ImageLoadingListener
24 {
25 private List allItems = new ArrayList();
26 private int allItemsCount;
27
28 private List filteredItems = new ArrayList();
29 private int filteredItemsCount;
30
31 private List filters = new ArrayList();
32 private Comparator filteredItemsComparator = new FilenameCellSorter();
33 private boolean useFoldersFirstWhenSorting;
34
35 private int columnCount;
36 private int rowCount;
37
38 /***
39 * Creates a new instance of BrowseTableModel
40 * @param cols number of columns
41 */
42 public ImageTableModel(int cols)
43 {
44 allItemsCount = 0;
45 filteredItemsCount = 0;
46 columnCount = cols;
47 recalculateRowCount();
48
49
50 }
51
52 /*** Returns the number of columns in the model. A
53 * <code>JTable</code> uses this method to determine how many columns it
54 * should create and display by default.
55 *
56 * @return the number of columns in the model
57 * @see #getRowCount
58 */
59 public int getColumnCount()
60 {
61 return columnCount;
62 }
63
64 /*** Returns the number of rows in the model. A
65 * <code>JTable</code> uses this method to determine how many rows it
66 * should display. This method should be quick, as it
67 * is called frequently during rendering.
68 *
69 * @return the number of rows in the model
70 * @see #getColumnCount
71 */
72 public int getRowCount()
73 {
74 return rowCount;
75 }
76
77 /*** Returns the value for the cell at <code>columnIndex</code> and
78 * <code>rowIndex</code>.
79 * @param row the row whose value is to be queried
80 * @param col the column whose value is to be queried
81 * @return the value Object at the specified cell
82 */
83 public Object getValueAt(int row, int col)
84 {
85 Object value = null;
86 if ( filteredItems != null )
87 {
88 int listIndex = getImageIndex( row, col );
89 if ( listIndex < filteredItemsCount )
90 {
91 value = filteredItems.get( listIndex );
92 }
93 }
94
95 return value;
96 }
97
98 /*** Returns the value for the cell at <code>columnIndex</code> and
99 * <code>rowIndex</code>.
100 * @param cell the cell
101 * @return the value Object at the specified cell
102 */
103 public Object getValueAt(JTableUtil.Cell cell)
104 {
105 return getValueAt( cell.row, cell.column );
106 }
107
108 /***
109 * Changes the number of columns
110 * @param cols the desired number of columns
111 */
112 public void setColumnCount( int cols )
113 {
114 if ( columnCount != cols )
115 {
116 columnCount = cols;
117 recalculateRowCount();
118 fireTableStructureChanged();
119 }
120 }
121
122 /***
123 * Returns a List containing all images that passes the filter.
124 * @param filter the Cell filter to filter out images with.
125 * @return a List, can be empty
126 */
127 List getImageCells( CellFilter filter )
128 {
129 List selectedImages = new Vector();
130 ListIterator iterator = filteredItems.listIterator();
131 while ( iterator.hasNext() )
132 {
133 Object cell = iterator.next();
134 if ( cell.getClass().equals( ImageCell.class ) )
135 {
136 ImageCell image = (ImageCell) cell;
137 if ( filter.accept(image) )
138 {
139 selectedImages.add( image );
140 }
141 }
142 }
143 return selectedImages;
144 }
145
146 /***
147 * Returns a List containing all image cells.
148 * @return a List, can be empty.
149 */
150 List getAllImageCells()
151 {
152 List selectedImages = new Vector();
153 ListIterator iterator = filteredItems.listIterator();
154 while ( iterator.hasNext() )
155 {
156 Object cell = iterator.next();
157 if ( cell.getClass().equals( ImageCell.class ) )
158 {
159 selectedImages.add( cell );
160 }
161 }
162 return selectedImages;
163 }
164
165 /***
166 * Returns a List containing all images that passes the filter.
167 * @param filter the Cell filter to filter out images with.
168 * @return a List, can be empty
169 */
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189 /***
190 * Return a List containing all selected image cells.
191 * @return a List
192 */
193
194
195
196
197
198 /***
199 * Returns if the specified Cell should be included in the filtered list
200 * or not
201 * @param cell the cell to test
202 * @return true if and only if the cell is accepted by all filters
203 */
204 private boolean acceptedByFilters( BaseCell cell )
205 {
206 boolean passedFilters = true;
207 ListIterator iterator = filters.listIterator();
208 while ( (passedFilters) && ( iterator.hasNext() ) )
209 {
210 CellFilter filter = (CellFilter) iterator.next();
211 if ( ! filter.accept( cell ) )
212 {
213 passedFilters = false;
214 }
215 }
216 return passedFilters;
217 }
218
219
220 /***
221 * @param nrOfImagesBefore
222 * @param startRow
223 */
224 private void revalidateData(int nrOfImagesBefore, int startRow) {
225 recalculateRowCount();
226 sortFilteredItems();
227 int endRow = rowCount;
228
229 if ( nrOfImagesBefore == 0 )
230 {
231 fireTableDataChanged();
232 }
233 else
234 {
235 if ( startRow == endRow )
236 {
237 fireTableRowsUpdated( endRow - 1, endRow );
238 }
239 else
240 {
241 fireTableRowsInserted( startRow - 1, endRow );
242 }
243 }
244 }
245
246 public void addImageModel(ImageModel imageModel)
247 {
248 int nrOfImagesBefore = allItemsCount;
249 int startRow = rowCount;
250
251 BaseCell cell = new ImageCell(imageModel);
252 allItems.add( cell );
253 allItemsCount++;
254
255 if ( acceptedByFilters( cell ) )
256 {
257 filteredItemsCount++;
258 filteredItems.add( cell );
259 }
260 revalidateData(nrOfImagesBefore, startRow);
261
262 }
263
264 /*** Adds the specified images to the model
265 * @param filesList a list of Files
266 */
267 public void addImageModels( List filesList )
268 {
269 int nrOfImagesBefore = allItemsCount;
270 int startRow = rowCount;
271 ListIterator iterator = filesList.listIterator();
272
273 while ( iterator.hasNext() )
274 {
275 BaseCell cell = new ImageCell((ImageModel) iterator.next());
276 if ( cell != null )
277 {
278 allItems.add( cell );
279 allItemsCount++;
280
281 if ( acceptedByFilters( cell ) )
282 {
283 filteredItemsCount++;
284 filteredItems.add( cell );
285 }
286 }
287 }
288 revalidateData(nrOfImagesBefore, startRow);
289 }
290
291 /*** Removes the Files in the specified list from the table
292 * @param filesList a List of Files
293 */
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317 /***
318 * Returns the cell that is the representation of the specified file
319 * @param file the file to find a cell for
320 * @return the cell; null if the cell wasnt found
321 */
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342 /*** Returns if the model contains the specified cell
343 * @param cell the cell to find in the model
344 * @return true if the cell is in the model; false otherwise
345 */
346 public boolean contains( BaseCell cell )
347 {
348 boolean retValue = false;
349 if ( cell != null )
350 {
351 retValue = allItems.contains( cell );
352 }
353 return retValue;
354 }
355
356 /***
357 * Generates an Cell for the table
358 * @param file the file
359 * @return an AbstractCell
360 */
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377 /*** Removes all items from the model */
378 public void clear()
379 {
380 allItems.clear();
381 filteredItems.clear();
382 allItemsCount = 0;
383 filteredItemsCount = 0;
384 recalculateRowCount();
385 fireTableDataChanged();
386 }
387
388 /***
389 * Recalculates the number of rows.
390 */
391 private void recalculateRowCount()
392 {
393 rowCount = (int) Math.floor( (double) filteredItemsCount / (double) columnCount );
394 rowCount += ( (filteredItemsCount % columnCount) == 0 ? 0 : 1 );
395 }
396
397 /***
398 * Invoked when an image has been loaded, specified by the index in the list
399 * This method fires a cell update event.
400 * @param cell the cell that was updated.
401 */
402 public void imageIsLoaded(BaseCell cell)
403 {
404 int cellIndex = filteredItems.indexOf( cell );
405 if ( cellIndex != -1 )
406 {
407 int row = (int) Math.floor( (double) cellIndex / (double) columnCount );
408 int col = cellIndex - ( row * columnCount );
409
410 fireTableCellUpdated( row, col );
411 }
412 if ( cell.getClass().equals(ImageCell.class))
413 {
414 ((ImageCell)cell).resetTooltip();
415 }
416 }
417
418 /*** Returns the number of images in the model
419 * @return number of items in table
420 */
421 public int getSize()
422 {
423 return filteredItemsCount;
424 }
425
426 /***
427 * Returns the image index (in the list) from the cells row and column.
428 * @param row the row.
429 * @param col the col.
430 * @return the image index (in the list).
431 */
432 int getImageIndex( int row, int col )
433 {
434 return row * columnCount + col;
435 }
436
437 /***
438 * Returns the image index (in the list) for the specified cell.
439 * @param cell the cell to find the index for.
440 * @return the image index (in the list).
441 */
442 int getImageIndex( BaseCell cell )
443 {
444 int index = -1;
445 JTableUtil.Cell tableCell = getTableCell(cell);
446 if ( tableCell != null )
447 {
448 index = getImageIndex(tableCell.row, tableCell.column);
449 }
450 return index;
451 }
452
453 /***
454 * Returns the AbstractCell at the specified index (in the list).
455 * @param index the index to find the cell for.
456 * @return an AbstractCell.
457 */
458 BaseCell getCell( int index )
459 {
460 return (BaseCell) filteredItems.get(index);
461 }
462
463
464 /***
465 * Returns whetever this cell is editable or not, this
466 * implementation returns false always.
467 * @param rowIndex the row
468 * @param columnIndex the column
469 * @return false.
470 */
471 public boolean isCellEditable(int rowIndex, int columnIndex)
472 {
473 return false;
474 }
475
476 /***
477 * Fires a cell update. The method checks if the cell is acceptable by the filters, if
478 * not it is removed from the filteredList.
479 * @param cell the cell to update.
480 */
481 public void fireTableCellUpdate( BaseCell cell )
482 {
483 JTableUtil.Cell tableCell = getTableCell( cell );
484
485 if ( tableCell != null )
486 {
487 if ( ! acceptedByFilters( cell ))
488 {
489 filteredItems.remove(cell);
490 filteredItemsCount = filteredItems.size();
491 fireTableRowsDeleted(tableCell.row, tableCell.row );
492 }
493 else
494 {
495 fireTableCellUpdated( tableCell.row, tableCell.column );
496 }
497 }
498 }
499
500 /*** Returns a JTableUtil.Cell from the specified list index
501 * @param cell the cell to find in the table
502 * @return a Cell containing the row and column of the cell
503 */
504 public JTableUtil.Cell getTableCell( BaseCell cell )
505 {
506 JTableUtil.Cell tableCell = null;
507
508 int cellIndex = filteredItems.indexOf( cell );
509 if ( cellIndex != -1 )
510 {
511 tableCell = getTableCell( cellIndex );
512 }
513 return tableCell;
514 }
515
516 /***
517 * Returns a JTableUtil.Cell that matches the specified file
518 * @param file the file to find in the filteres image cells
519 * @return a Cell containing the row and column of the cell
520 */
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542 /***
543 * Adds the filter to the filters list, the filter is used until it is
544 * removed from this list.
545 * @param filter the filter to add
546 */
547 public void addFilter( CellFilter filter )
548 {
549 filters.add( filter );
550 updateFilteredList();
551 }
552
553 /***
554 * Removes the filter from the filters list
555 * @param filter the filter to remove
556 */
557 public void removeFilter( CellFilter filter )
558 {
559 filters.remove( filter );
560 updateFilteredList();
561 }
562
563 /***
564 * Removes all filters from the list
565 */
566 public void removeAllFilters()
567 {
568 filters.clear();
569 updateFilteredList();
570 }
571
572 /***
573 * Reinits the filtere items list, it copies values from the main item list
574 * to the filtered items list if it passes all filters.
575 */
576 private void updateFilteredList()
577 {
578 filteredItemsCount = 0;
579 filteredItems.clear();
580
581 ListIterator itemIterator = allItems.listIterator();
582 while ( itemIterator.hasNext() )
583 {
584 BaseCell cell = (BaseCell) itemIterator.next();
585 if ( acceptedByFilters( cell ) )
586 {
587 filteredItems.add( cell );
588 }
589 }
590 filteredItemsCount = filteredItems.size();
591 sortFilteredItems();
592 recalculateRowCount();
593 fireTableDataChanged();
594 }
595
596 /***
597 * Returns a cell for the specified list index
598 * @param cellIndex the cell index.
599 * @return the cell.
600 */
601 JTableUtil.Cell getTableCell( int cellIndex )
602 {
603 int row = (int) Math.floor( (double) cellIndex / (double) columnCount );
604 int col = cellIndex - ( row * columnCount );
605
606 return new JTableUtil.Cell( row, col );
607 }
608
609 /***
610 * Sorts the filtereditems list. Note that it only sorts the list that is displayed
611 * and not the underlying.
612 */
613 private void sortFilteredItems()
614 {
615 Comparator c = filteredItemsComparator;
616 if (c != null)
617 {
618 if ( useFoldersFirstWhenSorting )
619 {
620 c = new FoldersFirstCellSorter(c);
621 }
622 Collections.sort(filteredItems, c);
623 }
624 }
625
626 /***
627 * Sets the new cell comparator.
628 * The comparator will be activated with Cells that extends
629 * the AbstractCell class. All comparators sent to this method must
630 * be able to sort the different cells.
631 * @param comparator
632 * @see AbstractCellSorter
633 */
634 public void setCellComparator( Comparator comparator )
635 {
636 filteredItemsComparator = comparator;
637 }
638 }