location question w/setVisibleMenuItemCount in JidePopupMenu

This is the forum for JIDE Common Layer which is open sourced at https://github.com/jidesoft/jide-oss. Please note, JIDE technical support doesn't monitor this forum as often as other forums. Please consider subscribe for technical support for JIDE Common Layer so that you can use customer only forum to get a timely response.

Moderator: JIDE Support

Forum rules
Community driven forum for open source JIDE Common Layer. JIDE technical support doesn't monitor this forum as often as other forums. If you only use JIDE Common Layer, please consider subscribing for technical support for JIDE Common Layer so that you can use customer only forum to get a timely response.

location question w/setVisibleMenuItemCount in JidePopupMenu

Postby ma16 » Mon Jan 11, 2016 10:33 am

Good afternoon all
I had a quick question that I am hoping someone else may have encountered with the latest version of the common library (3.6.12). I wanted to be able to limit the size of the viewable elements of a right click popup as well as have scrolls when there are too many items. To that end i am using a JidePopupMenu with a call to setVisibleMenuItemCount(15). I built a menu with 99 items and what I am seeing is that it builds the scrollable right click menu and only shows 15 elements as i was hoping but the popup appears to always display at the top of my screen. I wanted to see if I was simply not using the method correctly or if anyone else had seen the same issue. I had done some quick debugging and it appears the PortingUtils.ensureOnScreen call in JidePopupMenu.getPopupMenuOrigin(Component,int,int) modifies the y coordinate of the rectangle to be 0. I think it does this because it is looking at the getPreferredSize() and not the getPreferredScrollableViewportSize() but as I said I was only able to look through it quickly and I am not sure if I am using it correctly.

Thank you in advance for any information you can provide
Mike

Here is an SSCCE to demonstrate what i am trying to do
Code: Select all
import java.awt.BorderLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import com.jidesoft.swing.JideMenu;
import com.jidesoft.swing.JidePopupMenu;

/**
 * Test class to show issue with Y location for popup getting set to zero.
 * For large numbers of menu items, when setting the visible menu item count the menu itself sizes properly
 * but the Y coordinate for where it gets shown is pushed to the top of the screen (Y location = 0)
 */
public class JidePopupMenuTest extends JFrame
{
   /* create the menu */
   private JidePopupMenu menu = new JidePopupMenu();

   public JidePopupMenuTest()
   {
      /* make it so that more than 15 items will add the scroll processing */
      menu.setVisibleMenuItemCount(15);
      
      /* create the menus and submenus */
      for (int i = 1; i < 100; i++) {
         JideMenu menuItem = new JideMenu("Menu " + i);
         for (int j = 1; j < 10; j++) {
            menuItem.add(new JMenuItem("Submenu " + j));
         }
         menu.add(menuItem);
      }
      
      /* add a panel the frame */
      JPanel panel = new JPanel();
      getContentPane().add(panel, BorderLayout.CENTER);
      
      /* add a label to the panel */
      JLabel label = new JLabel("Right click to get a popup");
      panel.add(label);

      /* add a mouse listener to handle the right click */
      addMouseListener(new MouseAdapter(){
         /* (non-Javadoc)
          * @see java.awt.event.MouseAdapter#mouseReleased(java.awt.event.MouseEvent)
          */
         @Override
         public void mouseReleased(MouseEvent e)
         {
            if (e.isPopupTrigger()) {
               menu.show(e.getComponent(), e.getX(), e.getY());
            }
         }
      });
      
      setDefaultCloseOperation(EXIT_ON_CLOSE);
      pack();
      setVisible(true);
   }
   
   public static void main(String[] args)
   {
      try {
         UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
      } catch (ClassNotFoundException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      } catch (InstantiationException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      } catch (IllegalAccessException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      } catch (UnsupportedLookAndFeelException e) {
         // TODO Auto-generated catch block
         e.printStackTrace();
      }
      new JidePopupMenuTest();
   }
}
ma16
 
Posts: 4
Joined: Wed Jan 06, 2016 10:23 am

