KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > netbeans > lib > editor > bookmarks > api > BookmarkList


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19
20 package org.netbeans.lib.editor.bookmarks.api;
21
22 import java.beans.PropertyChangeListener JavaDoc;
23 import java.beans.PropertyChangeSupport JavaDoc;
24 import java.util.ArrayList JavaDoc;
25 import java.util.List JavaDoc;
26 import javax.swing.text.Document JavaDoc;
27 import javax.swing.text.Element JavaDoc;
28 import org.netbeans.lib.editor.bookmarks.BookmarksApiPackageAccessor;
29 import org.netbeans.lib.editor.bookmarks.BookmarksSpiPackageAccessor;
30 import org.netbeans.lib.editor.bookmarks.spi.BookmarkImplementation;
31 import org.netbeans.lib.editor.bookmarks.spi.BookmarkManager;
32 import org.netbeans.lib.editor.bookmarks.spi.BookmarkManagerFactory;
33 import org.netbeans.lib.editor.bookmarks.spi.BookmarkManagerSupport;
34 import org.openide.util.Lookup;
35
36 /**
37  * Services around document bookmarks.
38  *
39  * @author Miloslav Metelka
40  * @version 1.00
41  */

42
43 public final class BookmarkList {
44     
45     private static BookmarkManagerFactory bookmarkManagerFactory;
46     
47     static {
48         BookmarksApiPackageAccessor.register(new ApiAccessor());
49         BookmarkManagerSupport.initPackageAccess();
50     }
51     
52     public static BookmarkList get(Document JavaDoc doc) {
53         synchronized (org.netbeans.modules.editor.bookmarks.PersistentBookmarks.class) {
54             BookmarkList bookmarkList = (BookmarkList)doc.getProperty(BookmarkList.class);
55             if (bookmarkList == null) {
56                 BookmarkManager mgr = getBookmarkManagerFactory().createBookmarkManager(doc);
57                 bookmarkList = new BookmarkList(doc, mgr);
58                 doc.putProperty(BookmarkList.class, bookmarkList);
59             }
60             return bookmarkList;
61         }
62     }
63     
64     private static BookmarkManagerFactory getBookmarkManagerFactory() {
65         if (bookmarkManagerFactory == null) {
66             bookmarkManagerFactory = (BookmarkManagerFactory)
67                 Lookup.getDefault().lookup(BookmarkManagerFactory.class);
68             assert (bookmarkManagerFactory != null) : "No BookmarkManagerFactory available"; // NOI18N
69
}
70         return bookmarkManagerFactory;
71     }
72
73     private static final String JavaDoc PROP_BOOKMARKS = "bookmarks";
74     
75     /**
76      * Document for which the bookmark list was created.
77      */

78     private Document JavaDoc doc;
79     
80     /**
81      * Manager of the bookmarks.
82      */

83     private BookmarkManager manager;
84     
85     /**
86      * Support for the manager.
87      */

88     private BookmarkManagerSupport managerSupport;
89     
90     /**
91      * List of bookmark instances.
92      */

93     private List JavaDoc bookmarks;
94
95     private final PropertyChangeSupport JavaDoc PCS = new PropertyChangeSupport JavaDoc(this);
96     
97     private BookmarkList(Document JavaDoc doc, BookmarkManager manager) {
98         if (doc == null) {
99             throw new NullPointerException JavaDoc("Document cannot be null"); // NOI18N
100
}
101         this.doc = doc;
102         this.bookmarks = new ArrayList JavaDoc();
103         this.manager = manager;
104         this.managerSupport = BookmarksSpiPackageAccessor.get().createBookmarkManagerSupport(this);
105         this.manager.init(managerSupport);
106     }
107
108     /**
109      * Get document on which this bookmark list operates.
110      *
111      * @return non-null document.
112      */

113     public Document JavaDoc getDocument() {
114         return doc;
115     }
116     
117     /**
118      * Total count of bookmarks managed by this bookmark list.
119      *
120      * @return >=0 total count of bookmarks.
121      */

122     public int getBookmarkCount() {
123         return bookmarks.size();
124     }
125     
126     /**
127      * Get bookmark at the specified index.
128      * <br>
129      * The bookmarks are ordered by increasing offset.
130      *
131      * @param index index of the bookmark in the list of bookmarks.
132      * @return non-null bookmark instance.
133      */

134     public Bookmark getBookmark(int index) {
135         return (Bookmark)bookmarks.get(index);
136     }
137
138     /**
139      * Get the first bookmark
140      * that has the offset greater than the specified offset.
141      *
142      * @param offset &gt;=-1 offset for searching of the next bookmark.
143      * The offset -1 searches for the first bookmark.
144      * @param wrapSearch if true then continue searching from the begining of document
145      * in case a bookmark was not found.
146      * @return valid bookmark or null if there is no bookmark satisfying the condition.
147      */

148     public Bookmark getNextBookmark(int offset, boolean wrapSearch) {
149         offset++;
150         checkOffsetNonNegative(offset);
151         int index = getBookmarkIndex(offset);
152         return (index < getBookmarkCount())
153             ? getBookmark(index)
154             : wrapSearch ? getNextBookmark(-1, false) : null;
155     }
156     
157     /**
158      * Get the first bookmark in backward direction
159      * that has the line index lower than the specified line index.
160      *
161      * @param offset &gt;=0 offset for searching of the previous bookmark.
162      * The offset <code>Integer.MAX_VALUE</code> searches for the last bookmark.
163      * @param wrapSearch if true then continue searching from the end of document
164      * in case a bookmark was not found.
165      * @return valid bookmark or null if there is no bookmark satisfying the condition.
166      */

167     public Bookmark getPreviousBookmark(int offset, boolean wrapSearch) {
168         checkOffsetNonNegative(offset);
169         int bookmarkCount = getBookmarkCount();
170         Bookmark bookmark; // result
171
if (bookmarkCount > 0) {
172             offset--; // search from previous offset
173
int index = getBookmarkIndex(offset);
174             if (index == bookmarkCount || (bookmark = getBookmark(index)).getOffset() != offset) {
175                 index--; // go below
176
if (index >= 0) {
177                     bookmark = getBookmark(index);
178                 } else { // prior first bookmark
179
if (wrapSearch) {
180                         bookmark = getPreviousBookmark(Integer.MAX_VALUE, false);
181                     } else { // no previous bookmark
182
bookmark = null;
183                     }
184                 }
185             } // else -> bookmark right at offset is assigned
186
} else { // no bookmarks available
187
bookmark = null;
188         }
189         return bookmark;
190     }
191
192     /**
193      * Get index of first bookmark that has the line index greater or equal
194      * to the requested offset.
195      * <br>
196      * Return <code>getBookmarkCount()</code> in case there is no such mark.
197      * <br>
198      * The algorithm uses binary search.
199      *
200      * @param offset offset by which the bookmarks will be searched.
201      * @return &gt;=0 and &lt;={@link #getBookmarkCount()} index of the first bookmark
202      * with the offset greater or equal to the requested one.
203      */

204     public int getBookmarkIndex(int offset) {
205         // Find next bookmark by binary search
206
int low = 0;
207         int high = getBookmarkCount() - 1;
208         
209         while (low <= high) {
210             int mid = (low + high) / 2;
211             int midOffset = getBookmark(mid).getOffset();
212             
213             if (midOffset < offset) {
214                 low = mid + 1;
215             } else if (midOffset > offset) {
216                 high = mid - 1;
217             } else { // bookmark right at the offset
218
// Goto first bookmark of possible ones at the same line
219
mid--;
220                 while (mid >= 0) {
221                     if (getBookmark(mid).getOffset() != offset) {
222                         break;
223                     }
224                     mid--;
225                 }
226                 mid++;
227                 return mid;
228             }
229         }
230         
231         return low;
232     }
233     
234     /**
235      * Create bookmark if it did not exist before at the line containing
236      * the given offset.
237      * <br>
238      * Drop the existing bookmark if it was already present for the line
239      * containing the given offset.
240      *
241      * @param offset offset on a line in the document for which the presence of bookmark
242      * should be checked. The bookmarks are checked in a line-wise way.
243      * @return bookmark that was either created or removed by the operation.
244      * Calling {@link Bookmark#isValid()} determines whether the returned
245      * bookmark was added or removed by the operation.
246      * <br>
247      * <code>null</code> is returned if the offset is above the end of document.
248      */

249     public Bookmark toggleLineBookmark(int offset) {
250         checkOffsetInDocument(offset);
251         Element JavaDoc lineRoot = doc.getDefaultRootElement();
252         int lineIndex = lineRoot.getElementIndex(offset);
253         Bookmark bookmark = null;
254         if (lineIndex < lineRoot.getElementCount()) {
255             Element JavaDoc lineElem = lineRoot.getElement(lineIndex);
256             int lineStartOffset = lineElem.getStartOffset();
257             int index = getBookmarkIndex(lineStartOffset);
258             if (index < getBookmarkCount() // valid bookmark
259
&& getBookmark(index).getOffset() < lineElem.getEndOffset() // inside line
260
) { // remove the existing bookmark
261
bookmark = removeBookmarkAtIndex(index);
262             } else { // add bookmark
263
bookmark = addBookmark(manager.createBookmarkImplementation(lineStartOffset));
264             }
265             // Save the bookmarks
266
manager.saveBookmarks();
267         }
268         return bookmark;
269     }
270     
271     /**
272      * Remove bookmark at the given index among the bookmarks.
273      *
274      * @param index index at which the bookmark should be removed.
275      * @return removed (and invalidated) bookmark
276      */

277     public Bookmark removeBookmarkAtIndex(int index) {
278         Bookmark bookmark = (Bookmark)bookmarks.remove(index);
279         bookmark.release();
280         PCS.firePropertyChange(PROP_BOOKMARKS, null, null);
281         return bookmark;
282     }
283     
284     /** Removes all bookmarks */
285     public void removeAllBookmarks(){
286         if (!bookmarks.isEmpty()) {
287             for (int i = 0; i<bookmarks.size(); i++){
288                 Bookmark bookmark = (Bookmark)bookmarks.get(i);
289                 bookmark.release();
290             }
291             bookmarks.clear();
292             PCS.firePropertyChange(PROP_BOOKMARKS, null, null);
293         }
294     }
295     
296     /**
297      * Get manager of this bookmark list. Used by SPI accessor.
298      */

299     BookmarkManager getManager() {
300         return manager;
301     }
302     
303     /**
304      * Add bookmark to this list.
305      * <br>
306      * Intended for SPI accessor only.
307      */

308     Bookmark addBookmark(BookmarkImplementation impl) {
309         // Compute the index from increased offset to ensure to add the bookmark
310
// after all the possible bookmarks with the same offset
311
Bookmark bookmark = new Bookmark(this, impl);
312         int index = getBookmarkIndex(impl.getOffset() + 1);
313         bookmarks.add(index, bookmark);
314         PCS.firePropertyChange(PROP_BOOKMARKS, null, null);
315         return bookmark;
316     }
317
318     private void checkOffsetNonNegative(int offset) {
319         if (offset < 0) {
320             throw new IndexOutOfBoundsException JavaDoc("offset=" + offset + " < 0"); // NOI18N
321
}
322     }
323     
324     private void checkOffsetInDocument(int offset) {
325         checkOffsetNonNegative(offset);
326         int docLen = doc.getLength();
327         if (offset > docLen) {
328             throw new IndexOutOfBoundsException JavaDoc("offset=" + offset // NOI18N
329
+ " > doc.getLength()=" + docLen); // NOI18N
330
}
331     }
332     
333     public String JavaDoc toString() {
334         return "Bookmarks: " + bookmarks; // NOI18N
335
}
336
337     void addPropertyChangeListener(PropertyChangeListener JavaDoc l) {
338         PCS.addPropertyChangeListener(l);
339     }
340     
341     void removePropertyChangeListener(PropertyChangeListener JavaDoc l) {
342         PCS.removePropertyChangeListener(l);
343     }
344     
345     /**
346      * Implementation of the class accessing package-private methods
347      * in the bookmarks API.
348      */

349     private static final class ApiAccessor extends BookmarksApiPackageAccessor {
350         
351         public BookmarkManager getBookmarkManager(BookmarkList bookmarkList) {
352             return bookmarkList.getManager();
353         }
354         
355         public BookmarkImplementation getBookmarkImplementation(Bookmark bookmark) {
356             return bookmark.getImplementation();
357         }
358
359         public Bookmark addBookmark(BookmarkList list, BookmarkImplementation impl) {
360             return list.addBookmark(impl);
361         }
362         
363         public void addBookmarkListPcl(BookmarkList list, PropertyChangeListener JavaDoc l) {
364             list.addPropertyChangeListener(l);
365         }
366
367         public void removeBookmarkListPcl(BookmarkList list, PropertyChangeListener JavaDoc l) {
368             list.removePropertyChangeListener(l);
369         }
370     } // End of ApiAccessor class
371
}
372
373
Popular Tags