001: /*******************************************************************************
002: * Copyright (c) 2000, 2006 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 com.ibm.icu.text.Collator;
013: import java.util.ArrayList;
014: import java.util.Collections;
015: import java.util.Comparator;
016:
017: import org.eclipse.jface.dialogs.IDialogConstants;
018: import org.eclipse.jface.dialogs.MessageDialog;
019: import org.eclipse.jface.preference.IPreferenceStore;
020: import org.eclipse.jface.preference.PreferencePage;
021: import org.eclipse.jface.resource.ImageDescriptor;
022: import org.eclipse.osgi.util.NLS;
023: import org.eclipse.swt.SWT;
024: import org.eclipse.swt.events.SelectionAdapter;
025: import org.eclipse.swt.events.SelectionEvent;
026: import org.eclipse.swt.graphics.Font;
027: import org.eclipse.swt.layout.GridData;
028: import org.eclipse.swt.layout.GridLayout;
029: import org.eclipse.swt.widgets.Button;
030: import org.eclipse.swt.widgets.Composite;
031: import org.eclipse.swt.widgets.Control;
032: import org.eclipse.swt.widgets.Group;
033: import org.eclipse.swt.widgets.Label;
034: import org.eclipse.swt.widgets.Shell;
035: import org.eclipse.swt.widgets.Table;
036: import org.eclipse.swt.widgets.TableItem;
037: import org.eclipse.swt.widgets.Widget;
038: import org.eclipse.ui.IPerspectiveDescriptor;
039: import org.eclipse.ui.IWorkbench;
040: import org.eclipse.ui.IWorkbenchPage;
041: import org.eclipse.ui.IWorkbenchPreferenceConstants;
042: import org.eclipse.ui.IWorkbenchPreferencePage;
043: import org.eclipse.ui.IWorkbenchWindow;
044: import org.eclipse.ui.PlatformUI;
045: import org.eclipse.ui.internal.IPreferenceConstants;
046: import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
047: import org.eclipse.ui.internal.WorkbenchMessages;
048: import org.eclipse.ui.internal.WorkbenchPage;
049: import org.eclipse.ui.internal.WorkbenchPlugin;
050: import org.eclipse.ui.internal.registry.PerspectiveDescriptor;
051: import org.eclipse.ui.internal.registry.PerspectiveRegistry;
052: import org.eclipse.ui.internal.util.Descriptors;
053: import org.eclipse.ui.internal.util.PrefUtil;
054: import org.eclipse.ui.internal.util.Util;
055:
056: /**
057: * The Workbench / Perspectives preference page.
058: */
059: public class PerspectivesPreferencePage extends PreferencePage
060: implements IWorkbenchPreferencePage {
061: private IWorkbench workbench;
062:
063: private PerspectiveRegistry perspectiveRegistry;
064:
065: private ArrayList perspectives;
066:
067: private String defaultPerspectiveId;
068:
069: private ArrayList perspToDelete = new ArrayList();
070:
071: private ArrayList perspToRevert = new ArrayList();
072:
073: private Table perspectivesTable;
074:
075: private Button revertButton;
076:
077: private Button deleteButton;
078:
079: private Button setDefaultButton;
080:
081: // widgets for open perspective mode;
082: private Button openSameWindowButton;
083:
084: private Button openNewWindowButton;
085:
086: private int openPerspMode;
087:
088: // widgets for open view mode
089: private int openViewMode;
090:
091: private Button openEmbedButton;
092:
093: private Button openFastButton;
094:
095: // labels
096: private final String OVM_TITLE = WorkbenchMessages.OpenViewMode_title;
097:
098: private final String OVM_EMBED = WorkbenchMessages.OpenViewMode_embed;
099:
100: private final String OVM_FAST = WorkbenchMessages.OpenViewMode_fast;
101:
102: private final String OPM_TITLE = WorkbenchMessages.OpenPerspectiveMode_optionsTitle;
103:
104: private final String OPM_SAME_WINDOW = WorkbenchMessages.OpenPerspectiveMode_sameWindow;
105:
106: private final String OPM_NEW_WINDOW = WorkbenchMessages.OpenPerspectiveMode_newWindow;
107:
108: /**
109: * <code>Comparator</code> to compare two perspective descriptors
110: */
111: private Comparator comparator = new Comparator() {
112: private Collator collator = Collator.getInstance();
113:
114: public int compare(Object ob1, Object ob2) {
115: IPerspectiveDescriptor d1 = (IPerspectiveDescriptor) ob1;
116: IPerspectiveDescriptor d2 = (IPerspectiveDescriptor) ob2;
117: return collator.compare(d1.getLabel(), d2.getLabel());
118: }
119: };
120:
121: /**
122: * Creates the page's UI content.
123: */
124: protected Control createContents(Composite parent) {
125: // @issue if the product subclasses this page, then it should provide
126: // the help content
127: PlatformUI.getWorkbench().getHelpSystem().setHelp(parent,
128: IWorkbenchHelpContextIds.PERSPECTIVES_PREFERENCE_PAGE);
129:
130: Composite composite = createComposite(parent);
131:
132: createOpenPerspButtonGroup(composite);
133: createOpenViewButtonGroup(composite);
134: createCustomizePerspective(composite);
135:
136: return composite;
137: }
138:
139: /**
140: * Creates the composite which will contain all the preference controls for
141: * this page.
142: *
143: * @param parent
144: * the parent composite
145: * @return the composite for this page
146: */
147: protected Composite createComposite(Composite parent) {
148: Composite composite = new Composite(parent, SWT.NONE);
149: GridData data = new GridData(GridData.FILL_BOTH);
150: composite.setLayoutData(data);
151: composite.setFont(parent.getFont());
152: GridLayout layout = new GridLayout();
153: layout.marginWidth = 0;
154: layout.marginHeight = 0;
155: layout.verticalSpacing = 10;
156: composite.setLayout(layout);
157: return composite;
158: }
159:
160: /**
161: * Create a composite that contains buttons for selecting the open
162: * perspective mode.
163: *
164: * @param composite
165: * the parent composite
166: */
167: protected void createOpenPerspButtonGroup(Composite composite) {
168:
169: Font font = composite.getFont();
170:
171: Group buttonComposite = new Group(composite, SWT.LEFT);
172: buttonComposite.setText(OPM_TITLE);
173: buttonComposite.setLayoutData(new GridData(
174: GridData.FILL_HORIZONTAL));
175: buttonComposite.setFont(composite.getFont());
176: GridLayout layout = new GridLayout();
177: layout.numColumns = 2;
178: buttonComposite.setLayout(layout);
179:
180: openSameWindowButton = new Button(buttonComposite, SWT.RADIO);
181: openSameWindowButton.setText(OPM_SAME_WINDOW);
182: openSameWindowButton
183: .setSelection(IPreferenceConstants.OPM_ACTIVE_PAGE == openPerspMode);
184: openSameWindowButton.setFont(font);
185: openSameWindowButton
186: .addSelectionListener(new SelectionAdapter() {
187: public void widgetSelected(SelectionEvent e) {
188: openPerspMode = IPreferenceConstants.OPM_ACTIVE_PAGE;
189: }
190: });
191:
192: openNewWindowButton = new Button(buttonComposite, SWT.RADIO);
193: openNewWindowButton.setText(OPM_NEW_WINDOW);
194: openNewWindowButton
195: .setSelection(IPreferenceConstants.OPM_NEW_WINDOW == openPerspMode);
196: openNewWindowButton.setFont(font);
197: openNewWindowButton
198: .addSelectionListener(new SelectionAdapter() {
199: public void widgetSelected(SelectionEvent e) {
200: openPerspMode = IPreferenceConstants.OPM_NEW_WINDOW;
201: }
202: });
203:
204: }
205:
206: /**
207: * Creates a composite that contains buttons for selecting open view mode.
208: *
209: * @param composite
210: * the parent composite
211: */
212: protected void createOpenViewButtonGroup(Composite composite) {
213:
214: Font font = composite.getFont();
215:
216: Group buttonComposite = new Group(composite, SWT.LEFT);
217: buttonComposite.setText(OVM_TITLE);
218: buttonComposite.setLayoutData(new GridData(
219: GridData.FILL_HORIZONTAL));
220: buttonComposite.setFont(composite.getFont());
221: GridLayout layout = new GridLayout();
222: layout.numColumns = 2;
223: buttonComposite.setLayout(layout);
224:
225: openEmbedButton = new Button(buttonComposite, SWT.RADIO);
226: openEmbedButton.setText(OVM_EMBED);
227: openEmbedButton
228: .setSelection(openViewMode == IPreferenceConstants.OVM_EMBED);
229: openEmbedButton.addSelectionListener(new SelectionAdapter() {
230: public void widgetSelected(SelectionEvent e) {
231: openViewMode = IPreferenceConstants.OVM_EMBED;
232: }
233: });
234: openEmbedButton.setFont(font);
235:
236: // Open view as float no longer supported
237: if (openViewMode == IPreferenceConstants.OVM_FLOAT) {
238: openViewMode = IPreferenceConstants.OVM_FAST;
239: }
240:
241: openFastButton = new Button(buttonComposite, SWT.RADIO);
242: openFastButton.setText(OVM_FAST);
243: openFastButton
244: .setSelection(openViewMode == IPreferenceConstants.OVM_FAST);
245: openFastButton.addSelectionListener(new SelectionAdapter() {
246: public void widgetSelected(SelectionEvent e) {
247: openViewMode = IPreferenceConstants.OVM_FAST;
248: }
249: });
250: openFastButton.setFont(font);
251:
252: }
253:
254: /**
255: * Create a table of 3 buttons to enable the user to manage customized
256: * perspectives.
257: *
258: * @param parent
259: * the parent for the button parent
260: * @return Composite that the buttons are created in.
261: */
262: protected Composite createCustomizePerspective(Composite parent) {
263:
264: Font font = parent.getFont();
265:
266: // define container & its gridding
267: Composite perspectivesComponent = new Composite(parent,
268: SWT.NONE);
269: perspectivesComponent.setLayoutData(new GridData(
270: GridData.FILL_BOTH));
271: perspectivesComponent.setFont(parent.getFont());
272:
273: GridLayout layout = new GridLayout();
274: layout.numColumns = 2;
275: layout.marginWidth = 0;
276: layout.marginHeight = 0;
277: perspectivesComponent.setLayout(layout);
278:
279: // Add the label
280: Label label = new Label(perspectivesComponent, SWT.LEFT);
281: label
282: .setText(WorkbenchMessages.PerspectivesPreference_available);
283: GridData data = new GridData();
284: data.horizontalSpan = 2;
285: label.setLayoutData(data);
286: label.setFont(font);
287:
288: // Add perspectivesTable.
289: perspectivesTable = new Table(perspectivesComponent,
290: SWT.H_SCROLL | SWT.V_SCROLL | SWT.BORDER);
291: perspectivesTable.addSelectionListener(new SelectionAdapter() {
292: public void widgetSelected(SelectionEvent e) {
293: updateButtons();
294: }
295: });
296: perspectivesTable.setFont(font);
297:
298: data = new GridData(GridData.FILL_BOTH);
299: data.grabExcessHorizontalSpace = true;
300: data.grabExcessVerticalSpace = true;
301: perspectivesTable.setLayoutData(data);
302:
303: // Populate the perspectivesTable
304: IPerspectiveDescriptor[] persps = perspectiveRegistry
305: .getPerspectives();
306: perspectives = new ArrayList(persps.length);
307: for (int i = 0; i < persps.length; i++) {
308: perspectives.add(i, persps[i]);
309: }
310: Collections.sort(perspectives, comparator);
311: defaultPerspectiveId = perspectiveRegistry
312: .getDefaultPerspective();
313: updatePerspectivesTable();
314:
315: // Create vertical button bar.
316: Composite buttonBar = (Composite) createVerticalButtonBar(perspectivesComponent);
317: data = new GridData(GridData.FILL_VERTICAL);
318: buttonBar.setLayoutData(data);
319:
320: //Add note label
321: String NOTE_LABEL = WorkbenchMessages.Preference_note;
322: String REVERT_NOTE = WorkbenchMessages.RevertPerspective_note;
323: Composite noteComposite = createNoteComposite(font, parent,
324: NOTE_LABEL, REVERT_NOTE);
325: GridData noteData = new GridData();
326: noteData.horizontalSpan = 2;
327: noteComposite.setLayoutData(noteData);
328: return perspectivesComponent;
329: }
330:
331: /**
332: * Creates a new vertical button with the given id.
333: * <p>
334: * The default implementation of this framework method creates a standard
335: * push button, registers for selection events including button presses and
336: * help requests, and registers default buttons with its shell. The button
337: * id is stored as the buttons client data.
338: * </p>
339: *
340: * @param parent
341: * the parent composite
342: * @param label
343: * the label from the button
344: * @param defaultButton
345: * <code>true</code> if the button is to be the default button,
346: * and <code>false</code> otherwise
347: * @return Button The created button.
348: */
349: protected Button createVerticalButton(Composite parent,
350: String label, boolean defaultButton) {
351: Button button = new Button(parent, SWT.PUSH);
352:
353: button.setText(label);
354:
355: GridData data = setButtonLayoutData(button);
356: data.horizontalAlignment = GridData.FILL;
357:
358: button.addSelectionListener(new SelectionAdapter() {
359: public void widgetSelected(SelectionEvent event) {
360: verticalButtonPressed(event.widget);
361: }
362: });
363: button.setToolTipText(label);
364: if (defaultButton) {
365: Shell shell = parent.getShell();
366: if (shell != null) {
367: shell.setDefaultButton(button);
368: }
369: }
370: button.setFont(parent.getFont());
371: return button;
372: }
373:
374: /**
375: * Creates and returns the vertical button bar.
376: *
377: * @param parent
378: * the parent composite to contain the button bar
379: * @return the button bar control
380: */
381: protected Control createVerticalButtonBar(Composite parent) {
382: // Create composite.
383: Composite composite = new Composite(parent, SWT.NULL);
384:
385: // create a layout with spacing and margins appropriate for the font
386: // size.
387: GridLayout layout = new GridLayout();
388: layout.numColumns = 1;
389: layout.marginWidth = 5;
390: layout.marginHeight = 0;
391: layout.horizontalSpacing = convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING);
392: layout.verticalSpacing = convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING);
393: composite.setLayout(layout);
394: composite.setFont(parent.getFont());
395:
396: // Add the buttons to the button bar.
397: setDefaultButton = createVerticalButton(composite,
398: WorkbenchMessages.PerspectivesPreference_MakeDefault,
399: false);
400: setDefaultButton
401: .setToolTipText(WorkbenchMessages.PerspectivesPreference_MakeDefaultTip);
402:
403: revertButton = createVerticalButton(composite,
404: WorkbenchMessages.PerspectivesPreference_Reset, false);
405: revertButton
406: .setToolTipText(WorkbenchMessages.PerspectivesPreference_ResetTip);
407:
408: deleteButton = createVerticalButton(composite,
409: WorkbenchMessages.PerspectivesPreference_Delete, false);
410: deleteButton
411: .setToolTipText(WorkbenchMessages.PerspectivesPreference_DeleteTip);
412: updateButtons();
413:
414: return composite;
415: }
416:
417: /**
418: * @see IWorkbenchPreferencePage
419: */
420: public void init(IWorkbench aWorkbench) {
421: this .workbench = aWorkbench;
422: this .perspectiveRegistry = (PerspectiveRegistry) workbench
423: .getPerspectiveRegistry();
424: IPreferenceStore store = WorkbenchPlugin.getDefault()
425: .getPreferenceStore();
426: setPreferenceStore(store);
427:
428: openViewMode = store
429: .getInt(IPreferenceConstants.OPEN_VIEW_MODE);
430: openPerspMode = store
431: .getInt(IPreferenceConstants.OPEN_PERSP_MODE);
432: }
433:
434: /**
435: * The default button has been pressed.
436: */
437: protected void performDefaults() {
438: //Project perspective preferences
439: IPreferenceStore store = WorkbenchPlugin.getDefault()
440: .getPreferenceStore();
441:
442: openViewMode = store
443: .getDefaultInt(IPreferenceConstants.OPEN_VIEW_MODE);
444: // Open view as float no longer supported
445: if (openViewMode == IPreferenceConstants.OVM_FLOAT) {
446: openViewMode = IPreferenceConstants.OVM_FAST;
447: }
448: openEmbedButton
449: .setSelection(openViewMode == IPreferenceConstants.OVM_EMBED);
450: openFastButton
451: .setSelection(openViewMode == IPreferenceConstants.OVM_FAST);
452:
453: openPerspMode = store
454: .getDefaultInt(IPreferenceConstants.OPEN_PERSP_MODE);
455: openSameWindowButton
456: .setSelection(IPreferenceConstants.OPM_ACTIVE_PAGE == openPerspMode);
457: openNewWindowButton
458: .setSelection(IPreferenceConstants.OPM_NEW_WINDOW == openPerspMode);
459:
460: String currentDefault = perspectiveRegistry
461: .getDefaultPerspective();
462:
463: int index = indexOf(currentDefault);
464: if (index >= 0) {
465: defaultPerspectiveId = currentDefault;
466: updatePerspectivesTable();
467: perspectivesTable.setSelection(index);
468: }
469:
470: String newDefault = PrefUtil
471: .getAPIPreferenceStore()
472: .getDefaultString(
473: IWorkbenchPreferenceConstants.DEFAULT_PERSPECTIVE_ID);
474:
475: IPerspectiveDescriptor desc = null;
476: if (newDefault != null) {
477: desc = workbench.getPerspectiveRegistry()
478: .findPerspectiveWithId(newDefault);
479: }
480: if (desc == null) {
481: newDefault = workbench.getPerspectiveRegistry()
482: .getDefaultPerspective();
483: }
484:
485: defaultPerspectiveId = newDefault;
486: updatePerspectivesTable();
487:
488: }
489:
490: /**
491: * Look up the index of the perpective with the given if.
492: * @param perspectiveId or <code>null</code>
493: * @return int -1 if it cannot be found
494: */
495: private int indexOf(String perspectiveId) {
496: if (perspectiveId == null) {
497: return -1;
498: }
499: PerspectiveDescriptor[] descriptors = new PerspectiveDescriptor[perspectives
500: .size()];
501: perspectives.toArray(descriptors);
502: for (int i = 0; i < descriptors.length; i++) {
503: PerspectiveDescriptor descriptor = descriptors[i];
504: if (descriptor.getId().equals(perspectiveId)) {
505: return i;
506: }
507: }
508: return -1;
509: }
510:
511: /**
512: * Deletes the perspectives selected by the user if there is no opened
513: * instance of that perspective.
514: *
515: * @return boolean <code>true</code> if all of the perspectives could be
516: * deleted.
517: */
518: private boolean findOpenInstance(IPerspectiveDescriptor desc) {
519: IWorkbenchWindow windows[] = workbench.getWorkbenchWindows();
520:
521: //find all active perspectives currently
522: for (int i = 0; i < windows.length; i++) {
523: IWorkbenchPage pages[] = windows[i].getPages();
524: for (int j = 0; j < pages.length; j++) {
525: WorkbenchPage page = (WorkbenchPage) pages[j];
526: if (page.findPerspective(desc) != null) {
527: MessageDialog
528: .openInformation(
529: getShell(),
530: WorkbenchMessages.PerspectivesPreference_cannotdelete_title,
531: NLS
532: .bind(
533: WorkbenchMessages.PerspectivesPreference_cannotdelete_message,
534: desc.getLabel()));
535: return true;
536: }
537: }
538: }
539:
540: return false;
541: }
542:
543: /**
544: * Apply the user's changes if any
545: */
546: public boolean performOk() {
547: // Set the default perspective
548: if (!Util.equals(defaultPerspectiveId, perspectiveRegistry
549: .getDefaultPerspective())) {
550: perspectiveRegistry
551: .setDefaultPerspective(defaultPerspectiveId);
552: }
553:
554: //Delete the perspective
555: if (perspectives.size() < perspectiveRegistry.getPerspectives().length) {
556: perspectiveRegistry.deletePerspectives(perspToDelete);
557: }
558:
559: // Revert the perspectives
560: perspectiveRegistry.revertPerspectives(perspToRevert);
561:
562: IPreferenceStore store = getPreferenceStore();
563:
564: // store the open view mode setting
565: store.setValue(IPreferenceConstants.OPEN_VIEW_MODE,
566: openViewMode);
567:
568: // store the open perspective mode setting
569: store.setValue(IPreferenceConstants.OPEN_PERSP_MODE,
570: openPerspMode);
571:
572: // save both the API prefs and the internal prefs
573: // the API prefs are modified by
574: // PerspectiveRegistry.setDefaultPerspective
575: PrefUtil.savePrefs();
576:
577: return true;
578: }
579:
580: /**
581: * Update the button enablement state.
582: */
583: protected void updateButtons() {
584: // Get selection.
585: int index = perspectivesTable.getSelectionIndex();
586:
587: // Map it to the perspective descriptor
588: PerspectiveDescriptor desc = null;
589: if (index > -1) {
590: desc = (PerspectiveDescriptor) perspectives.get(index);
591: }
592:
593: // Do enable.
594: if (desc != null) {
595: revertButton.setEnabled(desc.isPredefined()
596: && desc.hasCustomDefinition()
597: && !perspToRevert.contains(desc));
598: deleteButton.setEnabled(!desc.isPredefined());
599: setDefaultButton.setEnabled(true);
600: } else {
601: revertButton.setEnabled(false);
602: deleteButton.setEnabled(false);
603: setDefaultButton.setEnabled(false);
604: }
605: }
606:
607: /**
608: * Update the perspectivesTable.
609: */
610: protected void updatePerspectivesTable() {
611: // Populate the table with the items
612: perspectivesTable.removeAll();
613: for (int i = 0; i < perspectives.size(); i++) {
614: PerspectiveDescriptor persp = (PerspectiveDescriptor) perspectives
615: .get(i);
616: newPerspectivesTableItem(persp, i, false);
617: }
618: }
619:
620: /**
621: * Create a new tableItem using given perspective, and set image for the new item.
622: */
623: protected TableItem newPerspectivesTableItem(
624: IPerspectiveDescriptor persp, int index, boolean selected) {
625:
626: ImageDescriptor image = persp.getImageDescriptor();
627:
628: TableItem item = new TableItem(perspectivesTable, SWT.NULL,
629: index);
630: if (image != null) {
631: Descriptors.setImage(item, image);
632: }
633: String label = persp.getLabel();
634: if (persp.getId().equals(defaultPerspectiveId)) {
635: label = NLS
636: .bind(
637: WorkbenchMessages.PerspectivesPreference_defaultLabel,
638: label);
639:
640: }
641: item.setText(label);
642: item.setData(persp);
643: if (selected) {
644: perspectivesTable.setSelection(index);
645: }
646:
647: return item;
648: }
649:
650: /**
651: * Notifies that this page's button with the given id has been pressed.
652: *
653: * @param button
654: * the button that was pressed
655: */
656: protected void verticalButtonPressed(Widget button) {
657: // Get selection.
658: int index = perspectivesTable.getSelectionIndex();
659:
660: // Map it to the perspective descriptor
661: PerspectiveDescriptor desc = null;
662: if (index > -1) {
663: desc = (PerspectiveDescriptor) perspectives.get(index);
664: } else {
665: return;
666: }
667:
668: // Take action.
669: if (button == revertButton) {
670: if (desc.isPredefined() && !perspToRevert.contains(desc)) {
671: perspToRevert.add(desc);
672: }
673: } else if (button == deleteButton) {
674: if (!desc.isPredefined() && !perspToDelete.contains(desc)) {
675: if (!findOpenInstance(desc)) {
676: perspToDelete.add(desc);
677: perspToRevert.remove(desc);
678: perspectives.remove(desc);
679: updatePerspectivesTable();
680: }
681:
682: }
683: } else if (button == setDefaultButton) {
684: defaultPerspectiveId = desc.getId();
685: updatePerspectivesTable();
686: perspectivesTable.setSelection(index);
687: }
688:
689: updateButtons();
690: }
691:
692: public void dispose() {
693: super.dispose();
694: }
695: }
|