Re: location question w/setVisibleMenuItemCount in JidePopup

Postby JIDE Support » Mon Jan 11, 2016 11:50 am

I examined the code and it is more than that. The popup menu was not added to the scroll pane the first time when getPopupMenuOrigin is called. I will have to change the logic here in order to make it working correctly.
JIDE Software Technical Support Team
JIDE Support
Site Admin
 
Posts: 36107
Joined: Sun Sep 14, 2003 10:49 am

Re: location question w/setVisibleMenuItemCount in JidePopup

Postby JIDE Support » Fri Feb 19, 2016 3:06 pm

Just so you know, this is fixed in the latest 3.6.13 release.
JIDE Software Technical Support Team
JIDE Support
Site Admin
 
Posts: 36107
Joined: Sun Sep 14, 2003 10:49 am

Re: location question w/setVisibleMenuItemCount in JidePopup

Postby ma16 » Fri Jun 10, 2016 6:28 am

Good morning

Sorry for the late reply but I wanted to say thank you for the information and the update. I got a little sidetracked with other things and have only now just been able to get back to looking at popups. To that end I updated to the 3.6.14 release and for some reason I am still seeing the popups appear at the top of the screen using the same example posted above. The horizontal location seems to be fine if you drag the frame to different locations on the screen but the popup stays stuck at the top of the screen. I am going to try and look at the updated code in a little more detail. I am not sure if I just didn't call the show method properly above, if I missed a method call to configure something, if it is that I am using Java 1.8.0_77 or if it is something else in my environment. If I see anything I will be sure to repost.

Thank you again for the update and sorry for taking so long to reply
Mike
ma16
 
Posts: 4
Joined: Wed Jan 06, 2016 10:23 am

Re: location question w/setVisibleMenuItemCount in JidePopup

Postby ma16 » Wed Jun 29, 2016 1:45 pm

I just wanted to post an update for this. It appears that I am seeing the menu appear at the top of the screen because the adjustPopupLocationToFitScreen(int xPosition, int yPosition) in the base JPopupMenu class is calling to get the preferredSize of the popup. In this case the preferred size is width=115, height=2578. When it sees that the height is beyond the boundary of the screen (in my case 1080 high) it sets the height to zero which puts it to the top of the screen. In the JidePopupMenu class the call in getPopupMenuOrigin(Component invoker, int x, int y) to getPreferredScrollableViewportSize() returns width=115, height=385. The strange thing is the first time I hit the breakpoint the getPreferredScrollableViewportSize() call is returning the preferred size which is width=115, height=2578 (because the first time through the container is null so the container instanceof SimpleScrollPane call is false) but after the first time it returns width=115, height=385. It makes me wonder if I am actually seeing the 3.6.14 version of the library...

That explains what appears to be happening when I run the demo. I will update again if i can figure out a workaround.

Thank you again
Mike
ma16
 
Posts: 4
Joined: Wed Jan 06, 2016 10:23 am

Re: location question w/setVisibleMenuItemCount in JidePopup

Postby JIDE Support » Thu Jun 30, 2016 8:01 am

Thanks for the update. Please feel free to let me know if you need me to change something in JIDE's code.
JIDE Software Technical Support Team
JIDE Support
Site Admin
 
Posts: 36107
Joined: Sun Sep 14, 2003 10:49 am

Re: location question w/setVisibleMenuItemCount in JidePopup

Postby ma16 » Thu Jun 30, 2016 8:27 am

