X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FAlignFrame.java;h=39a7fac5747da9257e14e4bd3264da6eb0fdc39d;hb=08bde8d252a69d4d6a3b2497f759bd5d6f154a3f;hp=1396c9336859f96570dbe48e68d4f613bfa6555e;hpb=cbfa4d2bc1282662ad88756f1b0b2d8b3b82bd11;p=jalview.git diff --git a/src/jalview/gui/AlignFrame.java b/src/jalview/gui/AlignFrame.java index 1396c93..39a7fac 100755 --- a/src/jalview/gui/AlignFrame.java +++ b/src/jalview/gui/AlignFrame.java @@ -28,6 +28,7 @@ import java.awt.dnd.*; import java.awt.event.*; import java.awt.print.*; import javax.swing.*; +import javax.swing.event.MenuEvent; import jalview.analysis.*; import jalview.commands.*; @@ -58,11 +59,17 @@ public class AlignFrame Vector alignPanels = new Vector(); - /** DOCUMENT ME!! */ + /** + * Last format used to load or save alignments in this window + */ String currentFileFormat = null; - + /** + * Current filename for this alignment + */ String fileName = null; + + /** * Creates a new AlignFrame object. @@ -112,8 +119,6 @@ public class AlignFrame void init() { - this.setDropTarget(new java.awt.dnd.DropTarget(this, this)); - if (viewport.conservation == null) { BLOSUM62Colour.setEnabled(false); @@ -137,12 +142,13 @@ public class AlignFrame if (Desktop.desktop != null) { + this.setDropTarget(new java.awt.dnd.DropTarget(this, this)); addServiceListeners(); setGUINucleotide(viewport.alignment.isNucleotide()); } setMenusFromViewport(viewport); - + buildSortByAnnotationScoresMenu(); if (viewport.wrapAlignment) { wrapMenuItem_actionPerformed(null); @@ -156,7 +162,12 @@ public class AlignFrame addKeyListener(); } - + /** + * Change the filename and format for the alignment, and + * enable the 'reload' button functionality. + * @param file valid filename + * @param format format of file + */ public void setFileName(String file, String format) { fileName = file; @@ -180,7 +191,6 @@ public class AlignFrame && Character.isDigit(evt.getKeyChar())) alignPanel.seqPanel.numberPressed(evt.getKeyChar()); - switch (evt.getKeyCode()) { @@ -499,14 +509,17 @@ public class AlignFrame showTranslation.setVisible( nucleotide ); conservationMenuItem.setEnabled( !nucleotide ); modifyConservation.setEnabled( !nucleotide ); - + //Remember AlignFrame always starts as protein if(!nucleotide) { calculateMenu.remove(calculateMenu.getItemCount()-2); } + setShowProductsEnabled(); } + + /** * Need to call this method when tabs are selected for multiple views, * or when loading from Jalview2XML.java @@ -520,6 +533,7 @@ public class AlignFrame conservationMenuItem.setSelected(av.getConservationSelected()); seqLimits.setSelected(av.getShowJVSuffix()); idRightAlign.setSelected(av.rightAlignIds); + centreColumnLabelsMenuItem.setState(av.centreColumnLabels); renderGapsMenuItem.setSelected(av.renderGaps); wrapMenuItem.setSelected(av.wrapAlignment); scaleAbove.setVisible(av.wrapAlignment); @@ -581,10 +595,18 @@ public class AlignFrame validate(); } - - - - + /** + * + * @return true if any progress bars are still active + */ + public boolean operationInProgress() + { + if (progressBars!=null && progressBars.size()>0) + { + return true; + } + return false; + } /* Added so Castor Mapping file can obtain Jalview Version */ @@ -669,7 +691,7 @@ public class AlignFrame public void save_actionPerformed(ActionEvent e) { if(fileName==null - || currentFileFormat==null + || (currentFileFormat==null || jalview.io.AppletFormatAdapter.isValidFormat(currentFileFormat, true)) || fileName.startsWith("http") ) { @@ -690,10 +712,8 @@ public class AlignFrame { JalviewFileChooser chooser = new JalviewFileChooser(jalview.bin.Cache. getProperty( "LAST_DIRECTORY"), - new String[] - { "fa, fasta, fastq", "aln", "pfam", "msf", "pir", "blc","jar" }, - new String[] - { "Fasta", "Clustal", "PFAM", "MSF", "PIR", "BLC", "Jalview" }, + jalview.io.AppletFormatAdapter.WRITABLE_EXTENSIONS, + jalview.io.AppletFormatAdapter.WRITABLE_FNAMES, currentFileFormat, false); @@ -723,7 +743,10 @@ public class AlignFrame currentFileFormat); jalview.bin.Cache.setProperty("LAST_DIRECTORY", fileName); - + if (currentFileFormat.indexOf(" ")>-1) + { + currentFileFormat = currentFileFormat.substring(0, currentFileFormat.indexOf(" ")); + } saveAlignment(fileName, currentFileFormat); } } @@ -750,8 +773,18 @@ public class AlignFrame } else - { - + { + if (!jalview.io.AppletFormatAdapter.isValidFormat(format, true)) + { + // JBPNote need to have a raise_gui flag here + JOptionPane.showInternalMessageDialog( + this, "Cannot save file " + fileName + " using format "+format, + "Alignment output format not supported", + JOptionPane.WARNING_MESSAGE); + saveAs_actionPerformed(null); + return false; + } + String[] omitHidden = null; if (viewport.hasHiddenColumns) @@ -767,11 +800,11 @@ public class AlignFrame omitHidden = viewport.getViewAsString(false); } } - - String output = new FormatAdapter().formatSequences( + FormatAdapter f = new FormatAdapter(); + String output = f.formatSequences( format, - viewport.alignment.getSequencesArray(), - omitHidden); + (Alignment) viewport.alignment, // class cast exceptions will occur in the distant future + omitHidden, f.getCacheSuffixDefault(format), viewport.colSel); if (output == null) { @@ -842,8 +875,8 @@ public class AlignFrame cap.setText(new FormatAdapter().formatSequences( e.getActionCommand(), - viewport.alignment.getSequencesArray(), - omitHidden)); + viewport.alignment, + omitHidden, viewport.colSel)); } /** @@ -913,7 +946,8 @@ public class AlignFrame new AnnotationExporter().exportAnnotations( alignPanel, viewport.showAnnotation ? viewport.alignment.getAlignmentAnnotation() : null, - viewport.alignment.getGroups() + viewport.alignment.getGroups(), + ((Alignment)viewport.alignment).alignmentProperties ); } @@ -1049,8 +1083,28 @@ public class AlignFrame } } - - + /** + * + * @return alignment objects for all views + */ + AlignmentI[] getViewAlignments() + { + if (alignPanels!=null) + { + Enumeration e = alignPanels.elements(); + AlignmentI[] als = new AlignmentI[alignPanels.size()]; + for (int i=0; e.hasMoreElements(); i++) + { + als[i] = ((AlignmentPanel) e.nextElement()).av.getAlignment(); + } + return als; + } + if (viewport!=null) + { + return new AlignmentI[] { viewport.alignment }; + } + return null; + } /** * DOCUMENT ME! * @@ -1058,9 +1112,11 @@ public class AlignFrame */ protected void undoMenuItem_actionPerformed(ActionEvent e) { + if (viewport.historyList.empty()) + return; CommandI command = (CommandI)viewport.historyList.pop(); viewport.redoList.push(command); - command.undoCommand(); + command.undoCommand(getViewAlignments()); AlignViewport originalSource = getOriginatingSource(command); updateEditMenuBar(); @@ -1088,7 +1144,7 @@ public class AlignFrame CommandI command = (CommandI) viewport.redoList.pop(); viewport.historyList.push(command); - command.doCommand(); + command.doCommand(getViewAlignments()); AlignViewport originalSource = getOriginatingSource(command); updateEditMenuBar(); @@ -1311,7 +1367,7 @@ public class AlignFrame { return; } - + // TODO: preserve the ordering of displayed alignment annotation in any internal paste (particularly sequence associated annotation) SequenceI [] seqs = viewport.getSelectionAsNewSequence(); String[] omitHidden = null; @@ -1403,12 +1459,13 @@ public class AlignFrame } /** - * DOCUMENT ME! + * Paste contents of Jalview clipboard * - * @param newAlignment DOCUMENT ME! + * @param newAlignment true to paste to a new alignment, otherwise add to this. */ void paste(boolean newAlignment) { + boolean externalPaste=true; try { Clipboard c = Toolkit.getDefaultToolkit().getSystemClipboard(); @@ -1451,102 +1508,175 @@ public class AlignFrame } SequenceI[] sequences; - + boolean annotationAdded = false; + AlignmentI alignment = null; if(Desktop.jalviewClipboard!=null) { // The clipboard was filled from within Jalview, we must use the sequences // And dataset from the copied alignment - sequences = (SequenceI[])Desktop.jalviewClipboard[0]; + SequenceI[] newseq = (SequenceI[])Desktop.jalviewClipboard[0]; + // be doubly sure that we create *new* sequence objects. + sequences = new SequenceI[newseq.length]; + for (int i=0;i"); + + float avg = 0; + int min=Integer.MAX_VALUE, max=0; + for(int i=0; imax) + max = size; + if(sizeSequences: "+ viewport.alignment.getHeight()); + contents.append("
Minimum Sequence Length: "+min); + contents.append("
Maximum Sequence Length: "+max); + contents.append("
Average Length: "+(int)avg); + + if (((Alignment)viewport.alignment).getProperties() != null) + { + Hashtable props = ((Alignment)viewport.alignment).getProperties(); + Enumeration en = props.keys(); + contents.append("

"); + while(en.hasMoreElements()) + { + String key = en.nextElement().toString(); + StringBuffer val = new StringBuffer(); + String vals = props.get(key).toString(); + int pos=0, npos; + do { + npos = vals.indexOf("\n",pos); + if (npos==-1) + { + val.append(vals.substring(pos)); + } else { + val.append(vals.substring(pos, npos)); + val.append("
"); + } + pos = npos+1; + } while (npos!=-1); + contents.append(""); + } + contents.append("
"+key+""+val+"
"); + } + editPane.setText(contents.toString()+""); + JInternalFrame frame = new JInternalFrame(); + frame.getContentPane().add(new JScrollPane(editPane)); + + Desktop.instance.addInternalFrame(frame,"Alignment Properties: "+getTitle(),500,400); + } + + /** * DOCUMENT ME! * @@ -2690,7 +2889,7 @@ public class AlignFrame { SequenceI [] oldOrder = viewport.getAlignment().getSequencesArray(); AlignmentSorter.sortByPID(viewport.getAlignment(), - viewport.getAlignment().getSequenceAt(0)); + viewport.getAlignment().getSequenceAt(0), null); addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder, viewport.alignment)); alignPanel.paintAlignment(true); @@ -2722,7 +2921,6 @@ public class AlignFrame alignPanel.paintAlignment(true); } - /** * DOCUMENT ME! * @@ -2940,6 +3138,73 @@ public class AlignFrame } }); } + /** + * Add a new sort by annotation score menu item + * @param sort the menu to add the option to + * @param scoreLabel the label used to retrieve scores for each sequence on the alignment + */ + public void addSortByAnnotScoreMenuItem(JMenu sort, final String scoreLabel) + { + final JMenuItem item = new JMenuItem(scoreLabel); + sort.add(item); + item.addActionListener(new java.awt.event.ActionListener() + { + public void actionPerformed(ActionEvent e) + { + SequenceI [] oldOrder = viewport.getAlignment().getSequencesArray(); + AlignmentSorter.sortByAnnotationScore(scoreLabel, viewport.getAlignment());//,viewport.getSelectionGroup()); + addHistoryItem(new OrderCommand("Sort by "+scoreLabel, oldOrder, viewport.alignment)); + alignPanel.paintAlignment(true); + } + }); + } + /** + * last hash for alignment's annotation array - used to minimise cost of rebuild. + */ + protected int _annotationScoreVectorHash; + /** + * search the alignment and rebuild the sort by annotation score submenu + * the last alignment annotation vector hash is stored to minimize + * cost of rebuilding in subsequence calls. + * + */ + public void buildSortByAnnotationScoresMenu() + { + if(viewport.alignment.getAlignmentAnnotation()==null) + { + return; + } + + if (viewport.alignment.getAlignmentAnnotation().hashCode()!=_annotationScoreVectorHash) + { + sortByAnnotScore.removeAll(); + // almost certainly a quicker way to do this - but we keep it simple + Hashtable scoreSorts=new Hashtable(); + AlignmentAnnotation aann[]; + Enumeration sq = viewport.alignment.getSequences().elements(); + while (sq.hasMoreElements()) + { + aann = ((SequenceI) sq.nextElement()).getAnnotation(); + for (int i=0;aann!=null && i0); + scoreSorts.clear(); + + _annotationScoreVectorHash = + viewport.alignment.getAlignmentAnnotation().hashCode(); + } + } /** * Maintain the Order by->Displayed Tree menu. @@ -3005,7 +3270,7 @@ public class AlignFrame * or just the selected set will be submitted for multiple alignment. * */ - private jalview.datamodel.AlignmentView gatherSequencesForAlignment() + public jalview.datamodel.AlignmentView gatherSequencesForAlignment() { // Now, check we have enough sequences AlignmentView msa = null; @@ -3043,12 +3308,14 @@ public class AlignFrame } /** - * Decides what is submitted to a secondary structure prediction service, - * the currently selected sequence, or the currently selected alignment + * Decides what is submitted to a secondary structure prediction service: + * the first sequence in the alignment, or in the current selection, + * or, if the alignment is 'aligned' (ie padded with gaps), then the + * currently selected region or the whole alignment. * (where the first sequence in the set is the one that the prediction * will be for). */ - AlignmentView gatherSeqOrMsaForSecStrPrediction() + public AlignmentView gatherSeqOrMsaForSecStrPrediction() { AlignmentView seqs = null; @@ -3091,21 +3358,28 @@ public class AlignFrame { String choice = chooser.getSelectedFile().getPath(); jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice); - + jalview.io.NewickFile fin = null; try { - jalview.io.NewickFile fin = new jalview.io.NewickFile(choice, + fin = new jalview.io.NewickFile(choice, "File"); viewport.setCurrentTree(ShowNewickTree(fin, choice).getTree()); } catch (Exception ex) { JOptionPane.showMessageDialog(Desktop.desktop, - "Problem reading tree file", ex.getMessage(), + "Problem reading tree file", JOptionPane.WARNING_MESSAGE); ex.printStackTrace(); } + if (fin!=null && fin.hasWarningMessage()) + { + JOptionPane.showMessageDialog(Desktop.desktop, + fin.getWarningMessage(), + "Possible problem with tree file", + JOptionPane.WARNING_MESSAGE); + } } } @@ -3170,7 +3444,7 @@ public class AlignFrame { ex.printStackTrace(); } - + return tp; } @@ -3181,11 +3455,18 @@ public class AlignFrame */ public void BuildWebServiceMenu() { + // TODO: add support for context dependent disabling of services based on alignment and current selection + // TODO: add additional serviceHandle parameter to specify abstract handler class independently of AbstractName + // TODO: add in rediscovery GUI function to restart discoverer + // TODO: group services by location as well as function and/or introduce object broker mechanism. if ( (Discoverer.services != null) && (Discoverer.services.size() > 0)) { + // TODO: refactor to allow list of AbstractName/Handler bindings to be stored or retrieved from elsewhere Vector msaws = (Vector) Discoverer.services.get("MsaWS"); Vector secstrpr = (Vector) Discoverer.services.get("SecStrPred"); + Vector seqsrch = (Vector) Discoverer.services.get("SeqSearch"); + // 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) Vector wsmenu = new Vector(); final AlignFrame af = this; if (msaws != null) @@ -3196,42 +3477,9 @@ public class AlignFrame { final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) msaws. get(i); - final JMenuItem method = new JMenuItem(sh.getName()); - method.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - AlignmentView msa = gatherSequencesForAlignment(); - new jalview.ws.MsaWSClient(sh, title, msa, - false, true, - viewport.getAlignment().getDataset(), - af); - - } - - }); - msawsmenu.add(method); - // Deal with services that we know accept partial alignments. - if (sh.getName().indexOf("lustal") > -1) - { - // We know that ClustalWS can accept partial alignments for refinement. - final JMenuItem methodR = new JMenuItem(sh.getName()+" Realign"); - methodR.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - AlignmentView msa = gatherSequencesForAlignment(); - new jalview.ws.MsaWSClient(sh, title, msa, - true, true, - viewport.getAlignment().getDataset(), - af); - - } - - }); - msawsmenu.add(methodR); - - } + jalview.ws.WSClient impl = jalview.ws.Discoverer.getServiceClient(sh); + impl.attachWSMenuEntry(msawsmenu, this); + } wsmenu.add(msawsmenu); } @@ -3243,33 +3491,26 @@ public class AlignFrame { final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) secstrpr.get(i); - final JMenuItem method = new JMenuItem(sh.getName()); - method.addActionListener(new ActionListener() - { - public void actionPerformed(ActionEvent e) - { - AlignmentView msa = gatherSeqOrMsaForSecStrPrediction(); - if (msa.getSequences().length == 1) - { - // Single Sequence prediction - new jalview.ws.JPredClient(sh, title, false, msa, af, true); - } - else - { - if (msa.getSequences().length > 1) - { - // Sequence profile based prediction - new jalview.ws.JPredClient(sh, - title, true, msa, af, true); - } - } - } - }); - secstrmenu.add(method); + jalview.ws.WSClient impl = jalview.ws.Discoverer.getServiceClient(sh); + impl.attachWSMenuEntry(secstrmenu, this); } wsmenu.add(secstrmenu); } - this.webService.removeAll(); + if (seqsrch!=null) + { + // Add any sequence search services + final JMenu seqsrchmenu = new JMenu("Sequence Database Search"); + for (int i = 0, j = seqsrch.size(); i < j; i++) + { + final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) + seqsrch.elementAt(i); + jalview.ws.WSClient impl = jalview.ws.Discoverer.getServiceClient(sh); + impl.attachWSMenuEntry(seqsrchmenu, this); + } + // finally, add the whole shebang onto the webservices menu + wsmenu.add(seqsrchmenu); + } + resetWebServiceMenu(); for (int i = 0, j = wsmenu.size(); i < j; i++) { webService.add( (JMenu) wsmenu.get(i)); @@ -3277,12 +3518,34 @@ public class AlignFrame } else { - this.webService.removeAll(); + resetWebServiceMenu(); this.webService.add(this.webServiceNoServices); } - // TODO: add in rediscovery function - // TODO: reduce code redundancy. - // TODO: group services by location as well as function. + } + + + /** + * empty the web service menu and add any ad-hoc functions + * not dynamically discovered. + * + */ + private void resetWebServiceMenu() + { + webService.removeAll(); + // Temporary hack - DBRef Fetcher always top level ws entry. + JMenuItem rfetch = new JMenuItem("Fetch DB References"); + rfetch.setToolTipText("Retrieve and parse uniprot records for the alignment or the currently selected sequences"); + webService.add(rfetch); + rfetch.addActionListener(new ActionListener() { + + public void actionPerformed(ActionEvent e) + { + new jalview.ws.DBRefFetcher( + alignPanel.av.getSequenceSelection(), + alignPanel.alignFrame).fetchDBRefs(false); + } + + }); } /* public void vamsasStore_actionPerformed(ActionEvent e) @@ -3303,22 +3566,177 @@ public class AlignFrame vs.storeJalview( chooser.getSelectedFile().getAbsolutePath(), this); } }*/ + /** + * prototype of an automatically enabled/disabled analysis function + * + */ + protected void setShowProductsEnabled() + { + SequenceI [] selection = viewport.getSequenceSelection(); + if (canShowProducts(selection, viewport.getSelectionGroup()!=null, viewport.getAlignment().getDataset())) + { + showProducts.setEnabled(true); + + } else { + showProducts.setEnabled(false); + } + } + /** + * search selection for sequence xRef products and build the + * show products menu. + * @param selection + * @param dataset + * @return true if showProducts menu should be enabled. + */ + public boolean canShowProducts(SequenceI[] selection, boolean isRegionSelection, Alignment dataset) + { + boolean showp=false; + try { + showProducts.removeAll(); + final boolean dna = viewport.getAlignment().isNucleotide(); + final Alignment ds = dataset; + String[] ptypes = CrossRef.findSequenceXrefTypes(dna, selection, dataset); + //Object[] prods = CrossRef.buildXProductsList(viewport.getAlignment().isNucleotide(), selection, dataset, true); + final SequenceI[] sel = selection; + for (int t=0; ptypes!=null && t0) + { + buildSortByAnnotationScoresMenu(); + } + } } class PrintThread