Jalview 2.6 source licence
[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     AlignmentPanel newap = new Jalview2XML().copyAlignPanel(alignPanel,
2247             true);
2248
2249     newap.av.gatherViewsHere = false;
2250
2251     if (viewport.viewName == null)
2252     {
2253       viewport.viewName = "Original";
2254     }
2255
2256     newap.av.historyList = viewport.historyList;
2257     newap.av.redoList = viewport.redoList;
2258
2259     int index = Desktop.getViewCount(viewport.getSequenceSetId());
2260     String newViewName = "View " + index;
2261
2262     Vector comps = (Vector) PaintRefresher.components.get(viewport
2263             .getSequenceSetId());
2264     Vector existingNames = new Vector();
2265     for (int i = 0; i < comps.size(); i++)
2266     {
2267       if (comps.elementAt(i) instanceof AlignmentPanel)
2268       {
2269         AlignmentPanel ap = (AlignmentPanel) comps.elementAt(i);
2270         if (!existingNames.contains(ap.av.viewName))
2271         {
2272           existingNames.addElement(ap.av.viewName);
2273         }
2274       }
2275     }
2276
2277     while (existingNames.contains(newViewName))
2278     {
2279       newViewName = "View " + (++index);
2280     }
2281
2282     newap.av.viewName = newViewName;
2283
2284     addAlignmentPanel(newap, true);
2285
2286     if (alignPanels.size() == 2)
2287     {
2288       viewport.gatherViewsHere = true;
2289     }
2290     tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
2291   }
2292
2293   public void expandViews_actionPerformed(ActionEvent e)
2294   {
2295     Desktop.instance.explodeViews(this);
2296   }
2297
2298   public void gatherViews_actionPerformed(ActionEvent e)
2299   {
2300     Desktop.instance.gatherViews(this);
2301   }
2302
2303   /**
2304    * DOCUMENT ME!
2305    * 
2306    * @param e
2307    *          DOCUMENT ME!
2308    */
2309   public void font_actionPerformed(ActionEvent e)
2310   {
2311     new FontChooser(alignPanel);
2312   }
2313
2314   /**
2315    * DOCUMENT ME!
2316    * 
2317    * @param e
2318    *          DOCUMENT ME!
2319    */
2320   protected void seqLimit_actionPerformed(ActionEvent e)
2321   {
2322     viewport.setShowJVSuffix(seqLimits.isSelected());
2323
2324     alignPanel.idPanel.idCanvas.setPreferredSize(alignPanel
2325             .calculateIdWidth());
2326     alignPanel.paintAlignment(true);
2327   }
2328
2329   public void idRightAlign_actionPerformed(ActionEvent e)
2330   {
2331     viewport.rightAlignIds = idRightAlign.isSelected();
2332     alignPanel.paintAlignment(true);
2333   }
2334
2335   public void centreColumnLabels_actionPerformed(ActionEvent e)
2336   {
2337     viewport.centreColumnLabels = centreColumnLabelsMenuItem.getState();
2338     alignPanel.paintAlignment(true);
2339   }
2340
2341   /*
2342    * (non-Javadoc)
2343    * 
2344    * @see jalview.jbgui.GAlignFrame#followHighlight_actionPerformed()
2345    */
2346   protected void followHighlight_actionPerformed()
2347   {
2348     if (viewport.followHighlight = this.followHighlightMenuItem.getState())
2349     {
2350       alignPanel.scrollToPosition(
2351               alignPanel.seqPanel.seqCanvas.searchResults, false);
2352     }
2353   }
2354
2355   /**
2356    * DOCUMENT ME!
2357    * 
2358    * @param e
2359    *          DOCUMENT ME!
2360    */
2361   protected void colourTextMenuItem_actionPerformed(ActionEvent e)
2362   {
2363     viewport.setColourText(colourTextMenuItem.isSelected());
2364     alignPanel.paintAlignment(true);
2365   }
2366
2367   /**
2368    * DOCUMENT ME!
2369    * 
2370    * @param e
2371    *          DOCUMENT ME!
2372    */
2373   public void wrapMenuItem_actionPerformed(ActionEvent e)
2374   {
2375     scaleAbove.setVisible(wrapMenuItem.isSelected());
2376     scaleLeft.setVisible(wrapMenuItem.isSelected());
2377     scaleRight.setVisible(wrapMenuItem.isSelected());
2378     viewport.setWrapAlignment(wrapMenuItem.isSelected());
2379     alignPanel.setWrapAlignment(wrapMenuItem.isSelected());
2380   }
2381
2382   public void showAllSeqs_actionPerformed(ActionEvent e)
2383   {
2384     viewport.showAllHiddenSeqs();
2385   }
2386
2387   public void showAllColumns_actionPerformed(ActionEvent e)
2388   {
2389     viewport.showAllHiddenColumns();
2390     repaint();
2391   }
2392
2393   public void hideSelSequences_actionPerformed(ActionEvent e)
2394   {
2395     viewport.hideAllSelectedSeqs();
2396     alignPanel.paintAlignment(true);
2397   }
2398
2399   /**
2400    * called by key handler and the hide all/show all menu items
2401    * 
2402    * @param toggleSeqs
2403    * @param toggleCols
2404    */
2405   private void toggleHiddenRegions(boolean toggleSeqs, boolean toggleCols)
2406   {
2407
2408     boolean hide = false;
2409     SequenceGroup sg = viewport.getSelectionGroup();
2410     if (!toggleSeqs && !toggleCols)
2411     {
2412       // Hide everything by the current selection - this is a hack - we do the
2413       // invert and then hide
2414       // first check that there will be visible columns after the invert.
2415       if ((viewport.colSel != null && viewport.colSel.getSelected() != null && viewport.colSel
2416               .getSelected().size() > 0)
2417               || (sg != null && sg.getSize() > 0 && sg.getStartRes() <= sg
2418                       .getEndRes()))
2419       {
2420         // now invert the sequence set, if required - empty selection implies
2421         // that no hiding is required.
2422         if (sg != null)
2423         {
2424           invertSequenceMenuItem_actionPerformed(null);
2425           sg = viewport.getSelectionGroup();
2426           toggleSeqs = true;
2427
2428         }
2429         viewport.expandColSelection(sg, true);
2430         // finally invert the column selection and get the new sequence
2431         // selection.
2432         invertColSel_actionPerformed(null);
2433         toggleCols = true;
2434       }
2435     }
2436
2437     if (toggleSeqs)
2438     {
2439       if (sg != null && sg.getSize() != viewport.alignment.getHeight())
2440       {
2441         hideSelSequences_actionPerformed(null);
2442         hide = true;
2443       }
2444       else if (!(toggleCols && viewport.colSel.getSelected().size() > 0))
2445       {
2446         showAllSeqs_actionPerformed(null);
2447       }
2448     }
2449
2450     if (toggleCols)
2451     {
2452       if (viewport.colSel.getSelected().size() > 0)
2453       {
2454         hideSelColumns_actionPerformed(null);
2455         if (!toggleSeqs)
2456         {
2457           viewport.selectionGroup = sg;
2458         }
2459       }
2460       else if (!hide)
2461       {
2462         showAllColumns_actionPerformed(null);
2463       }
2464     }
2465   }
2466
2467   /*
2468    * (non-Javadoc)
2469    * 
2470    * @see
2471    * jalview.jbgui.GAlignFrame#hideAllButSelection_actionPerformed(java.awt.
2472    * event.ActionEvent)
2473    */
2474   public void hideAllButSelection_actionPerformed(ActionEvent e)
2475   {
2476     toggleHiddenRegions(false, false);
2477   }
2478
2479   /*
2480    * (non-Javadoc)
2481    * 
2482    * @see
2483    * jalview.jbgui.GAlignFrame#hideAllSelection_actionPerformed(java.awt.event
2484    * .ActionEvent)
2485    */
2486   public void hideAllSelection_actionPerformed(ActionEvent e)
2487   {
2488     SequenceGroup sg = viewport.getSelectionGroup();
2489     viewport.expandColSelection(sg, false);
2490     viewport.hideAllSelectedSeqs();
2491     viewport.hideSelectedColumns();
2492     alignPanel.paintAlignment(true);
2493   }
2494
2495   /*
2496    * (non-Javadoc)
2497    * 
2498    * @see
2499    * jalview.jbgui.GAlignFrame#showAllhidden_actionPerformed(java.awt.event.
2500    * ActionEvent)
2501    */
2502   public void showAllhidden_actionPerformed(ActionEvent e)
2503   {
2504     viewport.showAllHiddenColumns();
2505     viewport.showAllHiddenSeqs();
2506     alignPanel.paintAlignment(true);
2507   }
2508
2509   public void hideSelColumns_actionPerformed(ActionEvent e)
2510   {
2511     viewport.hideSelectedColumns();
2512     alignPanel.paintAlignment(true);
2513   }
2514
2515   public void hiddenMarkers_actionPerformed(ActionEvent e)
2516   {
2517     viewport.setShowHiddenMarkers(hiddenMarkers.isSelected());
2518     repaint();
2519   }
2520
2521   /**
2522    * DOCUMENT ME!
2523    * 
2524    * @param e
2525    *          DOCUMENT ME!
2526    */
2527   protected void scaleAbove_actionPerformed(ActionEvent e)
2528   {
2529     viewport.setScaleAboveWrapped(scaleAbove.isSelected());
2530     alignPanel.paintAlignment(true);
2531   }
2532
2533   /**
2534    * DOCUMENT ME!
2535    * 
2536    * @param e
2537    *          DOCUMENT ME!
2538    */
2539   protected void scaleLeft_actionPerformed(ActionEvent e)
2540   {
2541     viewport.setScaleLeftWrapped(scaleLeft.isSelected());
2542     alignPanel.paintAlignment(true);
2543   }
2544
2545   /**
2546    * DOCUMENT ME!
2547    * 
2548    * @param e
2549    *          DOCUMENT ME!
2550    */
2551   protected void scaleRight_actionPerformed(ActionEvent e)
2552   {
2553     viewport.setScaleRightWrapped(scaleRight.isSelected());
2554     alignPanel.paintAlignment(true);
2555   }
2556
2557   /**
2558    * DOCUMENT ME!
2559    * 
2560    * @param e
2561    *          DOCUMENT ME!
2562    */
2563   public void viewBoxesMenuItem_actionPerformed(ActionEvent e)
2564   {
2565     viewport.setShowBoxes(viewBoxesMenuItem.isSelected());
2566     alignPanel.paintAlignment(true);
2567   }
2568
2569   /**
2570    * DOCUMENT ME!
2571    * 
2572    * @param e
2573    *          DOCUMENT ME!
2574    */
2575   public void viewTextMenuItem_actionPerformed(ActionEvent e)
2576   {
2577     viewport.setShowText(viewTextMenuItem.isSelected());
2578     alignPanel.paintAlignment(true);
2579   }
2580
2581   /**
2582    * DOCUMENT ME!
2583    * 
2584    * @param e
2585    *          DOCUMENT ME!
2586    */
2587   protected void renderGapsMenuItem_actionPerformed(ActionEvent e)
2588   {
2589     viewport.setRenderGaps(renderGapsMenuItem.isSelected());
2590     alignPanel.paintAlignment(true);
2591   }
2592
2593   public FeatureSettings featureSettings;
2594
2595   public void featureSettings_actionPerformed(ActionEvent e)
2596   {
2597     if (featureSettings != null)
2598     {
2599       featureSettings.close();
2600       featureSettings = null;
2601     }
2602     if (!showSeqFeatures.isSelected())
2603     {
2604       // make sure features are actually displayed
2605       showSeqFeatures.setSelected(true);
2606       showSeqFeatures_actionPerformed(null);
2607     }
2608     featureSettings = new FeatureSettings(this);
2609   }
2610
2611   /**
2612    * Set or clear 'Show Sequence Features'
2613    * 
2614    * @param evt
2615    *          DOCUMENT ME!
2616    */
2617   public void showSeqFeatures_actionPerformed(ActionEvent evt)
2618   {
2619     viewport.setShowSequenceFeatures(showSeqFeatures.isSelected());
2620     alignPanel.paintAlignment(true);
2621     if (alignPanel.getOverviewPanel() != null)
2622     {
2623       alignPanel.getOverviewPanel().updateOverviewImage();
2624     }
2625   }
2626
2627   /**
2628    * Set or clear 'Show Sequence Features'
2629    * 
2630    * @param evt
2631    *          DOCUMENT ME!
2632    */
2633   public void showSeqFeaturesHeight_actionPerformed(ActionEvent evt)
2634   {
2635     viewport.setShowSequenceFeaturesHeight(showSeqFeaturesHeight
2636             .isSelected());
2637     if (viewport.getShowSequenceFeaturesHeight())
2638     {
2639       // ensure we're actually displaying features
2640       viewport.setShowSequenceFeatures(true);
2641       showSeqFeatures.setSelected(true);
2642     }
2643     alignPanel.paintAlignment(true);
2644     if (alignPanel.getOverviewPanel() != null)
2645     {
2646       alignPanel.getOverviewPanel().updateOverviewImage();
2647     }
2648   }
2649
2650   /**
2651    * DOCUMENT ME!
2652    * 
2653    * @param e
2654    *          DOCUMENT ME!
2655    */
2656   public void annotationPanelMenuItem_actionPerformed(ActionEvent e)
2657   {
2658     viewport.setShowAnnotation(annotationPanelMenuItem.isSelected());
2659     alignPanel.setAnnotationVisible(annotationPanelMenuItem.isSelected());
2660   }
2661
2662   public void alignmentProperties()
2663   {
2664     JEditorPane editPane = new JEditorPane("text/html", "");
2665     editPane.setEditable(false);
2666     StringBuffer contents = new StringBuffer("<html>");
2667
2668     float avg = 0;
2669     int min = Integer.MAX_VALUE, max = 0;
2670     for (int i = 0; i < viewport.alignment.getHeight(); i++)
2671     {
2672       int size = viewport.alignment.getSequenceAt(i).getEnd()
2673               - viewport.alignment.getSequenceAt(i).getStart();
2674       avg += size;
2675       if (size > max)
2676         max = size;
2677       if (size < min)
2678         min = size;
2679     }
2680     avg = avg / (float) viewport.alignment.getHeight();
2681
2682     contents.append("<br>Sequences: " + viewport.alignment.getHeight());
2683     contents.append("<br>Minimum Sequence Length: " + min);
2684     contents.append("<br>Maximum Sequence Length: " + max);
2685     contents.append("<br>Average Length: " + (int) avg);
2686
2687     if (((Alignment) viewport.alignment).getProperties() != null)
2688     {
2689       Hashtable props = ((Alignment) viewport.alignment).getProperties();
2690       Enumeration en = props.keys();
2691       contents.append("<br><br><table border=\"1\">");
2692       while (en.hasMoreElements())
2693       {
2694         String key = en.nextElement().toString();
2695         StringBuffer val = new StringBuffer();
2696         String vals = props.get(key).toString();
2697         int pos = 0, npos;
2698         do
2699         {
2700           npos = vals.indexOf("\n", pos);
2701           if (npos == -1)
2702           {
2703             val.append(vals.substring(pos));
2704           }
2705           else
2706           {
2707             val.append(vals.substring(pos, npos));
2708             val.append("<br>");
2709           }
2710           pos = npos + 1;
2711         } while (npos != -1);
2712         contents.append("<tr><td>" + key + "</td><td>" + val + "</td></tr>");
2713       }
2714       contents.append("</table>");
2715     }
2716     editPane.setText(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   }
3998
3999   /*
4000    * public void vamsasStore_actionPerformed(ActionEvent e) { JalviewFileChooser
4001    * chooser = new JalviewFileChooser(jalview.bin.Cache.
4002    * getProperty("LAST_DIRECTORY"));
4003    * 
4004    * chooser.setFileView(new JalviewFileView()); chooser.setDialogTitle("Export
4005    * to Vamsas file"); chooser.setToolTipText("Export");
4006    * 
4007    * int value = chooser.showSaveDialog(this);
4008    * 
4009    * if (value == JalviewFileChooser.APPROVE_OPTION) {
4010    * jalview.io.VamsasDatastore vs = new jalview.io.VamsasDatastore(viewport);
4011    * //vs.store(chooser.getSelectedFile().getAbsolutePath() ); vs.storeJalview(
4012    * chooser.getSelectedFile().getAbsolutePath(), this); } }
4013    */
4014   /**
4015    * prototype of an automatically enabled/disabled analysis function
4016    * 
4017    */
4018   protected void setShowProductsEnabled()
4019   {
4020     SequenceI[] selection = viewport.getSequenceSelection();
4021     if (canShowProducts(selection, viewport.getSelectionGroup() != null,
4022             viewport.getAlignment().getDataset()))
4023     {
4024       showProducts.setEnabled(true);
4025
4026     }
4027     else
4028     {
4029       showProducts.setEnabled(false);
4030     }
4031   }
4032
4033   /**
4034    * search selection for sequence xRef products and build the show products
4035    * menu.
4036    * 
4037    * @param selection
4038    * @param dataset
4039    * @return true if showProducts menu should be enabled.
4040    */
4041   public boolean canShowProducts(SequenceI[] selection,
4042           boolean isRegionSelection, Alignment dataset)
4043   {
4044     boolean showp = false;
4045     try
4046     {
4047       showProducts.removeAll();
4048       final boolean dna = viewport.getAlignment().isNucleotide();
4049       final Alignment ds = dataset;
4050       String[] ptypes = (selection == null || selection.length == 0) ? null
4051               : CrossRef.findSequenceXrefTypes(dna, selection, dataset);
4052       // Object[] prods =
4053       // CrossRef.buildXProductsList(viewport.getAlignment().isNucleotide(),
4054       // selection, dataset, true);
4055       final SequenceI[] sel = selection;
4056       for (int t = 0; ptypes != null && t < ptypes.length; t++)
4057       {
4058         showp = true;
4059         final boolean isRegSel = isRegionSelection;
4060         final AlignFrame af = this;
4061         final String source = ptypes[t];
4062         JMenuItem xtype = new JMenuItem(ptypes[t]);
4063         xtype.addActionListener(new ActionListener()
4064         {
4065
4066           public void actionPerformed(ActionEvent e)
4067           {
4068             // TODO: new thread for this call with vis-delay
4069             af.showProductsFor(af.viewport.getSequenceSelection(), ds,
4070                     isRegSel, dna, source);
4071           }
4072
4073         });
4074         showProducts.add(xtype);
4075       }
4076       showProducts.setVisible(showp);
4077       showProducts.setEnabled(showp);
4078     } catch (Exception e)
4079     {
4080       jalview.bin.Cache.log
4081               .warn("canTranslate threw an exception - please report to help@jalview.org",
4082                       e);
4083       return false;
4084     }
4085     return showp;
4086   }
4087
4088   protected void showProductsFor(SequenceI[] sel, Alignment ds,
4089           boolean isRegSel, boolean dna, String source)
4090   {
4091     final boolean fisRegSel = isRegSel;
4092     final boolean fdna = dna;
4093     final String fsrc = source;
4094     final AlignFrame ths = this;
4095     final SequenceI[] fsel = sel;
4096     Runnable foo = new Runnable()
4097     {
4098
4099       public void run()
4100       {
4101         final long sttime = System.currentTimeMillis();
4102         ths.setProgressBar("Searching for sequences from " + fsrc, sttime);
4103         try
4104         {
4105           Alignment ds = ths.getViewport().alignment.getDataset(); // update
4106           // our local
4107           // dataset
4108           // reference
4109           Alignment prods = CrossRef
4110                   .findXrefSequences(fsel, fdna, fsrc, ds);
4111           if (prods != null)
4112           {
4113             SequenceI[] sprods = new SequenceI[prods.getHeight()];
4114             for (int s = 0; s < sprods.length; s++)
4115             {
4116               sprods[s] = (prods.getSequenceAt(s)).deriveSequence();
4117               if (ds.getSequences() == null
4118                       || !ds.getSequences().contains(
4119                               sprods[s].getDatasetSequence()))
4120                 ds.addSequence(sprods[s].getDatasetSequence());
4121               sprods[s].updatePDBIds();
4122             }
4123             Alignment al = new Alignment(sprods);
4124             AlignedCodonFrame[] cf = prods.getCodonFrames();
4125             al.setDataset(ds);
4126             for (int s = 0; cf != null && s < cf.length; s++)
4127             {
4128               al.addCodonFrame(cf[s]);
4129               cf[s] = null;
4130             }
4131             AlignFrame naf = new AlignFrame(al, DEFAULT_WIDTH,
4132                     DEFAULT_HEIGHT);
4133             String newtitle = "" + ((fdna) ? "Proteins " : "Nucleotides ")
4134                     + " for " + ((fisRegSel) ? "selected region of " : "")
4135                     + getTitle();
4136             Desktop.addInternalFrame(naf, newtitle, DEFAULT_WIDTH,
4137                     DEFAULT_HEIGHT);
4138           }
4139           else
4140           {
4141             System.err.println("No Sequences generated for xRef type "
4142                     + fsrc);
4143           }
4144         } catch (Exception e)
4145         {
4146           jalview.bin.Cache.log.error(
4147                   "Exception when finding crossreferences", e);
4148         } catch (OutOfMemoryError e)
4149         {
4150           new OOMWarning("whilst fetching crossreferences", e);
4151         } catch (Error e)
4152         {
4153           jalview.bin.Cache.log.error("Error when finding crossreferences",
4154                   e);
4155         }
4156         ths.setProgressBar("Finished searching for sequences from " + fsrc,
4157                 sttime);
4158       }
4159
4160     };
4161     Thread frunner = new Thread(foo);
4162     frunner.start();
4163   }
4164
4165   public boolean canShowTranslationProducts(SequenceI[] selection,
4166           AlignmentI alignment)
4167   {
4168     // old way
4169     try
4170     {
4171       return (jalview.analysis.Dna.canTranslate(selection,
4172               viewport.getViewAsVisibleContigs(true)));
4173     } catch (Exception e)
4174     {
4175       jalview.bin.Cache.log
4176               .warn("canTranslate threw an exception - please report to help@jalview.org",
4177                       e);
4178       return false;
4179     }
4180   }
4181
4182   public void showProducts_actionPerformed(ActionEvent e)
4183   {
4184     // /////////////////////////////
4185     // Collect Data to be translated/transferred
4186
4187     SequenceI[] selection = viewport.getSequenceSelection();
4188     AlignmentI al = null;
4189     try
4190     {
4191       al = jalview.analysis.Dna.CdnaTranslate(selection, viewport
4192               .getViewAsVisibleContigs(true), viewport.getGapCharacter(),
4193               viewport.getAlignment().getDataset());
4194     } catch (Exception ex)
4195     {
4196       al = null;
4197       jalview.bin.Cache.log.debug("Exception during translation.", ex);
4198     }
4199     if (al == null)
4200     {
4201       JOptionPane
4202               .showMessageDialog(
4203                       Desktop.desktop,
4204                       "Please select at least three bases in at least one sequence in order to perform a cDNA translation.",
4205                       "Translation Failed", JOptionPane.WARNING_MESSAGE);
4206     }
4207     else
4208     {
4209       AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
4210       Desktop.addInternalFrame(af, "Translation of " + this.getTitle(),
4211               DEFAULT_WIDTH, DEFAULT_HEIGHT);
4212     }
4213   }
4214
4215   public void showTranslation_actionPerformed(ActionEvent e)
4216   {
4217     // /////////////////////////////
4218     // Collect Data to be translated/transferred
4219
4220     SequenceI[] selection = viewport.getSequenceSelection();
4221     String[] seqstring = viewport.getViewAsString(true);
4222     AlignmentI al = null;
4223     try
4224     {
4225       al = jalview.analysis.Dna.CdnaTranslate(selection, seqstring,
4226               viewport.getViewAsVisibleContigs(true), viewport
4227                       .getGapCharacter(), viewport.alignment
4228                       .getAlignmentAnnotation(), viewport.alignment
4229                       .getWidth(), viewport.getAlignment().getDataset());
4230     } catch (Exception ex)
4231     {
4232       al = null;
4233       jalview.bin.Cache.log.debug("Exception during translation.", ex);
4234     }
4235     if (al == null)
4236     {
4237       JOptionPane
4238               .showMessageDialog(
4239                       Desktop.desktop,
4240                       "Please select at least three bases in at least one sequence in order to perform a cDNA translation.",
4241                       "Translation Failed", JOptionPane.WARNING_MESSAGE);
4242     }
4243     else
4244     {
4245       AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
4246       Desktop.addInternalFrame(af, "Translation of " + this.getTitle(),
4247               DEFAULT_WIDTH, DEFAULT_HEIGHT);
4248     }
4249   }
4250
4251   /**
4252    * Try to load a features file onto the alignment.
4253    * 
4254    * @param file
4255    *          contents or path to retrieve file
4256    * @param type
4257    *          access mode of file (see jalview.io.AlignFile)
4258    * @return true if features file was parsed corectly.
4259    */
4260   public boolean parseFeaturesFile(String file, String type)
4261   {
4262     boolean featuresFile = false;
4263     try
4264     {
4265       featuresFile = new FeaturesFile(file, type)
4266               .parse(viewport.alignment.getDataset(),
4267                       alignPanel.seqPanel.seqCanvas.getFeatureRenderer().featureColours,
4268                       false);
4269     } catch (Exception ex)
4270     {
4271       ex.printStackTrace();
4272     }
4273
4274     if (featuresFile)
4275     {
4276       viewport.showSequenceFeatures = true;
4277       showSeqFeatures.setSelected(true);
4278       if (alignPanel.seqPanel.seqCanvas.fr != null)
4279       {
4280         // update the min/max ranges where necessary
4281         alignPanel.seqPanel.seqCanvas.fr.findAllFeatures(true);
4282       }
4283       if (featureSettings != null)
4284       {
4285         featureSettings.setTableData();
4286       }
4287       alignPanel.paintAlignment(true);
4288     }
4289
4290     return featuresFile;
4291   }
4292
4293   public void dragEnter(DropTargetDragEvent evt)
4294   {
4295   }
4296
4297   public void dragExit(DropTargetEvent evt)
4298   {
4299   }
4300
4301   public void dragOver(DropTargetDragEvent evt)
4302   {
4303   }
4304
4305   public void dropActionChanged(DropTargetDragEvent evt)
4306   {
4307   }
4308
4309   public void drop(DropTargetDropEvent evt)
4310   {
4311     Transferable t = evt.getTransferable();
4312     java.util.List files = null;
4313
4314     try
4315     {
4316       DataFlavor uriListFlavor = new DataFlavor(
4317               "text/uri-list;class=java.lang.String");
4318       if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
4319       {
4320         // Works on Windows and MacOSX
4321         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
4322         files = (java.util.List) t
4323                 .getTransferData(DataFlavor.javaFileListFlavor);
4324       }
4325       else if (t.isDataFlavorSupported(uriListFlavor))
4326       {
4327         // This is used by Unix drag system
4328         evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
4329         String data = (String) t.getTransferData(uriListFlavor);
4330         files = new java.util.ArrayList(1);
4331         for (java.util.StringTokenizer st = new java.util.StringTokenizer(
4332                 data, "\r\n"); st.hasMoreTokens();)
4333         {
4334           String s = st.nextToken();
4335           if (s.startsWith("#"))
4336           {
4337             // the line is a comment (as per the RFC 2483)
4338             continue;
4339           }
4340
4341           java.net.URI uri = new java.net.URI(s);
4342           // check to see if we can handle this kind of URI
4343           if (uri.getScheme().toLowerCase().startsWith("http"))
4344           {
4345             files.add(uri.toString());
4346           }
4347           else
4348           {
4349             // otherwise preserve old behaviour: catch all for file objects
4350             java.io.File file = new java.io.File(uri);
4351             files.add(file.toString());
4352           }
4353         }
4354       }
4355     } catch (Exception e)
4356     {
4357       e.printStackTrace();
4358     }
4359     if (files != null)
4360     {
4361       try
4362       {
4363
4364         for (int i = 0; i < files.size(); i++)
4365         {
4366           loadJalviewDataFile(files.get(i).toString());
4367         }
4368       } catch (Exception ex)
4369       {
4370         ex.printStackTrace();
4371       }
4372     }
4373   }
4374
4375   /**
4376    * Attempt to load a "dropped" file or URL string: First by testing whether
4377    * it's and Annotation file, then a JNet file, and finally a features file. If
4378    * all are false then the user may have dropped an alignment file onto this
4379    * AlignFrame.
4380    * 
4381    * @param file
4382    *          either a filename or a URL string.
4383    */
4384   public void loadJalviewDataFile(String file)
4385   {
4386     try
4387     {
4388       String protocol = jalview.io.FormatAdapter.FILE;
4389       String f = file.toLowerCase();
4390       if (f.indexOf("http:") == 0 || f.indexOf("https:") == 0
4391               || f.indexOf("file:") == 0)
4392       {
4393         protocol = jalview.io.FormatAdapter.URL;
4394       }
4395
4396       boolean isAnnotation = new AnnotationFile().readAnnotationFile(
4397               viewport.alignment, file, protocol);
4398
4399       if (!isAnnotation)
4400       {
4401         // try to see if its a JNet 'concise' style annotation file *before* we
4402         // try to parse it as a features file
4403         String format = new IdentifyFile().Identify(file, protocol);
4404         if (format.equalsIgnoreCase("JnetFile"))
4405         {
4406           jalview.io.JPredFile predictions = new jalview.io.JPredFile(file,
4407                   protocol);
4408           new JnetAnnotationMaker().add_annotation(predictions,
4409                   viewport.getAlignment(), 0, false);
4410           isAnnotation = true;
4411         }
4412         else
4413         {
4414           // try to parse it as a features file
4415           boolean isGroupsFile = parseFeaturesFile(file, protocol);
4416           // if it wasn't a features file then we just treat it as a general
4417           // alignment file to load into the current view.
4418           if (!isGroupsFile)
4419           {
4420             new FileLoader().LoadFile(viewport, file, protocol, format);
4421           }
4422           else
4423           {
4424             alignPanel.paintAlignment(true);
4425           }
4426         }
4427       }
4428       if (isAnnotation)
4429       {
4430
4431         alignPanel.adjustAnnotationHeight();
4432         viewport.updateSequenceIdColours();
4433         buildSortByAnnotationScoresMenu();
4434         alignPanel.paintAlignment(true);
4435       }
4436     } catch (Exception ex)
4437     {
4438       ex.printStackTrace();
4439     }
4440   }
4441
4442   public void tabSelectionChanged(int index)
4443   {
4444     if (index > -1)
4445     {
4446       alignPanel = (AlignmentPanel) alignPanels.elementAt(index);
4447       viewport = alignPanel.av;
4448       setMenusFromViewport(viewport);
4449     }
4450   }
4451
4452   public void tabbedPane_mousePressed(MouseEvent e)
4453   {
4454     if (SwingUtilities.isRightMouseButton(e))
4455     {
4456       String reply = JOptionPane.showInternalInputDialog(this,
4457               "Enter View Name", "Edit View Name",
4458               JOptionPane.QUESTION_MESSAGE);
4459
4460       if (reply != null)
4461       {
4462         viewport.viewName = reply;
4463         tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), reply);
4464       }
4465     }
4466   }
4467
4468   public AlignViewport getCurrentView()
4469   {
4470     return viewport;
4471   }
4472
4473   /**
4474    * Open the dialog for regex description parsing.
4475    */
4476   protected void extractScores_actionPerformed(ActionEvent e)
4477   {
4478     ParseProperties pp = new jalview.analysis.ParseProperties(
4479             viewport.alignment);
4480     // TODO: verify regex and introduce GUI dialog for version 2.5
4481     // if (pp.getScoresFromDescription("col", "score column ",
4482     // "\\W*([-+]?\\d*\\.?\\d*e?-?\\d*)\\W+([-+]?\\d*\\.?\\d*e?-?\\d*)",
4483     // true)>0)
4484     if (pp.getScoresFromDescription("description column",
4485             "score in description column ", "\\W*([-+eE0-9.]+)", true) > 0)
4486     {
4487       buildSortByAnnotationScoresMenu();
4488     }
4489   }
4490
4491   /*
4492    * (non-Javadoc)
4493    * 
4494    * @see
4495    * jalview.jbgui.GAlignFrame#showDbRefs_actionPerformed(java.awt.event.ActionEvent
4496    * )
4497    */
4498   protected void showDbRefs_actionPerformed(ActionEvent e)
4499   {
4500     viewport.setShowDbRefs(showDbRefsMenuitem.isSelected());
4501   }
4502
4503   /*
4504    * (non-Javadoc)
4505    * 
4506    * @seejalview.jbgui.GAlignFrame#showNpFeats_actionPerformed(java.awt.event.
4507    * ActionEvent)
4508    */
4509   protected void showNpFeats_actionPerformed(ActionEvent e)
4510   {
4511     viewport.setShowNpFeats(showNpFeatsMenuitem.isSelected());
4512   }
4513
4514   /**
4515    * find the viewport amongst the tabs in this alignment frame and close that
4516    * tab
4517    * 
4518    * @param av
4519    */
4520   public boolean closeView(AlignViewport av)
4521   {
4522     if (viewport == av)
4523     {
4524       this.closeMenuItem_actionPerformed(false);
4525       return true;
4526     }
4527     Component[] comp = tabbedPane.getComponents();
4528     for (int i = 0; comp != null && i < comp.length; i++)
4529     {
4530       if (comp[i] instanceof AlignmentPanel)
4531       {
4532         if (((AlignmentPanel) comp[i]).av == av)
4533         {
4534           // close the view.
4535           closeView((AlignmentPanel) comp[i]);
4536           return true;
4537         }
4538       }
4539     }
4540     return false;
4541   }
4542
4543   protected void build_fetchdbmenu(JMenu webService)
4544   {
4545     // Temporary hack - DBRef Fetcher always top level ws entry.
4546     // TODO We probably want to store a sequence database checklist in
4547     // preferences and have checkboxes.. rather than individual sources selected
4548     // here
4549     final JMenu rfetch = new JMenu("Fetch DB References");
4550     rfetch.setToolTipText("Retrieve and parse sequence database records for the alignment or the currently selected sequences");
4551     webService.add(rfetch);
4552
4553     JMenuItem fetchr = new JMenuItem("Standard Databases");
4554     fetchr.setToolTipText("Fetch from EMBL/EMBLCDS or Uniprot/PDB and any selected DAS sources");
4555     fetchr.addActionListener(new ActionListener()
4556     {
4557
4558       public void actionPerformed(ActionEvent e)
4559       {
4560         new Thread(new Runnable()
4561         {
4562
4563           public void run()
4564           {
4565             new jalview.ws.DBRefFetcher(alignPanel.av
4566                     .getSequenceSelection(), alignPanel.alignFrame)
4567                     .fetchDBRefs(false);
4568           }
4569         }).start();
4570
4571       }
4572
4573     });
4574     rfetch.add(fetchr);
4575     final AlignFrame me=this;
4576     new Thread(new Runnable()
4577     {
4578       public void run()
4579       {
4580         final jalview.ws.SequenceFetcher sf = SequenceFetcher
4581                 .getSequenceFetcherSingleton(me);
4582         final String[] otherdb = sf.getOrderedSupportedSources();
4583         // sf.getDbInstances(jalview.ws.dbsources.DasSequenceSource.class);
4584         // jalview.util.QuickSort.sort(otherdb, otherdb);
4585         javax.swing.SwingUtilities.invokeLater(new Runnable()
4586         {
4587           public void run()
4588           {
4589
4590             JMenu dfetch = new JMenu();
4591             JMenuItem fetchr;
4592             rfetch.add(dfetch);
4593             int comp = 0, mcomp = 15;
4594             String mname = null;
4595             if (otherdb != null && otherdb.length > 0)
4596             {
4597               for (int i = 0; i < otherdb.length; i++)
4598               {
4599                 String dbname = sf.getSourceProxy(otherdb[i]).getDbName();
4600                 if (mname == null)
4601                 {
4602                   mname = "from '" + dbname + "'";
4603                 }
4604                 fetchr = new JMenuItem(otherdb[i]);
4605                 final String[] dassource = new String[]
4606                 { otherdb[i] };
4607                 fetchr.addActionListener(new ActionListener()
4608                 {
4609
4610                   public void actionPerformed(ActionEvent e)
4611                   {
4612                     new Thread(new Runnable()
4613                     {
4614
4615                       public void run()
4616                       {
4617                         new jalview.ws.DBRefFetcher(alignPanel.av
4618                                 .getSequenceSelection(),
4619                                 alignPanel.alignFrame, dassource)
4620                                 .fetchDBRefs(false);
4621                       }
4622                     }).start();
4623                   }
4624
4625                 });
4626                 fetchr.setToolTipText("Retrieve from " + dbname);
4627                 dfetch.add(fetchr);
4628                 if (comp++ == mcomp || i == (otherdb.length - 1))
4629                 {
4630                   dfetch.setText(mname + " to '" + dbname + "'");
4631                   rfetch.add(dfetch);
4632                   dfetch = new JMenu();
4633                   mname = null;
4634                   comp = 0;
4635                 }
4636               }
4637             }
4638           }
4639         });
4640       }
4641     }).start();
4642
4643   }
4644
4645   /**
4646    * Left justify the whole alignment.
4647    */
4648   protected void justifyLeftMenuItem_actionPerformed(ActionEvent e)
4649   {
4650     AlignmentI al = viewport.getAlignment();
4651     al.justify(false);
4652     viewport.firePropertyChange("alignment", null, al);
4653   }
4654
4655   /**
4656    * Right justify the whole alignment.
4657    */
4658   protected void justifyRightMenuItem_actionPerformed(ActionEvent e)
4659   {
4660     AlignmentI al = viewport.getAlignment();
4661     al.justify(true);
4662     viewport.firePropertyChange("alignment", null, al);
4663   }
4664
4665   public void setShowSeqFeatures(boolean b)
4666   {
4667     showSeqFeatures.setSelected(true);
4668     viewport.setShowSequenceFeatures(true);
4669   }
4670
4671   /*
4672    * (non-Javadoc)
4673    * 
4674    * @see
4675    * jalview.jbgui.GAlignFrame#showUnconservedMenuItem_actionPerformed(java.
4676    * awt.event.ActionEvent)
4677    */
4678   protected void showUnconservedMenuItem_actionPerformed(ActionEvent e)
4679   {
4680     viewport.setShowUnconserved(showNonconservedMenuItem.getState());
4681     alignPanel.paintAlignment(true);
4682   }
4683
4684   /*
4685    * (non-Javadoc)
4686    * 
4687    * @see
4688    * jalview.jbgui.GAlignFrame#showGroupConsensus_actionPerformed(java.awt.event
4689    * .ActionEvent)
4690    */
4691   protected void showGroupConsensus_actionPerformed(ActionEvent e)
4692   {
4693     viewport.setShowGroupConsensus(showGroupConsensus.getState());
4694     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
4695
4696   }
4697
4698   /*
4699    * (non-Javadoc)
4700    * 
4701    * @see
4702    * jalview.jbgui.GAlignFrame#showGroupConservation_actionPerformed(java.awt
4703    * .event.ActionEvent)
4704    */
4705   protected void showGroupConservation_actionPerformed(ActionEvent e)
4706   {
4707     viewport.setShowGroupConservation(showGroupConservation.getState());
4708     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
4709   }
4710
4711   /*
4712    * (non-Javadoc)
4713    * 
4714    * @see
4715    * jalview.jbgui.GAlignFrame#showConsensusHistogram_actionPerformed(java.awt
4716    * .event.ActionEvent)
4717    */
4718   protected void showConsensusHistogram_actionPerformed(ActionEvent e)
4719   {
4720     viewport.setShowConsensusHistogram(showConsensusHistogram.getState());
4721     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
4722   }
4723
4724   /*
4725    * (non-Javadoc)
4726    * 
4727    * @see
4728    * jalview.jbgui.GAlignFrame#showConsensusProfile_actionPerformed(java.awt
4729    * .event.ActionEvent)
4730    */
4731   protected void showSequenceLogo_actionPerformed(ActionEvent e)
4732   {
4733     viewport.setShowSequenceLogo(showSequenceLogo.getState());
4734     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
4735   }
4736
4737   protected void applyAutoAnnotationSettings_actionPerformed(ActionEvent e)
4738   {
4739     alignPanel.updateAnnotation(applyAutoAnnotationSettings.getState());
4740   }
4741
4742   /*
4743    * (non-Javadoc)
4744    * 
4745    * @see
4746    * jalview.jbgui.GAlignFrame#makeGrpsFromSelection_actionPerformed(java.awt
4747    * .event.ActionEvent)
4748    */
4749   protected void makeGrpsFromSelection_actionPerformed(ActionEvent e)
4750   {
4751     if (viewport.getSelectionGroup() != null)
4752     {
4753       SequenceGroup[] gps = jalview.analysis.Grouping.makeGroupsFrom(
4754               viewport.getSequenceSelection(),
4755               viewport.getAlignmentView(true).getSequenceStrings(
4756                       viewport.getGapCharacter()),
4757               viewport.alignment.getGroups());
4758       viewport.alignment.deleteAllGroups();
4759       viewport.sequenceColours = null;
4760       viewport.setSelectionGroup(null);
4761       // set view properties for each group
4762       for (int g = 0; g < gps.length; g++)
4763       {
4764         gps[g].setShowNonconserved(viewport.getShowUnconserved());
4765         gps[g].setshowSequenceLogo(viewport.isShowSequenceLogo());
4766         viewport.alignment.addGroup(gps[g]);
4767         Color col = new Color((int) (Math.random() * 255),
4768                 (int) (Math.random() * 255), (int) (Math.random() * 255));
4769         col = col.brighter();
4770         for (Enumeration sq = gps[g].getSequences(null).elements(); sq
4771                 .hasMoreElements(); viewport.setSequenceColour(
4772                 (SequenceI) sq.nextElement(), col))
4773           ;
4774       }
4775       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
4776       alignPanel.updateAnnotation();
4777       alignPanel.paintAlignment(true);
4778     }
4779   }
4780 }
4781
4782 class PrintThread extends Thread
4783 {
4784   AlignmentPanel ap;
4785
4786   public PrintThread(AlignmentPanel ap)
4787   {
4788     this.ap = ap;
4789   }
4790
4791   static PageFormat pf;
4792
4793   public void run()
4794   {
4795     PrinterJob printJob = PrinterJob.getPrinterJob();
4796
4797     if (pf != null)
4798     {
4799       printJob.setPrintable(ap, pf);
4800     }
4801     else
4802     {
4803       printJob.setPrintable(ap);
4804     }
4805
4806     if (printJob.printDialog())
4807     {
4808       try
4809       {
4810         printJob.print();
4811       } catch (Exception PrintException)
4812       {
4813         PrintException.printStackTrace();
4814       }
4815     }
4816   }
4817 }