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