1 /*******************************************************************************
2  * Copyright (c) 2000, 2015 IBM Corporation and others.
3  *
4  * This program and the accompanying materials
5  * are made available under the terms of the Eclipse Public License 2.0
6  * which accompanies this distribution, and is available at
7  * https://www.eclipse.org/legal/epl-2.0/
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  *     IBM Corporation - initial API and implementation
13  *******************************************************************************/
14 package org.eclipse.help.internal.base;
15 
16 import java.util.ArrayList;
17 import java.util.Observable;
18 import java.util.StringTokenizer;
19 
20 import org.eclipse.core.runtime.Platform;
21 import org.eclipse.core.runtime.preferences.IEclipsePreferences;
22 import org.eclipse.core.runtime.preferences.InstanceScope;
23 import org.eclipse.help.IHelpResource;
24 import org.eclipse.help.internal.base.util.TString;
25 import org.osgi.service.prefs.BackingStoreException;
26 
27 /**
28  * Code for bookmark management has been moved here so that it can be shared
29  * between the web app and the help view. The manager implements Observable so
30  * that views can be notified on bookmark changes. The webapp does not use this
31  * feature.
32  *
33  * @since 3.1
34  */
35 public class BookmarkManager extends Observable {
36 	// all bookmarks removed
37 	public static final int REMOVE_ALL = 1;
38 
39 	// bookmark added
40 	public static final int ADD = 2;
41 
42 	// bookmark removed
43 	public static final int REMOVE = 3;
44 
45 	// bookmark changed
46 	public static final int CHANGE = 4;
47 
48 	// everything changed (by the webapp)
49 	public static final int WORLD_CHANGED = 5;
50 
51 	private ArrayList<Bookmark> bookmarks;
52 
53 	public static class Bookmark implements IHelpResource {
54 		private String label;
55 
56 		private String href;
57 
Bookmark(String label, String href)58 		public Bookmark(String label, String href) {
59 			this.label = label;
60 			this.href = href;
61 		}
62 
63 		@Override
getHref()64 		public String getHref() {
65 			return href;
66 		}
67 
68 		@Override
getLabel()69 		public String getLabel() {
70 			return label;
71 		}
72 
73 		@Override
equals(Object object)74 		public boolean equals(Object object) {
75 			if (object == null)
76 				return false;
77 			if (object == this)
78 				return true;
79 			if (object instanceof Bookmark) {
80 				Bookmark b = (Bookmark) object;
81 				return b.href.equals(href) && b.label.equals(label);
82 			}
83 			return false;
84 		}
85 	}
86 
87 	public static class BookmarkEvent {
88 		private int type;
89 
90 		private Bookmark bookmark;
91 
BookmarkEvent(int type, Bookmark bookmark)92 		public BookmarkEvent(int type, Bookmark bookmark) {
93 			this.type = type;
94 			this.bookmark = bookmark;
95 		}
96 
getType()97 		public int getType() {
98 			return type;
99 		}
100 
getBookmark()101 		public Bookmark getBookmark() {
102 			return bookmark;
103 		}
104 	}
105 
BookmarkManager()106 	public BookmarkManager() {
107 	}
108 
close()109 	public void close() {
110 	}
111 
addBookmark(String bookmarkURL, String title)112 	public void addBookmark(String bookmarkURL, String title) {
113 		if (bookmarkURL != null && bookmarkURL.length() > 0
114 				&& !bookmarkURL.equals("about:blank")) { //$NON-NLS-1$
115 			if (title == null) {
116 				return;
117 			}
118 			String bookmarks = readBookmarks();
119 
120 			// separate the url and title by vertical bar
121 
122 			// check for duplicates
123 			if (bookmarks.contains("," + encode(bookmarkURL) + "|")) //$NON-NLS-1$ //$NON-NLS-2$
124 				return;
125 			bookmarks = bookmarks
126 					+ "," + encode(bookmarkURL) + "|" + encode(title); //$NON-NLS-1$ //$NON-NLS-2$
127 			saveBookmarks(bookmarks);
128 			Bookmark bookmark = new Bookmark(title, bookmarkURL);
129 			if (this.bookmarks!=null)
130 				this.bookmarks.add(bookmark);
131 			setChanged();
132 			notifyObservers(new BookmarkEvent(ADD, bookmark));
133 		}
134 	}
135 
removeBookmark(String bookmarkURL, String title)136 	public void removeBookmark(String bookmarkURL, String title) {
137 		removeBookmark(new Bookmark(title, bookmarkURL));
138 	}
139 
removeBookmark(Bookmark bookmark)140 	public void removeBookmark(Bookmark bookmark) {
141 		String bookmarkURL = bookmark.getHref();
142 		String title = bookmark.getLabel();
143 		if (bookmarkURL != null && bookmarkURL.length() > 0
144 				&& !bookmarkURL.equals("about:blank")) { //$NON-NLS-1$
145 			if (title == null) {
146 				return;
147 			}
148 			String bookmarks = readBookmarks();
149 			String removeString = "," + encode(bookmarkURL) + "|" + encode(title); //$NON-NLS-1$ //$NON-NLS-2$
150 			int i = bookmarks.indexOf(removeString);
151 			if (i == -1)
152 				return;
153 			bookmarks = bookmarks.substring(0, i)
154 					+ bookmarks.substring(i + removeString.length());
155 			saveBookmarks(bookmarks);
156 			if (this.bookmarks!=null)
157 				this.bookmarks.remove(bookmark);
158 			setChanged();
159 			notifyObservers(new BookmarkEvent(REMOVE, bookmark));
160 		}
161 	}
162 
removeAllBookmarks()163 	public void removeAllBookmarks() {
164 		saveBookmarks(""); //$NON-NLS-1$
165 		if (bookmarks!=null)
166 			bookmarks.clear();
167 		setChanged();
168 		notifyObservers(new BookmarkEvent(REMOVE_ALL, null));
169 	}
170 
getBookmarks()171 	public IHelpResource[] getBookmarks() {
172 		if (bookmarks==null) {
173 			String value = readBookmarks();
174 			StringTokenizer tokenizer = new StringTokenizer(value, ","); //$NON-NLS-1$
175 			bookmarks = new ArrayList<>();
176 			while (tokenizer.hasMoreTokens()) {
177 				String bookmark = tokenizer.nextToken();
178 				// url and title are separated by vertical bar
179 				int separator = bookmark.indexOf('|');
180 				String label = decode(bookmark.substring(separator + 1));
181 				String href = separator < 0 ? "" //$NON-NLS-1$
182 					: decode(bookmark.substring(0, separator));
183 				bookmarks.add(new Bookmark(label, href));
184 			}
185 		}
186 		return bookmarks.toArray(new IHelpResource[bookmarks.size()]);
187 	}
188 
189 	/**
190 	 * Ensures that string does not contains ',' or '|' characters.
191 	 *
192 	 * @param s
193 	 * @return String
194 	 */
195 	private static String encode(String s) {
196 		s = TString.change(s, "\\", "\\escape"); //$NON-NLS-1$ //$NON-NLS-2$
197 		s = TString.change(s, ",", "\\comma"); //$NON-NLS-1$ //$NON-NLS-2$
198 		return TString.change(s, "|", "\\pipe"); //$NON-NLS-1$ //$NON-NLS-2$
199 	}
200 
201 	private static String decode(String s) {
202 		s = TString.change(s, "\\pipe", "|"); //$NON-NLS-1$ //$NON-NLS-2$
203 		s = TString.change(s, "\\comma", ","); //$NON-NLS-1$ //$NON-NLS-2$
204 		return TString.change(s, "\\escape", "\\"); //$NON-NLS-1$ //$NON-NLS-2$
205 	}
206 
207 	private String readBookmarks() {
208 		return Platform.getPreferencesService().getString(HelpBasePlugin.PLUGIN_ID, BaseHelpSystem.BOOKMARKS, "", null); //$NON-NLS-1$
209 	}
210 
211 	private void saveBookmarks(String bookmarks) {
212 		IEclipsePreferences prefs = InstanceScope.INSTANCE.getNode(HelpBasePlugin.PLUGIN_ID);
213 		prefs.put(BaseHelpSystem.BOOKMARKS, bookmarks);
214 		try {
215 			prefs.flush();
216 		} catch (BackingStoreException e) {
217 		}
218 	}
219 
220 }
221