blob: 175083ec21bd588263011c9b8d3a94ea93cd4ef8 [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 com.ibm.icu.text.Collator;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.ProgressMonitorDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.DisposeEvent;
import org.eclipse.swt.events.DisposeListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Font;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
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.Label;
import org.eclipse.swt.widgets.Layout;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.IEditorDescriptor;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IEditorRegistry;
import org.eclipse.ui.IPerspectiveDescriptor;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.IWorkbenchWindow;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.SelectionDialog;
import org.eclipse.ui.internal.IWorkbenchGraphicConstants;
import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
import org.eclipse.ui.internal.WorkbenchImages;
import org.eclipse.ui.internal.WorkbenchMessages;
import org.eclipse.ui.internal.WorkbenchPage;
import org.eclipse.ui.internal.WorkbenchPartReference;
import org.eclipse.ui.internal.WorkbenchPlugin;
import org.eclipse.ui.internal.layout.CellData;
import org.eclipse.ui.internal.layout.CellLayout;
import org.eclipse.ui.internal.layout.Row;
import org.eclipse.ui.internal.progress.ProgressMonitorJobsDialog;
/**
* Implements a dialog showing all opened editors in the workbench
* and the recent closed editors
*/
public class WorkbenchEditorsDialog extends SelectionDialog {
private IWorkbenchWindow window;
private Table editorsTable;
private Button saveSelected;
private Button closeSelected;
private Button selectClean;
private Button invertSelection;
private Button allSelection;
private boolean showAllPersp = false;
private int sortColumn;
private List elements = new ArrayList();
private HashMap imageCache = new HashMap(11);
private HashMap disabledImageCache = new HashMap(11);
private boolean reverse = false;
private Collator collator = Collator.getInstance();
private Rectangle bounds;
private int columnsWidth[];
private static final String SORT = "sort"; //$NON-NLS-1$
private static final String ALLPERSP = "allPersp"; //$NON-NLS-1$
private static final String BOUNDS = "bounds"; //$NON-NLS-1$
private static final String COLUMNS = "columns"; //$NON-NLS-1$
private SelectionListener headerListener = new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
int index = editorsTable.indexOf((TableColumn) e.widget);
if (index == sortColumn) {
reverse = !reverse;
} else {
sortColumn = index;
}
updateItems();
}
};
/**
* Constructor for WorkbenchEditorsDialog.
*
* @param window the window
*/
public WorkbenchEditorsDialog(IWorkbenchWindow window) {
super(window.getShell());
this.window = window;
setTitle(WorkbenchMessages.WorkbenchEditorsDialog_title);
setShellStyle(getShellStyle() | SWT.RESIZE);
IDialogSettings s = getDialogSettings();
if (s.get(ALLPERSP) == null) {
sortColumn = 0;
} else {
showAllPersp = s.getBoolean(ALLPERSP);
sortColumn = s.getInt(SORT);
String[] array = s.getArray(BOUNDS);
if (array != null) {
bounds = new Rectangle(0, 0, 0, 0);
bounds.x = new Integer(array[0]).intValue();
bounds.y = new Integer(array[1]).intValue();
bounds.width = new Integer(array[2]).intValue();
bounds.height = new Integer(array[3]).intValue();
}
array = s.getArray(COLUMNS);
if (array != null) {
columnsWidth = new int[array.length];
for (int i = 0; i < columnsWidth.length; i++) {
columnsWidth[i] = new Integer(array[i]).intValue();
}
}
}
}
/* (non-Javadoc)
* Method declared on Window.
*/
protected void configureShell(Shell newShell) {
super.configureShell(newShell);
PlatformUI.getWorkbench().getHelpSystem().setHelp(newShell,
IWorkbenchHelpContextIds.WORKBENCH_EDITORS_DIALOG);
}
/*
* (non-Javadoc)
* @see org.eclipse.jface.dialogs.Dialog#createButtonsForButtonBar(org.eclipse.swt.widgets.Composite)
*/
protected void createButtonsForButtonBar(Composite parent) {
// Typically we would use the parent's createButtonsForButtonBar.
// However, we only want a Cancel button and not an OK button. The
// OK button will be used later (in createDialogArea) to activate
// the selected editor.
createButton(parent, IDialogConstants.CANCEL_ID,
IDialogConstants.CANCEL_LABEL, false);
Button button = getButton(IDialogConstants.CANCEL_ID);
if (button != null) {
button.setText(WorkbenchMessages.WorkbenchEditorsDialog_close);
}
}
/**
* Initialize the dialog bounds with the bounds saved
* from the settings.
*/
protected void initializeBounds() {
if (bounds != null) {
getShell().setBounds(bounds);
} else {
super.initializeBounds();
}
}
/**
* Creates the contents of this dialog, initializes the
* listener and the update thread.
*/
protected Control createDialogArea(Composite parent) {
initializeDialogUnits(parent);
Font font = parent.getFont();
Composite dialogArea = new Composite(parent, SWT.NONE);
CellLayout dialogAreaLayout = new CellLayout(1)
.setMargins(
convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_MARGIN),
convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN))
.setSpacing(
convertHorizontalDLUsToPixels(IDialogConstants.HORIZONTAL_SPACING),
convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_SPACING))
.setRow(1, Row.growing());
dialogArea.setLayout(dialogAreaLayout);
dialogArea.setLayoutData(new GridData(GridData.FILL_BOTH));
//Label over the table
Label l = new Label(dialogArea, SWT.NONE);
l.setText(WorkbenchMessages.WorkbenchEditorsDialog_label);
l.setFont(font);
l.setLayoutData(new CellData().align(SWT.FILL, SWT.CENTER));
//Table showing the editors name, full path and perspective
editorsTable = new Table(dialogArea, SWT.MULTI | SWT.BORDER
| SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
editorsTable.setLinesVisible(true);
editorsTable.setHeaderVisible(true);
editorsTable.setFont(font);
final int height = 16 * editorsTable.getItemHeight();
final int width = (int) (2.5 * height);
CellData tableData = new CellData().align(SWT.FILL, SWT.FILL).setHint(
CellData.OVERRIDE, width, height);
editorsTable.setLayoutData(tableData);
editorsTable.setLayout(new Layout() {
protected Point computeSize(Composite composite, int wHint,
int hHint, boolean flushCache) {
return new Point(width, height);
}
protected void layout(Composite composite, boolean flushCache) {
TableColumn c[] = editorsTable.getColumns();
if (columnsWidth == null) {
int w = editorsTable.getClientArea().width;
c[0].setWidth(w * 1 / 3);
c[1].setWidth(w - c[0].getWidth());
} else {
c[0].setWidth(columnsWidth[0]);
c[1].setWidth(columnsWidth[1]);
}
editorsTable.setLayout(null);
}
});
//Name column
TableColumn tc = new TableColumn(editorsTable, SWT.NONE);
tc.setResizable(true);
tc.setText(WorkbenchMessages.WorkbenchEditorsDialog_name);
tc.addSelectionListener(headerListener);
//Full path column
tc = new TableColumn(editorsTable, SWT.NONE);
tc.setResizable(true);
tc.setText(WorkbenchMessages.WorkbenchEditorsDialog_path);
tc.addSelectionListener(headerListener);
// A composite for selection option buttons
Composite selectionButtons = new Composite(dialogArea, SWT.NULL);
Label compLabel = new Label(selectionButtons, SWT.NULL);
compLabel.setFont(font);
GridLayout layout = new GridLayout();
layout.numColumns = 4;
selectionButtons.setLayout(layout);
//Select clean editors button
selectClean = new Button(selectionButtons, SWT.PUSH);
selectClean.setText(WorkbenchMessages.WorkbenchEditorsDialog_selectClean);
selectClean.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
editorsTable.setSelection(selectClean(editorsTable.getItems()));
updateButtons();
}
});
selectClean.setFont(font);
setButtonLayoutData(selectClean);
//Invert selection button
invertSelection = new Button(selectionButtons, SWT.PUSH);
invertSelection.setText(WorkbenchMessages.WorkbenchEditorsDialog_invertSelection);
invertSelection.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
editorsTable.setSelection(invertedSelection(editorsTable
.getItems(), editorsTable.getSelection()));
updateButtons();
}
});
invertSelection.setFont(font);
setButtonLayoutData(invertSelection);
//Select all button
allSelection = new Button(selectionButtons, SWT.PUSH);
allSelection.setText(WorkbenchMessages.WorkbenchEditorsDialog_allSelection);
allSelection.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
editorsTable.setSelection(editorsTable.getItems());
updateButtons();
}
});
allSelection.setFont(font);
setButtonLayoutData(allSelection);
// A composite for selected editor action buttons
Composite actionButtons = new Composite(dialogArea, SWT.NULL);
Label actLabel = new Label(actionButtons, SWT.NULL);
actLabel.setFont(font);
GridLayout actLayout = new GridLayout();
actLayout.numColumns = 4;
actionButtons.setLayout(actLayout);
// Activate selected editor button
createButton(actionButtons, IDialogConstants.OK_ID, WorkbenchMessages.WorkbenchEditorsDialog_activate,
true);
//Close selected editors button
closeSelected = new Button(actionButtons, SWT.PUSH);
closeSelected.setText(WorkbenchMessages.WorkbenchEditorsDialog_closeSelected);
closeSelected.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
closeItems(editorsTable.getSelection());
}
});
closeSelected.setFont(font);
setButtonLayoutData(closeSelected);
//Save selected editors button
saveSelected = new Button(actionButtons, SWT.PUSH);
saveSelected.setText(WorkbenchMessages.WorkbenchEditorsDialog_saveSelected);
saveSelected.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
saveItems(editorsTable.getSelection(), null);
}
});
saveSelected.setFont(font);
setButtonLayoutData(saveSelected);
//Show only active perspective button
final Button showAllPerspButton = new Button(dialogArea, SWT.CHECK);
showAllPerspButton.setText(WorkbenchMessages.WorkbenchEditorsDialog_showAllPersp);
showAllPerspButton.setSelection(showAllPersp);
showAllPerspButton.setFont(font);
setButtonLayoutData(showAllPerspButton);
showAllPerspButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
showAllPersp = showAllPerspButton.getSelection();
updateItems();
}
});
//Create the items and update buttons state
updateItems();
updateButtons();
editorsTable.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(SelectionEvent e) {
updateButtons();
}
public void widgetDefaultSelected(SelectionEvent e) {
okPressed();
}
});
editorsTable.addDisposeListener(new DisposeListener() {
public void widgetDisposed(DisposeEvent e) {
for (Iterator images = imageCache.values().iterator(); images
.hasNext();) {
Image i = (Image) images.next();
i.dispose();
}
for (Iterator images = disabledImageCache.values().iterator(); images
.hasNext();) {
Image i = (Image) images.next();
i.dispose();
}
}
});
editorsTable.setFocus();
applyDialogFont(dialogArea);
return dialogArea;
}
/**
* Updates the button state (enabled/disabled)
*/
private void updateButtons() {
TableItem selectedItems[] = editorsTable.getSelection();
boolean hasDirty = false;
for (int i = 0; i < selectedItems.length; i++) {
Adapter editor = (Adapter) selectedItems[i].getData();
if (editor.isDirty()) {
hasDirty = true;
break;
}
}
saveSelected.setEnabled(hasDirty);
TableItem allItems[] = editorsTable.getItems();
boolean hasClean = false;
for (int i = 0; i < allItems.length; i++) {
Adapter editor = (Adapter) allItems[i].getData();
if (!editor.isDirty()) {
hasClean = true;
break;
}
}
selectClean.setEnabled(hasClean);
invertSelection.setEnabled(allItems.length > 0);
closeSelected.setEnabled(selectedItems.length > 0);
Button ok = getOkButton();
if (ok != null) {
ok.setEnabled(selectedItems.length == 1);
}
}
/**
* Closes the specified editors
*/
private void closeItems(TableItem items[]) {
if (items.length == 0) {
return;
}
for (int i = 0; i < items.length; i++) {
Adapter e = (Adapter) items[i].getData();
e.close();
}
updateItems();
}
/**
* Saves the specified editors
*/
private void saveItems(TableItem items[], IProgressMonitor monitor) {
if (items.length == 0) {
return;
}
ProgressMonitorDialog pmd = new ProgressMonitorJobsDialog(getShell());
pmd.open();
for (int i = 0; i < items.length; i++) {
Adapter editor = (Adapter) items[i].getData();
editor.save(pmd.getProgressMonitor());
updateItem(items[i], editor);
}
pmd.close();
updateItems();
}
/**
* Returns all clean editors from items[];
*/
private TableItem[] selectClean(TableItem items[]) {
if (items.length == 0) {
return new TableItem[0];
}
ArrayList cleanItems = new ArrayList(items.length);
for (int i = 0; i < items.length; i++) {
Adapter editor = (Adapter) items[i].getData();
if (!editor.isDirty()) {
cleanItems.add(items[i]);
}
}
TableItem result[] = new TableItem[cleanItems.size()];
cleanItems.toArray(result);
return result;
}
/**
* Returns all clean editors from items[];
*/
private TableItem[] invertedSelection(TableItem allItems[],
TableItem selectedItems[]) {
if (allItems.length == 0) {
return allItems;
}
ArrayList invertedSelection = new ArrayList(allItems.length
- selectedItems.length);
outerLoop: for (int i = 0; i < allItems.length; i++) {
for (int j = 0; j < selectedItems.length; j++) {
if (allItems[i] == selectedItems[j]) {
continue outerLoop;
}
}
invertedSelection.add(allItems[i]);
}
TableItem result[] = new TableItem[invertedSelection.size()];
invertedSelection.toArray(result);
return result;
}
/**
* Updates the specified item
*/
private void updateItem(TableItem item, Adapter editor) {
item.setData(editor);
item.setText(editor.getText());
Image images[] = editor.getImage();
for (int i = 0; i < images.length; i++) {
if (images[i] != null) {
item.setImage(i, images[i]);
}
}
}
/**
* Adds all editors to elements
*/
private void updateEditors(IWorkbenchPage[] pages) {
for (int j = 0; j < pages.length; j++) {
IEditorReference editors[] = pages[j].getEditorReferences();
for (int k = 0; k < editors.length; k++) {
elements.add(new Adapter(editors[k]));
}
}
}
/**
* Updates all items in the table
*/
private void updateItems() {
editorsTable.removeAll();
elements = new ArrayList();
if (showAllPersp) {
IWorkbenchWindow windows[] = window.getWorkbench()
.getWorkbenchWindows();
for (int i = 0; i < windows.length; i++) {
updateEditors(windows[i].getPages());
}
} else {
IWorkbenchPage page = window.getActivePage();
if (page != null) {
updateEditors(new IWorkbenchPage[] { page });
}
}
sort();
Object selection = null;
if (window.getActivePage() != null) {
selection = window.getActivePage().getActiveEditor();
}
for (Iterator iterator = elements.iterator(); iterator.hasNext();) {
Adapter e = (Adapter) iterator.next();
TableItem item = new TableItem(editorsTable, SWT.NULL);
updateItem(item, e);
if ((selection != null) && (selection == e.editorRef)) {
editorsTable.setSelection(new TableItem[] { item });
}
}
// update the buttons, because the selection may have changed
updateButtons();
}
/**
* Sorts all the editors according to the table header
*/
private void sort() {
//Backward compatible. Table used to have 3 columns.
if (sortColumn > (editorsTable.getColumnCount() - 1)) {
sortColumn = 0;
}
Adapter a[] = new Adapter[elements.size()];
elements.toArray(a);
Arrays.sort(a);
elements = Arrays.asList(a);
}
/**
* The user has selected a resource and the dialog is closing.
*/
protected void okPressed() {
TableItem items[] = editorsTable.getSelection();
if (items.length != 1) {
super.okPressed();
return;
}
saveDialogSettings();
Adapter selection = (Adapter) items[0].getData();
//It would be better to activate before closing the
//dialog but it does not work when the editor is in other
//window. Must investigate.
super.okPressed();
selection.activate();
}
/**
* Saves the dialog settings.
*/
private void saveDialogSettings() {
IDialogSettings s = getDialogSettings();
s.put(ALLPERSP, showAllPersp);
s.put(SORT, sortColumn);
bounds = getShell().getBounds();
String array[] = new String[4];
array[0] = String.valueOf(bounds.x);
array[1] = String.valueOf(bounds.y);
array[2] = String.valueOf(bounds.width);
array[3] = String.valueOf(bounds.height);
s.put(BOUNDS, array);
array = new String[editorsTable.getColumnCount()];
for (int i = 0; i < array.length; i++) {
array[i] = String.valueOf(editorsTable.getColumn(i).getWidth());
}
s.put(COLUMNS, array);
}
/**
* Return a dialog setting section for this dialog
*/
private IDialogSettings getDialogSettings() {
IDialogSettings settings = WorkbenchPlugin.getDefault()
.getDialogSettings();
IDialogSettings thisSettings = settings
.getSection(getClass().getName());
if (thisSettings == null) {
thisSettings = settings.addNewSection(getClass().getName());
}
return thisSettings;
}
/**
* A helper inner class to adapt EditorHistoryItem and IEditorPart
* in the same type.
*/
private class Adapter implements Comparable {
IEditorReference editorRef;
IEditorInput input;
IEditorDescriptor desc;
String text[];
Image images[];
Adapter(IEditorReference ref) {
editorRef = ref;
}
Adapter(IEditorInput input, IEditorDescriptor desc) {
this.input = input;
this.desc = desc;
}
boolean isDirty() {
if (editorRef == null) {
return false;
}
return editorRef.isDirty();
}
boolean isOpened() {
return editorRef != null;
}
void close() {
if (editorRef == null) {
return;
}
WorkbenchPage p = ((WorkbenchPartReference) editorRef).getPane()
.getPage();
p.closeEditor(editorRef, true);
}
void save(IProgressMonitor monitor) {
if (editorRef == null) {
return;
}
IEditorPart editor = (IEditorPart) editorRef.getPart(true);
if (editor != null) {
editor.doSave(monitor);
}
}
String[] getText() {
if (text != null) {
return text;
}
text = new String[2];
if (editorRef != null) {
if (editorRef.isDirty()) {
text[0] = "*" + editorRef.getTitle(); //$NON-NLS-1$
} else {
text[0] = editorRef.getTitle();
}
text[1] = editorRef.getTitleToolTip();
} else {
text[0] = input.getName();
text[1] = input.getToolTipText();
}
return text;
}
Image[] getImage() {
if (images != null) {
return images;
}
images = new Image[2];
if (editorRef != null) {
images[0] = editorRef.getTitleImage();
WorkbenchPage p = ((WorkbenchPartReference) editorRef)
.getPane().getPage();
IPerspectiveDescriptor persp = p.getPerspective();
ImageDescriptor image = persp.getImageDescriptor();
if (image == null) {
image = WorkbenchImages
.getImageDescriptor(IWorkbenchGraphicConstants.IMG_ETOOL_DEF_PERSPECTIVE);
}
} else {
ImageDescriptor image = null;
if (desc != null) {
image = desc.getImageDescriptor();
}
if (image == null) {
IEditorRegistry registry = WorkbenchPlugin.getDefault()
.getEditorRegistry();
image = registry.getImageDescriptor(input.getName());
//TODO: how can this honour content types? Guessing at the content type perhaps?
if (image == null) {
// @issue what should be the default image?
// image = registry.getDefaultEditor().getImageDescriptor();
}
}
if (image != null) {
images[0] = (Image) disabledImageCache.get(image);
if (images[0] == null) {
Image enabled = image.createImage();
Image disabled = new Image(editorsTable.getDisplay(),
enabled, SWT.IMAGE_DISABLE);
enabled.dispose();
disabledImageCache.put(image, disabled);
images[0] = disabled;
}
}
}
return images;
}
private void activate() {
if (editorRef != null) {
IEditorPart editor = editorRef.getEditor(true);
WorkbenchPage p = (WorkbenchPage) editor.getEditorSite()
.getPage();
Shell s = p.getWorkbenchWindow().getShell();
if (s.getMinimized()) {
s.setMinimized(false);
}
s.moveAbove(null);
p.getWorkbenchWindow().setActivePage(p);
p.activate(editor);
} else {
IWorkbenchPage p = window.getActivePage();
if (p != null) {
try {
p.openEditor(input, desc.getId(), true);
} catch (PartInitException e) {
}
}
}
}
public int compareTo(Object another) {
Adapter adapter = (Adapter) another;
int result = collator.compare(getText()[sortColumn], adapter
.getText()[sortColumn]);
if (result == 0) {
int column = sortColumn == 0 ? 1 : 0;
result = collator.compare(getText()[column],
adapter.getText()[column]);
}
if (reverse) {
return result * -1;
}
return result;
}
}
}