1 package fr.ifremer.quadrige3.ui.swing;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 import jaxx.runtime.JAXXObject;
27 import jaxx.runtime.JAXXUtil;
28 import jaxx.runtime.SwingUtil;
29 import org.apache.commons.collections4.CollectionUtils;
30 import org.apache.commons.io.IOUtils;
31 import org.apache.commons.lang3.StringEscapeUtils;
32 import org.apache.commons.lang3.StringUtils;
33 import org.apache.commons.logging.Log;
34 import org.apache.commons.logging.LogFactory;
35 import org.jdesktop.beans.AbstractBean;
36 import org.nuiton.jaxx.application.ApplicationBusinessException;
37
38 import javax.swing.*;
39 import javax.swing.text.JTextComponent;
40 import java.awt.*;
41 import java.awt.image.BufferedImage;
42 import java.io.BufferedReader;
43 import java.io.IOException;
44 import java.io.InputStream;
45 import java.io.StringReader;
46 import java.net.MalformedURLException;
47 import java.net.URL;
48 import java.net.URLConnection;
49 import java.text.DecimalFormat;
50 import java.text.DecimalFormatSymbols;
51 import java.util.*;
52 import java.util.stream.Collectors;
53
54 import static org.nuiton.i18n.I18n.t;
55
56
57
58
59 public class ApplicationUIUtil extends org.nuiton.jaxx.application.swing.util.ApplicationUIUtil {
60
61 private static final DecimalFormatSymbols SYMBOLS = new DecimalFormatSymbols();
62
63 private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat();
64
65 private static final Date DEFAULT_TWO_DIGIT_YEAR_START;
66
67 static {
68 SYMBOLS.setDecimalSeparator('.');
69 SYMBOLS.setGroupingSeparator(' ');
70
71 DECIMAL_FORMAT.setDecimalFormatSymbols(SYMBOLS);
72 DECIMAL_FORMAT.setGroupingUsed(false);
73
74 Calendar calendar = Calendar.getInstance();
75 calendar.set(2000, Calendar.JANUARY, 1, 0, 0);
76
77 DEFAULT_TWO_DIGIT_YEAR_START = calendar.getTime();
78 }
79
80
81
82
83 private static final Log LOG = LogFactory.getLog(ApplicationUIUtil.class);
84
85
86
87
88 protected ApplicationUIUtil() {
89 }
90
91
92
93
94
95
96
97 public static void setParentUI(JAXXObject ui, ApplicationUI<?, ?> parentUI) {
98 JAXXUtil.initContext(ui, parentUI);
99 ApplicationUIContext context = parentUI.getHandler() != null ? parentUI.getHandler().getContext() : null;
100 context = context != null ? context : ApplicationUIContext.getInstance();
101 setApplicationContext(ui, context);
102 }
103
104
105
106
107
108
109
110 public static ApplicationUI<?, ?> getParentUI(ApplicationUI<?, ?> ui) {
111 return ui.getContextValue(ApplicationUI.class, JAXXUtil.PARENT);
112 }
113
114
115
116
117
118
119
120
121
122 public static void tryToConnectToUpdateUrl(String urlAsString,
123 String badUrlFormatI18nKey,
124 String notReachI18nKey,
125 String notFoundI18nKey) {
126 URL url;
127
128 try {
129 url = new URL(urlAsString);
130 } catch (MalformedURLException e) {
131 if (LOG.isErrorEnabled()) {
132 LOG.error("Bad url syntax at " + urlAsString, e);
133 }
134 throw new ApplicationBusinessException(t(badUrlFormatI18nKey, urlAsString));
135 }
136
137 URLConnection urlConnection;
138
139 try {
140 urlConnection = url.openConnection();
141 urlConnection.setConnectTimeout(10000);
142 urlConnection.connect();
143 } catch (Exception e) {
144 if (LOG.isErrorEnabled()) {
145 LOG.error("Could not connect to " + urlAsString, e);
146 }
147 throw new ApplicationBusinessException(t(notReachI18nKey, urlAsString));
148 }
149
150
151 try {
152 urlConnection.setReadTimeout(1000);
153 InputStream inputStream = null;
154 try {
155 inputStream = urlConnection.getInputStream();
156 } finally {
157 IOUtils.closeQuietly(inputStream);
158 }
159 } catch (Exception e) {
160 if (LOG.isErrorEnabled()) {
161 LOG.error("Could not found file at to " + urlAsString, e);
162 }
163 throw new ApplicationBusinessException(t(notFoundI18nKey, urlAsString));
164 }
165 }
166
167
168
169
170
171
172 public static DecimalFormatSymbols getDecimalFormatSymbols() {
173 return SYMBOLS;
174 }
175
176
177
178
179
180
181
182
183 public static DecimalFormat getDecimalFormat(int minDecimal, int maxDecimal) {
184 DECIMAL_FORMAT.setMinimumFractionDigits(minDecimal);
185 DECIMAL_FORMAT.setMaximumFractionDigits(maxDecimal);
186 return DECIMAL_FORMAT;
187 }
188
189 private static final String HTML_BEGIN = "<html>";
190 private static final String HTML_END = "</html>";
191 private static final String HTML_PATTERN = HTML_BEGIN + "%s" + HTML_END;
192 private static final String HTML_BR = "<br>";
193 private static final String HTML_BR2 = "<br/>";
194 private static final String HTML_LIST_PATTERN = "<ul>%s</ul>";
195 private static final String HTML_LIST_ITEM_PATTERN = "<li>%s</li>";
196 private static final String HTML_ITALIC_PATTERN = HTML_BEGIN + "<i>%s</i>" + HTML_END;
197
198
199
200
201
202
203
204 public static boolean isHtmlString(String text) {
205 if (StringUtils.isBlank(text)) {
206 return false;
207 }
208 String s = StringUtils.deleteWhitespace(text);
209 return s.startsWith(HTML_BEGIN) && s.endsWith(HTML_END);
210 }
211
212
213
214
215
216
217
218 public static String getHtmlString(String text) {
219
220 if (StringUtils.isBlank(text)) {
221 return HTML_BEGIN + HTML_END;
222 } else if (isHtmlString(text)) {
223 return text;
224 }
225
226 return String.format(HTML_PATTERN, formatHtmlText(text));
227 }
228
229 public static String getHtmlItalicText(String text) {
230
231 if (StringUtils.isBlank(text)) {
232 return HTML_BEGIN + HTML_END;
233 } else if (isHtmlString(text)) {
234 return getHtmlItalicText(removeHtmlTags(text));
235 }
236
237 return String.format(HTML_ITALIC_PATTERN, text);
238 }
239
240 private static String formatHtmlText(String text) {
241
242 try (BufferedReader st = new BufferedReader(new StringReader(text))) {
243
244
245 return st.lines().filter(Objects::nonNull)
246 .map(line -> {
247 if (line.equalsIgnoreCase(HTML_BR2) || line.equalsIgnoreCase(HTML_BR)) {
248 return HTML_BR;
249 } else {
250 return escapeHtmlString(line);
251 }
252 })
253 .collect(Collectors.joining(HTML_BR));
254
255 } catch (IOException e) {
256 LOG.warn("Problem formatting string to html", e);
257 return text;
258 }
259 }
260
261 private static String escapeHtmlString(String str) {
262 boolean containsHTML = str.matches(".*<[^>]+>.*");
263 return containsHTML ? str : StringEscapeUtils.escapeHtml4(str);
264 }
265
266
267
268
269
270
271
272 public static String getHtmlString(Collection<String> strings) {
273 if (CollectionUtils.isEmpty(strings)) {
274 return getHtmlString("");
275 }
276 return String.format(HTML_PATTERN, formatHtmlList(strings));
277 }
278
279
280
281
282
283
284
285 public static String formatHtmlList(Collection<String> strings) {
286 StringBuilder result = new StringBuilder();
287 for (String string : strings) {
288 result.append(String.format(HTML_LIST_ITEM_PATTERN, string));
289 }
290 return String.format(HTML_LIST_PATTERN, result.toString());
291 }
292
293
294
295
296
297
298
299
300 public static String getHtmlString(String text, Collection<String> strings) {
301 if (CollectionUtils.isEmpty(strings)) {
302 return getHtmlString(text);
303 }
304 StringBuilder builder = new StringBuilder();
305 for (String string : strings) {
306 if (StringUtils.isNotBlank(string)) {
307 builder.append(String.format(HTML_LIST_ITEM_PATTERN, formatHtmlText(string)));
308 }
309 }
310 String result = (text != null ? formatHtmlText(text) : "") + String.format(HTML_LIST_PATTERN, builder.toString());
311 return String.format(HTML_PATTERN, result);
312 }
313
314
315
316
317
318
319
320 public static String removeHtmlTags(String htmlString) {
321 String result = htmlString;
322
323 if (result.startsWith(HTML_BEGIN)) {
324 result = result.substring(HTML_BEGIN.length());
325 }
326 if (result.endsWith(HTML_END)) {
327 result = result.substring(0, result.length() - HTML_BEGIN.length() - 1);
328 }
329
330
331 result = result.replaceAll(HTML_BR, "").replaceAll(HTML_BR2, "");
332
333
334 result = result.replaceAll("<strong>", "").replaceAll("<.strong>", "");
335 result = result.replaceAll("<li>", "").replaceAll("<.li>", "");
336 result = result.replaceAll("<ul>", "").replaceAll("<.ul>", "");
337
338 return StringEscapeUtils.unescapeHtml4(result);
339 }
340
341
342
343
344
345
346
347 public static void setComponentLocationOnScreen(Component component, Point point) {
348
349 if (component == null || point == null) {
350 return;
351 }
352
353 Rectangle screenBounds = new Rectangle();
354 GraphicsDevice[] devices = GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices();
355 for (GraphicsDevice device : devices) {
356 screenBounds = screenBounds.union(device.getDefaultConfiguration().getBounds());
357 }
358
359 if (point.x < screenBounds.x) {
360 point.x = 0;
361 } else if (point.x + component.getWidth() > screenBounds.width) {
362 point.x = screenBounds.width - component.getWidth();
363 }
364
365 if (point.y < screenBounds.y) {
366 point.y = 0;
367 } else if (point.y + component.getHeight() > screenBounds.height) {
368 point.y = screenBounds.height - component.getHeight();
369 }
370
371 component.setLocation(point);
372 }
373
374
375
376
377
378
379
380 public static void setComponentTreeBackground(Component component, Color color) {
381
382 if (component instanceof JTable
383 || component instanceof JTextComponent
384 || component instanceof JComboBox
385 || component instanceof JButton
386 || component instanceof JToggleButton
387 ) {
388 return;
389 }
390
391 if (component instanceof JList && component.isEnabled()) {
392 return;
393 }
394
395 component.setBackground(color);
396
397 if (component instanceof Container) {
398 Container container = (Container) component;
399 if (container.getComponents() != null) {
400 for (Component child : container.getComponents()) {
401 setComponentTreeBackground(child, color);
402 }
403 }
404 }
405 }
406
407
408
409
410
411
412
413 public static void setChildrenLabelForeground(Container container, Color color) {
414
415 if (container.getComponents() != null) {
416 for (Component child : container.getComponents()) {
417
418 if (child instanceof JLabel) {
419 child.setForeground(color);
420 } else if (child instanceof Container) {
421 setChildrenLabelForeground((Container) child, color);
422 }
423 }
424 }
425 }
426
427
428
429
430
431
432 public static void destroy(Object object) {
433
434 if (object instanceof Container) {
435 Arrays.stream(((Container) object).getComponents()).forEach(ApplicationUIUtil::destroy);
436 }
437
438 if (object instanceof ApplicationUI) {
439 ApplicationUI ui = (ApplicationUI) object;
440 ui.getHandler().onCloseUI();
441 ui.getHandler().clearValidators();
442 removeBindings(ui);
443 if (ui.getModel() instanceof AbstractBean && !(ui.getModel() instanceof ApplicationUIContext)) {
444 removeListeners((AbstractBean) ui.getModel());
445 }
446 }
447
448 if (object instanceof Component) {
449 removeListeners((Component) object);
450 }
451 if (object instanceof Window) {
452 ((Window) object).dispose();
453 }
454 }
455
456
457
458
459
460
461 public static void removeListeners(AbstractBean bean) {
462 Arrays.stream(bean.getPropertyChangeListeners()).forEach(bean::removePropertyChangeListener);
463 Arrays.stream(bean.getVetoableChangeListeners()).forEach(bean::removeVetoableChangeListener);
464 }
465
466
467
468
469
470
471 public static void removeListeners(Component component) {
472 Arrays.stream(component.getPropertyChangeListeners()).forEach(component::removePropertyChangeListener);
473 Arrays.stream(component.getFocusListeners()).forEach(component::removeFocusListener);
474 }
475
476
477
478
479
480
481 public static void removeBindings(JAXXObject jaxxObject) {
482 Arrays.stream(jaxxObject.getDataBindings()).forEach(jaxxBinding -> SwingUtil.removeDataBinding(jaxxObject, jaxxBinding.getId()));
483 }
484
485
486
487
488
489
490 public static Date getDefault2DigitYearStart() {
491 return DEFAULT_TWO_DIGIT_YEAR_START;
492 }
493
494 public static Cursor getCustomCursor(String actionIconName) {
495
496 Toolkit toolkit = Toolkit.getDefaultToolkit();
497
498 ImageIcon imageIcon = SwingUtil.createActionIcon(actionIconName);
499
500 Dimension bestDimension = toolkit.getBestCursorSize(imageIcon.getIconWidth(), imageIcon.getIconHeight());
501 if (bestDimension.getWidth() == 0) {
502 return Cursor.getDefaultCursor();
503 }
504
505 BufferedImage cursorImage = new BufferedImage(bestDimension.width, bestDimension.height, BufferedImage.TYPE_INT_ARGB);
506 Graphics2D graphics2D = cursorImage.createGraphics();
507 graphics2D.drawImage(imageIcon.getImage(),
508 (bestDimension.width - imageIcon.getIconWidth()) / 2,
509 (bestDimension.height - imageIcon.getIconHeight()) / 2,
510 imageIcon.getIconWidth(),
511 imageIcon.getIconHeight(),
512 null);
513
514 return toolkit.createCustomCursor(
515 cursorImage,
516 new Point(bestDimension.width / 2, bestDimension.height / 2),
517 actionIconName);
518 }
519
520 }