Source code: org/gjt/sp/jedit/gui/HistoryModel.java
1 /*
2 * HistoryModel.java - History list model
3 * :tabSize=8:indentSize=8:noTabs=false:
4 * :folding=explicit:collapseFolds=1:
5 *
6 * Copyright (C) 1999, 2003 Slava Pestov
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 */
22
23 package org.gjt.sp.jedit.gui;
24
25 //{{{ Imports
26 import javax.swing.AbstractListModel;
27 import java.io.*;
28 import java.util.*;
29 import org.gjt.sp.jedit.jEdit;
30 import org.gjt.sp.jedit.MiscUtilities;
31 import org.gjt.sp.util.Log;
32 //}}}
33
34 /**
35 * A history list. One history list can be used by several history text
36 * fields. Note that the list model implementation is incomplete; no events
37 * are fired when the history model changes.
38 * @author Slava Pestov
39 * @version $Id: HistoryModel.java,v 1.16 2003/11/06 03:38:44 spestov Exp $
40 */
41 public class HistoryModel extends AbstractListModel
42 {
43 //{{{ HistoryModel constructor
44 /**
45 * Creates a new history list. Calling this is normally not
46 * necessary.
47 */
48 public HistoryModel(String name)
49 {
50 this.name = name;
51
52 data = new Vector(max);
53 } //}}}
54
55 //{{{ addItem() method
56 /**
57 * Adds an item to the end of this history list, trimming the list
58 * to the maximum number of items if necessary.
59 * @param text The item
60 */
61 public void addItem(String text)
62 {
63 if(text == null || text.length() == 0)
64 return;
65
66 modified = true;
67
68 int index = data.indexOf(text);
69 if(index != -1)
70 data.removeElementAt(index);
71
72 data.insertElementAt(text,0);
73
74 while(getSize() > max)
75 data.removeElementAt(data.size() - 1);
76 } //}}}
77
78 //{{{ getItem() method
79 /**
80 * Returns an item from the history list.
81 * @param index The index
82 */
83 public String getItem(int index)
84 {
85 return (String)data.elementAt(index);
86 } //}}}
87
88 //{{{ getElementAt() method
89 /**
90 * Returns an item from the history list. This method returns the
91 * same thing as {@link #getItem(int)} and only exists so that
92 * <code>HistoryModel</code> instances can be used as list models.
93 * @param index The index
94 * @since jEdit 4.2pre2
95 */
96 public Object getElementAt(int index)
97 {
98 return getItem(index);
99 } //}}}
100
101 //{{{ clear() method
102 /**
103 * Removes all entries from this history model.
104 * @since jEdit 4.2pre2
105 */
106 public void clear()
107 {
108 modified = true;
109 data.removeAllElements();
110 } //}}}
111
112 //{{{ getSize() method
113 /**
114 * Returns the number of elements in this history list.
115 */
116 public int getSize()
117 {
118 return data.size();
119 } //}}}
120
121 //{{{ getName() method
122 /**
123 * Returns the name of this history list. This can be passed
124 * to the HistoryTextField constructor.
125 */
126 public String getName()
127 {
128 return name;
129 } //}}}
130
131 //{{{ getModel() method
132 /**
133 * Returns a named model. If the specified model does not
134 * already exist, it will be created.
135 * @param name The model name
136 */
137 public static HistoryModel getModel(String name)
138 {
139 if(models == null)
140 models = new Hashtable();
141
142 HistoryModel model = (HistoryModel)models.get(name);
143 if(model == null)
144 {
145 model = new HistoryModel(name);
146 models.put(name,model);
147 }
148
149 return model;
150 } //}}}
151
152 //{{{ loadHistory() method
153 public static void loadHistory()
154 {
155 String settingsDirectory = jEdit.getSettingsDirectory();
156 if(settingsDirectory == null)
157 return;
158
159 history = new File(MiscUtilities.constructPath(
160 settingsDirectory,"history"));
161 if(!history.exists())
162 return;
163
164 historyModTime = history.lastModified();
165
166 Log.log(Log.MESSAGE,HistoryModel.class,"Loading history");
167
168 if(models == null)
169 models = new Hashtable();
170
171 BufferedReader in = null;
172
173 try
174 {
175 in = new BufferedReader(new FileReader(history));
176
177 HistoryModel currentModel = null;
178 String line;
179
180 while((line = in.readLine()) != null)
181 {
182 if(line.startsWith("[") && line.endsWith("]"))
183 {
184 if(currentModel != null)
185 {
186 models.put(currentModel.getName(),
187 currentModel);
188 }
189
190 String modelName = MiscUtilities
191 .escapesToChars(line.substring(
192 1,line.length() - 1));
193 currentModel = new HistoryModel(
194 modelName);
195 }
196 else if(currentModel == null)
197 {
198 throw new IOException("History data starts"
199 + " before model name");
200 }
201 else
202 {
203 currentModel.data.addElement(MiscUtilities
204 .escapesToChars(line));
205 }
206 }
207
208 if(currentModel != null)
209 {
210 models.put(currentModel.getName(),currentModel);
211 }
212 }
213 catch(FileNotFoundException fnf)
214 {
215 //Log.log(Log.DEBUG,HistoryModel.class,fnf);
216 }
217 catch(IOException io)
218 {
219 Log.log(Log.ERROR,HistoryModel.class,io);
220 }
221 finally
222 {
223 try
224 {
225 if(in != null)
226 in.close();
227 }
228 catch(IOException io)
229 {
230 }
231 }
232 } //}}}
233
234 //{{{ saveHistory() method
235 public static void saveHistory()
236 {
237 if(!modified)
238 return;
239
240 Log.log(Log.MESSAGE,HistoryModel.class,"Saving history");
241 File file1 = new File(MiscUtilities.constructPath(
242 jEdit.getSettingsDirectory(), "#history#save#"));
243 File file2 = new File(MiscUtilities.constructPath(
244 jEdit.getSettingsDirectory(), "history"));
245 if(file2.exists() && file2.lastModified() != historyModTime)
246 {
247 Log.log(Log.WARNING,HistoryModel.class,file2
248 + " changed on disk; will not save history");
249 return;
250 }
251
252 jEdit.backupSettingsFile(file2);
253
254 String lineSep = System.getProperty("line.separator");
255
256 try
257 {
258 BufferedWriter out = new BufferedWriter(
259 new FileWriter(file1));
260
261 if(models != null)
262 {
263 Enumeration modelEnum = models.elements();
264 while(modelEnum.hasMoreElements())
265 {
266 HistoryModel model = (HistoryModel)modelEnum
267 .nextElement();
268 if(model.getSize() == 0)
269 continue;
270
271 out.write('[');
272 out.write(MiscUtilities.charsToEscapes(
273 model.getName(),TO_ESCAPE));
274 out.write(']');
275 out.write(lineSep);
276
277 for(int i = 0; i < model.getSize(); i++)
278 {
279 out.write(MiscUtilities.charsToEscapes(
280 model.getItem(i),
281 TO_ESCAPE));
282 out.write(lineSep);
283 }
284 }
285 }
286
287 out.close();
288
289 /* to avoid data loss, only do this if the above
290 * completed successfully */
291 file2.delete();
292 file1.renameTo(file2);
293 modified = false;
294 }
295 catch(IOException io)
296 {
297 Log.log(Log.ERROR,HistoryModel.class,io);
298 }
299
300 historyModTime = file2.lastModified();
301 } //}}}
302
303 //{{{ propertiesChanged() method
304 public static void propertiesChanged()
305 {
306 max = jEdit.getIntegerProperty("history",25);
307 } //}}}
308
309 //{{{ Private members
310 private static final String TO_ESCAPE = "\r\n\t\\\"'[]";
311 private static int max;
312
313 private String name;
314 private Vector data;
315 private static Hashtable models;
316
317 private static boolean modified;
318 private static File history;
319 private static long historyModTime;
320 //}}}
321 }