Some Eclipse Foundation services are deprecated, or will be soon. Please ensure you've read this important communication.
View | Details | Raw Unified | Return to bug 244653 | Differences between
and this patch

Collapse All | Expand All

(-)src/org/eclipse/mylyn/internal/tasks/ui/editors/TaskEditorExtensions.java (-3 / +20 lines)
Lines 86-93 Link Here
86
		init();
86
		init();
87
		String id = taskRepository.getProperty(REPOSITORY_PROPERTY_EDITOR_EXTENSION);
87
		String id = taskRepository.getProperty(REPOSITORY_PROPERTY_EDITOR_EXTENSION);
88
		if (id == null) {
88
		if (id == null) {
89
			// TODO 3.1 disabled until bug 244653 is resolved
89
			id = getDefaultTaskEditorExtensionId(taskRepository);
90
			//id = getDefaultTaskEditorExtensionId(taskRepository);
91
		}
90
		}
92
		return id;
91
		return id;
93
	}
92
	}
Lines 96-104 Link Here
96
		repository.setProperty(REPOSITORY_PROPERTY_EDITOR_EXTENSION, editorExtensionId);
95
		repository.setProperty(REPOSITORY_PROPERTY_EDITOR_EXTENSION, editorExtensionId);
97
	}
96
	}
98
97
98
	/**
99
	 * Get the default task editor extension id for the given task repository
100
	 * 
101
	 * @param taskRepository
102
	 * @return the default task editor extension id or null if there is no default
103
	 */
99
	public static String getDefaultTaskEditorExtensionId(TaskRepository taskRepository) {
104
	public static String getDefaultTaskEditorExtensionId(TaskRepository taskRepository) {
105
		return getDefaultTaskEditorExtensionId(taskRepository.getConnectorKind());
106
	}
107
108
	/**
109
	 * Get the default task editor extension id for the given kind of connector
110
	 * 
111
	 * @param connectorKind
112
	 *            the kind of connector
113
	 * 
114
	 * @return the default task editor extension id or null if there is no default
115
	 */
116
	public static String getDefaultTaskEditorExtensionId(String connectorKind) {
100
		init();
117
		init();
101
		return associationByConnectorKind.get(taskRepository.getConnectorKind());
118
		return associationByConnectorKind.get(connectorKind);
102
	}
119
	}
103
120
104
	/**
121
	/**
(-)src/org/eclipse/mylyn/internal/tasks/ui/wizards/EditRepositoryWizard.java (-3 / +6 lines)
Lines 18-23 Link Here
18
import org.eclipse.jface.viewers.IStructuredSelection;
18
import org.eclipse.jface.viewers.IStructuredSelection;
19
import org.eclipse.jface.wizard.Wizard;
19
import org.eclipse.jface.wizard.Wizard;
20
import org.eclipse.mylyn.commons.core.StatusHandler;
20
import org.eclipse.mylyn.commons.core.StatusHandler;
21
import org.eclipse.mylyn.internal.tasks.core.LocalRepositoryConnector;
21
import org.eclipse.mylyn.internal.tasks.ui.RefactorRepositoryUrlOperation;
22
import org.eclipse.mylyn.internal.tasks.ui.RefactorRepositoryUrlOperation;
22
import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin;
23
import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin;
23
import org.eclipse.mylyn.tasks.core.TaskRepository;
24
import org.eclipse.mylyn.tasks.core.TaskRepository;
Lines 72-78 Link Here
72
73
73
			repository.flushAuthenticationCredentials();
74
			repository.flushAuthenticationCredentials();
74
75
75
			repository.setRepositoryUrl(newUrl);
76
			if (!repository.getConnectorKind().equals(LocalRepositoryConnector.CONNECTOR_KIND)) {
77
				repository.setRepositoryUrl(newUrl);
78
			}
76
			settingsPage.applyTo(repository);
79
			settingsPage.applyTo(repository);
77
			if (oldUrl != null && newUrl != null && !oldUrl.equals(newUrl)) {
80
			if (oldUrl != null && newUrl != null && !oldUrl.equals(newUrl)) {
78
				TasksUiPlugin.getRepositoryManager().notifyRepositoryUrlChanged(repository, oldUrl);
81
				TasksUiPlugin.getRepositoryManager().notifyRepositoryUrlChanged(repository, oldUrl);
Lines 90-97 Link Here
90
	@Override
93
	@Override
91
	public void addPages() {
94
	public void addPages() {
92
		AbstractRepositoryConnectorUi connectorUi = TasksUiPlugin.getConnectorUi(repository.getConnectorKind());
95
		AbstractRepositoryConnectorUi connectorUi = TasksUiPlugin.getConnectorUi(repository.getConnectorKind());
93
		// TODO 3.1 pass repository
96
94
		settingsPage = connectorUi.getSettingsPage(null);
97
		settingsPage = connectorUi.getSettingsPage(repository);
95
		if (settingsPage instanceof AbstractRepositorySettingsPage) {
98
		if (settingsPage instanceof AbstractRepositorySettingsPage) {
96
			((AbstractRepositorySettingsPage) settingsPage).setRepository(repository);
99
			((AbstractRepositorySettingsPage) settingsPage).setRepository(repository);
97
			((AbstractRepositorySettingsPage) settingsPage).setVersion(repository.getVersion());
100
			((AbstractRepositorySettingsPage) settingsPage).setVersion(repository.getVersion());
(-)src/org/eclipse/mylyn/tasks/ui/wizards/TaskAttachmentPage.java (-9 / +134 lines)
Lines 16-29 Link Here
16
import java.util.LinkedList;
16
import java.util.LinkedList;
17
import java.util.List;
17
import java.util.List;
18
18
19
import org.eclipse.jface.text.Document;
20
import org.eclipse.jface.text.ITextListener;
21
import org.eclipse.jface.text.TextEvent;
22
import org.eclipse.jface.text.source.AnnotationModel;
23
import org.eclipse.jface.text.source.IAnnotationAccess;
24
import org.eclipse.jface.text.source.SourceViewer;
19
import org.eclipse.jface.wizard.WizardPage;
25
import org.eclipse.jface.wizard.WizardPage;
20
import org.eclipse.mylyn.context.core.ContextCore;
26
import org.eclipse.mylyn.context.core.ContextCore;
21
import org.eclipse.mylyn.internal.provisional.commons.ui.CommonImages;
27
import org.eclipse.mylyn.internal.provisional.commons.ui.CommonImages;
22
import org.eclipse.mylyn.internal.tasks.core.data.FileTaskAttachmentSource;
28
import org.eclipse.mylyn.internal.tasks.core.data.FileTaskAttachmentSource;
29
import org.eclipse.mylyn.internal.tasks.ui.editors.AbstractHyperlinkTextPresentationManager;
30
import org.eclipse.mylyn.internal.tasks.ui.editors.EditorUtil;
31
import org.eclipse.mylyn.internal.tasks.ui.editors.HighlightingHyperlinkTextPresentationManager;
32
import org.eclipse.mylyn.internal.tasks.ui.editors.RepositoryTextViewer;
33
import org.eclipse.mylyn.internal.tasks.ui.editors.RepositoryTextViewerConfiguration;
34
import org.eclipse.mylyn.internal.tasks.ui.editors.TaskEditorExtensions;
35
import org.eclipse.mylyn.internal.tasks.ui.editors.TaskHyperlinkTextPresentationManager;
36
import org.eclipse.mylyn.internal.tasks.ui.editors.RepositoryTextViewerConfiguration.Mode;
37
import org.eclipse.mylyn.tasks.core.TaskRepository;
23
import org.eclipse.mylyn.tasks.core.data.TaskAttachmentMapper;
38
import org.eclipse.mylyn.tasks.core.data.TaskAttachmentMapper;
24
import org.eclipse.mylyn.tasks.core.data.TaskAttachmentModel;
39
import org.eclipse.mylyn.tasks.core.data.TaskAttachmentModel;
25
import org.eclipse.mylyn.tasks.ui.TasksUiImages;
40
import org.eclipse.mylyn.tasks.ui.TasksUiImages;
41
import org.eclipse.mylyn.tasks.ui.editors.AbstractTaskEditorExtension;
26
import org.eclipse.swt.SWT;
42
import org.eclipse.swt.SWT;
43
import org.eclipse.swt.events.DisposeEvent;
44
import org.eclipse.swt.events.DisposeListener;
27
import org.eclipse.swt.events.ModifyEvent;
45
import org.eclipse.swt.events.ModifyEvent;
28
import org.eclipse.swt.events.ModifyListener;
46
import org.eclipse.swt.events.ModifyListener;
29
import org.eclipse.swt.events.SelectionAdapter;
47
import org.eclipse.swt.events.SelectionAdapter;
Lines 36-41 Link Here
36
import org.eclipse.swt.widgets.Composite;
54
import org.eclipse.swt.widgets.Composite;
37
import org.eclipse.swt.widgets.Label;
55
import org.eclipse.swt.widgets.Label;
38
import org.eclipse.swt.widgets.Text;
56
import org.eclipse.swt.widgets.Text;
57
import org.eclipse.ui.PlatformUI;
58
import org.eclipse.ui.contexts.IContextActivation;
59
import org.eclipse.ui.contexts.IContextService;
60
import org.eclipse.ui.editors.text.EditorsUI;
61
import org.eclipse.ui.texteditor.AnnotationPreference;
62
import org.eclipse.ui.texteditor.DefaultMarkerAnnotationAccess;
63
import org.eclipse.ui.texteditor.MarkerAnnotationPreferences;
64
import org.eclipse.ui.texteditor.SourceViewerDecorationSupport;
39
65
40
/**
66
/**
41
 * A wizard page to enter details of a new attachment.
67
 * A wizard page to enter details of a new attachment.
Lines 43-48 Link Here
43
 * @author Jeff Pound
69
 * @author Jeff Pound
44
 * @author Mik Kersten
70
 * @author Mik Kersten
45
 * @author Steffen Pingel
71
 * @author Steffen Pingel
72
 * @author David Green task editor extension integration
46
 * @since 3.0
73
 * @since 3.0
47
 */
