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