JAL-3026 "final" removed in Desktop ; fixing #48. 80, 91, 94
[jalview.git] / src / jalview / gui / Desktop.java
index fc95f83..b3a82bd 100644 (file)
@@ -105,6 +105,7 @@ import javax.swing.JCheckBox;
 import javax.swing.JComboBox;
 import javax.swing.JComponent;
 import javax.swing.JDesktopPane;
+import javax.swing.JFileChooser;
 import javax.swing.JFrame;
 import javax.swing.JInternalFrame;
 import javax.swing.JLabel;
@@ -193,6 +194,13 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   public static MyDesktopPane desktop;
 
+  public static MyDesktopPane getDesktop()
+  {
+    // BH 2018 could use currentThread() here as a reference to a
+    // Hashtable<Thread, MyDesktopPane> in JavaScript
+    return desktop;
+  }
+
   static int openFrameCount = 0;
 
   static final int xOffset = 30;
@@ -379,8 +387,9 @@ public class Desktop extends jalview.jbgui.GDesktop
     else
     {
       Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
-      setBounds((screenSize.width - 900) / 2, (screenSize.height - 650) / 2,
-              900, 650);
+      int xPos = Math.max(5, (screenSize.width - 900) / 2);
+      int yPos = Math.max(5, (screenSize.height - 650) / 2);
+      setBounds(xPos, yPos, 900, 650);
     }
     /**
      * BH 2018
@@ -412,49 +421,50 @@ public class Desktop extends jalview.jbgui.GDesktop
 
       checkURLLinks();
 
-    this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
-    // Spawn a thread that shows the splashscreen
+      // Spawn a thread that shows the splashscreen
 
-    SwingUtilities.invokeLater(new Runnable()
-    {
-      @Override
-      public void run()
+      SwingUtilities.invokeLater(new Runnable()
       {
-        new SplashScreen();
-      }
-    });
+        @Override
+        public void run()
+        {
+          new SplashScreen();
+        }
+      });
 
-    // Thread off a new instance of the file chooser - this reduces the time it
-    // takes to open it later on.
-    new Thread(new Runnable()
-    {
-      @Override
-      public void run()
+      // Thread off a new instance of the file chooser - this reduces the time it
+      // takes to open it later on.
+      new Thread(new Runnable()
       {
-        Cache.log.debug("Filechooser init thread started.");
-        String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
-        JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
-                fileFormat);
-        Cache.log.debug("Filechooser init thread finished.");
-      }
-    }).start();
-    // Add the service change listener
-    changeSupport.addJalviewPropertyChangeListener("services",
-            new PropertyChangeListener()
-            {
-
-              @Override
-              public void propertyChange(PropertyChangeEvent evt)
+        @Override
+        public void run()
+        {
+          Cache.log.debug("Filechooser init thread started.");
+          String fileFormat = Cache.getProperty("DEFAULT_FILE_FORMAT");
+          JalviewFileChooser.forRead(Cache.getProperty("LAST_DIRECTORY"),
+                  fileFormat);
+          Cache.log.debug("Filechooser init thread finished.");
+        }
+      }).start();
+      // Add the service change listener
+      changeSupport.addJalviewPropertyChangeListener("services",
+              new PropertyChangeListener()
               {
-                Cache.log.debug("Firing service changed event for "
-                        + evt.getNewValue());
-                JalviewServicesChanged(evt);
-              }
 
-            });
+                @Override
+                public void propertyChange(PropertyChangeEvent evt)
+                {
+                  Cache.log.debug("Firing service changed event for "
+                          + evt.getNewValue());
+                  JalviewServicesChanged(evt);
+                }
+
+              });
 
     } // end BH 2018 ignore
 
+    this.setDropTarget(new java.awt.dnd.DropTarget(desktop, this));
+
     this.addWindowListener(new WindowAdapter()
     {
       @Override
@@ -880,7 +890,8 @@ public class Desktop extends jalview.jbgui.GDesktop
     frame.setResizable(resizable);
     frame.setMaximizable(resizable);
     frame.setIconifiable(resizable);
-    frame.setOpaque(false);
+    frame.setOpaque(/** @j2sNative true || */
+            false);
 
     if (frame.getX() < 1 && frame.getY() < 1)
     {
@@ -1052,7 +1063,7 @@ public class Desktop extends jalview.jbgui.GDesktop
     // Java's Transferable for native dnd
     evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
     Transferable t = evt.getTransferable();
-    List<String> files = new ArrayList<>();
+    List<Object> files = new ArrayList<>();
     List<DataSourceType> protocols = new ArrayList<>();
 
     try
@@ -1070,13 +1081,15 @@ public class Desktop extends jalview.jbgui.GDesktop
       {
         for (int i = 0; i < files.size(); i++)
         {
-          String file = files.get(i).toString();
+          // BH 2018 File or String
+          Object file = files.get(i);
+          String fileName = file.toString();
           DataSourceType protocol = (protocols == null)
                   ? DataSourceType.FILE
                   : protocols.get(i);
           FileFormatI format = null;
 
-          if (file.endsWith(".jar"))
+          if (fileName.endsWith(".jar"))
           {
             format = FileFormat.Jalview;
 
@@ -1086,7 +1099,7 @@ public class Desktop extends jalview.jbgui.GDesktop
             format = new IdentifyFile().identify(file, protocol);
           }
 
-          new FileLoader().LoadFile(file, protocol, format);
+          new FileLoader().LoadFile(null, file, protocol, format);
 
         }
       } catch (Exception ex)
@@ -1116,42 +1129,45 @@ public class Desktop extends jalview.jbgui.GDesktop
             MessageManager.getString("label.open_local_file"));
     chooser.setToolTipText(MessageManager.getString("action.open"));
 
