⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 concurrenttableupdator.java

📁 jfa2ce 源码帮助开发人员更好的理解运用
💻 JAVA
字号:
/******************************************************************************* * Copyright (c) 2004, 2006 IBM Corporation 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: *     IBM Corporation - initial API and implementation *******************************************************************************/package org.eclipse.jface.viewers.deferred;/** * Allows a table to be accessed from a background thread. Provides a table-like public  * interface that can accessed from a background thread. As updates arrive from the  * background thread, it batches and schedules updates to the real table in the UI thread.  * This class can be used with any widget that can be wrapped in the  * <code>AbstractVirtualTable</code> interface.   *  * @since 3.1 *//* package */ final class ConcurrentTableUpdator {	/**	 * Wrapper for the real table. May only be accessed in the UI thread.	 */    private AbstractVirtualTable table;        /**     * The array of objects that have been sent to the UI. Elements are null     * if they either haven't been sent yet or have been scheduled for clear.      * Maps indices onto elements.     */    private Object[] sentObjects = new Object[0];        /**     * Map of elements to object indices (inverse of the knownObjects array)     */    private IntHashMap knownIndices = new IntHashMap();        /**     * Contains all known objects that have been sent here from the background     * thread.     */    private Object[] knownObjects = new Object[0];        // Minimum length for the pendingFlushes stack    private static final int MIN_FLUSHLENGTH = 64;        /**     * Array of element indices. Contains elements scheduled to be     * cleared. Only the beginning of the array is used. The number     * of used elements is stored in lastClear     */    private int[] pendingClears = new int[MIN_FLUSHLENGTH];        /**     * Number of pending clears in the pendingClears array (this is normally     * used instead of pendingClears.length since the      * pendingClears array is usually larger than the actual number of pending     * clears)      */    private int lastClear = 0;        /**     * Last known visible range     */        private volatile Range lastRange = new Range(0,0);        /**     * True iff a UI update has been scheduled     */    private volatile boolean updateScheduled;        /**     * True iff this object has been disposed     */    private volatile boolean disposed = false;        /**     * Object that holds a start index and length. Allows     * the visible range to be returned as an atomic operation.     */    public final static class Range {        int start = 0;        int length = 0;                public Range(int s, int l) {            start = s;            length = l;        }    }        /**     * Runnable that can be posted with an asyncExec to schedule     * an update to the real table.       */    Runnable uiRunnable = new Runnable() {        public void run() {            updateScheduled = false;            if(!table.getControl().isDisposed()) {				updateTable();			}        }    };        /**     * Creates a new table updator     *      * @param table real table to update     */    public ConcurrentTableUpdator(AbstractVirtualTable table) {        this.table = table;    }        /**     * Cleans up the updator object (but not the table itself).     */    public void dispose() {    	disposed = true;    }        /**     * True iff this object has been disposed.      *      * @return true iff dispose() has been called     */    public boolean isDisposed() {    	return disposed;    }        /**     * Returns the currently visible range     *      * @return the currently visible range     */    public Range getVisibleRange() {    	return lastRange;    }        /**     * Marks the given object as dirty. Will cause it to be cleared     * in the table.      *      * @param toFlush     */    public void clear(Object toFlush) {        synchronized(this) {            int currentIdx = knownIndices.get(toFlush, -1);            // If we've never heard of this object, bail out.            if (currentIdx == -1) {                return;            }            pushClear(currentIdx);        }            }        /**     * Sets the size of the table. Called from a background thread.     *      * @param newTotal     */    public void setTotalItems(int newTotal) {        synchronized (this) {            if (newTotal != knownObjects.length) {                if (newTotal < knownObjects.length) {                    // Flush any objects that are being removed as a result of the resize                    for (int i = newTotal; i < knownObjects.length; i++) {                        Object toFlush = knownObjects[i];                                                if (toFlush != null) {                        	knownIndices.remove(toFlush);                        }                    }                }                                int minSize = Math.min(knownObjects.length, newTotal);                	            Object[] newKnownObjects = new Object[newTotal];	            System.arraycopy(knownObjects, 0, newKnownObjects, 0, minSize);	            knownObjects = newKnownObjects;	            	            	            scheduleUIUpdate();            }        }    }        /**     * Pushes an index onto the clear stack     *      * @param toClear row to clear     */    private void pushClear(int toClear) {            	// If beyond the end of the table    	if (toClear >= sentObjects.length) {    		return;    	}    	    	// If already flushed or never sent        if (sentObjects[toClear] == null) {        	return;                    }        // Mark as flushed        sentObjects[toClear] = null;    	        if (lastClear >= pendingClears.length) {            int newCapacity = Math.min(MIN_FLUSHLENGTH, lastClear * 2);            int[] newPendingClears = new int[newCapacity];            System.arraycopy(pendingClears, 0, newPendingClears, 0, lastClear);            pendingClears = newPendingClears;        }                pendingClears[lastClear++] = toClear;    }        /**     * Sets the item on the given row to the given value. May be called from a background     * thread. Schedules a UI update if necessary     *      * @param idx row to change     * @param value new value for the given row     */    public void replace(Object value, int idx) {                // Keep the synchronized block as small as possible, since the UI may        // be waiting on it.        synchronized(this) {            Object oldObject = knownObjects[idx];                        if (oldObject != value) {            	if (oldObject != null) {            		knownIndices.remove(oldObject);            	}            	                knownObjects[idx] = value;                            	if (value != null) {	        		int oldIndex = knownIndices.get(value, -1);	        		if (oldIndex != -1) {	        			knownObjects[oldIndex] = null;	        			pushClear(oldIndex);	        		}	        			        		knownIndices.put(value, idx);            	}                                pushClear(idx);                                scheduleUIUpdate();            }        }     }    /**     * Schedules a UI update. Has no effect if an update has already been     * scheduled.     */    private void scheduleUIUpdate() {        synchronized(this) {	        if (!updateScheduled) {	            updateScheduled = true;	            if(!table.getControl().isDisposed()) {					table.getControl().getDisplay().asyncExec(uiRunnable);				}	        }        }    }            /**     * Called in the UI thread by a SetData callback. Refreshes the     * table if necessary. Returns true iff a refresh is needed.     * @param includeIndex the index that should be included in the visible range.     */    public void checkVisibleRange(int includeIndex) {        int start = Math.min(table.getTopIndex() - 1, includeIndex);        int length = Math.max(table.getVisibleItemCount(), includeIndex - start);        Range r = lastRange;    	if (start != r.start || length != r.length) {    		updateTable();    	}    }        /**     * Updates the table. Sends any unsent items in the visible range to the table,     * and clears any previously-visible items that have not yet been sent to the table.     * Must be called from the UI thread.     */    private void updateTable() {    	                synchronized(this) {        	// Resize the table if necessary	        if (sentObjects.length != knownObjects.length) {	        	Object[] newSentObjects = new Object[knownObjects.length];	        	System.arraycopy(newSentObjects, 0, sentObjects, 0, 	        			Math.min(newSentObjects.length, sentObjects.length));	        	sentObjects = newSentObjects;	            table.setItemCount(newSentObjects.length);	        }	        // Compute the currently visible range	        int start = Math.min(table.getTopIndex(), knownObjects.length);	        int length = Math.min(table.getVisibleItemCount(), knownObjects.length - start);	        int itemCount = table.getItemCount();                    	int oldStart = lastRange.start;        	int oldLen = lastRange.length;        	        	// Store the visible range. Do it BEFORE sending any table.clear calls,        	// since clearing a visible row will result in a SetData callback which        	// cause another table update if the visible range is different from        	// the stored values -- this could cause infinite recursion.        	lastRange = new Range(start, length);        				// Re-clear any items in the old range that were never filled in			for(int idx = 0; idx < oldLen; idx++) {				int row = idx + oldStart;								// If this item is no longer visible				if (row < itemCount && (row < start || row >= start + length)) {										// Note: if we wanted to be really aggressive about clearing					// items that are no longer visible, we could clear here unconditionally.					// The current way of doing things won't clear a row if its contents are					// up-to-date.					if (sentObjects[row] == null) {						table.clear(row);					}				}			}						// Process any pending clears	        if (lastClear > 0) {				for (int i = 0; i < lastClear; i++) {					int row = pendingClears[i];							if (row < sentObjects.length) {						table.clear(row);					}				}					if (pendingClears.length > MIN_FLUSHLENGTH) {					pendingClears = new int[MIN_FLUSHLENGTH];				}				lastClear = 0;	        }		    	        // Send any unsent items in the visible range	        for (int idx = 0; idx < length; idx++) {	        	int row = idx + start;	        		        	Object obj = knownObjects[row];	        	if (obj != null && obj != sentObjects[idx]) {	        		table.replace(obj, row);	        		sentObjects[idx] = obj;	        	}	        }	                }    }	/**	 * Return the array of all known objects that have been sent here from the background     * thread.	 * @return the array of all known objects	 */	public Object[] getKnownObjects() {		return knownObjects;	}    }

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -