001    /*
002     *  Copyright (C) 2003 Adam Olsen
003     *  This program is free software; you can redistribute it and/or modify
004     *  it under the terms of the GNU General Public License as published by
005     *  the Free Software Foundation; either version 1, or (at your option)
006     *  any later version.
007     *  This program is distributed in the hope that it will be useful,
008     *  but WITHOUT ANY WARRANTY; without even the implied warranty of
009     *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
010     *  GNU General Public License for more details.
011     *  You should have received a copy of the GNU General Public License
012     *  along with this program; if not, write to the Free Software
013     *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
014     */
015    package com.valhalla.jbother;
016    
017    import java.awt.event.*;
018    
019    import java.io.*;
020    import java.text.SimpleDateFormat;
021    import java.util.*;
022    import java.text.*;
023    
024    import javax.swing.*;
025    import javax.swing.event.*;
026    import java.awt.*;
027    
028    import com.valhalla.gui.*;
029    import com.valhalla.jbother.*;
030    import com.valhalla.jbother.jabber.BuddyStatus;
031    import com.valhalla.jbother.plugins.events.*;
032    import com.valhalla.settings.Settings;
033    
034    /**
035     * Provides common tools for conversation windows (such as logging).
036     * Must be extended.
037     *
038     * @author     Adam Olsen
039     * @author     Yury Soldak (tail)
040     * @created    October 26, 2004
041     * @version    1.0
042     * @see        com.valhalla.jbother.jabber.BuddyStatus
043     */
044    public abstract class ConversationPanel extends JPanel implements LogViewerCaller, TabFramePanel
045    {
046            private ResourceBundle resources = ResourceBundle.getBundle( "JBotherBundle", Locale.getDefault() );
047            protected BuddyStatus buddy;
048            /**
049             *  the conversation area
050             */
051            protected ConversationArea conversationArea = new ConversationArea();
052    
053            private int oldMaximum = 0;
054            // for logging
055            private File logFile;
056            /**
057             *  the log writer
058             */
059            protected PrintWriter logOut;
060            private FileWriter fw;
061            /**
062             *  the close timer
063             */
064            protected javax.swing.Timer timer = new javax.swing.Timer( 600000, new CloseListener() );
065            private ConversationPanel thisPointer = this;
066            /**
067             *  the containing frame
068             */
069            protected JFrame frame = null;
070            /**
071             *  if the listeners have been added
072             */
073            protected boolean listenersAdded = false;
074    
075            /**
076             * Sets up the defaults in the ConversationPanel
077             *
078             * @param  buddy      the buddy that this window corresponds to
079             */
080            public ConversationPanel( BuddyStatus buddy )
081            {
082                    this.buddy = buddy;
083                    startLog();
084            }
085    
086            /**
087             * Listens for a right click - and displays a menu if it's caught
088             *
089             * @author     Adam Olsen
090             * @created    October 26, 2004
091             * @version    1.0
092             */
093            class RightClickListener extends MouseAdapter
094            {
095                    private JPopupMenu menu;
096                    private JMenuItem item = new JMenuItem( resources.getString( "closeConversation" ) );
097                    private boolean containsCloseItem = false;
098    
099                    /**
100                     *Constructor for the RightClickListener object
101                     *
102                     * @param  menu  the menu
103                     */
104                    public RightClickListener( JPopupMenu menu )
105                    {
106                            this.menu = menu;
107                    }
108    
109                    /**
110                     *  Description of the Method
111                     *
112                     * @param  e  the event
113                     */
114                    public void mousePressed( MouseEvent e )
115                    {
116                            checkPop( e );
117                    }
118    
119                    /**
120                     * @param  e  the mouse event
121                     */
122                    public void mouseReleased( MouseEvent e )
123                    {
124                            checkPop( e );
125                    }
126    
127                    /**
128                     * @param  e  the mouse event
129                     */
130                    public void mouseClicked( MouseEvent e )
131                    {
132                            checkPop( e );
133                    }
134    
135                    /**
136                     * @param  e  the mouse event
137                     */
138                    public void checkPop( MouseEvent e )
139                    {
140                            if( e.isPopupTrigger() )
141                            {
142                                    if( Settings.getInstance().getBoolean( "useTabbedWindow" ) && !containsCloseItem )
143                                    {
144                                            containsCloseItem = true;
145                                            menu.add( item );
146                                            item.addActionListener(
147                                                    new ActionListener()
148                                                    {
149                                                            public void actionPerformed( ActionEvent e )
150                                                            {
151                                                                    checkCloseHandler();
152                                                            }
153                                                    } );
154                                    }
155                                    else if( !Settings.getInstance().getBoolean( "useTabbedWindow" ) && containsCloseItem )
156                                    {
157                                            containsCloseItem = false;
158                                            menu.remove( item );
159                                    }
160    
161                                    // if a right click is detected, show the popup menu
162                                    menu.show( e.getComponent(), e.getX(), e.getY() );
163                            }
164                    }
165            }
166    
167            /**
168             * @return    true if the TabFrame panel listeners have already been added to this panel
169             */
170            public boolean listenersAdded()
171            {
172                    return listenersAdded;
173            }
174    
175            /**
176             * Sets whether or not the TabFrame panel listeners have been added
177             *
178             * @param  added  true if they have been added
179             */
180            public void setListenersAdded( boolean added )
181            {
182                    this.listenersAdded = added;
183            }
184    
185            /**
186             * @return    the input area of this panel
187             */
188            public Component getInputComponent()
189            {
190                    return conversationArea;
191            }
192    
193            /**
194             * @return    the name of the tab in the TabFrame
195             */
196            public String getPanelName()
197            {
198                    if( buddy != null )
199                    {
200                            return buddy.getName();
201                    }
202                    else
203                    {
204                            return "Blank Message";
205                    }
206            }
207    
208            /**
209             * @return    the title of the window in the TabFrame
210             */
211            public String getWindowTitle()
212            {
213                    if( buddy != null )
214                    {
215                            return buddy.getName() + " (" + buddy.getUser() + ")";
216                    }
217                    else
218                    {
219                            return "Blank Message";
220                    }
221            }
222    
223            /**
224             * @return    the tooltip for this tab in the TabFrame
225             */
226            public String getTooltip()
227            {
228                    if( buddy != null )
229                    {
230                            return buddy.getUser();
231                    }
232                    else
233                    {
234                            return "Blank Message";
235                    }
236            }
237    
238            /**
239             * @return    the containing frame for this panel
240             */
241            public JFrame getContainingFrame()
242            {
243                    return frame;
244            }
245    
246            /**
247             * @param  frame  the new containing frame
248             */
249            public void setContainingFrame( JFrame frame )
250            {
251                    this.frame = frame;
252            }
253    
254            /**
255             * Focuses when a Tab in the TabFrame is clicked
256             */
257            public abstract void focusYourself();
258    
259            /**
260             * Returns the buddy status for this dialog
261             *
262             * @return    the buddy passed in to the constructor
263             */
264            public BuddyStatus getBuddy()
265            {
266                    return buddy;
267            }
268    
269            /**
270             * Updates the conversation font
271             *
272             * @param  font  the font to update to
273             */
274            public void updateStyle( Font font )
275            {
276                    conversationArea.loadStyleSheet( font );
277            }
278    
279            /**
280             * Listens for a close event, and either makes the dialog hidden or removes it from
281             * the dialog tracker
282             *
283             * @author     Adam Olsen
284             * @created    October 26, 2004
285             * @version    1.0
286             */
287            class CloseListener implements ActionListener
288            {
289                    /**
290                     * @param  e  the event
291                     */
292                    public void actionPerformed( ActionEvent e )
293                    {
294                            timer.stop();
295                            closeHandler();
296                    }
297            }
298    
299            /**
300             * Checks to see if we are preserving messages.  If so, it starts the timer, otherwise
301             * it just closes the panel
302             */
303            public void checkCloseHandler()
304            {
305                    if( Settings.getInstance().getProperty( "preserveMessages" ) == null )
306                    {
307                            closeHandler();
308                    }
309                    else
310                    {
311                            startTimer();
312                            if( !Settings.getInstance().getBoolean( "useTabbedWindow" ) )
313                            {
314                                    frame.setVisible( false );
315                            }
316                            else
317                            {
318                                    BuddyList.getInstance().removeTabPanel( this );
319                            }
320                    }
321            }
322    
323            /**
324             * Destroys the dialog, disposes the containing frame if there is one
325             * and removes the panel from the TabFrame if required.
326             */
327            public void closeHandler()
328            {
329                    closeLog();
330                    if( frame != null )
331                    {
332                            frame.setVisible( false );
333                            frame.dispose();
334                    }
335    
336                    if( buddy != null )
337                    {
338                            com.valhalla.Logger.debug( "Closing ConversationPanel for " + buddy.getUser() );
339                            buddy.setConversation( null );
340                    }
341    
342                    if( Settings.getInstance().getBoolean( "useTabbedWindow" ) )
343                    {
344                            BuddyList.getInstance().removeTabPanel( this );
345                    }
346    
347                    MessageDelegator.getInstance().removePanel( this );
348            }
349    
350            /**
351             * Opens a <code>com.valhalla.jbother.LogViewerDialog</code>
352             */
353            public void openLogWindow()
354            {
355                    new LogViewerDialog( this, buddy.getUser() );
356            }
357    
358            /**
359             * Opens a log and starts it.
360             */
361            public void startLog()
362            {
363                    if( buddy == null ) return;
364                    // for loggingg
365                    if( Settings.getInstance().getBoolean( "keepLogs" ) )
366                    {
367                            try
368                            {
369                                    String logFileName = LogViewerDialog.getDateName() + ".log.html";
370                                    String logFileDir = JBother.profileDir + File.separatorChar + "logs" +
371                                                    File.separatorChar + this.buddy.getUser().replaceAll( "@", "_at_" ).replaceAll( "\\/", "-" );
372                                    File logDir = new File( logFileDir );
373    
374                                    if( !logDir.isDirectory() && !logDir.mkdirs() )
375                                    {
376                                            Standard.warningMessage( this, resources.getString( "log" ),
377                                                            resources.getString( "couldNotCreateLogDir" ) );
378                                    }
379                                    logFile = new File( logDir, logFileName );
380                                    fw = new FileWriter( logFile, true );
381                                    logOut = new PrintWriter( fw, true );
382                            }
383                            catch( IOException e )
384                            {
385                                    com.valhalla.Logger.debug( "Could not open logfile." );
386                            }
387                    }
388            }
389    
390            /**
391             * Sets a message to offline (displays "this message is offline")
392             */
393            public void setOfflineMessage()
394            {
395            }
396    
397            /**
398             * Gets the time in the format [hour:minute:second]
399             *
400             * @return    the time in the format [hour:minute:second]
401             */
402            public String getDate()
403            {
404                    SimpleDateFormat formatter = new SimpleDateFormat( "[HH:mm:ss]" );
405                    String date = formatter.format( new Date() );
406                    return date;
407            }
408    
409            /**
410             * Recieves a message
411             *
412             * @param  sbj       the subject of the message
413             * @param  body      the message body
414             * @param  resource  the message resource
415             */
416            public void recieveMessage( String sbj, String body, String resource )
417            {
418                    recieveMessage();
419            }
420    
421            /**
422             * Calls the recieved message events
423             */
424            public void recieveMessage()
425            {
426                    com.valhalla.jbother.sound.SoundPlayer.play( "recievedSound" );
427    
428                    MessageDelegator.getInstance().showPanel( this );
429    
430                    stopTimer();
431    
432                    JFrame f = frame;
433                    if( !(this instanceof MessagePanel) && Settings.getInstance().getBoolean( "useTabbedWindow" ) )
434                    {
435                            f = BuddyList.getInstance().getTabFrame();
436                            BuddyList.getInstance().getTabFrame().markTab( this );
437                    }
438                    else
439                    {
440                            if( !frame.isVisible() )
441                            {
442                                    frame.setVisible( true );
443                            }
444                            if( Settings.getInstance().getBoolean( "focusWindow" ) )
445                            {
446                                    frame.toFront();
447                            }
448                    }
449    
450                    MessageRecievedEvent event = new MessageRecievedEvent( this );
451                    com.valhalla.pluginmanager.PluginChain.fireEvent( event );
452            }
453    
454            /**
455             * Abstract createFrame - creates the containing frame of this panel
456             */
457            public abstract void createFrame();
458    
459            /**
460             * Stops the close timer
461             */
462            public void stopTimer()
463            {
464                    timer.stop();
465            }
466    
467            /**
468             * Starts the closet imer
469             */
470            public void startTimer()
471            {
472                    timer.start();
473            }
474    
475            /**
476             * Closes the log file
477             */
478            public void closeLog()
479            {
480                    try
481                    {
482                            if( fw != null )
483                            {
484                                    fw.close();
485                            }
486                    }
487                    catch( IOException e )
488                    {
489                    }
490            }
491    }
492