74
 */
48
public class TaskAttachmentPage extends WizardPage {
75
public class TaskAttachmentPage extends WizardPage {
Lines 62-68 Link Here
62
89
63
	private Button attachContextButton;
90
	private Button attachContextButton;
64
91
65
	private Text commentText;
92
	private SourceViewer comment;
66
93
67
	private Text descriptionText;
94
	private Text descriptionText;
68
95
Lines 80-85 Link Here
80
107
81
	private boolean first = true;
108
	private boolean first = true;
82
109
110
	private IContextActivation commentContext;
111
112
	private IContextService contextService;
113
83
	public TaskAttachmentPage(TaskAttachmentModel model) {
114
	public TaskAttachmentPage(TaskAttachmentModel model) {
84
		super("AttachmentDetails");
115
		super("AttachmentDetails");
85
		this.model = model;
116
		this.model = model;
Lines 118-131 Link Here
118
		Label label = new Label(composite, SWT.NONE);
149
		Label label = new Label(composite, SWT.NONE);
119
		label.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, false));
150
		label.setLayoutData(new GridData(SWT.LEFT, SWT.FILL, false, false));
120
		label.setText("Comment");
151
		label.setText("Comment");
121
		commentText = new Text(composite, SWT.V_SCROLL | SWT.BORDER | SWT.WRAP);
152
122
		commentText.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
153
		AbstractTaskEditorExtension extension = TaskEditorExtensions.getTaskEditorExtension(model.getTaskRepository());
123
		commentText.addModifyListener(new ModifyListener() {
154
		if (extension != null) {
124
			public void modifyText(ModifyEvent e) {
155
			// TODO: stack layout with preview
156
			comment = extension.createEditor(model.getTaskRepository(), composite, SWT.V_SCROLL | SWT.MULTI
157
					| SWT.BORDER);
158
			String contextId = extension.getEditorContextId();
159
			if (contextId != null) {
160
				// FIXME: keybindings don't work.  How do we use commands with a dialog/wizard?
161
				// related: http://dev.eclipse.org/newslists/news.eclipse.platform.rcp/msg14539.html
162
				contextService = (IContextService) PlatformUI.getWorkbench().getService(IContextService.class);
163
				if (contextService != null) {
164
					commentContext = contextService.activateContext(contextId);
165
				}
166
			}
167
		} else {
168
			comment = createDefaultEditor(composite, SWT.V_SCROLL | SWT.MULTI | SWT.BORDER);
169
		}
170
		configure(comment);
171
		comment.addTextListener(new ITextListener() {
172
			public void textChanged(TextEvent event) {
125
				apply();
173
				apply();
126
			}
174
			}
127
128
		});
175
		});
176
		comment.getControl().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 2, 1));
129
177
130
		new Label(composite, SWT.NONE).setText("Content Type");// .setBackground(parent.getBackground());
178
		new Label(composite, SWT.NONE).setText("Content Type");// .setBackground(parent.getBackground());
131
179
Lines 219-228 Link Here
219
		if (descriptionText != null) {
267
		if (descriptionText != null) {
220
			descriptionText.setFocus();
268
			descriptionText.setFocus();
221
		} else {
269
		} else {
222
			commentText.setFocus();
270
			comment.getTextWidget().setFocus();
223
		}
271
		}
224
	}
272
	}
225
273
274
	private RepositoryTextViewerConfiguration installHyperlinkPresenter(SourceViewer viewer) {
275
		RepositoryTextViewerConfiguration configuration = new RepositoryTextViewerConfiguration(
276
				model.getTaskRepository(), false);
277
		configuration.setMode(Mode.DEFAULT);
278
279
		// do not configure viewer, this has already been done in extension
280
281
		AbstractHyperlinkTextPresentationManager manager;
282
283
		manager = new HighlightingHyperlinkTextPresentationManager();
284
		manager.setHyperlinkDetectors(configuration.getDefaultHyperlinkDetectors(viewer, null));
285
		manager.install(viewer);
286
287
		manager = new TaskHyperlinkTextPresentationManager();
288
		manager.setHyperlinkDetectors(configuration.getDefaultHyperlinkDetectors(viewer, Mode.TASK));
289
		manager.install(viewer);
290
291
		return configuration;
292
	}
293
294
	private SourceViewer configure(final SourceViewer viewer) {
295
		// do this before setting the document to not require invalidating the presentation
296
		installHyperlinkPresenter(viewer);
297
298
		configureAsEditor(viewer, new Document());
299
300
		// enable cut/copy/paste
301
		EditorUtil.setTextViewer(viewer.getTextWidget(), viewer);
302
		viewer.setEditable(true);
303
304
		return viewer;
305
	}
306
307
	private void configureAsEditor(SourceViewer viewer, Document document) {
308
		AnnotationModel annotationModel = new AnnotationModel();
309
		viewer.showAnnotations(false);
310
		viewer.showAnnotationsOverview(false);
311
		IAnnotationAccess annotationAccess = new DefaultMarkerAnnotationAccess();
312
		final SourceViewerDecorationSupport support = new SourceViewerDecorationSupport(viewer, null, annotationAccess,
313
				EditorsUI.getSharedTextColors());
314
		Iterator<?> e = new MarkerAnnotationPreferences().getAnnotationPreferences().iterator();
315
		while (e.hasNext()) {
316
			support.setAnnotationPreference((AnnotationPreference) e.next());
317
		}
318
		support.install(EditorsUI.getPreferenceStore());
319
		viewer.getTextWidget().addDisposeListener(new DisposeListener() {
320
			public void widgetDisposed(DisposeEvent e) {
321
				support.uninstall();
322
			}
323
		});
324
		//viewer.getTextWidget().setIndent(2);
325
		viewer.setDocument(document, annotationModel);
326
	}
