PageRenderTime 413ms CodeModel.GetById 23ms RepoModel.GetById 4ms app.codeStats 0ms

/jEdit/tags/jedit-4-2-pre14/org/gjt/sp/jedit/buffer/KillRing.java

#
Java | 407 lines | 307 code | 52 blank | 48 comment | 52 complexity | 68b0924105726f95689c08b71de8cb13 MD5 | raw file
Possible License(s): BSD-3-Clause, AGPL-1.0, Apache-2.0, LGPL-2.0, LGPL-3.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0, MPL-2.0-no-copyleft-exception, IPL-1.0
  1. /*
  2. * KillRing.java - Stores deleted text
  3. * :tabSize=8:indentSize=8:noTabs=false:
  4. * :folding=explicit:collapseFolds=1:
  5. *
  6. * Copyright (C) 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. package org.gjt.sp.jedit.buffer;
  23. import com.microstar.xml.*;
  24. import javax.swing.event.ListDataListener;
  25. import javax.swing.ListModel;
  26. import java.io.*;
  27. import java.util.*;
  28. import org.gjt.sp.jedit.*;
  29. import org.gjt.sp.util.Log;
  30. public class KillRing
  31. {
  32. //{{{ propertiesChanged() method
  33. public static void propertiesChanged()
  34. {
  35. int newSize = jEdit.getIntegerProperty("history",25);
  36. if(ring == null)
  37. ring = new UndoManager.Remove[newSize];
  38. else if(newSize != ring.length)
  39. {
  40. UndoManager.Remove[] newRing = new UndoManager.Remove[
  41. newSize];
  42. ListModel model = new RingListModel();
  43. int newCount = Math.min(model.getSize(),newSize);
  44. for(int i = 0; i < newCount; i++)
  45. {
  46. newRing[i] = (UndoManager.Remove)
  47. model.getElementAt(i);
  48. }
  49. ring = newRing;
  50. count = newCount;
  51. wrap = false;
  52. }
  53. else if(count == ring.length)
  54. {
  55. count = 0;
  56. wrap = true;
  57. }
  58. } //}}}
  59. //{{{ getListModel() method
  60. public static ListModel getListModel()
  61. {
  62. return new RingListModel();
  63. } //}}}
  64. //{{{ load() method
  65. public static void load()
  66. {
  67. String settingsDirectory = jEdit.getSettingsDirectory();
  68. if(settingsDirectory == null)
  69. return;
  70. File killRing = new File(MiscUtilities.constructPath(
  71. settingsDirectory,"killring.xml"));
  72. if(!killRing.exists())
  73. return;
  74. killRingModTime = killRing.lastModified();
  75. Log.log(Log.MESSAGE,KillRing.class,"Loading killring.xml");
  76. KillRingHandler handler = new KillRingHandler();
  77. XmlParser parser = new XmlParser();
  78. Reader in = null;
  79. parser.setHandler(handler);
  80. try
  81. {
  82. in = new BufferedReader(new FileReader(killRing));
  83. parser.parse(null, null, in);
  84. }
  85. catch(XmlException xe)
  86. {
  87. int line = xe.getLine();
  88. String message = xe.getMessage();
  89. Log.log(Log.ERROR,KillRing.class,killRing + ":" + line
  90. + ": " + message);
  91. }
  92. catch(FileNotFoundException fnf)
  93. {
  94. //Log.log(Log.DEBUG,BufferHistory.class,fnf);
  95. }
  96. catch(Exception e)
  97. {
  98. Log.log(Log.ERROR,KillRing.class,e);
  99. }
  100. finally
  101. {
  102. try
  103. {
  104. if(in != null)
  105. in.close();
  106. }
  107. catch(IOException io)
  108. {
  109. Log.log(Log.ERROR,KillRing.class,io);
  110. }
  111. }
  112. ring = (UndoManager.Remove[])handler.list.toArray(
  113. new UndoManager.Remove[handler.list.size()]);
  114. count = ring.length;
  115. } //}}}
  116. //{{{ save() method
  117. public static void save()
  118. {
  119. String settingsDirectory = jEdit.getSettingsDirectory();
  120. if(settingsDirectory == null)
  121. return;
  122. File file1 = new File(MiscUtilities.constructPath(
  123. settingsDirectory, "#killring.xml#save#"));
  124. File file2 = new File(MiscUtilities.constructPath(
  125. settingsDirectory, "killring.xml"));
  126. if(file2.exists() && file2.lastModified() != killRingModTime)
  127. {
  128. Log.log(Log.WARNING,KillRing.class,file2
  129. + " changed on disk; will not save recent"
  130. + " files");
  131. return;
  132. }
  133. jEdit.backupSettingsFile(file2);
  134. Log.log(Log.MESSAGE,KillRing.class,"Saving killring.xml");
  135. String lineSep = System.getProperty("line.separator");
  136. BufferedWriter out = null;
  137. try
  138. {
  139. out = new BufferedWriter(new FileWriter(file1));
  140. out.write("<?xml version=\"1.0\"?>");
  141. out.write(lineSep);
  142. out.write("<!DOCTYPE KILLRING SYSTEM \"killring.dtd\">");
  143. out.write(lineSep);
  144. out.write("<KILLRING>");
  145. out.write(lineSep);
  146. ListModel model = getListModel();
  147. int size = model.getSize();
  148. for(int i = size - 1; i >=0; i--)
  149. {
  150. out.write("<ENTRY>");
  151. out.write(MiscUtilities.charsToEntities(
  152. model.getElementAt(i).toString()));
  153. out.write("</ENTRY>");
  154. out.write(lineSep);
  155. }
  156. out.write("</KILLRING>");
  157. out.write(lineSep);
  158. out.close();
  159. /* to avoid data loss, only do this if the above
  160. * completed successfully */
  161. file2.delete();
  162. file1.renameTo(file2);
  163. }
  164. catch(Exception e)
  165. {
  166. Log.log(Log.ERROR,KillRing.class,e);
  167. }
  168. finally
  169. {
  170. try
  171. {
  172. if(out != null)
  173. out.close();
  174. }
  175. catch(IOException e)
  176. {
  177. }
  178. }
  179. killRingModTime = file2.lastModified();
  180. } //}}}
  181. //{{{ Package-private members
  182. static UndoManager.Remove[] ring;
  183. static int count;
  184. static boolean wrap;
  185. //{{{ changed() method
  186. static void changed(UndoManager.Remove rem)
  187. {
  188. if(rem.inKillRing)
  189. {
  190. // compare existing entries' hashcode with this
  191. int length = (wrap ? ring.length : count);
  192. int kill = -1;
  193. boolean duplicate = false;
  194. for(int i = 0; i < length; i++)
  195. {
  196. if(ring[i] != rem
  197. && ring[i].hashcode == rem.hashcode
  198. && ring[i].str.equals(rem.str))
  199. {
  200. // we don't want duplicate
  201. // entries in the kill ring
  202. kill = i;
  203. break;
  204. }
  205. }
  206. if(kill != -1)
  207. remove(kill);
  208. }
  209. else
  210. add(rem);
  211. } //}}}
  212. //{{{ add() method
  213. static void add(UndoManager.Remove rem)
  214. {
  215. // compare existing entries' hashcode with this
  216. int length = (wrap ? ring.length : count);
  217. for(int i = 0; i < length; i++)
  218. {
  219. if(ring[i].hashcode == rem.hashcode)
  220. {
  221. // strings might be equal!
  222. if(ring[i].str.equals(rem.str))
  223. {
  224. // we don't want duplicate entries
  225. // in the kill ring
  226. return;
  227. }
  228. }
  229. }
  230. // no duplicates, check for all-whitespace string
  231. boolean allWhitespace = true;
  232. for(int i = 0; i < rem.str.length(); i++)
  233. {
  234. if(!Character.isWhitespace(rem.str.charAt(i)))
  235. {
  236. allWhitespace = false;
  237. break;
  238. }
  239. }
  240. if(allWhitespace)
  241. return;
  242. rem.inKillRing = true;
  243. if(ring[count] != null)
  244. ring[count].inKillRing = false;
  245. ring[count] = rem;
  246. if(++count >= ring.length)
  247. {
  248. wrap = true;
  249. count = 0;
  250. }
  251. } //}}}
  252. //{{{ remove() method
  253. static void remove(int i)
  254. {
  255. if(wrap)
  256. {
  257. UndoManager.Remove[] newRing = new UndoManager.Remove[
  258. ring.length];
  259. int newCount = 0;
  260. for(int j = 0; j < ring.length; j++)
  261. {
  262. int index;
  263. if(j < count)
  264. index = count - j - 1;
  265. else
  266. index = count + ring.length - j - 1;
  267. if(i == index)
  268. {
  269. ring[index].inKillRing = false;
  270. continue;
  271. }
  272. newRing[newCount++] = ring[index];
  273. }
  274. ring = newRing;
  275. count = newCount;
  276. wrap = false;
  277. }
  278. else
  279. {
  280. System.arraycopy(ring,i + 1,ring,i,count - i - 1);
  281. count--;
  282. }
  283. } //}}}
  284. //}}}
  285. //{{{ Private members
  286. private static long killRingModTime;
  287. private KillRing() {}
  288. //}}}
  289. //{{{ RingListModel class
  290. static class RingListModel implements ListModel
  291. {
  292. public void addListDataListener(ListDataListener listener)
  293. {
  294. }
  295. public void removeListDataListener(ListDataListener listener)
  296. {
  297. }
  298. public Object getElementAt(int index)
  299. {
  300. UndoManager.Remove rem;
  301. if(wrap)
  302. {
  303. if(index < count)
  304. rem = ring[count - index - 1];
  305. else
  306. rem = ring[count + ring.length - index - 1];
  307. }
  308. else
  309. rem = ring[count - index - 1];
  310. return rem;
  311. }
  312. public int getSize()
  313. {
  314. if(wrap)
  315. return ring.length;
  316. else
  317. return count;
  318. }
  319. } //}}}
  320. //{{{ KillRingHandler class
  321. static class KillRingHandler extends HandlerBase
  322. {
  323. List list = new LinkedList();
  324. public Object resolveEntity(String publicId, String systemId)
  325. {
  326. if("killring.dtd".equals(systemId))
  327. {
  328. // this will result in a slight speed up, since we
  329. // don't need to read the DTD anyway, as AElfred is
  330. // non-validating
  331. return new StringReader("<!-- -->");
  332. }
  333. return null;
  334. }
  335. public void doctypeDecl(String name, String publicId,
  336. String systemId) throws Exception
  337. {
  338. if("KILLRING".equals(name))
  339. return;
  340. Log.log(Log.ERROR,this,"killring.xml: DOCTYPE must be KILLRING");
  341. }
  342. public void endElement(String name)
  343. {
  344. if(name.equals("ENTRY"))
  345. {
  346. list.add(new UndoManager.Remove(null,0,0,charData));
  347. }
  348. }
  349. public void charData(char[] ch, int start, int length)
  350. {
  351. charData = new String(ch,start,length);
  352. }
  353. private String charData;
  354. } //}}}
  355. }