KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > gjt > sp > jedit > buffer > KillRing


1 /*
2  * KillRing.java - Stores deleted text
3  * :tabSize=8:indentSize=8:noTabs=false:
4  * :folding=explicit:collapseFolds=1:
5  *
6  * Copyright (C) 2003, 2005 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.buffer;
24
25 import javax.swing.event.ListDataListener JavaDoc;
26 import java.util.*;
27
28 import org.xml.sax.Attributes JavaDoc;
29 import org.xml.sax.InputSource JavaDoc;
30 import org.xml.sax.helpers.DefaultHandler JavaDoc;
31
32 import org.gjt.sp.jedit.gui.MutableListModel;
33 import org.gjt.sp.util.XMLUtilities;
34
35 /**
36  * The kill ring retains deleted text. This class is a singleton -- only one
37  * kill ring is used for all of jEdit. Nothing prevents plugins from making their
38  * own kill rings for whatever reason, though.
39  */

40 public class KillRing implements MutableListModel
41 {
42     //{{{ getInstance() method
43
public static KillRing getInstance()
44     {
45         return killRing;
46     } //}}}
47

48     //{{{ getInstance() method
49
public static void setInstance(KillRing killRing)
50     {
51         KillRing.killRing = killRing;
52     } //}}}
53

54     //{{{ propertiesChanged() method
55
public void propertiesChanged(int historySize)
56     {
57         int newSize = Math.max(1, historySize);
58         if(ring == null)
59             ring = new UndoManager.Remove[newSize];
60         else if(newSize != ring.length)
61         {
62             UndoManager.Remove[] newRing = new UndoManager.Remove[
63                 newSize];
64             int newCount = Math.min(getSize(),newSize);
65             for(int i = 0; i < newCount; i++)
66             {
67                 newRing[i] = (UndoManager.Remove)getElementAt(i);
68             }
69             ring = newRing;
70             count = newCount;
71             wrap = false;
72         }
73
74         if(count == ring.length)
75         {
76             count = 0;
77             wrap = true;
78         }
79     } //}}}
80

81     public void load() {}
82
83     public void save() {}
84
85     //{{{ MutableListModel implementation
86
public void addListDataListener(ListDataListener JavaDoc listener) {}
87
88     public void removeListDataListener(ListDataListener JavaDoc listener) {}
89
90     //{{{ getElementAt() method
91
public Object JavaDoc getElementAt(int index)
92     {
93         return ring[virtualToPhysicalIndex(index)];
94     } //}}}
95

96     //{{{ getSize() method
97
public int getSize()
98     {
99         if(wrap)
100             return ring.length;
101         else
102             return count;
103     } //}}}
104

105     //{{{ removeElement() method
106
public boolean removeElement(Object JavaDoc value)
107     {
108         for(int i = 0; i < getSize(); i++)
109         {
110             if(ring[i].equals(value))
111             {
112                 remove(i);
113                 return true;
114             }
115         }
116         return false;
117     } //}}}
118

119     //{{{ insertElementAt() method
120
public void insertElementAt(Object JavaDoc value, int index)
121     {
122         /* This is not terribly efficient, but this method is only
123         called by the 'Paste Deleted' dialog where the performance
124         is not exactly vital */

125         remove(index);
126         add((UndoManager.Remove)value);
127     } //}}}
128

129     //}}}
130

131     //{{{ Package-private members
132

133     //{{{ changed() method
134
void changed(UndoManager.Remove rem)
135     {
136         if(rem.inKillRing)
137         {
138             // compare existing entries' hashcode with this
139
int length = (wrap ? ring.length : count);
140             int kill = -1;
141
142             for(int i = 0; i < length; i++)
143             {
144                 if(ring[i] != rem
145                     && ring[i].hashcode == rem.hashcode
146                     && ring[i].str.equals(rem.str))
147                 {
148                     // we don't want duplicate
149
// entries in the kill ring
150
kill = i;
151                     break;
152                 }
153             }
154
155             if(kill != -1)
156                 remove(kill);
157         }
158         else
159             add(rem);
160     } //}}}
161

162     //{{{ add() method
163
void add(UndoManager.Remove rem)
164     {
165         // compare existing entries' hashcode with this
166
int length = (wrap ? ring.length : count);
167         for(int i = 0; i < length; i++)
168         {
169             if(ring[i].hashcode == rem.hashcode)
170             {
171                 // strings might be equal!
172
if(ring[i].str.equals(rem.str))
173                 {
174                     // we don't want duplicate entries
175
// in the kill ring
176
return;
177                 }
178             }
179         }
180
181         // no duplicates, check for all-whitespace string
182
boolean allWhitespace = true;
183         for(int i = 0; i < rem.str.length(); i++)
184         {
185             if(!Character.isWhitespace(rem.str.charAt(i)))
186             {
187                 allWhitespace = false;
188                 break;
189             }
190         }
191
192         if(allWhitespace)
193             return;
194
195         rem.inKillRing = true;
196
197         if(ring[count] != null)
198             ring[count].inKillRing = false;
199
200         ring[count] = rem;
201         if(++count >= ring.length)
202         {
203             wrap = true;
204             count = 0;
205         }
206     } //}}}
207

208     //{{{ remove() method
209
void remove(int i)
210     {
211         if(wrap)
212         {
213             UndoManager.Remove[] newRing = new UndoManager.Remove[
214                 ring.length];
215             int newCount = 0;
216             for(int j = 0; j < ring.length; j++)
217             {
218                 int index = virtualToPhysicalIndex(j);
219
220                 if(i == index)
221                 {
222                     ring[index].inKillRing = false;
223                     continue;
224                 }
225
226                 newRing[newCount++] = ring[index];
227             }
228             ring = newRing;
229             count = newCount;
230             wrap = false;
231         }
232         else
233         {
234             System.arraycopy(ring,i + 1,ring,i,count - i - 1);
235             count--;
236         }
237     } //}}}
238

239     //}}}
240

241     //{{{ Private members
242
protected UndoManager.Remove[] ring;
243     protected int count;
244     protected boolean wrap;
245     protected long killRingModTime;
246     private static KillRing killRing = new KillRing();
247
248     //{{{ virtualToPhysicalIndex() method
249
/**
250      * Since the kill ring has a wrap-around representation, we need to
251      * convert user-visible indices to actual indices in the array.
252      */

253     private int virtualToPhysicalIndex(int index)
254     {
255         if(wrap)
256         {
257             if(index < count)
258                 return count - index - 1;
259             else
260                 return count + ring.length - index - 1;
261         }
262         else
263             return count - index - 1;
264     } //}}}
265

266     //}}}
267

268     //{{{ KillRingHandler class
269
public static class KillRingHandler extends DefaultHandler JavaDoc
270     {
271         public List<UndoManager.Remove> list = new LinkedList<UndoManager.Remove>();
272
273         public InputSource JavaDoc resolveEntity(String JavaDoc publicId, String JavaDoc systemId)
274         {
275             return XMLUtilities.findEntity(systemId, "killring.dtd", getClass());
276         }
277
278         public void startElement(String JavaDoc uri, String JavaDoc localName,
279                      String JavaDoc qName, Attributes JavaDoc attrs)
280         {
281             inEntry = qName.equals("ENTRY");
282         }
283
284         public void endElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc name)
285         {
286             if(name.equals("ENTRY"))
287             {
288                 list.add(new UndoManager.Remove(null,0,0,charData.toString()));
289                 inEntry = false;
290                 charData.setLength(0);
291             }
292         }
293
294         public void characters(char[] ch, int start, int length)
295         {
296             if (inEntry)
297                 charData.append(ch, start, length);
298         }
299
300         private StringBuffer JavaDoc charData = new StringBuffer JavaDoc();
301         private boolean inEntry;
302     } //}}}
303
}
304
Popular Tags