186 }
187 else { }
188 }
189
190 /**
191 * A special thread to repopulate the test lists.
192 */
193 private class TableSynchronizer extends Thread {
194 TableSynchronizer() {
195 super("filtered-out list synchronizer");
196 setPriority(Thread.MIN_PRIORITY + 2);
197 }
198
199 public void run() {
200 // grab cache lock first because many other threads may alter that
201 // object, causing a deadlock here.
202 // sync. to hold observer traffic until re-sync is done
203 synchronized (cache) {
204 synchronized(BP_FilteredOutSubpanel.this) {
205 // resync with this node cache
206 Vector[] newData = cache.addObserver(cacheWatcher, true);
207
208 // add tests into the list model - this doesn't make the data
209 // live though
210 for (int j = 0; j < newData[newData.length-1].size() - 1; j++) {
211 if (stopping)
212 break;
213
214 mod.addTest(newData[newData.length-1].elementAt(j), true);
215 } // for
216
217 if (newData[newData.length-1].size() > 0 && !stopping) {
218 // final item with a notify
219 mod.addTest(newData[newData.length-1].lastElement(), false);
220 }
221
222 // to indicate completion
223 resyncThread = null;
224 } // this sync
225 } // cache sync
226
384 if (r == null)
385 r = uif.getI18NString("br.fo.noFi.txt");
386
387 return r;
388 }
389 }
390 else
391 throw new IndexOutOfBoundsException(
392 "Index into filtered out table is out of range: " +
393 row + ", " + column);
394 }
395
396 public boolean isCellEditable(int rowIndex, int colIndex) {
397 return false;
398 }
399
400 // ---------- Custom methods for this model ----------
401 /**
402 * @param suppressNotify Actively request that no update be scheduled.
403 */
404 void addTest(Object tr, boolean suppressNotify) {
405 synchronized (vLock) {
406 // make sure this item is not already in the list
407 if (!inQueue.contains(tr)) {
408 inQueue.addElement(tr);
409 }
410 } // sync
411
412 // try not to saturate the GUI event thread
413 if (!suppressNotify && !isUpdateScheduled) {
414 TableNotifier tn = new TableNotifier(subpanelNode, this);
415 pendingEvents.addElement(tn);
416 EventQueue.invokeLater(tn);
417 }
418 }
419
420 /**
421 * Remove the given test from the list.
422 * Ignored if the test is not in the list.
423 */
424 void removeTest(Object tr) {
425 synchronized (vLock) {
426 rmQueue.addElement(tr);
427
428 // try not to saturate the GUI event thread
429 if (!isUpdateScheduled) {
430 TableNotifier tn = new TableNotifier(subpanelNode, this);
431 pendingEvents.addElement(tn);
432 EventQueue.invokeLater(tn);
433 }
434 } // sync
435
436 }
437
438 void reset() {
439 synchronized (vLock) {
440 init();
441 }
442
443 // force GUI to update the now empty list
444 notifyDone();
445 }
446
447 // ------------ private --------------
448
449 private void init() {
450 // discard all pending events
451 // this is necessary to ensure that update events which haven't
452 // been processed are not processed after the model has changed
453 // arguably, this should be solved by putting this init() onto
454 // the event thread
455 synchronized (pendingEvents) {
456 for (int i = 0; i < pendingEvents.size(); i++) {
457 TableNotifier tn = (TableNotifier)(pendingEvents.get(i));
458 tn.cancel();
459 } // for
460 }
461
462 inQueue = new Vector();
463 rmQueue = new Vector();
464 liveData = new LinkedList();
465
466 isUpdateScheduled = false;
467 }
468
469 /**
470 * Transfer data from the internal queue to the live data queue.
471 * This is part of the Swing threading workaround. This method immediately
472 * exits if there is no work to do. It also dispatches model update events
473 * if necessary.
474 * This method always runs on the event dispatch thread.
475 */
476 private void goLive() {
477 int firstNew, lastNew = 0;
478 if (debug)
479 Debug.println("BP_TL.TLM - goLive() starting.");
480
481 // this is sync. against the outer class because we may change the
482 // list model object during execution of this block
483 synchronized (BP_FilteredOutSubpanel.this) {
484 synchronized (vLock) {
542
543 // this clears the "please wait" message if needed
544 if (table.getSelectedRow() == -1 && inQueue.size() == 0)
545 showMessage("");
546 } // sync
547 }
548
549 if (debug)
550 Debug.println("BP_TL.LT - goLive() finished");
551 }
552
553 /**
554 * Remove tests in the removal queue from the live data or the incoming data.
555 * vLock should be locked when you call this method
556 */
557 private void processRemoveQueue() {
558 if (rmQueue.size() == 0)
559 return;
560
561 while (rmQueue.size() > 0) {
562 TestResult target = (TestResult)(rmQueue.remove(0));
563 int targetIndex = liveData.indexOf(target);
564 if (targetIndex != -1) {
565 synchronized (liveData) {
566 // necessary for proper synchronization
567 // should not be a problem really, based on how other
568 // locking is done, all work on liveData occurs in goLive()
569 targetIndex = liveData.indexOf(target);
570
571 // only should happen if the item disappears
572 if (targetIndex == -1)
573 continue;
574
575 liveData.remove(targetIndex);
576
577 // WARNING: since we are continually changing the contents of
578 // the data, you must notify the observers synchronously to get
579 // proper results
580 notifyRemoved(target, targetIndex);
581 } // sync
582 }
643 EventQueue.invokeLater(tn);
644 }
645 }
646 }
647
648 private void notifyDone() {
649 if (listenerList.getListenerCount() > 0) {
650 // may want to buffer these messages
651 TableModelEvent e = new TableModelEvent(this);
652 // switch event onto AWT event thread
653 TableNotifier tn = new TableNotifier(e, mod);
654 pendingEvents.addElement(tn);
655 EventQueue.invokeLater(tn);
656 }
657 }
658
659 private String[] colNames;
660
661 // must sync. on vLock anytime you access inQueue or liveData
662 private final Object vLock = new Object(); // lock for inQueue & rmQueue
663 private Vector inQueue; // queue of items to be added to live data
664 private Vector rmQueue; // queue of items to be removed from live data
665 private LinkedList liveData; // to allow manual synchronization
666 Vector pendingEvents = new Vector();
667
668 volatile boolean isUpdateScheduled; // are updates waiting in inQueue or rmQueue
669
670 private static final int BATCH_SIZE = 100;
671 private static final int COLUMN_COUNT = 2;
672 }
673
674 private class CacheObserver extends TT_NodeCache.TT_NodeCacheObserver {
675 CacheObserver() {
676 super();
677 // configure our interest list
678 interestList[MSGS_FILTERED] = true;
679 }
680
681 public void testAdded(int msgType, TestResultTable.TreeNode[] path,
682 TestResult what, int index) {
683 synchronized(BP_FilteredOutSubpanel.this) {
684 mod.addTest(what, false);
685 }
686 }
|
186 }
187 else { }
188 }
189
190 /**
191 * A special thread to repopulate the test lists.
192 */
193 private class TableSynchronizer extends Thread {
194 TableSynchronizer() {
195 super("filtered-out list synchronizer");
196 setPriority(Thread.MIN_PRIORITY + 2);
197 }
198
199 public void run() {
200 // grab cache lock first because many other threads may alter that
201 // object, causing a deadlock here.
202 // sync. to hold observer traffic until re-sync is done
203 synchronized (cache) {
204 synchronized(BP_FilteredOutSubpanel.this) {
205 // resync with this node cache
206 Vector<TestResult>[] newData = cache.addObserver(cacheWatcher, true);
207
208 // add tests into the list model - this doesn't make the data
209 // live though
210 for (int j = 0; j < newData[newData.length-1].size() - 1; j++) {
211 if (stopping)
212 break;
213
214 mod.addTest(newData[newData.length-1].elementAt(j), true);
215 } // for
216
217 if (newData[newData.length-1].size() > 0 && !stopping) {
218 // final item with a notify
219 mod.addTest(newData[newData.length-1].lastElement(), false);
220 }
221
222 // to indicate completion
223 resyncThread = null;
224 } // this sync
225 } // cache sync
226
384 if (r == null)
385 r = uif.getI18NString("br.fo.noFi.txt");
386
387 return r;
388 }
389 }
390 else
391 throw new IndexOutOfBoundsException(
392 "Index into filtered out table is out of range: " +
393 row + ", " + column);
394 }
395
396 public boolean isCellEditable(int rowIndex, int colIndex) {
397 return false;
398 }
399
400 // ---------- Custom methods for this model ----------
401 /**
402 * @param suppressNotify Actively request that no update be scheduled.
403 */
404 void addTest(TestResult tr, boolean suppressNotify) {
405 synchronized (vLock) {
406 // make sure this item is not already in the list
407 if (!inQueue.contains(tr)) {
408 inQueue.addElement(tr);
409 }
410 } // sync
411
412 // try not to saturate the GUI event thread
413 if (!suppressNotify && !isUpdateScheduled) {
414 TableNotifier tn = new TableNotifier(subpanelNode, this);
415 pendingEvents.addElement(tn);
416 EventQueue.invokeLater(tn);
417 }
418 }
419
420 /**
421 * Remove the given test from the list.
422 * Ignored if the test is not in the list.
423 */
424 void removeTest(TestResult tr) {
425 synchronized (vLock) {
426 rmQueue.addElement(tr);
427
428 // try not to saturate the GUI event thread
429 if (!isUpdateScheduled) {
430 TableNotifier tn = new TableNotifier(subpanelNode, this);
431 pendingEvents.addElement(tn);
432 EventQueue.invokeLater(tn);
433 }
434 } // sync
435
436 }
437
438 void reset() {
439 synchronized (vLock) {
440 init();
441 }
442
443 // force GUI to update the now empty list
444 notifyDone();
445 }
446
447 // ------------ private --------------
448
449 private void init() {
450 // discard all pending events
451 // this is necessary to ensure that update events which haven't
452 // been processed are not processed after the model has changed
453 // arguably, this should be solved by putting this init() onto
454 // the event thread
455 synchronized (pendingEvents) {
456 for (int i = 0; i < pendingEvents.size(); i++) {
457 TableNotifier tn = (TableNotifier)(pendingEvents.get(i));
458 tn.cancel();
459 } // for
460 }
461
462 inQueue = new Vector<>();
463 rmQueue = new Vector<>();
464 liveData = new LinkedList<>();
465
466 isUpdateScheduled = false;
467 }
468
469 /**
470 * Transfer data from the internal queue to the live data queue.
471 * This is part of the Swing threading workaround. This method immediately
472 * exits if there is no work to do. It also dispatches model update events
473 * if necessary.
474 * This method always runs on the event dispatch thread.
475 */
476 private void goLive() {
477 int firstNew, lastNew = 0;
478 if (debug)
479 Debug.println("BP_TL.TLM - goLive() starting.");
480
481 // this is sync. against the outer class because we may change the
482 // list model object during execution of this block
483 synchronized (BP_FilteredOutSubpanel.this) {
484 synchronized (vLock) {
542
543 // this clears the "please wait" message if needed
544 if (table.getSelectedRow() == -1 && inQueue.size() == 0)
545 showMessage("");
546 } // sync
547 }
548
549 if (debug)
550 Debug.println("BP_TL.LT - goLive() finished");
551 }
552
553 /**
554 * Remove tests in the removal queue from the live data or the incoming data.
555 * vLock should be locked when you call this method
556 */
557 private void processRemoveQueue() {
558 if (rmQueue.size() == 0)
559 return;
560
561 while (rmQueue.size() > 0) {
562 TestResult target = rmQueue.remove(0);
563 int targetIndex = liveData.indexOf(target);
564 if (targetIndex != -1) {
565 synchronized (liveData) {
566 // necessary for proper synchronization
567 // should not be a problem really, based on how other
568 // locking is done, all work on liveData occurs in goLive()
569 targetIndex = liveData.indexOf(target);
570
571 // only should happen if the item disappears
572 if (targetIndex == -1)
573 continue;
574
575 liveData.remove(targetIndex);
576
577 // WARNING: since we are continually changing the contents of
578 // the data, you must notify the observers synchronously to get
579 // proper results
580 notifyRemoved(target, targetIndex);
581 } // sync
582 }
643 EventQueue.invokeLater(tn);
644 }
645 }
646 }
647
648 private void notifyDone() {
649 if (listenerList.getListenerCount() > 0) {
650 // may want to buffer these messages
651 TableModelEvent e = new TableModelEvent(this);
652 // switch event onto AWT event thread
653 TableNotifier tn = new TableNotifier(e, mod);
654 pendingEvents.addElement(tn);
655 EventQueue.invokeLater(tn);
656 }
657 }
658
659 private String[] colNames;
660
661 // must sync. on vLock anytime you access inQueue or liveData
662 private final Object vLock = new Object(); // lock for inQueue & rmQueue
663 private Vector<TestResult> inQueue; // queue of items to be added to live data
664 private Vector<TestResult> rmQueue; // queue of items to be removed from live data
665 private LinkedList<TestResult> liveData; // to allow manual synchronization
666 Vector<TableNotifier> pendingEvents = new Vector<>();
667
668 volatile boolean isUpdateScheduled; // are updates waiting in inQueue or rmQueue
669
670 private static final int BATCH_SIZE = 100;
671 private static final int COLUMN_COUNT = 2;
672 }
673
674 private class CacheObserver extends TT_NodeCache.TT_NodeCacheObserver {
675 CacheObserver() {
676 super();
677 // configure our interest list
678 interestList[MSGS_FILTERED] = true;
679 }
680
681 public void testAdded(int msgType, TestResultTable.TreeNode[] path,
682 TestResult what, int index) {
683 synchronized(BP_FilteredOutSubpanel.this) {
684 mod.addTest(what, false);
685 }
686 }
|