JAL-1998 JAL-3772 JAL-3416 Merge conflict resolution of JalviewFileChooser and JvOpti...
authorBen Soares <b.soares@dundee.ac.uk>
Fri, 4 Nov 2022 17:53:36 +0000 (17:53 +0000)
committerBen Soares <b.soares@dundee.ac.uk>
Fri, 4 Nov 2022 17:53:36 +0000 (17:53 +0000)
1  2 
src/jalview/bin/Jalview.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/Desktop.java
src/jalview/gui/FeatureSettings.java
src/jalview/gui/JvOptionPane.java
src/jalview/gui/StructureViewerBase.java
src/jalview/gui/UserDefinedColours.java
src/jalview/io/JalviewFileChooser.java

Simple merge
Simple merge
Simple merge
Simple merge
@@@ -40,12 -47,13 +48,15 @@@ import java.util.concurrent.Executors
  import javax.swing.Icon;
  import javax.swing.JButton;
  import javax.swing.JDialog;
 +import javax.swing.JFrame;
  import javax.swing.JInternalFrame;
+ import javax.swing.JLayeredPane;
  import javax.swing.JOptionPane;
  import javax.swing.JPanel;
 +import javax.swing.SwingUtilities;
  import javax.swing.UIManager;
+ import javax.swing.event.InternalFrameEvent;
+ import javax.swing.event.InternalFrameListener;
  
  import jalview.util.Platform;
  import jalview.util.dialogrunner.DialogRunnerI;
@@@ -927,13 -834,102 +938,101 @@@ public class JvOptionPane extends JOpti
         * attached to the button press of the dialog.  This means we can use
         * a non-modal JDialog for the confirmation without blocking the GUI.
         */
+       JOptionPane joptionpane = new JOptionPane();
+       // Make button options
+       int[] buttonActions = { JvOptionPane.YES_OPTION,
+           JvOptionPane.NO_OPTION, JvOptionPane.CANCEL_OPTION };
  
-       JDialog dialog = createDialog(parentComponent, message, title,
-               optionType, messageType, icon, options, initialValue, modal,
-               buttons);
-       jalview.bin.Console.debug("About to setVisible(true)");
+       // we need the strings to make the buttons with actionEventListener
+       if (options == null)
+       {
+         ArrayList<String> options_default = new ArrayList<>();
+         options_default
+                 .add(UIManager.getString("OptionPane.yesButtonText"));
+         if (optionType == JvOptionPane.YES_NO_OPTION
+                 || optionType == JvOptionPane.YES_NO_CANCEL_OPTION)
+         {
+           options_default
+                   .add(UIManager.getString("OptionPane.noButtonText"));
+         }
+         if (optionType == JvOptionPane.YES_NO_CANCEL_OPTION)
+         {
+           options_default
+                   .add(UIManager.getString("OptionPane.cancelButtonText"));
+         }
+         options = options_default.toArray();
+       }
+       ArrayList<JButton> options_btns = new ArrayList<>();
+       Object initialValue_btn = null;
 -      if (!Platform.isJS()) // JalviewJS already uses callback, don't need to
 -                            // add them here
