1/* 2 * Copyright (c) 2002, 2012, 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 com.sun.java.swing.plaf.gtk; 27 28import java.awt.Font; 29import java.util.*; 30import javax.swing.*; 31import javax.swing.plaf.synth.*; 32import com.sun.java.swing.plaf.gtk.GTKEngine.WidgetType; 33 34/** 35 * 36 * @author Scott Violet 37 */ 38class GTKStyleFactory extends SynthStyleFactory { 39 40 /** 41 * Saves all styles that have been accessed. In most common cases, 42 * the hash key is simply the WidgetType, but in more complex cases 43 * it will be a ComplexKey object that contains arguments to help 44 * differentiate similar styles. 45 */ 46 private final Map<Object, GTKStyle> stylesCache; 47 48 private Font defaultFont; 49 50 GTKStyleFactory() { 51 stylesCache = new HashMap<Object, GTKStyle>(); 52 } 53 54 /** 55 * Returns the <code>GTKStyle</code> to use based on the 56 * <code>Region</code> id 57 * 58 * @param c this parameter isn't used, may be null. 59 * @param id of the region to get the style. 60 */ 61 public synchronized SynthStyle getStyle(JComponent c, Region id) { 62 WidgetType wt = GTKEngine.getWidgetType(c, id); 63 64 Object key = null; 65 if (id == Region.SCROLL_BAR) { 66 // The style/insets of a scrollbar can depend on a number of 67 // factors (see GTKStyle.getScrollBarInsets()) so use a 68 // complex key here. 69 if (c != null) { 70 JScrollBar sb = (JScrollBar)c; 71 boolean sp = (sb.getParent() instanceof JScrollPane); 72 boolean horiz = (sb.getOrientation() == JScrollBar.HORIZONTAL); 73 boolean ltr = sb.getComponentOrientation().isLeftToRight(); 74 boolean focusable = sb.isFocusable(); 75 key = new ComplexKey(wt, sp, horiz, ltr, focusable); 76 } 77 } 78 else if (id == Region.CHECK_BOX || id == Region.RADIO_BUTTON) { 79 // The style/insets of a checkbox or radiobutton can depend 80 // on the component orientation, so use a complex key here. 81 if (c != null) { 82 boolean ltr = c.getComponentOrientation().isLeftToRight(); 83 key = new ComplexKey(wt, ltr); 84 } 85 } 86 else if (id == Region.BUTTON) { 87 // The style/insets of a button can depend on whether it is 88 // default capable or in a toolbar, so use a complex key here. 89 if (c != null) { 90 JButton btn = (JButton)c; 91 boolean toolButton = (btn.getParent() instanceof JToolBar); 92 boolean defaultCapable = btn.isDefaultCapable(); 93 key = new ComplexKey(wt, toolButton, defaultCapable); 94 } 95 } else if (id == Region.MENU) { 96 if (c instanceof JMenu && ((JMenu) c).isTopLevelMenu() && 97 UIManager.getBoolean("Menu.useMenuBarForTopLevelMenus")) { 98 wt = WidgetType.MENU_BAR; 99 } 100 } 101 102 if (key == null) { 103 // Otherwise, just use the WidgetType as the key. 104 key = wt; 105 } 106 107 GTKStyle result = stylesCache.get(key); 108 if (result == null) { 109 result = new GTKStyle(defaultFont, wt); 110 stylesCache.put(key, result); 111 } 112 113 return result; 114 } 115 116 void initStyles(Font defaultFont) { 117 this.defaultFont = defaultFont; 118 stylesCache.clear(); 119 } 120 121 /** 122 * Represents a hash key used for fetching GTKStyle objects from the 123 * cache. In most cases only the WidgetType is used for lookup, but 124 * in some complex cases, other Object arguments can be specified 125 * via a ComplexKey to differentiate the various styles. 126 */ 127 private static class ComplexKey { 128 private final WidgetType wt; 129 private final Object[] args; 130 131 ComplexKey(WidgetType wt, Object... args) { 132 this.wt = wt; 133 this.args = args; 134 } 135 136 @Override 137 public int hashCode() { 138 int hash = wt.hashCode(); 139 if (args != null) { 140 for (Object arg : args) { 141 hash = hash*29 + (arg == null ? 0 : arg.hashCode()); 142 } 143 } 144 return hash; 145 } 146 147 @Override 148 public boolean equals(Object o) { 149 if (!(o instanceof ComplexKey)) { 150 return false; 151 } 152 ComplexKey that = (ComplexKey)o; 153 if (this.wt == that.wt) { 154 if (this.args == null && that.args == null) { 155 return true; 156 } 157 if (this.args != null && that.args != null && 158 this.args.length == that.args.length) 159 { 160 for (int i = 0; i < this.args.length; i++) { 161 Object a1 = this.args[i]; 162 Object a2 = that.args[i]; 163 if (!(a1==null ? a2==null : a1.equals(a2))) { 164 return false; 165 } 166 } 167 return true; 168 } 169 } 170 return false; 171 } 172 173 @Override 174 public String toString() { 175 String str = "ComplexKey[wt=" + wt; 176 if (args != null) { 177 str += ",args=["; 178 for (int i = 0; i < args.length; i++) { 179 str += args[i]; 180 if (i < args.length-1) str += ","; 181 } 182 str += "]"; 183 } 184 str += "]"; 185 return str; 186 } 187 } 188} 189