1
0
mirror of https://github.com/arduino/Arduino.git synced 2025-03-15 12:29:26 +01:00
Reviewed its getMaximumItems method (now getMaximumDrawableMenuItems) so that it returns a 1/3rd less the max number, avoiding a bad crash on linuxes. Fixes #3174
This commit is contained in:
Federico Fissore 2015-05-21 11:28:35 +02:00
parent d8b6619de0
commit 17598368ac

View File

@ -3,43 +3,31 @@
*/ */
package processing.app.tools; package processing.app.tools;
import java.awt.Color; import javax.swing.*;
import java.awt.Component; import javax.swing.event.ChangeEvent;
import java.awt.Dimension; import javax.swing.event.ChangeListener;
import java.awt.Graphics; import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import java.awt.*;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.ActionListener; import java.awt.event.ActionListener;
import java.awt.event.MouseWheelEvent; import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener; import java.awt.event.MouseWheelListener;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.MenuSelectionManager;
import javax.swing.Timer;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import javax.swing.plaf.ButtonUI;
/** /**
* A class that provides scrolling capabilities to a long menu dropdown or * A class that provides scrolling capabilities to a long menu dropdown or
* popup menu. A number of items can optionally be frozen at the top and/or * popup menu. A number of items can optionally be frozen at the top and/or
* bottom of the menu. * bottom of the menu.
* <P> * <p/>
* <B>Implementation note:</B> The default number of items to display * <B>Implementation note:</B> The default number of items to display
* at a time is 15, and the default scrolling interval is 125 milliseconds. * at a time is 15, and the default scrolling interval is 125 milliseconds.
* <P> * <p/>
* *
* @version 1.5.0 04/05/12
* @author Darryl * @author Darryl
* @version 1.5.0 04/05/12
*/ */
public class MenuScroller { public class MenuScroller {
//private JMenu menu;
private JPopupMenu menu; private JPopupMenu menu;
private Component[] menuItems; private Component[] menuItems;
private MenuScrollItem upItem; private MenuScrollItem upItem;
@ -53,25 +41,6 @@ public class MenuScroller {
private int firstIndex = 0; private int firstIndex = 0;
private int keepVisibleIndex = -1; private int keepVisibleIndex = -1;
private static int getMaximumItems(JPopupMenu menu) {
JMenuItem test = new JMenuItem("test");
ButtonUI ui = test.getUI();
Dimension d = ui.getPreferredSize(test);
double item_height = d.getHeight();
//System.out.println("JMenuItem Height " + item_height);
JMenuItem up = new JMenuItem(MenuIcon.UP);
ui = up.getUI();
d = ui.getPreferredSize(up);
double icon_height = d.getHeight();
//System.out.println("icon item height " + icon_height);
double menu_border_height = 8.0; // kludge - how to detect this?
double screen_height = java.awt.Toolkit.getDefaultToolkit().getScreenSize().getHeight();
//System.out.println("screen height " + screen_height);
int n = (int)((screen_height - icon_height * 2 - menu_border_height) / item_height);
//System.out.println("max items " + n);
return n;
}
/** /**
* Registers a menu to be scrolled with the default number of items to * Registers a menu to be scrolled with the default number of items to
* display at a time and the default scrolling interval. * display at a time and the default scrolling interval.
@ -98,7 +67,7 @@ public class MenuScroller {
* Registers a menu to be scrolled with the default number of items to * Registers a menu to be scrolled with the default number of items to
* display at a time and the specified scrolling interval. * display at a time and the specified scrolling interval.
* *
* @param menu the menu * @param menu the menu
* @param scrollCount the number of items to display at a time * @param scrollCount the number of items to display at a time
* @return the MenuScroller * @return the MenuScroller
* @throws IllegalArgumentException if scrollCount is 0 or negative * @throws IllegalArgumentException if scrollCount is 0 or negative
@ -111,7 +80,7 @@ public class MenuScroller {
* Registers a popup menu to be scrolled with the default number of items to * Registers a popup menu to be scrolled with the default number of items to
* display at a time and the specified scrolling interval. * display at a time and the specified scrolling interval.
* *
* @param menu the popup menu * @param menu the popup menu
* @param scrollCount the number of items to display at a time * @param scrollCount the number of items to display at a time
* @return the MenuScroller * @return the MenuScroller
* @throws IllegalArgumentException if scrollCount is 0 or negative * @throws IllegalArgumentException if scrollCount is 0 or negative
@ -124,9 +93,9 @@ public class MenuScroller {
* Registers a menu to be scrolled, with the specified number of items to * Registers a menu to be scrolled, with the specified number of items to
* display at a time and the specified scrolling interval. * display at a time and the specified scrolling interval.
* *
* @param menu the menu * @param menu the menu
* @param scrollCount the number of items to be displayed at a time * @param scrollCount the number of items to be displayed at a time
* @param interval the scroll interval, in milliseconds * @param interval the scroll interval, in milliseconds
* @return the MenuScroller * @return the MenuScroller
* @throws IllegalArgumentException if scrollCount or interval is 0 or negative * @throws IllegalArgumentException if scrollCount or interval is 0 or negative
*/ */
@ -138,9 +107,9 @@ public class MenuScroller {
* Registers a popup menu to be scrolled, with the specified number of items to * Registers a popup menu to be scrolled, with the specified number of items to
* display at a time and the specified scrolling interval. * display at a time and the specified scrolling interval.
* *
* @param menu the popup menu * @param menu the popup menu
* @param scrollCount the number of items to be displayed at a time * @param scrollCount the number of items to be displayed at a time
* @param interval the scroll interval, in milliseconds * @param interval the scroll interval, in milliseconds
* @return the MenuScroller * @return the MenuScroller
* @throws IllegalArgumentException if scrollCount or interval is 0 or negative * @throws IllegalArgumentException if scrollCount or interval is 0 or negative
*/ */
@ -154,19 +123,19 @@ public class MenuScroller {
* and the specified numbers of items fixed at the top and bottom of the * and the specified numbers of items fixed at the top and bottom of the
* menu. * menu.
* *
* @param menu the menu * @param menu the menu
* @param scrollCount the number of items to display in the scrolling portion * @param scrollCount the number of items to display in the scrolling portion
* @param interval the scroll interval, in milliseconds * @param interval the scroll interval, in milliseconds
* @param topFixedCount the number of items to fix at the top. May be 0. * @param topFixedCount the number of items to fix at the top. May be 0.
* @param bottomFixedCount the number of items to fix at the bottom. May be 0 * @param bottomFixedCount the number of items to fix at the bottom. May be 0
* @throws IllegalArgumentException if scrollCount or interval is 0 or
* negative or if topFixedCount or bottomFixedCount is negative
* @return the MenuScroller * @return the MenuScroller
* @throws IllegalArgumentException if scrollCount or interval is 0 or
* negative or if topFixedCount or bottomFixedCount is negative
*/ */
public static MenuScroller setScrollerFor(JMenu menu, int scrollCount, int interval, public static MenuScroller setScrollerFor(JMenu menu, int scrollCount, int interval,
int topFixedCount, int bottomFixedCount) { int topFixedCount, int bottomFixedCount) {
return new MenuScroller(menu, scrollCount, interval, return new MenuScroller(menu, scrollCount, interval,
topFixedCount, bottomFixedCount); topFixedCount, bottomFixedCount);
} }
/** /**
@ -175,19 +144,19 @@ public class MenuScroller {
* and the specified numbers of items fixed at the top and bottom of the * and the specified numbers of items fixed at the top and bottom of the
* popup menu. * popup menu.
* *
* @param menu the popup menu * @param menu the popup menu
* @param scrollCount the number of items to display in the scrolling portion * @param scrollCount the number of items to display in the scrolling portion
* @param interval the scroll interval, in milliseconds * @param interval the scroll interval, in milliseconds
* @param topFixedCount the number of items to fix at the top. May be 0 * @param topFixedCount the number of items to fix at the top. May be 0
* @param bottomFixedCount the number of items to fix at the bottom. May be 0 * @param bottomFixedCount the number of items to fix at the bottom. May be 0
* @throws IllegalArgumentException if scrollCount or interval is 0 or
* negative or if topFixedCount or bottomFixedCount is negative
* @return the MenuScroller * @return the MenuScroller
* @throws IllegalArgumentException if scrollCount or interval is 0 or
* negative or if topFixedCount or bottomFixedCount is negative
*/ */
public static MenuScroller setScrollerFor(JPopupMenu menu, int scrollCount, int interval, public static MenuScroller setScrollerFor(JPopupMenu menu, int scrollCount, int interval,
int topFixedCount, int bottomFixedCount) { int topFixedCount, int bottomFixedCount) {
return new MenuScroller(menu, scrollCount, interval, return new MenuScroller(menu, scrollCount, interval,
topFixedCount, bottomFixedCount); topFixedCount, bottomFixedCount);
} }
/** /**
@ -198,7 +167,7 @@ public class MenuScroller {
* @param menu the menu * @param menu the menu
*/ */
public MenuScroller(JMenu menu) { public MenuScroller(JMenu menu) {
this(menu, -1); this(menu, 15);
} }
/** /**
@ -209,7 +178,7 @@ public class MenuScroller {
* @param menu the popup menu * @param menu the popup menu
*/ */
public MenuScroller(JPopupMenu menu) { public MenuScroller(JPopupMenu menu) {
this(menu, -1); this(menu, 15);
} }
/** /**
@ -217,7 +186,7 @@ public class MenuScroller {
* specified number of items to display at a time, and default scrolling * specified number of items to display at a time, and default scrolling
* interval. * interval.
* *
* @param menu the menu * @param menu the menu
* @param scrollCount the number of items to display at a time * @param scrollCount the number of items to display at a time
* @throws IllegalArgumentException if scrollCount is 0 or negative * @throws IllegalArgumentException if scrollCount is 0 or negative
*/ */
@ -230,7 +199,7 @@ public class MenuScroller {
* specified number of items to display at a time, and default scrolling * specified number of items to display at a time, and default scrolling
* interval. * interval.
* *
* @param menu the popup menu * @param menu the popup menu
* @param scrollCount the number of items to display at a time * @param scrollCount the number of items to display at a time
* @throws IllegalArgumentException if scrollCount is 0 or negative * @throws IllegalArgumentException if scrollCount is 0 or negative
*/ */
@ -243,9 +212,9 @@ public class MenuScroller {
* specified number of items to display at a time, and specified scrolling * specified number of items to display at a time, and specified scrolling
* interval. * interval.
* *
* @param menu the menu * @param menu the menu
* @param scrollCount the number of items to display at a time * @param scrollCount the number of items to display at a time
* @param interval the scroll interval, in milliseconds * @param interval the scroll interval, in milliseconds
* @throws IllegalArgumentException if scrollCount or interval is 0 or negative * @throws IllegalArgumentException if scrollCount or interval is 0 or negative
*/ */
public MenuScroller(JMenu menu, int scrollCount, int interval) { public MenuScroller(JMenu menu, int scrollCount, int interval) {
@ -257,9 +226,9 @@ public class MenuScroller {
* specified number of items to display at a time, and specified scrolling * specified number of items to display at a time, and specified scrolling
* interval. * interval.
* *
* @param menu the popup menu * @param menu the popup menu
* @param scrollCount the number of items to display at a time * @param scrollCount the number of items to display at a time
* @param interval the scroll interval, in milliseconds * @param interval the scroll interval, in milliseconds
* @throws IllegalArgumentException if scrollCount or interval is 0 or negative * @throws IllegalArgumentException if scrollCount or interval is 0 or negative
*/ */
public MenuScroller(JPopupMenu menu, int scrollCount, int interval) { public MenuScroller(JPopupMenu menu, int scrollCount, int interval) {
@ -272,16 +241,16 @@ public class MenuScroller {
* specified scrolling interval, and the specified numbers of items fixed at * specified scrolling interval, and the specified numbers of items fixed at
* the top and bottom of the menu. * the top and bottom of the menu.
* *
* @param menu the menu * @param menu the menu
* @param scrollCount the number of items to display in the scrolling portion * @param scrollCount the number of items to display in the scrolling portion
* @param interval the scroll interval, in milliseconds * @param interval the scroll interval, in milliseconds
* @param topFixedCount the number of items to fix at the top. May be 0 * @param topFixedCount the number of items to fix at the top. May be 0
* @param bottomFixedCount the number of items to fix at the bottom. May be 0 * @param bottomFixedCount the number of items to fix at the bottom. May be 0
* @throws IllegalArgumentException if scrollCount or interval is 0 or * @throws IllegalArgumentException if scrollCount or interval is 0 or
* negative or if topFixedCount or bottomFixedCount is negative * negative or if topFixedCount or bottomFixedCount is negative
*/ */
public MenuScroller(JMenu menu, int scrollCount, int interval, public MenuScroller(JMenu menu, int scrollCount, int interval,
int topFixedCount, int bottomFixedCount) { int topFixedCount, int bottomFixedCount) {
this(menu.getPopupMenu(), scrollCount, interval, topFixedCount, bottomFixedCount); this(menu.getPopupMenu(), scrollCount, interval, topFixedCount, bottomFixedCount);
} }
@ -291,22 +260,21 @@ public class MenuScroller {
* specified scrolling interval, and the specified numbers of items fixed at * specified scrolling interval, and the specified numbers of items fixed at
* the top and bottom of the popup menu. * the top and bottom of the popup menu.
* *
* @param menu the popup menu * @param menu the popup menu
* @param scrollCount the number of items to display in the scrolling portion * @param scrollCount the number of items to display in the scrolling portion
* @param interval the scroll interval, in milliseconds * @param interval the scroll interval, in milliseconds
* @param topFixedCount the number of items to fix at the top. May be 0 * @param topFixedCount the number of items to fix at the top. May be 0
* @param bottomFixedCount the number of items to fix at the bottom. May be 0 * @param bottomFixedCount the number of items to fix at the bottom. May be 0
* @throws IllegalArgumentException if scrollCount or interval is 0 or * @throws IllegalArgumentException if scrollCount or interval is 0 or
* negative or if topFixedCount or bottomFixedCount is negative * negative or if topFixedCount or bottomFixedCount is negative
*/ */
public MenuScroller(JPopupMenu menu, int scrollCount, int interval, public MenuScroller(JPopupMenu menu, int scrollCount, int interval,
int topFixedCount, int bottomFixedCount) { int topFixedCount, int bottomFixedCount) {
if(scrollCount == -1) int autoSizeScrollCount = getMaximumDrawableMenuItems();
scrollCount = getMaximumItems(menu)-topFixedCount-bottomFixedCount; // Autosize if (autoSizeScrollCount > scrollCount) {
scrollCount = autoSizeScrollCount;
if(interval == -1) }
interval = 150; // Default value
if (scrollCount <= 0 || interval <= 0) { if (scrollCount <= 0 || interval <= 0) {
throw new IllegalArgumentException("scrollCount and interval must be greater than 0"); throw new IllegalArgumentException("scrollCount and interval must be greater than 0");
@ -427,8 +395,7 @@ public class MenuScroller {
if (item == null) { if (item == null) {
keepVisibleIndex = -1; keepVisibleIndex = -1;
} else { } else {
int index = menu.getComponentIndex(item); keepVisibleIndex = menu.getComponentIndex(item);
keepVisibleIndex = index;
} }
} }
@ -460,55 +427,63 @@ public class MenuScroller {
* Ensures that the <code>dispose</code> method of this MenuScroller is * Ensures that the <code>dispose</code> method of this MenuScroller is
* called when there are no more refrences to it. * called when there are no more refrences to it.
* *
* @exception Throwable if an error occurs. * @throws Throwable if an error occurs.
* @see MenuScroller#dispose() * @see MenuScroller#dispose()
*/ */
@Override @Override
public void finalize() throws Throwable { public void finalize() throws Throwable {
super.finalize();
dispose(); dispose();
} }
private void refreshMenu() { private void refreshMenu() {
if (menuItems == null || menuItems.length == 0) { if (menuItems != null && menuItems.length > 0) {
return; firstIndex = Math.max(topFixedCount, firstIndex);
} firstIndex = Math.min(menuItems.length - bottomFixedCount - scrollCount, firstIndex);
int newFirstIndex = Math.max(topFixedCount, firstIndex); upItem.setEnabled(firstIndex > topFixedCount);
newFirstIndex = Math.min(menuItems.length - bottomFixedCount - scrollCount, newFirstIndex); downItem.setEnabled(firstIndex + scrollCount < menuItems.length - bottomFixedCount);
if (newFirstIndex < 0) { menu.removeAll();
return; for (int i = 0; i < topFixedCount; i++) {
} menu.add(menuItems[i]);
}
firstIndex = newFirstIndex; if (topFixedCount > 0) {
upItem.setEnabled(firstIndex > topFixedCount);
downItem.setEnabled(firstIndex + scrollCount < menuItems.length - bottomFixedCount);
menu.removeAll();
for (int i = 0; i < topFixedCount; i++) {
menu.add(menuItems[i]);
}
/*if (topFixedCount > 0) {
menu.addSeparator(); menu.addSeparator();
}*/ }
menu.add(upItem); menu.add(upItem);
for (int i = firstIndex; i < scrollCount + firstIndex; i++) { for (int i = firstIndex; i < scrollCount + firstIndex; i++) {
menu.add(menuItems[i]); menu.add(menuItems[i]);
} }
menu.add(downItem); menu.add(downItem);
/*if (bottomFixedCount > 0) { if (bottomFixedCount > 0) {
menu.addSeparator(); menu.addSeparator();
}*/ }
for (int i = menuItems.length - bottomFixedCount; i < menuItems.length; i++) { for (int i = menuItems.length - bottomFixedCount; i < menuItems.length; i++) {
menu.add(menuItems[i]); menu.add(menuItems[i]);
} }
JComponent parent = (JComponent) upItem.getParent(); JComponent parent = (JComponent) upItem.getParent();
parent.revalidate(); parent.revalidate();
parent.repaint(); parent.repaint();
}
}
private int getMaximumDrawableMenuItems() {
JMenuItem test = new JMenuItem("test");
double itemHeight = test.getUI().getPreferredSize(test).getHeight();
JMenuItem arrowMenuItem = new JMenuItem(MenuIcon.UP);
double arrowMenuItemHeight = arrowMenuItem.getUI().getPreferredSize(arrowMenuItem).getHeight();
double menuBorderHeight = 8.0; // kludge - how to detect this?
double screenHeight = java.awt.Toolkit.getDefaultToolkit().getScreenSize().getHeight();
int maxItems = (int) ((screenHeight - arrowMenuItemHeight * 2 - menuBorderHeight) / itemHeight);
maxItems -= maxItems / 3;
return maxItems;
} }
private class MouseScrollListener implements MouseWheelListener { private class MouseScrollListener implements MouseWheelListener {
@ -538,29 +513,10 @@ public class MenuScroller {
private void setMenuItems() { private void setMenuItems() {
menuItems = menu.getComponents(); menuItems = menu.getComponents();
// Hack for auto detect the topFixed total
/*int topFixedCountPrev = topFixedCount;
for(int i=menuItems.length-1;i>0;i--)
{
if(menuItems[i].getClass().getName().endsWith("Separator"))
{
System.out.println(i);
setTopFixedCount(i+1);
if(topFixedCount!=topFixedCountPrev)
{
scrollCount = getMaximumItems()-topFixedCount;
System.out.println(getMaximumItems()-topFixedCount);
}
break;
}
}*/
if (keepVisibleIndex >= topFixedCount if (keepVisibleIndex >= topFixedCount
&& keepVisibleIndex <= menuItems.length - bottomFixedCount && keepVisibleIndex <= menuItems.length - bottomFixedCount
&& (keepVisibleIndex > firstIndex + scrollCount && (keepVisibleIndex > firstIndex + scrollCount
|| keepVisibleIndex < firstIndex)) { || keepVisibleIndex < firstIndex)) {
firstIndex = Math.min(firstIndex, keepVisibleIndex); firstIndex = Math.min(firstIndex, keepVisibleIndex);
firstIndex = Math.max(firstIndex, keepVisibleIndex - scrollCount + 1); firstIndex = Math.max(firstIndex, keepVisibleIndex - scrollCount + 1);
} }
@ -577,7 +533,6 @@ public class MenuScroller {
} }
} }
@SuppressWarnings("serial")
private class MenuScrollTimer extends Timer { private class MenuScrollTimer extends Timer {
public MenuScrollTimer(final int increment, int interval) { public MenuScrollTimer(final int increment, int interval) {
@ -592,11 +547,10 @@ public class MenuScroller {
} }
} }
@SuppressWarnings("serial")
private class MenuScrollItem extends JMenuItem private class MenuScrollItem extends JMenuItem
implements ChangeListener { implements ChangeListener {
private MenuScrollTimer timer; private final MenuScrollTimer timer;
public MenuScrollItem(MenuIcon icon, int increment) { public MenuScrollItem(MenuIcon icon, int increment) {
setIcon(icon); setIcon(icon);
@ -620,7 +574,7 @@ public class MenuScroller {
} }
} }
private static enum MenuIcon implements Icon { private enum MenuIcon implements Icon {
UP(9, 1, 9), UP(9, 1, 9),
DOWN(1, 9, 1); DOWN(1, 9, 1);