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
;
10 import java
.awt
.RadialGradientPaint
;
11 import java
.awt
.RenderingHints
;
12 import java
.io
.IOException
;
13 import java
.net
.URISyntaxException
;
15 import javax
.swing
.JComponent
;
16 import javax
.swing
.JEditorPane
;
17 import javax
.swing
.JLabel
;
18 import javax
.swing
.JOptionPane
;
19 import javax
.swing
.JScrollPane
;
20 import javax
.swing
.UIManager
;
21 import javax
.swing
.UnsupportedLookAndFeelException
;
22 import javax
.swing
.event
.HyperlinkEvent
;
23 import javax
.swing
.event
.HyperlinkListener
;
25 import be
.nikiroo
.fanfix
.Instance
;
26 import be
.nikiroo
.utils
.Version
;
27 import be
.nikiroo
.utils
.VersionCheck
;
30 * Some Java Swing utilities.
34 public class UIUtils
{
36 * Set a fake "native Look & Feel" for the application if possible
37 * (check for the one currently in use, then try GTK).
39 * <b>Must</b> be called prior to any GUI work.
41 * @return TRUE if it succeeded
43 static public boolean setLookAndFeel() {
45 String noLF
= "javax.swing.plaf.metal.MetalLookAndFeel";
46 String lf
= UIManager
.getSystemLookAndFeelClassName();
48 lf
= "com.sun.java.swing.plaf.gtk.GTKLookAndFeel";
50 return setLookAndFeel(lf
);
54 * Switch to the given Look & Feel for the application if possible
55 * (check for the one currently in use, then try GTK).
57 * <b>Must</b> be called prior to any GUI work.
60 * the Look & Feel to use
62 * @return TRUE if it succeeded
64 static public boolean setLookAndFeel(String laf
) {
66 UIManager
.setLookAndFeel(laf
);
68 } catch (InstantiationException e
) {
69 } catch (ClassNotFoundException e
) {
70 } catch (UnsupportedLookAndFeelException e
) {
71 } catch (IllegalAccessException e
) {
78 * Draw a 3D-looking ellipse at the given location, if the given
79 * {@link Graphics} object is compatible (with {@link Graphics2D}); draw a
80 * simple ellipse if not.
83 * the {@link Graphics} to draw on
95 static public void drawEllipse3D(Graphics g
, Color color
, int x
, int y
,
96 int width
, int height
) {
97 drawEllipse3D(g
, color
, x
, y
, width
, height
, true);
101 * Draw a 3D-looking ellipse at the given location, if the given
102 * {@link Graphics} object is compatible (with {@link Graphics2D}); draw a
103 * simple ellipse if not.
106 * the {@link Graphics} to draw on
110 * the X coordinate of the upper left corner
112 * the Y coordinate of the upper left corner
118 * fill the content of the ellipse
120 static public void drawEllipse3D(Graphics g
, Color color
, int x
, int y
,
121 int width
, int height
, boolean fill
) {
122 if (g
instanceof Graphics2D
) {
123 Graphics2D g2
= (Graphics2D
) g
;
124 g2
.setRenderingHint(RenderingHints
.KEY_ANTIALIASING
,
125 RenderingHints
.VALUE_ANTIALIAS_ON
);
127 // Retains the previous state
128 Paint oldPaint
= g2
.getPaint();
133 g2
.fillOval(x
, y
, width
, height
);
135 g2
.drawOval(x
, y
, width
, height
);
138 // Compute dark/bright colours
140 Color dark
= color
.darker().darker();
141 Color bright
= color
.brighter().brighter();
142 Color darkEnd
= new Color(dark
.getRed(), dark
.getGreen(),
144 Color darkPartial
= new Color(dark
.getRed(), dark
.getGreen(),
146 Color brightEnd
= new Color(bright
.getRed(), bright
.getGreen(),
147 bright
.getBlue(), 0);
149 // Adds shadows at the bottom left
150 p
= new GradientPaint(0, height
, dark
, width
, 0, darkEnd
);
153 g2
.fillOval(x
, y
, width
, height
);
155 g2
.drawOval(x
, y
, width
, height
);
157 // Adds highlights at the top right
158 p
= new GradientPaint(width
, 0, bright
, 0, height
, brightEnd
);
161 g2
.fillOval(x
, y
, width
, height
);
163 g2
.drawOval(x
, y
, width
, height
);
167 p
= new RadialGradientPaint(x
+ width
/ 2f
, y
+ height
/ 2f
,
168 Math
.min(width
/ 2f
, height
/ 2f
), new float[] { 0f
, 1f
},
169 new Color
[] { darkEnd
, darkPartial
},
170 RadialGradientPaint
.CycleMethod
.NO_CYCLE
);
173 g2
.fillOval(x
, y
, width
, height
);
175 g2
.drawOval(x
, y
, width
, height
);
178 // Adds inner highlight at the top right
179 p
= new RadialGradientPaint(x
+ 3f
* width
/ 4f
, y
+ height
/ 4f
,
180 Math
.min(width
/ 4f
, height
/ 4f
),
181 new float[] { 0.0f
, 0.8f
},
182 new Color
[] { bright
, brightEnd
},
183 RadialGradientPaint
.CycleMethod
.NO_CYCLE
);
186 g2
.fillOval(x
* 2, y
, width
, height
);
188 g2
.drawOval(x
* 2, y
, width
, height
);
191 // Reset original paint
192 g2
.setPaint(oldPaint
);
196 g
.fillOval(x
, y
, width
, height
);
198 g
.drawOval(x
, y
, width
, height
);
204 * Add a {@link JScrollPane} around the given panel and use a sensible (for
205 * me) increment for the mouse wheel.
208 * the panel to wrap in a {@link JScrollPane}
209 * @param allowHorizontal
210 * allow horizontal scrolling (not always desired)
212 * @return the {@link JScrollPane}
214 static public JScrollPane
scroll(JComponent pane
, boolean allowHorizontal
) {
215 return scroll(pane
, allowHorizontal
, true);
219 * Add a {@link JScrollPane} around the given panel and use a sensible (for
220 * me) increment for the mouse wheel.
223 * the panel to wrap in a {@link JScrollPane}
224 * @param allowHorizontal
225 * allow horizontal scrolling (not always desired)
226 * @param allowVertical
227 * allow vertical scrolling (usually yes, but sometimes you only
230 * @return the {@link JScrollPane}
232 static public JScrollPane
scroll(JComponent pane
, boolean allowHorizontal
,
233 boolean allowVertical
) {
234 JScrollPane scroll
= new JScrollPane(pane
);
236 scroll
.getVerticalScrollBar().setUnitIncrement(16);
237 scroll
.getHorizontalScrollBar().setUnitIncrement(16);
239 if (!allowHorizontal
) {
240 scroll
.setHorizontalScrollBarPolicy(
241 JScrollPane
.HORIZONTAL_SCROLLBAR_NEVER
);
243 if (!allowVertical
) {
244 scroll
.setVerticalScrollBarPolicy(
245 JScrollPane
.VERTICAL_SCROLLBAR_NEVER
);
252 * Show a confirmation message to the user to show him the changes since
255 * HTML 3.2 supported, links included (the user browser will be launched if
258 * If this is already the latest version, a message will still be displayed.
260 * @param parentComponent
261 * determines the {@link java.awt.Frame} in which the dialog is
262 * displayed; if <code>null</code>, or if the
263 * <code>parentComponent</code> has no {@link java.awt.Frame}, a
264 * default {@link java.awt.Frame} is used
268 * an introduction text before the list of changes
270 * the title of the dialog
272 * @return TRUE if the user clicked on OK, false if the dialog was dismissed
274 static public boolean showUpdatedDialog(Component parentComponent
,
275 VersionCheck updates
, String introText
, String title
) {
277 StringBuilder builder
= new StringBuilder();
278 final JEditorPane updateMessage
= new JEditorPane("text/html", "");
279 if (introText
!= null && !introText
.isEmpty()) {
280 builder
.append(introText
);
281 builder
.append("<br>");
282 builder
.append("<br>");
284 for (Version v
: updates
.getNewer()) {
285 builder
.append("\t<b>" //
286 + "Version " + v
.toString() //
288 builder
.append("<br>");
289 builder
.append("<ul>");
290 for (String item
: updates
.getChanges().get(v
)) {
291 builder
.append("<li>" + item
+ "</li>");
293 builder
.append("</ul>");
297 updateMessage
.setText("<html><body>" //
301 // handle link events
302 updateMessage
.addHyperlinkListener(new HyperlinkListener() {
304 public void hyperlinkUpdate(HyperlinkEvent e
) {
305 if (e
.getEventType().equals(HyperlinkEvent
.EventType
.ACTIVATED
))
307 Desktop
.getDesktop().browse(e
.getURL().toURI());
308 } catch (IOException ee
) {
309 Instance
.getInstance().getTraceHandler().error(ee
);
310 } catch (URISyntaxException ee
) {
311 Instance
.getInstance().getTraceHandler().error(ee
);
315 updateMessage
.setEditable(false);
316 updateMessage
.setBackground(new JLabel().getBackground());
317 updateMessage
.addHyperlinkListener(new HyperlinkListener() {
319 public void hyperlinkUpdate(HyperlinkEvent evn
) {
320 if (evn
.getEventType() == HyperlinkEvent
.EventType
.ACTIVATED
) {
321 if (Desktop
.isDesktopSupported()) {
323 Desktop
.getDesktop().browse(evn
.getURL().toURI());
324 } catch (IOException e
) {
325 } catch (URISyntaxException e
) {
332 return JOptionPane
.showConfirmDialog(parentComponent
, updateMessage
,
333 title
, JOptionPane
.DEFAULT_OPTION
) == JOptionPane
.OK_OPTION
;