++      if (!Platform.isJS()) // JalviewJS already uses callback, don't need to add them here
+       {
+         for (int i = 0; i < options.length && i < 3; i++)
+         {
+           Object o = options[i];
+           int buttonAction = buttonActions[i];
+           Runnable action = callbacks.get(buttonAction);
+           JButton jb = new JButton();
+           jb.setText((String) o);
+           jb.addActionListener(new ActionListener()
+           {
+             @Override
+             public void actionPerformed(ActionEvent e)
+             {
+               joptionpane.setValue(buttonAction);
+               if (action != null)
+                 Executors.defaultThreadFactory().newThread(action).start();
+               // joptionpane.transferFocusBackward();
+               joptionpane.transferFocusBackward();
+               joptionpane.setVisible(false);
+               // put focus and raise parent window if possible, unless cancel
+               // button pressed
+               boolean raiseParent = (parentComponent != null);
+               if (buttonAction == JvOptionPane.CANCEL_OPTION)
+                 raiseParent = false;
+               if (optionType == JvOptionPane.YES_NO_OPTION
+                       && buttonAction == JvOptionPane.NO_OPTION)
+                 raiseParent = false;
+               if (raiseParent)
+               {
+                 parentComponent.requestFocus();
+                 if (parentComponent instanceof JInternalFrame)
+                 {
+                   JInternalFrame jif = (JInternalFrame) parentComponent;
+                   jif.show();
+                   jif.moveToFront();
+                   jif.grabFocus();
+                 }
+                 else if (parentComponent instanceof Window)
+                 {
+                   Window w = (Window) parentComponent;
+                   w.toFront();
+                   w.requestFocus();
+                 }
+               }
+               joptionpane.setVisible(false);
+             }
+           });
+           options_btns.add(jb);
+           if (o.equals(initialValue))
+             initialValue_btn = jb;
+         }
+       }
+       joptionpane.setMessage(message);
+       joptionpane.setMessageType(messageType);
+       joptionpane.setOptionType(optionType);
+       joptionpane.setIcon(icon);
+       joptionpane.setOptions(
+               Platform.isJS() ? options : options_btns.toArray());
+       joptionpane.setInitialValue(
+               Platform.isJS() ? initialValue : initialValue_btn);
+       JDialog dialog = joptionpane.createDialog(parentComponent, title);
+       dialog.setIconImage(WindowIcons.logoIcon.getImage());
+       dialog.setModalityType(modal ? ModalityType.APPLICATION_MODAL
+               : ModalityType.MODELESS);
+       dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
        dialog.setVisible(true);
-       jalview.bin.Console.debug("Just setVisible(true)");
      }
    }
  
        handleResponse(getMockResponse());
      }
  
