Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 35 additions & 34 deletions src/main/java/org/igv/ui/IGV.java
Original file line number Diff line number Diff line change
Expand Up @@ -2164,10 +2164,8 @@ public void repaintHeaderPanels() {
}




private volatile boolean isLoading = false;
private Set<Track> pendingTracks = null;
private volatile boolean repaintPending = false;
private final Object repaintLock = new Object();

private void repaint(final JComponent component, Collection<? extends Track> trackList) {
Expand Down Expand Up @@ -2195,28 +2193,32 @@ private void repaint(final JComponent component, Collection<? extends Track> tra

} else {

// Hold lock for the entire check-and-set operation to prevent race conditions
List<CompletableFuture<Void>> futures;
synchronized (repaintLock) {
if (isLoading) {
// Track data is being loaded. Paint the component with available data and queue these tracks for
// the next repaint cycle
UIUtilities.invokeOnEventThread(contentPane::repaint);
if (pendingTracks == null) {
pendingTracks = new HashSet<>();
}
pendingTracks.addAll(trackList);
// Track data is being loaded. Just flag that a repaint is needed when loading completes.
// Since repaint() has no state, we only need to know that *a* repaint was requested.
repaintPending = true;
return;
}
}

// Not currently loading
// Find tracks that need loading (not ready to paint)
List<CompletableFuture<Void>> futures = new ArrayList<>();
for (ReferenceFrame frame : FrameManager.getFrames()) {
for (Track track : trackList) {
if (!track.isReadyToPaint(frame)) {
futures.add(CompletableFuture.runAsync(() -> track.load(frame), threadExecutor));
// Not currently loading - find tracks that need loading (not ready to paint)
futures = new ArrayList<>();
for (ReferenceFrame frame : FrameManager.getFrames()) {
for (Track track : trackList) {
if (!track.isReadyToPaint(frame)) {
futures.add(CompletableFuture.runAsync(() -> track.load(frame), threadExecutor));
}
}
}

if (futures.isEmpty()) {
// All tracks are ready to paint - no need to set isLoading
} else {
// One or more tracks require loading before repaint - set loading flag while holding lock
isLoading = true;
}
}

if (futures.isEmpty()) {
Expand All @@ -2225,16 +2227,11 @@ private void repaint(final JComponent component, Collection<? extends Track> tra
UIUtilities.invokeOnEventThread(() -> {
checkPanelLayouts();
component.repaint();

});
return;
}


// One or more tracks require loading before repaint.
synchronized (repaintLock) {
isLoading = true;
}
// Loading is now in progress
final WaitCursorManager.CursorToken token = WaitCursorManager.showWaitCursor();

CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).whenComplete((ignored, ex) -> {
Expand All @@ -2244,12 +2241,12 @@ private void repaint(final JComponent component, Collection<? extends Track> tra
log.error("Error loading track data", ex);
}

// Collect pending tracks and reset state under lock
Set<Track> tracksToRepaint;
// Check if a repaint was requested while loading, and reset state under lock
boolean needsRepaint;
synchronized (repaintLock) {
isLoading = false;
tracksToRepaint = pendingTracks;
pendingTracks = null;
needsRepaint = repaintPending;
repaintPending = false;
}

// Autoscale (modifies track internal state, not UI)
Expand All @@ -2258,22 +2255,26 @@ private void repaint(final JComponent component, Collection<? extends Track> tra
// Check layouts and repaint on EDT
UIUtilities.invokeOnEventThread(() -> {
checkPanelLayouts();
if (tracksToRepaint != null && !tracksToRepaint.isEmpty()) {
// Pending tracks exist - repaint will be called by the recursive invocation
repaint(component, tracksToRepaint);
} else {
component.repaint();
component.repaint();
// If a repaint was requested while loading, trigger another repaint cycle
// to load any new data that may be needed
if (needsRepaint) {
repaint(component, getAllTracks());
}
});
});

}
}

/**
* Check if any track panels need layout revalidation due to height changes.
* Note: This method should be called from the EDT.
*/
private void checkPanelLayouts() {
for (TrackPanel tp : getTrackPanels()) {
if (tp.isHeightChanged()) {
UIUtilities.invokeOnEventThread(() -> tp.revalidate());
tp.revalidate();
}
}
}
Expand Down
10 changes: 0 additions & 10 deletions src/main/java/org/igv/ui/panel/RulerPanel.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,6 @@ public class RulerPanel extends JPanel {

public static final String CHROM_TOOLTIP = "Click and drag to zoom in.";

private final boolean darkMode;

boolean drawSpan = true;
private Font tickFont = FontManager.getFont(10);
private Font spanFont = FontManager.getFont(Font.BOLD, 12);
Expand All @@ -68,10 +66,8 @@ public class RulerPanel extends JPanel {
private Color collapsedInsertionColor = Color.BLACK;
private Color zoomedoutInsertionColor = ColorUtilities.modifyAlpha(Color.LIGHT_GRAY, 50);

private boolean showInsertions = false;
private List<ClickLink> clickLinks = new ArrayList();


boolean dragging = false;
int dragStart;
int dragEnd;
Expand All @@ -81,7 +77,6 @@ public class RulerPanel extends JPanel {

public RulerPanel(ReferenceFrame frame) {
this.frame = frame;
this.darkMode = Globals.isDarkMode();
init();
}

Expand Down Expand Up @@ -262,10 +257,7 @@ private void render(Graphics g) {
Collection<AlignmentTrack> tracks = IGV.getInstance().getAlignmentTracks();
int maxVizWindow = tracks.size() == 0 ? 0 : tracks.stream().mapToInt(t -> t.getVisibilityWindow()).max().getAsInt();
if (!frame.getChrName().equals(Globals.CHR_ALL) && (frame.getEnd() - frame.getOrigin()) <= maxVizWindow) {
showInsertions = true;
drawInsertionMarkers(g);
} else {
showInsertions = false;
}
}
}
Expand Down Expand Up @@ -420,9 +412,7 @@ private void drawChromosomeTicks(Graphics g) {
frame.changeChromosome((String) ch, true);
}));
}

even = !even;

}
}
}
Expand Down
Loading
Loading