*/
package jalview.api;
++import java.util.BitSet;
++
public interface AlignmentColsCollectionI extends Iterable<Integer>
{
/**
* @return true if there is at least 1 hidden column
*/
public boolean hasHidden();
++
++ /**
++ * Get the visible-column bitset, possibly containing hidden columns (which
++ * may or may not be hidden in the overview).
++ *
++ * @return a BitSet
++ */
++ public BitSet getOverviewBitSet();
++
++ /**
++ * Get the hidden-column bitset, (which may or may not be hidden in the
++ * overview).
++ *
++ * @return
++ */
++ BitSet getHiddenBitSet();
}
or = new OverviewRenderer(panel.ap, fr, od, av.getAlignment(),
av.getResidueShading(), new OverviewResColourFinder());
offscreen = nullFrame.createImage(od.getWidth(), od.getHeight());
-- or.draw(od.getRows(av.getAlignment()),
-- od.getColumns(av.getAlignment()));
++ or.drawMiniMe();
}
@Override
public void finalizeDraw(BufferedImage miniMe)
{
-- Graphics mg = miniMe.getGraphics();
--
-- // checks for conservation annotation to make sure overview works for DNA
-- // too
-- if (showAnnotation)
-- {
-- mg.translate(0, od.getSequencesHeight());
-- or.drawGraph(mg, av.getAlignmentConservationAnnotation(),
-- od.getGraphHeight(), od.getColumns(av.getAlignment()));
-- mg.translate(0, -od.getSequencesHeight());
-- }
--
if (restart)
{
restart = false;
}
else
{
++ this.miniMe = miniMe;
++ // checks for conservation annotation to make sure overview works for DNA
++ // too
++ if (showAnnotation)
++ {
++ or.drawGraph(av.getAlignmentConservationAnnotation());
++ }
updaterunning = false;
++ repaint();
}
}
@Override
public void run()
{
++ setBoxPosition();
canvas.draw(av.isShowSequenceFeatures(),
(av.isShowAnnotation()
&& av.getAlignmentConservationAnnotation() != null),
ap.seqPanel.seqCanvas.getFeatureRenderer());
-- setBoxPosition();
}
/**
synchronized (groups)
{
-- temp.clear();
int gSize = groups.size();
if (gSize == 0)
{
return noGroups;
}
++ temp.clear();
for (int i = 0; i < gSize; i++)
{
SequenceGroup sg = groups.get(i);
}
}
++ @Override
++ public void resetColors()
++ {
++ for (int i = getHeight(); --i >= 0;)
++ {
++ sequences.get(i).resetColors();
++ }
++ // if (dataset != null)
++ // {
++ // dataset.resetColors();
++ // }
++ }
++
}
public HiddenColumns propagateInsertions(SequenceI profileseq,
AlignmentView input);
++ /**
++ * Remove all color already assigned to sequences, causing them to be be
++ * recalculated.
++ */
++ void resetColors();
++
}
import jalview.api.AlignmentColsCollectionI;
++import java.util.BitSet;
import java.util.Iterator;
public class AllColsCollection implements AlignmentColsCollectionI
{
return hidden.hasHiddenColumns();
}
++
++ private BitSet bsVisible;
++
++ @Override
++ public BitSet getHiddenBitSet()
++ {
++ return hidden.getBitset();
++ }
++
++ /**
++ * return ALL columns, not just the truly visible ones
++ */
++ @Override
++ public BitSet getOverviewBitSet()
++ {
++ if (bsVisible == null)
++ {
++ bsVisible = new BitSet(end + 1);
++ bsVisible.set(0, end + 1);
++ }
++ return bsVisible;
++ }
}
*/
private List<int[]> hiddenColumns = new ArrayList<>();
++ private BitSet hiddenBitSet;
++
++ public BitSet getBitset()
++ {
++ if (hiddenBitSet == null)
++ {
++ hiddenBitSet = new BitSet();
++ for (int[] range : hiddenColumns)
++ {
++ hiddenBitSet.set(range[0], range[1] + 1);
++ }
++ }
++ return hiddenBitSet;
++ }
/**
* Constructor
*/
prevHiddenCount);
} finally
{
++ hiddenBitSet = null;
LOCK.writeLock().unlock();
}
}
insertRangeAtOverlap(i, start, end, region);
added = true;
}
++ hiddenBitSet = null;
return added;
}
}
numColumns += region[1] - oldend;
hiddenColumns.subList(i + 1, endi + 1).clear();
++ hiddenBitSet = null;
}
/**
} finally
{
++ hiddenBitSet = null;
LOCK.writeLock().unlock();
}
}
} finally
{
++ hiddenBitSet = null;
LOCK.writeLock().unlock();
}
}
}
} finally
{
++ hiddenBitSet = null;
LOCK.writeLock().unlock();
}
}
} finally
{
++ hiddenBitSet = null;
LOCK.readLock().unlock();
}
}
for (int firstSet = tohide
.nextSetBit(start), lastSet = start; firstSet >= start
&& lastSet <= end; firstSet = tohide
-- .nextSetBit(lastSet))
++ .nextSetBit(lastSet))
{
lastSet = tohide.nextClearBit(firstSet);
if (lastSet <= end)
cursor = new HiddenColumnsCursor(hiddenColumns);
} finally
{
++ hiddenBitSet = null;
LOCK.writeLock().unlock();
}
}
}
} finally
{
++ hiddenBitSet = null;
LOCK.writeLock().unlock();
}
}
{
LOCK.writeLock().lock();
-- BitSet hiddenBitSet = new BitSet();
-- for (int[] range : hiddenColumns)
-- {
-- hiddenBitSet.set(range[0], range[1] + 1);
-- }
-- hiddenBitSet.andNot(updates);
++ getBitset().andNot(updates);
hiddenColumns.clear();
hideColumns(hiddenBitSet);
} finally
{
++ hiddenBitSet = null;
LOCK.writeLock().unlock();
}
}
import jalview.util.MapList;
import jalview.util.StringUtils;
--import java.awt.Color;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
@Override
public void sequenceChanged()
{
++ argb = null;
changeCount++;
}
return 0;
}
++ private int[] argb;
++
@Override
-- public Color getColor(int i)
++ public int getColor(int i)
{
-- return null;
++ return argb == null ? 0 : argb[i];
}
@Override
-- public Color setColor(int i, Color c)
++ public int setColor(int i, int rgb)
{
-- return c;
++ if (argb == null)
++ {
++ argb = new int[this.sequence.length];
++ }
++ return (argb[i] = rgb);
}
@Override
public void resetColors()
{
++ argb = null;
}
}
import jalview.util.MapList;
import jalview.ws.params.InvalidArgumentException;
--import java.awt.Color;
import java.util.BitSet;
import java.util.Iterator;
import java.util.List;
*/
public int firstResidueOutsideIterator(Iterator<int[]> it);
-- public Color getColor(int i);
++ public int getColor(int i);
-- public Color setColor(int i, Color c);
++ public int setColor(int i, int rgb);
public void resetColors();
import jalview.api.AlignmentColsCollectionI;
++import java.util.BitSet;
import java.util.Iterator;
public class VisibleColsCollection implements AlignmentColsCollectionI
HiddenColumns hidden;
++ private BitSet bsVisible;
++
public VisibleColsCollection(int s, int e, HiddenColumns h)
{
start = s;
return false;
}
++ /**
++ * Only the visible columns.
++ */
++ @Override
++ public BitSet getOverviewBitSet()
++ {
++ if (bsVisible == null)
++ {
++ bsVisible = new BitSet(end + 1);
++ }
++ bsVisible.clear();
++ bsVisible.set(start, end + 1);
++ bsVisible.andNot(hidden.getBitset());
++
++ return bsVisible;
++ }
++
++ @Override
++ public BitSet getHiddenBitSet()
++ {
++ return new BitSet();
++ }
++
}
{
viewport.setShowSequenceFeatures(true);
showSeqFeatures.setSelected(true);
++ alignPanel.getAlignment().resetColors();
}
}
import javax.swing.SwingUtilities;
/**
-- * DOCUMENT ME!
++ * The main panel of an AlignFrame, containing holders for the IdPanel,
++ * SeqPanel, AnnotationLabels (a JPanel), and AnnotationPanel.
++ *
++ * Additional holders contain an IdPanelWidthAdjuster space above the idPanel,
++ * AnnotationScroller (JScrollPane for AnnotationPanel), and vertical and
++ * horizontal scrollbars.
++ *
++ *
*
* @author $author$
* @version $Revision: 1.161 $
if (overviewPanel != null)
{
++ getAlignment().resetColors();
overviewPanel.updateOverviewImage();
}
}
{
super(alignPanel.av);
this.ap = alignPanel;
-- if (alignPanel.getSeqPanel() != null
-- && alignPanel.getSeqPanel().seqCanvas != null
-- && alignPanel.getSeqPanel().seqCanvas.fr != null)
++ SeqPanel sp = alignPanel.getSeqPanel();
++ if (sp != null && sp.seqCanvas != null && sp.seqCanvas.fr != null)
{
-- transferSettings(alignPanel.getSeqPanel().seqCanvas.fr);
++ sp.clearColors();
++ transferSettings(sp.seqCanvas.fr);
}
}
}
private OverviewPanel panel;
++ private boolean showProgress;
++
public OverviewCanvas(OverviewPanel panel,
OverviewDimensions overviewDims,
AlignViewportI alignvp, ProgressPanel pp)
{
this.panel = panel;
od = overviewDims;
++ lastMiniMe = null;
av = alignvp;
progressPanel = pp;
--
++ showProgress = (pp != null);
sr = new SequenceRenderer(av);
sr.renderGaps = false;
fr = new jalview.renderer.seqfeatures.FeatureRenderer(av);
public void resetOviewDims(OverviewDimensions overviewDims)
{
od = overviewDims;
++ lastMiniMe = null;
}
/**
else
{
updaterunning = true;
++ restart = false;
}
return restart;
}
this.showSequenceFeatures = showSequenceFeatures;
this.showAnnotation = showAnnotation;
this.featureRenderer = featureRenderer;
--
-- // System.out.println("OC draw " + ++ndraw + " showseqf="
-- // + showSequenceFeatures + " showAnno=" + showAnnotation);
--
if (showSequenceFeatures)
{
fr.transferSettings(featureRenderer);
}
--
setPreferredSize(new Dimension(od.getWidth(), od.getHeight()));
--
AlignmentI al = av.getAlignment();
-- or = new OverviewRenderer(panel.ap, fr, od, al,
-- av.getResidueShading(), cf,
-- progressPanel != null);
-- if (progressPanel != null)
++ or = new OverviewRenderer(panel.ap, fr, od, al, av.getResidueShading(),
++ cf, showProgress);
++ if (showProgress)
{
or.addPropertyChangeListener(progressPanel);
}
-- or.draw(od.getRows(al), od.getColumns(al));
++ or.drawMiniMe();
}
-- void finalizeDraw(BufferedImage miniMe)
++ synchronized void finalizeDraw(BufferedImage miniMe)
{
-- Graphics mg = miniMe.getGraphics();
-- if (showAnnotation)
++
++ if (or == null)
{
-- mg.translate(0, od.getSequencesHeight());
-- or.drawGraph(mg, av.getAlignmentConservationAnnotation(),
-- od.getGraphHeight(), od.getColumns(av.getAlignment()));
-- mg.translate(0, -od.getSequencesHeight());
++ System.out.println("OC or is null");
}
-- mg.dispose(); // BH 2019
-- if (progressPanel != null)
++ else if (showProgress)
{
or.removePropertyChangeListener(progressPanel);
}
-- or = null;
if (restart)
{
++ or = null;
restart = false;
if (!disposed)
{
}
else
{
++ if (showAnnotation)
++ {
++ or.drawGraph(av.getAlignmentConservationAnnotation());
++ }
++ or = null;
updaterunning = false;
lastMiniMe = miniMe;
repaint();
}
--
}
++
@Override
public void paintComponent(Graphics g)
{
else if (drawMe)
{
// is this a resize?
-- if (w != od.getWidth() || h != od.getHeight()) {
-- // if there is annotation, scale the alignment and annotation
-- // separately
-- if (od.getGraphHeight() <= 0 && od.getSequencesHeight() <= 0)
++ if (w != od.getWidth() || h != od.getHeight())
{
-- od.setWidth(w);
-- od.setHeight(h);
++
++ lastMiniMe = null;
return;
-- }
-- // System.out.println("OC new subimages");
-- BufferedImage topImage = lastMiniMe.getSubimage(0, 0, od.getWidth(),
-- od.getSequencesHeight());
-- BufferedImage bottomImage = lastMiniMe.getSubimage(0,
-- od.getSequencesHeight(), od.getWidth(), od.getGraphHeight());
--
-- // must be done at this point as we rely on using old width/height
-- // above, and new width/height below
-- od.setWidth(w);
-- od.setHeight(h);
--
-- // stick the images back together so lastMiniMe is consistent in the
-- // event of a repaint - BUT probably not thread safe
-- // System.out.println("OC new lastminime " + w + " " + h);
-- lastMiniMe = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
-- Graphics lg = lastMiniMe.getGraphics();
-- lg.drawImage(topImage, 0, 0, w, od.getSequencesHeight(), null);
-- lg.drawImage(bottomImage, 0, od.getSequencesHeight(), w,
-- od.getGraphHeight(), this);
-- lg.dispose();
-- // BH 2019: removed -- this is now taken care of using vpbox in
-- // OverviewDimension
-- // // make sure the box is in the right place
-- // od.setBoxPosition(av.getAlignment().getHiddenSequences(),
-- // av.getAlignment().getHiddenColumns());
++ // // if there is annotation, scale the alignment and annotation
++ // // separately
++ // if (od.getGraphHeight() <= 0 && od.getSequencesHeight() <= 0)
++ // {
++ // od.setWidth(w);
++ // od.setHeight(h);
++ // return;
++ // }
++ // try
++ // {
++ // BufferedImage topImage = lastMiniMe.getSubimage(0, 0,
++ // od.getWidth(), od.getSequencesHeight());
++ //
++ // BufferedImage bottomImage = lastMiniMe.getSubimage(0,
++ // od.getSequencesHeight(), od.getWidth(),
++ // od.getGraphHeight());
++ //
++ // // must be done at this point as we rely on using old width/height
++ // // above, and new width/height below
++ // od.setWidth(w);
++ // od.setHeight(h);
++ //
++ // // stick the images back together so lastMiniMe is consistent in the
++ // // event of a repaint - BUT probably not thread safe
++ //
++ // // right -- this fails with fast user action.
++ //
++ // lastMiniMe = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
++ // Graphics lg = lastMiniMe.getGraphics();
++ // lg.drawImage(topImage, 0, 0, w, od.getSequencesHeight(), null);
++ // lg.drawImage(bottomImage, 0, od.getSequencesHeight(), w,
++ // od.getGraphHeight(), this);
++ // lg.dispose();
++ //
++ // } catch (RasterFormatException e)
++ // {
++ // System.out.println("OC Raster Exception " + lastMiniMe.getWidth()
++ // + "/" + w + "," + lastMiniMe.getHeight() + "/" + h + " "
++ // + od.getSequencesHeight() + " " + od.getGraphHeight());
++ // }
++ // BH 2019: removed -- this is now taken care of using vpbox in
++ // OverviewDimension
++ // // make sure the box is in the right place
++ // od.setBoxPosition(av.getAlignment().getHiddenSequences(),
++ // av.getAlignment().getHiddenColumns());
}
}
{
disposed = true;
od = null;
++ lastMiniMe = null;
synchronized (this)
{
setRestart("dispose");
if (getWidth() == od.getWidth()
&& getHeight() == od.getHeight() + ph)
{
++ // BH: resizing is now exceptionally fast.
updateOverviewImage();
}
else
}
od.setWidth(w);
od.setHeight(h - ph);
-- repaint();
++ updateOverviewImage();
++ // repaint();
}
// BH 2019.07.29 this is unnecessary -- it is what layout managers are
// for:
}
/**
- * Updates the overview image when the related alignment panel is updated
+ * Updates the overview image when the related alignment panel is updated.
+ *
+ * Cases:
+ *
++ * AlignFrame.setFeatureGroupState
++ *
++ * AlignmentPanel.paintAlignment(true,...) (117 references)
++ *
++ * OverviewPanel..componentResized() OverviewPanel.toggleHiddenColumns()
++ *
++ * PopupMenu for action.reveal_sequences, action.reveal_all
++ *
++ * SliderPanel.mouseReleased()
+ *
*/
public void updateOverviewImage()
{
{
if (canvas != null)
{
++ setBoxPosition();
canvas.draw(av.isShowSequenceFeatures(),
(av.isShowAnnotation()
&& av.getAlignmentConservationAnnotation() != null),
ap.getFeatureRenderer());
-- setBoxPosition();
}
}
@Override
public void propertyChange(PropertyChangeEvent evt)
{
-- // Respond to viewport change events (e.g. alignment panel was scrolled)
-- // Both scrolling and resizing change viewport ranges: scrolling changes
-- // both start and end points, but resize only changes end values.
-- // Here we only want to fastpaint on a scroll, with resize using a normal
-- // paint, so scroll events are identified as changes to the horizontal or
-- // vertical start value.
switch (evt.getPropertyName())
{
case ViewportRanges.STARTRES:
case ViewportRanges.STARTRESANDSEQ:
case ViewportRanges.MOVE_VIEWPORT:
// scroll event, repaint panel
-- // TODO: check this?
-- // BH: This is actually quite strange. AlignmentPanel is taking care of
-- // all of
-- // this with fast paint, so why indirectly trigger a repaint from the
-- // ScalePanel?
--
++ // original comment:
// Call repaint on alignment panel so that repaints from other alignment
// panel components can be aggregated. Otherwise performance of the
// overview
// window and others may be adversely affected.
-- // av.getAlignPanel().repaint();
-- System.out.println("ScalePanel propertyChange disabled "
-- + evt.getPropertyName());
++
++ // TODO: check this?
++ // BH: This is actually quite strange. AlignmentPanel is taking care of
++ // all of this with fast paint, so why indirectly trigger a repaint from
++ // the ScalePanel? Where do we see this behavior necessary?
++ // I have set this to check for a trigger from some other ViewportRanges,
++ // but I don't actually think that is possible.
++
++ if (evt.getSource() != av.getRanges())
++ {
++ av.getAlignPanel().repaint();
++ }
break;
}
}
int charHeight = av.getCharHeight();
int charWidth = av.getCharWidth();
-- int width = getWidth();
-- int height = getHeight();
++ int availWidth = getWidth();
++ int availHeight = getHeight();
-- width -= (width % charWidth);
-- height -= (height % charHeight);
++ availWidth -= (availWidth % charWidth);
++ availHeight -= (availHeight % charHeight);
// BH 2019 can't possibly fastPaint if either width or height is 0
-- if (width == 0 || height == 0)
++ if (availWidth == 0 || availHeight == 0)
{
return;
}
// img is a cached version of the last view we drew.
// If we have no img or the size has changed, make a new one.
//
-- if (img == null || width != img.getWidth()
-- || height != img.getHeight())
++ if (img == null || availWidth != img.getWidth()
++ || availHeight != img.getHeight())
{
-- img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
++ img = new BufferedImage(availWidth, availHeight,
++ BufferedImage.TYPE_INT_RGB);
}
Graphics2D gg = (Graphics2D) img.getGraphics();
}
gg.setColor(Color.white);
-- gg.fillRect(0, 0, img.getWidth(), img.getHeight());
++ gg.fillRect(0, 0, availWidth, availHeight);
if (av.getWrapAlignment())
{
-- drawWrappedPanel(gg, width, height, ranges.getStartRes());
++ drawWrappedPanel(gg, availWidth, availHeight, ranges.getStartRes());
}
else
{
}
/**
-- * Returns the visible width of the canvas in residues, after allowing for
-- * East or West scales (if shown)
++ * Using the current font, determine fields labelWidthEast and labelWidthWest,
++ * and return the number of residues that can fill the remaining width.
*
-- * @param canvasWidth
++ * @param width
* the width in pixels (possibly including scales)
*
-- * @return
++ * @return the visible width in residues, after allowing for East or West
++ * scales (if shown)
++ *
*/
-- public int getWrappedCanvasWidth(int canvasWidth)
++ public int getWrappedCanvasWidth(int width)
{
int charWidth = av.getCharWidth();
FontMetrics fm = getFontMetrics(av.getFont());
-- int labelWidth = 0;
--
-- if (av.getScaleRightWrapped() || av.getScaleLeftWrapped())
-- {
-- labelWidth = getLabelWidth(fm);
-- }
++ int labelWidth = (av.getScaleRightWrapped() || av.getScaleLeftWrapped()
++ ? getLabelWidth(fm)
++ : 0);
labelWidthEast = av.getScaleRightWrapped() ? labelWidth : 0;
labelWidthWest = av.getScaleLeftWrapped() ? labelWidth : 0;
-- return (canvasWidth - labelWidthEast - labelWidthWest) / charWidth;
++ return (width - labelWidthEast - labelWidthWest) / charWidth;
}
/**
maxWidth = Math.max(maxWidth, alignment.getSequenceAt(i).getEnd());
}
++ // quick int log10
int length = 0;
for (int i = maxWidth; i > 0; i /= 10)
{
* window
*
* @param g
-- * @param canvasWidth
++ * @param availWidth
* available width in pixels
-- * @param canvasHeight
++ * @param availHeight
* available height in pixels
* @param startColumn
* the first column (0...) of the alignment to draw
*/
-- public void drawWrappedPanel(Graphics g, int canvasWidth,
-- int canvasHeight, final int startColumn)
++ public void drawWrappedPanel(Graphics g, int availWidth, int availHeight,
++ final int startColumn)
{
-- int wrappedWidthInResidues = calculateWrappedGeometry(canvasWidth,
-- canvasHeight);
++ int wrappedWidthInResidues = calculateWrappedGeometry(availWidth,
++ availHeight);
av.setWrappedWidth(wrappedWidthInResidues);
// we need to call this again to make sure the startColumn +
// wrappedWidthInResidues values are used to calculate wrappedVisibleWidths
// correctly.
-- calculateWrappedGeometry(canvasWidth, canvasHeight);
++ calculateWrappedGeometry(availWidth, availHeight);
/*
* draw one width at a time (excluding any scales shown),
{
int endColumn = Math
.min(maxWidth, start + wrappedWidthInResidues - 1);
-- drawWrappedWidth(g, ypos, start, endColumn, canvasHeight);
++ drawWrappedWidth(g, ypos, start, endColumn, availHeight);
ypos += wrappedRepeatHeightPx;
start += wrappedWidthInResidues;
currentWidth++;
* <li>whether scales are shown left, right or above the alignment</li>
* </ul>
*
-- * @param canvasWidth
-- * @param canvasHeight
++ * @param availWidth
++ * @param availHeight
* @return the number of residue columns in each width
*/
-- protected int calculateWrappedGeometry(int canvasWidth, int canvasHeight)
++ protected int calculateWrappedGeometry(int availWidth, int availHeight)
{
int charHeight = av.getCharHeight();
* ensuring a part height includes at least one sequence
*/
ViewportRanges ranges = av.getRanges();
-- wrappedVisibleWidths = canvasHeight / wrappedRepeatHeightPx;
-- int remainder = canvasHeight % wrappedRepeatHeightPx;
++ wrappedVisibleWidths = availHeight / wrappedRepeatHeightPx;
++ int remainder = availHeight % wrappedRepeatHeightPx;
if (remainder >= (wrappedSpaceAboveAlignment + charHeight))
{
wrappedVisibleWidths++;
/*
* compute width in residues; this also sets East and West label widths
*/
-- int wrappedWidthInResidues = getWrappedCanvasWidth(canvasWidth);
++ int wrappedWidthInResidues = getWrappedCanvasWidth(availWidth);
/*
* limit visibleWidths to not exceed width of alignment
import javax.swing.ToolTipManager;
/**
-- * DOCUMENT ME!
++ * The main scrollable region containing the alignment and just to the right of
++ * the IDPanel.
*
* @author $author$
* @version $Revision: 1.130 $
SearchResultsI lastSearchResults;
/**
-- * Creates a new SeqPanel object
++ * Create a new SeqPanel.
*
* @param viewport
* @param alignPanel
true);
}
++ public void clearColors()
++ {
++ av.getAlignment().getSequences();
++ // TODO Auto-generated method stub
++
++ }
++
}
*/
protected void initData()
{
-- seqs = new Vector<SequenceI>();
-- annotations = new Vector<AlignmentAnnotation>();
-- seqGroups = new ArrayList<SequenceGroup>();
++ seqs = new Vector<>();
++ annotations = new Vector<>();
++ seqGroups = new ArrayList<>();
parseCalled = false;
}
/**
-- * DOCUMENT ME!
++ * Create the seqs Vector from a set of parsed sequences in an AlignFile,
++ * FeaturesFile, RnamlFile, or StockholmFile.
*
* @param s
* DOCUMENT ME!
@Override
public void setSeqs(SequenceI[] s)
{
-- seqs = new Vector<SequenceI>();
++ seqs = new Vector<>();
for (int i = 0; i < s.length; i++)
{
{
if (newickStrings == null)
{
-- newickStrings = new Vector<String[]>();
++ newickStrings = new Vector<>();
}
newickStrings.addElement(new String[] { treeName, newickString });
}
AlignViewportI av = getViewport();
if (av != null)
{
-- if (av.getAlignment() != null)
++ AlignmentI a = av.getAlignment();
++ if (a != null)
{
-- dataset = av.getAlignment().getDataset();
++ dataset = a.getDataset();
}
if (dataset == null)
{
// working in the applet context ?
-- dataset = av.getAlignment();
++ dataset = a;
}
}
else
hscrollFillerPanel.setPreferredSize(new Dimension(70, 10));
hscrollHolder.setBackground(Color.white);
annotationScroller.setBorder(null);
++ annotationScroller.setBackground(Color.BLUE);
annotationScroller.setPreferredSize(new Dimension(10, 80));
this.setPreferredSize(new Dimension(220, 166));
// image to render on
private BufferedImage miniMe;
-- // raw number of pixels to allocate to each column
++ /**
++ * Number of pixelsPerCol;
++ */
private float pixelsPerCol;
++ /**
++ * Number of visible columns per pixel.
++ *
++ */
++ private float colsPerPixel;
++
// raw number of pixels to allocate to each row
private float pixelsPerSeq;
private AlignmentViewPanel panel;
++ private int sequencesHeight;
++
public OverviewRenderer(AlignmentViewPanel panel, FeatureRenderer fr,
OverviewDimensions od,
AlignmentI alignment,
}
public OverviewRenderer(AlignmentViewPanel panel,
-- jalview.api.FeatureRenderer fr,
-- OverviewDimensions od,
++ jalview.api.FeatureRenderer fr, OverviewDimensions od,
AlignmentI alignment, ResidueShaderI resshader,
OverviewResColourFinder colFinder, boolean showProgress)
{
this.panel = panel;
finder = new FeatureColourFinder(fr);
-- resColFinder = colFinder;
--
al = alignment;
shader = resshader;
++ resColFinder = colFinder;
++ this.showProgress = showProgress;
-- pixelsPerCol = od.getPixelsPerCol();
-- pixelsPerSeq = od.getPixelsPerSeq();
++ w = od.getWidth();
++ h = od.getHeight();
++ rows = od.getRows(alignment);
++ cols = od.getColumns(alignment);
graphHeight = od.getGraphHeight();
-- miniMe = new BufferedImage(od.getWidth(), od.getHeight(),
-- BufferedImage.TYPE_INT_RGB);
-- this.showProgress = showProgress;
++ alignmentHeight = od.getSequencesHeight();
++
++ pixelsPerSeq = od.getPixelsPerSeq();
++ pixelsPerCol = od.getPixelsPerCol();
++ colsPerPixel = Math.max(1, 1f / pixelsPerCol);
++
}
final static int STATE_INIT = 0;
private Integer row;
-- void mainLoop()
++ /**
++ * Draw alignment rows and columns onto an image. This method is asynchronous
++ * in JavaScript and interruptible in Java.
++ *
++ * Whether hidden rows or columns are drawn depends upon the type of
++ * collection.
++ *
++ * Updated to skip through high-density sequences, where columns/pixels > 1.
++ *
++ * When the process is complete, the image is passed to the AlignmentViewPanel
++ * provided by the constructor.
++ *
++ * @param rows
++ * collection of rows to be drawn
++ * @param cols
++ * collection of columns to be drawn
++ * @return image containing the drawing
++ *
++ * @author Bob Hanson 2019.07.30
++ */
++ public void drawMiniMe()
{
-- while (!redraw)
++ state = STATE_INIT;
++ mainLoop();
++ }
++
++ protected void mainLoop()
++ {
++ out: while (!redraw)
{
switch (state)
{
case STATE_INIT:
-- seqIndex = 0;
-- pixelRow = 0;
++ init();
state = STATE_NEXT;
continue;
case STATE_NEXT:
-- if (iter.hasNext())
++ if (!rowIterator.hasNext())
{
-- nextRow();
++ state = STATE_DONE;
++ continue;
}
-- else
++ nextRow();
++ if (!loop())
{
-- state = STATE_DONE;
++ continue;
}
-- break;
-- case STATE_DONE:
-- done();
-- return;
-- }
-- if (delay > 0)
-- {
-- jsloop();
return;
++ case STATE_DONE:
++ break out;
}
++ // Java will continue without a timeout
}
done();
}
-- private void jsloop()
++ private void init()
{
-- if (timer == null)
-- {
-- timer = new Timer(delay, new ActionListener()
-- {
-- @Override
-- public void actionPerformed(ActionEvent e)
-- {
-- mainLoop();
-- }
++ rowIterator = rows.iterator();
++ seqIndex = 0;
++ pixelRow = 0;
++ lastRowUpdate = 0;
++ lastUpdate = 0;
++ totalPixels = w * alignmentHeight;
-- });
-- timer.setRepeats(false);
-- timer.start();
-- }
-- else
++ if (showProgress)
{
-- timer.restart();
++ changeSupport.firePropertyChange(UPDATE, -1, 0);
}
++
++ miniMe = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
++ WritableRaster raster = miniMe.getRaster();
++ DataBufferInt db = (DataBufferInt) raster.getDataBuffer();
++ Platform.timeCheck(null, Platform.TIME_MARK);
++ pixels = db.getBankData()[0];
++ bscol = cols.getOverviewBitSet();
}
private void nextRow()
{
-- row = iter.next();
++ row = rowIterator.next();
// System.out.println("OR row " + r);
// get details of this alignment row
SequenceI seq = rows.getSequence(row);
// calculate where this row extends to in pixels
int endRow = Math.min(Math.round((++seqIndex) * pixelsPerSeq), h);
--
-- for (int pixelCol = 0, colIndex = 0, c = bscol
-- .nextSetBit(0); c >= 0; c = bscol.nextSetBit(c + 1))
++ for (int pixelCol = 0, colNext = 0, pixelEnd = 0, icol = bscol
++ .nextSetBit(0); icol >= 0; icol = getNextCol(icol, pixelEnd))
{
if (redraw)
{
break;
}
-- // calculate where this column extends to in pixels
-- int endCol = Math.min(Math.round((++colIndex) * pixelsPerCol), w);
--
-- // don't do expensive colour determination if we're not going to use it
-- // NB this is important to avoid performance issues in the overview
-- // panel
++ ++colNext;
++ pixelEnd = getNextPixel(colNext, colNext);
-- if (pixelCol < endCol)
++ if (pixelCol == pixelEnd)
{
-- // System.out.println("OR pc ec " + pixelCol + " " + endCol);
-- int rgb = getColumnColourFromSequence(allGroups, seq, c);
++ break;
++ }
++ else if (pixelCol < pixelEnd)
++ {
++ int rgb = getColumnColourFromSequence(allGroups, seq, icol);
// fill in the appropriate number of pixels
++ // System.out.println(
++ // "OR colNext=" + colNext + " " + pixelCol
++ // + "-" + pixelEnd + " icol=" + icol + " " + rgb + " "
++ // + pixelsPerCol);
for (int row = pixelRow; row < endRow; ++row)
{
-- for (int col = pixelCol; col < endCol; ++col)
++ for (int col = pixelCol; col < pixelEnd; ++col)
{
// BH 2019.07.27 was:
//
ndone++;
}
}
-- // }
--
-- pixelCol = endCol;
++ pixelCol = pixelEnd;
// store last update value
if (showProgress)
{
-- lastUpdate = sendProgressUpdate(endCol * (endRow - 1 - pixelRow),
++ lastUpdate = sendProgressUpdate(
++ pixelEnd * (endRow - 1 - pixelRow),
totalPixels, lastRowUpdate, lastUpdate);
}
}
++
}
if (pixelRow < endRow)
{
}
}
++ /**
++ * The next column is either the next set bit (when there are multiple pixels
++ * per column) or the next set bit for the column that aligns with the next
++ * pixel (when there are more columns than pixels).
++ *
++ * @param icol
++ * @param pixel
++ * @return
++ */
++ private int getNextCol(int icol, int pixel)
++ {
++ return bscol.nextSetBit(
++ pixelsPerCol >= 1 ? icol + 1 : (int) (pixel * colsPerPixel));
++ }
++
++ private int getNextPixel(int icol, int pixel)
++ {
++ return Math.min(
++ pixelsPerCol >= 1 || pixel == 0
++ ? Math.round(icol * pixelsPerCol)
++ : pixel,
++ w);
++ }
++
++ private boolean loop()
++ {
++ if (delay <= 0)
++ {
++ return false;
++ }
++ if (timer == null)
++ {
++ timer = new Timer(delay, new ActionListener()
++ {
++ @Override
++ public void actionPerformed(ActionEvent e)
++ {
++ mainLoop();
++ }
++
++ });
++ timer.setRepeats(false);
++ timer.start();
++ }
++ else
++ {
++ timer.restart();
++ }
++ return true;
++ }
++
private void done()
{
Platform.timeCheck(
+ redraw,
Platform.TIME_MARK);
-- overlayHiddenRegions(rows, cols);
++ overlayHiddenRegions();
if (showProgress)
{
// final update to progress bar if present
private AlignmentColsCollectionI cols;
-- Iterator<Integer> iter;
++ Iterator<Integer> rowIterator;
int alignmentHeight;
int[] pixels;
-- BitSet bscol = new BitSet();
++ BitSet bscol;
int w, h;
-- /**
-- * Draw alignment rows and columns onto an image
-- *
-- * @param rit
-- * Iterator over rows to be drawn
-- * @param cit
-- * Iterator over columns to be drawn
-- * @return image containing the drawing
-- */
-- public BufferedImage draw(AlignmentRowsCollectionI rows,
-- AlignmentColsCollectionI cols)
-- {
-- this.rows = rows;
-- this.cols = cols;
-- iter = rows.iterator();
--
-- w = miniMe.getWidth();
-- h = miniMe.getHeight();
-- alignmentHeight = h - graphHeight;
-- totalPixels = w * alignmentHeight;
-- lastRowUpdate = 0;
-- lastUpdate = 0;
--
-- if (showProgress)
-- {
-- changeSupport.firePropertyChange(UPDATE, -1, 0);
-- }
--
-- WritableRaster raster = miniMe.getRaster();
-- DataBufferInt db = (DataBufferInt) raster.getDataBuffer();
-- Platform.timeCheck(null, Platform.TIME_MARK);
-- pixels = db.getBankData()[0];
-- bscol.clear();
-- for (int c : cols)
-- {
-- bscol.set(c);
-- }
-- state = STATE_INIT;
-- mainLoop();
--
-- return miniMe;
-- }
--
/*
* Calculate progress update value and fire event
* @param rowOffset number of rows to offset calculation by
{
return (seq == null || icol >= seq.getLength()
? resColFinder.GAP_COLOUR
-- : resColFinder.getResidueColour(true, shader, allGroups, seq,
-- icol, finder)).getRGB();
++ : resColFinder.getResidueColourInt(true, shader, allGroups, seq,
++ icol, finder));
}
/**
* Overlay the hidden regions on the overview image
*
-- * @param rows
-- * collection of rows the overview is built over
-- * @param cols
-- * collection of columns the overview is built over
*/
-- private void overlayHiddenRegions(AlignmentRowsCollectionI rows,
-- AlignmentColsCollectionI cols)
++ private void overlayHiddenRegions()
{
if (cols.hasHidden() || rows.hasHidden())
{
-- BufferedImage mask = buildHiddenImage(rows, cols, miniMe.getWidth(),
-- miniMe.getHeight());
++ BufferedImage mask = buildHiddenImage();
Graphics2D g = (Graphics2D) miniMe.getGraphics();
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
* height of overview in pixels
* @return BufferedImage containing mask of hidden regions
*/
-- private BufferedImage buildHiddenImage(AlignmentRowsCollectionI rows,
-- AlignmentColsCollectionI cols, int width, int height)
++ private BufferedImage buildHiddenImage()
{
// new masking image
-- BufferedImage hiddenImage = new BufferedImage(width, height,
++ BufferedImage hiddenImage = new BufferedImage(w, h,
BufferedImage.TYPE_INT_ARGB);
Color hidden = resColFinder.getHiddenColour();
Graphics2D g2d = (Graphics2D) hiddenImage.getGraphics();
++ g2d.setColor(hidden);
// set background to transparent
// g2d.setComposite(AlphaComposite.Clear);
// g2d.fillRect(0, 0, width, height);
// set next colour to opaque
g2d.setComposite(AlphaComposite.Src);
++ // System.out.println(cols.getClass().getName());
if (cols.hasHidden())
{
-- int colIndex = 0;
-- int pixelCol = 0;
-- for (int alignmentCol : cols)
++ // AllColsCollection only
++ BitSet bs = cols.getHiddenBitSet();
++ for (int pixelCol = -1, icol2 = 0, icol = bs
++ .nextSetBit(0); icol >= 0; icol = bs.nextSetBit(icol2))
{
if (redraw)
{
break;
}
--
-- // calculate where this column extends to in pixels
-- int endCol = Math.min(Math.round((++colIndex) * pixelsPerCol),
-- width);
--
-- // endCol is one more than old endCol
-- if (pixelCol < endCol)
++ icol2 = bs.nextClearBit(icol + 1);
++ int pixelEnd = getNextPixel(icol2, 0);
++ if (pixelEnd > pixelCol)
{
-- // determine the colour based on the sequence and column position
-- if (cols.isHidden(alignmentCol))
-- {
-- g2d.setColor(hidden);
-- g2d.fillRect(pixelCol, 0, endCol - pixelCol, height);
-- }
-- pixelCol = endCol;
++ pixelCol = getNextPixel(icol, 0);
++ g2d.fillRect(pixelCol, 0, Math.max(1, pixelEnd - pixelCol),
++ h);
++ pixelCol = pixelEnd;
}
}
}
// calculate where this row extends to in pixels
int endRow = Math.min(Math.round((++seqIndex) * pixelsPerSeq),
-- height);
++ h);
// get details of this alignment row
if (rows.isHidden(alignmentRow))
{
-- g2d.setColor(hidden);
-- g2d.fillRect(0, pixelRow, width, endRow - 1 - pixelRow);
++ g2d.fillRect(0, pixelRow, w, endRow - 1 - pixelRow);
}
pixelRow = endRow;
}
/**
* Draw the alignment annotation in the overview panel
*
-- * @param g
-- * the graphics object to draw on
* @param anno
* alignment annotation information
-- * @param y
-- * y-position for the annotation graph
-- * @param cols
-- * the collection of columns used in the overview panel
*/
-- public void drawGraph(Graphics g, AlignmentAnnotation anno, int y,
-- AlignmentColsCollectionI cols)
++ public void drawGraph(AlignmentAnnotation anno)
{
++ int y = graphHeight;
++ Graphics g = miniMe.getGraphics();
++ g.translate(0, alignmentHeight);
++
Annotation[] annotations = anno.annotations;
float max = anno.graphMax;
g.setColor(Color.white);
-- int width = miniMe.getWidth();
-- g.fillRect(0, 0, width, y);
++ g.fillRect(0, 0, w, y);
-- int colIndex = 0;
-- int pixelCol = 0;
-- for (int icol : cols)
++ for (int pixelCol = 0, colNext = 0, pixelEnd = 0, len = annotations.length, icol = bscol
++ .nextSetBit(0); icol >= 0
++ && icol < len; icol = getNextCol(icol, pixelEnd))
{
if (redraw)
{
break;
}
-- if (icol >= annotations.length)
-- {
-- break; // no more annotations to draw here
-- }
-- int endCol = Math.min(Math.round((++colIndex) * pixelsPerCol), width);
++ ++colNext;
++ pixelEnd = getNextPixel(colNext, colNext);
Annotation ann = annotations[icol];
if (ann != null)
{
Color color = ann.colour;
g.setColor(color == null ? Color.black : color);
--
int height = Math.min(y, (int) ((ann.value / max) * y));
-- g.fillRect(pixelCol, y - height, endCol - pixelCol, height);
++ g.fillRect(pixelCol, y - height, Math.max(1, pixelEnd - pixelCol),
++ height);
}
-- pixelCol = endCol;
++ pixelCol = pixelEnd;
}
++
++ g.translate(0, -alignmentHeight);
++ g.dispose();
++
if (showProgress)
{
changeSupport.firePropertyChange(UPDATE, MAX_PROGRESS - 1,
MAX_PROGRESS);
}
++
}
/**
import jalview.datamodel.SequenceGroup;
import jalview.datamodel.SequenceI;
++import jalview.renderer.seqfeatures.FeatureColourFinder;
import jalview.util.Comparison;
import java.awt.Color;
public class OverviewResColourFinder extends ResidueColourFinder
{
-- final Color GAP_COLOUR; // default colour to use at gaps
++ final int GAP_COLOUR; // default colour to use at gaps
-- final Color RESIDUE_COLOUR; // default colour to use at residues
++ final int RESIDUE_COLOUR; // default colour to use at residues
final Color HIDDEN_COLOUR; // colour for hidden regions
{
if (useLegacyColouring)
{
-- GAP_COLOUR = Color.white;
-- RESIDUE_COLOUR = Color.lightGray;
-- HIDDEN_COLOUR = hiddenCol;
++ GAP_COLOUR = Color.white.getRGB();
++ RESIDUE_COLOUR = Color.lightGray.getRGB();
}
else
{
-- GAP_COLOUR = gapCol;
-- RESIDUE_COLOUR = Color.white;
-- HIDDEN_COLOUR = hiddenCol;
++ GAP_COLOUR = gapCol.getRGB();
++ RESIDUE_COLOUR = Color.white.getRGB();
}
++ HIDDEN_COLOUR = hiddenCol;
}
-- @Override
-- public Color getBoxColour(ResidueShaderI shader, SequenceI seq, int i)
++ public int getBoxColourInt(ResidueShaderI shader, SequenceI seq, int i)
{
-- seq.resetColors();
-- Color c = seq.getColor(i);
-- if (c != null)
-- {
-- return c;
-- }
char currentChar = seq.getCharAt(i);
// In the overview window, gaps are coloured grey, unless the colour scheme
// specifies a gap colour, in which case gaps honour the colour scheme
boolean isGap = Comparison.isGap(currentChar);
if (shader.getColourScheme() == null)
{
-- return seq.setColor(i, isGap ? GAP_COLOUR : RESIDUE_COLOUR);
++ return (isGap ? GAP_COLOUR : RESIDUE_COLOUR);
}
-- return seq.setColor(i,
-- isGap && !shader.getColourScheme().hasGapColour() ? GAP_COLOUR
-- : shader.findColour(currentChar, i, seq));
++ return (isGap && !shader.getColourScheme().hasGapColour() ? GAP_COLOUR
++ : shader.findColour(currentChar, i, seq).getRGB());
}
++ public int getResidueColourInt(boolean showBoxes, ResidueShaderI shader,
++ SequenceGroup[] allGroups, final SequenceI seq, int i,
++ FeatureColourFinder finder)
++ {
++
++ int c = seq.getColor(i);
++ if (c != 0)
++ {
++ return c;
++ }
++
++ int col = getResidueBoxColourInt(showBoxes, shader, allGroups, seq,
++ i);
++
++
++ // if there's a FeatureColourFinder we might override the residue colour
++ // here with feature colouring
++ return seq.setColor(i,
++ finder == null || finder.noFeaturesDisplayed() ? col
++ : finder.findFeatureColourInt(col, seq, i));
++ }
++
/**
-- * {@inheritDoc} In the overview, the showBoxes setting is ignored, as the
-- * overview displays the colours regardless.
++ * In the overview, the showBoxes setting is ignored, as the overview displays
++ * the colours regardless.
*/
-- @Override
-- protected Color getResidueBoxColour(boolean showBoxes,
++ protected int getResidueBoxColourInt(boolean showBoxes,
ResidueShaderI shader, SequenceGroup[] allGroups, SequenceI seq,
int i)
{
i);
ResidueShaderI currentShader = (currentSequenceGroup == null ? shader
: currentSequenceGroup.getGroupColourScheme());
-- return getBoxColour(currentShader, seq, i);
++ return getBoxColourInt(currentShader, seq, i);
}
/**
public SequenceGroup getCurrentSequenceGroup(SequenceGroup[] allGroups,
int res)
{
-- if (allGroups == null)
++ int n;
++ if (allGroups == null || (n = allGroups.length) == 0)
{
return null;
}
-- for (int i = 0; i < allGroups.length; i++)
++ for (int i = 0; i < n; i++)
{
if ((allGroups[i].getStartRes() <= res)
&& (allGroups[i].getEndRes() >= res))
return c;
}
++ public int findFeatureColourInt(int defaultColour, SequenceI seq,
++ int column)
++ {
++ // if (noFeaturesDisplayed())
++ // {
++ // return defaultColour;
++ // }
++
++ Graphics g = null;
++
++ /*
++ * if transparency applies, provide a notional 1x1 graphics context
++ * that has been primed with the default colour
++ */
++ if (featureRenderer.getTransparency() != 1f)
++ {
++ g = goff;
++ if (defaultColour != 0)
++ {
++ offscreenImage.setRGB(0, 0, defaultColour);
++ }
++ }
++
++ Color c = featureRenderer.findFeatureColour(seq, column + 1, g);
++ if (c == null)
++ {
++ return defaultColour;
++ }
++
++ if (g != null)
++ {
++ return offscreenImage.getRGB(0, 0);
++ }
++ return c.getRGB();
++ }
/**
* Answers true if feature display is turned off, or there are no features
* configured to be visible
*
* @return
*/
-- boolean noFeaturesDisplayed()
++ public boolean noFeaturesDisplayed()
{
if (featureRenderer == null
|| !featureRenderer.getViewport().isShowSequenceFeatures())
boxY = Math.round(vpbox.y / heightRatio);
// boxWidth is the width in residues translated to pixels
-- boxWidth = Math.round(vpbox.width / widthRatio);
++ boxWidth = Math.max(1, Math.round(vpbox.width / widthRatio));
// boxHeight is the height in sequences translated to pixels
-- boxHeight = Math.round(vpbox.height / heightRatio);
++ boxHeight = Math.max(1, Math.round(vpbox.height / heightRatio));
}
/**
boolean findingFeatures = false;
++ int nup;
++
protected boolean updateFeatures()
{
if (av.getFeaturesDisplayed() == null || renderOrder == null
|| newFeatureAdded)
{
++ System.out.println("updateFeatures " + ++nup);
findAllFeatures();
if (av.getFeaturesDisplayed().getVisibleFeatureCount() < 1)
{