PageRenderTime 49ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

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

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