+ /*
+ * Make a copy of this alignment (sharing the same dataset
+ * sequences). If we are DNA, drop introns and update mappings
+ */
+ AlignmentI copyAlignment = null;
+ final SequenceI[] sequenceSelection = AlignFrame.this.viewport
+ .getSequenceSelection();
+ List<AlignedCodonFrame> cf = xrefs.getCodonFrames();
+ boolean copyAlignmentIsAligned = false;
+ if (dna)
+ {
+ copyAlignment = AlignmentUtils.makeCdsAlignment(
+ sequenceSelection, cf, alignment);
+ if (copyAlignment.getHeight() == 0)
+ {
+ System.err.println("Failed to make CDS alignment");
+ }
+ al.getCodonFrames().clear();
+ al.addCodonFrames(copyAlignment.getCodonFrames());
+ al.addCodonFrames(cf);
+
+ /*
+ * pending getting Embl transcripts to 'align',
+ * we are only doing this for Ensembl
+ */
+ // TODO proper criteria for 'can align as cdna'
+ if (DBRefSource.ENSEMBL.equalsIgnoreCase(source)
+ || AlignmentUtils.looksLikeEnsembl(alignment))
+ {
+ copyAlignment.alignAs(alignment);
+ copyAlignmentIsAligned = true;
+ }
+ }
+ else
+ {
+ copyAlignment = AlignmentUtils.makeCopyAlignment(
+ sequenceSelection, xrefs.getSequencesArray());
+ copyAlignment.addCodonFrames(cf);
+ al.addCodonFrames(copyAlignment.getCodonFrames());
+ al.addCodonFrames(cf);
+ }
+ copyAlignment.setGapCharacter(AlignFrame.this.viewport
+ .getGapCharacter());
+
+ StructureSelectionManager ssm = StructureSelectionManager
+ .getStructureSelectionManager(Desktop.instance);
+ ssm.registerMappings(cf);
+
+ if (copyAlignment.getHeight() <= 0)
+ {
+ System.err.println("No Sequences generated for xRef type "
+ + source);
+ return;
+ }
+ /*
+ * align protein to dna
+ */
+ if (dna && copyAlignmentIsAligned)
+ {
+ al.alignAs(copyAlignment);
+ }
+ else
+ {
+ /*
+ * align cdna to protein - currently only if
+ * fetching and aligning Ensembl transcripts!
+ */
+ if (DBRefSource.ENSEMBL.equalsIgnoreCase(source))
+ {
+ copyAlignment.alignAs(al);
+ }
+ }
+
+ AlignFrame copyThis = new AlignFrame(copyAlignment,
+ AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
+ copyThis.setTitle(AlignFrame.this.getTitle());
+
+ boolean showSequenceFeatures = viewport
+ .isShowSequenceFeatures();
+ newFrame.setShowSeqFeatures(showSequenceFeatures);
+ copyThis.setShowSeqFeatures(showSequenceFeatures);
+ FeatureRenderer myFeatureStyling = alignPanel.getSeqPanel().seqCanvas
+ .getFeatureRenderer();
+
+ /*
+ * copy feature rendering settings to split frame
+ */
+ newFrame.alignPanel.getSeqPanel().seqCanvas
+ .getFeatureRenderer()
+ .transferSettings(myFeatureStyling);
+ copyThis.alignPanel.getSeqPanel().seqCanvas
+ .getFeatureRenderer()
+ .transferSettings(myFeatureStyling);
+
+ /*
+ * apply 'database source' feature configuration
+ * if any was found
+ */
+ // TODO is this the feature colouring for the original
+ // alignment or the fetched xrefs? either could be Ensembl
+ newFrame.getViewport().applyFeaturesStyle(featureColourScheme);
+ copyThis.getViewport().applyFeaturesStyle(featureColourScheme);
+
+ SplitFrame sf = new SplitFrame(dna ? copyThis : newFrame,
+ dna ? newFrame : copyThis);
+ newFrame.setVisible(true);
+ copyThis.setVisible(true);
+ String linkedTitle = MessageManager
+ .getString("label.linked_view_title");
+ Desktop.addInternalFrame(sf, linkedTitle, -1, -1);
+ sf.adjustDivider();
+ }
+ } catch (Exception e)
+ {
+ Cache.log.error("Exception when finding crossreferences", e);
+ } catch (OutOfMemoryError e)
+ {
+ new OOMWarning("whilst fetching crossreferences", e);
+ } catch (Throwable e)
+ {
+ Cache.log.error("Error when finding crossreferences", e);
+ } finally
+ {
+ AlignFrame.this.setProgressBar(MessageManager.formatMessage(
+ "status.finished_searching_for_sequences_from",
+ new Object[] { source }), sttime);
+ }
+ }
+
+ /**
+ * Makes an alignment containing the given sequences. If this is of the
+ * same type as the given dataset (nucleotide/protein), then the new
+ * alignment shares the same dataset, and its dataset sequences are added
+ * to it. Otherwise a new dataset sequence is created for the
+ * cross-references.
+ *
+ * @param dataset
+ * @param seqs
+ * @return
+ */
+ protected AlignmentI makeCrossReferencesAlignment(AlignmentI dataset,
+ AlignmentI seqs)
+ {
+ boolean sameType = dataset.isNucleotide() == seqs.isNucleotide();
+
+ SequenceI[] sprods = new SequenceI[seqs.getHeight()];
+ for (int s = 0; s < sprods.length; s++)
+ {
+ sprods[s] = (seqs.getSequenceAt(s)).deriveSequence();
+ if (sameType)
+ {
+ if (dataset.getSequences() == null
+ || !dataset.getSequences().contains(
+ sprods[s].getDatasetSequence()))
+ {
+ dataset.addSequence(sprods[s].getDatasetSequence());
+ }
+ }
+ sprods[s].updatePDBIds();
+ }
+ Alignment al = new Alignment(sprods);
+ if (sameType)
+ {
+ al.setDataset((Alignment) dataset);
+ }
+ else
+ {
+ al.createDatasetAlignment();
+ }
+ return al;
+ }
+
+ };
+ Thread frunner = new Thread(foo);
+ frunner.start();
+ }
+
+ /**
+ * Construct and display a new frame containing the translation of this
+ * frame's DNA sequences to their aligned protein (amino acid) equivalents.
+ */
+ @Override
+ public void showTranslation_actionPerformed(ActionEvent e)
+ {
+ AlignmentI al = null;
+ try
+ {
+ Dna dna = new Dna(viewport, viewport.getViewAsVisibleContigs(true));
+
+ al = dna.translateCdna();
+ } catch (Exception ex)
+ {
+ jalview.bin.Cache.log.error(
+ "Exception during translation. Please report this !", ex);
+ final String msg = MessageManager
+ .getString("label.error_when_translating_sequences_submit_bug_report");
+ final String errorTitle = MessageManager
+ .getString("label.implementation_error")
+ + MessageManager.getString("label.translation_failed");
+ JOptionPane.showMessageDialog(Desktop.desktop, msg, errorTitle,
+ JOptionPane.ERROR_MESSAGE);
+ return;
+ }
+ if (al == null || al.getHeight() == 0)
+ {
+ final String msg = MessageManager
+ .getString("label.select_at_least_three_bases_in_at_least_one_sequence_to_cDNA_translation");
+ final String errorTitle = MessageManager
+ .getString("label.translation_failed");
+ JOptionPane.showMessageDialog(Desktop.desktop, msg, errorTitle,
+ JOptionPane.WARNING_MESSAGE);
+ }
+ else
+ {
+ AlignFrame af = new AlignFrame(al, DEFAULT_WIDTH, DEFAULT_HEIGHT);
+ af.setFileFormat(this.currentFileFormat);
+ final String newTitle = MessageManager.formatMessage(
+ "label.translation_of_params",
+ new Object[] { this.getTitle() });
+ af.setTitle(newTitle);
+ if (Cache.getDefault(Preferences.ENABLE_SPLIT_FRAME, true))
+ {
+ final SequenceI[] seqs = viewport.getSelectionAsNewSequence();
+ viewport.openSplitFrame(af, new Alignment(seqs));
+ }
+ else
+ {
+ Desktop.addInternalFrame(af, newTitle, DEFAULT_WIDTH,
+ DEFAULT_HEIGHT);
+ }
+ }
+ }
+
+ /**
+ * Set the file format
+ *
+ * @param fileFormat
+ */
+ public void setFileFormat(String fileFormat)
+ {
+ this.currentFileFormat = fileFormat;
+ }
+
+ /**
+ * Try to load a features file onto the alignment.
+ *
+ * @param file
+ * contents or path to retrieve file
+ * @param type
+ * access mode of file (see jalview.io.AlignFile)
+ * @return true if features file was parsed correctly.
+ */
+ public boolean parseFeaturesFile(String file, String type)
+ {
+ return avc.parseFeaturesFile(file, type,
+ jalview.bin.Cache.getDefault("RELAXEDSEQIDMATCHING", false));
+
+ }
+
+ @Override
+ public void refreshFeatureUI(boolean enableIfNecessary)
+ {
+ // note - currently this is only still here rather than in the controller
+ // because of the featureSettings hard reference that is yet to be
+ // abstracted
+ if (enableIfNecessary)
+ {
+ viewport.setShowSequenceFeatures(true);
+ showSeqFeatures.setSelected(true);
+ }
+
+ }
+
+ @Override
+ public void dragEnter(DropTargetDragEvent evt)
+ {
+ }
+
+ @Override
+ public void dragExit(DropTargetEvent evt)
+ {
+ }
+
+ @Override
+ public void dragOver(DropTargetDragEvent evt)
+ {
+ }
+
+ @Override
+ public void dropActionChanged(DropTargetDragEvent evt)
+ {
+ }
+
+ @Override
+ public void drop(DropTargetDropEvent evt)
+ {
+ Transferable t = evt.getTransferable();
+ java.util.List<String> files = new ArrayList<String>(), protocols = new ArrayList<String>();
+
+ try
+ {
+ Desktop.transferFromDropTarget(files, protocols, evt, t);
+ } catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ if (files != null)
+ {
+ try
+ {
+ // check to see if any of these files have names matching sequences in
+ // the alignment
+ SequenceIdMatcher idm = new SequenceIdMatcher(viewport
+ .getAlignment().getSequencesArray());
+ /**
+ * Object[] { String,SequenceI}
+ */
+ ArrayList<Object[]> filesmatched = new ArrayList<Object[]>();
+ ArrayList<String> filesnotmatched = new ArrayList<String>();
+ for (int i = 0; i < files.size(); i++)
+ {
+ String file = files.get(i).toString();
+ String pdbfn = "";
+ String protocol = FormatAdapter.checkProtocol(file);
+ if (protocol == jalview.io.FormatAdapter.FILE)
+ {
+ File fl = new File(file);
+ pdbfn = fl.getName();
+ }
+ else if (protocol == jalview.io.FormatAdapter.URL)
+ {
+ URL url = new URL(file);
+ pdbfn = url.getFile();
+ }
+ if (pdbfn.length() > 0)
+ {
+ // attempt to find a match in the alignment
+ SequenceI[] mtch = idm.findAllIdMatches(pdbfn);
+ int l = 0, c = pdbfn.indexOf(".");
+ while (mtch == null && c != -1)
+ {
+ do
+ {
+ l = c;
+ } while ((c = pdbfn.indexOf(".", l)) > l);
+ if (l > -1)
+ {
+ pdbfn = pdbfn.substring(0, l);
+ }
+ mtch = idm.findAllIdMatches(pdbfn);
+ }
+ if (mtch != null)
+ {
+ String type = null;
+ try
+ {
+ type = new IdentifyFile().identify(file, protocol);
+ } catch (Exception ex)
+ {
+ type = null;
+ }
+ if (type != null)
+ {
+ if (type.equalsIgnoreCase("PDB"))
+ {
+ filesmatched.add(new Object[] { file, protocol, mtch });
+ continue;
+ }
+ }
+ }
+ // File wasn't named like one of the sequences or wasn't a PDB file.
+ filesnotmatched.add(file);
+ }
+ }
+ int assocfiles = 0;
+ if (filesmatched.size() > 0)
+ {
+ if (Cache.getDefault("AUTOASSOCIATE_PDBANDSEQS", false)
+ || JOptionPane
+ .showConfirmDialog(
+ this,
+ MessageManager
+ .formatMessage(
+ "label.automatically_associate_pdb_files_with_sequences_same_name",
+ new Object[] { Integer
+ .valueOf(
+ filesmatched
+ .size())
+ .toString() }),
+ MessageManager
+ .getString("label.automatically_associate_pdb_files_by_name"),
+ JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)
+
+ {
+ for (Object[] fm : filesmatched)
+ {
+ // try and associate
+ // TODO: may want to set a standard ID naming formalism for
+ // associating PDB files which have no IDs.
+ for (SequenceI toassoc : (SequenceI[]) fm[2])
+ {
+ PDBEntry pe = new AssociatePdbFileWithSeq()
+ .associatePdbWithSeq((String) fm[0],
+ (String) fm[1], toassoc, false,
+ Desktop.instance);
+ if (pe != null)
+ {
+ System.err.println("Associated file : "
+ + ((String) fm[0]) + " with "
+ + toassoc.getDisplayId(true));
+ assocfiles++;
+ }
+ }
+ alignPanel.paintAlignment(true);
+ }
+ }
+ }
+ if (filesnotmatched.size() > 0)
+ {
+ if (assocfiles > 0
+ && (Cache.getDefault(
+ "AUTOASSOCIATE_PDBANDSEQS_IGNOREOTHERS", false) || JOptionPane
+ .showConfirmDialog(
+ this,
+ "<html>"
+ + MessageManager
+ .formatMessage(
+ "label.ignore_unmatched_dropped_files_info",
+ new Object[] { Integer
+ .valueOf(
+ filesnotmatched
+ .size())
+ .toString() })
+ + "</html>",
+ MessageManager
+ .getString("label.ignore_unmatched_dropped_files"),
+ JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION))
+ {
+ return;
+ }
+ for (String fn : filesnotmatched)
+ {
+ loadJalviewDataFile(fn, null, null, null);
+ }
+
+ }
+ } catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Attempt to load a "dropped" file or URL string: First by testing whether
+ * it's an Annotation file, then a JNet file, and finally a features file. If
+ * all are false then the user may have dropped an alignment file onto this
+ * AlignFrame.
+ *
+ * @param file
+ * either a filename or a URL string.
+ */
+ public void loadJalviewDataFile(String file, String protocol,
+ String format, SequenceI assocSeq)
+ {
+ try
+ {
+ if (protocol == null)
+ {
+ protocol = FormatAdapter.checkProtocol(file);
+ }
+ // if the file isn't identified, or not positively identified as some
+ // other filetype (PFAM is default unidentified alignment file type) then
+ // try to parse as annotation.
+ boolean isAnnotation = (format == null || format
+ .equalsIgnoreCase("PFAM")) ? new AnnotationFile()
+ .annotateAlignmentView(viewport, file, protocol) : false;
+
+ if (!isAnnotation)
+ {
+ // first see if its a T-COFFEE score file
+ TCoffeeScoreFile tcf = null;
+ try
+ {
+ tcf = new TCoffeeScoreFile(file, protocol);
+ if (tcf.isValid())
+ {
+ if (tcf.annotateAlignment(viewport.getAlignment(), true))
+ {
+ tcoffeeColour.setEnabled(true);
+ tcoffeeColour.setSelected(true);
+ changeColour(new TCoffeeColourScheme(viewport.getAlignment()));
+ isAnnotation = true;
+ statusBar
+ .setText(MessageManager
+ .getString("label.successfully_pasted_tcoffee_scores_to_alignment"));
+ }
+ else
+ {
+ // some problem - if no warning its probable that the ID matching
+ // process didn't work
+ JOptionPane
+ .showMessageDialog(
+ Desktop.desktop,
+ tcf.getWarningMessage() == null ? MessageManager
+ .getString("label.check_file_matches_sequence_ids_alignment")
+ : tcf.getWarningMessage(),
+ MessageManager
+ .getString("label.problem_reading_tcoffee_score_file"),
+ JOptionPane.WARNING_MESSAGE);
+ }
+ }
+ else
+ {
+ tcf = null;
+ }
+ } catch (Exception x)
+ {
+ Cache.log
+ .debug("Exception when processing data source as T-COFFEE score file",
+ x);
+ tcf = null;
+ }
+ if (tcf == null)
+ {
+ // try to see if its a JNet 'concise' style annotation file *before*
+ // we
+ // try to parse it as a features file
+ if (format == null)
+ {
+ format = new IdentifyFile().identify(file, protocol);
+ }
+ if (format.equalsIgnoreCase("JnetFile"))
+ {
+ jalview.io.JPredFile predictions = new jalview.io.JPredFile(
+ file, protocol);
+ new JnetAnnotationMaker();
+ JnetAnnotationMaker.add_annotation(predictions,
+ viewport.getAlignment(), 0, false);
+ SequenceI repseq = viewport.getAlignment().getSequenceAt(0);
+ viewport.getAlignment().setSeqrep(repseq);
+ ColumnSelection cs = new ColumnSelection();
+ cs.hideInsertionsFor(repseq);
+ viewport.setColumnSelection(cs);
+ isAnnotation = true;
+ }
+ else if (IdentifyFile.FeaturesFile.equals(format))
+ {
+ if (parseFeaturesFile(file, protocol))
+ {
+ alignPanel.paintAlignment(true);
+ }
+ }
+ else
+ {
+ new FileLoader().LoadFile(viewport, file, protocol, format);
+ }
+ }
+ }
+ if (isAnnotation)
+ {
+
+ alignPanel.adjustAnnotationHeight();
+ viewport.updateSequenceIdColours();
+ buildSortByAnnotationScoresMenu();
+ alignPanel.paintAlignment(true);
+ }
+ } catch (Exception ex)
+ {
+ ex.printStackTrace();
+ } catch (OutOfMemoryError oom)
+ {
+ try
+ {
+ System.gc();
+ } catch (Exception x)
+ {
+ }
+ new OOMWarning(
+ "loading data "
+ + (protocol != null ? (protocol.equals(FormatAdapter.PASTE) ? "from clipboard."
+ : "using " + protocol + " from " + file)
+ : ".")
+ + (format != null ? "(parsing as '" + format
+ + "' file)" : ""), oom, Desktop.desktop);
+ }
+ }
+
+ /**
+ * Method invoked by the ChangeListener on the tabbed pane, in other words
+ * when a different tabbed pane is selected by the user or programmatically.
+ */
+ @Override
+ public void tabSelectionChanged(int index)
+ {
+ if (index > -1)
+ {
+ alignPanel = alignPanels.get(index);
+ viewport = alignPanel.av;
+ avc.setViewportAndAlignmentPanel(viewport, alignPanel);
+ setMenusFromViewport(viewport);
+ }
+
+ /*
+ * If there is a frame linked to this one in a SplitPane, switch it to the
+ * same view tab index. No infinite recursion of calls should happen, since
+ * tabSelectionChanged() should not get invoked on setting the selected
+ * index to an unchanged value. Guard against setting an invalid index
+ * before the new view peer tab has been created.
+ */
+ final AlignViewportI peer = viewport.getCodingComplement();
+ if (peer != null)
+ {
+ AlignFrame linkedAlignFrame = ((AlignViewport) peer).getAlignPanel().alignFrame;
+ if (linkedAlignFrame.tabbedPane.getTabCount() > index)
+ {
+ linkedAlignFrame.tabbedPane.setSelectedIndex(index);
+ }
+ }
+ }
+
+ /**
+ * On right mouse click on view tab, prompt for and set new view name.
+ */
+ @Override
+ public void tabbedPane_mousePressed(MouseEvent e)
+ {
+ if (e.isPopupTrigger())
+ {
+ String msg = MessageManager.getString("label.enter_view_name");
+ String reply = JOptionPane.showInternalInputDialog(this, msg, msg,
+ JOptionPane.QUESTION_MESSAGE);
+
+ if (reply != null)
+ {
+ viewport.viewName = reply;
+ // TODO warn if reply is in getExistingViewNames()?
+ tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), reply);
+ }
+ }
+ }
+
+ public AlignViewport getCurrentView()
+ {
+ return viewport;
+ }
+
+ /**
+ * Open the dialog for regex description parsing.
+ */
+ @Override
+ protected void extractScores_actionPerformed(ActionEvent e)
+ {
+ ParseProperties pp = new jalview.analysis.ParseProperties(
+ viewport.getAlignment());
+ // TODO: verify regex and introduce GUI dialog for version 2.5
+ // if (pp.getScoresFromDescription("col", "score column ",
+ // "\\W*([-+]?\\d*\\.?\\d*e?-?\\d*)\\W+([-+]?\\d*\\.?\\d*e?-?\\d*)",
+ // true)>0)
+ if (pp.getScoresFromDescription("description column",
+ "score in description column ", "\\W*([-+eE0-9.]+)", true) > 0)
+ {
+ buildSortByAnnotationScoresMenu();
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * jalview.jbgui.GAlignFrame#showDbRefs_actionPerformed(java.awt.event.ActionEvent
+ * )
+ */
+ @Override
+ protected void showDbRefs_actionPerformed(ActionEvent e)
+ {
+ viewport.setShowDBRefs(showDbRefsMenuitem.isSelected());
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @seejalview.jbgui.GAlignFrame#showNpFeats_actionPerformed(java.awt.event.
+ * ActionEvent)
+ */
+ @Override
+ protected void showNpFeats_actionPerformed(ActionEvent e)
+ {
+ viewport.setShowNPFeats(showNpFeatsMenuitem.isSelected());
+ }
+
+ /**
+ * find the viewport amongst the tabs in this alignment frame and close that
+ * tab
+ *
+ * @param av
+ */
+ public boolean closeView(AlignViewportI av)
+ {
+ if (viewport == av)
+ {
+ this.closeMenuItem_actionPerformed(false);
+ return true;
+ }
+ Component[] comp = tabbedPane.getComponents();
+ for (int i = 0; comp != null && i < comp.length; i++)
+ {
+ if (comp[i] instanceof AlignmentPanel)
+ {
+ if (((AlignmentPanel) comp[i]).av == av)
+ {
+ // close the view.
+ closeView((AlignmentPanel) comp[i]);
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ protected void build_fetchdbmenu(JMenu webService)
+ {
+ // Temporary hack - DBRef Fetcher always top level ws entry.
+ // TODO We probably want to store a sequence database checklist in
+ // preferences and have checkboxes.. rather than individual sources selected
+ // here
+ final JMenu rfetch = new JMenu(
+ MessageManager.getString("action.fetch_db_references"));
+ rfetch.setToolTipText(MessageManager
+ .getString("label.retrieve_parse_sequence_database_records_alignment_or_selected_sequences"));
+ webService.add(rfetch);
+
+ final JCheckBoxMenuItem trimrs = new JCheckBoxMenuItem(
+ MessageManager.getString("option.trim_retrieved_seqs"));
+ trimrs.setToolTipText(MessageManager
+ .getString("label.trim_retrieved_sequences"));
+ trimrs.setSelected(Cache.getDefault("TRIM_FETCHED_DATASET_SEQS", true));
+ trimrs.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ trimrs.setSelected(trimrs.isSelected());
+ Cache.setProperty("TRIM_FETCHED_DATASET_SEQS",
+ Boolean.valueOf(trimrs.isSelected()).toString());
+ };
+ });
+ rfetch.add(trimrs);
+ JMenuItem fetchr = new JMenuItem(
+ MessageManager.getString("label.standard_databases"));
+ fetchr.setToolTipText(MessageManager
+ .getString("label.fetch_embl_uniprot"));
+ fetchr.addActionListener(new ActionListener()
+ {
+
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ new Thread(new Runnable()
+ {
+ @Override
+ public void run()