+     // need to set these separately so we can set the title bar icon later
+     this.setOptionType(yesNoCancelOption);
+     this.setMessageType(questionMessage);
+     this.setIcon(icon);
+     this.setInitialValue(initresponse);
+     this.setOptions(options);
+     this.setMessage(mainPanel);
      ourOptions = Arrays.asList(options);
 +    int response;
      if (parentComponent != this)
      {
-       response = JOptionPane.showInternalOptionDialog(parentComponent,
-               mainPanel, title, yesNoCancelOption, questionMessage, icon,
-               options, initresponse);
+       JInternalFrame jif = this.createInternalFrame(parentComponent, title);
+       jif.setFrameIcon(WindowIcons.logoIcon);
+       jif.addInternalFrameListener(new InternalFrameListener()
+       {
+         @Override
+         public void internalFrameActivated(InternalFrameEvent arg0)
+         {
+         }
+         @Override
+         public void internalFrameClosed(InternalFrameEvent arg0)
+         {
+           JvOptionPane.this.internalDialogHandleResponse();
+         }
+         @Override
+         public void internalFrameClosing(InternalFrameEvent arg0)
+         {
+         }
+         @Override
+         public void internalFrameDeactivated(InternalFrameEvent arg0)
+         {
+         }
+         @Override
+         public void internalFrameDeiconified(InternalFrameEvent arg0)
+         {
+         }
+         @Override
+         public void internalFrameIconified(InternalFrameEvent arg0)
+         {
+         }
+         @Override
+         public void internalFrameOpened(InternalFrameEvent arg0)
+         {
+         }
+       });
+       jif.setVisible(true);
+       startModal(jif);
+       return;
      }
      else
      {
      {
        return;
      }
 -    Runnable action = callbacks.get(response);
 +    Callable<Void> action = callbacks.get(response);
      if (action != null)
      {
 -      action.run();
 -      parentComponent.requestFocus();
 +      try
 +      {
 +        action.call();
 +      } catch (Exception e)
 +      {
 +        e.printStackTrace();
 +      }
 +      if (parentComponent != null)
 +        parentComponent.requestFocus();
 +    }
 +  }
 +
 +  /**
 +   * Create a non-modal confirm dialog
 +   */
 +  public JDialog createDialog(Component parentComponent, Object message,
 +          String title, int optionType, int messageType, Icon icon,
 +          Object[] options, Object initialValue, boolean modal)
 +  {
 +    return createDialog(parentComponent, message, title, optionType,
 +            messageType, icon, options, initialValue, modal, null);
 +  }
 +
 +  public JDialog createDialog(Component parentComponent, Object message,
 +          String title, int optionType, int messageType, Icon icon,
 +          Object[] options, Object initialValue, boolean modal,
 +          JButton[] buttons)
 +  {
 +    JButton[] optionsButtons = null;
 +    Object initialValueButton = null;
 +    JOptionPane joptionpane = new JOptionPane();
 +    // Make button options
 +    int[] buttonActions = { JOptionPane.YES_OPTION, JOptionPane.NO_OPTION,
 +        JOptionPane.CANCEL_OPTION };
 +
 +    // we need the strings to make the buttons with actionEventListener
 +    if (options == null)
 +    {
 +      ArrayList<String> options_default = new ArrayList<>();
 +      options_default.add(UIManager.getString("OptionPane.yesButtonText"));
 +      if (optionType == JOptionPane.YES_NO_OPTION
 +              || optionType == JOptionPane.YES_NO_CANCEL_OPTION)
 +      {
 +        options_default.add(UIManager.getString("OptionPane.noButtonText"));
 +      }
 +      if (optionType == JOptionPane.YES_NO_CANCEL_OPTION)
 +      {
 +        options_default
 +                .add(UIManager.getString("OptionPane.cancelButtonText"));
 +      }
 +      options = options_default.toArray();
      }
 +    if (!Platform.isJS()) // JalviewJS already uses callback, don't need to
 +                          // add them here
 +    {
 +      if (((optionType == JOptionPane.YES_OPTION
 +              || optionType == JOptionPane.NO_OPTION
 +              || optionType == JOptionPane.CANCEL_OPTION
 +              || optionType == JOptionPane.OK_OPTION
 +              || optionType == JOptionPane.DEFAULT_OPTION)
 +              && options.length < 1)
 +              || ((optionType == JOptionPane.YES_NO_OPTION
 +                      || optionType == JOptionPane.OK_CANCEL_OPTION)
 +                      && options.length < 2)
 +              || (optionType == JOptionPane.YES_NO_CANCEL_OPTION
 +                      && options.length < 3))
 +      {
 +        jalview.bin.Console
 +                .debug("JvOptionPane: not enough options for dialog type");
 +      }
 +      optionsButtons = new JButton[options.length];
 +      for (int i = 0; i < options.length && i < 3; i++)
 +      {
 +        Object o = options[i];
 +        int buttonAction = buttonActions[i];
 +        Callable<Void> action = callbacks.get(buttonAction);
 +        JButton jb;
 +        if (buttons != null && buttons.length > i && buttons[i] != null)
 +        {
 +          jb = buttons[i];
 +        }
 +        else
 +        {
 +          jb = new JButton();
 +        }
 +        jb.setText((String) o);
 +        jb.addActionListener(new ActionListener()
 +        {
 +          @Override
 +          public void actionPerformed(ActionEvent e)
 +          {
 +            joptionpane.setValue(buttonAction);
 +            if (action != null)
 +              Executors.newSingleThreadExecutor().submit(action);
 +            // joptionpane.transferFocusBackward();
 +            joptionpane.transferFocusBackward();
 +            joptionpane.setVisible(false);
 +            // put focus and raise parent window if possible, unless cancel
 +            // button pressed
 +            boolean raiseParent = (parentComponent != null);
 +            if (buttonAction == JOptionPane.CANCEL_OPTION)
 +              raiseParent = false;
 +            if (optionType == JOptionPane.YES_NO_OPTION
 +                    && buttonAction == JOptionPane.NO_OPTION)
 +              raiseParent = false;
 +            if (raiseParent)
 +            {
 +              parentComponent.requestFocus();
 +              if (parentComponent instanceof JInternalFrame)
 +              {
 +                JInternalFrame jif = (JInternalFrame) parentComponent;
 +                jif.show();
 +                jif.moveToFront();
 +                jif.grabFocus();
 +              }
 +              else if (parentComponent instanceof Window)
 +              {
 +                Window w = (Window) parentComponent;
 +                w.toFront();
 +                w.requestFocus();
 +              }
 +            }
 +            joptionpane.setVisible(false);
 +          }
 +        });
 +        optionsButtons[i] = jb;
 +        if (o.equals(initialValue))
 +          initialValueButton = jb;
 +      }
 +    }
 +    joptionpane.setMessage(message);
 +    joptionpane.setMessageType(messageType);
 +    joptionpane.setOptionType(optionType);
 +    joptionpane.setIcon(icon);
 +    joptionpane.setOptions(Platform.isJS() ? options : optionsButtons);
 +    joptionpane.setInitialValue(
 +            Platform.isJS() ? initialValue : initialValueButton);
 +
 +    JDialog dialog = joptionpane.createDialog(parentComponent, title);
 +    dialog.setModalityType(
 +            modal ? ModalityType.APPLICATION_MODAL : ModalityType.MODELESS);
 +    dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
 +    return dialog;
 +  }
 +
 +  /**
 +   * Utility to programmatically click a button on a JOptionPane (as a JFrame)
 +   * 
 +   * returns true if button was found
 +   */
 +  public static boolean clickButton(JFrame frame, int buttonType)
 +  {
 +
 +    return false;
    }