-    int value = chooser.showOpenDialog(this);
-
-    if (value == JalviewFileChooser.APPROVE_OPTION)
+    chooser.setCallback(new Runnable()
     {
-      String choice = chooser.getSelectedFile().getPath();
-      Cache.setProperty("LAST_DIRECTORY",
-              chooser.getSelectedFile().getParent());
-
-      FileFormatI format = chooser.getSelectedFormat();
 
-      /*
-       * Call IdentifyFile to verify the file contains what its extension implies.
-       * Skip this step for dynamically added file formats, because
-       * IdentifyFile does not know how to recognise them.
-       */
-      if (FileFormats.getInstance().isIdentifiable(format))
+      @Override
+      public void run()
       {
-        try
-        {
-          format = new IdentifyFile().identify(choice, DataSourceType.FILE);
-        } catch (FileFormatException e)
+        File selectedFile = chooser.getSelectedFile();
+        Cache.setProperty("LAST_DIRECTORY", selectedFile.getParent());
+
+        FileFormatI format = chooser.getSelectedFormat();
+
+        /*
+         * Call IdentifyFile to verify the file contains what its extension implies.
+         * Skip this step for dynamically added file formats, because
+         * IdentifyFile does not know how to recognise them.
+         */
+        if (FileFormats.getInstance().isIdentifiable(format))
         {
-          // format = null; //??
+          try
+          {
+            format = new IdentifyFile().identify(selectedFile,
+                    DataSourceType.FILE);
+          } catch (FileFormatException e)
+          {
+            // format = null; //??
+          }
         }
-      }
 
-      if (viewport != null)
-      {
-        new FileLoader().LoadFile(viewport, choice, DataSourceType.FILE,
-                format);
-      }
-      else
-      {
-        new FileLoader().LoadFile(choice, DataSourceType.FILE, format);
+        new FileLoader().LoadFile(viewport, selectedFile,
+                DataSourceType.FILE, format);
       }
+    });
+
+    int value = chooser.showOpenDialog(this);
+    if (value == JFileChooser.APPROVE_OPTION)
+    {
+      chooser.getCallback().run();
     }
