source: trunk/src/org/expeditee/gio/swing/SwingGraphicsManager.java@ 1540

Last change on this file since 1540 was 1540, checked in by bnemhaus, 4 years ago

Removed reliance of System.getProperty("user.name") by introducing some functions and a variable to Browser to be used instead. All previous occurrences of System.getProperty("user.name") now use these functions.

At the time, introduced new piping into various functions related to the creation and management of profile frames that distinguished between a profile name and a user name. This allows functions to be more specific about what is being used. For example, when modifying the users profile frames (in the profiles directory) that users profile name can be used instead of naming the variable 'username'. This distinction is important because while username's can end with numbers, profile names cannot and therefore get an 'A' on the end.

File size: 19.0 KB
Line 
1package org.expeditee.gio.swing;
2
3import java.awt.AlphaComposite;
4import java.awt.Component;
5import java.awt.Container;
6import java.awt.FontMetrics;
7import java.awt.Graphics;
8import java.awt.Graphics2D;
9import java.awt.GraphicsEnvironment;
10import java.awt.RenderingHints;
11import java.awt.Toolkit;
12import java.awt.event.ComponentListener;
13import java.awt.event.KeyListener;
14import java.awt.event.WindowListener;
15import java.awt.event.WindowStateListener;
16import java.awt.geom.AffineTransform;
17import java.awt.image.ImageObserver;
18
19import javax.swing.JFrame;
20import javax.swing.JLayeredPane;
21import javax.swing.JMenuBar;
22import javax.swing.JOptionPane;
23import javax.swing.RepaintManager;
24import javax.swing.SwingUtilities;
25import javax.swing.TransferHandler;
26
27import org.expeditee.core.Clip;
28import org.expeditee.core.Colour;
29import org.expeditee.core.Cursor;
30import org.expeditee.core.Dimension;
31import org.expeditee.core.Fill;
32import org.expeditee.core.Font;
33import org.expeditee.core.GradientFill;
34import org.expeditee.core.Image;
35import org.expeditee.core.Point;
36import org.expeditee.core.Stroke;
37import org.expeditee.core.TextLayout;
38import org.expeditee.core.bounds.PolygonBounds;
39import org.expeditee.gio.GraphicsManager;
40import org.expeditee.gio.GraphicsSurfaceStack;
41import org.expeditee.gio.swing.SwingImageManager.BlockingImageObserver;
42import org.expeditee.gio.swing.SwingImageManager.SelfAnimatingImageObserver;
43import org.expeditee.gui.DisplayController;
44import org.expeditee.items.widgets.SwingWidget;
45import org.expeditee.items.widgets.Widget;
46
47// TODO: Make stack thread-safe
48public class SwingGraphicsManager extends GraphicsManager {
49
50 private static SwingGraphicsManager _instance;
51
52 public static SwingGraphicsManager getInstance() {
53 if (_instance == null) {
54 try {
55 SwingUtilities.invokeAndWait(new Runnable() {
56 @Override
57 public void run() {
58 _instance = new SwingGraphicsManager();
59 }
60 });
61 } catch (Exception e) {
62 System.err.println("Error while initialising GraphicsManager. Aborting...");
63 e.printStackTrace(System.err);
64 System.exit(1);
65 }
66
67 // Block until the window is ready
68
69 }
70
71 return _instance;
72 }
73
74 private JFrame _jFrame;
75
76 private GraphicsSurfaceStack<Graphics2D> _surfaceStack;
77
78 private SwingGraphicsManager() {
79 _jFrame = new JFrame() {
80 private static final long serialVersionUID = 5179259234365906415L;
81
82 // Override the paint() method so that Expeditee's graphics are drawn
83 // when the window refreshes.
84 @Override
85 public void paint(Graphics g) {
86 DisplayController.requestRefresh(false);
87 }
88 };
89
90 setWindowIcon();
91
92 /*
93 * See Java bug ID 4016934. They say that window closed events are called once
94 * the JFrame is disposed.
95 */
96 _jFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
97
98 // Expeditee handles its own repainting of AWT/Swing components
99 RepaintManager.setCurrentManager(ExpediteeRepaintManager.getInstance());
100
101 // required to accept TAB key
102 _jFrame.setFocusTraversalKeysEnabled(false);
103
104 _jFrame.pack();
105
106 // Moved to here to work with JFXPanel
107 // TODO: Is the above comment still relevant? cts16
108 _jFrame.getContentPane().setLayout(new AbsoluteLayout());
109
110 // Set visible must be just after DisplayIO.Init for the message box to be the
111 // right size
112 // TODO: Is the above comment still relevant? cts16
113 _jFrame.setVisible(true);
114
115 // Create the surface stack
116 _surfaceStack = new GraphicsSurfaceStack<Graphics2D>() {
117 @Override
118 public Graphics2D getSurfaceFromImage(Image image) {
119 return SwingMiscManager.getIfUsingSwingImageManager().getImageGraphics(image);
120 }
121
122 @Override
123 public void setSurfaceClip(Graphics2D surface, Clip clip) {
124 if (surface == null) {
125 return;
126 }
127
128 if (clip == null) {
129 surface.setClip(null);
130 return;
131 }
132
133 if (clip.isFullyClipped()) {
134 return;
135 }
136
137 surface.setClip(SwingConversions.toSwingRectangle(clip.getBounds()));
138 }
139 };
140 refreshRootSurface();
141 }
142
143 @Override
144 protected GraphicsSurfaceStack<?> getGraphicsSurfaceStack() {
145 return _surfaceStack;
146 }
147
148 @Override
149 public Dimension getScreenSize() {
150 java.awt.Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
151
152 return SwingConversions.fromSwingDimension(size);
153 }
154
155 @Override
156 public Point getWindowLocation() {
157 return SwingConversions.fromSwingPoint(_jFrame.getContentPane().getLocationOnScreen());
158 }
159
160 @Override
161 public void setWindowLocation(Point p) {
162 _jFrame.setLocation(p.getX(), p.getY());
163 }
164
165 @Override
166 public Dimension getWindowSize() {
167 return SwingConversions.fromSwingDimension(_jFrame.getContentPane().getSize());
168 }
169
170 @Override
171 public void setWindowSize(Dimension d) {
172 _jFrame.setSize(d.width, d.height);
173 _jFrame.setPreferredSize(SwingConversions.toSwingDimension(d));
174 // Issue a command to graphics so that the JFrame draws itself white.
175 _jFrame.getGraphics().clearRect(0, 0, d.width, d.height);
176 }
177
178 @Override
179 public void requestFocus() {
180 _jFrame.requestFocus();
181 }
182
183 @Override
184 public void setCompositeAlpha(float alpha) {
185 _surfaceStack.getCurrentSurface().setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
186 }
187
188 @Override
189 public void setAntialiasing(boolean on) {
190 setAntialiasing(_surfaceStack.getCurrentSurface(), on);
191 }
192
193 private void setAntialiasing(Graphics2D surface, boolean on) {
194 if (surface == null) {
195 return;
196 }
197
198 if (on) {
199 if (hasAntialiasing) {
200 //return;
201 }
202 surface.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
203 hasAntialiasing = true;
204 } else {
205 if (hasAntialiasing) {
206 //return;
207 }
208 surface.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
209 }
210 }
211
212 private static boolean hasAntialiasing = false;
213
214 @Override
215 public void setFont(Font font) {
216 _surfaceStack.getCurrentSurface().setFont(SwingMiscManager.getIfUsingSwingFontManager().getInternalFont(font));
217 }
218
219 @Override
220 public void drawImage(Image image, Point topLeft, Dimension size, double angle, Point cropTopLeft,
221 Dimension cropSize) {
222 // Can't draw nothing
223 if (image == null) {
224 return;
225 }
226
227 // Can't draw nowhere
228 if (topLeft == null) {
229 return;
230 }
231
232 // If the cropped area is degenerate, abort
233 if (cropSize != null && (cropSize.width <= 0 || cropSize.height <= 0)) {
234 return;
235 }
236
237 // If the crop area is the entire image, pretend we are not cropping
238 if (Point.ORIGIN.equals(cropTopLeft) && image.getSize().equals(cropSize)) {
239 cropTopLeft = null;
240 cropSize = null;
241 }
242
243 SwingImageManager manager = SwingMiscManager.getIfUsingSwingImageManager();
244
245 ImageObserver animator = null;
246 if (image.isAnimated()) {
247 animator = manager.getAnimator(image);
248 if (animator != null) {
249 ((SelfAnimatingImageObserver) animator).activate();
250 }
251 } else {
252 animator = new SwingImageManager.LoadCompletedImageObserver();
253 }
254
255 // Default is the entire image
256 Image croppedImage = image;
257
258 // If we are cropping, do this now into a temporary image
259 if (cropTopLeft != null && cropSize != null) {
260 croppedImage = manager.createImage(cropSize.width, cropSize.height);
261 manager.getInternalImage(croppedImage).getGraphics().drawImage(manager.getInternalImage(image), 0, 0,
262 cropSize.width - 1, cropSize.height - 1, cropTopLeft.getX(), cropTopLeft.getY(),
263 cropTopLeft.getX() + cropSize.width - 1, cropTopLeft.getY() + cropSize.height - 1, animator);
264 animator = new BlockingImageObserver();
265 }
266
267 // Transform the image
268 AffineTransform tx = new AffineTransform();
269 if (size != null) {
270 tx.scale(((double) size.width) / croppedImage.getWidth(),
271 ((double) size.height) / croppedImage.getHeight());
272 }
273 if (angle != 0.0) {
274 tx.rotate(angle);
275 }
276 if (topLeft != null) {
277 tx.translate(topLeft.getX(), topLeft.getY());
278 }
279
280 // Draw the image to the current surface
281 boolean drawn = _surfaceStack.getCurrentSurface().drawImage(manager.getInternalImage(croppedImage), tx,
282 animator);
283
284 // If the draw didn't succeed, try again after waiting for the image to load
285 if (!drawn && animator instanceof BlockingImageObserver) {
286 ((BlockingImageObserver) animator).attemptWait();
287 _surfaceStack.getCurrentSurface().drawImage(manager.getInternalImage(croppedImage), tx, animator);
288 }
289 }
290
291 @Override
292 public void drawRectangle(Point topLeft, Dimension size, double angle, Fill fill, Colour borderColour,
293 Stroke borderStroke, Dimension cornerRadius) {
294 Graphics2D g = (Graphics2D) _surfaceStack.getCurrentSurface().create();
295
296 if (angle != 0.0) {
297 AffineTransform tx = new AffineTransform();
298 tx.rotate(angle);
299 g.transform(tx);
300 }
301
302 if (fill != null) {
303 if (fill instanceof GradientFill) {
304 g.setPaint(SwingConversions.toSwingGradientPaint((GradientFill) fill));
305 } else {
306 g.setColor(SwingConversions.toSwingColor(fill.getColour()));
307 }
308
309 if (cornerRadius != null) {
310 g.fillRoundRect(topLeft.getX(), topLeft.getY(), size.width, size.height, cornerRadius.width, cornerRadius.height);
311 } else {
312 g.fillRect(topLeft.getX(), topLeft.getY(), size.width, size.height);
313 }
314 }
315
316 if (borderColour != null && borderStroke != null) {
317 g.setColor(SwingConversions.toSwingColor(borderColour));
318 g.setStroke(SwingConversions.toSwingStroke(borderStroke));
319
320 if (cornerRadius != null) {
321 g.drawRoundRect(topLeft.getX(), topLeft.getY(), size.width, size.height, cornerRadius.width, cornerRadius.height);
322 } else {
323 g.drawRect(topLeft.getX(), topLeft.getY(), size.width, size.height);
324 }
325 }
326
327 g.dispose();
328 }
329
330 @Override
331 public void drawOval(Point centre, Dimension diameters, double angle, Fill fill, Colour borderColour,
332 Stroke borderStroke) {
333 Graphics2D g = (Graphics2D) _surfaceStack.getCurrentSurface().create();
334
335 if (angle != 0.0) {
336 AffineTransform tx = new AffineTransform();
337 tx.rotate(angle);
338 g.transform(tx);
339 }
340
341 Point topLeft = new Point(centre.getX() - diameters.width / 2, centre.getY() - diameters.height / 2);
342
343 if (fill != null) {
344 if (fill instanceof GradientFill) {
345 g.setPaint(SwingConversions.toSwingGradientPaint((GradientFill) fill));
346 } else {
347 g.setColor(SwingConversions.toSwingColor(fill.getColour()));
348 }
349
350 g.fillOval(topLeft.getX(), topLeft.getY(), diameters.width, diameters.height);
351 }
352
353 if (borderColour != null && borderStroke != null) {
354 g.setColor(SwingConversions.toSwingColor(borderColour));
355 g.setStroke(SwingConversions.toSwingStroke(borderStroke));
356
357 g.drawOval(topLeft.getX(), topLeft.getY(), diameters.width, diameters.height);
358 }
359
360 g.dispose();
361 }
362
363 @Override
364 public void drawPolygon(PolygonBounds points, Point offset, Dimension scale, double angle, Fill fill,
365 Colour borderColour, Stroke borderStroke) {
366 if (points == null || points.getPointCount() < 2) {
367 return;
368 }
369 if (fill == null && (borderColour == null || borderStroke == null)) {
370 return;
371 }
372
373 Graphics2D g = (Graphics2D) _surfaceStack.getCurrentSurface().create();
374
375 AffineTransform tx = new AffineTransform();
376 Point centre = points.getCentre();
377 tx.translate(-centre.getX(), -centre.getY());
378 if (angle != 0.0) {
379 tx.rotate(angle);
380 }
381 if (scale != null) {
382 double xScale = ((double) scale.width) / (points.getMaxX() - points.getMinX());
383 double yScale = ((double) scale.height) / (points.getMaxY() - points.getMinY());
384 tx.scale(xScale, yScale);
385 }
386 tx.translate(centre.getX(), centre.getY());
387 if (offset != null) {
388 tx.translate(offset.getX(), offset.getY());
389 }
390 g.transform(tx);
391
392 if (fill != null) {
393 if (fill instanceof GradientFill) {
394 g.setPaint(SwingConversions.toSwingGradientPaint((GradientFill) fill));
395 } else {
396 g.setColor(SwingConversions.toSwingColor(fill.getColour()));
397 }
398
399 g.fillPolygon(SwingConversions.toSwingPolygon(points));
400 }
401
402 if (borderColour != null && borderStroke != null) {
403 g.setColor(SwingConversions.toSwingColor(borderColour));
404 g.setStroke(SwingConversions.toSwingStroke(borderStroke));
405
406 if (points.isClosed()) {
407 g.drawPolygon(SwingConversions.toSwingPolygon(points));
408 } else {
409 int nPoints = points.getPointCount();
410 int[] xPoints = new int[nPoints];
411 int[] yPoints = new int[nPoints];
412
413 for (int i = 0; i < nPoints; i++) {
414 Point point = points.getPoint(i);
415 xPoints[i] = point.getX();
416 yPoints[i] = point.getY();
417 }
418
419 g.drawPolyline(xPoints, yPoints, nPoints);
420 }
421 }
422
423 g.dispose();
424 }
425
426 @Override
427 public void drawLine(int x1, int y1, int x2, int y2, Colour colour, Stroke stroke) {
428 if (colour == null || stroke == null) {
429 return;
430 }
431
432 Graphics2D g = (Graphics2D) _surfaceStack.getCurrentSurface().create();
433 g.setColor(SwingConversions.toSwingColor(colour));
434 g.setStroke(SwingConversions.toSwingStroke(stroke));
435
436 g.drawLine(x1, y1, x2, y2);
437
438 g.dispose();
439 }
440
441 @Override
442 public void drawString(String string, Point position, Font font, Colour colour) {
443 if (string == null || position == null || font == null || colour == null) {
444 return;
445 }
446
447 Graphics2D g = (Graphics2D) _surfaceStack.getCurrentSurface().create();
448 g.setColor(SwingConversions.toSwingColor(colour));
449 g.setFont(SwingMiscManager.getIfUsingSwingFontManager().getInternalFont(font));
450
451 g.drawString(string, position.getX(), position.getY());
452
453 g.dispose();
454 }
455
456 @Override
457 public void drawTextLayout(TextLayout layout, Point position, Colour colour) {
458 if (layout == null) {
459 return;
460 }
461
462 SwingTextLayoutManager layoutManager = SwingMiscManager.getIfUsingSwingTextLayoutManager();
463 if (layoutManager == null) {
464 drawString(layout.getLine(), position, layout.getFont(), colour);
465 return;
466 }
467
468 java.awt.font.TextLayout swingLayout = layoutManager.getInternalLayout(layout);
469
470 Graphics2D g = (Graphics2D) _surfaceStack.getCurrentSurface().create();
471 g.setColor(SwingConversions.toSwingColor(colour));
472
473 swingLayout.draw(g, position.getX(), position.getY());
474 }
475
476 private Dimension _preFullscreenSize = null;
477 private boolean _fullScreenTransitionPending = false;
478
479 /**
480 * Whether or not we are in the middle of transitioning to/from fullscreen.
481 */
482 public boolean isFullscreenTransitionPending() {
483 return _fullScreenTransitionPending;
484 }
485
486 /**
487 * Should be called when the SwingInputManager is notified that the fullscreen
488 * transition has finished.
489 */
490 public void finishFullscreenTransition() {
491 _fullScreenTransitionPending = false;
492 }
493
494 @Override
495 public boolean canGoFullscreen() {
496 return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().isFullScreenSupported();
497 }
498
499 @Override
500 public boolean isFullscreen() {
501 return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice()
502 .getFullScreenWindow() == _jFrame;
503 }
504
505 @Override
506 public void goFullscreen() {
507 if (!canGoFullscreen()) {
508 System.err.println("Warning: GraphicsManager::goFullScreen() called when not available -- ignoring");
509 return;
510 }
511
512 _preFullscreenSize = getWindowSize();
513
514 _fullScreenTransitionPending = true;
515
516 _jFrame.dispose();
517 _jFrame.setUndecorated(true);
518 _jFrame.pack();
519 _jFrame.setVisible(true);
520
521 GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(_jFrame);
522 }
523
524 @Override
525 public void exitFullscreen() {
526 _fullScreenTransitionPending = true;
527
528 _jFrame.dispose();
529 _jFrame.setUndecorated(false);
530
531 GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().setFullScreenWindow(null);
532 _jFrame.pack();
533 _jFrame.setVisible(true);
534 setWindowSize(_preFullscreenSize);
535 }
536
537 @Override
538 public void setCursor(Cursor cursor) {
539 if (cursor == null) {
540 return;
541 }
542
543 java.awt.Cursor swingCursor;
544 if (cursor.getType() == Cursor.CursorType.CUSTOM) {
545 SwingImageManager imageManager = SwingMiscManager.getIfUsingSwingImageManager();
546
547 if (imageManager == null) {
548 return;
549 }
550
551 swingCursor = Toolkit.getDefaultToolkit().createCustomCursor(
552 imageManager.getInternalImage(cursor.getImage()),
553 SwingConversions.toSwingPoint(cursor.getHotspot()), cursor.getName());
554 } else {
555 swingCursor = new java.awt.Cursor(SwingConversions.toSwingCursorType(cursor.getType()));
556 }
557
558 _jFrame.setCursor(swingCursor);
559 }
560
561 @Override
562 public Dimension getBestCursorSize(Dimension desiredSize) {
563 Toolkit toolkit = Toolkit.getDefaultToolkit();
564 java.awt.Dimension best_cursor_dim = toolkit.getBestCursorSize(desiredSize.width, desiredSize.height);
565 return SwingConversions.fromSwingDimension(best_cursor_dim);
566 }
567
568 @Override
569 public void setWindowTitle(String title) {
570 _jFrame.setTitle(title);
571 }
572
573 @Override
574 public boolean showDialog(String title, String message) {
575 int result = JOptionPane.showConfirmDialog(_jFrame, message, title, JOptionPane.OK_CANCEL_OPTION,
576 JOptionPane.WARNING_MESSAGE);
577 return result == JOptionPane.OK_OPTION;
578 }
579
580 @Override
581 public Dimension getCurrentDrawingSurfaceSize() {
582 Image currentImage = _surfaceStack.getCurrentImage();
583
584 if (currentImage != null) {
585 return currentImage.getSize();
586 } else {
587 return getWindowSize();
588 }
589 }
590
591 public void refreshRootSurface() {
592 Graphics2D rootSurface = (Graphics2D) _jFrame.getContentPane().getGraphics();
593 setAntialiasing(rootSurface, true);
594 final java.awt.Font rootSurfaceFont = rootSurface.getFont().deriveFont(40f);
595 rootSurface.setFont(rootSurfaceFont);
596 _surfaceStack.setRootSurface(rootSurface);
597 }
598
599 public JFrame getJFrame() {
600 return _jFrame;
601 }
602
603 public Container getContentPane() {
604 return _jFrame.getContentPane();
605 }
606
607 public JLayeredPane getLayeredPane() {
608 return _jFrame.getLayeredPane();
609 }
610
611 public void setTransferHandler(TransferHandler newHandler) {
612 _jFrame.setTransferHandler(newHandler);
613 }
614
615 public void addWindowListener(WindowListener l) {
616 _jFrame.addWindowListener(l);
617 }
618
619 public void addWindowStateListener(WindowStateListener l) {
620 _jFrame.addWindowStateListener(l);
621 }
622
623 public void addKeyListener(KeyListener l) {
624 _jFrame.addKeyListener(l);
625 }
626
627 public void addComponentListener(ComponentListener l) {
628 _jFrame.addComponentListener(l);
629 }
630
631 public void setGlassPane(Component glassPane) {
632 _jFrame.setGlassPane(glassPane);
633 }
634
635 public Component getGlassPane() {
636 return _jFrame.getGlassPane();
637 }
638
639 public JMenuBar getJMenuBar() {
640 return _jFrame.getJMenuBar();
641 }
642
643 public FontMetrics getFontMetrics(java.awt.Font font) {
644 return _jFrame.getFontMetrics(font);
645 }
646
647 public java.awt.Font getFont() {
648 return _jFrame.getFont();
649 }
650
651 public Graphics2D getCurrentSurface() {
652 return _surfaceStack.getCurrentSurface();
653 }
654
655 @Override
656 public boolean addInteractiveWidget(Widget iw) {
657 if (super.addInteractiveWidget(iw)) {
658 _jFrame.getContentPane().add(((SwingWidget) iw).getComponent());
659 return true;
660 }
661
662 return false;
663 }
664
665 @Override
666 public boolean removeInteractiveWidget(Widget iw) {
667 if (super.removeInteractiveWidget(iw)) {
668 _jFrame.getContentPane().remove(((SwingWidget) iw).getComponent());
669 return true;
670 }
671
672 return false;
673 }
674
675 @Override
676 protected void setWindowIcon(Image image) {
677 SwingImageManager imageManager = SwingMiscManager.getIfUsingSwingImageManager();
678
679 if (imageManager != null) {
680 _jFrame.setIconImage(imageManager.getInternalImage(image));
681 }
682 }
683
684 @Override
685 public int getFontHeight(final Font font) {
686 final java.awt.Font awtFont = SwingFontManager.getInstance().getInternalFont(font);
687 final FontMetrics fontMetrics = _jFrame.getGraphics().getFontMetrics(awtFont);
688 return fontMetrics.getHeight();
689 }
690}
Note: See TracBrowser for help on using the repository browser.