/* * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$) * Copyright (C) $$Year-Rel$$ The Jalview Authors * * This file is part of Jalview. * * Jalview is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation, either version 3 * of the License, or (at your option) any later version. * * Jalview is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty * of MERCHANTABILITY or FITNESS FOR A PARTICULAR * PURPOSE. See the GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Jalview. If not, see . * The Jalview Authors are detailed in the 'AUTHORS' file. */ package jalview.gui; import jalview.datamodel.SequenceI; import jalview.ext.varna.JalviewVarnaBinding; import jalview.structure.AtomSpec; import jalview.util.MessageManager; import java.awt.BorderLayout; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.datatransfer.DataFlavor; import java.awt.datatransfer.Transferable; import java.awt.dnd.DnDConstants; import java.awt.dnd.DropTarget; import java.awt.dnd.DropTargetAdapter; import java.awt.dnd.DropTargetDropEvent; import java.awt.event.ComponentEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.List; import javax.swing.DefaultListModel; import javax.swing.DefaultListSelectionModel; import javax.swing.JLabel; import javax.swing.JList; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.ListModel; import javax.swing.ListSelectionModel; import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionListener; import fr.orsay.lri.varna.VARNAPanel; import fr.orsay.lri.varna.components.ReorderableJList; import fr.orsay.lri.varna.exceptions.ExceptionLoadingFailed; import fr.orsay.lri.varna.exceptions.ExceptionNAViewAlgorithm; import fr.orsay.lri.varna.exceptions.ExceptionNonEqualLength; import fr.orsay.lri.varna.models.FullBackup; import fr.orsay.lri.varna.models.VARNAConfig; import fr.orsay.lri.varna.models.rna.RNA; public class AppVarnaBinding extends JalviewVarnaBinding { public VARNAPanel vp; protected JPanel _listPanel = new JPanel(); private ReorderableJList _sideList = null; private static String errorOpt = "error"; @SuppressWarnings("unused") private boolean _error; private Color _backgroundColor = Color.white; private static int _nextID = 1; @SuppressWarnings("unused") private int _algoCode; private BackupHolder _rnaList; /** * Constructor */ public AppVarnaBinding() { init(); } /** * Constructs the VARNAPanel and an (empty) selection list of structures to * show in it */ private void init() { DefaultListModel dlm = new DefaultListModel(); int marginTools = 40; DefaultListSelectionModel m = new DefaultListSelectionModel(); m.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); m.setLeadAnchorNotificationEnabled(false); _sideList = new ReorderableJList(); _sideList.setModel(dlm); _sideList.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { AppVarnaBinding.this.mouseClicked(e); } }); _sideList.setSelectionModel(m); _sideList.setPreferredSize(new Dimension(100, 0)); _sideList.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent evt) { changeSelectedStructure_actionPerformed(evt); } }); _rnaList = new BackupHolder(dlm, _sideList); try { vp = new VARNAPanel("0", "."); } catch (ExceptionNonEqualLength e) { vp.errorDialog(e); } vp.setPreferredSize(new Dimension(400, 400)); JScrollPane listScroller = new JScrollPane(_sideList); listScroller.setPreferredSize(new Dimension(150, 0)); vp.setBackground(_backgroundColor); JLabel j = new JLabel( MessageManager.getString("label.structures_manager"), JLabel.CENTER); _listPanel.setLayout(new BorderLayout()); _listPanel.add(j, BorderLayout.NORTH); _listPanel.add(listScroller, BorderLayout.CENTER); new DropTarget(vp, new DropTargetAdapter() { @Override public void drop(DropTargetDropEvent dtde) { AppVarnaBinding.this.drop(dtde); } }); } public JPanel getListPanel() { return _listPanel; } /** * Returns the currently selected RNA, or null if none selected * * @return */ public RNA getSelectedRNA() { int selectedIndex = _sideList.getSelectedIndex(); if (selectedIndex < 0) { return null; } FullBackup selected = _rnaList.getElementAt(selectedIndex); return selected.rna; } /** * Substitute currently selected RNA with the edited one * * @param rnaEdit */ public void updateSelectedRNA(RNA rnaEdit) { vp.repaint(); vp.showRNA(rnaEdit); } public static String generateDefaultName() { return "User file #" + _nextID++; } public String[][] getParameterInfo() { String[][] info = { // Parameter Name Kind of Value Description, { "sequenceDBN", "String", "A raw RNA sequence" }, { "structureDBN", "String", "An RNA structure in dot bracket notation (DBN)" }, { errorOpt, "boolean", "To show errors" }, }; return info; } @SuppressWarnings("unused") private Color getSafeColor(String col, Color def) { Color result; try { result = Color.decode(col); } catch (Exception e) { try { result = Color.getColor(col, def); } catch (Exception e2) { return def; } } return result; } public VARNAPanel get_varnaPanel() { return vp; } public void set_varnaPanel(VARNAPanel surface) { vp = surface; } public void drop(DropTargetDropEvent dtde) { try { Transferable tr = dtde.getTransferable(); DataFlavor[] flavors = tr.getTransferDataFlavors(); for (int i = 0; i < flavors.length; i++) { if (flavors[i].isFlavorJavaFileListType()) { dtde.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE); Object ob = tr.getTransferData(flavors[i]); if (ob instanceof List) { List list = (List) ob; for (int j = 0; j < list.size(); j++) { Object o = list.get(j); if (dtde.getSource() instanceof DropTarget) { DropTarget dt = (DropTarget) dtde.getSource(); Component c = dt.getComponent(); if (c instanceof VARNAPanel) { String path = o.toString(); VARNAPanel varnaPanel = (VARNAPanel) c; try { FullBackup bck = VARNAPanel.importSession(path); _rnaList.add(bck.config, bck.rna, bck.name, true); } catch (ExceptionLoadingFailed e3) { int mn = 1; Collection mdls = fr.orsay.lri.varna.factories.RNAFactory .loadSecStr(path); for (RNA r : mdls) { r.drawRNA(varnaPanel.getConfig()); String name = r.getName(); if (name.equals("")) { name = path.substring( path.lastIndexOf(File.separatorChar) + 1); } if (mdls.size() > 1) { name += " (Model " + mn++ + ")"; } _rnaList.add(varnaPanel.getConfig().clone(), r, name, true); // BH 2018 SwingJS clone of varnaPanel or its config will // be the object itself, not a clone } } } } } } // If we made it this far, everything worked. dtde.dropComplete(true); return; } } // Hmm, the user must not have dropped a file list dtde.rejectDrop(); } catch (Exception e) { e.printStackTrace(); dtde.rejectDrop(); } } private class BackupHolder { private DefaultListModel _rnalist; private List _rnas = new ArrayList(); JList _l; public BackupHolder(DefaultListModel rnaList, JList l) { _rnalist = rnaList; _l = l; } public void add(VARNAConfig c, RNA r, String name) { add(c, r, name, false); } /** * Adds an entry to the end of the selection list and (optionally) sets it * as selected * * @param c * @param r * @param name * @param select */ public void add(VARNAConfig c, RNA r, String name, boolean select) { if (select) { _l.removeSelectionInterval(0, _rnalist.size()); } if (name.equals("")) { name = generateDefaultName(); } FullBackup bck = new FullBackup(c, r, name); _rnas.add(r); _rnalist.addElement(bck); if (select) { _l.setSelectedIndex(0); } } public FullBackup getElementAt(int i) { return _rnalist.getElementAt(i); } } public void mouseClicked(MouseEvent e) { if (e.getClickCount() == 2) { int index = _sideList.locationToIndex(e.getPoint()); ListModel dlm = _sideList.getModel(); // FullBackup item = dlm.getElementAt(index); _sideList.ensureIndexIsVisible(index); /* * TODO Object newName = JvOptionPane.showInputDialog( this, * "Specify a new name for this RNA", "Rename RNA", * JvOptionPane.QUESTION_MESSAGE, (Icon)null, null, item.toString()); if * (newName!=null) { item.name = newName.toString(); * this._sideList.repaint(); } */ } } @Override public String[] getStructureFiles() { return null; } @Override public void releaseReferences(Object svl) { } @Override public void updateColours(Object source) { } @Override public void componentHidden(ComponentEvent e) { } @Override public void componentMoved(ComponentEvent e) { } @Override public void componentResized(ComponentEvent e) { } @Override public void componentShown(ComponentEvent e) { } @Override public void highlightAtoms(List atoms) { } @Override public boolean isListeningFor(SequenceI seq) { return true; } /** * Returns the path to a temporary file containing a representation of the * state of the Varna display, or null on any error * * @param rna * @param jds * * @return */ public String getStateInfo(RNA rna) { if (vp == null) { return null; } /* * we have to show the RNA we want to save in the viewer; get the currently * displayed model first so we can restore it */ FullBackup sel = (FullBackup) _sideList.getSelectedValue(); FullBackup model = null; ListModel models = _sideList.getModel(); for (int i = 0; i < models.getSize(); i++) { model = (FullBackup) models.getElementAt(i); if (model.rna == rna) { break; } } if (model == null) { return null; } /* * switch display */ vp.showRNA(model.rna, model.config); try { File temp; temp = File.createTempFile("varna", null); temp.deleteOnExit(); String filePath = temp.getAbsolutePath(); vp.toXML(filePath); /* * restore the previous display */ vp.showRNA(sel.rna, sel.config); return filePath; } catch (IOException e) { return null; } } public int getSelectedIndex() { return _sideList.getSelectedIndex(); } /** * Switch the Varna display to the structure selected in the left hand panel * * @param evt */ protected void changeSelectedStructure_actionPerformed( ListSelectionEvent evt) { if (!evt.getValueIsAdjusting()) { showSelectedStructure(); } } /** * */ protected void showSelectedStructure() { FullBackup sel = (FullBackup) _sideList.getSelectedValue(); if (sel != null) { vp.showRNA(sel.rna, sel.config); } } /** * Set and display the selected item in the list of structures * * @param selectedRna */ public void setSelectedIndex(final int selectedRna) { /* * note this does nothing if, say, selecting item 3 when only 1 has been * added on load */ _sideList.setSelectedIndex(selectedRna); // TODO ? need a worker thread to get this to happen properly } /** * Add an RNA structure to the selection list * * @param rna */ public void addStructure(RNA rna) { VARNAConfig config = vp.getConfig().clone(); // BH 2018 this will NOT be a // clone in SwingJS addStructure(rna, config); } /** * @param rna * @param config */ protected void addStructure(final RNA rna, final VARNAConfig config) { drawRna(rna, config); _rnaList.add(config, rna, rna.getName()); } /** * @param rna * @param config */ protected void drawRna(final RNA rna, final VARNAConfig config) { try { rna.drawRNA(rna.getDrawMode(), config); } catch (ExceptionNAViewAlgorithm e) { // only throwable for draw mode = 3 NAView System.err.println("Error drawing RNA: " + e.getMessage()); } } }