001 /* 002 * Copyright 2002-2004 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); you may not 005 * use this file except in compliance with the License. You may obtain a copy of 006 * the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 013 * License for the specific language governing permissions and limitations under 014 * the License. 015 */ 016 package org.springframework.richclient.table; 017 018 import java.awt.EventQueue; 019 import java.awt.Toolkit; 020 import java.lang.reflect.InvocationTargetException; 021 import java.util.List; 022 023 import javax.swing.RepaintManager; 024 import javax.swing.SwingUtilities; 025 026 /** 027 * Thread responsible for publishing changes to the Model. Sleeps for a defined 028 * amount of time, waits for no activity in the UI and then users invokeAndWait 029 * to publish changes. 030 */ 031 public class TableUpdater extends Thread { 032 private int sleepTime = 3000; 033 034 private int eqSleepTime = 1000; 035 036 private boolean updatesEnabled = true; 037 038 private Runnable publishRunnable; 039 040 private Runnable emptyRunnable; 041 042 private TableDataProvider tableDataProvider; 043 044 private MutableTableModel tableModel; 045 046 private boolean done; 047 048 public TableUpdater(TableDataProvider provider, MutableTableModel tableModel) { 049 super(); 050 setPriority(Thread.MIN_PRIORITY); 051 this.updatesEnabled = true; 052 this.tableDataProvider = provider; 053 this.tableModel = tableModel; 054 055 // Runnable used to publish changes to the event dispatching thread 056 this.publishRunnable = new Runnable() { 057 public void run() { 058 publishChangesOnEventDispatchingThread(); 059 } 060 }; 061 062 // Empty runnable, used to wait until the event dispatching thread 063 // has finished processing any pending events. 064 this.emptyRunnable = new Runnable() { 065 public void run() { 066 } 067 }; 068 } 069 070 public void interrupt() { 071 done = true; 072 super.interrupt(); 073 } 074 075 public void run() { 076 while (!isInterrupted() && !done) { 077 try { 078 sleep(sleepTime); 079 waitForUpdatesEnabled(); 080 waitForIdleEventQueue(); 081 publishChanges(); 082 } 083 catch (InterruptedException ie) { 084 } 085 } 086 } 087 088 private void waitForUpdatesEnabled() { 089 synchronized (this) { 090 while (!this.updatesEnabled) { 091 try { 092 wait(); 093 } 094 catch (InterruptedException ie) { 095 } 096 } 097 } 098 } 099 100 private void waitForIdleEventQueue() { 101 EventQueue queue = Toolkit.getDefaultToolkit().getSystemEventQueue(); 102 while (queue.peekEvent() != null) { 103 try { 104 sleep(eqSleepTime); 105 } 106 catch (InterruptedException ie) { 107 } 108 } 109 } 110 111 /** 112 * Publishes changes on the event dispatching thread when the system isn't 113 * busy. This blocks the caller until the changes have been published. 114 */ 115 private void publishChanges() { 116 // And wait until there are no pending events. 117 /* 118 * try { tableModel.lock(); } catch (InterruptedException e) { 119 * System.err.println("Table updater interrupted on table lock attempt. 120 * Nothing updated."); return; } 121 */ 122 123 try { 124 // publish the changes on the event dispatching thread 125 SwingUtilities.invokeAndWait(publishRunnable); 126 } 127 catch (InterruptedException ie) { 128 } 129 catch (InvocationTargetException ite) { 130 } 131 132 try { 133 // Wait until the system has completed processing of any 134 // events we triggered as part of publishing changes. 135 SwingUtilities.invokeAndWait(emptyRunnable); 136 } 137 catch (InterruptedException ie) { 138 } 139 catch (InvocationTargetException ite) { 140 } 141 142 /* 143 * tableModel.unlock(); 144 */ 145 } 146 147 /** 148 * Does the actual publishing of changes. 149 */ 150 private void publishChangesOnEventDispatchingThread() { 151 List newRows = tableDataProvider.takeData(); 152 if (newRows.size() > 0) { 153 tableModel.addRows(newRows); 154 RepaintManager.currentManager(null).paintDirtyRegions(); 155 newRows.clear(); 156 } 157 } 158 159 /** 160 * If enable is true, we are allowed to publish changes, otherwise we 161 * aren't. 162 */ 163 public void setUpdatesEnabled(boolean enable) { 164 synchronized (this) { 165 updatesEnabled = enable; 166 if (updatesEnabled) { 167 notify(); 168 } 169 } 170 } 171 172 public boolean getUpdatesEnabled() { 173 return updatesEnabled; 174 } 175 }