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.*;
018    import java.awt.event.*;
019    import java.beans.PropertyChangeEvent;
020    import java.beans.PropertyChangeListener;
021    import java.util.Date;
022    import java.util.Locale;
023    import java.util.ResourceBundle;
024    
025    import javax.swing.*;
026    import javax.swing.event.*;
027    
028    import com.valhalla.gui.CopyPasteContextMenu;
029    import com.valhalla.gui.MJTextArea;
030    import com.valhalla.gui.Standard;
031    import com.valhalla.jbother.jabber.BuddyStatus;
032    import com.valhalla.jbother.jabber.smack.Blank;
033    import com.valhalla.jbother.menus.ConversationPopupMenu;
034    import com.valhalla.settings.Settings;
035    
036    /**
037     * Handles XML packet exchange between client and server.
038     *
039     * @author Andrey Zakirov
040     * @created March 2, 2005
041     * @version 0.1
042     */
043    
044    public class ConsolePanel extends ConversationPanel {
045        private ResourceBundle resources = ResourceBundle.getBundle(
046                "JBotherBundle", Locale.getDefault());
047    
048        private JSplitPane container;
049    
050        private JPanel buttonPanel = new JPanel();
051    
052        private JPanel scrollPanel = new JPanel(new GridLayout(1, 0));
053    
054        private boolean divSetUp = false;
055    
056        private ConversationPopupMenu popMenu = new ConversationPopupMenu(this,
057                conversationArea);
058    
059        private DividerListener dividerListener = new DividerListener();
060        private static ConsolePanel instance = null;
061    
062        /**
063         * Sets up the ConsolePanel - creates all visual components and adds event
064         * listeners
065         *
066         * @param buddy
067         *            the buddy to associate with
068         */
069        private ConsolePanel(BuddyStatus buddy) {
070            super(buddy);
071            setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
072            setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
073            textEntryArea.setLineWrap(true);
074            textEntryArea.setWrapStyleWord(true);
075    
076            scrollPanel.add(conversationArea);
077    
078            container = new JSplitPane(JSplitPane.VERTICAL_SPLIT, scrollPanel,
079                    new JScrollPane(textEntryArea));
080            container.setResizeWeight(1);
081    
082            JPanel containerPanel = new JPanel();
083            containerPanel
084                    .setLayout(new BoxLayout(containerPanel, BoxLayout.X_AXIS));
085            containerPanel.add(container);
086    
087            conversationArea.getTextPane().addMouseListener(new RightClickListener(popMenu));
088            conversationArea.setEmoticons(false);
089            CopyPasteContextMenu.registerComponent(conversationArea.getTextPane());
090            popMenu.disableBlock();
091    
092            add(containerPanel);
093    
094            textEntryArea.grabFocus();
095    
096            addListeners();
097        }
098    
099        /**
100         * Destroys the dialog, disposes the containing frame if there is one and
101         * removes the panel from the TabFrame if required.
102         */
103        public void closeHandler() {
104            closeLog();
105            if (frame != null) {
106                frame.setVisible(false);
107                frame.dispose();
108            }
109    
110            if (buddy != null) {
111                com.valhalla.Logger.debug("Closing ConversationPanel for "
112                        + buddy.getUser());
113                buddy.setConversation(null);
114            }
115    
116            if (Settings.getInstance().getBoolean("useTabbedWindow")) {
117                BuddyList.getInstance().removeTabPanel(this);
118            }
119    
120            MessageDelegator.getInstance().removePanel(this);
121            instance = null;
122        }
123    
124    
125        public static ConsolePanel getInstance(BuddyStatus buddy)
126        {
127            if( instance == null ) instance = new ConsolePanel(buddy);
128            return instance;
129        }
130    
131        public static ConsolePanel getInstance()
132        {
133            return instance;
134        }
135    
136        private String getMessageTemplate() {
137            return "<message id=\"\" to=\"\" type=\"\"><body></body></message>";
138        }
139    
140        /**
141         * @return the input area of this panel
142         */
143        public JComponent getInputComponent() {
144            return textEntryArea;
145        }
146    
147        /**
148         * Sets up the Divider
149         */
150        public void setUpDivider() {
151            String modifier = "";
152            if (Settings.getInstance().getBoolean("useTabbedWindow")) {
153                modifier = "tabbed_";
154            }
155    
156            String stringHeight = Settings.getInstance().getProperty(
157                    modifier + "XMLconversationWindowHeight", "100");
158    
159            // set up the divider location from settings
160            String divLocString = Settings.getInstance().getProperty(
161                    modifier + "XMLconversationWindowDividerLocation", "50");
162            int divLoc = 50;
163    
164            //com.valhalla.Logger.debug( "divlocstring is " + divLocString );
165    
166            try {
167                if (divLocString != null) {
168                    divLoc = Integer.parseInt(divLocString);
169                } else {
170                    Settings
171                            .getInstance()
172                            .setProperty(
173                            modifier
174                            + "XMLconversationWindowDividerLocation",
175                            "30");
176                }
177            } catch (NumberFormatException ex) {
178                com.valhalla.Logger.logException( ex );
179            }
180    
181            //com.valhalla.Logger.debug( "getting divider to " + divLoc );
182            container.setDividerLocation(divLoc);
183    
184            if (!divSetUp) {
185                container.addPropertyChangeListener("lastDividerLocation",
186                        dividerListener);
187                divSetUp = true;
188            }
189        }
190    
191        /**
192         * Listens for the user to move the divider, and saves it's location
193         *
194         * @author Adam Olsen
195         * @version 1.0
196         */
197        private class DividerListener implements PropertyChangeListener {
198            public void propertyChange(PropertyChangeEvent e) {
199                String modifier = "";
200                if (Settings.getInstance().getBoolean("useTabbedWindow")) {
201                    modifier = "tabbed_";
202                }
203    
204                if (e.getOldValue().toString().equals("-1")) {
205                    return;
206                }
207    
208                //com.valhalla.Logger.debug( "Setting divider to " + e.getOldValue() );
209                Settings.getInstance().setProperty(
210                        modifier + "XMLconversationWindowDividerLocation",
211                        e.getOldValue().toString());
212            }
213        }
214    
215        public void removeDividerListener() {
216            container.removePropertyChangeListener(dividerListener);
217        }
218    
219        /**
220         * @return the ConsolePanel's JSPlitPane
221         */
222        public JSplitPane getSplitPane() {
223            return container;
224        }
225    
226        /**
227         * Adds the various event listeners for the components that are a part of
228         * this frame
229         */
230        private void addListeners() {
231    
232            //if the press enter, send the message
233            Action sendMessageAction = new AbstractAction() {
234                public void actionPerformed(ActionEvent e) {
235                    sendHandler();
236                }
237            };
238    
239            Action shiftEnterAction = new AbstractAction() {
240                public void actionPerformed(ActionEvent e) {
241                    int pos = textEntryArea.getCaretPosition();
242                    if (pos < 0) {
243                        pos = 0;
244                    }
245    
246                    textEntryArea.setText(textEntryArea.getText() + "\n");
247    
248                    try {
249                        textEntryArea.setCaretPosition(pos + 1);
250                    } catch (IllegalArgumentException ex) {
251                    }
252                }
253            };
254    
255            Action checkCloseAction = new AbstractAction() {
256                public void actionPerformed(ActionEvent e) {
257                    closeHandler();
258                }
259            };
260    
261            Action closeAction = new AbstractAction() {
262                public void actionPerformed(ActionEvent e) {
263                    closeHandler();
264                }
265            };
266    
267             //set it up so that if there isn't any selected text in the
268            // conversation area
269            //the textentryarea grabs the focus.
270            conversationArea.getTextPane().addMouseListener(new MouseAdapter() {
271                public void mouseReleased(MouseEvent e) {
272                    if (conversationArea.getSelectedText() == null) {
273                        textEntryArea.requestFocus();
274                    }
275                }
276            });
277    
278    
279            textEntryArea.getInputMap()
280            .put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0),
281                    sendMessageAction);
282            textEntryArea.getInputMap()
283            .put(
284                    KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,
285                    java.awt.event.InputEvent.SHIFT_MASK),
286                    shiftEnterAction);
287            textEntryArea.getInputMap().put(
288                    KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, Toolkit
289                    .getDefaultToolkit().getMenuShortcutKeyMask()),
290                    shiftEnterAction);
291            textEntryArea.getInputMap().put(
292                    KeyStroke.getKeyStroke(KeyEvent.VK_W, Toolkit
293                    .getDefaultToolkit().getMenuShortcutKeyMask()),
294                    checkCloseAction);
295            textEntryArea.getInputMap().put(
296                    KeyStroke.getKeyStroke(KeyEvent.VK_K, Toolkit
297                    .getDefaultToolkit().getMenuShortcutKeyMask()),
298                    closeAction);
299        }
300    
301        public String getPanelName() {
302            return resources.getString("console");
303        }
304    
305        /**
306         * Recieves a message
307         *
308         * @param sbj
309         *            Description of the Parameter
310         * @param message
311         *            Description of the Parameter
312         * @param resource
313         *            Description of the Parameter
314         * @param date
315         *            Description of the Parameter
316         */
317        public void append(final String message, boolean to) {
318            final Color color;
319    
320            if(!to) color = ConversationArea.SENDER;
321            else color = ConversationArea.RECEIVER;
322    
323            SwingUtilities.invokeLater(new Runnable() {
324                public void run() {
325                    conversationArea.append(message + "\n\n", color );
326                }
327            });
328        }
329    
330        /**
331         * Sends the message in the TextEntryArea
332         */
333        private void sendHandler() {
334            if (!textEntryArea.getText().equals("")) {
335                if (!BuddyList.getInstance().checkConnection()) {
336                    BuddyList.getInstance().connectionError();
337                    return;
338                }
339                sendBuddyMessage(textEntryArea.getText());
340    
341                textEntryArea.setText("");
342                //com.valhalla.jbother.sound.SoundPlayer.play( "sentSound" );
343            }
344    
345        }
346    
347        /**
348         * Sends the message
349         *
350         * @param text
351         *            the message to send
352         */
353        public void sendBuddyMessage(String text) {
354            Blank message = new Blank(text);
355            if (BuddyList.getInstance().checkConnection()) {
356                BuddyList.getInstance().getConnection().sendPacket(message);
357            } else {
358                BuddyList.getInstance().connectionError();
359            }
360        }
361    
362        /**
363         * Creates the containing frame
364         */
365        public void createFrame() {
366            frame = new JFrame();
367            frame.setContentPane(this);
368            frame.pack();
369    
370            frame.setIconImage(Standard.getImage("frameicon.png"));
371    
372            frame.addWindowListener(new WindowAdapter() {
373                public void windowClosing(WindowEvent e) {
374                    closeHandler();
375                }
376            });
377    
378            frame.setTitle(resources.getString("xmlConsole"));
379            frame.pack();
380    
381            String stringWidth = Settings.getInstance().getProperty(
382                    "XMLconversationWindowWidth");
383            String stringHeight = Settings.getInstance().getProperty(
384                    "XMLconversationWindowHeight");
385    
386            if (stringWidth == null) {
387                stringWidth = "400";
388            }
389            if (stringHeight == null) {
390                stringHeight = "340";
391            }
392    
393            frame.setSize(new Dimension(Integer.parseInt(stringWidth), Integer
394                    .parseInt(stringHeight)));
395    
396            // add a resize window listener
397            frame.addComponentListener(new ComponentAdapter() {
398                public void componentResized(ComponentEvent e) {
399                    Dimension dim = frame.getSize();
400                    Settings.getInstance().setProperty(
401                            "XMLconversationWindowWidth",
402                            new Integer((int) dim.getWidth()).toString());
403                    Settings.getInstance().setProperty(
404                            "XMLconversationWindowHeight",
405                            new Integer((int) dim.getHeight()).toString());
406                }
407            });
408            Standard.cascadePlacement(frame);
409    
410            setUpDivider();
411            frame.setVisible(true);
412        }
413    
414        /**
415         * Description of the Method
416         */
417        public void checkCloseHandler() {
418            closeHandler();
419        }
420    
421    }
422