blob: 1ee5d59e0f142ba95a45538e4b99fd76391d0ee4 [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.jdt.internal.ui.refactoring;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
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.IProgressMonitor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
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.Item;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.viewers.ArrayContentProvider;
import org.eclipse.jface.viewers.CellEditor;
import org.eclipse.jface.viewers.CheckStateChangedEvent;
import org.eclipse.jface.viewers.ColumnWeightData;
import org.eclipse.jface.viewers.ComboBoxCellEditor;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.ICellModifier;
import org.eclipse.jface.viewers.ICheckStateListener;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TableLayout;
import org.eclipse.jface.window.Window;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ltk.ui.refactoring.RefactoringWizard;
import org.eclipse.ltk.ui.refactoring.UserInputWizardPage;
import org.eclipse.jdt.core.IMember;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.corext.refactoring.structure.PushDownRefactoring;
import org.eclipse.jdt.internal.corext.refactoring.structure.PushDownRefactoringProcessor.MemberActionInfo;
import org.eclipse.jdt.internal.corext.util.Messages;
import org.eclipse.jdt.ui.JavaElementLabelProvider;
import org.eclipse.jdt.internal.ui.IJavaHelpContextIds;
import org.eclipse.jdt.internal.ui.util.ExceptionHandler;
import org.eclipse.jdt.internal.ui.util.PixelConverter;
import org.eclipse.jdt.internal.ui.util.SWTUtil;
import org.eclipse.jdt.internal.ui.util.TableLayoutComposite;
public final class PushDownWizard extends RefactoringWizard {
private static class PushDownInputPage extends UserInputWizardPage {
private static class MemberActionInfoLabelProvider extends LabelProvider implements ITableLabelProvider {
private static String getActionLabel(final int action) {
switch (action) {
case MemberActionInfo.NO_ACTION:
return ""; //$NON-NLS-1$
case MemberActionInfo.PUSH_ABSTRACT_ACTION:
return RefactoringMessages.PushDownInputPage_leave_abstract;
case MemberActionInfo.PUSH_DOWN_ACTION:
return RefactoringMessages.PushDownInputPage_push_down;
default:
Assert.isTrue(false);
return null;
}
}
private static String[] getAvailableActionLabels(final MemberActionInfo info) {
final int[] actions= info.getAvailableActions();
final String[] result= new String[actions.length];
for (int index= 0; index < actions.length; index++) {
result[index]= getActionLabel(actions[index]);
}
return result;
}
private final ILabelProvider fLabelProvider= new JavaElementLabelProvider(JavaElementLabelProvider.SHOW_DEFAULT | JavaElementLabelProvider.SHOW_SMALL_ICONS);
public void dispose() {
fLabelProvider.dispose();
super.dispose();
}
public Image getColumnImage(final Object element, final int index) {
final MemberActionInfo info= (MemberActionInfo) element;
switch (index) {
case MEMBER_COLUMN:
return fLabelProvider.getImage(info.getMember());
case ACTION_COLUMN:
return null;
default:
Assert.isTrue(false);
return null;
}
}
public String getColumnText(final Object element, final int index) {
final MemberActionInfo info= (MemberActionInfo) element;
switch (index) {
case MEMBER_COLUMN:
return fLabelProvider.getText(info.getMember());
case ACTION_COLUMN:
return getActionLabel(info.getAction());
default:
Assert.isTrue(false);
return null;
}
}
}
private class PushDownCellModifier implements ICellModifier {
public boolean canModify(final Object element, final String property) {
if (!ACTION_PROPERTY.equals(property))
return false;
return ((MemberActionInfo) element).isEditable();
}
public Object getValue(final Object element, final String property) {
if (!ACTION_PROPERTY.equals(property))
return null;
final MemberActionInfo info= (MemberActionInfo) element;
return new Integer(info.getAction());
}
public void modify(final Object element, final String property, final Object value) {
if (!ACTION_PROPERTY.equals(property))
return;
final int action= ((Integer) value).intValue();
MemberActionInfo info;
if (element instanceof Item) {
info= (MemberActionInfo) ((Item) element).getData();
} else
info= (MemberActionInfo) element;
if (!canModify(info, property))
return;
info.setAction(action);
PushDownInputPage.this.updateWizardPage(null, true);
}
}
private static final int ACTION_COLUMN= 1;
private final static String ACTION_PROPERTY= "action"; //$NON-NLS-1$
private static final int MEMBER_COLUMN= 0;
private final static String MEMBER_PROPERTY= "member"; //$NON-NLS-1$
private static final String PAGE_NAME= "PushDownInputPage"; //$NON-NLS-1$
private static final int ROW_COUNT= 10;
private static int countEditableInfos(final MemberActionInfo[] infos) {
int result= 0;
for (int index= 0; index < infos.length; index++) {
if (infos[index].isEditable())
result++;
}
return result;
}
private static void setInfoAction(final MemberActionInfo[] infos, final int action) {
for (int index= 0; index < infos.length; index++) {
infos[index].setAction(action);
}
}
private Button fDeselectAllButton;
private Button fEditButton;
private Button fSelectAllButton;
private Label fStatusLine;
private PullPushCheckboxTableViewer fTableViewer;
public PushDownInputPage() {
super(PAGE_NAME);
}
private boolean areAllElementsMarkedAsNoAction() {
return countInfosForAction(MemberActionInfo.NO_ACTION) == ((MemberActionInfo[]) fTableViewer.getInput()).length;
}
private boolean areAllElementsMarkedAsPushDownAction() {
return countInfosForAction(MemberActionInfo.PUSH_DOWN_ACTION) == ((MemberActionInfo[]) fTableViewer.getInput()).length;
}
private void checkPageCompletionStatus(final boolean displayErrorMessage) {
if (areAllElementsMarkedAsNoAction()) {
if (displayErrorMessage)
setErrorMessage(RefactoringMessages.PushDownInputPage_Select_members_to_push_down);
setPageComplete(false);
} else {
setErrorMessage(null);
setPageComplete(true);
}
}
private int countInfosForAction(final int action) {
final MemberActionInfo[] infos= (MemberActionInfo[]) fTableViewer.getInput();
int count= 0;
for (int index= 0; index < infos.length; index++) {
final MemberActionInfo info= infos[index];
if (info.getAction() == action)
count++;
}
return count;
}
private void createButtonComposite(final Composite parent) {
final Composite composite= new Composite(parent, SWT.NONE);
composite.setLayoutData(new GridData(GridData.FILL_VERTICAL));
final GridLayout layout= new GridLayout();
layout.marginHeight= 0;
layout.marginWidth= 0;
composite.setLayout(layout);
fSelectAllButton= new Button(composite, SWT.PUSH);
fSelectAllButton.setText(RefactoringMessages.PullUpWizard_select_all_label);
fSelectAllButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
fSelectAllButton.setEnabled(true);
SWTUtil.setButtonDimensionHint(fSelectAllButton);
fSelectAllButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent event) {
final IMember[] members= getMembers();
setActionForMembers(members, MemberActionInfo.PUSH_DOWN_ACTION);
updateWizardPage(null, true);
}
});
fDeselectAllButton= new Button(composite, SWT.PUSH);
fDeselectAllButton.setText(RefactoringMessages.PullUpWizard_deselect_all_label);
fDeselectAllButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
fDeselectAllButton.setEnabled(false);
SWTUtil.setButtonDimensionHint(fDeselectAllButton);
fDeselectAllButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent event) {
final IMember[] members= getMembers();
setActionForMembers(members, MemberActionInfo.NO_ACTION);
updateWizardPage(null, true);
}
});
fEditButton= new Button(composite, SWT.PUSH);
fEditButton.setText(RefactoringMessages.PushDownInputPage_Edit);
final GridData data= new GridData(GridData.FILL_HORIZONTAL);
data.verticalIndent= new PixelConverter(parent).convertVerticalDLUsToPixels(IDialogConstants.VERTICAL_MARGIN);
fEditButton.setLayoutData(data);
fEditButton.setEnabled(false);
SWTUtil.setButtonDimensionHint(fEditButton);
fEditButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent event) {
PushDownInputPage.this.editSelectedMembers();
}
});
final Button addButton= new Button(composite, SWT.PUSH);
addButton.setText(RefactoringMessages.PushDownInputPage_Add_Required);
addButton.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
SWTUtil.setButtonDimensionHint(addButton);
addButton.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent event) {
PushDownInputPage.this.markAdditionalRequiredMembersAsMembersToPushDown();
}
});
}
public void createControl(final Composite parent) {
final Composite composite= new Composite(parent, SWT.NONE);
composite.setLayout(new GridLayout());
createMemberTableLabel(composite);
createMemberTableComposite(composite);
createStatusLine(composite);
setControl(composite);
Dialog.applyDialogFont(composite);
PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), IJavaHelpContextIds.PUSH_DOWN_WIZARD_PAGE);
}
private void createMemberTable(final Composite parent) {
final TableLayoutComposite layouter= new TableLayoutComposite(parent, SWT.NONE);
layouter.addColumnData(new ColumnWeightData(60, true));
layouter.addColumnData(new ColumnWeightData(40, true));
final Table table= new Table(layouter, SWT.H_SCROLL | SWT.V_SCROLL | SWT.MULTI | SWT.BORDER | SWT.FULL_SELECTION | SWT.CHECK);
table.setHeaderVisible(true);
table.setLinesVisible(true);
final GridData data= new GridData(GridData.FILL_BOTH);
data.heightHint= SWTUtil.getTableHeightHint(table, ROW_COUNT);
data.widthHint= convertWidthInCharsToPixels(30);
layouter.setLayoutData(data);
final TableLayout layout= new TableLayout();
table.setLayout(layout);
final TableColumn first= new TableColumn(table, SWT.NONE);
first.setText(RefactoringMessages.PushDownInputPage_Member);
final TableColumn second= new TableColumn(table, SWT.NONE);
second.setText(RefactoringMessages.PushDownInputPage_Action);
fTableViewer= new PullPushCheckboxTableViewer(table);
fTableViewer.setUseHashlookup(true);
fTableViewer.setContentProvider(new ArrayContentProvider());
fTableViewer.setLabelProvider(new MemberActionInfoLabelProvider());
fTableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(final SelectionChangedEvent event) {
PushDownInputPage.this.updateButtonEnablementState((IStructuredSelection) event.getSelection());
}
});
fTableViewer.addCheckStateListener(new ICheckStateListener() {
public void checkStateChanged(final CheckStateChangedEvent event) {
final boolean checked= event.getChecked();
final MemberActionInfo info= (MemberActionInfo) event.getElement();
if (checked)
info.setAction(MemberActionInfo.PUSH_DOWN_ACTION);
else
info.setAction(MemberActionInfo.NO_ACTION);
updateWizardPage(null, true);
}
});
fTableViewer.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(final DoubleClickEvent event) {
PushDownInputPage.this.editSelectedMembers();
}
});
fTableViewer.setInput(getPushDownRefactoring().getPushDownProcessor().getMemberActionInfos());
updateWizardPage(null, false);
setupCellEditors(table);
}
private void createMemberTableComposite(final Composite parent) {
final Composite composite= new Composite(parent, SWT.NONE);
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
final GridLayout layout= new GridLayout();
layout.numColumns= 2;
layout.marginWidth= 0;
layout.marginHeight= 0;
composite.setLayout(layout);
createMemberTable(composite);
createButtonComposite(composite);
}
private void createMemberTableLabel(final Composite parent) {
final Label label= new Label(parent, SWT.NONE);
label.setText(RefactoringMessages.PushDownInputPage_Specify_actions);
label.setLayoutData(new GridData());
}
private void createStatusLine(final Composite composite) {
fStatusLine= new Label(composite, SWT.NONE);
final GridData data= new GridData();
data.horizontalSpan= 2;
updateStatusLine();
fStatusLine.setLayoutData(data);
}
// String -> Integer
private Map createStringMappingForSelectedElements() {
final Map result= new HashMap();
int action= MemberActionInfo.PUSH_DOWN_ACTION;
result.put(MemberActionInfoLabelProvider.getActionLabel(action), new Integer(action));
int action1= MemberActionInfo.PUSH_ABSTRACT_ACTION;
result.put(MemberActionInfoLabelProvider.getActionLabel(action1), new Integer(action1));
return result;
}
private void editSelectedMembers() {
if (!fEditButton.isEnabled())
return;
final ISelection preserved= fTableViewer.getSelection();
try {
final Map stringMapping= createStringMappingForSelectedElements();
final String[] keys= (String[]) stringMapping.keySet().toArray(new String[stringMapping.keySet().size()]);
Arrays.sort(keys);
final int initialSelectionIndex= getInitialSelectionIndexForEditDialog(stringMapping, keys);
final ComboSelectionDialog dialog= new ComboSelectionDialog(getShell(), RefactoringMessages.PushDownInputPage_Edit_members, RefactoringMessages.PushDownInputPage_Mark_selected_members, keys, initialSelectionIndex);
dialog.setBlockOnOpen(true);
if (dialog.open() == Window.CANCEL)
return;
final int action= ((Integer) stringMapping.get(dialog.getSelectedString())).intValue();
setInfoAction(getSelectedMemberActionInfos(), action);
} finally {
updateWizardPage(preserved, true);
}
}
private boolean enableEditButton(final IStructuredSelection selection) {
if (selection.isEmpty() || selection.size() == 0)
return false;
return selection.size() == countEditableInfos(getSelectedMemberActionInfos());
}
private MemberActionInfo[] getActiveInfos() {
final MemberActionInfo[] infos= getPushDownRefactoring().getPushDownProcessor().getMemberActionInfos();
final List result= new ArrayList(infos.length);
for (int index= 0; index < infos.length; index++) {
final MemberActionInfo info= infos[index];
if (info.isActive())
result.add(info);
}
return (MemberActionInfo[]) result.toArray(new MemberActionInfo[result.size()]);
}
private int getCommonActionCodeForSelectedInfos() {
final MemberActionInfo[] infos= getSelectedMemberActionInfos();
if (infos.length == 0)
return -1;
final int code= infos[0].getAction();
for (int index= 0; index < infos.length; index++) {
if (code != infos[index].getAction())
return -1;
}
return code;
}
private int getInitialSelectionIndexForEditDialog(final Map mapping, final String[] keys) {
final int commonActionCode= getCommonActionCodeForSelectedInfos();
if (commonActionCode == -1)
return 0;
for (final Iterator iterator= mapping.keySet().iterator(); iterator.hasNext();) {
final String key= (String) iterator.next();
final int action= ((Integer) mapping.get(key)).intValue();
if (commonActionCode == action) {
for (int index= 0; index < keys.length; index++) {
if (key.equals(keys[index]))
return index;
}
Assert.isTrue(false);// there's no way
}
}
return 0;
}
private IMember[] getMembers() {
final MemberActionInfo[] infos= (MemberActionInfo[]) fTableViewer.getInput();
final List result= new ArrayList(infos.length);
for (int index= 0; index < infos.length; index++) {
result.add(infos[index].getMember());
}
return (IMember[]) result.toArray(new IMember[result.size()]);
}
private PushDownRefactoring getPushDownRefactoring() {
return (PushDownRefactoring) getRefactoring();
}
private MemberActionInfo[] getSelectedMemberActionInfos() {
Assert.isTrue(fTableViewer.getSelection() instanceof IStructuredSelection);
final List result= ((IStructuredSelection) fTableViewer.getSelection()).toList();
return (MemberActionInfo[]) result.toArray(new MemberActionInfo[result.size()]);
}
public void markAdditionalRequiredMembersAsMembersToPushDown() {
try {
PlatformUI.getWorkbench().getActiveWorkbenchWindow().run(false, false, new IRunnableWithProgress() {
public void run(final IProgressMonitor pm) throws InvocationTargetException {
try {
getPushDownRefactoring().getPushDownProcessor().computeAdditionalRequiredMembersToPushDown(pm);
updateWizardPage(null, true);
} catch (final JavaModelException e) {
throw new InvocationTargetException(e);
} finally {
pm.done();
}
}
});
} catch (final InvocationTargetException e) {
ExceptionHandler.handle(e, getShell(), RefactoringMessages.PushDownInputPage_Push_Down, RefactoringMessages.PushDownInputPage_Internal_Error);
} catch (final InterruptedException e) {
Assert.isTrue(false);// not cancelable
}
}
private void setActionForMembers(final IMember[] members, final int action) {
final MemberActionInfo[] infos= (MemberActionInfo[]) fTableViewer.getInput();
for (int offset= 0; offset < members.length; offset++) {
for (int index= 0; index < infos.length; index++) {
if (infos[index].getMember().equals(members[offset]))
infos[index].setAction(action);
}
}
}
private void setupCellEditors(final Table table) {
final ComboBoxCellEditor comboBoxCellEditor= new ComboBoxCellEditor();
comboBoxCellEditor.setStyle(SWT.READ_ONLY);
fTableViewer.setCellEditors(new CellEditor[] { null, comboBoxCellEditor});
fTableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
public void selectionChanged(final SelectionChangedEvent event) {
if (comboBoxCellEditor.getControl() == null & !table.isDisposed())
comboBoxCellEditor.create(table);
Assert.isTrue(event.getSelection() instanceof IStructuredSelection);
final IStructuredSelection ss= (IStructuredSelection) event.getSelection();
if (ss.size() != 1)
return;
final MemberActionInfo mac= (MemberActionInfo) ss.getFirstElement();
comboBoxCellEditor.setItems(MemberActionInfoLabelProvider.getAvailableActionLabels(mac));
comboBoxCellEditor.setValue(new Integer(mac.getAction()));
}
});
final ICellModifier cellModifier= new PushDownCellModifier();
fTableViewer.setCellModifier(cellModifier);
fTableViewer.setColumnProperties(new String[] { MEMBER_PROPERTY, ACTION_PROPERTY});
}
public void setVisible(final boolean visible) {
super.setVisible(visible);
if (visible) {
fTableViewer.setSelection(new StructuredSelection(getActiveInfos()), true);
fTableViewer.getControl().setFocus();
}
}
private void updateButtonEnablementState(final IStructuredSelection tableSelection) {
if (tableSelection == null || fEditButton == null)
return;
fEditButton.setEnabled(enableEditButton(tableSelection));
if (fSelectAllButton != null)
fSelectAllButton.setEnabled(!areAllElementsMarkedAsPushDownAction());
if (fDeselectAllButton != null)
fDeselectAllButton.setEnabled(!areAllElementsMarkedAsNoAction());
}
private void updateStatusLine() {
if (fStatusLine == null)
return;
final int selected= fTableViewer.getCheckedElements().length;
final String[] keys= { String.valueOf(selected)};
final String msg= Messages.format(RefactoringMessages.PushDownInputPage_status_line, keys);
fStatusLine.setText(msg);
}
private void updateWizardPage(final ISelection preserved, final boolean displayErrorMessage) {
fTableViewer.refresh();
if (preserved != null) {
fTableViewer.getControl().setFocus();
fTableViewer.setSelection(preserved);
}
checkPageCompletionStatus(displayErrorMessage);
updateButtonEnablementState(((IStructuredSelection) fTableViewer.getSelection()));
updateStatusLine();
}
}
public PushDownWizard(final PushDownRefactoring ref) {
super(ref, DIALOG_BASED_USER_INTERFACE);
setDefaultPageTitle(RefactoringMessages.PushDownWizard_defaultPageTitle);
}
protected void addUserInputPages() {
addPage(new PushDownInputPage());
}
}