1 /*
2  * Created on 27-Apr-2004
3  * Created by Paul Gardner
4  * Copyright (C) Azureus Software, Inc, All Rights Reserved.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version.
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17  *
18  */
19 
20 package org.gudy.azureus2.pluginsimpl.local.ui.components;
21 
22 /**
23  * @author parg
24  *
25  */
26 
27 import java.io.File;
28 import java.io.FileOutputStream;
29 import java.io.OutputStreamWriter;
30 import java.io.PrintWriter;
31 import java.util.Iterator;
32 import java.util.LinkedList;
33 
34 import org.gudy.azureus2.core3.util.*;
35 import org.gudy.azureus2.plugins.ui.components.UIPropertyChangeListener;
36 import org.gudy.azureus2.plugins.ui.components.UITextArea;
37 
38 
39 public class
40 UITextAreaImpl
41 	extends		UIComponentImpl
42 	implements 	UITextArea
43 {
44 	private final boolean enable_history = System.getProperty( "az.logging.keep.ui.history", "true" ).equals( "true" );
45 
46 	private int	max_size		= DEFAULT_MAX_SIZE;
47 	private int max_file_size = 20 * max_size;
48 
49 	PoopWriter pw;
50 	int current_file_size;
51 	File poop_file;
52 	boolean useFile = true;
53 
54 	AEMonitor file_mon = new AEMonitor("filemon");
55 
56 	LinkedList<String>	delay_text	= new LinkedList<String>();
57 	int					delay_size	= 0;
58 
59 	FrequencyLimitedDispatcher	dispatcher =
60 		new FrequencyLimitedDispatcher(
61 			new AERunnable()
62 			{
63 				public void
64 				runSupport()
65 				{
66 					delayAppend();
67 				}
68 			},
69 			500 );
70 
71 	public
UITextAreaImpl()72 	UITextAreaImpl()
73 	{
74 		setText("");
75 	}
76 
77 	public void
setText( String text )78 	setText(
79 		String		text )
80 	{
81 		if ( !enable_history ){
82 
83 			return;
84 		}
85 
86 		if ( useFile ){
87 
88 			try{
89 				file_mon.enter();
90 
91 				if ( pw == null ){
92 
93 					pw = new PoopWriter();
94 
95 					pw.print(text);
96 
97 					current_file_size = text.length();
98 
99 					return;
100 				}
101 			}finally{
102 
103 				file_mon.exit();
104 			}
105 		}
106 
107 		// has property change listener, or error while doing file (fallthrough)
108 
109 		if ( text.length() > max_size ){
110 
111 			int	size_to_show = max_size - 10000;
112 
113 			if ( size_to_show < 0 ){
114 
115 				size_to_show	= max_size;
116 			}
117 
118 			text = text.substring( text.length() - size_to_show );
119 		}
120 
121 		setProperty( PT_VALUE, text );
122 	}
123 
124 	public void
appendText( String text )125 	appendText(
126 		String		text )
127 	{
128 		if ( !enable_history ){
129 
130 			return;
131 		}
132 
133 		if ( useFile && pw != null ){
134 
135 			try{
136 				file_mon.enter();
137 
138 					// shrink the file occasionally
139 
140 				if ( current_file_size > max_file_size ){
141 
142 					current_file_size = getFileText().length();
143 				}
144 
145 				pw.print(text);
146 
147 				current_file_size += text.length();
148 
149 				return;
150 
151 			}finally{
152 
153 				file_mon.exit();
154 			}
155 		}
156 
157 		synchronized( this ){
158 
159 			delay_text.addLast( text );
160 
161 			delay_size += text.length();
162 
163 			while( delay_size > max_size ){
164 
165 				if ( delay_text.size() == 0 ){
166 
167 					break;
168 				}
169 
170 				String	s = (String)delay_text.removeFirst();
171 
172 				delay_size -= s.length();
173 			}
174 		}
175 
176 		dispatcher.dispatch();
177 	}
178 
179 	protected void
delayAppend()180 	delayAppend()
181 	{
182 		String	str = getText();
183 
184 		String	text;
185 
186 		synchronized( this ){
187 
188 			if ( delay_text.size() == 1 ){
189 
190 				text = (String)delay_text.get(0);
191 
192 			}else{
193 
194 				StringBuffer sb = new StringBuffer( delay_size );
195 
196 				Iterator<String>	it = delay_text.iterator();
197 
198 				while( it.hasNext()){
199 
200 					sb.append( it.next());
201 				}
202 
203 				text = sb.toString();
204 			}
205 
206 			delay_text.clear();
207 			delay_size = 0;
208 		}
209 
210 		if ( str == null ){
211 
212 			setText( text );
213 
214 		}else{
215 
216 			setText( str + text );
217 		}
218 	}
219 
220 	public String
getText()221 	getText()
222 	{
223 		if ( !enable_history ){
224 
225 			return( "" );
226 		}
227 
228 		if ( useFile && pw != null ){
229 
230 			return( getFileText());
231 		}
232 
233 		return((String)getProperty( PT_VALUE ));
234 	}
235 
236 	public void
setMaximumSize( int _max_size )237 	setMaximumSize(
238 		int	_max_size )
239 	{
240 		max_size	= _max_size;
241 	}
242 
243 	private String
getFileText()244 	getFileText()
245 	{
246 		try{
247 			file_mon.enter();
248 
249 			String text = null;
250 
251 			if ( pw != null ){
252 
253 				pw.close();
254 
255 				text = pw.getText();
256 			}
257 
258 			if ( text == null ){
259 
260 				text = "";
261 			}
262 
263 			pw = null;
264 
265 			if ( useFile ){
266 
267 				pw = new PoopWriter();
268 
269 				pw.print(text);
270 
271 				current_file_size = text.length();
272 			}
273 
274 			return text;
275 
276 		}finally{
277 
278 			file_mon.exit();
279 		}
280 	}
281 
282 	public void
addPropertyChangeListener( UIPropertyChangeListener l )283 	addPropertyChangeListener(
284 		UIPropertyChangeListener l )
285 	{
286 		if ( useFile ){
287 
288 			useFile = false;
289 
290 			setText( getFileText());
291 		}
292 
293 		super.addPropertyChangeListener(l);
294 	}
295 
296 	protected class
297 	PoopWriter
298 	{
299 		private StringBuffer	buffer = new StringBuffer(256);
300 
301 		private PrintWriter		pw;
302 
303 		private void
print( String text )304 		print(
305 			String	text )
306 		{
307 			if ( pw == null ){
308 
309 				buffer.append( text );
310 
311 				if ( buffer.length() > 8*1024 ){
312 
313 					if ( poop_file == null ){
314 
315 						try{
316 							poop_file = AETemporaryFileHandler.createTempFile();
317 
318 						}catch( Throwable e ){
319 						}
320 					}
321 
322 					if ( poop_file != null ){
323 
324 						try{
325 							pw = new PrintWriter( new OutputStreamWriter( new FileOutputStream( poop_file ), "UTF-8" ));
326 
327 							pw.print( buffer.toString());
328 
329 						}catch( Throwable e ){
330 						}
331 					}
332 
333 					buffer.setLength( 0 );
334 				}
335 			}else{
336 
337 				pw.print( text );
338 			}
339 		}
340 
341 		private String
getText()342 		getText()
343 		{
344 			if ( poop_file == null ){
345 
346 				return( buffer.toString());
347 
348 			}else{
349 
350 				try{
351 					return( FileUtil.readFileEndAsString( poop_file, max_size, "UTF-8" ));
352 
353 				}catch( Throwable e ){
354 
355 					return( "" );
356 				}
357 			}
358 		}
359 
360 		private void
close()361 		close()
362 		{
363 			if ( pw != null ){
364 
365 				pw.close();
366 
367 				pw = null;
368 			}
369 		}
370 	}
371 }