/*******************************************************************************
* Copyright (c) 2012-2016 Codenvy, S.A.
* 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:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.ide.ext.java.client.refactoring.rename;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.eclipse.che.api.promises.client.Operation;
import org.eclipse.che.api.promises.client.OperationException;
import org.eclipse.che.api.promises.client.Promise;
import org.eclipse.che.api.promises.client.PromiseError;
import org.eclipse.che.ide.api.editor.EditorWithAutoSave;
import org.eclipse.che.ide.api.notification.NotificationManager;
import org.eclipse.che.ide.api.text.Position;
import org.eclipse.che.ide.dto.DtoFactory;
import org.eclipse.che.ide.ext.java.client.JavaLocalizationConstant;
import org.eclipse.che.ide.ext.java.client.projecttree.JavaSourceFolderUtil;
import org.eclipse.che.ide.ext.java.client.refactoring.RefactorInfo;
import org.eclipse.che.ide.ext.java.client.refactoring.RefactoringUpdater;
import org.eclipse.che.ide.ext.java.client.refactoring.move.RefactoredItemType;
import org.eclipse.che.ide.ext.java.client.refactoring.rename.wizard.RenamePresenter;
import org.eclipse.che.ide.ext.java.client.refactoring.service.RefactoringServiceClient;
import org.eclipse.che.ide.ext.java.shared.dto.LinkedData;
import org.eclipse.che.ide.ext.java.shared.dto.LinkedModeModel;
import org.eclipse.che.ide.ext.java.shared.dto.LinkedPositionGroup;
import org.eclipse.che.ide.ext.java.shared.dto.Region;
import org.eclipse.che.ide.ext.java.shared.dto.refactoring.CreateRenameRefactoring;
import org.eclipse.che.ide.ext.java.shared.dto.refactoring.LinkedRenameRefactoringApply;
import org.eclipse.che.ide.ext.java.shared.dto.refactoring.RefactoringResult;
import org.eclipse.che.ide.ext.java.shared.dto.refactoring.RenameRefactoringSession;
import org.eclipse.che.ide.jseditor.client.document.Document;
import org.eclipse.che.ide.jseditor.client.link.HasLinkedMode;
import org.eclipse.che.ide.jseditor.client.link.LinkedMode;
import org.eclipse.che.ide.jseditor.client.link.LinkedModel;
import org.eclipse.che.ide.jseditor.client.link.LinkedModelData;
import org.eclipse.che.ide.jseditor.client.link.LinkedModelGroup;
import org.eclipse.che.ide.jseditor.client.texteditor.TextEditor;
import org.eclipse.che.ide.ui.dialogs.DialogFactory;
import org.eclipse.che.ide.ui.loaders.request.LoaderFactory;
import org.eclipse.che.ide.ui.loaders.request.MessageLoader;
import javax.validation.constraints.NotNull;
import java.util.ArrayList;
import java.util.List;
import static org.eclipse.che.ide.api.notification.StatusNotification.Status.FAIL;
import static org.eclipse.che.ide.ext.java.shared.dto.refactoring.CreateRenameRefactoring.RenameType.JAVA_ELEMENT;
import static org.eclipse.che.ide.ext.java.shared.dto.refactoring.RefactoringStatus.ERROR;
import static org.eclipse.che.ide.ext.java.shared.dto.refactoring.RefactoringStatus.FATAL;
import static org.eclipse.che.ide.ext.java.shared.dto.refactoring.RefactoringStatus.INFO;
import static org.eclipse.che.ide.ext.java.shared.dto.refactoring.RefactoringStatus.OK;
import static org.eclipse.che.ide.ext.java.shared.dto.refactoring.RefactoringStatus.WARNING;
/**
* Class for rename refactoring java classes
*
* @author Alexander Andrienko
* @author Valeriy Svydenko
*/
@Singleton
public class JavaRefactoringRename {
private final RenamePresenter renamePresenter;
private final RefactoringUpdater refactoringUpdater;
private final JavaLocalizationConstant locale;
private final RefactoringServiceClient refactoringServiceClient;
private final DtoFactory dtoFactory;
private final DialogFactory dialogFactory;
private final NotificationManager notificationManager;
private final MessageLoader loader;
private boolean isActiveLinkedEditor;
private LinkedMode mode;
@Inject
public JavaRefactoringRename(RenamePresenter renamePresenter,
RefactoringUpdater refactoringUpdater,
JavaLocalizationConstant locale,
RefactoringServiceClient refactoringServiceClient,
DtoFactory dtoFactory,
DialogFactory dialogFactory,
NotificationManager notificationManager,
LoaderFactory loaderFactory) {
this.renamePresenter = renamePresenter;
this.refactoringUpdater = refactoringUpdater;
this.locale = locale;
this.dialogFactory = dialogFactory;
this.refactoringServiceClient = refactoringServiceClient;
this.dtoFactory = dtoFactory;
this.notificationManager = notificationManager;
this.loader = loaderFactory.newLoader();
isActiveLinkedEditor = false;
}
/**
* Launch java rename refactoring process
*
* @param textEditorPresenter
* editor where user makes refactoring
*/
public void refactor(final TextEditor textEditorPresenter) {
final CreateRenameRefactoring createRenameRefactoring = createRenameRefactoringDto(textEditorPresenter);
textEditorPresenter.setFocus();
Promise<RenameRefactoringSession> createRenamePromise = refactoringServiceClient.createRenameRefactoring(createRenameRefactoring);
createRenamePromise.then(new Operation<RenameRefactoringSession>() {
@Override
public void apply(RenameRefactoringSession session) throws OperationException {
if (session.isMastShowWizard() || isActiveLinkedEditor) {
renamePresenter.show(session);
if (mode != null) {
mode.exitLinkedMode(false);
}
} else if (session.getLinkedModeModel() != null && textEditorPresenter instanceof HasLinkedMode) {
isActiveLinkedEditor = true;
activateLinkedModeIntoEditor(session, ((HasLinkedMode)textEditorPresenter), textEditorPresenter.getDocument());
} else {
notificationManager.notify(locale.failedToRename(), locale.renameErrorEditor(), FAIL, true,
textEditorPresenter.getEditorInput().getFile().getProject().getProjectConfig());
}
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError arg) throws OperationException {
dialogFactory.createMessageDialog(locale.renameRename(), locale.renameOperationUnavailable(), null).show();
if (mode != null) {
mode.exitLinkedMode(false);
}
}
});
}
private void activateLinkedModeIntoEditor(final RenameRefactoringSession session,
final HasLinkedMode linkedEditor,
final Document document) {
mode = linkedEditor.getLinkedMode();
LinkedModel model = linkedEditor.createLinkedModel();
LinkedModeModel linkedModeModel = session.getLinkedModeModel();
List<LinkedModelGroup> groups = new ArrayList<>();
for (LinkedPositionGroup positionGroup : linkedModeModel.getGroups()) {
LinkedModelGroup group = linkedEditor.createLinkedGroup();
LinkedData data = positionGroup.getData();
if (data != null) {
LinkedModelData modelData = linkedEditor.createLinkedModelData();
modelData.setType("link");
modelData.setValues(data.getValues());
group.setData(modelData);
}
List<Position> positions = new ArrayList<>();
for (Region region : positionGroup.getPositions()) {
positions.add(new Position(region.getOffset(), region.getLength()));
}
group.setPositions(positions);
groups.add(group);
}
model.setGroups(groups);
if (linkedEditor instanceof EditorWithAutoSave) {
((EditorWithAutoSave)linkedEditor).disableAutoSave();
}
mode.enterLinkedMode(model);
mode.addListener(new LinkedMode.LinkedModeListener() {
@Override
public void onLinkedModeExited(boolean successful, int start, int end) {
try {
if (successful) {
loader.show(locale.renameLoader());
String newName = document.getContentRange(start, end - start);
performRename(newName, session, linkedEditor);
}
} finally {
mode.removeListener(this);
isActiveLinkedEditor = false;
if (linkedEditor instanceof EditorWithAutoSave) {
((EditorWithAutoSave)linkedEditor).enableAutoSave();
}
}
}
});
}
private void performRename(final String newName, RenameRefactoringSession session, final HasLinkedMode linkedEditor) {
final LinkedRenameRefactoringApply dto = createLinkedRenameRefactoringApplyDto(newName, session.getSessionId());
Promise<RefactoringResult> applyModelPromise = refactoringServiceClient.applyLinkedModeRename(dto);
applyModelPromise.then(new Operation<RefactoringResult>() {
@Override
public void apply(RefactoringResult result) throws OperationException {
onTargetRenamed(result, linkedEditor);
}
}).catchError(new Operation<PromiseError>() {
@Override
public void apply(PromiseError arg) throws OperationException {
if (linkedEditor instanceof EditorWithAutoSave) {
((EditorWithAutoSave)linkedEditor).enableAutoSave();
}
loader.hide();
notificationManager.notify(locale.failedToRename(), arg.getMessage(), FAIL, true);
}
});
}
private void onTargetRenamed(RefactoringResult result, HasLinkedMode linkedEditor) {
if (linkedEditor instanceof EditorWithAutoSave) {
((EditorWithAutoSave)linkedEditor).enableAutoSave();
}
switch (result.getSeverity()) {
case OK:
RefactorInfo refactorInfo = RefactorInfo.of(RefactoredItemType.JAVA_ELEMENT, null);
refactoringUpdater.updateAfterRefactoring(refactorInfo, result.getChanges());
loader.hide();
break;
case INFO:
case WARNING:
case ERROR:
case FATAL:
loader.hide();
default:
break;
}
}
@NotNull
private CreateRenameRefactoring createRenameRefactoringDto(TextEditor editor) {
CreateRenameRefactoring dto = dtoFactory.createDto(CreateRenameRefactoring.class);
dto.setOffset(editor.getCursorOffset());
dto.setRefactorLightweight(!isActiveLinkedEditor);
String fqn = JavaSourceFolderUtil.getFQNForFile(editor.getEditorInput().getFile());
dto.setPath(fqn);
String projectPath = editor.getDocument().getFile().getProject().getProjectConfig().getPath();
dto.setProjectPath(projectPath);
dto.setType(JAVA_ELEMENT);
return dto;
}
@NotNull
private LinkedRenameRefactoringApply createLinkedRenameRefactoringApplyDto(String newName, String sessionId) {
LinkedRenameRefactoringApply dto = dtoFactory.createDto(LinkedRenameRefactoringApply.class);
dto.setNewName(newName);
dto.setSessionId(sessionId);
return dto;
}
}