source: josm/trunk/src/org/openstreetmap/josm/gui/util/GuiHelper.java@ 12644

Last change on this file since 12644 was 12644, checked in by Don-vip, 7 years ago

see #15182 - remove dependence of I18n on GUI

  • Property svn:eol-style set to native
File size: 25.4 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.gui.util;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.Color;
7import java.awt.Component;
8import java.awt.Container;
9import java.awt.Dialog;
10import java.awt.Dimension;
11import java.awt.DisplayMode;
12import java.awt.Font;
13import java.awt.Frame;
14import java.awt.GraphicsDevice;
15import java.awt.GraphicsEnvironment;
16import java.awt.GridBagLayout;
17import java.awt.HeadlessException;
18import java.awt.Image;
19import java.awt.Stroke;
20import java.awt.Toolkit;
21import java.awt.Window;
22import java.awt.event.ActionListener;
23import java.awt.event.KeyEvent;
24import java.awt.event.MouseAdapter;
25import java.awt.event.MouseEvent;
26import java.awt.image.FilteredImageSource;
27import java.lang.reflect.InvocationTargetException;
28import java.util.Arrays;
29import java.util.Collection;
30import java.util.Enumeration;
31import java.util.EventObject;
32import java.util.Locale;
33import java.util.concurrent.Callable;
34import java.util.concurrent.ExecutionException;
35import java.util.concurrent.FutureTask;
36
37import javax.swing.GrayFilter;
38import javax.swing.ImageIcon;
39import javax.swing.JColorChooser;
40import javax.swing.JComponent;
41import javax.swing.JFileChooser;
42import javax.swing.JLabel;
43import javax.swing.JOptionPane;
44import javax.swing.JPanel;
45import javax.swing.JPopupMenu;
46import javax.swing.JScrollPane;
47import javax.swing.Scrollable;
48import javax.swing.SwingUtilities;
49import javax.swing.Timer;
50import javax.swing.ToolTipManager;
51import javax.swing.UIManager;
52import javax.swing.plaf.FontUIResource;
53
54import org.openstreetmap.josm.Main;
55import org.openstreetmap.josm.data.preferences.StrokeProperty;
56import org.openstreetmap.josm.gui.ExtendedDialog;
57import org.openstreetmap.josm.gui.MainApplication;
58import org.openstreetmap.josm.gui.widgets.AbstractFileChooser;
59import org.openstreetmap.josm.gui.widgets.HtmlPanel;
60import org.openstreetmap.josm.tools.CheckParameterUtil;
61import org.openstreetmap.josm.tools.ColorHelper;
62import org.openstreetmap.josm.tools.GBC;
63import org.openstreetmap.josm.tools.ImageOverlay;
64import org.openstreetmap.josm.tools.ImageProvider;
65import org.openstreetmap.josm.tools.ImageProvider.ImageSizes;
66import org.openstreetmap.josm.tools.LanguageInfo;
67import org.openstreetmap.josm.tools.Logging;
68import org.openstreetmap.josm.tools.bugreport.BugReport;
69import org.openstreetmap.josm.tools.bugreport.ReportedException;
70
71/**
72 * basic gui utils
73 */
74public final class GuiHelper {
75
76 /* Localization keys for file chooser (and color chooser). */
77 private static final String[] JAVA_INTERNAL_MESSAGE_KEYS = new String[] {
78 /* JFileChooser windows laf */
79 "FileChooser.detailsViewActionLabelText",
80 "FileChooser.detailsViewButtonAccessibleName",
81 "FileChooser.detailsViewButtonToolTipText",
82 "FileChooser.fileAttrHeaderText",
83 "FileChooser.fileDateHeaderText",
84 "FileChooser.fileNameHeaderText",
85 "FileChooser.fileNameLabelText",
86 "FileChooser.fileSizeHeaderText",
87 "FileChooser.fileTypeHeaderText",
88 "FileChooser.filesOfTypeLabelText",
89 "FileChooser.homeFolderAccessibleName",
90 "FileChooser.homeFolderToolTipText",
91 "FileChooser.listViewActionLabelText",
92 "FileChooser.listViewButtonAccessibleName",
93 "FileChooser.listViewButtonToolTipText",
94 "FileChooser.lookInLabelText",
95 "FileChooser.newFolderAccessibleName",
96 "FileChooser.newFolderActionLabelText",
97 "FileChooser.newFolderToolTipText",
98 "FileChooser.refreshActionLabelText",
99 "FileChooser.saveInLabelText",
100 "FileChooser.upFolderAccessibleName",
101 "FileChooser.upFolderToolTipText",
102 "FileChooser.viewMenuLabelText",
103
104 /* JFileChooser gtk laf */
105 "FileChooser.acceptAllFileFilterText",
106 "FileChooser.cancelButtonText",
107 "FileChooser.cancelButtonToolTipText",
108 "FileChooser.deleteFileButtonText",
109 "FileChooser.filesLabelText",
110 "FileChooser.filterLabelText",
111 "FileChooser.foldersLabelText",
112 "FileChooser.newFolderButtonText",
113 "FileChooser.newFolderDialogText",
114 "FileChooser.openButtonText",
115 "FileChooser.openButtonToolTipText",
116 "FileChooser.openDialogTitleText",
117 "FileChooser.pathLabelText",
118 "FileChooser.renameFileButtonText",
119 "FileChooser.renameFileDialogText",
120 "FileChooser.renameFileErrorText",
121 "FileChooser.renameFileErrorTitle",
122 "FileChooser.saveButtonText",
123 "FileChooser.saveButtonToolTipText",
124 "FileChooser.saveDialogTitleText",
125
126 /* JFileChooser motif laf */
127 //"FileChooser.cancelButtonText",
128 //"FileChooser.cancelButtonToolTipText",
129 "FileChooser.enterFileNameLabelText",
130 //"FileChooser.filesLabelText",
131 //"FileChooser.filterLabelText",
132 //"FileChooser.foldersLabelText",
133 "FileChooser.helpButtonText",
134 "FileChooser.helpButtonToolTipText",
135 //"FileChooser.openButtonText",
136 //"FileChooser.openButtonToolTipText",
137 //"FileChooser.openDialogTitleText",
138 //"FileChooser.pathLabelText",
139 //"FileChooser.saveButtonText",
140 //"FileChooser.saveButtonToolTipText",
141 //"FileChooser.saveDialogTitleText",
142 "FileChooser.updateButtonText",
143 "FileChooser.updateButtonToolTipText",
144
145 /* gtk color chooser */
146 "GTKColorChooserPanel.blueText",
147 "GTKColorChooserPanel.colorNameText",
148 "GTKColorChooserPanel.greenText",
149 "GTKColorChooserPanel.hueText",
150 "GTKColorChooserPanel.nameText",
151 "GTKColorChooserPanel.redText",
152 "GTKColorChooserPanel.saturationText",
153 "GTKColorChooserPanel.valueText",
154
155 /* JOptionPane */
156 "OptionPane.okButtonText",
157 "OptionPane.yesButtonText",
158 "OptionPane.noButtonText",
159 "OptionPane.cancelButtonText"
160 };
161
162 private GuiHelper() {
163 // Hide default constructor for utils classes
164 }
165
166 /**
167 * disable / enable a component and all its child components
168 * @param root component
169 * @param enabled enabled state
170 */
171 public static void setEnabledRec(Container root, boolean enabled) {
172 root.setEnabled(enabled);
173 Component[] children = root.getComponents();
174 for (Component child : children) {
175 if (child instanceof Container) {
176 setEnabledRec((Container) child, enabled);
177 } else {
178 child.setEnabled(enabled);
179 }
180 }
181 }
182
183 /**
184 * Add a task to the main worker that will block the worker and run in the GUI thread.
185 * @param task The task to run
186 */
187 public static void executeByMainWorkerInEDT(final Runnable task) {
188 MainApplication.worker.submit(() -> runInEDTAndWait(task));
189 }
190
191 /**
192 * Executes asynchronously a runnable in
193 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html">Event Dispatch Thread</a>.
194 * @param task The runnable to execute
195 * @see SwingUtilities#invokeLater
196 */
197 public static void runInEDT(Runnable task) {
198 if (SwingUtilities.isEventDispatchThread()) {
199 task.run();
200 } else {
201 SwingUtilities.invokeLater(task);
202 }
203 }
204
205 /**
206 * Executes synchronously a runnable in
207 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html">Event Dispatch Thread</a>.
208 * @param task The runnable to execute
209 * @see SwingUtilities#invokeAndWait
210 */
211 public static void runInEDTAndWait(Runnable task) {
212 if (SwingUtilities.isEventDispatchThread()) {
213 task.run();
214 } else {
215 try {
216 SwingUtilities.invokeAndWait(task);
217 } catch (InterruptedException | InvocationTargetException e) {
218 Logging.error(e);
219 }
220 }
221 }
222
223 /**
224 * Executes synchronously a runnable in
225 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html">Event Dispatch Thread</a>.
226 * <p>
227 * Passes on the exception that was thrown to the thread calling this.
228 * The exception is wrapped using a {@link ReportedException}.
229 * @param task The runnable to execute
230 * @see SwingUtilities#invokeAndWait
231 * @since 10271
232 */
233 public static void runInEDTAndWaitWithException(Runnable task) {
234 if (SwingUtilities.isEventDispatchThread()) {
235 task.run();
236 } else {
237 try {
238 SwingUtilities.invokeAndWait(task);
239 } catch (InterruptedException | InvocationTargetException e) {
240 throw BugReport.intercept(e).put("task", task);
241 }
242 }
243 }
244
245 /**
246 * Executes synchronously a callable in
247 * <a href="http://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html">Event Dispatch Thread</a>
248 * and return a value.
249 * @param <V> the result type of method <tt>call</tt>
250 * @param callable The callable to execute
251 * @return The computed result
252 * @since 7204
253 */
254 public static <V> V runInEDTAndWaitAndReturn(Callable<V> callable) {
255 if (SwingUtilities.isEventDispatchThread()) {
256 try {
257 return callable.call();
258 } catch (Exception e) { // NOPMD
259 Logging.error(e);
260 return null;
261 }
262 } else {
263 FutureTask<V> task = new FutureTask<>(callable);
264 SwingUtilities.invokeLater(task);
265 try {
266 return task.get();
267 } catch (InterruptedException | ExecutionException e) {
268 Logging.error(e);
269 return null;
270 }
271 }
272 }
273
274 /**
275 * This function fails if it was not called from the EDT thread.
276 * @throws IllegalStateException if called from wrong thread.
277 * @since 10271
278 */
279 public static void assertCallFromEdt() {
280 if (!SwingUtilities.isEventDispatchThread()) {
281 throw new IllegalStateException(
282 "Needs to be called from the EDT thread, not from " + Thread.currentThread().getName());
283 }
284 }
285
286 /**
287 * Warns user about a dangerous action requiring confirmation.
288 * @param title Title of dialog
289 * @param content Content of dialog
290 * @param baseActionIcon Unused? FIXME why is this parameter unused?
291 * @param continueToolTip Tooltip to display for "continue" button
292 * @return true if the user wants to cancel, false if they want to continue
293 */
294 public static boolean warnUser(String title, String content, ImageIcon baseActionIcon, String continueToolTip) {
295 ExtendedDialog dlg = new ExtendedDialog(Main.parent,
296 title, tr("Cancel"), tr("Continue"));
297 dlg.setContent(content);
298 dlg.setButtonIcons(
299 new ImageProvider("cancel").setMaxSize(ImageSizes.LARGEICON).get(),
300 new ImageProvider("upload").setMaxSize(ImageSizes.LARGEICON).addOverlay(
301 new ImageOverlay(new ImageProvider("warning-small"), 0.5, 0.5, 1.0, 1.0)).get());
302 dlg.setToolTipTexts(tr("Cancel"), continueToolTip);
303 dlg.setIcon(JOptionPane.WARNING_MESSAGE);
304 dlg.setCancelButton(1);
305 return dlg.showDialog().getValue() != 2;
306 }
307
308 /**
309 * Notifies user about an error received from an external source as an HTML page.
310 * @param parent Parent component
311 * @param title Title of dialog
312 * @param message Message displayed at the top of the dialog
313 * @param html HTML content to display (real error message)
314 * @since 7312
315 */
316 public static void notifyUserHtmlError(Component parent, String title, String message, String html) {
317 JPanel p = new JPanel(new GridBagLayout());
318 p.add(new JLabel(message), GBC.eol());
319 p.add(new JLabel(tr("Received error page:")), GBC.eol());
320 JScrollPane sp = embedInVerticalScrollPane(new HtmlPanel(html));
321 sp.setPreferredSize(new Dimension(640, 240));
322 p.add(sp, GBC.eol().fill(GBC.BOTH));
323
324 ExtendedDialog ed = new ExtendedDialog(parent, title, tr("OK"));
325 ed.setButtonIcons("ok");
326 ed.setContent(p);
327 ed.showDialog();
328 }
329
330 /**
331 * Replies the disabled (grayed) version of the specified image.
332 * @param image The image to disable
333 * @return The disabled (grayed) version of the specified image, brightened by 20%.
334 * @since 5484
335 */
336 public static Image getDisabledImage(Image image) {
337 return Toolkit.getDefaultToolkit().createImage(
338 new FilteredImageSource(image.getSource(), new GrayFilter(true, 20)));
339 }
340
341 /**
342 * Replies the disabled (grayed) version of the specified icon.
343 * @param icon The icon to disable
344 * @return The disabled (grayed) version of the specified icon, brightened by 20%.
345 * @since 5484
346 */
347 public static ImageIcon getDisabledIcon(ImageIcon icon) {
348 return new ImageIcon(getDisabledImage(icon.getImage()));
349 }
350
351 /**
352 * Attaches a {@code HierarchyListener} to the specified {@code Component} that
353 * will set its parent dialog resizeable. Use it before a call to JOptionPane#showXXXXDialog
354 * to make it resizeable.
355 * @param pane The component that will be displayed
356 * @param minDimension The minimum dimension that will be set for the dialog. Ignored if null
357 * @return {@code pane}
358 * @since 5493
359 */
360 public static Component prepareResizeableOptionPane(final Component pane, final Dimension minDimension) {
361 if (pane != null) {
362 pane.addHierarchyListener(e -> {
363 Window window = SwingUtilities.getWindowAncestor(pane);
364 if (window instanceof Dialog) {
365 Dialog dialog = (Dialog) window;
366 if (!dialog.isResizable()) {
367 dialog.setResizable(true);
368 if (minDimension != null) {
369 dialog.setMinimumSize(minDimension);
370 }
371 }
372 }
373 });
374 }
375 return pane;
376 }
377
378 /**
379 * Schedules a new Timer to be run in the future (once or several times).
380 * @param initialDelay milliseconds for the initial and between-event delay if repeatable
381 * @param actionListener an initial listener; can be null
382 * @param repeats specify false to make the timer stop after sending its first action event
383 * @return The (started) timer.
384 * @since 5735
385 */
386 public static Timer scheduleTimer(int initialDelay, ActionListener actionListener, boolean repeats) {
387 Timer timer = new Timer(initialDelay, actionListener);
388 timer.setRepeats(repeats);
389 timer.start();
390 return timer;
391 }
392
393 /**
394 * Return s new BasicStroke object with given thickness and style
395 * @param code = 3.5 -&gt; thickness=3.5px; 3.5 10 5 -&gt; thickness=3.5px, dashed: 10px filled + 5px empty
396 * @return stroke for drawing
397 * @see StrokeProperty
398 */
399 public static Stroke getCustomizedStroke(String code) {
400 return StrokeProperty.getFromString(code);
401 }
402
403 /**
404 * Gets the font used to display monospaced text in a component, if possible.
405 * @param component The component
406 * @return the font used to display monospaced text in a component, if possible
407 * @since 7896
408 */
409 public static Font getMonospacedFont(JComponent component) {
410 // Special font for Khmer script
411 if ("km".equals(LanguageInfo.getJOSMLocaleCode())) {
412 return component.getFont();
413 } else {
414 return new Font("Monospaced", component.getFont().getStyle(), component.getFont().getSize());
415 }
416 }
417
418 /**
419 * Gets the font used to display JOSM title in about dialog and splash screen.
420 * @return title font
421 * @since 5797
422 */
423 public static Font getTitleFont() {
424 return new Font("SansSerif", Font.BOLD, 23);
425 }
426
427 /**
428 * Embeds the given component into a new vertical-only scrollable {@code JScrollPane}.
429 * @param panel The component to embed
430 * @return the vertical scrollable {@code JScrollPane}
431 * @since 6666
432 */
433 public static JScrollPane embedInVerticalScrollPane(Component panel) {
434 return new JScrollPane(panel, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
435 }
436
437 /**
438 * Set the default unit increment for a {@code JScrollPane}.
439 *
440 * This fixes slow mouse wheel scrolling when the content of the {@code JScrollPane}
441 * is a {@code JPanel} or other component that does not implement the {@link Scrollable}
442 * interface.
443 * The default unit increment is 1 pixel. Multiplied by the number of unit increments
444 * per mouse wheel "click" (platform dependent, usually 3), this makes a very
445 * sluggish mouse wheel experience.
446 * This methods sets the unit increment to a larger, more reasonable value.
447 * @param sp the scroll pane
448 * @return the scroll pane (same object) with fixed unit increment
449 * @throws IllegalArgumentException if the component inside of the scroll pane
450 * implements the {@code Scrollable} interface ({@code JTree}, {@code JLayer},
451 * {@code JList}, {@code JTextComponent} and {@code JTable})
452 */
453 public static JScrollPane setDefaultIncrement(JScrollPane sp) {
454 if (sp.getViewport().getView() instanceof Scrollable) {
455 throw new IllegalArgumentException();
456 }
457 sp.getVerticalScrollBar().setUnitIncrement(10);
458 sp.getHorizontalScrollBar().setUnitIncrement(10);
459 return sp;
460 }
461
462 /**
463 * Returns extended modifier key used as the appropriate accelerator key for menu shortcuts.
464 * It is advised everywhere to use {@link Toolkit#getMenuShortcutKeyMask()} to get the cross-platform modifier, but:
465 * <ul>
466 * <li>it returns KeyEvent.CTRL_MASK instead of KeyEvent.CTRL_DOWN_MASK. We used the extended
467 * modifier for years, and Oracle recommends to use it instead, so it's best to keep it</li>
468 * <li>the method throws a HeadlessException ! So we would need to handle it for unit tests anyway</li>
469 * </ul>
470 * @return extended modifier key used as the appropriate accelerator key for menu shortcuts
471 * @since 7539
472 */
473 public static int getMenuShortcutKeyMaskEx() {
474 return Main.isPlatformOsx() ? KeyEvent.META_DOWN_MASK : KeyEvent.CTRL_DOWN_MASK;
475 }
476
477 /**
478 * Sets a global font for all UI, replacing default font of current look and feel.
479 * @param name Font name. It is up to the caller to make sure the font exists
480 * @throws IllegalArgumentException if name is null
481 * @since 7896
482 */
483 public static void setUIFont(String name) {
484 CheckParameterUtil.ensureParameterNotNull(name, "name");
485 Logging.info("Setting "+name+" as the default UI font");
486 Enumeration<?> keys = UIManager.getDefaults().keys();
487 while (keys.hasMoreElements()) {
488 Object key = keys.nextElement();
489 Object value = UIManager.get(key);
490 if (value instanceof FontUIResource) {
491 FontUIResource fui = (FontUIResource) value;
492 UIManager.put(key, new FontUIResource(name, fui.getStyle(), fui.getSize()));
493 }
494 }
495 }
496
497 /**
498 * Sets the background color for this component, and adjust the foreground color so the text remains readable.
499 * @param c component
500 * @param background background color
501 * @since 9223
502 */
503 public static void setBackgroundReadable(JComponent c, Color background) {
504 c.setBackground(background);
505 c.setForeground(ColorHelper.getForegroundColor(background));
506 }
507
508 /**
509 * Gets the size of the screen. On systems with multiple displays, the primary display is used.
510 * This method returns always 800x600 in headless mode (useful for unit tests).
511 * @return the size of this toolkit's screen, in pixels, or 800x600
512 * @see Toolkit#getScreenSize
513 * @since 9576
514 */
515 public static Dimension getScreenSize() {
516 return GraphicsEnvironment.isHeadless() ? new Dimension(800, 600) : Toolkit.getDefaultToolkit().getScreenSize();
517 }
518
519 /**
520 * Gets the size of the screen. On systems with multiple displays,
521 * contrary to {@link #getScreenSize()}, the biggest display is used.
522 * This method returns always 800x600 in headless mode (useful for unit tests).
523 * @return the size of maximum screen, in pixels, or 800x600
524 * @see Toolkit#getScreenSize
525 * @since 10470
526 */
527 public static Dimension getMaximumScreenSize() {
528 if (GraphicsEnvironment.isHeadless()) {
529 return new Dimension(800, 600);
530 }
531
532 int height = 0;
533 int width = 0;
534 for (GraphicsDevice gd: GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices()) {
535 DisplayMode dm = gd.getDisplayMode();
536 height = Math.max(height, dm.getHeight());
537 width = Math.max(width, dm.getWidth());
538 }
539 if (height == 0 || width == 0) {
540 return new Dimension(800, 600);
541 }
542 return new Dimension(width, height);
543 }
544
545 /**
546 * Returns the first <code>Window</code> ancestor of event source, or
547 * {@code null} if event source is not a component contained inside a <code>Window</code>.
548 * @param e event object
549 * @return a Window, or {@code null}
550 * @since 9916
551 */
552 public static Window getWindowAncestorFor(EventObject e) {
553 if (e != null) {
554 Object source = e.getSource();
555 if (source instanceof Component) {
556 Window ancestor = SwingUtilities.getWindowAncestor((Component) source);
557 if (ancestor != null) {
558 return ancestor;
559 } else {
560 Container parent = ((Component) source).getParent();
561 if (parent instanceof JPopupMenu) {
562 Component invoker = ((JPopupMenu) parent).getInvoker();
563 return SwingUtilities.getWindowAncestor(invoker);
564 }
565 }
566 }
567 }
568 return null;
569 }
570
571 /**
572 * Extends tooltip dismiss delay to a default value of 1 minute for the given component.
573 * @param c component
574 * @since 10024
575 */
576 public static void extendTooltipDelay(Component c) {
577 extendTooltipDelay(c, 60_000);
578 }
579
580 /**
581 * Extends tooltip dismiss delay to the specified value for the given component.
582 * @param c component
583 * @param delay tooltip dismiss delay in milliseconds
584 * @see <a href="http://stackoverflow.com/a/6517902/2257172">http://stackoverflow.com/a/6517902/2257172</a>
585 * @since 10024
586 */
587 public static void extendTooltipDelay(Component c, final int delay) {
588 final int defaultDismissTimeout = ToolTipManager.sharedInstance().getDismissDelay();
589 c.addMouseListener(new MouseAdapter() {
590 @Override
591 public void mouseEntered(MouseEvent me) {
592 ToolTipManager.sharedInstance().setDismissDelay(delay);
593 }
594
595 @Override
596 public void mouseExited(MouseEvent me) {
597 ToolTipManager.sharedInstance().setDismissDelay(defaultDismissTimeout);
598 }
599 });
600 }
601
602 /**
603 * Returns the specified component's <code>Frame</code> without throwing exception in headless mode.
604 *
605 * @param parentComponent the <code>Component</code> to check for a <code>Frame</code>
606 * @return the <code>Frame</code> that contains the component, or <code>getRootFrame</code>
607 * if the component is <code>null</code>, or does not have a valid <code>Frame</code> parent
608 * @see JOptionPane#getFrameForComponent
609 * @see GraphicsEnvironment#isHeadless
610 * @since 10035
611 */
612 public static Frame getFrameForComponent(Component parentComponent) {
613 try {
614 return JOptionPane.getFrameForComponent(parentComponent);
615 } catch (HeadlessException e) {
616 Logging.debug(e);
617 return null;
618 }
619 }
620
621 /**
622 * Localizations for file chooser dialog.
623 * For some locales (e.g. de, fr) translations are provided
624 * by Java, but not for others (e.g. ru, uk).
625 * @since 12644 (moved from I18n)
626 */
627 public static void translateJavaInternalMessages() {
628 Locale l = Locale.getDefault();
629
630 AbstractFileChooser.setDefaultLocale(l);
631 JFileChooser.setDefaultLocale(l);
632 JColorChooser.setDefaultLocale(l);
633 for (String key : JAVA_INTERNAL_MESSAGE_KEYS) {
634 String us = UIManager.getString(key, Locale.US);
635 String loc = UIManager.getString(key, l);
636 // only provide custom translation if it is not already localized by Java
637 if (us != null && us.equals(loc)) {
638 UIManager.put(key, tr(us));
639 }
640 }
641 }
642
643 /**
644 * Setup special font for Khmer script, as the default Java fonts do not display these characters.
645 * @since 12644 (moved from I18n)
646 * @since 8282
647 */
648 public static void setupLanguageFonts() {
649 // Use special font for Khmer script, as the default Java font do not display these characters
650 if ("km".equals(LanguageInfo.getJOSMLocaleCode())) {
651 Collection<String> fonts = Arrays.asList(
652 GraphicsEnvironment.getLocalGraphicsEnvironment().getAvailableFontFamilyNames());
653 for (String f : new String[]{"Khmer UI", "DaunPenh", "MoolBoran"}) {
654 if (fonts.contains(f)) {
655 setUIFont(f);
656 break;
657 }
658 }
659 }
660 }
661}
Note: See TracBrowser for help on using the repository browser.