1 /*
   2  * Copyright (c) 1998, 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 com.sun.java.swing.plaf.windows;
  27 
  28 import javax.swing.*;
  29 import javax.swing.plaf.ButtonUI;
  30 import javax.swing.plaf.UIResource;
  31 
  32 import java.awt.*;
  33 import java.io.Serializable;
  34 
  35 import static com.sun.java.swing.plaf.windows.TMSchema.*;
  36 import static com.sun.java.swing.plaf.windows.XPStyle.Skin;
  37 
  38 import sun.swing.MenuItemCheckIconFactory;
  39 
  40 /**
  41  * Factory object that can vend Icons appropriate for the Windows {@literal L & F}.
  42  * <p>
  43  * <strong>Warning:</strong>
  44  * Serialized objects of this class will not be compatible with
  45  * future Swing releases.  The current serialization support is appropriate
  46  * for short term storage or RMI between applications running the same
  47  * version of Swing.  A future release of Swing will provide support for
  48  * long term persistence.
  49  *
  50  * @author David Kloba
  51  * @author Georges Saab
  52  * @author Rich Schiavi
  53  */
  54 @SuppressWarnings("serial") // Same-version serialization only
  55 public class WindowsIconFactory implements Serializable
  56 {
  57     private static Icon frame_closeIcon;
  58     private static Icon frame_iconifyIcon;
  59     private static Icon frame_maxIcon;
  60     private static Icon frame_minIcon;
  61     private static Icon frame_resizeIcon;
  62     private static Icon checkBoxIcon;
  63     private static Icon radioButtonIcon;
  64     private static Icon checkBoxMenuItemIcon;
  65     private static Icon radioButtonMenuItemIcon;
  66     private static Icon menuItemCheckIcon;
  67     private static Icon menuItemArrowIcon;
  68     private static Icon menuArrowIcon;
  69     private static VistaMenuItemCheckIconFactory menuItemCheckIconFactory;
  70 
  71     public static Icon getMenuItemCheckIcon() {
  72         if (menuItemCheckIcon == null) {
  73             menuItemCheckIcon = new MenuItemCheckIcon();
  74         }
  75         return menuItemCheckIcon;
  76     }
  77 
  78     public static Icon getMenuItemArrowIcon() {
  79         if (menuItemArrowIcon == null) {
  80             menuItemArrowIcon = new MenuItemArrowIcon();
  81         }
  82         return menuItemArrowIcon;
  83     }
  84 
  85     public static Icon getMenuArrowIcon() {
  86         if (menuArrowIcon == null) {
  87             menuArrowIcon = new MenuArrowIcon();
  88         }
  89         return menuArrowIcon;
  90     }
  91 
  92     public static Icon getCheckBoxIcon() {
  93         if (checkBoxIcon == null) {
  94             checkBoxIcon = new CheckBoxIcon();
  95         }
  96         return checkBoxIcon;
  97     }
  98 
  99     public static Icon getRadioButtonIcon() {
 100         if (radioButtonIcon == null) {
 101             radioButtonIcon = new RadioButtonIcon();
 102         }
 103         return radioButtonIcon;
 104     }
 105 
 106     public static Icon getCheckBoxMenuItemIcon() {
 107         if (checkBoxMenuItemIcon == null) {
 108             checkBoxMenuItemIcon = new CheckBoxMenuItemIcon();
 109         }
 110         return checkBoxMenuItemIcon;
 111     }
 112 
 113     public static Icon getRadioButtonMenuItemIcon() {
 114         if (radioButtonMenuItemIcon == null) {
 115             radioButtonMenuItemIcon = new RadioButtonMenuItemIcon();
 116         }
 117         return radioButtonMenuItemIcon;
 118     }
 119 
 120     static
 121     synchronized VistaMenuItemCheckIconFactory getMenuItemCheckIconFactory() {
 122         if (menuItemCheckIconFactory == null) {
 123             menuItemCheckIconFactory =
 124                 new VistaMenuItemCheckIconFactory();
 125         }
 126         return menuItemCheckIconFactory;
 127     }
 128 
 129     public static Icon createFrameCloseIcon() {
 130         if (frame_closeIcon == null) {
 131             frame_closeIcon = new FrameButtonIcon(Part.WP_CLOSEBUTTON);
 132         }
 133         return frame_closeIcon;
 134     }
 135 
 136     public static Icon createFrameIconifyIcon() {
 137         if (frame_iconifyIcon == null) {
 138             frame_iconifyIcon = new FrameButtonIcon(Part.WP_MINBUTTON);
 139         }
 140         return frame_iconifyIcon;
 141     }
 142 
 143     public static Icon createFrameMaximizeIcon() {
 144         if (frame_maxIcon == null) {
 145             frame_maxIcon = new FrameButtonIcon(Part.WP_MAXBUTTON);
 146         }
 147         return frame_maxIcon;
 148     }
 149 
 150     public static Icon createFrameMinimizeIcon() {
 151         if (frame_minIcon == null) {
 152             frame_minIcon = new FrameButtonIcon(Part.WP_RESTOREBUTTON);
 153         }
 154         return frame_minIcon;
 155     }
 156 
 157     public static Icon createFrameResizeIcon() {
 158         if(frame_resizeIcon == null)
 159             frame_resizeIcon = new ResizeIcon();
 160         return frame_resizeIcon;
 161     }
 162 
 163 
 164     @SuppressWarnings("serial") // Same-version serialization only
 165     private static class FrameButtonIcon implements Icon, Serializable {
 166         private Part part;
 167 
 168         private FrameButtonIcon(Part part) {
 169             this.part = part;
 170         }
 171 
 172         public void paintIcon(Component c, Graphics g, int x0, int y0) {
 173             int width = getIconWidth();
 174             int height = getIconHeight();
 175 
 176             XPStyle xp = XPStyle.getXP();
 177             if (xp != null) {
 178                 Skin skin = xp.getSkin(c, part);
 179                 AbstractButton b = (AbstractButton)c;
 180                 ButtonModel model = b.getModel();
 181 
 182                 // Find out if frame is inactive
 183                 JInternalFrame jif = (JInternalFrame)SwingUtilities.
 184                                         getAncestorOfClass(JInternalFrame.class, b);
 185                 boolean jifSelected = (jif != null && jif.isSelected());
 186 
 187                 State state;
 188                 if (jifSelected) {
 189                     if (!model.isEnabled()) {
 190                         state = State.DISABLED;
 191                     } else if (model.isArmed() && model.isPressed()) {
 192                         state = State.PUSHED;
 193                     } else if (model.isRollover()) {
 194                         state = State.HOT;
 195                     } else {
 196                         state = State.NORMAL;
 197                     }
 198                 } else {
 199                     if (!model.isEnabled()) {
 200                         state = State.INACTIVEDISABLED;
 201                     } else if (model.isArmed() && model.isPressed()) {
 202                         state = State.INACTIVEPUSHED;
 203                     } else if (model.isRollover()) {
 204                         state = State.INACTIVEHOT;
 205                     } else {
 206                         state = State.INACTIVENORMAL;
 207                     }
 208                 }
 209                 skin.paintSkin(g, 0, 0, width, height, state);
 210             } else {
 211                 g.setColor(Color.black);
 212                 int x = width / 12 + 2;
 213                 int y = height / 5;
 214                 int h = height - y * 2 - 1;
 215                 int w = width * 3/4 -3;
 216                 int thickness2 = Math.max(height / 8, 2);
 217                 int thickness  = Math.max(width / 15, 1);
 218                 if (part == Part.WP_CLOSEBUTTON) {
 219                     int lineWidth;
 220                     if      (width > 47) lineWidth = 6;
 221                     else if (width > 37) lineWidth = 5;
 222                     else if (width > 26) lineWidth = 4;
 223                     else if (width > 16) lineWidth = 3;
 224                     else if (width > 12) lineWidth = 2;
 225                     else                 lineWidth = 1;
 226                     y = height / 12 + 2;
 227                     if (lineWidth == 1) {
 228                         if (w % 2 == 1) { x++; w++; }
 229                         g.drawLine(x,     y, x+w-2, y+w-2);
 230                         g.drawLine(x+w-2, y, x,     y+w-2);
 231                     } else if (lineWidth == 2) {
 232                         if (w > 6) { x++; w--; }
 233                         g.drawLine(x,     y, x+w-2, y+w-2);
 234                         g.drawLine(x+w-2, y, x,     y+w-2);
 235                         g.drawLine(x+1,   y, x+w-1, y+w-2);
 236                         g.drawLine(x+w-1, y, x+1,   y+w-2);
 237                     } else {
 238                         x += 2; y++; w -= 2;
 239                         g.drawLine(x,     y,   x+w-1, y+w-1);
 240                         g.drawLine(x+w-1, y,   x,     y+w-1);
 241                         g.drawLine(x+1,   y,   x+w-1, y+w-2);
 242                         g.drawLine(x+w-2, y,   x,     y+w-2);
 243                         g.drawLine(x,     y+1, x+w-2, y+w-1);
 244                         g.drawLine(x+w-1, y+1, x+1,   y+w-1);
 245                         for (int i = 4; i <= lineWidth; i++) {
 246                             g.drawLine(x+i-2,   y,     x+w-1,   y+w-i+1);
 247                             g.drawLine(x,       y+i-2, x+w-i+1, y+w-1);
 248                             g.drawLine(x+w-i+1, y,     x,       y+w-i+1);
 249                             g.drawLine(x+w-1,   y+i-2, x+i-2,   y+w-1);
 250                         }
 251                     }
 252                 } else if (part == Part.WP_MINBUTTON) {
 253                     g.fillRect(x, y+h-thickness2, w-w/3, thickness2);
 254                 } else if (part == Part.WP_MAXBUTTON) {
 255                     g.fillRect(x, y, w, thickness2);
 256                     g.fillRect(x, y, thickness, h);
 257                     g.fillRect(x+w-thickness, y, thickness, h);
 258                     g.fillRect(x, y+h-thickness, w, thickness);
 259                 } else if (part == Part.WP_RESTOREBUTTON) {
 260                     g.fillRect(x+w/3, y, w-w/3, thickness2);
 261                     g.fillRect(x+w/3, y, thickness, h/3);
 262                     g.fillRect(x+w-thickness, y, thickness, h-h/3);
 263                     g.fillRect(x+w-w/3, y+h-h/3-thickness, w/3, thickness);
 264 
 265                     g.fillRect(x, y+h/3, w-w/3, thickness2);
 266                     g.fillRect(x, y+h/3, thickness, h-h/3);
 267                     g.fillRect(x+w-w/3-thickness, y+h/3, thickness, h-h/3);
 268                     g.fillRect(x, y+h-thickness, w-w/3, thickness);
 269                 }
 270             }
 271         }
 272 
 273         public int getIconWidth() {
 274             int width;
 275             if (XPStyle.getXP() != null) {
 276                 // Fix for XP bug where sometimes these sizes aren't updated properly
 277                 // Assume for now that height is correct and derive width using the
 278                 // ratio from the uxtheme part
 279                 width = UIManager.getInt("InternalFrame.titleButtonHeight") -2;
 280                 Dimension d = XPStyle.getPartSize(Part.WP_CLOSEBUTTON, State.NORMAL);
 281                 if (d != null && d.width != 0 && d.height != 0) {
 282                     width = (int) ((float) width * d.width / d.height);
 283                 }
 284             } else {
 285                 width = UIManager.getInt("InternalFrame.titleButtonWidth") -2;
 286             }
 287             if (XPStyle.getXP() != null) {
 288                 width -= 2;
 289             }
 290             return width;
 291         }
 292 
 293         public int getIconHeight() {
 294             int height = UIManager.getInt("InternalFrame.titleButtonHeight")-4;
 295             return height;
 296         }
 297     }
 298 
 299 
 300 
 301         @SuppressWarnings("serial") // Same-version serialization only
 302         private static class ResizeIcon implements Icon, Serializable {
 303             public void paintIcon(Component c, Graphics g, int x, int y) {
 304                 g.setColor(UIManager.getColor("InternalFrame.resizeIconHighlight"));
 305                 g.drawLine(0, 11, 11, 0);
 306                 g.drawLine(4, 11, 11, 4);
 307                 g.drawLine(8, 11, 11, 8);
 308 
 309                 g.setColor(UIManager.getColor("InternalFrame.resizeIconShadow"));
 310                 g.drawLine(1, 11, 11, 1);
 311                 g.drawLine(2, 11, 11, 2);
 312                 g.drawLine(5, 11, 11, 5);
 313                 g.drawLine(6, 11, 11, 6);
 314                 g.drawLine(9, 11, 11, 9);
 315                 g.drawLine(10, 11, 11, 10);
 316             }
 317             public int getIconWidth() { return 13; }
 318             public int getIconHeight() { return 13; }
 319         };
 320 
 321     @SuppressWarnings("serial") // Same-version serialization only
 322     private static class CheckBoxIcon implements Icon, Serializable
 323     {
 324         final static int csize = 13;
 325         public void paintIcon(Component c, Graphics g, int x, int y) {
 326             JCheckBox cb = (JCheckBox) c;
 327             ButtonModel model = cb.getModel();
 328             XPStyle xp = XPStyle.getXP();
 329 
 330             if (xp != null) {
 331                 State state;
 332                 if (model.isSelected()) {
 333                     state = State.CHECKEDNORMAL;
 334                     if (!model.isEnabled()) {
 335                         state = State.CHECKEDDISABLED;
 336                     } else if (model.isPressed() && model.isArmed()) {
 337                         state = State.CHECKEDPRESSED;
 338                     } else if (model.isRollover()) {
 339                         state = State.CHECKEDHOT;
 340                     }
 341                 } else {
 342                     state = State.UNCHECKEDNORMAL;
 343                     if (!model.isEnabled()) {
 344                         state = State.UNCHECKEDDISABLED;
 345                     } else if (model.isPressed() && model.isArmed()) {
 346                         state = State.UNCHECKEDPRESSED;
 347                     } else if (model.isRollover()) {
 348                         state = State.UNCHECKEDHOT;
 349                     }
 350                 }
 351                 Part part = Part.BP_CHECKBOX;
 352                 xp.getSkin(c, part).paintSkin(g, x, y, state);
 353             } else {
 354                 // outer bevel
 355                 if(!cb.isBorderPaintedFlat()) {
 356                     // Outer top/left
 357                     g.setColor(UIManager.getColor("CheckBox.shadow"));
 358                     g.drawLine(x, y, x+11, y);
 359                     g.drawLine(x, y+1, x, y+11);
 360 
 361                     // Outer bottom/right
 362                     g.setColor(UIManager.getColor("CheckBox.highlight"));
 363                     g.drawLine(x+12, y, x+12, y+12);
 364                     g.drawLine(x, y+12, x+11, y+12);
 365 
 366                     // Inner top.left
 367                     g.setColor(UIManager.getColor("CheckBox.darkShadow"));
 368                     g.drawLine(x+1, y+1, x+10, y+1);
 369                     g.drawLine(x+1, y+2, x+1, y+10);
 370 
 371                     // Inner bottom/right
 372                     g.setColor(UIManager.getColor("CheckBox.light"));
 373                     g.drawLine(x+1, y+11, x+11, y+11);
 374                     g.drawLine(x+11, y+1, x+11, y+10);
 375 
 376                     // inside box
 377                     if((model.isPressed() && model.isArmed()) || !model.isEnabled()) {
 378                         g.setColor(UIManager.getColor("CheckBox.background"));
 379                     } else {
 380                         g.setColor(UIManager.getColor("CheckBox.interiorBackground"));
 381                     }
 382                     g.fillRect(x+2, y+2, csize-4, csize-4);
 383                 } else {
 384                     g.setColor(UIManager.getColor("CheckBox.shadow"));
 385                     g.drawRect(x+1, y+1, csize-3, csize-3);
 386 
 387                     if((model.isPressed() && model.isArmed()) || !model.isEnabled()) {
 388                         g.setColor(UIManager.getColor("CheckBox.background"));
 389                     } else {
 390                         g.setColor(UIManager.getColor("CheckBox.interiorBackground"));
 391                     }
 392                     g.fillRect(x+2, y+2, csize-4, csize-4);
 393                 }
 394 
 395                 if(model.isEnabled()) {
 396                     g.setColor(UIManager.getColor("CheckBox.foreground"));
 397                 } else {
 398                     g.setColor(UIManager.getColor("CheckBox.shadow"));
 399                 }
 400 
 401                 // paint check
 402                 if (model.isSelected()) {
 403                     g.drawLine(x+9, y+3, x+9, y+3);
 404                     g.drawLine(x+8, y+4, x+9, y+4);
 405                     g.drawLine(x+7, y+5, x+9, y+5);
 406                     g.drawLine(x+6, y+6, x+8, y+6);
 407                     g.drawLine(x+3, y+7, x+7, y+7);
 408                     g.drawLine(x+4, y+8, x+6, y+8);
 409                     g.drawLine(x+5, y+9, x+5, y+9);
 410                     g.drawLine(x+3, y+5, x+3, y+5);
 411                     g.drawLine(x+3, y+6, x+4, y+6);
 412                 }
 413             }
 414         }
 415 
 416         public int getIconWidth() {
 417             XPStyle xp = XPStyle.getXP();
 418             if (xp != null) {
 419                 return xp.getSkin(null, Part.BP_CHECKBOX).getWidth();
 420             } else {
 421                 return csize;
 422             }
 423         }
 424 
 425         public int getIconHeight() {
 426             XPStyle xp = XPStyle.getXP();
 427             if (xp != null) {
 428                 return xp.getSkin(null, Part.BP_CHECKBOX).getHeight();
 429             } else {
 430                 return csize;
 431             }
 432         }
 433     }
 434 
 435     @SuppressWarnings("serial") // Same-version serialization only
 436     private static class RadioButtonIcon implements Icon, UIResource, Serializable
 437     {
 438         public void paintIcon(Component c, Graphics g, int x, int y) {
 439             AbstractButton b = (AbstractButton) c;
 440             ButtonModel model = b.getModel();
 441             XPStyle xp = XPStyle.getXP();
 442 
 443             if (xp != null) {
 444                 Part part = Part.BP_RADIOBUTTON;
 445                 Skin skin = xp.getSkin(b, part);
 446                 State state;
 447                 int index = 0;
 448                 if (model.isSelected()) {
 449                     state = State.CHECKEDNORMAL;
 450                     if (!model.isEnabled()) {
 451                         state = State.CHECKEDDISABLED;
 452                     } else if (model.isPressed() && model.isArmed()) {
 453                         state = State.CHECKEDPRESSED;
 454                     } else if (model.isRollover()) {
 455                         state = State.CHECKEDHOT;
 456                     }
 457                 } else {
 458                     state = State.UNCHECKEDNORMAL;
 459                     if (!model.isEnabled()) {
 460                         state = State.UNCHECKEDDISABLED;
 461                     } else if (model.isPressed() && model.isArmed()) {
 462                         state = State.UNCHECKEDPRESSED;
 463                     } else if (model.isRollover()) {
 464                         state = State.UNCHECKEDHOT;
 465                     }
 466                 }
 467                 skin.paintSkin(g, x, y, state);
 468             } else {
 469                 // fill interior
 470                 if((model.isPressed() && model.isArmed()) || !model.isEnabled()) {
 471                     g.setColor(UIManager.getColor("RadioButton.background"));
 472                 } else {
 473                     g.setColor(UIManager.getColor("RadioButton.interiorBackground"));
 474                 }
 475                 g.fillRect(x+2, y+2, 8, 8);
 476 
 477 
 478                     // outter left arc
 479                 g.setColor(UIManager.getColor("RadioButton.shadow"));
 480                 g.drawLine(x+4, y+0, x+7, y+0);
 481                 g.drawLine(x+2, y+1, x+3, y+1);
 482                 g.drawLine(x+8, y+1, x+9, y+1);
 483                 g.drawLine(x+1, y+2, x+1, y+3);
 484                 g.drawLine(x+0, y+4, x+0, y+7);
 485                 g.drawLine(x+1, y+8, x+1, y+9);
 486 
 487                 // outter right arc
 488                 g.setColor(UIManager.getColor("RadioButton.highlight"));
 489                 g.drawLine(x+2, y+10, x+3, y+10);
 490                 g.drawLine(x+4, y+11, x+7, y+11);
 491                 g.drawLine(x+8, y+10, x+9, y+10);
 492                 g.drawLine(x+10, y+9, x+10, y+8);
 493                 g.drawLine(x+11, y+7, x+11, y+4);
 494                 g.drawLine(x+10, y+3, x+10, y+2);
 495 
 496 
 497                 // inner left arc
 498                 g.setColor(UIManager.getColor("RadioButton.darkShadow"));
 499                 g.drawLine(x+4, y+1, x+7, y+1);
 500                 g.drawLine(x+2, y+2, x+3, y+2);
 501                 g.drawLine(x+8, y+2, x+9, y+2);
 502                 g.drawLine(x+2, y+3, x+2, y+3);
 503                 g.drawLine(x+1, y+4, x+1, y+7);
 504                 g.drawLine(x+2, y+8, x+2, y+8);
 505 
 506 
 507                 // inner right arc
 508                 g.setColor(UIManager.getColor("RadioButton.light"));
 509                 g.drawLine(x+2,  y+9,  x+3,  y+9);
 510                 g.drawLine(x+4,  y+10, x+7,  y+10);
 511                 g.drawLine(x+8,  y+9,  x+9,  y+9);
 512                 g.drawLine(x+9,  y+8,  x+9,  y+8);
 513                 g.drawLine(x+10, y+7,  x+10, y+4);
 514                 g.drawLine(x+9,  y+3,  x+9,  y+3);
 515 
 516 
 517                  // indicate whether selected or not
 518                 if (model.isSelected()) {
 519                     if (model.isEnabled()) {
 520                         g.setColor(UIManager.getColor("RadioButton.foreground"));
 521                     } else {
 522                         g.setColor(UIManager.getColor("RadioButton.shadow"));
 523                     }
 524                     g.fillRect(x+4, y+5, 4, 2);
 525                     g.fillRect(x+5, y+4, 2, 4);
 526                 }
 527             }
 528         }
 529 
 530         public int getIconWidth() {
 531             XPStyle xp = XPStyle.getXP();
 532             if (xp != null) {
 533                 return xp.getSkin(null, Part.BP_RADIOBUTTON).getWidth();
 534             } else {
 535                 return 13;
 536             }
 537         }
 538 
 539         public int getIconHeight() {
 540             XPStyle xp = XPStyle.getXP();
 541             if (xp != null) {
 542                 return xp.getSkin(null, Part.BP_RADIOBUTTON).getHeight();
 543             } else {
 544                 return 13;
 545             }
 546         }
 547     } // end class RadioButtonIcon
 548 
 549 
 550     @SuppressWarnings("serial") // Same-version serialization only
 551     private static class CheckBoxMenuItemIcon implements Icon, UIResource, Serializable
 552     {
 553         public void paintIcon(Component c, Graphics g, int x, int y) {
 554             AbstractButton b = (AbstractButton) c;
 555             ButtonModel model = b.getModel();
 556             boolean isSelected = model.isSelected();
 557             if (isSelected) {
 558                 y = y - getIconHeight() / 2;
 559                 g.drawLine(x+9, y+3, x+9, y+3);
 560                 g.drawLine(x+8, y+4, x+9, y+4);
 561                 g.drawLine(x+7, y+5, x+9, y+5);
 562                 g.drawLine(x+6, y+6, x+8, y+6);
 563                 g.drawLine(x+3, y+7, x+7, y+7);
 564                 g.drawLine(x+4, y+8, x+6, y+8);
 565                 g.drawLine(x+5, y+9, x+5, y+9);
 566                 g.drawLine(x+3, y+5, x+3, y+5);
 567                 g.drawLine(x+3, y+6, x+4, y+6);
 568             }
 569         }
 570         public int getIconWidth() { return 9; }
 571         public int getIconHeight() { return 9; }
 572 
 573     } // End class CheckBoxMenuItemIcon
 574 
 575 
 576     @SuppressWarnings("serial") // Same-version serialization only
 577     private static class RadioButtonMenuItemIcon implements Icon, UIResource, Serializable
 578     {
 579         public void paintIcon(Component c, Graphics g, int x, int y) {
 580             AbstractButton b = (AbstractButton) c;
 581             ButtonModel model = b.getModel();
 582             if (b.isSelected() == true) {
 583                g.fillRoundRect(x+3,y+3, getIconWidth()-6, getIconHeight()-6,
 584                                4, 4);
 585             }
 586         }
 587         public int getIconWidth() { return 12; }
 588         public int getIconHeight() { return 12; }
 589 
 590     } // End class RadioButtonMenuItemIcon
 591 
 592 
 593     @SuppressWarnings("serial") // Same-version serialization only
 594     private static class MenuItemCheckIcon implements Icon, UIResource, Serializable{
 595         public void paintIcon(Component c, Graphics g, int x, int y) {
 596             /* For debugging:
 597                Color oldColor = g.getColor();
 598             g.setColor(Color.orange);
 599             g.fill3DRect(x,y,getIconWidth(), getIconHeight(), true);
 600             g.setColor(oldColor);
 601             */
 602         }
 603         public int getIconWidth() { return 9; }
 604         public int getIconHeight() { return 9; }
 605 
 606     } // End class MenuItemCheckIcon
 607 
 608     @SuppressWarnings("serial") // Same-version serialization only
 609     private static class MenuItemArrowIcon implements Icon, UIResource, Serializable {
 610         public void paintIcon(Component c, Graphics g, int x, int y) {
 611             /* For debugging:
 612             Color oldColor = g.getColor();
 613             g.setColor(Color.green);
 614             g.fill3DRect(x,y,getIconWidth(), getIconHeight(), true);
 615             g.setColor(oldColor);
 616             */
 617         }
 618         public int getIconWidth() { return 4; }
 619         public int getIconHeight() { return 8; }
 620 
 621     } // End class MenuItemArrowIcon
 622 
 623     @SuppressWarnings("serial") // Same-version serialization only
 624     private static class MenuArrowIcon implements Icon, UIResource, Serializable {
 625         public void paintIcon(Component c, Graphics g, int x, int y) {
 626             XPStyle xp = XPStyle.getXP();
 627             if (WindowsMenuItemUI.isVistaPainting(xp)) {
 628                 State state = State.NORMAL;
 629                 if (c instanceof JMenuItem) {
 630                     state = ((JMenuItem) c).getModel().isEnabled()
 631                     ? State.NORMAL : State.DISABLED;
 632                 }
 633                 Skin skin = xp.getSkin(c, Part.MP_POPUPSUBMENU);
 634                 if (WindowsGraphicsUtils.isLeftToRight(c)) {
 635                     skin.paintSkin(g, x, y, state);
 636                 } else {
 637                     Graphics2D g2d = (Graphics2D)g.create();
 638                     g2d.translate(x + skin.getWidth(), y);
 639                     g2d.scale(-1, 1);
 640                     skin.paintSkin(g2d, 0, 0, state);
 641                     g2d.dispose();
 642                 }
 643             } else {
 644                 g.translate(x,y);
 645                 if( WindowsGraphicsUtils.isLeftToRight(c) ) {
 646                     g.drawLine( 0, 0, 0, 7 );
 647                     g.drawLine( 1, 1, 1, 6 );
 648                     g.drawLine( 2, 2, 2, 5 );
 649                     g.drawLine( 3, 3, 3, 4 );
 650                 } else {
 651                     g.drawLine( 4, 0, 4, 7 );
 652                     g.drawLine( 3, 1, 3, 6 );
 653                     g.drawLine( 2, 2, 2, 5 );
 654                     g.drawLine( 1, 3, 1, 4 );
 655                 }
 656                 g.translate(-x,-y);
 657             }
 658         }
 659         public int getIconWidth() {
 660             XPStyle xp = XPStyle.getXP();
 661             if (WindowsMenuItemUI.isVistaPainting(xp)) {
 662                 Skin skin = xp.getSkin(null, Part.MP_POPUPSUBMENU);
 663                 return skin.getWidth();
 664             } else {
 665                 return 4;
 666             }
 667         }
 668         public int getIconHeight() {
 669             XPStyle xp = XPStyle.getXP();
 670             if (WindowsMenuItemUI.isVistaPainting(xp)) {
 671                 Skin skin = xp.getSkin(null, Part.MP_POPUPSUBMENU);
 672                 return skin.getHeight();
 673             } else {
 674                 return 8;
 675             }
 676         }
 677     } // End class MenuArrowIcon
 678 
 679     static class VistaMenuItemCheckIconFactory
 680            implements MenuItemCheckIconFactory {
 681         private static final int OFFSET = 3;
 682 
 683         public Icon getIcon(JMenuItem component) {
 684             return new VistaMenuItemCheckIcon(component);
 685         }
 686 
 687         public boolean isCompatible(Object icon, String prefix) {
 688             return icon instanceof VistaMenuItemCheckIcon
 689               && ((VistaMenuItemCheckIcon) icon).type == getType(prefix);
 690         }
 691 
 692         public Icon getIcon(String type) {
 693             return new VistaMenuItemCheckIcon(type);
 694         }
 695 
 696         static int getIconWidth() {
 697             XPStyle xp = XPStyle.getXP();
 698             return ((xp != null) ? xp.getSkin(null, Part.MP_POPUPCHECK).getWidth() : 16)
 699                 + 2 * OFFSET;
 700         }
 701 
 702         private static Class<? extends JMenuItem> getType(Component c) {
 703             Class<? extends JMenuItem> rv = null;
 704             if (c instanceof JCheckBoxMenuItem) {
 705                 rv = JCheckBoxMenuItem.class;
 706             } else if (c instanceof JRadioButtonMenuItem) {
 707                 rv = JRadioButtonMenuItem.class;
 708             } else if (c instanceof JMenu) {
 709                 rv = JMenu.class;
 710             } else if (c instanceof JMenuItem) {
 711                 rv = JMenuItem.class;
 712             }
 713             return rv;
 714         }
 715 
 716         private static Class<? extends JMenuItem> getType(String type) {
 717             Class<? extends JMenuItem> rv = null;
 718             if (type == "CheckBoxMenuItem") {
 719                 rv = JCheckBoxMenuItem.class;
 720             } else if (type == "RadioButtonMenuItem") {
 721                 rv = JRadioButtonMenuItem.class;
 722             } else if (type == "Menu") {
 723                 rv = JMenu.class;
 724             } else if (type == "MenuItem") {
 725                 rv = JMenuItem.class;
 726             } else {
 727                 // this should never happen
 728                 rv = JMenuItem.class;
 729             }
 730             return rv;
 731         }
 732 
 733         /**
 734          * CheckIcon for JMenuItem, JMenu, JCheckBoxMenuItem and
 735          * JRadioButtonMenuItem.
 736          * Note: to be used on Vista only.
 737          */
 738         @SuppressWarnings("serial") // Same-version serialization only
 739         private static class VistaMenuItemCheckIcon
 740               implements Icon, UIResource, Serializable {
 741 
 742             private final JMenuItem menuItem;
 743             private final Class<? extends JMenuItem> type;
 744 
 745             VistaMenuItemCheckIcon(JMenuItem menuItem) {
 746                 this.type = getType(menuItem);
 747                 this.menuItem = menuItem;
 748             }
 749             VistaMenuItemCheckIcon(String type) {
 750                 this.type = getType(type);
 751                 this.menuItem = null;
 752             }
 753 
 754             public int getIconHeight() {
 755                 Icon lafIcon = getLaFIcon();
 756                 if (lafIcon != null) {
 757                     return lafIcon.getIconHeight();
 758                 }
 759                 Icon icon = getIcon();
 760                 int height = 0;
 761                 if (icon != null) {
 762                     height = icon.getIconHeight();
 763                 } else {
 764                     XPStyle xp = XPStyle.getXP();
 765                     if (xp != null) {
 766                         Skin skin = xp.getSkin(null, Part.MP_POPUPCHECK);
 767                         height = skin.getHeight();
 768                     } else {
 769                         height = 16;
 770                     }
 771                 }
 772                 height +=  2 * OFFSET;
 773                 return height;
 774             }
 775 
 776             public int getIconWidth() {
 777                 Icon lafIcon = getLaFIcon();
 778                 if (lafIcon != null) {
 779                     return lafIcon.getIconWidth();
 780                 }
 781                 Icon icon = getIcon();
 782                 int width = 0;
 783                 if (icon != null) {
 784                     width = icon.getIconWidth() + 2 * OFFSET;
 785                 } else {
 786                     width = VistaMenuItemCheckIconFactory.getIconWidth();
 787                 }
 788                 return width;
 789             }
 790 
 791             public void paintIcon(Component c, Graphics g, int x, int y) {
 792                 Icon lafIcon = getLaFIcon();
 793                 if (lafIcon != null) {
 794                     lafIcon.paintIcon(c, g, x, y);
 795                     return;
 796                 }
 797                 assert menuItem == null || c == menuItem;
 798                 Icon icon = getIcon();
 799                 if (type == JCheckBoxMenuItem.class
 800                       || type == JRadioButtonMenuItem.class) {
 801                     AbstractButton b = (AbstractButton) c;
 802                     if (b.isSelected()) {
 803                         Part backgroundPart = Part.MP_POPUPCHECKBACKGROUND;
 804                         Part part = Part.MP_POPUPCHECK;
 805                         State backgroundState;
 806                         State state;
 807                         if (isEnabled(c, null)) {
 808                             backgroundState =
 809                                 (icon != null) ? State.BITMAP : State.NORMAL;
 810                             state = (type == JRadioButtonMenuItem.class)
 811                               ? State.BULLETNORMAL
 812                               : State.CHECKMARKNORMAL;
 813                         } else {
 814                             backgroundState = State.DISABLEDPUSHED;
 815                             state =
 816                                 (type == JRadioButtonMenuItem.class)
 817                                   ? State.BULLETDISABLED
 818                                   : State.CHECKMARKDISABLED;
 819                         }
 820                         XPStyle xp = XPStyle.getXP();
 821                         if (xp != null) {
 822                             Skin skin;
 823                             skin =  xp.getSkin(c, backgroundPart);
 824                             skin.paintSkin(g, x, y,
 825                                 getIconWidth(), getIconHeight(), backgroundState);
 826                             if (icon == null) {
 827                                 skin = xp.getSkin(c, part);
 828                                 skin.paintSkin(g, x + OFFSET, y + OFFSET, state);
 829                             }
 830                         }
 831                     }
 832                 }
 833                 if (icon != null) {
 834                     icon.paintIcon(c, g, x + OFFSET, y + OFFSET);
 835                 }
 836             }
 837             private static WindowsMenuItemUIAccessor getAccessor(
 838                     JMenuItem menuItem) {
 839                 WindowsMenuItemUIAccessor rv = null;
 840                 ButtonUI uiObject = (menuItem != null) ? menuItem.getUI()
 841                         : null;
 842                 if (uiObject instanceof WindowsMenuItemUI) {
 843                     rv = ((WindowsMenuItemUI) uiObject).accessor;
 844                 } else if (uiObject instanceof WindowsMenuUI) {
 845                     rv = ((WindowsMenuUI) uiObject).accessor;
 846                 } else if (uiObject instanceof WindowsCheckBoxMenuItemUI) {
 847                     rv = ((WindowsCheckBoxMenuItemUI) uiObject).accessor;
 848                 } else if (uiObject instanceof WindowsRadioButtonMenuItemUI) {
 849                     rv = ((WindowsRadioButtonMenuItemUI) uiObject).accessor;
 850                 }
 851                 return rv;
 852             }
 853 
 854             private static boolean isEnabled(Component  c, State state) {
 855                 if (state == null && c instanceof JMenuItem) {
 856                     WindowsMenuItemUIAccessor accessor =
 857                         getAccessor((JMenuItem) c);
 858                     if (accessor != null) {
 859                         state = accessor.getState((JMenuItem) c);
 860                     }
 861                 }
 862                 if (state == null) {
 863                     if (c != null) {
 864                         return c.isEnabled();
 865                     } else {
 866                         return true;
 867                     }
 868                 } else {
 869                     return (state != State.DISABLED)
 870                         && (state != State.DISABLEDHOT)
 871                         && (state != State.DISABLEDPUSHED);
 872                 }
 873             }
 874             private Icon getIcon() {
 875                 Icon rv = null;
 876                 if (menuItem == null) {
 877                     return rv;
 878                 }
 879                 WindowsMenuItemUIAccessor accessor =
 880                     getAccessor(menuItem);
 881                 State state = (accessor != null) ? accessor.getState(menuItem)
 882                         : null;
 883                 if (isEnabled(menuItem, null)) {
 884                     if (state == State.PUSHED) {
 885                         rv = menuItem.getPressedIcon();
 886                     } else {
 887                         rv = menuItem.getIcon();
 888                     }
 889                 } else {
 890                     rv = menuItem.getDisabledIcon();
 891                 }
 892                 return rv;
 893             }
 894             /**
 895              * Check if developer changed icon in the UI table.
 896              *
 897              * @return the icon to use or {@code null} if the current one is to
 898              * be used
 899              */
 900             private Icon getLaFIcon() {
 901                 // use icon from the UI table if it does not match this one.
 902                 Icon rv = (Icon) UIManager.getDefaults().get(typeToString(type));
 903                 if (rv instanceof VistaMenuItemCheckIcon
 904                       && ((VistaMenuItemCheckIcon) rv).type == type) {
 905                     rv = null;
 906                 }
 907                 return rv;
 908             }
 909 
 910             private static String typeToString(
 911                     Class<? extends JMenuItem> type) {
 912                 assert type == JMenuItem.class
 913                     || type == JMenu.class
 914                     || type == JCheckBoxMenuItem.class
 915                     || type == JRadioButtonMenuItem.class;
 916                 StringBuilder sb = new StringBuilder(type.getName());
 917                 // remove package name, dot and the first character
 918                 sb.delete(0, sb.lastIndexOf("J") + 1);
 919                 sb.append(".checkIcon");
 920                 return sb.toString();
 921             }
 922         }
 923     } // End class VistaMenuItemCheckIconFactory
 924 }