View Javadoc
1   package fr.ifremer.quadrige3.ui.swing.component.date;
2   
3   /*
4    * #%L
5    * Reef DB :: UI
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2014 - 2015 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU Affero General Public License as published by
13   * the Free Software Foundation, either version 3 of the License, or
14   * (at your option) any later version.
15   * 
16   * This program is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU General Public License for more details.
20   * 
21   * You should have received a copy of the GNU Affero General Public License
22   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
23   * #L%
24   */
25  
26  
27  import javax.swing.*;
28  import java.awt.*;
29  
30  /**
31   * Created by Ludovic on 23/11/2015.
32   */
33  public class FittingPopupFactory extends PopupFactory {
34  
35      /** {@inheritDoc} */
36      @Override
37      public Popup getPopup(Component owner, Component contents, int x, int y) throws IllegalArgumentException {
38  
39          if (owner instanceof JComponent && contents instanceof JComponent) {
40              Point bestLoc = adjustPopupLocationToFitScreen((JComponent) owner, (JComponent) contents, x, y);
41              x = bestLoc.x;
42              y = bestLoc.y;
43          }
44  
45          return super.getPopup(owner, contents, x, y);
46      }
47  
48      /**
49       * Returns an point which has been adjusted to take into account of the
50       * desktop bounds, taskbar and multi-monitor configuration.
51       */
52      private Point adjustPopupLocationToFitScreen(JComponent owner, JComponent content, int xPosition, int yPosition) {
53          Point popupLocation = new Point(xPosition, yPosition);
54  
55          if (GraphicsEnvironment.isHeadless()) {
56              return popupLocation;
57          }
58  
59          // Get screen bounds
60          Rectangle scrBounds;
61          GraphicsConfiguration gc = getCurrentGraphicsConfiguration(owner, popupLocation);
62          Toolkit toolkit = Toolkit.getDefaultToolkit();
63          if (gc != null) {
64              // If we have GraphicsConfiguration use it to get screen bounds
65              scrBounds = gc.getBounds();
66          } else {
67              // If we don't have GraphicsConfiguration use primary screen
68              scrBounds = new Rectangle(toolkit.getScreenSize());
69          }
70  
71          // Calculate the screen size that popup should fit
72          Dimension popupSize = content.getPreferredSize();
73          long popupRightX = (long) popupLocation.x + (long) popupSize.width;
74          long popupBottomY = (long) popupLocation.y + (long) popupSize.height;
75          int scrWidth = scrBounds.width;
76          int scrHeight = scrBounds.height;
77  
78          // Insets include the task bar. Take them into account.
79          Insets scrInsets = toolkit.getScreenInsets(gc);
80          scrBounds.x += scrInsets.left;
81          scrBounds.y += scrInsets.top;
82          scrWidth -= scrInsets.left + scrInsets.right;
83          scrHeight -= scrInsets.top + scrInsets.bottom;
84  
85          int scrRightX = scrBounds.x + scrWidth;
86          int scrBottomY = scrBounds.y + scrHeight;
87  
88          // Ensure that popup menu fits the screen
89          if (popupRightX > (long) scrRightX) {
90              popupLocation.x = scrRightX - popupSize.width;
91          }
92  
93          if (popupBottomY > (long) scrBottomY) {
94              popupLocation.y = scrBottomY - popupSize.height;
95          }
96  
97          if (popupLocation.x < scrBounds.x) {
98              popupLocation.x = scrBounds.x;
99          }
100 
101         if (popupLocation.y < scrBounds.y) {
102             popupLocation.y = scrBounds.y;
103         }
104 
105         return popupLocation;
106     }
107 
108     /**
109      * Tries to find GraphicsConfiguration
110      * that contains the mouse cursor position.
111      * Can return null.
112      */
113     private GraphicsConfiguration getCurrentGraphicsConfiguration(JComponent owner, Point popupLocation) {
114         GraphicsConfiguration gc = null;
115         GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
116         GraphicsDevice[] gd = ge.getScreenDevices();
117         for (GraphicsDevice aGd : gd) {
118             if (aGd.getType() == GraphicsDevice.TYPE_RASTER_SCREEN) {
119                 GraphicsConfiguration dgc = aGd.getDefaultConfiguration();
120                 if (dgc.getBounds().contains(popupLocation)) {
121                     gc = dgc;
122                     break;
123                 }
124             }
125         }
126         // If not found, ask this about his gc
127         if (gc == null) {
128             owner.getGraphicsConfiguration();
129         }
130         return gc;
131     }
132 
133 }