/*******************************************************************************
* Copyright (c) 2017 Alex Xu 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:
* Alex Xu - initial API and implementation
*******************************************************************************/
package org.eclipse.php.internal.ui.actions;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Comparator;
import org.eclipse.dltk.core.ISourceModule;
import org.eclipse.dltk.core.ISourceRange;
import org.eclipse.dltk.core.ModelException;
import org.eclipse.dltk.core.search.TypeNameMatch;
import org.eclipse.dltk.internal.corext.util.History;
import org.eclipse.dltk.internal.corext.util.QualifiedTypeNameHistory;
import org.eclipse.dltk.internal.ui.editor.EditorUtility;
import org.eclipse.dltk.internal.ui.util.TypeNameMatchLabelProvider;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IStatusLineManager;
import org.eclipse.jface.operation.IRunnableContext;
import org.eclipse.jface.text.*;
import org.eclipse.jface.text.source.ISourceViewer;
import org.eclipse.jface.viewers.ILabelProvider;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.window.Window;
import org.eclipse.php.core.ast.nodes.Program;
import org.eclipse.php.internal.ui.PHPUILanguageToolkit;
import org.eclipse.php.internal.ui.PHPUiPlugin;
import org.eclipse.php.internal.ui.corext.codemanipulation.OrganizeUseStatementsOperation;
import org.eclipse.php.internal.ui.corext.codemanipulation.OrganizeUseStatementsOperation.IChooseImportQuery;
import org.eclipse.php.internal.ui.dialogs.MultiElementListSelectionDialog;
import org.eclipse.php.internal.ui.editor.PHPStructuredEditor;
import org.eclipse.php.internal.ui.util.PHPTypeNameMatchLabelProvider;
import org.eclipse.php.ui.editor.SharedASTProvider;
import org.eclipse.ui.*;
import org.eclipse.ui.progress.IProgressService;
import com.ibm.icu.text.Collator;
/**
* Our sample action implements workbench action delegate. The action proxy will
* be created by the workbench and shown in the UI. When the user tries to use
* the action, this delegate will be created and execution will be delegated to
* it.
*/
public class OrganizeUseStatementsAction extends SelectionDispatchAction {
private static final OrganizeImportComparator ORGANIZE_IMPORT_COMPARATOR = new OrganizeImportComparator();
private PHPStructuredEditor fEditor;
/** <code>true</code> if the query dialog is showing. */
private boolean fIsQueryShowing = false;
public static class ObjectDelegate implements IObjectActionDelegate {
private OrganizeUseStatementsAction fAction;
@Override
public void setActivePart(IAction action, IWorkbenchPart targetPart) {
fAction = new OrganizeUseStatementsAction(targetPart.getSite());
}
@Override
public void run(IAction action) {
fAction.run();
}
@Override
public void selectionChanged(IAction action, ISelection selection) {
if (fAction == null)
action.setEnabled(false);
}
}
private static final class OrganizeImportComparator implements Comparator<String> {
@Override
public int compare(String o1, String o2) {
if (o1.equals(o2))
return 0;
History history = QualifiedTypeNameHistory.getDefault();
int pos1 = history.getPosition(o1);
int pos2 = history.getPosition(o2);
if (pos1 == pos2)
return Collator.getInstance().compare(o1, o2);
if (pos1 > pos2) {
return -1;
} else {
return 1;
}
}
}
public OrganizeUseStatementsAction(IWorkbenchSite site) {
super(site);
setText(Messages.OrganizeImportsAction_label);
setToolTipText(Messages.OrganizeImportsAction_tooltip);
setDescription(Messages.OrganizeImportsAction_description);
}
public OrganizeUseStatementsAction(IEditorPart part) {
this(part.getSite());
if (part instanceof PHPStructuredEditor) {
fEditor = (PHPStructuredEditor) part;
}
}
@Override
public void run(ITextSelection selection) {
ISourceModule cu = getSourceModule(fEditor);
if (cu != null) {
run(cu);
}
}
private static ISourceModule getSourceModule(PHPStructuredEditor fEditor) {
return EditorUtility.getEditorInputModelElement(fEditor, false);
}
@Override
public void run(IStructuredSelection selection) {
ISourceModule cu = getSourceModule(fEditor);
if (cu != null) {
run(cu);
}
}
public void run(ISourceModule sourceModule) {
try {
Program astRoot = SharedASTProvider.getAST(sourceModule, SharedASTProvider.WAIT_ACTIVE_ONLY, null);
OrganizeUseStatementsOperation op = new OrganizeUseStatementsOperation(sourceModule, astRoot,
createChooseImportQuery(fEditor));
IRewriteTarget target = (IRewriteTarget) fEditor.getAdapter(IRewriteTarget.class);
if (target != null) {
target.beginCompoundChange();
}
IProgressService progressService = PlatformUI.getWorkbench().getProgressService();
IRunnableContext context = getSite().getWorkbenchWindow();
IEditingSupport helper = createViewerHelper();
try {
registerHelper(helper, fEditor);
progressService.runInUI(context, new WorkbenchRunnableAdapter(op, op.getScheduleRule()),
op.getScheduleRule());
setStatusBarMessage(getOrganizeInfo(op), fEditor);
} catch (InvocationTargetException e) {
} catch (InterruptedException e) {
} finally {
deregisterHelper(helper, fEditor);
if (target != null) {
target.endCompoundChange();
}
}
} catch (ModelException | IOException e) {
PHPUiPlugin.log(e);
}
}
private String getOrganizeInfo(OrganizeUseStatementsOperation op) {
int nImportsAdded = op.getNumberOfImportsAdded();
if (nImportsAdded >= 0) {
if (nImportsAdded == 1) {
return Messages.OrganizeImportsAction_summary_added_singular;
} else {
return Messages.format(Messages.OrganizeImportsAction_summary_added_plural,
String.valueOf(nImportsAdded));
}
} else {
if (nImportsAdded == -1) {
return Messages.OrganizeImportsAction_summary_removed_singular;
} else {
return Messages.format(Messages.OrganizeImportsAction_summary_removed_plural,
String.valueOf(-nImportsAdded));
}
}
}
private IChooseImportQuery createChooseImportQuery(final PHPStructuredEditor editor) {
return new IChooseImportQuery() {
@Override
public TypeNameMatch[] chooseImports(TypeNameMatch[][] openChoices, ISourceRange[] ranges) {
return doChooseImports(openChoices, ranges, editor);
}
};
}
private TypeNameMatch[] doChooseImports(TypeNameMatch[][] openChoices, final ISourceRange[] ranges,
final PHPStructuredEditor editor) {
// remember selection
ISelection sel = editor.getSelectionProvider().getSelection();
TypeNameMatch[] result = null;
ILabelProvider labelProvider = new PHPTypeNameMatchLabelProvider(TypeNameMatchLabelProvider.SHOW_FULLYQUALIFIED,
PHPUILanguageToolkit.getInstance());
MultiElementListSelectionDialog dialog = new MultiElementListSelectionDialog(getShell(), labelProvider) {
@Override
protected void handleSelectionChanged() {
super.handleSelectionChanged();
// show choices in editor
doListSelectionChanged(getCurrentPage(), ranges, editor);
}
};
fIsQueryShowing = true;
dialog.setTitle(Messages.OrganizeImportsAction_selectiondialog_title);
dialog.setMessage(Messages.OrganizeImportsAction_selectiondialog_message);
dialog.setElements(openChoices);
dialog.setComparator(ORGANIZE_IMPORT_COMPARATOR);
if (dialog.open() == Window.OK) {
Object[] res = dialog.getResult();
result = new TypeNameMatch[res.length];
for (int i = 0; i < res.length; i++) {
Object[] array = (Object[]) res[i];
if (array.length > 0) {
result[i] = (TypeNameMatch) array[0];
QualifiedTypeNameHistory.remember(result[i].getFullyQualifiedName());
}
}
}
// restore selection
if (sel instanceof ITextSelection) {
ITextSelection textSelection = (ITextSelection) sel;
editor.selectAndReveal(textSelection.getOffset(), textSelection.getLength());
}
fIsQueryShowing = false;
return result;
}
private void doListSelectionChanged(int page, ISourceRange[] ranges, PHPStructuredEditor editor) {
if (ranges != null && page >= 0 && page < ranges.length) {
ISourceRange range = ranges[page];
editor.selectAndReveal(range.getOffset(), range.getLength());
}
}
private void setStatusBarMessage(String message, PHPStructuredEditor editor) {
IStatusLineManager manager = editor.getEditorSite().getActionBars().getStatusLineManager();
manager.setMessage(message);
}
private IEditingSupport createViewerHelper() {
return new IEditingSupport() {
@Override
public boolean isOriginator(DocumentEvent event, IRegion subjectRegion) {
return true; // assume true, since we only register while we are
// active
}
@Override
public boolean ownsFocusShell() {
return fIsQueryShowing;
}
};
}
private void registerHelper(IEditingSupport helper, PHPStructuredEditor editor) {
ISourceViewer viewer = editor.getViewer();
if (viewer instanceof IEditingSupportRegistry) {
IEditingSupportRegistry registry = (IEditingSupportRegistry) viewer;
registry.register(helper);
}
}
private void deregisterHelper(IEditingSupport helper, PHPStructuredEditor editor) {
ISourceViewer viewer = editor.getViewer();
if (viewer instanceof IEditingSupportRegistry) {
IEditingSupportRegistry registry = (IEditingSupportRegistry) viewer;
registry.unregister(helper);
}
}
}