001    /*
002        Copyright (C) 2003 Adam Olsen
003    
004            This program is free software; you can redistribute it and/or modify
005        it under the terms of the GNU General Public License as published by
006        the Free Software Foundation; either version 1, or (at your option)
007        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., 675 Mass Ave, Cambridge, MA 02139, USA.
017    */
018    
019    package com.valhalla.jbother.preferences;
020    
021    import java.awt.*;
022    import java.awt.event.*;
023    import java.io.*;
024    import java.util.*;
025    
026    import javax.swing.*;
027    import com.valhalla.pluginmanager.*;
028    
029    import org.jfree.ui.FontChooserDialog;
030    
031    import com.valhalla.gui.*;
032    import com.valhalla.pluginmanager.*;
033    import com.valhalla.jbother.*;
034    import com.valhalla.jbother.jabber.BuddyStatus;
035    import com.valhalla.settings.Settings;
036    import com.valhalla.settings.TempSettings;
037    
038    /**
039     * Allows the user to change appearance preferences
040     * @author Adam Olsen
041     * @version 1.0
042    */
043    public class AppearancePreferencesPanel extends JPanel implements PreferencesPanel
044    {
045            private ResourceBundle resources = ResourceBundle.getBundle( "JBotherBundle", Locale.getDefault() );
046            private PreferencesDialog prefs;
047            private GridBagLayout grid = new GridBagLayout();
048            private GridBagConstraints c = new GridBagConstraints();
049            private JLabel lafLabel = new JLabel( resources.getString( "themeLabel" ) + ": " );
050            private JLabel statusLabel = new JLabel( resources.getString( "statusLabel" ) + ": " );
051            private JLabel emoticonLabel = new JLabel( resources.getString( "emoticonLabel" ) + ": " );
052            private JLabel messageLabel = new JLabel( resources.getString( "messageWindowFont" ) + ": " );
053            private JButton messageFontButton = new JButton( "Font" );
054    
055            private JLabel appFontLabel = new JLabel( resources.getString( "appFontLabel" ) + ": " );
056            private JButton appFontButton = new JButton( "Font" );
057    
058            private JComboBox lookAndFeel, statusTheme, emoticonTheme;
059            private int current;
060            private UIManager.LookAndFeelInfo[] lfs;
061            private String[] names;
062    
063            /**
064             * Sets up the AppearancePreferences
065             * @param dialog the enclosing PreferencesDialog
066            */
067            public AppearancePreferencesPanel( PreferencesDialog dialog )
068            {
069                    this.prefs = dialog;
070                    setBorder( BorderFactory.createTitledBorder( resources.getString( "appearancePreferences" ) ) );
071                    setLayout( grid );
072    
073                    lfs = UIManager.getInstalledLookAndFeels();
074                    String lf = UIManager.getLookAndFeel().getClass().getName();
075    
076                    ArrayList list = new ArrayList();
077    
078                    int index = 0;
079                    for( int i = 0; i < lfs.length; i++ )
080                    {
081                            list.add( lfs[i].getName() );
082                            if( lf.equals( lfs[i].getClassName() ) )
083                            {
084                                    index = i;
085                                    current = index;
086                            }
087                    }
088    
089                    names = new String[list.size()];
090                    list.toArray( names );
091    
092                    lookAndFeel = new JComboBox( names );
093                    lookAndFeel.setSelectedIndex( index );
094    
095                    c.gridx = 0;
096                    c.gridy = 0;
097                    c.fill = GridBagConstraints.HORIZONTAL;
098                    c.anchor = GridBagConstraints.WEST;
099                    c.gridwidth = 1;
100    
101                    //display name stuff
102                    lafLabel.setBorder( BorderFactory.createEmptyBorder( 0, 5, 0, 5 ) );
103                    c.weightx = -.1;
104                    c.fill = GridBagConstraints.NONE;
105                    grid.setConstraints( lafLabel, c );
106                    add( lafLabel );
107    
108                    c.gridx = 1;
109    
110                    grid.setConstraints( lookAndFeel, c );
111                    add( lookAndFeel );
112    
113                    c.gridx = 0;
114                    c.gridy++;
115    
116                    statusLabel.setBorder( BorderFactory.createEmptyBorder( 0, 5, 0, 5 ) );
117                    grid.setConstraints( statusLabel, c );
118                    add( statusLabel );
119    
120                    statusTheme = getStatusThemes();
121                    c.gridx++;
122                    grid.setConstraints( statusTheme, c );
123                    add( statusTheme );
124    
125                    c.gridx = 0;
126                    c.gridy++;
127    
128                    emoticonLabel.setBorder( BorderFactory.createEmptyBorder( 0, 5, 0, 5 ) );
129                    grid.setConstraints( emoticonLabel, c );
130                    add( emoticonLabel );
131    
132                    emoticonTheme = getEmoticonThemes();
133                    c.gridx++;
134                    grid.setConstraints( emoticonTheme, c );
135                    add( emoticonTheme );
136    
137                    FontChangeListener fontListener = new FontChangeListener();
138    
139                    // get the message window font settings
140                    String messageFont = Settings.getInstance().getProperty( "messageWindowFont" );
141                    if( messageFont == null ) messageFont = "Default-PLAIN-12";
142    
143                    Font font = Font.decode( messageFont );
144                    messageFontButton.setText( getEncodedFontName( font ).replaceAll( "-", " " ) );
145                    messageFontButton.setFont( font );
146    
147                    c.gridx = 0;
148                    c.gridy++;
149                    messageLabel.setBorder( BorderFactory.createEmptyBorder( 0, 5, 0, 5 ) );
150                    grid.setConstraints( messageLabel, c );
151                    add( messageLabel );
152                    c.gridx++;
153                    messageFontButton.addActionListener( fontListener );
154                    grid.setConstraints( messageFontButton, c );
155                    add( messageFontButton );
156    
157                    // get the application font settings
158                    String appFont = Settings.getInstance().getProperty( "applicationFont" );
159                    if( appFont == null ) appFont = "Default-PLAIN-12";
160    
161                    font = Font.decode( appFont );
162                    appFontButton.setText( getEncodedFontName( font ).replaceAll( "-", " " ) );
163                    appFontButton.setFont( font );
164    
165                    c.gridx = 0;
166                    c.gridy++;
167                    appFontLabel.setBorder( BorderFactory.createEmptyBorder( 0, 5, 0, 5 ) );
168                    grid.setConstraints( appFontLabel, c );
169                    add( appFontLabel );
170                    c.gridx++;
171                    appFontButton.addActionListener( fontListener );
172                    grid.setConstraints( appFontButton, c );
173                    add( appFontButton );
174    
175                    //this is the space taker
176                    JLabel blankLabel = new JLabel( "" );
177                    c.weighty = 1;
178                    c.weightx = 1;
179                    c.gridx = 0;
180                    c.gridwidth = 3;
181                    c.gridy++;
182                    grid.setConstraints( blankLabel, c );
183                    add( blankLabel );
184            }
185    
186            /**
187             * Listens for one of the font buttons to be clicked and displays a FontChooserDialog for it
188             * @author Adam Olsen
189             * @version 1.0
190            */
191            private class FontChangeListener implements ActionListener
192            {
193                    public void actionPerformed( ActionEvent e )
194                    {
195                            JButton button = (JButton)e.getSource();
196                            FontChooserDialog dialog = new FontChooserDialog( prefs, resources.getString( "messageWindowFont" ),
197                                    true, button.getFont() );
198    
199                            dialog.show();
200    
201                            if( !dialog.isCancelled() )
202                            {
203                                    Font newFont = dialog.getSelectedFont();
204                                    button.setFont( newFont );
205                                    button.setText( getEncodedFontName( newFont ).replaceAll( "-", " " ) );
206                            }
207                    }
208            }
209    
210            /**
211             * Checks the default jar file and the user theme directory for status themes
212            */
213            private JComboBox getStatusThemes()
214            {
215                    JComboBox box = new JComboBox();
216                    String current = Settings.getInstance().getProperty( "statusTheme" );
217                    if( current == null ) current = "default";
218                    box.addItem( current );
219    
220    
221                    // user defined themes
222                    File path = new File(JBother.settingsDir + File.separatorChar + "themes" + File.separatorChar + "statusicons");
223    
224                    String[] userThemes = new String[0];
225    
226                    if( !path.isDirectory() && !path.mkdirs() )
227                    {
228                            com.valhalla.Logger.debug( "Could not create user defined settings directories." );
229                    }
230                    else {
231                            userThemes = path.list();
232                            for ( int i=0; i<userThemes.length; i++ ) {
233                                    if (!current.equals(userThemes[i]))     box.addItem(userThemes[i]);
234                            }
235                    }
236    
237                    // default themes in the jar
238                    InputStream stream = getClass().getClassLoader().getResourceAsStream( "imagethemes/statusicons/index.dat" );
239                    if( stream == null )
240                    {
241                            com.valhalla.Logger.debug( "Bad status theme file." );
242                            return box;
243                    }
244    
245                    InputStreamReader in  = new InputStreamReader( stream );
246                    BufferedReader reader = new BufferedReader( in );
247                    String line;
248                    try {
249                            while( ( line = reader.readLine() ) != null )
250                            {
251                                    boolean userTheme = false;
252                                    for (int i=0; i<userThemes.length; i++) {
253                                            if (line.equals(userThemes[i])) {
254                                                    userTheme = true;
255                                                    break;
256                                            }
257                                    }
258                                    if( !userTheme && !line.equals( current ) )     box.addItem( line );
259                            }
260                    }
261                    catch( IOException e ) { }
262    
263                    return box;
264            }
265    
266            /**
267             * Gets a list of emoticon themes
268            */
269            private JComboBox getEmoticonThemes()
270            {
271                    JComboBox box = new JComboBox();
272                    String current = Settings.getInstance().getProperty( "emoticonTheme" );
273                    if( current == null ) current = "default";
274                    box.addItem( current );
275    
276                    // default themes in the jar
277                    InputStream stream = getClass().getClassLoader().getResourceAsStream( "imagethemes/emoticons/index.dat" );
278                    if( stream == null )
279                    {
280                            com.valhalla.Logger.debug( "Bad emoticon theme file." );
281                            return box;
282                    }
283    
284                    InputStreamReader in  = new InputStreamReader( stream );
285                    BufferedReader reader = new BufferedReader( in );
286                    String line;
287                    try {
288                            while( ( line = reader.readLine() ) != null )
289                            {
290                                    if( !line.equals( current ) )   box.addItem( line );
291                            }
292                    }
293                    catch( IOException e ) { }
294    
295                    return box;
296            }
297    
298            /**
299             * Gets the String representation of a font
300             * @return the string representation of a font
301            */
302            private String getEncodedFontName( Font font )
303            {
304                    String fontString = font.getName() + "-";
305    
306                    if( font.isPlain() ) fontString += "PLAIN";
307                    if( font.isBold() ) fontString += "BOLD";
308                    if( font.isItalic() ) fontString += "ITALIC";
309                    fontString += "-" + font.getSize();
310    
311                    return fontString;
312            }
313    
314            /**
315             * Gets temporary settings
316             * @return temporary settings
317            */
318            public TempSettings getSettings()
319            {
320                    TempSettings tempSettings = new TempSettings();
321    
322                    if( lookAndFeel.getSelectedIndex() != current )
323                    {
324                            Standard.noticeMessage( prefs, resources.getString( "themeLabel" ),
325                                    resources.getString( "themeSettingsApplied" ) );
326    
327                            try {
328                                    Class c = PluginLoader.getInstance().loadClass( lfs[lookAndFeel.getSelectedIndex()].getClassName() );
329    
330                                    UIManager.setLookAndFeel( (LookAndFeel)c.newInstance() );
331                                    tempSettings.setProperty( "lookAndFeel", lfs[lookAndFeel.getSelectedIndex()].getClassName() );
332                                    SwingUtilities.updateComponentTreeUI( BuddyList.getInstance() );
333                                    SwingUtilities.updateComponentTreeUI( BuddyList.getInstance().getBuddyListTree() );
334                                    SwingUtilities.updateComponentTreeUI( prefs );
335                                    if( BuddyList.getInstance().getTabFrame() != null ) SwingUtilities.updateComponentTreeUI( BuddyList.getInstance().getTabFrame() );
336    
337                                    Hashtable map = BuddyList.getInstance().getBuddyStatuses();
338                                    java.util.List keys = new ArrayList( map.keySet() );
339                                    Iterator iterator = keys.iterator();
340                                    while( iterator.hasNext() )
341                                    {
342                                            BuddyStatus buddy = (BuddyStatus)map.get( iterator.next() );
343                                            if( buddy.getConversation() != null ) SwingUtilities.updateComponentTreeUI( buddy.getConversation() );
344                                    }
345    
346                                    current = lookAndFeel.getSelectedIndex();
347                            }
348                            catch( Exception e )
349                            {
350                                    Standard.warningMessage( prefs, resources.getString( "themeLabel" ), resources.getString( "couldNotApplyTheme" ) +
351                                            "\n" + resources.getString( "errorMessage" ) + " " + e.getMessage() );
352                                    com.valhalla.Logger.logException( e );
353                            }
354                    }
355    
356                    tempSettings.setProperty( "messageWindowFont", getEncodedFontName( messageFontButton.getFont() ) );
357                    // update all open conversation areas
358                    Hashtable buddyStatuses = BuddyList.getInstance().getBuddyStatuses();
359                    Iterator i = buddyStatuses.keySet().iterator();
360    
361                    while( i.hasNext() )
362                    {
363                            BuddyStatus buddy = BuddyList.getInstance().getBuddyStatus( (String)i.next() );
364                            if( buddy.getConversation() != null ) buddy.getConversation().updateStyle( messageFontButton.getFont() );
365                    }
366    
367                    if( BuddyList.getInstance().getTabFrame() != null ) BuddyList.getInstance().getTabFrame().updateStyles( messageFontButton.getFont() );
368    
369                    tempSettings.setProperty( "applicationFont", getEncodedFontName( appFontButton.getFont() ) );
370                    updateApplicationFonts( appFontButton.getFont(), prefs );
371    
372                    String selectedStatus = (String)statusTheme.getItemAt( statusTheme.getSelectedIndex() );
373                    tempSettings.setProperty( "statusTheme", selectedStatus );
374                    tempSettings.setProperty( "emoticonTheme", (String)emoticonTheme.getItemAt( emoticonTheme.getSelectedIndex() ) );
375    
376                    BuddyList.getInstance().getBuddyListTree().repaint();
377                    if( BuddyList.getInstance().getTabFrame() != null )
378                            BuddyList.getInstance().getTabFrame().repaint();
379    
380                    Emoticons.getInstance().switchTheme( tempSettings.getProperty( "emoticonTheme" ) );
381    
382                    return tempSettings;
383            }
384    
385            /**
386             * Updates all the fonts in the application
387             * @param font the font to update to
388            */
389            public static void updateApplicationFonts( Font font, PreferencesDialog prefs )
390            {
391                    com.valhalla.jbother.JBotherLoader.setupFont( font );
392                    SwingUtilities.updateComponentTreeUI( BuddyList.getInstance() );
393                    if( prefs != null ) SwingUtilities.updateComponentTreeUI( prefs );
394                    if( BuddyList.getInstance().getTabFrame() != null ) SwingUtilities.updateComponentTreeUI( BuddyList.getInstance().getTabFrame() );
395    
396                    Hashtable buddyStatuses = BuddyList.getInstance().getBuddyStatuses();
397                    if( buddyStatuses == null ) return;
398                    Iterator i = buddyStatuses.keySet().iterator();
399    
400                    while( i.hasNext() )
401                    {
402                            String id = (String)i.next();
403                            BuddyStatus buddy = (BuddyStatus)buddyStatuses.get( id );
404                            if( buddy.getConversation() != null )
405                                    SwingUtilities.updateComponentTreeUI( buddy.getConversation() );
406                    }
407            }
408    }