+ @Override
+ public void dragExit(DropTargetEvent evt)
+ {
+ }
+
+ @Override
+ public void dragOver(DropTargetDragEvent evt)
+ {
+ }
+
+ @Override
+ public void dropActionChanged(DropTargetDragEvent evt)
+ {
+ }
+
+ @Override
+ public void drop(DropTargetDropEvent evt)
+ {
+ // JAL-1552 - acceptDrop required before getTransferable call for
+ // Java's Transferable for native dnd
+ evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
+ Transferable t = evt.getTransferable();
+ final AlignFrame thisaf = this;
+ final List<String> files = new ArrayList<>();
+ List<DataSourceType> protocols = new ArrayList<>();
+
+ try
+ {
+ Desktop.transferFromDropTarget(files, protocols, evt, t);
+ } catch (Exception e)
+ {
+ e.printStackTrace();
+ }
+ if (files != null)
+ {
+ new Thread(new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ 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<>();
+ ArrayList<String> filesnotmatched = new ArrayList<>();
+ for (int i = 0; i < files.size(); i++)
+ {
+ String file = files.get(i).toString();
+ String pdbfn = "";
+ DataSourceType protocol = FormatAdapter.checkProtocol(file);
+ if (protocol == DataSourceType.FILE)
+ {
+ File fl = new File(file);
+ pdbfn = fl.getName();
+ }
+ else if (protocol == DataSourceType.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)
+ {
+ FileFormatI type = null;
+ try
+ {
+ type = new IdentifyFile().identify(file, protocol);
+ } catch (Exception ex)
+ {
+ type = null;
+ }
+ if (type != null && type.isStructureFile())
+ {
+ 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)
+ {
+ boolean autoAssociate = Cache
+ .getDefault("AUTOASSOCIATE_PDBANDSEQS", false);
+ if (!autoAssociate)
+ {
+ String msg = MessageManager.formatMessage(
+ "label.automatically_associate_structure_files_with_sequences_same_name",
+ new Object[]
+ { Integer.valueOf(filesmatched.size())
+ .toString() });
+ String ttl = MessageManager.getString(
+ "label.automatically_associate_structure_files_by_name");
+ int choice = JvOptionPane.showConfirmDialog(thisaf, msg,
+ ttl, JvOptionPane.YES_NO_OPTION);
+ autoAssociate = choice == JvOptionPane.YES_OPTION;
+ }
+ if (autoAssociate)
+ {
+ 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],
+ (DataSourceType) fm[1], toassoc, false,
+ Desktop.instance);
+ if (pe != null)
+ {
+ System.err.println("Associated file : "
+ + ((String) fm[0]) + " with "
+ + toassoc.getDisplayId(true));
+ assocfiles++;
+ }
+ }
+ // TODO: do we need to update overview ? only if features are
+ // shown I guess
+ alignPanel.paintAlignment(true, false);
+ }
+ }
+ else
+ {
+ /*
+ * add declined structures as sequences
+ */
+ for (Object[] o : filesmatched)
+ {
+ filesnotmatched.add((String) o[0]);
+ }
+ }
+ }
+ if (filesnotmatched.size() > 0)
+ {
+ if (assocfiles > 0 && (Cache.getDefault(
+ "AUTOASSOCIATE_PDBANDSEQS_IGNOREOTHERS", false)
+ || JvOptionPane.showConfirmDialog(thisaf,
+ "<html>" + MessageManager.formatMessage(
+ "label.ignore_unmatched_dropped_files_info",
+ new Object[]
+ { Integer.valueOf(
+ filesnotmatched.size())
+ .toString() })
+ + "</html>",
+ MessageManager.getString(
+ "label.ignore_unmatched_dropped_files"),
+ JvOptionPane.YES_NO_OPTION) == JvOptionPane.YES_OPTION))
+ {
+ return;
+ }
+ for (String fn : filesnotmatched)
+ {
+ loadJalviewDataFile(fn, null, null, null);
+ }
+
+ }
+ } catch (Exception ex)
+ {
+ ex.printStackTrace();
+ }
+ }
+ }).start();
+ }
+ }
+
+ /**
+ * Attempt to load a "dropped" file or URL string, by testing in turn for
+ * <ul>
+ * <li>an Annotation file</li>
+ * <li>a JNet file</li>
+ * <li>a features file</li>
+ * <li>else try to interpret as an alignment file</li>
+ * </ul>
+ *
+ * @param file
+ * either a filename or a URL string.
+ */
+ public void loadJalviewDataFile(String file, DataSourceType sourceType,
+ FileFormatI format, SequenceI assocSeq)
+ {
+ try
+ {
+ if (sourceType == null)
+ {
+ sourceType = 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
+ || FileFormat.Pfam.equals(format))
+ ? new AnnotationFile().annotateAlignmentView(viewport,
+ file, sourceType)
+ : false;
+
+ if (!isAnnotation)
+ {
+ // first see if its a T-COFFEE score file
+ TCoffeeScoreFile tcf = null;
+ try
+ {
+ tcf = new TCoffeeScoreFile(file, sourceType);
+ if (tcf.isValid())
+ {
+ if (tcf.annotateAlignment(viewport.getAlignment(), true))
+ {
+ buildColourMenu();
+ 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
+ JvOptionPane.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"),
+ JvOptionPane.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, sourceType);
+ }
+ if (FileFormat.ScoreMatrix == format)
+ {
+ ScoreMatrixFile sm = new ScoreMatrixFile(
+ new FileParse(file, sourceType));
+ sm.parse();
+ // todo: i18n this message
+ statusBar.setText(MessageManager.formatMessage(
+ "label.successfully_loaded_matrix",
+ sm.getMatrixName()));
+ }
+ else if (FileFormat.Jnet.equals(format))
+ {
+ JPredFile predictions = new JPredFile(file, sourceType);
+ new JnetAnnotationMaker();
+ JnetAnnotationMaker.add_annotation(predictions,
+ viewport.getAlignment(), 0, false);
+ viewport.getAlignment().setupJPredAlignment();
+ isAnnotation = true;
+ }
+ // else if (IdentifyFile.FeaturesFile.equals(format))
+ else if (FileFormat.Features.equals(format))
+ {
+ if (parseFeaturesFile(file, sourceType))
+ {
+ SplitFrame splitFrame = (SplitFrame) getSplitViewContainer();
+ if (splitFrame != null)
+ {
+ splitFrame.repaint();
+ }
+ else
+ {
+ alignPanel.paintAlignment(true, true);
+ }
+ }
+ }
+ else
+ {
+ new FileLoader().LoadFile(viewport, file, sourceType, format);
+ }
+ }
+ }
+ if (isAnnotation)
+ {
+
+ alignPanel.adjustAnnotationHeight();
+ viewport.updateSequenceIdColours();
+ buildSortByAnnotationScoresMenu();
+ alignPanel.paintAlignment(true, true);
+ }
+ } catch (Exception ex)
+ {
+ ex.printStackTrace();
+ } catch (OutOfMemoryError oom)
+ {
+ try
+ {
+ System.gc();
+ } catch (Exception x)
+ {
+ }
+ new OOMWarning(
+ "loading data "
+ + (sourceType != null
+ ? (sourceType == DataSourceType.PASTE
+ ? "from clipboard."
+ : "using " + sourceType + " 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 (featureSettings != null && featureSettings.isOpen()
+ && featureSettings.fr.getViewport() != viewport)
+ {
+ if (viewport.isShowSequenceFeatures())
+ {
+ // refresh the featureSettings to reflect UI change
+ showFeatureSettingsUI();
+ }
+ else
+ {
+ // close feature settings for this view.
+ featureSettings.close();
+ }
+ }
+
+ }
+
+ /*
+ * 'focus' any colour slider that is open to the selected viewport
+ */
+ if (viewport.getConservationSelected())
+ {
+ SliderPanel.setConservationSlider(alignPanel,
+ viewport.getResidueShading(), alignPanel.getViewName());
+ }
+ else
+ {
+ SliderPanel.hideConservationSlider();
+ }
+ if (viewport.getAbovePIDThreshold())
+ {
+ SliderPanel.setPIDSliderSource(alignPanel,
+ viewport.getResidueShading(), alignPanel.getViewName());
+ }
+ else
+ {
+ SliderPanel.hidePIDSlider();
+ }
+
+ /*
+ * 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 = JvOptionPane.showInternalInputDialog(this, msg, msg,
+ JvOptionPane.QUESTION_MESSAGE);
+
+ if (reply != null)
+ {
+ viewport.setViewName(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(DBRefFetcher.TRIM_RETRIEVED_SEQUENCES, true));
+ trimrs.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ trimrs.setSelected(trimrs.isSelected());
+ Cache.setProperty(DBRefFetcher.TRIM_RETRIEVED_SEQUENCES,
+ 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()
+ {
+ boolean isNucleotide = alignPanel.alignFrame.getViewport()
+ .getAlignment().isNucleotide();
+ DBRefFetcher dbRefFetcher = new DBRefFetcher(
+ alignPanel.av.getSequenceSelection(),
+ alignPanel.alignFrame, null,
+ alignPanel.alignFrame.featureSettings, isNucleotide);
+ dbRefFetcher.addListener(new FetchFinishedListenerI()
+ {
+ @Override
+ public void finished()
+ {
+
+ for (FeatureSettingsModelI srcSettings : dbRefFetcher
+ .getFeatureSettingsModels())
+ {
+
+ alignPanel.av.mergeFeaturesStyle(srcSettings);
+ }
+ AlignFrame.this.setMenusForViewport();
+ }
+ });
+ dbRefFetcher.fetchDBRefs(false);
+ }
+ }).start();