001 /*
002 * ConversationArea.java
003 *
004 * Created on September 9, 2005, 6:26 PM
005 *
006 * To change this template, choose Tools | Options and locate the template under
007 * the Source Creation and Management node. Right-click the template and choose
008 * Open. You can then make changes to the template in the Source Editor.
009 */
010
011 package com.valhalla.jbother;
012
013 import javax.swing.*;
014 import javax.swing.text.*;
015 import java.awt.*;
016 import javax.swing.event.*;
017 import java.awt.event.*;
018 import java.io.*;
019 import java.util.*;
020 import java.util.regex.*;
021
022 import com.valhalla.settings.*;
023 import com.valhalla.gui.*;
024
025 /**
026 *
027 * @author synic
028 */
029 public class ConversationArea extends JScrollPane {
030 private ResourceBundle resources = ResourceBundle.getBundle(
031 "JBotherBundle", Locale.getDefault());
032
033 JTextPane pane = new JTextPane();
034
035 public static Color SENDER = new Color(128, 0, 0);
036 public static Color RECEIVER = new Color(22, 86, 158);
037 public static Color SERVER = new Color(0, 128, 0);
038 public static Color BLACK = Color.BLACK;
039 public static Color HL = new Color(248,192,192);
040 public static Color GRAY = Color.GRAY;
041 Document doc = pane.getDocument();
042 File file;
043 PrintWriter out = null;
044 OutputStreamWriter fw = null;
045 LinkedList textBuffer = new LinkedList();
046 LinkedList sasBuffer = new LinkedList();
047 javax.swing.Timer timer = new javax.swing.Timer(50, new ShowHandler());
048 boolean emoticons = true;
049
050 /** Creates a new instance of ConversationArea */
051 public ConversationArea() {
052 pane.setBackground(Color.WHITE);
053 setViewportView(pane);
054 pane.setEditable(false);
055
056 Color c = UIManager.getColor("TextPane.foreground");
057 pane.setForeground(c);
058
059 setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
060
061 addAdapter(pane);
062 }
063
064 public void setEmoticons(boolean e) { this.emoticons = e; }
065
066 /**
067 * Sets the log file
068 *
069 * @param logFile
070 * the file to use for logging
071 * @param encoding
072 * the encoding of the log file
073 * (if null, empty, or invalid, the platform default encoding will
074 * be used)
075 */
076 public void setLogFile(File logFile, String encoding) {
077 try {
078 fw = null;
079 try {
080 fw = new OutputStreamWriter(
081 new FileOutputStream(logFile, true), encoding);
082 } catch (UnsupportedEncodingException ex) {
083 } catch (NullPointerException ex) {
084 }
085 if (fw == null) {
086 fw = new OutputStreamWriter(
087 new FileOutputStream(logFile, true));
088 }
089 out = new PrintWriter(fw, true);
090 } catch (Exception ex) {
091 fw = null;
092 }
093 }
094
095 public void closeLog()
096 {
097 try {
098 if( fw != null ) fw.close();
099 }
100 catch( Exception ex){}
101 }
102
103 public void setText(String text) { pane.setText(text);}
104
105 public JTextPane getTextPane() { return pane; }
106
107 public void append( String text, Color color )
108 {
109 this.append(text, color, false, Color.WHITE);
110 }
111
112 public void append( String text, Color color, boolean bold )
113 {
114 this.append(text, color, bold, Color.WHITE);
115 }
116
117 public String getSelectedText() { return pane.getSelectedText(); }
118
119 public void append( String text )
120 {
121 this.append(text, Color.BLACK);
122 }
123
124 public void appendIcon(ImageIcon icon)
125 {
126 pane.insertIcon(icon);
127 }
128
129 public void append( String text, final Color color,
130 final boolean bold, final Color background )
131 {
132 text = text.replaceAll("\n", " \n");
133 if( out != null )
134 {
135 out.print(text);
136 out.flush();
137 }
138
139 SimpleAttributeSet sas = new SimpleAttributeSet();
140 StyleConstants.setForeground(sas, color);
141 StyleConstants.setBackground(sas, background);
142 StyleConstants.setBold(sas, bold);
143
144 synchronized(textBuffer)
145 {
146 textBuffer.add(text);
147 sasBuffer.add(sas);
148 if(!timer.isRunning()) timer.start();
149 else timer.restart();
150 }
151 }
152
153 private synchronized void showItem(final String text, final SimpleAttributeSet sas)
154 {
155 SwingUtilities.invokeLater(new Runnable()
156 {
157 public void run()
158 {
159 final JScrollBar bar = getVerticalScrollBar();
160 final int barPos = bar.getValue();
161
162 boolean end = bar.getValue() - ( bar.getMaximum() - bar.getModel().getExtent() ) >= -16;
163 Point p = getViewport().getViewPosition();
164
165 boolean scrFlag = bar.isVisible();
166 p.y += 50; // just so it's not the first line (might scroll a bit)
167 int pos = pane.viewToModel( p );
168
169 try {
170
171 ConversationFormatter.getInstance().replaceIcons(text, (StyledDocument)doc, sas, pane, emoticons);
172 //doc.insertString(doc.getLength(), text , sas);
173
174 if( !end && scrFlag ) pane.setCaretPosition( pos );
175 else pane.setCaretPosition(doc.getLength());
176
177 }
178 catch( Exception blx )
179 {
180 //com.valhalla.Logger.logException( blx );
181 }
182 }
183 });
184
185 notify();
186
187 }
188
189 class ShowHandler implements ActionListener
190 {
191 public void actionPerformed(ActionEvent e)
192 {
193 synchronized(textBuffer)
194 {
195 while(textBuffer.size() > 0)
196 {
197 String text = (String)textBuffer.removeFirst();
198 SimpleAttributeSet sas = (SimpleAttributeSet)sasBuffer.removeFirst();
199 showItem(text, sas);
200 }
201
202 timer.stop();
203 }
204 }
205 }
206
207 private void addAdapter(final JTextPane pane)
208 {
209 pane.addMouseListener(new MouseAdapter()
210 {
211 public void mouseReleased(MouseEvent ev)
212 {
213 if(ev.getButton() != MouseEvent.BUTTON1) return;
214 ev.consume();
215
216 if( pane.getSelectedText() != null ) return;
217 int c = pane.viewToModel(ev.getPoint());
218 String text = pane.getText().replaceAll("\n", " ");
219
220 if(c == -1) return;
221 int b = text.lastIndexOf(" ", c);
222 if( b == -1 ) b = 0;
223 int e = text.indexOf(" ", c);
224 if( e == -1 ) e = text.length();
225
226 String word = text.substring(b, e).trim();
227 if(text.indexOf(" ") == -1) word = text;
228
229 String app = null;
230 boolean match = false;
231
232 if( Pattern.matches("^.*(\\s|^)((?!(ftp|https?)://)[^\\s\"'\\/]+?@[^\\s\"'\\/]+?)(\\s|$).*$", word))
233 {
234 app = Settings.getInstance().getProperty("emailApplication");
235 match = true;
236 }
237 else if( Pattern.matches("^.*(^|\\s)((ftp|http|https)://[^\\s\"']+?)(\\s|$).*$", word))
238 {
239 app = Settings.getInstance().getProperty("browserApplication");
240 match = true;
241 }
242
243 if( match )
244 {
245 try {
246 if (app != null && !app.equals("")) {
247 /* tail */
248 String command = app
249 .replaceAll("%s", word);
250 command = command.replaceAll("\\%l", word);
251
252 Runtime.getRuntime().exec(command);
253 /* tail */
254 } else
255 Standard.warningMessage(BuddyList.getInstance().getContainerFrame(), resources
256 .getString("hyperlink"), resources
257 .getString("noApplication"));
258 } catch (java.io.IOException ex) {
259 Standard.warningMessage(BuddyList.getInstance().getContainerFrame(), resources.getString("hyperlink"),
260 resources.getString("errorExecutingApplication"));
261 }
262 }
263 }
264 });
265 }
266 }