001 /* steelme theme manager for Java 002 * Copyright (C) 2000 - 2004 T.J. Willis 003 * 004 * This program is free software; you can redistribute it and/or 005 * modify it under the terms of the GNU General Public License 006 * as published by the Free Software Foundation; either version 2 007 * of the License, or (at your option) any later version. 008 * 009 * This program is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 012 * GNU General Public License for more details. 013 * 014 * You should have received a copy of the GNU General Public License 015 * along with this program; if not, write to the Free Software 016 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA. 017 * 018 * $Header: /cvsroot/steelme/steelme/src/net/sourceforge/steelme/SteelmeTheme.java,v 1.5 2004/05/15 16:11:47 tj_willis Exp $ 019 */ 020 package net.sourceforge.steelme; 021 022 import java.awt.*; 023 import java.awt.event.*; 024 import javax.swing.*; 025 import javax.swing.plaf.*; 026 import javax.swing.plaf.metal.*; 027 import java.io.*; 028 import java.util.*; 029 import org.apache.log4j.*; 030 031 /** 032 * A MetalTheme with persistence and public accessor methods. 033 * 034 * @author <a href="mailto:tj_willis@users.sourceforge.net">T.J. Willis</a> 035 * @version 1.0 036 */ 037 public class SteelmeTheme 038 extends DefaultMetalTheme 039 //implements ActionListener 040 { 041 private ColorUIResource p1,p2,p3; 042 private ColorUIResource s1,s2,s3; 043 private ColorUIResource t1,t2; 044 private ColorUIResource w,b; 045 private FontUIResource font; 046 private Properties prop; 047 private String myName; 048 private Component cc; 049 private static Category cat 050 = Category.getInstance(SteelmeTheme.class.getName()); 051 052 /** 053 * Creates a new <code>SteelmeTheme</code> instance. 054 * 055 * @param ip1 a <code>Color</code> value 056 * @param ip2 a <code>Color</code> value 057 * @param ip3 a <code>Color</code> value 058 * @param is1 a <code>Color</code> value 059 * @param is2 a <code>Color</code> value 060 * @param is3 a <code>Color</code> value 061 * @param iif a <code>Font</code> value 062 * @param it1 a <code>Color</code> value 063 * @param it2 a <code>Color</code> value 064 * @param iw a <code>Color</code> value 065 * @param ib a <code>Color</code> value 066 */ 067 public SteelmeTheme(Color ip1, Color ip2, Color ip3, Color is1, Color is2, Color is3, Font iif, Color it1, Color it2, Color iw, Color ib) { 068 super(); 069 prop = new Properties(); 070 setPrimary1(ip1); 071 setPrimary2(ip2); 072 setPrimary3(ip3); 073 setSecondary1(is1); 074 setSecondary2(is2); 075 setSecondary3(is3); 076 setFont(iif); 077 setText1(it1); 078 setText2(it2); 079 setWhite(iw); 080 setBlack(ib); 081 setName("Untitled"); 082 } 083 084 /** 085 * Creates a new <code>SteelmeTheme</code> instance which copies 086 * the attributes of DefaultMetalTheme. 087 * 088 */ 089 public SteelmeTheme () { 090 this(new DefaultMetalTheme()); 091 } 092 093 /** 094 * Creates a new <code>SteelmeTheme</code> instance which copies 095 * the attributes of the given MetalTheme. 096 * 097 * @param orig a <code>MetalTheme</code> value 098 */ 099 public SteelmeTheme(MetalTheme orig) 100 { 101 super(); 102 prop = new Properties(); 103 //DefaultMetalTheme mt = new DefaultMetalTheme(); 104 105 this.setPrimary1(orig.getSeparatorForeground()); // NPE here 106 this.setPrimary2(orig.getDesktopColor()); 107 this.setPrimary3(orig.getPrimaryControl()); 108 this.setSecondary1(orig.getControlDarkShadow()); 109 this.setSecondary2(orig.getControlShadow()); 110 this.setSecondary3(orig.getMenuBackground()); 111 this.setFont(orig.getUserTextFont()); 112 this.setText1( orig.getControlTextColor()); 113 this.setText2( orig.getControl()); 114 this.setWhite(orig.getControl()); 115 this.setBlack(orig.getControlTextColor()); 116 this.setName(orig.getName()); 117 } 118 119 120 /** 121 * Creates a new <code>SteelmeTheme</code> instance with 122 * attributes loaded from the specified file. 123 * 124 * @param themeFile a <code>File</code> value 125 */ 126 public SteelmeTheme(File themeFile) { 127 prop = new Properties(); 128 //targets = new Vector(); 129 initColors(); 130 try { 131 FileInputStream fis = new FileInputStream(themeFile); 132 loadProperties(fis); 133 } catch (Exception ex) { 134 cat.warn("Exception loading properties file: "+themeFile,ex); 135 } 136 } 137 138 139 /** 140 * Applies this theme to the Root component of the given component. 141 * 142 * @param who a <code>Component</code> value 143 */ 144 public void applyTheme(Component who) { 145 146 Component rrt = javax.swing.SwingUtilities.getRoot(who); 147 //cat.debug("root component (1): " + rrt); 148 JRootPane rr2 = null; 149 if( rrt instanceof JFrame){ 150 JFrame frm = (JFrame) rrt; 151 rr2 = frm.getRootPane(); 152 } else if (rrt instanceof JComponent) { 153 JComponent comp = (JComponent)rrt; 154 rr2 = comp.getRootPane(); 155 } else { 156 cat.warn("Setting theme on non-lightweight component: " + rrt); 157 return; 158 } 159 try { 160 MetalLookAndFeel.setCurrentTheme(this); 161 UIManager.setLookAndFeel("javax.swing.plaf.metal.MetalLookAndFeel"); 162 SwingUtilities.updateComponentTreeUI(rr2); 163 } catch (Exception e) { 164 cat.warn("Error applying theme",e); 165 } 166 } 167 168 169 /** 170 * Returns this theme's name. 171 * 172 * @return a <code>String</code> value 173 */ 174 public String getName() { 175 return myName; 176 } 177 178 /** 179 * Sets this theme's name. 180 * 181 * @param n a <code>String</code> value 182 */ 183 public void setName(String name) { 184 //super.setName(n); 185 myName = name; 186 prop.put("name",name); 187 188 } 189 190 191 /** 192 * Describe <code>getPrimary1</code> method here. 193 * 194 * @return a <code>ColorUIResource</code> value 195 */ 196 protected ColorUIResource getPrimary1() { 197 return p1; 198 } 199 200 /** 201 * Describe <code>getPrimary2</code> method here. 202 * 203 * @return a <code>ColorUIResource</code> value 204 */ 205 protected ColorUIResource getPrimary2() { 206 return p2; 207 } 208 /** 209 * Describe <code>getPrimary3</code> method here. 210 * 211 * @return a <code>ColorUIResource</code> value 212 */ 213 protected ColorUIResource getPrimary3() { 214 return p3; 215 } 216 /** 217 * Describe <code>getSecondary1</code> method here. 218 * 219 * @return a <code>ColorUIResource</code> value 220 */ 221 protected ColorUIResource getSecondary1() { 222 return s1; 223 } 224 /** 225 * Describe <code>getSecondary2</code> method here. 226 * 227 * @return a <code>ColorUIResource</code> value 228 */ 229 protected ColorUIResource getSecondary2() { 230 return s2; 231 } 232 /** 233 * Describe <code>getSecondary3</code> method here. 234 * 235 * @return a <code>ColorUIResource</code> value 236 */ 237 protected ColorUIResource getSecondary3() { 238 return s3; 239 } 240 241 /** 242 * Describe <code>getP1</code> method here. 243 * 244 * @return a <code>ColorUIResource</code> value 245 */ 246 public ColorUIResource getP1() { 247 return p1; 248 } 249 250 /** 251 * Describe <code>getP2</code> method here. 252 * 253 * @return a <code>ColorUIResource</code> value 254 */ 255 public ColorUIResource getP2() { 256 return p2; 257 } 258 /** 259 * Describe <code>getP3</code> method here. 260 * 261 * @return a <code>ColorUIResource</code> value 262 */ 263 public ColorUIResource getP3() { 264 return p3; 265 } 266 /** 267 * Describe <code>getS1</code> method here. 268 * 269 * @return a <code>ColorUIResource</code> value 270 */ 271 public ColorUIResource getS1() { 272 return s1; 273 } 274 /** 275 * Describe <code>getS2</code> method here. 276 * 277 * @return a <code>ColorUIResource</code> value 278 */ 279 public ColorUIResource getS2() { 280 return s2; 281 } 282 /** 283 * Describe <code>getS3</code> method here. 284 * 285 * @return a <code>ColorUIResource</code> value 286 */ 287 public ColorUIResource getS3() { 288 return s3; 289 } 290 /** 291 * Describe <code>getT1</code> method here. 292 * 293 * @return a <code>ColorUIResource</code> value 294 */ 295 public ColorUIResource getT1() { 296 return t1; 297 } 298 /** 299 * Describe <code>getT2</code> method here. 300 * 301 * @return a <code>ColorUIResource</code> value 302 */ 303 public ColorUIResource getT2() { 304 return t2; 305 } 306 /** 307 * Describe <code>getW</code> method here. 308 * 309 * @return a <code>ColorUIResource</code> value 310 */ 311 public ColorUIResource getW() { 312 return w; 313 } 314 /** 315 * Describe <code>getB</code> method here. 316 * 317 * @return a <code>ColorUIResource</code> value 318 */ 319 public ColorUIResource getB() { 320 return b; 321 } 322 323 /** 324 * Describe <code>getWhite</code> method here. 325 * 326 * @return a <code>ColorUIResource</code> value 327 */ 328 protected ColorUIResource getWhite() { 329 return w; 330 } 331 /** 332 * Describe <code>getBlack</code> method here. 333 * 334 * @return a <code>ColorUIResource</code> value 335 */ 336 protected ColorUIResource getBlack() { 337 return b; 338 } 339 340 /** 341 * Describe <code>getControlTextFont</code> method here. 342 * 343 * @return a <code>FontUIResource</code> value 344 */ 345 public FontUIResource getControlTextFont() { 346 return font; 347 } 348 349 /** 350 * Describe <code>getMenuTextFont</code> method here. 351 * 352 * @return a <code>FontUIResource</code> value 353 */ 354 public FontUIResource getMenuTextFont() { 355 return font; 356 } 357 358 /** 359 * Describe <code>getSubTextFont</code> method here. 360 * 361 * @return a <code>FontUIResource</code> value 362 */ 363 public FontUIResource getSubTextFont() { 364 return font; 365 } 366 /** 367 * Describe <code>getSystemTextFont</code> method here. 368 * 369 * @return a <code>FontUIResource</code> value 370 */ 371 public FontUIResource getSystemTextFont() { 372 return font; 373 } 374 /** 375 * Describe <code>getUserTextFont</code> method here. 376 * 377 * @return a <code>FontUIResource</code> value 378 */ 379 public FontUIResource getUserTextFont() { 380 return font; 381 } 382 /** 383 * Describe <code>getWindowTitleFont</code> method here. 384 * 385 * @return a <code>FontUIResource</code> value 386 */ 387 public FontUIResource getWindowTitleFont() { 388 return font; 389 } 390 391 /** 392 * Describe <code>getSystemTextColor</code> method here. 393 * 394 * @return a <code>ColorUIResource</code> value 395 */ 396 public ColorUIResource getSystemTextColor() { 397 return t1; 398 } 399 /** 400 * Describe <code>getUserTextColor</code> method here. 401 * 402 * @return a <code>ColorUIResource</code> value 403 */ 404 public ColorUIResource getUserTextColor() { 405 return t1; 406 } 407 /** 408 * Describe <code>getControlTextColor</code> method here. 409 * 410 * @return a <code>ColorUIResource</code> value 411 */ 412 public ColorUIResource getControlTextColor() { 413 return t1; 414 } 415 416 /** 417 * Describe <code>getHighlightedTextColor</code> method here. 418 * 419 * @return a <code>ColorUIResource</code> value 420 */ 421 public ColorUIResource getHighlightedTextColor() { 422 return t2; 423 } 424 /** 425 * Describe <code>getInactiveControlTextColor</code> method here. 426 * 427 * @return a <code>ColorUIResource</code> value 428 */ 429 public ColorUIResource getInactiveControlTextColor() { 430 return t2; 431 } 432 /** 433 * Describe <code>getInactiveSystemTextColor</code> method here. 434 * 435 * @return a <code>ColorUIResource</code> value 436 */ 437 public ColorUIResource getInactiveSystemTextColor() { 438 return t2; 439 } 440 441 /** 442 * Describe <code>setPrimary1</code> method here. 443 * 444 * @param x a <code>Color</code> value 445 */ 446 public void setPrimary1(Color x) { 447 p1=new ColorUIResource(x); 448 prop.put("primary1",getColorString(x)); 449 } 450 451 /** 452 * Describe <code>setPrimary2</code> method here. 453 * 454 * @param x a <code>Color</code> value 455 */ 456 public void setPrimary2(Color x) { 457 p2=new ColorUIResource(x); 458 prop.put("primary2",getColorString(x)); 459 } 460 /** 461 * Describe <code>setPrimary3</code> method here. 462 * 463 * @param x a <code>Color</code> value 464 */ 465 public void setPrimary3(Color x) { 466 p3=new ColorUIResource(x); 467 prop.put("primary3",getColorString(x)); 468 } 469 /** 470 * Describe <code>setSecondary1</code> method here. 471 * 472 * @param x a <code>Color</code> value 473 */ 474 public void setSecondary1(Color x) { 475 s1=new ColorUIResource(x); 476 prop.put("secondary1",getColorString(x)); 477 } 478 /** 479 * Describe <code>setSecondary2</code> method here. 480 * 481 * @param x a <code>Color</code> value 482 */ 483 public void setSecondary2(Color x) { 484 s2=new ColorUIResource(x); 485 prop.put("secondary2",getColorString(x)); 486 } 487 /** 488 * Describe <code>setSecondary3</code> method here. 489 * 490 * @param x a <code>Color</code> value 491 */ 492 public void setSecondary3(Color x) { 493 s3 =new ColorUIResource( x); 494 prop.put("secondary3",getColorString(x)); 495 } 496 /** 497 * Describe <code>setText1</code> method here. 498 * 499 * @param x a <code>Color</code> value 500 */ 501 public void setText1(Color x) { 502 t1=new ColorUIResource(x); 503 prop.put("text1",getColorString(x)); 504 } 505 /** 506 * Describe <code>setText2</code> method here. 507 * 508 * @param x a <code>Color</code> value 509 */ 510 public void setText2(Color x) { 511 t2=new ColorUIResource(x); 512 prop.put("text2",getColorString(x)); 513 } 514 515 /** 516 * Describe <code>setWhite</code> method here. 517 * 518 * @param x a <code>Color</code> value 519 */ 520 public void setWhite(final Color white) { 521 w=new ColorUIResource(white); 522 prop.put("white",getColorString(white)); 523 } 524 /** 525 * Describe <code>setBlack</code> method here. 526 * 527 * @param x a <code>Color</code> value 528 */ 529 public void setBlack(final Color black) { 530 b=new ColorUIResource(black); 531 prop.put("black",getColorString(black)); 532 } 533 534 /** 535 * Describe <code>setFont</code> method here. 536 * 537 * @param f a <code>Font</code> value 538 */ 539 public void setFont( final Font fnt) { 540 font = new FontUIResource(fnt); 541 prop.put("fontName",fnt.getName()); 542 //FIXME: these Integer conversions aren't good 543 prop.put("fontSize",new Integer(fnt.getSize()).toString()); 544 prop.put("fontStyle",new Integer(fnt.getStyle()).toString()); 545 } 546 547 /** 548 * pass an inputstream pointing to a properties file. 549 * Colors will be initialized to be the same as the DefaultMetalTheme, 550 * and then any colors provided in the properties file will override that. 551 * @param stream an <code>InputStream</code> value 552 */ 553 public SteelmeTheme( InputStream stream ) { 554 initColors(); 555 loadProperties(stream); 556 } 557 558 /** 559 * Initialize all colors to be the same as the DefaultMetalTheme. 560 */ 561 private void initColors() { 562 p1 = super.getPrimary1(); 563 p2 = super.getPrimary2(); 564 p3 = super.getPrimary3(); 565 566 s1 = super.getSecondary1(); 567 s2 = super.getSecondary2(); 568 s3 = super.getSecondary3(); 569 570 t1 = super.getBlack(); 571 t2 = super.getWhite(); 572 573 w = super.getWhite(); 574 b = super.getBlack(); 575 Font fnt= new Font("Default",Font.PLAIN,12); 576 font = new FontUIResource(fnt); 577 } 578 579 580 /** 581 * Saves the file to resources/themes/ThemeName.theme. 582 * 583 */ 584 public void save() { 585 // FIXME: this should throw the IOException 586 try { 587 String tname = getName(); 588 File fil = new File("resources/themes/" + tname+".theme"); 589 FileOutputStream fos = new FileOutputStream(fil); 590 prop.store(fos,"This is my title"); 591 } catch (Exception x) { 592 cat.warn("Error saving theme: " + getName(),x); 593 } 594 } 595 596 /** 597 * Describe <code>save</code> method here. 598 * 599 * @param t an <code>OutputStream</code> value 600 */ 601 public void save(OutputStream stream) { 602 //FIXME: this should throw the IOException 603 try { 604 prop.store(stream,"This is my title"); 605 } catch (Exception ex) { 606 cat.warn("Error saving theme: "+getName(),ex); 607 } 608 } 609 610 private ColorUIResource getColorUIResourceByName(String name) 611 { 612 Object colorString = prop.get(name); 613 ColorUIResource color = null; 614 if (colorString != null) { 615 color = parseColor(colorString.toString()); 616 } 617 return color; 618 } 619 /** 620 * Load the theme name and colors from the properties file 621 * Items not defined in the properties file are ignored 622 */ 623 private void loadProperties(InputStream stream) { 624 // FIXME: this should throw the IOException 625 try { 626 prop.load(stream); 627 } catch (IOException e) { 628 cat.warn("Error loading theme",e); 629 } 630 631 Object tempName = prop.get("name"); 632 if (tempName != null) { 633 setName(tempName.toString()); 634 } 635 636 Object colorString = null; 637 ColorUIResource co = getColorUIResourceByName("primary1"); 638 if(co!=null) setPrimary1(co); 639 co = getColorUIResourceByName("primary2"); 640 if(co!=null) setPrimary2(co); 641 co = getColorUIResourceByName("primary3"); 642 if(co!=null) setPrimary3(co); 643 co = getColorUIResourceByName("secondary1"); 644 if(co!=null) setSecondary1(co); 645 co = getColorUIResourceByName("secondary2"); 646 if(co!=null) setSecondary2(co); 647 co = getColorUIResourceByName("secondary3"); 648 if(co!=null) setSecondary3(co); 649 co = getColorUIResourceByName("text1"); 650 if(co!=null) setText1(co); 651 co = getColorUIResourceByName("text2"); 652 if(co!=null) setText2(co); 653 co = getColorUIResourceByName("white"); 654 if(co!=null) setWhite(co); 655 co = getColorUIResourceByName("black"); 656 if(co!=null) setBlack(co); 657 658 659 Font theFont = null; 660 Object fff = prop.get("fontName"); 661 // setFontName(fff.toString()); 662 String fontName = null; 663 if (fff!=null) 664 fontName = fff.toString(); 665 if(fontName!=null) { 666 int size = 12; 667 int style = Font.PLAIN; 668 669 670 Object sss = prop.get("fontSize"); 671 String fontSizeString = null; 672 if(sss!=null){ 673 fontSizeString = sss.toString(); 674 } 675 676 if (fontSizeString!=null) { 677 try { 678 size = Integer.parseInt(fontSizeString); 679 } catch (Exception x) { 680 cat.warn("Error parsing font size " + fontSizeString,x); 681 } 682 } 683 Object fSty = prop.get("fontStyle"); 684 String fontStyleString = null; 685 if(fSty!=null){ 686 fontStyleString = fSty.toString(); 687 } 688 if (fontStyleString!=null) { 689 try { 690 style = Integer.parseInt(fontStyleString); 691 } catch (Exception x) { 692 cat.warn("Error parsing font style " + fontStyleString,x); 693 } 694 } 695 theFont = new Font(fontName,style,size); 696 setFont(theFont);//new FontUIResource(theFont); 697 } else { 698 theFont = new Font("Default",Font.PLAIN,12); 699 setFont(theFont);//font = new FontUIResource(theFont); 700 } 701 } 702 703 /** 704 * parse a comma delimited list of 3 strings into a ColorUIResource. 705 * For example, "255,0,0" would give a new ColorUIResource(255,0,0). 706 */ 707 private static ColorUIResource parseColor(String string) { 708 int red = 0; 709 int green = 0; 710 int blue = 0; 711 try { 712 StringTokenizer st = new StringTokenizer(string, ","); 713 714 red = Integer.parseInt(st.nextToken()); 715 green = Integer.parseInt(st.nextToken()); 716 blue = Integer.parseInt(st.nextToken()); 717 718 } catch (Exception ex) { 719 cat.warn("Couldn't parse color :" + string,ex); 720 } 721 722 return new ColorUIResource(red, green, blue); 723 } 724 725 /** 726 * Convert a color to 3 integers separated by commas with values from 727 * 0..255 which represent it's red, green, and blue components. 728 * 729 * @param c a <code>Color</code> value 730 * @return a <code>String</code> value 731 */ 732 protected static String getColorString(Color color) { 733 if(color==null){ 734 return "0,0,0"; 735 } 736 return color.getRed() + "," + color.getGreen() + "," + color.getBlue(); 737 } 738 739 /** 740 * Sets the component to update when the theme is applied. 741 * 742 * @param cx a <code>Component</code> value 743 */ 744 public void setTarget(Component target) { 745 cc = target; 746 } 747 } 748 749