|
Lines 83-91
Link Here
|
| 83 |
private ListenerList fUpdateListeners = new ListenerList(); |
83 |
private ListenerList fUpdateListeners = new ListenerList(); |
| 84 |
|
84 |
|
| 85 |
/** |
85 |
/** |
| 86 |
* List of updates in progress |
86 |
* Map of updates in progress: element path -> list of requests |
| 87 |
*/ |
87 |
*/ |
| 88 |
private List fUpdatesInProgress = new ArrayList(); |
88 |
private Map fRequestsInProgress = new HashMap(); |
|
|
89 |
|
| 90 |
/** |
| 91 |
* Map of dependent requests waiting for parent requests to complete: |
| 92 |
* element path -> list of requests |
| 93 |
*/ |
| 94 |
private Map fWaitingRequests = new HashMap(); |
| 89 |
|
95 |
|
| 90 |
/** |
96 |
/** |
| 91 |
* Map of viewer states keyed by viewer input mementos |
97 |
* Map of viewer states keyed by viewer input mementos |
|
Lines 164-173
Link Here
|
| 164 |
*/ |
170 |
*/ |
| 165 |
public synchronized void dispose() { |
171 |
public synchronized void dispose() { |
| 166 |
// cancel pending updates |
172 |
// cancel pending updates |
| 167 |
synchronized (fUpdatesInProgress) { |
173 |
synchronized (fRequestsInProgress) { |
| 168 |
Iterator iterator = fUpdatesInProgress.iterator(); |
174 |
Iterator iterator = fRequestsInProgress.values().iterator(); |
| 169 |
while (iterator.hasNext()) { |
175 |
while (iterator.hasNext()) { |
| 170 |
((IRequest) iterator.next()).cancel(); |
176 |
List requests = (List) iterator.next(); |
|
|
177 |
Iterator reqIter = requests.iterator(); |
| 178 |
while (reqIter.hasNext()) { |
| 179 |
((IRequest) reqIter.next()).cancel(); |
| 180 |
} |
| 171 |
} |
181 |
} |
| 172 |
} |
182 |
} |
| 173 |
fModelListeners.clear(); |
183 |
fModelListeners.clear(); |
|
Lines 797-802
Link Here
|
| 797 |
protected void unmapPath(TreePath path) { |
807 |
protected void unmapPath(TreePath path) { |
| 798 |
//System.out.println("Unmap " + path.getLastSegment()); |
808 |
//System.out.println("Unmap " + path.getLastSegment()); |
| 799 |
fTransform.clear(path); |
809 |
fTransform.clear(path); |
|
|
810 |
cancelSubtreeUpdates(path); |
| 800 |
} |
811 |
} |
| 801 |
|
812 |
|
| 802 |
/** |
813 |
/** |
|
Lines 845-853
Link Here
|
| 845 |
*/ |
856 |
*/ |
| 846 |
void updateStarted(IViewerUpdate update) { |
857 |
void updateStarted(IViewerUpdate update) { |
| 847 |
boolean begin = false; |
858 |
boolean begin = false; |
| 848 |
synchronized (fUpdatesInProgress) { |
859 |
synchronized (fRequestsInProgress) { |
| 849 |
begin = fUpdatesInProgress.isEmpty(); |
860 |
begin = fRequestsInProgress.isEmpty(); |
| 850 |
fUpdatesInProgress.add(update); |
861 |
List requests = (List) fRequestsInProgress.get(update.getElementPath()); |
|
|
862 |
if (requests == null) { |
| 863 |
requests = new ArrayList(); |
| 864 |
fRequestsInProgress.put(update.getElementPath(), requests); |
| 865 |
} |
| 866 |
requests.add(update); |
| 851 |
} |
867 |
} |
| 852 |
if (begin) { |
868 |
if (begin) { |
| 853 |
if (DEBUG_UPDATE_SEQUENCE) { |
869 |
if (DEBUG_UPDATE_SEQUENCE) { |
|
Lines 868-876
Link Here
|
| 868 |
*/ |
884 |
*/ |
| 869 |
void updateComplete(IViewerUpdate update) { |
885 |
void updateComplete(IViewerUpdate update) { |
| 870 |
boolean end = false; |
886 |
boolean end = false; |
| 871 |
synchronized (fUpdatesInProgress) { |
887 |
synchronized (fRequestsInProgress) { |
| 872 |
fUpdatesInProgress.remove(update); |
888 |
List requests = (List) fRequestsInProgress.get(update.getElementPath()); |
| 873 |
end = fUpdatesInProgress.isEmpty(); |
889 |
if (requests != null) { |
|
|
890 |
requests.remove(update); |
| 891 |
trigger(update); |
| 892 |
if (requests.isEmpty()) { |
| 893 |
fRequestsInProgress.remove(update.getElementPath()); |
| 894 |
} |
| 895 |
} |
| 896 |
end = fRequestsInProgress.isEmpty(); |
| 874 |
} |
897 |
} |
| 875 |
notifyUpdate(UPDATE_COMPLETE, update); |
898 |
notifyUpdate(UPDATE_COMPLETE, update); |
| 876 |
if (DEBUG_UPDATE_SEQUENCE) { |
899 |
if (DEBUG_UPDATE_SEQUENCE) { |
|
Lines 915-928
Link Here
|
| 915 |
} |
938 |
} |
| 916 |
|
939 |
|
| 917 |
protected void cancelSubtreeUpdates(TreePath path) { |
940 |
protected void cancelSubtreeUpdates(TreePath path) { |
| 918 |
synchronized (fUpdatesInProgress) { |
941 |
synchronized (fRequestsInProgress) { |
| 919 |
for (int i = 0; i < fUpdatesInProgress.size(); i++) { |
942 |
Iterator iterator = fRequestsInProgress.entrySet().iterator(); |
| 920 |
ViewerUpdateMonitor update = (ViewerUpdateMonitor) fUpdatesInProgress.get(i); |
943 |
while (iterator.hasNext()) { |
| 921 |
if (update.isContained(path)) { |
944 |
Entry entry = (Entry) iterator.next(); |
| 922 |
update.cancel(); |
945 |
TreePath entryPath = (TreePath) entry.getKey(); |
|
|
946 |
if (entryPath.startsWith(path, null)) { |
| 947 |
List requests = (List) entry.getValue(); |
| 948 |
Iterator reqIter = requests.iterator(); |
| 949 |
while (reqIter.hasNext()) { |
| 950 |
((IRequest)reqIter.next()).cancel(); |
| 951 |
} |
| 952 |
} |
| 953 |
} |
| 954 |
List purge = new ArrayList(); |
| 955 |
iterator = fWaitingRequests.keySet().iterator(); |
| 956 |
while (iterator.hasNext()) { |
| 957 |
TreePath entryPath = (TreePath) iterator.next(); |
| 958 |
if (entryPath.startsWith(path, null)) { |
| 959 |
purge.add(entryPath); |
| 923 |
} |
960 |
} |
| 924 |
} |
961 |
} |
|
|
962 |
iterator = purge.iterator(); |
| 963 |
while (iterator.hasNext()) { |
| 964 |
fWaitingRequests.remove(iterator.next()); |
| 965 |
} |
| 966 |
} |
| 967 |
} |
| 968 |
|
| 969 |
/** |
| 970 |
* Returns whether this given request should be run, or should wait for parent |
| 971 |
* update to complete. |
| 972 |
* |
| 973 |
* @param update |
| 974 |
* @return whether to start the given request |
| 975 |
*/ |
| 976 |
void schedule(ViewerUpdateMonitor update) { |
| 977 |
synchronized (fRequestsInProgress) { |
| 978 |
List requests = (List) fWaitingRequests.get(update.getElementPath()); |
| 979 |
if (requests == null) { |
| 980 |
// no waiting requests |
| 981 |
TreePath parentPath = update.getElementPath(); |
| 982 |
while (fRequestsInProgress.get(parentPath) == null) { |
| 983 |
parentPath = parentPath.getParentPath(); |
| 984 |
if (parentPath == null) { |
| 985 |
// no running requests: start request |
| 986 |
update.start(); |
| 987 |
return; |
| 988 |
} |
| 989 |
} |
| 990 |
// request running on parent, add to waiting list |
| 991 |
requests = new ArrayList(); |
| 992 |
fWaitingRequests.put(update.getElementPath(), requests); |
| 993 |
requests.add(update); |
| 994 |
} else { |
| 995 |
// there are waiting requests: coalesce with existing request? |
| 996 |
Iterator reqIter = requests.iterator(); |
| 997 |
while (reqIter.hasNext()) { |
| 998 |
ViewerUpdateMonitor waiting = (ViewerUpdateMonitor) reqIter.next(); |
| 999 |
if (waiting.coalesce(update)) { |
| 1000 |
// coalesced with existing request, done |
| 1001 |
return; |
| 1002 |
} |
| 1003 |
} |
| 1004 |
// add to list of waiting requests |
| 1005 |
requests.add(update); |
| 1006 |
return; |
| 1007 |
} |
| 1008 |
} |
| 1009 |
} |
| 1010 |
|
| 1011 |
/** |
| 1012 |
* Triggers waiting requests based on the given request that just completed. |
| 1013 |
* |
| 1014 |
* TODO: do we cancel updates if the request has been canceled? |
| 1015 |
* |
| 1016 |
* @param request |
| 1017 |
*/ |
| 1018 |
void trigger(IViewerUpdate request) { |
| 1019 |
if (fWaitingRequests.isEmpty()) { |
| 1020 |
return; |
| 1021 |
} |
| 1022 |
TreePath completedPath = request.getElementPath(); |
| 1023 |
List waiting = (List) fWaitingRequests.get(completedPath); |
| 1024 |
if (waiting != null && waiting.isEmpty()) { |
| 1025 |
// TODO: why does this happen |
| 1026 |
fWaitingRequests.remove(completedPath); |
| 1027 |
waiting = null; |
| 1028 |
} |
| 1029 |
if (waiting == null) { |
| 1030 |
// no waiting, update the entry with the shortest path |
| 1031 |
int length = Integer.MAX_VALUE; |
| 1032 |
Iterator entries = fWaitingRequests.entrySet().iterator(); |
| 1033 |
Entry candidate = null; |
| 1034 |
while (entries.hasNext()) { |
| 1035 |
Entry entry = (Entry) entries.next(); |
| 1036 |
TreePath key = (TreePath) entry.getKey(); |
| 1037 |
if (key.getSegmentCount() < length) { |
| 1038 |
candidate = entry; |
| 1039 |
length = key.getSegmentCount(); |
| 1040 |
} |
| 1041 |
} |
| 1042 |
if (candidate != null) { |
| 1043 |
startHighestPriorityRequest(completedPath, (List) candidate.getValue()); |
| 1044 |
} |
| 1045 |
} else { |
| 1046 |
// start the highest priority request |
| 1047 |
startHighestPriorityRequest(completedPath, waiting); |
| 1048 |
} |
| 1049 |
} |
| 1050 |
|
| 1051 |
/** |
| 1052 |
* @param completedPath |
| 1053 |
* @param waiting |
| 1054 |
*/ |
| 1055 |
private void startHighestPriorityRequest(TreePath completedPath, List waiting) { |
| 1056 |
if (waiting.isEmpty()) { |
| 1057 |
// TODO: this should not happen? |
| 1058 |
fWaitingRequests.remove(completedPath); |
| 1059 |
return; |
| 1060 |
} |
| 1061 |
int priority = 4; |
| 1062 |
ViewerUpdateMonitor next = null; |
| 1063 |
Iterator requests = waiting.iterator(); |
| 1064 |
while (requests.hasNext()) { |
| 1065 |
ViewerUpdateMonitor vu = (ViewerUpdateMonitor) requests.next(); |
| 1066 |
if (vu.getPriority() < priority) { |
| 1067 |
next = vu; |
| 1068 |
priority = next.getPriority(); |
| 1069 |
} |
| 1070 |
} |
| 1071 |
waiting.remove(next); |
| 1072 |
if (waiting.isEmpty()) { |
| 1073 |
fWaitingRequests.remove(completedPath); |
| 925 |
} |
1074 |
} |
|
|
1075 |
next.start(); |
| 926 |
} |
1076 |
} |
| 927 |
|
1077 |
|
| 928 |
/** |
1078 |
/** |