import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
+import java.awt.Window;
import java.awt.datatransfer.Clipboard;
import java.awt.datatransfer.ClipboardOwner;
import java.awt.datatransfer.DataFlavor;
import java.awt.event.ActionListener;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
+import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
-import java.beans.PropertyVetoException;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileOutputStream;
-import java.lang.reflect.Constructor;
import java.net.URL;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.concurrent.Executors;
import java.util.concurrent.Semaphore;
+import javax.swing.AbstractAction;
import javax.swing.DefaultDesktopManager;
import javax.swing.DesktopManager;
import javax.swing.JButton;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JProgressBar;
+import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.HyperlinkEvent.EventType;
+import javax.swing.event.InternalFrameAdapter;
+import javax.swing.event.InternalFrameEvent;
import javax.swing.event.MenuEvent;
import javax.swing.event.MenuListener;
static final int yOffset = 30;
- private static AlignFrame currentAlignFrame;
-
public static jalview.ws.jws1.Discoverer discoverer;
public static Object[] jalviewClipboard;
*/
instance = this;
doVamsasClientCheck();
- doGroovyCheck();
+
+ groovyShell = new JMenuItem();
+ groovyShell.setText(MessageManager.getString("label.groovy_console"));
+ groovyShell.addActionListener(new ActionListener()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ groovyShell_actionPerformed();
+ }
+ });
+ toolsMenu.add(groovyShell);
+ groovyShell.setVisible(true);
+
doConfigureStructurePrefs();
setTitle("Jalview " + jalview.bin.Cache.getProperty("VERSION"));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
@Override
public void mousePressed(MouseEvent evt)
{
- if (SwingUtilities.isRightMouseButton(evt))
+ if (evt.isPopupTrigger()) // Mac
+ {
+ showPasteMenu(evt.getX(), evt.getY());
+ }
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent evt)
+ {
+ if (evt.isPopupTrigger()) // Windows
{
showPasteMenu(evt.getX(), evt.getY());
}
* ((openFrameCount - 1) % 10) + yOffset);
}
+ /*
+ * add an entry for the new frame in the Window menu
+ * (and remove it when the frame is closed)
+ */
final JMenuItem menuItem = new JMenuItem(title);
- frame.addInternalFrameListener(new javax.swing.event.InternalFrameAdapter()
+ frame.addInternalFrameListener(new InternalFrameAdapter()
{
@Override
- public void internalFrameActivated(
- javax.swing.event.InternalFrameEvent evt)
+ public void internalFrameActivated(InternalFrameEvent evt)
{
JInternalFrame itf = desktop.getSelectedFrame();
if (itf != null)
{
itf.requestFocus();
}
-
}
@Override
- public void internalFrameClosed(
- javax.swing.event.InternalFrameEvent evt)
+ public void internalFrameClosed(InternalFrameEvent evt)
{
PaintRefresher.RemoveComponent(frame);
- openFrameCount--;
+
+ /*
+ * defensive check to prevent frames being
+ * added half off the window
+ */
+ if (openFrameCount > 0)
+ {
+ openFrameCount--;
+ }
+
+ /*
+ * ensure no reference to alignFrame retained by menu item listener
+ */
+ if (menuItem.getActionListeners().length > 0)
+ {
+ menuItem.removeActionListener(menuItem.getActionListeners()[0]);
+ }
windowMenu.remove(menuItem);
JInternalFrame itf = desktop.getSelectedFrame();
if (itf != null)
{
itf.requestFocus();
+ if (itf instanceof AlignFrame)
+ {
+ Jalview.setCurrentAlignFrame((AlignFrame) itf);
+ }
}
System.gc();
};
}
}
});
- menuItem.addMouseListener(new MouseListener()
- {
-
- @Override
- public void mouseReleased(MouseEvent e)
- {
- }
-
- @Override
- public void mousePressed(MouseEvent e)
- {
- }
-
- @Override
- public void mouseExited(MouseEvent e)
- {
- try
- {
- frame.setSelected(false);
- } catch (PropertyVetoException e1)
- {
- }
- }
-
- @Override
- public void mouseEntered(MouseEvent e)
- {
- try
- {
- frame.setSelected(true);
- } catch (PropertyVetoException e1)
- {
- }
- }
-
- @Override
- public void mouseClicked(MouseEvent e)
- {
-
- }
- });
windowMenu.add(menuItem);
public void drop(DropTargetDropEvent evt)
{
boolean success = true;
+ // 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();
- java.util.List files = null;
- java.util.List protocols = null;
+ java.util.List<String> files = new ArrayList<String>();
+ java.util.List<String> protocols = new ArrayList<String>();
try
{
- DataFlavor uriListFlavor = new DataFlavor(
- "text/uri-list;class=java.lang.String");
- if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
- {
- // Works on Windows and MacOSX
- evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
- files = (java.util.List) t
- .getTransferData(DataFlavor.javaFileListFlavor);
- }
- else if (t.isDataFlavorSupported(uriListFlavor))
- {
- // This is used by Unix drag system
- evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
- String data = (String) t.getTransferData(uriListFlavor);
- files = new java.util.ArrayList(1);
- protocols = new java.util.ArrayList(1);
- for (java.util.StringTokenizer st = new java.util.StringTokenizer(
- data, "\r\n"); st.hasMoreTokens();)
- {
- String s = st.nextToken();
- if (s.startsWith("#"))
- {
- // the line is a comment (as per the RFC 2483)
- continue;
- }
- java.net.URI uri = new java.net.URI(s);
- if (uri.getScheme().toLowerCase().startsWith("http"))
- {
- protocols.add(FormatAdapter.URL);
- files.add(uri.toString());
- }
- else
- {
- // otherwise preserve old behaviour: catch all for file objects
- java.io.File file = new java.io.File(uri);
- protocols.add(FormatAdapter.FILE);
- files.add(file.toString());
- }
- }
- }
+ Desktop.transferFromDropTarget(files, protocols, evt, t);
} catch (Exception e)
{
+ e.printStackTrace();
success = false;
}
dialogExecutor.shutdownNow();
}
closeAll_actionPerformed(null);
+
+ if (groovyConsole != null)
+ {
+ // suppress a possible repeat prompt to save script
+ groovyConsole.setDirty(false);
+ groovyConsole.exit();
+ }
System.exit(0);
}
@Override
public void closeAll_actionPerformed(ActionEvent e)
{
+ // TODO show a progress bar while closing?
JInternalFrame[] frames = desktop.getAllFrames();
for (int i = 0; i < frames.length; i++)
{
{
}
}
+ Jalview.setCurrentAlignFrame(null);
System.out.println("ALL CLOSED");
if (v_client != null)
{
{
ssm.resetAll();
}
+ System.gc();
}
@Override
*
* @param af
*/
- public void explodeViews(AlignFrame af)
+ public static void explodeViews(AlignFrame af)
{
int size = af.alignPanels.size();
if (size < 2)
protected JMenuItem groovyShell;
- public void doGroovyCheck()
- {
- if (jalview.bin.Cache.groovyJarsPresent())
- {
- groovyShell = new JMenuItem();
- groovyShell.setText(MessageManager.getString("label.groovy_console"));
- groovyShell.addActionListener(new ActionListener()
- {
- @Override
- public void actionPerformed(ActionEvent e)
- {
- groovyShell_actionPerformed();
- }
- });
- toolsMenu.add(groovyShell);
- groovyShell.setVisible(true);
- }
- }
-
/**
* Accessor method to quickly get all the AlignmentFrames loaded.
*
if (Jalview.isHeadlessMode())
{
// Desktop.desktop is null in headless mode
- return new AlignFrame[] { currentAlignFrame };
+ return new AlignFrame[] { Jalview.currentAlignFrame };
}
JInternalFrame[] frames = Desktop.desktop.getAllFrames();
*/
public void groovyShell_actionPerformed()
{
- // use reflection to avoid creating compilation dependency.
- if (!jalview.bin.Cache.groovyJarsPresent())
- {
- throw new Error(
- MessageManager
- .getString("error.implementation_error_cannot_create_groovyshell"));
- }
try
{
- Class<?> gcClass = Desktop.class.getClassLoader().loadClass(
- "groovy.ui.Console");
- Constructor<?> gccons = gcClass.getConstructor();
- java.lang.reflect.Method setvar = gcClass.getMethod("setVariable",
- new Class[] { String.class, Object.class });
- java.lang.reflect.Method run = gcClass.getMethod("run");
- groovyConsole = gccons.newInstance();
- setvar.invoke(groovyConsole, new Object[] { "Jalview", this });
- run.invoke(groovyConsole);
- /*
- * and rebuild alignframe menus to enable 'Run Groovy'
- */
-
- AlignFrame[] alignFrames = getAlignFrames();
- if (alignFrames != null)
- {
- for (AlignFrame af : alignFrames)
- {
- af.setGroovyEnabled(true);
- }
- }
+ openGroovyConsole();
} catch (Exception ex)
{
jalview.bin.Cache.log.error("Groovy Shell Creation failed.", ex);
}
/**
+ * Open the Groovy console
+ */
+ void openGroovyConsole()
+ {
+ if (groovyConsole == null)
+ {
+ groovyConsole = new groovy.ui.Console();
+ groovyConsole.setVariable("Jalview", this);
+ groovyConsole.run();
+
+ /*
+ * We allow only one console at a time, so that AlignFrame menu option
+ * 'Calculate | Run Groovy script' is unambiguous.
+ * Disable 'Groovy Console', and enable 'Run script', when the console is
+ * opened, and the reverse when it is closed
+ */
+ Window window = (Window) groovyConsole.getFrame();
+ window.addWindowListener(new WindowAdapter()
+ {
+ @Override
+ public void windowClosed(WindowEvent e)
+ {
+ /*
+ * rebind CMD-Q from Groovy Console to Jalview Quit
+ */
+ addQuitHandler();
+ enableExecuteGroovy(false);
+ }
+ });
+ }
+
+ /*
+ * show Groovy console window (after close and reopen)
+ */
+ ((Window) groovyConsole.getFrame()).setVisible(true);
+
+ /*
+ * if we got this far, enable 'Run Groovy' in AlignFrame menus
+ * and disable opening a second console
+ */
+ enableExecuteGroovy(true);
+ }
+
+ /**
+ * Bind Ctrl/Cmd-Q to Quit - for reset as Groovy Console takes over this
+ * binding when opened
+ */
+ protected void addQuitHandler()
+ {
+ getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(
+ KeyStroke.getKeyStroke(KeyEvent.VK_Q, Toolkit
+ .getDefaultToolkit().getMenuShortcutKeyMask()), "Quit");
+ getRootPane().getActionMap().put("Quit", new AbstractAction()
+ {
+ @Override
+ public void actionPerformed(ActionEvent e)
+ {
+ quit();
+ }
+ });
+ }
+
+ /**
+ * Enable or disable 'Run Groovy script' in AlignFrame calculate menus
+ *
+ * @param enabled
+ * true if Groovy console is open
+ */
+ public void enableExecuteGroovy(boolean enabled)
+ {
+ /*
+ * disable opening a second Groovy console
+ * (or re-enable when the console is closed)
+ */
+ groovyShell.setEnabled(!enabled);
+
+ AlignFrame[] alignFrames = getAlignFrames();
+ if (alignFrames != null)
+ {
+ for (AlignFrame af : alignFrames)
+ {
+ af.setGroovyEnabled(enabled);
+ }
+ }
+ }
+
+ /**
* Progress bars managed by the IProgressIndicator method.
*/
private Hashtable<Long, JPanel> progressBars;
*/
private java.util.concurrent.Semaphore block = new Semaphore(0);
- /*
- * groovy.ui.Console object - if Groovy jars are present and the
- * user has activated the Groovy console. Use via reflection to
- * avoid compile-time dependency on Groovy libraries.
- */
- private static Object groovyConsole;
+ private static groovy.ui.Console groovyConsole;
/**
* add another dialog thread to the queue
* The dust settles...give focus to the tab we did this from.
*/
myTopFrame.setDisplayedView(myTopFrame.alignPanel);
-
}
- public static AlignFrame getCurrentAlignFrame()
+ public static groovy.ui.Console getGroovyConsole()
{
- return currentAlignFrame;
+ return groovyConsole;
}
- public static void setCurrentAlignFrame(AlignFrame currentAlignFrame)
+ public static void transferFromDropTarget(List<String> files,
+ List<String> protocols, DropTargetDropEvent evt, Transferable t)
+ throws Exception
{
- Desktop.currentAlignFrame = currentAlignFrame;
- }
- public static Object getGroovyConsole()
- {
- return groovyConsole;
+ DataFlavor uriListFlavor = new DataFlavor(
+ "text/uri-list;class=java.lang.String");
+ if (t.isDataFlavorSupported(DataFlavor.javaFileListFlavor))
+ {
+ // Works on Windows and MacOSX
+ Cache.log.debug("Drop handled as javaFileListFlavor");
+ evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
+ for (Object file : (List) t
+ .getTransferData(DataFlavor.javaFileListFlavor))
+ {
+ files.add(((File) file).toString());
+ protocols.add(FormatAdapter.FILE);
+ }
+ }
+ else
+ {
+ // Unix like behaviour
+ boolean added = false;
+ String data = null;
+ if (t.isDataFlavorSupported(uriListFlavor))
+ {
+ Cache.log.debug("Drop handled as uriListFlavor");
+ // This is used by Unix drag system
+ evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
+ data = (String) t.getTransferData(uriListFlavor);
+ }
+ if (data == null)
+ {
+ // fallback to text: workaround - on OSX where there's a JVM bug
+ Cache.log.debug("standard URIListFlavor failed. Trying text");
+ // try text fallback
+ data = (String) t.getTransferData(new DataFlavor(
+ "text/plain;class=java.lang.String"));
+ if (Cache.log.isDebugEnabled())
+ {
+ Cache.log.debug("fallback returned " + data);
+ }
+ }
+ while (protocols.size() < files.size())
+ {
+ Cache.log.debug("Adding missing FILE protocol for "
+ + files.get(protocols.size()));
+ protocols.add(FormatAdapter.FILE);
+ }
+ for (java.util.StringTokenizer st = new java.util.StringTokenizer(
+ data, "\r\n"); st.hasMoreTokens();)
+ {
+ added = true;
+ String s = st.nextToken();
+ if (s.startsWith("#"))
+ {
+ // the line is a comment (as per the RFC 2483)
+ continue;
+ }
+ java.net.URI uri = new java.net.URI(s);
+ if (uri.getScheme().toLowerCase().startsWith("http"))
+ {
+ protocols.add(FormatAdapter.URL);
+ files.add(uri.toString());
+ }
+ else
+ {
+ // otherwise preserve old behaviour: catch all for file objects
+ java.io.File file = new java.io.File(uri);
+ protocols.add(FormatAdapter.FILE);
+ files.add(file.toString());
+ }
+ }
+ if (Cache.log.isDebugEnabled())
+ {
+ if (data == null || !added)
+ {
+ Cache.log
+ .debug("Couldn't resolve drop data. Here are the supported flavors:");
+ for (DataFlavor fl : t.getTransferDataFlavors())
+ {
+ Cache.log.debug("Supported transfer dataflavor: "
+ + fl.toString());
+ evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
+ Object df = t.getTransferData(fl);
+ if (df != null)
+ {
+ Cache.log.debug("Retrieves: " + df);
+ }
+ else
+ {
+ Cache.log.debug("Retrieved nothing");
+ }
+ }
+ }
+ }
+ }
}
-
}