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