001: /*******************************************************************************
002: * Copyright (c) 2003, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal.dialogs;
011:
012: import java.util.ArrayList;
013: import java.util.Collection;
014: import java.util.Iterator;
015:
016: import org.eclipse.core.runtime.jobs.Job;
017: import org.eclipse.jface.action.ToolBarManager;
018: import org.eclipse.jface.dialogs.IDialogConstants;
019: import org.eclipse.jface.preference.IPreferenceNode;
020: import org.eclipse.jface.preference.IPreferencePage;
021: import org.eclipse.jface.preference.PreferenceContentProvider;
022: import org.eclipse.jface.preference.PreferenceDialog;
023: import org.eclipse.jface.preference.PreferenceManager;
024: import org.eclipse.jface.preference.PreferencePage;
025: import org.eclipse.jface.resource.JFaceResources;
026: import org.eclipse.jface.viewers.ISelectionChangedListener;
027: import org.eclipse.jface.viewers.ITreeContentProvider;
028: import org.eclipse.jface.viewers.SelectionChangedEvent;
029: import org.eclipse.jface.viewers.StructuredSelection;
030: import org.eclipse.jface.viewers.TreeViewer;
031: import org.eclipse.jface.viewers.ViewerFilter;
032: import org.eclipse.osgi.util.NLS;
033: import org.eclipse.swt.SWT;
034: import org.eclipse.swt.graphics.Font;
035: import org.eclipse.swt.layout.GridData;
036: import org.eclipse.swt.layout.GridLayout;
037: import org.eclipse.swt.widgets.Composite;
038: import org.eclipse.swt.widgets.Control;
039: import org.eclipse.swt.widgets.Shell;
040: import org.eclipse.swt.widgets.Text;
041: import org.eclipse.ui.activities.WorkbenchActivityHelper;
042: import org.eclipse.ui.dialogs.FilteredTree;
043: import org.eclipse.ui.dialogs.PatternFilter;
044: import org.eclipse.ui.internal.WorkbenchMessages;
045: import org.eclipse.ui.internal.misc.StatusUtil;
046: import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
047: import org.eclipse.ui.preferences.IWorkingCopyManager;
048: import org.eclipse.ui.preferences.WorkingCopyManager;
049: import org.eclipse.ui.statushandlers.StatusManager;
050: import org.osgi.service.prefs.BackingStoreException;
051:
052: /**
053: * Baseclass for preference dialogs that will show two tabs of preferences -
054: * filtered and unfiltered.
055: *
056: * @since 3.0
057: */
058: public abstract class FilteredPreferenceDialog extends PreferenceDialog
059: implements IWorkbenchPreferenceContainer {
060:
061: protected class PreferenceFilteredTree extends FilteredTree {
062: /**
063: * An (optional) additional filter on the TreeViewer.
064: */
065: private ViewerFilter viewerFilter;
066:
067: /**
068: * Initial title of dialog. This is only used if the additional filter provided
069: * by the addFilter(ViewerFilter) method is utilized.
070: */
071: private String cachedTitle;
072:
073: /**
074: * Constructor.
075: *
076: * @param parent parent Composite
077: * @param treeStyle SWT style bits for Tree
078: * @param filter the PatternFilter to use for the TreeViewer
079: */
080: PreferenceFilteredTree(Composite parent, int treeStyle,
081: PatternFilter filter) {
082: super (parent, treeStyle, filter);
083: }
084:
085: /**
086: * Add an additional, optional filter to the viewer.
087: * If the filter text is cleared, this filter will be
088: * removed from the TreeViewer.
089: *
090: * @param filter
091: */
092: protected void addFilter(ViewerFilter filter) {
093: viewerFilter = filter;
094: getViewer().addFilter(filter);
095: setInitialText(WorkbenchMessages.FilteredTree_FilterMessage);
096:
097: if (filterText != null) {
098: setFilterText(WorkbenchMessages.FilteredTree_FilterMessage);
099: textChanged();
100: }
101:
102: cachedTitle = getShell().getText();
103: getShell()
104: .setText(
105: NLS
106: .bind(
107: WorkbenchMessages.FilteredTree_FilteredDialogTitle,
108: cachedTitle));
109: }
110:
111: /*
112: * (non-Javadoc)
113: * @see org.eclipse.ui.dialogs.FilteredTree#updateToolbar(boolean)
114: */
115: protected void updateToolbar(boolean visible) {
116: if (filterToolBar != null) {
117: filterToolBar.getControl().setVisible(
118: viewerFilter != null || visible);
119: }
120: }
121:
122: /* (non-Javadoc)
123: * @see org.eclipse.ui.dialogs.FilteredTree#clearText()
124: */
125: protected void clearText() {
126: setFilterText(""); //$NON-NLS-1$
127: // remove the filter if text is cleared
128: if (viewerFilter != null) {
129: getViewer().removeFilter(viewerFilter);
130: viewerFilter = null;
131: getShell().setText(cachedTitle);
132: }
133: textChanged();
134: }
135: }
136:
137: protected PreferenceFilteredTree filteredTree;
138:
139: private Object pageData;
140:
141: IWorkingCopyManager workingCopyManager;
142:
143: private Collection updateJobs = new ArrayList();
144:
145: /**
146: * The preference page history.
147: *
148: * @since 3.1
149: */
150: PreferencePageHistory history;
151:
152: /**
153: * Creates a new preference dialog under the control of the given preference
154: * manager.
155: *
156: * @param parentShell
157: * the parent shell
158: * @param manager
159: * the preference manager
160: */
161: public FilteredPreferenceDialog(Shell parentShell,
162: PreferenceManager manager) {
163: super (parentShell, manager);
164: history = new PreferencePageHistory(this );
165: }
166:
167: /**
168: * Differs from super implementation in that if the node is found but should
169: * be filtered based on a call to
170: * <code>WorkbenchActivityHelper.filterItem()</code> then
171: * <code>null</code> is returned.
172: *
173: * @see org.eclipse.jface.preference.PreferenceDialog#findNodeMatching(java.lang.String)
174: */
175: protected IPreferenceNode findNodeMatching(String nodeId) {
176: IPreferenceNode node = super .findNodeMatching(nodeId);
177: if (WorkbenchActivityHelper.filterItem(node)) {
178: return null;
179: }
180: return node;
181: }
182:
183: /* (non-Javadoc)
184: * @see org.eclipse.jface.preference.PreferenceDialog#createTreeViewer(org.eclipse.swt.widgets.Composite)
185: */
186: protected TreeViewer createTreeViewer(Composite parent) {
187: int styleBits = SWT.SINGLE | SWT.H_SCROLL;
188: filteredTree = new PreferenceFilteredTree(parent, styleBits,
189: new PreferencePatternFilter());
190: GridData gd = new GridData(SWT.FILL, SWT.FILL, true, true);
191: gd.horizontalIndent = IDialogConstants.HORIZONTAL_MARGIN;
192: filteredTree.setBackground(parent.getDisplay().getSystemColor(
193: SWT.COLOR_LIST_BACKGROUND));
194:
195: TreeViewer tree = filteredTree.getViewer();
196:
197: setContentAndLabelProviders(tree);
198: tree.setInput(getPreferenceManager());
199:
200: //if the tree has only one or zero pages, make the combo area disable
201: if (hasAtMostOnePage(tree)) {
202: Text filterText = filteredTree.getFilterControl();
203: if (filterText != null) {
204: filteredTree.getFilterControl().setEnabled(false);
205: }
206: }
207:
208: tree.addFilter(new CapabilityFilter());
209:
210: tree
211: .addSelectionChangedListener(new ISelectionChangedListener() {
212: /*
213: * (non-Javadoc)
214: *
215: * @see org.eclipse.jface.viewers.ISelectionChangedListener#selectionChanged(org.eclipse.jface.viewers.SelectionChangedEvent)
216: */
217: public void selectionChanged(
218: SelectionChangedEvent event) {
219: handleTreeSelectionChanged(event);
220: }
221: });
222:
223: super .addListeners(filteredTree.getViewer());
224: return filteredTree.getViewer();
225: }
226:
227: /**
228: * Return whether or not there are less than two pages.
229: * @param tree
230: * @return <code>true</code> if there are less than two
231: * pages.
232: */
233: private boolean hasAtMostOnePage(TreeViewer tree) {
234: ITreeContentProvider contentProvider = (ITreeContentProvider) tree
235: .getContentProvider();
236: Object[] children = contentProvider
237: .getElements(tree.getInput());
238:
239: if (children.length <= 1) {
240: if (children.length == 0) {
241: return true;
242: }
243: return !contentProvider.hasChildren(children[0]);
244: }
245: return false;
246: }
247:
248: /**
249: * Set the content and label providers for the treeViewer
250: *
251: * @param treeViewer
252: */
253: protected void setContentAndLabelProviders(TreeViewer treeViewer) {
254: treeViewer.setLabelProvider(new PreferenceBoldLabelProvider(
255: filteredTree));
256: treeViewer.setContentProvider(new PreferenceContentProvider());
257: }
258:
259: /**
260: * A selection has been made in the tree.
261: * @param event SelectionChangedEvent
262: */
263: protected void handleTreeSelectionChanged(
264: SelectionChangedEvent event) {
265: //Do nothing by default
266: }
267:
268: /* (non-Javadoc)
269: * @see org.eclipse.jface.preference.PreferenceDialog#createTreeAreaContents(org.eclipse.swt.widgets.Composite)
270: */
271: protected Control createTreeAreaContents(Composite parent) {
272: Composite leftArea = new Composite(parent, SWT.NONE);
273: leftArea.setBackground(parent.getDisplay().getSystemColor(
274: SWT.COLOR_LIST_BACKGROUND));
275: leftArea.setFont(parent.getFont());
276: GridLayout leftLayout = new GridLayout();
277: leftLayout.numColumns = 1;
278: leftLayout.marginHeight = 0;
279: leftLayout.marginTop = IDialogConstants.VERTICAL_MARGIN;
280: leftLayout.marginWidth = 0;
281: leftLayout.marginLeft = IDialogConstants.HORIZONTAL_MARGIN;
282: leftLayout.horizontalSpacing = 0;
283: leftLayout.verticalSpacing = 0;
284: leftArea.setLayout(leftLayout);
285:
286: // Build the tree an put it into the composite.
287: TreeViewer viewer = createTreeViewer(leftArea);
288: setTreeViewer(viewer);
289:
290: updateTreeFont(JFaceResources.getDialogFont());
291: GridData viewerData = new GridData(GridData.FILL_BOTH
292: | GridData.GRAB_VERTICAL);
293: viewer.getControl().getParent().setLayoutData(viewerData);
294:
295: layoutTreeAreaControl(leftArea);
296:
297: return leftArea;
298: }
299:
300: /**
301: * Show only the supplied ids.
302: *
303: * @param filteredIds
304: */
305: public void showOnly(String[] filteredIds) {
306: filteredTree.addFilter(new PreferenceNodeFilter(filteredIds));
307: }
308:
309: /**
310: * Set the data to be applied to a page after it is created.
311: * @param pageData Object
312: */
313: public void setPageData(Object pageData) {
314: this .pageData = pageData;
315: }
316:
317: /* (non-Javadoc)
318: * @see org.eclipse.jface.preference.PreferenceDialog#createPage(org.eclipse.jface.preference.IPreferenceNode)
319: */
320: protected void createPage(IPreferenceNode node) {
321:
322: super .createPage(node);
323: if (this .pageData == null) {
324: return;
325: }
326: //Apply the data if it has been set.
327: IPreferencePage page = node.getPage();
328: if (page instanceof PreferencePage) {
329: ((PreferencePage) page).applyData(this .pageData);
330: }
331:
332: }
333:
334: /* (non-Javadoc)
335: * @see org.eclipse.jface.preference.PreferenceDialog#getCurrentPage()
336: */
337: public IPreferencePage getCurrentPage() {
338: return super .getCurrentPage();
339: }
340:
341: /* (non-Javadoc)
342: * @see org.eclipse.ui.preferences.IWorkbenchPreferenceContainer#openPage(java.lang.String, java.lang.Object)
343: */
344: public boolean openPage(String pageId, Object data) {
345: setPageData(data);
346: setCurrentPageId(pageId);
347: IPreferencePage page = getCurrentPage();
348: if (page instanceof PreferencePage) {
349: ((PreferencePage) page).applyData(data);
350: }
351: return true;
352: }
353:
354: /**
355: * Selects the current page based on the given preference page identifier.
356: * If no node can be found, then nothing will change.
357: *
358: * @param preferencePageId
359: * The preference page identifier to select; should not be
360: * <code>null</code>.
361: */
362: public final void setCurrentPageId(final String preferencePageId) {
363: final IPreferenceNode node = findNodeMatching(preferencePageId);
364: if (node != null) {
365: getTreeViewer().setSelection(new StructuredSelection(node));
366: showPage(node);
367: }
368: }
369:
370: /* (non-Javadoc)
371: * @see org.eclipse.ui.preferences.IWorkbenchPreferenceContainer#getWorkingCopyManager()
372: */
373: public IWorkingCopyManager getWorkingCopyManager() {
374: if (workingCopyManager == null) {
375: workingCopyManager = new WorkingCopyManager();
376: }
377: return workingCopyManager;
378: }
379:
380: /* (non-Javadoc)
381: * @see org.eclipse.jface.dialogs.Dialog#okPressed()
382: */
383: protected void okPressed() {
384: super .okPressed();
385:
386: if (getReturnCode() == FAILED) {
387: return;
388: }
389:
390: if (workingCopyManager != null) {
391: try {
392: workingCopyManager.applyChanges();
393: } catch (BackingStoreException e) {
394: String msg = e.getMessage();
395: if (msg == null) {
396: msg = WorkbenchMessages.FilteredPreferenceDialog_PreferenceSaveFailed;
397: }
398: StatusUtil
399: .handleStatus(
400: WorkbenchMessages.PreferencesExportDialog_ErrorDialogTitle
401: + ": " + msg, e, StatusManager.SHOW, //$NON-NLS-1$
402: getShell());
403: }
404: }
405:
406: // Run the update jobs
407: Iterator updateIterator = updateJobs.iterator();
408: while (updateIterator.hasNext()) {
409: ((Job) updateIterator.next()).schedule();
410: }
411: }
412:
413: /* (non-Javadoc)
414: * @see org.eclipse.ui.preferences.IWorkbenchPreferenceContainer#registerUpdateJob(org.eclipse.core.runtime.jobs.Job)
415: */
416: public void registerUpdateJob(Job job) {
417: updateJobs.add(job);
418: }
419:
420: /**
421: * Get the toolbar for the container
422: *
423: * @return Control
424: */
425: Control getContainerToolBar(Composite composite) {
426:
427: ToolBarManager historyManager = new ToolBarManager(
428: SWT.HORIZONTAL | SWT.FLAT);
429: historyManager.createControl(composite);
430:
431: history.createHistoryControls(historyManager.getControl(),
432: historyManager);
433:
434: historyManager.update(false);
435:
436: return historyManager.getControl();
437: }
438:
439: /* (non-Javadoc)
440: * @see org.eclipse.jface.preference.PreferenceDialog#showPage(org.eclipse.jface.preference.IPreferenceNode)
441: */
442: protected boolean showPage(IPreferenceNode node) {
443: final boolean success = super .showPage(node);
444: if (success) {
445: history.addHistoryEntry(new PreferenceHistoryEntry(node
446: .getId(), node.getLabelText(), null));
447: }
448: return success;
449: }
450:
451: /* (non-Javadoc)
452: * @see org.eclipse.jface.window.Window#close()
453: */
454: public boolean close() {
455: history.dispose();
456: return super .close();
457: }
458:
459: /* (non-Javadoc)
460: * @see org.eclipse.jface.preference.PreferenceDialog#createTitleArea(org.eclipse.swt.widgets.Composite)
461: */
462: protected Composite createTitleArea(Composite parent) {
463:
464: GridLayout parentLayout = (GridLayout) parent.getLayout();
465: parentLayout.numColumns = 2;
466: parentLayout.marginHeight = 0;
467: parentLayout.marginTop = IDialogConstants.VERTICAL_MARGIN;
468: parent.setLayout(parentLayout);
469:
470: Composite titleComposite = super .createTitleArea(parent);
471:
472: Composite toolbarArea = new Composite(parent, SWT.NONE);
473: GridLayout toolbarLayout = new GridLayout();
474: toolbarLayout.marginHeight = 0;
475: toolbarLayout.verticalSpacing = 0;
476: toolbarArea.setLayout(toolbarLayout);
477: toolbarArea.setLayoutData(new GridData(SWT.END, SWT.FILL,
478: false, true));
479: Control topBar = getContainerToolBar(toolbarArea);
480: topBar.setLayoutData(new GridData(SWT.END, SWT.FILL, false,
481: true));
482:
483: return titleComposite;
484: }
485:
486: protected void selectSavedItem() {
487: getTreeViewer().setInput(getPreferenceManager());
488: super .selectSavedItem();
489: if (getTreeViewer().getTree().getItemCount() > 1) {
490: //unfortunately super will force focus to the list but we want the type ahead combo to get it.
491: Text filterText = filteredTree.getFilterControl();
492: if (filterText != null) {
493: filterText.setFocus();
494: }
495: }
496: }
497:
498: /* (non-Javadoc)
499: * @see org.eclipse.jface.preference.PreferenceDialog#updateTreeFont(org.eclipse.swt.graphics.Font)
500: */
501: protected void updateTreeFont(Font dialogFont) {
502: applyDialogFont(filteredTree);
503: }
504: }
|