/******************************************************************************* * Copyright (c) 2004, 2013 Tasktop Technologies and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Tasktop Technologies - initial API and implementation *******************************************************************************/ package org.eclipse.mylyn.internal.tasks.ui; import java.util.Date; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.jobs.JobChangeAdapter; import org.eclipse.mylyn.commons.core.DateUtil; import org.eclipse.mylyn.monitor.ui.IUserAttentionListener; import org.eclipse.ui.PlatformUI; /** * @author Steffen Pingel */ public class TaskListSynchronizationScheduler implements IUserAttentionListener { private static final boolean TRACE_ENABLED = Boolean .valueOf(Platform.getDebugOption("org.eclipse.mylyn.tasks.ui/debug/synchronization")); //$NON-NLS-1$ private long interval; private long inactiveInterval; private final Job refreshJob; private boolean userActive; /** * Absolute time in milliseconds when refresh job will next run. */ private long scheduledTime; /** * Absolute time in milliseconds when refresh job last completed. */ private long lastSyncTime; private final JobChangeAdapter jobListener; public TaskListSynchronizationScheduler(Job refreshJob) { this.userActive = true; this.jobListener = new JobChangeAdapter() { @Override public void done(IJobChangeEvent event) { jobDone(); } }; this.refreshJob = refreshJob; // do not show in progress view by default this.refreshJob.setSystem(true); this.refreshJob.setUser(false); } private synchronized void reschedule() { long delay = this.interval; if (delay != 0 && PlatformUI.isWorkbenchRunning()) { if (!userActive) { // triple scheduling interval each time this.inactiveInterval *= 3; delay = this.inactiveInterval; if (TRACE_ENABLED) { trace("Set inactive interval to " + DateUtil.getFormattedDurationShort(this.inactiveInterval)); //$NON-NLS-1$ } } if (this.scheduledTime != 0) { if (this.scheduledTime < System.currentTimeMillis() + delay) { // already scheduled, nothing to do if (TRACE_ENABLED) { trace("Synchronization already scheduled in " //$NON-NLS-1$ + DateUtil.getFormattedDurationShort(this.scheduledTime - System.currentTimeMillis())); } return; } else { // reschedule for an earlier time cancel(); } } schedule(delay); } } private synchronized void cancel() { // prevent listener from rescheduling due to cancel if (TRACE_ENABLED) { trace("Canceling synchronization scheduled to run in " //$NON-NLS-1$ + DateUtil.getFormattedDurationShort(this.scheduledTime - System.currentTimeMillis())); } refreshJob.removeJobChangeListener(jobListener); refreshJob.cancel(); refreshJob.addJobChangeListener(jobListener); } private void schedule(long interval) { if (TRACE_ENABLED) { trace("Scheduling synchronization in " + DateUtil.getFormattedDurationShort(interval)); //$NON-NLS-1$ } this.scheduledTime = System.currentTimeMillis() + interval; refreshJob.schedule(interval); } public synchronized void setInterval(long interval) { setInterval(interval, interval); } public synchronized void setInterval(long delay, long interval) { if (this.interval != interval) { this.interval = interval; this.inactiveInterval = interval; this.scheduledTime = 0; cancel(); if (interval > 0) { schedule(delay); } } } public void userAttentionGained() { synchronized (this) { if (!userActive) { if (TRACE_ENABLED) { trace("User activity detected"); //$NON-NLS-1$ } this.userActive = true; // reset inactive interval each time the user becomes active this.inactiveInterval = interval; if (interval != 0) { if (System.currentTimeMillis() - lastSyncTime > interval) { // the last sync was long ago, sync right away cancel(); schedule(0); } else { reschedule(); } } } } } private void trace(String message) { System.err.println("[" + new Date() + "] " + message); //$NON-NLS-1$ //$NON-NLS-2$ } public void userAttentionLost() { synchronized (this) { this.userActive = false; } } synchronized void jobDone() { this.scheduledTime = 0; this.lastSyncTime = System.currentTimeMillis(); reschedule(); } public void dispose() { refreshJob.removeJobChangeListener(jobListener); refreshJob.cancel(); } }