/*
* Created on 4 mai 2004
* Created by Olivier Chalouhi
*
* Copyright (C) 2004, 2005, 2006 Aelitis SAS, All rights Reserved
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details ( see the LICENSE file ).
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* AELITIS, SAS au capital de 46,603.30 euros,
* 8 Alle Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
*/
package org.gudy.azureus2.ui.swt.mainwindow;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.swt.widgets.Display;
import org.gudy.azureus2.core3.config.COConfigurationManager;
import org.gudy.azureus2.core3.config.ParameterListener;
import org.gudy.azureus2.core3.logging.LogEvent;
import org.gudy.azureus2.core3.logging.LogIDs;
import org.gudy.azureus2.core3.logging.Logger;
import org.gudy.azureus2.core3.util.AERunnable;
import org.gudy.azureus2.core3.util.AEThread;
import org.gudy.azureus2.core3.util.Constants;
import org.gudy.azureus2.core3.util.Debug;
import org.gudy.azureus2.ui.swt.*;
import org.gudy.azureus2.ui.swt.minibar.MiniBarManager;
import org.gudy.azureus2.ui.swt.views.IView;
import org.gudy.azureus2.ui.systray.SystemTraySWT;
/**
* @author Olivier Chalouhi
*
*/
public class GUIUpdater extends AEThread implements ParameterListener {
private static final LogIDs LOGID = LogIDs.GUI;
/** Calculate timer statistics for GUI update */
private static final boolean DEBUG_TIMER = Constants.isCVSVersion();
private MainWindow mainWindow;
private Display display;
boolean finished = false;
boolean refreshed = true;
static List refreshables = new ArrayList();
int waitTime;
int inactiveFactor;
int mainwindowTicks;
Map averageTimes = DEBUG_TIMER ? new HashMap() : null;
public
GUIUpdater(
MainWindow mainWindow)
{
super("GUI updater", true);
this.mainWindow = mainWindow;
this.display = mainWindow.getDisplay();
setPriority(Thread.MAX_PRIORITY -2);
COConfigurationManager.addAndFireParameterListeners(new String[] {"GUI Refresh","Refresh When Inactive"}, this);
}
public void runSupport() {
while (!finished) {
if(refreshed)
update();
try {
Thread.sleep(waitTime);
}
catch (Exception e) {
Debug.printStackTrace( e );
}
}
}
/**
* @param parameterName the name of the parameter that has changed
* @see org.gudy.azureus2.core3.config.ParameterListener#parameterChanged(java.lang.String)
*/
public void parameterChanged(String parameterName) {
waitTime = COConfigurationManager.getIntParameter("GUI Refresh");
inactiveFactor = COConfigurationManager.getIntParameter("Refresh When Inactive");
}
private void update() {
refreshed = false;
Utils.execSWTThread(new AERunnable() {
public void runSupport() {
try {
long lTimeStart = System.currentTimeMillis();
Map timeMap = DEBUG_TIMER ? new LinkedHashMap() : null;
if (display == null || display.isDisposed())
return;
IView view = null;
if (!mainWindow.getShell().isDisposed() && mainWindow.isVisible()
&& !mainWindow.getShell().getMinimized())
mainupdate: {
mainwindowTicks++;
if(mainWindow.getShell().getDisplay().getActiveShell() != mainWindow.getShell() && mainwindowTicks % inactiveFactor != 0)
break mainupdate;
view = mainWindow.getCurrentView();
if (DEBUG_TIMER)
timeMap.put("Init", new Long(System.currentTimeMillis()));
if (view != null) {
view.refresh();
if (DEBUG_TIMER) {
String s = view.getFullTitle().replaceAll("[0-9.]++\\% : ", "");
timeMap.put("'" + s + "' Refresh", new Long(System.currentTimeMillis()));
}
Tab.refresh();
if (DEBUG_TIMER)
timeMap.put("Tab Refresh", new Long(System.currentTimeMillis()));
}
MainStatusBar mainStatusBar = mainWindow.getMainStatusBar();
if (mainStatusBar != null)
mainStatusBar.refreshStatusBar();
}
if (DEBUG_TIMER)
timeMap.put("Status Bar", new Long(System.currentTimeMillis()));
SystemTraySWT systemTraySWT = mainWindow.getSystemTraySWT();
if (systemTraySWT != null)
systemTraySWT.update();
if (DEBUG_TIMER)
timeMap.put("SysTray", new Long(System.currentTimeMillis()));
try {
MiniBarManager.getManager().refreshAll();
} catch (Exception e) {
Logger.log(new LogEvent(LOGID,
"Error while trying to update DL Bars", e));
}
TrayWindow tray = mainWindow.getTray();
if (tray != null) {
tray.refresh();
}
if (DEBUG_TIMER) {
timeMap.put("DLBars", new Long(System.currentTimeMillis()));
makeDebugToolTip(lTimeStart, timeMap);
}
synchronized (refreshables)
{
for(int i=0;i < refreshables.size();i++)
{
Refreshable item = (Refreshable)((WeakReference)refreshables.get(i)).get();
if(item == null)
{
refreshables.remove(i--);
continue;
}
item.refresh();
}
}
} catch (Exception e) {
Logger.log(new LogEvent(LOGID, "Error while trying to update GUI", e));
} finally {
refreshed = true;
}
}
});
}
public void stopIt() {
finished = true;
COConfigurationManager.removeParameterListener("Refresh When Inactive", this);
COConfigurationManager.removeParameterListener("GUI Refresh", this);
COConfigurationManager.removeParameterListener("config.style.refreshMT", this);
}
private void makeDebugToolTip(long lTimeStart, Map timeMap) {
final int IDX_AVG = 0;
final int IDX_SIZE = 1;
final int IDX_MAX = 2;
final int IDX_LAST = 3;
final int IDX_TIME = 4;
long lastTime = lTimeStart;
for (Iterator iter = timeMap.keySet().iterator(); iter.hasNext();) {
String key = (String) iter.next();
if (!averageTimes.containsKey(key))
averageTimes.put(key, new Object[] { new Long(0), new Long(0),
new Long(0), new Long(0), new Long(System.currentTimeMillis()) });
Object[] average = (Object[]) averageTimes.get(key);
long l = ((Long) timeMap.get(key)).longValue();
long diff = l - lastTime;
if (diff > 0) {
long count = ((Long) average[IDX_SIZE]).longValue();
// Limit to 20. Gives slightly scewed averages, but doesn't
// require storing all 20 values and averaging them each time
if (count >= 20)
count = 19;
long lNewAverage = ((((Long) average[IDX_AVG]).longValue() * count) + diff)
/ (count + 1);
average[IDX_AVG] = new Long(lNewAverage);
average[IDX_SIZE] = new Long(count + 1);
if (diff > ((Long) average[IDX_MAX]).longValue())
average[IDX_MAX] = new Long(diff);
average[IDX_LAST] = new Long(diff);
average[IDX_TIME] = new Long(System.currentTimeMillis());
} else {
average[IDX_LAST] = new Long(diff);
}
averageTimes.put(key, average);
lastTime = l;
}
StringBuffer sb = new StringBuffer();
for (Iterator iter = averageTimes.keySet().iterator(); iter.hasNext();) {
String key = (String) iter.next();
Object[] average = (Object[]) averageTimes.get(key);
long lLastUpdated = ((Long) average[IDX_TIME]).longValue();
if (System.currentTimeMillis() - lLastUpdated > 10000) {
iter.remove();
continue;
}
long lTime = ((Long) average[IDX_AVG]).longValue();
if (lTime > 0) {
if (sb.length() > 0)
sb.append("\n");
sb.append(average[IDX_AVG] + "ms avg: ");
sb.append("[" + key + "]");
sb.append(average[IDX_SIZE] + " samples");
sb.append("; max:" + average[IDX_MAX]);
sb.append("; last:" + average[IDX_LAST]);
}
}
MainStatusBar mainStatusBar = mainWindow.getMainStatusBar();
if (mainStatusBar != null)
mainStatusBar.setDebugInfo(sb.toString());
}
public static void addRefreshableItem(Refreshable item)
{
synchronized (refreshables)
{
refreshables.add(new WeakReference(item));
}
}
}