JAL-4159 peek in a Jalview project's PCA viewer's title to decide if it is a "pasimap...
[jalview.git] / src / jalview / gui / PaSiMapPanel.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.gui;
22
23 import jalview.analysis.scoremodels.ScoreModels;
24 import jalview.api.AlignViewportI;
25 import jalview.api.analysis.ScoreModelI;
26 import jalview.api.analysis.SimilarityParamsI;
27 import jalview.bin.Console;
28 import jalview.datamodel.Alignment;
29 import jalview.datamodel.AlignmentI;
30 import jalview.datamodel.AlignmentView;
31 import jalview.datamodel.HiddenColumns;
32 import jalview.datamodel.SequenceGroup;
33 import jalview.datamodel.SequenceI;
34 import jalview.gui.ImageExporter.ImageWriterI;
35 import jalview.gui.JalviewColourChooser.ColourChooserListener;
36 import jalview.jbgui.GPaSiMapPanel;
37 import jalview.math.RotatableMatrix.Axis;
38 import jalview.util.ImageMaker;
39 import jalview.util.MessageManager;
40 import jalview.viewmodel.AlignmentViewport;
41 import jalview.viewmodel.PaSiMapModel;
42
43 import java.awt.BorderLayout;
44 import java.awt.Color;
45 import java.awt.Dimension;
46 import java.awt.Graphics;
47 import java.awt.event.ActionEvent;
48 import java.awt.event.ActionListener;
49 import java.awt.print.PageFormat;
50 import java.awt.print.Printable;
51 import java.awt.print.PrinterException;
52 import java.awt.print.PrinterJob;
53 import java.beans.PropertyChangeEvent;
54 import java.beans.PropertyChangeListener;
55
56 import javax.swing.ButtonGroup;
57 import javax.swing.JMenuItem;
58 import javax.swing.JProgressBar;
59 import javax.swing.JRadioButtonMenuItem;
60 import javax.swing.event.InternalFrameAdapter;
61 import javax.swing.event.InternalFrameEvent;
62
63 /**
64  * The panel holding the Pairwise Similarity Map 3-D visualisation
65  */
66 public class PaSiMapPanel extends GPaSiMapPanel
67         implements Runnable, IProgressIndicator
68 {
69   private static final int MIN_WIDTH = 470;
70
71   private static final int MIN_HEIGHT = 250;
72
73   private static final int MAX_PASIMAP_SEQ = 20000;
74
75   private final int GAP_OPEN_COST = 100;
76
77   private final int GAP_EXTEND_COST = 5;
78
79   private RotatableCanvas rc;
80
81   AlignmentPanel ap;
82
83   AlignmentViewport av;
84
85   private PaSiMapModel pasimapModel;
86
87   private int top = 0;
88
89   private IProgressIndicator progressBar;
90
91   private long progId;
92
93   private boolean working;
94
95   /**
96    * Constructor given sequence data, a similarity (or distance) score model
97    * name, and score calculation parameters
98    * 
99    * @param alignPanel
100    * @param modelName
101    */
102   public PaSiMapPanel(AlignmentPanel alignPanel, String modelName)
103   {
104     super(8);   // dim = 8
105     this.av = alignPanel.av;
106     this.ap = alignPanel;
107     boolean nucleotide = av.getAlignment().isNucleotide();
108
109     //progressBar = new ProgressBar(statusPanel, statusBar);
110
111     addInternalFrameListener(new InternalFrameAdapter()
112     {
113       @Override
114       public void internalFrameClosed(InternalFrameEvent e)
115       {
116         close_actionPerformed();
117       }
118     });
119
120     boolean selected = av.getSelectionGroup() != null
121             && av.getSelectionGroup().getSize() > 0;
122     SequenceI[] seqs;
123     if (!selected)
124     {
125       seqs = av.getAlignment().getSequencesArray();
126     }
127     else
128     {
129       seqs = av.getSelectionGroup().getSequencesInOrder(av.getAlignment());
130     }
131
132     ScoreModelI scoreModel = ScoreModels.getInstance()
133             .getScoreModel(modelName, ap);
134     setPasimapModel(
135             new PaSiMapModel(av, seqs, nucleotide, scoreModel));
136     PaintRefresher.Register(this, av.getSequenceSetId());
137
138     setRotatableCanvas(new RotatableCanvas(alignPanel));
139     this.getContentPane().add(getRotatableCanvas(), BorderLayout.CENTER);
140
141     addKeyListener(getRotatableCanvas());
142     validate();
143   }
144
145   /**
146    * Ensure references to potentially very large objects (the PaSiMap matrices) are
147    * nulled when the frame is closed
148    */
149   protected void close_actionPerformed()
150   {
151     setPasimapModel(null);
152     if (this.rc != null)
153     {
154       this.rc.sequencePoints = null;
155       this.rc.setAxisEndPoints(null);
156       this.rc = null;
157     }
158   }
159
160   @Override
161   protected void bgcolour_actionPerformed()
162   {
163     String ttl = MessageManager.getString("label.select_background_colour");
164     ColourChooserListener listener = new ColourChooserListener()
165     {
166       @Override
167       public void colourSelected(Color c)
168       {
169         rc.setBgColour(c);
170         rc.repaint();
171       }
172     };
173     JalviewColourChooser.showColourChooser(this, ttl, rc.getBgColour(),
174             listener);
175   }
176
177   /**
178    * Calculates the PaSiMap and displays the results
179    */
180   @Override
181   public void run()
182   {
183     working = true;
184     progId = System.currentTimeMillis();
185     progressBar = this;
186     String message = MessageManager
187             .getString("label.pasimap_recalculating");
188     if (getParent() == null)
189     {
190       progressBar = ap.alignFrame;
191       message = MessageManager.getString("label.pasimap_calculating");
192     }
193     progressBar.setProgressBar(message, progId);
194     try
195     {
196       SequenceGroup selGroup=av.getSelectionGroup();
197       
198       if (selGroup==null)
199       {
200         selGroup = new SequenceGroup(av.getAlignment().getSequences());
201         selGroup.setStartRes(0);
202         selGroup.setEndRes(av.getAlignment().getWidth()-1);
203       }
204       
205       if (selGroup.getSize()>MAX_PASIMAP_SEQ)
206       {
207         int start = selGroup.getStartRes(),end=selGroup.getEndRes();
208           selGroup = new SequenceGroup(selGroup.getSequences().subList(0, MAX_PASIMAP_SEQ));
209           selGroup.setStartRes(start);
210           selGroup.setEndRes(end);
211           Console.warn("Truncated input sequences for PASIMAP analysis to "+MAX_PASIMAP_SEQ);
212       }
213       
214       PairwiseAlignPanel pap = new PairwiseAlignPanel(av, selGroup, true,
215               GAP_OPEN_COST, GAP_EXTEND_COST, false, null);
216       pap.setDiscardAlignments(true);
217       pap.setQuiet(true);
218       
219       System.out.println(pap != null);
220       setPairwiseAlignPanel(pap);
221       getPasimapModel().calculate(pap);
222
223       xCombobox.setSelectedIndex(0);
224       yCombobox.setSelectedIndex(1);
225       zCombobox.setSelectedIndex(2);
226
227       getPasimapModel().updateRc(getRotatableCanvas());
228       // rc.invalidate();
229       setTop(getPasimapModel().getTop());
230
231     } catch (OutOfMemoryError er)
232     {
233       new OOMWarning("calculating PaSiMap", er);
234       working = false;
235       return;
236     } finally
237     {
238       progressBar.setProgressBar("", progId);
239     }
240
241     repaint();
242     if (getParent() == null)
243     {
244       Desktop.addInternalFrame(
245               this, MessageManager.formatMessage("label.calc_title",
246                       "PaSiMap", ap.alignFrame.getTitle()),
247               475, 450);
248       this.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
249     }
250     working = false;
251   }
252
253   /**
254    * Updates the PaSiMap display after a change of component to use for x, y or z
255    * axis
256    */
257   @Override
258   protected void doDimensionChange()
259   {
260     if (getTop() == 0)
261     {
262       return;
263     }
264
265     int dim1 = getTop() - xCombobox.getSelectedIndex();
266     int dim2 = getTop() - yCombobox.getSelectedIndex();
267     int dim3 = getTop() - zCombobox.getSelectedIndex();
268     getPasimapModel().updateRcView(dim1, dim2, dim3);
269     getRotatableCanvas().resetView();
270   }
271
272   /**
273    * Sets the selected checkbox item index for PaSiMap dimension (1, 2, 3...) for
274    * the given axis (X/Y/Z)
275    * 
276    * @param index
277    * @param axis
278    */
279   public void setSelectedDimensionIndex(int index, Axis axis)
280   {
281     switch (axis)
282     {
283     case X:
284       xCombobox.setSelectedIndex(index);
285       break;
286     case Y:
287       yCombobox.setSelectedIndex(index);
288       break;
289     case Z:
290       zCombobox.setSelectedIndex(index);
291       break;
292     default:
293     }
294   }
295
296   @Override
297   protected void outputValues_actionPerformed()
298   {
299     CutAndPasteTransfer cap = new CutAndPasteTransfer();
300     try
301     {
302       cap.setText(getPasimapModel().getDetails());
303       Desktop.addInternalFrame(cap,
304               MessageManager.getString("label.pasimap_details"), 500, 500);
305     } catch (OutOfMemoryError oom)
306     {
307       new OOMWarning("opening PaSiMap details", oom);
308       cap.dispose();
309     }
310   }
311
312   @Override
313   protected void showLabels_actionPerformed()
314   {
315     getRotatableCanvas().showLabels(showLabels.getState());
316   }
317
318   @Override
319   protected void print_actionPerformed()
320   {
321     PaSiMapPrinter printer = new PaSiMapPrinter();
322     printer.start();
323   }
324
325   /**
326    * If available, shows the data which formed the inputs for the PaSiMap as a new
327    * alignment
328    */
329   @Override
330   public void originalSeqData_actionPerformed()
331   {
332     // JAL-2647 disabled after load from project (until save to project done)
333     if (getPasimapModel().getInputData() == null)
334     {
335       Console.info(
336               "Unexpected call to originalSeqData_actionPerformed - should have hidden this menu action.");
337       return;
338     }
339     // decide if av alignment is sufficiently different to original data to
340     // warrant a new window to be created
341     // create new alignment window with hidden regions (unhiding hidden regions
342     // yields unaligned seqs)
343     // or create a selection box around columns in alignment view
344     // test Alignment(SeqCigar[])
345     char gc = '-';
346     try
347     {
348       // we try to get the associated view's gap character
349       // but this may fail if the view was closed...
350       gc = av.getGapCharacter();
351     } catch (Exception ex)
352     {
353     }
354
355     Object[] alAndColsel = getPasimapModel().getInputData()
356             .getAlignmentView(false).getAlignmentAndHiddenColumns(gc);
357
358     if (alAndColsel != null && alAndColsel[0] != null)
359     {
360       // AlignmentOrder origorder = new AlignmentOrder(alAndColsel[0]);
361
362       AlignmentI al = new Alignment((SequenceI[]) alAndColsel[0]);
363       AlignmentI dataset = (av != null && av.getAlignment() != null)
364               ? av.getAlignment().getDataset()
365               : null;
366       if (dataset != null)
367       {
368         al.setDataset(dataset);
369       }
370
371       if (true)
372       {
373         // make a new frame!
374         AlignFrame af = new AlignFrame(al, (HiddenColumns) alAndColsel[1],
375                 AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
376
377         // >>>This is a fix for the moment, until a better solution is
378         // found!!<<<
379         // af.getFeatureRenderer().transferSettings(alignFrame.getFeatureRenderer());
380
381         // af.addSortByOrderMenuItem(ServiceName + " Ordering",
382         // msaorder);
383
384         Desktop.addInternalFrame(af, MessageManager.formatMessage(
385                 "label.original_data_for_params", new String[]
386                 { this.title }), AlignFrame.DEFAULT_WIDTH,
387                 AlignFrame.DEFAULT_HEIGHT);
388       }
389     }
390     /*
391      * CutAndPasteTransfer cap = new CutAndPasteTransfer(); for (int i = 0; i <
392      * seqs.length; i++) { cap.appendText(new jalview.util.Format("%-" + 15 +
393      * "s").form( seqs[i].getName())); cap.appendText(" " + seqstrings[i] +
394      * "\n"); }
395      * 
396      * Desktop.addInternalFrame(cap, "Original Data", 400, 400);
397      */
398   }
399
400   class PaSiMapPrinter extends Thread implements Printable
401   {
402     @Override
403     public void run()
404     {
405       PrinterJob printJob = PrinterJob.getPrinterJob();
406       PageFormat defaultPage = printJob.defaultPage();
407       PageFormat pf = printJob.pageDialog(defaultPage);
408
409       if (defaultPage == pf)
410       {
411         /*
412          * user cancelled
413          */
414         return;
415       }
416
417       printJob.setPrintable(this, pf);
418
419       if (printJob.printDialog())
420       {
421         try
422         {
423           printJob.print();
424         } catch (Exception PrintException)
425         {
426           PrintException.printStackTrace();
427         }
428       }
429     }
430
431     @Override
432     public int print(Graphics pg, PageFormat pf, int pi)
433             throws PrinterException
434     {
435       pg.translate((int) pf.getImageableX(), (int) pf.getImageableY());
436
437       getRotatableCanvas().drawBackground(pg);
438       getRotatableCanvas().drawScene(pg);
439       if (getRotatableCanvas().drawAxes)
440       {
441         getRotatableCanvas().drawAxes(pg);
442       }
443
444       if (pi == 0)
445       {
446         return Printable.PAGE_EXISTS;
447       }
448       else
449       {
450         return Printable.NO_SUCH_PAGE;
451       }
452     }
453   }
454
455   public void makePaSiMapImage(ImageMaker.TYPE type)  throws Exception
456   {
457     int width = getRotatableCanvas().getWidth();
458     int height = getRotatableCanvas().getHeight();
459     ImageWriterI writer = new ImageWriterI()
460     {
461       @Override
462       public void exportImage(Graphics g) throws Exception
463       {
464         RotatableCanvas canvas = getRotatableCanvas();
465         canvas.drawBackground(g);
466         canvas.drawScene(g);
467         if (canvas.drawAxes)
468         {
469           canvas.drawAxes(g);
470         }
471       }
472     };
473     String pasimap = MessageManager.getString("label.pasimap");
474     ImageExporter exporter = new ImageExporter(writer, null, type, pasimap);
475     exporter.doExport(null, this, width, height, pasimap);
476   }
477
478   @Override
479   protected void viewMenu_menuSelected()
480   {
481     buildAssociatedViewMenu();
482   }
483
484   /**
485    * Builds the menu showing the choice of possible views (for the associated
486    * sequence data) to which the PaSiMap may be linked
487    */
488   void buildAssociatedViewMenu()
489   {
490     AlignmentPanel[] aps = PaintRefresher
491             .getAssociatedPanels(av.getSequenceSetId());
492     if (aps.length == 1 && getRotatableCanvas().av == aps[0].av)
493     {
494       associateViewsMenu.setVisible(false);
495       return;
496     }
497
498     associateViewsMenu.setVisible(true);
499
500     if ((viewMenu
501             .getItem(viewMenu.getItemCount() - 2) instanceof JMenuItem))
502     {
503       viewMenu.insertSeparator(viewMenu.getItemCount() - 1);
504     }
505
506     associateViewsMenu.removeAll();
507
508     JRadioButtonMenuItem item;
509     ButtonGroup buttonGroup = new ButtonGroup();
510     int iSize = aps.length;
511
512     for (int i = 0; i < iSize; i++)
513     {
514       final AlignmentPanel panel = aps[i];
515       item = new JRadioButtonMenuItem(panel.av.getViewName(),
516               panel.av == getRotatableCanvas().av);
517       buttonGroup.add(item);
518       item.addActionListener(new ActionListener()
519       {
520         @Override
521         public void actionPerformed(ActionEvent evt)
522         {
523           selectAssociatedView(panel);
524         }
525       });
526
527       associateViewsMenu.add(item);
528     }
529
530     final JRadioButtonMenuItem itemf = new JRadioButtonMenuItem(
531             "All Views");
532
533     buttonGroup.add(itemf);
534
535     itemf.setSelected(getRotatableCanvas().isApplyToAllViews());
536     itemf.addActionListener(new ActionListener()
537     {
538       @Override
539       public void actionPerformed(ActionEvent evt)
540       {
541         getRotatableCanvas().setApplyToAllViews(itemf.isSelected());
542       }
543     });
544     associateViewsMenu.add(itemf);
545
546   }
547
548   /*
549    * (non-Javadoc)
550    * 
551    * @see
552    * jalview.jbgui.GPaSiMapPanel#outputPoints_actionPerformed(java.awt.event.ActionEvent
553    * )
554    */
555   @Override
556   protected void outputPoints_actionPerformed()
557   {
558     CutAndPasteTransfer cap = new CutAndPasteTransfer();
559     try
560     {
561       cap.setText(getPasimapModel().getPointsasCsv(false,
562               xCombobox.getSelectedIndex(), yCombobox.getSelectedIndex(),
563               zCombobox.getSelectedIndex()));
564       Desktop.addInternalFrame(cap, MessageManager
565               .formatMessage("label.points_for_params", new String[]
566               { this.getTitle() }), 500, 500);
567     } catch (OutOfMemoryError oom)
568     {
569       new OOMWarning("exporting PaSiMap points", oom);
570       cap.dispose();
571     }
572   }
573
574   /*
575    * (non-Javadoc)
576    * 
577    * @see
578    * jalview.jbgui.GPaSiMapPanel#outputProjPoints_actionPerformed(java.awt.event
579    * .ActionEvent)
580    */
581   @Override
582   protected void outputProjPoints_actionPerformed()
583   {
584     CutAndPasteTransfer cap = new CutAndPasteTransfer();
585     try
586     {
587       cap.setText(getPasimapModel().getPointsasCsv(true,
588               xCombobox.getSelectedIndex(), yCombobox.getSelectedIndex(),
589               zCombobox.getSelectedIndex()));
590       Desktop.addInternalFrame(cap, MessageManager.formatMessage(
591               "label.transformed_points_for_params", new String[]
592               { this.getTitle() }), 500, 500);
593     } catch (OutOfMemoryError oom)
594     {
595       new OOMWarning("exporting transformed PaSiMap points", oom);
596       cap.dispose();
597     }
598   }
599
600   /*
601    * (non-Javadoc)
602    * 
603    * @see
604    * jalview.jbgui.GPaSiMapPanel#outputAlignment_actionPerformed(java.awt.event
605    * .ActionEvent)
606    */
607   @Override
608   protected void outputAlignment_actionPerformed()
609   {
610     CutAndPasteTransfer cap = new CutAndPasteTransfer();
611     try
612     {
613       cap.setText(getPasimapModel().getAlignmentOutput());
614       Desktop.addInternalFrame(cap, MessageManager.formatMessage(
615         "label.pairwise_alignment_for_params", new String[] { this.getTitle() }), 500, 500);
616     } catch (OutOfMemoryError oom)
617     {
618       new OOMWarning("exporting pairwise alignments", oom);
619       cap.dispose();
620     }
621   }
622
623   /*
624    * (non-Javadoc)
625    * 
626    * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
627    */
628   @Override
629   public void setProgressBar(String message, long id)
630   {
631     progressBar.setProgressBar(message, id);
632     // if (progressBars == null)
633     // {
634     // progressBars = new Hashtable();
635     // progressBarHandlers = new Hashtable();
636     // }
637     //
638     // JPanel progressPanel;
639     // Long lId = Long.valueOf(id);
640     // GridLayout layout = (GridLayout) statusPanel.getLayout();
641     // if (progressBars.get(lId) != null)
642     // {
643     // progressPanel = (JPanel) progressBars.get(Long.valueOf(id));
644     // statusPanel.remove(progressPanel);
645     // progressBars.remove(lId);
646     // progressPanel = null;
647     // if (message != null)
648     // {
649     // statusBar.setText(message);
650     // }
651     // if (progressBarHandlers.contains(lId))
652     // {
653     // progressBarHandlers.remove(lId);
654     // }
655     // layout.setRows(layout.getRows() - 1);
656     // }
657     // else
658     // {
659     // progressPanel = new JPanel(new BorderLayout(10, 5));
660     //
661     // JProgressBar progressBar = new JProgressBar();
662     // progressBar.setIndeterminate(true);
663     //
664     // progressPanel.add(new JLabel(message), BorderLayout.WEST);
665     // progressPanel.add(progressBar, BorderLayout.CENTER);
666     //
667     // layout.setRows(layout.getRows() + 1);
668     // statusPanel.add(progressPanel);
669     //
670     // progressBars.put(lId, progressPanel);
671     // }
672     // // update GUI
673     // // setMenusForViewport();
674     // validate();
675   }
676
677   /*
678    * make the progressBar determinate and update its progress
679   */
680   public void updateProgressBar(int lengthOfTask, int progress)
681   {
682     JProgressBar pBar = progressBar.getProgressBar(progId);
683     if (pBar==null)
684     {
685       return;
686     }
687     if (pBar.isIndeterminate())
688     {
689       pBar.setMaximum(lengthOfTask);
690       pBar.setValue(0);
691       pBar.setIndeterminate(false);
692     }
693     updateProgressBar(progress);
694   }
695   public void updateProgressBar(int progress)
696   {
697     JProgressBar pBar = progressBar.getProgressBar(progId);
698     
699     if (pBar==null)
700     {
701       return;
702     }
703     
704     pBar.setValue(progress);
705     pBar.repaint();
706   }
707
708   /**
709    * adds a listener for a pairwise alignment panel's progress
710    * TODO: generalise for anything that can report progress ?
711    * @param pap
712    */
713   public void setPairwiseAlignPanel(PairwiseAlignPanel pap)
714   {
715     pap.addPropertyChangeListener(new PropertyChangeListener()
716     {
717       @Override
718       public void propertyChange(PropertyChangeEvent pcEvent)
719       {
720         if (PairwiseAlignPanel.PROGRESS.equals(pcEvent.getPropertyName()))
721         {
722           updateProgressBar((int) pcEvent.getNewValue());
723         }
724         else if (PairwiseAlignPanel.TOTAL.equals(pcEvent.getPropertyName()))
725         {
726           updateProgressBar((int) pcEvent.getNewValue(), 0);
727         }
728       }
729     });
730   }
731
732   @Override
733   public void registerHandler(final long id,
734           final IProgressIndicatorHandler handler)
735   {
736     progressBar.registerHandler(id, handler);
737     // if (progressBarHandlers == null ||
738     // !progressBars.contains(Long.valueOf(id)))
739     // {
740     // throw new
741     // Error(MessageManager.getString("error.call_setprogressbar_before_registering_handler"));
742     // }
743     // progressBarHandlers.put(Long.valueOf(id), handler);
744     // final JPanel progressPanel = (JPanel) progressBars.get(Long.valueOf(id));
745     // if (handler.canCancel())
746     // {
747     // JButton cancel = new JButton(
748     // MessageManager.getString("action.cancel"));
749     // final IProgressIndicator us = this;
750     // cancel.addActionListener(new ActionListener()
751     // {
752     //
753     // @Override
754     // public void actionPerformed(ActionEvent e)
755     // {
756     // handler.cancelActivity(id);
757     // us.setProgressBar(MessageManager.formatMessage("label.cancelled_params",
758     // new String[]{((JLabel) progressPanel.getComponent(0)).getText()}), id);
759     // }
760     // });
761     // progressPanel.add(cancel, BorderLayout.EAST);
762     // }
763   }
764
765   /**
766    * 
767    * @return true if any progress bars are still active
768    */
769   @Override
770   public boolean operationInProgress()
771   {
772     return progressBar.operationInProgress();
773   }
774
775   @Override
776   protected void resetButton_actionPerformed()
777   {
778     int t = getTop();
779     setTop(0); // ugly - prevents dimensionChanged events from being processed
780     xCombobox.setSelectedIndex(0);
781     yCombobox.setSelectedIndex(1);
782     setTop(t);
783     zCombobox.setSelectedIndex(2);
784   }
785
786   /**
787    * Answers true if PaSiMap calculation is in progress, else false
788    * 
789    * @return
790    */
791   public boolean isWorking()
792   {
793     return working;
794   }
795
796   /**
797    * Answers the selected checkbox item index for PaSiMap dimension for the X, Y or
798    * Z axis of the display
799    * 
800    * @param axis
801    * @return
802    */
803   public int getSelectedDimensionIndex(Axis axis)
804   {
805     switch (axis)
806     {
807     case X:
808       return xCombobox.getSelectedIndex();
809     case Y:
810       return yCombobox.getSelectedIndex();
811     default:
812       return zCombobox.getSelectedIndex();
813     }
814   }
815
816   public void setShowLabels(boolean show)
817   {
818     showLabels.setSelected(show);
819   }
820
821   /**
822    * Sets the input data used to calculate the PaSiMap. This is provided for
823    * 'restore from project', which does not currently support this (AL-2647), so
824    * sets the value to null, and hides the menu option for "Input Data...". J
825    * 
826    * @param data
827    */
828   public void setInputData(AlignmentViewport data)
829   {
830     getPasimapModel().setInputData(data);
831     originalSeqData.setVisible(data != null);
832   }
833
834   public AlignViewportI getAlignViewport()
835   {
836     return av;
837   }
838
839   public PaSiMapModel getPasimapModel()
840   {
841     return pasimapModel;
842   }
843
844   public void setPasimapModel(PaSiMapModel pasimapModel)
845   {
846     this.pasimapModel = pasimapModel;
847   }
848
849   public RotatableCanvas getRotatableCanvas()
850   {
851     return rc;
852   }
853
854   public void setRotatableCanvas(RotatableCanvas rc)
855   {
856     this.rc = rc;
857   }
858
859   public int getTop()
860   {
861     return top;
862   }
863
864   public void setTop(int top)
865   {
866     this.top = top;
867   }
868
869   /**
870    * set the associated view for this PaSiMap.
871    * 
872    * @param panel
873    */
874   public void selectAssociatedView(AlignmentPanel panel)
875   {
876     getRotatableCanvas().setApplyToAllViews(false);
877
878     ap = panel;
879     av = panel.av;
880
881     getRotatableCanvas().av = panel.av;
882     getRotatableCanvas().ap = panel;
883     PaintRefresher.Register(PaSiMapPanel.this, panel.av.getSequenceSetId());
884   }
885
886   @Override
887   public JProgressBar getProgressBar(long id)
888   {
889     return progressBar.getProgressBar(id);
890   }
891 }