6ee243eedff1a43cf9d21c61d6b150d396e70a6e
[jalview.git] / src / jalview / gui / AlignFrame.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.5)
3  * Copyright (C) 2010 J Procter, AM Waterhouse, G Barton, M Clamp, S Searle
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 of the License, or (at your option) any later version.
10  * 
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.gui;
19
20 import java.beans.*;
21 import java.io.*;
22 import java.util.*;
23
24 import java.awt.*;
25 import java.awt.datatransfer.*;
26 import java.awt.dnd.*;
27 import java.awt.event.*;
28 import java.awt.print.*;
29 import javax.swing.*;
30 import javax.swing.event.MenuEvent;
31
32 import jalview.analysis.*;
33 import jalview.bin.Cache;
34 import jalview.commands.*;
35 import jalview.datamodel.*;
36 import jalview.io.*;
37 import jalview.jbgui.*;
38 import jalview.schemes.*;
39 import jalview.ws.*;
40 import jalview.ws.jws1.Discoverer;
41 import jalview.ws.jws2.Jws2Discoverer;
42
43 /**
44  * DOCUMENT ME!
45  * 
46  * @author $author$
47  * @version $Revision$
48  */
49 public class AlignFrame extends GAlignFrame implements DropTargetListener,
50         IProgressIndicator
51 {
52
53   /** DOCUMENT ME!! */
54   public static final int DEFAULT_WIDTH = 700;
55
56   /** DOCUMENT ME!! */
57   public static final int DEFAULT_HEIGHT = 500;
58
59   public AlignmentPanel alignPanel;
60
61   AlignViewport viewport;
62
63   Vector alignPanels = new Vector();
64
65   /**
66    * Last format used to load or save alignments in this window
67    */
68   String currentFileFormat = null;
69
70   /**
71    * Current filename for this alignment
72    */
73   String fileName = null;
74
75   /**
76    * Creates a new AlignFrame object with specific width and height.
77    * 
78    * @param al
79    * @param width
80    * @param height
81    */
82   public AlignFrame(AlignmentI al, int width, int height)
83   {
84     this(al, null, width, height);
85   }
86
87   /**
88    * Creates a new AlignFrame object with specific width, height and
89    * sequenceSetId
90    * 
91    * @param al
92    * @param width
93    * @param height
94    * @param sequenceSetId
95    */
96   public AlignFrame(AlignmentI al, int width, int height,
97           String sequenceSetId)
98   {
99     this(al, null, width, height, sequenceSetId);
100   }
101
102   /**
103    * Creates a new AlignFrame object with specific width, height and
104    * sequenceSetId
105    * 
106    * @param al
107    * @param width
108    * @param height
109    * @param sequenceSetId
110    * @param viewId
111    */
112   public AlignFrame(AlignmentI al, int width, int height,
113           String sequenceSetId, String viewId)
114   {
115     this(al, null, width, height, sequenceSetId, viewId);
116   }
117
118   /**
119    * new alignment window with hidden columns
120    * 
121    * @param al
122    *          AlignmentI
123    * @param hiddenColumns
124    *          ColumnSelection or null
125    * @param width
126    *          Width of alignment frame
127    * @param height
128    *          height of frame.
129    */
130   public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
131           int width, int height)
132   {
133     this(al, hiddenColumns, width, height, null);
134   }
135
136   /**
137    * Create alignment frame for al with hiddenColumns, a specific width and
138    * height, and specific sequenceId
139    * 
140    * @param al
141    * @param hiddenColumns
142    * @param width
143    * @param height
144    * @param sequenceSetId
145    *          (may be null)
146    */
147   public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
148           int width, int height, String sequenceSetId)
149   {
150     this(al, hiddenColumns, width, height, sequenceSetId, null);
151   }
152
153   /**
154    * Create alignment frame for al with hiddenColumns, a specific width and
155    * height, and specific sequenceId
156    * 
157    * @param al
158    * @param hiddenColumns
159    * @param width
160    * @param height
161    * @param sequenceSetId
162    *          (may be null)
163    * @param viewId
164    *          (may be null)
165    */
166   public AlignFrame(AlignmentI al, ColumnSelection hiddenColumns,
167           int width, int height, String sequenceSetId, String viewId)
168   {
169     setSize(width, height);
170     viewport = new AlignViewport(al, hiddenColumns, sequenceSetId, viewId);
171
172     alignPanel = new AlignmentPanel(this, viewport);
173
174     if (al.getDataset() == null)
175     {
176       al.setDataset(null);
177     }
178
179     addAlignmentPanel(alignPanel, true);
180     init();
181   }
182
183   /**
184    * Make a new AlignFrame from exisiting alignmentPanels
185    * 
186    * @param ap
187    *          AlignmentPanel
188    * @param av
189    *          AlignViewport
190    */
191   public AlignFrame(AlignmentPanel ap)
192   {
193     viewport = ap.av;
194     alignPanel = ap;
195     addAlignmentPanel(ap, false);
196     init();
197   }
198
199   /**
200    * initalise the alignframe from the underlying viewport data and the
201    * configurations
202    */
203   void init()
204   {
205     if (viewport.conservation == null)
206     {
207       BLOSUM62Colour.setEnabled(false);
208       conservationMenuItem.setEnabled(false);
209       modifyConservation.setEnabled(false);
210       // PIDColour.setEnabled(false);
211       // abovePIDThreshold.setEnabled(false);
212       // modifyPID.setEnabled(false);
213     }
214
215     String sortby = jalview.bin.Cache.getDefault("SORT_ALIGNMENT",
216             "No sort");
217
218     if (sortby.equals("Id"))
219     {
220       sortIDMenuItem_actionPerformed(null);
221     }
222     else if (sortby.equals("Pairwise Identity"))
223     {
224       sortPairwiseMenuItem_actionPerformed(null);
225     }
226
227     if (Desktop.desktop != null)
228     {
229       this.setDropTarget(new java.awt.dnd.DropTarget(this, this));
230       addServiceListeners();
231       setGUINucleotide(viewport.alignment.isNucleotide());
232     }
233
234     setMenusFromViewport(viewport);
235     buildSortByAnnotationScoresMenu();
236     if (viewport.wrapAlignment)
237     {
238       wrapMenuItem_actionPerformed(null);
239     }
240
241     if (jalview.bin.Cache.getDefault("SHOW_OVERVIEW", false))
242     {
243       this.overviewMenuItem_actionPerformed(null);
244     }
245
246     addKeyListener();
247
248   }
249
250   /**
251    * Change the filename and format for the alignment, and enable the 'reload'
252    * button functionality.
253    * 
254    * @param file
255    *          valid filename
256    * @param format
257    *          format of file
258    */
259   public void setFileName(String file, String format)
260   {
261     fileName = file;
262     currentFileFormat = format;
263     reload.setEnabled(true);
264   }
265
266   void addKeyListener()
267   {
268     addKeyListener(new KeyAdapter()
269     {
270       public void keyPressed(KeyEvent evt)
271       {
272         if (viewport.cursorMode
273                 && ((evt.getKeyCode() >= KeyEvent.VK_0 && evt.getKeyCode() <= KeyEvent.VK_9) || (evt
274                         .getKeyCode() >= KeyEvent.VK_NUMPAD0 && evt
275                         .getKeyCode() <= KeyEvent.VK_NUMPAD9))
276                 && Character.isDigit(evt.getKeyChar()))
277           alignPanel.seqPanel.numberPressed(evt.getKeyChar());
278
279         switch (evt.getKeyCode())
280         {
281
282         case 27: // escape key
283           deselectAllSequenceMenuItem_actionPerformed(null);
284
285           break;
286
287         case KeyEvent.VK_DOWN:
288           if (evt.isAltDown() || !viewport.cursorMode)
289             moveSelectedSequences(false);
290           if (viewport.cursorMode)
291             alignPanel.seqPanel.moveCursor(0, 1);
292           break;
293
294         case KeyEvent.VK_UP:
295           if (evt.isAltDown() || !viewport.cursorMode)
296             moveSelectedSequences(true);
297           if (viewport.cursorMode)
298             alignPanel.seqPanel.moveCursor(0, -1);
299
300           break;
301
302         case KeyEvent.VK_LEFT:
303           if (evt.isAltDown() || !viewport.cursorMode)
304             slideSequences(false, alignPanel.seqPanel.getKeyboardNo1());
305           else
306             alignPanel.seqPanel.moveCursor(-1, 0);
307
308           break;
309
310         case KeyEvent.VK_RIGHT:
311           if (evt.isAltDown() || !viewport.cursorMode)
312             slideSequences(true, alignPanel.seqPanel.getKeyboardNo1());
313           else
314             alignPanel.seqPanel.moveCursor(1, 0);
315           break;
316
317         case KeyEvent.VK_SPACE:
318           if (viewport.cursorMode)
319           {
320             alignPanel.seqPanel.insertGapAtCursor(evt.isControlDown()
321                     || evt.isShiftDown() || evt.isAltDown());
322           }
323           break;
324
325         case KeyEvent.VK_DELETE:
326         case KeyEvent.VK_BACK_SPACE:
327           if (!viewport.cursorMode)
328           {
329             cut_actionPerformed(null);
330           }
331           else
332           {
333             alignPanel.seqPanel.deleteGapAtCursor(evt.isControlDown()
334                     || evt.isShiftDown() || evt.isAltDown());
335           }
336
337           break;
338
339         case KeyEvent.VK_S:
340           if (viewport.cursorMode)
341           {
342             alignPanel.seqPanel.setCursorRow();
343           }
344           break;
345         case KeyEvent.VK_C:
346           if (viewport.cursorMode && !evt.isControlDown())
347           {
348             alignPanel.seqPanel.setCursorColumn();
349           }
350           break;
351         case KeyEvent.VK_P:
352           if (viewport.cursorMode)
353           {
354             alignPanel.seqPanel.setCursorPosition();
355           }
356           break;
357
358         case KeyEvent.VK_ENTER:
359         case KeyEvent.VK_COMMA:
360           if (viewport.cursorMode)
361           {
362             alignPanel.seqPanel.setCursorRowAndColumn();
363           }
364           break;
365
366         case KeyEvent.VK_Q:
367           if (viewport.cursorMode)
368           {
369             alignPanel.seqPanel.setSelectionAreaAtCursor(true);
370           }
371           break;
372         case KeyEvent.VK_M:
373           if (viewport.cursorMode)
374           {
375             alignPanel.seqPanel.setSelectionAreaAtCursor(false);
376           }
377           break;
378
379         case KeyEvent.VK_F2:
380           viewport.cursorMode = !viewport.cursorMode;
381           statusBar.setText("Keyboard editing mode is "
382                   + (viewport.cursorMode ? "on" : "off"));
383           if (viewport.cursorMode)
384           {
385             alignPanel.seqPanel.seqCanvas.cursorX = viewport.startRes;
386             alignPanel.seqPanel.seqCanvas.cursorY = viewport.startSeq;
387           }
388           alignPanel.seqPanel.seqCanvas.repaint();
389           break;
390
391         case KeyEvent.VK_F1:
392           try
393           {
394             ClassLoader cl = jalview.gui.Desktop.class.getClassLoader();
395             java.net.URL url = javax.help.HelpSet.findHelpSet(cl,
396                     "help/help");
397             javax.help.HelpSet hs = new javax.help.HelpSet(cl, url);
398
399             javax.help.HelpBroker hb = hs.createHelpBroker();
400             hb.setCurrentID("home");
401             hb.setDisplayed(true);
402           } catch (Exception ex)
403           {
404             ex.printStackTrace();
405           }
406           break;
407         case KeyEvent.VK_H:
408         {
409           boolean toggleSeqs = !evt.isControlDown();
410           boolean toggleCols = !evt.isShiftDown();
411           toggleHiddenRegions(toggleSeqs, toggleCols);
412           break;
413         }
414         case KeyEvent.VK_PAGE_UP:
415           if (viewport.wrapAlignment)
416           {
417             alignPanel.scrollUp(true);
418           }
419           else
420           {
421             alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
422                     - viewport.endSeq + viewport.startSeq);
423           }
424           break;
425         case KeyEvent.VK_PAGE_DOWN:
426           if (viewport.wrapAlignment)
427           {
428             alignPanel.scrollUp(false);
429           }
430           else
431           {
432             alignPanel.setScrollValues(viewport.startRes, viewport.startSeq
433                     + viewport.endSeq - viewport.startSeq);
434           }
435           break;
436         }
437       }
438
439       public void keyReleased(KeyEvent evt)
440       {
441         switch (evt.getKeyCode())
442         {
443         case KeyEvent.VK_LEFT:
444           if (evt.isAltDown() || !viewport.cursorMode)
445             viewport.firePropertyChange("alignment", null, viewport
446                     .getAlignment().getSequences());
447           break;
448
449         case KeyEvent.VK_RIGHT:
450           if (evt.isAltDown() || !viewport.cursorMode)
451             viewport.firePropertyChange("alignment", null, viewport
452                     .getAlignment().getSequences());
453           break;
454         }
455       }
456     });
457   }
458
459   public void addAlignmentPanel(final AlignmentPanel ap, boolean newPanel)
460   {
461     ap.alignFrame = this;
462
463     alignPanels.addElement(ap);
464
465     PaintRefresher.Register(ap, ap.av.getSequenceSetId());
466
467     int aSize = alignPanels.size();
468
469     tabbedPane.setVisible(aSize > 1 || ap.av.viewName != null);
470
471     if (aSize == 1 && ap.av.viewName == null)
472     {
473       this.getContentPane().add(ap, BorderLayout.CENTER);
474     }
475     else
476     {
477       if (aSize == 2)
478       {
479         setInitialTabVisible();
480       }
481
482       expandViews.setEnabled(true);
483       gatherViews.setEnabled(true);
484       tabbedPane.addTab(ap.av.viewName, ap);
485
486       ap.setVisible(false);
487     }
488
489     if (newPanel)
490     {
491       if (ap.av.padGaps)
492       {
493         ap.av.alignment.padGaps();
494       }
495       ap.av.updateConservation(ap);
496       ap.av.updateConsensus(ap);
497     }
498   }
499
500   public void setInitialTabVisible()
501   {
502     expandViews.setEnabled(true);
503     gatherViews.setEnabled(true);
504     tabbedPane.setVisible(true);
505     AlignmentPanel first = (AlignmentPanel) alignPanels.firstElement();
506     tabbedPane.addTab(first.av.viewName, first);
507     this.getContentPane().add(tabbedPane, BorderLayout.CENTER);
508   }
509
510   public AlignViewport getViewport()
511   {
512     return viewport;
513   }
514
515   /* Set up intrinsic listeners for dynamically generated GUI bits. */
516   private void addServiceListeners()
517   {
518     final java.beans.PropertyChangeListener thisListener;
519     // Do this once to get current state
520     BuildWebServiceMenu();
521     Desktop.instance.addJalviewPropertyChangeListener("services",
522             thisListener=new java.beans.PropertyChangeListener()
523             {
524               public void propertyChange(PropertyChangeEvent evt)
525               {
526                 // // System.out.println("Discoverer property change.");
527                 // if (evt.getPropertyName().equals("services"))
528                 {
529                   SwingUtilities.invokeLater(new Runnable()
530                   {
531
532                     @Override
533                     public void run()
534                     {
535                       System.err
536                               .println("Rebuild WS Menu for service change");
537                       BuildWebServiceMenu();
538                     }
539
540                   });
541                 }
542               }
543             });
544     addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
545     {
546       public void internalFrameClosed(
547               javax.swing.event.InternalFrameEvent evt)
548       {
549         System.out.println("deregistering discoverer listener");
550         Desktop.instance.removeJalviewPropertyChangeListener("services",thisListener);
551         closeMenuItem_actionPerformed(true);
552       };
553     });
554   }
555
556   public void setGUINucleotide(boolean nucleotide)
557   {
558     showTranslation.setVisible(nucleotide);
559     conservationMenuItem.setEnabled(!nucleotide);
560     modifyConservation.setEnabled(!nucleotide);
561     showGroupConservation.setEnabled(!nucleotide);
562     // Remember AlignFrame always starts as protein
563     if (!nucleotide)
564     {
565       calculateMenu.remove(calculateMenu.getItemCount() - 2);
566     }
567   }
568
569   /**
570    * set up menus for the currently viewport. This may be called after any
571    * operation that affects the data in the current view (selection changed,
572    * etc) to update the menus to reflect the new state.
573    */
574   public void setMenusForViewport()
575   {
576     setMenusFromViewport(viewport);
577   }
578
579   /**
580    * Need to call this method when tabs are selected for multiple views, or when
581    * loading from Jalview2XML.java
582    * 
583    * @param av
584    *          AlignViewport
585    */
586   void setMenusFromViewport(AlignViewport av)
587   {
588     padGapsMenuitem.setSelected(av.padGaps);
589     colourTextMenuItem.setSelected(av.showColourText);
590     abovePIDThreshold.setSelected(av.getAbovePIDThreshold());
591     conservationMenuItem.setSelected(av.getConservationSelected());
592     seqLimits.setSelected(av.getShowJVSuffix());
593     idRightAlign.setSelected(av.rightAlignIds);
594     centreColumnLabelsMenuItem.setState(av.centreColumnLabels);
595     renderGapsMenuItem.setSelected(av.renderGaps);
596     wrapMenuItem.setSelected(av.wrapAlignment);
597     scaleAbove.setVisible(av.wrapAlignment);
598     scaleLeft.setVisible(av.wrapAlignment);
599     scaleRight.setVisible(av.wrapAlignment);
600     annotationPanelMenuItem.setState(av.showAnnotation);
601     viewBoxesMenuItem.setSelected(av.showBoxes);
602     viewTextMenuItem.setSelected(av.showText);
603     showNonconservedMenuItem.setSelected(av.showUnconserved);
604     showGroupConsensus.setSelected(av.showGroupConsensus);
605     showGroupConservation.setSelected(av.showGroupConservation);
606     showConsensusHistogram.setSelected(av.showConsensusHistogram);
607     showSequenceLogo.setSelected(av.showSequenceLogo);
608     setColourSelected(ColourSchemeProperty.getColourName(av
609             .getGlobalColourScheme()));
610
611     showSeqFeatures.setSelected(av.showSequenceFeatures);
612     hiddenMarkers.setState(av.showHiddenMarkers);
613     applyToAllGroups.setState(av.colourAppliesToAllGroups);
614     showNpFeatsMenuitem.setSelected(av.isShowNpFeats());
615     showDbRefsMenuitem.setSelected(av.isShowDbRefs());
616
617     setShowProductsEnabled();
618
619     updateEditMenuBar();
620   }
621
622   Hashtable progressBars, progressBarHandlers;
623
624   /*
625    * (non-Javadoc)
626    * 
627    * @see jalview.gui.IProgressIndicator#setProgressBar(java.lang.String, long)
628    */
629   public void setProgressBar(String message, long id)
630   {
631     if (progressBars == null)
632     {
633       progressBars = new Hashtable();
634       progressBarHandlers = new Hashtable();
635     }
636
637     JPanel progressPanel;
638     Long lId = new Long(id);
639     GridLayout layout = (GridLayout) statusPanel.getLayout();
640     if (progressBars.get(lId) != null)
641     {
642       progressPanel = (JPanel) progressBars.get(new Long(id));
643       statusPanel.remove(progressPanel);
644       progressBars.remove(lId);
645       progressPanel = null;
646       if (message != null)
647       {
648         statusBar.setText(message);
649       }
650       if (progressBarHandlers.contains(lId))
651       {
652         progressBarHandlers.remove(lId);
653       }
654       layout.setRows(layout.getRows() - 1);
655     }
656     else
657     {
658       progressPanel = new JPanel(new BorderLayout(10, 5));
659
660       JProgressBar progressBar = new JProgressBar();
661       progressBar.setIndeterminate(true);
662
663       progressPanel.add(new JLabel(message), BorderLayout.WEST);
664       progressPanel.add(progressBar, BorderLayout.CENTER);
665
666       layout.setRows(layout.getRows() + 1);
667       statusPanel.add(progressPanel);
668
669       progressBars.put(lId, progressPanel);
670     }
671     // update GUI
672     setMenusForViewport();
673     validate();
674   }
675
676   public void registerHandler(final long id,
677           final IProgressIndicatorHandler handler)
678   {
679     if (progressBarHandlers == null || !progressBars.contains(new Long(id)))
680     {
681       throw new Error(
682               "call setProgressBar before registering the progress bar's handler.");
683     }
684     progressBarHandlers.put(new Long(id), handler);
685     final JPanel progressPanel = (JPanel) progressBars.get(new Long(id));
686     if (handler.canCancel())
687     {
688       JButton cancel = new JButton("Cancel");
689       final IProgressIndicator us = this;
690       cancel.addActionListener(new ActionListener()
691       {
692
693         public void actionPerformed(ActionEvent e)
694         {
695           handler.cancelActivity(id);
696           us.setProgressBar("Cancelled "
697                   + ((JLabel) progressPanel.getComponent(0)).getText(), id);
698         }
699       });
700       progressPanel.add(cancel, BorderLayout.EAST);
701     }
702   }
703
704   /**
705    * 
706    * @return true if any progress bars are still active
707    */
708   public boolean operationInProgress()
709   {
710     if (progressBars != null && progressBars.size() > 0)
711     {
712       return true;
713     }
714     return false;
715   }
716
717   /*
718    * Added so Castor Mapping file can obtain Jalview Version
719    */
720   public String getVersion()
721   {
722     return jalview.bin.Cache.getProperty("VERSION");
723   }
724
725   public FeatureRenderer getFeatureRenderer()
726   {
727     return alignPanel.seqPanel.seqCanvas.getFeatureRenderer();
728   }
729
730   public void fetchSequence_actionPerformed(ActionEvent e)
731   {
732     new SequenceFetcher(this);
733   }
734
735   public void addFromFile_actionPerformed(ActionEvent e)
736   {
737     Desktop.instance.inputLocalFileMenuItem_actionPerformed(viewport);
738   }
739
740   public void reload_actionPerformed(ActionEvent e)
741   {
742     if (fileName != null)
743     {
744       // TODO: work out how to recover feature settings for correct view(s) when
745       // file is reloaded.
746       if (currentFileFormat.equals("Jalview"))
747       {
748         JInternalFrame[] frames = Desktop.desktop.getAllFrames();
749         for (int i = 0; i < frames.length; i++)
750         {
751           if (frames[i] instanceof AlignFrame && frames[i] != this
752                   && ((AlignFrame) frames[i]).fileName.equals(fileName))
753           {
754             try
755             {
756               frames[i].setSelected(true);
757               Desktop.instance.closeAssociatedWindows();
758             } catch (java.beans.PropertyVetoException ex)
759             {
760             }
761           }
762
763         }
764         Desktop.instance.closeAssociatedWindows();
765
766         FileLoader loader = new FileLoader();
767         String protocol = fileName.startsWith("http:") ? "URL" : "File";
768         loader.LoadFile(viewport, fileName, protocol, currentFileFormat);
769       }
770       else
771       {
772         Rectangle bounds = this.getBounds();
773
774         FileLoader loader = new FileLoader();
775         String protocol = fileName.startsWith("http:") ? "URL" : "File";
776         AlignFrame newframe = loader.LoadFileWaitTillLoaded(fileName,
777                 protocol, currentFileFormat);
778
779         newframe.setBounds(bounds);
780         if (featureSettings != null && featureSettings.isShowing())
781         {
782           final Rectangle fspos = featureSettings.frame.getBounds();
783           // TODO: need a 'show feature settings' function that takes bounds -
784           // need to refactor Desktop.addFrame
785           newframe.featureSettings_actionPerformed(null);
786           final FeatureSettings nfs = newframe.featureSettings;
787           SwingUtilities.invokeLater(new Runnable()
788           {
789             public void run()
790             {
791               nfs.frame.setBounds(fspos);
792             }
793           });
794           this.featureSettings.close();
795           this.featureSettings = null;
796         }
797         this.closeMenuItem_actionPerformed(true);
798       }
799     }
800   }
801
802   public void addFromText_actionPerformed(ActionEvent e)
803   {
804     Desktop.instance.inputTextboxMenuItem_actionPerformed(viewport);
805   }
806
807   public void addFromURL_actionPerformed(ActionEvent e)
808   {
809     Desktop.instance.inputURLMenuItem_actionPerformed(viewport);
810   }
811
812   public void save_actionPerformed(ActionEvent e)
813   {
814     if (fileName == null
815             || (currentFileFormat == null || !jalview.io.FormatAdapter
816                     .isValidIOFormat(currentFileFormat, true))
817             || fileName.startsWith("http"))
818     {
819       saveAs_actionPerformed(null);
820     }
821     else
822     {
823       saveAlignment(fileName, currentFileFormat);
824     }
825   }
826
827   /**
828    * DOCUMENT ME!
829    * 
830    * @param e
831    *          DOCUMENT ME!
832    */
833   public void saveAs_actionPerformed(ActionEvent e)
834   {
835     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache
836             .getProperty("LAST_DIRECTORY"),
837             jalview.io.AppletFormatAdapter.WRITABLE_EXTENSIONS,
838             jalview.io.AppletFormatAdapter.WRITABLE_FNAMES,
839             currentFileFormat, false);
840
841     chooser.setFileView(new JalviewFileView());
842     chooser.setDialogTitle("Save Alignment to file");
843     chooser.setToolTipText("Save");
844
845     int value = chooser.showSaveDialog(this);
846
847     if (value == JalviewFileChooser.APPROVE_OPTION)
848     {
849       currentFileFormat = chooser.getSelectedFormat();
850       if (currentFileFormat == null)
851       {
852         JOptionPane.showInternalMessageDialog(Desktop.desktop,
853                 "You must select a file format before saving!",
854                 "File format not specified", JOptionPane.WARNING_MESSAGE);
855         value = chooser.showSaveDialog(this);
856         return;
857       }
858
859       fileName = chooser.getSelectedFile().getPath();
860
861       jalview.bin.Cache.setProperty("DEFAULT_FILE_FORMAT",
862               currentFileFormat);
863
864       jalview.bin.Cache.setProperty("LAST_DIRECTORY", fileName);
865       if (currentFileFormat.indexOf(" ") > -1)
866       {
867         currentFileFormat = currentFileFormat.substring(0,
868                 currentFileFormat.indexOf(" "));
869       }
870       saveAlignment(fileName, currentFileFormat);
871     }
872   }
873
874   public boolean saveAlignment(String file, String format)
875   {
876     boolean success = true;
877
878     if (format.equalsIgnoreCase("Jalview"))
879     {
880       String shortName = title;
881
882       if (shortName.indexOf(java.io.File.separatorChar) > -1)
883       {
884         shortName = shortName.substring(shortName
885                 .lastIndexOf(java.io.File.separatorChar) + 1);
886       }
887
888       success = new Jalview2XML().SaveAlignment(this, file, shortName);
889
890       statusBar.setText("Successfully saved to file: " + fileName + " in "
891               + format + " format.");
892
893     }
894     else
895     {
896       if (!jalview.io.AppletFormatAdapter.isValidFormat(format, true))
897       {
898         warningMessage("Cannot save file " + fileName + " using format "
899                 + format, "Alignment output format not supported");
900         saveAs_actionPerformed(null);
901         // JBPNote need to have a raise_gui flag here
902         return false;
903       }
904
905       String[] omitHidden = null;
906
907       if (viewport.hasHiddenColumns)
908       {
909         int reply = JOptionPane
910                 .showInternalConfirmDialog(
911                         Desktop.desktop,
912                         "The Alignment contains hidden columns."
913                                 + "\nDo you want to save only the visible alignment?",
914                         "Save / Omit Hidden Columns",
915                         JOptionPane.YES_NO_OPTION,
916                         JOptionPane.QUESTION_MESSAGE);
917
918         if (reply == JOptionPane.YES_OPTION)
919         {
920           omitHidden = viewport.getViewAsString(false);
921         }
922       }
923       FormatAdapter f = new FormatAdapter();
924       String output = f.formatSequences(format,
925               (Alignment) viewport.alignment, // class cast exceptions will
926               // occur in the distant future
927               omitHidden, f.getCacheSuffixDefault(format), viewport.colSel);
928
929       if (output == null)
930       {
931         success = false;
932       }
933       else
934       {
935         try
936         {
937           java.io.PrintWriter out = new java.io.PrintWriter(
938                   new java.io.FileWriter(file));
939
940           out.print(output);
941           out.close();
942           this.setTitle(file);
943           statusBar.setText("Successfully saved to file: " + fileName
944                   + " in " + format + " format.");
945         } catch (Exception ex)
946         {
947           success = false;
948           ex.printStackTrace();
949         }
950       }
951     }
952
953     if (!success)
954     {
955       JOptionPane.showInternalMessageDialog(this, "Couldn't save file: "
956               + fileName, "Error Saving File", JOptionPane.WARNING_MESSAGE);
957     }
958
959     return success;
960   }
961
962   private void warningMessage(String warning, String title)
963   {
964     if (new jalview.util.Platform().isHeadless())
965     {
966       System.err.println("Warning: " + title + "\nWarning: " + warning);
967
968     }
969     else
970     {
971       JOptionPane.showInternalMessageDialog(this, warning, title,
972               JOptionPane.WARNING_MESSAGE);
973     }
974     return;
975   }
976
977   /**
978    * DOCUMENT ME!
979    * 
980    * @param e
981    *          DOCUMENT ME!
982    */
983   protected void outputText_actionPerformed(ActionEvent e)
984   {
985     String[] omitHidden = null;
986
987     if (viewport.hasHiddenColumns)
988     {
989       int reply = JOptionPane
990               .showInternalConfirmDialog(
991                       Desktop.desktop,
992                       "The Alignment contains hidden columns."
993                               + "\nDo you want to output only the visible alignment?",
994                       "Save / Omit Hidden Columns",
995                       JOptionPane.YES_NO_OPTION,
996                       JOptionPane.QUESTION_MESSAGE);
997
998       if (reply == JOptionPane.YES_OPTION)
999       {
1000         omitHidden = viewport.getViewAsString(false);
1001       }
1002     }
1003
1004     CutAndPasteTransfer cap = new CutAndPasteTransfer();
1005     cap.setForInput(null);
1006     Desktop.addInternalFrame(cap, "Alignment output - "
1007             + e.getActionCommand(), 600, 500);
1008
1009     cap.setText(new FormatAdapter().formatSequences(e.getActionCommand(),
1010             viewport.alignment, omitHidden, viewport.colSel));
1011   }
1012
1013   /**
1014    * DOCUMENT ME!
1015    * 
1016    * @param e
1017    *          DOCUMENT ME!
1018    */
1019   protected void htmlMenuItem_actionPerformed(ActionEvent e)
1020   {
1021     new HTMLOutput(alignPanel, alignPanel.seqPanel.seqCanvas
1022             .getSequenceRenderer(), alignPanel.seqPanel.seqCanvas
1023             .getFeatureRenderer());
1024   }
1025
1026   public void createImageMap(File file, String image)
1027   {
1028     alignPanel.makePNGImageMap(file, image);
1029   }
1030
1031   /**
1032    * DOCUMENT ME!
1033    * 
1034    * @param e
1035    *          DOCUMENT ME!
1036    */
1037   public void createPNG(File f)
1038   {
1039     alignPanel.makePNG(f);
1040   }
1041
1042   /**
1043    * DOCUMENT ME!
1044    * 
1045    * @param e
1046    *          DOCUMENT ME!
1047    */
1048   public void createEPS(File f)
1049   {
1050     alignPanel.makeEPS(f);
1051   }
1052
1053   public void pageSetup_actionPerformed(ActionEvent e)
1054   {
1055     PrinterJob printJob = PrinterJob.getPrinterJob();
1056     PrintThread.pf = printJob.pageDialog(printJob.defaultPage());
1057   }
1058
1059   /**
1060    * DOCUMENT ME!
1061    * 
1062    * @param e
1063    *          DOCUMENT ME!
1064    */
1065   public void printMenuItem_actionPerformed(ActionEvent e)
1066   {
1067     // Putting in a thread avoids Swing painting problems
1068     PrintThread thread = new PrintThread(alignPanel);
1069     thread.start();
1070   }
1071
1072   public void exportFeatures_actionPerformed(ActionEvent e)
1073   {
1074     new AnnotationExporter().exportFeatures(alignPanel);
1075   }
1076
1077   public void exportAnnotations_actionPerformed(ActionEvent e)
1078   {
1079     new AnnotationExporter().exportAnnotations(alignPanel,
1080             viewport.showAnnotation ? viewport.alignment
1081                     .getAlignmentAnnotation() : null, viewport.alignment
1082                     .getGroups(),
1083             ((Alignment) viewport.alignment).alignmentProperties);
1084   }
1085
1086   public void associatedData_actionPerformed(ActionEvent e)
1087   {
1088     // Pick the tree file
1089     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache
1090             .getProperty("LAST_DIRECTORY"));
1091     chooser.setFileView(new JalviewFileView());
1092     chooser.setDialogTitle("Load Jalview Annotations or Features File");
1093     chooser.setToolTipText("Load Jalview Annotations / Features file");
1094
1095     int value = chooser.showOpenDialog(null);
1096
1097     if (value == JalviewFileChooser.APPROVE_OPTION)
1098     {
1099       String choice = chooser.getSelectedFile().getPath();
1100       jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
1101       loadJalviewDataFile(choice);
1102     }
1103
1104   }
1105
1106   /**
1107    * Close the current view or all views in the alignment frame. If the frame
1108    * only contains one view then the alignment will be removed from memory.
1109    * 
1110    * @param closeAllTabs
1111    */
1112   public void closeMenuItem_actionPerformed(boolean closeAllTabs)
1113   {
1114     if (alignPanels != null && alignPanels.size() < 2)
1115     {
1116       closeAllTabs = true;
1117     }
1118
1119     try
1120     {
1121       if (alignPanels != null)
1122       {
1123         if (closeAllTabs)
1124         {
1125           if (this.isClosed())
1126           {
1127             // really close all the windows - otherwise wait till
1128             // setClosed(true) is called
1129             for (int i = 0; i < alignPanels.size(); i++)
1130             {
1131               AlignmentPanel ap = (AlignmentPanel) alignPanels.elementAt(i);
1132               ap.closePanel();
1133             }
1134           }
1135         }
1136         else
1137         {
1138           closeView(alignPanel);
1139         }
1140       }
1141
1142       if (closeAllTabs)
1143       {
1144         this.setClosed(true);
1145       }
1146     } catch (Exception ex)
1147     {
1148       ex.printStackTrace();
1149     }
1150   }
1151
1152   /**
1153    * close alignPanel2 and shuffle tabs appropriately.
1154    * 
1155    * @param alignPanel2
1156    */
1157   public void closeView(AlignmentPanel alignPanel2)
1158   {
1159     int index = tabbedPane.getSelectedIndex();
1160     int closedindex = tabbedPane.indexOfComponent(alignPanel2);
1161     alignPanels.removeElement(alignPanel2);
1162     // Unnecessary
1163     // if (viewport == alignPanel2.av)
1164     // {
1165     // viewport = null;
1166     // }
1167     alignPanel2.closePanel();
1168     alignPanel2 = null;
1169
1170     tabbedPane.removeTabAt(closedindex);
1171     tabbedPane.validate();
1172
1173     if (index > closedindex || index == tabbedPane.getTabCount())
1174     {
1175       // modify currently selected tab index if necessary.
1176       index--;
1177     }
1178
1179     this.tabSelectionChanged(index);
1180   }
1181
1182   /**
1183    * DOCUMENT ME!
1184    */
1185   void updateEditMenuBar()
1186   {
1187
1188     if (viewport.historyList.size() > 0)
1189     {
1190       undoMenuItem.setEnabled(true);
1191       CommandI command = (CommandI) viewport.historyList.peek();
1192       undoMenuItem.setText("Undo " + command.getDescription());
1193     }
1194     else
1195     {
1196       undoMenuItem.setEnabled(false);
1197       undoMenuItem.setText("Undo");
1198     }
1199
1200     if (viewport.redoList.size() > 0)
1201     {
1202       redoMenuItem.setEnabled(true);
1203
1204       CommandI command = (CommandI) viewport.redoList.peek();
1205       redoMenuItem.setText("Redo " + command.getDescription());
1206     }
1207     else
1208     {
1209       redoMenuItem.setEnabled(false);
1210       redoMenuItem.setText("Redo");
1211     }
1212   }
1213
1214   public void addHistoryItem(CommandI command)
1215   {
1216     if (command.getSize() > 0)
1217     {
1218       viewport.historyList.push(command);
1219       viewport.redoList.clear();
1220       updateEditMenuBar();
1221       viewport.hasHiddenColumns = (viewport.colSel != null
1222               && viewport.colSel.getHiddenColumns() != null && viewport.colSel
1223               .getHiddenColumns().size() > 0);
1224     }
1225   }
1226
1227   /**
1228    * 
1229    * @return alignment objects for all views
1230    */
1231   AlignmentI[] getViewAlignments()
1232   {
1233     if (alignPanels != null)
1234     {
1235       Enumeration e = alignPanels.elements();
1236       AlignmentI[] als = new AlignmentI[alignPanels.size()];
1237       for (int i = 0; e.hasMoreElements(); i++)
1238       {
1239         als[i] = ((AlignmentPanel) e.nextElement()).av.getAlignment();
1240       }
1241       return als;
1242     }
1243     if (viewport != null)
1244     {
1245       return new AlignmentI[]
1246       { viewport.alignment };
1247     }
1248     return null;
1249   }
1250
1251   /**
1252    * DOCUMENT ME!
1253    * 
1254    * @param e
1255    *          DOCUMENT ME!
1256    */
1257   protected void undoMenuItem_actionPerformed(ActionEvent e)
1258   {
1259     if (viewport.historyList.empty())
1260       return;
1261     CommandI command = (CommandI) viewport.historyList.pop();
1262     viewport.redoList.push(command);
1263     command.undoCommand(getViewAlignments());
1264
1265     AlignViewport originalSource = getOriginatingSource(command);
1266     updateEditMenuBar();
1267
1268     if (originalSource != null)
1269     {
1270       originalSource.hasHiddenColumns = (viewport.colSel != null
1271               && viewport.colSel.getHiddenColumns() != null && viewport.colSel
1272               .getHiddenColumns().size() > 0);
1273       originalSource.firePropertyChange("alignment", null,
1274               originalSource.alignment.getSequences());
1275     }
1276   }
1277
1278   /**
1279    * DOCUMENT ME!
1280    * 
1281    * @param e
1282    *          DOCUMENT ME!
1283    */
1284   protected void redoMenuItem_actionPerformed(ActionEvent e)
1285   {
1286     if (viewport.redoList.size() < 1)
1287     {
1288       return;
1289     }
1290
1291     CommandI command = (CommandI) viewport.redoList.pop();
1292     viewport.historyList.push(command);
1293     command.doCommand(getViewAlignments());
1294
1295     AlignViewport originalSource = getOriginatingSource(command);
1296     updateEditMenuBar();
1297
1298     if (originalSource != null)
1299     {
1300       originalSource.hasHiddenColumns = (viewport.colSel != null
1301               && viewport.colSel.getHiddenColumns() != null && viewport.colSel
1302               .getHiddenColumns().size() > 0);
1303       originalSource.firePropertyChange("alignment", null,
1304               originalSource.alignment.getSequences());
1305     }
1306   }
1307
1308   AlignViewport getOriginatingSource(CommandI command)
1309   {
1310     AlignViewport originalSource = null;
1311     // For sequence removal and addition, we need to fire
1312     // the property change event FROM the viewport where the
1313     // original alignment was altered
1314     AlignmentI al = null;
1315     if (command instanceof EditCommand)
1316     {
1317       EditCommand editCommand = (EditCommand) command;
1318       al = editCommand.getAlignment();
1319       Vector comps = (Vector) PaintRefresher.components.get(viewport
1320               .getSequenceSetId());
1321
1322       for (int i = 0; i < comps.size(); i++)
1323       {
1324         if (comps.elementAt(i) instanceof AlignmentPanel)
1325         {
1326           if (al == ((AlignmentPanel) comps.elementAt(i)).av.alignment)
1327           {
1328             originalSource = ((AlignmentPanel) comps.elementAt(i)).av;
1329             break;
1330           }
1331         }
1332       }
1333     }
1334
1335     if (originalSource == null)
1336     {
1337       // The original view is closed, we must validate
1338       // the current view against the closed view first
1339       if (al != null)
1340       {
1341         PaintRefresher.validateSequences(al, viewport.alignment);
1342       }
1343
1344       originalSource = viewport;
1345     }
1346
1347     return originalSource;
1348   }
1349
1350   /**
1351    * DOCUMENT ME!
1352    * 
1353    * @param up
1354    *          DOCUMENT ME!
1355    */
1356   public void moveSelectedSequences(boolean up)
1357   {
1358     SequenceGroup sg = viewport.getSelectionGroup();
1359
1360     if (sg == null)
1361     {
1362       return;
1363     }
1364
1365     if (up)
1366     {
1367       for (int i = 1; i < viewport.alignment.getHeight(); i++)
1368       {
1369         SequenceI seq = viewport.alignment.getSequenceAt(i);
1370
1371         if (!sg.getSequences(null).contains(seq))
1372         {
1373           continue;
1374         }
1375
1376         SequenceI temp = viewport.alignment.getSequenceAt(i - 1);
1377
1378         if (sg.getSequences(null).contains(temp))
1379         {
1380           continue;
1381         }
1382
1383         viewport.alignment.getSequences().setElementAt(temp, i);
1384         viewport.alignment.getSequences().setElementAt(seq, i - 1);
1385       }
1386     }
1387     else
1388     {
1389       for (int i = viewport.alignment.getHeight() - 2; i > -1; i--)
1390       {
1391         SequenceI seq = viewport.alignment.getSequenceAt(i);
1392
1393         if (!sg.getSequences(null).contains(seq))
1394         {
1395           continue;
1396         }
1397
1398         SequenceI temp = viewport.alignment.getSequenceAt(i + 1);
1399
1400         if (sg.getSequences(null).contains(temp))
1401         {
1402           continue;
1403         }
1404
1405         viewport.alignment.getSequences().setElementAt(temp, i);
1406         viewport.alignment.getSequences().setElementAt(seq, i + 1);
1407       }
1408     }
1409
1410     alignPanel.paintAlignment(true);
1411   }
1412
1413   synchronized void slideSequences(boolean right, int size)
1414   {
1415     Vector sg = new Vector();
1416     if (viewport.cursorMode)
1417     {
1418       sg.addElement(viewport.alignment
1419               .getSequenceAt(alignPanel.seqPanel.seqCanvas.cursorY));
1420     }
1421     else if (viewport.getSelectionGroup() != null
1422             && viewport.getSelectionGroup().getSize() != viewport.alignment
1423                     .getHeight())
1424     {
1425       sg = viewport.getSelectionGroup().getSequences(
1426               viewport.hiddenRepSequences);
1427     }
1428
1429     if (sg.size() < 1)
1430     {
1431       return;
1432     }
1433
1434     Vector invertGroup = new Vector();
1435
1436     for (int i = 0; i < viewport.alignment.getHeight(); i++)
1437     {
1438       if (!sg.contains(viewport.alignment.getSequenceAt(i)))
1439         invertGroup.add(viewport.alignment.getSequenceAt(i));
1440     }
1441
1442     SequenceI[] seqs1 = new SequenceI[sg.size()];
1443     for (int i = 0; i < sg.size(); i++)
1444       seqs1[i] = (SequenceI) sg.elementAt(i);
1445
1446     SequenceI[] seqs2 = new SequenceI[invertGroup.size()];
1447     for (int i = 0; i < invertGroup.size(); i++)
1448       seqs2[i] = (SequenceI) invertGroup.elementAt(i);
1449
1450     SlideSequencesCommand ssc;
1451     if (right)
1452       ssc = new SlideSequencesCommand("Slide Sequences", seqs2, seqs1,
1453               size, viewport.getGapCharacter());
1454     else
1455       ssc = new SlideSequencesCommand("Slide Sequences", seqs1, seqs2,
1456               size, viewport.getGapCharacter());
1457
1458     int groupAdjustment = 0;
1459     if (ssc.getGapsInsertedBegin() && right)
1460     {
1461       if (viewport.cursorMode)
1462         alignPanel.seqPanel.moveCursor(size, 0);
1463       else
1464         groupAdjustment = size;
1465     }
1466     else if (!ssc.getGapsInsertedBegin() && !right)
1467     {
1468       if (viewport.cursorMode)
1469         alignPanel.seqPanel.moveCursor(-size, 0);
1470       else
1471         groupAdjustment = -size;
1472     }
1473
1474     if (groupAdjustment != 0)
1475     {
1476       viewport.getSelectionGroup().setStartRes(
1477               viewport.getSelectionGroup().getStartRes() + groupAdjustment);
1478       viewport.getSelectionGroup().setEndRes(
1479               viewport.getSelectionGroup().getEndRes() + groupAdjustment);
1480     }
1481
1482     boolean appendHistoryItem = false;
1483     if (viewport.historyList != null && viewport.historyList.size() > 0
1484             && viewport.historyList.peek() instanceof SlideSequencesCommand)
1485     {
1486       appendHistoryItem = ssc
1487               .appendSlideCommand((SlideSequencesCommand) viewport.historyList
1488                       .peek());
1489     }
1490
1491     if (!appendHistoryItem)
1492       addHistoryItem(ssc);
1493
1494     repaint();
1495   }
1496
1497   /**
1498    * DOCUMENT ME!
1499    * 
1500    * @param e
1501    *          DOCUMENT ME!
1502    */
1503   protected void copy_actionPerformed(ActionEvent e)
1504   {
1505     System.gc();
1506     if (viewport.getSelectionGroup() == null)
1507     {
1508       return;
1509     }
1510     // TODO: preserve the ordering of displayed alignment annotation in any
1511     // internal paste (particularly sequence associated annotation)
1512     SequenceI[] seqs = viewport.getSelectionAsNewSequence();
1513     String[] omitHidden = null;
1514
1515     if (viewport.hasHiddenColumns)
1516     {
1517       omitHidden = viewport.getViewAsString(true);
1518     }
1519
1520     String output = new FormatAdapter().formatSequences("Fasta", seqs,
1521             omitHidden);
1522
1523     StringSelection ss = new StringSelection(output);
1524
1525     try
1526     {
1527       jalview.gui.Desktop.internalCopy = true;
1528       // Its really worth setting the clipboard contents
1529       // to empty before setting the large StringSelection!!
1530       Toolkit.getDefaultToolkit().getSystemClipboard().setContents(
1531               new StringSelection(""), null);
1532
1533       Toolkit.getDefaultToolkit().getSystemClipboard().setContents(ss,
1534               Desktop.instance);
1535     } catch (OutOfMemoryError er)
1536     {
1537       new OOMWarning("copying region", er);
1538       return;
1539     }
1540
1541     Vector hiddenColumns = null;
1542     if (viewport.hasHiddenColumns)
1543     {
1544       hiddenColumns = new Vector();
1545       int hiddenOffset = viewport.getSelectionGroup().getStartRes(), hiddenCutoff = viewport
1546               .getSelectionGroup().getEndRes();
1547       for (int i = 0; i < viewport.getColumnSelection().getHiddenColumns()
1548               .size(); i++)
1549       {
1550         int[] region = (int[]) viewport.getColumnSelection()
1551                 .getHiddenColumns().elementAt(i);
1552         if (region[0] >= hiddenOffset && region[1] <= hiddenCutoff)
1553         {
1554           hiddenColumns.addElement(new int[]
1555           { region[0] - hiddenOffset, region[1] - hiddenOffset });
1556         }
1557       }
1558     }
1559
1560     Desktop.jalviewClipboard = new Object[]
1561     { seqs, viewport.alignment.getDataset(), hiddenColumns };
1562     statusBar.setText("Copied " + seqs.length + " sequences to clipboard.");
1563   }
1564
1565   /**
1566    * DOCUMENT ME!
1567    * 
1568    * @param e
1569    *          DOCUMENT ME!
1570    */
1571   protected void pasteNew_actionPerformed(ActionEvent e)
1572   {
1573     paste(true);
1574   }
1575
1576   /**
1577    * DOCUMENT ME!
1578    * 
1579    * @param e
1580    *          DOCUMENT ME!
1581    */
1582   protected void pasteThis_actionPerformed(ActionEvent e)
1583   {
1584     paste(false);
1585   }
1586
1587   /**
1588    * Paste contents of Jalview clipboard
1589    * 
1590    * @param newAlignment
1591    *          true to paste to a new alignment, otherwise add to this.
1592    */
1593   void paste(boolean newAlignment)
1594   {
1595     boolean externalPaste = true;
1596     try
1597     {
1598       Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard();
1599       Transferable contents = c.getContents(this);
1600
1601       if (contents == null)
1602       {
1603         return;
1604       }
1605
1606       String str, format;
1607       try
1608       {
1609         str = (String) contents.getTransferData(DataFlavor.stringFlavor);
1610         if (str.length() < 1)
1611         {
1612           return;
1613         }
1614
1615         format = new IdentifyFile().Identify(str, "Paste");
1616
1617       } catch (OutOfMemoryError er)
1618       {
1619         new OOMWarning("Out of memory pasting sequences!!", er);
1620         return;
1621       }
1622
1623       SequenceI[] sequences;
1624       boolean annotationAdded = false;
1625       AlignmentI alignment = null;
1626
1627       if (Desktop.jalviewClipboard != null)
1628       {
1629         // The clipboard was filled from within Jalview, we must use the
1630         // sequences
1631         // And dataset from the copied alignment
1632         SequenceI[] newseq = (SequenceI[]) Desktop.jalviewClipboard[0];
1633         // be doubly sure that we create *new* sequence objects.
1634         sequences = new SequenceI[newseq.length];
1635         for (int i = 0; i < newseq.length; i++)
1636         {
1637           sequences[i] = new Sequence(newseq[i]);
1638         }
1639         alignment = new Alignment(sequences);
1640         externalPaste = false;
1641       }
1642       else
1643       {
1644         // parse the clipboard as an alignment.
1645         alignment = new FormatAdapter().readFile(str, "Paste", format);
1646         sequences = alignment.getSequencesArray();
1647       }
1648
1649       int alwidth = 0;
1650
1651       if (newAlignment)
1652       {
1653
1654         if (Desktop.jalviewClipboard != null)
1655         {
1656           // dataset is inherited
1657           alignment.setDataset((Alignment) Desktop.jalviewClipboard[1]);
1658         }
1659         else
1660         {
1661           // new dataset is constructed
1662           alignment.setDataset(null);
1663         }
1664         alwidth = alignment.getWidth() + 1;
1665       }
1666       else
1667       {
1668         AlignmentI pastedal = alignment; // preserve pasted alignment object
1669         // Add pasted sequences and dataset into existing alignment.
1670         alignment = viewport.getAlignment();
1671         alwidth = alignment.getWidth() + 1;
1672         // decide if we need to import sequences from an existing dataset
1673         boolean importDs = Desktop.jalviewClipboard != null
1674                 && Desktop.jalviewClipboard[1] != alignment.getDataset();
1675         // importDs==true instructs us to copy over new dataset sequences from
1676         // an existing alignment
1677         Vector newDs = (importDs) ? new Vector() : null; // used to create
1678         // minimum dataset set
1679
1680         for (int i = 0; i < sequences.length; i++)
1681         {
1682           if (importDs)
1683           {
1684             newDs.addElement(null);
1685           }
1686           SequenceI ds = sequences[i].getDatasetSequence(); // null for a simple
1687           // paste
1688           if (importDs && ds != null)
1689           {
1690             if (!newDs.contains(ds))
1691             {
1692               newDs.setElementAt(ds, i);
1693               ds = new Sequence(ds);
1694               // update with new dataset sequence
1695               sequences[i].setDatasetSequence(ds);
1696             }
1697             else
1698             {
1699               ds = sequences[newDs.indexOf(ds)].getDatasetSequence();
1700             }
1701           }
1702           else
1703           {
1704             // copy and derive new dataset sequence
1705             sequences[i] = sequences[i].deriveSequence();
1706             alignment.getDataset().addSequence(
1707                     sequences[i].getDatasetSequence());
1708             // TODO: avoid creation of duplicate dataset sequences with a
1709             // 'contains' method using SequenceI.equals()/SequenceI.contains()
1710           }
1711           alignment.addSequence(sequences[i]); // merges dataset
1712         }
1713         if (newDs != null)
1714         {
1715           newDs.clear(); // tidy up
1716         }
1717         if (pastedal.getAlignmentAnnotation() != null)
1718         {
1719           // Add any annotation attached to alignment.
1720           AlignmentAnnotation[] alann = pastedal.getAlignmentAnnotation();
1721           for (int i = 0; i < alann.length; i++)
1722           {
1723             annotationAdded = true;
1724             if (alann[i].sequenceRef == null && !alann[i].autoCalculated)
1725             {
1726               AlignmentAnnotation newann = new AlignmentAnnotation(alann[i]);
1727               newann.padAnnotation(alwidth);
1728               alignment.addAnnotation(newann);
1729             }
1730           }
1731         }
1732       }
1733       if (!newAlignment)
1734       {
1735         // /////
1736         // ADD HISTORY ITEM
1737         //
1738         addHistoryItem(new EditCommand("Add sequences", EditCommand.PASTE,
1739                 sequences, 0, alignment.getWidth(), alignment));
1740       }
1741       // Add any annotations attached to sequences
1742       for (int i = 0; i < sequences.length; i++)
1743       {
1744         if (sequences[i].getAnnotation() != null)
1745         {
1746           for (int a = 0; a < sequences[i].getAnnotation().length; a++)
1747           {
1748             annotationAdded = true;
1749             sequences[i].getAnnotation()[a].adjustForAlignment();
1750             sequences[i].getAnnotation()[a].padAnnotation(alwidth);
1751             alignment.addAnnotation(sequences[i].getAnnotation()[a]); // annotation
1752             // was
1753             // duplicated
1754             // earlier
1755             alignment
1756                     .setAnnotationIndex(sequences[i].getAnnotation()[a], a);
1757           }
1758         }
1759       }
1760       if (!newAlignment)
1761       {
1762
1763         // propagate alignment changed.
1764         viewport.setEndSeq(alignment.getHeight());
1765         if (annotationAdded)
1766         {
1767           // Duplicate sequence annotation in all views.
1768           AlignmentI[] alview = this.getViewAlignments();
1769           for (int i = 0; i < sequences.length; i++)
1770           {
1771             AlignmentAnnotation sann[] = sequences[i].getAnnotation();
1772             if (sann == null)
1773               continue;
1774             for (int avnum = 0; avnum < alview.length; avnum++)
1775             {
1776               if (alview[avnum] != alignment)
1777               {
1778                 // duplicate in a view other than the one with input focus
1779                 int avwidth = alview[avnum].getWidth() + 1;
1780                 // this relies on sann being preserved after we
1781                 // modify the sequence's annotation array for each duplication
1782                 for (int a = 0; a < sann.length; a++)
1783                 {
1784                   AlignmentAnnotation newann = new AlignmentAnnotation(
1785                           sann[a]);
1786                   sequences[i].addAlignmentAnnotation(newann);
1787                   newann.padAnnotation(avwidth);
1788                   alview[avnum].addAnnotation(newann); // annotation was
1789                   // duplicated earlier
1790                   alview[avnum].setAnnotationIndex(newann, a);
1791                 }
1792               }
1793             }
1794           }
1795           buildSortByAnnotationScoresMenu();
1796         }
1797         viewport.firePropertyChange("alignment", null, alignment
1798                 .getSequences());
1799
1800       }
1801       else
1802       {
1803         AlignFrame af = new AlignFrame(alignment, DEFAULT_WIDTH,
1804                 DEFAULT_HEIGHT);
1805         String newtitle = new String("Copied sequences");
1806
1807         if (Desktop.jalviewClipboard != null
1808                 && Desktop.jalviewClipboard[2] != null)
1809         {
1810           Vector hc = (Vector) Desktop.jalviewClipboard[2];
1811           for (int i = 0; i < hc.size(); i++)
1812           {
1813             int[] region = (int[]) hc.elementAt(i);
1814             af.viewport.hideColumns(region[0], region[1]);
1815           }
1816         }
1817
1818         // >>>This is a fix for the moment, until a better solution is
1819         // found!!<<<
1820         af.alignPanel.seqPanel.seqCanvas.getFeatureRenderer()
1821                 .transferSettings(
1822                         alignPanel.seqPanel.seqCanvas.getFeatureRenderer());
1823
1824         // TODO: maintain provenance of an alignment, rather than just make the
1825         // title a concatenation of operations.
1826         if (!externalPaste)
1827         {
1828           if (title.startsWith("Copied sequences"))
1829           {
1830             newtitle = title;
1831           }
1832           else
1833           {
1834             newtitle = newtitle.concat("- from " + title);
1835           }
1836         }
1837         else
1838         {
1839           newtitle = new String("Pasted sequences");
1840         }
1841
1842         Desktop.addInternalFrame(af, newtitle, DEFAULT_WIDTH,
1843                 DEFAULT_HEIGHT);
1844
1845       }
1846
1847     } catch (Exception ex)
1848     {
1849       ex.printStackTrace();
1850       System.out.println("Exception whilst pasting: " + ex);
1851       // could be anything being pasted in here
1852     }
1853
1854   }
1855
1856   /**
1857    * DOCUMENT ME!
1858    * 
1859    * @param e
1860    *          DOCUMENT ME!
1861    */
1862   protected void cut_actionPerformed(ActionEvent e)
1863   {
1864     copy_actionPerformed(null);
1865     delete_actionPerformed(null);
1866   }
1867
1868   /**
1869    * DOCUMENT ME!
1870    * 
1871    * @param e
1872    *          DOCUMENT ME!
1873    */
1874   protected void delete_actionPerformed(ActionEvent evt)
1875   {
1876
1877     SequenceGroup sg = viewport.getSelectionGroup();
1878     if (sg == null)
1879     {
1880       return;
1881     }
1882
1883     Vector seqs = new Vector();
1884     SequenceI seq;
1885     for (int i = 0; i < sg.getSize(); i++)
1886     {
1887       seq = sg.getSequenceAt(i);
1888       seqs.addElement(seq);
1889     }
1890
1891     // If the cut affects all sequences, remove highlighted columns
1892     if (sg.getSize() == viewport.alignment.getHeight())
1893     {
1894       viewport.getColumnSelection().removeElements(sg.getStartRes(),
1895               sg.getEndRes() + 1);
1896     }
1897
1898     SequenceI[] cut = new SequenceI[seqs.size()];
1899     for (int i = 0; i < seqs.size(); i++)
1900     {
1901       cut[i] = (SequenceI) seqs.elementAt(i);
1902     }
1903
1904     /*
1905      * //ADD HISTORY ITEM
1906      */
1907     addHistoryItem(new EditCommand("Cut Sequences", EditCommand.CUT, cut,
1908             sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1,
1909             viewport.alignment));
1910
1911     viewport.setSelectionGroup(null);
1912     viewport.sendSelection();
1913     viewport.alignment.deleteGroup(sg);
1914
1915     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
1916             .getSequences());
1917     if (viewport.getAlignment().getHeight() < 1)
1918     {
1919       try
1920       {
1921         this.setClosed(true);
1922       } catch (Exception ex)
1923       {
1924       }
1925     }
1926   }
1927
1928   /**
1929    * DOCUMENT ME!
1930    * 
1931    * @param e
1932    *          DOCUMENT ME!
1933    */
1934   protected void deleteGroups_actionPerformed(ActionEvent e)
1935   {
1936     viewport.alignment.deleteAllGroups();
1937     viewport.sequenceColours = null;
1938     viewport.setSelectionGroup(null);
1939     PaintRefresher.Refresh(this, viewport.getSequenceSetId());
1940     alignPanel.updateAnnotation();
1941     alignPanel.paintAlignment(true);
1942   }
1943
1944   /**
1945    * DOCUMENT ME!
1946    * 
1947    * @param e
1948    *          DOCUMENT ME!
1949    */
1950   public void selectAllSequenceMenuItem_actionPerformed(ActionEvent e)
1951   {
1952     SequenceGroup sg = new SequenceGroup();
1953
1954     for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
1955     {
1956       sg.addSequence(viewport.getAlignment().getSequenceAt(i), false);
1957     }
1958
1959     sg.setEndRes(viewport.alignment.getWidth() - 1);
1960     viewport.setSelectionGroup(sg);
1961     viewport.sendSelection();
1962     alignPanel.paintAlignment(true);
1963     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
1964   }
1965
1966   /**
1967    * DOCUMENT ME!
1968    * 
1969    * @param e
1970    *          DOCUMENT ME!
1971    */
1972   public void deselectAllSequenceMenuItem_actionPerformed(ActionEvent e)
1973   {
1974     if (viewport.cursorMode)
1975     {
1976       alignPanel.seqPanel.keyboardNo1 = null;
1977       alignPanel.seqPanel.keyboardNo2 = null;
1978     }
1979     viewport.setSelectionGroup(null);
1980     viewport.getColumnSelection().clear();
1981     viewport.setSelectionGroup(null);
1982     alignPanel.seqPanel.seqCanvas.highlightSearchResults(null);
1983     alignPanel.idPanel.idCanvas.searchResults = null;
1984     alignPanel.paintAlignment(true);
1985     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
1986   }
1987
1988   /**
1989    * DOCUMENT ME!
1990    * 
1991    * @param e
1992    *          DOCUMENT ME!
1993    */
1994   public void invertSequenceMenuItem_actionPerformed(ActionEvent e)
1995   {
1996     SequenceGroup sg = viewport.getSelectionGroup();
1997
1998     if (sg == null)
1999     {
2000       selectAllSequenceMenuItem_actionPerformed(null);
2001
2002       return;
2003     }
2004
2005     for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
2006     {
2007       sg.addOrRemove(viewport.getAlignment().getSequenceAt(i), false);
2008     }
2009
2010     alignPanel.paintAlignment(true);
2011     viewport.sendSelection();
2012     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
2013   }
2014
2015   public void invertColSel_actionPerformed(ActionEvent e)
2016   {
2017     viewport.invertColumnSelection();
2018     alignPanel.paintAlignment(true);
2019   }
2020
2021   /**
2022    * DOCUMENT ME!
2023    * 
2024    * @param e
2025    *          DOCUMENT ME!
2026    */
2027   public void remove2LeftMenuItem_actionPerformed(ActionEvent e)
2028   {
2029     trimAlignment(true);
2030   }
2031
2032   /**
2033    * DOCUMENT ME!
2034    * 
2035    * @param e
2036    *          DOCUMENT ME!
2037    */
2038   public void remove2RightMenuItem_actionPerformed(ActionEvent e)
2039   {
2040     trimAlignment(false);
2041   }
2042
2043   void trimAlignment(boolean trimLeft)
2044   {
2045     ColumnSelection colSel = viewport.getColumnSelection();
2046     int column;
2047
2048     if (colSel.size() > 0)
2049     {
2050       if (trimLeft)
2051       {
2052         column = colSel.getMin();
2053       }
2054       else
2055       {
2056         column = colSel.getMax();
2057       }
2058
2059       SequenceI[] seqs;
2060       if (viewport.getSelectionGroup() != null)
2061       {
2062         seqs = viewport.getSelectionGroup().getSequencesAsArray(
2063                 viewport.hiddenRepSequences);
2064       }
2065       else
2066       {
2067         seqs = viewport.alignment.getSequencesArray();
2068       }
2069
2070       TrimRegionCommand trimRegion;
2071       if (trimLeft)
2072       {
2073         trimRegion = new TrimRegionCommand("Remove Left",
2074                 TrimRegionCommand.TRIM_LEFT, seqs, column,
2075                 viewport.alignment, viewport.colSel,
2076                 viewport.selectionGroup);
2077         viewport.setStartRes(0);
2078       }
2079       else
2080       {
2081         trimRegion = new TrimRegionCommand("Remove Right",
2082                 TrimRegionCommand.TRIM_RIGHT, seqs, column,
2083                 viewport.alignment, viewport.colSel,
2084                 viewport.selectionGroup);
2085       }
2086
2087       statusBar.setText("Removed " + trimRegion.getSize() + " columns.");
2088
2089       addHistoryItem(trimRegion);
2090
2091       Vector groups = viewport.alignment.getGroups();
2092
2093       for (int i = 0; i < groups.size(); i++)
2094       {
2095         SequenceGroup sg = (SequenceGroup) groups.get(i);
2096
2097         if ((trimLeft && !sg.adjustForRemoveLeft(column))
2098                 || (!trimLeft && !sg.adjustForRemoveRight(column)))
2099         {
2100           viewport.alignment.deleteGroup(sg);
2101         }
2102       }
2103
2104       viewport.firePropertyChange("alignment", null, viewport
2105               .getAlignment().getSequences());
2106     }
2107   }
2108
2109   /**
2110    * DOCUMENT ME!
2111    * 
2112    * @param e
2113    *          DOCUMENT ME!
2114    */
2115   public void removeGappedColumnMenuItem_actionPerformed(ActionEvent e)
2116   {
2117     int start = 0, end = viewport.alignment.getWidth() - 1;
2118
2119     SequenceI[] seqs;
2120     if (viewport.getSelectionGroup() != null)
2121     {
2122       seqs = viewport.getSelectionGroup().getSequencesAsArray(
2123               viewport.hiddenRepSequences);
2124       start = viewport.getSelectionGroup().getStartRes();
2125       end = viewport.getSelectionGroup().getEndRes();
2126     }
2127     else
2128     {
2129       seqs = viewport.alignment.getSequencesArray();
2130     }
2131
2132     RemoveGapColCommand removeGapCols = new RemoveGapColCommand(
2133             "Remove Gapped Columns", seqs, start, end, viewport.alignment);
2134
2135     addHistoryItem(removeGapCols);
2136
2137     statusBar.setText("Removed " + removeGapCols.getSize()
2138             + " empty columns.");
2139
2140     // This is to maintain viewport position on first residue
2141     // of first sequence
2142     SequenceI seq = viewport.alignment.getSequenceAt(0);
2143     int startRes = seq.findPosition(viewport.startRes);
2144     // ShiftList shifts;
2145     // viewport.getAlignment().removeGaps(shifts=new ShiftList());
2146     // edit.alColumnChanges=shifts.getInverse();
2147     // if (viewport.hasHiddenColumns)
2148     // viewport.getColumnSelection().compensateForEdits(shifts);
2149     viewport.setStartRes(seq.findIndex(startRes) - 1);
2150     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
2151             .getSequences());
2152
2153   }
2154
2155   /**
2156    * DOCUMENT ME!
2157    * 
2158    * @param e
2159    *          DOCUMENT ME!
2160    */
2161   public void removeAllGapsMenuItem_actionPerformed(ActionEvent e)
2162   {
2163     int start = 0, end = viewport.alignment.getWidth() - 1;
2164
2165     SequenceI[] seqs;
2166     if (viewport.getSelectionGroup() != null)
2167     {
2168       seqs = viewport.getSelectionGroup().getSequencesAsArray(
2169               viewport.hiddenRepSequences);
2170       start = viewport.getSelectionGroup().getStartRes();
2171       end = viewport.getSelectionGroup().getEndRes();
2172     }
2173     else
2174     {
2175       seqs = viewport.alignment.getSequencesArray();
2176     }
2177
2178     // This is to maintain viewport position on first residue
2179     // of first sequence
2180     SequenceI seq = viewport.alignment.getSequenceAt(0);
2181     int startRes = seq.findPosition(viewport.startRes);
2182
2183     addHistoryItem(new RemoveGapsCommand("Remove Gaps", seqs, start, end,
2184             viewport.alignment));
2185
2186     viewport.setStartRes(seq.findIndex(startRes) - 1);
2187
2188     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
2189             .getSequences());
2190
2191   }
2192
2193   /**
2194    * DOCUMENT ME!
2195    * 
2196    * @param e
2197    *          DOCUMENT ME!
2198    */
2199   public void padGapsMenuitem_actionPerformed(ActionEvent e)
2200   {
2201     viewport.padGaps = padGapsMenuitem.isSelected();
2202     viewport.firePropertyChange("alignment", null, viewport.getAlignment()
2203             .getSequences());
2204   }
2205
2206   // else
2207   {
2208     // if (justifySeqs>0)
2209     {
2210       // alignment.justify(justifySeqs!=RIGHT_JUSTIFY);
2211     }
2212   }
2213
2214   // }
2215
2216   /**
2217    * DOCUMENT ME!
2218    * 
2219    * @param e
2220    *          DOCUMENT ME!
2221    */
2222   public void findMenuItem_actionPerformed(ActionEvent e)
2223   {
2224     new Finder();
2225   }
2226
2227   public void newView_actionPerformed(ActionEvent e)
2228   {
2229     AlignmentPanel newap = new Jalview2XML().copyAlignPanel(alignPanel,
2230             true);
2231
2232     newap.av.gatherViewsHere = false;
2233
2234     if (viewport.viewName == null)
2235     {
2236       viewport.viewName = "Original";
2237     }
2238
2239     newap.av.historyList = viewport.historyList;
2240     newap.av.redoList = viewport.redoList;
2241
2242     int index = Desktop.getViewCount(viewport.getSequenceSetId());
2243     String newViewName = "View " + index;
2244
2245     Vector comps = (Vector) PaintRefresher.components.get(viewport
2246             .getSequenceSetId());
2247     Vector existingNames = new Vector();
2248     for (int i = 0; i < comps.size(); i++)
2249     {
2250       if (comps.elementAt(i) instanceof AlignmentPanel)
2251       {
2252         AlignmentPanel ap = (AlignmentPanel) comps.elementAt(i);
2253         if (!existingNames.contains(ap.av.viewName))
2254         {
2255           existingNames.addElement(ap.av.viewName);
2256         }
2257       }
2258     }
2259
2260     while (existingNames.contains(newViewName))
2261     {
2262       newViewName = "View " + (++index);
2263     }
2264
2265     newap.av.viewName = newViewName;
2266
2267     addAlignmentPanel(newap, true);
2268
2269     if (alignPanels.size() == 2)
2270     {
2271       viewport.gatherViewsHere = true;
2272     }
2273     tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
2274   }
2275
2276   public void expandViews_actionPerformed(ActionEvent e)
2277   {
2278     Desktop.instance.explodeViews(this);
2279   }
2280
2281   public void gatherViews_actionPerformed(ActionEvent e)
2282   {
2283     Desktop.instance.gatherViews(this);
2284   }
2285
2286   /**
2287    * DOCUMENT ME!
2288    * 
2289    * @param e
2290    *          DOCUMENT ME!
2291    */
2292   public void font_actionPerformed(ActionEvent e)
2293   {
2294     new FontChooser(alignPanel);
2295   }
2296
2297   /**
2298    * DOCUMENT ME!
2299    * 
2300    * @param e
2301    *          DOCUMENT ME!
2302    */
2303   protected void seqLimit_actionPerformed(ActionEvent e)
2304   {
2305     viewport.setShowJVSuffix(seqLimits.isSelected());
2306
2307     alignPanel.idPanel.idCanvas.setPreferredSize(alignPanel
2308             .calculateIdWidth());
2309     alignPanel.paintAlignment(true);
2310   }
2311
2312   public void idRightAlign_actionPerformed(ActionEvent e)
2313   {
2314     viewport.rightAlignIds = idRightAlign.isSelected();
2315     alignPanel.paintAlignment(true);
2316   }
2317
2318   public void centreColumnLabels_actionPerformed(ActionEvent e)
2319   {
2320     viewport.centreColumnLabels = centreColumnLabelsMenuItem.getState();
2321     alignPanel.paintAlignment(true);
2322   }
2323
2324   /*
2325    * (non-Javadoc)
2326    * 
2327    * @see jalview.jbgui.GAlignFrame#followHighlight_actionPerformed()
2328    */
2329   protected void followHighlight_actionPerformed()
2330   {
2331     if (viewport.followHighlight = this.followHighlightMenuItem.getState())
2332     {
2333       alignPanel.scrollToPosition(
2334               alignPanel.seqPanel.seqCanvas.searchResults, false);
2335     }
2336   }
2337
2338   /**
2339    * DOCUMENT ME!
2340    * 
2341    * @param e
2342    *          DOCUMENT ME!
2343    */
2344   protected void colourTextMenuItem_actionPerformed(ActionEvent e)
2345   {
2346     viewport.setColourText(colourTextMenuItem.isSelected());
2347     alignPanel.paintAlignment(true);
2348   }
2349
2350   /**
2351    * DOCUMENT ME!
2352    * 
2353    * @param e
2354    *          DOCUMENT ME!
2355    */
2356   public void wrapMenuItem_actionPerformed(ActionEvent e)
2357   {
2358     scaleAbove.setVisible(wrapMenuItem.isSelected());
2359     scaleLeft.setVisible(wrapMenuItem.isSelected());
2360     scaleRight.setVisible(wrapMenuItem.isSelected());
2361     viewport.setWrapAlignment(wrapMenuItem.isSelected());
2362     alignPanel.setWrapAlignment(wrapMenuItem.isSelected());
2363   }
2364
2365   public void showAllSeqs_actionPerformed(ActionEvent e)
2366   {
2367     viewport.showAllHiddenSeqs();
2368   }
2369
2370   public void showAllColumns_actionPerformed(ActionEvent e)
2371   {
2372     viewport.showAllHiddenColumns();
2373     repaint();
2374   }
2375
2376   public void hideSelSequences_actionPerformed(ActionEvent e)
2377   {
2378     viewport.hideAllSelectedSeqs();
2379     alignPanel.paintAlignment(true);
2380   }
2381
2382   /**
2383    * called by key handler and the hide all/show all menu items
2384    * 
2385    * @param toggleSeqs
2386    * @param toggleCols
2387    */
2388   private void toggleHiddenRegions(boolean toggleSeqs, boolean toggleCols)
2389   {
2390
2391     boolean hide = false;
2392     SequenceGroup sg = viewport.getSelectionGroup();
2393     if (!toggleSeqs && !toggleCols)
2394     {
2395       // Hide everything by the current selection - this is a hack - we do the
2396       // invert and then hide
2397       // first check that there will be visible columns after the invert.
2398       if ((viewport.colSel != null && viewport.colSel.getSelected() != null && viewport.colSel
2399               .getSelected().size() > 0)
2400               || (sg != null && sg.getSize() > 0 && sg.getStartRes() <= sg
2401                       .getEndRes()))
2402       {
2403         // now invert the sequence set, if required - empty selection implies
2404         // that no hiding is required.
2405         if (sg != null)
2406         {
2407           invertSequenceMenuItem_actionPerformed(null);
2408           sg = viewport.getSelectionGroup();
2409           toggleSeqs = true;
2410
2411         }
2412         viewport.expandColSelection(sg, true);
2413         // finally invert the column selection and get the new sequence
2414         // selection.
2415         invertColSel_actionPerformed(null);
2416         toggleCols = true;
2417       }
2418     }
2419
2420     if (toggleSeqs)
2421     {
2422       if (sg != null && sg.getSize() != viewport.alignment.getHeight())
2423       {
2424         hideSelSequences_actionPerformed(null);
2425         hide = true;
2426       }
2427       else if (!(toggleCols && viewport.colSel.getSelected().size() > 0))
2428       {
2429         showAllSeqs_actionPerformed(null);
2430       }
2431     }
2432
2433     if (toggleCols)
2434     {
2435       if (viewport.colSel.getSelected().size() > 0)
2436       {
2437         hideSelColumns_actionPerformed(null);
2438         if (!toggleSeqs)
2439         {
2440           viewport.selectionGroup = sg;
2441         }
2442       }
2443       else if (!hide)
2444       {
2445         showAllColumns_actionPerformed(null);
2446       }
2447     }
2448   }
2449
2450   /*
2451    * (non-Javadoc)
2452    * 
2453    * @see
2454    * jalview.jbgui.GAlignFrame#hideAllButSelection_actionPerformed(java.awt.
2455    * event.ActionEvent)
2456    */
2457   public void hideAllButSelection_actionPerformed(ActionEvent e)
2458   {
2459     toggleHiddenRegions(false, false);
2460   }
2461
2462   /*
2463    * (non-Javadoc)
2464    * 
2465    * @see
2466    * jalview.jbgui.GAlignFrame#hideAllSelection_actionPerformed(java.awt.event
2467    * .ActionEvent)
2468    */
2469   public void hideAllSelection_actionPerformed(ActionEvent e)
2470   {
2471     SequenceGroup sg = viewport.getSelectionGroup();
2472     viewport.expandColSelection(sg, false);
2473     viewport.hideAllSelectedSeqs();
2474     viewport.hideSelectedColumns();
2475     alignPanel.paintAlignment(true);
2476   }
2477
2478   /*
2479    * (non-Javadoc)
2480    * 
2481    * @see
2482    * jalview.jbgui.GAlignFrame#showAllhidden_actionPerformed(java.awt.event.
2483    * ActionEvent)
2484    */
2485   public void showAllhidden_actionPerformed(ActionEvent e)
2486   {
2487     viewport.showAllHiddenColumns();
2488     viewport.showAllHiddenSeqs();
2489     alignPanel.paintAlignment(true);
2490   }
2491
2492   public void hideSelColumns_actionPerformed(ActionEvent e)
2493   {
2494     viewport.hideSelectedColumns();
2495     alignPanel.paintAlignment(true);
2496   }
2497
2498   public void hiddenMarkers_actionPerformed(ActionEvent e)
2499   {
2500     viewport.setShowHiddenMarkers(hiddenMarkers.isSelected());
2501     repaint();
2502   }
2503
2504   /**
2505    * DOCUMENT ME!
2506    * 
2507    * @param e
2508    *          DOCUMENT ME!
2509    */
2510   protected void scaleAbove_actionPerformed(ActionEvent e)
2511   {
2512     viewport.setScaleAboveWrapped(scaleAbove.isSelected());
2513     alignPanel.paintAlignment(true);
2514   }
2515
2516   /**
2517    * DOCUMENT ME!
2518    * 
2519    * @param e
2520    *          DOCUMENT ME!
2521    */
2522   protected void scaleLeft_actionPerformed(ActionEvent e)
2523   {
2524     viewport.setScaleLeftWrapped(scaleLeft.isSelected());
2525     alignPanel.paintAlignment(true);
2526   }
2527
2528   /**
2529    * DOCUMENT ME!
2530    * 
2531    * @param e
2532    *          DOCUMENT ME!
2533    */
2534   protected void scaleRight_actionPerformed(ActionEvent e)
2535   {
2536     viewport.setScaleRightWrapped(scaleRight.isSelected());
2537     alignPanel.paintAlignment(true);
2538   }
2539
2540   /**
2541    * DOCUMENT ME!
2542    * 
2543    * @param e
2544    *          DOCUMENT ME!
2545    */
2546   public void viewBoxesMenuItem_actionPerformed(ActionEvent e)
2547   {
2548     viewport.setShowBoxes(viewBoxesMenuItem.isSelected());
2549     alignPanel.paintAlignment(true);
2550   }
2551
2552   /**
2553    * DOCUMENT ME!
2554    * 
2555    * @param e
2556    *          DOCUMENT ME!
2557    */
2558   public void viewTextMenuItem_actionPerformed(ActionEvent e)
2559   {
2560     viewport.setShowText(viewTextMenuItem.isSelected());
2561     alignPanel.paintAlignment(true);
2562   }
2563
2564   /**
2565    * DOCUMENT ME!
2566    * 
2567    * @param e
2568    *          DOCUMENT ME!
2569    */
2570   protected void renderGapsMenuItem_actionPerformed(ActionEvent e)
2571   {
2572     viewport.setRenderGaps(renderGapsMenuItem.isSelected());
2573     alignPanel.paintAlignment(true);
2574   }
2575
2576   public FeatureSettings featureSettings;
2577
2578   public void featureSettings_actionPerformed(ActionEvent e)
2579   {
2580     if (featureSettings != null)
2581     {
2582       featureSettings.close();
2583       featureSettings = null;
2584     }
2585     if (!showSeqFeatures.isSelected())
2586     {
2587       // make sure features are actually displayed
2588       showSeqFeatures.setSelected(true);
2589       showSeqFeatures_actionPerformed(null);
2590     }
2591     featureSettings = new FeatureSettings(this);
2592   }
2593
2594   /**
2595    * Set or clear 'Show Sequence Features'
2596    * 
2597    * @param evt
2598    *          DOCUMENT ME!
2599    */
2600   public void showSeqFeatures_actionPerformed(ActionEvent evt)
2601   {
2602     viewport.setShowSequenceFeatures(showSeqFeatures.isSelected());
2603     alignPanel.paintAlignment(true);
2604     if (alignPanel.getOverviewPanel() != null)
2605     {
2606       alignPanel.getOverviewPanel().updateOverviewImage();
2607     }
2608   }
2609
2610   /**
2611    * Set or clear 'Show Sequence Features'
2612    * 
2613    * @param evt
2614    *          DOCUMENT ME!
2615    */
2616   public void showSeqFeaturesHeight_actionPerformed(ActionEvent evt)
2617   {
2618     viewport.setShowSequenceFeaturesHeight(showSeqFeaturesHeight
2619             .isSelected());
2620     if (viewport.getShowSequenceFeaturesHeight())
2621     {
2622       // ensure we're actually displaying features
2623       viewport.setShowSequenceFeatures(true);
2624       showSeqFeatures.setSelected(true);
2625     }
2626     alignPanel.paintAlignment(true);
2627     if (alignPanel.getOverviewPanel() != null)
2628     {
2629       alignPanel.getOverviewPanel().updateOverviewImage();
2630     }
2631   }
2632
2633   /**
2634    * DOCUMENT ME!
2635    * 
2636    * @param e
2637    *          DOCUMENT ME!
2638    */
2639   public void annotationPanelMenuItem_actionPerformed(ActionEvent e)
2640   {
2641     viewport.setShowAnnotation(annotationPanelMenuItem.isSelected());
2642     alignPanel.setAnnotationVisible(annotationPanelMenuItem.isSelected());
2643   }
2644
2645   public void alignmentProperties()
2646   {
2647     JEditorPane editPane = new JEditorPane("text/html", "");
2648     editPane.setEditable(false);
2649     StringBuffer contents = new StringBuffer("<html>");
2650
2651     float avg = 0;
2652     int min = Integer.MAX_VALUE, max = 0;
2653     for (int i = 0; i < viewport.alignment.getHeight(); i++)
2654     {
2655       int size = viewport.alignment.getSequenceAt(i).getEnd()
2656               - viewport.alignment.getSequenceAt(i).getStart();
2657       avg += size;
2658       if (size > max)
2659         max = size;
2660       if (size < min)
2661         min = size;
2662     }
2663     avg = avg / (float) viewport.alignment.getHeight();
2664
2665     contents.append("<br>Sequences: " + viewport.alignment.getHeight());
2666     contents.append("<br>Minimum Sequence Length: " + min);
2667     contents.append("<br>Maximum Sequence Length: " + max);
2668     contents.append("<br>Average Length: " + (int) avg);
2669
2670     if (((Alignment) viewport.alignment).getProperties() != null)
2671     {
2672       Hashtable props = ((Alignment) viewport.alignment).getProperties();
2673       Enumeration en = props.keys();
2674       contents.append("<br><br><table border=\"1\">");
2675       while (en.hasMoreElements())
2676       {
2677         String key = en.nextElement().toString();
2678         StringBuffer val = new StringBuffer();
2679         String vals = props.get(key).toString();
2680         int pos = 0, npos;
2681         do
2682         {
2683           npos = vals.indexOf("\n", pos);
2684           if (npos == -1)
2685           {
2686             val.append(vals.substring(pos));
2687           }
2688           else
2689           {
2690             val.append(vals.substring(pos, npos));
2691             val.append("<br>");
2692           }
2693           pos = npos + 1;
2694         } while (npos != -1);
2695         contents
2696                 .append("<tr><td>" + key + "</td><td>" + val + "</td></tr>");
2697       }
2698       contents.append("</table>");
2699     }
2700     editPane.setText(contents.toString() + "</html>");
2701     JInternalFrame frame = new JInternalFrame();
2702     frame.getContentPane().add(new JScrollPane(editPane));
2703
2704     Desktop.instance.addInternalFrame(frame, "Alignment Properties: "
2705             + getTitle(), 500, 400);
2706   }
2707
2708   /**
2709    * DOCUMENT ME!
2710    * 
2711    * @param e
2712    *          DOCUMENT ME!
2713    */
2714   public void overviewMenuItem_actionPerformed(ActionEvent e)
2715   {
2716     if (alignPanel.overviewPanel != null)
2717     {
2718       return;
2719     }
2720
2721     JInternalFrame frame = new JInternalFrame();
2722     OverviewPanel overview = new OverviewPanel(alignPanel);
2723     frame.setContentPane(overview);
2724     Desktop.addInternalFrame(frame, "Overview " + this.getTitle(), frame
2725             .getWidth(), frame.getHeight());
2726     frame.pack();
2727     frame.setLayer(JLayeredPane.PALETTE_LAYER);
2728     frame
2729             .addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
2730             {
2731               public void internalFrameClosed(
2732                       javax.swing.event.InternalFrameEvent evt)
2733               {
2734                 alignPanel.setOverviewPanel(null);
2735               };
2736             });
2737
2738     alignPanel.setOverviewPanel(overview);
2739   }
2740
2741   public void textColour_actionPerformed(ActionEvent e)
2742   {
2743     new TextColourChooser().chooseColour(alignPanel, null);
2744   }
2745
2746   /**
2747    * DOCUMENT ME!
2748    * 
2749    * @param e
2750    *          DOCUMENT ME!
2751    */
2752   protected void noColourmenuItem_actionPerformed(ActionEvent e)
2753   {
2754     changeColour(null);
2755   }
2756
2757   /**
2758    * DOCUMENT ME!
2759    * 
2760    * @param e
2761    *          DOCUMENT ME!
2762    */
2763   public void clustalColour_actionPerformed(ActionEvent e)
2764   {
2765     changeColour(new ClustalxColourScheme(
2766             viewport.alignment.getSequences(), viewport.alignment
2767                     .getWidth()));
2768   }
2769
2770   /**
2771    * DOCUMENT ME!
2772    * 
2773    * @param e
2774    *          DOCUMENT ME!
2775    */
2776   public void zappoColour_actionPerformed(ActionEvent e)
2777   {
2778     changeColour(new ZappoColourScheme());
2779   }
2780
2781   /**
2782    * DOCUMENT ME!
2783    * 
2784    * @param e
2785    *          DOCUMENT ME!
2786    */
2787   public void taylorColour_actionPerformed(ActionEvent e)
2788   {
2789     changeColour(new TaylorColourScheme());
2790   }
2791
2792   /**
2793    * DOCUMENT ME!
2794    * 
2795    * @param e
2796    *          DOCUMENT ME!
2797    */
2798   public void hydrophobicityColour_actionPerformed(ActionEvent e)
2799   {
2800     changeColour(new HydrophobicColourScheme());
2801   }
2802
2803   /**
2804    * DOCUMENT ME!
2805    * 
2806    * @param e
2807    *          DOCUMENT ME!
2808    */
2809   public void helixColour_actionPerformed(ActionEvent e)
2810   {
2811     changeColour(new HelixColourScheme());
2812   }
2813
2814   /**
2815    * DOCUMENT ME!
2816    * 
2817    * @param e
2818    *          DOCUMENT ME!
2819    */
2820   public void strandColour_actionPerformed(ActionEvent e)
2821   {
2822     changeColour(new StrandColourScheme());
2823   }
2824
2825   /**
2826    * DOCUMENT ME!
2827    * 
2828    * @param e
2829    *          DOCUMENT ME!
2830    */
2831   public void turnColour_actionPerformed(ActionEvent e)
2832   {
2833     changeColour(new TurnColourScheme());
2834   }
2835
2836   /**
2837    * DOCUMENT ME!
2838    * 
2839    * @param e
2840    *          DOCUMENT ME!
2841    */
2842   public void buriedColour_actionPerformed(ActionEvent e)
2843   {
2844     changeColour(new BuriedColourScheme());
2845   }
2846
2847   /**
2848    * DOCUMENT ME!
2849    * 
2850    * @param e
2851    *          DOCUMENT ME!
2852    */
2853   public void nucleotideColour_actionPerformed(ActionEvent e)
2854   {
2855     changeColour(new NucleotideColourScheme());
2856   }
2857
2858   public void annotationColour_actionPerformed(ActionEvent e)
2859   {
2860     new AnnotationColourChooser(viewport, alignPanel);
2861   }
2862
2863   /**
2864    * DOCUMENT ME!
2865    * 
2866    * @param e
2867    *          DOCUMENT ME!
2868    */
2869   protected void applyToAllGroups_actionPerformed(ActionEvent e)
2870   {
2871     viewport.setColourAppliesToAllGroups(applyToAllGroups.isSelected());
2872   }
2873
2874   /**
2875    * DOCUMENT ME!
2876    * 
2877    * @param cs
2878    *          DOCUMENT ME!
2879    */
2880   public void changeColour(ColourSchemeI cs)
2881   {
2882     int threshold = 0;
2883
2884     if (cs != null)
2885     {
2886       if (viewport.getAbovePIDThreshold())
2887       {
2888         threshold = SliderPanel.setPIDSliderSource(alignPanel, cs,
2889                 "Background");
2890
2891         cs.setThreshold(threshold, viewport.getIgnoreGapsConsensus());
2892
2893         viewport.setGlobalColourScheme(cs);
2894       }
2895       else
2896       {
2897         cs.setThreshold(0, viewport.getIgnoreGapsConsensus());
2898       }
2899
2900       if (viewport.getConservationSelected())
2901       {
2902
2903         Alignment al = (Alignment) viewport.alignment;
2904         Conservation c = new Conservation("All",
2905                 ResidueProperties.propHash, 3, al.getSequences(), 0, al
2906                         .getWidth() - 1);
2907
2908         c.calculate();
2909         c.verdict(false, viewport.ConsPercGaps);
2910
2911         cs.setConservation(c);
2912
2913         cs.setConservationInc(SliderPanel.setConservationSlider(alignPanel,
2914                 cs, "Background"));
2915       }
2916       else
2917       {
2918         cs.setConservation(null);
2919       }
2920
2921       cs.setConsensus(viewport.hconsensus);
2922     }
2923
2924     viewport.setGlobalColourScheme(cs);
2925
2926     if (viewport.getColourAppliesToAllGroups())
2927     {
2928       Vector groups = viewport.alignment.getGroups();
2929
2930       for (int i = 0; i < groups.size(); i++)
2931       {
2932         SequenceGroup sg = (SequenceGroup) groups.elementAt(i);
2933
2934         if (cs == null)
2935         {
2936           sg.cs = null;
2937           continue;
2938         }
2939
2940         if (cs instanceof ClustalxColourScheme)
2941         {
2942           sg.cs = new ClustalxColourScheme(sg
2943                   .getSequences(viewport.hiddenRepSequences), sg.getWidth());
2944         }
2945         else if (cs instanceof UserColourScheme)
2946         {
2947           sg.cs = new UserColourScheme(((UserColourScheme) cs).getColours());
2948         }
2949         else
2950         {
2951           try
2952           {
2953             sg.cs = (ColourSchemeI) cs.getClass().newInstance();
2954           } catch (Exception ex)
2955           {
2956           }
2957         }
2958
2959         if (viewport.getAbovePIDThreshold()
2960                 || cs instanceof PIDColourScheme
2961                 || cs instanceof Blosum62ColourScheme)
2962         {
2963           sg.cs.setThreshold(threshold, viewport.getIgnoreGapsConsensus());
2964
2965           sg.cs.setConsensus(AAFrequency.calculate(sg
2966                   .getSequences(viewport.hiddenRepSequences), sg
2967                   .getStartRes(), sg.getEndRes() + 1));
2968         }
2969         else
2970         {
2971           sg.cs.setThreshold(0, viewport.getIgnoreGapsConsensus());
2972         }
2973
2974         if (viewport.getConservationSelected())
2975         {
2976           Conservation c = new Conservation("Group",
2977                   ResidueProperties.propHash, 3, sg
2978                           .getSequences(viewport.hiddenRepSequences), sg
2979                           .getStartRes(), sg.getEndRes() + 1);
2980           c.calculate();
2981           c.verdict(false, viewport.ConsPercGaps);
2982           sg.cs.setConservation(c);
2983         }
2984         else
2985         {
2986           sg.cs.setConservation(null);
2987         }
2988       }
2989     }
2990
2991     if (alignPanel.getOverviewPanel() != null)
2992     {
2993       alignPanel.getOverviewPanel().updateOverviewImage();
2994     }
2995
2996     alignPanel.paintAlignment(true);
2997   }
2998
2999   /**
3000    * DOCUMENT ME!
3001    * 
3002    * @param e
3003    *          DOCUMENT ME!
3004    */
3005   protected void modifyPID_actionPerformed(ActionEvent e)
3006   {
3007     if (viewport.getAbovePIDThreshold()
3008             && viewport.globalColourScheme != null)
3009     {
3010       SliderPanel.setPIDSliderSource(alignPanel, viewport
3011               .getGlobalColourScheme(), "Background");
3012       SliderPanel.showPIDSlider();
3013     }
3014   }
3015
3016   /**
3017    * DOCUMENT ME!
3018    * 
3019    * @param e
3020    *          DOCUMENT ME!
3021    */
3022   protected void modifyConservation_actionPerformed(ActionEvent e)
3023   {
3024     if (viewport.getConservationSelected()
3025             && viewport.globalColourScheme != null)
3026     {
3027       SliderPanel.setConservationSlider(alignPanel,
3028               viewport.globalColourScheme, "Background");
3029       SliderPanel.showConservationSlider();
3030     }
3031   }
3032
3033   /**
3034    * DOCUMENT ME!
3035    * 
3036    * @param e
3037    *          DOCUMENT ME!
3038    */
3039   protected void conservationMenuItem_actionPerformed(ActionEvent e)
3040   {
3041     viewport.setConservationSelected(conservationMenuItem.isSelected());
3042
3043     viewport.setAbovePIDThreshold(false);
3044     abovePIDThreshold.setSelected(false);
3045
3046     changeColour(viewport.getGlobalColourScheme());
3047
3048     modifyConservation_actionPerformed(null);
3049   }
3050
3051   /**
3052    * DOCUMENT ME!
3053    * 
3054    * @param e
3055    *          DOCUMENT ME!
3056    */
3057   public void abovePIDThreshold_actionPerformed(ActionEvent e)
3058   {
3059     viewport.setAbovePIDThreshold(abovePIDThreshold.isSelected());
3060
3061     conservationMenuItem.setSelected(false);
3062     viewport.setConservationSelected(false);
3063
3064     changeColour(viewport.getGlobalColourScheme());
3065
3066     modifyPID_actionPerformed(null);
3067   }
3068
3069   /**
3070    * DOCUMENT ME!
3071    * 
3072    * @param e
3073    *          DOCUMENT ME!
3074    */
3075   public void userDefinedColour_actionPerformed(ActionEvent e)
3076   {
3077     if (e.getActionCommand().equals("User Defined..."))
3078     {
3079       new UserDefinedColours(alignPanel, null);
3080     }
3081     else
3082     {
3083       UserColourScheme udc = (UserColourScheme) UserDefinedColours
3084               .getUserColourSchemes().get(e.getActionCommand());
3085
3086       changeColour(udc);
3087     }
3088   }
3089
3090   public void updateUserColourMenu()
3091   {
3092
3093     Component[] menuItems = colourMenu.getMenuComponents();
3094     int i, iSize = menuItems.length;
3095     for (i = 0; i < iSize; i++)
3096     {
3097       if (menuItems[i].getName() != null
3098               && menuItems[i].getName().equals("USER_DEFINED"))
3099       {
3100         colourMenu.remove(menuItems[i]);
3101         iSize--;
3102       }
3103     }
3104     if (jalview.gui.UserDefinedColours.getUserColourSchemes() != null)
3105     {
3106       java.util.Enumeration userColours = jalview.gui.UserDefinedColours
3107               .getUserColourSchemes().keys();
3108
3109       while (userColours.hasMoreElements())
3110       {
3111         final JRadioButtonMenuItem radioItem = new JRadioButtonMenuItem(
3112                 userColours.nextElement().toString());
3113         radioItem.setName("USER_DEFINED");
3114         radioItem.addMouseListener(new MouseAdapter()
3115         {
3116           public void mousePressed(MouseEvent evt)
3117           {
3118             if (evt.isControlDown()
3119                     || SwingUtilities.isRightMouseButton(evt))
3120             {
3121               radioItem
3122                       .removeActionListener(radioItem.getActionListeners()[0]);
3123
3124               int option = JOptionPane.showInternalConfirmDialog(
3125                       jalview.gui.Desktop.desktop,
3126                       "Remove from default list?",
3127                       "Remove user defined colour",
3128                       JOptionPane.YES_NO_OPTION);
3129               if (option == JOptionPane.YES_OPTION)
3130               {
3131                 jalview.gui.UserDefinedColours
3132                         .removeColourFromDefaults(radioItem.getText());
3133                 colourMenu.remove(radioItem);
3134               }
3135               else
3136               {
3137                 radioItem.addActionListener(new ActionListener()
3138                 {
3139                   public void actionPerformed(ActionEvent evt)
3140                   {
3141                     userDefinedColour_actionPerformed(evt);
3142                   }
3143                 });
3144               }
3145             }
3146           }
3147         });
3148         radioItem.addActionListener(new ActionListener()
3149         {
3150           public void actionPerformed(ActionEvent evt)
3151           {
3152             userDefinedColour_actionPerformed(evt);
3153           }
3154         });
3155
3156         colourMenu.insert(radioItem, 15);
3157         colours.add(radioItem);
3158       }
3159     }
3160   }
3161
3162   /**
3163    * DOCUMENT ME!
3164    * 
3165    * @param e
3166    *          DOCUMENT ME!
3167    */
3168   public void PIDColour_actionPerformed(ActionEvent e)
3169   {
3170     changeColour(new PIDColourScheme());
3171   }
3172
3173   /**
3174    * DOCUMENT ME!
3175    * 
3176    * @param e
3177    *          DOCUMENT ME!
3178    */
3179   public void BLOSUM62Colour_actionPerformed(ActionEvent e)
3180   {
3181     changeColour(new Blosum62ColourScheme());
3182   }
3183
3184   /**
3185    * DOCUMENT ME!
3186    * 
3187    * @param e
3188    *          DOCUMENT ME!
3189    */
3190   public void sortPairwiseMenuItem_actionPerformed(ActionEvent e)
3191   {
3192     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3193     AlignmentSorter.sortByPID(viewport.getAlignment(), viewport
3194             .getAlignment().getSequenceAt(0), null);
3195     addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
3196             viewport.alignment));
3197     alignPanel.paintAlignment(true);
3198   }
3199
3200   /**
3201    * DOCUMENT ME!
3202    * 
3203    * @param e
3204    *          DOCUMENT ME!
3205    */
3206   public void sortIDMenuItem_actionPerformed(ActionEvent e)
3207   {
3208     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3209     AlignmentSorter.sortByID(viewport.getAlignment());
3210     addHistoryItem(new OrderCommand("ID Sort", oldOrder, viewport.alignment));
3211     alignPanel.paintAlignment(true);
3212   }
3213
3214   /**
3215    * DOCUMENT ME!
3216    * 
3217    * @param e
3218    *          DOCUMENT ME!
3219    */
3220   public void sortLengthMenuItem_actionPerformed(ActionEvent e)
3221   {
3222     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3223     AlignmentSorter.sortByLength(viewport.getAlignment());
3224     addHistoryItem(new OrderCommand("Length Sort", oldOrder,
3225             viewport.alignment));
3226     alignPanel.paintAlignment(true);
3227   }
3228
3229   /**
3230    * DOCUMENT ME!
3231    * 
3232    * @param e
3233    *          DOCUMENT ME!
3234    */
3235   public void sortGroupMenuItem_actionPerformed(ActionEvent e)
3236   {
3237     SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3238     AlignmentSorter.sortByGroup(viewport.getAlignment());
3239     addHistoryItem(new OrderCommand("Group Sort", oldOrder,
3240             viewport.alignment));
3241
3242     alignPanel.paintAlignment(true);
3243   }
3244
3245   /**
3246    * DOCUMENT ME!
3247    * 
3248    * @param e
3249    *          DOCUMENT ME!
3250    */
3251   public void removeRedundancyMenuItem_actionPerformed(ActionEvent e)
3252   {
3253     new RedundancyPanel(alignPanel, this);
3254   }
3255
3256   /**
3257    * DOCUMENT ME!
3258    * 
3259    * @param e
3260    *          DOCUMENT ME!
3261    */
3262   public void pairwiseAlignmentMenuItem_actionPerformed(ActionEvent e)
3263   {
3264     if ((viewport.getSelectionGroup() == null)
3265             || (viewport.getSelectionGroup().getSize() < 2))
3266     {
3267       JOptionPane.showInternalMessageDialog(this,
3268               "You must select at least 2 sequences.", "Invalid Selection",
3269               JOptionPane.WARNING_MESSAGE);
3270     }
3271     else
3272     {
3273       JInternalFrame frame = new JInternalFrame();
3274       frame.setContentPane(new PairwiseAlignPanel(viewport));
3275       Desktop.addInternalFrame(frame, "Pairwise Alignment", 600, 500);
3276     }
3277   }
3278
3279   /**
3280    * DOCUMENT ME!
3281    * 
3282    * @param e
3283    *          DOCUMENT ME!
3284    */
3285   public void PCAMenuItem_actionPerformed(ActionEvent e)
3286   {
3287     if (((viewport.getSelectionGroup() != null)
3288             && (viewport.getSelectionGroup().getSize() < 4) && (viewport
3289             .getSelectionGroup().getSize() > 0))
3290             || (viewport.getAlignment().getHeight() < 4))
3291     {
3292       JOptionPane.showInternalMessageDialog(this,
3293               "Principal component analysis must take\n"
3294                       + "at least 4 input sequences.",
3295               "Sequence selection insufficient",
3296               JOptionPane.WARNING_MESSAGE);
3297
3298       return;
3299     }
3300
3301     new PCAPanel(alignPanel);
3302   }
3303
3304   public void autoCalculate_actionPerformed(ActionEvent e)
3305   {
3306     viewport.autoCalculateConsensus = autoCalculate.isSelected();
3307     if (viewport.autoCalculateConsensus)
3308     {
3309       viewport.firePropertyChange("alignment", null, viewport
3310               .getAlignment().getSequences());
3311     }
3312   }
3313
3314   /**
3315    * DOCUMENT ME!
3316    * 
3317    * @param e
3318    *          DOCUMENT ME!
3319    */
3320   public void averageDistanceTreeMenuItem_actionPerformed(ActionEvent e)
3321   {
3322     NewTreePanel("AV", "PID", "Average distance tree using PID");
3323   }
3324
3325   /**
3326    * DOCUMENT ME!
3327    * 
3328    * @param e
3329    *          DOCUMENT ME!
3330    */
3331   public void neighbourTreeMenuItem_actionPerformed(ActionEvent e)
3332   {
3333     NewTreePanel("NJ", "PID", "Neighbour joining tree using PID");
3334   }
3335
3336   /**
3337    * DOCUMENT ME!
3338    * 
3339    * @param e
3340    *          DOCUMENT ME!
3341    */
3342   protected void njTreeBlosumMenuItem_actionPerformed(ActionEvent e)
3343   {
3344     NewTreePanel("NJ", "BL", "Neighbour joining tree using BLOSUM62");
3345   }
3346
3347   /**
3348    * DOCUMENT ME!
3349    * 
3350    * @param e
3351    *          DOCUMENT ME!
3352    */
3353   protected void avTreeBlosumMenuItem_actionPerformed(ActionEvent e)
3354   {
3355     NewTreePanel("AV", "BL", "Average distance tree using BLOSUM62");
3356   }
3357
3358   /**
3359    * DOCUMENT ME!
3360    * 
3361    * @param type
3362    *          DOCUMENT ME!
3363    * @param pwType
3364    *          DOCUMENT ME!
3365    * @param title
3366    *          DOCUMENT ME!
3367    */
3368   void NewTreePanel(String type, String pwType, String title)
3369   {
3370     TreePanel tp;
3371
3372     if (viewport.getSelectionGroup() != null)
3373     {
3374       if (viewport.getSelectionGroup().getSize() < 3)
3375       {
3376         JOptionPane
3377                 .showMessageDialog(
3378                         Desktop.desktop,
3379                         "You need to have more than two sequences selected to build a tree!",
3380                         "Not enough sequences", JOptionPane.WARNING_MESSAGE);
3381         return;
3382       }
3383
3384       int s = 0;
3385       SequenceGroup sg = viewport.getSelectionGroup();
3386
3387       /* Decide if the selection is a column region */
3388       while (s < sg.getSize())
3389       {
3390         if (((SequenceI) sg.getSequences(null).elementAt(s++)).getLength() < sg
3391                 .getEndRes())
3392         {
3393           JOptionPane
3394                   .showMessageDialog(
3395                           Desktop.desktop,
3396                           "The selected region to create a tree may\nonly contain residues or gaps.\n"
3397                                   + "Try using the Pad function in the edit menu,\n"
3398                                   + "or one of the multiple sequence alignment web services.",
3399                           "Sequences in selection are not aligned",
3400                           JOptionPane.WARNING_MESSAGE);
3401
3402           return;
3403         }
3404       }
3405
3406       title = title + " on region";
3407       tp = new TreePanel(alignPanel, type, pwType);
3408     }
3409     else
3410     {
3411       // are the visible sequences aligned?
3412       if (!viewport.alignment.isAligned(false))
3413       {
3414         JOptionPane
3415                 .showMessageDialog(
3416                         Desktop.desktop,
3417                         "The sequences must be aligned before creating a tree.\n"
3418                                 + "Try using the Pad function in the edit menu,\n"
3419                                 + "or one of the multiple sequence alignment web services.",
3420                         "Sequences not aligned",
3421                         JOptionPane.WARNING_MESSAGE);
3422
3423         return;
3424       }
3425
3426       if (viewport.alignment.getHeight() < 2)
3427       {
3428         return;
3429       }
3430
3431       tp = new TreePanel(alignPanel, type, pwType);
3432     }
3433
3434     title += " from ";
3435
3436     if (viewport.viewName != null)
3437     {
3438       title += viewport.viewName + " of ";
3439     }
3440
3441     title += this.title;
3442
3443     Desktop.addInternalFrame(tp, title, 600, 500);
3444   }
3445
3446   /**
3447    * DOCUMENT ME!
3448    * 
3449    * @param title
3450    *          DOCUMENT ME!
3451    * @param order
3452    *          DOCUMENT ME!
3453    */
3454   public void addSortByOrderMenuItem(String title,
3455           final AlignmentOrder order)
3456   {
3457     final JMenuItem item = new JMenuItem("by " + title);
3458     sort.add(item);
3459     item.addActionListener(new java.awt.event.ActionListener()
3460     {
3461       public void actionPerformed(ActionEvent e)
3462       {
3463         SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3464
3465         // TODO: JBPNote - have to map order entries to curent SequenceI
3466         // pointers
3467         AlignmentSorter.sortBy(viewport.getAlignment(), order);
3468
3469         addHistoryItem(new OrderCommand(order.getName(), oldOrder,
3470                 viewport.alignment));
3471
3472         alignPanel.paintAlignment(true);
3473       }
3474     });
3475   }
3476
3477   /**
3478    * Add a new sort by annotation score menu item
3479    * 
3480    * @param sort
3481    *          the menu to add the option to
3482    * @param scoreLabel
3483    *          the label used to retrieve scores for each sequence on the
3484    *          alignment
3485    */
3486   public void addSortByAnnotScoreMenuItem(JMenu sort,
3487           final String scoreLabel)
3488   {
3489     final JMenuItem item = new JMenuItem(scoreLabel);
3490     sort.add(item);
3491     item.addActionListener(new java.awt.event.ActionListener()
3492     {
3493       public void actionPerformed(ActionEvent e)
3494       {
3495         SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
3496         AlignmentSorter.sortByAnnotationScore(scoreLabel, viewport
3497                 .getAlignment());// ,viewport.getSelectionGroup());
3498         addHistoryItem(new OrderCommand("Sort by " + scoreLabel, oldOrder,
3499                 viewport.alignment));
3500         alignPanel.paintAlignment(true);
3501       }
3502     });
3503   }
3504
3505   /**
3506    * last hash for alignment's annotation array - used to minimise cost of
3507    * rebuild.
3508    */
3509   protected int _annotationScoreVectorHash;
3510
3511   /**
3512    * search the alignment and rebuild the sort by annotation score submenu the
3513    * last alignment annotation vector hash is stored to minimize cost of
3514    * rebuilding in subsequence calls.
3515    * 
3516    */
3517   public void buildSortByAnnotationScoresMenu()
3518   {
3519     if (viewport.alignment.getAlignmentAnnotation() == null)
3520     {
3521       return;
3522     }
3523
3524     if (viewport.alignment.getAlignmentAnnotation().hashCode() != _annotationScoreVectorHash)
3525     {
3526       sortByAnnotScore.removeAll();
3527       // almost certainly a quicker way to do this - but we keep it simple
3528       Hashtable scoreSorts = new Hashtable();
3529       AlignmentAnnotation aann[];
3530       Enumeration sq = viewport.alignment.getSequences().elements();
3531       while (sq.hasMoreElements())
3532       {
3533         aann = ((SequenceI) sq.nextElement()).getAnnotation();
3534         for (int i = 0; aann != null && i < aann.length; i++)
3535         {
3536           if (aann[i].hasScore() && aann[i].sequenceRef != null)
3537           {
3538             scoreSorts.put(aann[i].label, aann[i].label);
3539           }
3540         }
3541       }
3542       Enumeration labels = scoreSorts.keys();
3543       while (labels.hasMoreElements())
3544       {
3545         addSortByAnnotScoreMenuItem(sortByAnnotScore, (String) labels
3546                 .nextElement());
3547       }
3548       sortByAnnotScore.setVisible(scoreSorts.size() > 0);
3549       scoreSorts.clear();
3550
3551       _annotationScoreVectorHash = viewport.alignment
3552               .getAlignmentAnnotation().hashCode();
3553     }
3554   }
3555
3556   /**
3557    * Maintain the Order by->Displayed Tree menu. Creates a new menu item for a
3558    * TreePanel with an appropriate <code>jalview.analysis.AlignmentSorter</code>
3559    * call. Listeners are added to remove the menu item when the treePanel is
3560    * closed, and adjust the tree leaf to sequence mapping when the alignment is
3561    * modified.
3562    * 
3563    * @param treePanel
3564    *          Displayed tree window.
3565    * @param title
3566    *          SortBy menu item title.
3567    */
3568   public void buildTreeMenu()
3569   {
3570     sortByTreeMenu.removeAll();
3571
3572     Vector comps = (Vector) PaintRefresher.components.get(viewport
3573             .getSequenceSetId());
3574     Vector treePanels = new Vector();
3575     int i, iSize = comps.size();
3576     for (i = 0; i < iSize; i++)
3577     {
3578       if (comps.elementAt(i) instanceof TreePanel)
3579       {
3580         treePanels.add(comps.elementAt(i));
3581       }
3582     }
3583
3584     iSize = treePanels.size();
3585
3586     if (iSize < 1)
3587     {
3588       sortByTreeMenu.setVisible(false);
3589       return;
3590     }
3591
3592     sortByTreeMenu.setVisible(true);
3593
3594     for (i = 0; i < treePanels.size(); i++)
3595     {
3596       TreePanel tp = (TreePanel) treePanels.elementAt(i);
3597       final JMenuItem item = new JMenuItem(tp.getTitle());
3598       final NJTree tree = ((TreePanel) treePanels.elementAt(i)).getTree();
3599       item.addActionListener(new java.awt.event.ActionListener()
3600       {
3601         public void actionPerformed(ActionEvent e)
3602         {
3603           SequenceI[] oldOrder = viewport.getAlignment()
3604                   .getSequencesArray();
3605           AlignmentSorter.sortByTree(viewport.getAlignment(), tree);
3606
3607           addHistoryItem(new OrderCommand("Tree Sort", oldOrder,
3608                   viewport.alignment));
3609
3610           alignPanel.paintAlignment(true);
3611         }
3612       });
3613
3614       sortByTreeMenu.add(item);
3615     }
3616   }
3617
3618   /**
3619    * Work out whether the whole set of sequences or just the selected set will
3620    * be submitted for multiple alignment.
3621    * 
3622    */
3623   public jalview.datamodel.AlignmentView gatherSequencesForAlignment()
3624   {
3625     // Now, check we have enough sequences
3626     AlignmentView msa = null;
3627
3628     if ((viewport.getSelectionGroup() != null)
3629             && (viewport.getSelectionGroup().getSize() > 1))
3630     {
3631       // JBPNote UGLY! To prettify, make SequenceGroup and Alignment conform to
3632       // some common interface!
3633       /*
3634        * SequenceGroup seqs = viewport.getSelectionGroup(); int sz; msa = new
3635        * SequenceI[sz = seqs.getSize(false)];
3636        * 
3637        * for (int i = 0; i < sz; i++) { msa[i] = (SequenceI)
3638        * seqs.getSequenceAt(i); }
3639        */
3640       msa = viewport.getAlignmentView(true);
3641     }
3642     else
3643     {
3644       /*
3645        * Vector seqs = viewport.getAlignment().getSequences();
3646        * 
3647        * if (seqs.size() > 1) { msa = new SequenceI[seqs.size()];
3648        * 
3649        * for (int i = 0; i < seqs.size(); i++) { msa[i] = (SequenceI)
3650        * seqs.elementAt(i); } }
3651        */
3652       msa = viewport.getAlignmentView(false);
3653     }
3654     return msa;
3655   }
3656
3657   /**
3658    * Decides what is submitted to a secondary structure prediction service: the
3659    * first sequence in the alignment, or in the current selection, or, if the
3660    * alignment is 'aligned' (ie padded with gaps), then the currently selected
3661    * region or the whole alignment. (where the first sequence in the set is the
3662    * one that the prediction will be for).
3663    */
3664   public AlignmentView gatherSeqOrMsaForSecStrPrediction()
3665   {
3666     AlignmentView seqs = null;
3667
3668     if ((viewport.getSelectionGroup() != null)
3669             && (viewport.getSelectionGroup().getSize() > 0))
3670     {
3671       seqs = viewport.getAlignmentView(true);
3672     }
3673     else
3674     {
3675       seqs = viewport.getAlignmentView(false);
3676     }
3677     // limit sequences - JBPNote in future - could spawn multiple prediction
3678     // jobs
3679     // TODO: viewport.alignment.isAligned is a global state - the local
3680     // selection may well be aligned - we preserve 2.0.8 behaviour for moment.
3681     if (!viewport.alignment.isAligned(false))
3682     {
3683       seqs.setSequences(new SeqCigar[]
3684       { seqs.getSequences()[0] });
3685       // TODO: if seqs.getSequences().length>1 then should really have warned
3686       // user!
3687
3688     }
3689     return seqs;
3690   }
3691
3692   /**
3693    * DOCUMENT ME!
3694    * 
3695    * @param e
3696    *          DOCUMENT ME!
3697    */
3698   protected void LoadtreeMenuItem_actionPerformed(ActionEvent e)
3699   {
3700     // Pick the tree file
3701     JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache
3702             .getProperty("LAST_DIRECTORY"));
3703     chooser.setFileView(new JalviewFileView());
3704     chooser.setDialogTitle("Select a newick-like tree file");
3705     chooser.setToolTipText("Load a tree file");
3706
3707     int value = chooser.showOpenDialog(null);
3708
3709     if (value == JalviewFileChooser.APPROVE_OPTION)
3710     {
3711       String choice = chooser.getSelectedFile().getPath();
3712       jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
3713       jalview.io.NewickFile fin = null;
3714       try
3715       {
3716         fin = new jalview.io.NewickFile(choice, "File");
3717         viewport.setCurrentTree(ShowNewickTree(fin, choice).getTree());
3718       } catch (Exception ex)
3719       {
3720         JOptionPane.showMessageDialog(Desktop.desktop, ex.getMessage(),
3721                 "Problem reading tree file", JOptionPane.WARNING_MESSAGE);
3722         ex.printStackTrace();
3723       }
3724       if (fin != null && fin.hasWarningMessage())
3725       {
3726         JOptionPane.showMessageDialog(Desktop.desktop, fin
3727                 .getWarningMessage(), "Possible problem with tree file",
3728                 JOptionPane.WARNING_MESSAGE);
3729       }
3730     }
3731   }
3732
3733   public TreePanel ShowNewickTree(NewickFile nf, String title)
3734   {
3735     return ShowNewickTree(nf, title, 600, 500, 4, 5);
3736   }
3737
3738   public TreePanel ShowNewickTree(NewickFile nf, String title,
3739           AlignmentView input)
3740   {
3741     return ShowNewickTree(nf, title, input, 600, 500, 4, 5);
3742   }
3743
3744   public TreePanel ShowNewickTree(NewickFile nf, String title, int w,
3745           int h, int x, int y)
3746   {
3747     return ShowNewickTree(nf, title, null, w, h, x, y);
3748   }
3749
3750   /**
3751    * Add a treeviewer for the tree extracted from a newick file object to the
3752    * current alignment view
3753    * 
3754    * @param nf
3755    *          the tree
3756    * @param title
3757    *          tree viewer title
3758    * @param input
3759    *          Associated alignment input data (or null)
3760    * @param w
3761    *          width
3762    * @param h
3763    *          height
3764    * @param x
3765    *          position
3766    * @param y
3767    *          position
3768    * @return TreePanel handle
3769    */
3770   public TreePanel ShowNewickTree(NewickFile nf, String title,
3771           AlignmentView input, int w, int h, int x, int y)
3772   {
3773     TreePanel tp = null;
3774
3775     try
3776     {
3777       nf.parse();
3778
3779       if (nf.getTree() != null)
3780       {
3781         tp = new TreePanel(alignPanel, "FromFile", title, nf, input);
3782
3783         tp.setSize(w, h);
3784
3785         if (x > 0 && y > 0)
3786         {
3787           tp.setLocation(x, y);
3788         }
3789
3790         Desktop.addInternalFrame(tp, title, w, h);
3791       }
3792     } catch (Exception ex)
3793     {
3794       ex.printStackTrace();
3795     }
3796
3797     return tp;
3798   }
3799
3800   private boolean buildingMenu = false;
3801
3802   /**
3803    * Generates menu items and listener event actions for web service clients
3804    * 
3805    */
3806   public void BuildWebServiceMenu()
3807   {
3808     while (buildingMenu)
3809     {
3810       try
3811       {
3812         System.err.println("Waiting for building menu to finish.");
3813         Thread.sleep(10);
3814       } catch (Exception e)
3815       {
3816       }
3817       ;
3818     }
3819     buildingMenu = true;
3820     try
3821     {
3822       System.err
3823               .println("Building ws menu again " + Thread.currentThread());
3824       // TODO: add support for context dependent disabling of services based on
3825       // alignment and current selection
3826       // TODO: add additional serviceHandle parameter to specify abstract
3827       // handler
3828       // class independently of AbstractName
3829       // TODO: add in rediscovery GUI function to restart discoverer
3830       // TODO: group services by location as well as function and/or introduce
3831       // object broker mechanism.
3832       Vector wsmenu = new Vector();
3833       final IProgressIndicator af = this;
3834       if (Cache.getDefault("SHOW_JWS1_SERVICES", true)
3835               && Discoverer.services != null
3836               && (Discoverer.services.size() > 0))
3837       {
3838         // TODO: refactor to allow list of AbstractName/Handler bindings to be
3839         // stored or retrieved from elsewhere
3840         Vector msaws = (Vector) Discoverer.services.get("MsaWS");
3841         Vector secstrpr = (Vector) Discoverer.services.get("SecStrPred");
3842         Vector seqsrch = (Vector) Discoverer.services.get("SeqSearch");
3843         // TODO: move GUI generation code onto service implementation - so a
3844         // client instance attaches itself to the GUI with method call like
3845         // jalview.ws.MsaWSClient.bind(servicehandle, Desktop.instance,
3846         // alignframe)
3847         if (msaws != null)
3848         {
3849           // Add any Multiple Sequence Alignment Services
3850           final JMenu msawsmenu = new JMenu("Alignment");
3851           for (int i = 0, j = msaws.size(); i < j; i++)
3852           {
3853             final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) msaws
3854                     .get(i);
3855             jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer
3856                     .getServiceClient(sh);
3857             impl.attachWSMenuEntry(msawsmenu, this);
3858
3859           }
3860           wsmenu.add(msawsmenu);
3861         }
3862         if (secstrpr != null)
3863         {
3864           // Add any secondary structure prediction services
3865           final JMenu secstrmenu = new JMenu(
3866                   "Secondary Structure Prediction");
3867           for (int i = 0, j = secstrpr.size(); i < j; i++)
3868           {
3869             final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) secstrpr
3870                     .get(i);
3871             jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer
3872                     .getServiceClient(sh);
3873             impl.attachWSMenuEntry(secstrmenu, this);
3874           }
3875           wsmenu.add(secstrmenu);
3876         }
3877         if (seqsrch != null)
3878         {
3879           // Add any sequence search services
3880           final JMenu seqsrchmenu = new JMenu("Sequence Database Search");
3881           for (int i = 0, j = seqsrch.size(); i < j; i++)
3882           {
3883             final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) seqsrch
3884                     .elementAt(i);
3885             jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer
3886                     .getServiceClient(sh);
3887             impl.attachWSMenuEntry(seqsrchmenu, this);
3888           }
3889           wsmenu.add(seqsrchmenu);
3890         }
3891       }
3892
3893       // TODO: move into separate menu builder class.
3894       if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
3895       {
3896         Jws2Discoverer jws2servs = Jws2Discoverer.getDiscoverer();
3897         if (jws2servs != null)
3898         {
3899           if (jws2servs.hasServices())
3900           {
3901             JMenu jws2men = new JMenu("Jalview 2 Services");
3902             jws2servs.attachWSMenuEntry(jws2men, this);
3903             wsmenu.add(jws2men);
3904           }
3905         }
3906       }
3907       resetWebServiceMenu();
3908       // finally, add the whole shebang onto the webservices menu
3909       if (wsmenu.size() > 0)
3910       {
3911         for (int i = 0, j = wsmenu.size(); i < j; i++)
3912         {
3913           webService.add((JMenu) wsmenu.get(i));
3914         }
3915       }
3916       else
3917       {
3918         this.webService.add(this.webServiceNoServices);
3919       }
3920     } catch (Exception e)
3921     {
3922     }
3923     ;
3924     buildingMenu = false;
3925   }
3926
3927   /**
3928    * empty the web service menu and add any ad-hoc functions not dynamically
3929    * discovered.
3930    * 
3931    */
3932   private void resetWebServiceMenu()
3933   {
3934     webService.removeAll();
3935     build_fetchdbmenu(webService);
3936     build_urlServiceMenu(webService);
3937   }
3938
3939   /**
3940    * construct any groupURL type service menu entries.
3941    * 
3942    * @param webService
3943    */
3944   private void build_urlServiceMenu(JMenu webService)
3945   {
3946     if (Cache.getDefault("SHOW_ENFIN_SERVICES", true))
3947     {
3948       jalview.ws.EnfinEnvision2OneWay.getInstance().attachWSMenuEntry(
3949               webService, this);
3950     }
3951   }
3952
3953   /*
3954    * public void vamsasStore_actionPerformed(ActionEvent e) { JalviewFileChooser
3955    * chooser = new JalviewFileChooser(jalview.bin.Cache.
3956    * getProperty("LAST_DIRECTORY"));
3957    * 
3958    * chooser.setFileView(new JalviewFileView()); chooser.setDialogTitle("Export
3959    * to Vamsas file"); chooser.setToolTipText("Export");
3960    * 
3961    * int value = chooser.showSaveDialog(this);
3962    * 
3963    * if (value == JalviewFileChooser.APPROVE_OPTION) {
3964    * jalview.io.VamsasDatastore vs = new jalview.io.VamsasDatastore(viewport);
3965    * //vs.store(chooser.getSelectedFile().getAbsolutePath() ); vs.storeJalview(
3966    * chooser.getSelectedFile().getAbsolutePath(), this); } }
3967    */
3968   /**
3969    * prototype of an automatically enabled/disabled analysis function
3970    * 
3971    */
3972   protected void setShowProductsEnabled()
3973   {
3974     SequenceI[] selection = viewport.getSequenceSelection();
3975     if (canShowProducts(selection, viewport.getSelectionGroup() != null,
3976             viewport.getAlignment().getDataset()))
3977     {
3978       showProducts.setEnabled(true);
3979
3980     }
3981     else
3982     {
3983       showProducts.setEnabled(false);
3984     }
3985   }
3986
3987   /**
3988    * search selection for sequence xRef products and build the show products
3989    * menu.
3990    * 
3991    * @param selection
3992    * @param dataset
3993    * @return true if showProducts menu should be enabled.
3994    */
3995   public boolean canShowProducts(SequenceI[] selection,
3996           boolean isRegionSelection, Alignment dataset)
3997   {
3998     boolean showp = false;
3999     try
4000     {
4001       showProducts.removeAll();
4002       final boolean dna = viewport.getAlignment().isNucleotide();
4003       final Alignment ds = dataset;
4004       String[] ptypes = (selection == null || selection.length == 0) ? null
4005               : CrossRef.findSequenceXrefTypes(dna, selection, dataset);
4006       // Object[] prods =
4007       // CrossRef.buildXProductsList(viewport.getAlignment().isNucleotide(),
4008       // selection, dataset, true);
4009       final SequenceI[] sel = selection;
4010       for (int t = 0; ptypes != null && t < ptypes.length; t++)
4011       {
4012         showp = true;
4013         final boolean isRegSel = isRegionSelection;
4014         final AlignFrame af = this;
4015         final String source = ptypes[t];
4016         JMenuItem xtype = new JMenuItem(ptypes[t]);
4017         xtype.addActionListener(new ActionListener()
4018         {
4019
4020           public void actionPerformed(ActionEvent e)
4021           {
4022             // TODO: new thread for this call with vis-delay
4023             af.showProductsFor(af.viewport.getSequenceSelection(), ds,
4024                     isRegSel, dna, source);
4025           }
4026
4027         });
4028         showProducts.add(xtype);
4029       }
4030       showProducts.setVisible(showp);
4031       showProducts.setEnabled(showp);
4032     } catch (Exception e)
4033     {
4034       jalview.bin.Cache.log
4035               .warn(
4036                       "canTranslate threw an exception - please report to help@jalview.org",
4037                       e);
4038       return false;
4039     }
4040     return showp;
4041   }
4042
4043   protected void showProductsFor(SequenceI[] sel, Alignment ds,
4044           boolean isRegSel, boolean dna, String source)
4045   {
4046     final boolean fisRegSel = isRegSel;
4047     final boolean fdna = dna;
4048     final String fsrc = source;
4049     final AlignFrame ths = this;
4050     final SequenceI[] fsel = sel;
4051     Runnable foo = new Runnable()
4052     {
4053
4054       public void run()
4055       {
4056         final long sttime = System.currentTimeMillis();
4057         ths.setProgressBar("Searching for sequences from " + fsrc, sttime);
4058         try
4059         {
4060           Alignment ds = ths.getViewport().alignment.getDataset(); // update
4061           // our local
4062           // dataset
4063           // reference
4064           Alignment prods = CrossRef
4065                   .findXrefSequences(fsel, fdna, fsrc, ds);
4066           if (prods != null)
4067           {
4068             SequenceI[] sprods = new SequenceI[prods.getHeight()];
4069             for (int s = 0; s < sprods.length; s++)
4070             {
4071               sprods[s] = (prods.getSequenceAt(s)).deriveSequence();
4072               if (ds.getSequences() == null
4073                       || !ds.getSequences().contains(
4074                               sprods[s].getDatasetSequence()))
4075                 ds.addSequence(sprods[s].getDatasetSequence());
4076               sprods[s].updatePDBIds();
4077             }
4078             Alignment al = new Alignment(sprods);
4079             AlignedCodonFrame[] cf = prods.getCodonFrames();
4080             al.setDataset(ds);
4081             for (int s = 0; cf != null && s < cf.length; s++)
4082             {
4083               al.addCodonFrame(cf[s]);
4084               cf[s] = null;
4085             }
4086             AlignFrame naf = new AlignFrame(al, DEFAULT_WIDTH,
4087                     DEFAULT_HEIGHT);
4088             String newtitle = "" + ((fdna) ? "Proteins " : "Nucleotides ")
4089                     + " for " + ((fisRegSel) ? "selected region of " : "")
4090                     + getTitle();
4091             Desktop.addInternalFrame(naf, newtitle, DEFAULT_WIDTH,
4092                     DEFAULT_HEIGHT);
4093           }
4094           else
4095           {
4096             System.err.println("No Sequences generated for xRef type "
4097                     + fsrc);
4098           }
4099         } catch (Exception e)
4100         {
4101           jalview.bin.Cache.log.error(
4102                   "Exception when finding crossreferences", e);
4103         } catch (OutOfMemoryError e)
4104         {
4105           new OOMWarning("whilst fetching crossreferences", e);
4106         } catch (Error e)
4107         {
4108           jalview.bin.Cache.log.error("Error when finding crossreferences",
4109                   e);
4110         }
4111         ths.setProgressBar("Finished searching for sequences from " + fsrc,
4112                 sttime);
4113       }
4114
4115     };
4116     Thread frunner = new Thread(foo);
4117     frunner.start();
4118   }
4119
4120   public boolean canShowTranslationProducts(SequenceI[] selection,
4121           AlignmentI alignment)
4122   {
4123     // old way
4124     try
4125     {
4126       return (jalview.analysis.Dna.canTranslate(selection, viewport
4127               .getViewAsVisibleContigs(true)));
4128     } catch (Exception e)
4129     {
4130       jalview.bin.Cache.log
4131               .warn(
4132                       "canTranslate threw an exception - please report to help@jalview.org",
4133                       e);
4134       return false;
4135     }
4136   }
4137
4138   public void showProducts_actionPerformed(ActionEvent e)
4139   {
4140     // /////////////////////////////
4141     // Collect Data to be translated/transferred
4142
4143     SequenceI[] selection = viewport.getSequenceSelection();
4144     AlignmentI al = null;
4145     try
4146     {
4147       al = jalview.analysis.Dna.CdnaTranslate(selection, viewport
4148               .getViewAsVisibleContigs(true), viewport.getGapCharacter(),
4149               viewport.getAlignment().getDataset());
4150     } catch (Exception ex)
4151     {
4152       al = null;
4153       jalview.bin.Cache.log.debug("Exception during translation.", ex);
4154     }
4155     if (al == null)
4156     {
4157       JOptionPane
4158               .showMessageDialog(
4159                       Desktop.desktop,
4160                       "Please select at least three bases in at least one sequence in order to perform a cDNA translation.",
4161                       "Translation Failed", JOptionPane.WARNING_MESSAGE);
4162     }
4163     else
4164     {
4165       AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
4166       Desktop.addInternalFrame(af, "Translation of " + this.getTitle(),
4167               DEFAULT_WIDTH, DEFAULT_HEIGHT);
4168     }
4169   }
4170
4171   public void showTranslation_actionPerformed(ActionEvent e)
4172   {
4173     // /////////////////////////////
4174     // Collect Data to be translated/transferred
4175
4176     SequenceI[] selection = viewport.getSequenceSelection();
4177     String[] seqstring = viewport.getViewAsString(true);
4178     AlignmentI al = null;
4179     try
4180     {
4181       al = jalview.analysis.Dna.CdnaTranslate(selection, seqstring,
4182               viewport.getViewAsVisibleContigs(true), viewport
4183                       .getGapCharacter(), viewport.alignment
4184                       .getAlignmentAnnotation(), viewport.alignment
4185                       .getWidth(), viewport.getAlignment().getDataset());
4186     } catch (Exception ex)
4187     {
4188       al = null;
4189       jalview.bin.Cache.log.debug("Exception during translation.", ex);
4190     }
4191     if (al == null)
4192     {
4193       JOptionPane
4194               .showMessageDialog(
4195                       Desktop.desktop,
4196                       "Please select at least three bases in at least one sequence in order to perform a cDNA translation.",
4197                       "Translation Failed", JOptionPane.WARNING_MESSAGE);
4198     }
4199     else
4200     {
4201       AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
4202       Desktop.addInternalFrame(af, "Translation of " + this.getTitle(),
4203               DEFAULT_WIDTH, DEFAULT_HEIGHT);
4204     }
4205   }
4206
4207   /**
4208    * Try to load a features file onto the alignment.
4209    * 
4210    * @param file
4211    *          contents or path to retrieve file
4212    * @param type
4213    *          access mode of file (see jalview.io.AlignFile)
4214    * @return true if features file was parsed corectly.
4215    */
4216   public boolean parseFeaturesFile(String file, String type)
4217   {
4218     boolean featuresFile = false;
4219     try
4220     {
4221       featuresFile = new FeaturesFile(file, type).parse(viewport.alignment
4222               .getDataset(), alignPanel.seqPanel.seqCanvas
4223               .getFeatureRenderer().featureColours, false);
4224     } catch (Exception ex)
4225     {
4226       ex.printStackTrace();
4227     }
4228
4229     if (featuresFile)
4230     {
4231       viewport.showSequenceFeatures = true;
4232       showSeqFeatures.setSelected(true);
4233       if (alignPanel.seqPanel.seqCanvas.fr != null)
4234       {
4235         // update the min/max ranges where necessary
4236         alignPanel.seqPanel.seqCanvas.fr.findAllFeatures(true);
4237       }
4238       if (featureSettings != null)
4239       {
4240         featureSettings.setTableData();
4241       }
4242       alignPanel.paintAlignment(true);
4243     }
4244
4245     return featuresFile;
4246   }
4247
4248   public void dragEnter(DropTargetDragEvent evt)
4249   {
4250   }
4251
4252   public void dragExit(DropTargetEvent evt)
4253   {
4254   }
4255
4256   public void dragOver(DropTargetDragEvent evt)
4257   {
4258   }
4259
4260   public void dropActionChanged(DropTargetDragEvent evt)
4261   {
4262   }
4263
4264   public void drop(DropTargetDropEvent evt)
4265   {
4266     Transferable t = evt.getTransferable();
4267     java.util.List files = null;
4268
4269     try
4270     {
4271       DataFlavor uriListFlavor = new DataFlavor(
4272               "text/uri-list;class=java.lang.String");
4273       if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
4274       {
4275         // Works on Windows and MacOSX
4276         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
4277         files = (java.util.List) t
4278                 .getTransferData(DataFlavor.javaFileListFlavor);
4279       }
4280       else if (t.isDataFlavorSupported(uriListFlavor))
4281       {
4282         // This is used by Unix drag system
4283         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
4284         String data = (String) t.getTransferData(uriListFlavor);
4285         files = new java.util.ArrayList(1);
4286         for (java.util.StringTokenizer st = new java.util.StringTokenizer(
4287                 data, "\r\n"); st.hasMoreTokens();)
4288         {
4289           String s = st.nextToken();
4290           if (s.startsWith("#"))
4291           {
4292             // the line is a comment (as per the RFC 2483)
4293             continue;
4294           }
4295
4296           java.net.URI uri = new java.net.URI(s);
4297           // check to see if we can handle this kind of URI
4298           if (uri.getScheme().toLowerCase().startsWith("http"))
4299           {
4300             files.add(uri.toString());
4301           }
4302           else
4303           {
4304             // otherwise preserve old behaviour: catch all for file objects
4305             java.io.File file = new java.io.File(uri);
4306             files.add(file.toString());
4307           }
4308         }
4309       }
4310     } catch (Exception e)
4311     {
4312       e.printStackTrace();
4313     }
4314     if (files != null)
4315     {
4316       try
4317       {
4318
4319         for (int i = 0; i < files.size(); i++)
4320         {
4321           loadJalviewDataFile(files.get(i).toString());
4322         }
4323       } catch (Exception ex)
4324       {
4325         ex.printStackTrace();
4326       }
4327     }
4328   }
4329
4330   /**
4331    * Attempt to load a "dropped" file or URL string: First by testing whether
4332    * it's and Annotation file, then a JNet file, and finally a features file. If
4333    * all are false then the user may have dropped an alignment file onto this
4334    * AlignFrame.
4335    * 
4336    * @param file
4337    *          either a filename or a URL string.
4338    */
4339   public void loadJalviewDataFile(String file)
4340   {
4341     try
4342     {
4343       String protocol = jalview.io.FormatAdapter.FILE;
4344       String f = file.toLowerCase();
4345       if (f.indexOf("http:") == 0 || f.indexOf("https:") == 0
4346               || f.indexOf("file:") == 0)
4347       {
4348         protocol = jalview.io.FormatAdapter.URL;
4349       }
4350
4351       boolean isAnnotation = new AnnotationFile().readAnnotationFile(
4352               viewport.alignment, file, protocol);
4353
4354       if (!isAnnotation)
4355       {
4356         // try to see if its a JNet 'concise' style annotation file *before* we
4357         // try to parse it as a features file
4358         String format = new IdentifyFile().Identify(file, protocol);
4359         if (format.equalsIgnoreCase("JnetFile"))
4360         {
4361           jalview.io.JPredFile predictions = new jalview.io.JPredFile(file,
4362                   protocol);
4363           new JnetAnnotationMaker().add_annotation(predictions, viewport
4364                   .getAlignment(), 0, false);
4365           isAnnotation = true;
4366         }
4367         else
4368         {
4369           // try to parse it as a features file
4370           boolean isGroupsFile = parseFeaturesFile(file, protocol);
4371           // if it wasn't a features file then we just treat it as a general
4372           // alignment file to load into the current view.
4373           if (!isGroupsFile)
4374           {
4375             new FileLoader().LoadFile(viewport, file, protocol, format);
4376           }
4377           else
4378           {
4379             alignPanel.paintAlignment(true);
4380           }
4381         }
4382       }
4383       if (isAnnotation)
4384       {
4385
4386         alignPanel.adjustAnnotationHeight();
4387         viewport.updateSequenceIdColours();
4388         buildSortByAnnotationScoresMenu();
4389         alignPanel.paintAlignment(true);
4390       }
4391     } catch (Exception ex)
4392     {
4393       ex.printStackTrace();
4394     }
4395   }
4396
4397   public void tabSelectionChanged(int index)
4398   {
4399     if (index > -1)
4400     {
4401       alignPanel = (AlignmentPanel) alignPanels.elementAt(index);
4402       viewport = alignPanel.av;
4403       setMenusFromViewport(viewport);
4404     }
4405   }
4406
4407   public void tabbedPane_mousePressed(MouseEvent e)
4408   {
4409     if (SwingUtilities.isRightMouseButton(e))
4410     {
4411       String reply = JOptionPane.showInternalInputDialog(this,
4412               "Enter View Name", "Edit View Name",
4413               JOptionPane.QUESTION_MESSAGE);
4414
4415       if (reply != null)
4416       {
4417         viewport.viewName = reply;
4418         tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), reply);
4419       }
4420     }
4421   }
4422
4423   public AlignViewport getCurrentView()
4424   {
4425     return viewport;
4426   }
4427
4428   /**
4429    * Open the dialog for regex description parsing.
4430    */
4431   protected void extractScores_actionPerformed(ActionEvent e)
4432   {
4433     ParseProperties pp = new jalview.analysis.ParseProperties(
4434             viewport.alignment);
4435     // TODO: verify regex and introduce GUI dialog for version 2.5
4436     // if (pp.getScoresFromDescription("col", "score column ",
4437     // "\\W*([-+]?\\d*\\.?\\d*e?-?\\d*)\\W+([-+]?\\d*\\.?\\d*e?-?\\d*)",
4438     // true)>0)
4439     if (pp.getScoresFromDescription("description column",
4440             "score in description column ", "\\W*([-+eE0-9.]+)", true) > 0)
4441     {
4442       buildSortByAnnotationScoresMenu();
4443     }
4444   }
4445
4446   /*
4447    * (non-Javadoc)
4448    * 
4449    * @see
4450    * jalview.jbgui.GAlignFrame#showDbRefs_actionPerformed(java.awt.event.ActionEvent
4451    * )
4452    */
4453   protected void showDbRefs_actionPerformed(ActionEvent e)
4454   {
4455     viewport.setShowDbRefs(showDbRefsMenuitem.isSelected());
4456   }
4457
4458   /*
4459    * (non-Javadoc)
4460    * 
4461    * @seejalview.jbgui.GAlignFrame#showNpFeats_actionPerformed(java.awt.event.
4462    * ActionEvent)
4463    */
4464   protected void showNpFeats_actionPerformed(ActionEvent e)
4465   {
4466     viewport.setShowNpFeats(showNpFeatsMenuitem.isSelected());
4467   }
4468
4469   /**
4470    * find the viewport amongst the tabs in this alignment frame and close that
4471    * tab
4472    * 
4473    * @param av
4474    */
4475   public boolean closeView(AlignViewport av)
4476   {
4477     if (viewport == av)
4478     {
4479       this.closeMenuItem_actionPerformed(false);
4480       return true;
4481     }
4482     Component[] comp = tabbedPane.getComponents();
4483     for (int i = 0; comp != null && i < comp.length; i++)
4484     {
4485       if (comp[i] instanceof AlignmentPanel)
4486       {
4487         if (((AlignmentPanel) comp[i]).av == av)
4488         {
4489           // close the view.
4490           closeView((AlignmentPanel) comp[i]);
4491           return true;
4492         }
4493       }
4494     }
4495     return false;
4496   }
4497
4498   protected void build_fetchdbmenu(JMenu webService)
4499   {
4500     // Temporary hack - DBRef Fetcher always top level ws entry.
4501     // TODO We probably want to store a sequence database checklist in
4502     // preferences and have checkboxes.. rather than individual sources selected
4503     // here
4504     JMenu rfetch = new JMenu("Fetch DB References");
4505     rfetch
4506             .setToolTipText("Retrieve and parse sequence database records for the alignment or the currently selected sequences");
4507     webService.add(rfetch);
4508
4509     JMenuItem fetchr = new JMenuItem("Standard Databases");
4510     fetchr
4511             .setToolTipText("Fetch from EMBL/EMBLCDS or Uniprot/PDB and any selected DAS sources");
4512     fetchr.addActionListener(new ActionListener()
4513     {
4514
4515       public void actionPerformed(ActionEvent e)
4516       {
4517         new Thread(new Runnable()
4518         {
4519
4520           public void run()
4521           {
4522             new jalview.ws.DBRefFetcher(alignPanel.av
4523                     .getSequenceSelection(), alignPanel.alignFrame)
4524                     .fetchDBRefs(false);
4525           }
4526         }).start();
4527
4528       }
4529
4530     });
4531     rfetch.add(fetchr);
4532     JMenu dfetch = new JMenu();
4533     rfetch.add(dfetch);
4534     jalview.ws.SequenceFetcher sf = SequenceFetcher
4535             .getSequenceFetcherSingleton(this);
4536     String[] otherdb = sf.getOrderedSupportedSources();
4537     // sf.getDbInstances(jalview.ws.dbsources.DasSequenceSource.class);
4538     // jalview.util.QuickSort.sort(otherdb, otherdb);
4539     int comp = 0, mcomp = 15;
4540     String mname = null;
4541     if (otherdb != null && otherdb.length > 0)
4542     {
4543       for (int i = 0; i < otherdb.length; i++)
4544       {
4545         String dbname = sf.getSourceProxy(otherdb[i]).getDbName();
4546         if (mname == null)
4547         {
4548           mname = "from '" + dbname + "'";
4549         }
4550         fetchr = new JMenuItem(otherdb[i]);
4551         final String[] dassource = new String[]
4552         { otherdb[i] };
4553         fetchr.addActionListener(new ActionListener()
4554         {
4555
4556           public void actionPerformed(ActionEvent e)
4557           {
4558             new Thread(new Runnable()
4559             {
4560
4561               public void run()
4562               {
4563                 new jalview.ws.DBRefFetcher(alignPanel.av
4564                         .getSequenceSelection(), alignPanel.alignFrame,
4565                         dassource).fetchDBRefs(false);
4566               }
4567             }).start();
4568           }
4569
4570         });
4571         fetchr.setToolTipText("Retrieve from " + dbname);
4572         dfetch.add(fetchr);
4573         if (comp++ == mcomp || i == (otherdb.length - 1))
4574         {
4575           dfetch.setText(mname + " to '" + dbname + "'");
4576           rfetch.add(dfetch);
4577           dfetch = new JMenu();
4578           mname = null;
4579           comp = 0;
4580         }
4581       }
4582     }
4583   }
4584
4585   /**
4586    * Left justify the whole alignment.
4587    */
4588   protected void justifyLeftMenuItem_actionPerformed(ActionEvent e)
4589   {
4590     AlignmentI al = viewport.getAlignment();
4591     al.justify(false);
4592     viewport.firePropertyChange("alignment", null, al);
4593   }
4594
4595   /**
4596    * Right justify the whole alignment.
4597    */
4598   protected void justifyRightMenuItem_actionPerformed(ActionEvent e)
4599   {
4600     AlignmentI al = viewport.getAlignment();
4601     al.justify(true);
4602     viewport.firePropertyChange("alignment", null, al);
4603   }
4604
4605   public void setShowSeqFeatures(boolean b)
4606   {
4607     showSeqFeatures.setSelected(true);
4608     viewport.setShowSequenceFeatures(true);
4609   }
4610
4611   /*
4612    * (non-Javadoc)
4613    * 
4614    * @see
4615    * jalview.jbgui.GAlignFrame#showUnconservedMenuItem_actionPerformed(java.
4616    * awt.event.ActionEvent)
4617    */
4618   protected void showUnconservedMenuItem_actionPerformed(ActionEvent e)
4619   {
4620     viewport.setShowUnconserved(showNonconservedMenuItem.getState());
4621     alignPanel.paintAlignment(true);
4622   }
4623
4624   /*
4625    * (non-Javadoc)
4626    * 
4627    * @see
4628    * jalview.jbgui.GAlignFrame#showGroupConsensus_actionPerformed(java.awt.event
4629    * .ActionEvent)
4630    */
4631   protected void showGroupConsensus_actionPerformed(ActionEvent e)
4632   {
4633     viewport.setShowGroupConsensus(showGroupConsensus.getState());
4634     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
4635
4636   }
4637
4638   /*
4639    * (non-Javadoc)
4640    * 
4641    * @see
4642    * jalview.jbgui.GAlignFrame#showGroupConservation_actionPerformed(java.awt
4643    * .event.ActionEvent)
4644    */
4645   protected void showGroupConservation_actionPerformed(ActionEvent e)
4646   {
4647     viewport.setShowGroupConservation(showGroupConservation.getState());
4648     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
4649   }
4650
4651   /*
4652    * (non-Javadoc)
4653    * 
4654    * @see
4655    * jalview.jbgui.GAlignFrame#showConsensusHistogram_actionPerformed(java.awt
4656    * .event.ActionEvent)
4657    */
4658   protected void showConsensusHistogram_actionPerformed(ActionEvent e)
4659   {
4660     viewport.setShowConsensusHistogram(showConsensusHistogram.getState());
4661     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
4662   }
4663
4664   /*
4665    * (non-Javadoc)
4666    * 
4667    * @see
4668    * jalview.jbgui.GAlignFrame#showConsensusProfile_actionPerformed(java.awt
4669    * .event.ActionEvent)
4670    */
4671   protected void showSequenceLogo_actionPerformed(ActionEvent e)
4672   {
4673     viewport.setShowSequenceLogo(showSequenceLogo.getState());
4674     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
4675   }
4676
4677   protected void applyAutoAnnotationSettings_actionPerformed(ActionEvent e)
4678   {
4679     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
4680   }
4681
4682   /*
4683    * (non-Javadoc)
4684    * 
4685    * @see
4686    * jalview.jbgui.GAlignFrame#makeGrpsFromSelection_actionPerformed(java.awt
4687    * .event.ActionEvent)
4688    */
4689   protected void makeGrpsFromSelection_actionPerformed(ActionEvent e)
4690   {
4691     if (viewport.getSelectionGroup() != null)
4692     {
4693       SequenceGroup[] gps = jalview.analysis.Grouping.makeGroupsFrom(
4694               viewport.getSequenceSelection(), viewport.getAlignmentView(
4695                       true).getSequenceStrings(viewport.getGapCharacter()),
4696               viewport.alignment.getGroups());
4697       viewport.alignment.deleteAllGroups();
4698       viewport.sequenceColours = null;
4699       viewport.setSelectionGroup(null);
4700       // set view properties for each group
4701       for (int g = 0; g < gps.length; g++)
4702       {
4703         gps[g].setShowNonconserved(viewport.getShowUnconserved());
4704         gps[g].setshowSequenceLogo(viewport.isShowSequenceLogo());
4705         viewport.alignment.addGroup(gps[g]);
4706         Color col = new Color((int) (Math.random() * 255), (int) (Math
4707                 .random() * 255), (int) (Math.random() * 255));
4708         col = col.brighter();
4709         for (Enumeration sq = gps[g].getSequences(null).elements(); sq
4710                 .hasMoreElements(); viewport.setSequenceColour(
4711                 (SequenceI) sq.nextElement(), col))
4712           ;
4713       }
4714       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
4715       alignPanel.updateAnnotation();
4716       alignPanel.paintAlignment(true);
4717     }
4718   }
4719 }
4720
4721 class PrintThread extends Thread
4722 {
4723   AlignmentPanel ap;
4724
4725   public PrintThread(AlignmentPanel ap)
4726   {
4727     this.ap = ap;
4728   }
4729
4730   static PageFormat pf;
4731
4732   public void run()
4733   {
4734     PrinterJob printJob = PrinterJob.getPrinterJob();
4735
4736     if (pf != null)
4737     {
4738       printJob.setPrintable(ap, pf);
4739     }
4740     else
4741     {
4742       printJob.setPrintable(ap);
4743     }
4744
4745     if (printJob.printDialog())
4746     {
4747       try
4748       {
4749         printJob.print();
4750       } catch (Exception PrintException)
4751       {
4752         PrintException.printStackTrace();
4753       }
4754     }
4755   }
4756 }