KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > core > internal > resources > CharsetManager


1 /*******************************************************************************
2  * Copyright (c) 2004, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.core.internal.resources;
12
13 import java.util.*;
14 import org.eclipse.core.internal.utils.Messages;
15 import org.eclipse.core.internal.utils.Policy;
16 import org.eclipse.core.resources.*;
17 import org.eclipse.core.runtime.*;
18 import org.eclipse.core.runtime.jobs.ISchedulingRule;
19 import org.eclipse.core.runtime.jobs.Job;
20 import org.osgi.framework.Bundle;
21 import org.osgi.service.prefs.BackingStoreException;
22 import org.osgi.service.prefs.Preferences;
23
24 /**
25  * Manages user-defined encodings as preferences in the project content area.
26  *
27  * @since 3.0
28  */

29 public class CharsetManager implements IManager {
30     /**
31      * This job implementation is used to allow the resource change listener
32      * to schedule operations that need to modify the workspace.
33      */

34     private class CharsetManagerJob extends Job {
35         private static final int CHARSET_UPDATE_DELAY = 500;
36         private List asyncChanges = new ArrayList();
37
38         public CharsetManagerJob() {
39             super(Messages.resources_charsetUpdating);
40             setSystem(true);
41             setPriority(Job.INTERACTIVE);
42         }
43
44         public void addChanges(Set newChanges) {
45             if (newChanges.isEmpty())
46                 return;
47             synchronized (asyncChanges) {
48                 asyncChanges.addAll(newChanges);
49                 asyncChanges.notify();
50             }
51             schedule(CHARSET_UPDATE_DELAY);
52         }
53
54         public IProject getNextChange() {
55             synchronized (asyncChanges) {
56                 return asyncChanges.isEmpty() ? null : (IProject) asyncChanges.remove(asyncChanges.size() - 1);
57             }
58         }
59
60         /* (non-Javadoc)
61          * @see org.eclipse.core.internal.jobs.InternalJob#run(org.eclipse.core.runtime.IProgressMonitor)
62          */

63         protected IStatus run(IProgressMonitor monitor) {
64             MultiStatus result = new MultiStatus(ResourcesPlugin.PI_RESOURCES, IResourceStatus.FAILED_SETTING_CHARSET, Messages.resources_updatingEncoding, null);
65             monitor = Policy.monitorFor(monitor);
66             try {
67                 monitor.beginTask(Messages.resources_charsetUpdating, Policy.totalWork);
68                 final ISchedulingRule rule = workspace.getRuleFactory().modifyRule(workspace.getRoot());
69                 try {
70                     workspace.prepareOperation(rule, monitor);
71                     workspace.beginOperation(true);
72                     IProject next;
73                     while ((next = getNextChange()) != null) {
74                         //just exit if the system is shutting down or has been shut down
75
//it is too late to change the workspace at this point anyway
76
if (systemBundle.getState() != Bundle.ACTIVE)
77                             return Status.OK_STATUS;
78                         try {
79                             if (next.isAccessible()) {
80                                 Preferences projectPrefs = getPreferences(next, false);
81                                 if (projectPrefs != null)
82                                     projectPrefs.flush();
83                             }
84                         } catch (BackingStoreException e) {
85                             // we got an error saving
86
String JavaDoc detailMessage = Messages.resources_savingEncoding;
87                             result.add(new ResourceStatus(IResourceStatus.FAILED_SETTING_CHARSET, next.getFullPath(), detailMessage, e));
88                         }
89                     }
90                     monitor.worked(Policy.opWork);
91                 } catch (OperationCanceledException e) {
92                     workspace.getWorkManager().operationCanceled();
93                     throw e;
94                 } finally {
95                     workspace.endOperation(rule, true, Policy.subMonitorFor(monitor, Policy.endOpWork));
96                 }
97             } catch (CoreException ce) {
98                 return ce.getStatus();
99             } finally {
100                 monitor.done();
101             }
102             return result;
103         }
104
105         /* (non-Javadoc)
106          * @see org.eclipse.core.runtime.jobs.Job#shouldRun()
107          */

108         public boolean shouldRun() {
109             synchronized (asyncChanges) {
110                 return !asyncChanges.isEmpty();
111             }
112         }
113     }
114
115     class Listener implements IResourceChangeListener {
116
117         private void processEntryChanges(IResourceDelta projectDelta, Set projectsToSave) {
118             // check each resource with user-set encoding to see if it has
119
// been moved/deleted
120
boolean resourceChanges = false;
121             IProject currentProject = (IProject) projectDelta.getResource();
122             Preferences projectPrefs = getPreferences(currentProject, false);
123             if (projectPrefs == null)
124                 // no preferences for this project, just bail
125
return;
126             String JavaDoc[] affectedResources;
127             try {
128                 affectedResources = projectPrefs.keys();
129             } catch (BackingStoreException e) {
130                 // problems with the project scope... we gonna miss the changes (but will log)
131
String JavaDoc message = Messages.resources_readingEncoding;
132                 Policy.log(new ResourceStatus(IResourceStatus.FAILED_GETTING_CHARSET, currentProject.getFullPath(), message, e));
133                 return;
134             }
135             for (int i = 0; i < affectedResources.length; i++) {
136                 IResourceDelta memberDelta = projectDelta.findMember(new Path(affectedResources[i]));
137                 // no changes for the given resource
138
if (memberDelta == null)
139                     continue;
140                 if (memberDelta.getKind() == IResourceDelta.REMOVED) {
141                     resourceChanges = true;
142                     // remove the setting for the original location - save its value though
143
String JavaDoc currentValue = projectPrefs.get(affectedResources[i], null);
144                     projectPrefs.remove(affectedResources[i]);
145                     if ((memberDelta.getFlags() & IResourceDelta.MOVED_TO) != 0) {
146                         // if moving, copy the setting for the new location
147
IProject targetProject = workspace.getRoot().getProject(memberDelta.getMovedToPath().segment(0));
148                         Preferences targetPrefs = getPreferences(targetProject, true);
149                         targetPrefs.put(getKeyFor(memberDelta.getMovedToPath()), currentValue);
150                         if (targetProject != currentProject)
151                             projectsToSave.add(targetProject);
152                     }
153                 }
154             }
155             if (resourceChanges)
156                 projectsToSave.add(currentProject);
157         }
158
159         /**
160          * For any change to the encoding file or any resource with encoding
161          * set, just discard the cache for the corresponding project.
162          */

163         public void resourceChanged(IResourceChangeEvent event) {
164             IResourceDelta delta = event.getDelta();
165             if (delta == null)
166                 return;
167             IResourceDelta[] projectDeltas = delta.getAffectedChildren();
168             // process each project in the delta
169
Set projectsToSave = new HashSet();
170             for (int i = 0; i < projectDeltas.length; i++)
171                 //nothing to do if a project has been added/removed/moved
172
if (projectDeltas[i].getKind() == IResourceDelta.CHANGED && (projectDeltas[i].getFlags() & IResourceDelta.OPEN) == 0)
173                     processEntryChanges(projectDeltas[i], projectsToSave);
174             job.addChanges(projectsToSave);
175         }
176     }
177
178     public static final String JavaDoc ENCODING_PREF_NODE = "encoding"; //$NON-NLS-1$
179
private static final String JavaDoc PROJECT_KEY = "<project>"; //$NON-NLS-1$
180
private CharsetDeltaJob charsetListener;
181     CharsetManagerJob job;
182     private IResourceChangeListener listener;
183     protected final Bundle systemBundle = Platform.getBundle("org.eclipse.osgi"); //$NON-NLS-1$
184
Workspace workspace;
185
186     public CharsetManager(Workspace workspace) {
187         this.workspace = workspace;
188     }
189
190     /**
191      * Returns the charset explicitly set by the user for the given resource,
192      * or <code>null</code>. If no setting exists for the given resource and
193      * <code>recurse</code> is <code>true</code>, every parent up to the
194      * workspace root will be checked until a charset setting can be found.
195      *
196      * @param resourcePath the path for the resource
197      * @param recurse whether the parent should be queried
198      * @return the charset setting for the given resource
199      */

200     public String JavaDoc getCharsetFor(IPath resourcePath, boolean recurse) {
201         Assert.isLegal(resourcePath.segmentCount() >= 1);
202         IProject project = workspace.getRoot().getProject(resourcePath.segment(0));
203         Preferences encodingSettings = getPreferences(project, false);
204         if (encodingSettings == null)
205             // no preferences found - for performance reasons, short-circuit
206
// lookup by falling back to workspace's default setting
207
return recurse ? ResourcesPlugin.getEncoding() : null;
208         return internalGetCharsetFor(resourcePath, encodingSettings, recurse);
209     }
210
211     String JavaDoc getKeyFor(IPath resourcePath) {
212         return resourcePath.segmentCount() > 1 ? resourcePath.removeFirstSegments(1).toString() : PROJECT_KEY;
213     }
214
215     Preferences getPreferences(IProject project, boolean create) {
216         if (create)
217             // create all nodes down to the one we are interested in
218
return new ProjectScope(project).getNode(ResourcesPlugin.PI_RESOURCES).node(ENCODING_PREF_NODE);
219         // be careful looking up for our node so not to create any nodes as side effect
220
Preferences node = Platform.getPreferencesService().getRootNode().node(ProjectScope.SCOPE);
221         try {
222             //TODO once bug 90500 is fixed, should be as simple as this:
223
// String path = project.getName() + IPath.SEPARATOR + ResourcesPlugin.PI_RESOURCES + IPath.SEPARATOR + ENCODING_PREF_NODE;
224
// return node.nodeExists(path) ? node.node(path) : null;
225
// for now, take the long way
226
if (!node.nodeExists(project.getName()))
227                 return null;
228             node = node.node(project.getName());
229             if (!node.nodeExists(ResourcesPlugin.PI_RESOURCES))
230                 return null;
231             node = node.node(ResourcesPlugin.PI_RESOURCES);
232             if (!node.nodeExists(ENCODING_PREF_NODE))
233                 return null;
234             return node.node(ENCODING_PREF_NODE);
235         } catch (BackingStoreException e) {
236             // nodeExists failed
237
String JavaDoc message = Messages.resources_readingEncoding;
238             Policy.log(new ResourceStatus(IResourceStatus.FAILED_GETTING_CHARSET, project.getFullPath(), message, e));
239         }
240         return null;
241     }
242
243     private String JavaDoc internalGetCharsetFor(IPath resourcePath, Preferences encodingSettings, boolean recurse) {
244         String JavaDoc charset = encodingSettings.get(getKeyFor(resourcePath), null);
245         if (!recurse)
246             return charset;
247         while (charset == null && resourcePath.segmentCount() > 1) {
248             resourcePath = resourcePath.removeLastSegments(1);
249             charset = encodingSettings.get(getKeyFor(resourcePath), null);
250         }
251         // ensure we default to the workspace encoding if none is found
252
return charset == null ? ResourcesPlugin.getEncoding() : charset;
253     }
254
255     public void projectPreferencesChanged(IProject project) {
256         charsetListener.charsetPreferencesChanged(project);
257     }
258
259     public void setCharsetFor(IPath resourcePath, String JavaDoc newCharset) throws CoreException {
260         // for the workspace root we just set a preference in the instance scope
261
if (resourcePath.segmentCount() == 0) {
262             org.eclipse.core.runtime.Preferences resourcesPreferences = ResourcesPlugin.getPlugin().getPluginPreferences();
263             if (newCharset != null)
264                 resourcesPreferences.setValue(ResourcesPlugin.PREF_ENCODING, newCharset);
265             else
266                 resourcesPreferences.setToDefault(ResourcesPlugin.PREF_ENCODING);
267             ResourcesPlugin.getPlugin().savePluginPreferences();
268             return;
269         }
270         // for all other cases, we set a property in the corresponding project
271
IProject project = workspace.getRoot().getProject(resourcePath.segment(0));
272         Preferences encodingSettings = getPreferences(project, true);
273         if (newCharset == null || newCharset.trim().length() == 0)
274             encodingSettings.remove(getKeyFor(resourcePath));
275         else
276             encodingSettings.put(getKeyFor(resourcePath), newCharset);
277         try {
278             // disable the listener so we don't react to changes made by ourselves
279
charsetListener.setDisabled(true);
280             // save changes
281
encodingSettings.flush();
282         } catch (BackingStoreException e) {
283             String JavaDoc message = Messages.resources_savingEncoding;
284             throw new ResourceException(IResourceStatus.FAILED_SETTING_CHARSET, project.getFullPath(), message, e);
285         } finally {
286             charsetListener.setDisabled(false);
287         }
288
289     }
290
291     public void shutdown(IProgressMonitor monitor) {
292         workspace.removeResourceChangeListener(listener);
293         if (charsetListener != null)
294             charsetListener.shutdown();
295     }
296
297     public void startup(IProgressMonitor monitor) {
298         job = new CharsetManagerJob();
299         listener = new Listener();
300         workspace.addResourceChangeListener(listener, IResourceChangeEvent.POST_CHANGE);
301         charsetListener = new CharsetDeltaJob(workspace);
302         charsetListener.startup();
303     }
304 }
305
Popular Tags