001/* 002 * $Id: BasicTaskPaneUI.java 4158 2012-02-03 18:29:40Z kschaefe $ 003 * 004 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021package org.jdesktop.swingx.plaf.basic; 022 023import java.awt.Color; 024import java.awt.Component; 025import java.awt.Cursor; 026import java.awt.Dimension; 027import java.awt.Font; 028import java.awt.Graphics; 029import java.awt.Insets; 030import java.awt.Rectangle; 031import java.awt.event.ActionEvent; 032import java.awt.event.FocusEvent; 033import java.awt.event.FocusListener; 034import java.awt.event.MouseEvent; 035import java.beans.PropertyChangeEvent; 036import java.beans.PropertyChangeListener; 037 038import javax.swing.AbstractAction; 039import javax.swing.Action; 040import javax.swing.ActionMap; 041import javax.swing.BorderFactory; 042import javax.swing.Icon; 043import javax.swing.InputMap; 044import javax.swing.JComponent; 045import javax.swing.JLabel; 046import javax.swing.LookAndFeel; 047import javax.swing.SwingUtilities; 048import javax.swing.UIManager; 049import javax.swing.border.Border; 050import javax.swing.border.CompoundBorder; 051import javax.swing.event.MouseInputAdapter; 052import javax.swing.event.MouseInputListener; 053import javax.swing.plaf.ActionMapUIResource; 054import javax.swing.plaf.ColorUIResource; 055import javax.swing.plaf.ComponentUI; 056import javax.swing.plaf.FontUIResource; 057import javax.swing.plaf.UIResource; 058import javax.swing.plaf.basic.BasicGraphicsUtils; 059 060import org.jdesktop.swingx.JXCollapsiblePane; 061import org.jdesktop.swingx.JXHyperlink; 062import org.jdesktop.swingx.JXTaskPane; 063import org.jdesktop.swingx.SwingXUtilities; 064import org.jdesktop.swingx.icon.EmptyIcon; 065import org.jdesktop.swingx.plaf.TaskPaneUI; 066 067/** 068 * Base implementation of the <code>JXTaskPane</code> UI. 069 * 070 * @author <a href="mailto:fred@L2FProd.com">Frederic Lavigne</a> 071 */ 072public class BasicTaskPaneUI extends TaskPaneUI { 073 074 private static FocusListener focusListener = new RepaintOnFocus(); 075 076 public static ComponentUI createUI(JComponent c) { 077 return new BasicTaskPaneUI(); 078 } 079 080 protected int titleHeight = 25; 081 protected int roundHeight = 5; 082 083 protected JXTaskPane group; 084 085 protected boolean mouseOver; 086 protected MouseInputListener mouseListener; 087 088 protected PropertyChangeListener propertyListener; 089 090 /** 091 * {@inheritDoc} 092 */ 093 @Override 094 public void installUI(JComponent c) { 095 super.installUI(c); 096 group = (JXTaskPane) c; 097 098 installDefaults(); 099 installListeners(); 100 installKeyboardActions(); 101 } 102 103 /** 104 * Installs default properties. Following properties are installed: 105 * <ul> 106 * <li>TaskPane.background</li> 107 * <li>TaskPane.foreground</li> 108 * <li>TaskPane.font</li> 109 * <li>TaskPane.borderColor</li> 110 * <li>TaskPane.titleForeground</li> 111 * <li>TaskPane.titleBackgroundGradientStart</li> 112 * <li>TaskPane.titleBackgroundGradientEnd</li> 113 * <li>TaskPane.titleOver</li> 114 * <li>TaskPane.specialTitleOver</li> 115 * <li>TaskPane.specialTitleForeground</li> 116 * <li>TaskPane.specialTitleBackground</li> 117 * </ul> 118 */ 119 protected void installDefaults() { 120 LookAndFeel.installProperty(group, "opaque", true); 121 group.setBorder(createPaneBorder()); 122 ((JComponent) group.getContentPane()) 123 .setBorder(createContentPaneBorder()); 124 125 LookAndFeel.installColorsAndFont(group, "TaskPane.background", 126 "TaskPane.foreground", "TaskPane.font"); 127 128 LookAndFeel.installColorsAndFont((JComponent) group.getContentPane(), 129 "TaskPane.background", "TaskPane.foreground", "TaskPane.font"); 130 } 131 132 /** 133 * Installs listeners for UI delegate. 134 */ 135 protected void installListeners() { 136 mouseListener = createMouseInputListener(); 137 group.addMouseMotionListener(mouseListener); 138 group.addMouseListener(mouseListener); 139 140 group.addFocusListener(focusListener); 141 propertyListener = createPropertyListener(); 142 group.addPropertyChangeListener(propertyListener); 143 } 144 145 /** 146 * Installs keyboard actions to allow task pane to react on hot keys. 147 */ 148 protected void installKeyboardActions() { 149 InputMap inputMap = (InputMap) UIManager.get("TaskPane.focusInputMap"); 150 if (inputMap != null) { 151 SwingUtilities.replaceUIInputMap(group, JComponent.WHEN_FOCUSED, 152 inputMap); 153 } 154 155 ActionMap map = getActionMap(); 156 if (map != null) { 157 SwingUtilities.replaceUIActionMap(group, map); 158 } 159 } 160 161 ActionMap getActionMap() { 162 ActionMap map = new ActionMapUIResource(); 163 map.put("toggleCollapsed", new ToggleCollapsedAction()); 164 return map; 165 } 166 167 @Override 168 public void uninstallUI(JComponent c) { 169 uninstallListeners(); 170 super.uninstallUI(c); 171 } 172 173 /** 174 * Uninstalls previously installed listeners to free component for garbage collection. 175 */ 176 protected void uninstallListeners() { 177 group.removeMouseListener(mouseListener); 178 group.removeMouseMotionListener(mouseListener); 179 group.removeFocusListener(focusListener); 180 group.removePropertyChangeListener(propertyListener); 181 } 182 183 /** 184 * Creates new toggle listener. 185 * @return MouseInputListener reacting on toggle events of task pane. 186 */ 187 protected MouseInputListener createMouseInputListener() { 188 return new ToggleListener(); 189 } 190 191 /** 192 * Creates property change listener for task pane. 193 * @return Property change listener reacting on changes to the task pane. 194 */ 195 protected PropertyChangeListener createPropertyListener() { 196 return new ChangeListener(); 197 } 198 199 /** 200 * Evaluates whenever given mouse even have occurred within borders of task pane. 201 * @param event Evaluated event. 202 * @return True if event occurred within task pane area, false otherwise. 203 */ 204 protected boolean isInBorder(MouseEvent event) { 205 return event.getY() < getTitleHeight(event.getComponent()); 206 } 207 208 /** 209 * Gets current title height. Default value is 25 if not specified otherwise. Method checks 210 * provided component for user set font (!instanceof FontUIResource), if font is set, height 211 * will be calculated from font metrics instead of using internal preset height. 212 * @return Current title height. 213 */ 214 protected int getTitleHeight(Component c) { 215 if (c instanceof JXTaskPane) { 216 JXTaskPane taskPane = (JXTaskPane) c; 217 Font font = taskPane.getFont(); 218 int height = titleHeight; 219 220 if (font != null && !(font instanceof FontUIResource)) { 221 height = Math.max(height, taskPane.getFontMetrics(font).getHeight()); 222 } 223 224 Icon icon = taskPane.getIcon(); 225 226 if (icon != null) { 227 height = Math.max(height, icon.getIconHeight() + 4); 228 } 229 230 return height; 231 } 232 233 return titleHeight; 234 } 235 236 /** 237 * Creates new border for task pane. 238 * @return Fresh border on every call. 239 */ 240 protected Border createPaneBorder() { 241 return new PaneBorder(); 242 } 243 244 @Override 245 public Dimension getPreferredSize(JComponent c) { 246 Component component = group.getComponent(0); 247 if (!(component instanceof JXCollapsiblePane)) { 248 // something wrong in this JXTaskPane 249 return super.getPreferredSize(c); 250 } 251 252 JXCollapsiblePane collapsible = (JXCollapsiblePane) component; 253 Dimension dim = collapsible.getPreferredSize(); 254 255 Border groupBorder = group.getBorder(); 256 if (groupBorder instanceof PaneBorder) { 257 ((PaneBorder) groupBorder).label.setDisplayedMnemonic(group 258 .getMnemonic()); 259 Dimension border = ((PaneBorder) groupBorder) 260 .getPreferredSize(group); 261 dim.width = Math.max(dim.width, border.width); 262 dim.height += border.height; 263 } else { 264 dim.height += getTitleHeight(c); 265 } 266 267 return dim; 268 } 269 270 /** 271 * Creates content pane border. 272 * @return Fresh content pane border initialized with current value of TaskPane.borderColor 273 * on every call. 274 */ 275 protected Border createContentPaneBorder() { 276 Color borderColor = UIManager.getColor("TaskPane.borderColor"); 277 return new CompoundBorder(new ContentPaneBorder(borderColor), 278 BorderFactory.createEmptyBorder(10, 10, 10, 10)); 279 } 280 281 @Override 282 public Component createAction(Action action) { 283 JXHyperlink link = new JXHyperlink(action) { 284 @Override 285 public void updateUI() { 286 super.updateUI(); 287 // ensure the ui of this link is correctly update on l&f changes 288 configure(this); 289 } 290 }; 291 configure(link); 292 return link; 293 } 294 295 /** 296 * Configures internally used hyperlink on new action creation and on every call to 297 * <code>updateUI()</code>. 298 * @param link Configured hyperlink. 299 */ 300 protected void configure(JXHyperlink link) { 301 link.setOpaque(false); 302 link.setBorderPainted(false); 303 link.setFocusPainted(true); 304 link.setForeground(UIManager.getColor("TaskPane.titleForeground")); 305 } 306 307 /** 308 * Ensures expanded group is visible. Issues delayed request for scrolling to visible. 309 */ 310 protected void ensureVisible() { 311 SwingUtilities.invokeLater(new Runnable() { 312 @Override 313 public void run() { 314 group.scrollRectToVisible(new Rectangle(group.getWidth(), group 315 .getHeight())); 316 } 317 }); 318 } 319 320 /** 321 * Focus listener responsible for repainting of the taskpane on focus change. 322 */ 323 static class RepaintOnFocus implements FocusListener { 324 @Override 325 public void focusGained(FocusEvent e) { 326 e.getComponent().repaint(); 327 } 328 329 @Override 330 public void focusLost(FocusEvent e) { 331 e.getComponent().repaint(); 332 } 333 } 334 335 /** 336 * Change listener responsible for change handling. 337 */ 338 class ChangeListener implements PropertyChangeListener { 339 @Override 340 public void propertyChange(PropertyChangeEvent evt) { 341 // if group is expanded but not animated 342 // or if animated has reached expanded state 343 // scroll to visible if scrollOnExpand is enabled 344 if (("collapsed".equals(evt.getPropertyName()) 345 && Boolean.TRUE.equals(evt.getNewValue()) && !group 346 .isAnimated())) { 347 if (group.isScrollOnExpand()) { 348 ensureVisible(); 349 } 350 } else if (JXTaskPane.ICON_CHANGED_KEY 351 .equals(evt.getPropertyName()) 352 || JXTaskPane.TITLE_CHANGED_KEY.equals(evt 353 .getPropertyName()) 354 || JXTaskPane.SPECIAL_CHANGED_KEY.equals(evt 355 .getPropertyName())) { 356 // icon, title, special must lead to a repaint() 357 group.repaint(); 358 } else if ("mnemonic".equals(evt.getPropertyName())) { 359 SwingXUtilities.updateMnemonicBinding(group, "toggleCollapsed"); 360 361 Border b = group.getBorder(); 362 363 if (b instanceof PaneBorder) { 364 int key = (Integer) evt.getNewValue(); 365 ((PaneBorder) b).label.setDisplayedMnemonic(key); 366 } 367 } 368 } 369 } 370 371 /** 372 * Mouse listener responsible for handling of toggle events. 373 */ 374 class ToggleListener extends MouseInputAdapter { 375 @Override 376 public void mouseEntered(MouseEvent e) { 377 if (isInBorder(e)) { 378 e.getComponent().setCursor( 379 Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); 380 } else { 381 mouseOver = false; 382 group.repaint(0, 0, group.getWidth(), getTitleHeight(group)); 383 } 384 } 385 386 @Override 387 public void mouseExited(MouseEvent e) { 388 e.getComponent().setCursor(null); 389 mouseOver = false; 390 group.repaint(0, 0, group.getWidth(), getTitleHeight(group)); 391 } 392 393 @Override 394 public void mouseMoved(MouseEvent e) { 395 if (isInBorder(e)) { 396 e.getComponent().setCursor( 397 Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); 398 mouseOver = true; 399 } else { 400 e.getComponent().setCursor(null); 401 mouseOver = false; 402 } 403 404 group.repaint(0, 0, group.getWidth(), getTitleHeight(group)); 405 } 406 407 @Override 408 public void mouseReleased(MouseEvent e) { 409 if (SwingUtilities.isLeftMouseButton(e) && isInBorder(e)) { 410 group.setCollapsed(!group.isCollapsed()); 411 } 412 } 413 } 414 415 /** 416 * Toggle expanded action. 417 */ 418 class ToggleCollapsedAction extends AbstractAction { 419 /** 420 * Serial version UID. 421 */ 422 private static final long serialVersionUID = 5676859881615358815L; 423 424 public ToggleCollapsedAction() { 425 super("toggleCollapsed"); 426 } 427 428 @Override 429 public void actionPerformed(ActionEvent e) { 430 group.setCollapsed(!group.isCollapsed()); 431 } 432 433 @Override 434 public boolean isEnabled() { 435 return group.isVisible(); 436 } 437 } 438 439 /** 440 * Toggle icon. 441 */ 442 protected static class ChevronIcon implements Icon { 443 boolean up = true; 444 445 public ChevronIcon(boolean up) { 446 this.up = up; 447 } 448 449 @Override 450 public int getIconHeight() { 451 return 3; 452 } 453 454 @Override 455 public int getIconWidth() { 456 return 6; 457 } 458 459 @Override 460 public void paintIcon(Component c, Graphics g, int x, int y) { 461 if (up) { 462 g.drawLine(x + 3, y, x, y + 3); 463 g.drawLine(x + 3, y, x + 6, y + 3); 464 } else { 465 g.drawLine(x, y, x + 3, y + 3); 466 g.drawLine(x + 3, y + 3, x + 6, y); 467 } 468 } 469 } 470 471 /** 472 * The border around the content pane 473 */ 474 protected static class ContentPaneBorder implements Border, UIResource { 475 Color color; 476 477 public ContentPaneBorder(Color color) { 478 this.color = color; 479 } 480 481 @Override 482 public Insets getBorderInsets(Component c) { 483 return new Insets(0, 1, 1, 1); 484 } 485 486 @Override 487 public boolean isBorderOpaque() { 488 return true; 489 } 490 491 @Override 492 public void paintBorder(Component c, Graphics g, int x, int y, 493 int width, int height) { 494 g.setColor(color); 495 g.drawLine(x, y, x, y + height - 1); 496 g.drawLine(x, y + height - 1, x + width - 1, y + height - 1); 497 g.drawLine(x + width - 1, y, x + width - 1, y + height - 1); 498 } 499 } 500 501 /** 502 * The border of the taskpane group paints the "text", the "icon", the 503 * "expanded" status and the "special" type. 504 * 505 */ 506 protected class PaneBorder implements Border, UIResource { 507 508 protected Color borderColor; 509 protected Color titleForeground; 510 protected Color specialTitleBackground; 511 protected Color specialTitleForeground; 512 protected Color titleBackgroundGradientStart; 513 protected Color titleBackgroundGradientEnd; 514 515 protected Color titleOver; 516 protected Color specialTitleOver; 517 518 protected JLabel label; 519 520 /** 521 * Creates new instance of individual pane border. 522 */ 523 public PaneBorder() { 524 borderColor = UIManager.getColor("TaskPane.borderColor"); 525 526 titleForeground = UIManager.getColor("TaskPane.titleForeground"); 527 528 specialTitleBackground = UIManager 529 .getColor("TaskPane.specialTitleBackground"); 530 specialTitleForeground = UIManager 531 .getColor("TaskPane.specialTitleForeground"); 532 533 titleBackgroundGradientStart = UIManager 534 .getColor("TaskPane.titleBackgroundGradientStart"); 535 titleBackgroundGradientEnd = UIManager 536 .getColor("TaskPane.titleBackgroundGradientEnd"); 537 538 titleOver = UIManager.getColor("TaskPane.titleOver"); 539 if (titleOver == null) { 540 titleOver = specialTitleBackground.brighter(); 541 } 542 specialTitleOver = UIManager.getColor("TaskPane.specialTitleOver"); 543 if (specialTitleOver == null) { 544 specialTitleOver = specialTitleBackground.brighter(); 545 } 546 547 label = new JLabel(); 548 label.setOpaque(false); 549 label.setIconTextGap(8); 550 } 551 552 @Override 553 public Insets getBorderInsets(Component c) { 554 return new Insets(getTitleHeight(c), 0, 0, 0); 555 } 556 557 /** 558 * Overwritten to always return <code>true</code> to speed up 559 * painting. Don't use transparent borders unless providing UI delegate 560 * that provides proper return value when calling this method. 561 * 562 * @see javax.swing.border.Border#isBorderOpaque() 563 */ 564 @Override 565 public boolean isBorderOpaque() { 566 return true; 567 } 568 569 /** 570 * Calculates the preferred border size, its size so all its content 571 * fits. 572 * 573 * @param group 574 * Selected group. 575 */ 576 public Dimension getPreferredSize(JXTaskPane group) { 577 // calculate the title width so it is fully visible 578 // it starts with the title width 579 configureLabel(group); 580 Dimension dim = label.getPreferredSize(); 581 // add the title left offset 582 dim.width += 3; 583 // add the controls width 584 dim.width += getTitleHeight(group); 585 // and some space between label and controls 586 dim.width += 3; 587 588 dim.height = getTitleHeight(group); 589 return dim; 590 } 591 592 /** 593 * Paints background of the title. This may differ based on properties 594 * of the group. 595 * 596 * @param group 597 * Selected group. 598 * @param g 599 * Target graphics. 600 */ 601 protected void paintTitleBackground(JXTaskPane group, Graphics g) { 602 if (group.isSpecial()) { 603 g.setColor(specialTitleBackground); 604 } else { 605 g.setColor(titleBackgroundGradientStart); 606 } 607 g.fillRect(0, 0, group.getWidth(), getTitleHeight(group) - 1); 608 } 609 610 /** 611 * Paints current group title. 612 * 613 * @param group 614 * Selected group. 615 * @param g 616 * Target graphics. 617 * @param textColor 618 * Title color. 619 * @param x 620 * X coordinate of the top left corner. 621 * @param y 622 * Y coordinate of the top left corner. 623 * @param width 624 * Width of the box. 625 * @param height 626 * Height of the box. 627 */ 628 protected void paintTitle(JXTaskPane group, Graphics g, 629 Color textColor, int x, int y, int width, int height) { 630 configureLabel(group); 631 label.setForeground(textColor); 632 if (group.getFont() != null && ! (group.getFont() instanceof FontUIResource)) { 633 label.setFont(group.getFont()); 634 } 635 g.translate(x, y); 636 label.setBounds(0, 0, width, height); 637 label.paint(g); 638 g.translate(-x, -y); 639 } 640 641 /** 642 * Configures label for the group using its title, font, icon and 643 * orientation. 644 * 645 * @param group 646 * Selected group. 647 */ 648 protected void configureLabel(JXTaskPane group) { 649 label.applyComponentOrientation(group.getComponentOrientation()); 650 label.setFont(group.getFont()); 651 label.setText(group.getTitle()); 652 label.setIcon(group.getIcon() == null ? new EmptyIcon() : group 653 .getIcon()); 654 } 655 656 /** 657 * Paints expanded controls. Default implementation does nothing. 658 * 659 * @param group 660 * Expanded group. 661 * @param g 662 * Target graphics. 663 * @param x 664 * X coordinate of the top left corner. 665 * @param y 666 * Y coordinate of the top left corner. 667 * @param width 668 * Width of the box. 669 * @param height 670 * Height of the box. 671 */ 672 protected void paintExpandedControls(JXTaskPane group, Graphics g, 673 int x, int y, int width, int height) { 674 } 675 676 /** 677 * Gets current paint color. 678 * 679 * @param group 680 * Selected group. 681 * @return Color to be used for painting provided group. 682 */ 683 protected Color getPaintColor(JXTaskPane group) { 684 Color paintColor; 685 if (isMouseOverBorder()) { 686 if (mouseOver) { 687 if (group.isSpecial()) { 688 paintColor = specialTitleOver; 689 } else { 690 paintColor = titleOver; 691 } 692 } else { 693 if (group.isSpecial()) { 694 paintColor = specialTitleForeground; 695 } else { 696 paintColor = group.getForeground() == null || group.getForeground() instanceof ColorUIResource ? titleForeground : group.getForeground(); 697 } 698 } 699 } else { 700 if (group.isSpecial()) { 701 paintColor = specialTitleForeground; 702 } else { 703 paintColor = group.getForeground() == null || group.getForeground() instanceof ColorUIResource ? titleForeground : group.getForeground(); 704 } 705 } 706 return paintColor; 707 } 708 709 /* 710 * @see javax.swing.border.Border#paintBorder(java.awt.Component, 711 * java.awt.Graphics, int, int, int, int) 712 */ 713 @Override 714 public void paintBorder(Component c, Graphics g, int x, int y, 715 int width, int height) { 716 717 JXTaskPane group = (JXTaskPane) c; 718 719 // calculate position of title and toggle controls 720 int controlWidth = getTitleHeight(group) - 2 * getRoundHeight(); 721 int controlX = group.getWidth() - getTitleHeight(group); 722 int controlY = getRoundHeight() - 1; 723 int titleX = 3; 724 int titleY = 0; 725 int titleWidth = group.getWidth() - getTitleHeight(group) - 3; 726 int titleHeight = getTitleHeight(group); 727 728 if (!group.getComponentOrientation().isLeftToRight()) { 729 controlX = group.getWidth() - controlX - controlWidth; 730 titleX = group.getWidth() - titleX - titleWidth; 731 } 732 733 // paint the title background 734 paintTitleBackground(group, g); 735 736 // paint the the toggles 737 paintExpandedControls(group, g, controlX, controlY, controlWidth, 738 controlWidth); 739 740 // paint the title text and icon 741 Color paintColor = getPaintColor(group); 742 743 // focus painted same color as text 744 if (group.hasFocus()) { 745 paintFocus(g, paintColor, 3, 3, width - 6, getTitleHeight(group) - 6); 746 } 747 748 paintTitle(group, g, paintColor, titleX, titleY, titleWidth, 749 titleHeight); 750 } 751 752 /** 753 * Paints oval 'border' area around the control itself. 754 * 755 * @param group 756 * Expanded group. 757 * @param g 758 * Target graphics. 759 * @param x 760 * X coordinate of the top left corner. 761 * @param y 762 * Y coordinate of the top left corner. 763 * @param width 764 * Width of the box. 765 * @param height 766 * Height of the box. 767 */ 768 protected void paintRectAroundControls(JXTaskPane group, Graphics g, 769 int x, int y, int width, int height, Color highColor, 770 Color lowColor) { 771 if (mouseOver) { 772 int x2 = x + width; 773 int y2 = y + height; 774 g.setColor(highColor); 775 g.drawLine(x, y, x2, y); 776 g.drawLine(x, y, x, y2); 777 g.setColor(lowColor); 778 g.drawLine(x2, y, x2, y2); 779 g.drawLine(x, y2, x2, y2); 780 } 781 } 782 783 /** 784 * Paints oval 'border' area around the control itself. 785 * 786 * @param group 787 * Expanded group. 788 * @param g 789 * Target graphics. 790 * @param x 791 * X coordinate of the top left corner. 792 * @param y 793 * Y coordinate of the top left corner. 794 * @param width 795 * Width of the box. 796 * @param height 797 * Height of the box. 798 */ 799 protected void paintOvalAroundControls(JXTaskPane group, Graphics g, 800 int x, int y, int width, int height) { 801 if (group.isSpecial()) { 802 g.setColor(specialTitleBackground.brighter()); 803 g.drawOval(x, y, width, height); 804 } else { 805 g.setColor(titleBackgroundGradientStart); 806 g.fillOval(x, y, width, height); 807 808 g.setColor(titleBackgroundGradientEnd.darker()); 809 g.drawOval(x, y, width, width); 810 } 811 } 812 813 /** 814 * Paints controls for the group. 815 * 816 * @param group 817 * Expanded group. 818 * @param g 819 * Target graphics. 820 * @param x 821 * X coordinate of the top left corner. 822 * @param y 823 * Y coordinate of the top left corner. 824 * @param width 825 * Width of the box. 826 * @param height 827 * Height of the box. 828 */ 829 protected void paintChevronControls(JXTaskPane group, Graphics g, 830 int x, int y, int width, int height) { 831 ChevronIcon chevron; 832 if (group.isCollapsed()) { 833 chevron = new ChevronIcon(false); 834 } else { 835 chevron = new ChevronIcon(true); 836 } 837 int chevronX = x + width / 2 - chevron.getIconWidth() / 2; 838 int chevronY = y + (height / 2 - chevron.getIconHeight()); 839 chevron.paintIcon(group, g, chevronX, chevronY); 840 chevron.paintIcon(group, g, chevronX, chevronY 841 + chevron.getIconHeight() + 1); 842 } 843 844 /** 845 * Paints focused group. 846 * 847 * @param g 848 * Target graphics. 849 * @param paintColor 850 * Focused group color. 851 * @param x 852 * X coordinate of the top left corner. 853 * @param y 854 * Y coordinate of the top left corner. 855 * @param width 856 * Width of the box. 857 * @param height 858 * Height of the box. 859 */ 860 protected void paintFocus(Graphics g, Color paintColor, int x, int y, 861 int width, int height) { 862 g.setColor(paintColor); 863 BasicGraphicsUtils.drawDashedRect(g, x, y, width, height); 864 } 865 866 /** 867 * Default implementation returns false. 868 * 869 * @return true if this border wants to display things differently when 870 * the mouse is over it 871 */ 872 protected boolean isMouseOverBorder() { 873 return false; 874 } 875 } 876 877 /** 878 * Gets size of arc used to round corners. 879 * 880 * @return size of arc used to round corners of the panel. 881 */ 882 protected int getRoundHeight() { 883 return roundHeight; 884 } 885 886}