+
   }
 
   /**
@@ -1167,8 +1183,8 @@ public class Desktop extends jalview.jbgui.GDesktop
     // for viewing
     JLabel label = new JLabel(
             MessageManager.getString("label.input_file_url"));
-    final JComboBox history = new JComboBox();
 
+    JComboBox history = new JComboBox();
     JPanel panel = new JPanel(new GridLayout(2, 1));
     panel.add(label);
     panel.add(history);
@@ -1190,66 +1206,28 @@ public class Desktop extends jalview.jbgui.GDesktop
       }
     }
 
-    int reply = JvOptionPane.showInternalConfirmDialog(desktop, panel,
-            MessageManager.getString("label.input_alignment_from_url"),
-            JvOptionPane.OK_CANCEL_OPTION);
+    // BH 2018 -- providing a callback for SwingJS
+    // dialogOption is just a simple way to provide
+    // context for the modal-like response.
+    // The only requirement is that desktop implement
+    // PropertyChangeListener, which is used already in Java
+    // for changes in input value and such within the dialogs.
 
-    if (reply != JvOptionPane.OK_OPTION)
-    {
-      return;
-    }
+    String dialogOption = "label.input_alignment_from_url";
+    desktop.dialogData = new Object[] { dialogOption, viewport, history };
+    desktop.onDialogReturn(
+            JvOptionPane.showInternalConfirmDialog(desktop, panel,
+            MessageManager.getString(dialogOption),
+            JvOptionPane.OK_CANCEL_OPTION));
 
-    String url = history.getSelectedItem().toString();
+    // no code may follow this, as SwingJS will not block
+    // callback in JavaScript comes via a property change event,
+    // thus going into desktop.onDialogReturn(int) just the same as
+    // in Java.
 
-    if (url.toLowerCase().endsWith(".jar"))
-    {
-      if (viewport != null)
-      {
-        new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
-                FileFormat.Jalview);
-      }
-      else
-      {
-        new FileLoader().LoadFile(url, DataSourceType.URL,
-                FileFormat.Jalview);
-      }
-    }
-    else
-    {
-      FileFormatI format = null;
-      try
-      {
-        format = new IdentifyFile().identify(url, DataSourceType.URL);
-      } catch (FileFormatException e)
-      {
-        // TODO revise error handling, distinguish between
-        // URL not found and response not valid
-      }
-
-      if (format == null)
-      {
-        JvOptionPane.showInternalMessageDialog(Desktop.desktop,
-                MessageManager.formatMessage("label.couldnt_locate",
-                        new Object[]
-                        { url }),
-                MessageManager.getString("label.url_not_found"),
-                JvOptionPane.WARNING_MESSAGE);
-
-        return;
-      }
-
-      if (viewport != null)
-      {
-        new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
-                format);
-      }
-      else
-      {
-        new FileLoader().LoadFile(url, DataSourceType.URL, format);
-      }
-    }
   }
 
+
   /**
    * Opens the CutAndPaste window for the user to paste an alignment in to
    * 
@@ -1633,6 +1611,8 @@ public class Desktop extends jalview.jbgui.GDesktop
   @Override
   public void saveState_actionPerformed(ActionEvent e)
   {
+    // TODO: JAL-3048 not needed for Jalview-JS
+
     JalviewFileChooser chooser = new JalviewFileChooser("jvp",
             "Jalview Project");
 
@@ -1706,6 +1686,8 @@ public class Desktop extends jalview.jbgui.GDesktop
   @Override
   public void loadState_actionPerformed(ActionEvent e)
   {
+    // TODO: JAL-3048 not needed for Jalview-JS
+
     JalviewFileChooser chooser = new JalviewFileChooser(
             Cache.getProperty("LAST_DIRECTORY"), new String[]
             { "jvp", "jar" },
@@ -1765,7 +1747,7 @@ public class Desktop extends jalview.jbgui.GDesktop
 
   ArrayList<JPanel> fileLoadingPanels = new ArrayList<>();
 
-  public void startLoading(final String fileName)
+  public void startLoading(final Object fileName)
   {
     if (fileLoadingCount == 0)
     {
@@ -2013,6 +1995,8 @@ public class Desktop extends jalview.jbgui.GDesktop
   @Override
   public void vamsasImport_actionPerformed(ActionEvent e)
   {
+    // TODO: JAL-3048 not needed for Jalview-JS
+
     if (v_client == null)
     {
       // Load and try to start a session.
@@ -2289,6 +2273,8 @@ public class Desktop extends jalview.jbgui.GDesktop
   @Override
   public void vamsasSave_actionPerformed(ActionEvent e)
   {
+    // TODO: JAL-3048 not needed for Jalview-JS
+
     if (v_client != null)
     {
       // TODO: VAMSAS DOCUMENT EXTENSION is VDJ
@@ -2471,9 +2457,159 @@ public class Desktop extends jalview.jbgui.GDesktop
    * 
    * @author AMW
    */