+   /**
+    * This helper method makes the JInternalFrame wait until it is notified by an
+    * InternalFrameClosing event. This method also adds the given JOptionPane to
+    * the JInternalFrame and sizes it according to the JInternalFrame's preferred
+    * size.
+    *
+    * @param f
+    *          The JInternalFrame to make modal.
+    */
+   private static void startModal(JInternalFrame f)
+   {
+     // We need to add an additional glasspane-like component directly
+     // below the frame, which intercepts all mouse events that are not
+     // directed at the frame itself.
+     JPanel modalInterceptor = new JPanel();
+     modalInterceptor.setOpaque(false);
+     JLayeredPane lp = JLayeredPane.getLayeredPaneAbove(f);
+     lp.setLayer(modalInterceptor, JLayeredPane.MODAL_LAYER.intValue());
+     modalInterceptor.setBounds(0, 0, lp.getWidth(), lp.getHeight());
+     modalInterceptor.addMouseListener(new MouseAdapter()
+     {
+     });
+     modalInterceptor.addMouseMotionListener(new MouseMotionAdapter()
+     {
+     });
+     lp.add(modalInterceptor);
+     f.toFront();
+     // We need to explicitly dispatch events when we are blocking the event
+     // dispatch thread.
+     EventQueue queue = Toolkit.getDefaultToolkit().getSystemEventQueue();
+     try
+     {
+       while (!f.isClosed())
+       {
+         if (EventQueue.isDispatchThread())
+         {
+           // The getNextEventMethod() issues wait() when no
+           // event is available, so we don't need do explicitly wait().
+           AWTEvent ev = queue.getNextEvent();
+           // This mimics EventQueue.dispatchEvent(). We can't use
+           // EventQueue.dispatchEvent() directly, because it is
+           // protected, unfortunately.
+           if (ev instanceof ActiveEvent)
+             ((ActiveEvent) ev).dispatch();
+           else if (ev.getSource() instanceof Component)
+             ((Component) ev.getSource()).dispatchEvent(ev);
+           else if (ev.getSource() instanceof MenuComponent)
+             ((MenuComponent) ev.getSource()).dispatchEvent(ev);
+           // Other events are ignored as per spec in
+           // EventQueue.dispatchEvent
+         }
+         else
+         {
+           // Give other threads a chance to become active.
+           Thread.yield();
+         }
+       }
+     } catch (InterruptedException ex)
+     {
+       // If we get interrupted, then leave the modal state.
+     } finally
+     {
+       // Clean up the modal interceptor.
+       lp.remove(modalInterceptor);
+       // Remove the internal frame from its parent, so it is no longer
+       // lurking around and clogging memory.
+       Container parent = f.getParent();
+       if (parent != null)
+         parent.remove(f);
+     }
+   }
  }
  //////////////////////////////////////////////////////////////////
  package jalview.io;
  
++import jalview.bin.Cache;
++import jalview.gui.JvOptionPane;
++import jalview.util.MessageManager;
++import jalview.util.Platform;
++import jalview.util.dialogrunner.DialogRunnerI;
++
  import java.awt.Component;
  import java.awt.Dimension;
  import java.awt.EventQueue;
@@@ -43,9 -42,9 +49,10 @@@ import java.util.concurrent.Callable
  import javax.swing.BoxLayout;
  import javax.swing.DefaultListCellRenderer;
  import javax.swing.JCheckBox;
+ import javax.swing.JDialog;
  import javax.swing.JFileChooser;
  import javax.swing.JList;
 +import javax.swing.JOptionPane;
  import javax.swing.JPanel;
  import javax.swing.JScrollPane;
  import javax.swing.SpringLayout;