1 package be
.nikiroo
.utils
.ui
;
4 import java
.awt
.Component
;
5 import java
.awt
.Desktop
;
6 import java
.awt
.GradientPaint
;
7 import java
.awt
.Graphics
;
8 import java
.awt
.Graphics2D
;
9 import java
.awt
.GraphicsConfiguration
;
10 import java
.awt
.GraphicsDevice
;
11 import java
.awt
.GraphicsEnvironment
;
12 import java
.awt
.Paint
;
13 import java
.awt
.Point
;
14 import java
.awt
.RadialGradientPaint
;
15 import java
.awt
.Rectangle
;
16 import java
.awt
.RenderingHints
;
17 import java
.awt
.Window
;
18 import java
.io
.IOException
;
19 import java
.net
.URISyntaxException
;
21 import javax
.swing
.JButton
;
22 import javax
.swing
.JComponent
;
23 import javax
.swing
.JEditorPane
;
24 import javax
.swing
.JLabel
;
25 import javax
.swing
.JOptionPane
;
26 import javax
.swing
.JScrollPane
;
27 import javax
.swing
.UIManager
;
28 import javax
.swing
.UnsupportedLookAndFeelException
;
29 import javax
.swing
.event
.HyperlinkEvent
;
30 import javax
.swing
.event
.HyperlinkListener
;
32 import be
.nikiroo
.utils
.Version
;
33 import be
.nikiroo
.utils
.VersionCheck
;
35 import com
.sun
.java
.swing
.plaf
.windows
.resources
.windows
;
38 * Some Java Swing utilities.
42 public class UIUtils
{
43 static private Color buttonNormal
;
44 static private Color buttonPressed
;
47 * Set a fake "native Look & Feel" for the application if possible
48 * (check for the one currently in use, then try GTK).
50 * <b>Must</b> be called prior to any GUI work.
52 * @return TRUE if it succeeded
54 static public boolean setLookAndFeel() {
56 String noLF
= "javax.swing.plaf.metal.MetalLookAndFeel";
57 String lf
= UIManager
.getSystemLookAndFeelClassName();
59 lf
= "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
61 return setLookAndFeel(lf
);
65 * Switch to the given Look & Feel for the application if possible
66 * (check for the one currently in use, then try GTK).
68 * <b>Must</b> be called prior to any GUI work.
71 * the Look & Feel to use
73 * @return TRUE if it succeeded
75 static public boolean setLookAndFeel(String laf
) {
77 UIManager
.setLookAndFeel(laf
);
79 } catch (InstantiationException e
) {
80 } catch (ClassNotFoundException e
) {
81 } catch (UnsupportedLookAndFeelException e
) {
82 } catch (IllegalAccessException e
) {
89 * Draw a 3D-looking ellipse at the given location, if the given
90 * {@link Graphics} object is compatible (with {@link Graphics2D}); draw a
91 * simple ellipse if not.
94 * the {@link Graphics} to draw on
106 static public void drawEllipse3D(Graphics g
, Color color
, int x
, int y
,
107 int width
, int height
) {
108 drawEllipse3D(g
, color
, x
, y
, width
, height
, true);
112 * Draw a 3D-looking ellipse at the given location, if the given
113 * {@link Graphics} object is compatible (with {@link Graphics2D}); draw a
114 * simple ellipse if not.
117 * the {@link Graphics} to draw on
121 * the X coordinate of the upper left corner
123 * the Y coordinate of the upper left corner
129 * fill the content of the ellipse
131 static public void drawEllipse3D(Graphics g
, Color color
, int x
, int y
,
132 int width
, int height
, boolean fill
) {
133 if (g
instanceof Graphics2D
) {
134 Graphics2D g2
= (Graphics2D
) g
;
135 g2
.setRenderingHint(RenderingHints
.KEY_ANTIALIASING
,
136 RenderingHints
.VALUE_ANTIALIAS_ON
);
138 // Retains the previous state
139 Paint oldPaint
= g2
.getPaint();
144 g2
.fillOval(x
, y
, width
, height
);
146 g2
.drawOval(x
, y
, width
, height
);
149 // Compute dark/bright colours
151 Color dark
= color
.darker().darker();
152 Color bright
= color
.brighter().brighter();
153 Color darkEnd
= new Color(dark
.getRed(), dark
.getGreen(),
155 Color darkPartial
= new Color(dark
.getRed(), dark
.getGreen(),
157 Color brightEnd
= new Color(bright
.getRed(), bright
.getGreen(),
158 bright
.getBlue(), 0);
160 // Adds shadows at the bottom left
161 p
= new GradientPaint(0, height
, dark
, width
, 0, darkEnd
);
164 g2
.fillOval(x
, y
, width
, height
);
166 g2
.drawOval(x
, y
, width
, height
);
168 // Adds highlights at the top right
169 p
= new GradientPaint(width
, 0, bright
, 0, height
, brightEnd
);
172 g2
.fillOval(x
, y
, width
, height
);
174 g2
.drawOval(x
, y
, width
, height
);
178 p
= new RadialGradientPaint(x
+ width
/ 2f
, y
+ height
/ 2f
,
179 Math
.min(width
/ 2f
, height
/ 2f
), new float[] { 0f
, 1f
},
180 new Color
[] { darkEnd
, darkPartial
},
181 RadialGradientPaint
.CycleMethod
.NO_CYCLE
);
184 g2
.fillOval(x
, y
, width
, height
);
186 g2
.drawOval(x
, y
, width
, height
);
189 // Adds inner highlight at the top right
190 p
= new RadialGradientPaint(x
+ 3f
* width
/ 4f
, y
+ height
/ 4f
,
191 Math
.min(width
/ 4f
, height
/ 4f
),
192 new float[] { 0.0f
, 0.8f
},
193 new Color
[] { bright
, brightEnd
},
194 RadialGradientPaint
.CycleMethod
.NO_CYCLE
);
197 g2
.fillOval(x
* 2, y
, width
, height
);
199 g2
.drawOval(x
* 2, y
, width
, height
);
202 // Reset original paint
203 g2
.setPaint(oldPaint
);
207 g
.fillOval(x
, y
, width
, height
);
209 g
.drawOval(x
, y
, width
, height
);
215 * Add a {@link JScrollPane} around the given panel and use a sensible (for
216 * me) increment for the mouse wheel.
219 * the panel to wrap in a {@link JScrollPane}
220 * @param allowHorizontal
221 * allow horizontal scrolling (not always desired)
223 * @return the {@link JScrollPane}
225 static public JScrollPane
scroll(JComponent pane
, boolean allowHorizontal
) {
226 return scroll(pane
, allowHorizontal
, true);
230 * Add a {@link JScrollPane} around the given panel and use a sensible (for
231 * me) increment for the mouse wheel.
234 * the panel to wrap in a {@link JScrollPane}
235 * @param allowHorizontal
236 * allow horizontal scrolling (not always desired)
237 * @param allowVertical
238 * allow vertical scrolling (usually yes, but sometimes you only
241 * @return the {@link JScrollPane}
243 static public JScrollPane
scroll(JComponent pane
, boolean allowHorizontal
,
244 boolean allowVertical
) {
245 JScrollPane scroll
= new JScrollPane(pane
);
247 scroll
.getVerticalScrollBar().setUnitIncrement(16);
248 scroll
.getHorizontalScrollBar().setUnitIncrement(16);
250 if (!allowHorizontal
) {
251 scroll
.setHorizontalScrollBarPolicy(JScrollPane
.HORIZONTAL_SCROLLBAR_NEVER
);
253 if (!allowVertical
) {
254 scroll
.setVerticalScrollBarPolicy(JScrollPane
.VERTICAL_SCROLLBAR_NEVER
);
261 * Show a confirmation message to the user to show him the changes since
264 * HTML 3.2 supported, links included (the user browser will be launched if
267 * If this is already the latest version, a message will still be displayed.
269 * @param parentComponent
270 * determines the {@link java.awt.Frame} in which the dialog is
271 * displayed; if <code>null</code>, or if the
272 * <code>parentComponent</code> has no {@link java.awt.Frame}, a
273 * default {@link java.awt.Frame} is used
277 * an introduction text before the list of changes
279 * the title of the dialog
281 * @return TRUE if the user clicked on OK, false if the dialog was dismissed
283 static public boolean showUpdatedDialog(Component parentComponent
,
284 VersionCheck updates
, String introText
, String title
) {
286 StringBuilder builder
= new StringBuilder();
287 final JEditorPane updateMessage
= new JEditorPane("text/html", "");
288 if (introText
!= null && !introText
.isEmpty()) {
289 builder
.append(introText
);
290 builder
.append("<br>");
291 builder
.append("<br>");
293 for (Version v
: updates
.getNewer()) {
294 builder
.append("\t<b>" //
295 + "Version " + v
.toString() //
297 builder
.append("<br>");
298 builder
.append("<ul>");
299 for (String item
: updates
.getChanges().get(v
)) {
300 builder
.append("<li>" + item
+ "</li>");
302 builder
.append("</ul>");
306 updateMessage
.setText("<html><body>" //
310 // handle link events
311 updateMessage
.addHyperlinkListener(new HyperlinkListener() {
313 public void hyperlinkUpdate(HyperlinkEvent e
) {
314 if (e
.getEventType().equals(HyperlinkEvent
.EventType
.ACTIVATED
))
316 Desktop
.getDesktop().browse(e
.getURL().toURI());
317 } catch (IOException ee
) {
318 ee
.printStackTrace();
319 } catch (URISyntaxException ee
) {
320 ee
.printStackTrace();
324 updateMessage
.setEditable(false);
325 updateMessage
.setBackground(new JLabel().getBackground());
326 updateMessage
.addHyperlinkListener(new HyperlinkListener() {
328 public void hyperlinkUpdate(HyperlinkEvent evn
) {
329 if (evn
.getEventType() == HyperlinkEvent
.EventType
.ACTIVATED
) {
330 if (Desktop
.isDesktopSupported()) {
332 Desktop
.getDesktop().browse(evn
.getURL().toURI());
333 } catch (IOException e
) {
334 } catch (URISyntaxException e
) {
341 return JOptionPane
.showConfirmDialog(parentComponent
, updateMessage
,
342 title
, JOptionPane
.DEFAULT_OPTION
) == JOptionPane
.OK_OPTION
;
346 * Set the given {@link JButton} as "pressed" (selected, but with more UI
349 * The {@link JButton} will answer {@link JButton#isSelected()} if it is
353 * the button to select/press
355 * the new "pressed" state
357 static public void setButtonPressed(JButton button
, boolean pressed
) {
358 if (buttonNormal
== null) {
359 JButton defButton
= new JButton(" ");
360 buttonNormal
= defButton
.getBackground();
361 if (buttonNormal
.getBlue() >= 128) {
362 buttonPressed
= new Color( //
363 Math
.max(buttonNormal
.getRed() - 100, 0), //
364 Math
.max(buttonNormal
.getGreen() - 100, 0), //
365 Math
.max(buttonNormal
.getBlue() - 100, 0));
367 buttonPressed
= new Color( //
368 Math
.min(buttonNormal
.getRed() + 100, 255), //
369 Math
.min(buttonNormal
.getGreen() + 100, 255), //
370 Math
.min(buttonNormal
.getBlue() + 100, 255));
374 button
.setSelected(pressed
);
375 button
.setBackground(pressed ? buttonPressed
: buttonNormal
);
379 * Set the given {@link windows} to full screen mode, on the desktop it
380 * currently resides on.
382 * Can be cancelled by calling again with a NULL value.
385 * the window to set to full screen
387 static public void setFullscreenWindow(Window win
) {
388 GraphicsEnvironment env
= GraphicsEnvironment
389 .getLocalGraphicsEnvironment();
390 GraphicsDevice
[] screens
= env
.getScreenDevices();
393 for (GraphicsDevice screen
: screens
) {
395 screen
.setFullScreenWindow(null);
402 Rectangle r
= win
.getBounds();
403 Point center
= new Point(r
.x
+ r
.width
/ 2, r
.y
+ r
.height
/ 2);
405 GraphicsDevice current
= null;
406 for (GraphicsDevice screen
: screens
) {
407 GraphicsConfiguration
[] confs
= screen
.getConfigurations();
408 for (GraphicsConfiguration conf
: confs
) {
409 if (conf
.getBounds().contains(center
)) {
419 if (current
== null) {
420 current
= GraphicsEnvironment
.getLocalGraphicsEnvironment()
421 .getDefaultScreenDevice();
424 current
.setFullScreenWindow(win
);