1 /*******************************************************************************
2  * Copyright (c) 2003 Berthold Daum.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Common Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/cpl-v10.html
7  *
8  * Contributors:
9  *     Berthold Daum
10  *******************************************************************************/
11 package net.sourceforge.phpeclipse.ui.overlaypages;
12 
13 import java.util.ArrayList;
14 import java.util.Iterator;
15 import java.util.List;
16 
17 import org.eclipse.core.resources.IResource;
18 import org.eclipse.core.runtime.CoreException;
19 import org.eclipse.core.runtime.IAdaptable;
20 import org.eclipse.core.runtime.QualifiedName;
21 import org.eclipse.jface.preference.FieldEditor;
22 import org.eclipse.jface.preference.FieldEditorPreferencePage;
23 import org.eclipse.jface.preference.IPreferenceNode;
24 import org.eclipse.jface.preference.IPreferencePage;
25 import org.eclipse.jface.preference.IPreferenceStore;
26 import org.eclipse.jface.preference.PreferenceDialog;
27 import org.eclipse.jface.preference.PreferenceManager;
28 import org.eclipse.jface.preference.PreferenceNode;
29 import org.eclipse.jface.resource.ImageDescriptor;
30 import org.eclipse.swt.SWT;
31 import org.eclipse.swt.custom.BusyIndicator;
32 import org.eclipse.swt.events.SelectionAdapter;
33 import org.eclipse.swt.events.SelectionEvent;
34 import org.eclipse.swt.layout.GridData;
35 import org.eclipse.swt.layout.GridLayout;
36 import org.eclipse.swt.widgets.Button;
37 import org.eclipse.swt.widgets.Composite;
38 import org.eclipse.swt.widgets.Control;
39 import org.eclipse.ui.IWorkbenchPropertyPage;
40 
41 /**
42  * @author Berthold Daum
43  */
44 public abstract class FieldEditorOverlayPage extends FieldEditorPreferencePage
45 		implements IWorkbenchPropertyPage {
46 	/**
47 	 * * Name of resource property for the selection of workbench or project
48 	 * settings **
49 	 */
50 	public static final String USEPROJECTSETTINGS = "useProjectSettings"; //$NON-NLS-1$
51 
52 	private static final String FALSE = "false"; //$NON-NLS-1$
53 
54 	private static final String TRUE = "true"; //$NON-NLS-1$
55 
56 	private boolean fUseFileSettings = false;
57 
58 	// Stores all created field editors
59 	private List editors = new ArrayList();
60 
61 	// Stores owning element of properties
62 	private IAdaptable element;
63 
64 	// Additional buttons for property pages
65 	private Button useWorkspaceSettingsButton, useProjectSettingsButton,
66 			configureButton;
67 
68 	// Overlay preference store for property pages
69 	private IPreferenceStore overlayStore;
70 
71 	// The image descriptor of this pages title image
72 	private ImageDescriptor image;
73 
74 	// Cache for page id
75 	private String pageId;
76 
77 	/**
78 	 * Constructor
79 	 *
80 	 * @param style -
81 	 *            layout style
82 	 */
FieldEditorOverlayPage(int style)83 	public FieldEditorOverlayPage(int style) {
84 		super(style);
85 	}
86 
87 	/**
88 	 * Constructor
89 	 *
90 	 * @param style -
91 	 *            layout style
92 	 */
FieldEditorOverlayPage(int style, boolean isFileSettings)93 	public FieldEditorOverlayPage(int style, boolean isFileSettings) {
94 		super(style);
95 		fUseFileSettings = isFileSettings;
96 	}
97 
98 	/**
99 	 * Constructor
100 	 *
101 	 * @param title -
102 	 *            title string
103 	 * @param style -
104 	 *            layout style
105 	 */
FieldEditorOverlayPage(String title, int style)106 	public FieldEditorOverlayPage(String title, int style) {
107 		super(title, style);
108 	}
109 
FieldEditorOverlayPage(String title, int style, boolean isFileSettings)110 	public FieldEditorOverlayPage(String title, int style,
111 			boolean isFileSettings) {
112 		super(title, style);
113 		fUseFileSettings = isFileSettings;
114 	}
115 
116 	/**
117 	 * Constructor
118 	 *
119 	 * @param title -
120 	 *            title string
121 	 * @param image -
122 	 *            title image
123 	 * @param style -
124 	 *            layout style
125 	 */
FieldEditorOverlayPage(String title, ImageDescriptor image, int style)126 	public FieldEditorOverlayPage(String title, ImageDescriptor image, int style) {
127 		super(title, image, style);
128 		this.image = image;
129 	}
130 
131 	/**
132 	 * Returns the id of the current preference page as defined in plugin.xml
133 	 * Subclasses must implement.
134 	 *
135 	 * @return - the qualifier
136 	 */
getPageId()137 	protected abstract String getPageId();
138 
139 	/**
140 	 * Receives the object that owns the properties shown in this property page.
141 	 *
142 	 * @see org.eclipse.ui.IWorkbenchPropertyPage#setElement(org.eclipse.core.runtime.IAdaptable)
143 	 */
setElement(IAdaptable element)144 	public void setElement(IAdaptable element) {
145 		this.element = element;
146 	}
147 
148 	/**
149 	 * Delivers the object that owns the properties shown in this property page.
150 	 *
151 	 * @see org.eclipse.ui.IWorkbenchPropertyPage#getElement()
152 	 */
getElement()153 	public IAdaptable getElement() {
154 		return element;
155 	}
156 
157 	/**
158 	 * Returns true if this instance represents a property page
159 	 *
160 	 * @return - true for property pages, false for preference pages
161 	 */
isPropertyPage()162 	public boolean isPropertyPage() {
163 		return getElement() != null;
164 	}
165 
166 	/**
167 	 * We override the addField method. This allows us to store each field
168 	 * editor added by subclasses in a list for later processing.
169 	 *
170 	 * @see org.eclipse.jface.preference.FieldEditorPreferencePage#addField(org.eclipse.jface.preference.FieldEditor)
171 	 */
addField(FieldEditor editor)172 	protected void addField(FieldEditor editor) {
173 		editors.add(editor);
174 		super.addField(editor);
175 	}
176 
177 	/**
178 	 * We override the createControl method. In case of property pages we create
179 	 * a new PropertyStore as local preference store. After all control have
180 	 * been create, we enable/disable these controls.
181 	 *
182 	 * @see org.eclipse.jface.preference.PreferencePage#createControl()
183 	 */
createControl(Composite parent)184 	public void createControl(Composite parent) {
185 		// Special treatment for property pages
186 		if (isPropertyPage()) {
187 			// Cache the page id
188 			pageId = getPageId();
189 			// Create an overlay preference store and fill it with properties
190 			overlayStore = new PropertyStore((IResource) getElement(), super
191 					.getPreferenceStore(), pageId);
192 			// Set overlay store as current preference store
193 		}
194 		super.createControl(parent);
195 		// Update state of all subclass controls
196 		if (isPropertyPage())
197 			updateFieldEditors();
198 	}
199 
200 	/**
201 	 * We override the createContents method. In case of property pages we
202 	 * insert two radio buttons at the top of the page.
203 	 *
204 	 * @see org.eclipse.jface.preference.PreferencePage#createContents(org.eclipse.swt.widgets.Composite)
205 	 */
createContents(Composite parent)206 	protected Control createContents(Composite parent) {
207 		if (isPropertyPage())
208 			createSelectionGroup(parent);
209 		return super.createContents(parent);
210 	}
211 
212 	/**
213 	 * Creates and initializes a selection group with two choice buttons and one
214 	 * push button.
215 	 *
216 	 * @param parent -
217 	 *            the parent composite
218 	 */
createSelectionGroup(Composite parent)219 	private void createSelectionGroup(Composite parent) {
220 		Composite comp = new Composite(parent, SWT.NONE);
221 		GridLayout layout = new GridLayout(2, false);
222 		layout.marginHeight = 0;
223 		layout.marginWidth = 0;
224 		comp.setLayout(layout);
225 		comp.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
226 		Composite radioGroup = new Composite(comp, SWT.NONE);
227 		radioGroup.setLayout(new GridLayout());
228 		radioGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
229 		useWorkspaceSettingsButton = createRadioButton(radioGroup, Messages
230 				.getString("OverlayPage.Use_Workspace_Settings")); //$NON-NLS-1$
231 		if (fUseFileSettings) {
232 			useProjectSettingsButton = createRadioButton(radioGroup, Messages
233 					.getString("OverlayPage.Use_File_Settings")); //$NON-NLS-1$
234 		} else {
235 			useProjectSettingsButton = createRadioButton(radioGroup, Messages
236 					.getString("OverlayPage.Use_Project_Settings")); //$NON-NLS-1$
237 		}
238 		configureButton = new Button(comp, SWT.PUSH);
239 		configureButton.setText(Messages
240 				.getString("OverlayPage.Configure_Workspace_Settings")); //$NON-NLS-1$
241 		configureButton.addSelectionListener(new SelectionAdapter() {
242 			public void widgetSelected(SelectionEvent e) {
243 				configureWorkspaceSettings();
244 			}
245 		});
246 		// Set workspace/project radio buttons
247 		try {
248 			String use = ((IResource) getElement())
249 					.getPersistentProperty(new QualifiedName(pageId,
250 							USEPROJECTSETTINGS));
251 			if (TRUE.equals(use)) {
252 				useProjectSettingsButton.setSelection(true);
253 				configureButton.setEnabled(false);
254 			} else
255 				useWorkspaceSettingsButton.setSelection(true);
256 		} catch (CoreException e) {
257 			useWorkspaceSettingsButton.setSelection(true);
258 		}
259 	}
260 
261 	/**
262 	 * Convenience method creating a radio button
263 	 *
264 	 * @param parent -
265 	 *            the parent composite
266 	 * @param label -
267 	 *            the button label
268 	 * @return - the new button
269 	 */
createRadioButton(Composite parent, String label)270 	private Button createRadioButton(Composite parent, String label) {
271 		final Button button = new Button(parent, SWT.RADIO);
272 		button.setText(label);
273 		button.addSelectionListener(new SelectionAdapter() {
274 			public void widgetSelected(SelectionEvent e) {
275 				configureButton
276 						.setEnabled(button == useWorkspaceSettingsButton);
277 				updateFieldEditors();
278 			}
279 		});
280 		return button;
281 	}
282 
283 	/**
284 	 * Returns in case of property pages the overlay store, in case of
285 	 * preference pages the standard preference store
286 	 *
287 	 * @see org.eclipse.jface.preference.PreferencePage#getPreferenceStore()
288 	 */
getPreferenceStore()289 	public IPreferenceStore getPreferenceStore() {
290 		if (isPropertyPage())
291 			return overlayStore;
292 		return super.getPreferenceStore();
293 	}
294 
295 	/*
296 	 * Enables or disables the field editors and buttons of this page
297 	 */
updateFieldEditors()298 	private void updateFieldEditors() {
299 		// We iterate through all field editors
300 		boolean enabled = useProjectSettingsButton.getSelection();
301 		updateFieldEditors(enabled);
302 	}
303 
304 	/**
305 	 * Enables or disables the field editors and buttons of this page Subclasses
306 	 * may override.
307 	 *
308 	 * @param enabled -
309 	 *            true if enabled
310 	 */
updateFieldEditors(boolean enabled)311 	protected void updateFieldEditors(boolean enabled) {
312 		Composite parent = getFieldEditorParent();
313 		Iterator it = editors.iterator();
314 		while (it.hasNext()) {
315 			FieldEditor editor = (FieldEditor) it.next();
316 			editor.setEnabled(enabled, parent);
317 		}
318 	}
319 
320 	/**
321 	 * We override the performOk method. In case of property pages we copy the
322 	 * values in the overlay store into the property values of the selected
323 	 * project. We also save the state of the radio buttons.
324 	 *
325 	 * @see org.eclipse.jface.preference.IPreferencePage#performOk()
326 	 */
performOk()327 	public boolean performOk() {
328 		boolean result = super.performOk();
329 		if (result && isPropertyPage()) {
330 			// Save state of radiobuttons in project properties
331 			IResource resource = (IResource) getElement();
332 			try {
333 				String value = (useProjectSettingsButton.getSelection()) ? TRUE
334 						: FALSE;
335 				resource.setPersistentProperty(new QualifiedName(pageId,
336 						USEPROJECTSETTINGS), value);
337 			} catch (CoreException e) {
338 			}
339 		}
340 		return result;
341 	}
342 
343 	/**
344 	 * We override the performDefaults method. In case of property pages we
345 	 * switch back to the workspace settings and disable the field editors.
346 	 *
347 	 * @see org.eclipse.jface.preference.PreferencePage#performDefaults()
348 	 */
performDefaults()349 	protected void performDefaults() {
350 		if (isPropertyPage()) {
351 			useWorkspaceSettingsButton.setSelection(true);
352 			useProjectSettingsButton.setSelection(false);
353 			configureButton.setEnabled(true);
354 			updateFieldEditors();
355 		}
356 		super.performDefaults();
357 	}
358 
359 	/**
360 	 * Creates a new preferences page and opens it
361 	 *
362 	 * @see com.bdaum.SpellChecker.preferences.SpellCheckerPreferencePage#configureWorkspaceSettings()
363 	 */
configureWorkspaceSettings()364 	protected void configureWorkspaceSettings() {
365 		try {
366 			// create a new instance of the current class
367 			IPreferencePage page = (IPreferencePage) this.getClass()
368 					.newInstance();
369 			page.setTitle(getTitle());
370 			page.setImageDescriptor(image);
371 			// and show it
372 			showPreferencePage(pageId, page);
373 		} catch (InstantiationException e) {
374 			e.printStackTrace();
375 		} catch (IllegalAccessException e) {
376 			e.printStackTrace();
377 		}
378 	}
379 
380 	/**
381 	 * Show a single preference pages
382 	 *
383 	 * @param id -
384 	 *            the preference page identification
385 	 * @param page -
386 	 *            the preference page
387 	 */
showPreferencePage(String id, IPreferencePage page)388 	protected void showPreferencePage(String id, IPreferencePage page) {
389 		final IPreferenceNode targetNode = new PreferenceNode(id, page);
390 		PreferenceManager manager = new PreferenceManager();
391 		manager.addToRoot(targetNode);
392 		final PreferenceDialog dialog = new PreferenceDialog(getControl()
393 				.getShell(), manager);
394 		BusyIndicator.showWhile(getControl().getDisplay(), new Runnable() {
395 			public void run() {
396 				dialog.create();
397 				dialog.setMessage(targetNode.getLabelText());
398 				dialog.open();
399 			}
400 		});
401 	}
402 }
403