/*******************************************************************************
* Copyright (c) 2009 Andrey Loskutov.
* 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
* Contributor: Andrey Loskutov - initial API and implementation
*******************************************************************************/
package de.loskutov.anyedit.actions.compare;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
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.Job;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.window.Window;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IEditorReference;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.dialogs.ListDialog;
import org.eclipse.ui.progress.UIJob;
import de.loskutov.anyedit.AnyEditToolsPlugin;
import de.loskutov.anyedit.compare.ContentWrapper;
import de.loskutov.anyedit.compare.ExternalFileStreamContent;
import de.loskutov.anyedit.compare.FileStreamContent;
import de.loskutov.anyedit.compare.StreamContent;
import de.loskutov.anyedit.compare.TextStreamContent;
import de.loskutov.anyedit.ui.editor.AbstractEditor;
import de.loskutov.anyedit.util.EclipseUtils;
/**
* @author Andrey
*/
public class CompareWithEditorAction extends CompareWithAction {
private static final String COMPARE_EDITOR_ID = "org.eclipse.compare.CompareEditor";
public CompareWithEditorAction() {
super();
}
@Override
public void selectionChanged(IAction action, ISelection selection) {
// restore disabled state and let us re-test enablement
action.setEnabled(true);
super.selectionChanged(action, selection);
if (action.isEnabled()) {
Object[] elements = new EditorsContentProvider(editor, selectedContent).getElements(null);
action.setEnabled(elements.length > 0);
}
}
@Override
protected StreamContent createRightContent(StreamContent left) throws CoreException {
// WorkbenchLabelProvider.getDecoratingWorkbenchLabelProvider();
ListDialog dialog = createSelectionDialog(editor, selectedContent,
"Select an opened editor to compare with current file:");
int result = dialog.open();
if (result == Window.OK) {
Object[] objects = dialog.getResult();
if (objects != null && objects.length == 1
&& objects[0] instanceof IEditorReference) {
AbstractEditor editor1 = new AbstractEditor(((IEditorReference) objects[0])
.getEditor(true));
ContentWrapper content = ContentWrapper.create(editor1);
if(content == null){
return null;
}
IDocument document = editor1.getDocument();
if(document != null) {
return new TextStreamContent(content, editor1);
}
if (content.getIFile() != null) {
return new FileStreamContent(content);
}
if (content.getFile() != null) {
return new ExternalFileStreamContent(content);
}
}
}
return null;
}
public static ListDialog createSelectionDialog(AbstractEditor myEditor, ContentWrapper selectedContent, String message) {
EditorsContentProvider contentProvider = new EditorsContentProvider(myEditor, selectedContent);
ILabelProvider labelProvider = new EditorsLabelProvider(contentProvider);
class MyListDialog extends ListDialog {
public MyListDialog(Shell parent) {
super(parent);
setShellStyle(getShellStyle() | SWT.RESIZE);
}
}
ListDialog dialog = new MyListDialog(AnyEditToolsPlugin.getShell());
dialog.setContentProvider(contentProvider);
dialog.setLabelProvider(labelProvider);
dialog.setTitle("Select editor");
dialog.setMessage(message);
dialog.setInput(new byte[0]);
dialog.setDialogBoundsSettings(AnyEditToolsPlugin.getDefault()
.getDialogSettings(),
Dialog.DIALOG_PERSISTLOCATION | Dialog.DIALOG_PERSISTSIZE);
return dialog;
}
static final class EditorsLabelProvider extends LabelProvider {
private final EditorsContentProvider contentProvider;
// TODO WorkbenchLabelProvider.getDecoratingWorkbenchLabelProvider(); ???
public EditorsLabelProvider(EditorsContentProvider contentProvider) {
this.contentProvider = contentProvider;
}
@Override
public Image getImage(Object element) {
if (element instanceof IEditorReference) {
IEditorReference reference = (IEditorReference) element;
return reference.getTitleImage();
}
return super.getImage(element);
}
@Override
public String getText(Object element) {
if (element instanceof IEditorReference) {
IEditorReference ref = (IEditorReference) element;
if(contentProvider.isDuplicated(ref)) {
return getFullTitle(ref);
}
return ref.getTitle();
}
return super.getText(element);
}
String getFullTitle(IEditorReference ref) {
String tip = ref.getTitleToolTip();
String title = ref.getTitle();
if(tip != null && tip.endsWith(title)) {
tip = tip.substring(0, tip.lastIndexOf(title));
}
return title + " - " + tip;
}
}
/**
* This provider must not be re-used for more then one execution, as it creates cache
* of editors
* @author Andrey
*/
public static final class EditorsContentProvider implements IStructuredContentProvider {
private final AbstractEditor myEditor;
private final IEditorReference[] references;
private static boolean editorsInitialized;
private static boolean jobStarted;
public EditorsContentProvider(AbstractEditor myEditor, ContentWrapper selectedContent) {
super();
this.myEditor = myEditor;
IEditorReference[] editorReferences = EclipseUtils.getEditors();
boolean initEditor;
if(!editorsInitialized && editorReferences.length > 3){
// spawn a job to init editors for the next time menu is shown
initEditors(editorReferences);
initEditor = false;
} else {
initEditor = true;
}
List<IEditorReference> refs = new ArrayList<IEditorReference>();
for (int i = 0; i < editorReferences.length; i++) {
IEditorReference reference = editorReferences[i];
if(COMPARE_EDITOR_ID.equals(reference.getId())){
continue;
}
// if we are called from navigator (not from editor menu)
if(myEditor == null || myEditor.getPart() == null){
// if navigator context menu has no valid selection
if(selectedContent == null) {
continue;
}
AbstractEditor abstractEditor = new AbstractEditor(reference.getEditor(initEditor));
File file = selectedContent.getFile();
File anotherFile = abstractEditor.getFile();
if(file != null && file.equals(anotherFile)){
// same file as selection
continue;
}
refs.add(editorReferences[i]);
continue;
}
// here we was called from the editor menu
AbstractEditor abstractEditor = new AbstractEditor(reference.getEditor(initEditor));
if (abstractEditor.getPart() == null || sameEditor(abstractEditor)) {
continue;
}
refs.add(editorReferences[i]);
}
references = refs.toArray(new IEditorReference[refs.size()]);
}
private synchronized static void initEditors(final IEditorReference[] editorReferences) {
Job initJob = new UIJob("Initializing editor parts"){
@Override
public IStatus runInUIThread(IProgressMonitor monitor) {
monitor.beginTask("Initializing editor parts", editorReferences.length);
for (int i = 0; i < editorReferences.length; i++) {
if(monitor.isCanceled()){
jobStarted = false;
return Status.CANCEL_STATUS;
}
editorReferences[i].getEditor(true);
monitor.internalWorked(1);
}
editorsInitialized = true;
monitor.done();
return Status.OK_STATUS;
}
};
initJob.setPriority(Job.DECORATE);
initJob.setSystem(true);
if(!jobStarted) {
jobStarted = true;
initJob.schedule(5000);
}
}
private boolean sameEditor(AbstractEditor abstractEditor) {
if(myEditor == null){
return false;
}
File myFile = myEditor.getFile();
File another = abstractEditor.getFile();
return myFile != null && myFile.equals(another);
}
private boolean similarEditor(IEditorReference reference) {
if(myEditor == null) {
return false;
}
IWorkbenchPart part = myEditor.getPart();
if(part == null) {
return false;
}
String title = part.getTitle();
return title!= null && title.equals(reference.getTitle());
}
@Override
public Object[] getElements(Object inputElement) {
return references;
}
@Override
public void dispose() {
// ignore
}
@Override
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
// ignore
}
public boolean isDuplicated(IEditorReference ref) {
String title = ref.getTitle();
if(title == null || title.length() == 0) {
return false;
}
IEditorReference[] elements = (IEditorReference[]) getElements(null);
boolean seen = false;
for (int i = 0; i < elements.length; i++) {
if(title.equals(elements[i].getTitle())){
if(seen || similarEditor(elements[i])) {
return true;
}
seen = true;
}
}
return false;
}
}
}