1 /* 2 * Copyright (c) 2002, 2018, 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 package com.sun.java.swing.plaf.gtk; 26 27 import java.util.*; 28 import javax.swing.plaf.synth.*; 29 import java.awt.*; 30 import java.awt.image.BufferedImage; 31 import java.lang.reflect.*; 32 import javax.swing.*; 33 import javax.swing.plaf.*; 34 import sun.swing.plaf.synth.*; 35 import com.sun.java.swing.plaf.gtk.GTKConstants.ArrowType; 36 import com.sun.java.swing.plaf.gtk.GTKConstants.ExpanderStyle; 37 import com.sun.java.swing.plaf.gtk.GTKConstants.Orientation; 38 import com.sun.java.swing.plaf.gtk.GTKConstants.ShadowType; 39 40 /** 41 */ 42 class GTKIconFactory { 43 static final int CHECK_ICON_EXTRA_INSET = 1; 44 static final int DEFAULT_ICON_SPACING = 2; 45 static final int DEFAULT_ICON_SIZE = 13; 46 static final int DEFAULT_TOGGLE_MENU_ITEM_SIZE = 12; // For pre-gtk2.4 47 48 private static final String RADIO_BUTTON_ICON = "paintRadioButtonIcon"; 49 private static final String CHECK_BOX_ICON = "paintCheckBoxIcon"; 50 private static final String MENU_ARROW_ICON = "paintMenuArrowIcon"; 51 private static final String CHECK_BOX_MENU_ITEM_CHECK_ICON = 52 "paintCheckBoxMenuItemCheckIcon"; 53 private static final String RADIO_BUTTON_MENU_ITEM_CHECK_ICON = 54 "paintRadioButtonMenuItemCheckIcon"; 55 private static final String TREE_EXPANDED_ICON = "paintTreeExpandedIcon"; 56 private static final String TREE_COLLAPSED_ICON = "paintTreeCollapsedIcon"; 57 private static final String ASCENDING_SORT_ICON = "paintAscendingSortIcon"; 58 private static final String DESCENDING_SORT_ICON = "paintDescendingSortIcon"; 59 private static final String TOOL_BAR_HANDLE_ICON = "paintToolBarHandleIcon"; 60 61 private static Map<String, DelegatingIcon> iconsPool = 62 Collections.synchronizedMap(new HashMap<String, DelegatingIcon>()); 63 64 private static DelegatingIcon getIcon(String methodName) { 65 DelegatingIcon result = iconsPool.get(methodName); 66 if (result == null) { 67 if (methodName == TREE_COLLAPSED_ICON || 68 methodName == TREE_EXPANDED_ICON) 69 { 70 result = new SynthExpanderIcon(methodName); 71 72 } else if (methodName == TOOL_BAR_HANDLE_ICON) { 73 result = new ToolBarHandleIcon(); 74 75 } else if (methodName == MENU_ARROW_ICON) { 76 result = new MenuArrowIcon(); 77 78 } else { 79 result = new DelegatingIcon(methodName); 80 } 81 iconsPool.put(methodName, result); 82 } 83 return result; 84 } 85 86 // 87 // Sort arrow 88 // 89 public static Icon getAscendingSortIcon() { 90 return getIcon(ASCENDING_SORT_ICON); 91 } 92 93 public static Icon getDescendingSortIcon() { 94 return getIcon(DESCENDING_SORT_ICON); 95 } 96 97 // 98 // Tree methods 99 // 100 public static SynthIcon getTreeExpandedIcon() { 101 return getIcon(TREE_EXPANDED_ICON); 102 } 103 104 public static SynthIcon getTreeCollapsedIcon() { 105 return getIcon(TREE_COLLAPSED_ICON); 106 } 107 108 // 109 // Radio button 110 // 111 public static SynthIcon getRadioButtonIcon() { 112 return getIcon(RADIO_BUTTON_ICON); 113 } 114 115 // 116 // CheckBox 117 // 118 public static SynthIcon getCheckBoxIcon() { 119 return getIcon(CHECK_BOX_ICON); 120 } 121 122 // 123 // Menus 124 // 125 public static SynthIcon getMenuArrowIcon() { 126 return getIcon(MENU_ARROW_ICON); 127 } 128 129 public static SynthIcon getCheckBoxMenuItemCheckIcon() { 130 return getIcon(CHECK_BOX_MENU_ITEM_CHECK_ICON); 131 } 132 133 public static SynthIcon getRadioButtonMenuItemCheckIcon() { 134 return getIcon(RADIO_BUTTON_MENU_ITEM_CHECK_ICON); 135 } 136 137 // 138 // ToolBar Handle 139 // 140 public static SynthIcon getToolBarHandleIcon() { 141 return getIcon(TOOL_BAR_HANDLE_ICON); 142 } 143 144 static void resetIcons() { 145 synchronized (iconsPool) { 146 for (DelegatingIcon di: iconsPool.values()) { 147 di.resetIconDimensions(); 148 } 149 } 150 } 151 152 private static class DelegatingIcon extends SynthIcon implements 153 UIResource { 154 private static final Class[] PARAM_TYPES = new Class[] { 155 SynthContext.class, Graphics.class, int.class, 156 int.class, int.class, int.class, int.class 157 }; 158 159 private Object method; 160 int iconDimension = -1; 161 162 DelegatingIcon(String methodName ){ 163 this.method = methodName; 164 } 165 166 public void paintIcon(SynthContext context, Graphics g, 167 int x, int y, int w, int h) { 168 if (context != null) { 169 GTKPainter.INSTANCE.paintIcon(context, g, 170 getMethod(), x, y, w, h); 171 } 172 } 173 174 public int getIconWidth(SynthContext context) { 175 return getIconDimension(context); 176 } 177 178 public int getIconHeight(SynthContext context) { 179 return getIconDimension(context); 180 } 181 182 void resetIconDimensions() { 183 iconDimension = -1; 184 } 185 186 protected Method getMethod() { 187 if (method instanceof String) { 188 method = resolveMethod((String)method); 189 } 190 return (Method)method; 191 } 192 193 protected Class[] getMethodParamTypes() { 194 return PARAM_TYPES; 195 } 196 197 private Method resolveMethod(String name) { 198 try { 199 return GTKPainter.class.getMethod(name, getMethodParamTypes()); 200 } catch (NoSuchMethodException e) { 201 assert false; 202 } 203 return null; 204 } 205 206 int getIconDimension(SynthContext context) { 207 if (iconDimension >= 0) { 208 return iconDimension; 209 } 210 211 if (context == null) { 212 return DEFAULT_ICON_SIZE; 213 } 214 215 Region region = context.getRegion(); 216 GTKStyle style = (GTKStyle) context.getStyle(); 217 if (GTKLookAndFeel.is3() && region == Region.MENU) { 218 Object value = style.getClassSpecificValue("arrow-scaling"); 219 if (value instanceof Number) { 220 iconDimension = (int)(((Number) value).floatValue() * 221 (style.getFont(context).getSize2D() + 222 2 * style.getClassSpecificIntValue(context, 223 "indicator-spacing", DEFAULT_ICON_SPACING))); 224 if (iconDimension > 0) { 225 return iconDimension; 226 } 227 } 228 } 229 iconDimension = style.getClassSpecificIntValue(context, 230 "indicator-size", 231 (region == Region.CHECK_BOX_MENU_ITEM || 232 region == Region.RADIO_BUTTON_MENU_ITEM) ? 233 DEFAULT_TOGGLE_MENU_ITEM_SIZE : DEFAULT_ICON_SIZE); 234 235 if (region == Region.CHECK_BOX || region == Region.RADIO_BUTTON) { 236 iconDimension += 2 * style.getClassSpecificIntValue(context, 237 "indicator-spacing", DEFAULT_ICON_SPACING); 238 } else if (region == Region.CHECK_BOX_MENU_ITEM || 239 region == Region.RADIO_BUTTON_MENU_ITEM) { 240 iconDimension += 2 * CHECK_ICON_EXTRA_INSET; 241 } 242 return iconDimension; 243 } 244 } 245 246 private static class SynthExpanderIcon extends DelegatingIcon { 247 SynthExpanderIcon(String method) { 248 super(method); 249 } 250 251 public void paintIcon(SynthContext context, Graphics g, int x, int y, 252 int w, int h) { 253 if (context != null) { 254 super.paintIcon(context, g, x, y, w, h); 255 updateSizeIfNecessary(context); 256 } 257 } 258 259 int getIconDimension(SynthContext context) { 260 updateSizeIfNecessary(context); 261 return (iconDimension == -1) ? DEFAULT_ICON_SIZE : 262 iconDimension; 263 } 264 265 private void updateSizeIfNecessary(SynthContext context) { 266 if (iconDimension == -1 && context != null) { 267 iconDimension = context.getStyle().getInt(context, 268 "Tree.expanderSize", 10); 269 } 270 } 271 } 272 273 // GTK has a separate widget for the handle box, to mirror this 274 // we create a unique icon per ToolBar and lookup the style for the 275 // HandleBox. 276 private static class ToolBarHandleIcon extends DelegatingIcon { 277 private static final Class[] PARAM_TYPES = new Class[] { 278 SynthContext.class, Graphics.class, int.class, 279 int.class, int.class, int.class, int.class, Orientation.class, 280 }; 281 282 private SynthStyle style; 283 284 public ToolBarHandleIcon() { 285 super(TOOL_BAR_HANDLE_ICON); 286 } 287 288 protected Class[] getMethodParamTypes() { 289 return PARAM_TYPES; 290 } 291 292 public void paintIcon(SynthContext context, Graphics g, int x, int y, 293 int w, int h) { 294 if (context != null) { 295 JToolBar toolbar = (JToolBar)context.getComponent(); 296 Orientation orientation = 297 (toolbar.getOrientation() == JToolBar.HORIZONTAL ? 298 Orientation.HORIZONTAL : Orientation.VERTICAL); 299 300 if (style == null) { 301 style = SynthLookAndFeel.getStyleFactory().getStyle( 302 context.getComponent(), GTKRegion.HANDLE_BOX); 303 } 304 context = new SynthContext(toolbar, GTKRegion.HANDLE_BOX, 305 style, SynthConstants.ENABLED); 306 307 GTKPainter.INSTANCE.paintIcon(context, g, 308 getMethod(), x, y, w, h, orientation); 309 } 310 } 311 312 public int getIconWidth(SynthContext context) { 313 if (context == null) { 314 return 10; 315 } 316 if (((JToolBar)context.getComponent()).getOrientation() == 317 JToolBar.HORIZONTAL) { 318 return 10; 319 } else { 320 return context.getComponent().getWidth(); 321 } 322 } 323 324 public int getIconHeight(SynthContext context) { 325 if (context == null) { 326 return 10; 327 } 328 if (((JToolBar)context.getComponent()).getOrientation() == 329 JToolBar.HORIZONTAL) { 330 return context.getComponent().getHeight(); 331 } else { 332 return 10; 333 } 334 } 335 } 336 337 private static class MenuArrowIcon extends DelegatingIcon { 338 private static final Class[] PARAM_TYPES = new Class[] { 339 SynthContext.class, Graphics.class, int.class, 340 int.class, int.class, int.class, int.class, ArrowType.class, 341 }; 342 343 public MenuArrowIcon() { 344 super(MENU_ARROW_ICON); 345 } 346 347 protected Class[] getMethodParamTypes() { 348 return PARAM_TYPES; 349 } 350 351 public void paintIcon(SynthContext context, Graphics g, int x, int y, 352 int w, int h) { 353 if (context != null) { 354 ArrowType arrowDir = ArrowType.RIGHT; 355 if (!context.getComponent().getComponentOrientation().isLeftToRight()) { 356 arrowDir = ArrowType.LEFT; 357 } 358 GTKPainter.INSTANCE.paintIcon(context, g, 359 getMethod(), x, y, w, h, arrowDir); 360 } 361 } 362 } 363 }