JAL-244 Adjust wrapped alignment widths to always maintain a visible wrapped sequence...
[jalview.git] / src / jalview / gui / AlignmentPanel.java
index 7befa20..63455cb 100644 (file)
@@ -50,6 +50,7 @@ import jalview.api.AlignmentViewPanel;
 import jalview.bin.Cache;
 import jalview.bin.Console;
 import jalview.bin.Jalview;
+import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.SearchResultsI;
@@ -58,6 +59,7 @@ import jalview.datamodel.SequenceGroup;
 import jalview.datamodel.SequenceI;
 import jalview.gui.ImageExporter.ImageWriterI;
 import jalview.io.HTMLOutput;
+import jalview.io.exceptions.ImageOutputException;
 import jalview.jbgui.GAlignmentPanel;
 import jalview.math.AlignmentDimension;
 import jalview.schemes.ResidueProperties;
@@ -268,10 +270,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
     Dimension r = null;
     if (av.getIdWidth() < 0)
     {
-      int afwidth = (alignFrame != null ? alignFrame.getWidth() : 300);
-      int idWidth = Math.min(afwidth - 200, 2 * afwidth / 3);
-      int maxwidth = Math.max(IdwidthAdjuster.MIN_ID_WIDTH, idWidth);
-      r = calculateIdWidth(maxwidth);
+      r = calculateDefaultAlignmentIdWidth();
       av.setIdWidth(r.width);
     }
     else
@@ -293,6 +292,14 @@ public class AlignmentPanel extends GAlignmentPanel implements
     return r;
   }
 
+  public Dimension calculateDefaultAlignmentIdWidth()
+  {
+    int afwidth = (alignFrame != null ? alignFrame.getWidth() : 300);
+    int idWidth = Math.min(afwidth - 200, 2 * afwidth / 3);
+    int maxwidth = Math.max(IdwidthAdjuster.MIN_ID_WIDTH, idWidth);
+    return calculateIdWidth(-1, false, false);
+  }
+
   /**
    * Calculate the width of the alignment labels based on the displayed names
    * and any bounds on label width set in preferences.
@@ -304,6 +311,12 @@ public class AlignmentPanel extends GAlignmentPanel implements
    */
   protected Dimension calculateIdWidth(int maxwidth)
   {
+    return calculateIdWidth(maxwidth, true, false);
+  }
+
+  public Dimension calculateIdWidth(int maxwidth,
+          boolean includeAnnotations, boolean visibleOnly)
+  {
     Container c = new Container();
 
     FontMetrics fm = c.getFontMetrics(
@@ -323,18 +336,29 @@ public class AlignmentPanel extends GAlignmentPanel implements
     }
 
     // Also check annotation label widths
-    i = 0;
-
-    if (al.getAlignmentAnnotation() != null)
+    if (includeAnnotations && al.getAlignmentAnnotation() != null)
     {
-      fm = c.getFontMetrics(getAlabels().getFont());
-
-      while (i < al.getAlignmentAnnotation().length)
+      if (Jalview.isHeadlessMode())
       {
-        String label = al.getAlignmentAnnotation()[i].label;
-        int stringWidth = fm.stringWidth(label);
+        AnnotationLabels aal = this.getAlabels();
+        int stringWidth = aal.drawLabels(null, false, idWidth, false, fm);
         idWidth = Math.max(idWidth, stringWidth);
-        i++;
+      }
+      else
+      {
+        fm = c.getFontMetrics(getAlabels().getFont());
+
+        for (i = 0; i < al.getAlignmentAnnotation().length; i++)
+        {
+          AlignmentAnnotation aa = al.getAlignmentAnnotation()[i];
+          if (visibleOnly && !aa.visible)
+          {
+            continue;
+          }
+          String label = aa.label;
+          int stringWidth = fm.stringWidth(label);
+          idWidth = Math.max(idWidth, stringWidth);
+        }
       }
     }
 
@@ -566,21 +590,29 @@ public class AlignmentPanel extends GAlignmentPanel implements
     // not be called directly by programs.
     // I note that addNotify() is called in several areas of Jalview.
 
-    int annotationHeight = getAnnotationPanel().adjustPanelHeight();
-    annotationHeight = getAnnotationPanel()
-            .adjustForAlignFrame(adjustPanelHeight, annotationHeight);
+    AnnotationPanel ap = getAnnotationPanel();
+    int annotationHeight = ap.adjustPanelHeight();
+    annotationHeight = ap.adjustForAlignFrame(adjustPanelHeight,
+            annotationHeight);
 
     hscroll.addNotify();
-    annotationScroller.setPreferredSize(
-            new Dimension(annotationScroller.getWidth(), annotationHeight));
-
     Dimension e = idPanel.getSize();
-    alabels.setSize(new Dimension(e.width, annotationHeight));
+    int idWidth = e.width;
+    boolean manuallyAdjusted = this.getIdPanel().getIdCanvas()
+            .manuallyAdjusted();
+    annotationScroller.setPreferredSize(new Dimension(
+            manuallyAdjusted ? idWidth : annotationScroller.getWidth(),
+            annotationHeight));
+
+    alabels.setPreferredSize(new Dimension(idWidth, annotationHeight));
 
     annotationSpaceFillerHolder.setPreferredSize(new Dimension(
-            annotationSpaceFillerHolder.getWidth(), annotationHeight));
+            manuallyAdjusted ? idWidth
+                    : annotationSpaceFillerHolder.getWidth(),
+            annotationHeight));
     annotationScroller.validate();
     annotationScroller.addNotify();
