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