1 /* 2 * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.swing.plaf.synth; 27 28 import javax.swing.*; 29 import javax.swing.border.*; 30 import javax.swing.plaf.*; 31 import javax.swing.plaf.basic.BasicDesktopPaneUI; 32 import java.beans.*; 33 import java.awt.event.*; 34 import java.awt.*; 35 36 /** 37 * Provides the Synth L&F UI delegate for 38 * {@link javax.swing.JDesktopPane}. 39 * 40 * @author Joshua Outwater 41 * @author Steve Wilson 42 * @since 1.7 43 */ 44 public class SynthDesktopPaneUI extends BasicDesktopPaneUI implements 45 PropertyChangeListener, SynthUI { 46 private SynthStyle style; 47 private TaskBar taskBar; 48 private DesktopManager oldDesktopManager; 49 50 /** 51 * Creates a new UI object for the given component. 52 * 53 * @param c component to create UI object for 54 * @return the UI object 55 */ 56 public static ComponentUI createUI(JComponent c) { 57 return new SynthDesktopPaneUI(); 58 } 59 60 /** 61 * {@inheritDoc} 62 */ 63 @Override 64 protected void installListeners() { 65 super.installListeners(); 66 desktop.addPropertyChangeListener(this); 67 if (taskBar != null) { 68 // Listen for desktop being resized 69 desktop.addComponentListener(taskBar); 70 // Listen for frames being added to desktop 71 desktop.addContainerListener(taskBar); 72 } 73 } 74 75 /** 76 * {@inheritDoc} 77 */ 78 @Override 79 protected void installDefaults() { 80 updateStyle(desktop); 81 82 if (UIManager.getBoolean("InternalFrame.useTaskBar")) { 83 taskBar = new TaskBar(); 84 85 for (Component comp : desktop.getComponents()) { 86 JInternalFrame.JDesktopIcon desktopIcon; 87 88 if (comp instanceof JInternalFrame.JDesktopIcon) { 89 desktopIcon = (JInternalFrame.JDesktopIcon)comp; 90 } else if (comp instanceof JInternalFrame) { 91 desktopIcon = ((JInternalFrame)comp).getDesktopIcon(); 92 } else { 93 continue; 94 } 95 // Move desktopIcon from desktop to taskBar 96 if (desktopIcon.getParent() == desktop) { 97 desktop.remove(desktopIcon); 98 } 99 if (desktopIcon.getParent() != taskBar) { 100 taskBar.add(desktopIcon); 101 desktopIcon.getInternalFrame().addComponentListener( 102 taskBar); 103 } 104 } 105 taskBar.setBackground(desktop.getBackground()); 106 desktop.add(taskBar, 107 Integer.valueOf(JLayeredPane.PALETTE_LAYER.intValue() + 1)); 108 if (desktop.isShowing()) { 109 taskBar.adjustSize(); 110 } 111 } 112 } 113 114 private void updateStyle(JDesktopPane c) { 115 SynthStyle oldStyle = style; 116 SynthContext context = getContext(c, ENABLED); 117 style = SynthLookAndFeel.updateStyle(context, this); 118 if (oldStyle != null) { 119 uninstallKeyboardActions(); 120 installKeyboardActions(); 121 } 122 context.dispose(); 123 } 124 125 /** 126 * {@inheritDoc} 127 */ 128 @Override 129 protected void uninstallListeners() { 130 if (taskBar != null) { 131 desktop.removeComponentListener(taskBar); 132 desktop.removeContainerListener(taskBar); 133 } 134 desktop.removePropertyChangeListener(this); 135 super.uninstallListeners(); 136 } 137 138 /** 139 * {@inheritDoc} 140 */ 141 @Override 142 protected void uninstallDefaults() { 143 SynthContext context = getContext(desktop, ENABLED); 144 145 style.uninstallDefaults(context); 146 context.dispose(); 147 style = null; 148 149 if (taskBar != null) { 150 for (Component comp : taskBar.getComponents()) { 151 JInternalFrame.JDesktopIcon desktopIcon = 152 (JInternalFrame.JDesktopIcon)comp; 153 taskBar.remove(desktopIcon); 154 desktopIcon.setPreferredSize(null); 155 JInternalFrame f = desktopIcon.getInternalFrame(); 156 if (f.isIcon()) { 157 desktop.add(desktopIcon); 158 } 159 f.removeComponentListener(taskBar); 160 } 161 desktop.remove(taskBar); 162 taskBar = null; 163 } 164 } 165 166 /** 167 * {@inheritDoc} 168 */ 169 @Override 170 protected void installDesktopManager() { 171 if (UIManager.getBoolean("InternalFrame.useTaskBar")) { 172 desktopManager = oldDesktopManager = desktop.getDesktopManager(); 173 if (!(desktopManager instanceof SynthDesktopManager)) { 174 desktopManager = new SynthDesktopManager(); 175 desktop.setDesktopManager(desktopManager); 176 } 177 } else { 178 super.installDesktopManager(); 179 } 180 } 181 182 /** 183 * {@inheritDoc} 184 */ 185 @Override 186 protected void uninstallDesktopManager() { 187 if (oldDesktopManager != null && !(oldDesktopManager instanceof UIResource)) { 188 desktopManager = desktop.getDesktopManager(); 189 if (desktopManager == null || desktopManager instanceof UIResource) { 190 desktop.setDesktopManager(oldDesktopManager); 191 } 192 } 193 oldDesktopManager = null; 194 super.uninstallDesktopManager(); 195 } 196 197 @SuppressWarnings("serial") // Same-version serialization only and 198 // internal anonymous classes 199 static class TaskBar extends JPanel implements ComponentListener, ContainerListener { 200 TaskBar() { 201 setOpaque(true); 202 setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0) { 203 public void layoutContainer(Container target) { 204 // First shrink buttons to fit 205 Component[] comps = target.getComponents(); 206 int n = comps.length; 207 if (n > 0) { 208 // Start with the largest preferred width 209 int prefWidth = 0; 210 for (Component c : comps) { 211 c.setPreferredSize(null); 212 Dimension prefSize = c.getPreferredSize(); 213 if (prefSize.width > prefWidth) { 214 prefWidth = prefSize.width; 215 } 216 } 217 // Shrink equally to fit if needed 218 Insets insets = target.getInsets(); 219 int tw = target.getWidth() - insets.left - insets.right; 220 int w = Math.min(prefWidth, Math.max(10, tw/n)); 221 for (Component c : comps) { 222 Dimension prefSize = c.getPreferredSize(); 223 c.setPreferredSize(new Dimension(w, prefSize.height)); 224 } 225 } 226 super.layoutContainer(target); 227 } 228 }); 229 230 // PENDING: This should be handled by the painter 231 setBorder(new BevelBorder(BevelBorder.RAISED) { 232 protected void paintRaisedBevel(Component c, Graphics g, 233 int x, int y, int w, int h) { 234 Color oldColor = g.getColor(); 235 g.translate(x, y); 236 g.setColor(getHighlightOuterColor(c)); 237 g.drawLine(0, 0, 0, h-2); 238 g.drawLine(1, 0, w-2, 0); 239 g.setColor(getShadowOuterColor(c)); 240 g.drawLine(0, h-1, w-1, h-1); 241 g.drawLine(w-1, 0, w-1, h-2); 242 g.translate(-x, -y); 243 g.setColor(oldColor); 244 } 245 }); 246 } 247 248 void adjustSize() { 249 JDesktopPane desktop = (JDesktopPane)getParent(); 250 if (desktop != null) { 251 int height = getPreferredSize().height; 252 Insets insets = getInsets(); 253 if (height == insets.top + insets.bottom) { 254 if (getHeight() <= height) { 255 // Initial size, because we have no buttons yet 256 height += 21; 257 } else { 258 // We already have a good height 259 height = getHeight(); 260 } 261 } 262 setBounds(0, desktop.getHeight() - height, desktop.getWidth(), height); 263 revalidate(); 264 repaint(); 265 } 266 } 267 268 // ComponentListener interface 269 270 public void componentResized(ComponentEvent e) { 271 if (e.getSource() instanceof JDesktopPane) { 272 adjustSize(); 273 } 274 } 275 276 public void componentMoved(ComponentEvent e){} 277 278 public void componentShown(ComponentEvent e) { 279 if (e.getSource() instanceof JInternalFrame) { 280 adjustSize(); 281 } 282 } 283 284 public void componentHidden(ComponentEvent e) { 285 if (e.getSource() instanceof JInternalFrame) { 286 ((JInternalFrame)e.getSource()).getDesktopIcon().setVisible(false); 287 revalidate(); 288 } 289 } 290 291 // ContainerListener interface 292 293 public void componentAdded(ContainerEvent e) { 294 if (e.getChild() instanceof JInternalFrame) { 295 JDesktopPane desktop = (JDesktopPane)e.getSource(); 296 JInternalFrame f = (JInternalFrame)e.getChild(); 297 JInternalFrame.JDesktopIcon desktopIcon = f.getDesktopIcon(); 298 for (Component comp : getComponents()) { 299 if (comp == desktopIcon) { 300 // We have it already 301 return; 302 } 303 } 304 add(desktopIcon); 305 f.addComponentListener(this); 306 if (getComponentCount() == 1) { 307 adjustSize(); 308 } 309 } 310 } 311 312 public void componentRemoved(ContainerEvent e) { 313 if (e.getChild() instanceof JInternalFrame) { 314 JInternalFrame f = (JInternalFrame)e.getChild(); 315 if (!f.isIcon()) { 316 // Frame was removed without using setClosed(true) 317 remove(f.getDesktopIcon()); 318 f.removeComponentListener(this); 319 revalidate(); 320 repaint(); 321 } 322 } 323 } 324 } 325 326 @SuppressWarnings("serial") // Same-version serialization only 327 class SynthDesktopManager extends DefaultDesktopManager implements UIResource { 328 329 public void maximizeFrame(JInternalFrame f) { 330 if (f.isIcon()) { 331 try { 332 f.setIcon(false); 333 } catch (PropertyVetoException e2) { 334 } 335 } else { 336 f.setNormalBounds(f.getBounds()); 337 Component desktop = f.getParent(); 338 setBoundsForFrame(f, 0, 0, 339 desktop.getWidth(), 340 desktop.getHeight() - taskBar.getHeight()); 341 } 342 343 try { 344 f.setSelected(true); 345 } catch (PropertyVetoException e2) { 346 } 347 } 348 349 public void iconifyFrame(JInternalFrame f) { 350 JInternalFrame.JDesktopIcon desktopIcon; 351 Container c = f.getParent(); 352 JDesktopPane d = f.getDesktopPane(); 353 boolean findNext = f.isSelected(); 354 355 if (c == null) { 356 return; 357 } 358 359 desktopIcon = f.getDesktopIcon(); 360 361 if (!f.isMaximum()) { 362 f.setNormalBounds(f.getBounds()); 363 } 364 c.remove(f); 365 c.repaint(f.getX(), f.getY(), f.getWidth(), f.getHeight()); 366 try { 367 f.setSelected(false); 368 } catch (PropertyVetoException e2) { 369 } 370 371 // Get topmost of the remaining frames 372 if (findNext) { 373 for (Component comp : c.getComponents()) { 374 if (comp instanceof JInternalFrame) { 375 try { 376 ((JInternalFrame)comp).setSelected(true); 377 } catch (PropertyVetoException e2) { 378 } 379 ((JInternalFrame)comp).moveToFront(); 380 return; 381 } 382 } 383 } 384 } 385 386 387 public void deiconifyFrame(JInternalFrame f) { 388 JInternalFrame.JDesktopIcon desktopIcon = f.getDesktopIcon(); 389 Container c = desktopIcon.getParent(); 390 if (c != null) { 391 c = c.getParent(); 392 if (c != null) { 393 c.add(f); 394 if (f.isMaximum()) { 395 int w = c.getWidth(); 396 int h = c.getHeight() - taskBar.getHeight(); 397 if (f.getWidth() != w || f.getHeight() != h) { 398 setBoundsForFrame(f, 0, 0, w, h); 399 } 400 } 401 if (f.isSelected()) { 402 f.moveToFront(); 403 } else { 404 try { 405 f.setSelected(true); 406 } catch (PropertyVetoException e2) { 407 } 408 } 409 } 410 } 411 } 412 413 protected void removeIconFor(JInternalFrame f) { 414 super.removeIconFor(f); 415 taskBar.validate(); 416 } 417 418 public void setBoundsForFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) { 419 super.setBoundsForFrame(f, newX, newY, newWidth, newHeight); 420 if (taskBar != null && newY >= taskBar.getY()) { 421 f.setLocation(f.getX(), taskBar.getY()-f.getInsets().top); 422 } 423 } 424 } 425 426 /** 427 * {@inheritDoc} 428 */ 429 @Override 430 public SynthContext getContext(JComponent c) { 431 return getContext(c, getComponentState(c)); 432 } 433 434 private SynthContext getContext(JComponent c, int state) { 435 return SynthContext.getContext(SynthContext.class, c, 436 SynthLookAndFeel.getRegion(c), style, state); 437 } 438 439 private int getComponentState(JComponent c) { 440 return SynthLookAndFeel.getComponentState(c); 441 } 442 443 /** 444 * Notifies this UI delegate to repaint the specified component. 445 * This method paints the component background, then calls 446 * the {@link #paint(SynthContext,Graphics)} method. 447 * 448 * <p>In general, this method does not need to be overridden by subclasses. 449 * All Look and Feel rendering code should reside in the {@code paint} method. 450 * 451 * @param g the {@code Graphics} object used for painting 452 * @param c the component being painted 453 * @see #paint(SynthContext,Graphics) 454 */ 455 @Override 456 public void update(Graphics g, JComponent c) { 457 SynthContext context = getContext(c); 458 459 SynthLookAndFeel.update(context, g); 460 context.getPainter().paintDesktopPaneBackground(context, g, 0, 0, 461 c.getWidth(), c.getHeight()); 462 paint(context, g); 463 context.dispose(); 464 } 465 466 /** 467 * Paints the specified component according to the Look and Feel. 468 * <p>This method is not used by Synth Look and Feel. 469 * Painting is handled by the {@link #paint(SynthContext,Graphics)} method. 470 * 471 * @param g the {@code Graphics} object used for painting 472 * @param c the component being painted 473 * @see #paint(SynthContext,Graphics) 474 */ 475 @Override 476 public void paint(Graphics g, JComponent c) { 477 SynthContext context = getContext(c); 478 479 paint(context, g); 480 context.dispose(); 481 } 482 483 /** 484 * Paints the specified component. This implementation does nothing. 485 * 486 * @param context context for the component being painted 487 * @param g the {@code Graphics} object used for painting 488 * @see #update(Graphics,JComponent) 489 */ 490 protected void paint(SynthContext context, Graphics g) { 491 } 492 493 /** 494 * {@inheritDoc} 495 */ 496 @Override 497 public void paintBorder(SynthContext context, Graphics g, int x, 498 int y, int w, int h) { 499 context.getPainter().paintDesktopPaneBorder(context, g, x, y, w, h); 500 } 501 502 /** 503 * {@inheritDoc} 504 */ 505 @Override 506 public void propertyChange(PropertyChangeEvent evt) { 507 if (SynthLookAndFeel.shouldUpdateStyle(evt)) { 508 updateStyle((JDesktopPane)evt.getSource()); 509 } 510 if (evt.getPropertyName() == "ancestor" && taskBar != null) { 511 taskBar.adjustSize(); 512 } 513 } 514 }