blob: 90a725c74cffc55c1b5ea392ea999a7691b56193 [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 implementation
//------------------------------------------------------------------------------
package org.eclipse.epf.authoring.ui.util;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.WorkspaceJob;
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.jobs.IJobChangeEvent;
import org.eclipse.core.runtime.jobs.JobChangeAdapter;
import org.eclipse.emf.common.ui.viewer.IViewerProvider;
import org.eclipse.emf.ecore.resource.Resource;
import org.eclipse.emf.ecore.resource.ResourceSet;
import org.eclipse.epf.authoring.ui.AuthoringUIResources;
import org.eclipse.epf.authoring.ui.editors.MethodElementEditor;
import org.eclipse.epf.authoring.ui.editors.MethodElementEditorInput;
import org.eclipse.epf.library.ILibraryManager;
import org.eclipse.epf.library.LibraryService;
import org.eclipse.epf.library.services.SafeUpdateController;
import org.eclipse.epf.library.ui.BusyIndicatorHelper;
import org.eclipse.epf.persistence.MultiFileResourceSetImpl;
import org.eclipse.epf.persistence.refresh.IRefreshHandler;
import org.eclipse.epf.persistence.refresh.RefreshJob;
import org.eclipse.epf.persistence.util.PersistenceUtil;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorPart;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IWorkbenchPage;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.dialogs.ListSelectionDialog;
import org.eclipse.ui.part.ViewPart;
/**
* Notify changes in resources to refresh
*
* @author Phong Nguyen Le
* @since 1.0
*/
public class RefreshHandler implements IRefreshHandler {
private ViewPart view;
public RefreshHandler(ViewPart view) {
this.view = view;
}
private Control getControl() {
if(view instanceof IViewerProvider) {
Viewer viewer = ((IViewerProvider)view).getViewer();
if(viewer != null) {
return viewer.getControl();
}
}
return null;
}
public void refresh(IProgressMonitor monitor) {
Control ctrl = getControl();
if (ctrl == null || ctrl.isDisposed())
return;
doRefresh(monitor);
}
private void doRefresh(IProgressMonitor monitor) {
final boolean refreshViews = !RefreshJob.getInstance()
.getReloadedBeforeRefreshResources().isEmpty()
|| !RefreshJob.getInstance().getAddedResources().isEmpty();
ArrayList<Resource> removedResources = new ArrayList<Resource>(RefreshJob.getInstance()
.getRemovedResources());
ArrayList<Resource> changedResources = new ArrayList<Resource>(RefreshJob.getInstance()
.getChangedResources());
ArrayList<IResource> addedWsResources = new ArrayList<IResource>(RefreshJob.getInstance()
.getAddedWorkspaceResources());
if (!removedResources.isEmpty() || !changedResources.isEmpty()
|| !addedWsResources.isEmpty() || refreshViews) {
doRefresh(removedResources, changedResources,
addedWsResources, refreshViews, monitor);
}
if (!removedResources.isEmpty()) {
RefreshJob.getInstance().getRemovedResources().removeAll(
removedResources);
}
if (!changedResources.isEmpty()) {
RefreshJob.getInstance().getChangedResources().removeAll(
changedResources);
}
if (!addedWsResources.isEmpty()) {
RefreshJob.getInstance().getAddedWorkspaceResources().removeAll(
addedWsResources);
}
if (refreshViews) {
RefreshJob.getInstance().getReloadedBeforeRefreshResources()
.clear();
RefreshJob.getInstance().getAddedResources().clear();
}
}
/**
* Must be synchronized to avoid stepping on each other in reloading
* resources/refreshing UI
*
* @param removedResources
* @param changedResources
* @param addedWorkspaceResources
* collection of IResource objects that are just newly added to
* the library
* @param refreshViews
*/
public synchronized void doRefresh(final Collection<Resource> removedResources,
final Collection<Resource> changedResources, final Collection<IResource> addedWorkspaceResources,
final boolean refreshViews, IProgressMonitor monitor) {
final boolean[] refreshViewsHolder = new boolean[1];
final HashSet<IEditorPart> editorsToRefresh = new HashSet<IEditorPart>();
final Collection<Resource> changedResourcesToRefresh = new ArrayList<Resource>();
SafeUpdateController.syncExec(new Runnable() {
public void run() {
if (!removedResources.isEmpty()) {
collectEditorsToRefreshForRemovedResources(editorsToRefresh, removedResources);
refreshViewsHolder[0] = true;
}
if (!changedResources.isEmpty()) {
changedResourcesToRefresh.addAll(prepareChangedResources(editorsToRefresh, changedResources, null));
}
}
});
// long running operations
//
final boolean[] validateMarkersHolder = new boolean[1];
final WorkspaceJob refreshJob = new WorkspaceJob("Refresh Resources"){
@Override
public IStatus runInWorkspace(IProgressMonitor monitor)
throws CoreException {
monitor.beginTask("Refresh resources", IProgressMonitor.UNKNOWN);
try {
// Unload the removed resources.
if (!removedResources.isEmpty()) {
monitor.subTask("Unloading resources...");
PersistenceUtil.unload(removedResources);
}
// Reload the selected changed resources.
if(changedResourcesToRefresh != null && !changedResourcesToRefresh.isEmpty()) {
ILibraryManager manager = (ILibraryManager) LibraryService
.getInstance().getCurrentLibraryManager();
if (manager != null) {
monitor.subTask("Reloading resources...");
Collection<Resource> reloadedResources = manager.reloadResources(changedResourcesToRefresh);
refreshViewsHolder[0] = !reloadedResources.isEmpty();
}
}
// load new resources
MultiFileResourceSetImpl libResourceSet = null;
if (addedWorkspaceResources != null
&& !addedWorkspaceResources.isEmpty()) {
ILibraryManager mgr = LibraryService.getInstance()
.getCurrentLibraryManager();
if (mgr != null) {
ResourceSet resourceSet = mgr.getEditingDomain()
.getResourceSet();
if (resourceSet instanceof MultiFileResourceSetImpl) {
monitor.subTask("Loading new resources...");
libResourceSet = ((MultiFileResourceSetImpl) resourceSet);
libResourceSet.loadNewResources(addedWorkspaceResources);
}
}
}
validateMarkersHolder[0] = libResourceSet != null;
return Status.OK_STATUS;
} finally {
monitor.done();
}
}
};
SafeUpdateController.syncExec(new Runnable() {
public void run() {
PlatformUI.getWorkbench().getProgressService().showInDialog(Display.getDefault().getActiveShell(), refreshJob);
}
});
refreshJob.addJobChangeListener(new JobChangeAdapter() {
@Override
public void done(IJobChangeEvent event) {
SafeUpdateController.asyncExec(new Runnable() {
public void run() {
collectionEditorsToRefreshAfterUnload(editorsToRefresh, removedResources);
Integer busyId = null;
try {
busyId = BusyIndicatorHelper.showWhile(Display.getCurrent());
if (refreshViews || refreshViewsHolder[0]) {
refreshViews();
}
if (!editorsToRefresh.isEmpty()) {
// refresh the editors that handleRemovedResources requested
//
for (Iterator<IEditorPart> iter = editorsToRefresh.iterator(); iter
.hasNext();) {
Object editor = iter.next();
if (editor instanceof MethodElementEditor) {
((MethodElementEditor) editor).refresh();
}
}
}
} finally {
if(busyId != null) {
BusyIndicatorHelper.hideWhile(Display.getCurrent(), busyId);
}
}
}
});
}
});
refreshJob.setSystem(true);
refreshJob.schedule();
if(validateMarkersHolder[0]) {
// do this in background
WorkspaceJob job = new WorkspaceJob("Validate unresolved reference errors") {
@Override
public IStatus runInWorkspace(IProgressMonitor monitor)
throws CoreException {
ILibraryManager mgr = LibraryService.getInstance()
.getCurrentLibraryManager();
if (mgr != null) {
ResourceSet resourceSet = mgr.getEditingDomain()
.getResourceSet();
if (resourceSet instanceof MultiFileResourceSetImpl) {
((MultiFileResourceSetImpl) resourceSet).getUnresolvedProxyMarkerManager().validateAllMarkers();
}
}
return Status.OK_STATUS;
}
};
job.setSystem(true);
job.schedule();
}
}
private void collectionEditorsToRefreshAfterUnload(Set<IEditorPart> editorsToRefresh,
Collection<Resource> removedResources) {
IEditorReference[] editorReferences = view.getSite().getPage()
.getEditorReferences();
ArrayList<Resource> removedResourceList = new ArrayList<Resource>(removedResources);
for (int i = 0; i < editorReferences.length; i++) {
IEditorReference reference = editorReferences[i];
IEditorPart editor = reference.getEditor(true);
if (editor instanceof MethodElementEditor && !editor.isDirty()) {
Collection<Resource> usedResources = ((MethodElementEditor) editor)
.getUsedResources();
check_resource: for (int j = 0; j < removedResourceList.size(); j++) {
Resource resource = (Resource) removedResourceList.get(j);
if (usedResources.contains(resource)) {
editorsToRefresh.add(editor);
break check_resource;
}
}
}
}
}
/**
* Returns changed resources to be refreshed
*
* @param editorsToRefresh
* @param changedResources
* @return
*/
protected Collection<Resource> prepareChangedResources(
Set<IEditorPart> editorsToRefresh,
Collection<Resource> changedResources, Set<IEditorPart> editorsNotToRefresh) {
Control ctrl = getControl();
if (ctrl == null || ctrl.isDisposed())
return Collections.emptyList();
IWorkbenchPage workbenchPage = view.getSite().getPage();
IEditorReference[] editorReferences = workbenchPage
.getEditorReferences();
ArrayList<IEditorPart> dirtyEditorsWithConflict = new ArrayList<IEditorPart>();
ArrayList<Resource> changedResourceList = new ArrayList<Resource>(changedResources);
// find all editor with dirty conflict
//
for (int i = 0; i < editorReferences.length; i++) {
IEditorReference reference = editorReferences[i];
IEditorPart editor = reference.getEditor(true);
if (editor instanceof MethodElementEditor && editor.isDirty()) {
Collection<Resource> usedResources = ((MethodElementEditor) editor)
.getUsedResources();
check_resource: for (int j = 0; j < changedResourceList.size(); j++) {
Resource resource = (Resource) changedResourceList.get(j);
if (usedResources.contains(resource)) {
dirtyEditorsWithConflict.add(editor);
break check_resource;
}
}
}
}
if (!dirtyEditorsWithConflict.isEmpty()) {
Object[] result = selectDirtyEditors(dirtyEditorsWithConflict);
if(result != null) {
for (int i = 0; i < result.length; i++) {
Object editor = result[i];
if (editor instanceof IEditorPart && (editorsNotToRefresh == null || !editorsNotToRefresh
.contains(editor))
&& (editorsToRefresh == null || !editorsToRefresh
.contains(editor))) {
editorsToRefresh.add((IEditorPart) editor);
dirtyEditorsWithConflict.remove(editor);
}
}
}
// remove all resources used by dirty editors with conflict from the
// collection of changed resources after updating cached modification stamp
// so they will not be prompted to reload again until the next external change
//
for (int i = 0; i < dirtyEditorsWithConflict.size(); i++) {
MethodElementEditor editor = (MethodElementEditor) dirtyEditorsWithConflict
.get(i);
Collection<Resource> usedResources = editor.getUsedResources();
usedResources.retainAll(changedResourceList);
editor.updateResourceInfos(usedResources);
editor.ovewriteResources(usedResources);
changedResourceList.removeAll(usedResources);
}
}
if (!changedResourceList.isEmpty()) {
for (int i = 0; i < editorReferences.length; i++) {
IEditorReference reference = editorReferences[i];
IEditorPart editor = reference.getEditor(true);
if (editor instanceof MethodElementEditor && !editor.isDirty()) {
Collection<Resource> usedResources = ((MethodElementEditor) editor)
.getUsedResources();
check_resource: for (int j = 0; j < changedResourceList
.size(); j++) {
Resource resource = (Resource) changedResourceList
.get(j);
if (usedResources.contains(resource)) {
editorsToRefresh.add(editor);
break check_resource;
}
}
}
}
}
return changedResourceList;
}
private void collectEditorsToRefreshForRemovedResources(
Set<IEditorPart> editorsToRefresh,
Collection<Resource> removedResources) {
IWorkbenchPage workbenchPage = view.getSite().getPage();
IEditorReference[] editorReferences = workbenchPage
.getEditorReferences();
ArrayList<IEditorPart> dirtyEditorsWithConflict = new ArrayList<IEditorPart>();
ArrayList<Resource> removedResourceList = new ArrayList<Resource>(removedResources);
if (editorsToRefresh == null) {
editorsToRefresh = new HashSet<IEditorPart>();
}
// find all editor with dirty conflict
//
for (int i = 0; i < editorReferences.length; i++) {
IEditorReference reference = editorReferences[i];
IEditorPart editor = reference.getEditor(true);
if (editor instanceof MethodElementEditor && editor.isDirty()) {
MethodElementEditorInput input = (MethodElementEditorInput) editor
.getEditorInput();
Resource resource = input.getMethodElement() != null ? input
.getMethodElement().eResource() : null;
if (!removedResources.contains(resource)) {
Collection<Resource> usedResources = ((MethodElementEditor) editor)
.getUsedResources();
check_resource: for (int j = 0; j < removedResourceList
.size(); j++) {
resource = (Resource) removedResourceList.get(j);
if (usedResources.contains(resource)) {
dirtyEditorsWithConflict.add(editor);
break check_resource;
}
}
} else {
editorsToRefresh.add(editor);
}
}
}
if (!dirtyEditorsWithConflict.isEmpty()) {
Object[] selected = selectDirtyEditors(dirtyEditorsWithConflict);
for (int i = 0; i < selected.length; i++) {
editorsToRefresh.add((IEditorPart) selected[i]);
}
}
}
protected void refreshViews() {
}
private Object[] selectDirtyEditors(
ArrayList<IEditorPart> dirtyEditorsWithConflict) {
return selectDirtyEditors(dirtyEditorsWithConflict, view.getSite().getShell());
}
public static Object[] selectDirtyEditors(List<?> dirtyEditors, Shell shell) {
String title = AuthoringUIResources._UI_FileConflict_label;
String msg = AuthoringUIResources.selectEditorsToDiscardConflictChanges;
return selectEditors(dirtyEditors, title, msg, shell);
}
private static Object[] selectEditors(List<?> editors, String title, String msg, Shell shell) {
// prompt user to discard changes in editors that conflict with outside
// change
//
IStructuredContentProvider contentProvider = new IStructuredContentProvider() {
List<?> fContents;
public Object[] getElements(Object inputElement) {
if (fContents != null && fContents == inputElement)
return fContents.toArray();
return new Object[0];
}
public void dispose() {
}
public void inputChanged(Viewer viewer, Object oldInput,
Object newInput) {
if (newInput instanceof List)
fContents = (List<?>) newInput;
else
fContents = null;
}
};
ILabelProvider labelProvider = new LabelProvider() {
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.LabelProvider#getText(java.lang.Object)
*/
public String getText(Object element) {
if (element instanceof IEditorPart) {
return ((IEditorPart) element).getTitle();
}
return super.getText(element);
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.LabelProvider#getImage(java.lang.Object)
*/
public Image getImage(Object element) {
if (element instanceof IEditorPart) {
return ((IEditorPart) element).getTitleImage();
}
return super.getImage(element);
}
};
ListSelectionDialog dlg = new ListSelectionDialog(shell,
editors, contentProvider, labelProvider, msg);
dlg.setTitle(title);
dlg.setBlockOnOpen(true);
dlg.open();
return dlg.getResult();
}
}