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