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 26package javax.swing.plaf.synth; 27 28import javax.swing.*; 29import javax.swing.border.*; 30import javax.swing.plaf.*; 31import javax.swing.plaf.basic.BasicDesktopPaneUI; 32import java.beans.*; 33import java.awt.event.*; 34import 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 */ 44public 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 } 123 124 /** 125 * {@inheritDoc} 126 */ 127 @Override 128 protected void uninstallListeners() { 129 if (taskBar != null) { 130 desktop.removeComponentListener(taskBar); 131 desktop.removeContainerListener(taskBar); 132 } 133 desktop.removePropertyChangeListener(this); 134 super.uninstallListeners(); 135 } 136 137 /** 138 * {@inheritDoc} 139 */ 140 @Override 141 protected void uninstallDefaults() { 142 SynthContext context = getContext(desktop, ENABLED); 143 144 style.uninstallDefaults(context); 145 style = null; 146 147 if (taskBar != null) { 148 for (Component comp : taskBar.getComponents()) { 149 JInternalFrame.JDesktopIcon desktopIcon = 150 (JInternalFrame.JDesktopIcon)comp; 151 taskBar.remove(desktopIcon); 152 desktopIcon.setPreferredSize(null); 153 JInternalFrame f = desktopIcon.getInternalFrame(); 154 if (f.isIcon()) { 155 desktop.add(desktopIcon); 156 } 157 f.removeComponentListener(taskBar); 158 } 159 desktop.remove(taskBar); 160 taskBar = null; 161 } 162 } 163 164 /** 165 * {@inheritDoc} 166 */ 167 @Override 168 protected void installDesktopManager() { 169 if (UIManager.getBoolean("InternalFrame.useTaskBar")) { 170 desktopManager = oldDesktopManager = desktop.getDesktopManager(); 171 if (!(desktopManager instanceof SynthDesktopManager)) { 172 desktopManager = new SynthDesktopManager(); 173 desktop.setDesktopManager(desktopManager); 174 } 175 } else { 176 super.installDesktopManager(); 177 } 178 } 179 180 /** 181 * {@inheritDoc} 182 */ 183 @Override 184 protected void uninstallDesktopManager() { 185 if (oldDesktopManager != null && !(oldDesktopManager instanceof UIResource)) { 186 desktopManager = desktop.getDesktopManager(); 187 if (desktopManager == null || desktopManager instanceof UIResource) { 188 desktop.setDesktopManager(oldDesktopManager); 189 } 190 } 191 oldDesktopManager = null; 192 super.uninstallDesktopManager(); 193 } 194 195 @SuppressWarnings("serial") // Same-version serialization only and 196 // internal anonymous classes 197 static class TaskBar extends JPanel implements ComponentListener, ContainerListener { 198 TaskBar() { 199 setOpaque(true); 200 setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0) { 201 public void layoutContainer(Container target) { 202 // First shrink buttons to fit 203 Component[] comps = target.getComponents(); 204 int n = comps.length; 205 if (n > 0) { 206 // Start with the largest preferred width 207 int prefWidth = 0; 208 for (Component c : comps) { 209 c.setPreferredSize(null); 210 Dimension prefSize = c.getPreferredSize(); 211 if (prefSize.width > prefWidth) { 212 prefWidth = prefSize.width; 213 } 214 } 215 // Shrink equally to fit if needed 216 Insets insets = target.getInsets(); 217 int tw = target.getWidth() - insets.left - insets.right; 218 int w = Math.min(prefWidth, Math.max(10, tw/n)); 219 for (Component c : comps) { 220 Dimension prefSize = c.getPreferredSize(); 221 c.setPreferredSize(new Dimension(w, prefSize.height)); 222 } 223 } 224 super.layoutContainer(target); 225 } 226 }); 227 228 // PENDING: This should be handled by the painter 229 setBorder(new BevelBorder(BevelBorder.RAISED) { 230 protected void paintRaisedBevel(Component c, Graphics g, 231 int x, int y, int w, int h) { 232 Color oldColor = g.getColor(); 233 g.translate(x, y); 234 g.setColor(getHighlightOuterColor(c)); 235 g.drawLine(0, 0, 0, h-2); 236 g.drawLine(1, 0, w-2, 0); 237 g.setColor(getShadowOuterColor(c)); 238 g.drawLine(0, h-1, w-1, h-1); 239 g.drawLine(w-1, 0, w-1, h-2); 240 g.translate(-x, -y); 241 g.setColor(oldColor); 242 } 243 }); 244 } 245 246 void adjustSize() { 247 JDesktopPane desktop = (JDesktopPane)getParent(); 248 if (desktop != null) { 249 int height = getPreferredSize().height; 250 Insets insets = getInsets(); 251 if (height == insets.top + insets.bottom) { 252 if (getHeight() <= height) { 253 // Initial size, because we have no buttons yet 254 height += 21; 255 } else { 256 // We already have a good height 257 height = getHeight(); 258 } 259 } 260 setBounds(0, desktop.getHeight() - height, desktop.getWidth(), height); 261 revalidate(); 262 repaint(); 263 } 264 } 265 266 // ComponentListener interface 267 268 public void componentResized(ComponentEvent e) { 269 if (e.getSource() instanceof JDesktopPane) { 270 adjustSize(); 271 } 272 } 273 274 public void componentMoved(ComponentEvent e){} 275 276 public void componentShown(ComponentEvent e) { 277 if (e.getSource() instanceof JInternalFrame) { 278 adjustSize(); 279 } 280 } 281 282 public void componentHidden(ComponentEvent e) { 283 if (e.getSource() instanceof JInternalFrame) { 284 ((JInternalFrame)e.getSource()).getDesktopIcon().setVisible(false); 285 revalidate(); 286 } 287 } 288 289 // ContainerListener interface 290 291 public void componentAdded(ContainerEvent e) { 292 if (e.getChild() instanceof JInternalFrame) { 293 JDesktopPane desktop = (JDesktopPane)e.getSource(); 294 JInternalFrame f = (JInternalFrame)e.getChild(); 295 JInternalFrame.JDesktopIcon desktopIcon = f.getDesktopIcon(); 296 for (Component comp : getComponents()) { 297 if (comp == desktopIcon) { 298 // We have it already 299 return; 300 } 301 } 302 add(desktopIcon); 303 f.addComponentListener(this); 304 if (getComponentCount() == 1) { 305 adjustSize(); 306 } 307 } 308 } 309 310 public void componentRemoved(ContainerEvent e) { 311 if (e.getChild() instanceof JInternalFrame) { 312 JInternalFrame f = (JInternalFrame)e.getChild(); 313 if (!f.isIcon()) { 314 // Frame was removed without using setClosed(true) 315 remove(f.getDesktopIcon()); 316 f.removeComponentListener(this); 317 revalidate(); 318 repaint(); 319 } 320 } 321 } 322 } 323 324 @SuppressWarnings("serial") // Same-version serialization only 325 class SynthDesktopManager extends DefaultDesktopManager implements UIResource { 326 327 public void maximizeFrame(JInternalFrame f) { 328 if (f.isIcon()) { 329 try { 330 f.setIcon(false); 331 } catch (PropertyVetoException e2) { 332 } 333 } else { 334 f.setNormalBounds(f.getBounds()); 335 Component desktop = f.getParent(); 336 setBoundsForFrame(f, 0, 0, 337 desktop.getWidth(), 338 desktop.getHeight() - taskBar.getHeight()); 339 } 340 341 try { 342 f.setSelected(true); 343 } catch (PropertyVetoException e2) { 344 } 345 } 346 347 public void iconifyFrame(JInternalFrame f) { 348 JInternalFrame.JDesktopIcon desktopIcon; 349 Container c = f.getParent(); 350 JDesktopPane d = f.getDesktopPane(); 351 boolean findNext = f.isSelected(); 352 if (c == null || d == null) { 353 return; 354 } 355 desktopIcon = f.getDesktopIcon(); 356 if (!wasIcon(f)) { 357 Rectangle r = getBoundsForIconOf(f); 358 desktopIcon.setBounds(r.x, r.y, r.width, r.height); 359 desktopIcon.revalidate(); 360 setWasIcon(f, Boolean.TRUE); 361 } 362 363 c.remove(f); 364 c.repaint(f.getX(), f.getY(), f.getWidth(), f.getHeight()); 365 try { 366 f.setSelected(false); 367 } catch (PropertyVetoException e2) { 368 } 369 370 // Get topmost of the remaining frames 371 if (findNext) { 372 for (Component comp : c.getComponents()) { 373 if (comp instanceof JInternalFrame) { 374 try { 375 ((JInternalFrame)comp).setSelected(true); 376 } catch (PropertyVetoException e2) { 377 } 378 ((JInternalFrame)comp).moveToFront(); 379 return; 380 } 381 } 382 } 383 } 384 385 386 public void deiconifyFrame(JInternalFrame f) { 387 JInternalFrame.JDesktopIcon desktopIcon = f.getDesktopIcon(); 388 Container c = desktopIcon.getParent(); 389 if (c != null) { 390 c = c.getParent(); 391 if (c != null) { 392 c.add(f); 393 if (f.isMaximum()) { 394 int w = c.getWidth(); 395 int h = c.getHeight() - taskBar.getHeight(); 396 if (f.getWidth() != w || f.getHeight() != h) { 397 setBoundsForFrame(f, 0, 0, w, h); 398 } 399 } 400 if (f.isSelected()) { 401 f.moveToFront(); 402 } else { 403 try { 404 f.setSelected(true); 405 } catch (PropertyVetoException e2) { 406 } 407 } 408 } 409 } 410 } 411 412 protected void removeIconFor(JInternalFrame f) { 413 super.removeIconFor(f); 414 taskBar.validate(); 415 } 416 417 public void setBoundsForFrame(JComponent f, int newX, int newY, int newWidth, int newHeight) { 418 super.setBoundsForFrame(f, newX, newY, newWidth, newHeight); 419 if (taskBar != null && newY >= taskBar.getY()) { 420 f.setLocation(f.getX(), taskBar.getY()-f.getInsets().top); 421 } 422 } 423 } 424 425 /** 426 * {@inheritDoc} 427 */ 428 @Override 429 public SynthContext getContext(JComponent c) { 430 return getContext(c, getComponentState(c)); 431 } 432 433 private SynthContext getContext(JComponent c, int state) { 434 return SynthContext.getContext(c, style, state); 435 } 436 437 private int getComponentState(JComponent c) { 438 return SynthLookAndFeel.getComponentState(c); 439 } 440 441 /** 442 * Notifies this UI delegate to repaint the specified component. 443 * This method paints the component background, then calls 444 * the {@link #paint(SynthContext,Graphics)} method. 445 * 446 * <p>In general, this method does not need to be overridden by subclasses. 447 * All Look and Feel rendering code should reside in the {@code paint} method. 448 * 449 * @param g the {@code Graphics} object used for painting 450 * @param c the component being painted 451 * @see #paint(SynthContext,Graphics) 452 */ 453 @Override 454 public void update(Graphics g, JComponent c) { 455 SynthContext context = getContext(c); 456 457 SynthLookAndFeel.update(context, g); 458 context.getPainter().paintDesktopPaneBackground(context, g, 0, 0, 459 c.getWidth(), c.getHeight()); 460 paint(context, g); 461 } 462 463 /** 464 * Paints the specified component according to the Look and Feel. 465 * <p>This method is not used by Synth Look and Feel. 466 * Painting is handled by the {@link #paint(SynthContext,Graphics)} method. 467 * 468 * @param g the {@code Graphics} object used for painting 469 * @param c the component being painted 470 * @see #paint(SynthContext,Graphics) 471 */ 472 @Override 473 public void paint(Graphics g, JComponent c) { 474 SynthContext context = getContext(c); 475 476 paint(context, g); 477 } 478 479 /** 480 * Paints the specified component. This implementation does nothing. 481 * 482 * @param context context for the component being painted 483 * @param g the {@code Graphics} object used for painting 484 * @see #update(Graphics,JComponent) 485 */ 486 protected void paint(SynthContext context, Graphics g) { 487 } 488 489 /** 490 * {@inheritDoc} 491 */ 492 @Override 493 public void paintBorder(SynthContext context, Graphics g, int x, 494 int y, int w, int h) { 495 context.getPainter().paintDesktopPaneBorder(context, g, x, y, w, h); 496 } 497 498 /** 499 * {@inheritDoc} 500 */ 501 @Override 502 public void propertyChange(PropertyChangeEvent evt) { 503 if (SynthLookAndFeel.shouldUpdateStyle(evt)) { 504 updateStyle((JDesktopPane)evt.getSource()); 505 } 506 if (evt.getPropertyName() == "ancestor" && taskBar != null) { 507 taskBar.adjustSize(); 508 } 509 } 510} 511