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/editors/AbstractTaskEditorPage.java (-5 / +25 lines)
Lines 159-164 Link Here
159
 */
159
 */
160
public abstract class AbstractTaskEditorPage extends FormPage implements ISelectionProvider, ISelectionChangedListener {
160
public abstract class AbstractTaskEditorPage extends FormPage implements ISelectionProvider, ISelectionChangedListener {
161
161
162
	/**
163
	 * a resize listener that causes the form page to reflow
164
	 */
165
	private final class ParentResizeHandler implements Listener {
166
		private int generation = 0;
167
168
		public void handleEvent(Event event) {
169
			// bug 237503: delay the reflow as an optimization
170
			++generation;
171
172
			Display.getCurrent().timerExec(150, new Runnable() {
173
				int scheduledGeneration = generation;
174
175
				public void run() {
176
					// Only reflow if this is the latest generation.  This prevents
177
					// unnecessary reflows
178
					if (scheduledGeneration == generation) {
179
						getManagedForm().reflow(true);
180
					}
181
				}
182
			});
183
		}
184
	}
185
162
	private class SubmitTaskJobListener extends SubmitJobListener {
186
	private class SubmitTaskJobListener extends SubmitJobListener {
163
187
164
		private final boolean attachContext;
188
		private final boolean attachContext;
Lines 497-507 Link Here
497
521
498
	@Override
522
	@Override
499
	public void createPartControl(Composite parent) {
523
	public void createPartControl(Composite parent) {
500
		parent.addListener(SWT.Resize, new Listener() {
524
		parent.addListener(SWT.Resize, new ParentResizeHandler());
501
			public void handleEvent(Event event) {
502
				getManagedForm().reflow(true);
503
			}
504
		});
505
		super.createPartControl(parent);
525
		super.createPartControl(parent);
506
	}
526
	}
507
527
(-)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() {
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 (+347 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.util.ArrayList;
12
import java.util.Collections;
13
import java.util.Comparator;
14
import java.util.List;
15
16
import org.eclipse.core.runtime.IConfigurationElement;
17
import org.eclipse.core.runtime.IExtension;
18
import org.eclipse.core.runtime.IExtensionPoint;
19
import org.eclipse.core.runtime.IExtensionRegistry;
20
import org.eclipse.core.runtime.IProgressMonitor;
21
import org.eclipse.core.runtime.IStatus;
22
import org.eclipse.core.runtime.MultiStatus;
23
import org.eclipse.core.runtime.Platform;
24
import org.eclipse.core.runtime.Status;
25
import org.eclipse.jface.dialogs.IMessageProvider;
26
import org.eclipse.jface.layout.GridDataFactory;
27
import org.eclipse.jface.wizard.WizardPage;
28
import org.eclipse.mylyn.commons.core.StatusHandler;
29
import org.eclipse.mylyn.internal.tasks.ui.TasksUiPlugin;
30
import org.eclipse.mylyn.tasks.core.TaskRepository;
31
import org.eclipse.swt.SWT;
32
import org.eclipse.swt.layout.GridLayout;
33
import org.eclipse.swt.widgets.Composite;
34
import org.eclipse.swt.widgets.Display;
35
import org.eclipse.ui.forms.events.ExpansionAdapter;
36
import org.eclipse.ui.forms.events.ExpansionEvent;
37
import org.eclipse.ui.forms.widgets.ExpandableComposite;
38
import org.eclipse.ui.forms.widgets.FormToolkit;
39
40
/**
41
 * An abstract base class for repository settings page that supports the <code>taskRepositoryPageContribution</code>
42
 * extension point.
43
 * 
44
 * {@link ITaskRepositoryPage} implementations are encouraged to extend {@link AbstractRepositorySettingsPage} if
45
 * possible as it provides a standard UI for managing server settings.
46
 * 
47
 * @see AbstractRepositorySettingsPage
48
 * 
49
 * @since 3.1
50
 * 
51
 * @author David Green
52
 */
53
public abstract class AbstractExtensibleRepositorySettingsPage extends WizardPage implements ITaskRepositoryPage {
54
55
	private static final String KIND = "connectorKind";
56
57
	private static final String TASK_REPOSITORY_PAGE_CONTRIBUTION = "taskRepositoryPageContribution";
58
59
	private static final String TASK_REPOSITORY_PAGE_CONTRIBUTION_EXTENSION = "org.eclipse.mylyn.tasks.ui.taskRepositoryPageContribution";
60
61
	private static final Comparator<AbstractTaskRepositoryPageContribution> CONTRIBUTION_COMPARATOR = new ContributionComparator();
62
63
	protected final TaskRepository repository;
64
65
	private final List<AbstractTaskRepositoryPageContribution> contributions = new ArrayList<AbstractTaskRepositoryPageContribution>();
66
67
	protected FormToolkit toolkit;
68
69
	protected Composite compositeContainer;
70
71
	private final AbstractTaskRepositoryPageContribution.Listener contributionListener = new AbstractTaskRepositoryPageContribution.Listener() {
72
		public void validationRequired(AbstractTaskRepositoryPageContribution contribution) {
73
			validatePageSettings();
74
		}
75
	};
76
77
	public AbstractExtensibleRepositorySettingsPage(String title, String description, TaskRepository repository) {
78
		super(title);
79
		if (repository != null && !repository.getConnectorKind().equals(getConnectorKind())) {
80
			throw new IllegalArgumentException();
81
		}
82
		this.repository = repository;
83
		setTitle(title);
84
		setDescription(description);
85
	}
86
87
	/**
88
	 * Get the kind of connector supported by this page.
89
	 * 
90
	 * @return the kind of connector, never null
91
	 */
92
	public abstract String getConnectorKind();
93
94
	@Override
95
	public void dispose() {
96
		if (toolkit != null) {
97
			toolkit.dispose();
98
			toolkit = null;
99
		}
100
		super.dispose();
101
	}
102
103
	public void createControl(Composite parent) {
104
		toolkit = new FormToolkit(TasksUiPlugin.getDefault().getFormColors(parent.getDisplay()));
105
106
		compositeContainer = new Composite(parent, SWT.NULL);
107
		GridLayout layout = new GridLayout(1, true);
108
		compositeContainer.setLayout(layout);
109
110
		createContents(compositeContainer);
111
112
		setControl(compositeContainer);
113
	}
114
115
	/**
116
	 * Create the contents of the page. Subclasses may override this method to change where the contributions are added.
117
	 */
118
	protected void createContents(Composite parent) {
119
		createSettingControls(parent);
120
121
		addContributions(parent);
122
	}
123
124
	/**
125
	 * create the controls of this page
126
	 */
127
	protected abstract void createSettingControls(Composite parent);
128
129
	@Override
130
	public boolean isPageComplete() {
131
		return super.isPageComplete() && conributionsIsPageComplete();
132
	}
133
134
	@Override
135
	public boolean canFlipToNextPage() {
136
		return super.canFlipToNextPage() && contributionsCanFlipToNextPage();
137
	}
138
139
	private boolean contributionsCanFlipToNextPage() {
140
		for (AbstractTaskRepositoryPageContribution contribution : contributions) {
141
			if (!contribution.canFlipToNextPage()) {
142
				return false;
143
			}
144
		}
145
		return true;
146
	}
147
148
	private boolean conributionsIsPageComplete() {
149
		for (AbstractTaskRepositoryPageContribution contribution : contributions) {
150
			if (!contribution.isPageComplete()) {
151
				return false;
152
			}
153
		}
154
		return true;
155
	}
156
157
	/**
158
	 * subclasses should only call this method if they override {@link #createContents(Composite)}
159
	 * 
160
	 * @param parentControl
161
	 *            the container into which the contributions will create their UI
162
	 */
163
	protected void addContributions(Composite parentControl) {
164
		contributions.clear();
165
		contributions.addAll(findApplicableContributors());
166
167
		if (!contributions.isEmpty()) {
168
			for (AbstractTaskRepositoryPageContribution contribution : contributions) {
169
				contribution.init(getConnectorKind(), repository);
170
				contribution.addListener(contributionListener);
171
			}
172
173
			Collections.sort(contributions, CONTRIBUTION_COMPARATOR);
174
175
			for (AbstractTaskRepositoryPageContribution contribution : contributions) {
176
177
				ExpandableComposite section = toolkit.createExpandableComposite(parentControl,
178
						ExpandableComposite.COMPACT | ExpandableComposite.TWISTIE | ExpandableComposite.TITLE_BAR);
179
				section.clientVerticalSpacing = 0;
180
				section.setBackground(parentControl.getBackground());
181
				section.setFont(parentControl.getFont());
182
				section.addExpansionListener(new ExpansionAdapter() {
183
					@Override
184
					public void expansionStateChanged(ExpansionEvent e) {
185
						getControl().getShell().pack();
186
					}
187
				});
188
				section.setText(contribution.getTitle());
189
				section.setToolTipText(contribution.getDescription());
190
191
				GridDataFactory.fillDefaults().grab(true, false).applyTo(section);
192
193
				Composite sectionContentsContainer = toolkit.createComposite(section);
194
				sectionContentsContainer.setBackground(parentControl.getBackground());
195
				contribution.createControl(sectionContentsContainer, toolkit);
196
197
				section.setClient(sectionContentsContainer);
198
			}
199
		}
200
	}
201
202
	/**
203
	 * Validate the settings of this page, not including contributions. This method should not be called directly by
204
	 * page implementations. Always run on a UI thread.
205
	 * 
206
	 * @return the status, or null if there are no messages.
207
	 * 
208
	 * @see #validatePageSettings()
209
	 */
210
	protected abstract IStatus validate();
211
212
	/**
213
	 * Overriding methods should call <code>super.applyTo(repository)</code>
214
	 */
215
	public void applyTo(TaskRepository repository) {
216
		applyContributionSettingsTo(repository);
217
	}
218
219
	private void applyContributionSettingsTo(TaskRepository repository) {
220
		for (AbstractTaskRepositoryPageContribution contribution : contributions) {
221
			contribution.applyTo(repository);
222
		}
223
	}
224
225
	/**
226
	 * compute the validation
227
	 * 
228
	 * @return a status if there is a message to display, otherwise null
229
	 */
230
	private IStatus computeValidation() {
231
		if (Display.getCurrent() == null) {
232
			throw new IllegalStateException();
233
		}
234
		IStatus cumulativeResult;
235
236
		// validate the page
237
		cumulativeResult = validate();
238
239
		// validate contributions
240
		for (AbstractTaskRepositoryPageContribution contribution : contributions) {
241
			IStatus result = contribution.validate();
242
			if (result != null) {
243
				if (cumulativeResult == null) {
244
					cumulativeResult = result;
245
				} else if (cumulativeResult instanceof MultiStatus) {
246
					((MultiStatus) cumulativeResult).add(result);
247
				} else {
248
					cumulativeResult = new MultiStatus(cumulativeResult.getPlugin(), cumulativeResult.getCode(),
249
							new IStatus[] { cumulativeResult, result }, null, null);
250
				}
251
			}
252
		}
253
		return cumulativeResult;
254
	}
255
256
	/**
257
	 * Validate all settings in the page including contributions. This method should be called whenever a setting is
258
	 * changed on the page.
259
	 * 
260
	 * The results of validation are applied and the buttons of the page are updated.
261
	 * 
262
	 * @see #validate(IProgressMonitor)
263
	 * @see #applyValidationResult(IStatus[])
264
	 */
265
	protected void validatePageSettings() {
266
		IStatus validationStatus = computeValidation();
267
		applyValidationResult(validationStatus);
268
		getWizard().getContainer().updateButtons();
269
	}
270
271
	/**
272
	 * Apply the results of validation to the page. The implementation finds the most {@link IStatus#getSeverity()
273
	 * severe} status and {@link #setMessage(String, int) applies the message} to the page.
274
	 * 
275
	 * @param status
276
	 *            the status of the validation, or null
277
	 */
278
	protected void applyValidationResult(IStatus status) {
279
		if (status == null) {
280
			setMessage(null, IMessageProvider.INFORMATION);
281
			setErrorMessage(null);
282
		} else {
283
			// find the most severe status
284
			int messageType;
285
			switch (status.getSeverity()) {
286
			case IStatus.OK:
287
			case IStatus.INFO:
288
				messageType = IMessageProvider.INFORMATION;
289
				break;
290
			case IStatus.WARNING:
291
				messageType = IMessageProvider.WARNING;
292
				break;
293
			case IStatus.ERROR:
294
			default:
295
				messageType = IMessageProvider.ERROR;
296
				break;
297
			}
298
			setErrorMessage(null);
299
			setMessage(status.getMessage(), messageType);
300
		}
301
	}
302
303
	private List<AbstractTaskRepositoryPageContribution> findApplicableContributors() {
304
		List<AbstractTaskRepositoryPageContribution> contributors = new ArrayList<AbstractTaskRepositoryPageContribution>();
305
306
		IExtensionRegistry registry = Platform.getExtensionRegistry();
307
308
		IExtensionPoint editorExtensionPoint = registry.getExtensionPoint(TASK_REPOSITORY_PAGE_CONTRIBUTION_EXTENSION);
309
		IExtension[] editorExtensions = editorExtensionPoint.getExtensions();
310
		for (IExtension extension : editorExtensions) {
311
			IConfigurationElement[] elements = extension.getConfigurationElements();
312
			for (IConfigurationElement element : elements) {
313
				if (element.getName().equals(TASK_REPOSITORY_PAGE_CONTRIBUTION)) {
314
					String kind = element.getAttribute(KIND);
315
					if (kind == null || "".equals(kind) || getConnectorKind().equals(kind)) {
316
						try {
317
							Object contributor = element.createExecutableExtension("class");
318
							contributors.add((AbstractTaskRepositoryPageContribution) contributor);
319
						} catch (Exception e) {
320
							StatusHandler.log(new Status(IStatus.ERROR, TasksUiPlugin.ID_PLUGIN, "Could not load "
321
									+ TASK_REPOSITORY_PAGE_CONTRIBUTION, e));
322
						}
323
					}
324
				}
325
			}
326
		}
327
328
		return contributors;
329
	}
330
331
	private static class ContributionComparator implements Comparator<AbstractTaskRepositoryPageContribution> {
332
333
		public int compare(AbstractTaskRepositoryPageContribution o1, AbstractTaskRepositoryPageContribution o2) {
334
			if (o1 == o2) {
335
				return 0;
336
			}
337
			String s1 = o1.getTitle();
338
			String s2 = o2.getTitle();
339
			int i = s1.compareTo(s2);
340
			if (i == 0) {
341
				i = new Integer(System.identityHashCode(o1)).compareTo(System.identityHashCode(o2));
342
			}
343
			return i;
344
		}
345
346
	}
347
}
(-)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. Always called on the 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();
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 (+160 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.IStatus;
14
import org.eclipse.jface.resource.FontRegistry;
15
import org.eclipse.jface.resource.JFaceResources;
16
import org.eclipse.mylyn.internal.tasks.ui.editors.TaskEditorExtensions;
17
import org.eclipse.mylyn.internal.tasks.ui.editors.TaskEditorExtensions.RegisteredTaskEditorExtension;
18
import org.eclipse.mylyn.tasks.core.TaskRepository;
19
import org.eclipse.mylyn.tasks.ui.wizards.AbstractTaskRepositoryPageContribution;
20
import org.eclipse.swt.SWT;
21
import org.eclipse.swt.events.SelectionAdapter;
22
import org.eclipse.swt.events.SelectionEvent;
23
import org.eclipse.swt.events.SelectionListener;
24
import org.eclipse.swt.graphics.Font;
25
import org.eclipse.swt.graphics.FontData;
26
import org.eclipse.swt.layout.GridLayout;
27
import org.eclipse.swt.widgets.Button;
28
import org.eclipse.swt.widgets.Composite;
29
import org.eclipse.swt.widgets.Widget;
30
import org.eclipse.ui.forms.widgets.FormToolkit;
31
32
/**
33
 * A contribution that adds a section for 'Editor' on the task repository settings page.
34
 * 
35
 * @author David Green
36
 */
37
public class TaskEditorExtensionSettingsContribution extends AbstractTaskRepositoryPageContribution {
38
39
	private static final String LABEL_NONE = "Plain Text";
40
41
	private static final String LABEL_DEFAULT_SUFFIX = " (default)";
42
43
	private static final String DATA_EDITOR_EXTENSION = "editorExtension";
44
45
	private final SelectionListener listener = new SelectionAdapter() {
46
		@Override
47
		public void widgetSelected(SelectionEvent e) {
48
			selectedExtensionId = (String) ((Widget) e.getSource()).getData(DATA_EDITOR_EXTENSION);
49
			fireValidationRequired();
50
		}
51
	};
52
53
	private String selectedExtensionId = null;
54
55
	public TaskEditorExtensionSettingsContribution() {
56
		super("Editor", "Select the capabilities of the the task editor");
57
	}
58
59
	@Override
60
	public void applyTo(TaskRepository repository) {
61
		TaskEditorExtensions.setTaskEditorExtensionId(repository, selectedExtensionId == null ? "none"
62
				: selectedExtensionId);
63
	}
64
65
	@Override
66
	public boolean canFlipToNextPage() {
67
		return true;
68
	}
69
70
	@Override
71
	public boolean isPageComplete() {
72
		return true;
73
	}
74
75
	@Override
76
	public void createControl(Composite parent, FormToolkit toolkit) {
77
		parent.setLayout(new GridLayout(1, true));
78
79
		String defaultExtensionId = TaskEditorExtensions.getDefaultTaskEditorExtensionId(connectorKind);
80
		selectedExtensionId = repository == null ? defaultExtensionId
81
				: TaskEditorExtensions.getTaskEditorExtensionId(repository);
82
83
		Button noneButton;
84
		{ // configure a 'Plain Text' (none) button
85
			String noneTitle = LABEL_NONE;
86
87
			boolean isDefault = defaultExtensionId == null || defaultExtensionId.length() == 0;
88
			if (isDefault) {
89
				noneTitle += LABEL_DEFAULT_SUFFIX;
90
			}
91
			noneButton = toolkit.createButton(parent, noneTitle, SWT.RADIO);
92
			if (isDefault) {
93
				adjustForDefault(noneButton);
94
			}
95
96
			noneButton.addSelectionListener(listener);
97
		}
98
99
		boolean foundSelection = false;
100
101
		// now add selection buttons for all registered extensions
102
		SortedSet<RegisteredTaskEditorExtension> allEditorExtensions = TaskEditorExtensions.getTaskEditorExtensions();
103
		for (RegisteredTaskEditorExtension editorExtension : allEditorExtensions) {
104
			String name = editorExtension.getName();
105
106
			boolean isDefault = editorExtension.getId().equals(defaultExtensionId);
107
			if (isDefault) {
108
				name += LABEL_DEFAULT_SUFFIX;
109
			}
110
			Button button = toolkit.createButton(parent, name, SWT.RADIO);
111
			if (isDefault) {
112
				adjustForDefault(button);
113
			}
114
115
			if (editorExtension.getId().equals(selectedExtensionId)) {
116
				foundSelection = true;
117
				button.setSelection(true);
118
			}
119
			button.setText(name);
120
			button.setData(DATA_EDITOR_EXTENSION, editorExtension.getId());
121
			button.addSelectionListener(listener);
122
		}
123
		if (!foundSelection) {
124
			noneButton.setSelection(true);
125
		}
126
	}
127
128
	private void adjustForDefault(Button button) {
129
		Font font = button.getFont();
130
		button.setFont(getBold(font));
131
	}
132
133
	private Font getBold(Font font) {
134
		FontData[] originalFontData = font.getFontData();
135
		FontData fontData = originalFontData[0];
136
		if ((fontData.getStyle() & SWT.BOLD) != 0) {
137
			return font;
138
		}
139
140
		FontRegistry fontRegistry = JFaceResources.getFontRegistry();
141
		String key = fontData.getName() + '-' + fontData.getHeight() + "-" + fontData.getLocale() + "-"
142
				+ fontData.getStyle() + "-bold";
143
144
		if (!fontRegistry.hasValueFor(key)) {
145
			FontData[] boldFontDatas = new FontData[originalFontData.length];
146
			int index = -1;
147
			for (FontData fd : originalFontData) {
148
				boldFontDatas[++index] = new FontData(fd.getName(), fd.getHeight(), fd.getStyle() | SWT.BOLD);
149
			}
150
			fontRegistry.put(key, boldFontDatas);
151
		}
152
		return fontRegistry.get(key);
153
	}
154
155
	@Override
156
	public IStatus validate() {
157
		// nothing to validate
158
		return null;
159
	}
160
}
(-)src/org/eclipse/mylyn/internal/tasks/ui/wizards/LocalRepositorySettingsPage.java (+62 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.IStatus;
12
import org.eclipse.mylyn.internal.tasks.core.LocalRepositoryConnector;
13
import org.eclipse.mylyn.tasks.core.TaskRepository;
14
import org.eclipse.mylyn.tasks.ui.wizards.AbstractExtensibleRepositorySettingsPage;
15
import org.eclipse.swt.widgets.Composite;
16
import org.eclipse.swt.widgets.Control;
17
import org.eclipse.ui.forms.widgets.ExpandableComposite;
18
19
/**
20
 * A settings page for the local repository properties dialog. Local repositories have no settings, however they may
21
 * have settings contributed via the taskRepositoryPageContribution.
22
 * 
23
 * @author David Green
24
 */
25
public class LocalRepositorySettingsPage extends AbstractExtensibleRepositorySettingsPage {
26
27
	public LocalRepositorySettingsPage(TaskRepository taskRepository) {
28
		super("Local Repository Settings", "Configure the local repository", taskRepository);
29
	}
30
31
	@Override
32
	public String getConnectorKind() {
33
		return LocalRepositoryConnector.CONNECTOR_KIND;
34
	}
35
36
	public String getRepositoryUrl() {
37
		return null;
38
	}
39
40
	@Override
41
	protected void createSettingControls(Composite parent) {
42
		// nothing to do, since the local repository has no settings
43
	}
44
45
	@Override
46
	protected IStatus validate() {
47
		// nothing to do
48
		return null;
49
	}
50
51
	@Override
52
	protected void addContributions(Composite parentControl) {
53
		super.addContributions(parentControl);
54
		// expand the first contribution since we have no other settings
55
		Control[] children = parentControl.getChildren();
56
		if (children.length > 0) {
57
			if (children[0] instanceof ExpandableComposite) {
58
				((ExpandableComposite) children[0]).setExpanded(true);
59
			}
60
		}
61
	}
62
}

Return to bug 244653