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 
  26 package com.sun.java.swing.plaf.gtk;
  27 
  28 import java.awt.Font;
  29 import java.util.*;
  30 import javax.swing.*;
  31 import javax.swing.plaf.synth.*;
  32 import com.sun.java.swing.plaf.gtk.GTKEngine.WidgetType;
  33 
  34 /**
  35  *
  36  * @author Scott Violet
  37  */
  38 class 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} to use based on the
  56      * {@code Region} 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 }