Changeset 7463 in josm


Ignore:
Timestamp:
2014-08-30T01:59:31+02:00 (10 years ago)
Author:
Don-vip
Message:

fix #10392 - rework of MenuScroller to replace static scrollCount approach by dynamic behaviour (fix regressions from #10207)

Location:
trunk/src/org/openstreetmap/josm
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/actions/downloadtasks/DownloadOsmChangeTask.java

    r7005 r7463  
    5454    }
    5555
    56     /* (non-Javadoc)
    57      * @see org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask#download(boolean, org.openstreetmap.josm.data.Bounds, org.openstreetmap.josm.gui.progress.ProgressMonitor)
    58      */
    5956    @Override
    6057    public Future<?> download(boolean newLayer, Bounds downloadArea,
     
    6360    }
    6461
    65     /* (non-Javadoc)
    66      * @see org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask#loadUrl(boolean, java.lang.String, org.openstreetmap.josm.gui.progress.ProgressMonitor)
    67      */
    6862    @Override
    6963    public Future<?> loadUrl(boolean new_layer, String url,
     
    8478        }
    8579
    86         /* (non-Javadoc)
    87          * @see org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask.DownloadTask#parseDataSet()
    88          */
    8980        @Override
    9081        protected DataSet parseDataSet() throws OsmTransferException {
     
    9283        }
    9384
    94         /* (non-Javadoc)
    95          * @see org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask.DownloadTask#finish()
    96          */
    9785        @Override
    9886        protected void finish() {
  • trunk/src/org/openstreetmap/josm/actions/search/PushbackTokenizer.java

    r7083 r7463  
    3232        }
    3333
    34         /* (non-Javadoc)
    35          * @see java.lang.Object#toString()
    36          */
    3734        @Override
    3835        public String toString() {
  • trunk/src/org/openstreetmap/josm/gui/ImageryMenu.java

    r7291 r7463  
    3333import org.openstreetmap.josm.data.imagery.ImageryLayerInfo;
    3434import org.openstreetmap.josm.data.imagery.Shape;
     35import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
    3536import org.openstreetmap.josm.gui.layer.ImageryLayer;
    3637import org.openstreetmap.josm.gui.layer.Layer;
     
    3839import org.openstreetmap.josm.tools.ImageProvider;
    3940
    40 public class ImageryMenu extends JMenu implements MapView.LayerChangeListener {
     41/**
     42 * Imagery menu, holding entries for imagery preferences, offset actions and dynamic imagery entries
     43 * depending on current maview coordinates.
     44 * @since 3737
     45 */
     46public class ImageryMenu extends JMenu implements LayerChangeListener {
    4147
    4248    private Action offsetAction = new JosmAction(
     
    8389    private final MapRectifierWMSmenuAction rectaction = new MapRectifierWMSmenuAction();
    8490
     91    /**
     92     * Constructs a new {@code ImageryMenu}.
     93     * @param subMenu submenu in that contains plugin-managed additional imagery layers
     94     */
    8595    public ImageryMenu(JMenu subMenu) {
    8696        super(tr("Imagery"));
     
    107117    private void setupMenuScroller() {
    108118        if (!GraphicsEnvironment.isHeadless()) {
    109             int menuItemHeight = singleOffset.getPreferredSize().height;
    110             MenuScroller.setScrollerFor(this,
    111                     MenuScroller.computeScrollCount(this, menuItemHeight));
     119            MenuScroller.setScrollerFor(this, 150, 2);
    112120        }
    113121    }
  • trunk/src/org/openstreetmap/josm/gui/MainMenu.java

    r7291 r7463  
    570570        final JMenu menu = new JMenu(tr(name));
    571571        if (!GraphicsEnvironment.isHeadless()) {
    572             int menuItemHeight = new JMenu().add(newAction).getPreferredSize().height;
    573             MenuScroller.setScrollerFor(menu,
    574                     MenuScroller.computeScrollCount(menu, menuItemHeight));
     572            MenuScroller.setScrollerFor(menu);
    575573        }
    576574        return addMenu(menu, name, mnemonicKey, position, relativeHelpTopic);
  • trunk/src/org/openstreetmap/josm/gui/MenuScroller.java

    r7452 r7463  
    22 * MenuScroller.java    1.5.0 04/02/12
    33 * License: use / modify without restrictions (see https://tips4java.wordpress.com/about/)
     4 * Heavily modified for JOSM needs => drop unused features and replace static scrollcount approach by dynamic behaviour
    45 */
    56package org.openstreetmap.josm.gui;
     
    910import java.awt.Dimension;
    1011import java.awt.Graphics;
    11 import java.awt.GraphicsConfiguration;
    12 import java.awt.Insets;
    1312import java.awt.event.ActionEvent;
    1413import java.awt.event.ActionListener;
    1514import java.awt.event.MouseWheelEvent;
    1615import java.awt.event.MouseWheelListener;
     16import java.util.Arrays;
    1717
    1818import javax.swing.Icon;
    19 import javax.swing.JComponent;
     19import javax.swing.JFrame;
    2020import javax.swing.JMenu;
    2121import javax.swing.JMenuItem;
    2222import javax.swing.JPopupMenu;
    2323import javax.swing.JSeparator;
    24 import javax.swing.MenuSelectionManager;
    2524import javax.swing.Timer;
    2625import javax.swing.event.ChangeEvent;
     
    3029
    3130import org.openstreetmap.josm.Main;
     31import org.openstreetmap.josm.tools.WindowGeometry;
    3232
    3333/**
    3434 * A class that provides scrolling capabilities to a long menu dropdown or
    3535 * popup menu. A number of items can optionally be frozen at the top of the menu.
    36  * <P>
    37  * <B>Implementation note:</B>  The default number of items to display
    38  * at a time is 15, and the default scrolling interval is 150 milliseconds.
    39  * <P>
     36 * <p>
     37 * <b>Implementation note:</B>  The default scrolling interval is 150 milliseconds.
     38 * <p>
    4039 * @author Darryl, https://tips4java.wordpress.com/2009/02/01/menu-scroller/
     40 * @since 4593
    4141 */
    4242public class MenuScroller {
     
    4848    private final MenuScrollListener menuListener = new MenuScrollListener();
    4949    private final MouseWheelListener mouseWheelListener = new MouseScrollListener();
    50     private int scrollCount;
    5150    private int interval;
    5251    private int topFixedCount;
    5352    private int firstIndex = 0;
    54     private int keepVisibleIndex = -1;
    5553
    5654    private static final int ARROW_ICON_HEIGHT = 10;
    5755
    58     /**
    59      * Computes the number of items to display at once for the given component and a given item height.
    60      * @param comp The menu
    61      * @param itemHeight Average item height
    62      * @return the number of items to display at once
    63      * @since 7291
    64      */
    65     public static int computeScrollCount(JComponent comp, int itemHeight) {
     56    private int computeScrollCount(int startIndex) {
    6657        int result = 15;
    67         if (comp != null && itemHeight > 0) {
     58        if (menu != null) {
    6859            // Compute max height of current screen
    69             int maxHeight = 0;
    70             GraphicsConfiguration gc = comp.getGraphicsConfiguration();
    71             if (gc == null && Main.parent != null) {
    72                 gc = Main.parent.getGraphicsConfiguration();
    73             }
    74             if (gc != null) {
    75                 // Max displayable height (max screen height - vertical insets)
    76                 Insets insets = comp.getToolkit().getScreenInsets(gc);
    77                 maxHeight = gc.getBounds().height - insets.top - insets.bottom;
    78             }
    79 
    80             // Remove height of our two arrow icons + 2 pixels each for borders (arbitrary value)
    81             maxHeight -= 2*(ARROW_ICON_HEIGHT+2);
    82 
    83             if (maxHeight > 0) {
    84                 result = (maxHeight/itemHeight)-1;
     60            int maxHeight = WindowGeometry.getMaxDimensionOnScreen(menu).height - ((JFrame)Main.parent).getInsets().top;
     61
     62            // Remove top fixed part height
     63            if (topFixedCount > 0) {
     64                for (int i = 0; i < topFixedCount; i++) {
     65                    maxHeight -= menuItems[i].getPreferredSize().height;
     66                }
     67                maxHeight -= new JSeparator().getPreferredSize().height;
     68            }
     69
     70            // Remove height of our two arrow items + insets
     71            maxHeight -= menu.getInsets().top;
     72            maxHeight -= upItem.getPreferredSize().height;
     73            maxHeight -= downItem.getPreferredSize().height;
     74            maxHeight -= menu.getInsets().bottom;
     75
     76            // Compute scroll count
     77            result = 0;
     78            int height = 0;
     79            for (int i = startIndex; i < menuItems.length && height <= maxHeight; i++, result++) {
     80                height += menuItems[i].getPreferredSize().height;
     81            }
     82
     83            if (height > maxHeight) {
     84                // Remove extra item from count
     85                result--;
     86            } else {
     87                // Increase scroll count to take into account upper items that will be displayed
     88                // after firstIndex is updated
     89                for (int i=startIndex-1; i >= 0 && height <= maxHeight; i--, result++) {
     90                    height += menuItems[i].getPreferredSize().height;
     91                }
     92                if (height > maxHeight) {
     93                    result--;
     94                }
    8595            }
    8696        }
     
    8999
    90100    /**
    91      * Registers a menu to be scrolled with the default number of items to
    92      * display at a time and the default scrolling interval.
     101     * Registers a menu to be scrolled with the default scrolling interval.
    93102     *
    94103     * @param menu the menu
     
    100109
    101110    /**
    102      * Registers a popup menu to be scrolled with the default number of items to
    103      * display at a time and the default scrolling interval.
     111     * Registers a popup menu to be scrolled with the default scrolling interval.
    104112     *
    105113     * @param menu the popup menu
     
    111119
    112120    /**
    113      * Registers a menu to be scrolled with the default number of items to
    114      * display at a time and the specified scrolling interval.
     121     * Registers a menu to be scrolled, with the specified scrolling interval.
    115122     *
    116123     * @param menu the menu
    117      * @param scrollCount the number of items to display at a time
    118      * @return the MenuScroller
    119      * @throws IllegalArgumentException if scrollCount is 0 or negative
    120      */
    121     public static MenuScroller setScrollerFor(JMenu menu, int scrollCount) {
    122         return new MenuScroller(menu, scrollCount);
    123     }
    124 
    125     /**
    126      * Registers a popup menu to be scrolled with the default number of items to
    127      * display at a time and the specified scrolling interval.
    128      *
    129      * @param menu the popup menu
    130      * @param scrollCount the number of items to display at a time
    131      * @return the MenuScroller
    132      * @throws IllegalArgumentException if scrollCount is 0 or negative
    133      */
    134     public static MenuScroller setScrollerFor(JPopupMenu menu, int scrollCount) {
    135         return new MenuScroller(menu, scrollCount);
    136     }
    137 
    138     /**
    139      * Registers a menu to be scrolled, with the specified number of items to
    140      * display at a time and the specified scrolling interval.
    141      *
    142      * @param menu the menu
    143      * @param scrollCount the number of items to be displayed at a time
    144124     * @param interval the scroll interval, in milliseconds
    145125     * @return the MenuScroller
    146126     * @throws IllegalArgumentException if scrollCount or interval is 0 or negative
    147      */
    148     public static MenuScroller setScrollerFor(JMenu menu, int scrollCount, int interval) {
    149         return new MenuScroller(menu, scrollCount, interval);
    150     }
    151 
    152     /**
    153      * Registers a popup menu to be scrolled, with the specified number of items to
    154      * display at a time and the specified scrolling interval.
     127     * @since 7463
     128     */
     129    public static MenuScroller setScrollerFor(JMenu menu, int interval) {
     130        return new MenuScroller(menu, interval);
     131    }
     132
     133    /**
     134     * Registers a popup menu to be scrolled, with the specified scrolling interval.
    155135     *
    156136     * @param menu the popup menu
    157      * @param scrollCount the number of items to be displayed at a time
    158137     * @param interval the scroll interval, in milliseconds
    159138     * @return the MenuScroller
    160139     * @throws IllegalArgumentException if scrollCount or interval is 0 or negative
    161      */
    162     public static MenuScroller setScrollerFor(JPopupMenu menu, int scrollCount, int interval) {
    163         return new MenuScroller(menu, scrollCount, interval);
    164     }
    165 
    166     /**
    167      * Registers a menu to be scrolled, with the specified number of items
    168      * to display in the scrolling region, the specified scrolling interval,
     140     * @since 7463
     141     */
     142    public static MenuScroller setScrollerFor(JPopupMenu menu, int interval) {
     143        return new MenuScroller(menu, interval);
     144    }
     145
     146    /**
     147     * Registers a menu to be scrolled, with the specified scrolling interval,
    169148     * and the specified numbers of items fixed at the top of the menu.
    170149     *
    171150     * @param menu the menu
    172      * @param scrollCount the number of items to display in the scrolling portion
    173151     * @param interval the scroll interval, in milliseconds
    174152     * @param topFixedCount the number of items to fix at the top.  May be 0.
     
    176154     * negative or if topFixedCount is negative
    177155     * @return the MenuScroller
    178      */
    179     public static MenuScroller setScrollerFor(JMenu menu, int scrollCount, int interval,
    180             int topFixedCount) {
    181         return new MenuScroller(menu, scrollCount, interval, topFixedCount);
    182     }
    183 
    184     /**
    185      * Registers a popup menu to be scrolled, with the specified number of items
    186      * to display in the scrolling region, the specified scrolling interval,
     156     * @since 7463
     157     */
     158    public static MenuScroller setScrollerFor(JMenu menu, int interval, int topFixedCount) {
     159        return new MenuScroller(menu, interval, topFixedCount);
     160    }
     161
     162    /**
     163     * Registers a popup menu to be scrolled, with the specified scrolling interval,
    187164     * and the specified numbers of items fixed at the top of the popup menu.
    188165     *
    189166     * @param menu the popup menu
    190      * @param scrollCount the number of items to display in the scrolling portion
     167     * @param interval the scroll interval, in milliseconds
     168     * @param topFixedCount the number of items to fix at the top. May be 0
     169     * @throws IllegalArgumentException if scrollCount or interval is 0 or
     170     * negative or if topFixedCount is negative
     171     * @return the MenuScroller
     172     * @since 7463
     173     */
     174    public static MenuScroller setScrollerFor(JPopupMenu menu, int interval, int topFixedCount) {
     175        return new MenuScroller(menu, interval, topFixedCount);
     176    }
     177
     178    /**
     179     * Constructs a <code>MenuScroller</code> that scrolls a menu with the
     180     * default scrolling interval.
     181     *
     182     * @param menu the menu
     183     * @throws IllegalArgumentException if scrollCount is 0 or negative
     184     */
     185    public MenuScroller(JMenu menu) {
     186        this(menu, 150);
     187    }
     188
     189    /**
     190     * Constructs a <code>MenuScroller</code> that scrolls a popup menu with the
     191     * default scrolling interval.
     192     *
     193     * @param menu the popup menu
     194     * @throws IllegalArgumentException if scrollCount is 0 or negative
     195     */
     196    public MenuScroller(JPopupMenu menu) {
     197        this(menu, 150);
     198    }
     199
     200    /**
     201     * Constructs a <code>MenuScroller</code> that scrolls a menu with the
     202     * specified scrolling interval.
     203     *
     204     * @param menu the menu
     205     * @param interval the scroll interval, in milliseconds
     206     * @throws IllegalArgumentException if scrollCount or interval is 0 or negative
     207     * @since 7463
     208     */
     209    public MenuScroller(JMenu menu, int interval) {
     210        this(menu, interval, 0);
     211    }
     212
     213    /**
     214     * Constructs a <code>MenuScroller</code> that scrolls a popup menu with the
     215     * specified scrolling interval.
     216     *
     217     * @param menu the popup menu
     218     * @param interval the scroll interval, in milliseconds
     219     * @throws IllegalArgumentException if scrollCount or interval is 0 or negative
     220     * @since 7463
     221     */
     222    public MenuScroller(JPopupMenu menu, int interval) {
     223        this(menu, interval, 0);
     224    }
     225
     226    /**
     227     * Constructs a <code>MenuScroller</code> that scrolls a menu with the
     228     * specified scrolling interval, and the specified numbers of items fixed at
     229     * the top of the menu.
     230     *
     231     * @param menu the menu
    191232     * @param interval the scroll interval, in milliseconds
    192233     * @param topFixedCount the number of items to fix at the top.  May be 0
    193234     * @throws IllegalArgumentException if scrollCount or interval is 0 or
    194235     * negative or if topFixedCount is negative
    195      * @return the MenuScroller
    196      */
    197     public static MenuScroller setScrollerFor(JPopupMenu menu, int scrollCount, int interval,
    198             int topFixedCount) {
    199         return new MenuScroller(menu, scrollCount, interval, topFixedCount);
    200     }
    201 
    202     /**
    203      * Constructs a <code>MenuScroller</code> that scrolls a menu with the
    204      * default number of items to display at a time, and default scrolling
    205      * interval.
    206      *
    207      * @param menu the menu
    208      */
    209     public MenuScroller(JMenu menu) {
    210         this(menu, computeScrollCount(menu, 30));
     236     * @since 7463
     237     */
     238    public MenuScroller(JMenu menu, int interval, int topFixedCount) {
     239        this(menu.getPopupMenu(), interval, topFixedCount);
    211240    }
    212241
    213242    /**
    214243     * Constructs a <code>MenuScroller</code> that scrolls a popup menu with the
    215      * default number of items to display at a time, and default scrolling
    216      * interval.
     244     * specified scrolling interval, and the specified numbers of items fixed at
     245     * the top of the popup menu.
    217246     *
    218247     * @param menu the popup menu
    219      */
    220     public MenuScroller(JPopupMenu menu) {
    221         this(menu, computeScrollCount(menu, 30));
    222     }
    223 
    224     /**
    225      * Constructs a <code>MenuScroller</code> that scrolls a menu with the
    226      * specified number of items to display at a time, and default scrolling
    227      * interval.
    228      *
    229      * @param menu the menu
    230      * @param scrollCount the number of items to display at a time
    231      * @throws IllegalArgumentException if scrollCount is 0 or negative
    232      */
    233     public MenuScroller(JMenu menu, int scrollCount) {
    234         this(menu, scrollCount, 150);
    235     }
    236 
    237     /**
    238      * Constructs a <code>MenuScroller</code> that scrolls a popup menu with the
    239      * specified number of items to display at a time, and default scrolling
    240      * interval.
    241      *
    242      * @param menu the popup menu
    243      * @param scrollCount the number of items to display at a time
    244      * @throws IllegalArgumentException if scrollCount is 0 or negative
    245      */
    246     public MenuScroller(JPopupMenu menu, int scrollCount) {
    247         this(menu, scrollCount, 150);
    248     }
    249 
    250     /**
    251      * Constructs a <code>MenuScroller</code> that scrolls a menu with the
    252      * specified number of items to display at a time, and specified scrolling
    253      * interval.
    254      *
    255      * @param menu the menu
    256      * @param scrollCount the number of items to display at a time
    257      * @param interval the scroll interval, in milliseconds
    258      * @throws IllegalArgumentException if scrollCount or interval is 0 or negative
    259      */
    260     public MenuScroller(JMenu menu, int scrollCount, int interval) {
    261         this(menu, scrollCount, interval, 0);
    262     }
    263 
    264     /**
    265      * Constructs a <code>MenuScroller</code> that scrolls a popup menu with the
    266      * specified number of items to display at a time, and specified scrolling
    267      * interval.
    268      *
    269      * @param menu the popup menu
    270      * @param scrollCount the number of items to display at a time
    271      * @param interval the scroll interval, in milliseconds
    272      * @throws IllegalArgumentException if scrollCount or interval is 0 or negative
    273      */
    274     public MenuScroller(JPopupMenu menu, int scrollCount, int interval) {
    275         this(menu, scrollCount, interval, 0);
    276     }
    277 
    278     /**
    279      * Constructs a <code>MenuScroller</code> that scrolls a menu with the
    280      * specified number of items to display in the scrolling region, the
    281      * specified scrolling interval, and the specified numbers of items fixed at
    282      * the top of the menu.
    283      *
    284      * @param menu the menu
    285      * @param scrollCount the number of items to display in the scrolling portion
    286248     * @param interval the scroll interval, in milliseconds
    287249     * @param topFixedCount the number of items to fix at the top.  May be 0
    288250     * @throws IllegalArgumentException if scrollCount or interval is 0 or
    289251     * negative or if topFixedCount is negative
    290      */
    291     public MenuScroller(JMenu menu, int scrollCount, int interval, int topFixedCount) {
    292         this(menu.getPopupMenu(), scrollCount, interval, topFixedCount);
    293     }
    294 
    295     /**
    296      * Constructs a <code>MenuScroller</code> that scrolls a popup menu with the
    297      * specified number of items to display in the scrolling region, the
    298      * specified scrolling interval, and the specified numbers of items fixed at
    299      * the top of the popup menu.
    300      *
    301      * @param menu the popup menu
    302      * @param scrollCount the number of items to display in the scrolling portion
    303      * @param interval the scroll interval, in milliseconds
    304      * @param topFixedCount the number of items to fix at the top.  May be 0
    305      * @throws IllegalArgumentException if scrollCount or interval is 0 or
    306      * negative or if topFixedCount is negative
    307      */
    308     public MenuScroller(JPopupMenu menu, int scrollCount, int interval, int topFixedCount) {
    309         if (scrollCount <= 0 || interval <= 0) {
    310             throw new IllegalArgumentException("scrollCount and interval must be greater than 0");
     252     * @since 7463
     253     */
     254    public MenuScroller(JPopupMenu menu, int interval, int topFixedCount) {
     255        if (interval <= 0) {
     256            throw new IllegalArgumentException("interval must be greater than 0");
    311257        }
    312258        if (topFixedCount < 0) {
     
    316262        upItem = new MenuScrollItem(MenuIcon.UP, -1);
    317263        downItem = new MenuScrollItem(MenuIcon.DOWN, +1);
    318         setScrollCount(scrollCount);
    319264        setInterval(interval);
    320265        setTopFixedCount(topFixedCount);
     
    347292        downItem.setInterval(interval);
    348293        this.interval = interval;
    349     }
    350 
    351     /**
    352      * Returns the number of items in the scrolling portion of the menu.
    353      *
    354      * @return the number of items to display at a time
    355      */
    356     public int getscrollCount() {
    357         return scrollCount;
    358     }
    359 
    360     /**
    361      * Sets the number of items in the scrolling portion of the menu.
    362      *
    363      * @param scrollCount the number of items to display at a time
    364      * @throws IllegalArgumentException if scrollCount is 0 or negative
    365      */
    366     public void setScrollCount(int scrollCount) {
    367         if (scrollCount <= 0) {
    368             throw new IllegalArgumentException("scrollCount must be greater than 0");
    369         }
    370         this.scrollCount = scrollCount;
    371         MenuSelectionManager.defaultManager().clearSelectedPath();
    372294    }
    373295
     
    393315        }
    394316        this.topFixedCount = topFixedCount;
    395     }
    396 
    397     /**
    398      * Scrolls the specified item into view each time the menu is opened.  Call this method with
    399      * <code>null</code> to restore the default behavior, which is to show the menu as it last
    400      * appeared.
    401      *
    402      * @param item the item to keep visible
    403      * @see #keepVisible(int)
    404      */
    405     public void keepVisible(JMenuItem item) {
    406         if (item == null) {
    407             keepVisibleIndex = -1;
    408         } else {
    409             int index = menu.getComponentIndex(item);
    410             keepVisibleIndex = index;
    411         }
    412     }
    413 
    414     /**
    415      * Scrolls the item at the specified index into view each time the menu is opened.  Call this
    416      * method with <code>-1</code> to restore the default behavior, which is to show the menu as
    417      * it last appeared.
    418      *
    419      * @param index the index of the item to keep visible
    420      * @see #keepVisible(javax.swing.JMenuItem)
    421      */
    422     public void keepVisible(int index) {
    423         keepVisibleIndex = index;
    424317    }
    425318
     
    453346        if (menuItems != null && menuItems.length > 0) {
    454347
    455             int numOfNonSepItems = getNumberOfNonSeparatorItems(menuItems);
    456 
    457             firstIndex = Math.max(topFixedCount, firstIndex);
    458             firstIndex = Math.min(numOfNonSepItems - scrollCount, firstIndex);
    459 
    460             upItem.setEnabled(firstIndex > topFixedCount);
    461             downItem.setEnabled(firstIndex + scrollCount < numOfNonSepItems);
    462 
    463             menu.removeAll();
    464             for (int i = 0; i < topFixedCount; i++) {
    465                 menu.add(menuItems[i]);
    466             }
    467             if (topFixedCount > 0) {
    468                 menu.addSeparator();
    469             }
    470 
    471             menu.add(upItem);
    472             for (int i = firstIndex; i < scrollCount + firstIndex; i++) {
    473                 menu.add(menuItems[i]);
    474             }
    475             menu.add(downItem);
    476 
    477             int preferredWidth = 0;
     348            int allItemsHeight = 0;
    478349            for (Component item : menuItems) {
    479                 preferredWidth = Math.max(preferredWidth, item.getPreferredSize().width);
    480             }
    481             menu.setPreferredSize(new Dimension(preferredWidth, menu.getPreferredSize().height));
    482 
    483             JComponent parent = (JComponent) upItem.getParent();
    484             parent.revalidate();
    485             parent.repaint();
     350                allItemsHeight += item.getPreferredSize().height;
     351            }
     352
     353            int allowedHeight = WindowGeometry.getMaxDimensionOnScreen(menu).height - ((JFrame)Main.parent).getInsets().top;
     354
     355            boolean mustSCroll = allItemsHeight > allowedHeight;
     356
     357            if (mustSCroll) {
     358                firstIndex = Math.max(topFixedCount, firstIndex);
     359                int scrollCount = computeScrollCount(firstIndex);
     360                firstIndex = Math.min(menuItems.length - scrollCount, firstIndex);
     361
     362                upItem.setEnabled(firstIndex > topFixedCount);
     363                downItem.setEnabled(firstIndex + scrollCount < menuItems.length);
     364
     365                menu.removeAll();
     366                for (int i = 0; i < topFixedCount; i++) {
     367                    menu.add(menuItems[i]);
     368                }
     369                if (topFixedCount > 0) {
     370                    menu.addSeparator();
     371                }
     372
     373                menu.add(upItem);
     374                for (int i = firstIndex; i < scrollCount + firstIndex; i++) {
     375                    menu.add(menuItems[i]);
     376                }
     377                menu.add(downItem);
     378
     379                int preferredWidth = 0;
     380                for (Component item : menuItems) {
     381                    preferredWidth = Math.max(preferredWidth, item.getPreferredSize().width);
     382                }
     383                menu.setPreferredSize(new Dimension(preferredWidth, menu.getPreferredSize().height));
     384
     385            } else if (!Arrays.equals(menu.getComponents(), menuItems)) {
     386                // Scroll is not needed but menu is not up to date
     387                menu.removeAll();
     388                for (Component item : menuItems) {
     389                    menu.add(item);
     390                }
     391            }
     392
     393            menu.revalidate();
     394            menu.repaint();
    486395        }
    487396    }
     
    506415        private void setMenuItems() {
    507416            menuItems = menu.getComponents();
    508             int numOfNonSepItems = getNumberOfNonSeparatorItems(menuItems);
    509             if (keepVisibleIndex >= topFixedCount
    510                     && keepVisibleIndex <= numOfNonSepItems
    511                     && (keepVisibleIndex > firstIndex + scrollCount
    512                     || keepVisibleIndex < firstIndex)) {
    513                 firstIndex = Math.min(firstIndex, keepVisibleIndex);
    514                 firstIndex = Math.max(firstIndex, keepVisibleIndex - scrollCount + 1);
    515             }
    516             if (numOfNonSepItems > topFixedCount + scrollCount) {
    517                 refreshMenu();
    518             }
     417            refreshMenu();
    519418        }
    520419
     
    606505        @Override
    607506        public void mouseWheelMoved(MouseWheelEvent mwe) {
    608             if (getNumberOfNonSeparatorItems(menu.getComponents()) > scrollCount) {
    609                 firstIndex += mwe.getWheelRotation();
    610                 refreshMenu();
    611             }
    612             mwe.consume(); // (Comment 16, Huw)
    613         }
    614     }
    615 
    616     private int getNumberOfNonSeparatorItems(Component[] items) {
    617         int result = 0;
    618         for (Component c : items) {
    619             if (!(c instanceof JSeparator)) {
    620                 result++;
    621             }
    622         }
    623         return result;
     507            firstIndex += mwe.getWheelRotation();
     508            refreshMenu();
     509            mwe.consume();
     510        }
    624511    }
    625512}
  • trunk/src/org/openstreetmap/josm/gui/layer/ImageryLayer.java

    r7425 r7463  
    216216        }
    217217        if (menuItemHeight > 0) {
    218             int scrollcount = MenuScroller.computeScrollCount(subMenu, menuItemHeight);
    219218            if (subMenu instanceof JMenu) {
    220                 MenuScroller.setScrollerFor((JMenu) subMenu, scrollcount);
     219                MenuScroller.setScrollerFor((JMenu) subMenu);
    221220            } else if (subMenu instanceof JPopupMenu) {
    222                 MenuScroller.setScrollerFor((JPopupMenu)subMenu, scrollcount);
     221                MenuScroller.setScrollerFor((JPopupMenu)subMenu);
    223222            }
    224223        }
  • trunk/src/org/openstreetmap/josm/tools/WindowGeometry.java

    r7012 r7463  
    66import java.awt.Component;
    77import java.awt.Dimension;
     8import java.awt.GraphicsConfiguration;
    89import java.awt.GraphicsDevice;
    910import java.awt.GraphicsEnvironment;
     11import java.awt.Insets;
    1012import java.awt.Point;
    1113import java.awt.Rectangle;
     
    1416import java.util.regex.Matcher;
    1517import java.util.regex.Pattern;
     18
     19import javax.swing.JComponent;
    1620
    1721import org.openstreetmap.josm.Main;
     
    367371        }
    368372        return virtualBounds;
     373    }
     374
     375    /**
     376     * Computes the maximum dimension for a component to fit in screen displaying {@code component}.
     377     * @param component The component to get current screen info from. Must not be {@code null}
     378     * @return the maximum dimension for a component to fit in current screen
     379     * @throws IllegalArgumentException if {@code component} is null
     380     * @since 7463
     381     */
     382    public static Dimension getMaxDimensionOnScreen(JComponent component) {
     383        CheckParameterUtil.ensureParameterNotNull(component, "component");
     384        // Compute max dimension of current screen
     385        Dimension result = new Dimension();
     386        GraphicsConfiguration gc = component.getGraphicsConfiguration();
     387        if (gc == null && Main.parent != null) {
     388            gc = Main.parent.getGraphicsConfiguration();
     389        }
     390        if (gc != null) {
     391            // Max displayable dimension (max screen dimension - insets)
     392            Rectangle bounds = gc.getBounds();
     393            Insets insets = component.getToolkit().getScreenInsets(gc);
     394            result.width  = bounds.width  - insets.left - insets.right;
     395            result.height = bounds.height - insets.top - insets.bottom;
     396        }
     397        return result;
    369398    }
    370399
Note: See TracChangeset for help on using the changeset viewer.