327
328
	private SourceViewer createDefaultEditor(Composite parent, int styles) {
329
		TaskRepository taskRepository = model.getTaskRepository();
330
		SourceViewer defaultEditor = new RepositoryTextViewer(taskRepository, parent, styles | SWT.WRAP);
331
332
		RepositoryTextViewerConfiguration viewerConfig = new RepositoryTextViewerConfiguration(taskRepository, true);
333
		viewerConfig.setMode(Mode.DEFAULT);
334
		defaultEditor.configure(viewerConfig);
335
336
		return defaultEditor;
337
	}
338
226
	private void validate() {
339
	private void validate() {
227
		apply();
340
		apply();
228
		if (fileNameText != null && "".equals(fileNameText.getText().trim())) {
341
		if (fileNameText != null && "".equals(fileNameText.getText().trim())) {
Lines 243-249 Link Here
243
356
244
	private void apply() {
357
	private void apply() {
245
		taskAttachment.applyTo(model.getAttribute());
358
		taskAttachment.applyTo(model.getAttribute());
246
		model.setComment(commentText.getText());
359
		model.setComment(comment.getDocument().get());
247
		model.setAttachContext(attachContextButton.getSelection());
360
		model.setAttachContext(attachContextButton.getSelection());
248
		model.setContentType(taskAttachment.getContentType());
361
		model.setContentType(taskAttachment.getContentType());
249
	}
362
	}
Lines 298-307 Link Here
298
			if (descriptionText != null) {
411
			if (descriptionText != null) {
299
				descriptionText.setFocus();
412
				descriptionText.setFocus();
300
			} else {
413
			} else {
301
				commentText.setFocus();
414
				comment.getTextWidget().setFocus();
302
			}
415
			}
303
			first = false;
416
			first = false;
304
		}
417
		}
305
	}
418
	}
306
419
420
	@Override
421
	public void dispose() {
422
		deactivateCommentContext();
423
		super.dispose();
424
	}
425
426
	private void deactivateCommentContext() {
427
		if (contextService != null && commentContext != null) {
428
			contextService.deactivateContext(commentContext);
429
			commentContext = null;
430
		}
431
	}
307
}
432
}
(-)src/org/eclipse/mylyn/tasks/ui/wizards/AbstractRepositorySettingsPage.java (-18 / +42 lines)
Lines 1-5 Link Here
1
/*******************************************************************************
1
/*******************************************************************************
2
* Copyright (c) 2004, 2008 Tasktop Technologies and others.
2
 * Copyright (c) 2004, 2008 Tasktop Technologies and others.
3
 * All rights reserved. This program and the accompanying materials
3
 * All rights reserved. This program and the accompanying materials
4
 * are made available under the terms of the Eclipse Public License v1.0
4
 * are made available under the terms of the Eclipse Public License v1.0
5
 * which accompanies this distribution, and is available at
5
 * which accompanies this distribution, and is available at
Lines 28-34 Link Here
28
import org.eclipse.jface.operation.IRunnableWithProgress;
28
import org.eclipse.jface.operation.IRunnableWithProgress;
29
import org.eclipse.jface.preference.PreferenceDialog;
29
import org.eclipse.jface.preference.PreferenceDialog;
30
import org.eclipse.jface.preference.StringFieldEditor;
30
import org.eclipse.jface.preference.StringFieldEditor;
31
import org.eclipse.jface.wizard.WizardPage;
32
import org.eclipse.mylyn.commons.core.StatusHandler;
31
import org.eclipse.mylyn.commons.core.StatusHandler;
33
import org.eclipse.mylyn.commons.net.AuthenticationCredentials;
32
import org.eclipse.mylyn.commons.net.AuthenticationCredentials;
34
import org.eclipse.mylyn.commons.net.AuthenticationType;
33
import org.eclipse.mylyn.commons.net.AuthenticationType;
Lines 67-73 Link Here
67
import org.eclipse.ui.forms.events.HyperlinkEvent;
66
import org.eclipse.ui.forms.events.HyperlinkEvent;
68
import org.eclipse.ui.forms.events.IHyperlinkListener;
67
import org.eclipse.ui.forms.events.IHyperlinkListener;
69
import org.eclipse.ui.forms.widgets.ExpandableComposite;
68
import org.eclipse.ui.forms.widgets.ExpandableComposite;
70
import org.eclipse.ui.forms.widgets.FormToolkit;
71
import org.eclipse.ui.forms.widgets.Hyperlink;
69
import org.eclipse.ui.forms.widgets.Hyperlink;
72
70
73
/**
71
/**
Lines 78-85 Link Here
78
 * @author Rob Elves
76
 * @author Rob Elves
79
 * @author Steffen Pingel
77
 * @author Steffen Pingel
80
 * @author Frank Becker
78
 * @author Frank Becker
79
 * @author David Green
81
 */
80
 */