-  public class MyDesktopPane extends JDesktopPane implements Runnable
+  public class MyDesktopPane extends JDesktopPane
+          implements Runnable, PropertyChangeListener
   {
 
+    public Object[] dialogData;
+
+    // @Override
+    @Override
+    public void propertyChange(PropertyChangeEvent event)
+    {
+      Object val = event.getNewValue();
+      String name = event.getPropertyName();
+      System.out.println(name);
+      switch (event.getSource().getClass().getName())
+      {
+      case "javax.swing.JOptionPane":
+        switch (name)
+        {
+        case "inputValue":
+          onDialogReturn(val);
+          return;
+        case "value":
+          if (val instanceof Integer)
+          {
+            onDialogReturn(((Integer) val).intValue());
+          }
+          else
+          {
+            onDialogReturn(val);
+          }
+          return;
+        }
+        break;
+      case "javax.swing.ColorChooserDialog":
+        switch (name)
+        {
+        case "SelectedColor":
+          onDialogReturn(val);
+          return;
+        }
+        break;
+      case "javax.swing.JFileChooser":
+        switch (name)
+        {
+        case "SelectedFile":
+          // in JavaScript, this File object will have a _bytes property,
+          // because the file data has already been loaded
+          onDialogReturn(new Object[] { (File) val });
+          return;
+        }
+        break;
+      }
+      System.out.println(event.getSource().getClass().getName() + " "
+              + event.getPropertyName() + ": " + event.getNewValue());
+    }
+
+    // JSCOmponent.DialogCaller interface
+    void onDialogReturn(Object value)
+    {
+      switch ((String) dialogData[0])
+      {
+      case "SelectedFile":
+      case "runnable":
+        dialogData[0] = value;
+        ((Runnable) dialogData[1]).run();
+        break;
+      case "label.select_feature_colour":
+        ((FeatureRenderer) dialogData[1]).processColorDialog((Color) value);
+        break;
+      }
+    }
+
+    // JSCOmponent.DialogCaller interface
+    void onDialogReturn(int value)
+    {
+      if (value != Math.floor(value))
+      {
+        // in JavaScript, this will be NaN, oddly enough
+        return;
+      }
+
+      switch ((String) dialogData[0])
+      {
+      case "runnable":
+        dialogData[0] = Integer.valueOf(value);
+        ((Runnable) dialogData[1]).run();
+        break;
+      case "label.input_alignment_from_url":
+        // reconstruct the parameter data
+        int reply = value;
+        AlignViewport viewport = (AlignViewport) dialogData[1];
+        JComboBox history = (JComboBox) dialogData[2];
+        // the rest of this is unchangaed
+        if (reply != JvOptionPane.OK_OPTION)
+        {
+          return;
+        }
+
+        String url = history.getSelectedItem().toString();
+
+        if (url.toLowerCase().endsWith(".jar"))
+        {
+          if (viewport != null)
+          {
+            new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
+                    FileFormat.Jalview);
+          }
+          else
+          {
+            new FileLoader().LoadFile(url, DataSourceType.URL,
+                    FileFormat.Jalview);
+          }
+        }
+        else
+        {
+          FileFormatI format = null;
+          try
+          {
+            format = new IdentifyFile().identify(url, DataSourceType.URL);
+          } catch (FileFormatException e)
+          {
+            // TODO revise error handling, distinguish between
+            // URL not found and response not valid
+          }
+
+          if (format == null)
+          {
+            JvOptionPane.showInternalMessageDialog(Desktop.desktop,
+                    MessageManager.formatMessage("label.couldnt_locate",
+                            new Object[]
+                    { url }),
+                    MessageManager.getString("label.url_not_found"),
+                    JvOptionPane.WARNING_MESSAGE);
+
+            return;
+          }
+
+          if (viewport != null)
+          {
+            new FileLoader().LoadFile(viewport, url, DataSourceType.URL,
+                    format);
+          }
+          else
+          {
+            new FileLoader().LoadFile(url, DataSourceType.URL, format);
+          }
+        }
+
+        break;
+      }
+
+    }
+
     private static final float ONE_MB = 1048576f;
 
     boolean showMemoryUsage = false;