Thank you for the reply. I managed to figure out a way around the issue (after trying 4 or 5 different ways to get around it that didn't work) that I am seeing but to be honest I really don't like how I had to do it. I ended up having to check which method was actually calling the getPreferredSize() method. This is because the adjustPopupLocationToFitScreen call in JPopupMenu calls getPreferredSize() which is always the maximum size of the popup. These methods or parts of them are not accessible so I couldn't simply override them. When I tried to just change the preferred size to be the scrollable size the menu turned out to have tiny wording in it so that didn't work directly. Code wise what I did is extend JidePopupMenu and override the getPreferredScrollableViewportSize() in JidePopupMenu to add storing the calculated scrollableViewportSize. I also overrode the getPreferredSize() call so that it would return the scrollableViewportSize if the adjustPopupLocationToFitScreen is the calling method (this is the part that is really bad coding).

One thing to note is that the first time I clicked the popup the container was null so it used the preferred size. I had to call menu.show(e.getComponent(), e.getX(), e.getY()) twice to get it to work properly on the first click

I have added the code below in case others find themselves in the same predicament but it is with the caveat that this is a horrible way to get around the problem. It would be great if someone were to come up with a better solution that didn't rely on hacky code.

Code: Select all
/**
Copyright
 ********************************************************************************
 * PROGRAM:                   WIN-T
 *
 * EXPORT CONTROL LABEL:      U.S. Export Controlled Information:  Information
 *                            included herein is controlled under the
 *                            International Traffic in Arms Regulations (ITAR)
 *                            by the U.S. Department of State.  Transfer of this
 *                            information to a foreign person or foreign entity
 *                            requires an export license by the U.S. State
 *                            Department  or an ITAR exemption to the license
 *                            requirement prior to the export or transfer.
 *
 * COPYRIGHT:                 COPYRIGHT 2001 GENERAL DYNAMICS
 *                            ALL RIGHTS RESERVED
 *
 * GOVERNMENT PURPOSE RIGHTS: This document contains information exempt from
 *                            mandatory disclosure under FOIA. Exemption 1
 *                            applies. This document contains technical data that
 *                            are provided with restrictions in accordance with
 *                            paragraph (b)(3) of the Rights in Technical Data
 *                            - Noncommercial Items clause of Contract
 *                            DAAB07-02-C-F404.  These restrictions apply to
 *                            technical data conspicuously marked with a Limited
 *                            Rights legend consistent with the following:
 *
 *                            Limited Rights
 *                            Contract No: DAAB07-02-C-F404
 *                            Contractor Name: General Dynamics C4 Systems
 *                            Contractor Address: 400 John Quincy Adams Road,
 *                                                Taunton, MA, 02780-1069
 *
 *                            The Government’s rights to use, modify, reproduce,
 *                            release, perform, display, or disclose these
 *                            technical data are restricted by paragraph (b)(3)
 *                            of the Rights in Technical Data – Noncommerical
 *                            Items clause contained in the above identified
 *                            contract.  Any reproduction of technical data or
 *                            portions thereof marked with this legend must
 *                            also reproduce the markings.  Any person other
 *                            than the Government, who has been provided access
 *                            to such data, must promptly notify the above named
 *                            Contractor.
 ***************************************************************************
 */
package demo;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

import com.jidesoft.swing.JideMenu;
import com.jidesoft.swing.JidePopupMenu;
import com.jidesoft.swing.SimpleScrollPane;
import com.jidesoft.utils.PortingUtils;

/**
 * Test class to show issue with Y location for popup getting set to zero.
 * For large numbers of menu items, when setting the visible menu item count the menu itself sizes properly
 * but the Y coordinate for where it gets shown is pushed to the top of the screen (Y location = 0)
 */
public class JidePopupMenuTestForForum extends JFrame
{
   /* create the menu */
   private JidePopupMenu menu;

   /**
    * Constructor
    */
   public JidePopupMenuTestForForum()
   {
     menu = new MyJidePopupMenu();

     /* make it so that more than 15 items will add the scroll processing */
      menu.setVisibleMenuItemCount(15);
     
      /* create the menus and submenus */
      for (int i = 1; i < 100; i++) {
         JideMenu menuItem = new JideMenu("Menu " + i);
         for (int j = 1; j < 10; j++) {
            menuItem.add(new JMenuItem("Submenu " + j));
         }
         menu.add(menuItem);
      }
     
      /* add a panel the frame */
      JPanel panel = new JPanel();
      getContentPane().add(panel, BorderLayout.CENTER);
     
      /* add a label to the panel */
      JLabel label = new JLabel("Right click to get a popup");
      panel.add(label);

      /* add a mouse listener to handle the right click */
      addMouseListener(new MouseAdapter(){
         /* (non-Javadoc)
          * @see java.awt.event.MouseAdapter#mouseReleased(java.awt.event.MouseEvent)
          */
         @Override
         public void mouseReleased(MouseEvent e)
         {
            if (e.isPopupTrigger()) {
               menu.show(e.getComponent(), e.getX(), e.getY());
               
               /* need to call show a second time because the first time through the
                * getPreferredScrollableViewportSize in JidePopupMenu the container is
                * null which means the (container instanceof SimpleScrollPane) call is
                * false. This has the effect of just returning the preferredSize the first
                * time through. I would prefer to not have to call it twice since this is
                * bad practice but the second time through the container is set properly */
               menu.show(e.getComponent(), e.getX(), e.getY());
            }
         }
      });
     
      setDefaultCloseOperation(EXIT_ON_CLOSE);
      this.setSize(300, 100);
      this.setLocationRelativeTo(null);
      setVisible(true);
   }
   
   public static void main(String[] args)
   {
      try {
         UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
      } catch (ClassNotFoundException e) {
         e.printStackTrace();
      } catch (InstantiationException e) {
         e.printStackTrace();
      } catch (IllegalAccessException e) {
         e.printStackTrace();
      } catch (UnsupportedLookAndFeelException e) {
         e.printStackTrace();
      }
      new JidePopupMenuTestForForum();
   }
   
   /**
    * Extended version of the JidePopupMenu. This is a REALLY bad way to do this but I didn't have access
    * in the base classes (e.g. JPopupMenu had package access and couldn't override) to change some of the
    * items that would need to be changed in order to fix it properly
    */
   public class MyJidePopupMenu extends JidePopupMenu
   {
      private Dimension scrollableViewportSize = null;

      @Override
      public Dimension getPreferredScrollableViewportSize()
      {
         Dimension size = getPreferredSize();
         Dimension screenSize = PortingUtils.getLocalScreenSize(this);
         Container container = SwingUtilities.getAncestorOfClass(SimpleScrollPane.class, this);
         if (container instanceof SimpleScrollPane) {
            SimpleScrollPane scrollPane = (SimpleScrollPane) container;
            int height = screenSize.height;
            // limit it to the height determined by the visible menu item count
            if (getVisibleMenuItemCount() > 0) {
               int totalHeight = getVisibleMenuItemCount() * getScrollableUnitIncrement(null, 0, 0);
               if (height > totalHeight) {
                  height = totalHeight;
               }
            }
            size.height = Math.min(size.height, height - scrollPane.getScrollUpButton().getPreferredSize().height
                  - scrollPane.getScrollDownButton().getPreferredSize().height);

            scrollableViewportSize = size;
         }

         return size;
      }

      @Override
      public Dimension getPreferredSize()
      {
         StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
         StackTraceElement element = stackTrace[2];
         /* it is a VERY BAD PRACTICE to look at what method is calling this method but
          * the adjustPopupLocationToFitScreen in JPopupMenu method uses getPreferredSize and if
          * the size is too large then it sets the Y-coordinate to 0. In this example, the menu
          * was very large but limited by the number of visible items. The adjustPopupLocationToFitScreen
          * only looked at the overall size that came back from getPreferredSize and not the smaller
          * size that is returned by getPreferredScrollableViewportSize */
         if (scrollableViewportSize != null && element.getMethodName().contains("adjustPopupLocationToFitScreen")) {
            return scrollableViewportSize;
         }
         return super.getPreferredSize();
      }
   }
}


Thank you again
Mike
ma16
 
Posts: 4
Joined: Wed Jan 06, 2016 10:23 am


Return to JIDE Common Layer Open Source Project Discussion (Community Driven)

Who is online

Users browsing this forum: No registered users and 1 guest