/* * Copyright 2010-2013 Institut Pasteur. * * This file is part of Icy. * * Icy 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 3 of the License, or * (at your option) any later version. * * Icy 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. * * You should have received a copy of the GNU General Public License * along with Icy. If not, see <http://www.gnu.org/licenses/>. */ package icy.common; import icy.common.listener.ChangeListener; import icy.system.thread.ThreadUtil; import java.util.ArrayList; import java.util.List; /** * @author stephane */ public class UpdateEventHandler { ChangeListener parent; /** * dispatch in AWT dispatch thread */ private boolean awtDispatch; /** * internal update counter */ private int updateCnt; /** * internal pending change events */ private final List<EventHierarchicalChecker> pendingChanges; /** * */ public UpdateEventHandler(ChangeListener parent, boolean awtDispatch) { super(); this.parent = parent; this.awtDispatch = awtDispatch; updateCnt = 0; pendingChanges = new ArrayList<EventHierarchicalChecker>(); } /** * */ public UpdateEventHandler(ChangeListener parent) { this(parent, false); } /** * @return the awtDispatch */ public boolean isAwtDispatch() { return awtDispatch; } /** * @param awtDispatch * the awtDispatch to set */ public void setAwtDispatch(boolean awtDispatch) { this.awtDispatch = awtDispatch; } public List<EventHierarchicalChecker> getPendingChanges() { return pendingChanges; } public void beginUpdate() { updateCnt++; } public void endUpdate() { updateCnt--; if (updateCnt <= 0) { boolean done = false; // fire pending events while (!done) { final EventHierarchicalChecker compare; synchronized (pendingChanges) { // check and remove it from list done = pendingChanges.isEmpty(); if (!done) compare = pendingChanges.remove(0); else compare = null; } // and then process (avoid some dead lock) if (compare != null) dispatchOnChanged(compare); } } } public boolean isUpdating() { return updateCnt > 0; } public boolean hasPendingChanges() { return !pendingChanges.isEmpty(); } protected void addPendingChange(EventHierarchicalChecker include) { synchronized (pendingChanges) { // test if we already have an including object in the list for (EventHierarchicalChecker cmp : pendingChanges) if (cmp.isEventRedundantWith(include)) return; // we add it only if it isn't already existing pendingChanges.add(include); } } public void changed(EventHierarchicalChecker include) { if (isUpdating()) addPendingChange(include); else dispatchOnChanged(include); } protected void dispatchOnChanged(EventHierarchicalChecker include) { final EventHierarchicalChecker event = include; if (awtDispatch) { // dispatch on AWT Dispatch Thread now ThreadUtil.invokeNow(new Runnable() { @Override public void run() { parent.onChanged(event); } }); } else parent.onChanged(event); } }