blob: f675fc96ec767802947eac4f319735db6d2fe04b [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2006 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.ui.internal.dialogs;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.content.IContentType;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.preference.PreferencePage;
import org.eclipse.jface.window.Window;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IFileEditorMapping;
import org.eclipse.ui.IWorkbench;
import org.eclipse.ui.IWorkbenchPreferencePage;
import org.eclipse.ui.dialogs.PreferenceLinkArea;
import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
import org.eclipse.ui.internal.WorkbenchMessages;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.internal.registry.EditorDescriptor;
import org.eclipse.ui.internal.registry.EditorRegistry;
import org.eclipse.ui.internal.registry.FileEditorMapping;
import org.eclipse.ui.internal.util.PrefUtil;
import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
/**
* The file editors page presents the collection of file names and extensions
* for which the user has registered editors. It also lets the user add new
* internal or external (program) editors for a given file name and extension.
*
* The user can add an editor for either a specific file name and extension
* (e.g. report.doc), or for all file names of a given extension (e.g. *.doc)
*
* The set of registered editors is tracked by the EditorRegistery
* available from the workbench plugin.
*/
public class FileEditorsPreferencePage extends PreferencePage implements
IWorkbenchPreferencePage, Listener {
private static final String DATA_EDITOR = "editor"; //$NON-NLS-1$
private static final String DATA_FROM_CONTENT_TYPE = "type"; //$NON-NLS-1$
protected Table resourceTypeTable;
protected Button addResourceTypeButton;
protected Button removeResourceTypeButton;
protected Table editorTable;
protected Button addEditorButton;
protected Button removeEditorButton;
protected Button defaultEditorButton;
protected Label editorLabel;
protected IWorkbench workbench;
protected List imagesToDispose;
protected Map editorsToImages;
/**
* Add a new resource type to the collection shown in the top of the page.
* This is typically called after the extension dialog is shown to the user.
*
* @param newName the new name
* @param newExtension the new extension
*/
public void addResourceType(String newName, String newExtension) {
// Either a file name or extension must be provided
Assert.isTrue((newName != null && newName.length() != 0)
|| (newExtension != null && newExtension.length() != 0));
// Wild card only valid by itself (i.e. rep* is not valid)
// And must have an extension
int index = newName.indexOf('*');
if (index > -1) {
Assert.isTrue(index == 0 && newName.length() == 1);
Assert.isTrue(newExtension != null && newExtension.length() != 0);
}
// Find the index at which to insert the new entry.
String newFilename = (newName + (newExtension == null
|| newExtension.length() == 0 ? "" : "." + newExtension)).toUpperCase();//$NON-NLS-1$ //$NON-NLS-2$
IFileEditorMapping resourceType;
TableItem[] items = resourceTypeTable.getItems();
boolean found = false;
int i = 0;
while (i < items.length && !found) {
resourceType = (IFileEditorMapping) items[i].getData();
int result = newFilename.compareToIgnoreCase(resourceType
.getLabel());
if (result == 0) {
// Same resource type not allowed!
MessageDialog
.openInformation(
getControl().getShell(),
WorkbenchMessages.FileEditorPreference_existsTitle,
WorkbenchMessages.FileEditorPreference_existsMessage);
return;
}
if (result < 0) {
found = true;
} else {
i++;
}
}
// Create the new type and insert it
resourceType = new FileEditorMapping(newName, newExtension);
TableItem item = newResourceTableItem(resourceType, i, true);
resourceTypeTable.setFocus();
resourceTypeTable.showItem(item);
fillEditorTable();
}
/**
* Creates the page's UI content.
*/
protected Control createContents(Composite parent) {
imagesToDispose = new ArrayList();
editorsToImages = new HashMap(50);
// define container & its gridding
Composite pageComponent = new Composite(parent, SWT.NULL);
GridLayout layout = new GridLayout();
layout.numColumns = 2;
layout.marginWidth = 0;
layout.marginHeight = 0;
pageComponent.setLayout(layout);
GridData data = new GridData();
data.verticalAlignment = GridData.FILL;
data.horizontalAlignment = GridData.FILL;
pageComponent.setLayoutData(data);
//layout the contents
PreferenceLinkArea contentTypeArea = new PreferenceLinkArea(pageComponent, SWT.NONE,
"org.eclipse.ui.preferencePages.ContentTypes", WorkbenchMessages.FileEditorPreference_contentTypesRelatedLink,//$NON-NLS-1$
(IWorkbenchPreferenceContainer) getContainer(),null);
data = new GridData(GridData.FILL_HORIZONTAL | GridData.GRAB_HORIZONTAL);
contentTypeArea.getControl().setLayoutData(data);
//layout the top table & its buttons
Label label = new Label(pageComponent, SWT.LEFT);
label.setText(WorkbenchMessages.FileEditorPreference_fileTypes);
data = new GridData();
data.horizontalAlignment = GridData.FILL;
data.horizontalSpan = 2;
label.setLayoutData(data);
resourceTypeTable = new Table(pageComponent, SWT.SINGLE | SWT.BORDER
| SWT.FULL_SELECTION);
resourceTypeTable.addListener(SWT.Selection, this);
resourceTypeTable.addListener(SWT.DefaultSelection, this);
data = new GridData(GridData.FILL_HORIZONTAL);
int availableRows = DialogUtil.availableRows(pageComponent);
data.heightHint = resourceTypeTable.getItemHeight()
* (availableRows / 8);
resourceTypeTable.setLayoutData(data);
Composite groupComponent = new Composite(pageComponent, SWT.NULL);
GridLayout groupLayout = new GridLayout();
groupLayout.marginWidth = 0;
groupLayout.marginHeight = 0;
groupComponent.setLayout(groupLayout);
data = new GridData();
data.verticalAlignment = GridData.FILL;
data.horizontalAlignment = GridData.FILL;
groupComponent.setLayoutData(data);
addResourceTypeButton = new Button(groupComponent, SWT.PUSH);
addResourceTypeButton.setText(WorkbenchMessages.FileEditorPreference_add);
addResourceTypeButton.addListener(SWT.Selection, this);
addResourceTypeButton.setLayoutData(data);
setButtonLayoutData(addResourceTypeButton);
removeResourceTypeButton = new Button(groupComponent, SWT.PUSH);
removeResourceTypeButton.setText(WorkbenchMessages.FileEditorPreference_remove);
removeResourceTypeButton.addListener(SWT.Selection, this);
setButtonLayoutData(removeResourceTypeButton);
//Spacer
label = new Label(pageComponent, SWT.LEFT);
data = new GridData();
data.horizontalAlignment = GridData.FILL;
data.horizontalSpan = 2;
label.setLayoutData(data);
// layout the bottom table & its buttons
editorLabel = new Label(pageComponent, SWT.LEFT);
editorLabel.setText(WorkbenchMessages.FileEditorPreference_associatedEditors);
data = new GridData();
data.horizontalAlignment = GridData.FILL;
data.horizontalSpan = 2;
editorLabel.setLayoutData(data);
editorTable = new Table(pageComponent, SWT.SINGLE | SWT.BORDER);
editorTable.addListener(SWT.Selection, this);
editorTable.addListener(SWT.DefaultSelection, this);
data = new GridData(GridData.FILL_BOTH);
data.heightHint = editorTable.getItemHeight() * 7;
editorTable.setLayoutData(data);
groupComponent = new Composite(pageComponent, SWT.NULL);
groupLayout = new GridLayout();
groupLayout.marginWidth = 0;
groupLayout.marginHeight = 0;
groupComponent.setLayout(groupLayout);
data = new GridData();
data.verticalAlignment = GridData.FILL;
data.horizontalAlignment = GridData.FILL;
groupComponent.setLayoutData(data);
addEditorButton = new Button(groupComponent, SWT.PUSH);
addEditorButton.setText(WorkbenchMessages.FileEditorPreference_addEditor);
addEditorButton.addListener(SWT.Selection, this);
addEditorButton.setLayoutData(data);
setButtonLayoutData(addEditorButton);
removeEditorButton = new Button(groupComponent, SWT.PUSH);
removeEditorButton.setText(WorkbenchMessages.FileEditorPreference_removeEditor);
removeEditorButton.addListener(SWT.Selection, this);
setButtonLayoutData(removeEditorButton);
defaultEditorButton = new Button(groupComponent, SWT.PUSH);
defaultEditorButton.setText(WorkbenchMessages.FileEditorPreference_default);
defaultEditorButton.addListener(SWT.Selection, this);
setButtonLayoutData(defaultEditorButton);
fillResourceTypeTable();
if (resourceTypeTable.getItemCount() > 0) {
resourceTypeTable.setSelection(0);
}
fillEditorTable();
updateEnabledState();
workbench.getHelpSystem().setHelp(parent,
IWorkbenchHelpContextIds.FILE_EDITORS_PREFERENCE_PAGE);
applyDialogFont(pageComponent);
return pageComponent;
}
/**
* The preference page is going to be disposed. So deallocate all allocated
* SWT resources that aren't disposed automatically by disposing the page
* (i.e fonts, cursors, etc). Subclasses should reimplement this method to
* release their own allocated SWT resources.
*/
public void dispose() {
super.dispose();
if (imagesToDispose != null) {
for (Iterator e = imagesToDispose.iterator(); e.hasNext();) {
((Image) e.next()).dispose();
}
imagesToDispose = null;
}
if (editorsToImages != null) {
for (Iterator e = editorsToImages.values().iterator(); e.hasNext();) {
((Image) e.next()).dispose();
}
editorsToImages = null;
}
}
/**
* Hook method to get a page specific preference store. Reimplement this
* method if a page don't want to use its parent's preference store.
*/
protected IPreferenceStore doGetPreferenceStore() {
return WorkbenchPlugin.getDefault().getPreferenceStore();
}
protected void fillEditorTable() {
editorTable.removeAll();
FileEditorMapping resourceType = getSelectedResourceType();
if (resourceType != null) {
IEditorDescriptor[] array = resourceType.getEditors();
for (int i = 0; i < array.length; i++) {
IEditorDescriptor editor = array[i];
TableItem item = new TableItem(editorTable, SWT.NULL);
item.setData(DATA_EDITOR, editor);
// Check if it is the default editor
String defaultString = null;
if (resourceType != null) {
if (resourceType.getDefaultEditor() == editor && resourceType.isDeclaredDefaultEditor(editor)) {
defaultString = WorkbenchMessages.FileEditorPreference_defaultLabel;
}
}
if (defaultString != null) {
item.setText(editor.getLabel() + " " + defaultString); //$NON-NLS-1$
} else {
item.setText(editor.getLabel());
}
item.setImage(getImage(editor));
}
// now add any content type editors
EditorRegistry registry = (EditorRegistry) WorkbenchPlugin
.getDefault().getEditorRegistry();
IContentType[] contentTypes = Platform.getContentTypeManager()
.findContentTypesFor(resourceType.getLabel());
for (int i = 0; i < contentTypes.length; i++) {
array = registry.getEditorsForContentType(contentTypes[i]);
for (int j = 0; j < array.length; j++) {
IEditorDescriptor editor = array[j];
// don't add duplicates
TableItem[] items = editorTable.getItems();
TableItem foundItem = null;
for (int k = 0; k < items.length; k++) {
if (items[k].getData(DATA_EDITOR).equals(editor)) {
foundItem = items[k];
break;
}
}
if (foundItem == null) {
TableItem item = new TableItem(editorTable, SWT.NULL);
item.setData(DATA_EDITOR, editor);
item.setData(DATA_FROM_CONTENT_TYPE, contentTypes[i]);
setLockedItemText(item, editor.getLabel());
item.setImage(getImage(editor));
} else { // update the item to reflect its origin
foundItem.setData(DATA_FROM_CONTENT_TYPE, contentTypes[i]);
setLockedItemText(foundItem, foundItem.getText());
}
}
}
}
}
/**
* Set the locked message on the item. Assumes the item has an instance of
* IContentType in the data map.
*
* @param item the item to set
* @param baseLabel the base label
*/
private void setLockedItemText(TableItem item, String baseLabel) {
item.setText(NLS
.bind(WorkbenchMessages.FileEditorPreference_isLocked,
baseLabel, ((IContentType) item
.getData(DATA_FROM_CONTENT_TYPE)).getName()));
}
/**
* Place the existing resource types in the table
*/
protected void fillResourceTypeTable() {
// Populate the table with the items
IFileEditorMapping[] array = WorkbenchPlugin.getDefault()
.getEditorRegistry().getFileEditorMappings();
for (int i = 0; i < array.length; i++) {
FileEditorMapping mapping = (FileEditorMapping) array[i];
mapping = (FileEditorMapping) mapping.clone(); // want a copy
newResourceTableItem(mapping, i, false);
}
}
/**
* Returns the image associated with the given editor.
*/
protected Image getImage(IEditorDescriptor editor) {
Image image = (Image) editorsToImages.get(editor);
if (image == null) {
image = editor.getImageDescriptor().createImage();
editorsToImages.put(editor, image);
}
return image;
}
protected FileEditorMapping getSelectedResourceType() {
TableItem[] items = resourceTypeTable.getSelection();
if (items.length > 0) {
return (FileEditorMapping) items[0].getData(); //Table is single select
}
return null;
}
protected IEditorDescriptor[] getAssociatedEditors() {
if (getSelectedResourceType() == null) {
return null;
}
if (editorTable.getItemCount() > 0) {
ArrayList editorList = new ArrayList();
for (int i = 0; i < editorTable.getItemCount(); i++) {
editorList.add(editorTable.getItem(i).getData(DATA_EDITOR));
}
return (IEditorDescriptor[]) editorList
.toArray(new IEditorDescriptor[editorList.size()]);
}
return null;
}
public void handleEvent(Event event) {
if (event.widget == addResourceTypeButton) {
promptForResourceType();
} else if (event.widget == removeResourceTypeButton) {
removeSelectedResourceType();
} else if (event.widget == addEditorButton) {
promptForEditor();
} else if (event.widget == removeEditorButton) {
removeSelectedEditor();
} else if (event.widget == defaultEditorButton) {
setSelectedEditorAsDefault();
} else if (event.widget == resourceTypeTable) {
fillEditorTable();
}
updateEnabledState();
}
/**
* @see IWorkbenchPreferencePage
*/
public void init(IWorkbench aWorkbench) {
this.workbench = aWorkbench;
noDefaultAndApplyButton();
}
/*
* Create a new <code>TableItem</code> to represent the resource
* type editor description supplied.
*/
protected TableItem newResourceTableItem(IFileEditorMapping mapping,
int index, boolean selected) {
Image image = mapping.getImageDescriptor().createImage(false);
if (image != null) {
imagesToDispose.add(image);
}
TableItem item = new TableItem(resourceTypeTable, SWT.NULL, index);
if (image != null) {
item.setImage(image);
}
item.setText(mapping.getLabel());
item.setData(mapping);
if (selected) {
resourceTypeTable.setSelection(index);
}
return item;
}
/**
* This is a hook for sublcasses to do special things when the ok
* button is pressed.
* For example reimplement this method if you want to save the
* page's data into the preference bundle.
*/
public boolean performOk() {
TableItem[] items = resourceTypeTable.getItems();
FileEditorMapping[] resourceTypes = new FileEditorMapping[items.length];
for (int i = 0; i < items.length; i++) {
resourceTypes[i] = (FileEditorMapping) (items[i].getData());
}
EditorRegistry registry = (EditorRegistry) WorkbenchPlugin.getDefault()
.getEditorRegistry(); // cast to allow save to be called
registry.setFileEditorMappings(resourceTypes);
registry.saveAssociations();
PrefUtil.savePrefs();
return true;
}
/**
* Prompt for editor.
*/
public void promptForEditor() {
EditorSelectionDialog dialog = new EditorSelectionDialog(getControl()
.getShell());
dialog.setEditorsToFilter(getAssociatedEditors());
dialog
.setMessage(NLS.bind(WorkbenchMessages.Choose_the_editor_for_file,getSelectedResourceType().getLabel() ));
if (dialog.open() == Window.OK) {
EditorDescriptor editor = (EditorDescriptor) dialog
.getSelectedEditor();
if (editor != null) {
int i = editorTable.getItemCount();
boolean isEmpty = i < 1;
TableItem item = new TableItem(editorTable, SWT.NULL, i);
item.setData(DATA_EDITOR, editor);
if (isEmpty) {
item
.setText(editor.getLabel()
+ " " + WorkbenchMessages.FileEditorPreference_defaultLabel); //$NON-NLS-1$
} else {
item.setText(editor.getLabel());
}
item.setImage(getImage(editor));
editorTable.setSelection(i);
editorTable.setFocus();
getSelectedResourceType().addEditor(editor);
if (isEmpty) {
getSelectedResourceType().setDefaultEditor(editor);
}
updateSelectedResourceType(); //in case of new default
}
}
}
/**
* Prompt for resource type.
*/
public void promptForResourceType() {
FileExtensionDialog dialog = new FileExtensionDialog(getControl()
.getShell());
if (dialog.open() == Window.OK) {
String name = dialog.getName();
String extension = dialog.getExtension();
addResourceType(name, extension);
}
}
/**
* Remove the editor from the table
*/
public void removeSelectedEditor() {
TableItem[] items = editorTable.getSelection();
boolean defaultEditor = editorTable.getSelectionIndex() == 0;
if (items.length > 0) {
getSelectedResourceType().removeEditor(
(EditorDescriptor) items[0].getData(DATA_EDITOR));
items[0].dispose(); //Table is single selection
}
if (defaultEditor && editorTable.getItemCount() > 0) {
TableItem item = editorTable.getItem(0);
// explicitly set the new editor first editor to default
getSelectedResourceType().setDefaultEditor(
(EditorDescriptor) item.getData(DATA_EDITOR));
if (item != null) {
item
.setText(((EditorDescriptor) (item.getData(DATA_EDITOR)))
.getLabel()
+ " " + WorkbenchMessages.FileEditorPreference_defaultLabel); //$NON-NLS-1$
}
if (!isEditorRemovable(item)) {
setLockedItemText(item, item.getText());
}
}
}
/**
* Remove the type from the table
*/
public void removeSelectedResourceType() {
TableItem[] items = resourceTypeTable.getSelection();
if (items.length > 0) {
items[0].dispose(); //Table is single selection
}
//Clear out the editors too
editorTable.removeAll();
}
/**
* Add the selected editor to the default list.
*/
public void setSelectedEditorAsDefault() {
TableItem[] items = editorTable.getSelection();
if (items.length > 0) {
// First change the label of the old default
TableItem oldDefaultItem = editorTable.getItem(0);
oldDefaultItem
.setText(((EditorDescriptor) oldDefaultItem.getData(DATA_EDITOR))
.getLabel());
// update the label to reflect the locked state
if (!isEditorRemovable(oldDefaultItem)) {
setLockedItemText(oldDefaultItem, oldDefaultItem.getText());
}
// Now set the new default
EditorDescriptor editor = (EditorDescriptor) items[0].getData(DATA_EDITOR);
getSelectedResourceType().setDefaultEditor(editor);
IContentType fromContentType = (IContentType) items[0].getData(DATA_FROM_CONTENT_TYPE);
items[0].dispose(); //Table is single selection
TableItem item = new TableItem(editorTable, SWT.NULL, 0);
item.setData(DATA_EDITOR, editor);
if (fromContentType != null) {
item.setData(DATA_FROM_CONTENT_TYPE, fromContentType);
}
item
.setText(editor.getLabel()
+ " " + WorkbenchMessages.FileEditorPreference_defaultLabel); //$NON-NLS-1$
item.setImage(getImage(editor));
if (!isEditorRemovable(item)) {
setLockedItemText(item, item.getText());
}
editorTable.setSelection(new TableItem[] { item });
}
}
/**
* Update the enabled state.
*/
public void updateEnabledState() {
//Update enabled state
boolean resourceTypeSelected = resourceTypeTable.getSelectionIndex() != -1;
boolean editorSelected = editorTable.getSelectionIndex() != -1;
removeResourceTypeButton.setEnabled(resourceTypeSelected);
editorLabel.setEnabled(resourceTypeSelected);
addEditorButton.setEnabled(resourceTypeSelected);
removeEditorButton.setEnabled(editorSelected && isEditorRemovable());
defaultEditorButton.setEnabled(editorSelected);
}
/**
* Return whether the selected editor is removable. An editor is removable
* if it is not submitted via a content-type binding.
*
* @return whether the selected editor is removable
* @since 3.1
*/
private boolean isEditorRemovable() {
TableItem[] items = editorTable.getSelection();
if (items.length > 0) {
return isEditorRemovable(items[0]);
}
return false;
}
/**
* Return whether the given editor is removable. An editor is removable
* if it is not submitted via a content-type binding.
*
* @param item the item to test
* @return whether the selected editor is removable
* @since 3.1
*/
private boolean isEditorRemovable(TableItem item) {
IContentType fromContentType = (IContentType) item.getData(DATA_FROM_CONTENT_TYPE);
return fromContentType == null;
}
/**
* Update the selected type.
*/
public void updateSelectedResourceType() {
// TableItem item = resourceTypeTable.getSelection()[0]; //Single select
// Image image = ((IFileEditorMapping)item.getData()).getImageDescriptor().getImage();
// imagesToDispose.addElement(image);
// item.setImage(image);
}
}