Issue #3045 - Change to prevent race conditions while getting table labels.

Change-Id: I82d0ab9deaa2b2b89a859fcb76af5d5cd7692120
(cherry picked from commit 9dad4c959b [formerly 17a06743e41fe6bf15a895d9842bb51d99901602])

Conflicts:
	cave/com.raytheon.uf.viz.archive/src/com/raytheon/uf/viz/archive/ui/CaseCreationDlg.java

Former-commit-id: 47a22d226ed36c07443d540bf800cbb2fc3e2a15
This commit is contained in:
Roger Ferrel 2014-04-23 11:02:38 -05:00 committed by Steve Harris
parent 2b4bdeb10b
commit 7e6a90c895
7 changed files with 412 additions and 143 deletions

View file

@ -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();
}

View file

@ -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);
}
}
}

View file

@ -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.
*

View file

@ -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.
}
}

View file

@ -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.
*

View file

@ -76,6 +76,8 @@ import com.raytheon.viz.ui.dialogs.ICloseCallback;
* Mar 24, 2014 #2853 rferrel Populate case label directory with default value.
* Apr 11, 2014 #3023 rferrel Configurable Threshold options.
* Mar 26, 2014 32880 rferrerl Implement case compression and split.
* Apr 23, 2014 #3045 rferrel To prevent race condition only allow a case
* load after all labels are loaded.
*
* </pre>
*
@ -169,6 +171,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.
*
@ -491,34 +496,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... ");
@ -607,11 +626,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();
}
}
}
});
@ -1083,4 +1103,40 @@ public class CaseCreationDlg extends AbstractArchiveDlg {
defaultCaseDir));
}
}
/*
* (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();
}
}

View file

@ -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);