Improve error handling in EGit UI
[egit.git] / org.eclipse.egit.ui / src / org / eclipse / egit / ui / internal / repository / RepositoryPropertySource.java
blob454506080a8d1e259ca1a180ada284bb86dda73f
1 /*******************************************************************************
2 * Copyright (c) 2010 SAP AG.
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
8 * Contributors:
9 * Mathias Kinzler (SAP AG) - initial implementation
10 *******************************************************************************/
11 package org.eclipse.egit.ui.internal.repository;
13 import java.io.File;
14 import java.io.IOException;
15 import java.util.ArrayList;
16 import java.util.List;
17 import java.util.Set;
18 import java.util.StringTokenizer;
20 import org.eclipse.core.runtime.preferences.InstanceScope;
21 import org.eclipse.egit.core.Activator;
22 import org.eclipse.egit.ui.UIText;
23 import org.eclipse.jface.action.Action;
24 import org.eclipse.jface.action.ActionContributionItem;
25 import org.eclipse.jface.action.IAction;
26 import org.eclipse.jface.window.Window;
27 import org.eclipse.jgit.errors.ConfigInvalidException;
28 import org.eclipse.jgit.lib.Config;
29 import org.eclipse.jgit.lib.FileBasedConfig;
30 import org.eclipse.jgit.lib.Repository;
31 import org.eclipse.jgit.lib.RepositoryConfig;
32 import org.eclipse.jgit.util.SystemReader;
33 import org.eclipse.ui.IActionBars;
34 import org.eclipse.ui.preferences.ScopedPreferenceStore;
35 import org.eclipse.ui.views.properties.IPropertyDescriptor;
36 import org.eclipse.ui.views.properties.IPropertySource;
37 import org.eclipse.ui.views.properties.IPropertySource2;
38 import org.eclipse.ui.views.properties.PropertyDescriptor;
39 import org.eclipse.ui.views.properties.PropertySheetPage;
40 import org.eclipse.ui.views.properties.TextPropertyDescriptor;
42 /**
43 * Properties for repository configuration
46 public class RepositoryPropertySource implements IPropertySource,
47 IPropertySource2 {
49 private static final String USER_ID_PREFIX = "user"; //$NON-NLS-1$
51 private static final String REPO_ID_PREFIX = "repo"; //$NON-NLS-1$
53 private static final String EFFECTIVE_ID_PREFIX = "effe"; //$NON-NLS-1$
55 private static final String PREFERENCE_KEYS = "RepositoryPropertySource.ConfiguredKeys"; //$NON-NLS-1$
57 private Action configureKeyAction;
59 private Action modeToggleAction;
61 private Action restoreKeyAction;
63 private final PropertySheetPage myPage;
65 private final FileBasedConfig userHomeConfig;
67 private final FileBasedConfig repositoryConfig;
69 private final RepositoryConfig effectiveConfig;
71 /**
72 * @param rep
73 * the repository
74 * @param page
76 public RepositoryPropertySource(Repository rep, PropertySheetPage page) {
78 myPage = page;
80 makeActions();
81 addActions();
83 effectiveConfig = rep.getConfig();
84 userHomeConfig = SystemReader.getInstance().openUserConfig();
85 // TODO constant?
86 File configFile = new File(rep.getDirectory(), "config"); //$NON-NLS-1$
87 repositoryConfig = new FileBasedConfig(configFile);
89 try {
90 effectiveConfig.load();
91 userHomeConfig.load();
92 repositoryConfig.load();
93 } catch (IOException e) {
94 showExceptionMessage(e);
95 } catch (ConfigInvalidException e) {
96 showExceptionMessage(e);
100 private void makeActions() {
102 configureKeyAction = new Action(
103 UIText.RepositoryPropertySource_ConfigureKeysAction) {
105 @Override
106 public String getId() {
107 return "ConfigKeyActionId"; //$NON-NLS-1$
110 @Override
111 public void run() {
112 ConfigureKeysDialog dlg = new ConfigureKeysDialog(myPage
113 .getSite().getShell(), getConfiguredKeys());
114 if (dlg.open() == Window.OK)
115 try {
116 setConfiguredKeys(dlg.getActiveKeys());
117 myPage.refresh();
118 } catch (IOException e) {
119 showExceptionMessage(e);
126 modeToggleAction = new Action(
127 UIText.RepositoryPropertySource_EffectiveConfigurationAction) {
128 // TODO icon
129 @Override
130 public String getId() {
131 return "ViewModeToggle"; //$NON-NLS-1$
134 @Override
135 public void run() {
136 myPage.refresh();
139 @Override
140 public int getStyle() {
141 return IAction.AS_CHECK_BOX;
146 restoreKeyAction = new Action(
147 UIText.RepositoryPropertySource_RestoreStandardAction) {
149 @Override
150 public String getId() {
151 return "RestoreKeys"; //$NON-NLS-1$
154 @Override
155 public void run() {
156 try {
157 setConfiguredKeys(new ArrayList<String>());
158 myPage.refresh();
159 } catch (IOException e) {
160 showExceptionMessage(e);
167 private void addActions() {
169 boolean refreshToolbar = false;
170 IActionBars bars = myPage.getSite().getActionBars();
172 if (bars.getToolBarManager().find(modeToggleAction.getId()) == null) {
173 bars.getToolBarManager().add(modeToggleAction);
174 refreshToolbar = true;
177 if (bars.getMenuManager().find(configureKeyAction.getId()) == null)
178 bars.getMenuManager().add(configureKeyAction);
180 if (bars.getMenuManager().find(restoreKeyAction.getId()) == null)
181 bars.getMenuManager().add(restoreKeyAction);
183 if (refreshToolbar)
184 bars.getToolBarManager().update(false);
187 private List<String> getConfiguredKeys() {
189 List<String> result = new ArrayList<String>();
190 ScopedPreferenceStore store = new ScopedPreferenceStore(
191 new InstanceScope(), Activator.getPluginId());
192 String keys = store.getString(PREFERENCE_KEYS);
193 if (keys.length() > 0) {
194 StringTokenizer tok = new StringTokenizer(keys, " "); //$NON-NLS-1$
195 while (tok.hasMoreTokens()) {
196 result.add(tok.nextToken());
198 } else {
199 result.addAll(ConfigureKeysDialog.standardKeys);
201 return result;
204 private void setConfiguredKeys(List<String> keys) throws IOException {
206 StringBuilder sb = new StringBuilder();
207 for (String key : keys) {
208 sb.append(key);
209 sb.append(" "); //$NON-NLS-1$
211 ScopedPreferenceStore store = new ScopedPreferenceStore(
212 new InstanceScope(), Activator.getPluginId());
213 store.putValue(PREFERENCE_KEYS, sb.toString());
214 store.save();
218 private Object getValueFromConfig(Config config, String keyString) {
220 StringTokenizer tok = new StringTokenizer(keyString, "."); //$NON-NLS-1$
222 String section;
223 String subsection;
224 String name;
226 String[] valueList = null;
227 if (tok.countTokens() == 2) {
228 section = tok.nextToken();
229 subsection = null;
230 name = tok.nextToken();
231 } else if (tok.countTokens() == 3) {
232 section = tok.nextToken();
233 subsection = tok.nextToken();
234 name = tok.nextToken();
235 } else {
236 // TODO exception?
237 return null;
240 valueList = config.getStringList(section, subsection, name);
242 if (valueList == null || valueList.length == 0)
243 return null;
245 if (valueList.length == 1) {
246 return valueList[0];
249 StringBuilder sb = new StringBuilder();
250 for (String value: valueList){
251 sb.append('[');
252 sb.append(value);
253 sb.append(']');
256 return sb.toString();
260 public Object getEditableValue() {
261 return null;
264 public IPropertyDescriptor[] getPropertyDescriptors() {
266 // initFromConfig();
268 try {
269 userHomeConfig.load();
270 repositoryConfig.load();
271 effectiveConfig.load();
272 } catch (IOException e) {
273 showExceptionMessage(e);
274 } catch (ConfigInvalidException e) {
275 showExceptionMessage(e);
278 List<IPropertyDescriptor> resultList = new ArrayList<IPropertyDescriptor>();
280 List<String> configuredKeys = getConfiguredKeys();
282 boolean effectiveMode = false;
284 ActionContributionItem item = (ActionContributionItem) myPage.getSite()
285 .getActionBars().getToolBarManager().find(
286 modeToggleAction.getId());
287 if (item != null) {
288 effectiveMode = ((Action) item.getAction()).isChecked();
291 if (effectiveMode) {
292 for (String key : configuredKeys) {
294 for (String sub : getSubSections(effectiveConfig, key)) {
295 PropertyDescriptor desc = new PropertyDescriptor(
296 EFFECTIVE_ID_PREFIX + sub, sub);
298 desc
299 .setCategory(UIText.RepositoryPropertySource_EffectiveConfigurationCategory);
300 resultList.add(desc);
304 } else {
306 String categoryString = UIText.RepositoryPropertySource_GlobalConfigurationCategory
307 + userHomeConfig.getFile().getAbsolutePath();
308 for (String key : configuredKeys) {
310 // no remote configuration globally....
311 if (key.startsWith(RepositoriesView.REMOTE + ".")) //$NON-NLS-1$
312 continue;
314 for (String sub : getSubSections(effectiveConfig, key)) {
315 TextPropertyDescriptor desc = new TextPropertyDescriptor(
316 USER_ID_PREFIX + sub, sub);
317 desc.setCategory(categoryString);
318 resultList.add(desc);
321 categoryString = UIText.RepositoryPropertySource_RepositoryConfigurationCategory
322 + repositoryConfig.getFile().getAbsolutePath();
324 boolean editable = true;
326 for (String key : configuredKeys) {
328 // remote stuff is not configurable
329 editable = !key.startsWith("remote"); //$NON-NLS-1$
331 for (String sub : getSubSections(effectiveConfig, key)) {
332 PropertyDescriptor desc;
333 if (editable)
334 desc = new TextPropertyDescriptor(REPO_ID_PREFIX + sub,
335 sub);
336 else
337 desc = new PropertyDescriptor(REPO_ID_PREFIX + sub, sub);
338 desc.setCategory(categoryString);
339 resultList.add(desc);
344 return resultList.toArray(new IPropertyDescriptor[0]);
347 private List<String> getSubSections(Config configuration, String key) {
349 List<String> result = new ArrayList<String>();
351 if (key.indexOf(".?.") < 0) { //$NON-NLS-1$
352 result.add(key);
353 return result;
356 StringTokenizer stok = new StringTokenizer(key, "."); //$NON-NLS-1$
357 if (stok.countTokens() == 3) {
358 String section = stok.nextToken();
359 String subsection = stok.nextToken();
360 String name = stok.nextToken();
361 if (subsection.equals("?")) { //$NON-NLS-1$
362 Set<String> subs = configuration.getSubsections(section);
363 for (String sub : subs)
364 result.add(section + "." + sub + "." + name); //$NON-NLS-1$ //$NON-NLS-2$
365 return result;
366 } else {
367 result.add(key);
370 return result;
373 public Object getPropertyValue(Object id) {
374 String actId = ((String) id);
375 Object value = null;
376 if (actId.startsWith(USER_ID_PREFIX)) {
377 value = getValueFromConfig(userHomeConfig, actId.substring(4));
378 } else if (actId.startsWith(REPO_ID_PREFIX)) {
379 value = getValueFromConfig(repositoryConfig, actId.substring(4));
380 } else if (actId.startsWith(EFFECTIVE_ID_PREFIX)) {
381 value = getValueFromConfig(effectiveConfig, actId.substring(4));
383 if (value == null)
384 // the text editor needs this to work
385 return ""; //$NON-NLS-1$
387 return value;
390 public boolean isPropertySet(Object id) {
391 String actId = ((String) id);
392 Object value = null;
393 if (actId.startsWith(USER_ID_PREFIX)) {
394 value = getValueFromConfig(userHomeConfig, actId.substring(4));
395 } else if (actId.startsWith(REPO_ID_PREFIX)) {
396 value = getValueFromConfig(repositoryConfig, actId.substring(4));
397 } else if (actId.startsWith(EFFECTIVE_ID_PREFIX)) {
398 value = getValueFromConfig(effectiveConfig, actId.substring(4));
400 return value != null;
403 public void resetPropertyValue(Object id) {
404 setPropertyValue(id, null);
407 public void setPropertyValue(Object id, Object value) {
409 String actId = (String) id;
410 try {
411 if (actId.startsWith(USER_ID_PREFIX)) {
412 setConfigValue(userHomeConfig, actId.substring(4),
413 (String) value);
415 if (actId.startsWith(REPO_ID_PREFIX)) {
416 setConfigValue(repositoryConfig, actId.substring(4),
417 (String) value);
419 } catch (IOException e) {
420 showExceptionMessage(e);
425 public boolean isPropertyResettable(Object id) {
426 return isPropertySet(id);
429 private void setConfigValue(FileBasedConfig configuration, String key,
430 String value) throws IOException {
431 // we un-set empty strings, as the config API does not allow to
432 // distinguish this case
433 // (null is returned, even if the value is set to "", but in the
434 // effective configuration
435 // this results in shadowing of the base configured values
436 StringTokenizer tok = new StringTokenizer(key, "."); //$NON-NLS-1$
437 if (tok.countTokens() == 2) {
438 if (value == null || value.length() == 0) {
439 configuration.unset(tok.nextToken(), null, tok.nextToken());
440 } else {
441 configuration.setString(tok.nextToken(), null, tok.nextToken(),
442 value);
445 if (tok.countTokens() == 3) {
446 if (value == null || value.length() == 0) {
447 configuration.unset(tok.nextToken(), tok.nextToken(), tok
448 .nextToken());
449 } else {
450 configuration.setString(tok.nextToken(), tok.nextToken(), tok
451 .nextToken(), value);
455 configuration.save();
458 private void showExceptionMessage(Exception e) {
459 org.eclipse.egit.ui.Activator.handleError(UIText.RepositoryPropertySource_ErrorHeader, e, true);