Issue #3045 - Change to prevent race conditions while getting table labels.
Change-Id: I82d0ab9deaa2b2b89a859fcb76af5d5cd7692120 Former-commit-id:e2b03eb190
[formerly9dad4c959b
] [formerly2a0a9b5334
[formerly 17a06743e41fe6bf15a895d9842bb51d99901602]] Former-commit-id:2a0a9b5334
Former-commit-id:d73f61c7e7
This commit is contained in:
parent
f9b04639a4
commit
ef81949dd1
7 changed files with 412 additions and 143 deletions
|
@ -0,0 +1,44 @@
|
|||
/**
|
||||
* This software was developed and / or modified by Raytheon Company,
|
||||
* pursuant to Contract DG133W-05-CQ-1067 with the US Government.
|
||||
*
|
||||
* U.S. EXPORT CONTROLLED TECHNICAL DATA
|
||||
* This software product contains export-restricted data whose
|
||||
* export/transfer/disclosure is restricted by U.S. law. Dissemination
|
||||
* to non-U.S. persons whether in the United States or abroad requires
|
||||
* an export license or other authorization.
|
||||
*
|
||||
* Contractor Name: Raytheon Company
|
||||
* Contractor Address: 6825 Pine Street, Suite 340
|
||||
* Mail Stop B8
|
||||
* Omaha, NE 68106
|
||||
* 402.291.0100
|
||||
*
|
||||
* See the AWIPS II Master Rights File ("Master Rights File.pdf") for
|
||||
* further licensing information.
|
||||
**/
|
||||
package com.raytheon.uf.viz.archive.data;
|
||||
|
||||
/**
|
||||
* A listener to notify when SizeJob has obtain all display data.
|
||||
*
|
||||
* <pre>
|
||||
*
|
||||
* SOFTWARE HISTORY
|
||||
*
|
||||
* Date Ticket# Engineer Description
|
||||
* ------------ ---------- ----------- --------------------------
|
||||
* Apr 23, 2014 3045 rferrel Initial creation
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
* @author rferrel
|
||||
* @version 1.0
|
||||
*/
|
||||
public interface ILoadDisplayDataListener {
|
||||
/**
|
||||
* Called by SizeJob after obtaining all display data for all
|
||||
* archive/category tables.
|
||||
*/
|
||||
public void loadedAllDisplayData();
|
||||
}
|
|
@ -52,6 +52,7 @@ import com.raytheon.uf.common.time.util.TimeUtil;
|
|||
* Dec 11, 2013 #2603 rferrel Selected list changed to a Set.
|
||||
* Dec 11, 2013 #2624 rferrel Clear display variables when recomputing sizes.
|
||||
* Mar 27, 2014 #2879 rferrel Loading Case no longer changes Start/End times.
|
||||
* Apr 23, 2014 #3045 rferrel Changes to prevent race condition while getting labels.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -156,17 +157,17 @@ public class SizeJob extends Job {
|
|||
private boolean stopComputeSize;
|
||||
|
||||
/**
|
||||
* Priority queue for getting display data for an archive/category.
|
||||
* Priority queue for getting display data all archive/category tables.
|
||||
*/
|
||||
// Do not use a PriorityBlockingQueue since the load select and change
|
||||
// display methods need to be notified when the display data is available.
|
||||
private final PriorityQueue<MissingData> missingDataQueue = new PriorityQueue<SizeJob.MissingData>(
|
||||
DEFAULT_INITIAL_CAPACITY, new Comparator<MissingData>() {
|
||||
private final PriorityQueue<LoadDisplayData> loadDisplayDataQueue = new PriorityQueue<SizeJob.LoadDisplayData>(
|
||||
DEFAULT_INITIAL_CAPACITY, new Comparator<LoadDisplayData>() {
|
||||
|
||||
@Override
|
||||
public int compare(MissingData o1, MissingData o2) {
|
||||
if (o1.visiable != o2.visiable) {
|
||||
return o1.visiable ? -1 : +1;
|
||||
public int compare(LoadDisplayData o1, LoadDisplayData o2) {
|
||||
if (o1.visible != o2.visible) {
|
||||
return o1.visible ? -1 : +1;
|
||||
}
|
||||
if (o1.isSelected() != o2.isSelected()) {
|
||||
return o1.isSelected() ? -1 : +1;
|
||||
|
@ -182,16 +183,22 @@ public class SizeJob extends Job {
|
|||
});
|
||||
|
||||
/**
|
||||
* Job for processing the missing data queue.
|
||||
* Job for obtaining display data for all the archive/category tables.
|
||||
*/
|
||||
private final MissingDataJob missingDataJob = new MissingDataJob();
|
||||
private LoadDisplayDataJob loadDisplayDataJob;
|
||||
|
||||
/**
|
||||
* Listener to invoke when all display data loaded.
|
||||
*/
|
||||
private final ILoadDisplayDataListener loadDisplayDataListener;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
public SizeJob() {
|
||||
public SizeJob(ILoadDisplayDataListener loadDisplayDataListener) {
|
||||
super("Size Job");
|
||||
setSystem(true);
|
||||
this.loadDisplayDataListener = loadDisplayDataListener;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -285,9 +292,11 @@ public class SizeJob extends Job {
|
|||
* Check all displayData selection state so only the data in selections are
|
||||
* set.
|
||||
*
|
||||
* @param selections
|
||||
* @param selectName
|
||||
* @param type
|
||||
* @return errorMessage when unable to load else null
|
||||
*/
|
||||
public void loadSelect(String selectName, ArchiveConstants.Type type) {
|
||||
public String loadSelect(String selectName, ArchiveConstants.Type type) {
|
||||
ArchiveConfigManager manager = ArchiveConfigManager.getInstance();
|
||||
String fileName = ArchiveConstants.selectFileName(type, selectName);
|
||||
SelectConfig selections = manager.loadSelection(fileName);
|
||||
|
@ -301,24 +310,18 @@ public class SizeJob extends Job {
|
|||
for (String categoryName : archiveInfo.getCategoryNames()) {
|
||||
Set<String> selectionsSet = selections.getSelectedSet(
|
||||
archiveName, categoryName);
|
||||
MissingData missingData = removeMissingData(archiveName,
|
||||
categoryName);
|
||||
if (missingData != null) {
|
||||
missingData.setSelectedSet(selectionsSet);
|
||||
addMissingData(missingData);
|
||||
} else {
|
||||
CategoryInfo categoryInfo = archiveInfo.get(categoryName);
|
||||
for (DisplayData displayData : categoryInfo
|
||||
.getDisplayDataList()) {
|
||||
String displayLabel = displayData.getDisplayLabel();
|
||||
boolean selected = selectionsSet.contains(displayLabel);
|
||||
if (selected != displayData.isSelected()) {
|
||||
setSelect(displayData, selected);
|
||||
}
|
||||
CategoryInfo categoryInfo = archiveInfo.get(categoryName);
|
||||
for (DisplayData displayData : categoryInfo
|
||||
.getDisplayDataList()) {
|
||||
String displayLabel = displayData.getDisplayLabel();
|
||||
boolean selected = selectionsSet.contains(displayLabel);
|
||||
if (selected != displayData.isSelected()) {
|
||||
setSelect(displayData, selected);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -327,10 +330,13 @@ public class SizeJob extends Job {
|
|||
* @return selected
|
||||
*/
|
||||
public List<DisplayData> getSelectAll() {
|
||||
synchronized (missingDataQueue) {
|
||||
while (!missingDataQueue.isEmpty()) {
|
||||
if (missingDataJob.currentMissingData == null
|
||||
|| missingDataJob.currentMissingData.isSelected()) {
|
||||
synchronized (loadDisplayDataQueue) {
|
||||
while (!loadDisplayDataQueue.isEmpty()) {
|
||||
if ((loadDisplayDataJob.currentLoadDisplayData == null)
|
||||
|| loadDisplayDataJob.currentLoadDisplayData
|
||||
.isVisible()
|
||||
|| loadDisplayDataJob.currentLoadDisplayData
|
||||
.isSelected()) {
|
||||
missingDataQueueWait();
|
||||
} else {
|
||||
break;
|
||||
|
@ -440,33 +446,81 @@ public class SizeJob extends Job {
|
|||
}
|
||||
|
||||
/**
|
||||
* Change the archive/category display.
|
||||
*
|
||||
* @param archiveName
|
||||
* - non null value
|
||||
* @param categoryName
|
||||
* @return displayData when display needs to change otherwise null
|
||||
* - non null value
|
||||
* @return true if archiveName and categoryName match the current display
|
||||
*/
|
||||
public boolean isCurrentDisplay(String archiveName, String categoryName) {
|
||||
return archiveName.equals(displayArchive)
|
||||
&& categoryName.equals(displayCategory);
|
||||
}
|
||||
|
||||
/**
|
||||
* This method returns a display data list to replace the contents of the
|
||||
* GUI's achive/category display table or a null list if no update is
|
||||
* needed. It is assumed this method is called from an non-UI thread.
|
||||
*
|
||||
* @param archiveName
|
||||
* - archive for the new display table
|
||||
* @param categoryName
|
||||
* - category for the new display table
|
||||
* @param shutdown
|
||||
* - Becomes true when user requests a different table while this
|
||||
* is waiting for data.
|
||||
* @return displayData
|
||||
*/
|
||||
public List<DisplayData> changeDisplay(String archiveName,
|
||||
String categoryName) {
|
||||
String categoryName, AtomicBoolean shutdown) {
|
||||
List<DisplayData> displayDatas = null;
|
||||
|
||||
// Only get data when the display really needs to be changed.
|
||||
if (!archiveName.equals(displayArchive)
|
||||
|| !categoryName.equals(displayCategory)) {
|
||||
MissingData missingData = removeMissingData(archiveName,
|
||||
|
||||
// Update visible status of current display.
|
||||
if ((displayArchive != null) && (displayCategory != null)) {
|
||||
LoadDisplayData currentMissingData = removeLoadDisplayData(
|
||||
displayArchive, displayCategory);
|
||||
if (currentMissingData != null) {
|
||||
currentMissingData.setVisible(false);
|
||||
addLoadDisplayData(currentMissingData);
|
||||
}
|
||||
}
|
||||
|
||||
LoadDisplayData missingData = removeLoadDisplayData(archiveName,
|
||||
categoryName);
|
||||
displayArchive = archiveName;
|
||||
displayCategory = categoryName;
|
||||
|
||||
// Update visible status of the new current display.
|
||||
if (missingData != null) {
|
||||
missingData.setVisiable(true);
|
||||
synchronized (missingDataQueue) {
|
||||
addMissingData(missingData);
|
||||
while (missingDataQueue.contains(missingData)) {
|
||||
missingDataQueueWait();
|
||||
synchronized (loadDisplayDataQueue) {
|
||||
missingData.setVisible(true);
|
||||
addLoadDisplayData(missingData);
|
||||
|
||||
/*
|
||||
* Wait for the display data to be loaded or no longer
|
||||
* needed.
|
||||
*/
|
||||
while (loadDisplayDataJob.processing(missingData)
|
||||
&& !shutdown.get()) {
|
||||
missingDataQueueWait(500L);
|
||||
}
|
||||
}
|
||||
}
|
||||
displayDatas = archiveInfoMap.get(archiveName).get(categoryName)
|
||||
.getDisplayDataList();
|
||||
displayArchive = archiveName;
|
||||
displayCategory = categoryName;
|
||||
changeDisplay(displayDatas);
|
||||
|
||||
/*
|
||||
* If user still needs the data update status of old visible data
|
||||
* and the new visible data.
|
||||
*/
|
||||
if (!shutdown.get()) {
|
||||
displayDatas = archiveInfoMap.get(archiveName)
|
||||
.get(categoryName).getDisplayDataList();
|
||||
changeDisplay(displayDatas);
|
||||
}
|
||||
}
|
||||
return displayDatas;
|
||||
}
|
||||
|
@ -474,7 +528,7 @@ public class SizeJob extends Job {
|
|||
/**
|
||||
* Change to display all selected data..
|
||||
*
|
||||
* @return displayhData when display needs to change otherwise null.
|
||||
* @return displayData when display needs to change otherwise null.
|
||||
*/
|
||||
public List<DisplayData> changeDisplayAll() {
|
||||
List<DisplayData> selectedData = null;
|
||||
|
@ -499,7 +553,7 @@ public class SizeJob extends Job {
|
|||
}
|
||||
iRetentionHour.setRetentionTimes(selections.getStarRetentionHours());
|
||||
|
||||
missingDataQueue.clear();
|
||||
loadDisplayDataQueue.clear();
|
||||
|
||||
visibleList = manager.getDisplayData(displayArchive, displayCategory,
|
||||
false);
|
||||
|
@ -527,51 +581,48 @@ public class SizeJob extends Job {
|
|||
} else {
|
||||
selectedSet = selections.getSelectedSet(archiveName,
|
||||
categoryName);
|
||||
MissingData missingData = new MissingData(archiveName,
|
||||
categoryName, selectedSet);
|
||||
missingDataQueue.add(missingData);
|
||||
LoadDisplayData missingData = new LoadDisplayData(
|
||||
archiveName, categoryName, selectedSet);
|
||||
loadDisplayDataQueue.add(missingData);
|
||||
}
|
||||
}
|
||||
put(archiveName, archiveInfo);
|
||||
}
|
||||
|
||||
missingDataJob.schedule();
|
||||
loadDisplayDataJob = new LoadDisplayDataJob(loadDisplayDataListener,
|
||||
loadDisplayDataQueue.size());
|
||||
|
||||
loadDisplayDataJob.schedule();
|
||||
|
||||
return selections.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Find and remove the missing data from the missing data queue.
|
||||
* Find and remove the associated load display data from the queue.
|
||||
*
|
||||
* @param archiveName
|
||||
* @param categoryName
|
||||
* @return missingData or null if not on the missing data queue
|
||||
* @return loadDisplayData or null if no longer on the queue
|
||||
*/
|
||||
private MissingData removeMissingData(String archiveName,
|
||||
private LoadDisplayData removeLoadDisplayData(String archiveName,
|
||||
String categoryName) {
|
||||
MissingData missingData = null;
|
||||
synchronized (missingDataQueue) {
|
||||
if (missingDataJob.currentMissingData != null
|
||||
&& archiveName
|
||||
.equals(missingDataJob.currentMissingData.archive)
|
||||
&& categoryName
|
||||
.equals(missingDataJob.currentMissingData.category)) {
|
||||
// Finish the process of getting the data.
|
||||
missingDataQueueWait();
|
||||
} else if (!missingDataQueue.isEmpty()) {
|
||||
Iterator<MissingData> iterator = missingDataQueue.iterator();
|
||||
LoadDisplayData loadDisplayData = null;
|
||||
synchronized (loadDisplayDataQueue) {
|
||||
if (!loadDisplayDataQueue.isEmpty()) {
|
||||
Iterator<LoadDisplayData> iterator = loadDisplayDataQueue
|
||||
.iterator();
|
||||
while (iterator.hasNext()) {
|
||||
MissingData md = iterator.next();
|
||||
LoadDisplayData md = iterator.next();
|
||||
if (md.archive.equals(archiveName)
|
||||
&& md.category.equals(categoryName)) {
|
||||
iterator.remove();
|
||||
missingData = md;
|
||||
loadDisplayData = md;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return missingData;
|
||||
return loadDisplayData;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -580,9 +631,20 @@ public class SizeJob extends Job {
|
|||
* @return false when interrupted exception
|
||||
*/
|
||||
private boolean missingDataQueueWait() {
|
||||
return missingDataQueueWait(0L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wait for notification that the current missing data is finished
|
||||
* processing or the desired time has lapsed.
|
||||
*
|
||||
* @param time
|
||||
* @return false when interrupted exception
|
||||
*/
|
||||
private boolean missingDataQueueWait(long time) {
|
||||
boolean state = true;
|
||||
try {
|
||||
missingDataQueue.wait();
|
||||
loadDisplayDataQueue.wait(time);
|
||||
} catch (InterruptedException e) {
|
||||
state = false;
|
||||
statusHandler.handle(Priority.INFO, e.getLocalizedMessage(), e);
|
||||
|
@ -591,32 +653,30 @@ public class SizeJob extends Job {
|
|||
}
|
||||
|
||||
/**
|
||||
* This inserts a load display data onto the queue. Should
|
||||
*
|
||||
* @param missingData
|
||||
* @param loadDisplayData
|
||||
*/
|
||||
private void addMissingData(MissingData missingData) {
|
||||
synchronized (missingDataQueue) {
|
||||
missingDataQueue.add(missingData);
|
||||
if (missingDataJob.getState() == Job.NONE) {
|
||||
missingDataJob.schedule();
|
||||
private void addLoadDisplayData(LoadDisplayData loadDisplayData) {
|
||||
synchronized (loadDisplayDataQueue) {
|
||||
loadDisplayDataQueue.add(loadDisplayData);
|
||||
if (loadDisplayDataJob.getState() == Job.NONE) {
|
||||
loadDisplayDataJob.schedule();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Change update visible to the new list.
|
||||
* Change visible status to reflect the new list.
|
||||
*
|
||||
* @param newDisplays
|
||||
*/
|
||||
private void changeDisplay(List<DisplayData> newDisplays) {
|
||||
List<DisplayData> oldDisplays = visibleList;
|
||||
visibleList = newDisplays;
|
||||
List<DisplayData> visibleList = new ArrayList<DisplayData>(newDisplays);
|
||||
|
||||
for (DisplayData displayData : oldDisplays) {
|
||||
if (!visibleList.remove(displayData)) {
|
||||
setVisible(displayData, false);
|
||||
}
|
||||
setVisible(displayData, false);
|
||||
}
|
||||
|
||||
for (DisplayData displayData : visibleList) {
|
||||
|
@ -761,25 +821,25 @@ public class SizeJob extends Job {
|
|||
@Override
|
||||
protected void canceling() {
|
||||
clearQueue();
|
||||
missingDataQueue.clear();
|
||||
missingDataJob.cancel();
|
||||
loadDisplayDataQueue.clear();
|
||||
loadDisplayDataJob.cancel();
|
||||
shutdown.set(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Class used by the missing data job to obtain display data for given
|
||||
* archive/category off the UI thread.
|
||||
* Class used to track missing display data for the archive/category tables.
|
||||
* Allowing the information to be retrieved in a non-UI thread.
|
||||
*/
|
||||
private static class MissingData {
|
||||
private static class LoadDisplayData {
|
||||
protected final String archive;
|
||||
|
||||
protected final String category;
|
||||
|
||||
protected final Set<String> selectedSet;
|
||||
|
||||
protected boolean visiable = false;
|
||||
protected boolean visible = false;
|
||||
|
||||
public MissingData(String archive, String category,
|
||||
public LoadDisplayData(String archive, String category,
|
||||
Set<String> selectedSet) {
|
||||
this.archive = archive;
|
||||
this.category = category;
|
||||
|
@ -790,21 +850,20 @@ public class SizeJob extends Job {
|
|||
return !selectedSet.isEmpty();
|
||||
}
|
||||
|
||||
public void setVisiable(boolean state) {
|
||||
this.visiable = state;
|
||||
public boolean isVisible() {
|
||||
return visible;
|
||||
}
|
||||
|
||||
public void setSelectedSet(Set<String> selectedSet) {
|
||||
this.selectedSet.clear();
|
||||
this.selectedSet.addAll(selectedSet);
|
||||
public void setVisible(boolean state) {
|
||||
this.visible = state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("MissingData[");
|
||||
StringBuilder sb = new StringBuilder("LoadDisplayData[");
|
||||
sb.append("archive: ").append(archive);
|
||||
sb.append(", category: ").append(category);
|
||||
sb.append(", visible: ").append(visiable);
|
||||
sb.append(", visible: ").append(isVisible());
|
||||
sb.append(", isSelected: ").append(isSelected());
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
|
@ -815,14 +874,34 @@ public class SizeJob extends Job {
|
|||
* This handles getting the display data in the missing data queue and
|
||||
* queuing the results for the size job.
|
||||
*/
|
||||
private class MissingDataJob extends Job {
|
||||
private class LoadDisplayDataJob extends Job {
|
||||
|
||||
private final AtomicBoolean shutdown = new AtomicBoolean(false);
|
||||
|
||||
protected MissingData currentMissingData = null;
|
||||
protected LoadDisplayData currentLoadDisplayData = null;
|
||||
|
||||
public MissingDataJob() {
|
||||
super("MissingData");
|
||||
private final ILoadDisplayDataListener loadDisplayDataListener;
|
||||
|
||||
/**
|
||||
* Must be set to the maximum number of LoadDisplayData to process.
|
||||
* Cannot use the queue size since adjusting the queue to change the
|
||||
* priority may make its size 0. This could cause the job to be
|
||||
* rescheduled to finish when data added back onto the queue.
|
||||
*/
|
||||
private int loadDisplayDataCnt;
|
||||
|
||||
/**
|
||||
* The constructor.
|
||||
*
|
||||
* @param loadDisplayDataListener
|
||||
* @param loadDisplayDataCnt
|
||||
*/
|
||||
public LoadDisplayDataJob(
|
||||
ILoadDisplayDataListener loadDisplayDataListener,
|
||||
int loadDisplayDataCnt) {
|
||||
super("Loading Category labels");
|
||||
this.loadDisplayDataListener = loadDisplayDataListener;
|
||||
this.loadDisplayDataCnt = loadDisplayDataCnt;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -834,20 +913,21 @@ public class SizeJob extends Job {
|
|||
ArchiveConfigManager manager = ArchiveConfigManager.getInstance();
|
||||
|
||||
while (!shutdown.get()) {
|
||||
synchronized (missingDataQueue) {
|
||||
if (currentMissingData != null) {
|
||||
missingDataQueue.notifyAll();
|
||||
synchronized (loadDisplayDataQueue) {
|
||||
if (currentLoadDisplayData != null) {
|
||||
currentLoadDisplayData = null;
|
||||
loadDisplayDataQueue.notifyAll();
|
||||
--loadDisplayDataCnt;
|
||||
}
|
||||
currentLoadDisplayData = loadDisplayDataQueue.poll();
|
||||
if (currentLoadDisplayData == null) {
|
||||
break;
|
||||
}
|
||||
currentMissingData = missingDataQueue.poll();
|
||||
}
|
||||
|
||||
if (currentMissingData == null) {
|
||||
break;
|
||||
}
|
||||
|
||||
String archiveName = currentMissingData.archive;
|
||||
String categoryName = currentMissingData.category;
|
||||
Set<String> selectedSet = currentMissingData.selectedSet;
|
||||
String archiveName = currentLoadDisplayData.archive;
|
||||
String categoryName = currentLoadDisplayData.category;
|
||||
Set<String> selectedSet = currentLoadDisplayData.selectedSet;
|
||||
List<DisplayData> displayDatas = manager.getDisplayData(
|
||||
archiveName, categoryName, false);
|
||||
if (shutdown.get()) {
|
||||
|
@ -868,13 +948,31 @@ public class SizeJob extends Job {
|
|||
}
|
||||
}
|
||||
|
||||
if (loadDisplayDataCnt == 0) {
|
||||
if (loadDisplayDataListener != null) {
|
||||
loadDisplayDataListener.loadedAllDisplayData();
|
||||
}
|
||||
}
|
||||
|
||||
return Status.OK_STATUS;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param loadDisplayData
|
||||
* @return true when missingData still needs to be processed.
|
||||
*/
|
||||
public boolean processing(LoadDisplayData loadDisplayData) {
|
||||
synchronized (loadDisplayDataQueue) {
|
||||
return loadDisplayDataQueue.contains(loadDisplayData)
|
||||
|| loadDisplayData.equals(currentLoadDisplayData);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void canceling() {
|
||||
shutdown.set(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -22,6 +22,7 @@ package com.raytheon.uf.viz.archive.ui;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
import org.eclipse.core.runtime.IProgressMonitor;
|
||||
|
@ -53,6 +54,7 @@ import com.raytheon.uf.common.util.SizeUtil;
|
|||
import com.raytheon.uf.viz.archive.data.ArchiveInfo;
|
||||
import com.raytheon.uf.viz.archive.data.CategoryInfo;
|
||||
import com.raytheon.uf.viz.archive.data.IArchiveTotals;
|
||||
import com.raytheon.uf.viz.archive.data.ILoadDisplayDataListener;
|
||||
import com.raytheon.uf.viz.archive.data.IRetentionHour;
|
||||
import com.raytheon.uf.viz.archive.data.IUpdateListener;
|
||||
import com.raytheon.uf.viz.archive.data.SizeJob;
|
||||
|
@ -79,6 +81,7 @@ import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
|
|||
* Dec 11, 2013 2624 rferrel No longer clear table prior to populating.
|
||||
* Apr 15, 2014 3034 lvenable Added dispose checks in runAsync calls.
|
||||
* Apr 10, 2014 3023 rferrel Added setTotalSelectedSize method.
|
||||
* Apr 23, 2014 3045 rferrel Changes to prevent race condition while getting labels.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -87,7 +90,8 @@ import com.raytheon.viz.ui.dialogs.CaveSWTDialog;
|
|||
*/
|
||||
|
||||
public abstract class AbstractArchiveDlg extends CaveSWTDialog implements
|
||||
IArchiveTotals, IUpdateListener, IModifyListener, IRetentionHour {
|
||||
IArchiveTotals, IUpdateListener, IModifyListener, IRetentionHour,
|
||||
ILoadDisplayDataListener {
|
||||
|
||||
/** Table composite that holds the table controls. */
|
||||
private ArchiveTableComp tableComp;
|
||||
|
@ -115,7 +119,7 @@ public abstract class AbstractArchiveDlg extends CaveSWTDialog implements
|
|||
/**
|
||||
* Job that computes sizes of table row entries off the UI thread.
|
||||
*/
|
||||
protected final SizeJob sizeJob = new SizeJob();
|
||||
protected final SizeJob sizeJob = new SizeJob(this);
|
||||
|
||||
/** Keeps track of when it is safe to clear the busy cursor. */
|
||||
protected final AtomicInteger busyCnt = new AtomicInteger(0);
|
||||
|
@ -139,6 +143,9 @@ public abstract class AbstractArchiveDlg extends CaveSWTDialog implements
|
|||
|
||||
private String previousSelectedCategory = null;
|
||||
|
||||
/** Job running to populate the currently selected archive/category. */
|
||||
private Job populateTableJob = null;
|
||||
|
||||
/**
|
||||
* @param parentShell
|
||||
*/
|
||||
|
@ -365,6 +372,9 @@ public abstract class AbstractArchiveDlg extends CaveSWTDialog implements
|
|||
protected void disposed() {
|
||||
sizeJob.removeUpdateListener(this);
|
||||
sizeJob.cancel();
|
||||
if (populateTableJob != null) {
|
||||
populateTableJob.cancel();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -463,12 +473,17 @@ public abstract class AbstractArchiveDlg extends CaveSWTDialog implements
|
|||
}
|
||||
|
||||
/**
|
||||
* Load a select configuration file.
|
||||
* Load selected configuration file.
|
||||
*
|
||||
* @param selectName
|
||||
*/
|
||||
protected void loadSelect(String selectName) {
|
||||
sizeJob.loadSelect(selectName, type);
|
||||
protected boolean loadSelect(String selectName) {
|
||||
String message = sizeJob.loadSelect(selectName, type);
|
||||
if (message != null) {
|
||||
MessageDialog.openError(shell, "Unable to load Case", message);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -483,15 +498,39 @@ public abstract class AbstractArchiveDlg extends CaveSWTDialog implements
|
|||
|
||||
setShowingSelected(false);
|
||||
|
||||
Job job = new Job("populate category table") {
|
||||
if (populateTableJob != null) {
|
||||
populateTableJob.cancel();
|
||||
setCursorBusy(false);
|
||||
}
|
||||
|
||||
populateTableJob = new Job("populate category table") {
|
||||
private AtomicBoolean shutdown = new AtomicBoolean(false);
|
||||
|
||||
@Override
|
||||
protected IStatus run(IProgressMonitor monitor) {
|
||||
getCategoryTableData(archiveName, categoryName);
|
||||
getCategoryTableData(archiveName, categoryName, shutdown);
|
||||
|
||||
// Just populated the current table update cursor.
|
||||
if (!shutdown.get()) {
|
||||
populateTableJob = null;
|
||||
VizApp.runAsync(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
setCursorBusy(false);
|
||||
}
|
||||
});
|
||||
}
|
||||
return Status.OK_STATUS;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void canceling() {
|
||||
shutdown.set(true);
|
||||
}
|
||||
|
||||
};
|
||||
job.schedule();
|
||||
populateTableJob.schedule();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -501,12 +540,25 @@ public abstract class AbstractArchiveDlg extends CaveSWTDialog implements
|
|||
*
|
||||
* @param archiveName
|
||||
* @param categoryName
|
||||
* @param shutdown
|
||||
*/
|
||||
private void getCategoryTableData(final String archiveName,
|
||||
final String categoryName) {
|
||||
final String categoryName, final AtomicBoolean shutdown) {
|
||||
|
||||
if (!sizeJob.isCurrentDisplay(archiveName, categoryName)) {
|
||||
VizApp.runAsync(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!isDisposed()) {
|
||||
tableComp.clearTable();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
final List<DisplayData> displayDatas = sizeJob.changeDisplay(
|
||||
archiveName, categoryName);
|
||||
archiveName, categoryName, shutdown);
|
||||
|
||||
VizApp.runAsync(new Runnable() {
|
||||
|
||||
|
@ -517,15 +569,11 @@ public abstract class AbstractArchiveDlg extends CaveSWTDialog implements
|
|||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (displayDatas != null) {
|
||||
tableComp.populateTable(archiveName, categoryName,
|
||||
displayDatas);
|
||||
} else {
|
||||
tableComp.refresh();
|
||||
}
|
||||
} finally {
|
||||
setCursorBusy(false);
|
||||
if (displayDatas != null) {
|
||||
tableComp.populateTable(archiveName, categoryName,
|
||||
displayDatas);
|
||||
} else {
|
||||
tableComp.refresh();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -537,11 +585,14 @@ public abstract class AbstractArchiveDlg extends CaveSWTDialog implements
|
|||
* @param state
|
||||
*/
|
||||
protected void setCursorBusy(boolean state) {
|
||||
if (state) {
|
||||
busyCnt.addAndGet(1);
|
||||
shell.setCursor(shell.getDisplay().getSystemCursor(SWT.CURSOR_WAIT));
|
||||
} else if (busyCnt.addAndGet(-1) == 0) {
|
||||
shell.setCursor(null);
|
||||
if (!shell.isDisposed()) {
|
||||
if (state) {
|
||||
busyCnt.addAndGet(1);
|
||||
shell.setCursor(shell.getDisplay().getSystemCursor(
|
||||
SWT.CURSOR_WAIT));
|
||||
} else if (busyCnt.addAndGet(-1) == 0) {
|
||||
shell.setCursor(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -786,6 +837,11 @@ public abstract class AbstractArchiveDlg extends CaveSWTDialog implements
|
|||
return errorMsg == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows sub-class to perform updates once all the display data is loaded.
|
||||
*/
|
||||
abstract public void loadedAllDisplayData();
|
||||
|
||||
/**
|
||||
* When unsaved modifications this asks the user to verify the close.
|
||||
*
|
||||
|
|
|
@ -57,6 +57,7 @@ import com.raytheon.uf.common.time.util.TimeUtil;
|
|||
* Oct 01, 2013 #2147 rferrel Change getEnd() to pick up files with future time stamps.
|
||||
* Oct 07, 2013 #2438 rferrel Properly save and load retention times.
|
||||
* Apr 14, 2014 #3023 rferrel Code clean up.
|
||||
* Apr 24, 2014 #3045 rferrel Implement loadedAllDsipalyData.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -415,4 +416,9 @@ public class ArchiveRetentionDlg extends AbstractArchiveDlg {
|
|||
archiveComboSelection();
|
||||
categoryComboSelection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadedAllDisplayData() {
|
||||
// nothing to update.
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
**/
|
||||
package com.raytheon.uf.viz.archive.ui;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
@ -63,6 +64,7 @@ import com.raytheon.uf.viz.archive.data.SizeJob;
|
|||
* Aug 06, 2013 #2222 rferrel Changes to display all selected data.
|
||||
* Aug 14, 2013 #2220 rferrel Add refresh method.
|
||||
* Aug 26, 2013 #2225 rferrel Add missing updates.
|
||||
* Apr 23, 2014 #3045 rferrel Added clearTable method.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -468,6 +470,13 @@ public class ArchiveTableComp extends Composite {
|
|||
populateTable(displayDatas);
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear table entries.
|
||||
*/
|
||||
protected void clearTable() {
|
||||
populateTable(new ArrayList<DisplayData>(0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag table as showing all selected data and update display.
|
||||
*
|
||||
|
|
|
@ -72,6 +72,8 @@ import com.raytheon.viz.ui.dialogs.ICloseCallback;
|
|||
* Aug 06, 2013 #2222 rferrel Changes to display all selected data.
|
||||
* Aug 26, 2013 #2225 rferrel Make perspective independent and no longer modal.
|
||||
* Apr 11, 2014 #3023 rferrel Configurable Threshold options.
|
||||
* Apr 23, 2014 #3045 rferrel To prevent race condition only allow a case
|
||||
* load after all labels are loaded.
|
||||
*
|
||||
* </pre>
|
||||
*
|
||||
|
@ -166,6 +168,9 @@ public class CaseCreationDlg extends AbstractArchiveDlg {
|
|||
/** Manager for configurable values for the dialog. */
|
||||
private final CaseCreationManager ccManager;
|
||||
|
||||
/** Flag to indicate all labels for all tables are loaded. */
|
||||
private volatile boolean haveAllLabels = false;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
|
@ -490,34 +495,48 @@ public class CaseCreationDlg extends AbstractArchiveDlg {
|
|||
// }
|
||||
// });
|
||||
|
||||
String tooltip = "Waiting on loading of table labels.";
|
||||
Color color = shell.getDisplay().getSystemColor(SWT.COLOR_YELLOW);
|
||||
saveBtn = new Button(actionControlComp, SWT.PUSH);
|
||||
saveBtn.setText(" Save ");
|
||||
saveBtn.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent selectionEvent) {
|
||||
saveSelection(selectName);
|
||||
clearModified();
|
||||
if (haveAllLabels) {
|
||||
saveSelection(selectName);
|
||||
clearModified();
|
||||
}
|
||||
}
|
||||
});
|
||||
saveBtn.setToolTipText(tooltip);
|
||||
saveBtn.setEnabled(false);
|
||||
saveBtn.setBackground(color);
|
||||
|
||||
saveAsBtn = new Button(actionControlComp, SWT.PUSH);
|
||||
saveAsBtn.setText(" Save As... ");
|
||||
saveAsBtn.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent selectionEvent) {
|
||||
handleSaveAsCase();
|
||||
if (haveAllLabels) {
|
||||
handleSaveAsCase();
|
||||
}
|
||||
}
|
||||
});
|
||||
saveAsBtn.setToolTipText(tooltip);
|
||||
saveAsBtn.setBackground(color);
|
||||
|
||||
loadBtn = new Button(actionControlComp, SWT.PUSH);
|
||||
loadBtn.setText(" Load... ");
|
||||
loadBtn.addSelectionListener(new SelectionAdapter() {
|
||||
@Override
|
||||
public void widgetSelected(SelectionEvent selectionEvent) {
|
||||
handleLoadCase();
|
||||
if (haveAllLabels) {
|
||||
handleLoadCase();
|
||||
}
|
||||
}
|
||||
});
|
||||
loadBtn.setToolTipText(tooltip);
|
||||
loadBtn.setBackground(color);
|
||||
|
||||
deleteBtn = new Button(actionControlComp, SWT.PUSH);
|
||||
deleteBtn.setText(" Delete... ");
|
||||
|
@ -606,11 +625,12 @@ public class CaseCreationDlg extends AbstractArchiveDlg {
|
|||
public void dialogClosed(Object returnValue) {
|
||||
if (returnValue instanceof String) {
|
||||
String name = returnValue.toString();
|
||||
loadSelect(name);
|
||||
populateTableComp();
|
||||
updateTotals(null);
|
||||
setSelectName(name);
|
||||
clearModified();
|
||||
if (loadSelect(name)) {
|
||||
populateTableComp();
|
||||
updateTotals(null);
|
||||
setSelectName(name);
|
||||
clearModified();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -1059,4 +1079,40 @@ public class CaseCreationDlg extends AbstractArchiveDlg {
|
|||
super.clearModified();
|
||||
saveBtn.setEnabled(false);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see com.raytheon.uf.viz.archive.ui.AbstractArchiveDlg#haveAllLabels()
|
||||
*/
|
||||
@Override
|
||||
public void loadedAllDisplayData() {
|
||||
haveAllLabels = true;
|
||||
|
||||
/*
|
||||
* Restore the buttons' default background color and tooltip text. The
|
||||
* buttons color is not the system standard and the tool tip text
|
||||
* indicates it is waiting for the labels to be loaded.
|
||||
*/
|
||||
VizApp.runAsync(new Runnable() {
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
if (!isDisposed()) {
|
||||
saveBtn.setBackground(null);
|
||||
saveBtn.setToolTipText(null);
|
||||
saveAsBtn.setBackground(null);
|
||||
saveAsBtn.setToolTipText(null);
|
||||
loadBtn.setBackground(null);
|
||||
loadBtn.setToolTipText(null);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isModified() {
|
||||
return super.isModified();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -116,7 +116,7 @@ public class CaseLoadSaveDeleteDlg extends CaveSWTDialog {
|
|||
private void init() {
|
||||
createCaseControls();
|
||||
GuiUtil.addSeparator(shell, SWT.HORIZONTAL);
|
||||
createBottomAcitonButtons();
|
||||
createBottomActionButtons();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -151,7 +151,7 @@ public class CaseLoadSaveDeleteDlg extends CaveSWTDialog {
|
|||
/**
|
||||
* Button layout at the bottom of the dialog.
|
||||
*/
|
||||
private void createBottomAcitonButtons() {
|
||||
private void createBottomActionButtons() {
|
||||
Composite actionControlComp = new Composite(shell, SWT.NONE);
|
||||
GridLayout gl = new GridLayout(2, false);
|
||||
GridData gd = new GridData(SWT.FILL, SWT.DEFAULT, true, false);
|
||||
|
|
Loading…
Add table
Reference in a new issue