/******************************************************************************* * Copyright (c) 2008 Olivier Moises * * 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: * Olivier Moises- initial API and implementation *******************************************************************************/ package org.eclipse.wazaabi.engine.swt.commons.views; import java.util.ArrayList; import java.util.List; import org.eclipse.swt.SWT; import org.eclipse.swt.SWTException; import org.eclipse.swt.widgets.Display; import org.eclipse.wazaabi.engine.core.views.WidgetView; /** * An UpdateManager that asynchronously updates the affected figures. */ public class DeferredUpdateManager extends UpdateManager { /** * Calls {@link DeferredUpdateManager#performUpdate()}. */ protected class UpdateRequest implements Runnable { public UpdateRequest() { super(); } /** * Calls {@link DeferredUpdateManager#performUpdate()}. */ public void run() { performUpdate(); } } private List<WidgetView> invalidFigures = new ArrayList<WidgetView>(); private boolean updateQueued; private boolean updating; private boolean validating; private RunnableChain afterUpdate; private static class RunnableChain { RunnableChain next; Runnable run; RunnableChain(Runnable run, RunnableChain next) { this.run = run; this.next = next; } void run() { if (next != null) next.run(); run.run(); } } /** * Empty constructor. */ public DeferredUpdateManager() { } /** * Adds the given figure to the update queue. Invalid figures will be * validated before the damaged regions are repainted. * * @param f * the invalid figure */ public synchronized void addInvalidFigure(WidgetView f) { if (invalidFigures.contains(f)) return; queueWork(); invalidFigures.add(f); } /** * Performs the update. Validates the invalid figures and then repaints the * dirty regions. * * @see #validateFigures() * @see #repairDamage() */ public synchronized void performUpdate() { if (isDisposed() || updating) return; updating = true; try { performValidation(); updateQueued = false; if (afterUpdate != null) { RunnableChain chain = afterUpdate; afterUpdate = null; chain.run(); // chain may queue additional Runnable. if (afterUpdate != null) queueWork(); } } finally { updating = false; } } /** * @see UpdateManager#performValidation() */ public void performValidation() { if (invalidFigures.isEmpty() || validating) return; try { WidgetView fig; validating = true; fireValidating(); for (int i = 0; i < invalidFigures.size(); i++) { fig = (WidgetView) invalidFigures.get(i); invalidFigures.set(i, null); fig.validate(); } } finally { invalidFigures.clear(); validating = false; } } /** * Posts an {@link UpdateRequest} using {@link Display#asyncExec(Runnable)}. * If work has already been queued, a new request is not needed. */ protected void queueWork() { if (!updateQueued) { sendUpdateRequest(); updateQueued = true; } } /** * Fires the <code>UpdateRequest</code> to the current display * asynchronously. * * @since 3.2 */ protected void sendUpdateRequest() { Display display = Display.getCurrent(); if (display == null) { throw new SWTException(SWT.ERROR_THREAD_INVALID_ACCESS); } display.asyncExec(new UpdateRequest()); } /** * Adds the given runnable and queues an update if an update is not under * progress. * * @param runnable * the runnable */ public synchronized void runWithUpdate(Runnable runnable) { afterUpdate = new RunnableChain(runnable, afterUpdate); if (!updating) queueWork(); } /** * Validates all invalid figures on the update queue and calls * {@link UpdateManager#fireValidating()} unless there are no invalid * figures. */ protected void validateFigures() { performValidation(); } }