1. /*
  2. * @(#)PixmapStyle.java 1.19 03/12/19
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package com.sun.java.swing.plaf.gtk;
  8. import javax.swing.plaf.synth.*;
  9. import java.awt.*;
  10. import java.util.*;
  11. import javax.swing.*;
  12. import java.security.*;
  13. import sun.swing.plaf.synth.*;
  14. /**
  15. * PixmapStyle extends GTKStyle adding support for a set of <code>Info</code>s.
  16. *
  17. * @version 1.19, 12/19/03
  18. * @author Scott Violet
  19. */
  20. class PixmapStyle extends GTKStyle implements GTKConstants {
  21. /**
  22. * There should only ever be one pixmap engine.
  23. */
  24. private static final GTKEngine PIXMAP_ENGINE = new PixmapEngine();
  25. /**
  26. * Set of Infos used to determine what to paint.
  27. */
  28. private Info[] info;
  29. /**
  30. * Creates a duplicate of the passed in style.
  31. */
  32. public PixmapStyle(DefaultSynthStyle style) {
  33. super(style);
  34. if (style instanceof PixmapStyle) {
  35. this.info = ((PixmapStyle)style).info;
  36. }
  37. }
  38. /**
  39. * Creates a PixmapStyle from the passed in arguments.
  40. */
  41. public PixmapStyle(StateInfo[] states,
  42. CircularIdentityList classSpecificValues,
  43. Font font,
  44. int xThickness, int yThickness,
  45. GTKStockIconInfo[] icons,
  46. Info[] info) {
  47. super(states, classSpecificValues, font, xThickness, yThickness, icons);
  48. this.info = info;
  49. }
  50. /**
  51. * Adds the state of this PixmapStyle to that of <code>s</code>
  52. * returning a combined SynthStyle.
  53. */
  54. public DefaultSynthStyle addTo(DefaultSynthStyle s) {
  55. if (!(s instanceof PixmapStyle)) {
  56. s = new PixmapStyle(s);
  57. }
  58. PixmapStyle style = (PixmapStyle)super.addTo(s);
  59. if (info != null) {
  60. if (style.info == null) {
  61. style.info = info;
  62. }
  63. else {
  64. // Place the more specific first.
  65. Info[] merged = new Info[style.info.length + info.length];
  66. System.arraycopy(info, 0, merged, 0, info.length);
  67. System.arraycopy(style.info, 0, merged, info.length,
  68. style.info.length);
  69. style.info = merged;
  70. }
  71. }
  72. return style;
  73. }
  74. /**
  75. * Creates a copy of the reciever and returns it.
  76. */
  77. public Object clone() {
  78. PixmapStyle style = (PixmapStyle)super.clone();
  79. // Info is immutable, no need to clone it.
  80. style.info = this.info;
  81. return style;
  82. }
  83. /**
  84. * Returns a GTKEngine to use for rendering.
  85. */
  86. public GTKEngine getEngine(SynthContext context) {
  87. return PIXMAP_ENGINE;
  88. }
  89. /**
  90. * Returns the first instance of Info that matches the past in args, may
  91. * return null if nothing matches.
  92. *
  93. * @param function String name for the painting method
  94. * @param detail Description of what is being painted
  95. * @param componentState State of the Component
  96. * @param shadow Shadow type
  97. * @param orientation Orientation of what is being painted
  98. * @param gapSide Side of the gap being drawn
  99. * @param arrowDirection direction of the arrow.
  100. * @return Best matching Info, or null if none match
  101. */
  102. public Info getInfo(String function, String detail, int componentState,
  103. int shadow, int orientation, int gapSide,
  104. int arrowDirection) {
  105. if (info != null) {
  106. for (int counter = 0, max = info.length; counter < max;counter++) {
  107. if (info[counter].getFunction() == function && info[counter].
  108. getMatchCount(detail, componentState, shadow,
  109. orientation, gapSide, arrowDirection) != -1) {
  110. return info[counter];
  111. }
  112. }
  113. }
  114. return null;
  115. }
  116. /**
  117. * Returns the number of non-null arugments and arguments that are
  118. * != UNDEFINED.
  119. */
  120. private int getMaxMatchCount(int componentState, int shadow,
  121. int orientation, int gapSide,
  122. int arrowDirection, String detail) {
  123. int count = 0;
  124. if (detail != null) {
  125. count++;
  126. }
  127. if (componentState != UNDEFINED) {
  128. count++;
  129. }
  130. if (shadow != UNDEFINED) {
  131. count++;
  132. }
  133. if (orientation != UNDEFINED) {
  134. count++;
  135. }
  136. if (gapSide != UNDEFINED) {
  137. count++;
  138. }
  139. if (arrowDirection != UNDEFINED) {
  140. count++;
  141. }
  142. return count;
  143. }
  144. /**
  145. * A description of how to paint a portion of a widget.
  146. */
  147. public static class Info {
  148. // match data
  149. private String function = null;
  150. private String detail = null;
  151. int gapSide = UNDEFINED;
  152. int orientation = UNDEFINED;
  153. int componentState = UNDEFINED;
  154. int shadow = UNDEFINED;
  155. int arrowDirection = UNDEFINED;
  156. boolean recolorable = false;
  157. // background
  158. Object image = null;
  159. Insets fileInsets = null;
  160. boolean stretch = false;
  161. // overlay
  162. Object overlayImage = null;
  163. Insets overlayInsets = null;
  164. boolean overlayStretch = false;
  165. // gap start
  166. Object gapStartImage = null;
  167. Insets gapStartInsets = null;
  168. // gap
  169. Object gapImage = null;
  170. Insets gapInsets = null;
  171. // gap end
  172. Object gapEndImage = null;
  173. Insets gapEndInsets = null;
  174. public void setFunction(String function) {
  175. this.function = function.intern();
  176. }
  177. public void setDetail(String detail) {
  178. this.detail = detail.intern();
  179. }
  180. public String getFunction() {
  181. return function;
  182. }
  183. public Image getImage() {
  184. image = getImage(image);
  185. return (Image)image;
  186. }
  187. public boolean isRecolorable() {
  188. return recolorable;
  189. }
  190. public Insets getImageInsets() {
  191. return fileInsets;
  192. }
  193. public boolean getStretch() {
  194. return stretch;
  195. }
  196. public String getDetail() {
  197. return detail;
  198. }
  199. public int getComponentState() {
  200. return componentState;
  201. }
  202. public int getShadow() {
  203. return shadow;
  204. }
  205. public int getGapSide() {
  206. return gapSide;
  207. }
  208. public Image getGapImage() {
  209. gapImage = getImage(gapImage);
  210. return (Image)gapImage;
  211. }
  212. public Insets getGapInsets() {
  213. return gapInsets;
  214. }
  215. public Image getGapStartImage() {
  216. gapStartImage = getImage(gapStartImage);
  217. return (Image)gapStartImage;
  218. }
  219. public Insets getGapStartInsets() {
  220. return gapStartInsets;
  221. }
  222. public Image getGapEndImage() {
  223. gapEndImage = getImage(gapEndImage);
  224. return (Image)gapEndImage;
  225. }
  226. public Insets getGapEndInsets() {
  227. return gapEndInsets;
  228. }
  229. public Image getOverlayImage() {
  230. overlayImage = getImage(overlayImage);
  231. return (Image)overlayImage;
  232. }
  233. public Insets getOverlayInsets() {
  234. return overlayInsets;
  235. }
  236. public boolean getOverlayStretch() {
  237. return overlayStretch;
  238. }
  239. public int getArrowDirection() {
  240. return arrowDirection;
  241. }
  242. public int getOrientation() {
  243. return orientation;
  244. }
  245. private Image getImage(final Object o) {
  246. if (o == null || o instanceof Image) {
  247. return (Image)o;
  248. }
  249. ImageIcon ii = (ImageIcon)AccessController.doPrivileged(new PrivilegedAction() {
  250. public Object run() {
  251. return new ImageIcon((String)o);
  252. }
  253. });
  254. if (ii.getIconWidth() > 0 && ii.getIconHeight() > 0) {
  255. return ii.getImage();
  256. }
  257. return null;
  258. }
  259. /**
  260. * Will return < 0 if doesn't match, otherwise return the
  261. * number of parameters that match.
  262. */
  263. int getMatchCount(String detail, int componentState, int shadow,
  264. int orientation, int gapSide, int arrowDirection) {
  265. int matchCount = 0;
  266. if (this.componentState != UNDEFINED) {
  267. if (componentState != UNDEFINED &&
  268. this.componentState != componentState) {
  269. return -1;
  270. }
  271. matchCount++;
  272. }
  273. if (this.shadow != UNDEFINED) {
  274. if (shadow != UNDEFINED && this.shadow != shadow) {
  275. return -1;
  276. }
  277. matchCount++;
  278. }
  279. if (this.orientation != UNDEFINED) {
  280. if (orientation != UNDEFINED &&
  281. this.orientation != orientation) {
  282. return -1;
  283. }
  284. matchCount++;
  285. }
  286. if (this.gapSide != UNDEFINED) {
  287. if (gapSide != UNDEFINED && this.gapSide != gapSide) {
  288. return -1;
  289. }
  290. matchCount++;
  291. }
  292. if (this.arrowDirection != UNDEFINED) {
  293. if (arrowDirection != UNDEFINED &&
  294. this.arrowDirection != arrowDirection) {
  295. return -1;
  296. }
  297. matchCount++;
  298. }
  299. if (this.detail != null) {
  300. if (this.detail != detail) {
  301. return -1;
  302. }
  303. matchCount++;
  304. }
  305. return matchCount;
  306. }
  307. /**
  308. * Returns true if this Info matches that of the passed in Info.
  309. * This differs from equals in so far as this only compares the
  310. * properties that are used in lookup vs the actual images or
  311. * insets.
  312. *
  313. * @return true if the receiver and info can be considered equal
  314. * for lookup.
  315. */
  316. boolean matches(Info info) {
  317. return (info.function == function && info.detail == detail &&
  318. info.componentState == componentState &&
  319. info.shadow == shadow && info.gapSide == gapSide &&
  320. info.arrowDirection == arrowDirection &&
  321. info.orientation == orientation);
  322. }
  323. public String toString() {
  324. StringBuffer buf = new StringBuffer();
  325. buf.append("IMAGE:\n");
  326. if (function != null) {
  327. buf.append(" function=").append(function).append('\n');
  328. }
  329. if (detail != null) {
  330. buf.append(" detail=").append(detail).append('\n');
  331. }
  332. if (gapSide != UNDEFINED) {
  333. buf.append(" gapSide=");
  334. buf.append(getSideName(gapSide)).append('\n');
  335. }
  336. if (orientation != UNDEFINED) {
  337. buf.append(" orientation=");
  338. buf.append(getOrientName(orientation)).append('\n');
  339. }
  340. if (componentState != UNDEFINED) {
  341. buf.append(" componentState=");
  342. buf.append(getStateName(componentState, "UNDEFINED")).append('\n');
  343. }
  344. if (shadow != UNDEFINED) {
  345. buf.append(" shadow=");
  346. buf.append(getShadowName(shadow)).append('\n');
  347. }
  348. if (arrowDirection != UNDEFINED) {
  349. buf.append(" arrowDirection=");
  350. buf.append(getArrowDirectionName(arrowDirection)).append('\n');
  351. }
  352. if (recolorable != false) {
  353. buf.append(" recolorable=").append(recolorable).append('\n');
  354. }
  355. if (image != null) {
  356. buf.append(" image=").append(image).append('\n');
  357. }
  358. if (fileInsets != null) {
  359. buf.append(" fileInsets=").append(fileInsets).append('\n');
  360. }
  361. if (stretch != false) {
  362. buf.append(" stretch=").append(stretch).append('\n');
  363. }
  364. if (overlayImage != null) {
  365. buf.append(" overlayImage=").append(overlayImage).append('\n');
  366. }
  367. if (overlayInsets != null) {
  368. buf.append(" overlayInsets=").append(overlayInsets).append('\n');
  369. }
  370. if (overlayStretch != false) {
  371. buf.append(" overlayStretch=").append(overlayStretch).append('\n');
  372. }
  373. if (gapStartImage != null) {
  374. buf.append(" gapStartImage=").append(gapStartImage).append('\n');
  375. }
  376. if (gapStartInsets != null) {
  377. buf.append(" gapStartInsets=").append(gapStartInsets).append('\n');
  378. }
  379. if (gapImage != null) {
  380. buf.append(" gapImage=").append(gapImage).append('\n');
  381. }
  382. if (gapInsets != null) {
  383. buf.append(" gapInsets=").append(gapInsets).append('\n');
  384. }
  385. if (gapEndImage != null) {
  386. buf.append(" gapEndImage=").append(gapEndImage).append('\n');
  387. }
  388. if (gapEndInsets != null) {
  389. buf.append(" gapEndInsets=").append(gapEndInsets).append('\n');
  390. }
  391. buf.deleteCharAt(buf.length() - 1);
  392. return buf.toString();
  393. }
  394. private static String getSideName(int side) {
  395. switch(side) {
  396. case TOP: return "TOP";
  397. case BOTTOM: return "BOTTOM";
  398. case LEFT: return "LEFT";
  399. case RIGHT: return "RIGHT";
  400. case UNDEFINED: return "UNDEFINED";
  401. }
  402. return "UNKNOWN";
  403. }
  404. private static String getOrientName(int orient) {
  405. switch(orient) {
  406. case HORIZONTAL: return "HORIZONTAL";
  407. case VERTICAL: return "VERTICAL";
  408. case UNDEFINED: return "UNDEFINED";
  409. }
  410. return "UNKNOWN";
  411. }
  412. private static String getShadowName(int shadow) {
  413. switch(shadow) {
  414. case SHADOW_IN: return "SHADOW_IN";
  415. case SHADOW_OUT: return "SHADOW_OUT";
  416. case SHADOW_ETCHED_IN: return "SHADOW_ETCHED_IN";
  417. case SHADOW_ETCHED_OUT: return "SHADOW_ETCHED_OUT";
  418. case SHADOW_NONE: return "SHADOW_NONE";
  419. case UNDEFINED: return "UNDEFINED";
  420. }
  421. return "UNKNOWN";
  422. }
  423. private static String getArrowDirectionName(int dir) {
  424. switch(dir) {
  425. case ARROW_UP: return "ARROW_UP";
  426. case ARROW_DOWN: return "ARROW_DOWN";
  427. case ARROW_LEFT: return "ARROW_LEFT";
  428. case ARROW_RIGHT: return "ARROW_RIGHT";
  429. case UNDEFINED: return "UNDEFINED";
  430. }
  431. return "UNKNOWN";
  432. }
  433. }
  434. public String toString() {
  435. if (info == null) {
  436. return super.toString();
  437. } else {
  438. StringBuffer buf = new StringBuffer(super.toString());
  439. if (buf.length() > 0) {
  440. buf.append('\n');
  441. }
  442. buf.append("*** Pixmap Engine Info ***\n");
  443. for (int i = 0; i < info.length; i++) {
  444. buf.append(info[i].toString()).append('\n');
  445. }
  446. // remove last newline
  447. buf.deleteCharAt(buf.length() - 1);
  448. return buf.toString();
  449. }
  450. }
  451. }