blob: 2fae97e6065662b98139c5dd42e8ef27995e6a1a [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2005, 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.ltk.internal.ui.refactoring.history;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.SubProgressMonitor;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.core.runtime.preferences.IEclipsePreferences;
import org.eclipse.core.runtime.preferences.IScopeContext;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ProjectScope;
import org.eclipse.ltk.core.refactoring.RefactoringCore;
import org.eclipse.ltk.core.refactoring.RefactoringDescriptorProxy;
import org.eclipse.ltk.core.refactoring.RefactoringStatus;
import org.eclipse.ltk.core.refactoring.history.IRefactoringHistoryService;
import org.eclipse.ltk.core.refactoring.history.RefactoringHistory;
import org.eclipse.ltk.internal.core.refactoring.RefactoringCoreMessages;
import org.eclipse.ltk.internal.core.refactoring.RefactoringPreferenceConstants;
import org.eclipse.ltk.internal.core.refactoring.history.IRefactoringDescriptorDeleteQuery;
import org.eclipse.ltk.internal.core.refactoring.history.RefactoringHistoryService;
import org.eclipse.ltk.internal.ui.refactoring.IRefactoringHelpContextIds;
import org.eclipse.ltk.internal.ui.refactoring.Messages;
import org.eclipse.ltk.internal.ui.refactoring.RefactoringUIMessages;
import org.eclipse.ltk.internal.ui.refactoring.RefactoringUIPlugin;
import org.eclipse.ltk.internal.ui.refactoring.history.RefactoringHistoryEditHelper.IRefactoringHistoryProvider;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
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.Shell;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.dialogs.IDialogSettings;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.dialogs.MessageDialogWithToggle;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.jface.preference.IPreferencePageContainer;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.PropertyPage;
import org.eclipse.ui.preferences.IWorkbenchPreferenceContainer;
import org.eclipse.ui.preferences.IWorkingCopyManager;
import org.eclipse.ltk.ui.refactoring.history.RefactoringHistoryControlConfiguration;
import org.osgi.service.prefs.BackingStoreException;
/**
* Property page for a project's refactoring history.
*
* @since 3.2
*/
public final class RefactoringPropertyPage extends PropertyPage {
/** The refactoring descriptor delete query */
private final class RefactoringDescriptorDeleteQuery implements IRefactoringDescriptorDeleteQuery {
/** The number of descriptors to delete */
private final int fCount;
/** The return code */
private int fReturnCode= -1;
/** The shell to use */
private final Shell fShell;
/** Has the user already been warned once? */
private boolean fWarned= false;
/**
* Creates a new refactoring descriptor delete query.
*
* @param shell
* the shell to use
* @param count
* the number of descriptors to delete
*/
public RefactoringDescriptorDeleteQuery(final Shell shell, final int count) {
Assert.isNotNull(shell);
Assert.isTrue(count >= 0);
fShell= shell;
fCount= count;
}
/**
* {@inheritDoc}
*/
public boolean hasDeletions() {
return fReturnCode == IDialogConstants.YES_ID;
}
/**
* {@inheritDoc}
*/
public RefactoringStatus proceed(final RefactoringDescriptorProxy proxy) {
final IProject project= getCurrentProject();
if (project != null) {
final IPreferenceStore store= RefactoringUIPlugin.getDefault().getPreferenceStore();
if (!fWarned && !store.getBoolean(PREFERENCE_DO_NOT_WARN_DELETE)) {
fShell.getDisplay().syncExec(new Runnable() {
public final void run() {
if (!fShell.isDisposed()) {
final MessageDialogWithToggle dialog= MessageDialogWithToggle.openYesNoQuestion(fShell, RefactoringUIMessages.RefactoringPropertyPage_confirm_delete_caption, Messages.format(RefactoringUIMessages.RefactoringPropertyPage_confirm_delete_pattern, new String[] { new Integer(fCount).toString(), project.getName()}), RefactoringUIMessages.RefactoringHistoryWizard_do_not_show_message, store.getBoolean(PREFERENCE_DO_NOT_WARN_DELETE), null, null);
store.setValue(PREFERENCE_DO_NOT_WARN_DELETE, dialog.getToggleState());
fReturnCode= dialog.getReturnCode();
}
}
});
}
fWarned= true;
if (fReturnCode == IDialogConstants.YES_ID)
return new RefactoringStatus();
}
return RefactoringStatus.createErrorStatus(IDialogConstants.NO_LABEL);
}
}
/** The dialog settings key */
private static String DIALOG_SETTINGS_KEY= "RefactoringPropertyPage"; //$NON-NLS-1$
/** The empty descriptors constant */
static final RefactoringDescriptorProxy[] EMPTY_DESCRIPTORS= new RefactoringDescriptorProxy[0];
/** Preference key for the warn delete preference */
private static final String PREFERENCE_DO_NOT_WARN_DELETE= RefactoringUIPlugin.getPluginId() + ".do.not.warn.delete.descriptor"; //$NON-NLS-1$;
/** Preference key for the warn delete all preference */
private static final String PREFERENCE_DO_NOT_WARN_DELETE_ALL= RefactoringUIPlugin.getPluginId() + ".do.not.warn.delete.history"; //$NON-NLS-1$;
/** The sort dialog setting */
private static final String SETTING_SORT= "org.eclipse.ltk.ui.refactoring.sortRefactorings"; //$NON-NLS-1$
/** The refactoring preference */
private boolean fHasProjectHistory= false;
/** The refactoring history control */
private ShowRefactoringHistoryControl fHistoryControl;
/** The preferences working copy manager, or <code>null</code> */
private IWorkingCopyManager fManager= null;
/** Has the property page new dialog settings? */
private boolean fNewSettings;
/** The dialog settings, or <code>null</code> */
private IDialogSettings fSettings= null;
/** The share history button, or <code>null</code> */
private Button fShareHistoryButton= null;
/**
* Creates a new refactoring property page.
*/
public RefactoringPropertyPage() {
noDefaultAndApplyButton();
final IDialogSettings settings= RefactoringUIPlugin.getDefault().getDialogSettings();
final IDialogSettings section= settings.getSection(DIALOG_SETTINGS_KEY);
if (section == null)
fNewSettings= true;
else {
fNewSettings= false;
fSettings= section;
}
}
/**
* {@inheritDoc}
*/
protected Control createContents(final Composite parent) {
initializeDialogUnits(parent);
final IPreferencePageContainer container= getContainer();
if (container instanceof IWorkbenchPreferenceContainer)
fManager= ((IWorkbenchPreferenceContainer) container).getWorkingCopyManager();
final Composite composite= new Composite(parent, SWT.NONE);
final GridLayout layout= new GridLayout();
layout.marginWidth= 0;
composite.setLayout(layout);
fHistoryControl= new ShowRefactoringHistoryControl(composite, new RefactoringHistoryControlConfiguration(getCurrentProject(), true, false) {
public String getProjectPattern() {
return RefactoringUIMessages.RefactoringPropertyPage_project_pattern;
}
}) {
protected void createEditButton(final Composite control) {
// No edit button so far
}
};
fHistoryControl.createControl();
boolean sortProjects= true;
final IDialogSettings settings= fSettings;
if (settings != null)
sortProjects= settings.getBoolean(SETTING_SORT);
if (sortProjects)
fHistoryControl.sortByProjects();
else
fHistoryControl.sortByDate();
fHistoryControl.getDeleteAllButton().addSelectionListener(new SelectionAdapter() {
public final void widgetSelected(final SelectionEvent event) {
final IProject project= getCurrentProject();
if (project != null) {
IRunnableContext context= PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (context == null)
context= PlatformUI.getWorkbench().getProgressService();
final IPreferenceStore store= RefactoringUIPlugin.getDefault().getPreferenceStore();
MessageDialogWithToggle dialog= null;
if (!store.getBoolean(PREFERENCE_DO_NOT_WARN_DELETE_ALL) && !fHistoryControl.getInput().isEmpty()) {
dialog= MessageDialogWithToggle.openYesNoQuestion(getShell(), RefactoringUIMessages.RefactoringPropertyPage_confirm_delete_all_caption, Messages.format(RefactoringUIMessages.RefactoringPropertyPage_confirm_delete_all_pattern, project.getName()), RefactoringUIMessages.RefactoringHistoryWizard_do_not_show_message, false, null, null);
store.setValue(PREFERENCE_DO_NOT_WARN_DELETE_ALL, dialog.getToggleState());
}
if (dialog == null || dialog.getReturnCode() == IDialogConstants.YES_ID)
promptDeleteHistory(context, project);
}
}
});
fHistoryControl.getDeleteButton().addSelectionListener(new SelectionAdapter() {
public final void widgetSelected(final SelectionEvent event) {
final RefactoringDescriptorProxy[] selection= fHistoryControl.getCheckedDescriptors();
if (selection.length > 0) {
IRunnableContext context= PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (context == null)
context= PlatformUI.getWorkbench().getProgressService();
final IProject project= getCurrentProject();
if (project != null) {
final Shell shell= getShell();
RefactoringHistoryEditHelper.promptRefactoringDelete(shell, context, fHistoryControl, new RefactoringDescriptorDeleteQuery(shell, selection.length), new IRefactoringHistoryProvider() {
public RefactoringHistory getRefactoringHistory(final IProgressMonitor monitor) {
return RefactoringHistoryService.getInstance().getProjectHistory(project, monitor);
}
}, selection);
}
}
}
});
final Button button= fHistoryControl.getEditButton();
if (button != null) {
button.addSelectionListener(new SelectionAdapter() {
public final void widgetSelected(final SelectionEvent event) {
final RefactoringDescriptorProxy[] selection= fHistoryControl.getSelectedDescriptors();
if (selection.length > 0) {
IRunnableContext context= PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (context == null)
context= PlatformUI.getWorkbench().getProgressService();
RefactoringHistoryEditHelper.promptRefactoringDetails(context, fHistoryControl, selection[0]);
}
}
});
}
fShareHistoryButton= new Button(composite, SWT.CHECK);
fShareHistoryButton.setText(RefactoringUIMessages.RefactoringPropertyPage_share_message);
fShareHistoryButton.setData(RefactoringPreferenceConstants.PREFERENCE_SHARED_REFACTORING_HISTORY);
final GridData data= new GridData(GridData.HORIZONTAL_ALIGN_FILL);
data.verticalIndent= convertHeightInCharsToPixels(1) / 2;
fShareHistoryButton.setLayoutData(data);
fShareHistoryButton.setSelection(hasSharedRefactoringHistory());
new Label(composite, SWT.NONE);
final IProject project= getCurrentProject();
if (project != null) {
IRunnableContext context= PlatformUI.getWorkbench().getActiveWorkbenchWindow();
if (context == null)
context= PlatformUI.getWorkbench().getProgressService();
handleInputEvent(context, project);
}
applyDialogFont(composite);
PlatformUI.getWorkbench().getHelpSystem().setHelp(getControl(), IRefactoringHelpContextIds.REFACTORING_PROPERTY_PAGE);
return composite;
}
/**
* Returns the project currently associated with this property page.
*
* @return the currently associated project, or <code>null</code>
*/
private IProject getCurrentProject() {
return (IProject) getElement().getAdapter(IProject.class);
}
/**
* Returns the preferences for the specified context.
*
* @param manager
* the working copy manager
* @param context
* the scope context
* @return the preferences
*/
private IEclipsePreferences getPreferences(final IWorkingCopyManager manager, final IScopeContext context) {
final IEclipsePreferences preferences= context.getNode(RefactoringCore.ID_PLUGIN);
if (manager != null)
return manager.getWorkingCopy(preferences);
return preferences;
}
/**
* Handles the input event.
*
* @param context
* the runnable context to use
* @param project
* the project
*/
private void handleInputEvent(final IRunnableContext context, final IProject project) {
Assert.isNotNull(context);
Assert.isNotNull(project);
try {
context.run(false, false, new IRunnableWithProgress() {
public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
final IRefactoringHistoryService service= RefactoringCore.getHistoryService();
try {
service.connect();
fHistoryControl.setInput(service.getProjectHistory(project, monitor));
} finally {
service.disconnect();
}
}
});
} catch (InvocationTargetException exception) {
RefactoringUIPlugin.log(exception);
} catch (InterruptedException exception) {
// Do nothing
}
}
/**
* Returns whether a project has an shared refactoring history.
*
* @return <code>true</code> if the project contains an shared project
* history, <code>false</code> otherwise
*/
private boolean hasSharedRefactoringHistory() {
final IProject project= getCurrentProject();
if (project != null)
return RefactoringHistoryService.hasSharedRefactoringHistory(project);
return false;
}
/**
* {@inheritDoc}
*/
protected void performDefaults() {
super.performDefaults();
final IProject project= getCurrentProject();
if (project != null)
setPreference(fManager, new ProjectScope(project), RefactoringPreferenceConstants.PREFERENCE_SHARED_REFACTORING_HISTORY, null);
}
/**
* {@inheritDoc}
*/
public boolean performOk() {
if (fNewSettings) {
final IDialogSettings settings= RefactoringUIPlugin.getDefault().getDialogSettings();
IDialogSettings section= settings.getSection(DIALOG_SETTINGS_KEY);
section= settings.addNewSection(DIALOG_SETTINGS_KEY);
fSettings= section;
}
fSettings.put(SETTING_SORT, fHistoryControl.isSortByProjects());
final IProject project= getCurrentProject();
if (project != null)
setPreference(fManager, new ProjectScope(project), RefactoringPreferenceConstants.PREFERENCE_SHARED_REFACTORING_HISTORY, Boolean.valueOf(fShareHistoryButton.getSelection()).toString());
if (fManager != null)
try {
fManager.applyChanges();
final boolean history= RefactoringHistoryService.hasSharedRefactoringHistory(project);
if (history != fHasProjectHistory && project != null) {
final Job job= new Job(history ? RefactoringUIMessages.RefactoringPropertyPage_sharing_refactoring_history : RefactoringUIMessages.RefactoringPropertyPage_unsharing_refactoring_history) {
public final IStatus run(final IProgressMonitor monitor) {
try {
RefactoringHistoryService.setSharedRefactoringHistory(project, history, monitor);
} catch (CoreException exception) {
RefactoringUIPlugin.log(exception);
return exception.getStatus();
}
return Status.OK_STATUS;
}
};
job.setRule(project);
job.setPriority(Job.SHORT);
job.schedule();
}
} catch (BackingStoreException exception) {
RefactoringUIPlugin.log(exception);
}
return super.performOk();
}
/**
* Prompts the user to delete the project refactoring history.
*
* @param context
* the runnable context to use
* @param project
* the project to delete its refactoring history
*/
protected void promptDeleteHistory(final IRunnableContext context, final IProject project) {
Assert.isNotNull(context);
Assert.isNotNull(project);
final RefactoringHistoryService service= RefactoringHistoryService.getInstance();
try {
service.connect();
try {
final Shell shell= getShell();
context.run(false, true, new IRunnableWithProgress() {
public void run(final IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try {
monitor.beginTask(RefactoringCoreMessages.RefactoringHistoryService_deleting_refactorings, 100);
try {
service.deleteRefactoringHistory(project, new SubProgressMonitor(monitor, 50, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL));
} catch (CoreException exception) {
final Throwable throwable= exception.getStatus().getException();
if (throwable instanceof IOException) {
shell.getDisplay().syncExec(new Runnable() {
public void run() {
MessageDialog.openError(shell, RefactoringUIMessages.ChangeExceptionHandler_refactoring, throwable.getLocalizedMessage());
}
});
} else
throw new InvocationTargetException(exception);
}
final RefactoringHistory history= service.getProjectHistory(project, new SubProgressMonitor(monitor, 50, SubProgressMonitor.SUPPRESS_SUBTASK_LABEL));
shell.getDisplay().syncExec(new Runnable() {
public void run() {
fHistoryControl.setInput(history);
fHistoryControl.setCheckedDescriptors(EMPTY_DESCRIPTORS);
}
});
} finally {
monitor.done();
}
}
});
} catch (InvocationTargetException exception) {
RefactoringUIPlugin.log(exception);
} catch (InterruptedException exception) {
// Do nothing
}
} finally {
service.disconnect();
}
}
/**
* Sets the preference for a certain context.
*
* @param manager
* the working copy manager
* @param context
* the scope context
* @param key
* the key of the preference
* @param value
* the value of the preference
*/
private void setPreference(final IWorkingCopyManager manager, final IScopeContext context, final String key, final String value) {
final IEclipsePreferences preferences= getPreferences(manager, context);
if (value != null)
preferences.put(key, value);
else
preferences.remove(key);
}
/**
* {@inheritDoc}
*/
public void setVisible(final boolean visible) {
fHasProjectHistory= hasSharedRefactoringHistory();
super.setVisible(visible);
}
}