}
/**
- * close alignPanel2 and shuffle tabs appropriately.
+ * Close the specified panel and close up tabs appropriately.
*
- * @param alignPanel2
+ * @param panelToClose
*/
- public void closeView(AlignmentPanel alignPanel2)
+ public void closeView(AlignmentPanel panelToClose)
{
int index = tabbedPane.getSelectedIndex();
- int closedindex = tabbedPane.indexOfComponent(alignPanel2);
- alignPanels.remove(alignPanel2);
- // Unnecessary
- // if (viewport == alignPanel2.av)
- // {
- // viewport = null;
- // }
- alignPanel2.closePanel();
- alignPanel2 = null;
+ int closedindex = tabbedPane.indexOfComponent(panelToClose);
+ alignPanels.remove(panelToClose);
+ panelToClose.closePanel();
+ panelToClose = null;
tabbedPane.removeTabAt(closedindex);
tabbedPane.validate();
viewport.getAlignment().moveSelectedSequencesByOne(sg,
viewport.getHiddenRepSequences(), up);
alignPanel.paintAlignment(true);
-
- final AlignViewportI peer = viewport.getCodingComplement();
- if (peer != null)
- {
- final SequenceGroup selectionGroup = peer.getSelectionGroup();
- if (selectionGroup != null)
- {
- peer.getAlignment().moveSelectedSequencesByOne(
- peer.getSelectionGroup(), peer.getHiddenRepSequences(), up);
- ((AlignViewport) peer).getAlignPanel().paintAlignment(true);
- }
- }
}
synchronized void slideSequences(boolean right, int size)
@Override
public void newView_actionPerformed(ActionEvent e)
{
- /*
- * Note if the current view has a protein/cdna complementary view
- */
- AlignViewportI linkedView = this.viewport.getCodingComplement();
-
- AlignmentPanel newPanel = newView(null, true);
-
- /*
- * If the original view has a protein/cdna linked view, make and link a new
- * view there also.
- */
- // TODO refactor the hell out of this - move to a controller, lose the casts
- // and direct member access, etc
- if (linkedView != null)
- {
- AlignFrame linkedAlignFrame = ((AlignViewport) linkedView)
- .getAlignPanel().alignFrame;
- AlignmentPanel newLinkedPanel = linkedAlignFrame.newView(null, true);
- newLinkedPanel.av.viewName = newPanel.av.viewName;
- newPanel.av.setCodingComplement(newLinkedPanel.av);
- final StructureSelectionManager ssm = StructureSelectionManager
- .getStructureSelectionManager(Desktop.instance);
- ssm.addCommandListener(newPanel.av);
- ssm.addCommandListener(newLinkedPanel.av);
-
- }
+ newView(null, true);
}
/**
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);
+ }
+ }
}
/**
*
* @param av
*/
- public boolean closeView(AlignmentViewport av)
+ public boolean closeView(AlignViewportI av)
{
if (viewport == av)
{
String linkedTitle = MessageManager.formatMessage(
"label.linked_view_title", dnaShortName, proteinShortName);
JInternalFrame splitFrame = new SplitFrame(cdnaFrame, proteinFrame);
- Desktop.addInternalFrame(splitFrame, linkedTitle,
- AlignFrame.DEFAULT_WIDTH,
- AlignFrame.DEFAULT_HEIGHT);
+ Desktop.addInternalFrame(splitFrame, linkedTitle, -1, -1);
/*
* Set the frames to listen for each other's edit and sort commands.
*/
package jalview.gui;
+import jalview.api.AlignmentViewPanel;
import jalview.bin.Cache;
import jalview.io.FileLoader;
import jalview.io.FormatAdapter;
+ jalview.bin.Cache.getProperty("VERSION") + "\n"
+ "Jalview Installation: "
+ jalview.bin.Cache.getDefault("INSTALLATION", "unknown")
- + "\n"
- + "Build Date: "
+ + "\n" + "Build Date: "
+ jalview.bin.Cache.getDefault("BUILD_DATE", "unknown") + "\n"
+ "Java version: " + System.getProperty("java.version") + "\n"
+ System.getProperty("os.arch") + " "
{
ssm.setAddTempFacAnnot(jalview.bin.Cache.getDefault(
Preferences.ADD_TEMPFACT_ANN, true));
- ssm.setProcessSecondaryStructure(jalview.bin.Cache.getDefault(Preferences.STRUCT_FROM_PDB, true));
- ssm.setSecStructServices(jalview.bin.Cache.getDefault(Preferences.USE_RNAVIEW,
- true));
+ ssm.setProcessSecondaryStructure(jalview.bin.Cache.getDefault(
+ Preferences.STRUCT_FROM_PDB, true));
+ ssm.setSecStructServices(jalview.bin.Cache.getDefault(
+ Preferences.USE_RNAVIEW, true));
}
else
{
public void run()
{
long instance = System.currentTimeMillis();
- Desktop.instance.setProgressBar(MessageManager.getString("status.refreshing_news"), instance);
+ Desktop.instance.setProgressBar(
+ MessageManager.getString("status.refreshing_news"),
+ instance);
jvnews.refreshNews();
Desktop.instance.setProgressBar(null, instance);
jvnews.showNews();
addInternalFrame(frame, title, true, w, h, true);
}
-
/**
* Add an internal frame to the Jalview desktop
*
if (shortv)
{
message.append("<h1><strong>Version: "
- + jalview.bin.Cache.getProperty("VERSION")
- + "</strong></h1>");
+ + jalview.bin.Cache.getProperty("VERSION") + "</strong></h1>");
message.append("<strong>Last Updated: <em>"
+ jalview.bin.Cache.getDefault("BUILD_DATE", "unknown")
+ "</em></strong>");
}
message.append("<br>Authors: "
+ jalview.bin.Cache
- .getDefault(
- "AUTHORFNAMES",
+ .getDefault("AUTHORFNAMES",
"The Jalview Authors (See AUTHORS file for current list)")
+ "<br><br>Development managed by The Barton Group, University of Dundee, Scotland, UK.<br>"
+ "<br><br>For help, see the FAQ at <a href=\"http://www.jalview.org/faq\">www.jalview.org/faq</a> and/or join the jalview-discuss@jalview.org mailing list"
public void run()
{
- setProgressBar(MessageManager.formatMessage("label.saving_jalview_project", new Object[]{choice.getName()}),
- choice.hashCode());
+ setProgressBar(MessageManager.formatMessage(
+ "label.saving_jalview_project", new Object[]
+ { choice.getName() }), choice.hashCode());
jalview.bin.Cache.setProperty("LAST_DIRECTORY",
choice.getParent());
// TODO catch and handle errors for savestate
Cache.log.error(
"Problems whilst trying to save to " + choice.getName(),
ex);
- JOptionPane.showMessageDialog(
- me,
- MessageManager.formatMessage("label.error_whilst_saving_current_state_to", new Object[]{ choice.getName()}),
- MessageManager.getString("label.couldnt_save_project"),
+ JOptionPane.showMessageDialog(me, MessageManager.formatMessage(
+ "label.error_whilst_saving_current_state_to",
+ new Object[]
+ { choice.getName() }), MessageManager
+ .getString("label.couldnt_save_project"),
JOptionPane.WARNING_MESSAGE);
}
setProgressBar(null, choice.hashCode());
final File selectedFile = chooser.getSelectedFile();
setProjectFile(selectedFile);
final String choice = selectedFile.getAbsolutePath();
- jalview.bin.Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
+ jalview.bin.Cache.setProperty("LAST_DIRECTORY",
+ selectedFile.getParent());
new Thread(new Runnable()
{
public void run()
{
setProgressBar(MessageManager.formatMessage(
"label.loading_jalview_project", new Object[]
- { choice }),
- choice.hashCode());
+ { choice }), choice.hashCode());
try
{
new Jalview2XML().loadJalviewAlign(choice);
{
Cache.log.error("Problems whilst loading project from "
+ choice, ex);
- JOptionPane.showMessageDialog(Desktop.desktop,
- MessageManager
+ JOptionPane.showMessageDialog(Desktop.desktop, MessageManager
.formatMessage(
"label.error_whilst_loading_project_from",
new Object[]
- { choice }),
- MessageManager.getString("label.couldnt_load_project"), JOptionPane.WARNING_MESSAGE);
+ { choice }), MessageManager
+ .getString("label.couldnt_load_project"),
+ JOptionPane.WARNING_MESSAGE);
}
setProgressBar(null, choice.hashCode());
}
return null;
}
+ /**
+ * Explode the views in the given frame into separate AlignFrame
+ *
+ * @param af
+ */
public void explodeViews(AlignFrame af)
{
int size = af.alignPanels.size();
}
+ /**
+ * Gather expanded views (separate AlignFrame's) with the same sequence set
+ * identifier back in to this frame as additional views, and close the
+ * expanded views. Note the expanded frames may themselves have multiple
+ * views. We take the lot.
+ *
+ * @param source
+ */
public void gatherViews(AlignFrame source)
{
source.viewport.gatherViewsHere = true;
jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
chooser.setFileView(new JalviewFileView());
- chooser.setDialogTitle(MessageManager.getString("label.open_saved_vamsas_session"));
+ chooser.setDialogTitle(MessageManager
+ .getString("label.open_saved_vamsas_session"));
chooser.setToolTipText(MessageManager
.getString("label.select_vamsas_session_opened_as_new_vamsas_session"));
return false;
}
- setProgressBar(MessageManager.formatMessage("status.importing_vamsas_session_from", new Object[]{file.getName()}),
- file.hashCode());
+ setProgressBar(MessageManager.formatMessage(
+ "status.importing_vamsas_session_from", new Object[]
+ { file.getName() }), file.hashCode());
try
{
v_client = new jalview.gui.VamsasApplication(this, file, null);
} catch (Exception ex)
{
- setProgressBar(MessageManager.formatMessage("status.importing_vamsas_session_from", new Object[]{file.getName()}),
- file.hashCode());
+ setProgressBar(MessageManager.formatMessage(
+ "status.importing_vamsas_session_from", new Object[]
+ { file.getName() }), file.hashCode());
jalview.bin.Cache.log.error(
"New vamsas session from existing session file failed:", ex);
return false;
}
setupVamsasConnectedGui();
v_client.initial_update(); // TODO: thread ?
- setProgressBar(MessageManager.formatMessage("status.importing_vamsas_session_from", new Object[]{file.getName()}),
- file.hashCode());
+ setProgressBar(MessageManager.formatMessage(
+ "status.importing_vamsas_session_from", new Object[]
+ { file.getName() }), file.hashCode());
return v_client.inSession();
}
{
if (v_client != null)
{
- throw new Error(MessageManager.getString("error.try_join_vamsas_session_another"));
+ throw new Error(
+ MessageManager
+ .getString("error.try_join_vamsas_session_another"));
}
if (mysesid == null)
{
- throw new Error(MessageManager.getString("error.invalid_vamsas_session_id"));
+ throw new Error(
+ MessageManager.getString("error.invalid_vamsas_session_id"));
}
v_client = new VamsasApplication(this, mysesid);
setupVamsasConnectedGui();
{ "Vamsas Document" }, "Vamsas Document");
chooser.setFileView(new JalviewFileView());
- chooser.setDialogTitle(MessageManager.getString("label.save_vamsas_document_archive"));
+ chooser.setDialogTitle(MessageManager
+ .getString("label.save_vamsas_document_archive"));
int value = chooser.showSaveDialog(this);
if (value == JalviewFileChooser.APPROVE_OPTION)
{
java.io.File choice = chooser.getSelectedFile();
- JPanel progpanel = addProgressPanel(MessageManager.formatMessage("label.saving_vamsas_doc", new Object[]{choice.getName()}));
+ JPanel progpanel = addProgressPanel(MessageManager.formatMessage(
+ "label.saving_vamsas_doc", new Object[]
+ { choice.getName() }));
jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice.getParent());
String warnmsg = null;
String warnttl = null;
}
if (b)
{
- vamUpdate = this.addProgressPanel(MessageManager.getString("label.updating_vamsas_session"));
+ vamUpdate = this.addProgressPanel(MessageManager
+ .getString("label.updating_vamsas_session"));
}
vamsasStart.setVisible(!b);
vamsasStop.setVisible(!b);
* Also check for a split frame containing an AlignFrame
*/
SplitFrame sf = (SplitFrame) frames[i];
- if (sf.getTopComponent() instanceof AlignFrame)
+ if (sf.getTopFrame() instanceof AlignFrame)
{
- avp.add((AlignFrame) sf.getTopComponent());
+ avp.add((AlignFrame) sf.getTopFrame());
}
- if (sf.getBottomComponent() instanceof AlignFrame)
+ if (sf.getBottomFrame() instanceof AlignFrame)
{
- avp.add((AlignFrame) sf.getBottomComponent());
+ avp.add((AlignFrame) sf.getBottomFrame());
}
}
}
// use reflection to avoid creating compilation dependency.
if (!jalview.bin.Cache.groovyJarsPresent())
{
- throw new Error(MessageManager.getString("error.implementation_error_cannot_create_groovyshell"));
+ throw new Error(
+ MessageManager
+ .getString("error.implementation_error_cannot_create_groovyshell"));
}
try
{
} catch (Exception ex)
{
jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
- JOptionPane
- .showInternalMessageDialog(
- Desktop.desktop,
+ JOptionPane.showInternalMessageDialog(Desktop.desktop,
- MessageManager.getString("label.couldnt_create_groovy_shell"),
- MessageManager.getString("label.groovy_support_failed"),
- JOptionPane.ERROR_MESSAGE);
+ MessageManager.getString("label.couldnt_create_groovy_shell"),
+ MessageManager.getString("label.groovy_support_failed"),
+ JOptionPane.ERROR_MESSAGE);
}
}
{
if (progressBarHandlers == null || !progressBars.contains(new Long(id)))
{
- throw new Error(MessageManager.getString("error.call_setprogressbar_before_registering_handler"));
+ throw new Error(
+ MessageManager
+ .getString("error.call_setprogressbar_before_registering_handler"));
}
progressBarHandlers.put(new Long(id), handler);
final JPanel progressPanel = progressBars.get(new Long(id));
public void actionPerformed(ActionEvent e)
{
handler.cancelActivity(id);
- us.setProgressBar(MessageManager.formatMessage("label.cancelled_params", new Object[]{((JLabel) progressPanel.getComponent(0)).getText()}), id);
+ us.setProgressBar(MessageManager.formatMessage(
+ "label.cancelled_params", new Object[]
+ { ((JLabel) progressPanel.getComponent(0)).getText() }),
+ id);
}
});
progressPanel.add(cancel, BorderLayout.EAST);
{
if (progress != null)
{
- progress.setProgressBar(MessageManager.formatMessage("status.opening_params", new Object[]{url}), this.hashCode());
+ progress.setProgressBar(MessageManager.formatMessage(
+ "status.opening_params", new Object[]
+ { url }), this.hashCode());
}
jalview.util.BrowserLauncher.openURL(url);
} catch (Exception ex)
{
- JOptionPane
- .showInternalMessageDialog(
- Desktop.desktop,
- MessageManager.getString("label.web_browser_not_found_unix"),
- MessageManager.getString("label.web_browser_not_found"),
- JOptionPane.WARNING_MESSAGE);
+ JOptionPane.showInternalMessageDialog(Desktop.desktop,
+ MessageManager
+ .getString("label.web_browser_not_found_unix"),
+ MessageManager.getString("label.web_browser_not_found"),
+ JOptionPane.WARNING_MESSAGE);
ex.printStackTrace();
}
dialogPause = false;
block.release();
}
+
@Override
protected void snapShotWindow_actionPerformed(ActionEvent e)
{
"View of Desktop", getWidth(), getHeight(), of = new File(
"Jalview_snapshot" + System.currentTimeMillis()
+ ".eps"), "View of desktop");
- try {
+ try
+ {
paintAll(im.getGraphics());
im.writeImage();
} catch (Exception q)
{
- Cache.log.error("Couldn't write snapshot to "+of.getAbsolutePath(),q);
+ Cache.log.error("Couldn't write snapshot to " + of.getAbsolutePath(),
+ q);
+ return;
+ }
+ Cache.log.info("Successfully written snapshot to file "
+ + of.getAbsolutePath());
+ }
+
+ /**
+ * Explode the views in the given frame into separate AlignFrame
+ *
+ * @param sf
+ */
+ public void explodeViews(SplitFrame sf)
+ {
+ AlignFrame oldTopFrame = (AlignFrame) sf.getTopFrame();
+ AlignFrame oldBottomFrame = (AlignFrame) sf.getBottomFrame();
+ List<? extends AlignmentViewPanel> topPanels = oldTopFrame
+ .getAlignPanels();
+ List<? extends AlignmentViewPanel> bottomPanels = oldBottomFrame
+ .getAlignPanels();
+ int viewCount = topPanels.size();
+ if (viewCount < 2)
+ {
return;
}
- Cache.log.info("Successfully written snapshot to file "+of.getAbsolutePath());
+
+ /*
+ * Processing in reverse order works, forwards order leaves the first panels
+ * not visible. I don't know why!
+ */
+ for (int i = viewCount - 1; i >= 0; i--)
+ {
+ /*
+ * Make new top and bottom frames. These take over the respective
+ * AlignmentPanel objects, including their AlignmentViewports, so the
+ * cdna/protein relationships between the viewports is carried over to the
+ * new split frames.
+ */
+ AlignFrame newTopFrame = new AlignFrame(
+ (AlignmentPanel) topPanels.get(i));
+ newTopFrame.setVisible(true);
+ AlignFrame newBottomFrame = new AlignFrame(
+ (AlignmentPanel) bottomPanels.get(i));
+ newBottomFrame.setVisible(true);
+ JInternalFrame splitFrame = new SplitFrame(newTopFrame,
+ newBottomFrame);
+ Desktop.addInternalFrame(splitFrame, sf.getTitle(), -1, -1);
+
+ // if (ap.av.explodedPosition != null
+ // && !ap.av.explodedPosition.equals(af.getBounds()))
+ // {
+ // newaf.setBounds(ap.av.explodedPosition);
+ // }
+ //
+ // ap.av.gatherViewsHere = false;
+ }
+
+ /*
+ * Clear references to the panels (now relocated in the new SplitFrames)
+ * before closing the old SplitFrame.
+ */
+ topPanels.clear();
+ bottomPanels.clear();
+ sf.close();
+ }
+
+ /**
+ * Gather expanded split frames, sharing the same pairs of sequence set ids,
+ * back into the given SplitFrame as additional views. Note that the gathered
+ * frames may themselves have multiple views.
+ *
+ * @param source
+ */
+ public void gatherViews(SplitFrame source)
+ {
+ // source.viewport.gatherViewsHere = true;
+ // source.viewport.explodedPosition = source.getBounds();
+ AlignFrame myTopFrame = (AlignFrame) source.getTopFrame();
+ AlignFrame myBottomFrame = (AlignFrame) source.getBottomFrame();
+ String topViewId = myTopFrame.viewport.getSequenceSetId();
+ String bottomViewId = myBottomFrame.viewport.getSequenceSetId();
+
+ JInternalFrame[] frames = desktop.getAllFrames();
+ for (JInternalFrame frame : frames)
+ {
+ if (frame instanceof SplitFrame && frame != source)
+ {
+ SplitFrame sf = (SplitFrame) frame;
+ AlignFrame topFrame = (AlignFrame) sf.getTopFrame();
+ AlignFrame bottomFrame = (AlignFrame) sf.getBottomFrame();
+ boolean gatherThis = false;
+ for (int a = 0; a < topFrame.alignPanels.size(); a++)
+ {
+ AlignmentPanel topPanel = topFrame.alignPanels.get(a);
+ AlignmentPanel bottomPanel = bottomFrame.alignPanels.get(a);
+ if (topViewId.equals(topPanel.av.getSequenceSetId())
+ && bottomViewId.equals(bottomPanel.av.getSequenceSetId()))
+ {
+ gatherThis = true;
+ topPanel.av.gatherViewsHere = false;
+ bottomPanel.av.gatherViewsHere = false;
+ // topPanel.av.explodedPosition = af.getBounds();
+ myTopFrame.addAlignmentPanel(topPanel, false);
+ myBottomFrame.addAlignmentPanel(bottomPanel, false);
+ }
+ }
+
+ if (gatherThis)
+ {
+ topFrame.getAlignPanels().clear();
+ bottomFrame.getAlignPanels().clear();
+ sf.close();
+ }
+ }
+ }
+
+ /*
+ * The dust settles...give focus to the tab we did this from.
+ */
+ myTopFrame.setDisplayedView(myTopFrame.alignPanel);
+
}
}
package jalview.gui;
+import jalview.jbgui.GAlignFrame;
import jalview.jbgui.GSplitFrame;
+import jalview.structure.StructureSelectionManager;
import java.awt.Component;
import java.awt.MouseInfo;
import java.awt.Point;
import java.awt.Rectangle;
+import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
+import java.beans.PropertyVetoException;
import java.util.Map.Entry;
import javax.swing.AbstractAction;
+import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JMenuItem;
import javax.swing.KeyStroke;
{
private static final long serialVersionUID = 1L;
- public SplitFrame(JComponent top, JComponent bottom)
+ public SplitFrame(GAlignFrame top, GAlignFrame bottom)
{
super(top, bottom);
init();
addKeyListener();
addKeyBindings();
-
}
/**
@Override
public void internalFrameClosed(InternalFrameEvent evt)
{
- if (getTopComponent() instanceof AlignFrame)
+ if (getTopFrame() instanceof AlignFrame)
{
- ((AlignFrame) getTopComponent())
+ ((AlignFrame) getTopFrame())
.closeMenuItem_actionPerformed(true);
}
- if (getBottomComponent() instanceof AlignFrame)
+ if (getBottomFrame() instanceof AlignFrame)
{
- ((AlignFrame) getBottomComponent())
+ ((AlignFrame) getBottomFrame())
.closeMenuItem_actionPerformed(true);
}
};
*/
protected void addKeyListener()
{
- // TODO Key Bindings rather than KeyListener are recommended for Swing
addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e)
{
- Component c = getComponentAtMouse();
- if (c != null)
+ AlignFrame af = (AlignFrame) getFrameAtMouse();
+
+ /*
+ * Intercept and override any keys here if wanted.
+ */
+ if (!overrideKey(e, af))
{
- for (KeyListener kl : c.getKeyListeners())
+ if (af != null)
{
- kl.keyPressed(e);
+ for (KeyListener kl : af.getKeyListeners())
+ {
+ kl.keyPressed(e);
+ }
}
}
}
@Override
public void keyReleased(KeyEvent e)
{
- Component c = getComponentAtMouse();
+ Component c = getFrameAtMouse();
if (c != null)
{
for (KeyListener kl : c.getKeyListeners())
}
/**
+ * Returns true if the key event is overriden and actioned (or ignored) here,
+ * else returns false, indicating it should be delegated to the AlignFrame's
+ * usual handler.
+ * <p>
+ * We can't handle Cmd-Key combinations here, instead this is done by
+ * overriding key bindings.
+ *
+ * @see addKeyOverrides
+ * @param e
+ * @param af
+ * @return
+ */
+ protected boolean overrideKey(KeyEvent e, AlignFrame af)
+ {
+ boolean actioned = false;
+ int keyCode = e.getKeyCode();
+ switch (keyCode)
+ {
+ case KeyEvent.VK_DOWN:
+ if (e.isAltDown() || !af.viewport.cursorMode)
+ {
+ /*
+ * Key down (or Alt-key-down in cursor mode) - move selected sequences
+ */
+ ((AlignFrame) getTopFrame()).moveSelectedSequences(false);
+ ((AlignFrame) getBottomFrame()).moveSelectedSequences(false);
+ actioned = true;
+ e.consume();
+ }
+ break;
+ case KeyEvent.VK_UP:
+ if (e.isAltDown() || !af.viewport.cursorMode)
+ {
+ /*
+ * Key up (or Alt-key-up in cursor mode) - move selected sequences
+ */
+ ((AlignFrame) getTopFrame()).moveSelectedSequences(true);
+ ((AlignFrame) getBottomFrame()).moveSelectedSequences(true);
+ actioned = true;
+ e.consume();
+ }
+ default:
+ }
+ return actioned;
+ }
+
+ /**
* Returns the split pane component the mouse is in, or null if neither.
*
* @return
*/
- protected Component getComponentAtMouse()
+ protected GAlignFrame getFrameAtMouse()
{
Point loc = MouseInfo.getPointerInfo().getLocation();
- if (isIn(loc, getTopComponent())) {
- return getTopComponent();
+ if (isIn(loc, getTopFrame()))
+ {
+ return getTopFrame();
}
- else if (isIn(loc, getBottomComponent()))
+ else if (isIn(loc, getBottomFrame()))
{
- return getBottomComponent();
+ return getBottomFrame();
}
return null;
}
}
/**
- * Set key bindings (recommended for Swing over key accelerators). For now,
- * delegate to the corresponding key accelerator for the AlignFrame that the
- * mouse is in. Hopefully can be simplified in future if AlignFrame is changed
- * to use key bindings rather than accelerators.
+ * Set key bindings (recommended for Swing over key accelerators).
*/
private void addKeyBindings()
{
- if (getTopComponent() instanceof AlignFrame)
+ overrideDelegatedKeyBindings();
+
+ overrideImplementedKeyBindings();
+ }
+
+ /**
+ * Override key bindings with alternative action methods implemented in this
+ * class.
+ */
+ protected void overrideImplementedKeyBindings()
+ {
+ overrideNewView();
+ overrideCloseView();
+ overrideExpandViews();
+ overrideGatherViews();
+ }
+
+ /**
+ * Replace Cmd-W close view action with our version.
+ */
+ protected void overrideCloseView()
+ {
+ AbstractAction action;
+ /*
+ * Ctrl-W / Cmd-W - close view or window
+ */
+ KeyStroke key_cmdW = KeyStroke.getKeyStroke(KeyEvent.VK_W, Toolkit
+ .getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ action = new AbstractAction()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ closeView_actionPerformed();
+ }
+ };
+ overrideKeyBinding(key_cmdW, action);
+ }
+
+ /**
+ * Replace Cmd-T new view action with our version.
+ */
+ protected void overrideNewView()
+ {
+ /*
+ * Ctrl-T / Cmd-T open new view
+ */
+ KeyStroke key_cmdT = KeyStroke.getKeyStroke(KeyEvent.VK_T, Toolkit
+ .getDefaultToolkit().getMenuShortcutKeyMask(), false);
+ AbstractAction action = new AbstractAction()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ newView_actionPerformed();
+ }
+ };
+ overrideKeyBinding(key_cmdT, action);
+ }
+
+ /**
+ * For now, delegates key events to the corresponding key accelerator for the
+ * AlignFrame that the mouse is in. Hopefully can be simplified in future if
+ * AlignFrame is changed to use key bindings rather than accelerators.
+ */
+ protected void overrideDelegatedKeyBindings()
+ {
+ if (getTopFrame() instanceof AlignFrame)
{
- for (Entry<KeyStroke, JMenuItem> acc : ((AlignFrame) getTopComponent())
+ /*
+ * Get all accelerator keys in the top frame (the bottom should be
+ * identical) and override each one.
+ */
+ for (Entry<KeyStroke, JMenuItem> acc : ((AlignFrame) getTopFrame())
.getAccelerators().entrySet())
{
+ overrideKeyBinding(acc);
+ }
+ }
+ }
- final KeyStroke ks = acc.getKey();
- this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ks, ks);
- this.getActionMap().put(ks, new AbstractAction()
+ /**
+ * Overrides an AlignFrame key accelerator with our version which delegates to
+ * the action listener in whichever frame has the mouse (and does nothing if
+ * neither has).
+ *
+ * @param acc
+ */
+ private void overrideKeyBinding(Entry<KeyStroke, JMenuItem> acc)
+ {
+ final KeyStroke ks = acc.getKey();
+ InputMap inputMap = this.getInputMap(JComponent.WHEN_FOCUSED);
+ inputMap.put(ks, ks);
+ this.getActionMap().put(ks, new AbstractAction()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ Component c = getFrameAtMouse();
+ if (c != null && c instanceof AlignFrame)
{
- @Override
- public void actionPerformed(ActionEvent e)
+ for (ActionListener a : ((AlignFrame) c).getAccelerators()
+ .get(ks).getActionListeners())
{
- Component c = getComponentAtMouse();
- if (c instanceof AlignFrame)
- {
- for (ActionListener a : ((AlignFrame) c).getAccelerators()
- .get(ks).getActionListeners())
- {
-
- a.actionPerformed(null);
- }
- }
+ a.actionPerformed(null);
}
- });
+ }
}
- /*
- * Disable unwanted here
- */
- // X expand views - wrecks the split pane view
- KeyStroke key_X = KeyStroke.getKeyStroke(KeyEvent.VK_X, 0, false);
- disableAccelerator(key_X);
+ });
+ }
+
+ /**
+ * Replace an accelerator key's action with the specified action.
+ *
+ * @param ks
+ */
+ protected void overrideKeyBinding(KeyStroke ks, AbstractAction action)
+ {
+ this.getActionMap().put(ks, action);
+ overrideMenuItem(ks, action);
+ }
+
+ /**
+ * Create and link new views (with matching names) in both panes.
+ * <p>
+ * Note this is _not_ multiple tabs, each hosting a split pane view, rather it
+ * is a single split pane with each split holding multiple tabs which are
+ * linked in pairs.
+ */
+ protected void newView_actionPerformed()
+ {
+ System.out.println("newView " + this.hashCode());
+ AlignFrame topFrame = (AlignFrame) getTopFrame();
+ AlignFrame bottomFrame = (AlignFrame) getBottomFrame();
+
+ AlignmentPanel newTopPanel = topFrame.newView(null, true);
+ AlignmentPanel newBottomPanel = bottomFrame.newView(null, true);
+
+ /*
+ * This currently (for the first new view only) leaves the top pane on tab 0
+ * but the bottom on tab 1. This results from 'setInitialTabVisible' echoing
+ * from the bottom back to the first frame. Next line is a fudge to work
+ * around this. TODO find a better way.
+ */
+ if (topFrame.getTabIndex() != bottomFrame.getTabIndex())
+ {
+ topFrame.setDisplayedView(newTopPanel);
+ }
+
+ newBottomPanel.av.viewName = newTopPanel.av.viewName;
+ newTopPanel.av.setCodingComplement(newBottomPanel.av);
+
+ final StructureSelectionManager ssm = StructureSelectionManager
+ .getStructureSelectionManager(Desktop.instance);
+ ssm.addCommandListener(newTopPanel.av);
+ ssm.addCommandListener(newBottomPanel.av);
+ }
+
+ /**
+ * Close the currently selected view in both panes. If there is only one view,
+ * close this split frame.
+ */
+ protected void closeView_actionPerformed()
+ {
+ int viewCount = ((AlignFrame) getTopFrame()).getAlignPanels().size();
+ if (viewCount < 2)
+ {
+ close();
+ return;
+ }
+
+ AlignmentPanel topPanel = ((AlignFrame) getTopFrame()).alignPanel;
+ AlignmentPanel bottomPanel = ((AlignFrame) getBottomFrame()).alignPanel;
+
+ ((AlignFrame) getTopFrame()).closeView(topPanel);
+ ((AlignFrame) getBottomFrame()).closeView(bottomPanel);
+
+ }
+
+ /**
+ * Close child frames and this split frame.
+ */
+ public void close()
+ {
+ ((AlignFrame) getTopFrame()).closeMenuItem_actionPerformed(true);
+ ((AlignFrame) getBottomFrame()).closeMenuItem_actionPerformed(true);
+ try
+ {
+ this.setClosed(true);
+ } catch (PropertyVetoException e)
+ {
+ // ignore
}
}
/**
- * Ugly hack for Proof of Concept that disables the key binding in this frame
- * _and_ disables the bound menu item _and_ removes the key accelerator in the
- * child frames.
+ * Replace AlignFrame 'expand views' action with SplitFrame version.
+ */
+ protected void overrideExpandViews()
+ {
+ KeyStroke key_X = KeyStroke.getKeyStroke(KeyEvent.VK_X, 0, false);
+ AbstractAction action = new AbstractAction()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ expandViews_actionPerformed();
+ }
+ };
+ overrideMenuItem(key_X, action);
+ }
+
+ /**
+ * Replace AlignFrame 'gather views' action with SplitFrame version.
+ */
+ protected void overrideGatherViews()
+ {
+ KeyStroke key_G = KeyStroke.getKeyStroke(KeyEvent.VK_G, 0, false);
+ AbstractAction action = new AbstractAction()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ gatherViews_actionPerformed();
+ }
+ };
+ overrideMenuItem(key_G, action);
+ }
+
+ /**
+ * Override the menu action associated with the keystroke in the child frames,
+ * replacing it with the given action.
*
- * @param key
+ * @param ks
+ * @param action
*/
- protected void disableAccelerator(KeyStroke key)
+ private void overrideMenuItem(KeyStroke ks, AbstractAction action)
{
- disableAccelerator(key, getTopComponent());
- disableAccelerator(key, getBottomComponent());
- this.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).remove(key);
+ overrideMenuItem(ks, action, getTopFrame());
+ overrideMenuItem(ks, action, getBottomFrame());
}
/**
- * Disable the menu item for which this key is the accelerator, also removes
- * its action listeners to prevent key accelerator working.
+ * Override the menu action associated with the keystroke in one child frame,
+ * replacing it with the given action. Mwahahahaha.
*
* @param key
+ * @param action
* @param comp
*/
- private void disableAccelerator(KeyStroke key, JComponent comp)
+ private void overrideMenuItem(KeyStroke key, final AbstractAction action,
+ JComponent comp)
{
- // HACKED ONLY FOR PROOF OF CONCEPT
- // Proper solution might involve explicit 'configure menu' method on
- // AlignFrame, or
- // changing key listeners to key bindings in AlignFrame, or both
if (comp instanceof AlignFrame)
{
JMenuItem mi = ((AlignFrame) comp).getAccelerators().get(key);
if (mi != null)
{
- mi.setEnabled(false);
for (ActionListener al : mi.getActionListeners())
{
mi.removeActionListener(al);
}
+ mi.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ action.actionPerformed(e);
+ }
+ });
}
}
}
+
+ /**
+ * Expand any multiple views (which are always in pairs) into separate split
+ * frames.
+ */
+ protected void expandViews_actionPerformed()
+ {
+ Desktop.instance.explodeViews(this);
+ }
+
+ /**
+ * Gather any other SplitFrame views of this alignment back in as multiple
+ * (pairs of) views in this SplitFrame.
+ */
+ protected void gatherViews_actionPerformed()
+ {
+ Desktop.instance.gatherViews(this);
+ }
}
{
return this.accelerators;
}
+
+ /**
+ * Returns the selected index of the tabbed pane, or -1 if none selected
+ * (including the case where the tabbed pane has not been made visible).
+ *
+ * @return
+ */
+ public int getTabIndex()
+ {
+ return tabbedPane.getSelectedIndex();
+ }
}
package jalview.jbgui;
-import javax.swing.JComponent;
import javax.swing.JInternalFrame;
import javax.swing.JSplitPane;
{
private static final long serialVersionUID = 1L;
- private JComponent topComponent;
+ private GAlignFrame topFrame;
- private JComponent bottomComponent;
+ private GAlignFrame bottomFrame;
/**
* Constructor
* @param top
* @param bottom
*/
- public GSplitFrame(JComponent top, JComponent bottom)
+ public GSplitFrame(GAlignFrame top, GAlignFrame bottom)
{
- this.topComponent = top;
- this.bottomComponent = bottom;
+ this.topFrame = top;
+ this.bottomFrame = bottom;
JSplitPane splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, top,
bottom);
splitPane.setVisible(true);
splitPane.setDividerSize(0);
}
- public JComponent getTopComponent()
+ public GAlignFrame getTopFrame()
{
- return topComponent;
+ return topFrame;
}
- public JComponent getBottomComponent()
+ public GAlignFrame getBottomFrame()
{
- return bottomComponent;
+ return bottomFrame;
}
}
--- /dev/null
+package jalview.structure;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+import jalview.datamodel.AlignedCodonFrame;
+
+import java.util.HashSet;
+import java.util.Set;
+
+import org.junit.Before;
+import org.junit.Test;
+
+public class StructureSelectionManagerTest
+{
+ private StructureSelectionManager ssm;
+
+ @Before
+ public void setUp()
+ {
+ ssm = new StructureSelectionManager();
+ }
+
+ @Test
+ public void testAddMapping()
+ {
+ AlignedCodonFrame acf1 = new AlignedCodonFrame();
+ AlignedCodonFrame acf2 = new AlignedCodonFrame();
+
+ /*
+ * One mapping only.
+ */
+ ssm.addMapping(acf1);
+ assertEquals(1, ssm.seqmappings.size());
+ assertTrue(ssm.seqmappings.contains(acf1));
+ assertEquals(1, ssm.seqMappingRefCounts.size());
+ assertEquals(1, ssm.seqMappingRefCounts.get(acf1).intValue());
+
+ /*
+ * A second mapping.
+ */
+ ssm.addMapping(acf2);
+ assertEquals(2, ssm.seqmappings.size());
+ assertTrue(ssm.seqmappings.contains(acf1));
+ assertTrue(ssm.seqmappings.contains(acf2));
+ assertEquals(2, ssm.seqMappingRefCounts.size());
+ assertEquals(1, ssm.seqMappingRefCounts.get(acf1).intValue());
+ assertEquals(1, ssm.seqMappingRefCounts.get(acf2).intValue());
+
+ /*
+ * A second reference to the first mapping.
+ */
+ ssm.addMapping(acf1);
+ assertEquals(2, ssm.seqmappings.size());
+ assertTrue(ssm.seqmappings.contains(acf1));
+ assertTrue(ssm.seqmappings.contains(acf2));
+ assertEquals(2, ssm.seqMappingRefCounts.size());
+ assertEquals(2, ssm.seqMappingRefCounts.get(acf1).intValue());
+ assertEquals(1, ssm.seqMappingRefCounts.get(acf2).intValue());
+ }
+
+ @Test
+ public void testAddMappings()
+ {
+ AlignedCodonFrame acf1 = new AlignedCodonFrame();
+ AlignedCodonFrame acf2 = new AlignedCodonFrame();
+ AlignedCodonFrame acf3 = new AlignedCodonFrame();
+
+ Set<AlignedCodonFrame> set1 = new HashSet<AlignedCodonFrame>();
+ set1.add(acf1);
+ set1.add(acf2);
+ Set<AlignedCodonFrame> set2 = new HashSet<AlignedCodonFrame>();
+ set2.add(acf2);
+ set2.add(acf3);
+
+ /*
+ * Adding both sets adds acf2 twice and acf1 and acf3 once each.
+ */
+ ssm.addMappings(set1);
+ ssm.addMappings(set2);
+
+ assertEquals(3, ssm.seqmappings.size());
+ assertTrue(ssm.seqmappings.contains(acf1));
+ assertTrue(ssm.seqmappings.contains(acf2));
+ assertTrue(ssm.seqmappings.contains(acf3));
+ assertEquals(3, ssm.seqMappingRefCounts.size());
+ assertEquals(1, ssm.seqMappingRefCounts.get(acf1).intValue());
+ assertEquals(2, ssm.seqMappingRefCounts.get(acf2).intValue());
+ assertEquals(1, ssm.seqMappingRefCounts.get(acf3).intValue());
+ }
+
+ @Test
+ public void testRemoveMapping()
+ {
+ AlignedCodonFrame acf1 = new AlignedCodonFrame();
+ AlignedCodonFrame acf2 = new AlignedCodonFrame();
+ ssm.addMapping(acf1);
+
+ /*
+ * Add one and remove it.
+ */
+ ssm.removeMapping(acf1);
+ ssm.removeMapping(acf2);
+ assertEquals(0, ssm.seqmappings.size());
+ assertEquals(0, ssm.seqMappingRefCounts.size());
+
+ /*
+ * Add one twice and remove it once.
+ */
+ ssm.addMapping(acf1);
+ ssm.addMapping(acf2);
+ ssm.addMapping(acf1);
+ ssm.removeMapping(acf1);
+ assertEquals(2, ssm.seqmappings.size());
+ assertTrue(ssm.seqmappings.contains(acf1));
+ assertTrue(ssm.seqmappings.contains(acf2));
+ assertEquals(2, ssm.seqMappingRefCounts.size());
+ assertEquals(1, ssm.seqMappingRefCounts.get(acf1).intValue());
+ assertEquals(1, ssm.seqMappingRefCounts.get(acf2).intValue());
+
+ /*
+ * Remove both once more to clear the set.
+ */
+ ssm.removeMapping(acf1);
+ ssm.removeMapping(acf2);
+ assertEquals(0, ssm.seqmappings.size());
+ assertEquals(0, ssm.seqMappingRefCounts.size());
+ }
+
+ @Test
+ public void testRemoveMappings()
+ {
+ AlignedCodonFrame acf1 = new AlignedCodonFrame();
+ AlignedCodonFrame acf2 = new AlignedCodonFrame();
+ AlignedCodonFrame acf3 = new AlignedCodonFrame();
+
+ /*
+ * Initial ref counts are 3/2/1:
+ */
+ ssm.addMapping(acf1);
+ ssm.addMapping(acf1);
+ ssm.addMapping(acf1);
+ ssm.addMapping(acf2);
+ ssm.addMapping(acf2);
+ ssm.addMapping(acf3);
+
+ Set<AlignedCodonFrame> set1 = new HashSet<AlignedCodonFrame>();
+ set1.add(acf1);
+ set1.add(acf2);
+ Set<AlignedCodonFrame> set2 = new HashSet<AlignedCodonFrame>();
+ set2.add(acf2);
+ set2.add(acf3);
+
+ /*
+ * Remove one ref each to acf1, acf2, counts are now 2/1/1:
+ */
+ ssm.removeMappings(set1);
+ assertEquals(3, ssm.seqmappings.size());
+ assertTrue(ssm.seqmappings.contains(acf1));
+ assertTrue(ssm.seqmappings.contains(acf2));
+ assertTrue(ssm.seqmappings.contains(acf3));
+ assertEquals(3, ssm.seqMappingRefCounts.size());
+ assertEquals(2, ssm.seqMappingRefCounts.get(acf1).intValue());
+ assertEquals(1, ssm.seqMappingRefCounts.get(acf2).intValue());
+ assertEquals(1, ssm.seqMappingRefCounts.get(acf3).intValue());
+
+ /*
+ * Remove one ref each to acf2, acf3 - they are removed
+ */
+ ssm.removeMappings(set2);
+ assertEquals(1, ssm.seqmappings.size());
+ assertTrue(ssm.seqmappings.contains(acf1));
+ assertEquals(1, ssm.seqMappingRefCounts.size());
+ assertEquals(2, ssm.seqMappingRefCounts.get(acf1).intValue());
+ }
+}