+    ap.validate();
   }
 
   /**
@@ -598,7 +630,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
     ranges.setStartSeq(0);
     scalePanelHolder.setVisible(!wrap);
     hscroll.setVisible(!wrap);
-    idwidthAdjuster.setVisible(!wrap);
+    // Allow idPanel width adjustment in wrap mode
+    idwidthAdjuster.setVisible(true);
 
     if (wrap)
     {
@@ -632,7 +665,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
       }
     }
 
-    idSpaceFillerPanel1.setVisible(!wrap);
+    // idSpaceFillerPanel1.setVisible(!wrap);
 
     repaint();
   }
@@ -853,10 +886,24 @@ public class AlignmentPanel extends GAlignmentPanel implements
   public void paintComponent(Graphics g)
   {
     invalidate(); // needed so that the id width adjuster works correctly
-
     Dimension d = getIdPanel().getIdCanvas().getPreferredSize();
-    idPanelHolder.setPreferredSize(d);
-    hscrollFillerPanel.setPreferredSize(new Dimension(d.width, 12));
+    int idWidth = d.width;
+
+    // check wrapped alignment as at least 1 residue width
+    if (av.getWrapAlignment())
+    {
+      SeqCanvas sc = this.getSeqPanel().seqCanvas;
+      if (sc != null && sc.getWidth() < sc.getMinimumWrappedCanvasWidth())
+      {
+        // need to make some adjustments
+        idWidth -= (sc.getMinimumWrappedCanvasWidth() - sc.getWidth());
+        av.setIdWidth(idWidth);
+        validateAnnotationDimensions(false);
+      }
+    }
+
+    idPanelHolder.setPreferredSize(new Dimension(idWidth, d.height));
+    hscrollFillerPanel.setPreferredSize(new Dimension(idWidth, 12));
 
     validate(); // needed so that the id width adjuster works correctly
 
@@ -1171,10 +1218,12 @@ public class AlignmentPanel extends GAlignmentPanel implements
     }
 
     int w = getIdPanel().getWidth();
+    w = this.calculateIdWidth(-1, true, true).width;
     return (w > 0 ? w : calculateIdWidth().width);
   }
 
   void makeAlignmentImage(ImageMaker.TYPE type, File file, String renderer)
+          throws ImageOutputException
   {
     makeAlignmentImage(type, file, renderer,
             BitmapImageSizing.nullBitmapImageSizing());
@@ -1190,11 +1239,12 @@ public class AlignmentPanel extends GAlignmentPanel implements
    * @param bitmapscale
    */
   void makeAlignmentImage(ImageMaker.TYPE type, File file, String renderer,
-          BitmapImageSizing userBis)
+          BitmapImageSizing userBis) throws ImageOutputException
   {
     final int borderBottomOffset = 5;
 
     AlignmentDimension aDimension = getAlignmentDimension();
+
     // todo use a lambda function in place of callback here?
     ImageWriterI writer = new ImageWriterI()
     {
@@ -1266,6 +1316,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
   }
 
   public void makePNGImageMap(File imgMapFile, String imageName)
+          throws ImageOutputException
   {
     // /////ONLY WORKS WITH NON WRAPPED ALIGNMENTS
     // ////////////////////////////////////////////
@@ -1390,7 +1441,8 @@ public class AlignmentPanel extends GAlignmentPanel implements
 
       } catch (Exception ex)
       {
-        ex.printStackTrace();
+        throw new ImageOutputException(
+                "couldn't write ImageMap due to unexpected error", ex);
       }
     } // /////////END OF IMAGE MAP
 
@@ -1406,8 +1458,7 @@ public class AlignmentPanel extends GAlignmentPanel implements
   {
     int seqPanelWidth = getSeqPanel().seqCanvas.getWidth();
 
-    if (System.getProperty("java.awt.headless") != null
-            && System.getProperty("java.awt.headless").equals("true"))
+    if (Jalview.isHeadlessMode())
     {
       seqPanelWidth = alignFrame.getWidth() - getVisibleIdWidth()
               - vscroll.getPreferredSize().width