82
public abstract class AbstractRepositorySettingsPage extends WizardPage implements ITaskRepositoryPage {
81
public abstract class AbstractRepositorySettingsPage extends AbstractExtensibleRepositorySettingsPage implements
82
		ITaskRepositoryPage {
83
83
84
	protected static final String PREFS_PAGE_ID_NET_PROXY = "org.eclipse.ui.net.NetPreferences";
84
	protected static final String PREFS_PAGE_ID_NET_PROXY = "org.eclipse.ui.net.NetPreferences";
85
85
Lines 205-222 Link Here
205
205
206
	private Button disconnectedButton;
206
	private Button disconnectedButton;
207
207
208
	// TODO 3.1 make accessible to subclasses 
209
	private FormToolkit toolkit;
210
211
	/**
208
	/**
212
	 * @since 3.0
209
	 * @since 3.0
213
	 */
210
	 */
214
	public AbstractRepositorySettingsPage(String title, String description, TaskRepository taskRepository) {
211
	public AbstractRepositorySettingsPage(String title, String description, TaskRepository taskRepository) {
215
		super(title);
212
		super(title, description, taskRepository);
216
		this.repository = taskRepository;
217
		this.connector = TasksUi.getRepositoryManager().getRepositoryConnector(getConnectorKind());
213
		this.connector = TasksUi.getRepositoryManager().getRepositoryConnector(getConnectorKind());
218
		setTitle(title);
219
		setDescription(description);
220
		setNeedsAnonymousLogin(false);
214
		setNeedsAnonymousLogin(false);
221
		setNeedsEncoding(true);
215
		setNeedsEncoding(true);
222
		setNeedsTimeZone(true);
216
		setNeedsTimeZone(true);
Lines 228-247 Link Here
228
	/**
222
	/**
229
	 * @since 3.0
223
	 * @since 3.0
230
	 */
224
	 */
225
	@Override
231
	public abstract String getConnectorKind();
226
	public abstract String getConnectorKind();
232
227
233
	@Override
228
	@Override
234
	public void dispose() {
229
	public void dispose() {
235
		super.dispose();
230
		super.dispose();
236
		if (toolkit != null) {
237
			toolkit.dispose();
238
			toolkit = null;
239
		}
240
	}
231
	}
241
232
242
	public void createControl(Composite parent) {
233
	@Override
243
		toolkit = new FormToolkit(TasksUiPlugin.getDefault().getFormColors(parent.getDisplay()));
234
	protected void createContents(Composite parent) {
235
		createSettingControls(parent);
236
	}
244
237
238
	@Override
239
	protected void createSettingControls(Composite parent) {
245
		if (repository != null) {
240
		if (repository != null) {
246
			originalUrl = repository.getRepositoryUrl();
241
			originalUrl = repository.getRepositoryUrl();
247
			AuthenticationCredentials oldCredentials = repository.getCredentials(AuthenticationType.REPOSITORY);
242
			AuthenticationCredentials oldCredentials = repository.getCredentials(AuthenticationType.REPOSITORY);
Lines 628-633 Link Here
628
623
629
		addStatusSection();
624
		addStatusSection();
630
625
626
		addContributionSection();
627
631
		Composite managementComposite = new Composite(compositeContainer, SWT.NULL);
628
		Composite managementComposite = new Composite(compositeContainer, SWT.NULL);
632
		GridLayout managementLayout = new GridLayout(4, false);
629
		GridLayout managementLayout = new GridLayout(4, false);
633
		managementLayout.marginHeight = 0;
630
		managementLayout.marginHeight = 0;
Lines 701-707 Link Here
701
698
702
		updateHyperlinks();
699
		updateHyperlinks();
703
700
704
		setControl(compositeContainer);
705
	}
701
	}
706
702
707
	private void addProxySection() {
703
	private void addProxySection() {
Lines 855-860 Link Here
855
		proxyExpComposite.setExpanded(!systemProxyButton.getSelection());
851
		proxyExpComposite.setExpanded(!systemProxyButton.getSelection());
856
	}
852
	}
857
853
854
	private void addContributionSection() {
855
		Composite composite = toolkit.createComposite(compositeContainer);
856
		GridDataFactory.fillDefaults().grab(true, false).span(2, SWT.DEFAULT).applyTo(composite);
857
858
		GridLayout layout = new GridLayout(1, false);
859
		layout.marginWidth = 0;
860
		layout.marginTop = -5;
861
		composite.setLayout(layout);
862
863
		composite.setBackground(compositeContainer.getBackground());
864
865
		addContributions(composite);
866
	}
867
858
	private void addStatusSection() {
868
	private void addStatusSection() {
859
		ExpandableComposite statusComposite = toolkit.createExpandableComposite(compositeContainer,
869
		ExpandableComposite statusComposite = toolkit.createExpandableComposite(compositeContainer,
860
				ExpandableComposite.COMPACT | ExpandableComposite.TWISTIE | ExpandableComposite.TITLE_BAR);
870
				ExpandableComposite.COMPACT | ExpandableComposite.TWISTIE | ExpandableComposite.TITLE_BAR);
Lines 1269-1274 Link Here
1269
	/**
1279
	/**
1270
	 * @since 2.2
1280
	 * @since 2.2
1271
	 */
1281
	 */
1282
	@Override
1272
	public void applyTo(TaskRepository repository) {
1283
	public void applyTo(TaskRepository repository) {
1273
		repository.setVersion(getVersion());
1284
		repository.setVersion(getVersion());
1274
		if (needsEncoding()) {
1285
		if (needsEncoding()) {
Lines 1307-1312 Link Here
1307
		}
1318
		}
1308
1319
1309
		repository.setOffline(disconnectedButton.getSelection());
1320
		repository.setOffline(disconnectedButton.getSelection());
1321
1322
		super.applyTo(repository);
1310
	}
1323
	}
1311
1324
1312
	public AbstractRepositoryConnector getConnector() {
1325
	public AbstractRepositoryConnector getConnector() {
Lines 1413-1418 Link Here
1413
		}
1426
		}
1414
	}
1427
	}
1415
1428
1429
	/**
1430
	 * validate settings provided by the {@link #getValidator(TaskRepository) validator}, typically the server settings.
1431
	 */
1416
	protected void validateSettings() {
1432
	protected void validateSettings() {
1417
		final Validator validator = getValidator(createTaskRepository());
1433
		final Validator validator = getValidator(createTaskRepository());
1418
		if (validator == null) {
1434
		if (validator == null) {
Lines 1453-1458 Link Here
1453
		getWizard().getContainer().updateButtons();
1469
		getWizard().getContainer().updateButtons();
1454
	}
1470
	}
1455
1471
1472
	/**
1473
	 * @since 3.1
1474
	 */
1475
	@Override
1476
	protected IStatus validate(IProgressMonitor monitor) {
1477
		return null;
1478
	}
1479
1456
	protected void applyValidatorResult(Validator validator) {
1480
	protected void applyValidatorResult(Validator validator) {
1457
		IStatus status = validator.getStatus();
1481
		IStatus status = validator.getStatus();
1458
		String message = status.getMessage();
1482
		String message = status.getMessage();
(-)plugin.xml (-12 / +10 lines)
Lines 8-13 Link Here
8
    <extension-point id="duplicateDetectors" name="duplicateDetectors" schema="schema/duplicateDetectors.exsd"/>
8
    <extension-point id="duplicateDetectors" name="duplicateDetectors" schema="schema/duplicateDetectors.exsd"/>
9
    <extension-point id="presentations" name="presentations" schema="schema/presentations.exsd"/>
9
    <extension-point id="presentations" name="presentations" schema="schema/presentations.exsd"/>
10
    <extension-point id="taskEditorExtensions" name="Task Editor Extension" schema="schema/taskEditorExtensions.exsd"/>
10
    <extension-point id="taskEditorExtensions" name="Task Editor Extension" schema="schema/taskEditorExtensions.exsd"/>
11
    <extension-point id="taskRepositoryPageContribution" name="Task Repository Page Contribution" schema="schema/taskRepositoryPageContribution.exsd"/>
11
12
12
    <extension
13
    <extension
13
          point="org.eclipse.mylyn.context.core.bridges">
14
          point="org.eclipse.mylyn.context.core.bridges">
Lines 1410-1427 Link Here
1410
                     value="1">
1411
                     value="1">
1411
               </count>
1412
               </count>
1412
               <iterate>
1413
               <iterate>
1413
                  <and>
1414
                 <instanceof
1414
                     <instanceof
1415
                       value="org.eclipse.mylyn.tasks.core.TaskRepository">
1415
                           value="org.eclipse.mylyn.tasks.core.TaskRepository">
1416
                 </instanceof>
1416
                     </instanceof>
1417
                     <not>
1418
                        <test
1419
                              forcePluginActivation="false"
1420
                              property="org.eclipse.mylyn.taskRepository.connectorKind"
1421
                              value="local">
1422
                        </test>
1423
                     </not>
1424
                  </and>
1425
               </iterate>
1417
               </iterate>
1426
            </and>
1418
            </and>
1427
         </enabledWhen>
1419
         </enabledWhen>
Lines 1780-1783 Link Here
1780
            type="org.eclipse.mylyn.tasks.core.TaskRepository">
1772
            type="org.eclipse.mylyn.tasks.core.TaskRepository">
1781
      </propertyTester>
1773
      </propertyTester>
1782
   </extension>
1774
   </extension>
1775
    <extension
1776
          point="org.eclipse.mylyn.tasks.ui.taskRepositoryPageContribution">
1777
       <taskRepositoryPageContribution
1778
             class="org.eclipse.mylyn.internal.tasks.ui.wizards.TaskEditorExtensionSettingsContribution">
1779
       </taskRepositoryPageContribution>
1780
    </extension>
1783
</plugin>
1781
</plugin>
(-)src/org/eclipse/mylyn/internal/tasks/ui/LocalRepositoryConnectorUi.java (-1 / +2 lines)
Lines 14-19 Link Here
14
import org.eclipse.jface.resource.ImageDescriptor;
14
import org.eclipse.jface.resource.ImageDescriptor;
15
import org.eclipse.jface.wizard.IWizard;
15
import org.eclipse.jface.wizard.IWizard;
16
import org.eclipse.mylyn.internal.tasks.core.LocalRepositoryConnector;
16
import org.eclipse.mylyn.internal.tasks.core.LocalRepositoryConnector;
17
import org.eclipse.mylyn.internal.tasks.ui.wizards.LocalRepositorySettingsPage;
17
import org.eclipse.mylyn.internal.tasks.ui.wizards.NewLocalTaskWizard;
18
import org.eclipse.mylyn.internal.tasks.ui.wizards.NewLocalTaskWizard;
18
import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
19
import org.eclipse.mylyn.tasks.core.IRepositoryQuery;
19
import org.eclipse.mylyn.tasks.core.ITask;
20
import org.eclipse.mylyn.tasks.core.ITask;
Lines 50-56 Link Here
50
51
51
	@Override
52
	@Override
52
	public ITaskRepositoryPage getSettingsPage(TaskRepository taskRepository) {
53
	public ITaskRepositoryPage getSettingsPage(TaskRepository taskRepository) {
53
		return null;
54
		return new LocalRepositorySettingsPage(taskRepository);
54
	}
55
	}
55
56
56
	@Override
57
	@Override
(-)schema/taskRepositoryPageContribution.exsd (+112 lines)
Added Link Here
1
<?xml version='1.0' encoding='UTF-8'?>
2
<!-- Schema file written by PDE -->
3
<schema targetNamespace="org.eclipse.mylyn.tasks.ui" xmlns="http://www.w3.org/2001/XMLSchema">
4
<annotation>
5
      <appinfo>
6
         <meta.schema plugin="org.eclipse.mylyn.tasks.ui" id="taskRepositoryPageContribution" name="Task Repository Page Contribution"/>
7
      </appinfo>
8
      <documentation>
9
         This extension point enables plug-ins to contribute user interface to the task repository settings dialog.
10
      </documentation>
11
   </annotation>
12
13
   <element name="extension">
14
      <annotation>
15
         <appinfo>
16
            <meta.element />
17
         </appinfo>
18
      </annotation>
19
      <complexType>
20
         <sequence>
21
            <element ref="taskRepositoryPageContribution" minOccurs="1" maxOccurs="unbounded"/>
22
         </sequence>
23
         <attribute name="point" type="string" use="required">
24
            <annotation>
25
               <documentation>
26
                  
27
               </documentation>
28
            </annotation>
29
         </attribute>
30
         <attribute name="id" type="string">
31
            <annotation>
32
               <documentation>
33
                  
34
               </documentation>
35
            </annotation>
36
         </attribute>
37
         <attribute name="name" type="string">
38
            <annotation>
39
               <documentation>
40
                  
41
               </documentation>
42
               <appinfo>
43
                  <meta.attribute translatable="true"/>
44
               </appinfo>
45
            </annotation>
46
         </attribute>
47
      </complexType>
48
   </element>
49
50
   <element name="taskRepositoryPageContribution">
51
      <complexType>
52
         <attribute name="class" type="string" use="required">
53
            <annotation>
54
               <documentation>
55
                  
56
               </documentation>
57
               <appinfo>
58
                  <meta.attribute kind="java" basedOn="org.eclipse.mylyn.tasks.ui.wizards.AbstractTaskRepositoryPageContribution:"/>
59
               </appinfo>
60
            </annotation>
61
         </attribute>
62
         <attribute name="connectorKind" type="string">
63
            <annotation>
64
               <documentation>
65
                  the kind of repository connector for which this contributor should be used, or &quot;&quot; (the empty string) if it applies to all connectors
66
               </documentation>
67
            </annotation>
68
         </attribute>
69
      </complexType>
70
   </element>
71
72
   <annotation>
73
      <appinfo>
74
         <meta.section type="since"/>
75
      </appinfo>
76
      <documentation>
77
         3.1
78
      </documentation>
79
   </annotation>
80
81
   <annotation>
82
      <appinfo>
83
         <meta.section type="examples"/>
84
      </appinfo>
85
      <documentation>
86
             &lt;extension
87
          point=&quot;org.eclipse.mylyn.tasks.ui.taskRepositoryPageContribution&quot;&gt;
88
       &lt;taskRepositoryPageContribution class=&quot;org.eclipse.mylyn.internal.tasks.ui.wizards.TaskEditorExtensionSettingsContribution&quot;/&gt;
89
    &lt;/extension&gt;
90
      </documentation>
91
   </annotation>
92
93
   <annotation>
94
      <appinfo>
95
         <meta.section type="apiinfo"/>
96
      </appinfo>
97
      <documentation>
98
         [Enter API information here.]
99
      </documentation>
100
   </annotation>
101
102
   <annotation>
103
      <appinfo>
104
         <meta.section type="implementation"/>
105
      </appinfo>
106
      <documentation>
107
         [Enter information about supplied implementation of this extension point.]
108
      </documentation>
109
   </annotation>
110
111
112
</schema>
(-)src/org/eclipse/mylyn/tasks/ui/wizards/AbstractExtensibleRepositorySettingsPage.java (+376 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2004, 2008 Mylyn project committers 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
9
package org.eclipse.mylyn.tasks.ui.wizards;
10
11
import java.lang.reflect.InvocationTargetException;
12
import java.util.ArrayList;
13
import java.util.Collections;
14
import java.util.Comparator;
15
import java.util.List;
16
17
import org.eclipse.core.runtime.IConfigurationElement;
18
import org.eclipse.core.runtime.IExtension;
19
import org.eclipse.core.runtime.IExtensionPoint;
20
import org.eclipse.core.runtime.IExtensionRegistry;
21
import org.eclipse.core.runtime.IProgressMonitor;
22
import org.eclipse.core.runtime.IStatus;
23
import org.eclipse.core.runtime.MultiStatus;
24
import org.eclipse.core.runtime.Platform;
25
import org.eclipse.core.runtime.Status;
26
import org.eclipse.core.runtime.SubProgressMonitor;
27
import org.eclipse.jface.dialogs.IMessageProvider;
28
import org.eclipse.jface.layout.GridDataFactory;
29
import org.eclipse.jface.operation.IRunnableWithProgress;
30
import org.eclipse.jface.wizard.WizardPage;
31
import org.eclipse.mylyn.commons.core.StatusHandler;
32
import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin;
33
import org.eclipse.mylyn.tasks.core.TaskRepository;
34
import org.eclipse.swt.SWT;
35
import org.eclipse.swt.layout.GridLayout;
36
import org.eclipse.swt.widgets.Composite;
37
import org.eclipse.ui.forms.events.ExpansionAdapter;
38
import org.eclipse.ui.forms.events.ExpansionEvent;
39
import org.eclipse.ui.forms.widgets.ExpandableComposite;
40
import org.eclipse.ui.forms.widgets.FormToolkit;
41
42
/**
43
 * An abstract base class for repository settings page that supports the <code>taskRepositoryPageContribution</code>
44
 * extension point.
45
 * 
46
 * {@link ITaskRepositoryPage} implementations are encouraged to extend {@link AbstractRepositorySettingsPage} if
47
 * possible as it provides a standard UI for managing server settings.
48
 * 
49
 * @see AbstractRepositorySettingsPage
50
 * 
51
 * @since 3.1
52
 * 
53
 * @author David Green
54
 */
55
public abstract class AbstractExtensibleRepositorySettingsPage extends WizardPage implements ITaskRepositoryPage {
56
57
	private static final String KIND = "connectorKind";
58
59
	private static final String TASK_REPOSITORY_PAGE_CONTRIBUTION = "taskRepositoryPageContribution";
60
61
	private static final String TASK_REPOSITORY_PAGE_CONTRIBUTION_EXTENSION = "org.eclipse.mylyn.tasks.ui.taskRepositoryPageContribution";
62
63
	private static final Comparator<AbstractTaskRepositoryPageContribution> CONTRIBUTION_COMPARATOR = new ContributionComparator();
64
65
	protected final TaskRepository repository;
66
67
	private final List<AbstractTaskRepositoryPageContribution> contributions = new ArrayList<AbstractTaskRepositoryPageContribution>();
68
69
	protected FormToolkit toolkit;
70
71
	protected Composite compositeContainer;
72
73
	private final AbstractTaskRepositoryPageContribution.Listener contributionListener = new AbstractTaskRepositoryPageContribution.Listener() {
74
		public void validationRequired(AbstractTaskRepositoryPageContribution contribution) {
75
			validatePageSettings();
76
		}
77
	};
78
79
	public AbstractExtensibleRepositorySettingsPage(String title, String description, TaskRepository repository) {
80
		super(title);
81
		if (repository != null && !repository.getConnectorKind().equals(getConnectorKind())) {
82
			throw new IllegalArgumentException();
83
		}
84
		this.repository = repository;
85
		setTitle(title);
86
		setDescription(description);
87
	}
88
89
	/**
90
	 * Get the kind of connector supported by this page.
91
	 * 
92
	 * @return the kind of connector, never null
93
	 */
94
	public abstract String getConnectorKind();
95
96
	@Override
97
	public void dispose() {
98
		if (toolkit != null) {
99
			toolkit.dispose();
100
			toolkit = null;
101
		}
102
		super.dispose();
103
	}
104
105
	public void createControl(Composite parent) {
106
		toolkit = new FormToolkit(TasksUiPlugin.getDefault().getFormColors(parent.getDisplay()));
107
108
		compositeContainer = new Composite(parent, SWT.NULL);
109
		GridLayout layout = new GridLayout(1, true);
110
		compositeContainer.setLayout(layout);
111
112
		createContents(compositeContainer);
113
114
		setControl(compositeContainer);
115
	}
116
117
	/**
118
	 * Create the contents of the page. Subclasses may override this method to change where the contributions are added.
119
	 */
120
	protected void createContents(Composite parent) {
121
		createSettingControls(parent);
122
123
		addContributions(parent);
124
	}
125
126
	/**
127
	 * create the controls of this page
128
	 */
129
	protected abstract void createSettingControls(Composite parent);
130
131
	@Override
132
	public boolean isPageComplete() {
133
		return super.isPageComplete() && conributionsIsPageComplete();
134
	}
135
136
	@Override
137
	public boolean canFlipToNextPage() {
138
		return super.canFlipToNextPage() && contributionsCanFlipToNextPage();
139
	}
140
141
	private boolean contributionsCanFlipToNextPage() {
142
		for (AbstractTaskRepositoryPageContribution contribution : contributions) {
143
			if (!contribution.canFlipToNextPage()) {
144
				return false;
145
			}
146
		}
147
		return true;
148
	}
149
150
	private boolean conributionsIsPageComplete() {
151
		for (AbstractTaskRepositoryPageContribution contribution : contributions) {
152
			if (!contribution.isPageComplete()) {
153
				return false;
154
			}
155
		}
156
		return true;
157
	}
158
159
	/**
160
	 * subclasses should only call this method if they override {@link #createContents(Composite)}
161
	 * 
162
	 * @param parentControl
163
	 *            the container into which the contributions will create their UI
164
	 */
165
	protected void addContributions(Composite parentControl) {
166
		contributions.clear();
167
		contributions.addAll(findApplicableContributors());
168
169
		if (!contributions.isEmpty()) {
170
			for (AbstractTaskRepositoryPageContribution contribution : contributions) {
171
				contribution.init(getConnectorKind(), repository);
172
				contribution.addListener(contributionListener);
173
			}
174
175
			Collections.sort(contributions, CONTRIBUTION_COMPARATOR);
176
177
			for (AbstractTaskRepositoryPageContribution contribution : contributions) {
178
179
				ExpandableComposite section = toolkit.createExpandableComposite(parentControl,
180
						ExpandableComposite.COMPACT | ExpandableComposite.TWISTIE | ExpandableComposite.TITLE_BAR);
181
				section.clientVerticalSpacing = 0;
182
				section.setBackground(parentControl.getBackground());
183
				section.setFont(parentControl.getFont());
184
				section.addExpansionListener(new ExpansionAdapter() {
185
					@Override
186
					public void expansionStateChanged(ExpansionEvent e) {
187
						getControl().getShell().pack();
188
					}
189
				});
190
				section.setText(contribution.getTitle());
191
				section.setToolTipText(contribution.getDescription());
192
193
				GridDataFactory.fillDefaults().grab(true, false).applyTo(section);
194
195
				Composite sectionContentsContainer = toolkit.createComposite(section);
196
				sectionContentsContainer.setBackground(parentControl.getBackground());
197
				contribution.createControl(sectionContentsContainer, toolkit);
198
199
				section.setClient(sectionContentsContainer);
200
			}
201
		}
202
	}
203
204
	/**
205
	 * Validate the settings of this page, not including contributions. This method should not be called directly by
206
	 * page implementations. Implementations of this method must be capable of running in a non-UI thread.
207
	 * 
208
	 * @return the status, or null if there are no messages.
209
	 * 
210
	 * @see #validatePageSettings()
211
	 */
212
	protected abstract IStatus validate(IProgressMonitor monitor);
213
214
	/**
215
	 * Overriding methods should call <code>super.applyTo(repository)</code>
216
	 */
217
	public void applyTo(TaskRepository repository) {
218
		applyContributionSettingsTo(repository);
219
	}
220
221
	private void applyContributionSettingsTo(TaskRepository repository) {
222
		for (AbstractTaskRepositoryPageContribution contribution : contributions) {
223
			contribution.applyTo(repository);
224
		}
225
	}
226
227
	/**
228
	 * compute the validation
229
	 * 
230
	 * @return a status if there is a message to display, otherwise null
231
	 */
232
	private IStatus computeValidation(IProgressMonitor monitor) {
233
		int factor = 100;
234
		monitor.beginTask("Validating settings", (contributions.size() + 1) * factor);
235
236
		IStatus cumulativeResult = null;
237
238
		// validate the page
239
		{
240
			SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, factor);
241
			cumulativeResult = validate(subMonitor);
242
			subMonitor.done();
243
		}
244
245
		// validate contributions
246
		for (AbstractTaskRepositoryPageContribution contribution : contributions) {
247
			SubProgressMonitor subMonitor = new SubProgressMonitor(monitor, factor);
248
			IStatus result = contribution.validate(subMonitor);
249
			if (result != null) {
250
				if (cumulativeResult == null) {
251
					cumulativeResult = result;
252
				} else if (cumulativeResult instanceof MultiStatus) {
253
					((MultiStatus) cumulativeResult).add(result);
254
				} else {
255
					cumulativeResult = new MultiStatus(cumulativeResult.getPlugin(), cumulativeResult.getCode(),
256
							new IStatus[] { cumulativeResult, result }, null, null);
257
				}
258
			}
259
			subMonitor.done();
260
		}
261
		monitor.done();
262
		return cumulativeResult;
263
	}
264
265
	/**
266
	 * Validate all settings in the page including contributions. This method should be called whenever a setting is
267
	 * changed on the page.
268
	 * 
269
	 * The results of validation are applied and the buttons of the page are updated.
270
	 * 
271
	 * @see #validate(IProgressMonitor)
272
	 * @see #applyValidationResult(IStatus[])
273
	 */
274
	protected void validatePageSettings() {
275
		final Object[] result = new Object[1];
276
		try {
277
			getWizard().getContainer().run(true, true, new IRunnableWithProgress() {
278
				public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
279
					result[0] = computeValidation(monitor);
280
				}
281
			});
282
		} catch (InvocationTargetException e) {
283
			StatusHandler.fail(new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN,
284
					"Internal error validating repository", e.getCause()));
285
			return;
286
		} catch (InterruptedException e) {
287
			// canceled
288
			return;
289
		}
290
		applyValidationResult((IStatus[]) result[0]);
291
		getWizard().getContainer().updateButtons();
292
	}
293
294
	/**
295
	 * Apply the results of validation to the page. The implementation finds the most {@link IStatus#getSeverity()
296
	 * severe} status and {@link #setMessage(String, int) applies the message} to the page.
297
	 * 
298
	 * @param statuses
299
	 *            an array of statuses that indicate the result of validation, or null
300
	 */
301
	protected void applyValidationResult(IStatus[] statuses) {
302
		if (statuses == null || statuses.length == 0) {
303
			setMessage(null, IMessageProvider.INFORMATION);
304
			setErrorMessage(null);
305
		} else {
306
			// find the most severe status
307
			IStatus status = statuses[0];
308
			for (IStatus s : statuses) {
309
				if (status == null || s.getSeverity() > status.getSeverity()) {
310
					status = s;
311
				}
312
			}
313
			int messageType;
314
			switch (status.getSeverity()) {
315
			case IStatus.OK:
316
			case IStatus.INFO:
317
				messageType = IMessageProvider.INFORMATION;
318
				break;
319
			case IStatus.WARNING:
320
				messageType = IMessageProvider.WARNING;
321
				break;
322
			case IStatus.ERROR:
323
			default:
324
				messageType = IMessageProvider.ERROR;
325
				break;
326
			}
327
			setErrorMessage(null);
328
			setMessage(status.getMessage(), messageType);
329
		}
330
	}
331
332
	private List<AbstractTaskRepositoryPageContribution> findApplicableContributors() {
333
		List<AbstractTaskRepositoryPageContribution> contributors = new ArrayList<AbstractTaskRepositoryPageContribution>();
334
335
		IExtensionRegistry registry = Platform.getExtensionRegistry();
336
337
		IExtensionPoint editorExtensionPoint = registry.getExtensionPoint(TASK_REPOSITORY_PAGE_CONTRIBUTION_EXTENSION);
338
		IExtension[] editorExtensions = editorExtensionPoint.getExtensions();
339
		for (IExtension extension : editorExtensions) {
340
			IConfigurationElement[] elements = extension.getConfigurationElements();
341
			for (IConfigurationElement element : elements) {
342
				if (element.getName().equals(TASK_REPOSITORY_PAGE_CONTRIBUTION)) {
343
					String kind = element.getAttribute(KIND);
344
					if (kind == null || "".equals(kind) || getConnectorKind().equals(kind)) {
345
						try {
346
							Object contributor = element.createExecutableExtension("class");
347
							contributors.add((AbstractTaskRepositoryPageContribution) contributor);
348
						} catch (Exception e) {
349
							StatusHandler.log(new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, "Could not load "
350
									+ TASK_REPOSITORY_PAGE_CONTRIBUTION, e));
351
						}
352
					}
353
				}
354
			}
355
		}
356
357
		return contributors;
358
	}
359
360
	private static class ContributionComparator implements Comparator<AbstractTaskRepositoryPageContribution> {
361
362
		public int compare(AbstractTaskRepositoryPageContribution o1, AbstractTaskRepositoryPageContribution o2) {
363
			if (o1 == o2) {
364
				return 0;
365
			}
366
			String s1 = o1.getTitle();
367
			String s2 = o2.getTitle();
368
			int i = s1.compareTo(s2);
369
			if (i == 0) {
370
				i = new Integer(System.identityHashCode(o1)).compareTo(System.identityHashCode(o2));
371
			}
372
			return i;
373
		}
374
375
	}
376
}
(-)src/org/eclipse/mylyn/tasks/ui/wizards/AbstractTaskRepositoryPageContribution.java (+166 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2004, 2007 Mylyn project committers 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
9
package org.eclipse.mylyn.tasks.ui.wizards;
10
11
import java.util.List;
12
import java.util.concurrent.CopyOnWriteArrayList;
13
14
import org.eclipse.core.runtime.IProgressMonitor;
15
import org.eclipse.core.runtime.IStatus;
16
import org.eclipse.jface.dialogs.IDialogPage;
17
import org.eclipse.jface.wizard.IWizardPage;
18
import org.eclipse.mylyn.tasks.core.TaskRepository;
19
import org.eclipse.swt.widgets.Composite;
20
import org.eclipse.ui.forms.widgets.FormToolkit;
21
22
/**
23
 * A contribution to a {@link ITaskRepositoryPage}, which enables plug-ins to contribute UI to the task repository
24
 * settings.
25
 * 
26
 * subclasses must have a default public constructor.
27
 * 
28
 * @since 3.1
29
 * 
30
 * @author David Green
31
 */
32
public abstract class AbstractTaskRepositoryPageContribution {
33
34
	/**
35
	 * a listener interface that should be implemented by classes wishing to be notified of changes that occur within
36
	 * the contribution.
37
	 */
38
	public interface Listener {
39
		/**
40
		 * Called when the state of the contribution changes such that validation should be performed
41
		 * 
42
		 * @param contribution
43
		 *            the contribution that changed
44
		 * 
45
		 * @see ITaskRepositoryPageContribution#validate(IProgressMonitor)
46
		 */
47
		public void validationRequired(AbstractTaskRepositoryPageContribution contribution);
48
	}
49
50
	private final List<Listener> listeners = new CopyOnWriteArrayList<Listener>();
51
52
	private final String title;
53
54
	private final String description;
55
56
	/**
57
	 * the repository for which this contribution was created, or null if it was created for a new repository
58
	 */
59
	protected TaskRepository repository;
60
61
	/**
62
	 * the kind of connector for which this contribution was created
63
	 */
64
	protected String connectorKind;
65
66
	/**
67
	 * 
68
	 * @param title
69
	 *            the title of the contribution, as displayed to the user, usually used as a section heading
70
	 * @param description
71
	 *            the description of the contribution, as displayed to the user, typically as a tool-tip
72
	 */
73
	protected AbstractTaskRepositoryPageContribution(String title, String description) {
74
		this.title = title;
75
		this.description = description;
76
	}
77
78
	/**
79
	 * Initialize the contribution
80
	 * 
81
	 * @param connectorKind
82
	 *            the kind of connector for which this is a contribution
83
	 * @param repository
84
	 *            the repository for which this contribution was created, or null if the repository is not yet available
85
	 */
86
	public void init(String connectorKind, TaskRepository repository) {
87
		this.connectorKind = connectorKind;
88
		this.repository = repository;
89
	}
90
91
	/**
92
	 * Add a listener to this contribution. The contribution must notify the listener at the appropriate times, for
93
	 * example when a setting has changed in the UI.
94
	 * 
95
	 * @see #removeListener(Listener)
96
	 */
97
	public void addListener(Listener listener) {
98
		listeners.add(listener);
99
	}
100
101
	/**
102
	 * Remove a listener from this contribution.
103
	 * 
104
	 * @see #addListener(Listener)
105
	 */
106
	public void removeListener(Listener listener) {
107
		listeners.remove(listener);
108
	}
109
110
	/**
111
	 * @see IDialogPage#createControl(Composite)
112
	 */
113
	public abstract void createControl(Composite parent, FormToolkit toolkit);
114
115
	/**
116
	 * @see IDialogPage#getTitle()
117
	 */
118
	public String getTitle() {
119
		return title;
120
	}
121
122
	/**
123
	 * @see IDialogPage#getDescription()
124
	 */
125
	public String getDescription() {
126
		return description;
127
	}
128
129
	/**
130
	 * @see IWizardPage#isPageComplete()
131
	 */
132
	public abstract boolean isPageComplete();
133
134
	/**
135
	 * @see IWizardPage#canFlipToNextPage()
136
	 */
137
	public abstract boolean canFlipToNextPage();
138
139
	/**
140
	 * Validate the settings of the contribution. Contributions should expect this method to be called often and should
141
	 * thus return quickly. Implementations of this method must be capable of running in a non-UI thread.
142
	 * 
143
	 * @return the status (errors) on the contribution, or null if there are none. A MultiStatus should be used to
144
	 *         return multiple error messages or warnings.
145
	 */
146
	public abstract IStatus validate(IProgressMonitor monitor);
147
148
	/**
149
	 * Apply the settings in the contribution to the given repository.
150
	 * 
151
	 * @param repository
152
	 *            the repository to which settings should be applied
153
	 * 
154
	 * @see ITaskRepositoryPage#applyTo(TaskRepository)
155
	 */
156
	public abstract void applyTo(TaskRepository repository);
157
158
	/**
159
	 * fire the validation required event.
160
	 */
161
	protected void fireValidationRequired() {
162
		for (Listener l : listeners) {
163
			l.validationRequired(this);
164
		}
165
	}
166
}
(-)src/org/eclipse/mylyn/internal/tasks/ui/wizards/TaskEditorExtensionSettingsContribution.java (+161 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2004, 2007 Mylyn project committers 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
9
package org.eclipse.mylyn.internal.tasks.ui.wizards;
10
11
import java.util.SortedSet;
12
13
import org.eclipse.core.runtime.IProgressMonitor;
14
import org.eclipse.core.runtime.IStatus;
15
import org.eclipse.jface.resource.FontRegistry;
16
import org.eclipse.jface.resource.JFaceResources;
17
import org.eclipse.mylyn.internal.tasks.ui.editors.TaskEditorExtensions;
18
import org.eclipse.mylyn.internal.tasks.ui.editors.TaskEditorExtensions.RegisteredTaskEditorExtension;
19
import org.eclipse.mylyn.tasks.core.TaskRepository;
20
import org.eclipse.mylyn.tasks.ui.wizards.AbstractTaskRepositoryPageContribution;
21
import org.eclipse.swt.SWT;
22
import org.eclipse.swt.events.SelectionAdapter;
23
import org.eclipse.swt.events.SelectionEvent;
24
import org.eclipse.swt.events.SelectionListener;
25
import org.eclipse.swt.graphics.Font;
26
import org.eclipse.swt.graphics.FontData;
27
import org.eclipse.swt.layout.GridLayout;
28
import org.eclipse.swt.widgets.Button;
29
import org.eclipse.swt.widgets.Composite;
30
import org.eclipse.swt.widgets.Widget;
31
import org.eclipse.ui.forms.widgets.FormToolkit;
32
33
/**
34
 * A contribution that adds a section for 'Editor' on the task repository settings page.
35
 * 
36
 * @author David Green
37
 */
38
public class TaskEditorExtensionSettingsContribution extends AbstractTaskRepositoryPageContribution {
39
40
	private static final String LABEL_NONE = "Plain Text";
41
42
	private static final String LABEL_DEFAULT_SUFFIX = " (default)";
43
44
	private static final String DATA_EDITOR_EXTENSION = "editorExtension";
45
46
	private final SelectionListener listener = new SelectionAdapter() {
47
		@Override
48
		public void widgetSelected(SelectionEvent e) {
49
			selectedExtensionId = (String) ((Widget) e.getSource()).getData(DATA_EDITOR_EXTENSION);
50
			fireValidationRequired();
51
		}
52
	};
53
54
	private String selectedExtensionId = null;
55
56
	public TaskEditorExtensionSettingsContribution() {
57
		super("Editor", "Select the capabilities of the the task editor");
58
	}
59
60
	@Override
61
	public void applyTo(TaskRepository repository) {
62
		TaskEditorExtensions.setTaskEditorExtensionId(repository, selectedExtensionId == null ? "none"
63
				: selectedExtensionId);
64
	}
65
66
	@Override
67
	public boolean canFlipToNextPage() {
68
		return true;
69
	}
70
71
	@Override
72
	public boolean isPageComplete() {
73
		return true;
74
	}
75
76
	@Override
77
	public void createControl(Composite parent, FormToolkit toolkit) {
78
		parent.setLayout(new GridLayout(1, true));
79
80
		String defaultExtensionId = TaskEditorExtensions.getDefaultTaskEditorExtensionId(connectorKind);
81
		selectedExtensionId = repository == null ? defaultExtensionId
82
				: TaskEditorExtensions.getTaskEditorExtensionId(repository);
83
84
		Button noneButton;
85
		{ // configure a 'Plain Text' (none) button
86
			String noneTitle = LABEL_NONE;
87
88
			boolean isDefault = defaultExtensionId == null || defaultExtensionId.length() == 0;
89
			if (isDefault) {
90
				noneTitle += LABEL_DEFAULT_SUFFIX;
91
			}
92
			noneButton = toolkit.createButton(parent, noneTitle, SWT.RADIO);
93
			if (isDefault) {
94
				adjustForDefault(noneButton);
95
			}
96
97
			noneButton.addSelectionListener(listener);
98
		}
99
100
		boolean foundSelection = false;
101
102
		// now add selection buttons for all registered extensions
103
		SortedSet<RegisteredTaskEditorExtension> allEditorExtensions = TaskEditorExtensions.getTaskEditorExtensions();
104
		for (RegisteredTaskEditorExtension editorExtension : allEditorExtensions) {
105
			String name = editorExtension.getName();
106
107
			boolean isDefault = editorExtension.getId().equals(defaultExtensionId);
108
			if (isDefault) {
109
				name += LABEL_DEFAULT_SUFFIX;
110
			}
111
			Button button = toolkit.createButton(parent, name, SWT.RADIO);
112
			if (isDefault) {
113
				adjustForDefault(button);
114
			}
115
116
			if (editorExtension.getId().equals(selectedExtensionId)) {
117
				foundSelection = true;
118
				button.setSelection(true);
119
			}
120
			button.setText(name);
121
			button.setData(DATA_EDITOR_EXTENSION, editorExtension.getId());
122
			button.addSelectionListener(listener);
123
		}
124
		if (!foundSelection) {
125
			noneButton.setSelection(true);
126
		}
127
	}
128
129
	private void adjustForDefault(Button button) {
130
		Font font = button.getFont();
131
		button.setFont(getBold(font));
132
	}
133
134
	private Font getBold(Font font) {
135
		FontData[] originalFontData = font.getFontData();
136
		FontData fontData = originalFontData[0];
137
		if ((fontData.getStyle() & SWT.BOLD) != 0) {
138
			return font;
139
		}
140
141
		FontRegistry fontRegistry = JFaceResources.getFontRegistry();
142
		String key = fontData.getName() + '-' + fontData.getHeight() + "-" + fontData.getLocale() + "-"
143
				+ fontData.getStyle() + "-bold";
144
145
		if (!fontRegistry.hasValueFor(key)) {
146
			FontData[] boldFontDatas = new FontData[originalFontData.length];
147
			int index = -1;
148
			for (FontData fd : originalFontData) {
149
				boldFontDatas[++index] = new FontData(fd.getName(), fd.getHeight(), fd.getStyle() | SWT.BOLD);
150
			}
151
			fontRegistry.put(key, boldFontDatas);
152
		}
153
		return fontRegistry.get(key);
154
	}
155
156
	@Override
157
	public IStatus validate(IProgressMonitor monitor) {
158
		// nothing to validate
159
		return null;
160
	}
161
}
(-)src/org/eclipse/mylyn/internal/tasks/ui/wizards/LocalRepositorySettingsPage.java (+63 lines)
Added Link Here
1
/*******************************************************************************
2
 * Copyright (c) 2004, 2008 Mylyn project committers 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
9
package org.eclipse.mylyn.internal.tasks.ui.wizards;
10
11
import org.eclipse.core.runtime.IProgressMonitor;
12
import org.eclipse.core.runtime.IStatus;
13
import org.eclipse.mylyn.internal.tasks.core.LocalRepositoryConnector;
14
import org.eclipse.mylyn.tasks.core.TaskRepository;
15
import org.eclipse.mylyn.tasks.ui.wizards.AbstractExtensibleRepositorySettingsPage;
16
import org.eclipse.swt.widgets.Composite;
17
import org.eclipse.swt.widgets.Control;
18
import org.eclipse.ui.forms.widgets.ExpandableComposite;
19
20
/**
21
 * A settings page for the local repository properties dialog. Local repositories have no settings, however they may
22
 * have settings contributed via the taskRepositoryPageContribution.
23
 * 
24
 * @author David Green
25
 */
26
public class LocalRepositorySettingsPage extends AbstractExtensibleRepositorySettingsPage {
27
28
	public LocalRepositorySettingsPage(TaskRepository taskRepository) {
29
		super("Local Repository Settings", "Configure the local repository", taskRepository);
30
	}
31
32
	@Override
33
	public String getConnectorKind() {
34
		return LocalRepositoryConnector.CONNECTOR_KIND;
35
	}
36
37
	public String getRepositoryUrl() {
38
		return null;
39
	}
40
41
	@Override
42
	protected void createSettingControls(Composite parent) {
43
		// nothing to do, since the local repository has no settings
44
	}
45
46
	@Override
47
	protected IStatus validate(IProgressMonitor monitor) {
48
		// nothing to do
49
		return null;
50
	}
51
52
	@Override
53
	protected void addContributions(Composite parentControl) {
54
		super.addContributions(parentControl);
55
		// expand the first contribution since we have no other settings
56
		Control[] children = parentControl.getChildren();
57
		if (children.length > 0) {
58
			if (children[0] instanceof ExpandableComposite) {
59
				((ExpandableComposite) children[0]).setExpanded(true);
60
			}
61
		}
62
	}
63
}

Return to bug 244653