@@ -3379,10 +3515,29 @@ public class Desktop extends jalview.jbgui.GDesktop
    *          - the payload from the drop event
    * @throws Exception
    */
-  public static void transferFromDropTarget(List<String> files,
+  public static void transferFromDropTarget(List<Object> files,
           List<DataSourceType> protocols, DropTargetDropEvent evt,
           Transferable t) throws Exception
   {
+    
+    // BH 2018 changed List<String> to List<Object> to allow for File from SwingJS
+
+//    DataFlavor[] flavors = t.getTransferDataFlavors();
+//    for (int i = 0; i < flavors.length; i++) {
+//      if (flavors[i].isFlavorJavaFileListType()) {
+//              evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
+//              List<File> list = (List<File>) t.getTransferData(flavors[i]);
+//              for (int j = 0; j < list.size(); j++) {
+//                      File file = (File) list.get(j);
+//                      byte[] data = getDroppedFileBytes(file);
+//                      fileName.setText(file.getName() + " - " + data.length + " " + evt.getLocation());
+//                      JTextArea target = (JTextArea) ((DropTarget) evt.getSource()).getComponent();
+//                      target.setText(new String(data));
+//              }
+//              dtde.dropComplete(true);
+//              return;
+//      }
+//
 
     DataFlavor uriListFlavor = new DataFlavor(
             "text/uri-list;class=java.lang.String"), urlFlavour = null;
@@ -3432,7 +3587,7 @@ public class Desktop extends jalview.jbgui.GDesktop
       for (Object file : (List) t
               .getTransferData(DataFlavor.javaFileListFlavor))
       {
-        files.add(((File) file).toString());
+        files.add(file);
         protocols.add(DataSourceType.FILE);
       }
     }
@@ -3538,13 +3693,14 @@ public class Desktop extends jalview.jbgui.GDesktop
       // resolve any .lnk files in the file drop
       for (int f = 0; f < files.size(); f++)
       {
-        String source = files.get(f).toLowerCase();
+        String source = files.get(f).toString().toLowerCase();
         if (protocols.get(f).equals(DataSourceType.FILE)
                 && (source.endsWith(".lnk") || source.endsWith(".url")
                         || source.endsWith(".site")))
         {
           try {
-            File lf = new File(files.get(f));
+            Object obj = files.get(f);
+            File lf = (obj instanceof File ? (File) obj : new File((String) obj));
             // process link file to get a URL
             Cache.log.debug("Found potential link file: " + lf);
             WindowsShortcut wscfile = new WindowsShortcut(lf);